diff options
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r-- | drivers/net/macvlan.c | 83 |
1 files changed, 72 insertions, 11 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 025367a94add..66a9bfe7b1c8 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -57,7 +57,7 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, | |||
57 | struct hlist_node *n; | 57 | struct hlist_node *n; |
58 | 58 | ||
59 | hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) { | 59 | hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) { |
60 | if (!compare_ether_addr_64bits(vlan->dev->dev_addr, addr)) | 60 | if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr)) |
61 | return vlan; | 61 | return vlan; |
62 | } | 62 | } |
63 | return NULL; | 63 | return NULL; |
@@ -96,7 +96,7 @@ static int macvlan_addr_busy(const struct macvlan_port *port, | |||
96 | * currently in use by the underlying device or | 96 | * currently in use by the underlying device or |
97 | * another macvlan. | 97 | * another macvlan. |
98 | */ | 98 | */ |
99 | if (!compare_ether_addr_64bits(port->dev->dev_addr, addr)) | 99 | if (ether_addr_equal_64bits(port->dev->dev_addr, addr)) |
100 | return 1; | 100 | return 1; |
101 | 101 | ||
102 | if (macvlan_hash_lookup(port, addr)) | 102 | if (macvlan_hash_lookup(port, addr)) |
@@ -118,8 +118,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, | |||
118 | return vlan->forward(dev, skb); | 118 | return vlan->forward(dev, skb); |
119 | 119 | ||
120 | skb->dev = dev; | 120 | skb->dev = dev; |
121 | if (!compare_ether_addr_64bits(eth->h_dest, | 121 | if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) |
122 | dev->broadcast)) | ||
123 | skb->pkt_type = PACKET_BROADCAST; | 122 | skb->pkt_type = PACKET_BROADCAST; |
124 | else | 123 | else |
125 | skb->pkt_type = PACKET_MULTICAST; | 124 | skb->pkt_type = PACKET_MULTICAST; |
@@ -312,7 +311,8 @@ static int macvlan_open(struct net_device *dev) | |||
312 | int err; | 311 | int err; |
313 | 312 | ||
314 | if (vlan->port->passthru) { | 313 | if (vlan->port->passthru) { |
315 | dev_set_promiscuity(lowerdev, 1); | 314 | if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) |
315 | dev_set_promiscuity(lowerdev, 1); | ||
316 | goto hash_add; | 316 | goto hash_add; |
317 | } | 317 | } |
318 | 318 | ||
@@ -344,12 +344,15 @@ static int macvlan_stop(struct net_device *dev) | |||
344 | struct macvlan_dev *vlan = netdev_priv(dev); | 344 | struct macvlan_dev *vlan = netdev_priv(dev); |
345 | struct net_device *lowerdev = vlan->lowerdev; | 345 | struct net_device *lowerdev = vlan->lowerdev; |
346 | 346 | ||
347 | dev_uc_unsync(lowerdev, dev); | ||
348 | dev_mc_unsync(lowerdev, dev); | ||
349 | |||
347 | if (vlan->port->passthru) { | 350 | if (vlan->port->passthru) { |
348 | dev_set_promiscuity(lowerdev, -1); | 351 | if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) |
352 | dev_set_promiscuity(lowerdev, -1); | ||
349 | goto hash_del; | 353 | goto hash_del; |
350 | } | 354 | } |
351 | 355 | ||
352 | dev_mc_unsync(lowerdev, dev); | ||
353 | if (dev->flags & IFF_ALLMULTI) | 356 | if (dev->flags & IFF_ALLMULTI) |
354 | dev_set_allmulti(lowerdev, -1); | 357 | dev_set_allmulti(lowerdev, -1); |
355 | 358 | ||
@@ -399,10 +402,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change) | |||
399 | dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); | 402 | dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); |
400 | } | 403 | } |
401 | 404 | ||
402 | static void macvlan_set_multicast_list(struct net_device *dev) | 405 | static void macvlan_set_mac_lists(struct net_device *dev) |
403 | { | 406 | { |
404 | struct macvlan_dev *vlan = netdev_priv(dev); | 407 | struct macvlan_dev *vlan = netdev_priv(dev); |
405 | 408 | ||
409 | dev_uc_sync(vlan->lowerdev, dev); | ||
406 | dev_mc_sync(vlan->lowerdev, dev); | 410 | dev_mc_sync(vlan->lowerdev, dev); |
407 | } | 411 | } |
408 | 412 | ||
@@ -542,6 +546,43 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, | |||
542 | return 0; | 546 | return 0; |
543 | } | 547 | } |
544 | 548 | ||
549 | static int macvlan_fdb_add(struct ndmsg *ndm, | ||
550 | struct net_device *dev, | ||
551 | unsigned char *addr, | ||
552 | u16 flags) | ||
553 | { | ||
554 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
555 | int err = -EINVAL; | ||
556 | |||
557 | if (!vlan->port->passthru) | ||
558 | return -EOPNOTSUPP; | ||
559 | |||
560 | if (is_unicast_ether_addr(addr)) | ||
561 | err = dev_uc_add_excl(dev, addr); | ||
562 | else if (is_multicast_ether_addr(addr)) | ||
563 | err = dev_mc_add_excl(dev, addr); | ||
564 | |||
565 | return err; | ||
566 | } | ||
567 | |||
568 | static int macvlan_fdb_del(struct ndmsg *ndm, | ||
569 | struct net_device *dev, | ||
570 | unsigned char *addr) | ||
571 | { | ||
572 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
573 | int err = -EINVAL; | ||
574 | |||
575 | if (!vlan->port->passthru) | ||
576 | return -EOPNOTSUPP; | ||
577 | |||
578 | if (is_unicast_ether_addr(addr)) | ||
579 | err = dev_uc_del(dev, addr); | ||
580 | else if (is_multicast_ether_addr(addr)) | ||
581 | err = dev_mc_del(dev, addr); | ||
582 | |||
583 | return err; | ||
584 | } | ||
585 | |||
545 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, | 586 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, |
546 | struct ethtool_drvinfo *drvinfo) | 587 | struct ethtool_drvinfo *drvinfo) |
547 | { | 588 | { |
@@ -572,11 +613,14 @@ static const struct net_device_ops macvlan_netdev_ops = { | |||
572 | .ndo_change_mtu = macvlan_change_mtu, | 613 | .ndo_change_mtu = macvlan_change_mtu, |
573 | .ndo_change_rx_flags = macvlan_change_rx_flags, | 614 | .ndo_change_rx_flags = macvlan_change_rx_flags, |
574 | .ndo_set_mac_address = macvlan_set_mac_address, | 615 | .ndo_set_mac_address = macvlan_set_mac_address, |
575 | .ndo_set_rx_mode = macvlan_set_multicast_list, | 616 | .ndo_set_rx_mode = macvlan_set_mac_lists, |
576 | .ndo_get_stats64 = macvlan_dev_get_stats64, | 617 | .ndo_get_stats64 = macvlan_dev_get_stats64, |
577 | .ndo_validate_addr = eth_validate_addr, | 618 | .ndo_validate_addr = eth_validate_addr, |
578 | .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, | 619 | .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, |
579 | .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, | 620 | .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, |
621 | .ndo_fdb_add = macvlan_fdb_add, | ||
622 | .ndo_fdb_del = macvlan_fdb_del, | ||
623 | .ndo_fdb_dump = ndo_dflt_fdb_dump, | ||
580 | }; | 624 | }; |
581 | 625 | ||
582 | void macvlan_common_setup(struct net_device *dev) | 626 | void macvlan_common_setup(struct net_device *dev) |
@@ -711,6 +755,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | |||
711 | if (data && data[IFLA_MACVLAN_MODE]) | 755 | if (data && data[IFLA_MACVLAN_MODE]) |
712 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | 756 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); |
713 | 757 | ||
758 | if (data && data[IFLA_MACVLAN_FLAGS]) | ||
759 | vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); | ||
760 | |||
714 | if (vlan->mode == MACVLAN_MODE_PASSTHRU) { | 761 | if (vlan->mode == MACVLAN_MODE_PASSTHRU) { |
715 | if (port->count) | 762 | if (port->count) |
716 | return -EINVAL; | 763 | return -EINVAL; |
@@ -760,6 +807,16 @@ static int macvlan_changelink(struct net_device *dev, | |||
760 | struct macvlan_dev *vlan = netdev_priv(dev); | 807 | struct macvlan_dev *vlan = netdev_priv(dev); |
761 | if (data && data[IFLA_MACVLAN_MODE]) | 808 | if (data && data[IFLA_MACVLAN_MODE]) |
762 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | 809 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); |
810 | if (data && data[IFLA_MACVLAN_FLAGS]) { | ||
811 | __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); | ||
812 | bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; | ||
813 | |||
814 | if (promisc && (flags & MACVLAN_FLAG_NOPROMISC)) | ||
815 | dev_set_promiscuity(vlan->lowerdev, -1); | ||
816 | else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC)) | ||
817 | dev_set_promiscuity(vlan->lowerdev, 1); | ||
818 | vlan->flags = flags; | ||
819 | } | ||
763 | return 0; | 820 | return 0; |
764 | } | 821 | } |
765 | 822 | ||
@@ -773,7 +830,10 @@ static int macvlan_fill_info(struct sk_buff *skb, | |||
773 | { | 830 | { |
774 | struct macvlan_dev *vlan = netdev_priv(dev); | 831 | struct macvlan_dev *vlan = netdev_priv(dev); |
775 | 832 | ||
776 | NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode); | 833 | if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) |
834 | goto nla_put_failure; | ||
835 | if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags)) | ||
836 | goto nla_put_failure; | ||
777 | return 0; | 837 | return 0; |
778 | 838 | ||
779 | nla_put_failure: | 839 | nla_put_failure: |
@@ -781,7 +841,8 @@ nla_put_failure: | |||
781 | } | 841 | } |
782 | 842 | ||
783 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { | 843 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { |
784 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, | 844 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, |
845 | [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, | ||
785 | }; | 846 | }; |
786 | 847 | ||
787 | int macvlan_link_register(struct rtnl_link_ops *ops) | 848 | int macvlan_link_register(struct rtnl_link_ops *ops) |