Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org> --- include/linux/inetdevice.h | 2 ++ net/ipv4/devinet.c | 27 ++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 01cbcfe93383b7..a41bfce099e0a1 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -170,6 +170,8 @@ int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); void devinet_init(void); struct in_device *inetdev_by_index(struct net *, int); +__be32 __inet_select_addr(const struct net_device *dev, __be32 dst, int scope, + struct afnetns *afnetns); __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, __be32 local, int scope); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index cc15afefa1df0a..0844d917aa8d7d 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1224,7 +1224,17 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len) return done; } -__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) +static struct afnetns *ifa_afnetns(struct in_ifaddr *ifa) +{ +#if IS_ENABLED(CONFIG_AFNETNS) + return ifa->afnetns; +#else + return NULL; +#endif +} + +__be32 __inet_select_addr(const struct net_device *dev, __be32 dst, + int scope, struct afnetns *afnetns) { __be32 addr = 0; struct in_device *in_dev; @@ -1237,6 +1247,8 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) goto no_in_dev; for_primary_ifa(in_dev) { + if (afnetns && afnetns != ifa_afnetns(ifa)) + continue; if (ifa->ifa_scope > scope) continue; if (!dst || inet_ifa_match(dst, ifa)) { @@ -1262,7 +1274,8 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) (in_dev = __in_dev_get_rcu(dev))) { for_primary_ifa(in_dev) { if (ifa->ifa_scope != RT_SCOPE_LINK && - ifa->ifa_scope <= scope) { + ifa->ifa_scope <= scope && + (!afnetns || afnetns == ifa_afnetns(ifa))) { addr = ifa->ifa_local; goto out_unlock; } @@ -1283,7 +1296,8 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) for_primary_ifa(in_dev) { if (ifa->ifa_scope != RT_SCOPE_LINK && - ifa->ifa_scope <= scope) { + ifa->ifa_scope <= scope && + (!afnetns || afnetns == ifa_afnetns(ifa))) { addr = ifa->ifa_local; goto out_unlock; } @@ -1293,6 +1307,13 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) rcu_read_unlock(); return addr; } +EXPORT_SYMBOL(__inet_select_addr); + +__be32 inet_select_addr(const struct net_device *dev, __be32 dst, + int scope) +{ + return __inet_select_addr(dev, dst, scope, NULL); +} EXPORT_SYMBOL(inet_select_addr); static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, -- 2.9.3