在获取内核IPv6地址信息时,序号seq的值初始化为命名空间内IPv6地址标识ipv6.dev_addr_genid和接口标识dev_base_seq的异或值。这里有个问题,如何保证cb->seq的值不为零?如果目标命名空间中,ipv6.dev_addr_genid的值等于dev_base_seq的值,将导致seq为零。虽然这个概率很小,但是一旦发生,将导致nl_dump_check_consistent函数出错。
static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type)
struct net *net = sock_net(skb->sk);
struct net *tgt_net = net;
cb->seq = atomic_read(&tgt_net->ipv6.dev_addr_genid) ^ tgt_net->dev_base_seq;
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
head = &tgt_net->dev_index_head[h];
hlist_for_each_entry_rcu(dev, head, index_hlist) {
if (idx < s_idx)
goto cont;
if (h > s_h || idx > s_idx)
s_ip_idx = 0;
idev = __in6_dev_get(dev);
if (!idev)
goto cont;
if (in6_dump_addrs(idev, skb, cb, s_ip_idx, &fillargs) < 0)
goto done;
如下in6_dump_addrs函数,只有在遍历单播地址过程中,才会调用nl_dump_check_consistent函数,检查序号seq是否发生改变。
static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
struct netlink_callback *cb, int s_ip_idx, struct inet6_fill_args *fillargs)
switch (fillargs->type) {
case UNICAST_ADDR: {
struct inet6_ifaddr *ifa;
fillargs->event = RTM_NEWADDR;
/* unicast address incl. temp addr */
list_for_each_entry(ifa, &idev->addr_list, if_list) {
if (ip_idx < s_ip_idx)
goto next;
err = inet6_fill_ifaddr(skb, ifa, fillargs);
if (err < 0)
break;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
next:
ip_idx++;
break;
case MULTICAST_ADDR:
break;
case ANYCAST_ADDR:
内核版本 5.10
对于IPv4,在初始化时,为命名空间的设备地址标识赋于一个随机值。static __net_init int rt_genid_init(struct net *net){ atomic_set(&net->ipv4.rt_genid, 0); atomic_set(&net->fnhe_genid, 0); atomic_set(&net->ipv4.dev_addr_genid, get_random_int()); retu
文章目录前言1 NetID 与 DevAddr前缀的关系2 DevAddr 列举3 小结End
DevAddr 标识入网设备地址,v1.1 的核心规范开始关注网络漫游,联盟将DevAddr管控起来,高级别成员享受到较多的设备地址数量。
《LoRaWAN-Backend-Interfaces-v1.0》,即LoRaWAN后端接口协议规范 V1.0 版本( 2017 年 10 月 11 日定稿...
什么是NAPI
NAPI是linux一套最新的处理网口数据的API,linux 2.5引入的,所以很多驱动并不支持这种操作方式。简单来说,NAPI是综合中断方式与轮询方式的技术。数据量很低与很高时,NAPI可以发挥中断方式与轮询方式的优点,性能较好。如果数据量不稳定,且说高不高说低不低,则NAPI会在两种方式切换上消耗不少时间,效率反而较低一些。
下面会用到netdev_priv()这个
DAD冲突检测和IPv6
地址失效检测使用的都是addrconf_wq队列,其在addrconf_init函数中创建。
int __init addrconf_init(void)
struct inet6_dev *idev;
addrconf_wq = create_workqueue("ipv6_addrconf");
if (!addrconf_wq) {
err = -ENOMEM;
goto out_nowq;
内核中为网络设备定义了5中MAC地址类型,如下所示,其中NETDEV_HW_ADDR_T_SLAVE类型目前没有使用。局域网LAN类型与存储SAN类型的MAC地址保存在net_device结构体的dev_addrs链表中;UNICAST与MULTICAST类型的MAC地址分别保存在uc和mc链表中。
#define NETDEV_HW_ADDR_T_LAN 1 // Loca...
上一节描述了snull网络接口的入口和出口函数,在入口函数分配一个net_device,用snull_init函数初始化net_device的成员,之后注册这个网络设备。初始化net_device成员主要是实现一些设备操作方法,如下所示:
static const struct net_device_ops snull_dev_ops = {
.ndo_open = s...
用C语言写出int16_t i2c_read_reg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t size)