usters %d\n", n_clusters);) IFNET_RLOCK();/*新加的,老版本中没有,其定义为mtx_lock(&ifnet_lock),好象是互斥锁,我没有研究过.关于ifnet_lock,是 定义在if.c中,mtx结构,应该是互斥体结构,之所以加上他,应该是和SMP有关系.*/ TAILQ_FOREACH(ifp, &ifnet, if_link) {/*if_link是ifnet链表中的下一个ifnet*/ struct bdg_softc *b;
if (ifp->if_index >= BDG_MAX_PORTS)/*一般不会出现这种情况*/ continue; /* */ b = &(ifp2sc[ifp->if_index]);
if ( b->flags & IFF_BDG_PROMISC ) {/*如果网卡在混杂模式就做下面的工作*/ s = splimp();/*关网络中断*/ ifpromisc(ifp, 0);/*去掉混杂模式,ifp是要去掉该模式的网卡的ifnet结构指针.*/ splx(s);/*开网络中断*/ b->flags &= ~(IFF_BDG_PROMISC|IFF_MUTE) ; DEB(printf(">> now %s%d promisc OFF if_flags 0x%x bdg_flags 0x%x\n", ifp->if_name, ifp->if_unit, ifp->if_flags, b->flags);) } b->flags &= ~(IFF_USED) ;/*去掉IFF_USED标志,既不再桥转发了.*/ b->cluster = NULL;/*该卡所在的组的指针也置空.*/ bdg_stats.s[ifp->if_index].name[0] = '\0';/*当然统计信息也要改了.*/ } IFNET_RUNLOCK();/*解互斥锁,看到这应该明白了,互斥锁是在修改ifnet结构和bdg_stats结构时进行保护的.*/
s = splimp(); for (i=0; i < n_clusters; i++) {/*所有组*/ free(clusters[i].ht, M_IFADDR);/*把HASH表释放掉*/ free(clusters[i].my_macs, M_IFADDR);/*把在组中记录本机网卡硬件地址的空间释放掉*/ } if (clusters != NULL) free(clusters, M_IFADDR);/*释放组占用的空间*/ clusters = NULL;/*置组的头的指针为空*/ n_clusters =0;/*卡分组的数量也重新置0*/ splx(s); }
/* * 把所有卡都置为混杂模式. */ static void bridge_on(void) { struct ifnet *ifp ; int s ;
IFNET_RLOCK();/*看前面bridge_off函数有说明*/ TAILQ_FOREACH(ifp, &ifnet, if_link) {/*遍历整个ifnet结构*/ struct bdg_softc *b = &ifp2sc[ifp->if_index];
if ( !(b->flags & IFF_USED) )/*如果没有在使用*/ continue ; if ( !( ifp->if_flags & IFF_UP) ) {/*如果接口关闭*/ s = splimp(); if_up(ifp);/*打开接口,在if.c中,调用if_route函数,比较复杂,到讲route.c和radix.c的时候再讲*/ splx(s); } if ( !(b->flags & IFF_BDG_PROMISC) ) {/*是否在混杂模式?*/ int ret ; s = splimp(); ret = ifpromisc(ifp, 1);/*设置混杂模式,1是加上混杂模式,0是取消混杂模式*/ splx(s); b->flags |= IFF_BDG_PROMISC ;/*在该卡的bdg_softc结构中也加上混杂模式*/ DEB(printf(">> now %s%d promisc ON if_flags 0x%x bdg_flags 0x%x\n", ifp->if_name, ifp->if_unit, ifp->if_flags, b->flags);) } if (b->flags & IFF_MUTE) {/*去掉阻塞*/ DEB(printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit);) b->flags &= ~IFF_MUTE; } } IFNET_RUNLOCK(); }
/** *该函数在执行系统命令 sysctl net.link.ether.bridge 和sysctl net.link.ether.bdg_cfg后 */ static void reconfigure_bridge(void) { bridge_off();/*先关闭所有卡的桥转发,该函数在上面*/ if (do_bridge) {/*如果桥转发打开了,就执行分析bdg_cfg设置的字符串*/ if (if_index >= BDG_MAX_PORTS) { printf("-- sorry too many interfaces (%d, max is %d)," " disabling bridging\n", if_index, BDG_MAX_PORTS); do_bridge=0; return; } parse_bdg_cfg();/*分析字符串,该函数在下面*/ bridge_on();/*打开所有卡的桥转发,该函数的描述在上面*/ } }
static char bridge_cfg[1024]; /* in BSS so initialized to all NULs */
/* *分析字符串函数,如:...bdg_cfg=vr0:1,vr1:1,fxp0:2,fxp1:2 也就是说对卡进行分组时,要把卡的名称,设备号,及组号 *分解出来,该函数不和内核有太多牵连,纯粹是字符串分解函数,按照目前的这种分解情况,每块卡只能存在于一个组中, *如果我们希望他能在多个组中应该怎么办?而且一卡多组的情况是非常有用的,如: *..........................................| *..........................................| ...Internet 入口 *................................._____________________ *.................................|.......卡1 ........| *.................................|.卡2...........卡3.| 透明网桥A *.................................|___________________| *...................................|..............| *...................................|..............| *................................主机B...........主机C *说明:网桥A是一个有三块卡的FreeBSD主机,其中卡1通向Internet * 主机B是认证服务器,主机C是数据库服务器. * 要求从Internet进入的数据包只能到主机B进行认证,认证后该机IP地址存入主机A的缓冲,才能和C通讯 * 也就是说卡1和卡2是同组,卡1同卡3在认证后将是同组,关于A记录已认证IP地址的方法,我认为最好使用 * patricia树,但在树中只存储主机路由及认证信息. */ static void parse_bdg_cfg() { char *p, *beg ; int l, cluster; static char *sep = ", \t";
for (p = bridge_cfg; *p ; p++) { struct ifnet *ifp; int found = 0; char c; /*该函数在libc库中,index.c中.如下:*/ /* index(p, ch) register const char *p, ch; { for (;; ++p) { if (*p == ch) return((char *)p); if (!*p) return((char *)NULL); } } */
if (index(sep, *p)) /* 由上面的解释可知道,跳过',号' 和 'TAB键 ' */ continue ; /* 卡名是由小写字母和数字组成,如:vr0,fxp0,等 */ for ( beg = p ; islower(*p) || isdigit(*p) ; p++ )/*循环开始,是小写或数字时继续*/ ; l = p - beg ; /* 得到了名字的长度*/ if (l == 0) /* 长度是0当然是不行的 */ break ; if ( *p != ':' ) /* 紧接的后面的字符如果不是":",那么就假定默认为组1 */ cluster = 1 ; else cluster = strtoul( p+1, &p, 10);/*字符转换为无符号整数*/ c = *p; /*暂时把p指针中的东西保存到C中,因为要把0(字符串结尾)放到*p中,以后再换回*/ *p = '\0'; /* * 开始在接口列表中查找该网卡名 */ IFNET_RLOCK(); /* 互斥锁 */ TAILQ_FOREACH(ifp, &ifnet, if_link) {/*遍历整个ifnet结构*/ char buf[IFNAMSIZ];
snprintf(buf, sizeof(buf), "%s%d", ifp->if_name, ifp->if_unit);/*把卡名字和子设备号合并放到buf中,如:名字=vr,子设备号=0,合并后为vr0*/ if (!strncmp(beg, buf, max(l, strlen(buf)))) {/*比较我们参数的设备名和buf中的相等吗?*/ struct bdg_softc *b = &ifp2sc[ifp->if_index]; if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN) {/*不是以太网卡*/ printf("%s is not an ethernet, continue\n", buf); continue; } if (b->flags & IFF_USED) {/*如果接口卡中有该标志,那他已经用于bridge了.*/ printf("%s already used, skipping\n", buf); break; } b->cluster = add_cluster(htons(cluster), (struct arpcom *)ifp);/*调用前面的函数,把卡加入到组中.*/ b->flags |= IFF_USED ;/*加上bridge开始使用标志*/ sprintf(bdg_stats.s[ifp->if_index].name, /*打印信息到屏幕*/ "%s%d:%d", ifp->if_name, ifp->if_unit, cluster);
DEB(printf("--++ found %s next c %d\n", bdg_stats.s[ifp->if_index].name, c);) found = 1;/*置发现标志*/ break ; } } IFNET_RUNLOCK();/*解互斥锁*/ if (!found)/*没找到接口,可能是你参数输入错误*/ printf("interface %s Not found in bridge\n", beg); *p = c;/*换回来*/ if (c == '\0') break; /* 到了字符串结尾 */ } }
/* * 如果使用的是SYSCTL_PROC来定义一个控制节点,那么第7个参数是一个处理函数指针,以下这两个函数都是处理函数 */ static int sysctl_bdg(SYSCTL_HANDLER_ARGS) /*以下是在sysctl.h中关于SYSCTL_HANDLER_ARGS的说明*/ /*#define SYSCTL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req */ { int error, oldval = do_bridge ;/*把do_bridge放到oldval中暂时保存*/
error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);/*该函数把数据放到全局结构变量oidp中*/ /*由于oidp中有指向do_bridge的指针,所以*/ /*sysctl中的=xxx的值将放到do_bridge中*/ DEB( printf("called sysctl for bridge name %s arg2 %d val %d->%d\n", oidp->oid_name, oidp->oid_arg2, oldval, do_bridge); )
if (oldval != do_bridge)/*如果和原来的值不同,就重新设置bridge*/ reconfigure_bridge(); return error ; }
/* * 和上面是一样的,这里就不多解释了.他们不同之处是一个是整数型,一个是字符串型 */ static int sysctl_bdg_cfg(SYSCTL_HANDLER_ARGS) { int error = 0 ; char old_cfg[1024] ;/*不同的地方,即是字符串*/
strcpy(old_cfg, bridge_cfg) ;/*字符串拷贝,已经检查过,没有溢出产生.如有兴趣,可查LIBC库*/
error = sysctl_handle_string(oidp, bridge_cfg, oidp->oid_arg2, req); DEB( printf("called sysctl for bridge name %s arg2 %d err %d val %s->%s\n", oidp->oid_name, oidp->oid_arg2, error, old_cfg, bridge_cfg); ) if (strcmp(old_cfg, bridge_cfg)) reconfigure_bridge(); return error ; }
static int sysctl_refresh(SYSCTL_HANDLER_ARGS) { if (req->newptr) reconfigure_bridge();/*该函数在上面*/
return 0; }
SYSCTL_DECL(_net_link_ether);/*申明一节点,表示下面的SYSCTL将继承该节点*/ SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_cfg, CTLTYPE_STRING|CTLFLAG_RW, &bridge_cfg, sizeof(bridge_cfg), &sysctl_bdg_cfg, "A", "Bridge configuration");/*网卡的分组,"A"代表参数是字符串,sysctl_bdg_cfg是处理的函数的名称*/
SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW, &do_bridge, 0, &sysctl_bdg, "I", "Bridging");/*对桥转发开关的控制,sysctl_bdf是控制函数,"I"代表参数是整数型*/
SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,"Pass bridged pkts through firewall");/*对桥的防火墙的开关*/
SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ip上一页 [1] [2] [3] [4] [5] 下一页 |