Skip to content

Commit 23f4eac

Browse files
committed
Merge branch 'net-bridge-add-per-vlan-state-option'
Nikolay Aleksandrov says: ==================== net: bridge: add per-vlan state option This set adds the first per-vlan option - state, which uses the new vlan infrastructure that was recently added. It gives us forwarding control on per-vlan basis. The first 3 patches prepare the vlan code to support option dumping and modification. We still compress vlan ranges which have equal options, each new option will have to add its own equality check to br_vlan_opts_eq(). The vlans are created in forwarding state by default to be backwards compatible and vlan state is considered only when the port state is forwarding (more info in patch 4). I'll send the selftest for the vlan state with the iproute2 patch-set. v2: patch 3: do full (all-vlan) notification only on vlan create/delete, otherwise use the per-vlan notifications only, rework how option change ranges are detected, add more verbose error messages when setting options and add checks if a vlan should be used. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 9bbc8be + a580c76 commit 23f4eac

File tree

8 files changed

+311
-32
lines changed

8 files changed

+311
-32
lines changed

include/uapi/linux/if_bridge.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ enum {
130130
#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
131131
#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
132132
#define BRIDGE_VLAN_INFO_BRENTRY (1<<5) /* Global bridge VLAN entry */
133+
#define BRIDGE_VLAN_INFO_ONLY_OPTS (1<<6) /* Skip create/delete/flags */
133134

134135
struct bridge_vlan_info {
135136
__u16 flags;
@@ -190,6 +191,7 @@ enum {
190191
BRIDGE_VLANDB_ENTRY_UNSPEC,
191192
BRIDGE_VLANDB_ENTRY_INFO,
192193
BRIDGE_VLANDB_ENTRY_RANGE,
194+
BRIDGE_VLANDB_ENTRY_STATE,
193195
__BRIDGE_VLANDB_ENTRY_MAX,
194196
};
195197
#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)

net/bridge/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
2020

2121
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
2222

23-
bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o br_vlan_tunnel.o
23+
bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o br_vlan_tunnel.o br_vlan_options.o
2424

2525
bridge-$(CONFIG_NET_SWITCHDEV) += br_switchdev.o
2626

net/bridge/br_device.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
3232
struct net_bridge_mdb_entry *mdst;
3333
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
3434
const struct nf_br_ops *nf_ops;
35+
u8 state = BR_STATE_FORWARDING;
3536
const unsigned char *dest;
3637
struct ethhdr *eth;
3738
u16 vid = 0;
@@ -56,7 +57,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
5657
eth = eth_hdr(skb);
5758
skb_pull(skb, ETH_HLEN);
5859

59-
if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid))
60+
if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid, &state))
6061
goto out;
6162

6263
if (IS_ENABLED(CONFIG_INET) &&

net/bridge/br_forward.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static inline int should_deliver(const struct net_bridge_port *p,
2525

2626
vg = nbp_vlan_group_rcu(p);
2727
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
28-
br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
28+
p->state == BR_STATE_FORWARDING && br_allowed_egress(vg, skb) &&
2929
nbp_switchdev_allowed_egress(p, skb) &&
3030
!br_skb_isolated(p, skb);
3131
}

net/bridge/br_input.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,14 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
7676
bool local_rcv, mcast_hit = false;
7777
struct net_bridge *br;
7878
u16 vid = 0;
79+
u8 state;
7980

8081
if (!p || p->state == BR_STATE_DISABLED)
8182
goto drop;
8283

83-
if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid))
84+
state = p->state;
85+
if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid,
86+
&state))
8487
goto out;
8588

8689
nbp_switchdev_frame_mark(p, skb);
@@ -103,7 +106,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
103106
}
104107
}
105108

106-
if (p->state == BR_STATE_LEARNING)
109+
if (state == BR_STATE_LEARNING)
107110
goto drop;
108111

109112
BR_INPUT_SKB_CB(skb)->brdev = br->dev;

