From: Roopa Prabhu <[email protected]>

This patch adds support to get MAC and VLAN filter netdev ops
on a macvlan interface. It adds support for get_rx_filter_addr_size,
get_rx_filter_vlan_size, fill_rx_filter_addr and fill_rx_filter_vlan
netdev ops

Signed-off-by: Roopa Prabhu <[email protected]>
Signed-off-by: Christian Benvenuti <[email protected]>
Signed-off-by: David Wang <[email protected]>
---
 drivers/net/macvlan.c |  158 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 158 insertions(+), 0 deletions(-)


diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 9d8cbe3..15dd7de 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -616,6 +616,55 @@ static int macvlan_set_rx_filter_vlan(struct net_device 
*dev, int vf,
        return 0;
 }
 
+static size_t macvlan_get_rx_filter_vlan_size(const struct net_device *dev,
+                                             int vf)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (vf != SELF_VF)
+               return -EINVAL;
+
+       switch (vlan->mode) {
+       case MACVLAN_MODE_PASSTHRU:
+               if (ops->ndo_get_rx_filter_vlan_size)
+                       return ops->ndo_get_rx_filter_vlan_size(dev, vf);
+               /* IFLA_RX_FILTER_VLAN_BITMAP */
+               return nla_total_size(VLAN_BITMAP_SIZE);
+       default:
+               return 0;
+       }
+}
+
+static int macvlan_get_rx_filter_vlan(const struct net_device *dev, int vf,
+                                     struct sk_buff *skb)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (vf != SELF_VF)
+               return -EINVAL;
+
+       switch (vlan->mode) {
+       case MACVLAN_MODE_PASSTHRU:
+               if (ops->ndo_get_rx_filter_vlan)
+                       return ops->ndo_get_rx_filter_vlan(dev, vf, skb);
+
+               NLA_PUT(skb, IFLA_RX_FILTER_VLAN_BITMAP, VLAN_BITMAP_SIZE,
+                       vlan->vlan_filter);
+               break;
+       default:
+               return -ENODATA; /* No data to Fill */
+       }
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
 static int macvlan_addr_in_hw_list(struct netdev_hw_addr_list *list,
                                   u8 *addr, int addrlen)
 {
@@ -795,6 +844,111 @@ static int macvlan_set_rx_filter_addr(struct net_device 
*dev, int vf,
        return 0;
 }
 
+static size_t macvlan_get_rx_filter_addr_passthru_size(
+                       const struct net_device *dev, int vf)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+       size_t size;
+
+       if (ops->ndo_get_rx_filter_addr_size)
+               return ops->ndo_get_rx_filter_addr_size(dev, vf);
+
+       /* IFLA_RX_FILTER_ADDR_FLAGS */
+       size = nla_total_size(sizeof(u32));
+
+       if (netdev_uc_count(dev))
+               /* IFLA_RX_FILTER_ADDR_UC_LIST */
+               size += nla_total_size(netdev_uc_count(dev) *
+                                      ETH_ALEN * sizeof(struct nlattr));
+
+       if (netdev_mc_count(dev))
+               /* IFLA_RX_FILTER_ADDR_MC_LIST */
+               size += nla_total_size(netdev_mc_count(dev) *
+                                      ETH_ALEN * sizeof(struct nlattr));
+
+       return size;
+}
+
+static size_t macvlan_get_rx_filter_addr_size(const struct net_device *dev,
+                                             int vf)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+
+       if (vf != SELF_VF)
+               return -EINVAL;
+
+       switch (vlan->mode) {
+       case MACVLAN_MODE_PASSTHRU:
+               return macvlan_get_rx_filter_addr_passthru_size(dev, vf);
+       default:
+               return 0;
+       }
+}
+
+static int macvlan_get_rx_filter_addr_passthru(const struct net_device *dev,
+                                              int vf, struct sk_buff *skb)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+       struct nlattr *uninitialized_var(uc_list), *mc_list;
+       struct netdev_hw_addr *ha;
+
+       if (ops->ndo_get_rx_filter_addr)
+               return ops->ndo_get_rx_filter_addr(dev, vf, skb);
+
+       NLA_PUT_U32(skb, IFLA_RX_FILTER_ADDR_FLAGS,
+               dev->flags & RX_FILTER_FLAGS);
+
+       if (netdev_uc_count(dev)) {
+               uc_list = nla_nest_start(skb, IFLA_RX_FILTER_ADDR_UC_LIST);
+               if (uc_list == NULL)
+                       goto nla_put_failure;
+
+               netdev_for_each_uc_addr(ha, dev) {
+                       NLA_PUT(skb, IFLA_ADDR_LIST_ENTRY, ETH_ALEN, ha->addr);
+               }
+               nla_nest_end(skb, uc_list);
+       }
+
+       if (netdev_mc_count(dev)) {
+               mc_list = nla_nest_start(skb, IFLA_RX_FILTER_ADDR_MC_LIST);
+               if (mc_list == NULL)
+                       goto nla_uc_list_cancel;
+
+               netdev_for_each_mc_addr(ha, dev) {
+                       NLA_PUT(skb, IFLA_ADDR_LIST_ENTRY, ETH_ALEN, ha->addr);
+               }
+               nla_nest_end(skb, mc_list);
+       }
+
+       return 0;
+
+nla_uc_list_cancel:
+       if (netdev_uc_count(dev))
+               nla_nest_cancel(skb, uc_list);
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static int macvlan_get_rx_filter_addr(const struct net_device *dev, int vf,
+                                     struct sk_buff *skb)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+
+       if (vf != SELF_VF)
+               return -EINVAL;
+
+       switch (vlan->mode) {
+       case MACVLAN_MODE_PASSTHRU:
+               return macvlan_get_rx_filter_addr_passthru(dev, vf, skb);
+       default:
+               return -ENODATA; /* No data to Fill */
+       }
+}
+
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *drvinfo)
 {
@@ -831,7 +985,11 @@ static const struct net_device_ops macvlan_netdev_ops = {
        .ndo_vlan_rx_add_vid            = macvlan_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid           = macvlan_vlan_rx_kill_vid,
        .ndo_set_rx_filter_addr         = macvlan_set_rx_filter_addr,
+       .ndo_get_rx_filter_addr_size    = macvlan_get_rx_filter_addr_size,
+       .ndo_get_rx_filter_addr         = macvlan_get_rx_filter_addr,
        .ndo_set_rx_filter_vlan         = macvlan_set_rx_filter_vlan,
+       .ndo_get_rx_filter_vlan_size    = macvlan_get_rx_filter_vlan_size,
+       .ndo_get_rx_filter_vlan         = macvlan_get_rx_filter_vlan,
 };
 
 void macvlan_common_setup(struct net_device *dev)

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to