diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 612e0731142d..1df38bdae2ee 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1471,11 +1471,17 @@ int macvlan_link_register(struct rtnl_link_ops *ops) }; EXPORT_SYMBOL_GPL(macvlan_link_register); +static struct net *macvlan_get_link_net(const struct net_device *dev) +{ + return dev_net(macvlan_dev_real_dev(dev)); +} + static struct rtnl_link_ops macvlan_link_ops = { .kind = "macvlan", .setup = macvlan_setup, .newlink = macvlan_newlink, .dellink = macvlan_dellink, + .get_link_net = macvlan_get_link_net, }; static int macvlan_device_event(struct notifier_block *unused, diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8ad596573d17..4cca36ebc4fb 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -469,6 +469,14 @@ static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = { [VETH_INFO_PEER] = { .len = sizeof(struct ifinfomsg) }, }; +static struct net *veth_get_link_net(const struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer = rtnl_dereference(priv->peer); + + return peer ? dev_net(peer) : dev_net(dev); +} + static struct rtnl_link_ops veth_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct veth_priv), @@ -478,6 +486,7 @@ static struct rtnl_link_ops veth_link_ops = { .dellink = veth_dellink, .policy = veth_policy, .maxtype = VETH_INFO_MAX, + .get_link_net = veth_get_link_net, }; /* diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0346eaa6d236..19d3664ab9dd 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -339,6 +339,11 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, ndm->ndm_flags = fdb->flags; ndm->ndm_type = RTN_UNICAST; + if (!net_eq(dev_net(vxlan->dev), vxlan->net) && + nla_put_s32(skb, NDA_NDM_IFINDEX_NETNSID, + peernet2id(vxlan->net, dev_net(vxlan->dev)))) + goto nla_put_failure; + if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr)) goto nla_put_failure; diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h index f3d77f9f1e0b..38f236853cc0 100644 --- a/include/uapi/linux/neighbour.h +++ b/include/uapi/linux/neighbour.h @@ -25,6 +25,7 @@ enum { NDA_VNI, NDA_IFINDEX, NDA_MASTER, + NDA_NDM_IFINDEX_NETNSID, __NDA_MAX }; diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 8ac8a5cc2143..c92b52f37d38 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -238,6 +238,13 @@ nla_put_failure: return -EMSGSIZE; } +static struct net *vlan_get_link_net(const struct net_device *dev) +{ + struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; + + return dev_net(real_dev); +} + struct rtnl_link_ops vlan_link_ops __read_mostly = { .kind = "vlan", .maxtype = IFLA_VLAN_MAX, @@ -250,6 +257,7 @@ struct rtnl_link_ops vlan_link_ops __read_mostly = { .dellink = unregister_vlan_dev, .get_size = vlan_get_size, .fill_info = vlan_fill_info, + .get_link_net = vlan_get_link_net, }; int __init vlan_netlink_init(void) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 9d1a4cac83b6..b7bde551ef76 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -202,6 +202,7 @@ int peernet2id(struct net *net, struct net *peer) return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; } +EXPORT_SYMBOL(peernet2id); struct net *get_net_ns_by_id(struct net *net, int id) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index a12eecc0f976..07447d1665e6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2172,8 +2172,11 @@ replay: goto out; } - if (link_net) + if (link_net) { err = dev_change_net_namespace(dev, dest_net, ifname); + if (err < 0) + unregister_netdevice(dev); + } out: if (link_net) put_net(link_net); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 9306a5ff9149..6dee2a8ca0a9 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1676,6 +1676,7 @@ static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { .changelink = ip6gre_changelink, .get_size = ip6gre_get_size, .fill_info = ip6gre_fill_info, + .get_link_net = ip6_tnl_get_link_net, }; /*