⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bridge_current.c

📁 Details description of Free BSD network source code.Those documents have explained each line of code
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 intsysctl_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 intsysctl_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 intsysctl_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_ipf, CTLFLAG_RW,	    &bdg_ipf, 0,"Pass bridged pkts through IPFilter");/*包过滤的开关*//*因为下面都是控制整数型变量,所以做一个宏*/#define SY(parent, var, comment)			\  	static int var ;				\	SYSCTL_INT(parent, OID_AUTO, var, CTLFLAG_RW, &(var), 0, comment);/*以下的SYSCTL大都用于防火墙控制*/int bdg_ipfw_drops;SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_drop,	CTLFLAG_RW, &bdg_ipfw_drops,0,"");int bdg_ipfw_colls;SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_collisions,	CTLFLAG_RW, &bdg_ipfw_colls,0,"");SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_refresh, CTLTYPE_INT|CTLFLAG_WR,	    NULL, 0, &sysctl_refresh, "I", "iface refresh");#if 1 SY(_net_link_ether, verbose, "Be verbose");SY(_net_link_ether, bdg_split_pkts, "Packets split in bdg_forward");SY(_net_link_ether, bdg_thru, "Packets through bridge");SY(_net_link_ether, bdg_copied, "Packets copied in bdg_forward");SY(_net_link_ether, bdg_dropped, "Packets dropped in bdg_forward");SY(_net_link_ether, bdg_copy, "Force copy in bdg_forward");SY(_net_link_ether, bdg_predict, "Correctly predicted header location");SY(_net_link_ether, bdg_fw_avg, "Cycle counter avg");SY(_net_link_ether, bdg_fw_ticks, "Cycle counter item");SY(_net_link_ether, bdg_fw_count, "Cycle counter count");#endifSYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats,	CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");static int bdg_loops ;static voidbdg_timeout(void *dummy){    static int slowtimer; /*会初始化为0*/    if (do_bridge) {/*桥转发打开了就执行下面的*/		static int age_index = 0 ;		int l = age_index + HASH_SIZE/4 ;/*l=2048,因为HASH表内放的是指针,每个指针占用4字节,所以/4表示有多少个指针*/		int i;	/*	 */		if (l > HASH_SIZE)/*这时候l=2048,怎么可能>HASH_SIZE(9182)*/			l = HASH_SIZE ;		for (i=0; i<n_clusters; i++) {/*遍历每个组*/			bdg_hash_table *bdg_table = clusters[i].ht;/*该网卡的HASH表*/			for (; age_index < l ; age_index++)/*遍历整个HASH表*/				if (bdg_table[age_index].used)  /*如果该成员被使用了*/					bdg_table[age_index].used = 0 ;/*清除掉,但我不清楚为什么不同时清除成员name,如果在此时bridge_in正接收*/													/*到包,会把name保存到old变量中,会不会出问题呢?(可看看下面的bridge_in)*/				else if (bdg_table[age_index].name) {					bdg_table[age_index].name = NULL ;				}		}		if (age_index >= HASH_SIZE)			age_index = 0 ;		if (--slowtimer <= 0 ) {/*经过5次的bdg_timeout后,才为0*/			slowtimer = 5 ;/*由于在初始化时,slowtimer被置为0,所以在函数第一次被调用时,次处总会被执行*/			bridge_on() ; /* 打开桥的一些设置,看上面的该函数说明.*/			bdg_loops = 0 ;		}    }    bdg_timeout_h = timeout(bdg_timeout, NULL, 2*hz );/*启动监视器*/}/* * 查找包的目的地,返回值如下: *	BDG_BCAST	广播包,这种包是要发送到每一个接口的 *	BDG_MCAST	多播包 *	BDG_LOCAL	该包是发送给本机的一个包,如果该机做为透明网桥放火墙,应该拦截该包,并做特殊处理 *	BDG_DROP	该包必须抛弃 *	other		其他类型的包 * */static __inlinestruct ifnet *bridge_dst_lookup(struct ether_header *eh, struct cluster_softc *c){/*eh是以太网包的头部*/    struct ifnet *dst ;    int index ;    struct bdg_addr *p ;    bdg_hash_table *bt;		/*HASH表入口指针 */    if (IS_ETHER_BROADCAST(eh->ether_dhost))/*是广播地址吗?*/	return BDG_BCAST ;/*是的就返回广播地址标志*/    if (eh->ether_dhost[0] & 1)/*硬件地址的最后一位是1吗?即是多播地址吗*/	return BDG_MCAST ;/*是的就返回多播地址标志*/    /*     * 以下循环是查看本机的所有网卡的硬件地址是否和eh中的目的地址相同,相同就是发送到本机的.     */    for (index = c->ports, p = c->my_macs; index ; index--, p++ )/*在cluster_softc结构中遍历本机所有网卡*/	if (BDG_MATCH(p->etheraddr, eh->ether_dhost) )/*和这块卡的硬件地址相同吗?*/	    return BDG_LOCAL ;/*相同就返回本地的标志*/    /*     * 如果以上都不是,那么在HASH表中查找一下,目的地和本机的那块卡相连.     */    index= HASH_FN( eh->ether_dhost );/*HASH查找,精华部分,查到该地址在HASH表的第index个偏移*/    bt = &(c->ht[index]);/*定位该HASH条目的入口*/    dst = bt->name;/*得到与目的地机器相连的本机某网卡的ifnet结构指针*/    if ( dst && BDG_MATCH( bt->etheraddr, eh->ether_dhost) )	return dst ;/*返回该指针*/    else	return BDG_UNKNOWN ;/*否则没查到,我不知道什么时候将出现该情况.*/}/** * bridge_in() 函数由if_ethersubr.c中的ether_input函数调用,在该函数中会判断bridge功能是否打开,如果打开 * 既调用该函数.ether_input函数会根据返回值决定是否调用我们即将讲的下一个函数bridge_forward. * 函数入口: *   eh		进入以太网包的以太网包头. *   ifp	ifnet结构,即该包是从哪块卡进来的.(ifnet包含了卡的所有信息) * * 函数返回: 目的地要进过本机哪块网卡发送,即那块卡的ifnet结构指针.说明如下 *   BDG_BCAST	广播地址 *   BDG_MCAST  多播地址 *   BDG_LOCAL  不需要转发,该包是发给本机的. *   BDG_DROP   该包要丢弃 *   ifp	即将发送的网卡的ifnet指针. * */static struct ifnet *bridge_in(struct ifnet *ifp, struct ether_header *eh){    int index;    struct ifnet *dst , *old ;    bdg_hash_table *bt;			/* 将用来放置当前HASH表中该地址的HASH指针的位置 */    int dropit = BDG_MUTED(ifp) ;    /*     * HASH_FN宏在上面的函数中已经有描述.不过在这里是查看对方的MAC地址是否以前有记录(即在HASH表中查找)     */    index= HASH_FN(eh->ether_shost);/*这中HASH的查找方法是否有问题,是否会产生同义词?他的算法是MAC地址的*/									/*[1]和[2]两字节互补后在和HASH长度-1相与,那他认为是唯一值,这是不可靠的.*/									/*我们可以利用该情况生成同义词,进行HASH覆盖,带着次问题我又查看了OpenBSD*/									/*的源代码,他的算法又是另外一种,请看OpenBSD的Alley算法(Bob Jenkins):*/	/*	#define	mix(a,b,c) \            本人因能力有限,看不懂OpenBSD的算法	do {						\		a -= b; a -= c; a ^= (c >> 13);		\		b -= c; b -= a; b ^= (a << 8);		\		c -= a; c -= b; c ^= (b >> 13);		\		a -= b; a -= c; a ^= (c >> 12);		\		b -= c; b -= a; b ^= (a << 16);		\		c -= a; c -= b; c ^= (b >> 5);		\		a -= b; a -= c; a ^= (c >> 3);		\		b -= c; b -= a; b ^= (a << 10);		\		c -= a; c -= b; c ^= (b >> 15);		\	} while (0)	u_int32_t	bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)   下面的更看不懂了,OpenBSD的哈稀函数	{		u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_hashkey;		b += addr->ether_addr_octet[5] << 8;		b += addr->ether_addr_octet[4];		a += addr->ether_addr_octet[3] << 24;		a += addr->ether_addr_octet[2] << 16;		a += addr->ether_addr_octet[1] << 8;		a += addr->ether_addr_octet[0];		mix(a, b, c);		return (c & BRIDGE_RTABLE_MASK);	}	如果你不懂得以上的算法,那么桥的技术应该说还没精通.本人就是这样,不是谦虚.计算机搞	到后面基本上就是拼算法的先进与合理性.	*/    bt = &(ifp2sc[ifp->if_index].cluster->ht[index]);/*当然假定index没有同义词,那么就													/*可以找到该MAC地址在HASH表的入口了*/    bt->used = 1 ;/*该MAC的HASH指针开始启用.*/    old = bt->name ;/*暂时存放到old中,记住,大家看看timeout中对bt->name的清除是多么的重要啊*/    if ( old ) { /* 为真就是以前就填充过,说明该机器以前发过包通过本机. */		if (!BDG_MATCH( eh->ether_shost, bt->etheraddr) ) {/*看看上次对方机器的包的源硬件地址和本次的地址相同吗?*/			bdg_ipfw_colls++ ;/*不同,有问题,其实这里的操作有点类似ARP中的.*/			bt->name = NULL ;		} else if (old != ifp) {/*源地址是对的,但本机接收网卡发生了更换(重新设置了网卡)或源机器移动了.环回也有可能*/		bt->name = ifp ; /* 指向新的正确的接收网卡的ifnet结构 */	    printf("-- loop (%d) %6D to %s%d from %s%d (%s)\n",			bdg_loops, eh->ether_shost, ".",			ifp->if_name, ifp->if_unit,			old->if_name, old->if_unit,			BDG_MUTED(old) ? "muted":"active");/*打印信息到屏幕*/	    dropit = 1 ;/*在本次转发中是否转发,1是不转发,就是说在发现上面的那种情况后,不转发该包*/	    if ( !BDG_MUTED(old) ) {			if (++bdg_loops > 10)				BDG_MUTE(old) ;			}		}    }    /*     * 把发送方的地址写到HASH表中.     */    if (bt->name == NULL) {/*因为发送方是第一次发送包.*/	DEB(printf("new addr %6D at %d for %s%d\n",	    eh->ether_shost, ".", index, ifp->if_name, ifp->if_unit);)	bcopy(eh->ether_shost, bt->etheraddr, 6);/*把发送方的以太网硬件地址放到HASH表中该发送方HASH索引的地方.*/	bt->name = ifp ;    }    dst = bridge_dst_lookup(eh, ifp2sc[ifp->if_index].cluster);/*调用上面说明的函数来查找目的地要经过的本机网卡.*/    /*     * BDG_STAT是对bdg_port_stat结构进行操作,统计各种包的in的数量(做++操作)     */    BDG_STAT(ifp, BDG_IN);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -