netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode
@ 2011-10-29  2:33 Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 1/6 RFC v3] rtnetlink: Netlink interface for setting MAC and VLAN filters Roopa Prabhu
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:33 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

v2 -> v3
- Moved set and get filter ops from rtnl_link_ops to netdev_ops
- Support for SRIOV VFs.
	[Note: The get filters msg might get too big for SRIOV vfs. 
        But this patch follows existing sriov vf get code and 
	accomodate filters for all VF's in a PF. 
        And for the SRIOV case I have only tested the fact that the VF 
	arguments are getting delivered to rtnetlink correctly. The rest of
	the code follows existing sriov vf handling code so it should work 
	just fine]
- Fixed all op and netlink attribute names to start with IFLA_RX_FILTER
- Changed macvlan filter ops to call corresponding lowerdev op if lowerdev 
  supports it for passthru mode. Else it falls back on macvlan handling the 
  filters locally as in v1 and v2

v1 -> v2
- Instead of TUNSETTXFILTER introduced rtnetlink interface for the same


Background and details:
=======================
Today macvtap used in virtualized environment does not have support to 
propagate MAC, VLAN and interface flags from guest to lowerdev.
Which means to be able to register additional VLANs, unicast and multicast
addresses or change pkt filter flags in the guest, the lowerdev has to be
put in promisocous mode. Today the only macvlan mode that supports this is 
the PASSTHRU mode and it puts the lower dev in promiscous mode.

PASSTHRU mode was added primarily for the SRIOV usecase. In PASSTHRU mode 
there is a 1-1 mapping between macvtap and physical NIC or VF.

