Skip to content

Commit 743a53d

Browse files
Nikolay Aleksandrovdavem330
authored andcommitted
net: bridge: vlan: add support for dumping global vlan options
Add a new vlan options dump flag which causes only global vlan options to be dumped. The dumps are done only with bridge devices, ports are ignored. They support vlan compression if the options in sequential vlans are equal (currently always true). Signed-off-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 47ecd2d commit 743a53d

File tree

4 files changed

+69
-8
lines changed

4 files changed

+69
-8
lines changed

include/uapi/linux/if_bridge.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ enum {
479479

480480
/* flags used in BRIDGE_VLANDB_DUMP_FLAGS attribute to affect dumps */
481481
#define BRIDGE_VLANDB_DUMPF_STATS (1 << 0) /* Include stats in the dump */
482+
#define BRIDGE_VLANDB_DUMPF_GLOBAL (1 << 1) /* Dump global vlan options only */
482483

483484
/* Bridge vlan RTM attributes
484485
* [BRIDGE_VLANDB_ENTRY] = {

net/bridge/br_private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,10 @@ int br_vlan_rtm_process_global_options(struct net_device *dev,
15961596
const struct nlattr *attr,
15971597
int cmd,
15981598
struct netlink_ext_ack *extack);
1599+
bool br_vlan_global_opts_can_enter_range(const struct net_bridge_vlan *v_curr,
1600+
const struct net_bridge_vlan *r_end);
1601+
bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range,
1602+
const struct net_bridge_vlan *v_opts);
15991603

16001604
/* vlan state manipulation helpers using *_ONCE to annotate lock-free access */
16011605
static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)

net/bridge/br_vlan.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,6 +1919,7 @@ static int br_vlan_dump_dev(const struct net_device *dev,
19191919
u32 dump_flags)
19201920
{
19211921
struct net_bridge_vlan *v, *range_start = NULL, *range_end = NULL;
1922+
bool dump_global = !!(dump_flags & BRIDGE_VLANDB_DUMPF_GLOBAL);
19221923
bool dump_stats = !!(dump_flags & BRIDGE_VLANDB_DUMPF_STATS);
19231924
struct net_bridge_vlan_group *vg;
19241925
int idx = 0, s_idx = cb->args[1];
@@ -1937,6 +1938,10 @@ static int br_vlan_dump_dev(const struct net_device *dev,
19371938
vg = br_vlan_group_rcu(br);
19381939
p = NULL;
19391940
} else {
1941+
/* global options are dumped only for bridge devices */
1942+
if (dump_global)
1943+
return 0;
1944+
19401945
p = br_port_get_rcu(dev);
19411946
if (WARN_ON(!p))
19421947
return -EINVAL;
@@ -1959,7 +1964,7 @@ static int br_vlan_dump_dev(const struct net_device *dev,
19591964

19601965
/* idx must stay at range's beginning until it is filled in */
19611966
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
1962-
if (!br_vlan_should_use(v))
1967+
if (!dump_global && !br_vlan_should_use(v))
19631968
continue;
19641969
if (idx < s_idx) {
19651970
idx++;
@@ -1972,8 +1977,21 @@ static int br_vlan_dump_dev(const struct net_device *dev,
19721977
continue;
19731978
}
19741979

1975-
if (dump_stats || v->vid == pvid ||
1976-
!br_vlan_can_enter_range(v, range_end)) {
1980+
if (dump_global) {
1981+
if (br_vlan_global_opts_can_enter_range(v, range_end))
1982+
continue;
1983+
if (!br_vlan_global_opts_fill(skb, range_start->vid,
1984+
range_end->vid,
1985+
range_start)) {
1986+
err = -EMSGSIZE;
1987+
break;
1988+
}
1989+
/* advance number of filled vlans */
1990+
idx += range_end->vid - range_start->vid + 1;
1991+
1992+
range_start = v;
1993+
} else if (dump_stats || v->vid == pvid ||
1994+
!br_vlan_can_enter_range(v, range_end)) {
19771995
u16 vlan_flags = br_vlan_flags(range_start, pvid);
19781996

19791997
if (!br_vlan_fill_vids(skb, range_start->vid,
@@ -1995,11 +2013,18 @@ static int br_vlan_dump_dev(const struct net_device *dev,
19952013
* - last vlan (range_start == range_end, not in range)
19962014
* - last vlan range (range_start != range_end, in range)
19972015
*/
1998-
if (!err && range_start &&
1999-
!br_vlan_fill_vids(skb, range_start->vid, range_end->vid,
2000-
range_start, br_vlan_flags(range_start, pvid),
2001-
dump_stats))
2002-
err = -EMSGSIZE;
2016+
if (!err && range_start) {
2017+
if (dump_global &&
2018+
!br_vlan_global_opts_fill(skb, range_start->vid,
2019+
range_end->vid, range_start))
2020+
err = -EMSGSIZE;
2021+
else if (!dump_global &&
2022+
!br_vlan_fill_vids(skb, range_start->vid,
2023+
range_end->vid, range_start,
2024+
br_vlan_flags(range_start, pvid),
2025+
dump_stats))
2026+
err = -EMSGSIZE;
2027+
}
20032028

20042029
cb->args[1] = err ? idx : 0;
20052030

net/bridge/br_vlan_options.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,37 @@ int br_vlan_process_options(const struct net_bridge *br,
259259
return err;
260260
}
261261

262+
bool br_vlan_global_opts_can_enter_range(const struct net_bridge_vlan *v_curr,
263+
const struct net_bridge_vlan *r_end)
264+
{
265+
return v_curr->vid - r_end->vid == 1;
266+
}
267+
268+
bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range,
269+
const struct net_bridge_vlan *v_opts)
270+
{
271+
struct nlattr *nest;
272+
273+
nest = nla_nest_start(skb, BRIDGE_VLANDB_GLOBAL_OPTIONS);
274+
if (!nest)
275+
return false;
276+
277+
if (nla_put_u16(skb, BRIDGE_VLANDB_GOPTS_ID, vid))
278+
goto out_err;
279+
280+
if (vid_range && vid < vid_range &&
281+
nla_put_u16(skb, BRIDGE_VLANDB_GOPTS_RANGE, vid_range))
282+
goto out_err;
283+
284+
nla_nest_end(skb, nest);
285+
286+
return true;
287+
288+
out_err:
289+
nla_nest_cancel(skb, nest);
290+
return false;
291+
}
292+
262293
static int br_vlan_process_global_one_opts(const struct net_bridge *br,
263294
struct net_bridge_vlan_group *vg,
264295
struct net_bridge_vlan *v,

0 commit comments

Comments
 (0)