Skip to content

Commit 5b9ea6e

Browse files
Jiri Pirkodavem330
Jiri Pirko
authored andcommitted
vlan: introduce vid list with reference counting
This allows to keep track of vids needed to be in rx vlan filters of devices even if they are used in bond/team etc. vlan_info as well as vlan_group previously was, is allocated when first vid is added and dealocated whan last vid is deleted. vlan_group definition is moved to private header. Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 87002b0 commit 5b9ea6e

File tree

5 files changed

+219
-89
lines changed

5 files changed

+219
-89
lines changed

include/linux/if_vlan.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,7 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
7474
/* found in socket.c */
7575
extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
7676

77-
/* if this changes, algorithm will have to be reworked because this
78-
* depends on completely exhausting the VLAN identifier space. Thus
79-
* it gives constant time look-up, but in many cases it wastes memory.
80-
*/
81-
#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
82-
#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
83-
84-
struct vlan_group {
85-
struct net_device *real_dev; /* The ethernet(like) device
86-
* the vlan is attached to.
87-
*/
88-
unsigned int nr_vlans;
89-
struct hlist_node hlist; /* linked list */
90-
struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS];
91-
struct rcu_head rcu;
92-
};
77+
struct vlan_info;
9378

9479
static inline int is_vlan_dev(struct net_device *dev)
9580
{

include/linux/netdevice.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555

5656
#include <linux/netdev_features.h>
5757

58-
struct vlan_group;
5958
struct netpoll_info;
6059
struct phy_device;
6160
/* 802.11 specific */
@@ -1096,7 +1095,7 @@ struct net_device {
10961095
/* Protocol specific pointers */
10971096

10981097
#if IS_ENABLED(CONFIG_VLAN_8021Q)
1099-
struct vlan_group __rcu *vlgrp; /* VLAN group */
1098+
struct vlan_info __rcu *vlan_info; /* VLAN info */
11001099
#endif
11011100
#if IS_ENABLED(CONFIG_NET_DSA)
11021101
struct dsa_switch_tree *dsa_ptr; /* dsa specific data */

net/8021q/vlan.c

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,6 @@ const char vlan_version[] = DRV_VERSION;
5151

5252
/* End of global variables definitions. */
5353

54-
static void vlan_group_free(struct vlan_group *grp)
55-
{
56-
int i;
57-
58-
for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
59-
kfree(grp->vlan_devices_arrays[i]);
60-
kfree(grp);
61-
}
62-
63-
static struct vlan_group *vlan_group_alloc(struct net_device *real_dev)
64-
{
65-
struct vlan_group *grp;
66-
67-
grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
68-
if (!grp)
69-
return NULL;
70-
71-
grp->real_dev = real_dev;
72-
return grp;
73-
}
74-
7554
static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
7655
{
7756
struct net_device **array;
@@ -92,22 +71,20 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
9271
return 0;
9372
}
9473

95-
static void vlan_rcu_free(struct rcu_head *rcu)
96-
{
97-
vlan_group_free(container_of(rcu, struct vlan_group, rcu));
98-
}
99-
10074
void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
10175
{
10276
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
10377
struct net_device *real_dev = vlan->real_dev;
78+
struct vlan_info *vlan_info;
10479
struct vlan_group *grp;
10580
u16 vlan_id = vlan->vlan_id;
10681

10782
ASSERT_RTNL();
10883

109-
grp = rtnl_dereference(real_dev->vlgrp);
110-
BUG_ON(!grp);
84+
vlan_info = rtnl_dereference(real_dev->vlan_info);
85+
BUG_ON(!vlan_info);
86+
87+
grp = &vlan_info->grp;
11188

11289
/* Take it out of our own structures, but be sure to interlock with
11390
* HW accelerating devices or SW vlan input packet processing if
@@ -116,7 +93,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
11693
if (vlan_id)
11794
vlan_vid_del(real_dev, vlan_id);
11895

119-
grp->nr_vlans--;
96+
grp->nr_vlan_devs--;
12097

12198
if (vlan->flags & VLAN_FLAG_GVRP)
12299
vlan_gvrp_request_leave(dev);
@@ -128,16 +105,9 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
128105
*/
129106
unregister_netdevice_queue(dev, head);
130107

131-
/* If the group is now empty, kill off the group. */
132-
if (grp->nr_vlans == 0) {
108+
if (grp->nr_vlan_devs == 0)
133109
vlan_gvrp_uninit_applicant(real_dev);
134110

135-
RCU_INIT_POINTER(real_dev->vlgrp, NULL);
136-
137-
/* Free the group, after all cpu's are done. */
138-
call_rcu(&grp->rcu, vlan_rcu_free);
139-
}
140-
141111
/* Get rid of the vlan's reference to real_dev */
142112
dev_put(real_dev);
143113
}
@@ -169,17 +139,23 @@ int register_vlan_dev(struct net_device *dev)
169139
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
170140
struct net_device *real_dev = vlan->real_dev;
171141
u16 vlan_id = vlan->vlan_id;
172-
struct vlan_group *grp, *ngrp = NULL;
142+
struct vlan_info *vlan_info;
143+
struct vlan_group *grp;
173144
int err;
174145

175-
grp = rtnl_dereference(real_dev->vlgrp);
176-
if (!grp) {
177-
ngrp = grp = vlan_group_alloc(real_dev);
178-
if (!grp)
179-
return -ENOBUFS;
146+
err = vlan_vid_add(real_dev, vlan_id);
147+
if (err)
148+
return err;
149+
150+
vlan_info = rtnl_dereference(real_dev->vlan_info);
151+
/* vlan_info should be there now. vlan_vid_add took care of it */
152+
BUG_ON(!vlan_info);
153+
154+
grp = &vlan_info->grp;
155+
if (grp->nr_vlan_devs == 0) {
180156
err = vlan_gvrp_init_applicant(real_dev);
181157
if (err < 0)
182-
goto out_free_group;
158+
goto out_vid_del;
183159
}
184160

185161
err = vlan_group_prealloc_vid(grp, vlan_id);
@@ -200,23 +176,15 @@ int register_vlan_dev(struct net_device *dev)
200176
* it into our local structure.
201177
*/
202178
vlan_group_set_device(grp, vlan_id, dev);
203-
grp->nr_vlans++;
204-
205-
if (ngrp) {
206-
rcu_assign_pointer(real_dev->vlgrp, ngrp);
207-
}
208-
vlan_vid_add(real_dev, vlan_id);
179+
grp->nr_vlan_devs++;
209180

210181
return 0;
211182

212183
out_uninit_applicant:
213-
if (ngrp)
184+
if (grp->nr_vlan_devs == 0)
214185
vlan_gvrp_uninit_applicant(real_dev);
215-
out_free_group:
216-
if (ngrp) {
217-
/* Free the group, after all cpu's are done. */
218-
call_rcu(&ngrp->rcu, vlan_rcu_free);
219-
}
186+
out_vid_del:
187+
vlan_vid_del(real_dev, vlan_id);
220188
return err;
221189
}
222190

@@ -357,6 +325,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
357325
{
358326
struct net_device *dev = ptr;
359327
struct vlan_group *grp;
328+
struct vlan_info *vlan_info;
360329
int i, flgs;
361330
struct net_device *vlandev;
362331
struct vlan_dev_priv *vlan;
@@ -372,9 +341,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
372341
vlan_vid_add(dev, 0);
373342
}
374343

375-
grp = rtnl_dereference(dev->vlgrp);
376-
if (!grp)
344+
vlan_info = rtnl_dereference(dev->vlan_info);
345+
if (!vlan_info)
377346
goto out;
347+
grp = &vlan_info->grp;
378348

379349
/* It is OK that we do not hold the group lock right now,
380350
* as we run under the RTNL lock.
@@ -478,9 +448,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
478448
if (!vlandev)
479449
continue;
480450

481-
/* unregistration of last vlan destroys group, abort
451+
/* removal of last vid destroys vlan_info, abort
482452
* afterwards */
483-
if (grp->nr_vlans == 1)
453+
if (vlan_info->nr_vids == 1)
484454
i = VLAN_N_VID;
485455

486456
unregister_vlan_dev(vlandev, &list);

net/8021q/vlan.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/if_vlan.h>
55
#include <linux/u64_stats_sync.h>
6+
#include <linux/list.h>
67

78

89
/**
@@ -74,6 +75,29 @@ static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)
7475
return netdev_priv(dev);
7576
}
7677

78+
/* if this changes, algorithm will have to be reworked because this
79+
* depends on completely exhausting the VLAN identifier space. Thus
80+
* it gives constant time look-up, but in many cases it wastes memory.
81+
*/
82+
#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
83+
#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
84+
85+
struct vlan_group {
86+
unsigned int nr_vlan_devs;
87+
struct hlist_node hlist; /* linked list */
88+
struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS];
89+
};
90+
91+
struct vlan_info {
92+
struct net_device *real_dev; /* The ethernet(like) device
93+
* the vlan is attached to.
94+
*/
95+
struct vlan_group grp;
96+
struct list_head vid_list;
97+
unsigned int nr_vids;
98+
struct rcu_head rcu;
99+
};
100+
77101
static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
78102
u16 vlan_id)
79103
{
@@ -97,10 +121,10 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
97121
static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
98122
u16 vlan_id)
99123
{
100-
struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
124+
struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info);
101125

102-
if (grp)
103-
return vlan_group_get_device(grp, vlan_id);
126+
if (vlan_info)
127+
return vlan_group_get_device(&vlan_info->grp, vlan_id);
104128

105129
return NULL;
106130
}

0 commit comments

Comments
 (0)