1/* 2 * net/switchdev/switchdev.c - Switch device API 3 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> 4 * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/types.h> 14#include <linux/init.h> 15#include <linux/mutex.h> 16#include <linux/notifier.h> 17#include <linux/netdevice.h> 18#include <linux/rtnetlink.h> 19#include <net/ip_fib.h> 20#include <net/switchdev.h> 21 22/** 23 * netdev_switch_parent_id_get - Get ID of a switch 24 * @dev: port device 25 * @psid: switch ID 26 * 27 * Get ID of a switch this port is part of. 28 */ 29int netdev_switch_parent_id_get(struct net_device *dev, 30 struct netdev_phys_item_id *psid) 31{ 32 const struct swdev_ops *ops = dev->swdev_ops; 33 34 if (!ops || !ops->swdev_parent_id_get) 35 return -EOPNOTSUPP; 36 return ops->swdev_parent_id_get(dev, psid); 37} 38EXPORT_SYMBOL_GPL(netdev_switch_parent_id_get); 39 40/** 41 * netdev_switch_port_stp_update - Notify switch device port of STP 42 * state change 43 * @dev: port device 44 * @state: port STP state 45 * 46 * Notify switch device port of bridge port STP state change. 47 */ 48int netdev_switch_port_stp_update(struct net_device *dev, u8 state) 49{ 50 const struct swdev_ops *ops = dev->swdev_ops; 51 struct net_device *lower_dev; 52 struct list_head *iter; 53 int err = -EOPNOTSUPP; 54 55 if (ops && ops->swdev_port_stp_update) 56 return ops->swdev_port_stp_update(dev, state); 57 58 netdev_for_each_lower_dev(dev, lower_dev, iter) { 59 err = netdev_switch_port_stp_update(lower_dev, state); 60 if (err && err != -EOPNOTSUPP) 61 return err; 62 } 63 64 return err; 65} 66EXPORT_SYMBOL_GPL(netdev_switch_port_stp_update); 67 68static RAW_NOTIFIER_HEAD(netdev_switch_notif_chain); 69 70/** 71 * register_netdev_switch_notifier - Register notifier 72 * @nb: notifier_block 73 * 74 * Register switch device notifier. This should be used by code 75 * which needs to monitor events happening in particular device. 76 * Return values are same as for atomic_notifier_chain_register(). 77 */ 78int register_netdev_switch_notifier(struct notifier_block *nb) 79{ 80 int err; 81 82 rtnl_lock(); 83 err = raw_notifier_chain_register(&netdev_switch_notif_chain, nb); 84 rtnl_unlock(); 85 return err; 86} 87EXPORT_SYMBOL_GPL(register_netdev_switch_notifier); 88 89/** 90 * unregister_netdev_switch_notifier - Unregister notifier 91 * @nb: notifier_block 92 * 93 * Unregister switch device notifier. 94 * Return values are same as for atomic_notifier_chain_unregister(). 95 */ 96int unregister_netdev_switch_notifier(struct notifier_block *nb) 97{ 98 int err; 99 100 rtnl_lock(); 101 err = raw_notifier_chain_unregister(&netdev_switch_notif_chain, nb); 102 rtnl_unlock(); 103 return err; 104} 105EXPORT_SYMBOL_GPL(unregister_netdev_switch_notifier); 106 107/** 108 * call_netdev_switch_notifiers - Call notifiers 109 * @val: value passed unmodified to notifier function 110 * @dev: port device 111 * @info: notifier information data 112 * 113 * Call all network notifier blocks. This should be called by driver 114 * when it needs to propagate hardware event. 115 * Return values are same as for atomic_notifier_call_chain(). 116 * rtnl_lock must be held. 117 */ 118int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev, 119 struct netdev_switch_notifier_info *info) 120{ 121 int err; 122 123 ASSERT_RTNL(); 124 125 info->dev = dev; 126 err = raw_notifier_call_chain(&netdev_switch_notif_chain, val, info); 127 return err; 128} 129EXPORT_SYMBOL_GPL(call_netdev_switch_notifiers); 130 131/** 132 * netdev_switch_port_bridge_setlink - Notify switch device port of bridge 133 * port attributes 134 * 135 * @dev: port device 136 * @nlh: netlink msg with bridge port attributes 137 * @flags: bridge setlink flags 138 * 139 * Notify switch device port of bridge port attributes 140 */ 141int netdev_switch_port_bridge_setlink(struct net_device *dev, 142 struct nlmsghdr *nlh, u16 flags) 143{ 144 const struct net_device_ops *ops = dev->netdev_ops; 145 146 if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) 147 return 0; 148 149 if (!ops->ndo_bridge_setlink) 150 return -EOPNOTSUPP; 151 152 return ops->ndo_bridge_setlink(dev, nlh, flags); 153} 154EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_setlink); 155 156/** 157 * netdev_switch_port_bridge_dellink - Notify switch device port of bridge 158 * port attribute delete 159 * 160 * @dev: port device 161 * @nlh: netlink msg with bridge port attributes 162 * @flags: bridge setlink flags 163 * 164 * Notify switch device port of bridge port attribute delete 165 */ 166int netdev_switch_port_bridge_dellink(struct net_device *dev, 167 struct nlmsghdr *nlh, u16 flags) 168{ 169 const struct net_device_ops *ops = dev->netdev_ops; 170 171 if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) 172 return 0; 173 174 if (!ops->ndo_bridge_dellink) 175 return -EOPNOTSUPP; 176 177 return ops->ndo_bridge_dellink(dev, nlh, flags); 178} 179EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_dellink); 180 181/** 182 * ndo_dflt_netdev_switch_port_bridge_setlink - default ndo bridge setlink 183 * op for master devices 184 * 185 * @dev: port device 186 * @nlh: netlink msg with bridge port attributes 187 * @flags: bridge setlink flags 188 * 189 * Notify master device slaves of bridge port attributes 190 */ 191int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev, 192 struct nlmsghdr *nlh, u16 flags) 193{ 194 struct net_device *lower_dev; 195 struct list_head *iter; 196 int ret = 0, err = 0; 197 198 if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) 199 return ret; 200 201 netdev_for_each_lower_dev(dev, lower_dev, iter) { 202 err = netdev_switch_port_bridge_setlink(lower_dev, nlh, flags); 203 if (err && err != -EOPNOTSUPP) 204 ret = err; 205 } 206 207 return ret; 208} 209EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_setlink); 210 211/** 212 * ndo_dflt_netdev_switch_port_bridge_dellink - default ndo bridge dellink 213 * op for master devices 214 * 215 * @dev: port device 216 * @nlh: netlink msg with bridge port attributes 217 * @flags: bridge dellink flags 218 * 219 * Notify master device slaves of bridge port attribute deletes 220 */ 221int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev, 222 struct nlmsghdr *nlh, u16 flags) 223{ 224 struct net_device *lower_dev; 225 struct list_head *iter; 226 int ret = 0, err = 0; 227 228 if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) 229 return ret; 230 231 netdev_for_each_lower_dev(dev, lower_dev, iter) { 232 err = netdev_switch_port_bridge_dellink(lower_dev, nlh, flags); 233 if (err && err != -EOPNOTSUPP) 234 ret = err; 235 } 236 237 return ret; 238} 239EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_dellink); 240 241static struct net_device *netdev_switch_get_lowest_dev(struct net_device *dev) 242{ 243 const struct swdev_ops *ops = dev->swdev_ops; 244 struct net_device *lower_dev; 245 struct net_device *port_dev; 246 struct list_head *iter; 247 248 /* Recusively search down until we find a sw port dev. 249 * (A sw port dev supports swdev_parent_id_get). 250 */ 251 252 if (dev->features & NETIF_F_HW_SWITCH_OFFLOAD && 253 ops && ops->swdev_parent_id_get) 254 return dev; 255 256 netdev_for_each_lower_dev(dev, lower_dev, iter) { 257 port_dev = netdev_switch_get_lowest_dev(lower_dev); 258 if (port_dev) 259 return port_dev; 260 } 261 262 return NULL; 263} 264 265static struct net_device *netdev_switch_get_dev_by_nhs(struct fib_info *fi) 266{ 267 struct netdev_phys_item_id psid; 268 struct netdev_phys_item_id prev_psid; 269 struct net_device *dev = NULL; 270 int nhsel; 271 272 /* For this route, all nexthop devs must be on the same switch. */ 273 274 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { 275 const struct fib_nh *nh = &fi->fib_nh[nhsel]; 276 277 if (!nh->nh_dev) 278 return NULL; 279 280 dev = netdev_switch_get_lowest_dev(nh->nh_dev); 281 if (!dev) 282 return NULL; 283 284 if (netdev_switch_parent_id_get(dev, &psid)) 285 return NULL; 286 287 if (nhsel > 0) { 288 if (prev_psid.id_len != psid.id_len) 289 return NULL; 290 if (memcmp(prev_psid.id, psid.id, psid.id_len)) 291 return NULL; 292 } 293 294 prev_psid = psid; 295 } 296 297 return dev; 298} 299 300/** 301 * netdev_switch_fib_ipv4_add - Add IPv4 route entry to switch 302 * 303 * @dst: route's IPv4 destination address 304 * @dst_len: destination address length (prefix length) 305 * @fi: route FIB info structure 306 * @tos: route TOS 307 * @type: route type 308 * @nlflags: netlink flags passed in (NLM_F_*) 309 * @tb_id: route table ID 310 * 311 * Add IPv4 route entry to switch device. 312 */ 313int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, 314 u8 tos, u8 type, u32 nlflags, u32 tb_id) 315{ 316 struct net_device *dev; 317 const struct swdev_ops *ops; 318 int err = 0; 319 320 /* Don't offload route if using custom ip rules or if 321 * IPv4 FIB offloading has been disabled completely. 322 */ 323 324#ifdef CONFIG_IP_MULTIPLE_TABLES 325 if (fi->fib_net->ipv4.fib_has_custom_rules) 326 return 0; 327#endif 328 329 if (fi->fib_net->ipv4.fib_offload_disabled) 330 return 0; 331 332 dev = netdev_switch_get_dev_by_nhs(fi); 333 if (!dev) 334 return 0; 335 ops = dev->swdev_ops; 336 337 if (ops->swdev_fib_ipv4_add) { 338 err = ops->swdev_fib_ipv4_add(dev, htonl(dst), dst_len, 339 fi, tos, type, nlflags, 340 tb_id); 341 if (!err) 342 fi->fib_flags |= RTNH_F_OFFLOAD; 343 } 344 345 return err; 346} 347EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_add); 348 349/** 350 * netdev_switch_fib_ipv4_del - Delete IPv4 route entry from switch 351 * 352 * @dst: route's IPv4 destination address 353 * @dst_len: destination address length (prefix length) 354 * @fi: route FIB info structure 355 * @tos: route TOS 356 * @type: route type 357 * @tb_id: route table ID 358 * 359 * Delete IPv4 route entry from switch device. 360 */ 361int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, 362 u8 tos, u8 type, u32 tb_id) 363{ 364 struct net_device *dev; 365 const struct swdev_ops *ops; 366 int err = 0; 367 368 if (!(fi->fib_flags & RTNH_F_OFFLOAD)) 369 return 0; 370 371 dev = netdev_switch_get_dev_by_nhs(fi); 372 if (!dev) 373 return 0; 374 ops = dev->swdev_ops; 375 376 if (ops->swdev_fib_ipv4_del) { 377 err = ops->swdev_fib_ipv4_del(dev, htonl(dst), dst_len, 378 fi, tos, type, tb_id); 379 if (!err) 380 fi->fib_flags &= ~RTNH_F_OFFLOAD; 381 } 382 383 return err; 384} 385EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_del); 386 387/** 388 * netdev_switch_fib_ipv4_abort - Abort an IPv4 FIB operation 389 * 390 * @fi: route FIB info structure 391 */ 392void netdev_switch_fib_ipv4_abort(struct fib_info *fi) 393{ 394 /* There was a problem installing this route to the offload 395 * device. For now, until we come up with more refined 396 * policy handling, abruptly end IPv4 fib offloading for 397 * for entire net by flushing offload device(s) of all 398 * IPv4 routes, and mark IPv4 fib offloading broken from 399 * this point forward. 400 */ 401 402 fib_flush_external(fi->fib_net); 403 fi->fib_net->ipv4.fib_offload_disabled = true; 404} 405EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_abort); 406