2005-04-17 02:20:36 +04: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 11:48:24 +04:00
# include <linux/netpoll.h>
2005-12-22 05:51:49 +03:00
# include <linux/etherdevice.h>
2005-12-22 06:00:58 +03:00
# include <linux/ethtool.h>
2010-05-06 11:48:24 +04:00
# include <linux/list.h>
2010-04-15 14:14:51 +04:00
# include <linux/netfilter_bridge.h>
2005-12-22 05:51:49 +03:00
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include "br_private.h"
2013-05-22 11:49:34 +04:00
# define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM )
2015-03-10 12:27:18 +03:00
const struct nf_br_ops __rcu * nf_br_ops __read_mostly ;
EXPORT_SYMBOL_GPL ( nf_br_ops ) ;
2010-07-27 12:26:30 +04:00
/* net device transmit always called with BH disabled */
2009-08-31 23:50:41 +04:00
netdev_tx_t br_dev_xmit ( struct sk_buff * skb , struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct net_bridge * br = netdev_priv ( dev ) ;
const unsigned char * dest = skb - > data ;
struct net_bridge_fdb_entry * dst ;
2010-02-27 22:41:48 +03:00
struct net_bridge_mdb_entry * mdst ;
2014-01-04 09:57:59 +04:00
struct pcpu_sw_netstats * brstats = this_cpu_ptr ( br - > stats ) ;
2015-03-10 12:27:18 +03:00
const struct nf_br_ops * nf_ops ;
2013-02-13 16:00:14 +04:00
u16 vid = 0 ;
2005-04-17 02:20:36 +04:00
2012-08-14 19:19:33 +04:00
rcu_read_lock ( ) ;
2015-03-10 12:27:18 +03:00
nf_ops = rcu_dereference ( nf_br_ops ) ;
if ( nf_ops & & nf_ops - > br_dev_xmit_hook ( skb ) ) {
2012-08-14 19:19:33 +04:00
rcu_read_unlock ( ) ;
2010-04-15 14:14:51 +04:00
return NETDEV_TX_OK ;
}
2010-06-24 00:00:48 +04:00
u64_stats_update_begin ( & brstats - > syncp ) ;
2010-03-02 16:32:09 +03:00
brstats - > tx_packets + + ;
brstats - > tx_bytes + = skb - > len ;
2010-06-24 00:00:48 +04:00
u64_stats_update_end ( & brstats - > syncp ) ;
2010-02-27 22:41:42 +03:00
2010-03-02 16:32:09 +03:00
BR_INPUT_SKB_CB ( skb ) - > brdev = dev ;
2005-04-17 02:20:36 +04:00
2007-03-20 01:30:44 +03:00
skb_reset_mac_header ( skb ) ;
2005-04-17 02:20:36 +04:00
skb_pull ( skb , ETH_HLEN ) ;
2015-09-30 21:16:53 +03:00
if ( ! br_allowed_ingress ( br , br_vlan_group ( br ) , skb , & vid ) )
2014-03-27 16:46:55 +04:00
goto out ;
2011-07-05 17:58:33 +04:00
if ( is_broadcast_ether_addr ( dest ) )
2013-06-05 18:08:01 +04:00
br_flood_deliver ( br , skb , false ) ;
2011-07-05 17:58:33 +04:00
else if ( is_multicast_ether_addr ( dest ) ) {
2010-06-10 20:12:50 +04:00
if ( unlikely ( netpoll_tx_running ( dev ) ) ) {
2013-06-05 18:08:01 +04:00
br_flood_deliver ( br , skb , false ) ;
2010-06-10 20:12:50 +04:00
goto out ;
}
2013-10-28 23:45:07 +04:00
if ( br_multicast_rcv ( br , NULL , skb , vid ) ) {
2010-07-29 05:12:31 +04:00
kfree_skb ( skb ) ;
2010-02-27 22:41:48 +03:00
goto out ;
2010-07-29 05:12:31 +04:00
}
2010-02-27 22:41:48 +03:00
2013-03-07 07:05:33 +04:00
mdst = br_mdb_get ( br , skb , vid ) ;
2013-08-01 03:06:20 +04:00
if ( ( mdst | | BR_INPUT_SKB_CB_MROUTERS_ONLY ( skb ) ) & &
2013-08-30 19:28:17 +04:00
br_multicast_querier_exists ( br , eth_hdr ( skb ) ) )
2010-02-27 22:41:48 +03:00
br_multicast_deliver ( mdst , skb ) ;
else
2013-06-05 18:08:01 +04:00
br_flood_deliver ( br , skb , false ) ;
2013-02-13 16:00:16 +04:00
} else if ( ( dst = __br_fdb_get ( br , dest , vid ) ) ! = NULL )
2005-04-17 02:20:36 +04:00
br_deliver ( dst - > dst , skb ) ;
else
2013-06-05 18:08:01 +04:00
br_flood_deliver ( br , skb , true ) ;
2005-04-17 02:20:36 +04:00
2010-02-27 22:41:48 +03:00
out :
2010-07-27 12:26:30 +04:00
rcu_read_unlock ( ) ;
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
2011-04-04 18:03:32 +04:00
static int br_dev_init ( struct net_device * dev )
{
struct net_bridge * br = netdev_priv ( dev ) ;
2014-10-03 19:29:18 +04:00
int err ;
2011-04-04 18:03:32 +04:00
2014-02-13 23:46:28 +04:00
br - > stats = netdev_alloc_pcpu_stats ( struct pcpu_sw_netstats ) ;
2011-04-04 18:03:32 +04:00
if ( ! br - > stats )
return - ENOMEM ;
2014-10-03 19:29:18 +04:00
err = br_vlan_init ( br ) ;
if ( err )
free_percpu ( br - > stats ) ;
return err ;
2011-04-04 18:03:32 +04:00
}
2005-04-17 02:20:36 +04:00
static int br_dev_open ( struct net_device * dev )
{
2005-05-30 01:15:17 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2011-04-22 10:31:16 +04:00
netdev_update_features ( dev ) ;
2005-05-30 01:15:17 +04:00
netif_start_queue ( dev ) ;
br_stp_enable_bridge ( br ) ;
2010-02-28 11:49:38 +03:00
br_multicast_open ( br ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void br_dev_set_multicast_list ( struct net_device * dev )
{
}
2014-05-16 17:59:20 +04: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-17 02:20:36 +04:00
static int br_dev_stop ( struct net_device * dev )
{
2010-02-28 11:49:38 +03:00
struct net_bridge * br = netdev_priv ( dev ) ;
br_stp_disable_bridge ( br ) ;
br_multicast_stop ( br ) ;
2005-04-17 02:20:36 +04:00
netif_stop_queue ( dev ) ;
return 0 ;
}
2010-07-08 01:58:56 +04:00
static struct rtnl_link_stats64 * br_get_stats64 ( struct net_device * dev ,
struct rtnl_link_stats64 * stats )
2010-03-02 16:32:09 +03:00
{
struct net_bridge * br = netdev_priv ( dev ) ;
2014-01-04 09:57:59 +04:00
struct pcpu_sw_netstats tmp , sum = { 0 } ;
2010-03-02 16:32:09 +03:00
unsigned int cpu ;
for_each_possible_cpu ( cpu ) {
2010-06-24 00:00:48 +04:00
unsigned int start ;
2014-01-04 09:57:59 +04:00
const struct pcpu_sw_netstats * bstats
2010-03-02 16:32:09 +03:00
= per_cpu_ptr ( br - > stats , cpu ) ;
2010-06-24 00:00:48 +04:00
do {
2014-03-14 08:26:42 +04:00
start = u64_stats_fetch_begin_irq ( & bstats - > syncp ) ;
2010-06-24 00:00:48 +04:00
memcpy ( & tmp , bstats , sizeof ( tmp ) ) ;
2014-03-14 08:26:42 +04:00
} while ( u64_stats_fetch_retry_irq ( & bstats - > syncp , start ) ) ;
2010-06-24 00:00:48 +04: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 16:32:09 +03: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 ;
return stats ;
}
2005-04-17 02:20:36 +04:00
static int br_change_mtu ( struct net_device * dev , int new_mtu )
{
2008-07-31 03:27:55 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
if ( new_mtu < 68 | | new_mtu > br_min_mtu ( br ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
dev - > mtu = new_mtu ;
2008-07-31 03:27:55 +04:00
2014-09-18 13:29:03 +04:00
# if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
2008-07-31 03:27:55 +04:00
/* remember the MTU in the rtable for PMTU */
2010-12-09 08:16:57 +03:00
dst_metric_set ( & br - > fake_rtable . dst , RTAX_MTU , new_mtu ) ;
2008-07-31 03:27:55 +04:00
# endif
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-04-09 22:49:58 +04:00
/* Allow setting mac address to any valid ethernet address. */
2005-12-22 05:51:49 +03: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 22:49:58 +04:00
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
2012-02-21 06:07:52 +04:00
return - EADDRNOTAVAIL ;
2005-12-22 05:51:49 +03: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 22:56:49 +04:00
if ( ! ether_addr_equal ( dev - > dev_addr , addr - > sa_data ) ) {
2014-02-07 11:48:20 +04:00
/* Mac address will be changed in br_stp_change_bridge_id(). */
2011-12-08 11:17:49 +04:00
br_stp_change_bridge_id ( br , addr - > sa_data ) ;
}
2005-12-22 05:51:49 +03:00
spin_unlock_bh ( & br - > lock ) ;
2007-04-09 22:49:58 +04:00
return 0 ;
2005-12-22 05:51:49 +03:00
}
2005-12-22 06:00:58 +03:00
static void br_getinfo ( struct net_device * dev , struct ethtool_drvinfo * info )
{
2013-01-06 04:44:26 +04: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 06:00:58 +03:00
}
2011-11-15 19:29:55 +04:00
static netdev_features_t br_fix_features ( struct net_device * dev ,
netdev_features_t features )
2005-12-22 06:00:58 +03:00
{
struct net_bridge * br = netdev_priv ( dev ) ;
2011-04-22 10:31:16 +04:00
return br_features_recompute ( br , features ) ;
2010-10-20 17:56:08 +04:00
}
2010-05-06 11:48:24 +04:00
# ifdef CONFIG_NET_POLL_CONTROLLER
2010-06-10 20:12:50 +04:00
static void br_poll_controller ( struct net_device * br_dev )
2010-05-06 11:48:24 +04:00
{
}
2010-06-10 20:12:50 +04:00
static void br_netpoll_cleanup ( struct net_device * dev )
2010-05-06 11:48:24 +04:00
{
2010-06-10 20:12:50 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
2012-08-10 05:24:44 +04:00
struct net_bridge_port * p ;
2010-05-06 11:48:24 +04:00
2012-08-10 05:24:44 +04:00
list_for_each_entry ( p , & br - > port_list , list )
2010-06-10 20:12:50 +04:00
br_netpoll_disable ( p ) ;
2010-05-06 11:48:24 +04:00
}
2014-03-28 02:36:38 +04:00
static int __br_netpoll_enable ( struct net_bridge_port * p )
2014-02-07 03:00:52 +04:00
{
struct netpoll * np ;
int err ;
2014-03-28 02:36:38 +04:00
np = kzalloc ( sizeof ( * p - > np ) , GFP_KERNEL ) ;
2014-02-07 03:00:52 +04:00
if ( ! np )
return - ENOMEM ;
2014-03-28 02:36:38 +04:00
err = __netpoll_setup ( np , p - > dev ) ;
2014-02-07 03:00:52 +04:00
if ( err ) {
kfree ( np ) ;
return err ;
}
p - > np = np ;
return err ;
}
2014-03-28 02:36:38 +04:00
int br_netpoll_enable ( struct net_bridge_port * p )
2014-02-07 03:00:52 +04:00
{
if ( ! p - > br - > dev - > npinfo )
return 0 ;
2014-03-28 02:36:38 +04:00
return __br_netpoll_enable ( p ) ;
2014-02-07 03:00:52 +04:00
}
2014-03-28 02:36:38 +04:00
static int br_netpoll_setup ( struct net_device * dev , struct netpoll_info * ni )
2010-05-06 11:48:24 +04:00
{
2010-05-10 13:31:08 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
2012-08-10 05:24:44 +04:00
struct net_bridge_port * p ;
2010-06-10 20:12:50 +04:00
int err = 0 ;
2010-05-06 11:48:24 +04:00
2012-08-10 05:24:44 +04:00
list_for_each_entry ( p , & br - > port_list , list ) {
2010-06-10 20:12:50 +04:00
if ( ! p - > dev )
continue ;
2014-03-28 02:36:38 +04:00
err = __br_netpoll_enable ( p ) ;
2010-06-10 20:12:50 +04:00
if ( err )
goto fail ;
2010-05-06 11:48:24 +04:00
}
2010-06-10 20:12:50 +04:00
out :
return err ;
fail :
br_netpoll_cleanup ( dev ) ;
goto out ;
2010-05-06 11:48:24 +04:00
}
2010-06-10 20:12:50 +04:00
void br_netpoll_disable ( struct net_bridge_port * p )
2010-05-06 11:48:24 +04:00
{
2010-06-10 20:12:50 +04:00
struct netpoll * np = p - > np ;
if ( ! np )
return ;
p - > np = NULL ;
2013-02-11 14:25:30 +04:00
__netpoll_free_async ( np ) ;
2010-05-06 11:48:24 +04:00
}
# endif
2011-02-13 12:33:42 +03:00
static int br_add_slave ( struct net_device * dev , struct net_device * slave_dev )
{
struct net_bridge * br = netdev_priv ( dev ) ;
return br_add_if ( br , slave_dev ) ;
}
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 08:49:00 +03:00
static const struct ethtool_ops br_ethtool_ops = {
2008-08-16 06:51:07 +04:00
. get_drvinfo = br_getinfo ,
. get_link = ethtool_op_get_link ,
2005-12-22 06:00:58 +03:00
} ;
2008-11-20 08:49:00 +03:00
static const struct net_device_ops br_netdev_ops = {
. ndo_open = br_dev_open ,
. ndo_stop = br_dev_stop ,
2011-04-04 18:03:32 +04:00
. ndo_init = br_dev_init ,
2008-11-21 07:14:53 +03:00
. ndo_start_xmit = br_dev_xmit ,
2010-06-24 00:00:48 +04:00
. ndo_get_stats64 = br_get_stats64 ,
2008-11-21 07:14:53 +03:00
. ndo_set_mac_address = br_set_mac_address ,
2011-08-16 10:29:01 +04:00
. ndo_set_rx_mode = br_dev_set_multicast_list ,
2014-05-16 17:59:20 +04:00
. ndo_change_rx_flags = br_dev_change_rx_flags ,
2008-11-21 07:14:53 +03:00
. ndo_change_mtu = br_change_mtu ,
. ndo_do_ioctl = br_dev_ioctl ,
2010-05-06 11:48:24 +04:00
# ifdef CONFIG_NET_POLL_CONTROLLER
2010-06-10 20:12:50 +04:00
. ndo_netpoll_setup = br_netpoll_setup ,
2010-05-06 11:48:24 +04:00
. ndo_netpoll_cleanup = br_netpoll_cleanup ,
. ndo_poll_controller = br_poll_controller ,
# endif
2011-02-13 12:33:42 +03:00
. ndo_add_slave = br_add_slave ,
. ndo_del_slave = br_del_slave ,
2011-04-22 10:31:16 +04:00
. ndo_fix_features = br_fix_features ,
2012-04-15 10:43:56 +04:00
. ndo_fdb_add = br_fdb_add ,
. ndo_fdb_del = br_fdb_delete ,
. ndo_fdb_dump = br_fdb_dump ,
2012-10-24 12:12:57 +04:00
. ndo_bridge_getlink = br_getlink ,
. ndo_bridge_setlink = br_setlink ,
2013-02-13 16:00:12 +04:00
. ndo_bridge_dellink = br_dellink ,
2015-07-31 09:03:26 +03:00
. ndo_features_check = passthru_features_check ,
2008-11-20 08:49:00 +03:00
} ;
2010-03-02 16:32:09 +03:00
static void br_dev_free ( struct net_device * dev )
{
struct net_bridge * br = netdev_priv ( dev ) ;
free_percpu ( br - > stats ) ;
free_netdev ( dev ) ;
}
2011-04-04 18:03:32 +04:00
static struct device_type br_type = {
. name = " bridge " ,
} ;
2005-04-17 02:20:36 +04:00
void br_dev_setup ( struct net_device * dev )
{
2011-04-04 18:03:32 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
2012-02-15 10:45:40 +04:00
eth_hw_addr_random ( dev ) ;
2005-04-17 02:20:36 +04:00
ether_setup ( dev ) ;
2008-11-20 08:49:00 +03:00
dev - > netdev_ops = & br_netdev_ops ;
2010-03-02 16:32:09 +03:00
dev - > destructor = br_dev_free ;
2014-05-11 04:12:32 +04:00
dev - > ethtool_ops = & br_ethtool_ops ;
2011-04-04 18:03:32 +04:00
SET_NETDEV_DEVTYPE ( dev , & br_type ) ;
2015-08-18 11:30:37 +03:00
dev - > priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE ;
2005-12-22 06:00:58 +03:00
2013-05-22 11:49:34 +04:00
dev - > features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL |
2014-06-10 15:59:22 +04: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 11:49:34 +04:00
dev - > vlan_features = COMMON_FEATURES ;
2011-04-04 18:03:32 +04:00
br - > dev = dev ;
spin_lock_init ( & br - > lock ) ;
INIT_LIST_HEAD ( & br - > port_list ) ;
spin_lock_init ( & br - > hash_lock ) ;
br - > bridge_id . prio [ 0 ] = 0x80 ;
br - > bridge_id . prio [ 1 ] = 0x00 ;
2014-02-23 12:05:25 +04:00
ether_addr_copy ( br - > group_addr , eth_reserved_addr_base ) ;
2011-04-04 18:03:32 +04:00
br - > stp_enabled = BR_NO_STP ;
2011-10-03 22:14:46 +04:00
br - > group_fwd_mask = BR_GROUPFWD_DEFAULT ;
2014-06-10 15:59:24 +04:00
br - > group_fwd_mask_required = BR_GROUPFWD_DEFAULT ;
2011-10-03 22:14:46 +04:00
2011-04-04 18:03:32 +04: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 ;
2015-09-23 18:39:16 +03:00
br - > ageing_time = BR_DEFAULT_AGEING_TIME ;
2011-04-04 18:03:32 +04:00
br_netfilter_rtable_init ( br ) ;
br_stp_timer_init ( br ) ;
br_multicast_init ( br ) ;
2005-04-17 02:20:36 +04:00
}