Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'macvlan-broadcast-queue-bypass'

Herbert Xu says:

====================
macvlan: Allow some packets to bypass broadcast queue

This patch series allows some packets to bypass the broadcast
queue on receive. Currently all multicast packets are queued
on receive and then processed in a work queue. This is to avoid
an unbounded amount of work occurring in the receive path, as
one broadcast packet could easily translate into 4,000 packets.

However, for multicast packets with just one receiver (possible
for IPv6 ND), this introduces unnecessary latency as the packet
will go to exactly one device.

This series allows such multicast packets to be processed inline.
It also adds a toggle which lets the admin control what threshold
to set between queueing and not queueing. A follow-up patch for
iproute will be posted.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+75 -28
+73 -28
drivers/net/macvlan.c
··· 47 47 struct sk_buff_head bc_queue; 48 48 struct work_struct bc_work; 49 49 u32 bc_queue_len_used; 50 + int bc_cutoff; 50 51 u32 flags; 51 52 int count; 52 53 struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE]; 54 + DECLARE_BITMAP(bc_filter, MACVLAN_MC_FILTER_SZ); 53 55 DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ); 54 56 unsigned char perm_addr[ETH_ALEN]; 55 57 }; ··· 293 291 } 294 292 } 295 293 294 + static void macvlan_multicast_rx(const struct macvlan_port *port, 295 + const struct macvlan_dev *src, 296 + struct sk_buff *skb) 297 + { 298 + if (!src) 299 + /* frame comes from an external address */ 300 + macvlan_broadcast(skb, port, NULL, 301 + MACVLAN_MODE_PRIVATE | 302 + MACVLAN_MODE_VEPA | 303 + MACVLAN_MODE_PASSTHRU| 304 + MACVLAN_MODE_BRIDGE); 305 + else if (src->mode == MACVLAN_MODE_VEPA) 306 + /* flood to everyone except source */ 307 + macvlan_broadcast(skb, port, src->dev, 308 + MACVLAN_MODE_VEPA | 309 + MACVLAN_MODE_BRIDGE); 310 + else 311 + /* 312 + * flood only to VEPA ports, bridge ports 313 + * already saw the frame on the way out. 314 + */ 315 + macvlan_broadcast(skb, port, src->dev, 316 + MACVLAN_MODE_VEPA); 317 + } 318 + 296 319 static void macvlan_process_broadcast(struct work_struct *w) 297 320 { 298 321 struct macvlan_port *port = container_of(w, struct macvlan_port, ··· 335 308 const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src; 336 309 337 310 rcu_read_lock(); 338 - 339 - if (!src) 340 - /* frame comes from an external address */ 341 - macvlan_broadcast(skb, port, NULL, 342 - MACVLAN_MODE_PRIVATE | 343 - MACVLAN_MODE_VEPA | 344 - MACVLAN_MODE_PASSTHRU| 345 - MACVLAN_MODE_BRIDGE); 346 - else if (src->mode == MACVLAN_MODE_VEPA) 347 - /* flood to everyone except source */ 348 - macvlan_broadcast(skb, port, src->dev, 349 - MACVLAN_MODE_VEPA | 350 - MACVLAN_MODE_BRIDGE); 351 - else 352 - /* 353 - * flood only to VEPA ports, bridge ports 354 - * already saw the frame on the way out. 355 - */ 356 - macvlan_broadcast(skb, port, src->dev, 357 - MACVLAN_MODE_VEPA); 358 - 311 + macvlan_multicast_rx(port, src, skb); 359 312 rcu_read_unlock(); 360 313 361 314 if (src) ··· 483 476 } 484 477 485 478 hash = mc_hash(NULL, eth->h_dest); 486 - if (test_bit(hash, port->mc_filter)) 479 + if (test_bit(hash, port->bc_filter)) 487 480 macvlan_broadcast_enqueue(port, src, skb); 481 + else if (test_bit(hash, port->mc_filter)) 482 + macvlan_multicast_rx(port, src, skb); 488 483 489 484 return RX_HANDLER_PASS; 490 485 } ··· 789 780 790 781 static void macvlan_compute_filter(unsigned long *mc_filter, 791 782 struct net_device *dev, 792 - struct macvlan_dev *vlan) 783 + struct macvlan_dev *vlan, int cutoff) 793 784 { 794 785 if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { 795 - bitmap_fill(mc_filter, MACVLAN_MC_FILTER_SZ); 786 + if (cutoff >= 0) 787 + bitmap_fill(mc_filter, MACVLAN_MC_FILTER_SZ); 788 + else 789 + bitmap_zero(mc_filter, MACVLAN_MC_FILTER_SZ); 796 790 } else { 797 - struct netdev_hw_addr *ha; 798 791 DECLARE_BITMAP(filter, MACVLAN_MC_FILTER_SZ); 792 + struct netdev_hw_addr *ha; 799 793 800 794 bitmap_zero(filter, MACVLAN_MC_FILTER_SZ); 801 795 netdev_for_each_mc_addr(ha, dev) { 796 + if (cutoff >= 0 && ha->synced <= cutoff) 797 + continue; 798 + 802 799 __set_bit(mc_hash(vlan, ha->addr), filter); 803 800 } 804 801 805 - __set_bit(mc_hash(vlan, dev->broadcast), filter); 802 + if (cutoff >= 0) 803 + __set_bit(mc_hash(vlan, dev->broadcast), filter); 806 804 807 805 bitmap_copy(mc_filter, filter, MACVLAN_MC_FILTER_SZ); 808 806 } 807 + } 808 + 809 + static void macvlan_recompute_bc_filter(struct macvlan_dev *vlan) 810 + { 811 + macvlan_compute_filter(vlan->port->bc_filter, vlan->lowerdev, NULL, 812 + vlan->port->bc_cutoff); 809 813 } 810 814 811 815 static void macvlan_set_mac_lists(struct net_device *dev) 812 816 { 813 817 struct macvlan_dev *vlan = netdev_priv(dev); 814 818 815 - macvlan_compute_filter(vlan->mc_filter, dev, vlan); 819 + macvlan_compute_filter(vlan->mc_filter, dev, vlan, 0); 816 820 817 821 dev_uc_sync(vlan->lowerdev, dev); 818 822 dev_mc_sync(vlan->lowerdev, dev); ··· 843 821 * The solution is to maintain a list of broadcast addresses like 844 822 * we do for uc/mc, if you care. 845 823 */ 846 - macvlan_compute_filter(vlan->port->mc_filter, vlan->lowerdev, NULL); 824 + macvlan_compute_filter(vlan->port->mc_filter, vlan->lowerdev, NULL, 825 + 0); 826 + macvlan_recompute_bc_filter(vlan); 827 + } 828 + 829 + static void update_port_bc_cutoff(struct macvlan_dev *vlan, int cutoff) 830 + { 831 + if (vlan->port->bc_cutoff == cutoff) 832 + return; 833 + 834 + vlan->port->bc_cutoff = cutoff; 835 + macvlan_recompute_bc_filter(vlan); 847 836 } 848 837 849 838 static int macvlan_change_mtu(struct net_device *dev, int new_mtu) ··· 1269 1236 INIT_HLIST_HEAD(&port->vlan_source_hash[i]); 1270 1237 1271 1238 port->bc_queue_len_used = 0; 1239 + port->bc_cutoff = 1; 1272 1240 skb_queue_head_init(&port->bc_queue); 1273 1241 INIT_WORK(&port->bc_work, macvlan_process_broadcast); 1274 1242 ··· 1543 1509 if (data && data[IFLA_MACVLAN_BC_QUEUE_LEN]) 1544 1510 vlan->bc_queue_len_req = nla_get_u32(data[IFLA_MACVLAN_BC_QUEUE_LEN]); 1545 1511 1512 + if (data && data[IFLA_MACVLAN_BC_CUTOFF]) 1513 + update_port_bc_cutoff( 1514 + vlan, nla_get_s32(data[IFLA_MACVLAN_BC_CUTOFF])); 1515 + 1546 1516 err = register_netdevice(dev); 1547 1517 if (err < 0) 1548 1518 goto destroy_macvlan_port; ··· 1643 1605 update_port_bc_queue_len(vlan->port); 1644 1606 } 1645 1607 1608 + if (data && data[IFLA_MACVLAN_BC_CUTOFF]) 1609 + update_port_bc_cutoff( 1610 + vlan, nla_get_s32(data[IFLA_MACVLAN_BC_CUTOFF])); 1611 + 1646 1612 if (set_mode) 1647 1613 vlan->mode = mode; 1648 1614 if (data && data[IFLA_MACVLAN_MACADDR_MODE]) { ··· 1726 1684 if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) 1727 1685 goto nla_put_failure; 1728 1686 if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) 1687 + goto nla_put_failure; 1688 + if (port->bc_cutoff != 1 && 1689 + nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff)) 1729 1690 goto nla_put_failure; 1730 1691 return 0; 1731 1692
+1
include/uapi/linux/if_link.h
··· 635 635 IFLA_MACVLAN_MACADDR_COUNT, 636 636 IFLA_MACVLAN_BC_QUEUE_LEN, 637 637 IFLA_MACVLAN_BC_QUEUE_LEN_USED, 638 + IFLA_MACVLAN_BC_CUTOFF, 638 639 __IFLA_MACVLAN_MAX, 639 640 }; 640 641
+1
tools/include/uapi/linux/if_link.h
··· 605 605 IFLA_MACVLAN_MACADDR_COUNT, 606 606 IFLA_MACVLAN_BC_QUEUE_LEN, 607 607 IFLA_MACVLAN_BC_QUEUE_LEN_USED, 608 + IFLA_MACVLAN_BC_CUTOFF, 608 609 __IFLA_MACVLAN_MAX, 609 610 }; 610 611