There are two problems with putting the lowerdev in promiscous mode (ie SRIOV 
VF's):
	- Some SRIOV cards dont support promiscous mode today (Thread on Intel
	driver indicates that http://lists.openwall.net/netdev/2011/09/27/6)
	- For the SRIOV NICs that support it, Putting the lowerdev in 
	promiscous mode leads to additional traffic being sent up to the 
	guest virtio-net to filter result in extra overheads.
	
Both the above problems can be solved by offloading filtering to the 
lowerdev hw. ie lowerdev does not need to be in promiscous mode as 
long as the guest filters are passed down to the lowerdev. 

This patch basically adds the infrastructure to set and get MAC and VLAN 
filters on an interface via rtnetlink. It adds new netlink msg and netdev
ops for the same. And implements these ops in macvlan for passthru mode.

- Netlink interface:
    This patch provides the following netlink interface to set mac and vlan
    filters :

    Interface to set RX filter on a SRIOV VF:
    [IFLA_VF_RX_FILTERS] = {
    	[IFLA_VF_RX_FILTER] = {
    		[IFLA_RX_FILTER_VF]
    		[IFLA_RX_FILTER_ADDR] = {
    			[IFLA_RX_FILTER_ADDR_FLAGS]
    			[IFLA_RX_FILTER_ADDR_UC_LIST] = {
    				[IFLA_ADDR_LIST_ENTRY]
    			}
    			[IFLA_RX_FILTER_ADDR_MC_LIST] = {
    				[IFLA_ADDR_LIST_ENTRY]
    			}
    		}
    		[IFLA_RX_FILTER_VLAN] = {
    			[IFLA_RX_FILTER_VLAN_BITMAP]
    		}
    	}
    	...
    }
    
    Interface to set RX filter on a any network interface.:
    [IFLA_RX_FILTER] = {
    	[IFLA_RX_FILTER_VF]
    	[IFLA_RX_FILTER_ADDR] = {
    		[IFLA_RX_FILTER_ADDR_FLAGS]
    		[IFLA_RX_FILTER_ADDR_UC_LIST] = {
    			[IFLA_ADDR_LIST_ENTRY]
    		}
    		[IFLA_RX_FILTER_ADDR_MC_LIST] = {
    			[IFLA_ADDR_LIST_ENTRY]
    		}
    	}
    	[IFLA_RX_FILTER_VLAN] = {
    		[IFLA_RX_FILTER_VLAN_BITMAP]
	}
    } 

    Note1: The IFLA_RX_FILTER_VLAN is a nested attribute, but contains only 
    IFLA_RX_FILTER_VLAN_BITMAP today. The idea is that the IFLA_RX_FILTER_VLAN 
    can be extended tomorrow to have a vlan list if some implementations 
    prefer a list instead. 

    And it provides the following netdev_ops to set/get MAC/VLAN filters:

    int                     (*ndo_set_rx_filter_addr)(
	                                        struct net_device *dev, int vf,
                                                struct nlattr *tb[]);
    int                     (*ndo_set_rx_filter_vlan)(
                                                struct net_device *dev, int vf,
                                                struct nlattr *tb[]);
    size_t                  (*ndo_get_rx_filter_addr_size)(
                                                const struct net_device *dev,
                                                int vf);
    size_t                  (*ndo_get_rx_filter_vlan_size)(
                                                const struct net_device *dev,
                                                int vf);
    int                     (*ndo_get_rx_filter_addr)(
                                                const struct net_device *dev,
                                                int vf, struct sk_buff *skb);
    int                     (*ndo_get_rx_filter_vlan)(
                                                const struct net_device *dev,
                                                int vf, struct sk_buff *skb);

Some answers to questions that were raised during the review:
- Protection against address spoofing:
	- This patch adds filtering support only for macvtap PASSTHRU 
	Mode. PASSTHRU mode is used mainly with SRIOV VF's. And SRIOV VF's 
	come with anti mac/vlan spoofing support in the lowerdev driver. 
	(netdev infrastructure to support this was added recently 
	with IFLA_VF_SPOOFCHK). For 802.1Qbh devices, the port profile has a 
	knob to enable/disable anti spoof check. Lowerdevice drivers also 
	enforce limits on the number of address registrations allowed. 
	For non-SRIOV VF's its the responsibility of the lowerdev driver
	to implement any such protection. The currrent netdev hooks for 
	SRIOV VF's spoof check could be extended to accomodate any network 
	interface in the future.

- Support for multiqueue devices: Enable filtering on individual queues (?):
	As i understand after the thread between (Micheal and Greg),
	VMdq Linux implementation is not in yet and dont know how its going to
	take shape. But Intel VMdq devices do accept filters on a per-queue
	basis. Since the netdev infrastructure for VMdq is not in yet, Its
	hard to say how this patch can support it.

	This patch makes use of current netdev infrastructure for setting
	address and vlan filters. And if that changes for vmdq tomorrow,
	then the work that this patch represents can be modified to accomodate
	vmdq devices at that time. 

	So i dont see a huge problem with this patch coming in the way for
	vmdq devices.

- Support for non-PASSTHRU mode:
	I started implementing this. But there are a couple of problems.	
	- Today, in non-PASSTHRU cases macvlan_handle_frame assumes that 
	every macvlan device has a single unique mac.
	And the macvlans are hashed on that single mac address. 
	To support filtering for non-PASSTHRU mode in addition to this 
	patch the following needs to be done:
		- non-passthru mode with a single macvlan over a lower dev
		can be treated as PASSTHRU case
		- For non-PASSTHRU mode with multiple macvlans over a single 
		lower dev:  
			- Multiple unicast mac's now need to be hashed to the 
			same macvlan device. The macvlan hash needs to change 
			for lookup based on any one of the multiple unicast 
			addresses a macvlan is interested in
			- We need to consider vlans during the lookup too
			- So the macvlan device hash needs to hash on both mac 
			and vlan
		- But the support for filtering in non-PASSTHRU mode can be 
		built on this patch

This patch series implements the following 
01/6 rtnetlink: Netlink interface for setting MAC and VLAN filters
02/6 netdev: Add netdev_ops to set and get MAC/VLAN rx filters
03/6 rtnetlink: Add support to set MAC/VLAN filters
04/6 rtnetlink: Add support to get MAC/VLAN filters
05/6 macvlan: Add support to set MAC/VLAN filter netdev ops
06/6 macvlan: Add support to get MAC/VLAN filter netdev ops

Please comment. Thanks.

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [net-next-2.6 PATCH 1/6 RFC v3] rtnetlink: Netlink interface for setting MAC and VLAN filters
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
@ 2011-10-29  2:34 ` Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 2/6 RFC v3] net: Add netdev_ops to set and get MAC/VLAN rx filters Roopa Prabhu
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:34 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

From: Roopa Prabhu <roprabhu@cisco.com>

This patch introduces the following netlink interface to set
MAC and VLAN filters on an network interface. It can be used to
set RX filter on any network interface (if supported by the driver) and
also on a SRIOV VF via its PF

Interface to set RX filter on a SRIOV VF
[IFLA_VF_RX_FILTERS] = {
	[IFLA_VF_RX_FILTER] = {
		[IFLA_RX_FILTER_VF]
		[IFLA_RX_FILTER_ADDR] = {
			[IFLA_RX_FILTER_ADDR_FLAGS]
			[IFLA_RX_FILTER_ADDR_UC_LIST] = {
				[IFLA_ADDR_LIST_ENTRY]
			}
			[IFLA_RX_FILTER_ADDR_MC_LIST] = {
				[IFLA_ADDR_LIST_ENTRY]
			}
		}
		[IFLA_RX_FILTER_VLAN] = {
			[IFLA_RX_FILTER_VLAN_BITMAP]
		}
	}
	...
}

Interface to set RX filter on any network interface.:
[IFLA_RX_FILTER] = {
	[IFLA_RX_FILTER_VF]
	[IFLA_RX_FILTER_ADDR] = {
		[IFLA_RX_FILTER_ADDR_FLAGS]
		[IFLA_RX_FILTER_ADDR_UC_LIST] = {
			[IFLA_ADDR_LIST_ENTRY]
		}
		[IFLA_RX_FILTER_ADDR_MC_LIST] = {
			[IFLA_ADDR_LIST_ENTRY]
		}
	}
	[IFLA_RX_FILTER_VLAN] = {
		[IFLA_RX_FILTER_VLAN_BITMAP]
	}
}

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 include/linux/if_link.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++
 net/core/rtnetlink.c    |   20 +++++++++++++++
 2 files changed, 81 insertions(+), 0 deletions(-)


diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index c52d4b5..74a9f17 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -137,6 +137,8 @@ enum {
 	IFLA_AF_SPEC,
 	IFLA_GROUP,		/* Group the device belongs to */
 	IFLA_NET_NS_FD,
+	IFLA_VF_RX_FILTERS,
+	IFLA_RX_FILTER,
 	__IFLA_MAX
 };
 
@@ -390,4 +392,63 @@ struct ifla_port_vsi {
 	__u8 pad[3];
 };
 
+/* VF rx filters management section
+ *
+ *	Nested layout of set/get msg is:
+ *
+ *	[IFLA_VF_RX_FILTERS]
+ *		[IFLA_VF_RX_FILTER]
+ *			[IFLA_RX_FILTER_*], ...
+ *		[IFLA_VF_RX_FILTER]
+ *			[IFLA_RX_FILTER_*], ...
+ *		...
+ *	[IFLA_RX_FILTER]
+ *		[IFLA_RX_FILTER_*], ...
+ */
+enum {
+	IFLA_VF_RX_FILTER_UNSPEC,
+	IFLA_VF_RX_FILTER,			/* nest */
+	__IFLA_VF_RX_FILTER_MAX,
+};
+
+#define IFLA_VF_RX_FILTER_MAX (__IFLA_VF_RX_FILTER_MAX - 1)
+
+enum {
+	IFLA_RX_FILTER_UNSPEC,
+	IFLA_RX_FILTER_VF,		/* __u32 */
+	IFLA_RX_FILTER_ADDR,
+	IFLA_RX_FILTER_VLAN,
+	__IFLA_RX_FILTER_MAX,
+};
+#define IFLA_RX_FILTER_MAX (__IFLA_RX_FILTER_MAX - 1)
+
+enum {
+	IFLA_RX_FILTER_ADDR_UNSPEC,
+	IFLA_RX_FILTER_ADDR_FLAGS,
+	IFLA_RX_FILTER_ADDR_UC_LIST,
+	IFLA_RX_FILTER_ADDR_MC_LIST,
+	__IFLA_RX_FILTER_ADDR_MAX,
+};
+#define IFLA_RX_FILTER_ADDR_MAX (__IFLA_RX_FILTER_ADDR_MAX - 1)
+
+#define RX_FILTER_FLAGS (IFF_UP | IFF_BROADCAST | IFF_MULTICAST | \
+				IFF_PROMISC | IFF_ALLMULTI)
+
+enum {
+	IFLA_ADDR_LIST_UNSPEC,
+	IFLA_ADDR_LIST_ENTRY,
+	__IFLA_ADDR_LIST_MAX,
+};
+#define IFLA_ADDR_LIST_MAX (__IFLA_ADDR_LIST_MAX - 1)
+
+enum {
+	IFLA_RX_FILTER_VLAN_UNSPEC,
+	IFLA_RX_FILTER_VLAN_BITMAP,
+	__IFLA_RX_FILTER_VLAN_MAX,
+};
+#define IFLA_RX_FILTER_VLAN_MAX (__IFLA_RX_FILTER_VLAN_MAX - 1)
+
+#define VLAN_BITMAP_SPLIT_MAX 8
+#define VLAN_BITMAP_SIZE	(VLAN_N_VID/VLAN_BITMAP_SPLIT_MAX)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 9083e82..9eead8e 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -42,6 +42,7 @@
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/if_vlan.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -1097,6 +1098,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
 	[IFLA_VF_PORTS]		= { .type = NLA_NESTED },
 	[IFLA_PORT_SELF]	= { .type = NLA_NESTED },
 	[IFLA_AF_SPEC]		= { .type = NLA_NESTED },
+	[IFLA_VF_RX_FILTERS]	= { .type = NLA_NESTED },
+	[IFLA_RX_FILTER]	= { .type = NLA_NESTED },
 };
 EXPORT_SYMBOL(ifla_policy);
 
@@ -1132,6 +1135,23 @@ static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
 	[IFLA_PORT_RESPONSE]	= { .type = NLA_U16, },
 };
 
+static const struct nla_policy ifla_rx_filter_policy[IFLA_RX_FILTER_MAX+1] = {
+	[IFLA_RX_FILTER_VF]	= { .type = NLA_U32 },
+	[IFLA_RX_FILTER_ADDR]	= { .type = NLA_NESTED },
+	[IFLA_RX_FILTER_VLAN]	= { .type = NLA_NESTED },
+};
+
+static const struct nla_policy ifla_addr_filter_policy[IFLA_RX_FILTER_ADDR_MAX+1] = {
+	[IFLA_RX_FILTER_ADDR_FLAGS]	= { .type = NLA_U32 },
+	[IFLA_RX_FILTER_ADDR_UC_LIST]	= { .type = NLA_NESTED },
+	[IFLA_RX_FILTER_ADDR_MC_LIST]	= { .type = NLA_NESTED },
+};
+
+static const struct nla_policy ifla_vlan_filter_policy[IFLA_RX_FILTER_VLAN_MAX+1] = {
+	[IFLA_RX_FILTER_VLAN_BITMAP]	= { .type = NLA_BINARY,
+					    .len = VLAN_BITMAP_SIZE },
+};
+
 struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
 {
 	struct net *net;

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [net-next-2.6 PATCH 2/6 RFC v3] net: Add netdev_ops to set and get MAC/VLAN rx filters
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 1/6 RFC v3] rtnetlink: Netlink interface for setting MAC and VLAN filters Roopa Prabhu
@ 2011-10-29  2:34 ` Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 3/6 RFC v3] rtnetlink: Add support to set MAC/VLAN filters Roopa Prabhu
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:34 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

From: Roopa Prabhu <roprabhu@cisco.com>

This patch adds the following netdev_ops to set and get MAC/VLAN
filters on a SRIOV VF or any netdev interface. Each op takes a vf argument.
vf value of SELF_VF or -1 is for applying the operation directly on the
interface.

ndo_set_rx_filter_addr - to set address filter
ndo_get_rx_filter_addr_size - to get address filter size
ndo_get_rx_filter_addr - To get addr filter

ndo_set_rx_filter_vlan - to set vlan filter
ndo_get_rx_filter_vlan_size - to get vlan filter size
ndo_get_rx_filter_vlan - To get vlan filter

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 include/linux/netdevice.h |   32 ++++++++++++++++++++++++++++++++
 1 files changed, 32 insertions(+), 0 deletions(-)


diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0db1f5f..94f2bc1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -855,6 +855,20 @@ struct netdev_tc_txq {
  *	feature set might be less than what was returned by ndo_fix_features()).
  *	Must return >0 or -errno if it changed dev->features itself.
  *
+ * Address Filter management functions:
+ * int (*ndo_set_rx_filter_addr)(struct net_device *dev, int vf,
+ *				 struct nlattr *tb[]);
+ * size_t (*ndo_get_rx_filter_addr_size)(const struct net_device *dev, int vf);
+ * int (*ndo_get_rx_filter_addr)(const struct net_device *dev, int vf,
+ *				 struct sk_buff *skb);
+ *
+ * Vlan Filter management functions:
+ * int (*ndo_set_rx_filter_vlan)(struct net_device *dev, int vf,
+ *				 struct nlattr *tb[]);
+ * size_t (*ndo_get_rx_filter_vlan_size)(const struct net_device *dev, int vf);
+ * int (*ndo_get_rx_filter_vlan)(const struct net_device *dev, int vf,
+ *				 struct sk_buff *skb);
+ *
  */
 struct net_device_ops {
 	int			(*ndo_init)(struct net_device *dev);
@@ -948,6 +962,24 @@ struct net_device_ops {
 						    u32 features);
 	int			(*ndo_set_features)(struct net_device *dev,
 						    u32 features);
+	int			(*ndo_set_rx_filter_addr)(
+						struct net_device *dev, int vf,
+						struct nlattr *tb[]);
+	size_t			(*ndo_get_rx_filter_addr_size)(
+						const struct net_device *dev,
+						int vf);
+	int			(*ndo_get_rx_filter_addr)(
+						const struct net_device *dev,
+						int vf, struct sk_buff *skb);
+	int			(*ndo_set_rx_filter_vlan)(
+						struct net_device *dev, int vf,
+						struct nlattr *tb[]);
+	size_t			(*ndo_get_rx_filter_vlan_size)(
+						const struct net_device *dev,
+						int vf);
+	int			(*ndo_get_rx_filter_vlan)(
+						const struct net_device *dev,
+						int vf, struct sk_buff *skb);
 };
 
 /*


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [net-next-2.6 PATCH 3/6 RFC v3] rtnetlink: Add support to set MAC/VLAN filters
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 1/6 RFC v3] rtnetlink: Netlink interface for setting MAC and VLAN filters Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 2/6 RFC v3] net: Add netdev_ops to set and get MAC/VLAN rx filters Roopa Prabhu
@ 2011-10-29  2:34 ` Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 4/6 RFC v3] rtnetlink: Add support to get " Roopa Prabhu
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:34 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

From: Roopa Prabhu <roprabhu@cisco.com>

This patch adds support in rtnetlink for IFLA_RX_FILTER and
IFLA_VF_RX_FILTERS set. It calls netdev_ops->set_rx_filter_addr and
rtnl_link_ops->set_rx_filter_vlan

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 include/linux/if_link.h |    2 +
 net/core/rtnetlink.c    |  101 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 0 deletions(-)


diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 74a9f17..a8c2c14 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -268,6 +268,8 @@ enum macvlan_mode {
 
 /* SR-IOV virtual function management section */
 
+#define SELF_VF		-1
+
 enum {
 	IFLA_VF_INFO_UNSPEC,
 	IFLA_VF_INFO,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 9eead8e..a042910 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1294,6 +1294,66 @@ static int do_set_master(struct net_device *dev, int ifindex)
 	return 0;
 }
 
+static int do_set_rx_filter(struct net_device *dev, int vf,
+			    struct nlattr *rx_filter[],
+			    int *modified)
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+	int err = 0;
+
+	if (rx_filter[IFLA_RX_FILTER_ADDR]) {
+		struct nlattr *addr_filter[IFLA_RX_FILTER_ADDR_MAX+1];
+
+		if (!ops->ndo_set_rx_filter_addr) {
+			err = -EOPNOTSUPP;
+			goto errout;
+		}
+
+		err = nla_parse_nested(addr_filter, IFLA_RX_FILTER_ADDR_MAX,
+				rx_filter[IFLA_RX_FILTER_ADDR],
+				ifla_addr_filter_policy);
+		if (err < 0)
+			goto errout;
+
+		if (addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]) {
+			unsigned int flags = nla_get_u32(
+					addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]);
+			if (flags & ~RX_FILTER_FLAGS) {
+				err = -EINVAL;
+				goto errout;
+			}
+		}
+
+		err = ops->ndo_set_rx_filter_addr(dev, vf, addr_filter);
+		if (err < 0)
+			goto errout;
+		*modified = 1;
+	}
+
+	if (rx_filter[IFLA_RX_FILTER_VLAN]) {
+		struct nlattr *vlan_filter[IFLA_RX_FILTER_VLAN_MAX+1];
+
+		if (!ops->ndo_set_rx_filter_vlan) {
+			err = -EOPNOTSUPP;
+			goto errout;
+		}
+
+		err = nla_parse_nested(vlan_filter, IFLA_RX_FILTER_VLAN_MAX,
+				rx_filter[IFLA_RX_FILTER_VLAN],
+				ifla_vlan_filter_policy);
+		if (err < 0)
+			goto errout;
+
+		err = ops->ndo_set_rx_filter_vlan(dev, vf, vlan_filter);
+		if (err < 0)
+			goto errout;
+		*modified = 1;
+	}
+
+errout:
+	return err;
+}
+
 static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
 		      struct nlattr **tb, char *ifname, int modified)
 {
@@ -1515,6 +1575,47 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
 			modified = 1;
 		}
 	}
