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