aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2018-01-25 09:01:39 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-29 12:23:52 -0500
commit38e01b30563a5b5ade7b54e5d739d16a2b02fe82 (patch)
tree4c8fa3f46034244bb2e5eaa7cc1258b0ae427c68
parentc36ac8e2307334c83e8bf81ed361f0e4959d995f (diff)
dev: advertise the new ifindex when the netns iface changes
The goal is to let the user follow an interface that moves to another netns. CC: Jiri Benc <jbenc@redhat.com> CC: Christian Brauner <christian.brauner@ubuntu.com> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Reviewed-by: Jiri Benc <jbenc@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/rtnetlink.h5
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--net/core/dev.c19
-rw-r--r--net/core/rtnetlink.c31
4 files changed, 36 insertions, 20 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 62d508b31f56..0514cc36ac34 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -19,10 +19,11 @@ extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
19 19
20void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags); 20void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags);
21void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change, 21void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
22 gfp_t flags, int *new_nsid); 22 gfp_t flags, int *new_nsid, int new_ifindex);
23struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, 23struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
24 unsigned change, u32 event, 24 unsigned change, u32 event,
25 gfp_t flags, int *new_nsid); 25 gfp_t flags, int *new_nsid,
26 int new_ifindex);
26void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, 27void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev,
27 gfp_t flags); 28 gfp_t flags);
28 29
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 8616131e2c61..6d9447700e18 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -163,6 +163,7 @@ enum {
163 IFLA_IF_NETNSID, 163 IFLA_IF_NETNSID,
164 IFLA_CARRIER_UP_COUNT, 164 IFLA_CARRIER_UP_COUNT,
165 IFLA_CARRIER_DOWN_COUNT, 165 IFLA_CARRIER_DOWN_COUNT,
166 IFLA_NEW_IFINDEX,
166 __IFLA_MAX 167 __IFLA_MAX
167}; 168};
168 169
diff --git a/net/core/dev.c b/net/core/dev.c
index 59987eb6511a..858501b12869 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7360,7 +7360,7 @@ static void rollback_registered_many(struct list_head *head)
7360 if (!dev->rtnl_link_ops || 7360 if (!dev->rtnl_link_ops ||
7361 dev->rtnl_link_state == RTNL_LINK_INITIALIZED) 7361 dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
7362 skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0, 7362 skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0,
7363 GFP_KERNEL, NULL); 7363 GFP_KERNEL, NULL, 0);
7364 7364
7365 /* 7365 /*
7366 * Flush the unicast and multicast chains 7366 * Flush the unicast and multicast chains
@@ -8473,7 +8473,7 @@ EXPORT_SYMBOL(unregister_netdev);
8473 8473
8474int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) 8474int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat)
8475{ 8475{
8476 int err, new_nsid; 8476 int err, new_nsid, new_ifindex;
8477 8477
8478 ASSERT_RTNL(); 8478 ASSERT_RTNL();
8479 8479
@@ -8529,8 +8529,16 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
8529 call_netdevice_notifiers(NETDEV_UNREGISTER, dev); 8529 call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
8530 rcu_barrier(); 8530 rcu_barrier();
8531 call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); 8531 call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev);
8532
8532 new_nsid = peernet2id_alloc(dev_net(dev), net); 8533 new_nsid = peernet2id_alloc(dev_net(dev), net);
8533 rtmsg_ifinfo_newnet(RTM_DELLINK, dev, ~0U, GFP_KERNEL, &new_nsid); 8534 /* If there is an ifindex conflict assign a new one */
8535 if (__dev_get_by_index(net, dev->ifindex))
8536 new_ifindex = dev_new_index(net);
8537 else
8538 new_ifindex = dev->ifindex;
8539
8540 rtmsg_ifinfo_newnet(RTM_DELLINK, dev, ~0U, GFP_KERNEL, &new_nsid,
8541 new_ifindex);
8534 8542
8535 /* 8543 /*
8536 * Flush the unicast and multicast chains 8544 * Flush the unicast and multicast chains
@@ -8544,10 +8552,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
8544 8552
8545 /* Actually switch the network namespace */ 8553 /* Actually switch the network namespace */
8546 dev_net_set(dev, net); 8554 dev_net_set(dev, net);
8547 8555 dev->ifindex = new_ifindex;
8548 /* If there is an ifindex conflict assign a new one */
8549 if (__dev_get_by_index(net, dev->ifindex))
8550 dev->ifindex = dev_new_index(net);
8551 8556
8552 /* Send a netdev-add uevent to the new namespace */ 8557 /* Send a netdev-add uevent to the new namespace */
8553 kobject_uevent(&dev->dev.kobj, KOBJ_ADD); 8558 kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index f111557958bb..e04af7b7f448 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -988,6 +988,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
988 + rtnl_xdp_size() /* IFLA_XDP */ 988 + rtnl_xdp_size() /* IFLA_XDP */
989 + nla_total_size(4) /* IFLA_EVENT */ 989 + nla_total_size(4) /* IFLA_EVENT */
990 + nla_total_size(4) /* IFLA_NEW_NETNSID */ 990 + nla_total_size(4) /* IFLA_NEW_NETNSID */
991 + nla_total_size(4) /* IFLA_NEW_IFINDEX */
991 + nla_total_size(1) /* IFLA_PROTO_DOWN */ 992 + nla_total_size(1) /* IFLA_PROTO_DOWN */
992 + nla_total_size(4) /* IFLA_IF_NETNSID */ 993 + nla_total_size(4) /* IFLA_IF_NETNSID */
993 + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ 994 + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */
@@ -1511,7 +1512,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
1511 struct net_device *dev, struct net *src_net, 1512 struct net_device *dev, struct net *src_net,
1512 int type, u32 pid, u32 seq, u32 change, 1513 int type, u32 pid, u32 seq, u32 change,
1513 unsigned int flags, u32 ext_filter_mask, 1514 unsigned int flags, u32 ext_filter_mask,
1514 u32 event, int *new_nsid, int tgt_netnsid) 1515 u32 event, int *new_nsid, int new_ifindex,
1516 int tgt_netnsid)
1515{ 1517{
1516 struct ifinfomsg *ifm; 1518 struct ifinfomsg *ifm;
1517 struct nlmsghdr *nlh; 1519 struct nlmsghdr *nlh;
@@ -1608,6 +1610,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
1608 if (new_nsid && 1610 if (new_nsid &&
1609 nla_put_s32(skb, IFLA_NEW_NETNSID, *new_nsid) < 0) 1611 nla_put_s32(skb, IFLA_NEW_NETNSID, *new_nsid) < 0)
1610 goto nla_put_failure; 1612 goto nla_put_failure;
1613 if (new_ifindex &&
1614 nla_put_s32(skb, IFLA_NEW_IFINDEX, new_ifindex) < 0)
1615 goto nla_put_failure;
1616
1611 1617
1612 rcu_read_lock(); 1618 rcu_read_lock();
1613 if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) 1619 if (rtnl_fill_link_af(skb, dev, ext_filter_mask))
@@ -1853,7 +1859,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1853 NETLINK_CB(cb->skb).portid, 1859 NETLINK_CB(cb->skb).portid,
1854 cb->nlh->nlmsg_seq, 0, 1860 cb->nlh->nlmsg_seq, 0,
1855 flags, 1861 flags,
1856 ext_filter_mask, 0, NULL, 1862 ext_filter_mask, 0, NULL, 0,
1857 netnsid); 1863 netnsid);
1858 1864
1859 if (err < 0) { 1865 if (err < 0) {
@@ -3088,7 +3094,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
3088 err = rtnl_fill_ifinfo(nskb, dev, net, 3094 err = rtnl_fill_ifinfo(nskb, dev, net,
3089 RTM_NEWLINK, NETLINK_CB(skb).portid, 3095 RTM_NEWLINK, NETLINK_CB(skb).portid,
3090 nlh->nlmsg_seq, 0, 0, ext_filter_mask, 3096 nlh->nlmsg_seq, 0, 0, ext_filter_mask,
3091 0, NULL, netnsid); 3097 0, NULL, 0, netnsid);
3092 if (err < 0) { 3098 if (err < 0) {
3093 /* -EMSGSIZE implies BUG in if_nlmsg_size */ 3099 /* -EMSGSIZE implies BUG in if_nlmsg_size */
3094 WARN_ON(err == -EMSGSIZE); 3100 WARN_ON(err == -EMSGSIZE);
@@ -3184,7 +3190,8 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
3184 3190
3185struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, 3191struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
3186 unsigned int change, 3192 unsigned int change,
3187 u32 event, gfp_t flags, int *new_nsid) 3193 u32 event, gfp_t flags, int *new_nsid,
3194 int new_ifindex)
3188{ 3195{
3189 struct net *net = dev_net(dev); 3196 struct net *net = dev_net(dev);
3190 struct sk_buff *skb; 3197 struct sk_buff *skb;
@@ -3197,7 +3204,7 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
3197 3204
3198 err = rtnl_fill_ifinfo(skb, dev, dev_net(dev), 3205 err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
3199 type, 0, 0, change, 0, 0, event, 3206 type, 0, 0, change, 0, 0, event,
3200 new_nsid, -1); 3207 new_nsid, new_ifindex, -1);
3201 if (err < 0) { 3208 if (err < 0) {
3202 /* -EMSGSIZE implies BUG in if_nlmsg_size() */ 3209 /* -EMSGSIZE implies BUG in if_nlmsg_size() */
3203 WARN_ON(err == -EMSGSIZE); 3210 WARN_ON(err == -EMSGSIZE);
@@ -3220,14 +3227,15 @@ void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, gfp_t flags)
3220 3227
3221static void rtmsg_ifinfo_event(int type, struct net_device *dev, 3228static void rtmsg_ifinfo_event(int type, struct net_device *dev,
3222 unsigned int change, u32 event, 3229 unsigned int change, u32 event,
3223 gfp_t flags, int *new_nsid) 3230 gfp_t flags, int *new_nsid, int new_ifindex)
3224{ 3231{
3225 struct sk_buff *skb; 3232 struct sk_buff *skb;
3226 3233
3227 if (dev->reg_state != NETREG_REGISTERED) 3234 if (dev->reg_state != NETREG_REGISTERED)
3228 return; 3235 return;
3229 3236
3230 skb = rtmsg_ifinfo_build_skb(type, dev, change, event, flags, new_nsid); 3237 skb = rtmsg_ifinfo_build_skb(type, dev, change, event, flags, new_nsid,
3238 new_ifindex);
3231 if (skb) 3239 if (skb)
3232 rtmsg_ifinfo_send(skb, dev, flags); 3240 rtmsg_ifinfo_send(skb, dev, flags);
3233} 3241}
@@ -3235,14 +3243,15 @@ static void rtmsg_ifinfo_event(int type, struct net_device *dev,
3235void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, 3243void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change,
3236 gfp_t flags) 3244 gfp_t flags)
3237{ 3245{
3238 rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags, NULL); 3246 rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags,
3247 NULL, 0);
3239} 3248}
3240 3249
3241void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change, 3250void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
3242 gfp_t flags, int *new_nsid) 3251 gfp_t flags, int *new_nsid, int new_ifindex)
3243{ 3252{
3244 rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags, 3253 rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags,
3245 new_nsid); 3254 new_nsid, new_ifindex);
3246} 3255}
3247 3256
3248static int nlmsg_populate_fdb_fill(struct sk_buff *skb, 3257static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
@@ -4642,7 +4651,7 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
4642 case NETDEV_CHANGELOWERSTATE: 4651 case NETDEV_CHANGELOWERSTATE:
4643 case NETDEV_CHANGE_TX_QUEUE_LEN: 4652 case NETDEV_CHANGE_TX_QUEUE_LEN:
4644 rtmsg_ifinfo_event(RTM_NEWLINK, dev, 0, rtnl_get_event(event), 4653 rtmsg_ifinfo_event(RTM_NEWLINK, dev, 0, rtnl_get_event(event),
4645 GFP_KERNEL, NULL); 4654 GFP_KERNEL, NULL, 0);
4646 break; 4655 break;
4647 default: 4656 default:
4648 break; 4657 break;