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"
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 ;
2010-03-02 16:32:09 +03:00
struct br_cpu_netstats * brstats = this_cpu_ptr ( br - > stats ) ;
2005-04-17 02:20:36 +04:00
2010-04-15 14:14:51 +04:00
# ifdef CONFIG_BRIDGE_NETFILTER
if ( skb - > nf_bridge & & ( skb - > nf_bridge - > mask & BRNF_BRIDGED_DNAT ) ) {
br_nf_pre_routing_finish_bridge_slow ( skb ) ;
return NETDEV_TX_OK ;
}
# endif
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 ) ;
2010-07-27 12:26:30 +04:00
rcu_read_lock ( ) ;
2011-07-05 17:58:33 +04:00
if ( is_broadcast_ether_addr ( dest ) )
br_flood_deliver ( br , skb ) ;
else if ( is_multicast_ether_addr ( dest ) ) {
2010-06-10 20:12:50 +04:00
if ( unlikely ( netpoll_tx_running ( dev ) ) ) {
br_flood_deliver ( br , skb ) ;
goto out ;
}
2010-07-29 05:12:31 +04:00
if ( br_multicast_rcv ( br , NULL , skb ) ) {
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
mdst = br_mdb_get ( br , skb ) ;
2010-03-16 00:51:18 +03:00
if ( mdst | | BR_INPUT_SKB_CB_MROUTERS_ONLY ( skb ) )
2010-02-27 22:41:48 +03:00
br_multicast_deliver ( mdst , skb ) ;
else
br_flood_deliver ( br , skb ) ;
} else if ( ( dst = __br_fdb_get ( br , dest ) ) ! = NULL )
2005-04-17 02:20:36 +04:00
br_deliver ( dst - > dst , skb ) ;
else
2007-09-17 03:20:48 +04:00
br_flood_deliver ( br , skb ) ;
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 ) ;
br - > stats = alloc_percpu ( struct br_cpu_netstats ) ;
if ( ! br - > stats )
return - ENOMEM ;
return 0 ;
}
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 )
{
}
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 ) ;
2010-06-24 00:00:48 +04:00
struct br_cpu_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 ;
2010-03-02 16:32:09 +03:00
const struct br_cpu_netstats * bstats
= per_cpu_ptr ( br - > stats , cpu ) ;
2010-06-24 00:00:48 +04:00
do {
start = u64_stats_fetch_begin ( & bstats - > syncp ) ;
memcpy ( & tmp , bstats , sizeof ( tmp ) ) ;
} while ( u64_stats_fetch_retry ( & bstats - > syncp , start ) ) ;
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
# ifdef CONFIG_BRIDGE_NETFILTER
/* 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 ) ;
2011-12-08 11:17:49 +04:00
if ( compare_ether_addr ( dev - > dev_addr , addr - > sa_data ) ) {
2012-02-15 10:45:40 +04:00
dev - > addr_assign_type & = ~ NET_ADDR_RANDOM ;
2011-12-08 11:17:49 +04:00
memcpy ( dev - > dev_addr , addr - > sa_data , ETH_ALEN ) ;
br_fdb_change_mac_address ( br , addr - > sa_data ) ;
br_stp_change_bridge_id ( br , addr - > sa_data ) ;
}
2008-06-18 03:10:06 +04:00
br - > flags | = BR_SET_MAC_ADDR ;
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 )
{
strcpy ( info - > driver , " bridge " ) ;
strcpy ( info - > version , BR_VERSION ) ;
strcpy ( info - > fw_version , " N/A " ) ;
strcpy ( info - > bus_info , " N/A " ) ;
}
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 ) ;
struct net_bridge_port * p , * n ;
2010-05-06 11:48:24 +04:00
2010-06-10 20:12:50 +04:00
list_for_each_entry_safe ( p , n , & br - > port_list , list ) {
br_netpoll_disable ( p ) ;
}
2010-05-06 11:48:24 +04:00
}
2010-06-10 20:12:50 +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 ) ;
2010-05-06 11:48:24 +04:00
struct net_bridge_port * p , * n ;
2010-06-10 20:12:50 +04:00
int err = 0 ;
2010-05-06 11:48:24 +04:00
list_for_each_entry_safe ( p , n , & br - > port_list , list ) {
2010-06-10 20:12:50 +04:00
if ( ! p - > dev )
continue ;
err = br_netpoll_enable ( p ) ;
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
int br_netpoll_enable ( struct net_bridge_port * p )
2010-05-10 13:31:08 +04:00
{
2010-06-10 20:12:50 +04:00
struct netpoll * np ;
int err = 0 ;
np = kzalloc ( sizeof ( * p - > np ) , GFP_KERNEL ) ;
err = - ENOMEM ;
if ( ! np )
goto out ;
np - > dev = p - > dev ;
2011-06-20 03:13:01 +04:00
strlcpy ( np - > dev_name , p - > dev - > name , IFNAMSIZ ) ;
2010-06-10 20:12:50 +04:00
err = __netpoll_setup ( np ) ;
if ( err ) {
kfree ( np ) ;
goto out ;
}
p - > np = np ;
out :
return err ;
2010-05-10 13:31:08 +04:00
}
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 ;
/* Wait for transmitting packets to finish before freeing. */
synchronize_rcu_bh ( ) ;
__netpoll_cleanup ( np ) ;
kfree ( 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 ,
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 ,
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 ;
2007-02-09 17:24:35 +03:00
SET_ETHTOOL_OPS ( dev , & br_ethtool_ops ) ;
2011-04-04 18:03:32 +04:00
SET_NETDEV_DEVTYPE ( dev , & br_type ) ;
2005-04-17 02:20:36 +04:00
dev - > tx_queue_len = 0 ;
dev - > priv_flags = IFF_EBRIDGE ;
2005-12-22 06:00:58 +03:00
2007-02-09 17:24:35 +03:00
dev - > features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
2011-11-15 19:29:55 +04:00
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | NETIF_F_LLTX |
2011-04-22 10:31:16 +04:00
NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX ;
dev - > hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
2011-11-15 19:29:55 +04:00
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
2011-04-22 10:31:16 +04:00
NETIF_F_HW_VLAN_TX ;
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 ;
memcpy ( br - > group_addr , br_group_address , ETH_ALEN ) ;
br - > stp_enabled = BR_NO_STP ;
2011-10-03 22:14:46 +04:00
br - > group_fwd_mask = BR_GROUPFWD_DEFAULT ;
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 ;
br - > ageing_time = 300 * HZ ;
br_netfilter_rtable_init ( br ) ;
br_stp_timer_init ( br ) ;
br_multicast_init ( br ) ;
2005-04-17 02:20:36 +04:00
}