* [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges
@ 2012-09-19 12:42 Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 1/7] bridge: Add vlan check to forwarding path Vlad Yasevich
` (6 more replies)
0 siblings, 7 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
This series of patches provides an ability to add VLAN IDs to the bridge
ports. This is similar to what can be found in most switches. The bridge
port may have any number of VLANs added to it including vlan 0 for untagged
traffic. When vlans are added to the port, only traffic tagged with particular
vlan will forwarded over this port. Additionally, vlan ids are added to FDB
entries and become part of the lookup. This way we correctly identify the FDB
entry.
The default behavior ofthe bridge is unchanged if no vlans have been
configured.
Changes since v1:
- Comments addressed regarding formatting and RCU usage
- iocts have been removed and changed over the netlink interface.
- Added support of user added ndb entries.
- changed sysfs interface to export a bitmap. Also added a write interface.
I am not sure how much I like it, but it made my testing easier/faster. I
might change the write interface to take text instead of binary.
Vlad Yasevich (7):
bridge: Add vlan check to forwarding path
bridge: Add vlan to unicast fdb entries
bridge: Add vlan id to multicast groups
bridge: Add netlink interface to configure vlans on bridge ports
bridge: Add vlan support to static neighbors
bridge: Add sysfs interface to display VLANS
bridge: Add the ability to show dump the vlan map from a bridge port
include/linux/if_bridge.h | 3 +-
include/linux/if_link.h | 23 ++++++
include/linux/neighbour.h | 2 +-
net/bridge/br_device.c | 2 +-
net/bridge/br_fdb.c | 77 +++++++++++--------
net/bridge/br_forward.c | 15 ++++-
net/bridge/br_if.c | 74 +++++++++++++++++
net/bridge/br_input.c | 19 ++++-
net/bridge/br_multicast.c | 64 +++++++++++-----
net/bridge/br_netlink.c | 190 ++++++++++++++++++++++++++++++++++++++------
net/bridge/br_private.h | 29 +++++++-
net/bridge/br_sysfs_if.c | 70 +++++++++++++++++
12 files changed, 481 insertions(+), 87 deletions(-)
--
1.7.7.6
^ permalink raw reply [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 1/7] bridge: Add vlan check to forwarding path
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries Vlad Yasevich
` (5 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
When forwarding packets make sure vlan matches any configured vlan for
the port.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
net/bridge/br_forward.c | 15 ++++++++++++++-
net/bridge/br_input.c | 12 ++++++++++++
net/bridge/br_private.h | 17 +++++++++++++++++
3 files changed, 43 insertions(+), 1 deletions(-)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 02015a5..f917cb8 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -26,11 +26,24 @@ static int deliver_clone(const struct net_bridge_port *prev,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb));
-/* Don't forward packets to originating port or forwarding diasabled */
+/* check to see that the vlan is allowed to be forwarded on this interface */
+static inline int vlan_match(const struct net_bridge_port *p,
+ const struct sk_buff *skb)
+{
+ unsigned long *vlan_map = rcu_dereference(p->vlan_map);
+ unsigned short vid = br_get_vlan(skb);
+
+ /* The map keeps the vlans off by 1 so adjust for that */
+ return vlan_map && test_bit(br_vid(vid), vlan_map);
+}
+
+/* Don't forward packets to originating port or forwarding diasabled.
+ */
static inline int should_deliver(const struct net_bridge_port *p,
const struct sk_buff *skb)
{
return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
+ vlan_match(p, skb) &&
p->state == BR_STATE_FORWARDING);
}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 76f15fd..44f352d 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -53,10 +53,22 @@ int br_handle_frame_finish(struct sk_buff *skb)
struct net_bridge_fdb_entry *dst;
struct net_bridge_mdb_entry *mdst;
struct sk_buff *skb2;
+ unsigned long *vlan_map;
+ u16 vid = 0;
if (!p || p->state == BR_STATE_DISABLED)
goto drop;
+ /* If VLAN filter is configured on the port, make sure we accept
+ * only traffic matching the VLAN filter.
+ */
+ vlan_map = rcu_dereference(p->vlan_map);
+ if (vlan_map) {
+ vid = br_get_vlan(skb);
+ if (!test_bit(br_vid(vid), vlan_map))
+ goto drop;
+ }
+
/* insert into forwarding database after filtering to avoid spoofing */
br = p->br;
br_fdb_update(br, p, eth_hdr(skb)->h_source);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f507d2a..baf1835 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -18,6 +18,7 @@
#include <linux/netpoll.h>
#include <linux/u64_stats_sync.h>
#include <net/route.h>
+#include <linux/if_vlan.h>
#define BR_HASH_BITS 8
#define BR_HASH_SIZE (1 << BR_HASH_BITS)
@@ -152,10 +153,17 @@ struct net_bridge_port
#ifdef CONFIG_NET_POLL_CONTROLLER
struct netpoll *np;
#endif
+ /* VLAN map of all vlans allowed on this port. Stored off by 1,
+ * such at VLAN 0 (untagged) is stored in bit 1.
+ */
+ unsigned long __rcu *vlan_map;
};
#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
+/* Use this macro to get the correct VLAN id */
+#define br_vid(vid) ((vid) + 1)
+
static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev)
{
struct net_bridge_port *port = rcu_dereference(dev->rx_handler_data);
@@ -168,6 +176,15 @@ static inline struct net_bridge_port *br_port_get_rtnl(struct net_device *dev)
rtnl_dereference(dev->rx_handler_data) : NULL;
}
+static inline u16 br_get_vlan(const struct sk_buff *skb)
+{
+ u16 uninitialized_var(tag);
+
+ if (vlan_get_tag(skb, &tag))
+ return 0;
+ return tag & VLAN_VID_MASK;
+}
+
struct br_cpu_netstats {
u64 rx_packets;
u64 rx_bytes;
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 1/7] bridge: Add vlan check to forwarding path Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-22 17:17 ` Ben Hutchings
2012-09-19 12:42 ` [RFC PATCHv2 bridge 3/7] bridge: Add vlan id to multicast groups Vlad Yasevich
` (4 subsequent siblings)
6 siblings, 1 reply; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
This patch adds vlan to unicast fdb entries that are created for
learned addresses (not the manually configured ones). It adds
vlan id into the hash mix and uses vlan as an addditional parameter
for an entry match.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
include/linux/if_bridge.h | 2 +-
net/bridge/br_device.c | 2 +-
net/bridge/br_fdb.c | 71 ++++++++++++++++++++++++++------------------
net/bridge/br_input.c | 7 ++--
net/bridge/br_private.h | 7 +++-
5 files changed, 53 insertions(+), 36 deletions(-)
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index dd3f201..8476d6f 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -94,7 +94,7 @@ struct __fdb_entry {
__u32 ageing_timer_value;
__u8 port_hi;
__u8 pad0;
- __u16 unused;
+ __u16 fdb_vid;
};
#ifdef __KERNEL__
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 070e8a6..bf08c09 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -67,7 +67,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
br_multicast_deliver(mdst, skb);
else
br_flood_deliver(br, skb);
- } else if ((dst = __br_fdb_get(br, dest)) != NULL)
+ } else if ((dst = __br_fdb_get(br, dest, br_get_vlan(skb))) != NULL)
br_deliver(dst->dst, skb);
else
br_flood_deliver(br, skb);
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 9ce430b..e17f9f2 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/atomic.h>
#include <asm/unaligned.h>
+#include <linux/if_vlan.h>
#include "br_private.h"
static struct kmem_cache *br_fdb_cache __read_mostly;
@@ -67,11 +68,12 @@ static inline int has_expired(const struct net_bridge *br,
time_before_eq(fdb->updated + hold_time(br), jiffies);
}
-static inline int br_mac_hash(const unsigned char *mac)
+static inline int br_mac_hash(const unsigned char *mac, __u16 vlan_tci)
{
- /* use 1 byte of OUI cnd 3 bytes of NIC */
+ /* use 1 byte of OUI and 3 bytes of NIC */
u32 key = get_unaligned((u32 *)(mac + 2));
- return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
+ return jhash_2words(key, (vlan_tci & VLAN_VID_MASK),
+ fdb_salt) & (BR_HASH_SIZE - 1);
}
static void fdb_rcu_free(struct rcu_head *head)
@@ -132,7 +134,7 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
struct net_bridge_fdb_entry *f;
/* If old entry was unassociated with any port, then delete it. */
- f = __br_fdb_get(br, br->dev->dev_addr);
+ f = __br_fdb_get(br, br->dev->dev_addr, 0);
if (f && f->is_local && !f->dst)
fdb_delete(br, f);
@@ -231,13 +233,16 @@ void br_fdb_delete_by_port(struct net_bridge *br,
/* No locking or refcounting, assumes caller has rcu_read_lock */
struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
- const unsigned char *addr)
+ const unsigned char *addr,
+ __u16 vlan_tci)
{
struct hlist_node *h;
struct net_bridge_fdb_entry *fdb;
- hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {
- if (ether_addr_equal(fdb->addr.addr, addr)) {
+ hlist_for_each_entry_rcu(fdb, h,
+ &br->hash[br_mac_hash(addr, vlan_tci)], hlist) {
+ if (ether_addr_equal(fdb->addr.addr, addr) &&
+ fdb->vlan_id == (vlan_tci & VLAN_VID_MASK) ) {
if (unlikely(has_expired(br, fdb)))
break;
return fdb;
@@ -261,7 +266,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
if (!port)
ret = 0;
else {
- fdb = __br_fdb_get(port->br, addr);
+ fdb = __br_fdb_get(port->br, addr, 0);
ret = fdb && fdb->dst && fdb->dst->dev != dev &&
fdb->dst->state == BR_STATE_FORWARDING;
}
@@ -313,6 +318,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
fe->is_local = f->is_local;
if (!f->is_static)
fe->ageing_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated);
+ fe->fdb_vid = f->vlan_id;
++fe;
++num;
}
@@ -325,26 +331,30 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
}
static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
- const unsigned char *addr)
+ const unsigned char *addr,
+ __u16 vlan_tci)
{
struct hlist_node *h;
struct net_bridge_fdb_entry *fdb;
hlist_for_each_entry(fdb, h, head, hlist) {
- if (ether_addr_equal(fdb->addr.addr, addr))
+ if (ether_addr_equal(fdb->addr.addr, addr) &&
+ fdb->vlan_id == (vlan_tci & VLAN_VID_MASK))
return fdb;
}
return NULL;
}
static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
- const unsigned char *addr)
+ const unsigned char *addr,
+ __u16 vlan_tci)
{
struct hlist_node *h;
struct net_bridge_fdb_entry *fdb;
hlist_for_each_entry_rcu(fdb, h, head, hlist) {
- if (ether_addr_equal(fdb->addr.addr, addr))
+ if (ether_addr_equal(fdb->addr.addr, addr) &&
+ fdb->vlan_id == (vlan_tci & VLAN_VID_MASK))
return fdb;
}
return NULL;
@@ -352,7 +362,8 @@ static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
struct net_bridge_port *source,
- const unsigned char *addr)
+ const unsigned char *addr,
+ __u16 vlan_tci)
{
struct net_bridge_fdb_entry *fdb;
@@ -360,6 +371,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
if (fdb) {
memcpy(fdb->addr.addr, addr, ETH_ALEN);
fdb->dst = source;
+ fdb->vlan_id = (vlan_tci & VLAN_VID_MASK);
fdb->is_local = 0;
fdb->is_static = 0;
fdb->updated = fdb->used = jiffies;
@@ -371,13 +383,13 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr)
{
- struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+ struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
struct net_bridge_fdb_entry *fdb;
if (!is_valid_ether_addr(addr))
return -EINVAL;
- fdb = fdb_find(head, addr);
+ fdb = fdb_find(head, addr, 0);
if (fdb) {
/* it is okay to have multiple ports with same
* address, just use the first one.
@@ -390,7 +402,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
fdb_delete(br, fdb);
}
- fdb = fdb_create(head, source, addr);
+ fdb = fdb_create(head, source, addr, 0);
if (!fdb)
return -ENOMEM;
@@ -412,9 +424,9 @@ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
}
void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
- const unsigned char *addr)
+ const unsigned char *addr, __u16 vlan_tci)
{
- struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+ struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan_tci)];
struct net_bridge_fdb_entry *fdb;
/* some users want to always flood. */
@@ -426,7 +438,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
source->state == BR_STATE_FORWARDING))
return;
- fdb = fdb_find_rcu(head, addr);
+ fdb = fdb_find_rcu(head, addr, vlan_tci);
if (likely(fdb)) {
/* attempt to update an entry for a local interface */
if (unlikely(fdb->is_local)) {
@@ -441,8 +453,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
}
} else {
spin_lock(&br->hash_lock);
- if (likely(!fdb_find(head, addr))) {
- fdb = fdb_create(head, source, addr);
+ if (likely(!fdb_find(head, addr, vlan_tci))) {
+ fdb = fdb_create(head, source, addr, vlan_tci);
if (fdb)
fdb_notify(br, fdb, RTM_NEWNEIGH);
}
@@ -571,18 +583,18 @@ out:
/* Update (create or replace) forwarding database entry */
static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
- __u16 state, __u16 flags)
+ __u16 state, __u16 flags, __u16 vlan_tci)
{
struct net_bridge *br = source->br;
- struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+ struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan_tci)];
struct net_bridge_fdb_entry *fdb;
- fdb = fdb_find(head, addr);
+ fdb = fdb_find(head, addr, vlan_tci);
if (fdb == NULL) {
if (!(flags & NLM_F_CREATE))
return -ENOENT;
- fdb = fdb_create(head, source, addr);
+ fdb = fdb_create(head, source, addr, vlan_tci);
if (!fdb)
return -ENOMEM;
fdb_notify(br, fdb, RTM_NEWNEIGH);
@@ -628,11 +640,12 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
if (ndm->ndm_flags & NTF_USE) {
rcu_read_lock();
- br_fdb_update(p->br, p, addr);
+ br_fdb_update(p->br, p, addr, 0);
rcu_read_unlock();
} else {
spin_lock_bh(&p->br->hash_lock);
- err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags);
+ err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags,
+ 0);
spin_unlock_bh(&p->br->hash_lock);
}
@@ -642,10 +655,10 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr)
{
struct net_bridge *br = p->br;
- struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+ struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
struct net_bridge_fdb_entry *fdb;
- fdb = fdb_find(head, addr);
+ fdb = fdb_find(head, addr, 0);
if (!fdb)
return -ENOENT;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 44f352d..c4f0020 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -71,7 +71,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
/* insert into forwarding database after filtering to avoid spoofing */
br = p->br;
- br_fdb_update(br, p, eth_hdr(skb)->h_source);
+ br_fdb_update(br, p, eth_hdr(skb)->h_source, vid);
if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
br_multicast_rcv(br, p, skb))
@@ -106,7 +106,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
skb2 = skb;
br->dev->stats.multicast++;
- } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
+ } else if ((dst = __br_fdb_get(br, dest, vid)) &&
+ dst->is_local) {
skb2 = skb;
/* Do not forward the packet since it's local. */
skb = NULL;
@@ -135,7 +136,7 @@ static int br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
- br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, br_get_vlan(skb));
return 0; /* process further */
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index baf1835..bb382f1 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -73,6 +73,7 @@ struct net_bridge_fdb_entry
unsigned long updated;
unsigned long used;
mac_addr addr;
+ __u16 vlan_id;
unsigned char is_local;
unsigned char is_static;
};
@@ -367,7 +368,8 @@ extern void br_fdb_cleanup(unsigned long arg);
extern void br_fdb_delete_by_port(struct net_bridge *br,
const struct net_bridge_port *p, int do_all);
extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
- const unsigned char *addr);
+ const unsigned char *addr,
+ __u16 vlan_tci);
extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr);
extern int br_fdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long count, unsigned long off);
@@ -376,7 +378,8 @@ extern int br_fdb_insert(struct net_bridge *br,
const unsigned char *addr);
extern void br_fdb_update(struct net_bridge *br,
struct net_bridge_port *source,
- const unsigned char *addr);
+ const unsigned char *addr,
+ __u16 vlan_tci);
extern int br_fdb_delete(struct ndmsg *ndm,
struct net_device *dev,
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 3/7] bridge: Add vlan id to multicast groups
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 1/7] bridge: Add vlan check to forwarding path Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 4/7] bridge: Add netlink interface to configure vlans on bridge ports Vlad Yasevich
` (3 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
Add vlan_id to multicasts groups so that we know which vlan each group belongs
to and can correctly forward to appropriate vlan.
Signed-off-by: Vlad Yasevich <vyasevich@redhat.com>
---
net/bridge/br_multicast.c | 64 +++++++++++++++++++++++++++++++--------------
net/bridge/br_private.h | 1 +
2 files changed, 45 insertions(+), 20 deletions(-)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2417434..888fc08 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -51,6 +51,8 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
{
if (a->proto != b->proto)
return 0;
+ if (a->vid != b->vid)
+ return 0;
switch (a->proto) {
case htons(ETH_P_IP):
return a->u.ip4 == b->u.ip4;
@@ -62,16 +64,19 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
return 0;
}
-static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip)
+static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip,
+ __u16 vid)
{
- return jhash_1word(mdb->secret, (__force u32)ip) & (mdb->max - 1);
+ return jhash_2words((__force u32)ip, vid, mdb->secret) & (mdb->max - 1);
}
#if IS_ENABLED(CONFIG_IPV6)
static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb,
- const struct in6_addr *ip)
+ const struct in6_addr *ip,
+ __u16 vid)
{
- return jhash2((__force u32 *)ip->s6_addr32, 4, mdb->secret) & (mdb->max - 1);
+ return jhash_2words(ipv6_addr_hash(ip), vid,
+ mdb->secret) & (mdb->max - 1);
}
#endif
@@ -80,10 +85,10 @@ static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
{
switch (ip->proto) {
case htons(ETH_P_IP):
- return __br_ip4_hash(mdb, ip->u.ip4);
+ return __br_ip4_hash(mdb, ip->u.ip4, ip->vid);
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
- return __br_ip6_hash(mdb, &ip->u.ip6);
+ return __br_ip6_hash(mdb, &ip->u.ip6, ip->vid);
#endif
}
return 0;
@@ -113,24 +118,27 @@ static struct net_bridge_mdb_entry *br_mdb_ip_get(
}
static struct net_bridge_mdb_entry *br_mdb_ip4_get(
- struct net_bridge_mdb_htable *mdb, __be32 dst)
+ struct net_bridge_mdb_htable *mdb, __be32 dst, __u16 vlan_tci)
{
struct br_ip br_dst;
br_dst.u.ip4 = dst;
br_dst.proto = htons(ETH_P_IP);
+ br_dst.vid = vlan_tci & VLAN_VID_MASK;
return br_mdb_ip_get(mdb, &br_dst);
}
#if IS_ENABLED(CONFIG_IPV6)
static struct net_bridge_mdb_entry *br_mdb_ip6_get(
- struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst)
+ struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst,
+ __u16 vlan_tci)
{
struct br_ip br_dst;
br_dst.u.ip6 = *dst;
br_dst.proto = htons(ETH_P_IPV6);
+ br_dst.vid = vlan_tci & VLAN_VID_MASK;
return br_mdb_ip_get(mdb, &br_dst);
}
@@ -692,7 +700,8 @@ err:
static int br_ip4_multicast_add_group(struct net_bridge *br,
struct net_bridge_port *port,
- __be32 group)
+ __be32 group,
+ __u16 vlan_tci)
{
struct br_ip br_group;
@@ -701,6 +710,7 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
br_group.u.ip4 = group;
br_group.proto = htons(ETH_P_IP);
+ br_group.vid = vlan_tci & VLAN_VID_MASK;
return br_multicast_add_group(br, port, &br_group);
}
@@ -708,7 +718,8 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
#if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_add_group(struct net_bridge *br,
struct net_bridge_port *port,
- const struct in6_addr *group)
+ const struct in6_addr *group,
+ __u16 vlan_tci)
{
struct br_ip br_group;
@@ -717,6 +728,7 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
br_group.u.ip6 = *group;
br_group.proto = htons(ETH_P_IPV6);
+ br_group.vid = vlan_tci & VLAN_VID_MASK;
return br_multicast_add_group(br, port, &br_group);
}
@@ -928,7 +940,8 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
continue;
}
- err = br_ip4_multicast_add_group(br, port, group);
+ err = br_ip4_multicast_add_group(br, port, group,
+ br_get_vlan(skb));
if (err)
break;
}
@@ -988,7 +1001,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
continue;
}
- err = br_ip6_multicast_add_group(br, port, &grec->grec_mca);
+ err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
+ br_get_vlan(skb));
if (!err)
break;
}
@@ -1106,7 +1120,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
if (!group)
goto out;
- mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group);
+ mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group,
+ br_get_vlan(skb));
if (!mp)
goto out;
@@ -1178,7 +1193,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (!group)
goto out;
- mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group);
+ mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group,
+ br_get_vlan(skb));
if (!mp)
goto out;
@@ -1262,7 +1278,8 @@ out:
static void br_ip4_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
- __be32 group)
+ __be32 group,
+ __u16 vlan_tci)
{
struct br_ip br_group;
@@ -1271,6 +1288,7 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
br_group.u.ip4 = group;
br_group.proto = htons(ETH_P_IP);
+ br_group.vid = vlan_tci & VLAN_VID_MASK;
br_multicast_leave_group(br, port, &br_group);
}
@@ -1278,7 +1296,8 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
- const struct in6_addr *group)
+ const struct in6_addr *group,
+ __u16 vlan_tci)
{
struct br_ip br_group;
@@ -1287,6 +1306,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
br_group.u.ip6 = *group;
br_group.proto = htons(ETH_P_IPV6);
+ br_group.vid = vlan_tci & VLAN_VID_MASK;
br_multicast_leave_group(br, port, &br_group);
}
@@ -1369,7 +1389,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT:
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
- err = br_ip4_multicast_add_group(br, port, ih->group);
+ err = br_ip4_multicast_add_group(br, port, ih->group,
+ br_get_vlan(skb2));
break;
case IGMPV3_HOST_MEMBERSHIP_REPORT:
err = br_ip4_multicast_igmp3_report(br, port, skb2);
@@ -1378,7 +1399,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
err = br_ip4_multicast_query(br, port, skb2);
break;
case IGMP_HOST_LEAVE_MESSAGE:
- br_ip4_multicast_leave_group(br, port, ih->group);
+ br_ip4_multicast_leave_group(br, port, ih->group,
+ br_get_vlan(skb2));
break;
}
@@ -1498,7 +1520,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
}
mld = (struct mld_msg *)skb_transport_header(skb2);
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
- err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
+ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca,
+ br_get_vlan(skb2));
break;
}
case ICMPV6_MLD2_REPORT:
@@ -1515,7 +1538,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
goto out;
}
mld = (struct mld_msg *)skb_transport_header(skb2);
- br_ip6_multicast_leave_group(br, port, &mld->mld_mca);
+ br_ip6_multicast_leave_group(br, port, &mld->mld_mca,
+ br_get_vlan(skb2));
}
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index bb382f1..166dcf4 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -62,6 +62,7 @@ struct br_ip
#endif
} u;
__be16 proto;
+ __u16 vid;
};
struct net_bridge_fdb_entry
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 4/7] bridge: Add netlink interface to configure vlans on bridge ports
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
` (2 preceding siblings ...)
2012-09-19 12:42 ` [RFC PATCHv2 bridge 3/7] bridge: Add vlan id to multicast groups Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-22 17:17 ` Ben Hutchings
2012-09-19 12:42 ` [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors Vlad Yasevich
` (2 subsequent siblings)
6 siblings, 1 reply; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
Add a netlink interface to add and remove vlan configuration on bridge port.
The interface uses the RTM_SETLINK message and encodes the vlan
configuration inside the IFLA_AF_SPEC. It is possble to include multiple
vlans to either add or remove in a single message.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
include/linux/if_link.h | 22 +++++++++
net/bridge/br_if.c | 74 +++++++++++++++++++++++++++++
net/bridge/br_netlink.c | 117 ++++++++++++++++++++++++++++++++++++++--------
net/bridge/br_private.h | 2 +
4 files changed, 194 insertions(+), 21 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index ac173bd..38dbcff 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -398,4 +398,26 @@ struct ifla_port_vsi {
__u8 pad[3];
};
+/* Bridge Section
+ * [IFLA_AF_SPEC] = {
+ * [AF_BRIDGE] = {
+ * [IFLA_BR_VLAN_INFO] = ...
+ * }
+ * }
+ */
+enum {
+ IFLA_BR_UNSPEC,
+ IFLA_BR_VLAN_INFO,
+ __IFLA_BR_MAX,
+};
+#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+
+enum {
+ IFLA_BR_VLAN_UNSPEC,
+ IFLA_BR_VLAN_ADD,
+ IFLA_BR_VLAN_DEL,
+ __IFLA_BR_VLAN_MAX,
+};
+#define IFLA_BR_VLAN_MAX (__IFLA_BR_VLAN_MAX - 1)
+
#endif /* _LINUX_IF_LINK_H */
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 1c8fdc3..c6a66e2 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -23,6 +23,7 @@
#include <linux/if_ether.h>
#include <linux/slab.h>
#include <net/sock.h>
+#include <linux/if_vlan.h>
#include "br_private.h"
@@ -445,6 +446,79 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
return 0;
}
+/* Called with RTNL */
+int br_set_port_vlan(struct net_bridge_port *p, unsigned short vlan)
+{
+ unsigned long table_size = BITS_TO_LONGS(br_vid(VLAN_N_VID));
+ unsigned long *vid_map = NULL;
+ __u16 vid = br_vid(vlan);
+ int ret = 0;
+
+ /* The vlan map is indexed by vid+1. This way we can store
+ * vid 0 (untagged) into the map as well.
+ */
+ if (!p->vlan_map) {
+ vid_map = kzalloc(table_size, GFP_KERNEL);
+ if (!vid_map) {
+ return -ENOMEM;
+ }
+
+ set_bit(vid, vid_map);
+ rcu_assign_pointer(p->vlan_map, vid_map);
+ synchronize_net();
+ } else {
+ /* Map is already allocated */
+ set_bit(vid, rcu_dereference_rtnl(p->vlan_map));
+ }
+
+ return ret;
+}
+
+
+/* Called with RTNL */
+int br_del_port_vlan(struct net_bridge_port *p, unsigned short vlan)
+{
+ unsigned long first_bit;
+ unsigned long next_bit;
+ __u16 vid = br_vid(vlan);
+ unsigned long tbl_len = BITS_TO_LONGS(br_vid(VLAN_N_VID));
+
+ if (!p->vlan_map) {
+ return -EINVAL;
+ }
+
+ if (!test_bit(vlan, p->vlan_map)) {
+ return -EINVAL;
+ }
+
+ /* Check to see if any other vlans are in this table. If this
+ * is the last vlan, delete the whole table. If this is not the
+ * last vlan, just clear the bit.
+ */
+ first_bit = find_first_bit(p->vlan_map, tbl_len);
+ next_bit = find_next_bit(p->vlan_map, tbl_len, (tbl_len - vid));
+
+ if (first_bit != vid || next_bit < tbl_len) {
+ /* There are other vlans still configured. We can simply
+ * clear our bit and be safe.
+ */
+ clear_bit(vid, rcu_dereference_rtnl(p->vlan_map));
+ } else {
+ unsigned long *map = NULL;
+
+ /* This is the last vlan we are removing. Replace the
+ * map with a NULL pointer and free the old map
+ */
+ map = rcu_dereference(p->vlan_map);
+
+ rcu_assign_pointer(p->vlan_map, NULL);
+ synchronize_net();
+ kfree(map);
+ }
+
+ return 0;
+}
+
void __net_exit br_net_exit(struct net *net)
{
struct net_device *dev;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index fe41260..8a97f93 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -16,6 +16,7 @@
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/sock.h>
+#include <linux/if_vlan.h>
#include "br_private.h"
#include "br_private_stp.h"
@@ -140,6 +141,71 @@ skip:
return skb->len;
}
+static int br_validate_vlan_info(struct nlattr *attr)
+{
+ struct nlattr *vinfo;
+ int rem;
+
+ nla_for_each_nested(vinfo, attr, rem) {
+ int type = nla_type(vinfo);
+ unsigned short vid = nla_get_u16(vinfo);
+
+ if (vid > VLAN_N_VID)
+ return -EINVAL;
+
+ if (type < IFLA_BR_VLAN_ADD || type > IFLA_BR_VLAN_DEL)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+const struct nla_policy ifla_br_policy[IFLA_BR_MAX + 1] = {
+ [IFLA_BR_VLAN_INFO] = { .type = NLA_NESTED },
+};
+
+static int br_afspec(struct net_bridge_port *p, struct nlattr *af_spec)
+{
+ struct nlattr *vinfo;
+ struct nlattr *tb[IFLA_BR_MAX+1];
+ int err;
+ int rem;
+
+ if (nla_type(af_spec) != AF_BRIDGE)
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, IFLA_BR_MAX, af_spec, ifla_br_policy);
+ if (err)
+ return err;
+
+ if (tb[IFLA_BR_VLAN_INFO]) {
+ err = br_validate_vlan_info(tb[IFLA_BR_VLAN_INFO]);
+ if (err)
+ return err;
+
+ nla_for_each_nested(vinfo, tb[IFLA_BR_VLAN_INFO], rem) {
+ int type = nla_type(vinfo);
+ unsigned short vid = nla_get_u16(vinfo);
+
+ switch (type) {
+ case IFLA_BR_VLAN_ADD:
+ br_set_port_vlan(p, vid);
+ break;
+ case IFLA_BR_VLAN_DEL:
+ br_del_port_vlan(p, vid);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+const struct nla_policy ifla_policy[IFLA_MAX+1] = {
+ [IFLA_PROTINFO] = { .type = NLA_U8 },
+ [IFLA_AF_SPEC] = { .type = NLA_NESTED },
+};
+
/*
* Change state of port (ie from forwarding to blocking etc)
* Used by spanning tree in user space.
@@ -148,26 +214,23 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
- struct nlattr *protinfo;
+ struct nlattr *tb[IFLA_MAX+1];
struct net_device *dev;
struct net_bridge_port *p;
+ int err = 0;
u8 new_state;
if (nlmsg_len(nlh) < sizeof(*ifm))
return -EINVAL;
+ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
+ if (err)
+ return err;
+
ifm = nlmsg_data(nlh);
if (ifm->ifi_family != AF_BRIDGE)
return -EPFNOSUPPORT;
- protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
- if (!protinfo || nla_len(protinfo) < sizeof(u8))
- return -EINVAL;
-
- new_state = nla_get_u8(protinfo);
- if (new_state > BR_STATE_BLOCKING)
- return -EINVAL;
-
dev = __dev_get_by_index(net, ifm->ifi_index);
if (!dev)
return -ENODEV;
@@ -176,23 +239,35 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (!p)
return -EINVAL;
- /* if kernel STP is running, don't allow changes */
- if (p->br->stp_enabled == BR_KERNEL_STP)
- return -EBUSY;
+ if (tb[IFLA_PROTINFO]) {
+ new_state = nla_get_u8(tb[IFLA_PROTINFO]);
+ if (new_state > BR_STATE_BLOCKING)
+ return -EINVAL;
- if (!netif_running(dev) ||
- (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
- return -ENETDOWN;
+ /* if kernel STP is running, don't allow changes */
+ if (p->br->stp_enabled == BR_KERNEL_STP)
+ return -EBUSY;
- p->state = new_state;
- br_log_state(p);
+ if (!netif_running(dev) ||
+ (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
+ return -ENETDOWN;
- spin_lock_bh(&p->br->lock);
- br_port_state_selection(p->br);
- spin_unlock_bh(&p->br->lock);
+ p->state = new_state;
+ br_log_state(p);
- br_ifinfo_notify(RTM_NEWLINK, p);
+ spin_lock_bh(&p->br->lock);
+ br_port_state_selection(p->br);
+ spin_unlock_bh(&p->br->lock);
+ }
+
+ if (tb[IFLA_AF_SPEC]) {
+ err = br_afspec(p, tb[IFLA_AF_SPEC]);
+ if (err)
+ return err;
+ }
+
+ br_ifinfo_notify(RTM_NEWLINK, p);
return 0;
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 166dcf4..8eb3ffc 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -417,6 +417,8 @@ extern int br_del_if(struct net_bridge *br,
extern int br_min_mtu(const struct net_bridge *br);
extern netdev_features_t br_features_recompute(struct net_bridge *br,
netdev_features_t features);
+extern int br_set_port_vlan(struct net_bridge_port *p, unsigned short vid);
+extern int br_del_port_vlan(struct net_bridge_port *p, unsigned short vid);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
` (3 preceding siblings ...)
2012-09-19 12:42 ` [RFC PATCHv2 bridge 4/7] bridge: Add netlink interface to configure vlans on bridge ports Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-19 15:20 ` John Fastabend
2012-09-19 12:42 ` [RFC PATCHv2 bridge 6/7] bridge: Add sysfs interface to display VLANS Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port Vlad Yasevich
6 siblings, 1 reply; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
---
include/linux/neighbour.h | 2 +-
net/bridge/br_fdb.c | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
index 275e5d6..044df8f 100644
--- a/include/linux/neighbour.h
+++ b/include/linux/neighbour.h
@@ -7,7 +7,7 @@
struct ndmsg {
__u8 ndm_family;
__u8 ndm_pad1;
- __u16 ndm_pad2;
+ __u16 ndm_vlan;
__s32 ndm_ifindex;
__u16 ndm_state;
__u8 ndm_flags;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index e17f9f2..3c21a3d 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -493,7 +493,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
ndm = nlmsg_data(nlh);
ndm->ndm_family = AF_BRIDGE;
ndm->ndm_pad1 = 0;
- ndm->ndm_pad2 = 0;
+ ndm->ndm_vlan = fdb->vlan_id;
ndm->ndm_flags = 0;
ndm->ndm_type = 0;
ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
@@ -640,25 +640,25 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
if (ndm->ndm_flags & NTF_USE) {
rcu_read_lock();
- br_fdb_update(p->br, p, addr, 0);
+ br_fdb_update(p->br, p, addr, ndm->ndm_vlan);
rcu_read_unlock();
} else {
spin_lock_bh(&p->br->hash_lock);
err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags,
- 0);
+ ndm->ndm_vlan);
spin_unlock_bh(&p->br->hash_lock);
}
return err;
}
-static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr)
+static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr, u16 vlan)
{
struct net_bridge *br = p->br;
struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
struct net_bridge_fdb_entry *fdb;
- fdb = fdb_find(head, addr, 0);
+ fdb = fdb_find(head, addr, vlan);
if (!fdb)
return -ENOENT;
@@ -681,7 +681,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
}
spin_lock_bh(&p->br->hash_lock);
- err = fdb_delete_by_addr(p, addr);
+ err = fdb_delete_by_addr(p, addr, ndm->ndm_vlan);
spin_unlock_bh(&p->br->hash_lock);
return err;
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 6/7] bridge: Add sysfs interface to display VLANS
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
` (4 preceding siblings ...)
2012-09-19 12:42 ` [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port Vlad Yasevich
6 siblings, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
Add a binary sysfs file that will dump out vlans currently configured on the
port.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
include/linux/if_bridge.h | 1 +
net/bridge/br_sysfs_if.c | 70 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 71 insertions(+), 0 deletions(-)
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 8476d6f..cc85739 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -20,6 +20,7 @@
#define SYSFS_BRIDGE_PORT_SUBDIR "brif"
#define SYSFS_BRIDGE_PORT_ATTR "brport"
#define SYSFS_BRIDGE_PORT_LINK "bridge"
+#define SYSFS_BRIDGE_PORT_VLANS "vlans"
#define BRCTL_VERSION 1
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 13b36bd..b07a743 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -234,6 +234,71 @@ const struct sysfs_ops brport_sysfs_ops = {
};
/*
+ * Export the vlan table for a given port as a binary file.
+ * The entire bitmap is exported.
+ *
+ * Returns the number of bytes read.
+ */
+static ssize_t brport_vlans_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct net_bridge_port *p = to_brport(kobj);
+ unsigned long *map = rcu_dereference(p->vlan_map);
+ ssize_t map_len;
+
+ /* Just write the map back to userspace. brctl will interpret
+ * it correctly.
+ */
+ map_len = BITS_TO_LONGS(br_vid(VLAN_N_VID));
+ memcpy(buf, map, map_len);
+ return map_len;
+}
+
+/* Set a vlan id specified in @buf into the vlan map of the port. The vlan id
+ * is specified as an unsinged short.
+ */
+static ssize_t brport_vlans_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct net_bridge_port *p = to_brport(kobj);
+ unsigned short val;
+ int rc = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (count < sizeof(unsigned short))
+ return -EINVAL;
+
+ val = *(unsigned short *)buf;
+
+ if (val > VLAN_N_VID)
+ return -EINVAL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ if (p->dev && p->br) {
+ rc = br_set_port_vlan(p, val);
+
+ if (rc == 0)
+ rc = count;
+ }
+
+ rtnl_unlock();
+ return rc;
+}
+
+static struct bin_attribute port_vlans = {
+ .attr = { .name = SYSFS_BRIDGE_PORT_VLANS,
+ .mode = S_IRUGO | S_IWUSR, },
+ .read = brport_vlans_read,
+ .write = brport_vlans_write,
+};
+
+/*
* Add sysfs entries to ethernet device added to a bridge.
* Creates a brport subdirectory with bridge attributes.
* Puts symlink in bridge's brif subdirectory
@@ -255,6 +320,11 @@ int br_sysfs_addif(struct net_bridge_port *p)
return err;
}
+ err = sysfs_create_bin_file(&p->kobj, &port_vlans);
+ if (err) {
+ return err;
+ }
+
strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
}
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
` (5 preceding siblings ...)
2012-09-19 12:42 ` [RFC PATCHv2 bridge 6/7] bridge: Add sysfs interface to display VLANS Vlad Yasevich
@ 2012-09-19 12:42 ` Vlad Yasevich
2012-09-22 17:15 ` Ben Hutchings
6 siblings, 1 reply; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 12:42 UTC (permalink / raw)
To: netdev; +Cc: shemminger, Vlad Yasevich
Using the RTM_GETLINK dump the vlan map of a given bridge port.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
include/linux/if_link.h | 1 +
net/bridge/br_netlink.c | 73 +++++++++++++++++++++++++++++++++++++++++++---
net/bridge/br_private.h | 2 +
3 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 38dbcff..6953233 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -416,6 +416,7 @@ enum {
IFLA_BR_VLAN_UNSPEC,
IFLA_BR_VLAN_ADD,
IFLA_BR_VLAN_DEL,
+ IFLA_BR_VLAN_MAP,
__IFLA_BR_VLAN_MAX,
};
#define IFLA_BR_VLAN_MAX (__IFLA_BR_VLAN_MAX - 1)
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 8a97f93..72fec1b 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -69,9 +69,35 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
(dev->ifindex != dev->iflink &&
nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
- (event == RTM_NEWLINK &&
+ ((event == RTM_NEWLINK || event == RTM_GETLINK) &&
nla_put_u8(skb, IFLA_PROTINFO, port->state)))
goto nla_put_failure;
+
+ if (event == RTM_GETLINK) {
+ unsigned long *map = rcu_dereference(port->vlan_map);
+ struct nlattr *af;
+ struct nlattr *vidinfo;
+
+ if (!map)
+ goto done;
+
+ af = nla_nest_start(skb, IFLA_AF_SPEC);
+ if (!af)
+ goto nla_put_failure;
+
+ vidinfo = nla_nest_start(skb, IFLA_BR_VLAN_INFO);
+ if (!vidinfo)
+ goto nla_put_failure;
+
+ if (nla_put(skb, IFLA_BR_VLAN_MAP,
+ BITS_TO_LONGS(br_vid(VLAN_N_VID)), map))
+ goto nla_put_failure;
+
+ nla_nest_end(skb, vidinfo);
+ nla_nest_end(skb, af);
+ }
+
+done:
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -129,7 +155,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
if (br_fill_ifinfo(skb, port,
NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, RTM_NEWLINK,
+ cb->nlh->nlmsg_seq, RTM_GETLINK,
NLM_F_MULTI) < 0)
break;
skip:
@@ -283,6 +309,36 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
return 0;
}
+static size_t br_get_link_af_size(const struct net_device *dev)
+{
+ struct net_bridge_port *p;
+ unsigned long *map;
+
+ rcu_read_lock();
+ p = br_port_get_rcu(dev);
+ if (!p)
+ goto err;
+
+ map = rcu_dereference(p->vlan_map);
+ if (!map)
+ goto err;
+
+ rcu_read_unlock();
+
+ /* Account for the full bitmap length. We are going to export the
+ * whole bitmap.
+ */
+ return nla_total_size(BITS_TO_LONGS(br_vid(VLAN_N_VID)));
+err:
+ rcu_read_unlock();
+ return 0;
+}
+
+struct rtnl_af_ops br_af_ops = {
+ .family = AF_BRIDGE,
+ .get_link_af_size = br_get_link_af_size,
+};
+
struct rtnl_link_ops br_link_ops __read_mostly = {
.kind = "bridge",
.priv_size = sizeof(struct net_bridge),
@@ -299,19 +355,25 @@ int __init br_netlink_init(void)
if (err < 0)
goto err1;
+ err = rtnl_af_register(&br_af_ops);
+ if (err < 0)
+ goto err2;
+
err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL,
br_dump_ifinfo, NULL);
if (err)
- goto err2;
+ goto err3;
err = __rtnl_register(PF_BRIDGE, RTM_SETLINK,
br_rtm_setlink, NULL, NULL);
if (err)
- goto err3;
+ goto err4;
return 0;
-err3:
+err4:
rtnl_unregister_all(PF_BRIDGE);
+err3:
+ rtnl_af_unregister(&br_af_ops);
err2:
rtnl_link_unregister(&br_link_ops);
err1:
@@ -320,6 +382,7 @@ err1:
void __exit br_netlink_fini(void)
{
+ rtnl_af_unregister(&br_af_ops);
rtnl_link_unregister(&br_link_ops);
rtnl_unregister_all(PF_BRIDGE);
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8eb3ffc..0575edb 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -419,6 +419,8 @@ extern netdev_features_t br_features_recompute(struct net_bridge *br,
netdev_features_t features);
extern int br_set_port_vlan(struct net_bridge_port *p, unsigned short vid);
extern int br_del_port_vlan(struct net_bridge_port *p, unsigned short vid);
+extern size_t br_port_fill_vlans(struct net_bridge_port *p, char *buf,
+ unsigned long max, unsigned long skip);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
--
1.7.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors
2012-09-19 12:42 ` [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors Vlad Yasevich
@ 2012-09-19 15:20 ` John Fastabend
2012-09-19 15:24 ` Vlad Yasevich
0 siblings, 1 reply; 20+ messages in thread
From: John Fastabend @ 2012-09-19 15:20 UTC (permalink / raw)
To: Vlad Yasevich; +Cc: netdev, shemminger
On 9/19/2012 5:42 AM, Vlad Yasevich wrote:
> ---
> include/linux/neighbour.h | 2 +-
> net/bridge/br_fdb.c | 12 ++++++------
> 2 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
> index 275e5d6..044df8f 100644
> --- a/include/linux/neighbour.h
> +++ b/include/linux/neighbour.h
> @@ -7,7 +7,7 @@
> struct ndmsg {
> __u8 ndm_family;
> __u8 ndm_pad1;
> - __u16 ndm_pad2;
> + __u16 ndm_vlan;
But ndm_pad2 is also used in neighbour.c so you'll need to fix that up
as well.
net/core/neighbour.c: In function âneigh_fill_infoâ:
net/core/neighbour.c:2152: error: âstruct ndmsgâ has no member named
ândm_pad2â
net/core/neighbour.c: In function âpneigh_fill_infoâ:
net/core/neighbour.c:2203: error: âstruct ndmsgâ has no member named
ândm_pad2â
make[2]: *** [net/core/neighbour.o] Error 1
make[1]: *** [net/core] Error 2
make[1]: *** Waiting for unfinished jobs....
make: *** [net] Error 2
make: *** Waiting for unfinished jobs....
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors
2012-09-19 15:20 ` John Fastabend
@ 2012-09-19 15:24 ` Vlad Yasevich
0 siblings, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-19 15:24 UTC (permalink / raw)
To: John Fastabend; +Cc: netdev, shemminger
On 09/19/2012 11:20 AM, John Fastabend wrote:
> On 9/19/2012 5:42 AM, Vlad Yasevich wrote:
>> ---
>> include/linux/neighbour.h | 2 +-
>> net/bridge/br_fdb.c | 12 ++++++------
>> 2 files changed, 7 insertions(+), 7 deletions(-)
>>
>> diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
>> index 275e5d6..044df8f 100644
>> --- a/include/linux/neighbour.h
>> +++ b/include/linux/neighbour.h
>> @@ -7,7 +7,7 @@
>> struct ndmsg {
>> __u8 ndm_family;
>> __u8 ndm_pad1;
>> - __u16 ndm_pad2;
>> + __u16 ndm_vlan;
>
> But ndm_pad2 is also used in neighbour.c so you'll need to fix that up
> as well.
>
> net/core/neighbour.c: In function âneigh_fill_infoâ:
> net/core/neighbour.c:2152: error: âstruct ndmsgâ has no member named
> ândm_pad2â
> net/core/neighbour.c: In function âpneigh_fill_infoâ:
> net/core/neighbour.c:2203: error: âstruct ndmsgâ has no member named
> ândm_pad2â
> make[2]: *** [net/core/neighbour.o] Error 1
> make[1]: *** [net/core] Error 2
> make[1]: *** Waiting for unfinished jobs....
> make: *** [net] Error 2
> make: *** Waiting for unfinished jobs....
dough!!! patches from wrong branch. sorry about that.
-vlad
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-19 12:42 ` [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port Vlad Yasevich
@ 2012-09-22 17:15 ` Ben Hutchings
2012-09-22 17:27 ` David Miller
2012-09-24 13:48 ` Vlad Yasevich
0 siblings, 2 replies; 20+ messages in thread
From: Ben Hutchings @ 2012-09-22 17:15 UTC (permalink / raw)
To: Vlad Yasevich; +Cc: netdev, shemminger
On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
> Using the RTM_GETLINK dump the vlan map of a given bridge port.
[...]
This enlarges the RTM_GETLINK response quite a bit. I think perhaps
this should be optional, like IFLA_VFINFO_LIST is now.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries
2012-09-19 12:42 ` [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries Vlad Yasevich
@ 2012-09-22 17:17 ` Ben Hutchings
2012-09-24 13:56 ` Vlad Yasevich
0 siblings, 1 reply; 20+ messages in thread
From: Ben Hutchings @ 2012-09-22 17:17 UTC (permalink / raw)
To: Vlad Yasevich; +Cc: netdev, shemminger
On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
> This patch adds vlan to unicast fdb entries that are created for
> learned addresses (not the manually configured ones). It adds
> vlan id into the hash mix and uses vlan as an addditional parameter
> for an entry match.
[...]
> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
> index 9ce430b..e17f9f2 100644
> --- a/net/bridge/br_fdb.c
> +++ b/net/bridge/br_fdb.c
[...]
> @@ -67,11 +68,12 @@ static inline int has_expired(const struct net_bridge *br,
> time_before_eq(fdb->updated + hold_time(br), jiffies);
> }
>
> -static inline int br_mac_hash(const unsigned char *mac)
> +static inline int br_mac_hash(const unsigned char *mac, __u16 vlan_tci)
> {
> - /* use 1 byte of OUI cnd 3 bytes of NIC */
> + /* use 1 byte of OUI and 3 bytes of NIC */
> u32 key = get_unaligned((u32 *)(mac + 2));
> - return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
> + return jhash_2words(key, (vlan_tci & VLAN_VID_MASK),
> + fdb_salt) & (BR_HASH_SIZE - 1);
> }
Why do you add a vlan_tci parameter to so many functions, which they
then mask to get the VID? Would it not make more sense to pass only
VIDs around?
[...]
> @@ -628,11 +640,12 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
>
> if (ndm->ndm_flags & NTF_USE) {
> rcu_read_lock();
> - br_fdb_update(p->br, p, addr);
> + br_fdb_update(p->br, p, addr, 0);
> rcu_read_unlock();
> } else {
> spin_lock_bh(&p->br->hash_lock);
> - err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags);
> + err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags,
> + 0);
> spin_unlock_bh(&p->br->hash_lock);
> }
>
> @@ -642,10 +655,10 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
> static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr)
> {
> struct net_bridge *br = p->br;
> - struct hlist_head *head = &br->hash[br_mac_hash(addr)];
> + struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
> struct net_bridge_fdb_entry *fdb;
>
> - fdb = fdb_find(head, addr);
> + fdb = fdb_find(head, addr, 0);
> if (!fdb)
> return -ENOENT;
>
So current tools will only be able to manipulate forwarding entries for
untagged frames? Surely they should still insert and delete forwarding
entries that affect all VLANs, and new tools will be able to restrict
forwarding entries to specific VLANs?
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 4/7] bridge: Add netlink interface to configure vlans on bridge ports
2012-09-19 12:42 ` [RFC PATCHv2 bridge 4/7] bridge: Add netlink interface to configure vlans on bridge ports Vlad Yasevich
@ 2012-09-22 17:17 ` Ben Hutchings
0 siblings, 0 replies; 20+ messages in thread
From: Ben Hutchings @ 2012-09-22 17:17 UTC (permalink / raw)
To: Vlad Yasevich; +Cc: netdev, shemminger
On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
> Add a netlink interface to add and remove vlan configuration on bridge port.
> The interface uses the RTM_SETLINK message and encodes the vlan
> configuration inside the IFLA_AF_SPEC. It is possble to include multiple
> vlans to either add or remove in a single message.
[...]
> --- a/net/bridge/br_if.c
> +++ b/net/bridge/br_if.c
> @@ -23,6 +23,7 @@
> #include <linux/if_ether.h>
> #include <linux/slab.h>
> #include <net/sock.h>
> +#include <linux/if_vlan.h>
>
> #include "br_private.h"
>
> @@ -445,6 +446,79 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
> return 0;
> }
>
> +/* Called with RTNL */
> +int br_set_port_vlan(struct net_bridge_port *p, unsigned short vlan)
> +{
> + unsigned long table_size = BITS_TO_LONGS(br_vid(VLAN_N_VID));
> + unsigned long *vid_map = NULL;
> + __u16 vid = br_vid(vlan);
> + int ret = 0;
> +
> + /* The vlan map is indexed by vid+1. This way we can store
> + * vid 0 (untagged) into the map as well.
> + */
So bit 1 is for untagged, bits 2-4096 are for tagged, and bit 0 is
for...?
> + if (!p->vlan_map) {
> + vid_map = kzalloc(table_size, GFP_KERNEL);
> + if (!vid_map) {
> + return -ENOMEM;
> + }
> +
> + set_bit(vid, vid_map);
> + rcu_assign_pointer(p->vlan_map, vid_map);
> + synchronize_net();
> + } else {
> + /* Map is already allocated */
> + set_bit(vid, rcu_dereference_rtnl(p->vlan_map));
> + }
> +
> + return ret;
> +}
> +
> +
> +/* Called with RTNL */
> +int br_del_port_vlan(struct net_bridge_port *p, unsigned short vlan)
> +{
> + unsigned long first_bit;
> + unsigned long next_bit;
> + __u16 vid = br_vid(vlan);
Which is the bit number, not really the VID - a little confusing...
> + unsigned long tbl_len = BITS_TO_LONGS(br_vid(VLAN_N_VID));
> +
> + if (!p->vlan_map) {
> + return -EINVAL;
> + }
> +
> + if (!test_bit(vlan, p->vlan_map)) {
> + return -EINVAL;
> + }
> +
> + /* Check to see if any other vlans are in this table. If this
> + * is the last vlan, delete the whole table. If this is not the
> + * last vlan, just clear the bit.
> + */
> + first_bit = find_first_bit(p->vlan_map, tbl_len);
> + next_bit = find_next_bit(p->vlan_map, tbl_len, (tbl_len - vid));
[...]
Last parameter to find_next_bit is the starting offset, which should
presumably be vid + 1.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-22 17:15 ` Ben Hutchings
@ 2012-09-22 17:27 ` David Miller
2012-09-22 20:05 ` Stephen Hemminger
2012-09-24 13:48 ` Vlad Yasevich
1 sibling, 1 reply; 20+ messages in thread
From: David Miller @ 2012-09-22 17:27 UTC (permalink / raw)
To: bhutchings; +Cc: vyasevic, netdev, shemminger
From: Ben Hutchings <bhutchings@solarflare.com>
Date: Sat, 22 Sep 2012 18:15:32 +0100
> On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
>> Using the RTM_GETLINK dump the vlan map of a given bridge port.
> [...]
>
> This enlarges the RTM_GETLINK response quite a bit. I think perhaps
> this should be optional, like IFLA_VFINFO_LIST is now.
Completely agreed.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-22 17:27 ` David Miller
@ 2012-09-22 20:05 ` Stephen Hemminger
2012-09-24 13:49 ` Vlad Yasevich
0 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2012-09-22 20:05 UTC (permalink / raw)
To: David Miller; +Cc: bhutchings, vyasevic, netdev
On Sat, 22 Sep 2012 13:27:47 -0400 (EDT)
David Miller <davem@davemloft.net> wrote:
> From: Ben Hutchings <bhutchings@solarflare.com>
> Date: Sat, 22 Sep 2012 18:15:32 +0100
>
> > On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
> >> Using the RTM_GETLINK dump the vlan map of a given bridge port.
> > [...]
> >
> > This enlarges the RTM_GETLINK response quite a bit. I think perhaps
> > this should be optional, like IFLA_VFINFO_LIST is now.
>
> Completely agreed.
Since most users won't use it, it should be not necessary to include
it if the map is blank.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-22 17:15 ` Ben Hutchings
2012-09-22 17:27 ` David Miller
@ 2012-09-24 13:48 ` Vlad Yasevich
1 sibling, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-24 13:48 UTC (permalink / raw)
To: Ben Hutchings; +Cc: netdev, shemminger
On 09/22/2012 01:15 PM, Ben Hutchings wrote:
> On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
>> Using the RTM_GETLINK dump the vlan map of a given bridge port.
> [...]
>
> This enlarges the RTM_GETLINK response quite a bit. I think perhaps
> this should be optional, like IFLA_VFINFO_LIST is now.
>
> Ben.
>
Only for AF_BRIDGE and only if VLANs are set. I guess I could add
a filter option similar to VFINFO as well, if you think that's necessary.
-vlad
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-22 20:05 ` Stephen Hemminger
@ 2012-09-24 13:49 ` Vlad Yasevich
2012-09-24 18:39 ` Ben Hutchings
0 siblings, 1 reply; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-24 13:49 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, bhutchings, netdev
On 09/22/2012 04:05 PM, Stephen Hemminger wrote:
> On Sat, 22 Sep 2012 13:27:47 -0400 (EDT)
> David Miller <davem@davemloft.net> wrote:
>
>> From: Ben Hutchings <bhutchings@solarflare.com>
>> Date: Sat, 22 Sep 2012 18:15:32 +0100
>>
>>> On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
>>>> Using the RTM_GETLINK dump the vlan map of a given bridge port.
>>> [...]
>>>
>>> This enlarges the RTM_GETLINK response quite a bit. I think perhaps
>>> this should be optional, like IFLA_VFINFO_LIST is now.
>>
>> Completely agreed.
>
> Since most users won't use it, it should be not necessary to include
> it if the map is blank.
>
Response is included only for AF_BRIDGE calls (proably used by STP
implementation) and only when vlan filtering is configured.
I do see the point though and can add a filter for this.
-vlad
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries
2012-09-22 17:17 ` Ben Hutchings
@ 2012-09-24 13:56 ` Vlad Yasevich
0 siblings, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-24 13:56 UTC (permalink / raw)
To: Ben Hutchings; +Cc: netdev, shemminger
On 09/22/2012 01:17 PM, Ben Hutchings wrote:
> On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
>> This patch adds vlan to unicast fdb entries that are created for
>> learned addresses (not the manually configured ones). It adds
>> vlan id into the hash mix and uses vlan as an addditional parameter
>> for an entry match.
> [...]
>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>> index 9ce430b..e17f9f2 100644
>> --- a/net/bridge/br_fdb.c
>> +++ b/net/bridge/br_fdb.c
> [...]
>> @@ -67,11 +68,12 @@ static inline int has_expired(const struct net_bridge *br,
>> time_before_eq(fdb->updated + hold_time(br), jiffies);
>> }
>>
>> -static inline int br_mac_hash(const unsigned char *mac)
>> +static inline int br_mac_hash(const unsigned char *mac, __u16 vlan_tci)
>> {
>> - /* use 1 byte of OUI cnd 3 bytes of NIC */
>> + /* use 1 byte of OUI and 3 bytes of NIC */
>> u32 key = get_unaligned((u32 *)(mac + 2));
>> - return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
>> + return jhash_2words(key, (vlan_tci & VLAN_VID_MASK),
>> + fdb_salt) & (BR_HASH_SIZE - 1);
>> }
>
> Why do you add a vlan_tci parameter to so many functions, which they
> then mask to get the VID? Would it not make more sense to pass only
> VIDs around?
Its either do it in the few spots that use the value or doing in a lot
of spots that call the functions. I had it the other way and the
masking was in even more places as a result.
>
> [...]
>> @@ -628,11 +640,12 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
>>
>> if (ndm->ndm_flags & NTF_USE) {
>> rcu_read_lock();
>> - br_fdb_update(p->br, p, addr);
>> + br_fdb_update(p->br, p, addr, 0);
>> rcu_read_unlock();
>> } else {
>> spin_lock_bh(&p->br->hash_lock);
>> - err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags);
>> + err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags,
>> + 0);
>> spin_unlock_bh(&p->br->hash_lock);
>> }
>>
>> @@ -642,10 +655,10 @@ int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
>> static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr)
>> {
>> struct net_bridge *br = p->br;
>> - struct hlist_head *head = &br->hash[br_mac_hash(addr)];
>> + struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
>> struct net_bridge_fdb_entry *fdb;
>>
>> - fdb = fdb_find(head, addr);
>> + fdb = fdb_find(head, addr, 0);
>> if (!fdb)
>> return -ENOENT;
>>
>
> So current tools will only be able to manipulate forwarding entries for
> untagged frames? Surely they should still insert and delete forwarding
> entries that affect all VLANs, and new tools will be able to restrict
> forwarding entries to specific VLANs?
>
I think that's patch5. It allows you to add an fdb to specific vlan.
I am not sure about all though, but that's a thought as well. What
happens though if something like this happens:
1) Admin adds vlans on the port.
2) Admin adds fdb for _all_ vlans on the port.
3) new vlan needs to be added.
Do we now have to look at all fdbs for that port and add them for a new
vlan?
I am making it explicit, so if the admin whats to add an fdb for a
specific vlan, he has to do that separately (from patch which I need to
resend, got really busy with something else).
-vlad
> Ben.
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-24 13:49 ` Vlad Yasevich
@ 2012-09-24 18:39 ` Ben Hutchings
2012-09-24 20:29 ` Vlad Yasevich
0 siblings, 1 reply; 20+ messages in thread
From: Ben Hutchings @ 2012-09-24 18:39 UTC (permalink / raw)
To: vyasevic; +Cc: Stephen Hemminger, David Miller, netdev
On Mon, 2012-09-24 at 09:49 -0400, Vlad Yasevich wrote:
> On 09/22/2012 04:05 PM, Stephen Hemminger wrote:
> > On Sat, 22 Sep 2012 13:27:47 -0400 (EDT)
> > David Miller <davem@davemloft.net> wrote:
> >
> >> From: Ben Hutchings <bhutchings@solarflare.com>
> >> Date: Sat, 22 Sep 2012 18:15:32 +0100
> >>
> >>> On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
> >>>> Using the RTM_GETLINK dump the vlan map of a given bridge port.
> >>> [...]
> >>>
> >>> This enlarges the RTM_GETLINK response quite a bit. I think perhaps
> >>> this should be optional, like IFLA_VFINFO_LIST is now.
> >>
> >> Completely agreed.
> >
> > Since most users won't use it, it should be not necessary to include
> > it if the map is blank.
> >
>
> Response is included only for AF_BRIDGE calls (proably used by STP
> implementation) and only when vlan filtering is configured.
>
> I do see the point though and can add a filter for this.
I thought the per-AF stuff was included by default (or at least what
most clients ask for). If not then this is probably fine.
IFLA_VFINFO_LIST was causing glibc's queries to fail and that must be
avoided.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port
2012-09-24 18:39 ` Ben Hutchings
@ 2012-09-24 20:29 ` Vlad Yasevich
0 siblings, 0 replies; 20+ messages in thread
From: Vlad Yasevich @ 2012-09-24 20:29 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Stephen Hemminger, David Miller, netdev
On 09/24/2012 02:39 PM, Ben Hutchings wrote:
> On Mon, 2012-09-24 at 09:49 -0400, Vlad Yasevich wrote:
>> On 09/22/2012 04:05 PM, Stephen Hemminger wrote:
>>> On Sat, 22 Sep 2012 13:27:47 -0400 (EDT)
>>> David Miller <davem@davemloft.net> wrote:
>>>
>>>> From: Ben Hutchings <bhutchings@solarflare.com>
>>>> Date: Sat, 22 Sep 2012 18:15:32 +0100
>>>>
>>>>> On Wed, 2012-09-19 at 08:42 -0400, Vlad Yasevich wrote:
>>>>>> Using the RTM_GETLINK dump the vlan map of a given bridge port.
>>>>> [...]
>>>>>
>>>>> This enlarges the RTM_GETLINK response quite a bit. I think perhaps
>>>>> this should be optional, like IFLA_VFINFO_LIST is now.
>>>>
>>>> Completely agreed.
>>>
>>> Since most users won't use it, it should be not necessary to include
>>> it if the map is blank.
>>>
>>
>> Response is included only for AF_BRIDGE calls (proably used by STP
>> implementation) and only when vlan filtering is configured.
>>
>> I do see the point though and can add a filter for this.
>
> I thought the per-AF stuff was included by default (or at least what
> most clients ask for). If not then this is probably fine.
> IFLA_VFINFO_LIST was causing glibc's queries to fail and that must be
> avoided.
>
> Ben.
>
Not just that. This is a PF_BRIDGE family request. Note the
err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL,
br_dump_ifinfo, NULL);
in br_netlink_init.
-vlad
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2012-09-24 20:29 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-19 12:42 [RFC PATCHv2 bridge 0/7] Add basic VLAN support to bridges Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 1/7] bridge: Add vlan check to forwarding path Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 2/7] bridge: Add vlan to unicast fdb entries Vlad Yasevich
2012-09-22 17:17 ` Ben Hutchings
2012-09-24 13:56 ` Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 3/7] bridge: Add vlan id to multicast groups Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 4/7] bridge: Add netlink interface to configure vlans on bridge ports Vlad Yasevich
2012-09-22 17:17 ` Ben Hutchings
2012-09-19 12:42 ` [RFC PATCHv2 bridge 5/7] bridge: Add vlan support to static neighbors Vlad Yasevich
2012-09-19 15:20 ` John Fastabend
2012-09-19 15:24 ` Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 6/7] bridge: Add sysfs interface to display VLANS Vlad Yasevich
2012-09-19 12:42 ` [RFC PATCHv2 bridge 7/7] bridge: Add the ability to show dump the vlan map from a bridge port Vlad Yasevich
2012-09-22 17:15 ` Ben Hutchings
2012-09-22 17:27 ` David Miller
2012-09-22 20:05 ` Stephen Hemminger
2012-09-24 13:49 ` Vlad Yasevich
2012-09-24 18:39 ` Ben Hutchings
2012-09-24 20:29 ` Vlad Yasevich
2012-09-24 13:48 ` Vlad Yasevich
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).