网络知识 娱乐 Linux中in_device和in_ifaddr数据结构

Linux中in_device和in_ifaddr数据结构

net_device、in_device、in_ifaddr数据结构关系:

Linux中in_device和in_ifaddr数据结构

一、in_device数据结构:

IP配置块,网络设备层与IPv4相关的配置都存放在in_device结构中,应用层可以通过ip或者ifconfig工具来修改这些配置。
该结构实例的地址保存在net_device的in_ptr中,可以通过in_dev_get()访问它。访问结束后,必须使用in_dev_put()。
in_dev_get()会递增该实例的引用计数,in_dev_put()函数会递减该结构的引用计数,当引用计数为0时,才真正释放该实例。

struct in_device {ntstruct net_devicet*dev;/*指向所属的网络设备*/ntatomic_tttrefcnt;/*引用计数*/ntinttttdead;/*为1时标识所在的IP配置块将要被释放,不允许再访问其成员*/ntnt/*指向 in_ifaddr架构链表,in_ifaddr中存储了网络设备的IP地址,nt因为一个网络设备可以配置多个IP地址,因此使用链表来存储。*/ntstruct in_ifaddrt*ifa_list;nntstruct ip_mc_list __rcut*mc_list;t/* IP multicast filter chain */ntstruct ip_mc_list __rcut* __rcu *mc_hash;nnt/*与组播相关配置*/ntinttttmc_count;t/* Number of installed mcastst*/ntspinlock_tttmc_tomb_lock;ntstruct ip_mc_listt*mc_tomb;ntunsigned longttmr_v1_seen;ntunsigned longttmr_v2_seen;ntunsigned longttmr_maxdelay;ntunsigned charttmr_qrv;ntunsigned charttmr_gq_running;ntunsigned charttmr_ifc_count;ntstruct timer_listtmr_gq_timer;t/* general query timer */ntstruct timer_listtmr_ifc_timer;t/* interface change timer */nnt/*指向neigh_parms结构实例,存储一些与ARP相关的参数*/ntstruct neigh_parmst*arp_parms;ntnt/*ipv4_devconf相关信息,还不知道干啥的,以后再看*/ntstruct ipv4_devconftcnf;ntnt/*RCU机制使用,实现互斥,如果锁一般*/ntstruct rcu_headttrcu_head;n};

二、in_ifaddr数据结构:

IP地址块,存储主机的IP地址,子网掩码,广播地址等信息。一个网络设备有多少个IP地址,就有多少个IP地址块。

struct in_ifaddr {ntstruct hlist_nodethash;ntstruct in_ifaddrt*ifa_next;//in_ifaddr链表ntstruct in_devicet*ifa_dev;//指向所属的in_device结构ntstruct rcu_headttrcu_head;nt__be32tttifa_local;//本地IP地址nt__be32tttifa_address;//本地IP地址或对端IP地址nt__be32tttifa_mask;//子网掩码nt__be32tttifa_broadcast;//广播地址ntunsigned charttifa_scope;//寻址范围ntunsigned charttifa_prefixlen;//子网掩码长度nt__u32tttifa_flags;//IP地址属性ntchartttifa_label[IFNAMSIZ];//网络设备名nnt/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */nt__u32tttifa_valid_lft;nt__u32tttifa_preferred_lft;ntunsigned longttifa_cstamp; /* created timestamp */ntunsigned longttifa_tstamp; /* updated timestamp */n};n

现在的in_ifaddr结构中加了hash结点hlist_node,上面图应该有点小变化吧,这个结点链接到哪里去了?

ifa_local和ifa_address的区别:

https://www.cnblogs.com/wanpengcoder/p/7385274.html

/*n* Important comment:n* IFA_ADDRESS is prefix address, rather than local interface address.n* It makes no difference for normally configured broadcast interfaces,n* but for point-to-point IFA_ADDRESS is DESTINATION address,n* local address is supplied in IFA_LOCAL attribute.n*/

1.ifa_local始终表示本地IP地址

2.如果设备配置了支持广播,ifa_address和if_local一样,也是本地IP地址;如果点对点链路,ifa_address表示对端的IP地址。

ifa_scope:

http://www.bubuko.com/infodetail-948730.html

/* rtm_scopen Really it is not scope, but sort of distance to the destination.n NOWHERE are reserved for not existing destinations, HOST is ourn local addresses, LINK are destinations, located on directly attachedn link and UNIVERSE is everywhere in the Universe.n Intermediate values are also possible f.e. interior routesn could be assigned a value between UNIVERSE and LINK.n*/n nenum rt_scope_t {ntRT_SCOPE_UNIVERSE=0,n/* User defined values */ntRT_SCOPE_SITE=200,ntRT_SCOPE_LINK=253,ntRT_SCOPE_HOST=254,ntRT_SCOPE_NOWHERE=255n};Linux中in_device和in_ifaddr数据结构

HOST:表示该地址只用于主机的内部通信。例如:127.0.0.1

Linux中in_device和in_ifaddr数据结构

LINK:表示地址仅在局域网内部有意义,例如私有地址?

UNIBERSE:表示地址可以在任何地方使用,普通的外网IP地址?

NOWHERE:表示目的地址不存在

SITE:??

ifa_flags

Linux中in_device和in_ifaddr数据结构

三、in_device相关操作函数

1. inetdev_init()函数
给网络设备分配IP配置块,应该在初始化网络设备net_device的时候调用的吧。就是创建in_device结构,初始化其成员。

static struct in_device *inetdev_init(struct net_device *dev)n{ntstruct in_device *in_dev;ntint err = -ENOMEM;nntASSERT_RTNL();nntin_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);//分配in_device内存ntif (!in_dev)nttgoto out;ntnt/*初始化in_device的cnf成员*/ntmemcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,ntttsizeof(in_dev->cnf));ntin_dev->cnf.sysctl = NULL;ntin_dev->dev = dev;//指向net_devicentnt/*初始化in_device的arp_parms成员*/ntin_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);ntif (!in_dev->arp_parms)nttgoto out_kfree;ntif (IPV4_DEVCONF(in_dev->cnf, FORWARDING))nttdev_disable_lro(dev);nt/* Reference in_dev->dev */ntdev_hold(dev);nt/* Account for reference dev->ip_ptr (below) */ntin_dev_hold(in_dev);nnterr = devinet_sysctl_register(in_dev);ntif (err) {nttin_dev->dead = 1;nttin_dev_put(in_dev);nttin_dev = NULL;nttgoto out;nt}nt/*初始化igmp模块*/ntip_mc_init_dev(in_dev);nt/*如果网络设备已启用,则初始化该网络设备上的组播信息,例如将该网路设备加入224.0.0.1组播组等操作*/ntif (dev->flags & IFF_UP)nttip_mc_up(in_dev);nnt/* we can receive as soon as ip_ptr is set -- do this last */nt/*net_device的ip_ptr指针指向in_device*/ntrcu_assign_pointer(dev->ip_ptr, in_dev);nout:ntreturn in_dev ?: ERR_PTR(err);nout_kfree:ntkfree(in_dev);ntin_dev = NULL;ntgoto out;n}n

看看devinet_sysctl_register()函数都干了啥

devinet_sysctl_register()函数:

static int devinet_sysctl_register(struct in_device *idev)n{ntint err;ntnt/*判断网络设备的名称是否合法,不能为default,all*/ntif (!sysctl_dev_name_is_allowed(idev->dev->name))nttreturn -EINVAL;nnterr = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);ntif (err)nttreturn err;nterr = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,nttttt&idev->cnf);ntif (err)nttneigh_sysctl_unregister(idev->arp_parms);ntreturn err;n}

