Skip to content

Commit 7b8e1a8

Browse files
committed
Merge branch 'ipvlan-addrs_lock-made-per-port'
Dmitry Skorodumov says: ==================== ipvlan: addrs_lock made per port First patch fixes a rather minor issues that sometimes ipvlan-addrs are modified without lock (because for IPv6 addr can be sometimes added without RTNL) ==================== Link: https://patch.msgid.link/20260112142417.4039566-1-skorodumov.dmitry@huawei.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 7a29f6b + 8becfe1 commit 7b8e1a8

6 files changed

Lines changed: 208 additions & 30 deletions

File tree

drivers/net/ipvlan/ipvlan.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ struct ipvl_dev {
6969
DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE);
7070
netdev_features_t sfeatures;
7171
u32 msg_enable;
72-
spinlock_t addrs_lock;
7372
};
7473

7574
struct ipvl_addr {
@@ -90,6 +89,7 @@ struct ipvl_port {
9089
struct net_device *dev;
9190
possible_net_t pnet;
9291
struct hlist_head hlhead[IPVLAN_HASH_SIZE];
92+
spinlock_t addrs_lock; /* guards hash-table and addrs */
9393
struct list_head ipvlans;
9494
u16 mode;
9595
u16 flags;

drivers/net/ipvlan/ipvlan_core.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,15 @@ void ipvlan_ht_addr_del(struct ipvl_addr *addr)
107107
struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
108108
const void *iaddr, bool is_v6)
109109
{
110-
struct ipvl_addr *addr, *ret = NULL;
110+
struct ipvl_addr *addr;
111111

112-
rcu_read_lock();
113-
list_for_each_entry_rcu(addr, &ipvlan->addrs, anode) {
114-
if (addr_equal(is_v6, addr, iaddr)) {
115-
ret = addr;
116-
break;
117-
}
112+
assert_spin_locked(&ipvlan->port->addrs_lock);
113+
114+
list_for_each_entry(addr, &ipvlan->addrs, anode) {
115+
if (addr_equal(is_v6, addr, iaddr))
116+
return addr;
118117
}
119-
rcu_read_unlock();
120-
return ret;
118+
return NULL;
121119
}
122120

123121
bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)

drivers/net/ipvlan/ipvlan_main.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ static int ipvlan_port_create(struct net_device *dev)
7575
for (idx = 0; idx < IPVLAN_HASH_SIZE; idx++)
7676
INIT_HLIST_HEAD(&port->hlhead[idx]);
7777

78+
spin_lock_init(&port->addrs_lock);
7879
skb_queue_head_init(&port->backlog);
7980
INIT_WORK(&port->wq, ipvlan_process_multicast);
8081
ida_init(&port->ida);
@@ -181,6 +182,7 @@ static void ipvlan_uninit(struct net_device *dev)
181182
static int ipvlan_open(struct net_device *dev)
182183
{
183184
struct ipvl_dev *ipvlan = netdev_priv(dev);
185+
struct ipvl_port *port = ipvlan->port;
184186
struct ipvl_addr *addr;
185187

186188
if (ipvlan->port->mode == IPVLAN_MODE_L3 ||
@@ -189,10 +191,10 @@ static int ipvlan_open(struct net_device *dev)
189191
else
190192
dev->flags &= ~IFF_NOARP;
191193

192-
rcu_read_lock();
193-
list_for_each_entry_rcu(addr, &ipvlan->addrs, anode)
194+
spin_lock_bh(&port->addrs_lock);
195+
list_for_each_entry(addr, &ipvlan->addrs, anode)
194196
ipvlan_ht_addr_add(ipvlan, addr);
195-
rcu_read_unlock();
197+
spin_unlock_bh(&port->addrs_lock);
196198

197199
return 0;
198200
}
@@ -206,10 +208,10 @@ static int ipvlan_stop(struct net_device *dev)
206208
dev_uc_unsync(phy_dev, dev);
207209
dev_mc_unsync(phy_dev, dev);
208210

209-
rcu_read_lock();
210-
list_for_each_entry_rcu(addr, &ipvlan->addrs, anode)
211+
spin_lock_bh(&ipvlan->port->addrs_lock);
212+
list_for_each_entry(addr, &ipvlan->addrs, anode)
211213
ipvlan_ht_addr_del(addr);
212-
rcu_read_unlock();
214+
spin_unlock_bh(&ipvlan->port->addrs_lock);
213215

214216
return 0;
215217
}
@@ -579,7 +581,6 @@ int ipvlan_link_new(struct net_device *dev, struct rtnl_newlink_params *params,
579581
if (!tb[IFLA_MTU])
580582
ipvlan_adjust_mtu(ipvlan, phy_dev);
581583
INIT_LIST_HEAD(&ipvlan->addrs);
582-
spin_lock_init(&ipvlan->addrs_lock);
583584

584585
/* TODO Probably put random address here to be presented to the
585586
* world but keep using the physical-dev address for the outgoing
@@ -657,13 +658,13 @@ void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
657658
struct ipvl_dev *ipvlan = netdev_priv(dev);
658659
struct ipvl_addr *addr, *next;
659660

660-
spin_lock_bh(&ipvlan->addrs_lock);
661+
spin_lock_bh(&ipvlan->port->addrs_lock);
661662
list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
662663
ipvlan_ht_addr_del(addr);
663664
list_del_rcu(&addr->anode);
664665
kfree_rcu(addr, rcu);
665666
}
666-
spin_unlock_bh(&ipvlan->addrs_lock);
667+
spin_unlock_bh(&ipvlan->port->addrs_lock);
667668

668669
ida_free(&ipvlan->port->ida, dev->dev_id);
669670
list_del_rcu(&ipvlan->pnode);
@@ -817,6 +818,8 @@ static int ipvlan_add_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
817818
{
818819
struct ipvl_addr *addr;
819820

821+
assert_spin_locked(&ipvlan->port->addrs_lock);
822+
820823
addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC);
821824
if (!addr)
822825
return -ENOMEM;
@@ -847,16 +850,16 @@ static void ipvlan_del_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
847850
{
848851
struct ipvl_addr *addr;
849852

850-
spin_lock_bh(&ipvlan->addrs_lock);
853+
spin_lock_bh(&ipvlan->port->addrs_lock);
851854
addr = ipvlan_find_addr(ipvlan, iaddr, is_v6);
852855
if (!addr) {
853-
spin_unlock_bh(&ipvlan->addrs_lock);
856+
spin_unlock_bh(&ipvlan->port->addrs_lock);
854857
return;
855858
}
856859

857860
ipvlan_ht_addr_del(addr);
858861
list_del_rcu(&addr->anode);
859-
spin_unlock_bh(&ipvlan->addrs_lock);
862+
spin_unlock_bh(&ipvlan->port->addrs_lock);
860863
kfree_rcu(addr, rcu);
861864
}
862865

@@ -878,14 +881,14 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
878881
{
879882
int ret = -EINVAL;
880883

881-
spin_lock_bh(&ipvlan->addrs_lock);
884+
spin_lock_bh(&ipvlan->port->addrs_lock);
882885
if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true))
883886
netif_err(ipvlan, ifup, ipvlan->dev,
884887
"Failed to add IPv6=%pI6c addr for %s intf\n",
885888
ip6_addr, ipvlan->dev->name);
886889
else
887890
ret = ipvlan_add_addr(ipvlan, ip6_addr, true);
888-
spin_unlock_bh(&ipvlan->addrs_lock);
891+
spin_unlock_bh(&ipvlan->port->addrs_lock);
889892
return ret;
890893
}
891894

@@ -924,36 +927,39 @@ static int ipvlan_addr6_validator_event(struct notifier_block *unused,
924927
struct in6_validator_info *i6vi = (struct in6_validator_info *)ptr;
925928
struct net_device *dev = (struct net_device *)i6vi->i6vi_dev->dev;
926929
struct ipvl_dev *ipvlan = netdev_priv(dev);
930+
int ret = NOTIFY_OK;
927931

928932
if (!ipvlan_is_valid_dev(dev))
929933
return NOTIFY_DONE;
930934

931935
switch (event) {
932936
case NETDEV_UP:
937+
spin_lock_bh(&ipvlan->port->addrs_lock);
933938
if (ipvlan_addr_busy(ipvlan->port, &i6vi->i6vi_addr, true)) {
934939
NL_SET_ERR_MSG(i6vi->extack,
935940
"Address already assigned to an ipvlan device");
936-
return notifier_from_errno(-EADDRINUSE);
941+
ret = notifier_from_errno(-EADDRINUSE);
937942
}
943+
spin_unlock_bh(&ipvlan->port->addrs_lock);
938944
break;
939945
}
940946

941-
return NOTIFY_OK;
947+
return ret;
942948
}
943949
#endif
944950

945951
static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
946952
{
947953
int ret = -EINVAL;
948954

949-
spin_lock_bh(&ipvlan->addrs_lock);
955+
spin_lock_bh(&ipvlan->port->addrs_lock);
950956
if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false))
951957
netif_err(ipvlan, ifup, ipvlan->dev,
952958
"Failed to add IPv4=%pI4 on %s intf.\n",
953959
ip4_addr, ipvlan->dev->name);
954960
else
955961
ret = ipvlan_add_addr(ipvlan, ip4_addr, false);
956-
spin_unlock_bh(&ipvlan->addrs_lock);
962+
spin_unlock_bh(&ipvlan->port->addrs_lock);
957963
return ret;
958964
}
959965

@@ -995,21 +1001,24 @@ static int ipvlan_addr4_validator_event(struct notifier_block *unused,
9951001
struct in_validator_info *ivi = (struct in_validator_info *)ptr;
9961002
struct net_device *dev = (struct net_device *)ivi->ivi_dev->dev;
9971003
struct ipvl_dev *ipvlan = netdev_priv(dev);
1004+
int ret = NOTIFY_OK;
9981005

9991006
if (!ipvlan_is_valid_dev(dev))
10001007
return NOTIFY_DONE;
10011008

10021009
switch (event) {
10031010
case NETDEV_UP:
1011+
spin_lock_bh(&ipvlan->port->addrs_lock);
10041012
if (ipvlan_addr_busy(ipvlan->port, &ivi->ivi_addr, false)) {
10051013
NL_SET_ERR_MSG(ivi->extack,
10061014
"Address already assigned to an ipvlan device");
1007-
return notifier_from_errno(-EADDRINUSE);
1015+
ret = notifier_from_errno(-EADDRINUSE);
10081016
}
1017+
spin_unlock_bh(&ipvlan->port->addrs_lock);
10091018
break;
10101019
}
10111020

1012-
return NOTIFY_OK;
1021+
return ret;
10131022
}
10141023

10151024
static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = {

tools/testing/selftests/net/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ TEST_PROGS := \
4848
ipv6_flowlabel.sh \
4949
ipv6_force_forwarding.sh \
5050
ipv6_route_update_soft_lockup.sh \
51+
ipvtap_test.sh \
5152
l2_tos_ttl_inherit.sh \
5253
l2tp.sh \
5354
link_netns.py \

tools/testing/selftests/net/config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ CONFIG_IPV6_SEG6_LWTUNNEL=y
4848
CONFIG_IPV6_SIT=y
4949
CONFIG_IPV6_VTI=y
5050
CONFIG_IPVLAN=m
51+
CONFIG_IPVTAP=m
5152
CONFIG_KALLSYMS=y
5253
CONFIG_L2TP=m
5354
CONFIG_L2TP_ETH=m
@@ -116,6 +117,7 @@ CONFIG_PROC_SYSCTL=y
116117
CONFIG_PSAMPLE=m
117118
CONFIG_RPS=y
118119
CONFIG_SYSFS=y
120+
CONFIG_TAP=m
119121
CONFIG_TCP_MD5SIG=y
120122
CONFIG_TEST_BLACKHOLE_DEV=m
121123
CONFIG_TEST_BPF=m

0 commit comments

Comments
 (0)