2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Device handling code
|
|
|
|
* Linux ethernet bridge
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Lennert Buytenhek <buytenh@gnu.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/netdevice.h>
|
2010-05-06 07:48:24 +00:00
|
|
|
#include <linux/netpoll.h>
|
2005-12-22 02:51:49 +00:00
|
|
|
#include <linux/etherdevice.h>
|
2005-12-22 03:00:58 +00:00
|
|
|
#include <linux/ethtool.h>
|
2010-05-06 07:48:24 +00:00
|
|
|
#include <linux/list.h>
|
2010-04-15 10:14:51 +00:00
|
|
|
#include <linux/netfilter_bridge.h>
|
2005-12-22 02:51:49 +00:00
|
|
|
|
2016-12-24 19:46:01 +00:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "br_private.h"
|
|
|
|
|
2013-05-22 07:49:34 +00:00
|
|
|
#define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \
|
|
|
|
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM)
|
|
|
|
|
2015-03-10 09:27:18 +00:00
|
|
|
const struct nf_br_ops __rcu *nf_br_ops __read_mostly;
|
|
|
|
EXPORT_SYMBOL_GPL(nf_br_ops);
|
|
|
|
|
2016-01-15 18:03:54 +00:00
|
|
|
static struct lock_class_key bridge_netdev_addr_lock_key;
|
|
|
|
|
2010-07-27 08:26:30 +00:00
|
|
|
/* net device transmit always called with BH disabled */
|
2009-08-31 19:50:41 +00:00
|
|
|
netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
struct net_bridge_fdb_entry *dst;
|
2010-02-27 19:41:48 +00:00
|
|
|
struct net_bridge_mdb_entry *mdst;
|
2014-01-04 05:57:59 +00:00
|
|
|
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
|
2015-03-10 09:27:18 +00:00
|
|
|
const struct nf_br_ops *nf_ops;
|
2017-07-13 13:09:10 +00:00
|
|
|
const unsigned char *dest;
|
2017-10-07 05:12:38 +00:00
|
|
|
struct ethhdr *eth;
|
2013-02-13 12:00:14 +00:00
|
|
|
u16 vid = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2012-08-14 15:19:33 +00:00
|
|
|
rcu_read_lock();
|
2015-03-10 09:27:18 +00:00
|
|
|
nf_ops = rcu_dereference(nf_br_ops);
|
|
|
|
if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) {
|
2012-08-14 15:19:33 +00:00
|
|
|
rcu_read_unlock();
|
2010-04-15 10:14:51 +00:00
|
|
|
return NETDEV_TX_OK;
|
|
|
|
}
|
|
|
|
|
2010-06-23 20:00:48 +00:00
|
|
|
u64_stats_update_begin(&brstats->syncp);
|
2010-03-02 13:32:09 +00:00
|
|
|
brstats->tx_packets++;
|
|
|
|
brstats->tx_bytes += skb->len;
|
2010-06-23 20:00:48 +00:00
|
|
|
u64_stats_update_end(&brstats->syncp);
|
2010-02-27 19:41:42 +00:00
|
|
|
|
2017-09-03 14:44:13 +00:00
|
|
|
br_switchdev_frame_unmark(skb);
|
2010-03-02 13:32:09 +00:00
|
|
|
BR_INPUT_SKB_CB(skb)->brdev = dev;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-03-19 22:30:44 +00:00
|
|
|
skb_reset_mac_header(skb);
|
2017-10-07 05:12:38 +00:00
|
|
|
eth = eth_hdr(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
skb_pull(skb, ETH_HLEN);
|
|
|
|
|
2015-10-12 19:47:02 +00:00
|
|
|
if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid))
|
2014-03-27 12:46:55 +00:00
|
|
|
goto out;
|
|
|
|
|
2017-10-07 05:12:38 +00:00
|
|
|
if (IS_ENABLED(CONFIG_INET) &&
|
|
|
|
(eth->h_proto == htons(ETH_P_ARP) ||
|
|
|
|
eth->h_proto == htons(ETH_P_RARP)) &&
|
2018-09-26 14:01:05 +00:00
|
|
|
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
|
2017-10-07 05:12:38 +00:00
|
|
|
br_do_proxy_suppress_arp(skb, br, vid, NULL);
|
2017-10-07 05:12:39 +00:00
|
|
|
} else if (IS_ENABLED(CONFIG_IPV6) &&
|
|
|
|
skb->protocol == htons(ETH_P_IPV6) &&
|
2018-09-26 14:01:05 +00:00
|
|
|
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
|
2017-10-07 05:12:39 +00:00
|
|
|
pskb_may_pull(skb, sizeof(struct ipv6hdr) +
|
|
|
|
sizeof(struct nd_msg)) &&
|
|
|
|
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
|
|
|
|
struct nd_msg *msg, _msg;
|
|
|
|
|
|
|
|
msg = br_is_nd_neigh_msg(skb, &_msg);
|
|
|
|
if (msg)
|
|
|
|
br_do_suppress_nd(skb, br, vid, NULL, msg);
|
2017-10-07 05:12:38 +00:00
|
|
|
}
|
|
|
|
|
2017-07-13 13:09:10 +00:00
|
|
|
dest = eth_hdr(skb)->h_dest;
|
2016-07-14 03:10:02 +00:00
|
|
|
if (is_broadcast_ether_addr(dest)) {
|
2016-08-31 13:36:51 +00:00
|
|
|
br_flood(br, skb, BR_PKT_BROADCAST, false, true);
|
2016-07-14 03:10:02 +00:00
|
|
|
} else if (is_multicast_ether_addr(dest)) {
|
2010-06-10 16:12:50 +00:00
|
|
|
if (unlikely(netpoll_tx_running(dev))) {
|
2016-08-31 13:36:51 +00:00
|
|
|
br_flood(br, skb, BR_PKT_MULTICAST, false, true);
|
2010-06-10 16:12:50 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2013-10-28 19:45:07 +00:00
|
|
|
if (br_multicast_rcv(br, NULL, skb, vid)) {
|
2010-07-29 01:12:31 +00:00
|
|
|
kfree_skb(skb);
|
2010-02-27 19:41:48 +00:00
|
|
|
goto out;
|
2010-07-29 01:12:31 +00:00
|
|
|
}
|
2010-02-27 19:41:48 +00:00
|
|
|
|
2013-03-07 03:05:33 +00:00
|
|
|
mdst = br_mdb_get(br, skb, vid);
|
2013-07-31 23:06:20 +00:00
|
|
|
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
|
2013-08-30 15:28:17 +00:00
|
|
|
br_multicast_querier_exists(br, eth_hdr(skb)))
|
2016-07-14 03:10:02 +00:00
|
|
|
br_multicast_flood(mdst, skb, false, true);
|
2010-02-27 19:41:48 +00:00
|
|
|
else
|
2016-08-31 13:36:51 +00:00
|
|
|
br_flood(br, skb, BR_PKT_MULTICAST, false, true);
|
2017-02-13 13:59:09 +00:00
|
|
|
} else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) {
|
2016-07-14 03:10:02 +00:00
|
|
|
br_forward(dst->dst, skb, false, true);
|
|
|
|
} else {
|
2016-08-31 13:36:51 +00:00
|
|
|
br_flood(br, skb, BR_PKT_UNICAST, false, true);
|
2016-07-14 03:10:02 +00:00
|
|
|
}
|
2010-02-27 19:41:48 +00:00
|
|
|
out:
|
2010-07-27 08:26:30 +00:00
|
|
|
rcu_read_unlock();
|
2009-06-23 06:03:08 +00:00
|
|
|
return NETDEV_TX_OK;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 18:03:54 +00:00
|
|
|
static void br_set_lockdep_class(struct net_device *dev)
|
|
|
|
{
|
|
|
|
lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key);
|
|
|
|
}
|
|
|
|
|
2011-04-04 14:03:32 +00:00
|
|
|
static int br_dev_init(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
2014-10-03 15:29:18 +00:00
|
|
|
int err;
|
2011-04-04 14:03:32 +00:00
|
|
|
|
2014-02-13 19:46:28 +00:00
|
|
|
br->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
2011-04-04 14:03:32 +00:00
|
|
|
if (!br->stats)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-12-12 14:02:50 +00:00
|
|
|
err = br_fdb_hash_init(br);
|
|
|
|
if (err) {
|
|
|
|
free_percpu(br->stats);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-12-05 13:14:24 +00:00
|
|
|
err = br_mdb_hash_init(br);
|
|
|
|
if (err) {
|
|
|
|
free_percpu(br->stats);
|
|
|
|
br_fdb_hash_fini(br);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2014-10-03 15:29:18 +00:00
|
|
|
err = br_vlan_init(br);
|
2016-06-28 14:57:06 +00:00
|
|
|
if (err) {
|
2014-10-03 15:29:18 +00:00
|
|
|
free_percpu(br->stats);
|
2018-12-05 13:14:24 +00:00
|
|
|
br_mdb_hash_fini(br);
|
2017-12-12 14:02:50 +00:00
|
|
|
br_fdb_hash_fini(br);
|
2016-06-28 14:57:06 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = br_multicast_init_stats(br);
|
|
|
|
if (err) {
|
|
|
|
free_percpu(br->stats);
|
|
|
|
br_vlan_flush(br);
|
2018-12-05 13:14:24 +00:00
|
|
|
br_mdb_hash_fini(br);
|
2017-12-12 14:02:50 +00:00
|
|
|
br_fdb_hash_fini(br);
|
2016-06-28 14:57:06 +00:00
|
|
|
}
|
2016-01-15 18:03:54 +00:00
|
|
|
br_set_lockdep_class(dev);
|
2014-10-03 15:29:18 +00:00
|
|
|
|
|
|
|
return err;
|
2011-04-04 14:03:32 +00:00
|
|
|
}
|
|
|
|
|
2017-04-10 11:59:27 +00:00
|
|
|
static void br_dev_uninit(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
|
2017-04-25 14:58:37 +00:00
|
|
|
br_multicast_dev_del(br);
|
2017-04-10 11:59:27 +00:00
|
|
|
br_multicast_uninit_stats(br);
|
|
|
|
br_vlan_flush(br);
|
2018-12-05 13:14:24 +00:00
|
|
|
br_mdb_hash_fini(br);
|
2017-12-12 14:02:50 +00:00
|
|
|
br_fdb_hash_fini(br);
|
2017-04-10 11:59:27 +00:00
|
|
|
free_percpu(br->stats);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static int br_dev_open(struct net_device *dev)
|
|
|
|
{
|
2005-05-29 21:15:17 +00:00
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2011-04-22 06:31:16 +00:00
|
|
|
netdev_update_features(dev);
|
2005-05-29 21:15:17 +00:00
|
|
|
netif_start_queue(dev);
|
|
|
|
br_stp_enable_bridge(br);
|
2010-02-28 08:49:38 +00:00
|
|
|
br_multicast_open(br);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void br_dev_set_multicast_list(struct net_device *dev)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-05-16 13:59:20 +00:00
|
|
|
static void br_dev_change_rx_flags(struct net_device *dev, int change)
|
|
|
|
{
|
|
|
|
if (change & IFF_PROMISC)
|
|
|
|
br_manage_promisc(netdev_priv(dev));
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static int br_dev_stop(struct net_device *dev)
|
|
|
|
{
|
2010-02-28 08:49:38 +00:00
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
|
|
|
|
br_stp_disable_bridge(br);
|
|
|
|
br_multicast_stop(br);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
netif_stop_queue(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-07 03:12:52 +00:00
|
|
|
static void br_get_stats64(struct net_device *dev,
|
|
|
|
struct rtnl_link_stats64 *stats)
|
2010-03-02 13:32:09 +00:00
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
2014-01-04 05:57:59 +00:00
|
|
|
struct pcpu_sw_netstats tmp, sum = { 0 };
|
2010-03-02 13:32:09 +00:00
|
|
|
unsigned int cpu;
|
|
|
|
|
|
|
|
for_each_possible_cpu(cpu) {
|
2010-06-23 20:00:48 +00:00
|
|
|
unsigned int start;
|
2014-01-04 05:57:59 +00:00
|
|
|
const struct pcpu_sw_netstats *bstats
|
2010-03-02 13:32:09 +00:00
|
|
|
= per_cpu_ptr(br->stats, cpu);
|
2010-06-23 20:00:48 +00:00
|
|
|
do {
|
2014-03-14 04:26:42 +00:00
|
|
|
start = u64_stats_fetch_begin_irq(&bstats->syncp);
|
2010-06-23 20:00:48 +00:00
|
|
|
memcpy(&tmp, bstats, sizeof(tmp));
|
2014-03-14 04:26:42 +00:00
|
|
|
} while (u64_stats_fetch_retry_irq(&bstats->syncp, start));
|
2010-06-23 20:00:48 +00:00
|
|
|
sum.tx_bytes += tmp.tx_bytes;
|
|
|
|
sum.tx_packets += tmp.tx_packets;
|
|
|
|
sum.rx_bytes += tmp.rx_bytes;
|
|
|
|
sum.rx_packets += tmp.rx_packets;
|
2010-03-02 13:32:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stats->tx_bytes = sum.tx_bytes;
|
|
|
|
stats->tx_packets = sum.tx_packets;
|
|
|
|
stats->rx_bytes = sum.rx_bytes;
|
|
|
|
stats->rx_packets = sum.rx_packets;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static int br_change_mtu(struct net_device *dev, int new_mtu)
|
|
|
|
{
|
2008-07-30 23:27:55 +00:00
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
2018-03-30 10:46:18 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->mtu = new_mtu;
|
2008-07-30 23:27:55 +00:00
|
|
|
|
2018-03-30 10:46:19 +00:00
|
|
|
/* this flag will be cleared if the MTU was automatically adjusted */
|
2018-09-26 14:01:06 +00:00
|
|
|
br_opt_toggle(br, BROPT_MTU_SET_BY_USER, true);
|
2014-09-18 09:29:03 +00:00
|
|
|
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
2008-07-30 23:27:55 +00:00
|
|
|
/* remember the MTU in the rtable for PMTU */
|
2010-12-09 05:16:57 +00:00
|
|
|
dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
|
2008-07-30 23:27:55 +00:00
|
|
|
#endif
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-09 18:49:58 +00:00
|
|
|
/* Allow setting mac address to any valid ethernet address. */
|
2005-12-22 02:51:49 +00:00
|
|
|
static int br_set_mac_address(struct net_device *dev, void *p)
|
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
struct sockaddr *addr = p;
|
2007-04-09 18:49:58 +00:00
|
|
|
|
|
|
|
if (!is_valid_ether_addr(addr->sa_data))
|
2012-02-21 02:07:52 +00:00
|
|
|
return -EADDRNOTAVAIL;
|
2005-12-22 02:51:49 +00:00
|
|
|
|
|
|
|
spin_lock_bh(&br->lock);
|
bridge: Convert compare_ether_addr to ether_addr_equal
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-05-08 18:56:49 +00:00
|
|
|
if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
|
2014-02-07 07:48:20 +00:00
|
|
|
/* Mac address will be changed in br_stp_change_bridge_id(). */
|
2011-12-08 07:17:49 +00:00
|
|
|
br_stp_change_bridge_id(br, addr->sa_data);
|
|
|
|
}
|
2005-12-22 02:51:49 +00:00
|
|
|
spin_unlock_bh(&br->lock);
|
|
|
|
|
2007-04-09 18:49:58 +00:00
|
|
|
return 0;
|
2005-12-22 02:51:49 +00:00
|
|
|
}
|
|
|
|
|
2005-12-22 03:00:58 +00:00
|
|
|
static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
|
|
|
{
|
2013-01-06 00:44:26 +00:00
|
|
|
strlcpy(info->driver, "bridge", sizeof(info->driver));
|
|
|
|
strlcpy(info->version, BR_VERSION, sizeof(info->version));
|
|
|
|
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
|
|
|
|
strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
|
2005-12-22 03:00:58 +00:00
|
|
|
}
|
|
|
|
|
2011-11-15 15:29:55 +00:00
|
|
|
static netdev_features_t br_fix_features(struct net_device *dev,
|
|
|
|
netdev_features_t features)
|
2005-12-22 03:00:58 +00:00
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
|
2011-04-22 06:31:16 +00:00
|
|
|
return br_features_recompute(br, features);
|
2010-10-20 13:56:08 +00:00
|
|
|
}
|
|
|
|
|
2010-05-06 07:48:24 +00:00
|
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
2010-06-10 16:12:50 +00:00
|
|
|
static void br_poll_controller(struct net_device *br_dev)
|
2010-05-06 07:48:24 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-06-10 16:12:50 +00:00
|
|
|
static void br_netpoll_cleanup(struct net_device *dev)
|
2010-05-06 07:48:24 +00:00
|
|
|
{
|
2010-06-10 16:12:50 +00:00
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
2012-08-10 01:24:44 +00:00
|
|
|
struct net_bridge_port *p;
|
2010-05-06 07:48:24 +00:00
|
|
|
|
2012-08-10 01:24:44 +00:00
|
|
|
list_for_each_entry(p, &br->port_list, list)
|
2010-06-10 16:12:50 +00:00
|
|
|
br_netpoll_disable(p);
|
2010-05-06 07:48:24 +00:00
|
|
|
}
|
|
|
|
|
2014-03-27 22:36:38 +00:00
|
|
|
static int __br_netpoll_enable(struct net_bridge_port *p)
|
2014-02-06 23:00:52 +00:00
|
|
|
{
|
|
|
|
struct netpoll *np;
|
|
|
|
int err;
|
|
|
|
|
2014-03-27 22:36:38 +00:00
|
|
|
np = kzalloc(sizeof(*p->np), GFP_KERNEL);
|
2014-02-06 23:00:52 +00:00
|
|
|
if (!np)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-03-27 22:36:38 +00:00
|
|
|
err = __netpoll_setup(np, p->dev);
|
2014-02-06 23:00:52 +00:00
|
|
|
if (err) {
|
|
|
|
kfree(np);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->np = np;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2014-03-27 22:36:38 +00:00
|
|
|
int br_netpoll_enable(struct net_bridge_port *p)
|
2014-02-06 23:00:52 +00:00
|
|
|
{
|
|
|
|
if (!p->br->dev->npinfo)
|
|
|
|
return 0;
|
|
|
|
|
2014-03-27 22:36:38 +00:00
|
|
|
return __br_netpoll_enable(p);
|
2014-02-06 23:00:52 +00:00
|
|
|
}
|
|
|
|
|
2014-03-27 22:36:38 +00:00
|
|
|
static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
|
2010-05-06 07:48:24 +00:00
|
|
|
{
|
2010-05-10 09:31:08 +00:00
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
2012-08-10 01:24:44 +00:00
|
|
|
struct net_bridge_port *p;
|
2010-06-10 16:12:50 +00:00
|
|
|
int err = 0;
|
2010-05-06 07:48:24 +00:00
|
|
|
|
2012-08-10 01:24:44 +00:00
|
|
|
list_for_each_entry(p, &br->port_list, list) {
|
2010-06-10 16:12:50 +00:00
|
|
|
if (!p->dev)
|
|
|
|
continue;
|
2014-03-27 22:36:38 +00:00
|
|
|
err = __br_netpoll_enable(p);
|
2010-06-10 16:12:50 +00:00
|
|
|
if (err)
|
|
|
|
goto fail;
|
2010-05-06 07:48:24 +00:00
|
|
|
}
|
2010-06-10 16:12:50 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
br_netpoll_cleanup(dev);
|
|
|
|
goto out;
|
2010-05-06 07:48:24 +00:00
|
|
|
}
|
|
|
|
|
2010-06-10 16:12:50 +00:00
|
|
|
void br_netpoll_disable(struct net_bridge_port *p)
|
2010-05-06 07:48:24 +00:00
|
|
|
{
|
2010-06-10 16:12:50 +00:00
|
|
|
struct netpoll *np = p->np;
|
|
|
|
|
|
|
|
if (!np)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->np = NULL;
|
|
|
|
|
2018-10-18 15:18:26 +00:00
|
|
|
__netpoll_free(np);
|
2010-05-06 07:48:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-10-05 00:48:46 +00:00
|
|
|
static int br_add_slave(struct net_device *dev, struct net_device *slave_dev,
|
|
|
|
struct netlink_ext_ack *extack)
|
2011-02-13 09:33:42 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
|
2017-10-05 00:48:50 +00:00
|
|
|
return br_add_if(br, slave_dev, extack);
|
2011-02-13 09:33:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
|
|
|
|
{
|
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
|
|
|
|
return br_del_if(br, slave_dev);
|
|
|
|
}
|
|
|
|
|
2008-11-20 05:49:00 +00:00
|
|
|
static const struct ethtool_ops br_ethtool_ops = {
|
2008-08-16 02:51:07 +00:00
|
|
|
.get_drvinfo = br_getinfo,
|
|
|
|
.get_link = ethtool_op_get_link,
|
2005-12-22 03:00:58 +00:00
|
|
|
};
|
|
|
|
|
2008-11-20 05:49:00 +00:00
|
|
|
static const struct net_device_ops br_netdev_ops = {
|
|
|
|
.ndo_open = br_dev_open,
|
|
|
|
.ndo_stop = br_dev_stop,
|
2011-04-04 14:03:32 +00:00
|
|
|
.ndo_init = br_dev_init,
|
2017-04-10 11:59:27 +00:00
|
|
|
.ndo_uninit = br_dev_uninit,
|
2008-11-21 04:14:53 +00:00
|
|
|
.ndo_start_xmit = br_dev_xmit,
|
2010-06-23 20:00:48 +00:00
|
|
|
.ndo_get_stats64 = br_get_stats64,
|
2008-11-21 04:14:53 +00:00
|
|
|
.ndo_set_mac_address = br_set_mac_address,
|
2011-08-16 06:29:01 +00:00
|
|
|
.ndo_set_rx_mode = br_dev_set_multicast_list,
|
2014-05-16 13:59:20 +00:00
|
|
|
.ndo_change_rx_flags = br_dev_change_rx_flags,
|
2008-11-21 04:14:53 +00:00
|
|
|
.ndo_change_mtu = br_change_mtu,
|
|
|
|
.ndo_do_ioctl = br_dev_ioctl,
|
2010-05-06 07:48:24 +00:00
|
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
2010-06-10 16:12:50 +00:00
|
|
|
.ndo_netpoll_setup = br_netpoll_setup,
|
2010-05-06 07:48:24 +00:00
|
|
|
.ndo_netpoll_cleanup = br_netpoll_cleanup,
|
|
|
|
.ndo_poll_controller = br_poll_controller,
|
|
|
|
#endif
|
2011-02-13 09:33:42 +00:00
|
|
|
.ndo_add_slave = br_add_slave,
|
|
|
|
.ndo_del_slave = br_del_slave,
|
2011-04-22 06:31:16 +00:00
|
|
|
.ndo_fix_features = br_fix_features,
|
2012-04-15 06:43:56 +00:00
|
|
|
.ndo_fdb_add = br_fdb_add,
|
|
|
|
.ndo_fdb_del = br_fdb_delete,
|
|
|
|
.ndo_fdb_dump = br_fdb_dump,
|
2018-12-16 06:35:09 +00:00
|
|
|
.ndo_fdb_get = br_fdb_get,
|
2012-10-24 08:12:57 +00:00
|
|
|
.ndo_bridge_getlink = br_getlink,
|
|
|
|
.ndo_bridge_setlink = br_setlink,
|
2013-02-13 12:00:12 +00:00
|
|
|
.ndo_bridge_dellink = br_dellink,
|
2015-07-31 06:03:26 +00:00
|
|
|
.ndo_features_check = passthru_features_check,
|
2008-11-20 05:49:00 +00:00
|
|
|
};
|
|
|
|
|
2011-04-04 14:03:32 +00:00
|
|
|
static struct device_type br_type = {
|
|
|
|
.name = "bridge",
|
|
|
|
};
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
void br_dev_setup(struct net_device *dev)
|
|
|
|
{
|
2011-04-04 14:03:32 +00:00
|
|
|
struct net_bridge *br = netdev_priv(dev);
|
|
|
|
|
2012-02-15 06:45:40 +00:00
|
|
|
eth_hw_addr_random(dev);
|
2005-04-16 22:20:36 +00:00
|
|
|
ether_setup(dev);
|
|
|
|
|
2008-11-20 05:49:00 +00:00
|
|
|
dev->netdev_ops = &br_netdev_ops;
|
net: Fix inconsistent teardown and release of private netdev state.
Network devices can allocate reasources and private memory using
netdev_ops->ndo_init(). However, the release of these resources
can occur in one of two different places.
Either netdev_ops->ndo_uninit() or netdev->destructor().
The decision of which operation frees the resources depends upon
whether it is necessary for all netdev refs to be released before it
is safe to perform the freeing.
netdev_ops->ndo_uninit() presumably can occur right after the
NETDEV_UNREGISTER notifier completes and the unicast and multicast
address lists are flushed.
netdev->destructor(), on the other hand, does not run until the
netdev references all go away.
Further complicating the situation is that netdev->destructor()
almost universally does also a free_netdev().
This creates a problem for the logic in register_netdevice().
Because all callers of register_netdevice() manage the freeing
of the netdev, and invoke free_netdev(dev) if register_netdevice()
fails.
If netdev_ops->ndo_init() succeeds, but something else fails inside
of register_netdevice(), it does call ndo_ops->ndo_uninit(). But
it is not able to invoke netdev->destructor().
This is because netdev->destructor() will do a free_netdev() and
then the caller of register_netdevice() will do the same.
However, this means that the resources that would normally be released
by netdev->destructor() will not be.
Over the years drivers have added local hacks to deal with this, by
invoking their destructor parts by hand when register_netdevice()
fails.
Many drivers do not try to deal with this, and instead we have leaks.
Let's close this hole by formalizing the distinction between what
private things need to be freed up by netdev->destructor() and whether
the driver needs unregister_netdevice() to perform the free_netdev().
netdev->priv_destructor() performs all actions to free up the private
resources that used to be freed by netdev->destructor(), except for
free_netdev().
netdev->needs_free_netdev is a boolean that indicates whether
free_netdev() should be done at the end of unregister_netdevice().
Now, register_netdevice() can sanely release all resources after
ndo_ops->ndo_init() succeeds, by invoking both ndo_ops->ndo_uninit()
and netdev->priv_destructor().
And at the end of unregister_netdevice(), we invoke
netdev->priv_destructor() and optionally call free_netdev().
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-05-08 16:52:56 +00:00
|
|
|
dev->needs_free_netdev = true;
|
2014-05-11 00:12:32 +00:00
|
|
|
dev->ethtool_ops = &br_ethtool_ops;
|
2011-04-04 14:03:32 +00:00
|
|
|
SET_NETDEV_DEVTYPE(dev, &br_type);
|
2015-08-18 08:30:37 +00:00
|
|
|
dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE;
|
2005-12-22 03:00:58 +00:00
|
|
|
|
2013-05-22 07:49:34 +00:00
|
|
|
dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL |
|
2014-06-10 11:59:22 +00:00
|
|
|
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
|
|
|
|
dev->hw_features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
|
|
|
|
NETIF_F_HW_VLAN_STAG_TX;
|
2013-05-22 07:49:34 +00:00
|
|
|
dev->vlan_features = COMMON_FEATURES;
|
2011-04-04 14:03:32 +00:00
|
|
|
|
|
|
|
br->dev = dev;
|
|
|
|
spin_lock_init(&br->lock);
|
|
|
|
INIT_LIST_HEAD(&br->port_list);
|
2017-12-12 14:02:50 +00:00
|
|
|
INIT_HLIST_HEAD(&br->fdb_list);
|
2011-04-04 14:03:32 +00:00
|
|
|
spin_lock_init(&br->hash_lock);
|
|
|
|
|
|
|
|
br->bridge_id.prio[0] = 0x80;
|
|
|
|
br->bridge_id.prio[1] = 0x00;
|
|
|
|
|
2017-11-02 09:36:48 +00:00
|
|
|
ether_addr_copy(br->group_addr, eth_stp_addr);
|
2011-04-04 14:03:32 +00:00
|
|
|
|
|
|
|
br->stp_enabled = BR_NO_STP;
|
2011-10-03 18:14:46 +00:00
|
|
|
br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
|
2014-06-10 11:59:24 +00:00
|
|
|
br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
|
2011-10-03 18:14:46 +00:00
|
|
|
|
2011-04-04 14:03:32 +00:00
|
|
|
br->designated_root = br->bridge_id;
|
|
|
|
br->bridge_max_age = br->max_age = 20 * HZ;
|
|
|
|
br->bridge_hello_time = br->hello_time = 2 * HZ;
|
|
|
|
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
2016-12-10 18:44:29 +00:00
|
|
|
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
net: use core MTU range checking in core net infra
geneve:
- Merge __geneve_change_mtu back into geneve_change_mtu, set max_mtu
- This one isn't quite as straight-forward as others, could use some
closer inspection and testing
macvlan:
- set min/max_mtu
tun:
- set min/max_mtu, remove tun_net_change_mtu
vxlan:
- Merge __vxlan_change_mtu back into vxlan_change_mtu
- Set max_mtu to IP_MAX_MTU and retain dynamic MTU range checks in
change_mtu function
- This one is also not as straight-forward and could use closer inspection
and testing from vxlan folks
bridge:
- set max_mtu of IP_MAX_MTU and retain dynamic MTU range checks in
change_mtu function
openvswitch:
- set min/max_mtu, remove internal_dev_change_mtu
- note: max_mtu wasn't checked previously, it's been set to 65535, which
is the largest possible size supported
sch_teql:
- set min/max_mtu (note: max_mtu previously unchecked, used max of 65535)
macsec:
- min_mtu = 0, max_mtu = 65535
macvlan:
- min_mtu = 0, max_mtu = 65535
ntb_netdev:
- min_mtu = 0, max_mtu = 65535
veth:
- min_mtu = 68, max_mtu = 65535
8021q:
- min_mtu = 0, max_mtu = 65535
CC: netdev@vger.kernel.org
CC: Nicolas Dichtel <nicolas.dichtel@6wind.com>
CC: Hannes Frederic Sowa <hannes@stressinduktion.org>
CC: Tom Herbert <tom@herbertland.com>
CC: Daniel Borkmann <daniel@iogearbox.net>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Paolo Abeni <pabeni@redhat.com>
CC: Jiri Benc <jbenc@redhat.com>
CC: WANG Cong <xiyou.wangcong@gmail.com>
CC: Roopa Prabhu <roopa@cumulusnetworks.com>
CC: Pravin B Shelar <pshelar@ovn.org>
CC: Sabrina Dubroca <sd@queasysnail.net>
CC: Patrick McHardy <kaber@trash.net>
CC: Stephen Hemminger <stephen@networkplumber.org>
CC: Pravin Shelar <pshelar@nicira.com>
CC: Maxim Krasnyansky <maxk@qti.qualcomm.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-10-20 17:55:20 +00:00
|
|
|
dev->max_mtu = ETH_MAX_MTU;
|
2011-04-04 14:03:32 +00:00
|
|
|
|
|
|
|
br_netfilter_rtable_init(br);
|
|
|
|
br_stp_timer_init(br);
|
|
|
|
br_multicast_init(br);
|
2017-02-04 17:05:07 +00:00
|
|
|
INIT_DELAYED_WORK(&br->gc_work, br_fdb_cleanup);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|