lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20120229071719.10937.68718.stgit@jf-dev1-dcblab>
Date:	Tue, 28 Feb 2012 23:17:19 -0800
From:	John Fastabend <john.r.fastabend@...el.com>
To:	jhs@...atatu.com, shemminger@...tta.com, kernel@...tstofly.org
Cc:	hadi@...erus.ca, bhutchings@...arflare.com, roprabhu@...co.com,
	mst@...hat.com, netdev@...r.kernel.org, gregory.v.rose@...el.com,
	davem@...emloft.net
Subject: [RFC PATCH 2/3] net: expose ebridge FDB with priv flag
	IFF_OFFLOADED_FDB

This adds a new private interface flag IFF_OFFLOADED_FDB and an
additional ndmsg flag NTF_EMBEDDED.

The private flag IFF_OFFLOADED_FDB should be set on devices to
indicate an embedded bridging component exists with a forwarding
database.

With this set PF_BRIDGE:{RTM_NEWNEIGH|RTM_DELNEIGH|RTM_GETNEIGH}
netlink msgs can manage the unicast address list on these devices
by setting the NTF_EMBEDDED flag in ndm_flags.

These commands are compatible with the SW bridge allowing the same
user space tools to be used with both SW bridges and HW bridges.

PF_BRIDGE:RTM_NEWNEIGH - adds an address to the unicast mac address
			 list. This fails if the address already
			 exists in the list. We do not allow user
			 space to bump the reference count on the
			 address list.
PF_BRIDGE:RTM_DELNEIGH - deletes an address in the unicast mac
			 address list if it exists.
PF_BRIDGE:RTM_GETNEIGH - dumps the unicast mac address list.

Examples session using the 'br'[1] tool to add, dump and then
delete a mac address with a new "embedded" option:

# ./br fdb add embedded 00:1b:21:55:23:ac dev eth6_rename
# ./br fdb
port			mac addr                flags
Embedded eth6_rename    00:1b:21:55:23:aa       local
Embedded eth6_rename    00:1b:21:55:23:ab       local
Embedded eth6_rename    00:1b:21:55:23:ac       local
	 veth2		76:99:5e:bf:e6:52       local
	 eth6_rename	00:1b:21:55:23:59       local
	 veth0		c6:09:6e:6c:7d:54       local

[1] 'br' tool was published as an RFC here and will be renamed 'bridge'
    http://patchwork.ozlabs.org/patch/117664/

Signed-off-by: John Fastabend <john.r.fastabend@...el.com>
---

 include/linux/if.h        |    2 -
 include/linux/neighbour.h |    2 +
 net/bridge/br_netlink.c   |  144 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+), 2 deletions(-)

diff --git a/include/linux/if.h b/include/linux/if.h
index f995c66..bd0efbc 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -81,7 +81,7 @@
 #define IFF_UNICAST_FLT	0x20000		/* Supports unicast filtering	*/
 #define IFF_TEAM_PORT	0x40000		/* device used as team port */
 #define IFF_SUPP_NOFCS	0x80000		/* device supports sending custom FCS */
-
+#define IFF_OFFLOADED_FDB 0x100000	/* devices used with HW FDB */
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
index b188f68..9a478d3 100644
--- a/include/linux/neighbour.h
+++ b/include/linux/neighbour.h
@@ -33,6 +33,8 @@ enum {
 #define NTF_PROXY	0x08	/* == ATF_PUBL */
 #define NTF_ROUTER	0x80
 
+#define NTF_EMBEDDED	0x02	/* PF_BRIDGE embedded entry */
+
 /*
  *	Neighbor Cache Entry States.
  */
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 9e70191..7b1a581 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -211,6 +211,57 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
 	return 0;
 }
 
+static int rtnl_offloaded_fdb_add(struct nlmsghdr *nlh, struct net_device *dev)
+{
+	struct ndmsg *ndm;
+	struct netdev_hw_addr *ha;
+	struct nlattr *tb[NDA_MAX+1];
+	__u8 *addr;
+	int err;
+
+	ASSERT_RTNL();
+
+	if (!(dev->priv_flags & IFF_OFFLOADED_FDB))
+		return -ENODEV;
+
+	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
+	if (err < 0)
+		return err;
+
+	ndm = nlmsg_data(nlh);
+	if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
+		pr_info("fdb_add: RTM_NEWNEIGH with invalid address\n");
+		return -EINVAL;
+	}
+
+	addr = nla_data(tb[NDA_LLADDR]);
+	if (!is_valid_ether_addr(addr)) {
+		pr_info("fdb_add: RTM_NEWNEIGH with invalid ether address\n");
+		return -EINVAL;
+	}
+
+	if (ndm->ndm_state & NUD_PERMANENT) {
+		pr_info("fdb_add: RTM_NEWNEIGH with invalid state %#x\n",
+			ndm->ndm_state);
+		return -EINVAL;
+	}
+
+	if (is_multicast_ether_addr(addr))
+		return -EINVAL;
+
+	netif_addr_lock_bh(dev);
+	list_for_each_entry(ha, &dev->uc.list, list) {
+		if (!compare_ether_addr(ha->addr, addr)) {
+			netif_addr_unlock_bh(dev);
+			return -EEXIST;
+		}
+	}
+	netif_addr_unlock_bh(dev);
+
+	err = dev_uc_add(dev, addr);
+	return err;
+}
+
 static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
