0.1. SUMMARY
There is a struct in_device __rcu *ip_ptr under every net_device.
which stores all the IPv4 related information for this device.
Each IPv4 address is stored a struct in_ifaddr,
all the IPv4 address of a net device are stored into a list(netdev->ip_ptr->ifa_list).

0.1.1. 相关结构体
0.1.1.1. net_device 和in_device
1 2 3
| 1075 struct net_device { ... 1208 struct in_device __rcu *ip_ptr;
|
1 2 3 4 5 6
| 55 struct in_device { 56 struct net_device *dev; 57 atomic_t refcnt; 58 int dead; 59 struct in_ifaddr *ifa_list; ...
|
0.1.1.2. ifa结构体struct in_ifaddr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 161 struct in_ifaddr { 162 struct hlist_node hash; 163 struct in_ifaddr *ifa_next; 164 struct in_device *ifa_dev; 165 struct rcu_head rcu_head; 166 __be32 ifa_local; 167 __be32 ifa_address; 168 __be32 ifa_mask; 169 __be32 ifa_broadcast; 170 unsigned char ifa_scope; 171 unsigned char ifa_flags; 172 unsigned char ifa_prefixlen; 173 char ifa_label[IFNAMSIZ]; 174 175 /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ 176 __u32 ifa_valid_lft; 177 __u32 ifa_preferred_lft; 178 unsigned long ifa_cstamp; /* created timestamp */ 179 unsigned long ifa_tstamp; /* updated timestamp */ 180 };
|
0.1.1.3. 注册处理增删IP地址命令的入口函数
1 2 3 4 5
| 2284 void __init devinet_init(void) 2285 { ... 2300 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL); 2301 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
|
0.2. 内核如何处理增加ip地址
0.2.1. calltrace
1 2 3 4 5 6 7 8
| > inet_rtm_newaddr > > rtm_to_ifaddr > > find_matching_ifa > > __inet_insert_ifa > > > insert ifa to ifa_list with right postion. > > > inet_hash_insert(dev_net(in_dev->dev), ifa); > > > rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid); > > > blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
|
0.2.1.1. NOTE:
inetaddr_chain will be shown in next blog.
0.2.2. 处理增加IP地址命令的入口函数
0.2.2.1. inet_rtm_newaddr
- 创建:函数
rtm_to_ifaddr根据netlink 消息,生成一个 ifa实例
- 查找:使用函数
find_matching_ifa查找是否有相同的ifa
- 插入:如果没有找到, 则通过``__inet_insert_ifa`添加ifa到内核里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 807 static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) 808 { 809 struct net *net = sock_net(skb->sk); 810 struct in_ifaddr *ifa; 811 struct in_ifaddr *ifa_existing; 812 __u32 valid_lft = INFINITY_LIFE_TIME; 813 __u32 prefered_lft = INFINITY_LIFE_TIME; 814 815 ASSERT_RTNL(); 816 817 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft); 818 if (IS_ERR(ifa)) 819 return PTR_ERR(ifa); 820 821 ifa_existing = find_matching_ifa(ifa); 822 if (!ifa_existing) { 823 /* It would be best to check for !NLM_F_CREATE here but 824 * userspace alreay relies on not having to provide this. 825 */ 826 set_ifa_lifetime(ifa, valid_lft, prefered_lft); 827 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid); 828 } else { 829 inet_free_ifa(ifa); 830 831 if (nlh->nlmsg_flags & NLM_F_EXCL || 832 !(nlh->nlmsg_flags & NLM_F_REPLACE)) 833 return -EEXIST; 834 ifa = ifa_existing; 835 set_ifa_lifetime(ifa, valid_lft, prefered_lft); 836 cancel_delayed_work(&check_lifetime_work); 837 schedule_delayed_work(&check_lifetime_work, 0); 838 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid); 839 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); 840 } 841 return 0; 842 }
|
0.2.2.1.1. rtm_to_ifaddr
根据netlink消息生成 ifa
- 查找并确认netdev 网口名字: 查找 ip命令指定的网口下,是否有这个IP地址,而不是在整个ns下查
- 分配一个ifa实例
- 根据 netlink 消息内容初始化 ifa
Q: 同一个IP地址(掩码也相同)可以配置的多个网口上吗?或者说多个网口可以配置相同的ip地址(ip 和掩码都相同)?
A: 可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| 708 static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, 709 __u32 *pvalid_lft, __u32 *pprefered_lft) 710 { 711 struct nlattr *tb[IFA_MAX+1]; 712 struct in_ifaddr *ifa; 713 struct ifaddrmsg *ifm; 714 struct net_device *dev; 715 struct in_device *in_dev; 716 int err; 717 718 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); 719 if (err < 0) 720 goto errout; 721 722 ifm = nlmsg_data(nlh); 723 err = -EINVAL; 724 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) 725 goto errout; 726 727 dev = __dev_get_by_index(net, ifm->ifa_index); 728 err = -ENODEV; 729 if (dev == NULL) 730 goto errout; 731 732 in_dev = __in_dev_get_rtnl(dev); 733 err = -ENOBUFS; 734 if (in_dev == NULL) 735 goto errout; 736 737 ifa = inet_alloc_ifa(); 738 if (ifa == NULL) 739 /* 740 * A potential indev allocation can be left alive, it stays 741 * assigned to its device and is destroy with it. 742 */ 743 goto errout; 744 745 ipv4_devconf_setall(in_dev); 746 in_dev_hold(in_dev); 747 748 if (tb[IFA_ADDRESS] == NULL) 749 tb[IFA_ADDRESS] = tb[IFA_LOCAL]; 750 751 INIT_HLIST_NODE(&ifa->hash); 752 ifa->ifa_prefixlen = ifm->ifa_prefixlen; 753 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); 754 ifa->ifa_flags = ifm->ifa_flags; 755 ifa->ifa_scope = ifm->ifa_scope; 756 ifa->ifa_dev = in_dev; 757 758 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]); 759 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]); 760 761 if (tb[IFA_BROADCAST]) 762 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]); 763 764 if (tb[IFA_LABEL]) 765 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ); 766 else 767 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 768 769 if (tb[IFA_CACHEINFO]) { 770 struct ifa_cacheinfo *ci; 771 772 ci = nla_data(tb[IFA_CACHEINFO]); 773 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) { 774 err = -EINVAL; 775 goto errout_free; 776 } 777 *pvalid_lft = ci->ifa_valid; 778 *pprefered_lft = ci->ifa_prefered; 779 } 780 781 return ifa; 782 783 errout_free: 784 inet_free_ifa(ifa); 785 errout: 786 return ERR_PTR(err); 787 }
|
0.2.2.2. 把 ifa 插入到对应的两个链表里。
- 插入到网口下的 ip 地址列表
- 插入同 ns 下的 hash 链表
- 发送 netlink 更新消息
- 发送
blocking_notifier_call_chain :待学习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| 426 static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, 427 u32 portid) 428 { 429 struct in_device *in_dev = ifa->ifa_dev; 430 struct in_ifaddr *ifa1, **ifap, **last_primary; 431 432 ASSERT_RTNL(); 433 434 if (!ifa->ifa_local) { 435 inet_free_ifa(ifa); 436 return 0; 437 } 438 439 ifa->ifa_flags &= ~IFA_F_SECONDARY; 440 last_primary = &in_dev->ifa_list; 441 442 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; 443 ifap = &ifa1->ifa_next) { 444 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) && 445 ifa->ifa_scope <= ifa1->ifa_scope) 446 last_primary = &ifa1->ifa_next; 447 if (ifa1->ifa_mask == ifa->ifa_mask && 448 inet_ifa_match(ifa1->ifa_address, ifa)) { 449 if (ifa1->ifa_local == ifa->ifa_local) { 450 inet_free_ifa(ifa); 451 return -EEXIST; 452 } 453 if (ifa1->ifa_scope != ifa->ifa_scope) { 454 inet_free_ifa(ifa); 455 return -EINVAL; 456 } 457 ifa->ifa_flags |= IFA_F_SECONDARY; 458 } 459 } 460 461 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { 462 net_srandom(ifa->ifa_local); 463 ifap = last_primary; 464 } 465 466 ifa->ifa_next = *ifap; 467 *ifap = ifa; 468 469 inet_hash_insert(dev_net(in_dev->dev), ifa); 470 471 cancel_delayed_work(&check_lifetime_work); 472 schedule_delayed_work(&check_lifetime_work, 0); 473 474 /* Send message first, then call notifier. 475 Notifier will trigger FIB update, so that 476 listeners of netlink will know about new ifaddr */ 477 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid); 478 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); 479 480 return 0; 481 }
|