diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2018-01-25 09:01:39 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-29 12:23:52 -0500 |
commit | 38e01b30563a5b5ade7b54e5d739d16a2b02fe82 (patch) | |
tree | 4c8fa3f46034244bb2e5eaa7cc1258b0ae427c68 | |
parent | c36ac8e2307334c83e8bf81ed361f0e4959d995f (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.h | 5 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 1 | ||||
-rw-r--r-- | net/core/dev.c | 19 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 31 |
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 | ||
20 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags); | 20 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags); |
21 | void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change, | 21 | void 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); |
23 | struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, | 23 | struct 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); | ||
26 | void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, | 27 | void 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 | ||
8474 | int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) | 8474 | int 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 | ||
3185 | struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, | 3191 | struct 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 | ||
3221 | static void rtmsg_ifinfo_event(int type, struct net_device *dev, | 3228 | static 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, | |||
3235 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, | 3243 | void 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 | ||
3241 | void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change, | 3250 | void 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 | ||
3248 | static int nlmsg_populate_fdb_fill(struct sk_buff *skb, | 3257 | static 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; |