hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Bridge per vlan tunnel port dst_metadata netlink control interface
34 *
45 * Authors:
56 * Roopa Prabhu <roopa@cumulusnetworks.com>
6
- *
7
- * This program is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU General Public License
9
- * as published by the Free Software Foundation; either version
10
- * 2 of the License, or (at your option) any later version.
117 */
128
139 #include <linux/kernel.h>
....@@ -30,8 +26,8 @@
3026 nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
3127 }
3228
33
-static bool vlan_tunid_inrange(struct net_bridge_vlan *v_curr,
34
- struct net_bridge_vlan *v_last)
29
+bool vlan_tunid_inrange(const struct net_bridge_vlan *v_curr,
30
+ const struct net_bridge_vlan *v_last)
3531 {
3632 __be32 tunid_curr = tunnel_id_to_key32(v_curr->tinfo.tunnel_id);
3733 __be32 tunid_last = tunnel_id_to_key32(v_last->tinfo.tunnel_id);
....@@ -97,7 +93,7 @@
9793 __be32 tid = tunnel_id_to_key32(tunnel_id);
9894 struct nlattr *tmap;
9995
100
- tmap = nla_nest_start(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
96
+ tmap = nla_nest_start_noflag(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
10197 if (!tmap)
10298 return -EMSGSIZE;
10399 if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
....@@ -197,8 +193,8 @@
197193 [IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
198194 };
199195
200
-static int br_vlan_tunnel_info(struct net_bridge_port *p, int cmd,
201
- u16 vid, u32 tun_id, bool *changed)
196
+int br_vlan_tunnel_info(const struct net_bridge_port *p, int cmd,
197
+ u16 vid, u32 tun_id, bool *changed)
202198 {
203199 int err = 0;
204200
....@@ -230,8 +226,8 @@
230226
231227 memset(tinfo, 0, sizeof(*tinfo));
232228
233
- err = nla_parse_nested(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX, attr,
234
- vlan_tunnel_policy, NULL);
229
+ err = nla_parse_nested_deprecated(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
230
+ attr, vlan_tunnel_policy, NULL);
235231 if (err < 0)
236232 return err;
237233
....@@ -254,8 +250,38 @@
254250 return 0;
255251 }
256252
257
-int br_process_vlan_tunnel_info(struct net_bridge *br,
258
- struct net_bridge_port *p, int cmd,
253
+/* send a notification if v_curr can't enter the range and start a new one */
254
+static void __vlan_tunnel_handle_range(const struct net_bridge_port *p,
255
+ struct net_bridge_vlan **v_start,
256
+ struct net_bridge_vlan **v_end,
257
+ int v_curr, bool curr_change)
258
+{
259
+ struct net_bridge_vlan_group *vg;
260
+ struct net_bridge_vlan *v;
261
+
262
+ vg = nbp_vlan_group(p);
263
+ if (!vg)
264
+ return;
265
+
266
+ v = br_vlan_find(vg, v_curr);
267
+
268
+ if (!*v_start)
269
+ goto out_init;
270
+
271
+ if (v && curr_change && br_vlan_can_enter_range(v, *v_end)) {
272
+ *v_end = v;
273
+ return;
274
+ }
275
+
276
+ br_vlan_notify(p->br, p, (*v_start)->vid, (*v_end)->vid, RTM_NEWVLAN);
277
+out_init:
278
+ /* we start a range only if there are any changes to notify about */
279
+ *v_start = curr_change ? v : NULL;
280
+ *v_end = *v_start;
281
+}
282
+
283
+int br_process_vlan_tunnel_info(const struct net_bridge *br,
284
+ const struct net_bridge_port *p, int cmd,
259285 struct vtunnel_info *tinfo_curr,
260286 struct vtunnel_info *tinfo_last,
261287 bool *changed)
....@@ -267,6 +293,7 @@
267293 return -EINVAL;
268294 memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
269295 } else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
296
+ struct net_bridge_vlan *v_start = NULL, *v_end = NULL;
270297 int t, v;
271298
272299 if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
....@@ -276,11 +303,24 @@
276303 return -EINVAL;
277304 t = tinfo_last->tunid;
278305 for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
279
- err = br_vlan_tunnel_info(p, cmd, v, t, changed);
306
+ bool curr_change = false;
307
+
308
+ err = br_vlan_tunnel_info(p, cmd, v, t, &curr_change);
280309 if (err)
281
- return err;
310
+ break;
282311 t++;
312
+
313
+ if (curr_change)
314
+ *changed = curr_change;
315
+ __vlan_tunnel_handle_range(p, &v_start, &v_end, v,
316
+ curr_change);
283317 }
318
+ if (v_start && v_end)
319
+ br_vlan_notify(br, p, v_start->vid, v_end->vid,
320
+ RTM_NEWVLAN);
321
+ if (err)
322
+ return err;
323
+
284324 memset(tinfo_last, 0, sizeof(struct vtunnel_info));
285325 memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
286326 } else {
....@@ -290,6 +330,7 @@
290330 tinfo_curr->tunid, changed);
291331 if (err)
292332 return err;
333
+ br_vlan_notify(br, p, tinfo_curr->vid, 0, RTM_NEWVLAN);
293334 memset(tinfo_last, 0, sizeof(struct vtunnel_info));
294335 memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
295336 }