diff options
-rw-r--r-- | drivers/net/macvlan.c | 73 | ||||
-rw-r--r-- | include/linux/if_link.h | 3 | ||||
-rw-r--r-- | include/linux/if_macvlan.h | 1 |
3 files changed, 71 insertions, 6 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index b17fc9007099..9653ed6998fe 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -312,7 +312,8 @@ static int macvlan_open(struct net_device *dev) | |||
312 | int err; | 312 | int err; |
313 | 313 | ||
314 | if (vlan->port->passthru) { | 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 | goto hash_add; | 317 | goto hash_add; |
317 | } | 318 | } |
318 | 319 | ||
@@ -344,12 +345,15 @@ static int macvlan_stop(struct net_device *dev) | |||
344 | struct macvlan_dev *vlan = netdev_priv(dev); | 345 | struct macvlan_dev *vlan = netdev_priv(dev); |
345 | struct net_device *lowerdev = vlan->lowerdev; | 346 | struct net_device *lowerdev = vlan->lowerdev; |
346 | 347 | ||
348 | dev_uc_unsync(lowerdev, dev); | ||
349 | dev_mc_unsync(lowerdev, dev); | ||
350 | |||
347 | if (vlan->port->passthru) { | 351 | if (vlan->port->passthru) { |
348 | dev_set_promiscuity(lowerdev, -1); | 352 | if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) |
353 | dev_set_promiscuity(lowerdev, -1); | ||
349 | goto hash_del; | 354 | goto hash_del; |
350 | } | 355 | } |
351 | 356 | ||
352 | dev_mc_unsync(lowerdev, dev); | ||
353 | if (dev->flags & IFF_ALLMULTI) | 357 | if (dev->flags & IFF_ALLMULTI) |
354 | dev_set_allmulti(lowerdev, -1); | 358 | dev_set_allmulti(lowerdev, -1); |
355 | 359 | ||
@@ -399,10 +403,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change) | |||
399 | dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); | 403 | dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); |
400 | } | 404 | } |
401 | 405 | ||
402 | static void macvlan_set_multicast_list(struct net_device *dev) | 406 | static void macvlan_set_mac_lists(struct net_device *dev) |
403 | { | 407 | { |
404 | struct macvlan_dev *vlan = netdev_priv(dev); | 408 | struct macvlan_dev *vlan = netdev_priv(dev); |
405 | 409 | ||
410 | dev_uc_sync(vlan->lowerdev, dev); | ||
406 | dev_mc_sync(vlan->lowerdev, dev); | 411 | dev_mc_sync(vlan->lowerdev, dev); |
407 | } | 412 | } |
408 | 413 | ||
@@ -542,6 +547,43 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, | |||
542 | return 0; | 547 | return 0; |
543 | } | 548 | } |
544 | 549 | ||
550 | static int macvlan_fdb_add(struct ndmsg *ndm, | ||
551 | struct net_device *dev, | ||
552 | unsigned char *addr, | ||
553 | u16 flags) | ||
554 | { | ||
555 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
556 | int err = -EINVAL; | ||
557 | |||
558 | if (!vlan->port->passthru) | ||
559 | return -EOPNOTSUPP; | ||
560 | |||
561 | if (is_unicast_ether_addr(addr)) | ||
562 | err = dev_uc_add_excl(dev, addr); | ||
563 | else if (is_multicast_ether_addr(addr)) | ||
564 | err = dev_mc_add_excl(dev, addr); | ||
565 | |||
566 | return err; | ||
567 | } | ||
568 | |||
569 | static int macvlan_fdb_del(struct ndmsg *ndm, | ||
570 | struct net_device *dev, | ||
571 | unsigned char *addr) | ||
572 | { | ||
573 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
574 | int err = -EINVAL; | ||
575 | |||
576 | if (!vlan->port->passthru) | ||
577 | return -EOPNOTSUPP; | ||
578 | |||
579 | if (is_unicast_ether_addr(addr)) | ||
580 | err = dev_uc_del(dev, addr); | ||
581 | else if (is_multicast_ether_addr(addr)) | ||
582 | err = dev_mc_del(dev, addr); | ||
583 | |||
584 | return err; | ||
585 | } | ||
586 | |||
545 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, | 587 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, |
546 | struct ethtool_drvinfo *drvinfo) | 588 | struct ethtool_drvinfo *drvinfo) |
547 | { | 589 | { |
@@ -572,11 +614,14 @@ static const struct net_device_ops macvlan_netdev_ops = { | |||
572 | .ndo_change_mtu = macvlan_change_mtu, | 614 | .ndo_change_mtu = macvlan_change_mtu, |
573 | .ndo_change_rx_flags = macvlan_change_rx_flags, | 615 | .ndo_change_rx_flags = macvlan_change_rx_flags, |
574 | .ndo_set_mac_address = macvlan_set_mac_address, | 616 | .ndo_set_mac_address = macvlan_set_mac_address, |
575 | .ndo_set_rx_mode = macvlan_set_multicast_list, | 617 | .ndo_set_rx_mode = macvlan_set_mac_lists, |
576 | .ndo_get_stats64 = macvlan_dev_get_stats64, | 618 | .ndo_get_stats64 = macvlan_dev_get_stats64, |
577 | .ndo_validate_addr = eth_validate_addr, | 619 | .ndo_validate_addr = eth_validate_addr, |
578 | .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, | 620 | .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, |
579 | .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, | 621 | .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, |
622 | .ndo_fdb_add = macvlan_fdb_add, | ||
623 | .ndo_fdb_del = macvlan_fdb_del, | ||
624 | .ndo_fdb_dump = ndo_dflt_fdb_dump, | ||
580 | }; | 625 | }; |
581 | 626 | ||
582 | void macvlan_common_setup(struct net_device *dev) | 627 | void macvlan_common_setup(struct net_device *dev) |
@@ -711,6 +756,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | |||
711 | if (data && data[IFLA_MACVLAN_MODE]) | 756 | if (data && data[IFLA_MACVLAN_MODE]) |
712 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | 757 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); |
713 | 758 | ||
759 | if (data && data[IFLA_MACVLAN_FLAGS]) | ||
760 | vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); | ||
761 | |||
714 | if (vlan->mode == MACVLAN_MODE_PASSTHRU) { | 762 | if (vlan->mode == MACVLAN_MODE_PASSTHRU) { |
715 | if (port->count) | 763 | if (port->count) |
716 | return -EINVAL; | 764 | return -EINVAL; |
@@ -760,6 +808,16 @@ static int macvlan_changelink(struct net_device *dev, | |||
760 | struct macvlan_dev *vlan = netdev_priv(dev); | 808 | struct macvlan_dev *vlan = netdev_priv(dev); |
761 | if (data && data[IFLA_MACVLAN_MODE]) | 809 | if (data && data[IFLA_MACVLAN_MODE]) |
762 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | 810 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); |
811 | if (data && data[IFLA_MACVLAN_FLAGS]) { | ||
812 | __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); | ||
813 | bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; | ||
814 | |||
815 | if (promisc && (flags & MACVLAN_FLAG_NOPROMISC)) | ||
816 | dev_set_promiscuity(vlan->lowerdev, -1); | ||
817 | else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC)) | ||
818 | dev_set_promiscuity(vlan->lowerdev, 1); | ||
819 | vlan->flags = flags; | ||
820 | } | ||
763 | return 0; | 821 | return 0; |
764 | } | 822 | } |
765 | 823 | ||
@@ -775,6 +833,8 @@ static int macvlan_fill_info(struct sk_buff *skb, | |||
775 | 833 | ||
776 | if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) | 834 | if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) |
777 | goto nla_put_failure; | 835 | goto nla_put_failure; |
836 | if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags)) | ||
837 | goto nla_put_failure; | ||
778 | return 0; | 838 | return 0; |
779 | 839 | ||
780 | nla_put_failure: | 840 | nla_put_failure: |
@@ -782,7 +842,8 @@ nla_put_failure: | |||
782 | } | 842 | } |
783 | 843 | ||
784 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { | 844 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { |
785 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, | 845 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, |
846 | [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, | ||
786 | }; | 847 | }; |
787 | 848 | ||
788 | int macvlan_link_register(struct rtnl_link_ops *ops) | 849 | int macvlan_link_register(struct rtnl_link_ops *ops) |
diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 2f4fa93454c7..f715750d0b87 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h | |||
@@ -255,6 +255,7 @@ struct ifla_vlan_qos_mapping { | |||
255 | enum { | 255 | enum { |
256 | IFLA_MACVLAN_UNSPEC, | 256 | IFLA_MACVLAN_UNSPEC, |
257 | IFLA_MACVLAN_MODE, | 257 | IFLA_MACVLAN_MODE, |
258 | IFLA_MACVLAN_FLAGS, | ||
258 | __IFLA_MACVLAN_MAX, | 259 | __IFLA_MACVLAN_MAX, |
259 | }; | 260 | }; |
260 | 261 | ||
@@ -267,6 +268,8 @@ enum macvlan_mode { | |||
267 | MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ | 268 | MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ |
268 | }; | 269 | }; |
269 | 270 | ||
271 | #define MACVLAN_FLAG_NOPROMISC 1 | ||
272 | |||
270 | /* SR-IOV virtual function management section */ | 273 | /* SR-IOV virtual function management section */ |
271 | 274 | ||
272 | enum { | 275 | enum { |
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index d103dca5c563..f65e8d250f7e 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h | |||
@@ -60,6 +60,7 @@ struct macvlan_dev { | |||
60 | struct net_device *lowerdev; | 60 | struct net_device *lowerdev; |
61 | struct macvlan_pcpu_stats __percpu *pcpu_stats; | 61 | struct macvlan_pcpu_stats __percpu *pcpu_stats; |
62 | enum macvlan_mode mode; | 62 | enum macvlan_mode mode; |
63 | u16 flags; | ||
63 | int (*receive)(struct sk_buff *skb); | 64 | int (*receive)(struct sk_buff *skb); |
64 | int (*forward)(struct net_device *dev, struct sk_buff *skb); | 65 | int (*forward)(struct net_device *dev, struct sk_buff *skb); |
65 | struct macvtap_queue *taps[MAX_MACVTAP_QUEUES]; | 66 | struct macvtap_queue *taps[MAX_MACVTAP_QUEUES]; |