sysctl_dev_name_is_allowed()函数:

static inline bool sysctl_dev_name_is_allowed(const char *name)n{ntreturn strcmp(name, "default") != 0 && strcmp(name, "all") != 0;n}

邻居子系统的知识以后再补上,现在还不会邻居子系统。

2. inetdev_destroy()函数

通常在设备被注销时调用,释放指定的IP配置块。

这函数没意思。

static void inetdev_destroy(struct in_device *in_dev)n{ntstruct in_ifaddr *ifa;ntstruct net_device *dev;nntASSERT_RTNL();nntdev = in_dev->dev;nntin_dev->dead = 1;nntip_mc_destroy_dev(in_dev);nntwhile ((ifa = in_dev->ifa_list) != NULL) {nttinet_del_ifa(in_dev, &in_dev->ifa_list, 0);nttinet_free_ifa(ifa);nt}nntRCU_INIT_POINTER(dev->ip_ptr, NULL);nntdevinet_sysctl_unregister(in_dev);ntneigh_parms_release(&arp_tbl, in_dev->arp_parms);ntarp_ifdown(dev);nntcall_rcu(&in_dev->rcu_head, in_dev_rcu_put);n}

3.in_dev_get()函数
这个函数比较简单,就是获取in_device结构,将in_device结构引用计数+1,返回其指针。

static inline struct in_device *in_dev_get(const struct net_device *dev)n{ntstruct in_device *in_dev;nntrcu_read_lock();ntin_dev = __in_dev_get_rcu(dev);ntif (in_dev)nttatomic_inc(&in_dev->refcnt);ntrcu_read_unlock();ntreturn in_dev;n}nnstatic inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)n{ntreturn rcu_dereference(dev->ip_ptr);n}n

4. in_dev_put()函数

也比较简单,将in_device实例的应用计数减1,当应用计数为0时,释放该实例。

static inline void in_dev_put(struct in_device *idev)n{ntif (atomic_dec_and_test(&idev->refcnt))nttin_dev_finish_destroy(idev);n}

5. inetdev_dy_index()

根据net_device的ifindex查找该设备的in_device结构。

/* Caller must hold RCU or RTNL :n * We dont take a reference on found in_devicen */nstruct in_device *inetdev_by_index(struct net *net, int ifindex)n{ntstruct net_device *dev;ntstruct in_device *in_dev = NULL;nntrcu_read_lock();ntdev = dev_get_by_index_rcu(net, ifindex);ntif (dev)nttin_dev = rcu_dereference_rtnl(dev->ip_ptr);ntrcu_read_unlock();ntreturn in_dev;n}n