diff options
Diffstat (limited to 'drivers/net/macvlan.c')
| -rw-r--r-- | drivers/net/macvlan.c | 44 | 
1 files changed, 40 insertions, 4 deletions
| diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c8d803d3616c..fb51329f8964 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -35,7 +35,7 @@  #define MACVLAN_HASH_BITS	8  #define MACVLAN_HASH_SIZE	(1<<MACVLAN_HASH_BITS) -#define MACVLAN_BC_QUEUE_LEN	1000 +#define MACVLAN_DEFAULT_BC_QUEUE_LEN	1000  #define MACVLAN_F_PASSTHRU	1  #define MACVLAN_F_ADDRCHANGE	2 @@ -46,6 +46,7 @@ struct macvlan_port {  	struct list_head	vlans;  	struct sk_buff_head	bc_queue;  	struct work_struct	bc_work; +	u32			bc_queue_len_used;  	u32			flags;  	int			count;  	struct hlist_head	vlan_source_hash[MACVLAN_HASH_SIZE]; @@ -67,6 +68,7 @@ struct macvlan_skb_cb {  #define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0]))  static void macvlan_port_destroy(struct net_device *dev); +static void update_port_bc_queue_len(struct macvlan_port *port);  static inline bool macvlan_passthru(const struct macvlan_port *port)  { @@ -354,7 +356,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,  	MACVLAN_SKB_CB(nskb)->src = src;  	spin_lock(&port->bc_queue.lock); -	if (skb_queue_len(&port->bc_queue) < MACVLAN_BC_QUEUE_LEN) { +	if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) {  		if (src)  			dev_hold(src->dev);  		__skb_queue_tail(&port->bc_queue, nskb); @@ -1096,7 +1098,7 @@ static int macvlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info  	struct macvlan_dev *vlan = netdev_priv(dev);  	struct net_device *real_dev = vlan->lowerdev;  	struct netpoll *netpoll; -	int err = 0; +	int err;  	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);  	err = -ENOMEM; @@ -1218,6 +1220,7 @@ static int macvlan_port_create(struct net_device *dev)  	for (i = 0; i < MACVLAN_HASH_SIZE; i++)  		INIT_HLIST_HEAD(&port->vlan_source_hash[i]); +	port->bc_queue_len_used = 0;  	skb_queue_head_init(&port->bc_queue);  	INIT_WORK(&port->bc_work, macvlan_process_broadcast); @@ -1339,7 +1342,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[],  	return 0;  } -/** +/*   * reconfigure list of remote source mac address   * (only for macvlan devices in source mode)   * Note regarding alignment: all netlink data is aligned to 4 Byte, which @@ -1486,6 +1489,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,  			goto destroy_macvlan_port;  	} +	vlan->bc_queue_len_req = MACVLAN_DEFAULT_BC_QUEUE_LEN; +	if (data && data[IFLA_MACVLAN_BC_QUEUE_LEN]) +		vlan->bc_queue_len_req = nla_get_u32(data[IFLA_MACVLAN_BC_QUEUE_LEN]); +  	err = register_netdevice(dev);  	if (err < 0)  		goto destroy_macvlan_port; @@ -1496,6 +1503,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,  		goto unregister_netdev;  	list_add_tail_rcu(&vlan->list, &port->vlans); +	update_port_bc_queue_len(vlan->port);  	netif_stacked_transfer_operstate(lowerdev, dev);  	linkwatch_fire_event(dev); @@ -1529,6 +1537,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)  	if (vlan->mode == MACVLAN_MODE_SOURCE)  		macvlan_flush_sources(vlan->port, vlan);  	list_del_rcu(&vlan->list); +	update_port_bc_queue_len(vlan->port);  	unregister_netdevice_queue(dev, head);  	netdev_upper_dev_unlink(vlan->lowerdev, dev);  } @@ -1572,6 +1581,12 @@ static int macvlan_changelink(struct net_device *dev,  		}  		vlan->flags = flags;  	} + +	if (data && data[IFLA_MACVLAN_BC_QUEUE_LEN]) { +		vlan->bc_queue_len_req = nla_get_u32(data[IFLA_MACVLAN_BC_QUEUE_LEN]); +		update_port_bc_queue_len(vlan->port); +	} +  	if (set_mode)  		vlan->mode = mode;  	if (data && data[IFLA_MACVLAN_MACADDR_MODE]) { @@ -1602,6 +1617,8 @@ static size_t macvlan_get_size(const struct net_device *dev)  		+ nla_total_size(2) /* IFLA_MACVLAN_FLAGS */  		+ nla_total_size(4) /* IFLA_MACVLAN_MACADDR_COUNT */  		+ macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ +		+ nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */ +		+ nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */  		);  } @@ -1625,6 +1642,7 @@ static int macvlan_fill_info(struct sk_buff *skb,  				const struct net_device *dev)  {  	struct macvlan_dev *vlan = netdev_priv(dev); +	struct macvlan_port *port = vlan->port;  	int i;  	struct nlattr *nest; @@ -1645,6 +1663,10 @@ static int macvlan_fill_info(struct sk_buff *skb,  		}  		nla_nest_end(skb, nest);  	} +	if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) +		goto nla_put_failure; +	if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) +		goto nla_put_failure;  	return 0;  nla_put_failure: @@ -1658,6 +1680,8 @@ static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {  	[IFLA_MACVLAN_MACADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },  	[IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED },  	[IFLA_MACVLAN_MACADDR_COUNT] = { .type = NLA_U32 }, +	[IFLA_MACVLAN_BC_QUEUE_LEN] = { .type = NLA_U32 }, +	[IFLA_MACVLAN_BC_QUEUE_LEN_USED] = { .type = NLA_REJECT },  };  int macvlan_link_register(struct rtnl_link_ops *ops) @@ -1688,6 +1712,18 @@ static struct rtnl_link_ops macvlan_link_ops = {  	.priv_size      = sizeof(struct macvlan_dev),  }; +static void update_port_bc_queue_len(struct macvlan_port *port) +{ +	u32 max_bc_queue_len_req = 0; +	struct macvlan_dev *vlan; + +	list_for_each_entry(vlan, &port->vlans, list) { +		if (vlan->bc_queue_len_req > max_bc_queue_len_req) +			max_bc_queue_len_req = vlan->bc_queue_len_req; +	} +	port->bc_queue_len_used = max_bc_queue_len_req; +} +  static int macvlan_device_event(struct notifier_block *unused,  				unsigned long event, void *ptr)  { | 
