1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020, Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
3 #include <linux/kernel.h>
4 #include <linux/netdevice.h>
5 #include <linux/rtnetlink.h>
6 #include <linux/slab.h>
7 #include <net/ip_tunnels.h>
9 #include "br_private.h"
10 #include "br_private_tunnel.h"
12 static bool __vlan_tun_put(struct sk_buff
*skb
, const struct net_bridge_vlan
*v
)
14 __be32 tid
= tunnel_id_to_key32(v
->tinfo
.tunnel_id
);
17 if (!v
->tinfo
.tunnel_dst
)
20 nest
= nla_nest_start(skb
, BRIDGE_VLANDB_ENTRY_TUNNEL_INFO
);
23 if (nla_put_u32(skb
, BRIDGE_VLANDB_TINFO_ID
, be32_to_cpu(tid
))) {
24 nla_nest_cancel(skb
, nest
);
27 nla_nest_end(skb
, nest
);
32 static bool __vlan_tun_can_enter_range(const struct net_bridge_vlan
*v_curr
,
33 const struct net_bridge_vlan
*range_end
)
35 return (!v_curr
->tinfo
.tunnel_dst
&& !range_end
->tinfo
.tunnel_dst
) ||
36 vlan_tunid_inrange(v_curr
, range_end
);
39 /* check if the options' state of v_curr allow it to enter the range */
40 bool br_vlan_opts_eq_range(const struct net_bridge_vlan
*v_curr
,
41 const struct net_bridge_vlan
*range_end
)
43 return v_curr
->state
== range_end
->state
&&
44 __vlan_tun_can_enter_range(v_curr
, range_end
);
47 bool br_vlan_opts_fill(struct sk_buff
*skb
, const struct net_bridge_vlan
*v
)
49 return !nla_put_u8(skb
, BRIDGE_VLANDB_ENTRY_STATE
,
50 br_vlan_get_state(v
)) &&
51 __vlan_tun_put(skb
, v
);
54 size_t br_vlan_opts_nl_size(void)
56 return nla_total_size(sizeof(u8
)) /* BRIDGE_VLANDB_ENTRY_STATE */
57 + nla_total_size(0) /* BRIDGE_VLANDB_ENTRY_TUNNEL_INFO */
58 + nla_total_size(sizeof(u32
)); /* BRIDGE_VLANDB_TINFO_ID */
61 static int br_vlan_modify_state(struct net_bridge_vlan_group
*vg
,
62 struct net_bridge_vlan
*v
,
65 struct netlink_ext_ack
*extack
)
67 struct net_bridge
*br
;
71 if (state
> BR_STATE_BLOCKING
) {
72 NL_SET_ERR_MSG_MOD(extack
, "Invalid vlan state");
76 if (br_vlan_is_brentry(v
))
81 if (br
->stp_enabled
== BR_KERNEL_STP
) {
82 NL_SET_ERR_MSG_MOD(extack
, "Can't modify vlan state when using kernel STP");
86 if (v
->state
== state
)
89 if (v
->vid
== br_get_pvid(vg
))
90 br_vlan_set_pvid_state(vg
, state
);
92 br_vlan_set_state(v
, state
);
98 static const struct nla_policy br_vlandb_tinfo_pol
[BRIDGE_VLANDB_TINFO_MAX
+ 1] = {
99 [BRIDGE_VLANDB_TINFO_ID
] = { .type
= NLA_U32
},
100 [BRIDGE_VLANDB_TINFO_CMD
] = { .type
= NLA_U32
},
103 static int br_vlan_modify_tunnel(const struct net_bridge_port
*p
,
104 struct net_bridge_vlan
*v
,
107 struct netlink_ext_ack
*extack
)
109 struct nlattr
*tun_tb
[BRIDGE_VLANDB_TINFO_MAX
+ 1], *attr
;
110 struct bridge_vlan_info
*vinfo
;
115 NL_SET_ERR_MSG_MOD(extack
, "Can't modify tunnel mapping of non-port vlans");
118 if (!(p
->flags
& BR_VLAN_TUNNEL
)) {
119 NL_SET_ERR_MSG_MOD(extack
, "Port doesn't have tunnel flag set");
123 attr
= tb
[BRIDGE_VLANDB_ENTRY_TUNNEL_INFO
];
124 err
= nla_parse_nested(tun_tb
, BRIDGE_VLANDB_TINFO_MAX
, attr
,
125 br_vlandb_tinfo_pol
, extack
);
129 if (!tun_tb
[BRIDGE_VLANDB_TINFO_CMD
]) {
130 NL_SET_ERR_MSG_MOD(extack
, "Missing tunnel command attribute");
133 cmd
= nla_get_u32(tun_tb
[BRIDGE_VLANDB_TINFO_CMD
]);
136 if (!tun_tb
[BRIDGE_VLANDB_TINFO_ID
]) {
137 NL_SET_ERR_MSG_MOD(extack
, "Missing tunnel id attribute");
140 /* when working on vlan ranges this is the starting tunnel id */
141 tun_id
= nla_get_u32(tun_tb
[BRIDGE_VLANDB_TINFO_ID
]);
142 /* vlan info attr is guaranteed by br_vlan_rtm_process_one */
143 vinfo
= nla_data(tb
[BRIDGE_VLANDB_ENTRY_INFO
]);
144 /* tunnel ids are mapped to each vlan in increasing order,
145 * the starting vlan is in BRIDGE_VLANDB_ENTRY_INFO and v is the
146 * current vlan, so we compute: tun_id + v - vinfo->vid
148 tun_id
+= v
->vid
- vinfo
->vid
;
153 NL_SET_ERR_MSG_MOD(extack
, "Unsupported tunnel command");
157 return br_vlan_tunnel_info(p
, cmd
, v
->vid
, tun_id
, changed
);
160 static int br_vlan_process_one_opts(const struct net_bridge
*br
,
161 const struct net_bridge_port
*p
,
162 struct net_bridge_vlan_group
*vg
,
163 struct net_bridge_vlan
*v
,
166 struct netlink_ext_ack
*extack
)
171 if (tb
[BRIDGE_VLANDB_ENTRY_STATE
]) {
172 u8 state
= nla_get_u8(tb
[BRIDGE_VLANDB_ENTRY_STATE
]);
174 err
= br_vlan_modify_state(vg
, v
, state
, changed
, extack
);
178 if (tb
[BRIDGE_VLANDB_ENTRY_TUNNEL_INFO
]) {
179 err
= br_vlan_modify_tunnel(p
, v
, tb
, changed
, extack
);
187 int br_vlan_process_options(const struct net_bridge
*br
,
188 const struct net_bridge_port
*p
,
189 struct net_bridge_vlan
*range_start
,
190 struct net_bridge_vlan
*range_end
,
192 struct netlink_ext_ack
*extack
)
194 struct net_bridge_vlan
*v
, *curr_start
= NULL
, *curr_end
= NULL
;
195 struct net_bridge_vlan_group
*vg
;
200 vg
= nbp_vlan_group(p
);
202 vg
= br_vlan_group(br
);
204 if (!range_start
|| !br_vlan_should_use(range_start
)) {
205 NL_SET_ERR_MSG_MOD(extack
, "Vlan range start doesn't exist, can't process options");
208 if (!range_end
|| !br_vlan_should_use(range_end
)) {
209 NL_SET_ERR_MSG_MOD(extack
, "Vlan range end doesn't exist, can't process options");
213 pvid
= br_get_pvid(vg
);
214 for (vid
= range_start
->vid
; vid
<= range_end
->vid
; vid
++) {
215 bool changed
= false;
217 v
= br_vlan_find(vg
, vid
);
218 if (!v
|| !br_vlan_should_use(v
)) {
219 NL_SET_ERR_MSG_MOD(extack
, "Vlan in range doesn't exist, can't process options");
224 err
= br_vlan_process_one_opts(br
, p
, vg
, v
, tb
, &changed
,
230 /* vlan options changed, check for range */
237 if (v
->vid
== pvid
||
238 !br_vlan_can_enter_range(v
, curr_end
)) {
239 br_vlan_notify(br
, p
, curr_start
->vid
,
240 curr_end
->vid
, RTM_NEWVLAN
);
245 /* nothing changed and nothing to notify yet */
249 br_vlan_notify(br
, p
, curr_start
->vid
, curr_end
->vid
,
256 br_vlan_notify(br
, p
, curr_start
->vid
, curr_end
->vid
,