12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2efa5356bSRoopa Prabhu /*
3efa5356bSRoopa Prabhu  *	Bridge per vlan tunnel port dst_metadata netlink control interface
4efa5356bSRoopa Prabhu  *
5efa5356bSRoopa Prabhu  *	Authors:
6efa5356bSRoopa Prabhu  *	Roopa Prabhu		<roopa@cumulusnetworks.com>
7efa5356bSRoopa Prabhu  */
8efa5356bSRoopa Prabhu 
9efa5356bSRoopa Prabhu #include <linux/kernel.h>
10efa5356bSRoopa Prabhu #include <linux/slab.h>
11efa5356bSRoopa Prabhu #include <linux/etherdevice.h>
12efa5356bSRoopa Prabhu #include <net/rtnetlink.h>
13efa5356bSRoopa Prabhu #include <net/net_namespace.h>
14efa5356bSRoopa Prabhu #include <net/sock.h>
15efa5356bSRoopa Prabhu #include <uapi/linux/if_bridge.h>
16efa5356bSRoopa Prabhu #include <net/dst_metadata.h>
17efa5356bSRoopa Prabhu 
18efa5356bSRoopa Prabhu #include "br_private.h"
19efa5356bSRoopa Prabhu #include "br_private_tunnel.h"
20efa5356bSRoopa Prabhu 
21efa5356bSRoopa Prabhu static size_t __get_vlan_tinfo_size(void)
22efa5356bSRoopa Prabhu {
23efa5356bSRoopa Prabhu 	return nla_total_size(0) + /* nest IFLA_BRIDGE_VLAN_TUNNEL_INFO */
24efa5356bSRoopa Prabhu 		  nla_total_size(sizeof(u32)) + /* IFLA_BRIDGE_VLAN_TUNNEL_ID */
25efa5356bSRoopa Prabhu 		  nla_total_size(sizeof(u16)) + /* IFLA_BRIDGE_VLAN_TUNNEL_VID */
26efa5356bSRoopa Prabhu 		  nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
27efa5356bSRoopa Prabhu }
28efa5356bSRoopa Prabhu 
298ef95947SRoopa Prabhu static bool vlan_tunid_inrange(struct net_bridge_vlan *v_curr,
308ef95947SRoopa Prabhu 			       struct net_bridge_vlan *v_last)
31efa5356bSRoopa Prabhu {
328ef95947SRoopa Prabhu 	__be32 tunid_curr = tunnel_id_to_key32(v_curr->tinfo.tunnel_id);
338ef95947SRoopa Prabhu 	__be32 tunid_last = tunnel_id_to_key32(v_last->tinfo.tunnel_id);
34efa5356bSRoopa Prabhu 
358ef95947SRoopa Prabhu 	return (be32_to_cpu(tunid_curr) - be32_to_cpu(tunid_last)) == 1;
36efa5356bSRoopa Prabhu }
37efa5356bSRoopa Prabhu 
38efa5356bSRoopa Prabhu static int __get_num_vlan_tunnel_infos(struct net_bridge_vlan_group *vg)
39efa5356bSRoopa Prabhu {
408ef95947SRoopa Prabhu 	struct net_bridge_vlan *v, *vtbegin = NULL, *vtend = NULL;
41efa5356bSRoopa Prabhu 	int num_tinfos = 0;
42efa5356bSRoopa Prabhu 
43efa5356bSRoopa Prabhu 	/* Count number of vlan infos */
44efa5356bSRoopa Prabhu 	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
45efa5356bSRoopa Prabhu 		/* only a context, bridge vlan not activated */
46efa5356bSRoopa Prabhu 		if (!br_vlan_should_use(v) || !v->tinfo.tunnel_id)
47efa5356bSRoopa Prabhu 			continue;
48efa5356bSRoopa Prabhu 
498ef95947SRoopa Prabhu 		if (!vtbegin) {
50efa5356bSRoopa Prabhu 			goto initvars;
518ef95947SRoopa Prabhu 		} else if ((v->vid - vtend->vid) == 1 &&
528ef95947SRoopa Prabhu 			   vlan_tunid_inrange(v, vtend)) {
538ef95947SRoopa Prabhu 			vtend = v;
54efa5356bSRoopa Prabhu 			continue;
55efa5356bSRoopa Prabhu 		} else {
568ef95947SRoopa Prabhu 			if ((vtend->vid - vtbegin->vid) > 0)
57efa5356bSRoopa Prabhu 				num_tinfos += 2;
58efa5356bSRoopa Prabhu 			else
59efa5356bSRoopa Prabhu 				num_tinfos += 1;
60efa5356bSRoopa Prabhu 		}
61efa5356bSRoopa Prabhu initvars:
628ef95947SRoopa Prabhu 		vtbegin = v;
638ef95947SRoopa Prabhu 		vtend = v;
64efa5356bSRoopa Prabhu 	}
65efa5356bSRoopa Prabhu 
668ef95947SRoopa Prabhu 	if (vtbegin && vtend) {
678ef95947SRoopa Prabhu 		if ((vtend->vid - vtbegin->vid) > 0)
68efa5356bSRoopa Prabhu 			num_tinfos += 2;
69efa5356bSRoopa Prabhu 		else
70efa5356bSRoopa Prabhu 			num_tinfos += 1;
71efa5356bSRoopa Prabhu 	}
72efa5356bSRoopa Prabhu 
73efa5356bSRoopa Prabhu 	return num_tinfos;
74efa5356bSRoopa Prabhu }
75efa5356bSRoopa Prabhu 
76efa5356bSRoopa Prabhu int br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group *vg)
77efa5356bSRoopa Prabhu {
78efa5356bSRoopa Prabhu 	int num_tinfos;
79efa5356bSRoopa Prabhu 
80efa5356bSRoopa Prabhu 	if (!vg)
81efa5356bSRoopa Prabhu 		return 0;
82efa5356bSRoopa Prabhu 
83efa5356bSRoopa Prabhu 	rcu_read_lock();
84efa5356bSRoopa Prabhu 	num_tinfos = __get_num_vlan_tunnel_infos(vg);
85efa5356bSRoopa Prabhu 	rcu_read_unlock();
86efa5356bSRoopa Prabhu 
87efa5356bSRoopa Prabhu 	return num_tinfos * __get_vlan_tinfo_size();
88efa5356bSRoopa Prabhu }
89efa5356bSRoopa Prabhu 
90efa5356bSRoopa Prabhu static int br_fill_vlan_tinfo(struct sk_buff *skb, u16 vid,
91efa5356bSRoopa Prabhu 			      __be64 tunnel_id, u16 flags)
92efa5356bSRoopa Prabhu {
93efa5356bSRoopa Prabhu 	__be32 tid = tunnel_id_to_key32(tunnel_id);
94efa5356bSRoopa Prabhu 	struct nlattr *tmap;
95efa5356bSRoopa Prabhu 
96ae0be8deSMichal Kubecek 	tmap = nla_nest_start_noflag(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
97efa5356bSRoopa Prabhu 	if (!tmap)
98efa5356bSRoopa Prabhu 		return -EMSGSIZE;
99efa5356bSRoopa Prabhu 	if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
100efa5356bSRoopa Prabhu 			be32_to_cpu(tid)))
101efa5356bSRoopa Prabhu 		goto nla_put_failure;
102efa5356bSRoopa Prabhu 	if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_VID,
103efa5356bSRoopa Prabhu 			vid))
104efa5356bSRoopa Prabhu 		goto nla_put_failure;
105efa5356bSRoopa Prabhu 	if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
106efa5356bSRoopa Prabhu 			flags))
107efa5356bSRoopa Prabhu 		goto nla_put_failure;
108efa5356bSRoopa Prabhu 	nla_nest_end(skb, tmap);
109efa5356bSRoopa Prabhu 
110efa5356bSRoopa Prabhu 	return 0;
111efa5356bSRoopa Prabhu 
112efa5356bSRoopa Prabhu nla_put_failure:
113efa5356bSRoopa Prabhu 	nla_nest_cancel(skb, tmap);
114efa5356bSRoopa Prabhu 
115efa5356bSRoopa Prabhu 	return -EMSGSIZE;
116efa5356bSRoopa Prabhu }
117efa5356bSRoopa Prabhu 
118efa5356bSRoopa Prabhu static int br_fill_vlan_tinfo_range(struct sk_buff *skb,
119efa5356bSRoopa Prabhu 				    struct net_bridge_vlan *vtbegin,
120efa5356bSRoopa Prabhu 				    struct net_bridge_vlan *vtend)
121efa5356bSRoopa Prabhu {
122efa5356bSRoopa Prabhu 	int err;
123efa5356bSRoopa Prabhu 
124a8cab863SRoopa Prabhu 	if (vtend && (vtend->vid - vtbegin->vid) > 0) {
125efa5356bSRoopa Prabhu 		/* add range to skb */
126efa5356bSRoopa Prabhu 		err = br_fill_vlan_tinfo(skb, vtbegin->vid,
127efa5356bSRoopa Prabhu 					 vtbegin->tinfo.tunnel_id,
128efa5356bSRoopa Prabhu 					 BRIDGE_VLAN_INFO_RANGE_BEGIN);
129efa5356bSRoopa Prabhu 		if (err)
130efa5356bSRoopa Prabhu 			return err;
131efa5356bSRoopa Prabhu 
132efa5356bSRoopa Prabhu 		err = br_fill_vlan_tinfo(skb, vtend->vid,
133efa5356bSRoopa Prabhu 					 vtend->tinfo.tunnel_id,
134efa5356bSRoopa Prabhu 					 BRIDGE_VLAN_INFO_RANGE_END);
135efa5356bSRoopa Prabhu 		if (err)
136efa5356bSRoopa Prabhu 			return err;
137efa5356bSRoopa Prabhu 	} else {
138efa5356bSRoopa Prabhu 		err = br_fill_vlan_tinfo(skb, vtbegin->vid,
139efa5356bSRoopa Prabhu 					 vtbegin->tinfo.tunnel_id,
140efa5356bSRoopa Prabhu 					 0);
141efa5356bSRoopa Prabhu 		if (err)
142efa5356bSRoopa Prabhu 			return err;
143efa5356bSRoopa Prabhu 	}
144efa5356bSRoopa Prabhu 
145efa5356bSRoopa Prabhu 	return 0;
146efa5356bSRoopa Prabhu }
147efa5356bSRoopa Prabhu 
148efa5356bSRoopa Prabhu int br_fill_vlan_tunnel_info(struct sk_buff *skb,
149efa5356bSRoopa Prabhu 			     struct net_bridge_vlan_group *vg)
150efa5356bSRoopa Prabhu {
151efa5356bSRoopa Prabhu 	struct net_bridge_vlan *vtbegin = NULL;
152efa5356bSRoopa Prabhu 	struct net_bridge_vlan *vtend = NULL;
153efa5356bSRoopa Prabhu 	struct net_bridge_vlan *v;
154efa5356bSRoopa Prabhu 	int err;
155efa5356bSRoopa Prabhu 
156efa5356bSRoopa Prabhu 	/* Count number of vlan infos */
157efa5356bSRoopa Prabhu 	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
158efa5356bSRoopa Prabhu 		/* only a context, bridge vlan not activated */
159efa5356bSRoopa Prabhu 		if (!br_vlan_should_use(v))
160efa5356bSRoopa Prabhu 			continue;
161efa5356bSRoopa Prabhu 
162efa5356bSRoopa Prabhu 		if (!v->tinfo.tunnel_dst)
163efa5356bSRoopa Prabhu 			continue;
164efa5356bSRoopa Prabhu 
165efa5356bSRoopa Prabhu 		if (!vtbegin) {
166efa5356bSRoopa Prabhu 			goto initvars;
167efa5356bSRoopa Prabhu 		} else if ((v->vid - vtend->vid) == 1 &&
1688ef95947SRoopa Prabhu 			    vlan_tunid_inrange(v, vtend)) {
169efa5356bSRoopa Prabhu 			vtend = v;
170efa5356bSRoopa Prabhu 			continue;
171efa5356bSRoopa Prabhu 		} else {
172efa5356bSRoopa Prabhu 			err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
173efa5356bSRoopa Prabhu 			if (err)
174efa5356bSRoopa Prabhu 				return err;
175efa5356bSRoopa Prabhu 		}
176efa5356bSRoopa Prabhu initvars:
177efa5356bSRoopa Prabhu 		vtbegin = v;
178efa5356bSRoopa Prabhu 		vtend = v;
179efa5356bSRoopa Prabhu 	}
180efa5356bSRoopa Prabhu 
181efa5356bSRoopa Prabhu 	if (vtbegin) {
182efa5356bSRoopa Prabhu 		err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
183efa5356bSRoopa Prabhu 		if (err)
184efa5356bSRoopa Prabhu 			return err;
185efa5356bSRoopa Prabhu 	}
186efa5356bSRoopa Prabhu 
187efa5356bSRoopa Prabhu 	return 0;
188efa5356bSRoopa Prabhu }
189efa5356bSRoopa Prabhu 
190efa5356bSRoopa Prabhu static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1] = {
191efa5356bSRoopa Prabhu 	[IFLA_BRIDGE_VLAN_TUNNEL_ID] = { .type = NLA_U32 },
192efa5356bSRoopa Prabhu 	[IFLA_BRIDGE_VLAN_TUNNEL_VID] = { .type = NLA_U16 },
193efa5356bSRoopa Prabhu 	[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
194efa5356bSRoopa Prabhu };
195efa5356bSRoopa Prabhu 
196efa5356bSRoopa Prabhu static int br_vlan_tunnel_info(struct net_bridge_port *p, int cmd,
197e19b42a1SNikolay Aleksandrov 			       u16 vid, u32 tun_id, bool *changed)
198efa5356bSRoopa Prabhu {
199efa5356bSRoopa Prabhu 	int err = 0;
200efa5356bSRoopa Prabhu 
201efa5356bSRoopa Prabhu 	if (!p)
202efa5356bSRoopa Prabhu 		return -EINVAL;
203efa5356bSRoopa Prabhu 
204efa5356bSRoopa Prabhu 	switch (cmd) {
205efa5356bSRoopa Prabhu 	case RTM_SETLINK:
206efa5356bSRoopa Prabhu 		err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
207e19b42a1SNikolay Aleksandrov 		if (!err)
208e19b42a1SNikolay Aleksandrov 			*changed = true;
209efa5356bSRoopa Prabhu 		break;
210efa5356bSRoopa Prabhu 	case RTM_DELLINK:
211e19b42a1SNikolay Aleksandrov 		if (!nbp_vlan_tunnel_info_delete(p, vid))
212e19b42a1SNikolay Aleksandrov 			*changed = true;
213efa5356bSRoopa Prabhu 		break;
214efa5356bSRoopa Prabhu 	}
215efa5356bSRoopa Prabhu 
216efa5356bSRoopa Prabhu 	return err;
217efa5356bSRoopa Prabhu }
218efa5356bSRoopa Prabhu 
219efa5356bSRoopa Prabhu int br_parse_vlan_tunnel_info(struct nlattr *attr,
220efa5356bSRoopa Prabhu 			      struct vtunnel_info *tinfo)
221efa5356bSRoopa Prabhu {
222efa5356bSRoopa Prabhu 	struct nlattr *tb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
223efa5356bSRoopa Prabhu 	u32 tun_id;
224efa5356bSRoopa Prabhu 	u16 vid, flags = 0;
225efa5356bSRoopa Prabhu 	int err;
226efa5356bSRoopa Prabhu 
227efa5356bSRoopa Prabhu 	memset(tinfo, 0, sizeof(*tinfo));
228efa5356bSRoopa Prabhu 
2298cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
2308cb08174SJohannes Berg 					  attr, vlan_tunnel_policy, NULL);
231efa5356bSRoopa Prabhu 	if (err < 0)
232efa5356bSRoopa Prabhu 		return err;
233efa5356bSRoopa Prabhu 
234bb580ad6SNikolay Aleksandrov 	if (!tb[IFLA_BRIDGE_VLAN_TUNNEL_ID] ||
235bb580ad6SNikolay Aleksandrov 	    !tb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
236bb580ad6SNikolay Aleksandrov 		return -EINVAL;
237bb580ad6SNikolay Aleksandrov 
238efa5356bSRoopa Prabhu 	tun_id = nla_get_u32(tb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
239efa5356bSRoopa Prabhu 	vid = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
240efa5356bSRoopa Prabhu 	if (vid >= VLAN_VID_MASK)
241efa5356bSRoopa Prabhu 		return -ERANGE;
242efa5356bSRoopa Prabhu 
243efa5356bSRoopa Prabhu 	if (tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
244efa5356bSRoopa Prabhu 		flags = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
245efa5356bSRoopa Prabhu 
246efa5356bSRoopa Prabhu 	tinfo->tunid = tun_id;
247efa5356bSRoopa Prabhu 	tinfo->vid = vid;
248efa5356bSRoopa Prabhu 	tinfo->flags = flags;
249efa5356bSRoopa Prabhu 
250efa5356bSRoopa Prabhu 	return 0;
251efa5356bSRoopa Prabhu }
252efa5356bSRoopa Prabhu 
253efa5356bSRoopa Prabhu int br_process_vlan_tunnel_info(struct net_bridge *br,
254efa5356bSRoopa Prabhu 				struct net_bridge_port *p, int cmd,
255efa5356bSRoopa Prabhu 				struct vtunnel_info *tinfo_curr,
256e19b42a1SNikolay Aleksandrov 				struct vtunnel_info *tinfo_last,
257e19b42a1SNikolay Aleksandrov 				bool *changed)
258efa5356bSRoopa Prabhu {
259efa5356bSRoopa Prabhu 	int err;
260efa5356bSRoopa Prabhu 
261efa5356bSRoopa Prabhu 	if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
262efa5356bSRoopa Prabhu 		if (tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
263efa5356bSRoopa Prabhu 			return -EINVAL;
264efa5356bSRoopa Prabhu 		memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
265efa5356bSRoopa Prabhu 	} else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
266efa5356bSRoopa Prabhu 		int t, v;
267efa5356bSRoopa Prabhu 
268efa5356bSRoopa Prabhu 		if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
269efa5356bSRoopa Prabhu 			return -EINVAL;
270efa5356bSRoopa Prabhu 		if ((tinfo_curr->vid - tinfo_last->vid) !=
271efa5356bSRoopa Prabhu 		    (tinfo_curr->tunid - tinfo_last->tunid))
272efa5356bSRoopa Prabhu 			return -EINVAL;
273efa5356bSRoopa Prabhu 		t = tinfo_last->tunid;
274efa5356bSRoopa Prabhu 		for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
275e19b42a1SNikolay Aleksandrov 			err = br_vlan_tunnel_info(p, cmd, v, t, changed);
276efa5356bSRoopa Prabhu 			if (err)
277efa5356bSRoopa Prabhu 				return err;
278efa5356bSRoopa Prabhu 			t++;
279efa5356bSRoopa Prabhu 		}
280efa5356bSRoopa Prabhu 		memset(tinfo_last, 0, sizeof(struct vtunnel_info));
281efa5356bSRoopa Prabhu 		memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
282efa5356bSRoopa Prabhu 	} else {
283efa5356bSRoopa Prabhu 		if (tinfo_last->flags)
284efa5356bSRoopa Prabhu 			return -EINVAL;
285efa5356bSRoopa Prabhu 		err = br_vlan_tunnel_info(p, cmd, tinfo_curr->vid,
286e19b42a1SNikolay Aleksandrov 					  tinfo_curr->tunid, changed);
287efa5356bSRoopa Prabhu 		if (err)
288efa5356bSRoopa Prabhu 			return err;
289efa5356bSRoopa Prabhu 		memset(tinfo_last, 0, sizeof(struct vtunnel_info));
290efa5356bSRoopa Prabhu 		memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
291efa5356bSRoopa Prabhu 	}
292efa5356bSRoopa Prabhu 
293efa5356bSRoopa Prabhu 	return 0;
294efa5356bSRoopa Prabhu }
295