18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Userspace interface 48c2ecf20Sopenharmony_ci * Linux ethernet bridge 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Lennert Buytenhek <buytenh@gnu.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/netpoll.h> 148c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 158c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 198c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <net/dsa.h> 228c2ecf20Sopenharmony_ci#include <net/sock.h> 238c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 248c2ecf20Sopenharmony_ci#include <net/switchdev.h> 258c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "br_private.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Determine initial path cost based on speed. 318c2ecf20Sopenharmony_ci * using recommendations from 802.1d standard 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Since driver might sleep need to not be holding any locks. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic int port_cost(struct net_device *dev) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct ethtool_link_ksettings ecmd; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (!__ethtool_get_link_ksettings(dev, &ecmd)) { 408c2ecf20Sopenharmony_ci switch (ecmd.base.speed) { 418c2ecf20Sopenharmony_ci case SPEED_10000: 428c2ecf20Sopenharmony_ci return 2; 438c2ecf20Sopenharmony_ci case SPEED_1000: 448c2ecf20Sopenharmony_ci return 4; 458c2ecf20Sopenharmony_ci case SPEED_100: 468c2ecf20Sopenharmony_ci return 19; 478c2ecf20Sopenharmony_ci case SPEED_10: 488c2ecf20Sopenharmony_ci return 100; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Old silly heuristics based on name */ 538c2ecf20Sopenharmony_ci if (!strncmp(dev->name, "lec", 3)) 548c2ecf20Sopenharmony_ci return 7; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (!strncmp(dev->name, "plip", 4)) 578c2ecf20Sopenharmony_ci return 2500; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 100; /* assume old 10Mbps */ 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Check for port carrier transitions. */ 648c2ecf20Sopenharmony_civoid br_port_carrier_check(struct net_bridge_port *p, bool *notified) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct net_device *dev = p->dev; 678c2ecf20Sopenharmony_ci struct net_bridge *br = p->br; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!(p->flags & BR_ADMIN_COST) && 708c2ecf20Sopenharmony_ci netif_running(dev) && netif_oper_up(dev)) 718c2ecf20Sopenharmony_ci p->path_cost = port_cost(dev); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci *notified = false; 748c2ecf20Sopenharmony_ci if (!netif_running(br->dev)) 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci spin_lock_bh(&br->lock); 788c2ecf20Sopenharmony_ci if (netif_running(dev) && netif_oper_up(dev)) { 798c2ecf20Sopenharmony_ci if (p->state == BR_STATE_DISABLED) { 808c2ecf20Sopenharmony_ci br_stp_enable_port(p); 818c2ecf20Sopenharmony_ci *notified = true; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci if (p->state != BR_STATE_DISABLED) { 858c2ecf20Sopenharmony_ci br_stp_disable_port(p); 868c2ecf20Sopenharmony_ci *notified = true; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci spin_unlock_bh(&br->lock); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void br_port_set_promisc(struct net_bridge_port *p) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int err = 0; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (br_promisc_port(p)) 978c2ecf20Sopenharmony_ci return; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci err = dev_set_promiscuity(p->dev, 1); 1008c2ecf20Sopenharmony_ci if (err) 1018c2ecf20Sopenharmony_ci return; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci br_fdb_unsync_static(p->br, p); 1048c2ecf20Sopenharmony_ci p->flags |= BR_PROMISC; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void br_port_clear_promisc(struct net_bridge_port *p) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int err; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Check if the port is already non-promisc or if it doesn't 1128c2ecf20Sopenharmony_ci * support UNICAST filtering. Without unicast filtering support 1138c2ecf20Sopenharmony_ci * we'll end up re-enabling promisc mode anyway, so just check for 1148c2ecf20Sopenharmony_ci * it here. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT)) 1178c2ecf20Sopenharmony_ci return; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* Since we'll be clearing the promisc mode, program the port 1208c2ecf20Sopenharmony_ci * first so that we don't have interruption in traffic. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci err = br_fdb_sync_static(p->br, p); 1238c2ecf20Sopenharmony_ci if (err) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci dev_set_promiscuity(p->dev, -1); 1278c2ecf20Sopenharmony_ci p->flags &= ~BR_PROMISC; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* When a port is added or removed or when certain port flags 1318c2ecf20Sopenharmony_ci * change, this function is called to automatically manage 1328c2ecf20Sopenharmony_ci * promiscuity setting of all the bridge ports. We are always called 1338c2ecf20Sopenharmony_ci * under RTNL so can skip using rcu primitives. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_civoid br_manage_promisc(struct net_bridge *br) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct net_bridge_port *p; 1388c2ecf20Sopenharmony_ci bool set_all = false; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* If vlan filtering is disabled or bridge interface is placed 1418c2ecf20Sopenharmony_ci * into promiscuous mode, place all ports in promiscuous mode. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br->dev)) 1448c2ecf20Sopenharmony_ci set_all = true; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 1478c2ecf20Sopenharmony_ci if (set_all) { 1488c2ecf20Sopenharmony_ci br_port_set_promisc(p); 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci /* If the number of auto-ports is <= 1, then all other 1518c2ecf20Sopenharmony_ci * ports will have their output configuration 1528c2ecf20Sopenharmony_ci * statically specified through fdbs. Since ingress 1538c2ecf20Sopenharmony_ci * on the auto-port becomes forwarding/egress to other 1548c2ecf20Sopenharmony_ci * ports and egress configuration is statically known, 1558c2ecf20Sopenharmony_ci * we can say that ingress configuration of the 1568c2ecf20Sopenharmony_ci * auto-port is also statically known. 1578c2ecf20Sopenharmony_ci * This lets us disable promiscuous mode and write 1588c2ecf20Sopenharmony_ci * this config to hw. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci if ((p->dev->priv_flags & IFF_UNICAST_FLT) && 1618c2ecf20Sopenharmony_ci (br->auto_cnt == 0 || 1628c2ecf20Sopenharmony_ci (br->auto_cnt == 1 && br_auto_port(p)))) 1638c2ecf20Sopenharmony_ci br_port_clear_promisc(p); 1648c2ecf20Sopenharmony_ci else 1658c2ecf20Sopenharmony_ci br_port_set_promisc(p); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint nbp_backup_change(struct net_bridge_port *p, 1718c2ecf20Sopenharmony_ci struct net_device *backup_dev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct net_bridge_port *old_backup = rtnl_dereference(p->backup_port); 1748c2ecf20Sopenharmony_ci struct net_bridge_port *backup_p = NULL; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci ASSERT_RTNL(); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (backup_dev) { 1798c2ecf20Sopenharmony_ci if (!netif_is_bridge_port(backup_dev)) 1808c2ecf20Sopenharmony_ci return -ENOENT; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci backup_p = br_port_get_rtnl(backup_dev); 1838c2ecf20Sopenharmony_ci if (backup_p->br != p->br) 1848c2ecf20Sopenharmony_ci return -EINVAL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (p == backup_p) 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (old_backup == backup_p) 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* if the backup link is already set, clear it */ 1948c2ecf20Sopenharmony_ci if (old_backup) 1958c2ecf20Sopenharmony_ci old_backup->backup_redirected_cnt--; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (backup_p) 1988c2ecf20Sopenharmony_ci backup_p->backup_redirected_cnt++; 1998c2ecf20Sopenharmony_ci rcu_assign_pointer(p->backup_port, backup_p); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void nbp_backup_clear(struct net_bridge_port *p) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci nbp_backup_change(p, NULL); 2078c2ecf20Sopenharmony_ci if (p->backup_redirected_cnt) { 2088c2ecf20Sopenharmony_ci struct net_bridge_port *cur_p; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci list_for_each_entry(cur_p, &p->br->port_list, list) { 2118c2ecf20Sopenharmony_ci struct net_bridge_port *backup_p; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci backup_p = rtnl_dereference(cur_p->backup_port); 2148c2ecf20Sopenharmony_ci if (backup_p == p) 2158c2ecf20Sopenharmony_ci nbp_backup_change(cur_p, NULL); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci WARN_ON(rcu_access_pointer(p->backup_port) || p->backup_redirected_cnt); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void nbp_update_port_count(struct net_bridge *br) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct net_bridge_port *p; 2258c2ecf20Sopenharmony_ci u32 cnt = 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 2288c2ecf20Sopenharmony_ci if (br_auto_port(p)) 2298c2ecf20Sopenharmony_ci cnt++; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci if (br->auto_cnt != cnt) { 2328c2ecf20Sopenharmony_ci br->auto_cnt = cnt; 2338c2ecf20Sopenharmony_ci br_manage_promisc(br); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void nbp_delete_promisc(struct net_bridge_port *p) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci /* If port is currently promiscuous, unset promiscuity. 2408c2ecf20Sopenharmony_ci * Otherwise, it is a static port so remove all addresses 2418c2ecf20Sopenharmony_ci * from it. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci dev_set_allmulti(p->dev, -1); 2448c2ecf20Sopenharmony_ci if (br_promisc_port(p)) 2458c2ecf20Sopenharmony_ci dev_set_promiscuity(p->dev, -1); 2468c2ecf20Sopenharmony_ci else 2478c2ecf20Sopenharmony_ci br_fdb_unsync_static(p->br, p); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void release_nbp(struct kobject *kobj) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct net_bridge_port *p 2538c2ecf20Sopenharmony_ci = container_of(kobj, struct net_bridge_port, kobj); 2548c2ecf20Sopenharmony_ci kfree(p); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void brport_get_ownership(struct kobject *kobj, kuid_t *uid, kgid_t *gid) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct net_bridge_port *p = kobj_to_brport(kobj); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci net_ns_get_ownership(dev_net(p->dev), uid, gid); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic struct kobj_type brport_ktype = { 2658c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS 2668c2ecf20Sopenharmony_ci .sysfs_ops = &brport_sysfs_ops, 2678c2ecf20Sopenharmony_ci#endif 2688c2ecf20Sopenharmony_ci .release = release_nbp, 2698c2ecf20Sopenharmony_ci .get_ownership = brport_get_ownership, 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void destroy_nbp(struct net_bridge_port *p) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct net_device *dev = p->dev; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci p->br = NULL; 2778c2ecf20Sopenharmony_ci p->dev = NULL; 2788c2ecf20Sopenharmony_ci dev_put(dev); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci kobject_put(&p->kobj); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void destroy_nbp_rcu(struct rcu_head *head) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct net_bridge_port *p = 2868c2ecf20Sopenharmony_ci container_of(head, struct net_bridge_port, rcu); 2878c2ecf20Sopenharmony_ci destroy_nbp(p); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic unsigned get_max_headroom(struct net_bridge *br) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci unsigned max_headroom = 0; 2938c2ecf20Sopenharmony_ci struct net_bridge_port *p; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 2968c2ecf20Sopenharmony_ci unsigned dev_headroom = netdev_get_fwd_headroom(p->dev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (dev_headroom > max_headroom) 2998c2ecf20Sopenharmony_ci max_headroom = dev_headroom; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return max_headroom; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void update_headroom(struct net_bridge *br, int new_hr) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct net_bridge_port *p; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) 3108c2ecf20Sopenharmony_ci netdev_set_rx_headroom(p->dev, new_hr); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci br->dev->needed_headroom = new_hr; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* Delete port(interface) from bridge is done in two steps. 3168c2ecf20Sopenharmony_ci * via RCU. First step, marks device as down. That deletes 3178c2ecf20Sopenharmony_ci * all the timers and stops new packets from flowing through. 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * Final cleanup doesn't occur until after all CPU's finished 3208c2ecf20Sopenharmony_ci * processing packets. 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * Protected from multiple admin operations by RTNL mutex 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cistatic void del_nbp(struct net_bridge_port *p) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct net_bridge *br = p->br; 3278c2ecf20Sopenharmony_ci struct net_device *dev = p->dev; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci sysfs_remove_link(br->ifobj, p->dev->name); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci nbp_delete_promisc(p); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci spin_lock_bh(&br->lock); 3348c2ecf20Sopenharmony_ci br_stp_disable_port(p); 3358c2ecf20Sopenharmony_ci spin_unlock_bh(&br->lock); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci br_mrp_port_del(br, p); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci br_ifinfo_notify(RTM_DELLINK, NULL, p); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci list_del_rcu(&p->list); 3428c2ecf20Sopenharmony_ci if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom) 3438c2ecf20Sopenharmony_ci update_headroom(br, get_max_headroom(br)); 3448c2ecf20Sopenharmony_ci netdev_reset_rx_headroom(dev); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci nbp_vlan_flush(p); 3478c2ecf20Sopenharmony_ci br_fdb_delete_by_port(br, p, 0, 1); 3488c2ecf20Sopenharmony_ci switchdev_deferred_process(); 3498c2ecf20Sopenharmony_ci nbp_backup_clear(p); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci nbp_update_port_count(br); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci netdev_upper_dev_unlink(dev, br->dev); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci dev->priv_flags &= ~IFF_BRIDGE_PORT; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci netdev_rx_handler_unregister(dev); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci br_multicast_del_port(p); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci kobject_uevent(&p->kobj, KOBJ_REMOVE); 3628c2ecf20Sopenharmony_ci kobject_del(&p->kobj); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci br_netpoll_disable(p); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci call_rcu(&p->rcu, destroy_nbp_rcu); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/* Delete bridge device */ 3708c2ecf20Sopenharmony_civoid br_dev_delete(struct net_device *dev, struct list_head *head) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 3738c2ecf20Sopenharmony_ci struct net_bridge_port *p, *n; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, n, &br->port_list, list) { 3768c2ecf20Sopenharmony_ci del_nbp(p); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci br_recalculate_neigh_suppress_enabled(br); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci br_fdb_delete_by_port(br, NULL, 0, 1); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&br->gc_work); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci br_sysfs_delbr(br->dev); 3868c2ecf20Sopenharmony_ci unregister_netdevice_queue(br->dev, head); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* find an available port number */ 3908c2ecf20Sopenharmony_cistatic int find_portno(struct net_bridge *br) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int index; 3938c2ecf20Sopenharmony_ci struct net_bridge_port *p; 3948c2ecf20Sopenharmony_ci unsigned long *inuse; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci inuse = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL); 3978c2ecf20Sopenharmony_ci if (!inuse) 3988c2ecf20Sopenharmony_ci return -ENOMEM; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci set_bit(0, inuse); /* zero is reserved */ 4018c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 4028c2ecf20Sopenharmony_ci set_bit(p->port_no, inuse); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci index = find_first_zero_bit(inuse, BR_MAX_PORTS); 4058c2ecf20Sopenharmony_ci bitmap_free(inuse); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return (index >= BR_MAX_PORTS) ? -EXFULL : index; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/* called with RTNL but without bridge lock */ 4118c2ecf20Sopenharmony_cistatic struct net_bridge_port *new_nbp(struct net_bridge *br, 4128c2ecf20Sopenharmony_ci struct net_device *dev) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct net_bridge_port *p; 4158c2ecf20Sopenharmony_ci int index, err; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci index = find_portno(br); 4188c2ecf20Sopenharmony_ci if (index < 0) 4198c2ecf20Sopenharmony_ci return ERR_PTR(index); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci p = kzalloc(sizeof(*p), GFP_KERNEL); 4228c2ecf20Sopenharmony_ci if (p == NULL) 4238c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci p->br = br; 4268c2ecf20Sopenharmony_ci dev_hold(dev); 4278c2ecf20Sopenharmony_ci p->dev = dev; 4288c2ecf20Sopenharmony_ci p->path_cost = port_cost(dev); 4298c2ecf20Sopenharmony_ci p->priority = 0x8000 >> BR_PORT_BITS; 4308c2ecf20Sopenharmony_ci p->port_no = index; 4318c2ecf20Sopenharmony_ci p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 4328c2ecf20Sopenharmony_ci br_init_port(p); 4338c2ecf20Sopenharmony_ci br_set_state(p, BR_STATE_DISABLED); 4348c2ecf20Sopenharmony_ci br_stp_port_timer_init(p); 4358c2ecf20Sopenharmony_ci err = br_multicast_add_port(p); 4368c2ecf20Sopenharmony_ci if (err) { 4378c2ecf20Sopenharmony_ci dev_put(dev); 4388c2ecf20Sopenharmony_ci kfree(p); 4398c2ecf20Sopenharmony_ci p = ERR_PTR(err); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return p; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciint br_add_bridge(struct net *net, const char *name) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct net_device *dev; 4488c2ecf20Sopenharmony_ci int res; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN, 4518c2ecf20Sopenharmony_ci br_dev_setup); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (!dev) 4548c2ecf20Sopenharmony_ci return -ENOMEM; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci dev_net_set(dev, net); 4578c2ecf20Sopenharmony_ci dev->rtnl_link_ops = &br_link_ops; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci res = register_netdev(dev); 4608c2ecf20Sopenharmony_ci if (res) 4618c2ecf20Sopenharmony_ci free_netdev(dev); 4628c2ecf20Sopenharmony_ci return res; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ciint br_del_bridge(struct net *net, const char *name) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct net_device *dev; 4688c2ecf20Sopenharmony_ci int ret = 0; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci rtnl_lock(); 4718c2ecf20Sopenharmony_ci dev = __dev_get_by_name(net, name); 4728c2ecf20Sopenharmony_ci if (dev == NULL) 4738c2ecf20Sopenharmony_ci ret = -ENXIO; /* Could not find device */ 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci else if (!(dev->priv_flags & IFF_EBRIDGE)) { 4768c2ecf20Sopenharmony_ci /* Attempt to delete non bridge device! */ 4778c2ecf20Sopenharmony_ci ret = -EPERM; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci else if (dev->flags & IFF_UP) { 4818c2ecf20Sopenharmony_ci /* Not shutdown yet. */ 4828c2ecf20Sopenharmony_ci ret = -EBUSY; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci else 4868c2ecf20Sopenharmony_ci br_dev_delete(dev, NULL); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci rtnl_unlock(); 4898c2ecf20Sopenharmony_ci return ret; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ 4938c2ecf20Sopenharmony_cistatic int br_mtu_min(const struct net_bridge *br) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci const struct net_bridge_port *p; 4968c2ecf20Sopenharmony_ci int ret_mtu = 0; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) 4998c2ecf20Sopenharmony_ci if (!ret_mtu || ret_mtu > p->dev->mtu) 5008c2ecf20Sopenharmony_ci ret_mtu = p->dev->mtu; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci return ret_mtu ? ret_mtu : ETH_DATA_LEN; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_civoid br_mtu_auto_adjust(struct net_bridge *br) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci ASSERT_RTNL(); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* if the bridge MTU was manually configured don't mess with it */ 5108c2ecf20Sopenharmony_ci if (br_opt_get(br, BROPT_MTU_SET_BY_USER)) 5118c2ecf20Sopenharmony_ci return; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* change to the minimum MTU and clear the flag which was set by 5148c2ecf20Sopenharmony_ci * the bridge ndo_change_mtu callback 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci dev_set_mtu(br->dev, br_mtu_min(br)); 5178c2ecf20Sopenharmony_ci br_opt_toggle(br, BROPT_MTU_SET_BY_USER, false); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void br_set_gso_limits(struct net_bridge *br) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci unsigned int gso_max_size = GSO_MAX_SIZE; 5238c2ecf20Sopenharmony_ci u16 gso_max_segs = GSO_MAX_SEGS; 5248c2ecf20Sopenharmony_ci const struct net_bridge_port *p; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 5278c2ecf20Sopenharmony_ci gso_max_size = min(gso_max_size, p->dev->gso_max_size); 5288c2ecf20Sopenharmony_ci gso_max_segs = min(gso_max_segs, p->dev->gso_max_segs); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci br->dev->gso_max_size = gso_max_size; 5318c2ecf20Sopenharmony_ci br->dev->gso_max_segs = gso_max_segs; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/* 5358c2ecf20Sopenharmony_ci * Recomputes features using slave's features 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_cinetdev_features_t br_features_recompute(struct net_bridge *br, 5388c2ecf20Sopenharmony_ci netdev_features_t features) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct net_bridge_port *p; 5418c2ecf20Sopenharmony_ci netdev_features_t mask; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (list_empty(&br->port_list)) 5448c2ecf20Sopenharmony_ci return features; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci mask = features; 5478c2ecf20Sopenharmony_ci features &= ~NETIF_F_ONE_FOR_ALL; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 5508c2ecf20Sopenharmony_ci features = netdev_increment_features(features, 5518c2ecf20Sopenharmony_ci p->dev->features, mask); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci features = netdev_add_tso_features(features, mask); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return features; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/* called with RTNL */ 5598c2ecf20Sopenharmony_ciint br_add_if(struct net_bridge *br, struct net_device *dev, 5608c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct net_bridge_port *p; 5638c2ecf20Sopenharmony_ci int err = 0; 5648c2ecf20Sopenharmony_ci unsigned br_hr, dev_hr; 5658c2ecf20Sopenharmony_ci bool changed_addr, fdb_synced = false; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Don't allow bridging non-ethernet like devices. */ 5688c2ecf20Sopenharmony_ci if ((dev->flags & IFF_LOOPBACK) || 5698c2ecf20Sopenharmony_ci dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN || 5708c2ecf20Sopenharmony_ci !is_valid_ether_addr(dev->dev_addr)) 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Also don't allow bridging of net devices that are DSA masters, since 5748c2ecf20Sopenharmony_ci * the bridge layer rx_handler prevents the DSA fake ethertype handler 5758c2ecf20Sopenharmony_ci * to be invoked, so we don't get the chance to strip off and parse the 5768c2ecf20Sopenharmony_ci * DSA switch tag protocol header (the bridge layer just returns 5778c2ecf20Sopenharmony_ci * RX_HANDLER_CONSUMED, stopping RX processing for these frames). 5788c2ecf20Sopenharmony_ci * The only case where that would not be an issue is when bridging can 5798c2ecf20Sopenharmony_ci * already be offloaded, such as when the DSA master is itself a DSA 5808c2ecf20Sopenharmony_ci * or plain switchdev port, and is bridged only with other ports from 5818c2ecf20Sopenharmony_ci * the same hardware device. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci if (netdev_uses_dsa(dev)) { 5848c2ecf20Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 5858c2ecf20Sopenharmony_ci if (!netdev_port_same_parent_id(dev, p->dev)) { 5868c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 5878c2ecf20Sopenharmony_ci "Cannot do software bridging with a DSA master"); 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* No bridging of bridges */ 5948c2ecf20Sopenharmony_ci if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) { 5958c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 5968c2ecf20Sopenharmony_ci "Can not enslave a bridge to a bridge"); 5978c2ecf20Sopenharmony_ci return -ELOOP; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Device has master upper dev */ 6018c2ecf20Sopenharmony_ci if (netdev_master_upper_dev_get(dev)) 6028c2ecf20Sopenharmony_ci return -EBUSY; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* No bridging devices that dislike that (e.g. wireless) */ 6058c2ecf20Sopenharmony_ci if (dev->priv_flags & IFF_DONT_BRIDGE) { 6068c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 6078c2ecf20Sopenharmony_ci "Device does not allow enslaving to a bridge"); 6088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci p = new_nbp(br, dev); 6128c2ecf20Sopenharmony_ci if (IS_ERR(p)) 6138c2ecf20Sopenharmony_ci return PTR_ERR(p); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci call_netdevice_notifiers(NETDEV_JOIN, dev); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci err = dev_set_allmulti(dev, 1); 6188c2ecf20Sopenharmony_ci if (err) { 6198c2ecf20Sopenharmony_ci br_multicast_del_port(p); 6208c2ecf20Sopenharmony_ci kfree(p); /* kobject not yet init'd, manually free */ 6218c2ecf20Sopenharmony_ci goto err1; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), 6258c2ecf20Sopenharmony_ci SYSFS_BRIDGE_PORT_ATTR); 6268c2ecf20Sopenharmony_ci if (err) 6278c2ecf20Sopenharmony_ci goto err2; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci err = br_sysfs_addif(p); 6308c2ecf20Sopenharmony_ci if (err) 6318c2ecf20Sopenharmony_ci goto err2; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci err = br_netpoll_enable(p); 6348c2ecf20Sopenharmony_ci if (err) 6358c2ecf20Sopenharmony_ci goto err3; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci err = netdev_rx_handler_register(dev, br_get_rx_handler(dev), p); 6388c2ecf20Sopenharmony_ci if (err) 6398c2ecf20Sopenharmony_ci goto err4; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_BRIDGE_PORT; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci err = netdev_master_upper_dev_link(dev, br->dev, NULL, NULL, extack); 6448c2ecf20Sopenharmony_ci if (err) 6458c2ecf20Sopenharmony_ci goto err5; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci err = nbp_switchdev_mark_set(p); 6488c2ecf20Sopenharmony_ci if (err) 6498c2ecf20Sopenharmony_ci goto err6; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci dev_disable_lro(dev); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci list_add_rcu(&p->list, &br->port_list); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci nbp_update_port_count(br); 6568c2ecf20Sopenharmony_ci if (!br_promisc_port(p) && (p->dev->priv_flags & IFF_UNICAST_FLT)) { 6578c2ecf20Sopenharmony_ci /* When updating the port count we also update all ports' 6588c2ecf20Sopenharmony_ci * promiscuous mode. 6598c2ecf20Sopenharmony_ci * A port leaving promiscuous mode normally gets the bridge's 6608c2ecf20Sopenharmony_ci * fdb synced to the unicast filter (if supported), however, 6618c2ecf20Sopenharmony_ci * `br_port_clear_promisc` does not distinguish between 6628c2ecf20Sopenharmony_ci * non-promiscuous ports and *new* ports, so we need to 6638c2ecf20Sopenharmony_ci * sync explicitly here. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci fdb_synced = br_fdb_sync_static(br, p) == 0; 6668c2ecf20Sopenharmony_ci if (!fdb_synced) 6678c2ecf20Sopenharmony_ci netdev_err(dev, "failed to sync bridge static fdb addresses to this port\n"); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci netdev_update_features(br->dev); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci br_hr = br->dev->needed_headroom; 6738c2ecf20Sopenharmony_ci dev_hr = netdev_get_fwd_headroom(dev); 6748c2ecf20Sopenharmony_ci if (br_hr < dev_hr) 6758c2ecf20Sopenharmony_ci update_headroom(br, dev_hr); 6768c2ecf20Sopenharmony_ci else 6778c2ecf20Sopenharmony_ci netdev_set_rx_headroom(dev, br_hr); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (br_fdb_insert(br, p, dev->dev_addr, 0)) 6808c2ecf20Sopenharmony_ci netdev_err(dev, "failed insert local address bridge forwarding table\n"); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (br->dev->addr_assign_type != NET_ADDR_SET) { 6838c2ecf20Sopenharmony_ci /* Ask for permission to use this MAC address now, even if we 6848c2ecf20Sopenharmony_ci * don't end up choosing it below. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci err = dev_pre_changeaddr_notify(br->dev, dev->dev_addr, extack); 6878c2ecf20Sopenharmony_ci if (err) 6888c2ecf20Sopenharmony_ci goto err7; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci err = nbp_vlan_init(p, extack); 6928c2ecf20Sopenharmony_ci if (err) { 6938c2ecf20Sopenharmony_ci netdev_err(dev, "failed to initialize vlan filtering on this port\n"); 6948c2ecf20Sopenharmony_ci goto err7; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci spin_lock_bh(&br->lock); 6988c2ecf20Sopenharmony_ci changed_addr = br_stp_recalculate_bridge_id(br); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (netif_running(dev) && netif_oper_up(dev) && 7018c2ecf20Sopenharmony_ci (br->dev->flags & IFF_UP)) 7028c2ecf20Sopenharmony_ci br_stp_enable_port(p); 7038c2ecf20Sopenharmony_ci spin_unlock_bh(&br->lock); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (changed_addr) 7088c2ecf20Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci br_mtu_auto_adjust(br); 7118c2ecf20Sopenharmony_ci br_set_gso_limits(br); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci kobject_uevent(&p->kobj, KOBJ_ADD); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cierr7: 7188c2ecf20Sopenharmony_ci if (fdb_synced) 7198c2ecf20Sopenharmony_ci br_fdb_unsync_static(br, p); 7208c2ecf20Sopenharmony_ci list_del_rcu(&p->list); 7218c2ecf20Sopenharmony_ci br_fdb_delete_by_port(br, p, 0, 1); 7228c2ecf20Sopenharmony_ci nbp_update_port_count(br); 7238c2ecf20Sopenharmony_cierr6: 7248c2ecf20Sopenharmony_ci netdev_upper_dev_unlink(dev, br->dev); 7258c2ecf20Sopenharmony_cierr5: 7268c2ecf20Sopenharmony_ci dev->priv_flags &= ~IFF_BRIDGE_PORT; 7278c2ecf20Sopenharmony_ci netdev_rx_handler_unregister(dev); 7288c2ecf20Sopenharmony_cierr4: 7298c2ecf20Sopenharmony_ci br_netpoll_disable(p); 7308c2ecf20Sopenharmony_cierr3: 7318c2ecf20Sopenharmony_ci sysfs_remove_link(br->ifobj, p->dev->name); 7328c2ecf20Sopenharmony_cierr2: 7338c2ecf20Sopenharmony_ci br_multicast_del_port(p); 7348c2ecf20Sopenharmony_ci kobject_put(&p->kobj); 7358c2ecf20Sopenharmony_ci dev_set_allmulti(dev, -1); 7368c2ecf20Sopenharmony_cierr1: 7378c2ecf20Sopenharmony_ci dev_put(dev); 7388c2ecf20Sopenharmony_ci return err; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci/* called with RTNL */ 7428c2ecf20Sopenharmony_ciint br_del_if(struct net_bridge *br, struct net_device *dev) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct net_bridge_port *p; 7458c2ecf20Sopenharmony_ci bool changed_addr; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci p = br_port_get_rtnl(dev); 7488c2ecf20Sopenharmony_ci if (!p || p->br != br) 7498c2ecf20Sopenharmony_ci return -EINVAL; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Since more than one interface can be attached to a bridge, 7528c2ecf20Sopenharmony_ci * there still maybe an alternate path for netconsole to use; 7538c2ecf20Sopenharmony_ci * therefore there is no reason for a NETDEV_RELEASE event. 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci del_nbp(p); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci br_mtu_auto_adjust(br); 7588c2ecf20Sopenharmony_ci br_set_gso_limits(br); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci spin_lock_bh(&br->lock); 7618c2ecf20Sopenharmony_ci changed_addr = br_stp_recalculate_bridge_id(br); 7628c2ecf20Sopenharmony_ci spin_unlock_bh(&br->lock); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (changed_addr) 7658c2ecf20Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci netdev_update_features(br->dev); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci return 0; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_civoid br_port_flags_change(struct net_bridge_port *p, unsigned long mask) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct net_bridge *br = p->br; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (mask & BR_AUTO_MASK) 7778c2ecf20Sopenharmony_ci nbp_update_port_count(br); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (mask & BR_NEIGH_SUPPRESS) 7808c2ecf20Sopenharmony_ci br_recalculate_neigh_suppress_enabled(br); 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cibool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct net_bridge_port *p; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci p = br_port_get_rtnl_rcu(dev); 7888c2ecf20Sopenharmony_ci if (!p) 7898c2ecf20Sopenharmony_ci return false; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return p->flags & flag; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(br_port_flag_is_set); 794