1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Bridge per vlan tunnel port dst_metadata netlink control interface
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Authors:
6*4882a593Smuzhiyun * Roopa Prabhu <roopa@cumulusnetworks.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/etherdevice.h>
12*4882a593Smuzhiyun #include <net/rtnetlink.h>
13*4882a593Smuzhiyun #include <net/net_namespace.h>
14*4882a593Smuzhiyun #include <net/sock.h>
15*4882a593Smuzhiyun #include <uapi/linux/if_bridge.h>
16*4882a593Smuzhiyun #include <net/dst_metadata.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "br_private.h"
19*4882a593Smuzhiyun #include "br_private_tunnel.h"
20*4882a593Smuzhiyun
__get_vlan_tinfo_size(void)21*4882a593Smuzhiyun static size_t __get_vlan_tinfo_size(void)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun return nla_total_size(0) + /* nest IFLA_BRIDGE_VLAN_TUNNEL_INFO */
24*4882a593Smuzhiyun nla_total_size(sizeof(u32)) + /* IFLA_BRIDGE_VLAN_TUNNEL_ID */
25*4882a593Smuzhiyun nla_total_size(sizeof(u16)) + /* IFLA_BRIDGE_VLAN_TUNNEL_VID */
26*4882a593Smuzhiyun nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
vlan_tunid_inrange(const struct net_bridge_vlan * v_curr,const struct net_bridge_vlan * v_last)29*4882a593Smuzhiyun bool vlan_tunid_inrange(const struct net_bridge_vlan *v_curr,
30*4882a593Smuzhiyun const struct net_bridge_vlan *v_last)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun __be32 tunid_curr = tunnel_id_to_key32(v_curr->tinfo.tunnel_id);
33*4882a593Smuzhiyun __be32 tunid_last = tunnel_id_to_key32(v_last->tinfo.tunnel_id);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun return (be32_to_cpu(tunid_curr) - be32_to_cpu(tunid_last)) == 1;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
__get_num_vlan_tunnel_infos(struct net_bridge_vlan_group * vg)38*4882a593Smuzhiyun static int __get_num_vlan_tunnel_infos(struct net_bridge_vlan_group *vg)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun struct net_bridge_vlan *v, *vtbegin = NULL, *vtend = NULL;
41*4882a593Smuzhiyun int num_tinfos = 0;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /* Count number of vlan infos */
44*4882a593Smuzhiyun list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
45*4882a593Smuzhiyun /* only a context, bridge vlan not activated */
46*4882a593Smuzhiyun if (!br_vlan_should_use(v) || !v->tinfo.tunnel_id)
47*4882a593Smuzhiyun continue;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (!vtbegin) {
50*4882a593Smuzhiyun goto initvars;
51*4882a593Smuzhiyun } else if ((v->vid - vtend->vid) == 1 &&
52*4882a593Smuzhiyun vlan_tunid_inrange(v, vtend)) {
53*4882a593Smuzhiyun vtend = v;
54*4882a593Smuzhiyun continue;
55*4882a593Smuzhiyun } else {
56*4882a593Smuzhiyun if ((vtend->vid - vtbegin->vid) > 0)
57*4882a593Smuzhiyun num_tinfos += 2;
58*4882a593Smuzhiyun else
59*4882a593Smuzhiyun num_tinfos += 1;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun initvars:
62*4882a593Smuzhiyun vtbegin = v;
63*4882a593Smuzhiyun vtend = v;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (vtbegin && vtend) {
67*4882a593Smuzhiyun if ((vtend->vid - vtbegin->vid) > 0)
68*4882a593Smuzhiyun num_tinfos += 2;
69*4882a593Smuzhiyun else
70*4882a593Smuzhiyun num_tinfos += 1;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun return num_tinfos;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group * vg)76*4882a593Smuzhiyun int br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group *vg)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun int num_tinfos;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (!vg)
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun rcu_read_lock();
84*4882a593Smuzhiyun num_tinfos = __get_num_vlan_tunnel_infos(vg);
85*4882a593Smuzhiyun rcu_read_unlock();
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return num_tinfos * __get_vlan_tinfo_size();
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
br_fill_vlan_tinfo(struct sk_buff * skb,u16 vid,__be64 tunnel_id,u16 flags)90*4882a593Smuzhiyun static int br_fill_vlan_tinfo(struct sk_buff *skb, u16 vid,
91*4882a593Smuzhiyun __be64 tunnel_id, u16 flags)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun __be32 tid = tunnel_id_to_key32(tunnel_id);
94*4882a593Smuzhiyun struct nlattr *tmap;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun tmap = nla_nest_start_noflag(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
97*4882a593Smuzhiyun if (!tmap)
98*4882a593Smuzhiyun return -EMSGSIZE;
99*4882a593Smuzhiyun if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
100*4882a593Smuzhiyun be32_to_cpu(tid)))
101*4882a593Smuzhiyun goto nla_put_failure;
102*4882a593Smuzhiyun if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_VID,
103*4882a593Smuzhiyun vid))
104*4882a593Smuzhiyun goto nla_put_failure;
105*4882a593Smuzhiyun if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
106*4882a593Smuzhiyun flags))
107*4882a593Smuzhiyun goto nla_put_failure;
108*4882a593Smuzhiyun nla_nest_end(skb, tmap);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun nla_put_failure:
113*4882a593Smuzhiyun nla_nest_cancel(skb, tmap);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun return -EMSGSIZE;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
br_fill_vlan_tinfo_range(struct sk_buff * skb,struct net_bridge_vlan * vtbegin,struct net_bridge_vlan * vtend)118*4882a593Smuzhiyun static int br_fill_vlan_tinfo_range(struct sk_buff *skb,
119*4882a593Smuzhiyun struct net_bridge_vlan *vtbegin,
120*4882a593Smuzhiyun struct net_bridge_vlan *vtend)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun int err;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (vtend && (vtend->vid - vtbegin->vid) > 0) {
125*4882a593Smuzhiyun /* add range to skb */
126*4882a593Smuzhiyun err = br_fill_vlan_tinfo(skb, vtbegin->vid,
127*4882a593Smuzhiyun vtbegin->tinfo.tunnel_id,
128*4882a593Smuzhiyun BRIDGE_VLAN_INFO_RANGE_BEGIN);
129*4882a593Smuzhiyun if (err)
130*4882a593Smuzhiyun return err;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun err = br_fill_vlan_tinfo(skb, vtend->vid,
133*4882a593Smuzhiyun vtend->tinfo.tunnel_id,
134*4882a593Smuzhiyun BRIDGE_VLAN_INFO_RANGE_END);
135*4882a593Smuzhiyun if (err)
136*4882a593Smuzhiyun return err;
137*4882a593Smuzhiyun } else {
138*4882a593Smuzhiyun err = br_fill_vlan_tinfo(skb, vtbegin->vid,
139*4882a593Smuzhiyun vtbegin->tinfo.tunnel_id,
140*4882a593Smuzhiyun 0);
141*4882a593Smuzhiyun if (err)
142*4882a593Smuzhiyun return err;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
br_fill_vlan_tunnel_info(struct sk_buff * skb,struct net_bridge_vlan_group * vg)148*4882a593Smuzhiyun int br_fill_vlan_tunnel_info(struct sk_buff *skb,
149*4882a593Smuzhiyun struct net_bridge_vlan_group *vg)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun struct net_bridge_vlan *vtbegin = NULL;
152*4882a593Smuzhiyun struct net_bridge_vlan *vtend = NULL;
153*4882a593Smuzhiyun struct net_bridge_vlan *v;
154*4882a593Smuzhiyun int err;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* Count number of vlan infos */
157*4882a593Smuzhiyun list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
158*4882a593Smuzhiyun /* only a context, bridge vlan not activated */
159*4882a593Smuzhiyun if (!br_vlan_should_use(v))
160*4882a593Smuzhiyun continue;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (!v->tinfo.tunnel_dst)
163*4882a593Smuzhiyun continue;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun if (!vtbegin) {
166*4882a593Smuzhiyun goto initvars;
167*4882a593Smuzhiyun } else if ((v->vid - vtend->vid) == 1 &&
168*4882a593Smuzhiyun vlan_tunid_inrange(v, vtend)) {
169*4882a593Smuzhiyun vtend = v;
170*4882a593Smuzhiyun continue;
171*4882a593Smuzhiyun } else {
172*4882a593Smuzhiyun err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
173*4882a593Smuzhiyun if (err)
174*4882a593Smuzhiyun return err;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun initvars:
177*4882a593Smuzhiyun vtbegin = v;
178*4882a593Smuzhiyun vtend = v;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (vtbegin) {
182*4882a593Smuzhiyun err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
183*4882a593Smuzhiyun if (err)
184*4882a593Smuzhiyun return err;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1] = {
191*4882a593Smuzhiyun [IFLA_BRIDGE_VLAN_TUNNEL_ID] = { .type = NLA_U32 },
192*4882a593Smuzhiyun [IFLA_BRIDGE_VLAN_TUNNEL_VID] = { .type = NLA_U16 },
193*4882a593Smuzhiyun [IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun
br_vlan_tunnel_info(const struct net_bridge_port * p,int cmd,u16 vid,u32 tun_id,bool * changed)196*4882a593Smuzhiyun int br_vlan_tunnel_info(const struct net_bridge_port *p, int cmd,
197*4882a593Smuzhiyun u16 vid, u32 tun_id, bool *changed)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun int err = 0;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun if (!p)
202*4882a593Smuzhiyun return -EINVAL;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun switch (cmd) {
205*4882a593Smuzhiyun case RTM_SETLINK:
206*4882a593Smuzhiyun err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
207*4882a593Smuzhiyun if (!err)
208*4882a593Smuzhiyun *changed = true;
209*4882a593Smuzhiyun break;
210*4882a593Smuzhiyun case RTM_DELLINK:
211*4882a593Smuzhiyun if (!nbp_vlan_tunnel_info_delete(p, vid))
212*4882a593Smuzhiyun *changed = true;
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return err;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
br_parse_vlan_tunnel_info(struct nlattr * attr,struct vtunnel_info * tinfo)219*4882a593Smuzhiyun int br_parse_vlan_tunnel_info(struct nlattr *attr,
220*4882a593Smuzhiyun struct vtunnel_info *tinfo)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct nlattr *tb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
223*4882a593Smuzhiyun u32 tun_id;
224*4882a593Smuzhiyun u16 vid, flags = 0;
225*4882a593Smuzhiyun int err;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun memset(tinfo, 0, sizeof(*tinfo));
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun err = nla_parse_nested_deprecated(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
230*4882a593Smuzhiyun attr, vlan_tunnel_policy, NULL);
231*4882a593Smuzhiyun if (err < 0)
232*4882a593Smuzhiyun return err;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (!tb[IFLA_BRIDGE_VLAN_TUNNEL_ID] ||
235*4882a593Smuzhiyun !tb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
236*4882a593Smuzhiyun return -EINVAL;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun tun_id = nla_get_u32(tb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
239*4882a593Smuzhiyun vid = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
240*4882a593Smuzhiyun if (vid >= VLAN_VID_MASK)
241*4882a593Smuzhiyun return -ERANGE;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
244*4882a593Smuzhiyun flags = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun tinfo->tunid = tun_id;
247*4882a593Smuzhiyun tinfo->vid = vid;
248*4882a593Smuzhiyun tinfo->flags = flags;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun return 0;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /* send a notification if v_curr can't enter the range and start a new one */
__vlan_tunnel_handle_range(const struct net_bridge_port * p,struct net_bridge_vlan ** v_start,struct net_bridge_vlan ** v_end,int v_curr,bool curr_change)254*4882a593Smuzhiyun static void __vlan_tunnel_handle_range(const struct net_bridge_port *p,
255*4882a593Smuzhiyun struct net_bridge_vlan **v_start,
256*4882a593Smuzhiyun struct net_bridge_vlan **v_end,
257*4882a593Smuzhiyun int v_curr, bool curr_change)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun struct net_bridge_vlan_group *vg;
260*4882a593Smuzhiyun struct net_bridge_vlan *v;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun vg = nbp_vlan_group(p);
263*4882a593Smuzhiyun if (!vg)
264*4882a593Smuzhiyun return;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun v = br_vlan_find(vg, v_curr);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun if (!*v_start)
269*4882a593Smuzhiyun goto out_init;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun if (v && curr_change && br_vlan_can_enter_range(v, *v_end)) {
272*4882a593Smuzhiyun *v_end = v;
273*4882a593Smuzhiyun return;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun br_vlan_notify(p->br, p, (*v_start)->vid, (*v_end)->vid, RTM_NEWVLAN);
277*4882a593Smuzhiyun out_init:
278*4882a593Smuzhiyun /* we start a range only if there are any changes to notify about */
279*4882a593Smuzhiyun *v_start = curr_change ? v : NULL;
280*4882a593Smuzhiyun *v_end = *v_start;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
br_process_vlan_tunnel_info(const struct net_bridge * br,const struct net_bridge_port * p,int cmd,struct vtunnel_info * tinfo_curr,struct vtunnel_info * tinfo_last,bool * changed)283*4882a593Smuzhiyun int br_process_vlan_tunnel_info(const struct net_bridge *br,
284*4882a593Smuzhiyun const struct net_bridge_port *p, int cmd,
285*4882a593Smuzhiyun struct vtunnel_info *tinfo_curr,
286*4882a593Smuzhiyun struct vtunnel_info *tinfo_last,
287*4882a593Smuzhiyun bool *changed)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int err;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
292*4882a593Smuzhiyun if (tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
293*4882a593Smuzhiyun return -EINVAL;
294*4882a593Smuzhiyun memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
295*4882a593Smuzhiyun } else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
296*4882a593Smuzhiyun struct net_bridge_vlan *v_start = NULL, *v_end = NULL;
297*4882a593Smuzhiyun int t, v;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
300*4882a593Smuzhiyun return -EINVAL;
301*4882a593Smuzhiyun if ((tinfo_curr->vid - tinfo_last->vid) !=
302*4882a593Smuzhiyun (tinfo_curr->tunid - tinfo_last->tunid))
303*4882a593Smuzhiyun return -EINVAL;
304*4882a593Smuzhiyun t = tinfo_last->tunid;
305*4882a593Smuzhiyun for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
306*4882a593Smuzhiyun bool curr_change = false;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun err = br_vlan_tunnel_info(p, cmd, v, t, &curr_change);
309*4882a593Smuzhiyun if (err)
310*4882a593Smuzhiyun break;
311*4882a593Smuzhiyun t++;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (curr_change)
314*4882a593Smuzhiyun *changed = curr_change;
315*4882a593Smuzhiyun __vlan_tunnel_handle_range(p, &v_start, &v_end, v,
316*4882a593Smuzhiyun curr_change);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun if (v_start && v_end)
319*4882a593Smuzhiyun br_vlan_notify(br, p, v_start->vid, v_end->vid,
320*4882a593Smuzhiyun RTM_NEWVLAN);
321*4882a593Smuzhiyun if (err)
322*4882a593Smuzhiyun return err;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun memset(tinfo_last, 0, sizeof(struct vtunnel_info));
325*4882a593Smuzhiyun memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
326*4882a593Smuzhiyun } else {
327*4882a593Smuzhiyun if (tinfo_last->flags)
328*4882a593Smuzhiyun return -EINVAL;
329*4882a593Smuzhiyun err = br_vlan_tunnel_info(p, cmd, tinfo_curr->vid,
330*4882a593Smuzhiyun tinfo_curr->tunid, changed);
331*4882a593Smuzhiyun if (err)
332*4882a593Smuzhiyun return err;
333*4882a593Smuzhiyun br_vlan_notify(br, p, tinfo_curr->vid, 0, RTM_NEWVLAN);
334*4882a593Smuzhiyun memset(tinfo_last, 0, sizeof(struct vtunnel_info));
335*4882a593Smuzhiyun memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun return 0;
339*4882a593Smuzhiyun }
340