+
+	if (tb[IFLA_VF_RX_FILTERS]) {
+		struct nlattr *vf_rx_filter[IFLA_RX_FILTER_MAX+1];
+		struct nlattr *attr;
+		int vf;
+		int rem;
+
+		nla_for_each_nested(attr, tb[IFLA_VF_RX_FILTERS], rem) {
+			if (nla_type(attr) != IFLA_VF_RX_FILTER)
+				continue;
+			err = nla_parse_nested(vf_rx_filter, IFLA_RX_FILTER_MAX,
+					attr, ifla_rx_filter_policy);
+			if (err < 0)
+				goto errout;
+
+			if (!vf_rx_filter[IFLA_RX_FILTER_VF]) {
+				err = -EOPNOTSUPP;
+				goto errout;
+			}
+			vf = nla_get_u32(vf_rx_filter[IFLA_RX_FILTER_VF]);
+
+			err = do_set_rx_filter(dev, vf, vf_rx_filter,
+					 &modified);
+			if (err < 0)
+				goto errout;
+		}
+	}
+
+	if (tb[IFLA_RX_FILTER]) {
+		struct nlattr *rx_filter[IFLA_RX_FILTER_MAX+1];
+
+		err = nla_parse_nested(rx_filter, IFLA_RX_FILTER_MAX,
+				tb[IFLA_RX_FILTER], ifla_rx_filter_policy);
+		if (err < 0)
+			goto errout;
+
+		err = do_set_rx_filter(dev, SELF_VF, rx_filter, &modified);
+		if (err < 0)
+			goto errout;
+	}
+
 	err = 0;
 
 errout:


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [net-next-2.6 PATCH 4/6 RFC v3] rtnetlink: Add support to get MAC/VLAN filters
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
                   ` (2 preceding siblings ...)
  2011-10-29  2:34 ` [net-next-2.6 PATCH 3/6 RFC v3] rtnetlink: Add support to set MAC/VLAN filters Roopa Prabhu
@ 2011-10-29  2:34 ` Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 5/6 RFC v3] macvlan: Add support to for netdev ops to set " Roopa Prabhu
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:34 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

From: Roopa Prabhu <roprabhu@cisco.com>

This patch adds support in rtnetlink for IFLA_RX_VF_FILTERS and
IFLA_RX_FILTER get. It gets the size of the filters using
netdev_ops->get_rx_filter_addr_size and netdev_ops->get_rx_filter_vlan_size
and uses netdev_ops->get_rx_filter_addr and netdev_ops->get_rx_filter_vlan.
In case of IFLA_RX_VF_FILTERS it loops through all vf's to get the filter
data

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 net/core/rtnetlink.c |  159 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 158 insertions(+), 1 deletions(-)


diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a042910..ea861b4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -475,6 +475,62 @@ static size_t rtnl_link_get_af_size(const struct net_device *dev)
 	return size;
 }
 
+static size_t rtnl_vf_rx_filter_size(const struct net_device *dev, int vf)
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+	size_t size;
+
+	/* IFLA_RX_FILTER  or IFLA_VF_RX_FILTER */
+	size = nla_total_size(sizeof(struct nlattr));
+
+	if (vf != SELF_VF)
+		size = nla_total_size(4); /* IFLA_RX_FILTER_VF */
+
+	if (ops->ndo_get_rx_filter_addr_size) {
+		size_t rx_filter_addr_size =
+				ops->ndo_get_rx_filter_addr_size(dev, vf);
+
+		if (rx_filter_addr_size)
+			/* IFLA_RX_FILTER_ADDR */
+			size += nla_total_size(sizeof(struct nlattr)) +
+					rx_filter_addr_size;
+	}
+
+	if (ops->ndo_get_rx_filter_vlan_size) {
+		size_t rx_filter_vlan_size =
+				ops->ndo_get_rx_filter_vlan_size(dev, vf);
+
+		if (rx_filter_vlan_size)
+			/* IFLA_RX_FILTER_VLAN */
+			size += nla_total_size(sizeof(struct nlattr)) +
+					rx_filter_vlan_size;
+	}
+
+	return size;
+}
+
+static size_t rtnl_rx_filter_size(const struct net_device *dev)
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+	int vf = SELF_VF;
+	size_t size;
+
+	if (!ops->ndo_get_rx_filter_addr_size &&
+	    !ops->ndo_get_rx_filter_vlan_size)
+		return 0;
+
+	size = rtnl_vf_rx_filter_size(dev, vf); /* SELF_VF */
+
+	if (dev->dev.parent && dev_num_vf(dev->dev.parent)) {
+		/* IFLA_VF_RX_FILTERS */
+		size = nla_total_size(sizeof(struct nlattr));
+		for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++)
+			size += rtnl_vf_rx_filter_size(dev, vf);
+	}
+
+	return size;
+}
+
 static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
 {
 	const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
@@ -513,6 +569,102 @@ out:
 	return err;
 }
 
+static int rtnl_vf_rx_filter_fill(struct sk_buff *skb,
+				  const struct net_device *dev, int vf)
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+	struct nlattr *addr_filter = NULL, *vlan_filter = NULL;
+	struct nlattr *rx_filter;
+	int err = -EMSGSIZE;
+	int filter_attrtype =
+		(vf == SELF_VF ? IFLA_RX_FILTER : IFLA_VF_RX_FILTER);
+
+	rx_filter = nla_nest_start(skb, filter_attrtype);
+	if (rx_filter == NULL)
+		goto nla_put_failure;
+
+	if (vf != SELF_VF)
+		NLA_PUT_U32(skb, IFLA_RX_FILTER_VF, vf);
+
+	if (ops->ndo_get_rx_filter_addr) {
+		addr_filter = nla_nest_start(skb, IFLA_RX_FILTER_ADDR);
+		if (addr_filter == NULL)
+			goto err_cancel_rx_filter;
+		err = ops->ndo_get_rx_filter_addr(dev, vf, skb);
+		if (err == -ENODATA)
+			nla_nest_cancel(skb, addr_filter);
+		else if (err < 0)
+			goto err_cancel_addr_filter;
+		else
+			nla_nest_end(skb, addr_filter);
+	}
+
+	if (ops->ndo_get_rx_filter_vlan) {
+		vlan_filter = nla_nest_start(skb, IFLA_RX_FILTER_VLAN);
+		if (vlan_filter == NULL)
+			goto err_cancel_addr_filter;
+		err = ops->ndo_get_rx_filter_vlan(dev, vf, skb);
+		if (err == -ENODATA)
+			nla_nest_cancel(skb, vlan_filter);
+		else if (err)
+			goto err_cancel_vlan_filter;
+		else
+			nla_nest_end(skb, vlan_filter);
+	}
+	nla_nest_end(skb, rx_filter);
+
+	return 0;
+
+err_cancel_vlan_filter:
+	if (vlan_filter)
+		nla_nest_cancel(skb, vlan_filter);
+err_cancel_addr_filter:
+	if (addr_filter)
+		nla_nest_cancel(skb, addr_filter);
+err_cancel_rx_filter:
+	nla_nest_cancel(skb, rx_filter);
+nla_put_failure:
+	return err;
+}
+
+static int rtnl_rx_filter_fill(struct sk_buff *skb,
+			       const struct net_device *dev)
+{
+	struct nlattr *vf_rx_filters = NULL;
+	int vf = SELF_VF;
+	int err;
+
+	if (!dev->netdev_ops->ndo_get_rx_filter_addr &&
+	    !dev->netdev_ops->ndo_get_rx_filter_vlan)
+		return 0;
+
+	err = rtnl_vf_rx_filter_fill(skb, dev, vf); /* SELF_VF */
+	if (err)
+		return err;
+
+	if (dev->dev.parent && dev_num_vf(dev->dev.parent)) {
+		vf_rx_filters = nla_nest_start(skb, IFLA_VF_RX_FILTERS);
+		if (!vf_rx_filters)
+			return -EMSGSIZE;
+
+		for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) {
+			err = rtnl_vf_rx_filter_fill(skb, dev, vf);
+			if (err == -EMSGSIZE)
+				goto err_cancel_nest_vf_rx_filters;
+		}
+
+		nla_nest_end(skb, vf_rx_filters);
+	}
+
+	return 0;
+
+err_cancel_nest_vf_rx_filters:
+	if (vf_rx_filters)
+		nla_nest_cancel(skb, vf_rx_filters);
+
+	return err;
+}
+
 static const int rtm_min[RTM_NR_FAMILIES] =
 {
 	[RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -786,7 +938,9 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev)
 	       + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */
 	       + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
 	       + rtnl_link_get_size(dev) /* IFLA_LINKINFO */
-	       + rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */
+	       + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
+		/* IFLA_VF_RX_FILTERS + IFLA_RX_FILTER */
+	       + rtnl_rx_filter_size(dev);
 }
 
 static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
@@ -996,6 +1150,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
 	if (rtnl_port_fill(skb, dev))
 		goto nla_put_failure;
 
+	if (rtnl_rx_filter_fill(skb, dev) < 0)
+		goto nla_put_failure;
+
 	if (dev->rtnl_link_ops) {
 		if (rtnl_link_fill(skb, dev) < 0)
 			goto nla_put_failure;

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [net-next-2.6 PATCH 5/6 RFC v3] macvlan: Add support to for netdev ops to set MAC/VLAN filters
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
                   ` (3 preceding siblings ...)
  2011-10-29  2:34 ` [net-next-2.6 PATCH 4/6 RFC v3] rtnetlink: Add support to get " Roopa Prabhu
@ 2011-10-29  2:34 ` Roopa Prabhu
  2011-10-29  2:34 ` [net-next-2.6 PATCH 6/6 RFC v3] macvlan: Add support to get MAC/VLAN filter netdev ops Roopa Prabhu
  2011-10-31 16:38 ` [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Rose, Gregory V
  6 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:34 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

From: Roopa Prabhu <roprabhu@cisco.com>

This patch adds support for MAC and VLAN filter netdev ops
on a macvlan interface. It adds support for set_rx_filter_addr and
set_rx_filter_vlan netdev operations. It currently supports only macvlan
PASSTHRU mode. And removes the code that puts the lowerdev in promiscous mode.

For passthru mode,
	For both Address and vlan filters set, lowerdev
	netdev_ops->set_rx_filter_addr and netdev_ops->set_rx_filter_vlan
	are called if the lowerdev supports these ops.

	Else parse the filter data and update the lowerdev filters:
	 - Address filters: macvlan netdev uc and mc lists and flags are
	updated to reflect the addresses and address filter flags that came
	in the filter. Which inturn results in calls to macvlan_set_rx_mode and
	macvlan_change_rx_flags. These functions pass the filter addresses
	and flags to lowerdev netdev. And the lowerdev driver will pass it
	to the hw.

	- VLAN filter: Currently applied vlan bitmap is cached in
	struct macvlan_dev->vlan_filter. This vlan bitmap is updated to
	reflect the new bitmap that came in the netlink vlan filter msg.
	macvlan_vlan_rx_add_vid and macvlan_vlan_rx_kill_vid are called
	to update the vlan ids on the macvlan netdev, which in turn results in
	passing the vlan ids to the lowerdev using netdev_ops
	ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid


Note: If in future if most lowerdev drivers find use for these ops and start
supporting them, we could remove the local handling of filters for passthru
mode in macvlan

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 drivers/net/macvlan.c      |  331 ++++++++++++++++++++++++++++++++++++++++----
 include/linux/if_macvlan.h |    2 
 2 files changed, 300 insertions(+), 33 deletions(-)


diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index a3ce3d4..9d8cbe3 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -302,30 +302,37 @@ static int macvlan_open(struct net_device *dev)
 	struct net_device *lowerdev = vlan->lowerdev;
 	int err;
 
-	if (vlan->port->passthru) {
-		dev_set_promiscuity(lowerdev, 1);
-		goto hash_add;
-	}
+	if (!vlan->port->passthru) {
+		err = -EBUSY;
+		if (macvlan_addr_busy(vlan->port, dev->dev_addr))
+			goto out;
 
-	err = -EBUSY;
-	if (macvlan_addr_busy(vlan->port, dev->dev_addr))
-		goto out;
+		err = dev_uc_add(lowerdev, dev->dev_addr);
+		if (err < 0)
+			goto out;
+	}
 
-	err = dev_uc_add(lowerdev, dev->dev_addr);
-	if (err < 0)
-		goto out;
 	if (dev->flags & IFF_ALLMULTI) {
 		err = dev_set_allmulti(lowerdev, 1);
 		if (err < 0)
 			goto del_unicast;
 	}
 
-hash_add:
+	if (dev->flags & IFF_PROMISC) {
+		err = dev_set_promiscuity(lowerdev, 1);
+		if (err < 0)
+			goto unset_allmulti;
+	}
+
 	macvlan_hash_add(vlan);
 	return 0;
 
+unset_allmulti:
+	dev_set_allmulti(lowerdev, -1);
+
 del_unicast:
-	dev_uc_del(lowerdev, dev->dev_addr);
+	if (!vlan->port->passthru)
+		dev_uc_del(lowerdev, dev->dev_addr);
 out:
 	return err;
 }
