Commit d4bff72c authored by Thomas Karlsson's avatar Thomas Karlsson Committed by Jakub Kicinski

macvlan: Support for high multicast packet rate

Background:
Broadcast and multicast packages are enqueued for later processing.
This queue was previously hardcoded to 1000.

This proved insufficient for handling very high packet rates.
This resulted in packet drops for multicast.
While at the same time unicast worked fine.

The change:
This patch make the queue length adjustable to accommodate
for environments with very high multicast packet rate.
But still keeps the default value of 1000 unless specified.

The queue length is specified as a request per macvlan
using the IFLA_MACVLAN_BC_QUEUE_LEN parameter.

The actual used queue length will then be the maximum of
any macvlan connected to the same port. The actual used
queue length for the port can be retrieved (read only)
by the IFLA_MACVLAN_BC_QUEUE_LEN_USED parameter for verification.

This will be followed up by a patch to iproute2
in order to adjust the parameter from userspace.
Signed-off-by: default avatarThomas Karlsson <thomas.karlsson@paneda.se>
Link: https://lore.kernel.org/r/dd4673b2-7eab-edda-6815-85c67ce87f63@paneda.seSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent cec85994
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#define MACVLAN_HASH_BITS 8 #define MACVLAN_HASH_BITS 8
#define MACVLAN_HASH_SIZE (1<<MACVLAN_HASH_BITS) #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_PASSTHRU 1
#define MACVLAN_F_ADDRCHANGE 2 #define MACVLAN_F_ADDRCHANGE 2
...@@ -46,6 +46,7 @@ struct macvlan_port { ...@@ -46,6 +46,7 @@ struct macvlan_port {
struct list_head vlans; struct list_head vlans;
struct sk_buff_head bc_queue; struct sk_buff_head bc_queue;
struct work_struct bc_work; struct work_struct bc_work;
u32 bc_queue_len_used;
u32 flags; u32 flags;
int count; int count;
struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE]; struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE];
...@@ -67,6 +68,7 @@ struct macvlan_skb_cb { ...@@ -67,6 +68,7 @@ struct macvlan_skb_cb {
#define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0])) #define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0]))
static void macvlan_port_destroy(struct net_device *dev); 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) static inline bool macvlan_passthru(const struct macvlan_port *port)
{ {
...@@ -354,7 +356,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, ...@@ -354,7 +356,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,
MACVLAN_SKB_CB(nskb)->src = src; MACVLAN_SKB_CB(nskb)->src = src;
spin_lock(&port->bc_queue.lock); 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) if (src)
dev_hold(src->dev); dev_hold(src->dev);
__skb_queue_tail(&port->bc_queue, nskb); __skb_queue_tail(&port->bc_queue, nskb);
...@@ -1218,6 +1220,7 @@ static int macvlan_port_create(struct net_device *dev) ...@@ -1218,6 +1220,7 @@ static int macvlan_port_create(struct net_device *dev)
for (i = 0; i < MACVLAN_HASH_SIZE; i++) for (i = 0; i < MACVLAN_HASH_SIZE; i++)
INIT_HLIST_HEAD(&port->vlan_source_hash[i]); INIT_HLIST_HEAD(&port->vlan_source_hash[i]);
port->bc_queue_len_used = 0;
skb_queue_head_init(&port->bc_queue); skb_queue_head_init(&port->bc_queue);
INIT_WORK(&port->bc_work, macvlan_process_broadcast); INIT_WORK(&port->bc_work, macvlan_process_broadcast);
...@@ -1486,6 +1489,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, ...@@ -1486,6 +1489,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
goto destroy_macvlan_port; 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); err = register_netdevice(dev);
if (err < 0) if (err < 0)
goto destroy_macvlan_port; goto destroy_macvlan_port;
...@@ -1496,6 +1503,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, ...@@ -1496,6 +1503,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
goto unregister_netdev; goto unregister_netdev;
list_add_tail_rcu(&vlan->list, &port->vlans); list_add_tail_rcu(&vlan->list, &port->vlans);
update_port_bc_queue_len(vlan->port);
netif_stacked_transfer_operstate(lowerdev, dev); netif_stacked_transfer_operstate(lowerdev, dev);
linkwatch_fire_event(dev); linkwatch_fire_event(dev);
...@@ -1529,6 +1537,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head) ...@@ -1529,6 +1537,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)
if (vlan->mode == MACVLAN_MODE_SOURCE) if (vlan->mode == MACVLAN_MODE_SOURCE)
macvlan_flush_sources(vlan->port, vlan); macvlan_flush_sources(vlan->port, vlan);
list_del_rcu(&vlan->list); list_del_rcu(&vlan->list);
update_port_bc_queue_len(vlan->port);
unregister_netdevice_queue(dev, head); unregister_netdevice_queue(dev, head);
netdev_upper_dev_unlink(vlan->lowerdev, dev); netdev_upper_dev_unlink(vlan->lowerdev, dev);
} }
...@@ -1572,6 +1581,12 @@ static int macvlan_changelink(struct net_device *dev, ...@@ -1572,6 +1581,12 @@ static int macvlan_changelink(struct net_device *dev,
} }
vlan->flags = flags; 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) if (set_mode)
vlan->mode = mode; vlan->mode = mode;
if (data && data[IFLA_MACVLAN_MACADDR_MODE]) { if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
...@@ -1602,6 +1617,8 @@ static size_t macvlan_get_size(const struct net_device *dev) ...@@ -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(2) /* IFLA_MACVLAN_FLAGS */
+ nla_total_size(4) /* IFLA_MACVLAN_MACADDR_COUNT */ + nla_total_size(4) /* IFLA_MACVLAN_MACADDR_COUNT */
+ macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ + 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, ...@@ -1625,6 +1642,7 @@ static int macvlan_fill_info(struct sk_buff *skb,
const struct net_device *dev) const struct net_device *dev)
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
int i; int i;
struct nlattr *nest; struct nlattr *nest;
...@@ -1645,6 +1663,10 @@ static int macvlan_fill_info(struct sk_buff *skb, ...@@ -1645,6 +1663,10 @@ static int macvlan_fill_info(struct sk_buff *skb,
} }
nla_nest_end(skb, nest); 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; return 0;
nla_put_failure: nla_put_failure:
...@@ -1658,6 +1680,8 @@ static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { ...@@ -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] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
[IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED }, [IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED },
[IFLA_MACVLAN_MACADDR_COUNT] = { .type = NLA_U32 }, [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) int macvlan_link_register(struct rtnl_link_ops *ops)
...@@ -1688,6 +1712,18 @@ static struct rtnl_link_ops macvlan_link_ops = { ...@@ -1688,6 +1712,18 @@ static struct rtnl_link_ops macvlan_link_ops = {
.priv_size = sizeof(struct macvlan_dev), .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, static int macvlan_device_event(struct notifier_block *unused,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
......
...@@ -30,6 +30,7 @@ struct macvlan_dev { ...@@ -30,6 +30,7 @@ struct macvlan_dev {
enum macvlan_mode mode; enum macvlan_mode mode;
u16 flags; u16 flags;
unsigned int macaddr_count; unsigned int macaddr_count;
u32 bc_queue_len_req;
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
struct netpoll *netpoll; struct netpoll *netpoll;
#endif #endif
......
...@@ -588,6 +588,8 @@ enum { ...@@ -588,6 +588,8 @@ enum {
IFLA_MACVLAN_MACADDR, IFLA_MACVLAN_MACADDR,
IFLA_MACVLAN_MACADDR_DATA, IFLA_MACVLAN_MACADDR_DATA,
IFLA_MACVLAN_MACADDR_COUNT, IFLA_MACVLAN_MACADDR_COUNT,
IFLA_MACVLAN_BC_QUEUE_LEN,
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
__IFLA_MACVLAN_MAX, __IFLA_MACVLAN_MAX,
}; };
......
...@@ -409,6 +409,8 @@ enum { ...@@ -409,6 +409,8 @@ enum {
IFLA_MACVLAN_MACADDR, IFLA_MACVLAN_MACADDR,
IFLA_MACVLAN_MACADDR_DATA, IFLA_MACVLAN_MACADDR_DATA,
IFLA_MACVLAN_MACADDR_COUNT, IFLA_MACVLAN_MACADDR_COUNT,
IFLA_MACVLAN_BC_QUEUE_LEN,
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
__IFLA_MACVLAN_MAX, __IFLA_MACVLAN_MAX,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment