net_device、in_device、in_ifaddr数据结构关系:
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 {
struct net_device *dev;/*指向所属的网络设备*/
atomic_t refcnt;/*引用计数*/
int dead;/*为1时标识所在的IP配置块将要被释放,不允许再访问其成员*/
/*指向 in_ifaddr架构链表,in_ifaddr中存储了网络设备的IP地址,
因为一个网络设备可以配置多个IP地址,因此使用链表来存储。*/
struct in_ifaddr *ifa_list;
struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */
struct ip_mc_list __rcu * __rcu *mc_hash;
/*与组播相关配置*/
int mc_count; /* Number of installed mcasts */
spinlock_t mc_tomb_lock;
struct ip_mc_list *mc_tomb;
unsigned long mr_v1_seen;
unsigned long mr_v2_seen;
unsigned long mr_maxdelay;
unsigned char mr_qrv;
unsigned char mr_gq_running;
unsigned char mr_ifc_count;
struct timer_list mr_gq_timer; /* general query timer */
struct timer_list mr_ifc_timer; /* interface change timer */
/*指向neigh_parms结构实例,存储一些与ARP相关的参数*/
struct neigh_parms *arp_parms;
/*ipv4_devconf相关信息,还不知道干啥的,以后再看*/
struct ipv4_devconf cnf;
/*RCU机制使用,实现互斥,如果锁一般*/
struct rcu_head rcu_head;
};
IP地址块,存储主机的IP地址,子网掩码,广播地址等信息。一个网络设备有多少个IP地址,就有多少个IP地址块。
struct in_ifaddr {
struct hlist_node hash;
struct in_ifaddr *ifa_next;//in_ifaddr链表
struct in_device *ifa_dev;//指向所属的in_device结构
struct rcu_head rcu_head;
__be32 ifa_local;//本地IP地址
__be32 ifa_address;//本地IP地址或对端IP地址
__be32 ifa_mask;//子网掩码
__be32 ifa_broadcast;//广播地址
unsigned char ifa_scope;//寻址范围
unsigned char ifa_prefixlen;//子网掩码长度
__u32 ifa_flags;//IP地址属性
char ifa_label[IFNAMSIZ];//网络设备名
/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
__u32 ifa_valid_lft;
__u32 ifa_preferred_lft;
unsigned long ifa_cstamp; /* created timestamp */
unsigned long ifa_tstamp; /* updated timestamp */
};
现在的in_ifaddr结构中加了hash结点hlist_node,上面图应该有点小变化吧,这个结点链接到哪里去了?
ifa_local和ifa_address的区别:
https://www.cnblogs.com/wanpengcoder/p/7385274.html
/*
* Important comment:
* IFA_ADDRESS is prefix address, rather than local interface address.
* It makes no difference for normally configured broadcast interfaces,
* but for point-to-point IFA_ADDRESS is DESTINATION address,
* local address is supplied in IFA_LOCAL attribute.
*/
1.ifa_local始终表示本地IP地址
2.如果设备配置了支持广播,ifa_address和if_local一样,也是本地IP地址;如果点对点链路,ifa_address表示对端的IP地址。
ifa_scope:
http://www.bubuko.com/infodetail-948730.html
/* rtm_scope
Really it is not scope, but sort of distance to the destination.
NOWHERE are reserved for not existing destinations, HOST is our
local addresses, LINK are destinations, located on directly attached
link and UNIVERSE is everywhere in the Universe.
Intermediate values are also possible f.e. interior routes
could be assigned a value between UNIVERSE and LINK.
*/
enum rt_scope_t {
RT_SCOPE_UNIVERSE=0,
/* User defined values */
RT_SCOPE_SITE=200,
RT_SCOPE_LINK=253,
RT_SCOPE_HOST=254,
RT_SCOPE_NOWHERE=255
};
HOST:表示该地址只用于主机的内部通信。例如:127.0.0.1
LINK:表示地址仅在局域网内部有意义,例如私有地址?
UNIBERSE:表示地址可以在任何地方使用,普通的外网IP地址?
NOWHERE:表示目的地址不存在
SITE:??
ifa_flags
1. inetdev_init()函数
给网络设备分配IP配置块,应该在初始化网络设备net_device的时候调用的吧。就是创建in_device结构,初始化其成员。
static struct in_device *inetdev_init(struct net_device *dev)
{
struct in_device *in_dev;
int err = -ENOMEM;
ASSERT_RTNL();
in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);//分配in_device内存
if (!in_dev)
goto out;
/*初始化in_device的cnf成员*/
memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
sizeof(in_dev->cnf));
in_dev->cnf.sysctl = NULL;
in_dev->dev = dev;//指向net_device
/*初始化in_device的arp_parms成员*/
in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
if (!in_dev->arp_parms)
goto out_kfree;
if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
dev_disable_lro(dev);
/* Reference in_dev->dev */
dev_hold(dev);
/* Account for reference dev->ip_ptr (below) */
in_dev_hold(in_dev);
err = devinet_sysctl_register(in_dev);
if (err) {
in_dev->dead = 1;
in_dev_put(in_dev);
in_dev = NULL;
goto out;
}
/*初始化igmp模块*/
ip_mc_init_dev(in_dev);
/*如果网络设备已启用,则初始化该网络设备上的组播信息,例如将该网路设备加入224.0.0.1组播组等操作*/
if (dev->flags & IFF_UP)
ip_mc_up(in_dev);
/* we can receive as soon as ip_ptr is set -- do this last */
/*net_device的ip_ptr指针指向in_device*/
rcu_assign_pointer(dev->ip_ptr, in_dev);
out:
return in_dev ?: ERR_PTR(err);
out_kfree:
kfree(in_dev);
in_dev = NULL;
goto out;
}
看看devinet_sysctl_register()函数都干了啥
devinet_sysctl_register()函数:
static int devinet_sysctl_register(struct in_device *idev)
{
int err;
/*判断网络设备的名称是否合法,不能为default,all*/
if (!sysctl_dev_name_is_allowed(idev->dev->name))
return -EINVAL;
err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
if (err)
return err;
err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
&idev->cnf);
if (err)
neigh_sysctl_unregister(idev->arp_parms);
return err;
}
sysctl_dev_name_is_allowed()函数:
static inline bool sysctl_dev_name_is_allowed(const char *name)
{
return strcmp(name, "default") != 0 && strcmp(name, "all") != 0;
}
邻居子系统的知识以后再补上,现在还不会邻居子系统。
2. inetdev_destroy()函数
通常在设备被注销时调用,释放指定的IP配置块。
这函数没意思。
static void inetdev_destroy(struct in_device *in_dev)
{
struct in_ifaddr *ifa;
struct net_device *dev;
ASSERT_RTNL();
dev = in_dev->dev;
in_dev->dead = 1;
ip_mc_destroy_dev(in_dev);
while ((ifa = in_dev->ifa_list) != NULL) {
inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
inet_free_ifa(ifa);
}
RCU_INIT_POINTER(dev->ip_ptr, NULL);
devinet_sysctl_unregister(in_dev);
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
arp_ifdown(dev);
call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
}
3.in_dev_get()函数
这个函数比较简单,就是获取in_device结构,将in_device结构引用计数+1,返回其指针。
static inline struct in_device *in_dev_get(const struct net_device *dev)
{
struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
atomic_inc(&in_dev->refcnt);
rcu_read_unlock();
return in_dev;
}
static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
{
return rcu_dereference(dev->ip_ptr);
}
4. in_dev_put()函数
也比较简单,将in_device实例的应用计数减1,当应用计数为0时,释放该实例。
static inline void in_dev_put(struct in_device *idev)
{
if (atomic_dec_and_test(&idev->refcnt))
in_dev_finish_destroy(idev);
}
5. inetdev_dy_index()
根据net_device的ifindex查找该设备的in_device结构。
/* Caller must hold RCU or RTNL :
* We dont take a reference on found in_device
*/
struct in_device *inetdev_by_index(struct net *net, int ifindex)
{
struct net_device *dev;
struct in_device *in_dev = NULL;
rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
if (dev)
in_dev = rcu_dereference_rtnl(dev->ip_ptr);
rcu_read_unlock();
return in_dev;
}
留言与评论(共有 0 条评论) “” |