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