net/bridge/br_private.h

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ enum {
113113
* @vid: VLAN id
114114
* @flags: bridge vlan flags
115115
* @priv_flags: private (in-kernel) bridge vlan flags
116+
* @state: STP state (e.g. blocking, learning, forwarding)
116117
* @stats: per-cpu VLAN statistics
117118
* @br: if MASTER flag set, this points to a bridge struct
118119
* @port: if MASTER flag unset, this points to a port struct
@@ -133,6 +134,7 @@ struct net_bridge_vlan {
133134
u16 vid;
134135
u16 flags;
135136
u16 priv_flags;
137+
u8 state;
136138
struct br_vlan_stats __percpu *stats;
137139
union {
138140
struct net_bridge *br;
@@ -157,6 +159,7 @@ struct net_bridge_vlan {
157159
* @vlan_list: sorted VLAN entry list
158160
* @num_vlans: number of total VLAN entries
159161
* @pvid: PVID VLAN id
162+
* @pvid_state: PVID's STP state (e.g. forwarding, learning, blocking)
160163
*
161164
* IMPORTANT: Be careful when checking if there're VLAN entries using list
162165
* primitives because the bridge can have entries in its list which
@@ -170,6 +173,7 @@ struct net_bridge_vlan_group {
170173
struct list_head vlan_list;
171174
u16 num_vlans;
172175
u16 pvid;
176+
u8 pvid_state;
173177
};
174178

175179
/* bridge fdb flags */
@@ -935,7 +939,7 @@ static inline int br_multicast_igmp_type(const struct sk_buff *skb)
935939
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
936940
bool br_allowed_ingress(const struct net_bridge *br,
937941
struct net_bridge_vlan_group *vg, struct sk_buff *skb,
938-
u16 *vid);
942+
u16 *vid, u8 *state);
939943
bool br_allowed_egress(struct net_bridge_vlan_group *vg,
940944
const struct sk_buff *skb);
941945
bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid);
@@ -976,6 +980,8 @@ void br_vlan_notify(const struct net_bridge *br,
976980
const struct net_bridge_port *p,
977981
u16 vid, u16 vid_range,
978982
int cmd);
983+
bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
984+
const struct net_bridge_vlan *range_end);
979985

980986
static inline struct net_bridge_vlan_group *br_vlan_group(
981987
const struct net_bridge *br)
@@ -1035,7 +1041,7 @@ static inline u16 br_vlan_flags(const struct net_bridge_vlan *v, u16 pvid)
10351041
static inline bool br_allowed_ingress(const struct net_bridge *br,
10361042
struct net_bridge_vlan_group *vg,
10371043
struct sk_buff *skb,
1038-
u16 *vid)
1044+
u16 *vid, u8 *state)
10391045
{
10401046
return true;
10411047
}
@@ -1191,6 +1197,55 @@ static inline void br_vlan_notify(const struct net_bridge *br,
11911197
}
11921198
#endif
11931199

1200+
/* br_vlan_options.c */
1201+
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
1202+
bool br_vlan_opts_eq(const struct net_bridge_vlan *v1,
1203+
const struct net_bridge_vlan *v2);
1204+
bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v);
1205+
size_t br_vlan_opts_nl_size(void);
1206+
int br_vlan_process_options(const struct net_bridge *br,
1207+
const struct net_bridge_port *p,
1208+
struct net_bridge_vlan *range_start,
1209+
struct net_bridge_vlan *range_end,
1210+
struct nlattr **tb,
1211+
struct netlink_ext_ack *extack);
1212+
1213+
/* vlan state manipulation helpers using *_ONCE to annotate lock-free access */
1214+
static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)
1215+
{
1216+
return READ_ONCE(v->state);
1217+
}
1218+
1219+
static inline void br_vlan_set_state(struct net_bridge_vlan *v, u8 state)
1220+
{
1221+
WRITE_ONCE(v->state, state);
1222+
}
1223+
1224+
static inline u8 br_vlan_get_pvid_state(const struct net_bridge_vlan_group *vg)
1225+
{
1226+
return READ_ONCE(vg->pvid_state);
1227+
}
1228+
1229+
static inline void br_vlan_set_pvid_state(struct net_bridge_vlan_group *vg,
1230+
u8 state)
1231+
{
1232+
WRITE_ONCE(vg->pvid_state, state);
1233+
}
1234+
1235+
/* learn_allow is true at ingress and false at egress */
1236+
static inline bool br_vlan_state_allowed(u8 state, bool learn_allow)
1237+
{
1238+
switch (state) {
1239+
case BR_STATE_LEARNING:
1240+
return learn_allow;
1241+
case BR_STATE_FORWARDING:
1242+
return true;
1243+
default:
1244+
return false;
1245+
}
1246+
}
1247+
#endif
1248+
11941249
struct nf_br_ops {
11951250
int (*br_dev_xmit_hook)(struct sk_buff *skb);
11961251
};

0 commit comments

Comments
 (0)