Skip to content

Commit fc69dec

Browse files
fengsxyPaolo Abeni
authored andcommitted
8021q: use RCU for egress QoS mappings
The TX fast path and reporting paths walk egress QoS mappings without RTNL. Convert the mapping lists to RCU-protected pointers, use RCU reader annotations in readers, and defer freeing mapping nodes with an embedded rcu_head. This prepares the egress QoS mapping code for safe removal of mapping nodes in a follow-up change while preserving the current behavior. Co-developed-by: Yuan Tan <yuantan098@gmail.com> Signed-off-by: Yuan Tan <yuantan098@gmail.com> Signed-off-by: Longxuan Yu <ylong030@ucr.edu> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn> Link: https://patch.msgid.link/9136768189f8c6d3f824f476c62d2fa1111688e8.1776647968.git.yuantan098@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 5a5db99 commit fc69dec

4 files changed

Lines changed: 46 additions & 32 deletions

File tree

include/linux/if_vlan.h

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,13 @@ extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
147147
* @priority: skb priority
148148
* @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000
149149
* @next: pointer to next struct
150+
* @rcu: used for deferred freeing of mapping nodes
150151
*/
151152
struct vlan_priority_tci_mapping {
152153
u32 priority;
153154
u16 vlan_qos;
154-
struct vlan_priority_tci_mapping *next;
155+
struct vlan_priority_tci_mapping __rcu *next;
156+
struct rcu_head rcu;
155157
};
156158

157159
struct proc_dir_entry;
@@ -177,7 +179,7 @@ struct vlan_dev_priv {
177179
unsigned int nr_ingress_mappings;
178180
u32 ingress_priority_map[8];
179181
unsigned int nr_egress_mappings;
180-
struct vlan_priority_tci_mapping *egress_priority_map[16];
182+
struct vlan_priority_tci_mapping __rcu *egress_priority_map[16];
181183

182184
__be16 vlan_proto;
183185
u16 vlan_id;
@@ -209,19 +211,24 @@ static inline u16
209211
vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio)
210212
{
211213
struct vlan_priority_tci_mapping *mp;
214+
u16 vlan_qos = 0;
212215

213-
smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */
216+
rcu_read_lock();
214217

215-
mp = vlan_dev_priv(dev)->egress_priority_map[(skprio & 0xF)];
218+
mp = rcu_dereference(vlan_dev_priv(dev)->egress_priority_map[skprio & 0xF]);
216219
while (mp) {
217220
if (mp->priority == skprio) {
218-
return mp->vlan_qos; /* This should already be shifted
219-
* to mask correctly with the
220-
* VLAN's TCI */
221+
vlan_qos = READ_ONCE(mp->vlan_qos);
222+
break;
221223
}
222-
mp = mp->next;
224+
mp = rcu_dereference(mp->next);
223225
}
224-
return 0;
226+
rcu_read_unlock();
227+
228+
/* This should already be shifted to mask correctly with
229+
* the VLAN's TCI.
230+
*/
231+
return vlan_qos;
225232
}
226233

227234
extern bool vlan_do_receive(struct sk_buff **skb);

