diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 36faf49..25ac2e0 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -27,6 +27,7 @@ #include #include #include +#include struct user_namespace; struct proc_dir_entry; @@ -291,7 +292,18 @@ static inline struct net *read_pnet(struct net * const *pnet) #define __net_initconst __initconst #endif -int peernet2id(struct net *net, struct net *peer); +int __peernet2id(struct net *net, struct net *peer, bool alloc); + +/* This function returns the id of a peer netns. If no id is assigned, one will + * be allocated and returned. + */ +static inline int peernet2id(struct net *net, struct net *peer) +{ + int id = __peernet2id(net, peer, true); + + return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; +} + struct net *get_net_ns_by_id(struct net *net, int id); struct pernet_operations { diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index cb5290b..9ff2164 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -175,7 +175,7 @@ static int net_eq_idr(int id, void *net, void *peer) return 0; } -static int __peernet2id(struct net *net, struct net *peer, bool alloc) +int __peernet2id(struct net *net, struct net *peer, bool alloc) { int id = idr_for_each(&net->netns_ids, net_eq_idr, peer); @@ -192,17 +192,7 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc) return -ENOENT; } - -/* This function returns the id of a peer netns. If no id is assigned, one will - * be allocated and returned. - */ -int peernet2id(struct net *net, struct net *peer) -{ - int id = __peernet2id(net, peer, true); - - return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; -} -EXPORT_SYMBOL(peernet2id); +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 1385de0..bd41427 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1175,8 +1175,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, struct net *link_net = dev->rtnl_link_ops->get_link_net(dev); if (!net_eq(dev_net(dev), link_net)) { - int id = peernet2id(dev_net(dev), link_net); + int id = __peernet2id(dev_net(dev), link_net, false); + if (id < 0) + id = NETNSA_NSID_NOT_ASSIGNED; if (nla_put_s32(skb, IFLA_LINK_NETNSID, id)) goto nla_put_failure; } @@ -2142,7 +2144,13 @@ replay: dev->ifindex = ifm->ifi_index; if (ops->newlink) { - err = ops->newlink(link_net ? : net, dev, tb, data); + struct net *src_net = link_net ?: net; + + if (ops->get_link_net && !net_eq(src_net, dev_net(dev))) + /* We don't care the return value */ + (void) peernet2id(dev_net(dev), src_net); + + err = ops->newlink(src_net, dev, tb, data); /* Drivers should call free_netdev() in ->destructor * and unregister it on failure after registration * so that device could be finally freed in rtnl_unlock.