1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (c) 2020, Nikolay Aleksandrov <nikolay@cumulusnetworks.com> 3 #include <linux/kernel.h> 4 #include <linux/netdevice.h> 5 #include <linux/rtnetlink.h> 6 #include <linux/slab.h> 7 #include <net/ip_tunnels.h> 8 9 #include "br_private.h" 10 #include "br_private_tunnel.h" 11 12 static bool __vlan_tun_put(struct sk_buff *skb, const struct net_bridge_vlan *v) 13 { 14 __be32 tid = tunnel_id_to_key32(v->tinfo.tunnel_id); 15 16 if (!v->tinfo.tunnel_dst) 17 return true; 18 19 return !nla_put_u32(skb, BRIDGE_VLANDB_ENTRY_TUNNEL_ID, 20 be32_to_cpu(tid)); 21 } 22 23 static bool __vlan_tun_can_enter_range(const struct net_bridge_vlan *v_curr, 24 const struct net_bridge_vlan *range_end) 25 { 26 return (!v_curr->tinfo.tunnel_dst && !range_end->tinfo.tunnel_dst) || 27 vlan_tunid_inrange(v_curr, range_end); 28 } 29 30 /* check if the options' state of v_curr allow it to enter the range */ 31 bool br_vlan_opts_eq_range(const struct net_bridge_vlan *v_curr, 32 const struct net_bridge_vlan *range_end) 33 { 34 return v_curr->state == range_end->state && 35 __vlan_tun_can_enter_range(v_curr, range_end); 36 } 37 38 bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v) 39 { 40 return !nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE, 41 br_vlan_get_state(v)) && 42 __vlan_tun_put(skb, v); 43 } 44 45 size_t br_vlan_opts_nl_size(void) 46 { 47 return nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_ENTRY_STATE */ 48 + nla_total_size(sizeof(u32)); /* BRIDGE_VLANDB_ENTRY_TUNNEL_ID */ 49 } 50 51 static int br_vlan_modify_state(struct net_bridge_vlan_group *vg, 52 struct net_bridge_vlan *v, 53 u8 state, 54 bool *changed, 55 struct netlink_ext_ack *extack) 56 { 57 struct net_bridge *br; 58 59 ASSERT_RTNL(); 60 61 if (state > BR_STATE_BLOCKING) { 62 NL_SET_ERR_MSG_MOD(extack, "Invalid vlan state"); 63 return -EINVAL; 64 } 65 66 if (br_vlan_is_brentry(v)) 67 br = v->br; 68 else 69 br = v->port->br; 70 71 if (br->stp_enabled == BR_KERNEL_STP) { 72 NL_SET_ERR_MSG_MOD(extack, "Can't modify vlan state when using kernel STP"); 73 return -EBUSY; 74 } 75 76 if (v->state == state) 77 return 0; 78 79 if (v->vid == br_get_pvid(vg)) 80 br_vlan_set_pvid_state(vg, state); 81 82 br_vlan_set_state(v, state); 83 *changed = true; 84 85 return 0; 86 } 87 88 static int br_vlan_modify_tunnel(const struct net_bridge_port *p, 89 struct net_bridge_vlan *v, 90 struct nlattr **tb, 91 bool *changed, 92 struct netlink_ext_ack *extack) 93 { 94 struct bridge_vlan_info *vinfo; 95 int cmdmap; 96 u32 tun_id; 97 98 if (!p) { 99 NL_SET_ERR_MSG_MOD(extack, "Can't modify tunnel mapping of non-port vlans"); 100 return -EINVAL; 101 } 102 if (!(p->flags & BR_VLAN_TUNNEL)) { 103 NL_SET_ERR_MSG_MOD(extack, "Port doesn't have tunnel flag set"); 104 return -EINVAL; 105 } 106 107 /* vlan info attribute is guaranteed by br_vlan_rtm_process_one */ 108 vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]); 109 cmdmap = vinfo->flags & BRIDGE_VLAN_INFO_REMOVE_TUN ? RTM_DELLINK : 110 RTM_SETLINK; 111 /* when working on vlan ranges this represents the starting tunnel id */ 112 tun_id = nla_get_u32(tb[BRIDGE_VLANDB_ENTRY_TUNNEL_ID]); 113 /* tunnel ids are mapped to each vlan in increasing order, 114 * the starting vlan is in BRIDGE_VLANDB_ENTRY_INFO and v is the 115 * current vlan, so we compute: tun_id + v - vinfo->vid 116 */ 117 tun_id += v->vid - vinfo->vid; 118 119 return br_vlan_tunnel_info(p, cmdmap, v->vid, tun_id, changed); 120 } 121 122 static int br_vlan_process_one_opts(const struct net_bridge *br, 123 const struct net_bridge_port *p, 124 struct net_bridge_vlan_group *vg, 125 struct net_bridge_vlan *v, 126 struct nlattr **tb, 127 bool *changed, 128 struct netlink_ext_ack *extack) 129 { 130 int err; 131 132 *changed = false; 133 if (tb[BRIDGE_VLANDB_ENTRY_STATE]) { 134 u8 state = nla_get_u8(tb[BRIDGE_VLANDB_ENTRY_STATE]); 135 136 err = br_vlan_modify_state(vg, v, state, changed, extack); 137 if (err) 138 return err; 139 } 140 if (tb[BRIDGE_VLANDB_ENTRY_TUNNEL_ID]) { 141 err = br_vlan_modify_tunnel(p, v, tb, changed, extack); 142 if (err) 143 return err; 144 } 145 146 return 0; 147 } 148 149 int br_vlan_process_options(const struct net_bridge *br, 150 const struct net_bridge_port *p, 151 struct net_bridge_vlan *range_start, 152 struct net_bridge_vlan *range_end, 153 struct nlattr **tb, 154 struct netlink_ext_ack *extack) 155 { 156 struct net_bridge_vlan *v, *curr_start = NULL, *curr_end = NULL; 157 struct net_bridge_vlan_group *vg; 158 int vid, err = 0; 159 u16 pvid; 160 161 if (p) 162 vg = nbp_vlan_group(p); 163 else 164 vg = br_vlan_group(br); 165 166 if (!range_start || !br_vlan_should_use(range_start)) { 167 NL_SET_ERR_MSG_MOD(extack, "Vlan range start doesn't exist, can't process options"); 168 return -ENOENT; 169 } 170 if (!range_end || !br_vlan_should_use(range_end)) { 171 NL_SET_ERR_MSG_MOD(extack, "Vlan range end doesn't exist, can't process options"); 172 return -ENOENT; 173 } 174 175 pvid = br_get_pvid(vg); 176 for (vid = range_start->vid; vid <= range_end->vid; vid++) { 177 bool changed = false; 178 179 v = br_vlan_find(vg, vid); 180 if (!v || !br_vlan_should_use(v)) { 181 NL_SET_ERR_MSG_MOD(extack, "Vlan in range doesn't exist, can't process options"); 182 err = -ENOENT; 183 break; 184 } 185 186 err = br_vlan_process_one_opts(br, p, vg, v, tb, &changed, 187 extack); 188 if (err) 189 break; 190 191 if (changed) { 192 /* vlan options changed, check for range */ 193 if (!curr_start) { 194 curr_start = v; 195 curr_end = v; 196 continue; 197 } 198 199 if (v->vid == pvid || 200 !br_vlan_can_enter_range(v, curr_end)) { 201 br_vlan_notify(br, p, curr_start->vid, 202 curr_end->vid, RTM_NEWVLAN); 203 curr_start = v; 204 } 205 curr_end = v; 206 } else { 207 /* nothing changed and nothing to notify yet */ 208 if (!curr_start) 209 continue; 210 211 br_vlan_notify(br, p, curr_start->vid, curr_end->vid, 212 RTM_NEWVLAN); 213 curr_start = NULL; 214 curr_end = NULL; 215 } 216 } 217 if (curr_start) 218 br_vlan_notify(br, p, curr_start->vid, curr_end->vid, 219 RTM_NEWVLAN); 220 221 return err; 222 } 223