f, 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"); #endif
SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats, CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");
static int bdg_loops ;
static void bdg_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 __inline struct 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); switch ((uintptr_t)dst) { case (uintptr_t)BDG_BCAST: case (uintptr_t)BDG_MCAST: case (uintptr_t)BDG_LOCAL: case (uintptr_t)BDG_UNKNOWN: case (uintptr_t)BDG_DROP: BDG_STAT(ifp, dst); break ; default : if (dst == ifp || dropit) BDG_STAT(ifp, BDG_DROP); else BDG_STAT(ifp, BDG_FORWARD); break ; }
if ( dropit ) {/*不转发为真吗?*/ if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL) dst = BDG_LOCAL ;/*如果是发送给本机的包,即上面那些条件成立,返回该标志由ether_input函数处理*/ else dst = BDG_DROP ;/*该标志返回给ether_input后,该函数会把包抛弃*/ } else { if (dst == ifp)/*如果包来自该接口,又要发送到该接口,当然应该丢弃该包*/ dst = BDG_DROP; } DEB(printf("bridge_in %6D ->%6D ty 0x%04x dst %s%d\n",eh->ether_shost, ".",eh->ether_dhost, ".",ntohs(eh->ether_type), (dst <= BDG_FORWARD) ? bdg_dst_names[(int)dst] :dst->if_name,(dst <= BDG_FORWARD) ? 0 : dst->if_unit); )
return dst ;/*返回的值是给ether_input函数的*/ }
/* 该函数由ether_input函数(if_ethersubr.c中)调用,作用是把包转发到相应的网络接口 * 参数dst是将要被转发的接口,当然,他可以是一个接口,也有可能是一组或所有接口. * 该函数内是作为放火墙代码的放置地的理想地方.非同组接口过滤,以太层包过滤,IP层包过滤 * 或自己编写的钩子都可以在此实现. */ static struct mbuf * bdg_forward(struct mbuf *m0, struct ifnet *dst) { /*该宏的作用是把先前保存的以太网包头部恢复到mbuf中.*/ #define EH_RESTORE(_m) do { \
上一页 [1] [2] [3] [4] [5] 下一页 |