📄 fib_frontend.c
字号:
/* fib_frontend.c * linqianghe@163.com * 2006-11-06 */#include "fib_frontend.h"#include "fib_rules.h"#include "rtnetlink.h"#include "log.h"#include "devinet.h"#include "ip_fib.h"#include "fib_hash.h"#include "arp.h"#include "route.h"#include "fib_semantics.h"#include <linux/inetdevice.h>#include <linux/in.h>#define RT_TABLE_MIN 1struct fib_table *myfib_tables[ RT_TABLE_MAX+1];struct fib_table *__myfib_new_table(int id){ struct fib_table *tb; tb = myfib_hash_init( id ); if( !tb ) return NULL; myfib_tables[id] = tb; return tb;}static void myfib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa){ struct fib_table * tb; struct { struct nlmsghdr nlh; struct rtmsg rtm; } req; struct kern_rta rta; memset( &req.rtm, 0, sizeof(req.rtm) ); memset( &rta, 0, sizeof(rta) ); if( type == RTN_UNICAST ) tb = myfib_new_table( RT_TABLE_MAIN ); else tb = myfib_new_table( RT_TABLE_LOCAL ); if( tb == NULL ) return; req.nlh.nlmsg_len = sizeof( req ); req.nlh.nlmsg_type = cmd; req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = 0; req.rtm.rtm_dst_len = dst_len; req.rtm.rtm_table = tb->tb_id; req.rtm.rtm_protocol = RTPROT_KERNEL; req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); req.rtm.rtm_type = type; rta.rta_dst = &dst; rta.rta_prefsrc = &ifa->ifa_local; rta.rta_oif = &ifa->ifa_dev->dev->ifindex; if (cmd == RTM_NEWROUTE) tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); else tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);}void myfib_add_ifaddr(struct in_ifaddr *ifa){ struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *prim = ifa; u32 mask = ifa->ifa_mask; u32 addr = ifa->ifa_local; u32 prefix = ifa->ifa_address & mask; if( ifa->ifa_flags & IFA_F_SECONDARY ){ prim = myinet_ifa_byprefix(in_dev, prefix, mask); if (prim == NULL) { PR_ERR( "fib_add_ifaddr: bug: prim == NULL\n" ); return; } } myfib_magic( RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim ); if( !(dev->flags & IFF_UP) ) return; if( ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF ) myfib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); if( !ZERONET(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && ( prefix != addr || ifa->ifa_prefixlen < 32) ){ myfib_magic(RTM_NEWROUTE, dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim); if( ifa->ifa_prefixlen < 31 ){ myfib_magic( RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim ); myfib_magic( RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim ); } }#if 0 dump_fib_info(); if( myip_fib_local_table ) dump_fib_node( myip_fib_local_table ); if( myip_fib_main_table ) dump_fib_node( myip_fib_main_table ); { /*AC103002*/ /*FFFFFF7F*/ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = 0xFFFFFF7F } } }; struct fib_result res; int j; if( myip_fib_local_table ) myip_fib_local_table->tb_lookup( myip_fib_local_table, &fl, &res ); printk( KERN_NOTICE "prefixlen: %d\n", res.prefixlen ); printk( KERN_NOTICE "nh_sel: %d\n", res.nh_sel ); printk( KERN_NOTICE "type: %d\n", res.type ); printk( KERN_NOTICE "scope: %d\n", res.scope ); if( res.fi != NULL ){ printk( KERN_NOTICE "info: \n" ); printk( KERN_NOTICE "\tflags: %x\n", res.fi->fib_flags ); printk( KERN_NOTICE "\tprotocol: %d\n", res.fi->fib_protocol ); printk( KERN_NOTICE "\tprefsrc: %u.%u.%u.%u\n", NIPQUAD(res.fi->fib_prefsrc) ); printk( KERN_NOTICE "\tpriority: %u\n", res.fi->fib_priority ); printk( KERN_NOTICE "\tnhs: %d\n", res.fi->fib_nhs ); for( j=0; j < res.fi->fib_nhs; j ++ ){ printk( KERN_NOTICE "\t\tdev name: %s\n", res.fi->fib_nh[j].nh_dev->name ); printk( KERN_NOTICE "\t\tflags: %x\n", res.fi->fib_nh[j].nh_flags ); printk( KERN_NOTICE "\t\tscope: %x\n", res.fi->fib_nh[j].nh_scope ); printk( KERN_NOTICE "\t\tgw: %u.%u.%u.%u\n", NIPQUAD(res.fi->fib_nh[j].nh_gw) ); } } }#endif}unsigned myinet_addr_type(u32 addr){ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; unsigned ret = RTN_BROADCAST; if( ZERONET(addr) || BADCLASS(addr) ) return RTN_BROADCAST; if( MULTICAST(addr) ) return RTN_MULTICAST; res.r = NULL; if( myip_fib_local_table ){ ret = RTN_UNICAST; if( !myip_fib_local_table->tb_lookup( myip_fib_local_table, &fl, &res) ){ ret = res.type; myfib_res_put( &res ); } } return ret;}static void myfib_flush(void){ int flushed = 0; struct fib_table *tb; int id; for( id = RT_TABLE_MAX; id > 0; id-- ){ if( (tb = myfib_get_table(id))==NULL ) continue; flushed += tb->tb_flush( tb ); } if( flushed ) myrt_cache_flush(-1);}static void myfib_disable_ip( struct net_device *dev, int force ){ if( myfib_sync_down(0, dev, force) ) myfib_flush(); myrt_cache_flush( 0 ); myarp_ifdown( dev );}static void myfib_del_ifaddr( struct in_ifaddr *ifa ){ struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *ifa1; struct in_ifaddr *prim = ifa; u32 brd = ifa->ifa_address | ~ifa->ifa_mask; u32 any = ifa->ifa_address & ifa->ifa_mask;#define LOCAL_OK 1#define BRD_OK 2#define BRD0_OK 4#define BRD1_OK 8 unsigned ok = 0; if( !(ifa->ifa_flags & IFA_F_SECONDARY) ) myfib_magic( RTM_DELROUTE, dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, any, ifa->ifa_prefixlen, prim ); else{ prim = myinet_ifa_byprefix(in_dev, any, ifa->ifa_mask); if (prim == NULL) { PR_ERR( "fib_del_ifaddr: bug: prim == NULL\n" ); return; } } for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { if (ifa->ifa_local == ifa1->ifa_local) ok |= LOCAL_OK; if (ifa->ifa_broadcast == ifa1->ifa_broadcast) ok |= BRD_OK; if (brd == ifa1->ifa_broadcast) ok |= BRD1_OK; if (any == ifa1->ifa_broadcast) ok |= BRD0_OK; } if ( !(ok & BRD_OK) ) myfib_magic( RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim ); if ( !(ok & BRD1_OK) ) myfib_magic( RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim ); if ( !(ok & BRD0_OK) ) myfib_magic( RTM_DELROUTE, RTN_BROADCAST, any, 32, prim ); if ( !(ok & LOCAL_OK) ){ myfib_magic( RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim ); if( myinet_addr_type(ifa->ifa_local) != RTN_LOCAL ){ if( myfib_sync_down(ifa->ifa_local, NULL, 0) ) myfib_flush(); } }#undef LOCAL_OK#undef BRD_OK#undef BRD0_OK#undef BRD1_OK}struct net_device * myip_dev_find(u32 addr){ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; struct net_device *dev = NULL;#ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL;#endif if( !myip_fib_local_table || myip_fib_local_table->tb_lookup( myip_fib_local_table, &fl, &res) ) return NULL; if (res.type != RTN_LOCAL) goto out; dev = FIB_RES_DEV(res); if( dev ) dev_hold( dev );out: myfib_res_put( &res ); return dev;}static int myfib_inetaddr_event( struct notifier_block *this, unsigned long event, void *ptr ){ struct in_ifaddr *ifa = (struct in_ifaddr*)ptr; switch (event) { case NETDEV_UP: myfib_add_ifaddr(ifa);#ifdef CONFIG_IP_ROUTE_MULTIPATH myfib_sync_up(ifa->ifa_dev->dev);#endif myrt_cache_flush(-1); break; case NETDEV_DOWN: myfib_del_ifaddr(ifa); if( ifa->ifa_dev->ifa_list == NULL ){ myfib_disable_ip( ifa->ifa_dev->dev, 1 ); }else{ myrt_cache_flush(-1); } break; } return NOTIFY_DONE;}static int myfib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); if (event == NETDEV_UNREGISTER) { myfib_disable_ip(dev, 2); return NOTIFY_DONE; } if (!in_dev) return NOTIFY_DONE; switch (event) { case NETDEV_UP: for_ifa(in_dev) { myfib_add_ifaddr(ifa); } endfor_ifa(in_dev);#ifdef CONFIG_IP_ROUTE_MULTIPATH myfib_sync_up(dev);#endif myrt_cache_flush(-1); break; case NETDEV_DOWN: myfib_disable_ip(dev, 0); break; case NETDEV_CHANGEMTU: case NETDEV_CHANGE: myrt_cache_flush(0); break; } return NOTIFY_DONE;}static struct notifier_block myfib_inetaddr_notifier = { .notifier_call = myfib_inetaddr_event,};static struct notifier_block myfib_netdev_notifier = { .notifier_call = myfib_netdev_event,};void __init myip_fib_init(void){ myfib_rules_init(); register_netdevice_notifier( &myfib_netdev_notifier ); register_inetaddr_notifier( &myfib_inetaddr_notifier ); //nl_fib_lookup_init();}void __exit myip_fib_exit(void){ int i; struct fn_hash *table; struct fn_zone *plist1, *plist2; unregister_inetaddr_notifier( &myfib_inetaddr_notifier ); unregister_netdevice_notifier( &myfib_netdev_notifier ); myfib_rules_exit(); for( i = 0; i < RT_TABLE_MAX+1; i ++ ){ if( myfib_tables[i] != NULL ){ table = (struct fn_hash *) myfib_tables[i]->tb_data; plist1 = table->fn_zone_list; while( plist1 != NULL ){ PR_DEBUG( "delete fz_zone!\n"); plist2 = plist1->fz_next; myfn_zone_free( plist1 ); plist1 = plist2; } kfree( table ); } } myfib_hash_exit();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -