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

macvlan: add FDB bridge ops and macvlan flags

This adds FDB bridge ops to the macvlan device passthru mode.
Additionally a flags field was added and a NOPROMISC bit to
allow users to use passthru mode without the driver calling
dev_set_promiscuity(). The flags field is a u16 placed in a
4 byte hole (consuming 2 bytes) of the macvlan_dev struct.

We want to do this so that the macvlan driver or stack
above the macvlan driver does not have to process every
packet. For the use case where we know all the MAC addresses
of the endstations above us this works well.

This patch is a result of Roopa Prabhu's work. Follow up
patches are needed for VEPA and VEB macvlan modes.

v2: Change from distinct nopromisc mode to a flags field to
configure this. This avoids the tendency to add a new
mode every time we need some slightly different behavior.
v3: fix error in dev_set_promiscuity and add change and get
link attributes for flags.

CC: Roopa Prabhu <roprabhu@cisco.com>
CC: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

John Fastabend and committed by
David S. Miller
df8ef8f3 2b202712

+71 -6
+67 -6
drivers/net/macvlan.c
··· 312 312 int err; 313 313 314 314 if (vlan->port->passthru) { 315 - dev_set_promiscuity(lowerdev, 1); 315 + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) 316 + dev_set_promiscuity(lowerdev, 1); 316 317 goto hash_add; 317 318 } 318 319 ··· 345 344 struct macvlan_dev *vlan = netdev_priv(dev); 346 345 struct net_device *lowerdev = vlan->lowerdev; 347 346 347 + dev_uc_unsync(lowerdev, dev); 348 + dev_mc_unsync(lowerdev, dev); 349 + 348 350 if (vlan->port->passthru) { 349 - dev_set_promiscuity(lowerdev, -1); 351 + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) 352 + dev_set_promiscuity(lowerdev, -1); 350 353 goto hash_del; 351 354 } 352 355 353 - dev_mc_unsync(lowerdev, dev); 354 356 if (dev->flags & IFF_ALLMULTI) 355 357 dev_set_allmulti(lowerdev, -1); 356 358 ··· 403 399 dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); 404 400 } 405 401 406 - static void macvlan_set_multicast_list(struct net_device *dev) 402 + static void macvlan_set_mac_lists(struct net_device *dev) 407 403 { 408 404 struct macvlan_dev *vlan = netdev_priv(dev); 409 405 406 + dev_uc_sync(vlan->lowerdev, dev); 410 407 dev_mc_sync(vlan->lowerdev, dev); 411 408 } 412 409 ··· 547 542 return 0; 548 543 } 549 544 545 + static int macvlan_fdb_add(struct ndmsg *ndm, 546 + struct net_device *dev, 547 + unsigned char *addr, 548 + u16 flags) 549 + { 550 + struct macvlan_dev *vlan = netdev_priv(dev); 551 + int err = -EINVAL; 552 + 553 + if (!vlan->port->passthru) 554 + return -EOPNOTSUPP; 555 + 556 + if (is_unicast_ether_addr(addr)) 557 + err = dev_uc_add_excl(dev, addr); 558 + else if (is_multicast_ether_addr(addr)) 559 + err = dev_mc_add_excl(dev, addr); 560 + 561 + return err; 562 + } 563 + 564 + static int macvlan_fdb_del(struct ndmsg *ndm, 565 + struct net_device *dev, 566 + unsigned char *addr) 567 + { 568 + struct macvlan_dev *vlan = netdev_priv(dev); 569 + int err = -EINVAL; 570 + 571 + if (!vlan->port->passthru) 572 + return -EOPNOTSUPP; 573 + 574 + if (is_unicast_ether_addr(addr)) 575 + err = dev_uc_del(dev, addr); 576 + else if (is_multicast_ether_addr(addr)) 577 + err = dev_mc_del(dev, addr); 578 + 579 + return err; 580 + } 581 + 550 582 static void macvlan_ethtool_get_drvinfo(struct net_device *dev, 551 583 struct ethtool_drvinfo *drvinfo) 552 584 { ··· 614 572 .ndo_change_mtu = macvlan_change_mtu, 615 573 .ndo_change_rx_flags = macvlan_change_rx_flags, 616 574 .ndo_set_mac_address = macvlan_set_mac_address, 617 - .ndo_set_rx_mode = macvlan_set_multicast_list, 575 + .ndo_set_rx_mode = macvlan_set_mac_lists, 618 576 .ndo_get_stats64 = macvlan_dev_get_stats64, 619 577 .ndo_validate_addr = eth_validate_addr, 620 578 .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, 621 579 .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, 580 + .ndo_fdb_add = macvlan_fdb_add, 581 + .ndo_fdb_del = macvlan_fdb_del, 582 + .ndo_fdb_dump = ndo_dflt_fdb_dump, 622 583 }; 623 584 624 585 void macvlan_common_setup(struct net_device *dev) ··· 756 711 if (data && data[IFLA_MACVLAN_MODE]) 757 712 vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); 758 713 714 + if (data && data[IFLA_MACVLAN_FLAGS]) 715 + vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); 716 + 759 717 if (vlan->mode == MACVLAN_MODE_PASSTHRU) { 760 718 if (port->count) 761 719 return -EINVAL; ··· 808 760 struct macvlan_dev *vlan = netdev_priv(dev); 809 761 if (data && data[IFLA_MACVLAN_MODE]) 810 762 vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); 763 + if (data && data[IFLA_MACVLAN_FLAGS]) { 764 + __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); 765 + bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; 766 + 767 + if (promisc && (flags & MACVLAN_FLAG_NOPROMISC)) 768 + dev_set_promiscuity(vlan->lowerdev, -1); 769 + else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC)) 770 + dev_set_promiscuity(vlan->lowerdev, 1); 771 + vlan->flags = flags; 772 + } 811 773 return 0; 812 774 } 813 775 ··· 833 775 834 776 if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) 835 777 goto nla_put_failure; 778 + if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags)) 779 + goto nla_put_failure; 836 780 return 0; 837 781 838 782 nla_put_failure: ··· 842 782 } 843 783 844 784 static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { 845 - [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, 785 + [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, 786 + [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, 846 787 }; 847 788 848 789 int macvlan_link_register(struct rtnl_link_ops *ops)
+3
include/linux/if_link.h
··· 255 255 enum { 256 256 IFLA_MACVLAN_UNSPEC, 257 257 IFLA_MACVLAN_MODE, 258 + IFLA_MACVLAN_FLAGS, 258 259 __IFLA_MACVLAN_MAX, 259 260 }; 260 261 ··· 267 266 MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ 268 267 MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ 269 268 }; 269 + 270 + #define MACVLAN_FLAG_NOPROMISC 1 270 271 271 272 /* SR-IOV virtual function management section */ 272 273
+1
include/linux/if_macvlan.h
··· 60 60 struct net_device *lowerdev; 61 61 struct macvlan_pcpu_stats __percpu *pcpu_stats; 62 62 enum macvlan_mode mode; 63 + u16 flags; 63 64 int (*receive)(struct sk_buff *skb); 64 65 int (*forward)(struct net_device *dev, struct sk_buff *skb); 65 66 struct macvtap_queue *taps[MAX_MACVTAP_QUEUES];