@@ -235,7 +286,9 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 		return -ENODEV;
 	}
 
-	if (dev->priv_flags & IFF_BRIDGE_PORT)
+	if (ndm->ndm_flags & NTF_EMBEDDED)
+		err = rtnl_offloaded_fdb_add(nlh, dev);
+	else if (dev->priv_flags & IFF_BRIDGE_PORT)
 		err = br_fdb_add(nlh, dev);
 	else
 		err = -ENODEV;
@@ -243,6 +296,43 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 	return err;
 }
 
+static int rtnl_offloaded_fdb_del(struct nlmsghdr *nlh, struct net_device *dev)
+{
+	struct ndmsg *ndm;
+	struct nlattr *tb[NDA_MAX+1];
+	__u8 *addr;
+	int err;
+
+	ASSERT_RTNL();
+	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
+	if (err < 0)
+		return err;
+
+	ndm = nlmsg_data(nlh);
+	if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
+		pr_info("fdb_add: RTM_NEWNEIGH with invalid address\n");
+		return -EINVAL;
+	}
+
+	addr = nla_data(tb[NDA_LLADDR]);
+	if (!is_valid_ether_addr(addr)) {
+		pr_info("fdb_add: RTM_NEWNEIGH with invalid ether address\n");
+		return -EINVAL;
+	}
+
+	if (ndm->ndm_state & NUD_PERMANENT) {
+		pr_info("fdb_add: RTM_NEWNEIGH with invalid state %#x\n",
+			ndm->ndm_state);
+		return -EINVAL;
+	}
+
+	if (is_multicast_ether_addr(addr))
+		return -EINVAL;
+
+	err = dev_uc_del(dev, addr);
+	return err;
+}
+
 static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
@@ -268,12 +358,61 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
 	if (dev->priv_flags & IFF_BRIDGE_PORT)
 		err = br_fdb_del(nlh, dev);
+	else if (dev->priv_flags & IFF_OFFLOADED_FDB)
+		err = rtnl_offloaded_fdb_del(nlh, dev);
 	else
 		err = -ENODEV;
 
 	return err;
 }
 
+static int rtnl_offloaded_fdb_dump(struct sk_buff *skb,
+				   struct netlink_callback *cb,
+				   struct net_device *dev,
+				   int idx)
+{
+	struct netdev_hw_addr *ha;
+	struct nlmsghdr *nlh;
+	struct ndmsg *ndm;
+	u32 pid, seq;
+
+	pid = NETLINK_CB(cb->skb).pid;
+	seq = cb->nlh->nlmsg_seq;
+
+	netif_addr_lock_bh(dev);
+	list_for_each_entry(ha, &dev->uc.list, list) {
+		if (idx < cb->args[0])
+			goto skip;
+
+		nlh = nlmsg_put(skb, pid, seq,
+				RTM_NEWNEIGH, sizeof(*ndm), NLM_F_MULTI);
+		if (!nlh)
+			break;
+
+		ndm = nlmsg_data(nlh);
+		ndm->ndm_family  = AF_BRIDGE;
+		ndm->ndm_pad1	 = 0;
+		ndm->ndm_pad2    = 0;
+		ndm->ndm_flags	 = NTF_EMBEDDED;
+		ndm->ndm_type	 = 0;
+		ndm->ndm_ifindex = dev->ifindex;
+		ndm->ndm_state   = NUD_PERMANENT;
+
+		NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, ha->addr);
+
+		nlmsg_end(skb, nlh);
+skip:
+		++idx;
+	}
+	netif_addr_unlock_bh(dev);
+
+	return idx;
+nla_put_failure:
+	netif_addr_unlock_bh(dev);
+	nlmsg_cancel(skb, nlh);
+	return idx;
+}
+
 static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int idx = 0;
@@ -284,6 +423,9 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	for_each_netdev_rcu(net, dev) {
 		if (dev->priv_flags & IFF_EBRIDGE)
 			idx = br_fdb_dump(skb, cb, dev, idx);
+
+		if (dev->priv_flags & IFF_OFFLOADED_FDB)
+			idx = rtnl_offloaded_fdb_dump(skb, cb, dev, idx);
 	}
 	rcu_read_unlock();
 

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