@@ -335,18 +342,16 @@ static int macvlan_stop(struct net_device *dev)
 	struct macvlan_dev *vlan = netdev_priv(dev);
 	struct net_device *lowerdev = vlan->lowerdev;
 
-	if (vlan->port->passthru) {
-		dev_set_promiscuity(lowerdev, -1);
-		goto hash_del;
-	}
-
+	dev_uc_unsync(lowerdev, dev);
 	dev_mc_unsync(lowerdev, dev);
 	if (dev->flags & IFF_ALLMULTI)
 		dev_set_allmulti(lowerdev, -1);
+	if (dev->flags & IFF_PROMISC)
+		dev_set_promiscuity(lowerdev, -1);
 
-	dev_uc_del(lowerdev, dev->dev_addr);
+	if (!vlan->port->passthru)
+		dev_uc_del(lowerdev, dev->dev_addr);
 
-hash_del:
 	macvlan_hash_del(vlan, !dev->dismantle);
 	return 0;
 }
@@ -387,12 +392,16 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
 
 	if (change & IFF_ALLMULTI)
 		dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+	if (change & IFF_PROMISC)
+		dev_set_promiscuity(lowerdev,
+			dev->flags & IFF_PROMISC ? 1 : -1);
 }
 
-static void macvlan_set_multicast_list(struct net_device *dev)
+static void macvlan_set_rx_mode(struct net_device *dev)
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
 
+	dev_uc_sync(vlan->lowerdev, dev);
 	dev_mc_sync(vlan->lowerdev, dev);
 }
 
@@ -535,6 +544,257 @@ static void macvlan_vlan_rx_kill_vid(struct net_device *dev,
 		ops->ndo_vlan_rx_kill_vid(lowerdev, vid);
 }
 
