📄 fib_semantics.c
字号:
memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4); if (rta->rta_mp) {#ifdef CONFIG_IP_ROUTE_MULTIPATH if ((err = myfib_get_nhs(fi, rta->rta_mp, r)) != 0) goto failure; if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) goto err_inval; if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4)) goto err_inval;#ifdef CONFIG_NET_CLS_ROUTE if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4)) goto err_inval;#endif#else goto err_inval;#endif }else{ struct fib_nh *nh = fi->fib_nh; if (rta->rta_oif) nh->nh_oif = *rta->rta_oif; if (rta->rta_gw) memcpy(&nh->nh_gw, rta->rta_gw, 4);#ifdef CONFIG_NET_CLS_ROUTE if (rta->rta_flow) memcpy(&nh->nh_tclassid, rta->rta_flow, 4);#endif nh->nh_flags = r->rtm_flags;#ifdef CONFIG_IP_ROUTE_MULTIPATH nh->nh_weight = 1;#endif }#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED fi->fib_mp_alg = mp_alg;#endif if( myfib_props[r->rtm_type].error ){ if( rta->rta_gw || rta->rta_oif || rta->rta_mp ) goto err_inval; goto link_it; } if( r->rtm_scope > RT_SCOPE_HOST ) goto err_inval; if( r->rtm_scope == RT_SCOPE_HOST ){ struct fib_nh *nh = fi->fib_nh; if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; nh->nh_dev = dev_get_by_index( fi->fib_nh->nh_oif ); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; }else{ change_nexthops(fi) { if ((err = myfib_check_nh(r, fi, nh)) != 0) goto failure; } endfor_nexthops(fi) } if( fi->fib_prefsrc ){ if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) if( myinet_addr_type(fi->fib_prefsrc) != RTN_LOCAL ) goto err_inval; }link_it: if( (ofi = myfib_find_info(fi)) != NULL ){ PR_DEBUG( "find an old one: %u.%u.%u.%u\n, new: %u.%u.%u.%u\n", NIPQUAD(fi->fib_prefsrc), NIPQUAD(ofi->fib_prefsrc) ); fi->fib_dead = 1; myfree_fib_info(fi); ofi->fib_treeref++; return ofi; } fi->fib_treeref++; atomic_inc( &fi->fib_clntref ); write_lock( &myfib_info_lock ); hlist_add_head( &fi->fib_hash, &myfib_info_hash[myfib_info_hashfn(fi)] ); if( fi->fib_prefsrc ){ struct hlist_head *head; head = &myfib_info_laddrhash[myfib_laddr_hashfn(fi->fib_prefsrc)]; hlist_add_head(&fi->fib_lhash, head); } change_nexthops(fi) { struct hlist_head *head; unsigned int hash; if (!nh->nh_dev) continue; hash = myfib_devindex_hashfn(nh->nh_dev->ifindex); head = &myfib_info_devhash[hash]; hlist_add_head(&nh->nh_hash, head); } endfor_nexthops(fi) write_unlock( &myfib_info_lock ); return fi;err_inval: err = -EINVAL;failure: *errp = err; if( fi ){ fi->fib_dead = 1; myfree_fib_info(fi); } return NULL;}void myfib_release_info(struct fib_info *fi){ write_lock( &myfib_info_lock ); PR_DEBUG( "myfib_release_info\n"); if( fi && --fi->fib_treeref == 0 ){ hlist_del(&fi->fib_hash); if( fi->fib_prefsrc ) hlist_del(&fi->fib_lhash); change_nexthops( fi ){ if( !nh->nh_dev ) continue; hlist_del(&nh->nh_hash); }endfor_nexthops( fi ) fi->fib_dead = 1; myfib_info_put(fi); } write_unlock( &myfib_info_lock );}int myfib_semantic_match(struct list_head *head, const struct flowi *flp, struct fib_result *res, __u32 zone, __u32 mask, int prefixlen){ struct fib_alias *fa; int nh_sel = 0; list_for_each_entry_rcu(fa, head, fa_list) { int err; if( fa->fa_tos && fa->fa_tos != flp->fl4_tos ) continue; if( fa->fa_scope < flp->fl4_scope ) continue; fa->fa_state |= FA_S_ACCESSED; err = myfib_props[fa->fa_type].error; if (err == 0) { struct fib_info *fi = fa->fa_info; if (fi->fib_flags & RTNH_F_DEAD) continue; switch( fa->fa_type ){ case RTN_UNICAST: case RTN_LOCAL: case RTN_BROADCAST: case RTN_ANYCAST: case RTN_MULTICAST: for_nexthops(fi) { if( nh->nh_flags & RTNH_F_DEAD ) continue; if( !flp->oif || flp->oif == nh->nh_oif ) break; }#ifdef CONFIG_IP_ROUTE_MULTIPATH if( nhsel < fi->fib_nhs ){ nh_sel = nhsel; goto out_fill_res; }#else if( nhsel < 1 ){ goto out_fill_res; }#endif endfor_nexthops(fi); continue; default: PR_DEBUG( "impossible 102\n" ); return -EINVAL; }; } return err; } return 1;out_fill_res: res->prefixlen = prefixlen; res->nh_sel = nh_sel; res->type = fa->fa_type; res->scope = fa->fa_scope; res->fi = fa->fa_info;#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED res->netmask = mask; res->network = zone & ( 0xFFFFFFFF >> (32 - prefixlen) );#endif atomic_inc(&res->fi->fib_clntref); return 0;}#ifdef CONFIG_IP_ROUTE_MULTIPATHint myfib_sync_up(struct net_device *dev){ struct fib_info *prev_fi; unsigned int hash; struct hlist_head *head; struct hlist_node *node; struct fib_nh *nh; int ret; if( !(dev->flags & IFF_UP) ) return 0; prev_fi = NULL; hash = myfib_devindex_hashfn( dev->ifindex ); head = &myfib_info_devhash[hash]; ret = 0; hlist_for_each_entry( nh, node, head, nh_hash ){ struct fib_info *fi = nh->nh_parent; int alive; BUG_ON( !fi->fib_nhs ); if (nh->nh_dev != dev || fi == prev_fi) continue; prev_fi = fi; alive = 0; change_nexthops(fi) { if( !(nh->nh_flags & RTNH_F_DEAD) ){ alive++; continue; } if( nh->nh_dev == NULL || !(nh->nh_dev->flags & IFF_UP) ) continue; if( nh->nh_dev != dev || !__in_dev_get_rtnl(dev) ) continue; alive++; spin_lock_bh( &myfib_multipath_lock ); nh->nh_power = 0; nh->nh_flags &= ~RTNH_F_DEAD; spin_unlock_bh( &myfib_multipath_lock ); } endfor_nexthops(fi) if (alive > 0) { fi->fib_flags &= ~RTNH_F_DEAD; ret++; } } return ret;}void myfib_select_multipath(const struct flowi *flp, struct fib_result *res){ struct fib_info *fi = res->fi; int w; spin_lock_bh( &myfib_multipath_lock ); if( fi->fib_power <= 0 ){ int power = 0; change_nexthops(fi) { if( !(nh->nh_flags & RTNH_F_DEAD) ){ power += nh->nh_weight; nh->nh_power = nh->nh_weight; } } endfor_nexthops(fi); fi->fib_power = power; if (power <= 0) { spin_unlock_bh( &myfib_multipath_lock ); res->nh_sel = 0; return; } } w = jiffies % fi->fib_power; change_nexthops(fi) { if( !(nh->nh_flags & RTNH_F_DEAD) && nh->nh_power ){ if( (w -= nh->nh_power) <= 0 ){ nh->nh_power--; fi->fib_power--; res->nh_sel = nhsel; spin_unlock_bh( &myfib_multipath_lock ); return; } } } endfor_nexthops(fi); res->nh_sel = 0; spin_unlock_bh( &myfib_multipath_lock );}#endifint myfib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, struct fib_info *fi){#ifdef CONFIG_IP_ROUTE_MULTIPATH struct rtnexthop *nhp; int nhlen;#endif if( rta->rta_priority && *rta->rta_priority != fi->fib_priority) return 1; if( rta->rta_oif || rta->rta_gw ){ if( (!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0)) return 0; return 1; }#ifdef CONFIG_IP_ROUTE_MULTIPATH if( rta->rta_mp == NULL ) return 0; nhp = RTA_DATA(rta->rta_mp); nhlen = RTA_PAYLOAD(rta->rta_mp); for_nexthops( fi ){ int attrlen = nhlen - sizeof(struct rtnexthop); u32 gw; if( attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0 ) return -EINVAL; if( nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif ) return 1; if( attrlen ){ gw = myfib_get_attr32( RTNH_DATA(nhp), attrlen, RTA_GATEWAY ); if( gw && gw != nh->nh_gw ) return 1;#ifdef CONFIG_NET_CLS_ROUTE gw = myfib_get_attr32( RTNH_DATA(nhp), attrlen, RTA_FLOW ); if( gw && gw != nh->nh_tclassid ) return 1;#endif } nhp = RTNH_NEXT(nhp); }endfor_nexthops(fi);#endif return 0;}int myfib_sync_down( u32 local, struct net_device *dev, int force ){ int ret = 0; int scope = RT_SCOPE_NOWHERE; if( force ) scope = -1; if( local && myfib_info_laddrhash ){ unsigned int hash = myfib_laddr_hashfn( local ); struct hlist_head *head = &myfib_info_laddrhash[hash]; struct hlist_node *node; struct fib_info *fi; hlist_for_each_entry(fi, node, head, fib_lhash) { if( fi->fib_prefsrc == local ){ fi->fib_flags |= RTNH_F_DEAD; ret++; } } } if( dev ){ struct fib_info *prev_fi = NULL; unsigned int hash = myfib_devindex_hashfn( dev->ifindex ); struct hlist_head *head = &myfib_info_devhash[hash]; struct hlist_node *node; struct fib_nh *nh; hlist_for_each_entry( nh, node, head, nh_hash ){ struct fib_info *fi = nh->nh_parent; int dead; BUG_ON( !fi->fib_nhs ); if( nh->nh_dev != dev || fi == prev_fi ) continue; prev_fi = fi; dead = 0; change_nexthops(fi) { if( nh->nh_flags & RTNH_F_DEAD ) dead++; else if( nh->nh_dev == dev && nh->nh_scope != scope ){ nh->nh_flags |= RTNH_F_DEAD;#ifdef CONFIG_IP_ROUTE_MULTIPATH spin_lock_bh(&myfib_multipath_lock); fi->fib_power -= nh->nh_power; nh->nh_power = 0; spin_unlock_bh( &myfib_multipath_lock );#endif dead++; }#ifdef CONFIG_IP_ROUTE_MULTIPATH if( force > 1 && nh->nh_dev == dev ){ dead = fi->fib_nhs; break; }#endif } endfor_nexthops(fi) if (dead == fi->fib_nhs) { fi->fib_flags |= RTNH_F_DEAD; ret++; } } } return ret;}#if 0void dump_fib_info(void){ struct hlist_head *head; struct hlist_node *node; struct hlist_node *tmp; struct fib_info *f; int i; for( i = 0; i < myfib_hash_size; i ++ ){ f = NULL; head = &myfib_info_hash[i]; hlist_for_each_entry_safe( f, node, tmp, head, fib_hash ){ int j; printk( KERN_NOTICE "%d\n", i ); printk( KERN_NOTICE "\ttreeref: %d\n", f->fib_treeref ); printk( KERN_NOTICE "\tclntref: %d\n", atomic_read(&f->fib_clntref) ); printk( KERN_NOTICE "\tflags: %x\n", f->fib_flags ); printk( KERN_NOTICE "\tprotocol: %d\n", f->fib_protocol ); printk( KERN_NOTICE "\tprefsrc: %u.%u.%u.%u\n", NIPQUAD(f->fib_prefsrc) ); printk( KERN_NOTICE "\tpriority: %u\n", f->fib_priority ); printk( KERN_NOTICE "\tmtu: %u\n", f->fib_mtu ); printk( KERN_NOTICE "\twindow: %u\n", f->fib_window ); printk( KERN_NOTICE "\trtt: %u\n", f->fib_rtt ); printk( KERN_NOTICE "\tadvmss: %u\n", f->fib_advmss ); printk( KERN_NOTICE "\tnhs: %d\n", f->fib_nhs ); for( j=0; j < f->fib_nhs; j ++ ){ printk( KERN_NOTICE "\t%d\n", j ); printk( KERN_NOTICE "\t\tdev name: %s\n", f->fib_nh[j].nh_dev->name ); printk( KERN_NOTICE "\t\tflags: %x\n", f->fib_nh[j].nh_flags ); printk( KERN_NOTICE "\t\tscope: %x\n", f->fib_nh[j].nh_scope ); printk( KERN_NOTICE "\t\tgw: %u.%u.%u.%u\n", NIPQUAD(f->fib_nh[j].nh_gw) ); } } }}#elsevoid dump_fib_info(void){}#endifint myfib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, struct fib_info *fi, unsigned int flags){ return 0;}void __exit myfib_info_exit(void){ struct hlist_head *head; struct hlist_node *node; struct hlist_node *tmp; struct fib_info *f; int i; for( i = 0; i < myfib_hash_size; i ++ ){ f = NULL; head = &myfib_info_hash[i]; hlist_for_each_entry_safe( f, node, tmp, head, fib_hash ){ hlist_del( node ); PR_DEBUG( "presrc: %u.%u.%u.%u\n", NIPQUAD(f->fib_prefsrc) ); f->fib_dead = 1; myfree_fib_info( f ); } } myfib_hash_free( myfib_info_hash, myfib_hash_size * sizeof(struct hlist_head *) ); myfib_hash_free( myfib_info_laddrhash, myfib_hash_size * sizeof(struct hlist_head *) ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -