mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 02:00:43 -04:00
Merge branch 'ipv6-convert-rtm_-new-del-addr-and-more-to-per-netns-rtnl'
Kuniyuki Iwashima says:
====================
ipv6: Convert RTM_{NEW,DEL}ADDR and more to per-netns RTNL.
This series converts RTM_NEWADDR/RTM_DELADDR and some more
RTNL users in addrconf.c to per-netns RTNL.
v1: https://lore.kernel.org/20250114080516.46155-1-kuniyu@amazon.com
====================
Link: https://patch.msgid.link/20250115080608.28127-1-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -347,6 +347,11 @@ static inline struct inet6_dev *__in6_dev_get(const struct net_device *dev)
|
||||
return rcu_dereference_rtnl(dev->ip6_ptr);
|
||||
}
|
||||
|
||||
static inline struct inet6_dev *__in6_dev_get_rtnl_net(const struct net_device *dev)
|
||||
{
|
||||
return rtnl_net_dereference(dev_net(dev), dev->ip6_ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* __in6_dev_stats_get - get inet6_dev pointer for stats
|
||||
* @dev: network device
|
||||
|
||||
@@ -852,7 +852,7 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
|
||||
struct inet6_dev *idev;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
idev = __in6_dev_get(dev);
|
||||
idev = __in6_dev_get_rtnl_net(dev);
|
||||
if (idev) {
|
||||
int changed = (!idev->cnf.forwarding) ^ (!newf);
|
||||
|
||||
@@ -865,13 +865,12 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
|
||||
|
||||
static int addrconf_fixup_forwarding(const struct ctl_table *table, int *p, int newf)
|
||||
{
|
||||
struct net *net;
|
||||
struct net *net = (struct net *)table->extra2;
|
||||
int old;
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
net = (struct net *)table->extra2;
|
||||
old = *p;
|
||||
WRITE_ONCE(*p, newf);
|
||||
|
||||
@@ -881,7 +880,7 @@ static int addrconf_fixup_forwarding(const struct ctl_table *table, int *p, int
|
||||
NETCONFA_FORWARDING,
|
||||
NETCONFA_IFINDEX_DEFAULT,
|
||||
net->ipv6.devconf_dflt);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -903,7 +902,7 @@ static int addrconf_fixup_forwarding(const struct ctl_table *table, int *p, int
|
||||
net->ipv6.devconf_all);
|
||||
} else if ((!newf) ^ (!old))
|
||||
dev_forward_change((struct inet6_dev *)table->extra1);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
|
||||
if (newf)
|
||||
rt6_purge_dflt_routers(net);
|
||||
@@ -916,7 +915,7 @@ static void addrconf_linkdown_change(struct net *net, __s32 newf)
|
||||
struct inet6_dev *idev;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
idev = __in6_dev_get(dev);
|
||||
idev = __in6_dev_get_rtnl_net(dev);
|
||||
if (idev) {
|
||||
int changed = (!idev->cnf.ignore_routes_with_linkdown) ^ (!newf);
|
||||
|
||||
@@ -933,13 +932,12 @@ static void addrconf_linkdown_change(struct net *net, __s32 newf)
|
||||
|
||||
static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int newf)
|
||||
{
|
||||
struct net *net;
|
||||
struct net *net = (struct net *)table->extra2;
|
||||
int old;
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
net = (struct net *)table->extra2;
|
||||
old = *p;
|
||||
WRITE_ONCE(*p, newf);
|
||||
|
||||
@@ -950,7 +948,7 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne
|
||||
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
|
||||
NETCONFA_IFINDEX_DEFAULT,
|
||||
net->ipv6.devconf_dflt);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -964,7 +962,8 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne
|
||||
NETCONFA_IFINDEX_ALL,
|
||||
net->ipv6.devconf_all);
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
rtnl_net_unlock(net);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2980,11 +2979,11 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg)
|
||||
if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
|
||||
return -EFAULT;
|
||||
|
||||
rtnl_lock();
|
||||
rtnl_net_lock(net);
|
||||
dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
|
||||
if (dev && dev->type == ARPHRD_SIT)
|
||||
err = addrconf_set_sit_dstaddr(net, dev, &ireq);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -3008,39 +3007,25 @@ static int ipv6_mc_config(struct sock *sk, bool join,
|
||||
/*
|
||||
* Manual configuration of address on an interface
|
||||
*/
|
||||
static int inet6_addr_add(struct net *net, int ifindex,
|
||||
struct ifa6_config *cfg,
|
||||
static int inet6_addr_add(struct net *net, struct net_device *dev,
|
||||
struct ifa6_config *cfg, clock_t expires, u32 flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct inet6_ifaddr *ifp;
|
||||
struct inet6_dev *idev;
|
||||
struct net_device *dev;
|
||||
unsigned long timeout;
|
||||
clock_t expires;
|
||||
u32 flags;
|
||||
|
||||
ASSERT_RTNL();
|
||||
ASSERT_RTNL_NET(net);
|
||||
|
||||
if (cfg->plen > 128) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Invalid prefix length");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check the lifetime */
|
||||
if (!cfg->valid_lft || cfg->preferred_lft > cfg->valid_lft) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "address lifetime invalid");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg->ifa_flags & IFA_F_MANAGETEMPADDR && cfg->plen != 64) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "address with \"mngtmpaddr\" flag must have a prefix length of 64");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = __dev_get_by_index(net, ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
idev = addrconf_add_dev(dev);
|
||||
if (IS_ERR(idev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "IPv6 is disabled on this device");
|
||||
@@ -3049,7 +3034,7 @@ static int inet6_addr_add(struct net *net, int ifindex,
|
||||
|
||||
if (cfg->ifa_flags & IFA_F_MCAUTOJOIN) {
|
||||
int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk,
|
||||
true, cfg->pfx, ifindex);
|
||||
true, cfg->pfx, dev->ifindex);
|
||||
|
||||
if (ret < 0) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Multicast auto join failed");
|
||||
@@ -3059,24 +3044,6 @@ static int inet6_addr_add(struct net *net, int ifindex,
|
||||
|
||||
cfg->scope = ipv6_addr_scope(cfg->pfx);
|
||||
|
||||
timeout = addrconf_timeout_fixup(cfg->valid_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
expires = jiffies_to_clock_t(timeout * HZ);
|
||||
cfg->valid_lft = timeout;
|
||||
flags = RTF_EXPIRES;
|
||||
} else {
|
||||
expires = 0;
|
||||
flags = 0;
|
||||
cfg->ifa_flags |= IFA_F_PERMANENT;
|
||||
}
|
||||
|
||||
timeout = addrconf_timeout_fixup(cfg->preferred_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
if (timeout == 0)
|
||||
cfg->ifa_flags |= IFA_F_DEPRECATED;
|
||||
cfg->preferred_lft = timeout;
|
||||
}
|
||||
|
||||
ifp = ipv6_add_addr(idev, cfg, true, extack);
|
||||
if (!IS_ERR(ifp)) {
|
||||
if (!(cfg->ifa_flags & IFA_F_NOPREFIXROUTE)) {
|
||||
@@ -3104,7 +3071,7 @@ static int inet6_addr_add(struct net *net, int ifindex,
|
||||
return 0;
|
||||
} else if (cfg->ifa_flags & IFA_F_MCAUTOJOIN) {
|
||||
ipv6_mc_config(net->ipv6.mc_autojoin_sk, false,
|
||||
cfg->pfx, ifindex);
|
||||
cfg->pfx, dev->ifindex);
|
||||
}
|
||||
|
||||
return PTR_ERR(ifp);
|
||||
@@ -3129,7 +3096,7 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
idev = __in6_dev_get(dev);
|
||||
idev = __in6_dev_get_rtnl_net(dev);
|
||||
if (!idev) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "IPv6 is disabled on this device");
|
||||
return -ENXIO;
|
||||
@@ -3170,6 +3137,7 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
|
||||
.preferred_lft = INFINITY_LIFE_TIME,
|
||||
.valid_lft = INFINITY_LIFE_TIME,
|
||||
};
|
||||
struct net_device *dev;
|
||||
struct in6_ifreq ireq;
|
||||
int err;
|
||||
|
||||
@@ -3182,9 +3150,13 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
|
||||
cfg.pfx = &ireq.ifr6_addr;
|
||||
cfg.plen = ireq.ifr6_prefixlen;
|
||||
|
||||
rtnl_lock();
|
||||
err = inet6_addr_add(net, ireq.ifr6_ifindex, &cfg, NULL);
|
||||
rtnl_unlock();
|
||||
rtnl_net_lock(net);
|
||||
dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
|
||||
if (dev)
|
||||
err = inet6_addr_add(net, dev, &cfg, 0, 0, NULL);
|
||||
else
|
||||
err = -ENODEV;
|
||||
rtnl_net_unlock(net);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -3199,10 +3171,10 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg)
|
||||
if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
|
||||
return -EFAULT;
|
||||
|
||||
rtnl_lock();
|
||||
rtnl_net_lock(net);
|
||||
err = inet6_addr_del(net, ireq.ifr6_ifindex, 0, &ireq.ifr6_addr,
|
||||
ireq.ifr6_prefixlen, NULL);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -4205,6 +4177,7 @@ static void addrconf_dad_work(struct work_struct *w)
|
||||
struct inet6_dev *idev = ifp->idev;
|
||||
bool bump_id, disable_ipv6 = false;
|
||||
struct in6_addr mcaddr;
|
||||
struct net *net;
|
||||
|
||||
enum {
|
||||
DAD_PROCESS,
|
||||
@@ -4212,7 +4185,9 @@ static void addrconf_dad_work(struct work_struct *w)
|
||||
DAD_ABORT,
|
||||
} action = DAD_PROCESS;
|
||||
|
||||
rtnl_lock();
|
||||
net = dev_net(idev->dev);
|
||||
|
||||
rtnl_net_lock(net);
|
||||
|
||||
spin_lock_bh(&ifp->lock);
|
||||
if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
|
||||
@@ -4222,7 +4197,7 @@ static void addrconf_dad_work(struct work_struct *w)
|
||||
action = DAD_ABORT;
|
||||
ifp->state = INET6_IFADDR_STATE_POSTDAD;
|
||||
|
||||
if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->accept_dad) > 1 ||
|
||||
if ((READ_ONCE(net->ipv6.devconf_all->accept_dad) > 1 ||
|
||||
READ_ONCE(idev->cnf.accept_dad) > 1) &&
|
||||
!idev->cnf.disable_ipv6 &&
|
||||
!(ifp->flags & IFA_F_STABLE_PRIVACY)) {
|
||||
@@ -4304,7 +4279,7 @@ static void addrconf_dad_work(struct work_struct *w)
|
||||
ifp->dad_nonce);
|
||||
out:
|
||||
in6_ifa_put(ifp);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
}
|
||||
|
||||
/* ifp->idev must be at least read locked */
|
||||
@@ -4752,9 +4727,9 @@ static void addrconf_verify_work(struct work_struct *w)
|
||||
struct net *net = container_of(to_delayed_work(w), struct net,
|
||||
ipv6.addr_chk_work);
|
||||
|
||||
rtnl_lock();
|
||||
rtnl_net_lock(net);
|
||||
addrconf_verify_rtnl(net);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
}
|
||||
|
||||
static void addrconf_verify(struct net *net)
|
||||
@@ -4817,8 +4792,12 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
/* We ignore other flags so far. */
|
||||
ifa_flags &= IFA_F_MANAGETEMPADDR;
|
||||
|
||||
return inet6_addr_del(net, ifm->ifa_index, ifa_flags, pfx,
|
||||
ifm->ifa_prefixlen, extack);
|
||||
rtnl_net_lock(net);
|
||||
err = inet6_addr_del(net, ifm->ifa_index, ifa_flags, pfx,
|
||||
ifm->ifa_prefixlen, extack);
|
||||
rtnl_net_unlock(net);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int modify_prefix_route(struct net *net, struct inet6_ifaddr *ifp,
|
||||
@@ -4867,19 +4846,14 @@ static int modify_prefix_route(struct net *net, struct inet6_ifaddr *ifp,
|
||||
}
|
||||
|
||||
static int inet6_addr_modify(struct net *net, struct inet6_ifaddr *ifp,
|
||||
struct ifa6_config *cfg)
|
||||
struct ifa6_config *cfg, clock_t expires,
|
||||
u32 flags)
|
||||
{
|
||||
u32 flags;
|
||||
clock_t expires;
|
||||
unsigned long timeout;
|
||||
bool was_managetempaddr;
|
||||
bool had_prefixroute;
|
||||
bool new_peer = false;
|
||||
bool had_prefixroute;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!cfg->valid_lft || cfg->preferred_lft > cfg->valid_lft)
|
||||
return -EINVAL;
|
||||
ASSERT_RTNL_NET(net);
|
||||
|
||||
if (cfg->ifa_flags & IFA_F_MANAGETEMPADDR &&
|
||||
(ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64))
|
||||
@@ -4888,24 +4862,6 @@ static int inet6_addr_modify(struct net *net, struct inet6_ifaddr *ifp,
|
||||
if (!(ifp->flags & IFA_F_TENTATIVE) || ifp->flags & IFA_F_DADFAILED)
|
||||
cfg->ifa_flags &= ~IFA_F_OPTIMISTIC;
|
||||
|
||||
timeout = addrconf_timeout_fixup(cfg->valid_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
expires = jiffies_to_clock_t(timeout * HZ);
|
||||
cfg->valid_lft = timeout;
|
||||
flags = RTF_EXPIRES;
|
||||
} else {
|
||||
expires = 0;
|
||||
flags = 0;
|
||||
cfg->ifa_flags |= IFA_F_PERMANENT;
|
||||
}
|
||||
|
||||
timeout = addrconf_timeout_fixup(cfg->preferred_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
if (timeout == 0)
|
||||
cfg->ifa_flags |= IFA_F_DEPRECATED;
|
||||
cfg->preferred_lft = timeout;
|
||||
}
|
||||
|
||||
if (cfg->peer_pfx &&
|
||||
memcmp(&ifp->peer_addr, cfg->peer_pfx, sizeof(struct in6_addr))) {
|
||||
if (!ipv6_addr_any(&ifp->peer_addr))
|
||||
@@ -4990,13 +4946,16 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct ifaddrmsg *ifm;
|
||||
struct nlattr *tb[IFA_MAX+1];
|
||||
struct in6_addr *peer_pfx;
|
||||
struct inet6_ifaddr *ifa;
|
||||
struct net_device *dev;
|
||||
struct inet6_dev *idev;
|
||||
struct ifa6_config cfg;
|
||||
struct ifaddrmsg *ifm;
|
||||
unsigned long timeout;
|
||||
clock_t expires;
|
||||
u32 flags;
|
||||
int err;
|
||||
|
||||
err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
|
||||
@@ -5019,23 +4978,6 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (tb[IFA_PROTO])
|
||||
cfg.ifa_proto = nla_get_u8(tb[IFA_PROTO]);
|
||||
|
||||
cfg.valid_lft = INFINITY_LIFE_TIME;
|
||||
cfg.preferred_lft = INFINITY_LIFE_TIME;
|
||||
|
||||
if (tb[IFA_CACHEINFO]) {
|
||||
struct ifa_cacheinfo *ci;
|
||||
|
||||
ci = nla_data(tb[IFA_CACHEINFO]);
|
||||
cfg.valid_lft = ci->ifa_valid;
|
||||
cfg.preferred_lft = ci->ifa_prefered;
|
||||
}
|
||||
|
||||
dev = __dev_get_by_index(net, ifm->ifa_index);
|
||||
if (!dev) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to find the interface");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cfg.ifa_flags = nla_get_u32_default(tb[IFA_FLAGS], ifm->ifa_flags);
|
||||
|
||||
/* We ignore other flags so far. */
|
||||
@@ -5043,9 +4985,55 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE |
|
||||
IFA_F_MCAUTOJOIN | IFA_F_OPTIMISTIC;
|
||||
|
||||
cfg.ifa_flags |= IFA_F_PERMANENT;
|
||||
cfg.valid_lft = INFINITY_LIFE_TIME;
|
||||
cfg.preferred_lft = INFINITY_LIFE_TIME;
|
||||
expires = 0;
|
||||
flags = 0;
|
||||
|
||||
if (tb[IFA_CACHEINFO]) {
|
||||
struct ifa_cacheinfo *ci;
|
||||
|
||||
ci = nla_data(tb[IFA_CACHEINFO]);
|
||||
cfg.valid_lft = ci->ifa_valid;
|
||||
cfg.preferred_lft = ci->ifa_prefered;
|
||||
|
||||
if (!cfg.valid_lft || cfg.preferred_lft > cfg.valid_lft) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "address lifetime invalid");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
timeout = addrconf_timeout_fixup(cfg.valid_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
cfg.ifa_flags &= ~IFA_F_PERMANENT;
|
||||
cfg.valid_lft = timeout;
|
||||
expires = jiffies_to_clock_t(timeout * HZ);
|
||||
flags = RTF_EXPIRES;
|
||||
}
|
||||
|
||||
timeout = addrconf_timeout_fixup(cfg.preferred_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
if (timeout == 0)
|
||||
cfg.ifa_flags |= IFA_F_DEPRECATED;
|
||||
|
||||
cfg.preferred_lft = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
rtnl_net_lock(net);
|
||||
|
||||
dev = __dev_get_by_index(net, ifm->ifa_index);
|
||||
if (!dev) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to find the interface");
|
||||
err = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
idev = ipv6_find_idev(dev);
|
||||
if (IS_ERR(idev))
|
||||
return PTR_ERR(idev);
|
||||
if (IS_ERR(idev)) {
|
||||
err = PTR_ERR(idev);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!ipv6_allow_optimistic_dad(net, idev))
|
||||
cfg.ifa_flags &= ~IFA_F_OPTIMISTIC;
|
||||
@@ -5053,7 +5041,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (cfg.ifa_flags & IFA_F_NODAD &&
|
||||
cfg.ifa_flags & IFA_F_OPTIMISTIC) {
|
||||
NL_SET_ERR_MSG(extack, "IFA_F_NODAD and IFA_F_OPTIMISTIC are mutually exclusive");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ifa = ipv6_get_ifaddr(net, cfg.pfx, dev, 1);
|
||||
@@ -5062,7 +5051,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
* It would be best to check for !NLM_F_CREATE here but
|
||||
* userspace already relies on not having to provide this.
|
||||
*/
|
||||
return inet6_addr_add(net, ifm->ifa_index, &cfg, extack);
|
||||
err = inet6_addr_add(net, dev, &cfg, expires, flags, extack);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_flags & NLM_F_EXCL ||
|
||||
@@ -5070,10 +5060,12 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
NL_SET_ERR_MSG_MOD(extack, "address already assigned");
|
||||
err = -EEXIST;
|
||||
} else {
|
||||
err = inet6_addr_modify(net, ifa, &cfg);
|
||||
err = inet6_addr_modify(net, ifa, &cfg, expires, flags);
|
||||
}
|
||||
|
||||
in6_ifa_put(ifa);
|
||||
unlock:
|
||||
rtnl_net_unlock(net);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -6370,7 +6362,7 @@ static void addrconf_disable_change(struct net *net, __s32 newf)
|
||||
struct inet6_dev *idev;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
idev = __in6_dev_get(dev);
|
||||
idev = __in6_dev_get_rtnl_net(dev);
|
||||
if (idev) {
|
||||
int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
|
||||
|
||||
@@ -6391,7 +6383,7 @@ static int addrconf_disable_ipv6(const struct ctl_table *table, int *p, int newf
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
old = *p;
|
||||
@@ -6400,10 +6392,11 @@ static int addrconf_disable_ipv6(const struct ctl_table *table, int *p, int newf
|
||||
if (p == &net->ipv6.devconf_all->disable_ipv6) {
|
||||
WRITE_ONCE(net->ipv6.devconf_dflt->disable_ipv6, newf);
|
||||
addrconf_disable_change(net, newf);
|
||||
} else if ((!newf) ^ (!old))
|
||||
} else if ((!newf) ^ (!old)) {
|
||||
dev_disable_change((struct inet6_dev *)table->extra1);
|
||||
}
|
||||
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6446,20 +6439,20 @@ static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write,
|
||||
if (write && old != new) {
|
||||
struct net *net = ctl->extra2;
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
if (valp == &net->ipv6.devconf_dflt->proxy_ndp)
|
||||
if (valp == &net->ipv6.devconf_dflt->proxy_ndp) {
|
||||
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
|
||||
NETCONFA_PROXY_NEIGH,
|
||||
NETCONFA_IFINDEX_DEFAULT,
|
||||
net->ipv6.devconf_dflt);
|
||||
else if (valp == &net->ipv6.devconf_all->proxy_ndp)
|
||||
} else if (valp == &net->ipv6.devconf_all->proxy_ndp) {
|
||||
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
|
||||
NETCONFA_PROXY_NEIGH,
|
||||
NETCONFA_IFINDEX_ALL,
|
||||
net->ipv6.devconf_all);
|
||||
else {
|
||||
} else {
|
||||
struct inet6_dev *idev = ctl->extra1;
|
||||
|
||||
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
|
||||
@@ -6467,7 +6460,7 @@ static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write,
|
||||
idev->dev->ifindex,
|
||||
&idev->cnf);
|
||||
}
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -6487,7 +6480,7 @@ static int addrconf_sysctl_addr_gen_mode(const struct ctl_table *ctl, int write,
|
||||
.mode = ctl->mode,
|
||||
};
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
new_val = *((u32 *)ctl->data);
|
||||
@@ -6517,7 +6510,7 @@ static int addrconf_sysctl_addr_gen_mode(const struct ctl_table *ctl, int write,
|
||||
|
||||
WRITE_ONCE(net->ipv6.devconf_dflt->addr_gen_mode, new_val);
|
||||
for_each_netdev(net, dev) {
|
||||
idev = __in6_dev_get(dev);
|
||||
idev = __in6_dev_get_rtnl_net(dev);
|
||||
if (idev &&
|
||||
idev->cnf.addr_gen_mode != new_val) {
|
||||
WRITE_ONCE(idev->cnf.addr_gen_mode,
|
||||
@@ -6531,7 +6524,7 @@ static int addrconf_sysctl_addr_gen_mode(const struct ctl_table *ctl, int write,
|
||||
}
|
||||
|
||||
out:
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -6553,7 +6546,7 @@ static int addrconf_sysctl_stable_secret(const struct ctl_table *ctl, int write,
|
||||
lctl.maxlen = IPV6_MAX_STRLEN;
|
||||
lctl.data = str;
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
if (!write && !secret->initialized) {
|
||||
@@ -6583,7 +6576,7 @@ static int addrconf_sysctl_stable_secret(const struct ctl_table *ctl, int write,
|
||||
struct net_device *dev;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
struct inet6_dev *idev = __in6_dev_get(dev);
|
||||
struct inet6_dev *idev = __in6_dev_get_rtnl_net(dev);
|
||||
|
||||
if (idev) {
|
||||
WRITE_ONCE(idev->cnf.addr_gen_mode,
|
||||
@@ -6598,7 +6591,7 @@ static int addrconf_sysctl_stable_secret(const struct ctl_table *ctl, int write,
|
||||
}
|
||||
|
||||
out:
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -6682,7 +6675,7 @@ int addrconf_disable_policy(const struct ctl_table *ctl, int *valp, int val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_net_trylock(net))
|
||||
return restart_syscall();
|
||||
|
||||
WRITE_ONCE(*valp, val);
|
||||
@@ -6691,7 +6684,7 @@ int addrconf_disable_policy(const struct ctl_table *ctl, int *valp, int val)
|
||||
struct net_device *dev;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
idev = __in6_dev_get(dev);
|
||||
idev = __in6_dev_get_rtnl_net(dev);
|
||||
if (idev)
|
||||
addrconf_disable_policy_idev(idev, val);
|
||||
}
|
||||
@@ -6700,7 +6693,7 @@ int addrconf_disable_policy(const struct ctl_table *ctl, int *valp, int val)
|
||||
addrconf_disable_policy_idev(idev, val);
|
||||
}
|
||||
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(net);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7413,9 +7406,9 @@ static const struct rtnl_msg_handler addrconf_rtnl_msg_handlers[] __initconst_or
|
||||
{.owner = THIS_MODULE, .protocol = PF_INET6, .msgtype = RTM_GETLINK,
|
||||
.dumpit = inet6_dump_ifinfo, .flags = RTNL_FLAG_DUMP_UNLOCKED},
|
||||
{.owner = THIS_MODULE, .protocol = PF_INET6, .msgtype = RTM_NEWADDR,
|
||||
.doit = inet6_rtm_newaddr},
|
||||
.doit = inet6_rtm_newaddr, .flags = RTNL_FLAG_DOIT_PERNET},
|
||||
{.owner = THIS_MODULE, .protocol = PF_INET6, .msgtype = RTM_DELADDR,
|
||||
.doit = inet6_rtm_deladdr},
|
||||
.doit = inet6_rtm_deladdr, .flags = RTNL_FLAG_DOIT_PERNET},
|
||||
{.owner = THIS_MODULE, .protocol = PF_INET6, .msgtype = RTM_GETADDR,
|
||||
.doit = inet6_rtm_getaddr, .dumpit = inet6_dump_ifaddr,
|
||||
.flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
|
||||
@@ -7457,9 +7450,9 @@ int __init addrconf_init(void)
|
||||
goto out_nowq;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
rtnl_net_lock(&init_net);
|
||||
idev = ipv6_add_dev(blackhole_netdev);
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(&init_net);
|
||||
if (IS_ERR(idev)) {
|
||||
err = PTR_ERR(idev);
|
||||
goto errlo;
|
||||
@@ -7509,17 +7502,17 @@ void addrconf_cleanup(void)
|
||||
|
||||
rtnl_af_unregister(&inet6_ops);
|
||||
|
||||
rtnl_lock();
|
||||
rtnl_net_lock(&init_net);
|
||||
|
||||
/* clean dev list */
|
||||
for_each_netdev(&init_net, dev) {
|
||||
if (__in6_dev_get(dev) == NULL)
|
||||
if (!__in6_dev_get_rtnl_net(dev))
|
||||
continue;
|
||||
addrconf_ifdown(dev, true);
|
||||
}
|
||||
addrconf_ifdown(init_net.loopback_dev, true);
|
||||
|
||||
rtnl_unlock();
|
||||
rtnl_net_unlock(&init_net);
|
||||
|
||||
destroy_workqueue(addrconf_wq);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user