+static inline void macvlan_set_filter_vlan(struct net_device *dev, int vid)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	set_bit(vid, vlan->vlan_filter);
+	macvlan_vlan_rx_add_vid(dev, vid);
+}
+
+static inline void macvlan_clear_filter_vlan(struct net_device *dev, int vid)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	clear_bit(vid, vlan->vlan_filter);
+	macvlan_vlan_rx_kill_vid(dev, vid);
+}
+
+static int macvlan_set_rx_filter_vlan_passthru(struct net_device *dev, int vf,
+					       struct nlattr *tb[])
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+	const struct net_device_ops *ops = lowerdev->netdev_ops;
+	unsigned long *vlans;
+	u16 vid;
+
+	if (ops->ndo_set_rx_filter_vlan)
+		return ops->ndo_set_rx_filter_vlan(dev, vf, tb);
+
+	if (!tb[IFLA_RX_FILTER_VLAN_BITMAP])
+		return -EINVAL;
+
+	vlans = nla_data(tb[IFLA_RX_FILTER_VLAN_BITMAP]);
+
+	/*
+	 *	Clear vlans that are not present in the new filter
+	 */
+	for_each_set_bit(vid, vlan->vlan_filter, VLAN_N_VID) {
+		if (!test_bit(vid, vlans))
+			macvlan_clear_filter_vlan(dev, vid);
+	}
+
+	/*
+	 *	Set new vlans that came in the filter
+	 */
+	for_each_set_bit(vid, vlans, VLAN_N_VID) {
+		if (!test_bit(vid, vlan->vlan_filter))
+			macvlan_set_filter_vlan(dev, vid);
+	}
+
+	return 0;
+}
+
+static int macvlan_set_rx_filter_vlan(struct net_device *dev, int vf,
+				      struct nlattr *tb[])
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	int err;
+
+	if (vf != SELF_VF)
+		return -EINVAL;
+
+	switch (vlan->mode) {
+	case MACVLAN_MODE_PASSTHRU:
+		return macvlan_set_rx_filter_vlan_passthru(dev, vf, tb);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int macvlan_addr_in_hw_list(struct netdev_hw_addr_list *list,
+				   u8 *addr, int addrlen)
+{
+	struct netdev_hw_addr *ha;
+
+	netdev_hw_addr_list_for_each(ha, list) {
+		if (!memcmp(ha->addr, addr, addrlen))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int macvlan_addr_in_attrs(struct nlattr *addr_list, u8 *addr,
+				 int addrlen)
+{
+	struct nlattr *addr_attr;
+	int addr_rem;
+
+	nla_for_each_nested(addr_attr, addr_list, addr_rem) {
+		if (!memcmp(nla_data(addr_attr), addr, addrlen))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int macvlan_update_hw_addr_list(struct net_device *dev,
+				struct netdev_hw_addr_list *curr_addr_list,
+				int addr_list_type,
+				struct nlattr *new_addr_attrs)
+{
+	struct nlattr *addr_attr;
+	int addr_rem;
+	u8 *addr;
+	int alen, i;
+	int err = 0;
+
+	if (!netdev_hw_addr_list_empty(curr_addr_list)) {
+		struct netdev_hw_addr *ha;
+		u8 *del_addrlist;
+		int del_addr_count = 0;
+
+		alen = ETH_ALEN * netdev_hw_addr_list_count(curr_addr_list);
+		del_addrlist = kmalloc(alen, GFP_KERNEL);
+		if (!del_addrlist) {
+			err = -ENOMEM;
+			goto err_out;
+		}
+
+		/*
+		 *	Get the addresses that need to be deleted
+		 */
+		netdev_hw_addr_list_for_each(ha, curr_addr_list) {
+			if (!macvlan_addr_in_attrs(new_addr_attrs, ha->addr,
+				ETH_ALEN))
+				memcpy(del_addrlist + (del_addr_count++ *
+					ETH_ALEN), ha->addr, ETH_ALEN);
+		}
+
+		/*
+		 * Delete addresses
+		 */
+		for (i = 0, addr = del_addrlist; i < del_addr_count && addr;
+			i++, addr += ETH_ALEN) {
+			if (addr_list_type == NETDEV_HW_ADDR_T_UNICAST)
+				dev_uc_del(dev, addr);
+			else if (addr_list_type == NETDEV_HW_ADDR_T_MULTICAST)
+				dev_mc_del(dev, addr);
+		}
+		kfree(del_addrlist);
+	}
+
+	/* Add new addresses */
+	nla_for_each_nested(addr_attr, new_addr_attrs, addr_rem) {
+		if (!macvlan_addr_in_hw_list(curr_addr_list,
+			nla_data(addr_attr), ETH_ALEN)) {
+			if (addr_list_type == NETDEV_HW_ADDR_T_UNICAST)
+				dev_uc_add(dev, nla_data(addr_attr));
+			else if (addr_list_type == NETDEV_HW_ADDR_T_MULTICAST)
+				dev_mc_add(dev, nla_data(addr_attr));
+		}
+	}
+
+	return 0;
+
+err_out:
+	return err;
+}
+
+static int macvlan_set_rx_filter_addr_passthru(struct net_device *dev,
+					       int vf, struct nlattr *tb[])
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+	const struct net_device_ops *ops = lowerdev->netdev_ops;
+	unsigned int flags, flags_changed;
+	int err;
+
+	if (ops->ndo_set_rx_filter_addr)
+		return ops->ndo_set_rx_filter_addr(vlan->lowerdev, vf, tb);
+
+	if (tb[IFLA_RX_FILTER_ADDR_FLAGS]) {
+		flags = nla_get_u32(tb[IFLA_RX_FILTER_ADDR_FLAGS]);
+
+		flags_changed = (dev->flags ^ flags) & RX_FILTER_FLAGS;
+		if (flags_changed)
+			dev_change_flags(dev, dev->flags ^ flags_changed);
+	}
+
+	if (tb[IFLA_RX_FILTER_ADDR_UC_LIST]) {
+		err = macvlan_update_hw_addr_list(dev, &dev->uc,
+				NETDEV_HW_ADDR_T_UNICAST,
+				tb[IFLA_RX_FILTER_ADDR_UC_LIST]);
+		if (err)
+			return err;
+	}
+
+	if (tb[IFLA_RX_FILTER_ADDR_MC_LIST]) {
+		err = macvlan_update_hw_addr_list(dev, &dev->mc,
+				NETDEV_HW_ADDR_T_MULTICAST,
+				tb[IFLA_RX_FILTER_ADDR_MC_LIST]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int macvlan_validate_rx_filter_addr(struct net_device *dev, int vf,
+					   struct nlattr *tb[])
+{
+	struct nlattr *addr_attr;
+	int addr_rem;
+
+	if (vf != SELF_VF)
+		return -EINVAL;
+
+	if (tb[IFLA_RX_FILTER_ADDR_UC_LIST]) {
+		nla_for_each_nested(addr_attr, tb[IFLA_RX_FILTER_ADDR_UC_LIST],
+				    addr_rem) {
+			if ((nla_type(addr_attr) != IFLA_ADDR_LIST_ENTRY) ||
+				!is_unicast_ether_addr(nla_data(addr_attr)))
+				return -EINVAL;
+		}
+	}
+
+	if (tb[IFLA_RX_FILTER_ADDR_MC_LIST]) {
+		nla_for_each_nested(addr_attr, tb[IFLA_RX_FILTER_ADDR_MC_LIST],
+				    addr_rem) {
+			if ((nla_type(addr_attr) != IFLA_ADDR_LIST_ENTRY) ||
+				!is_multicast_ether_addr(nla_data(addr_attr)))
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int macvlan_set_rx_filter_addr(struct net_device *dev, int vf,
+				      struct nlattr *tb[])
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	int err;
+
+	err = macvlan_validate_rx_filter_addr(dev, vf, tb);
+	if (err)
+		return err;
+
+	switch (vlan->mode) {
+	case MACVLAN_MODE_PASSTHRU:
+		return macvlan_set_rx_filter_addr_passthru(dev, vf, tb);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
 					struct ethtool_drvinfo *drvinfo)
 {
@@ -557,19 +817,21 @@ static const struct ethtool_ops macvlan_ethtool_ops = {
 };
 
 static const struct net_device_ops macvlan_netdev_ops = {
-	.ndo_init		= macvlan_init,
-	.ndo_uninit		= macvlan_uninit,
-	.ndo_open		= macvlan_open,
-	.ndo_stop		= macvlan_stop,
-	.ndo_start_xmit		= macvlan_start_xmit,
-	.ndo_change_mtu		= macvlan_change_mtu,
-	.ndo_change_rx_flags	= macvlan_change_rx_flags,
-	.ndo_set_mac_address	= macvlan_set_mac_address,
-	.ndo_set_rx_mode	= macvlan_set_multicast_list,
-	.ndo_get_stats64	= macvlan_dev_get_stats64,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_vlan_rx_add_vid	= macvlan_vlan_rx_add_vid,
-	.ndo_vlan_rx_kill_vid	= macvlan_vlan_rx_kill_vid,
+	.ndo_init			= macvlan_init,
+	.ndo_uninit			= macvlan_uninit,
+	.ndo_open			= macvlan_open,
+	.ndo_stop			= macvlan_stop,
+	.ndo_start_xmit			= macvlan_start_xmit,
+	.ndo_change_mtu			= macvlan_change_mtu,
+	.ndo_change_rx_flags		= macvlan_change_rx_flags,
+	.ndo_set_mac_address		= macvlan_set_mac_address,
+	.ndo_set_rx_mode		= macvlan_set_rx_mode,
+	.ndo_get_stats64		= macvlan_dev_get_stats64,
+	.ndo_validate_addr		= eth_validate_addr,
+	.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_set_rx_filter_vlan		= macvlan_set_rx_filter_vlan,
 };
 
 void macvlan_common_setup(struct net_device *dev)
@@ -577,6 +839,7 @@ void macvlan_common_setup(struct net_device *dev)
 	ether_setup(dev);
 
 	dev->priv_flags	       &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
+	dev->priv_flags	       |= IFF_UNICAST_FLT;
 	dev->netdev_ops		= &macvlan_netdev_ops;
 	dev->destructor		= free_netdev;
 	dev->header_ops		= &macvlan_hard_header_ops,
@@ -704,6 +967,8 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 	if (data && data[IFLA_MACVLAN_MODE])
 		vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
 
+	memset(vlan->vlan_filter, 0, VLAN_BITMAP_SIZE);
+
 	if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
 		if (port->count)
 			return -EINVAL;
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index d103dca..c0d84a5 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -7,6 +7,7 @@
 #include <linux/netlink.h>
 #include <net/netlink.h>
 #include <linux/u64_stats_sync.h>
+#include <linux/if_vlan.h>
 
 #if defined(CONFIG_MACVTAP) || defined(CONFIG_MACVTAP_MODULE)
 struct socket *macvtap_get_socket(struct file *);
@@ -65,6 +66,7 @@ struct macvlan_dev {
 	struct macvtap_queue	*taps[MAX_MACVTAP_QUEUES];
 	int			numvtaps;
 	int			minor;
+	unsigned long		vlan_filter[BITS_TO_LONGS(VLAN_N_VID)];
 };
 
 static inline void macvlan_count_rx(const struct macvlan_dev *vlan,


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [net-next-2.6 PATCH 6/6 RFC v3] macvlan: Add support to get MAC/VLAN filter netdev ops
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
                   ` (4 preceding siblings ...)
  2011-10-29  2:34 ` [net-next-2.6 PATCH 5/6 RFC v3] macvlan: Add support to for netdev ops to set " Roopa Prabhu
@ 2011-10-29  2:34 ` Roopa Prabhu
  2011-10-31 16:38 ` [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Rose, Gregory V
  6 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-29  2:34 UTC (permalink / raw)
  To: netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, gregory.v.rose,
	mchan, dwang2, shemminger, eric.dumazet, kaber, benve

From: Roopa Prabhu <roprabhu@cisco.com>

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 <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 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)

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* RE: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode
  2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
                   ` (5 preceding siblings ...)
  2011-10-29  2:34 ` [net-next-2.6 PATCH 6/6 RFC v3] macvlan: Add support to get MAC/VLAN filter netdev ops Roopa Prabhu
@ 2011-10-31 16:38 ` Rose, Gregory V
  2011-10-31 17:09   ` Roopa Prabhu
  6 siblings, 1 reply; 11+ messages in thread
From: Rose, Gregory V @ 2011-10-31 16:38 UTC (permalink / raw)
  To: Roopa Prabhu, netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, mchan, dwang2,
	shemminger, eric.dumazet, kaber, benve

> -----Original Message-----
> From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
> On Behalf Of Roopa Prabhu
> Sent: Friday, October 28, 2011 7:34 PM
> To: netdev@vger.kernel.org
> Cc: sri@us.ibm.com; dragos.tatulea@gmail.com; kvm@vger.kernel.org;
> arnd@arndb.de; mst@redhat.com; davem@davemloft.net; Rose, Gregory V;
> mchan@broadcom.com; dwang2@cisco.com; shemminger@vyatta.com;
> eric.dumazet@gmail.com; kaber@trash.net; benve@cisco.com
> Subject: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering
> support for passthru mode
> 
> v2 -> v3
> - Moved set and get filter ops from rtnl_link_ops to netdev_ops
> - Support for SRIOV VFs.
> 	[Note: The get filters msg might get too big for SRIOV vfs.
>         But this patch follows existing sriov vf get code and
> 	accomodate filters for all VF's in a PF.
>         And for the SRIOV case I have only tested the fact that the VF
> 	arguments are getting delivered to rtnetlink correctly. The rest of
> 	the code follows existing sriov vf handling code so it should work
> 	just fine]
> - Fixed all op and netlink attribute names to start with IFLA_RX_FILTER
> - Changed macvlan filter ops to call corresponding lowerdev op if lowerdev
>   supports it for passthru mode. Else it falls back on macvlan handling
> the
>   filters locally as in v1 and v2
> 
> v1 -> v2
> - Instead of TUNSETTXFILTER introduced rtnetlink interface for the same
> 

[snip...]

> 
> This patch series implements the following
> 01/6 rtnetlink: Netlink interface for setting MAC and VLAN filters
> 02/6 netdev: Add netdev_ops to set and get MAC/VLAN rx filters
> 03/6 rtnetlink: Add support to set MAC/VLAN filters
> 04/6 rtnetlink: Add support to get MAC/VLAN filters
> 05/6 macvlan: Add support to set MAC/VLAN filter netdev ops
> 06/6 macvlan: Add support to get MAC/VLAN filter netdev ops
> 
> Please comment. Thanks.

After some preliminary review this looks pretty good to me in so far as adding the necessary hooks to do what I need to do.  I appreciate your effort on this.

I'm sort of a hands-on type of person so I need to apply this patch to a private git tree and then take it for a test drive (so to speak).  If I have further comments I'll get back to you.

Did you have any plans for modifying any user space tools such as 'ip' to use this interface?

- Greg

> 
> Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
> Signed-off-by: Christian Benvenuti <benve@cisco.com>
> Signed-off-by: David Wang <dwang2@cisco.com>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode
  2011-10-31 16:38 ` [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Rose, Gregory V
@ 2011-10-31 17:09   ` Roopa Prabhu
  2011-10-31 17:39     ` Rose, Gregory V
  0 siblings, 1 reply; 11+ messages in thread
From: Roopa Prabhu @ 2011-10-31 17:09 UTC (permalink / raw)
  To: Rose, Gregory V, netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, mchan, dwang2,
	shemminger, eric.dumazet, kaber, benve




On 10/31/11 9:38 AM, "Rose, Gregory V" <gregory.v.rose@intel.com> wrote:

>> -----Original Message-----
>> From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
>> On Behalf Of Roopa Prabhu
>> Sent: Friday, October 28, 2011 7:34 PM
>> To: netdev@vger.kernel.org
>> Cc: sri@us.ibm.com; dragos.tatulea@gmail.com; kvm@vger.kernel.org;
>> arnd@arndb.de; mst@redhat.com; davem@davemloft.net; Rose, Gregory V;
>> mchan@broadcom.com; dwang2@cisco.com; shemminger@vyatta.com;
>> eric.dumazet@gmail.com; kaber@trash.net; benve@cisco.com
>> Subject: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering
>> support for passthru mode
>> 
>> v2 -> v3
>> - Moved set and get filter ops from rtnl_link_ops to netdev_ops
>> - Support for SRIOV VFs.
>> [Note: The get filters msg might get too big for SRIOV vfs.
>>         But this patch follows existing sriov vf get code and
>> accomodate filters for all VF's in a PF.
>>         And for the SRIOV case I have only tested the fact that the VF
>> arguments are getting delivered to rtnetlink correctly. The rest of
>> the code follows existing sriov vf handling code so it should work
>> just fine]
>> - Fixed all op and netlink attribute names to start with IFLA_RX_FILTER
>> - Changed macvlan filter ops to call corresponding lowerdev op if lowerdev
>>   supports it for passthru mode. Else it falls back on macvlan handling
>> the
>>   filters locally as in v1 and v2
>> 
>> v1 -> v2
>> - Instead of TUNSETTXFILTER introduced rtnetlink interface for the same
>> 
> 
> [snip...]
> 
>> 
>> This patch series implements the following
>> 01/6 rtnetlink: Netlink interface for setting MAC and VLAN filters
>> 02/6 netdev: Add netdev_ops to set and get MAC/VLAN rx filters
>> 03/6 rtnetlink: Add support to set MAC/VLAN filters
>> 04/6 rtnetlink: Add support to get MAC/VLAN filters
>> 05/6 macvlan: Add support to set MAC/VLAN filter netdev ops
>> 06/6 macvlan: Add support to get MAC/VLAN filter netdev ops
>> 
>> Please comment. Thanks.
> 
> After some preliminary review this looks pretty good to me in so far as adding
> the necessary hooks to do what I need to do.  I appreciate your effort on
> this.
> 
> I'm sort of a hands-on type of person so I need to apply this patch to a
> private git tree and then take it for a test drive (so to speak).  If I have
> further comments I'll get back to you.
> 
Sounds good. 

> Did you have any plans for modifying any user space tools such as 'ip' to use
> this interface?
> 

Yes, I have an iproute2 sample patch for setting and displaying the filters
which I have been using to test this interface. I can send the patch to you
after some cleanup if you think it will be useful for you to try out this
interface.

Thanks Greg.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode
  2011-10-31 17:09   ` Roopa Prabhu
@ 2011-10-31 17:39     ` Rose, Gregory V
  2011-11-01 12:17       ` Roopa Prabhu
  0 siblings, 1 reply; 11+ messages in thread
From: Rose, Gregory V @ 2011-10-31 17:39 UTC (permalink / raw)
  To: Roopa Prabhu, netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, mchan, dwang2,
	shemminger, eric.dumazet, kaber, benve

> -----Original Message-----
> From: Roopa Prabhu [mailto:roprabhu@cisco.com]
> Sent: Monday, October 31, 2011 10:09 AM
> To: Rose, Gregory V; netdev@vger.kernel.org
> Cc: sri@us.ibm.com; dragos.tatulea@gmail.com; kvm@vger.kernel.org;
> arnd@arndb.de; mst@redhat.com; davem@davemloft.net; mchan@broadcom.com;
> dwang2@cisco.com; shemminger@vyatta.com; eric.dumazet@gmail.com;
> kaber@trash.net; benve@cisco.com
> Subject: Re: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address
> filtering support for passthru mode
> 
> 
> 
> 
> On 10/31/11 9:38 AM, "Rose, Gregory V" <gregory.v.rose@intel.com> wrote:
> 
> >> -----Original Message-----
> >> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org]
> >> On Behalf Of Roopa Prabhu
> >> Sent: Friday, October 28, 2011 7:34 PM
> >> To: netdev@vger.kernel.org
> >> Cc: sri@us.ibm.com; dragos.tatulea@gmail.com; kvm@vger.kernel.org;
> >> arnd@arndb.de; mst@redhat.com; davem@davemloft.net; Rose, Gregory V;
> >> mchan@broadcom.com; dwang2@cisco.com; shemminger@vyatta.com;
> >> eric.dumazet@gmail.com; kaber@trash.net; benve@cisco.com
> >> Subject: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering
> >> support for passthru mode
> >>
> >> v2 -> v3
> >> - Moved set and get filter ops from rtnl_link_ops to netdev_ops
> >> - Support for SRIOV VFs.
> >> [Note: The get filters msg might get too big for SRIOV vfs.
> >>         But this patch follows existing sriov vf get code and
> >> accomodate filters for all VF's in a PF.
> >>         And for the SRIOV case I have only tested the fact that the VF
> >> arguments are getting delivered to rtnetlink correctly. The rest of
> >> the code follows existing sriov vf handling code so it should work
> >> just fine]
> >> - Fixed all op and netlink attribute names to start with IFLA_RX_FILTER
> >> - Changed macvlan filter ops to call corresponding lowerdev op if
> lowerdev
> >>   supports it for passthru mode. Else it falls back on macvlan handling
> >> the
> >>   filters locally as in v1 and v2
> >>
> >> v1 -> v2
> >> - Instead of TUNSETTXFILTER introduced rtnetlink interface for the same
> >>
> >
> > [snip...]
> >
> >>
> >> This patch series implements the following
> >> 01/6 rtnetlink: Netlink interface for setting MAC and VLAN filters
> >> 02/6 netdev: Add netdev_ops to set and get MAC/VLAN rx filters
> >> 03/6 rtnetlink: Add support to set MAC/VLAN filters
> >> 04/6 rtnetlink: Add support to get MAC/VLAN filters
> >> 05/6 macvlan: Add support to set MAC/VLAN filter netdev ops
> >> 06/6 macvlan: Add support to get MAC/VLAN filter netdev ops
> >>
> >> Please comment. Thanks.
> >
> > After some preliminary review this looks pretty good to me in so far as
> adding
> > the necessary hooks to do what I need to do.  I appreciate your effort
> on
> > this.
> >
> > I'm sort of a hands-on type of person so I need to apply this patch to a
> > private git tree and then take it for a test drive (so to speak).  If I have
> > further comments I'll get back to you.
> >
> Sounds good.
> 
> > Did you have any plans for modifying any user space tools such as 'ip' to use
> > this interface?
> >
> 
> Yes, I have an iproute2 sample patch for setting and displaying the filters
> which I have been using to test this interface. I can send the patch to you
> after some cleanup if you think it will be useful for you to try out this
> interface.
> 
> Thanks Greg.

Yes, please do.

Thanks,

- Greg


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode
  2011-10-31 17:39     ` Rose, Gregory V
@ 2011-11-01 12:17       ` Roopa Prabhu
  0 siblings, 0 replies; 11+ messages in thread
From: Roopa Prabhu @ 2011-11-01 12:17 UTC (permalink / raw)
  To: Rose, Gregory V, netdev
  Cc: sri, dragos.tatulea, kvm, arnd, mst, davem, mchan, dwang2,
	shemminger, eric.dumazet, kaber, benve




On 10/31/11 10:39 AM, "Rose, Gregory V" <gregory.v.rose@intel.com> wrote:

>> -----Original Message-----
>> From: Roopa Prabhu [mailto:roprabhu@cisco.com]
>> Sent: Monday, October 31, 2011 10:09 AM
>> To: Rose, Gregory V; netdev@vger.kernel.org
>> Cc: sri@us.ibm.com; dragos.tatulea@gmail.com; kvm@vger.kernel.org;
>> arnd@arndb.de; mst@redhat.com; davem@davemloft.net; mchan@broadcom.com;
>> dwang2@cisco.com; shemminger@vyatta.com; eric.dumazet@gmail.com;
>> kaber@trash.net; benve@cisco.com
>> Subject: Re: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address
>> filtering support for passthru mode
>> 
>> 
>> 
>> 
>> On 10/31/11 9:38 AM, "Rose, Gregory V" <gregory.v.rose@intel.com> wrote:
>> 
>>>> -----Original Message-----
>>>> From: netdev-owner@vger.kernel.org [mailto:netdev-
>> owner@vger.kernel.org]
>>>> On Behalf Of Roopa Prabhu
>>>> Sent: Friday, October 28, 2011 7:34 PM
>>>> To: netdev@vger.kernel.org
>>>> Cc: sri@us.ibm.com; dragos.tatulea@gmail.com; kvm@vger.kernel.org;
>>>> arnd@arndb.de; mst@redhat.com; davem@davemloft.net; Rose, Gregory V;
>>>> mchan@broadcom.com; dwang2@cisco.com; shemminger@vyatta.com;
>>>> eric.dumazet@gmail.com; kaber@trash.net; benve@cisco.com
>>>> Subject: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering
>>>> support for passthru mode
>>>> 
>>>> v2 -> v3
>>>> - Moved set and get filter ops from rtnl_link_ops to netdev_ops
>>>> - Support for SRIOV VFs.
>>>> [Note: The get filters msg might get too big for SRIOV vfs.
>>>>         But this patch follows existing sriov vf get code and
>>>> accomodate filters for all VF's in a PF.
>>>>         And for the SRIOV case I have only tested the fact that the VF
>>>> arguments are getting delivered to rtnetlink correctly. The rest of
>>>> the code follows existing sriov vf handling code so it should work
>>>> just fine]
>>>> - Fixed all op and netlink attribute names to start with IFLA_RX_FILTER
>>>> - Changed macvlan filter ops to call corresponding lowerdev op if
>> lowerdev
>>>>   supports it for passthru mode. Else it falls back on macvlan handling
>>>> the
>>>>   filters locally as in v1 and v2
>>>> 
>>>> v1 -> v2
>>>> - Instead of TUNSETTXFILTER introduced rtnetlink interface for the same
>>>> 
>>> 
>>> [snip...]
>>> 
>>>> 
>>>> This patch series implements the following
>>>> 01/6 rtnetlink: Netlink interface for setting MAC and VLAN filters
>>>> 02/6 netdev: Add netdev_ops to set and get MAC/VLAN rx filters
>>>> 03/6 rtnetlink: Add support to set MAC/VLAN filters
>>>> 04/6 rtnetlink: Add support to get MAC/VLAN filters
>>>> 05/6 macvlan: Add support to set MAC/VLAN filter netdev ops
>>>> 06/6 macvlan: Add support to get MAC/VLAN filter netdev ops
>>>> 
>>>> Please comment. Thanks.
>>> 
>>> After some preliminary review this looks pretty good to me in so far as
>> adding
>>> the necessary hooks to do what I need to do.  I appreciate your effort
>> on
>>> this.
>>> 
>>> I'm sort of a hands-on type of person so I need to apply this patch to a
>>> private git tree and then take it for a test drive (so to speak).  If I have
>>> further comments I'll get back to you.
>>> 
>> Sounds good.
>> 
>>> Did you have any plans for modifying any user space tools such as 'ip' to
>>> use
>>> this interface?
>>> 
>> 
>> Yes, I have an iproute2 sample patch for setting and displaying the filters
>> which I have been using to test this interface. I can send the patch to you
>> after some cleanup if you think it will be useful for you to try out this
>> interface.
>> 
>> Thanks Greg.
> 
> Yes, please do.
> 
> Thanks,
> 
> - Greg
> 
Greg, here is the patch. I rebased it with tip-of-tree iproute2 git. Thanks.

    iproute2: support for MAC/VLAN filter
    
    This patch is not complete. Its a bit hackish right now.
    I implemented this patch to only test the kernel interface
    without usability in mind.
    
    Limitations:
    - Havent checked corner cases for sriov vfs
    - usage msg needs to be fixed. Its ugly right now
    - vf = -1 for direct assignment of filters on a vf or any network
interface
    - functions could be broken down, var names changed etc
    - show part definately needs to change. It does not
    follow the convention right now
    - it has some redundant code which can be removed and simplified
    
    I will work on this patch some more and resubmit this patch
    after the kernel patch gets accepted.

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 304c44f..ffd03e1 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -137,6 +137,8 @@ enum {
     IFLA_AF_SPEC,
     IFLA_GROUP,        /* Group the device belongs to */
     IFLA_NET_NS_FD,
+    IFLA_VF_RX_FILTERS,
+    IFLA_RX_FILTER,
     __IFLA_MAX
 };
 
@@ -264,6 +266,8 @@ enum macvlan_mode {
 
 /* SR-IOV virtual function management section */
 
+#define SELF_VF        -1
+
 enum {
     IFLA_VF_INFO_UNSPEC,
     IFLA_VF_INFO,
@@ -378,4 +382,63 @@ struct ifla_port_vsi {
     __u8 pad[3];
 };
 
+/* VF rx filters management section
+ *
+ *    Nested layout of set/get msg is:
+ *
+ *    [IFLA_VF_RX_FILTERS]
+ *        [IFLA_VF_RX_FILTER]
+ *            [IFLA_RX_FILTER_*], ...
+ *        [IFLA_VF_RX_FILTER]
+ *            [IFLA_RX_FILTER_*], ...
+ *        ...
+ *    [IFLA_RX_FILTER]
+ *        [IFLA_RX_FILTER_*], ...
+ */
+enum {
+    IFLA_VF_RX_FILTER_UNSPEC,
+    IFLA_VF_RX_FILTER,            /* nest */
+    __IFLA_VF_RX_FILTER_MAX,
+};
+
+#define IFLA_VF_RX_FILTER_MAX (__IFLA_VF_RX_FILTER_MAX - 1)
+
+enum {
+    IFLA_RX_FILTER_UNSPEC,
+    IFLA_RX_FILTER_VF,        /* __u32 */
+    IFLA_RX_FILTER_ADDR,
+    IFLA_RX_FILTER_VLAN,
+    __IFLA_RX_FILTER_MAX,
+};
+#define IFLA_RX_FILTER_MAX (__IFLA_RX_FILTER_MAX - 1)
+
+enum {
+    IFLA_RX_FILTER_ADDR_UNSPEC,
+    IFLA_RX_FILTER_ADDR_FLAGS,
+    IFLA_RX_FILTER_ADDR_UC_LIST,
+    IFLA_RX_FILTER_ADDR_MC_LIST,
+    __IFLA_RX_FILTER_ADDR_MAX,
+};
+#define IFLA_RX_FILTER_ADDR_MAX (__IFLA_RX_FILTER_ADDR_MAX - 1)
+
+#define RX_FILTER_FLAGS (IFF_UP | IFF_BROADCAST | IFF_MULTICAST | \
+                IFF_PROMISC | IFF_ALLMULTI)
+
+enum {
+    IFLA_ADDR_LIST_UNSPEC,
+    IFLA_ADDR_LIST_ENTRY,
+    __IFLA_ADDR_LIST_MAX,
+};
+#define IFLA_ADDR_LIST_MAX (__IFLA_ADDR_LIST_MAX - 1)
+
+enum {
+    IFLA_RX_FILTER_VLAN_UNSPEC,
+    IFLA_RX_FILTER_VLAN_BITMAP,
+    __IFLA_RX_FILTER_VLAN_MAX,
+};
+#define IFLA_RX_FILTER_VLAN_MAX (__IFLA_RX_FILTER_VLAN_MAX - 1)
+
+#define VLAN_BITMAP_SPLIT_MAX 8
+#define VLAN_BITMAP_SIZE    (VLAN_N_VID/VLAN_BITMAP_SPLIT_MAX)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 85f05a2..4154b07 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -192,6 +192,120 @@ static void print_linktype(FILE *fp, struct rtattr
*tb)
     }
 }
 
+static void print_vlan_bitmap(FILE *fp, struct rtattr *vlan_bitmap)
+{
+    unsigned long active_vlans[4096/64];
+    int i = 0, j = 0;
+    int first = 1;
+
+    memcpy(active_vlans, RTA_DATA(vlan_bitmap), sizeof(active_vlans));
+
+    for (i = 0 ; i < 64; i++) {
+        for (j = 0; j  < 64; j++) {
+            if (((active_vlans[i] >> j) & 1UL) == 1 ) {
+                if (!first)
+                    fprintf(fp, ",");
+                else
+                    first = 0;
+                  
+                fprintf(fp, "%d", j + 64 * i);
+            }
+        }
+    }
+}
+
+static void print_rx_filter(FILE *fp, struct rtattr *tb)
+{
+    struct rtattr *rx_filter[IFLA_RX_FILTER_MAX+1];
+    int first;
+
+    parse_rtattr_nested(rx_filter, IFLA_RX_FILTER_MAX, tb);
+
+    fprintf(fp, "rx_filter ");
+    if (rx_filter[IFLA_RX_FILTER_VF])
+        fprintf(fp, "vf:%d ",
+        *(unsigned int *)RTA_DATA(rx_filter[IFLA_RX_FILTER_VF]));
+
+    if (rx_filter[IFLA_RX_FILTER_ADDR]) {
+        struct rtattr *rx_addr_filter[IFLA_RX_FILTER_ADDR_MAX+1];
+        unsigned int flags;
+
+        parse_rtattr_nested(rx_addr_filter, IFLA_RX_FILTER_ADDR_MAX,
+                rx_filter[IFLA_RX_FILTER_ADDR]);
+
+        if (rx_addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]) {
+            flags = *(unsigned int *)RTA_DATA(
+                rx_addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]);
+            fprintf(fp, "flags IFF_UP=%s, "
+                "IFF_BROADCAST=%s, "
+                "IFF_MULTICAST=%s, IFF_PROMISC=%s, "
+                "IFF_ALLMULTI=%s ",
+                ((flags & IFF_UP) ? "on" : "off"),
+                ((flags & IFF_BROADCAST) ? "on" : "off"),
+                ((flags & IFF_MULTICAST) ? "on" : "off"),
+                ((flags & IFF_PROMISC) ? "on" : "off"),
+                ((flags & IFF_ALLMULTI) ? "on" : "off"));
+        }
+
+        if (rx_addr_filter[IFLA_RX_FILTER_ADDR_UC_LIST]) {
+            struct rtattr *i;
+            struct rtattr *uclist =
rx_addr_filter[IFLA_RX_FILTER_ADDR_UC_LIST];
+            int rem = RTA_PAYLOAD(uclist);
+            SPRINT_BUF(b1);
+            first = 1;
+            fprintf(fp, " uc ");
+            for (i = RTA_DATA(uclist); RTA_OK(i, rem);
+                i = RTA_NEXT(i, rem)) {
+                if (!first)
+                    fprintf(fp, ",");
+                else
+                    first = 0;
+                fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(i),
+                    RTA_PAYLOAD(i), 0, b1, sizeof(b1)));
+            }
+        }
+
+        if (rx_addr_filter[IFLA_RX_FILTER_ADDR_MC_LIST]) {
+            struct rtattr *i;
+            struct rtattr *mclist =
rx_addr_filter[IFLA_RX_FILTER_ADDR_MC_LIST];
+            SPRINT_BUF(b1);
+            int rem = RTA_PAYLOAD(mclist);
+
+            first = 1;
+            fprintf(fp, " mc ");
+            for (i = RTA_DATA(mclist); RTA_OK(i, rem);
+                i = RTA_NEXT(i, rem)) {
+                if (!first)
+                    fprintf(fp, ",");
+                else
+                    first = 0;
+                fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(i),
+                    RTA_PAYLOAD(i), 0, b1, sizeof(b1)));
+            }
+        }
+    }    
+
+    if (rx_filter[IFLA_RX_FILTER_VLAN]) {
+        struct rtattr *rx_vlan_filter[IFLA_RX_FILTER_VLAN_MAX+1];
+
+        fprintf(fp, " vlans ");
+        parse_rtattr_nested(rx_vlan_filter, IFLA_RX_FILTER_VLAN_MAX,
+                rx_filter[IFLA_RX_FILTER_VLAN]);
+        print_vlan_bitmap(fp,
+                rx_vlan_filter[IFLA_RX_FILTER_VLAN_BITMAP]);
+    }
+    fprintf(fp, "\n");
+}
+
+static void print_vf_rx_filters(FILE *fp, struct rtattr *tb)
+{
+    struct rtattr *i, *vf_filters = tb;
+    int rem = RTA_PAYLOAD(vf_filters);
+
+    for (i = RTA_DATA(vf_filters); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+        print_rx_filter(fp, i);
+}
+
 static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
 {
     struct ifla_vf_mac *vf_mac;
@@ -319,6 +433,16 @@ int print_linkinfo(const struct sockaddr_nl *who,
     if (do_link && tb[IFLA_LINKINFO] && show_details)
         print_linktype(fp, tb[IFLA_LINKINFO]);
 
+    if (do_link && tb[IFLA_RX_FILTER] ) {
+        fprintf(fp, "\n\t");
+        print_rx_filter(fp, tb[IFLA_RX_FILTER]);
+    }
+
+    if (do_link && tb[IFLA_VF_RX_FILTERS] ) {
+        fprintf(fp, "\n\t");
+        print_vf_rx_filters(fp, tb[IFLA_VF_RX_FILTERS]);
+    }
+
     if (do_link && tb[IFLA_IFALIAS])
         fprintf(fp,"\n    alias %s",
             (const char *) RTA_DATA(tb[IFLA_IFALIAS]));
diff --git a/ip/iplink.c b/ip/iplink.c
index 35e6dc6..42897fb 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -71,7 +71,8 @@ void iplink_usage(void)
     fprintf(stderr, "              [ alias NAME ]\n");
     fprintf(stderr, "                      [ vf NUM [ mac LLADDR ]\n");
     fprintf(stderr, "                   [ vlan VLANID [ qos VLAN-QOS ]
]\n");
-    fprintf(stderr, "                   [ rate TXRATE ] ] \n");
+    fprintf(stderr, "                   [ rate TXRATE ] \n");
+    fprintf(stderr, "                                [ rx_filter [flags
FILTER_FLAGS uc UC_LIST mc MC_LIST] [vlan VLANID_LIST]]\n");
     fprintf(stderr, "              [ master DEVICE ]\n");
     fprintf(stderr, "              [ nomaster ]\n");
     fprintf(stderr, "       ip link show [ DEVICE | group GROUP ]\n");
@@ -79,6 +80,10 @@ void iplink_usage(void)
     if (iplink_have_newlink()) {
         fprintf(stderr, "\n");
         fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb |
macvlan | can | bridge }\n");
+        fprintf(stderr, "FILTER_FLAGS := ifup,\n");
+        fprintf(stderr, "UC_LIST := <coma_separated_list_of_unicast
addrs>\n");
+        fprintf(stderr, "MC_LIST := <coma_separated_list_of_multicast
addrs>\n");
+        fprintf(stderr, "VLANID_LIST :=
<coma_separated_list_of_vlanids>\n");
     }
     exit(-1);
 }
@@ -179,55 +184,259 @@ struct iplink_req {
     char            buf[1024];
 };
 
-int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+int
+parse_comma_separated_list(char *argv, int *num_entries, char ***array)
+{
+    char *str = strdup(argv), *tok = NULL;
+    int n = 0;
+    
+    if (!str)
+        return -1;
+
+    for (tok = strtok(str, ","); tok;
+        tok = strtok(NULL, ","), ++n);
+    free(str);
+
+    *array = (char **)malloc(n * sizeof(char *));
+    
+    str = strdup(argv);
+    n = 0;
+    for (tok = strtok(str, ","); tok; tok = strtok(NULL, ","), ++n)
+        (*array)[n] = strdup(tok);
+
+    *num_entries = n;
+
+    return 0;
+}
+
+int iplink_parse_rx_filter(int vf, int *argcp, char ***argvp,
                struct iplink_req *req)
 {
+    int argc = *argcp;
+    char **argv = *argvp;
+    char **mc_list = NULL, **uc_list = NULL, **flags_list = NULL;
+    char **vlan_list = NULL;
+    int i, len;
+    int mc_list_count = 0, uc_list_count = 0, flags_list_count = 0;
+    int vlan_list_count = 0;
+    __u8 mac[32];
+
+    while (NEXT_ARG_OK()) {
+        NEXT_ARG();
+        if (matches(*argv, "rx_filter") == 0) {
+            /* Skip: Hack */
+        }
+        else if (matches(*argv, "flags") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &flags_list_count, &flags_list);
+            }
+        }
+        else if (matches(*argv, "uc") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &uc_list_count, &uc_list);
+            }
+        } else if (matches(*argv, "mc") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &mc_list_count, &mc_list);
+            }
+        } else if (matches(*argv, "vlan") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &vlan_list_count, &vlan_list);
+            }
+        } else {
+            /* rewind arg */
+            PREV_ARG();
+            break;
+        }
+    }
+
+    if (argc == *argcp)
+        incomplete_command();
+
+    if (flags_list || uc_list || mc_list || vlan_list) {
+        struct rtattr *nest_rx_filter = NULL;
+        struct rtattr *nest_vf_filters = NULL;
+
+        if (vf != SELF_VF)
+            nest_vf_filters = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_VF_RX_FILTERS);
+
+
+        if (vf != SELF_VF) {
+            nest_rx_filter = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_VF_RX_FILTER);
+            addattr_l(&req->n, sizeof(*req), IFLA_RX_FILTER_VF,
+                (uint32_t *)&vf, sizeof(uint32_t));
+        }
+        else {
+            nest_rx_filter = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_RX_FILTER);
+        }
+
+        if (flags_list || uc_list || mc_list) {
+            struct rtattr *nest_addr_filter = NULL;
+
+            nest_addr_filter = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_RX_FILTER_ADDR);
+
+            if (flags_list) {
+                unsigned int flags = 0;
+
+                for (i = 0; i < flags_list_count; i++) {
+                    if (!strcmp(flags_list[i], "promisc"))
+                        flags |= IFF_PROMISC;
+                    else if (!strcmp(flags_list[i],
+                        "allmulti"))
+                        flags |= IFF_ALLMULTI;
+                    else if (!strcmp(flags_list[i],
+                        "multicast"))
+                        flags |= IFF_MULTICAST;
+                    else if (!strcmp(flags_list[i],
+                        "broadcast"))
+                        flags |= IFF_BROADCAST;
+                    else if (!strcmp(flags_list[i], "ifup"))
+                        flags |= IFF_UP;
+                }
+        
+                //printf("DEBUG: %s: flags = %x\n",
+                //    __FUNCTION__, flags);
+
+                addattr32(&req->n, sizeof(*req),
+                    IFLA_RX_FILTER_ADDR_FLAGS, flags);
+            }
+    
+            if (uc_list) {
+                struct rtattr *nest_uc_list = NULL;
+
+                nest_uc_list = addattr_nest(&req->n,
+                        sizeof(*req),
+                        IFLA_RX_FILTER_ADDR_UC_LIST);
+                for (i = 0; i < uc_list_count; i++) {
+                    if (!strcmp(uc_list[i], "null"))
+                        continue;
+                    //printf("DEBUG: uc[%d] = %s\n", i, uc_list[i]);
+                    len = ll_addr_a2n((char *)mac, 32,
+                            uc_list[i]);
+                    if (len < 0)
+                         invarg("Invalid \"mac\" value\n", mac);
+                    addattr_l(&req->n, sizeof(*req),
+                        IFLA_ADDR_LIST_ENTRY, mac, 32);
+                }
+                addattr_nest_end(&req->n, nest_uc_list);
+            }
+
+            if (mc_list) {
+                struct rtattr *nest_mc_list = NULL;
+
+                nest_mc_list = addattr_nest(&req->n,
+                        sizeof(*req),
+                        IFLA_RX_FILTER_ADDR_MC_LIST);
+                for (i = 0; i < mc_list_count; i++) {
+                    if (!strcmp(mc_list[i], "null"))
+                        continue;
+                    //printf("DEBUG: mc[%d] = %s\n", i, mc_list[i]);
+                    len = ll_addr_a2n((char *)mac, 32,
+                            mc_list[i]);
+                    if (len < 0)
+                         invarg("Invalid \"mac\" value\n", mac);
+                    addattr_l(&req->n, sizeof(*req),
+                        IFLA_ADDR_LIST_ENTRY, mac, 32);
+                }
+                addattr_nest_end(&req->n, nest_mc_list);
+            }
+            addattr_nest_end(&req->n, nest_addr_filter);
+        }
+
+        if (vlan_list) {
+            struct rtattr *nest_vlans = NULL;
+            unsigned long arg_vlans[4096/64];
+
+            memset(arg_vlans, 0, 512);
+            for (i = 0; i < vlan_list_count; i++)
+                arg_vlans[atoi(vlan_list[i])/64] |=
+                    1UL << (atoi(vlan_list[i])%64);
+
+            nest_vlans = addattr_nest(&req->n, sizeof(*req),
+                    IFLA_RX_FILTER_VLAN);
+            addattr_l(&req->n, sizeof(*req),
+                IFLA_RX_FILTER_VLAN_BITMAP,
+                arg_vlans, sizeof(arg_vlans));
+            addattr_nest_end(&req->n, nest_vlans);
+        }
+
+        addattr_nest_end(&req->n, nest_rx_filter);
+        if (nest_vf_filters)
+            addattr_nest_end(&req->n, nest_vf_filters);
+
+        if (flags_list) {
+            for (i = 0; i < flags_list_count; i++)
+                free(flags_list[i]);
+            free(flags_list);
+        }
+        if (uc_list) {
+            for (i = 0; i < uc_list_count; i++)
+                free(uc_list[i]);
+            free(uc_list);
+        }
+        if (mc_list) {
+            for (i = 0; i < mc_list_count; i++)
+                free(mc_list[i]);
+            free(mc_list);
+        }
+    }
+
+    *argcp = argc;
+    *argvp = argv;
+
+    return 0;
+}
+
+int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+             struct iplink_req *req)
+{
     int len, argc = *argcp;
     char **argv = *argvp;
+    struct rtattr *vflist;
     struct rtattr *vfinfo;
-
-    vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+    char *mac = NULL;
+    char *vlan = NULL;
+    char *qos = NULL;
+    char *rate = NULL;
+    struct ifla_vf_mac ivm = { .vf = vf, };
+    struct ifla_vf_vlan ivv = { .vf = vf, .qos = 0, };
+    struct ifla_vf_tx_rate ivt = { .vf = vf, };
 
     while (NEXT_ARG_OK()) {
         NEXT_ARG();
-        if (matches(*argv, "mac") == 0) {
-            struct ifla_vf_mac ivm;
+        if (matches(*argv, "rx_filter") == 0) {
+            iplink_parse_rx_filter(vf, &argc, &argv, req);
+        } else if (matches(*argv, "mac") == 0) {
             NEXT_ARG();
-            ivm.vf = vf;
-            len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
-            if (len < 0)
-                return -1;
-            addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm,
sizeof(ivm));
+            mac = *argv;
         } else if (matches(*argv, "vlan") == 0) {
-            struct ifla_vf_vlan ivv;
             NEXT_ARG();
-            if (get_unsigned(&ivv.vlan, *argv, 0)) {
-                invarg("Invalid \"vlan\" value\n", *argv);
-            }
-            ivv.vf = vf;
-            ivv.qos = 0;
+            vlan = *argv;
             if (NEXT_ARG_OK()) {
                 NEXT_ARG();
                 if (matches(*argv, "qos") == 0) {
                     NEXT_ARG();
-                    if (get_unsigned(&ivv.qos, *argv, 0)) {
-                        invarg("Invalid \"qos\" value\n", *argv);
-                    }
+                    qos = *argv;
                 } else {
                     /* rewind arg */
                     PREV_ARG();
                 }
             }
-            addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv,
sizeof(ivv));
         } else if (matches(*argv, "rate") == 0) {
-            struct ifla_vf_tx_rate ivt;
             NEXT_ARG();
-            if (get_unsigned(&ivt.rate, *argv, 0)) {
-                invarg("Invalid \"rate\" value\n", *argv);
-            }
-            ivt.vf = vf;
-            addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt,
sizeof(ivt));
-        
+            rate = *argv;
         } else {
             /* rewind arg */
             PREV_ARG();
@@ -238,14 +447,46 @@ int iplink_parse_vf(int vf, int *argcp, char ***argvp,
     if (argc == *argcp)
         incomplete_command();
 
-    addattr_nest_end(&req->n, vfinfo);
+    if (mac || vlan || rate) {
+
+        vflist = addattr_nest(&req->n, sizeof(*req), IFLA_VFINFO_LIST);
+        vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+
+        if (mac) {
+            len = ll_addr_a2n((char *)ivm.mac, 32, mac);
+            if (len < 0)
+                invarg("Invalid \"mac\" value\n", mac);
+            addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
+                &ivm, sizeof(ivm));
+        }
+
+        if (vlan) {
+            if (get_unsigned(&ivv.vlan, vlan, 0))
+                invarg("Invalid \"vlan\" value\n", vlan);
+            if (qos) {
+                if (get_unsigned(&ivv.qos, qos, 0))
+                    invarg("Invalid \"qos\" value\n", qos);
+            }
+            addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN,
+                &ivv, sizeof(ivv));
+        }
+
+        if (rate) {
+            if (get_unsigned(&ivt.rate, rate, 0))
+                invarg("Invalid \"rate\" value\n", rate);
+            addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE,
+                &ivt, sizeof(ivt));
+        }
+
+        addattr_nest_end(&req->n, vfinfo);
+        addattr_nest_end(&req->n, vflist);
+    }
 
     *argcp = argc;
     *argvp = argv;
     return 0;
 }
 
