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