net/8021q/vlan_dev.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -172,39 +172,34 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
172172
u32 skb_prio, u16 vlan_prio)
173173
{
174174
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
175-
struct vlan_priority_tci_mapping *mp = NULL;
175+
struct vlan_priority_tci_mapping *mp;
176176
struct vlan_priority_tci_mapping *np;
177+
u32 bucket = skb_prio & 0xF;
177178
u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
178179

179180
/* See if a priority mapping exists.. */
180-
mp = vlan->egress_priority_map[skb_prio & 0xF];
181+
mp = rtnl_dereference(vlan->egress_priority_map[bucket]);
181182
while (mp) {
182183
if (mp->priority == skb_prio) {
183184
if (mp->vlan_qos && !vlan_qos)
184185
vlan->nr_egress_mappings--;
185186
else if (!mp->vlan_qos && vlan_qos)
186187
vlan->nr_egress_mappings++;
187-
mp->vlan_qos = vlan_qos;
188+
WRITE_ONCE(mp->vlan_qos, vlan_qos);
188189
return 0;
189190
}
190-
mp = mp->next;
191+
mp = rtnl_dereference(mp->next);
191192
}
192193

193194
/* Create a new mapping then. */
194-
mp = vlan->egress_priority_map[skb_prio & 0xF];
195195
np = kmalloc_obj(struct vlan_priority_tci_mapping);
196196
if (!np)
197197
return -ENOBUFS;
198198

199-
np->next = mp;
200199
np->priority = skb_prio;
201200
np->vlan_qos = vlan_qos;
202-
/* Before inserting this element in hash table, make sure all its fields
203-
* are committed to memory.
204-
* coupled with smp_rmb() in vlan_dev_get_egress_qos_mask()
205-
*/
206-
smp_wmb();
207-
vlan->egress_priority_map[skb_prio & 0xF] = np;
201+
RCU_INIT_POINTER(np->next, rtnl_dereference(vlan->egress_priority_map[bucket]));
202+
rcu_assign_pointer(vlan->egress_priority_map[bucket], np);
208203
if (vlan_qos)
209204
vlan->nr_egress_mappings++;
210205
return 0;
@@ -604,11 +599,17 @@ void vlan_dev_free_egress_priority(const struct net_device *dev)
604599
int i;
605600

606601
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
607-
while ((pm = vlan->egress_priority_map[i]) != NULL) {
608-
vlan->egress_priority_map[i] = pm->next;
609-
kfree(pm);
602+
pm = rtnl_dereference(vlan->egress_priority_map[i]);
603+
RCU_INIT_POINTER(vlan->egress_priority_map[i], NULL);
604+
while (pm) {
605+
struct vlan_priority_tci_mapping *next;
606+
607+
next = rtnl_dereference(pm->next);
608+
kfree_rcu(pm, rcu);
609+
pm = next;
610610
}
611611
}
612+
vlan->nr_egress_mappings = 0;
612613
}
613614

614615
static void vlan_dev_uninit(struct net_device *dev)

net/8021q/vlan_netlink.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,15 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
260260
goto nla_put_failure;
261261

262262
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
263-
for (pm = vlan->egress_priority_map[i]; pm;
264-
pm = pm->next) {
265-
if (!pm->vlan_qos)
263+
for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm;
264+
pm = rcu_dereference_rtnl(pm->next)) {
265+
u16 vlan_qos = READ_ONCE(pm->vlan_qos);
266+
267+
if (!vlan_qos)
266268
continue;
267269

268270
m.from = pm->priority;
269-
m.to = (pm->vlan_qos >> 13) & 0x7;
271+
m.to = (vlan_qos >> 13) & 0x7;
270272
if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
271273
sizeof(m), &m))
272274
goto nla_put_failure;

net/8021q/vlanproc.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,19 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
262262
vlan->ingress_priority_map[7]);
263263

264264
seq_printf(seq, " EGRESS priority mappings: ");
265+
rcu_read_lock();
265266
for (i = 0; i < 16; i++) {
266-
const struct vlan_priority_tci_mapping *mp
267-
= vlan->egress_priority_map[i];
267+
const struct vlan_priority_tci_mapping *mp =
268+
rcu_dereference(vlan->egress_priority_map[i]);
268269
while (mp) {
270+
u16 vlan_qos = READ_ONCE(mp->vlan_qos);
271+
269272
seq_printf(seq, "%u:%d ",
270-
mp->priority, ((mp->vlan_qos >> 13) & 0x7));
271-
mp = mp->next;
273+
mp->priority, ((vlan_qos >> 13) & 0x7));
274+
mp = rcu_dereference(mp->next);
272275
}
273276
}
277+
rcu_read_unlock();
274278
seq_puts(seq, "\n");
275279

276280
return 0;

0 commit comments

Comments
 (0)