-
 int iplink_parse(int argc, char **argv, struct iplink_req *req,
         char **name, char **type, char **link, char **dev, int *group)
 {
@@ -362,12 +603,9 @@ int iplink_parse(int argc, char **argv, struct
iplink_req *req,
             if (get_integer(&vf,  *argv, 0)) {
                 invarg("Invalid \"vf\" value\n", *argv);
             }
-            vflist = addattr_nest(&req->n, sizeof(*req),
-                          IFLA_VFINFO_LIST);
             len = iplink_parse_vf(vf, &argc, &argv, req);
             if (len < 0)
                 return -1;
-            addattr_nest_end(&req->n, vflist);
         } else if (matches(*argv, "master") == 0) {
             int ifindex;
             NEXT_ARG();


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-11-01 12:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-29  2:33 [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Roopa Prabhu
2011-10-29  2:34 ` [net-next-2.6 PATCH 1/6 RFC v3] rtnetlink: Netlink interface for setting MAC and VLAN filters Roopa Prabhu
2011-10-29  2:34 ` [net-next-2.6 PATCH 2/6 RFC v3] net: Add netdev_ops to set and get MAC/VLAN rx filters Roopa Prabhu
2011-10-29  2:34 ` [net-next-2.6 PATCH 3/6 RFC v3] rtnetlink: Add support to set MAC/VLAN filters Roopa Prabhu
2011-10-29  2:34 ` [net-next-2.6 PATCH 4/6 RFC v3] rtnetlink: Add support to get " Roopa Prabhu
2011-10-29  2:34 ` [net-next-2.6 PATCH 5/6 RFC v3] macvlan: Add support to for netdev ops to set " Roopa Prabhu
2011-10-29  2:34 ` [net-next-2.6 PATCH 6/6 RFC v3] macvlan: Add support to get MAC/VLAN filter netdev ops Roopa Prabhu
2011-10-31 16:38 ` [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode Rose, Gregory V
2011-10-31 17:09   ` Roopa Prabhu
2011-10-31 17:39     ` Rose, Gregory V
2011-11-01 12:17       ` Roopa Prabhu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).