* [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink
@ 2012-12-12 8:23 Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries Cong Wang
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Cong Wang @ 2012-12-12 8:23 UTC (permalink / raw)
To: netdev
Cc: Cong Wang, bridge, Herbert Xu, Thomas Graf, Stephen Hemminger,
David S. Miller
From: Cong Wang <amwang@redhat.com>
As Stephen mentioned, we need to monitor the mdb
changes in user-space, so add notifications via netlink too.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
include/uapi/linux/rtnetlink.h | 6 +++
net/bridge/br_mdb.c | 80 ++++++++++++++++++++++++++++++++++++++++
net/bridge/br_multicast.c | 2 +
net/bridge/br_private.h | 2 +
4 files changed, 90 insertions(+), 0 deletions(-)
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 354a1e7..7a5eb19 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -125,6 +125,10 @@ enum {
RTM_GETNETCONF = 82,
#define RTM_GETNETCONF RTM_GETNETCONF
+ RTM_NEWMDB = 84,
+#define RTM_NEWMDB RTM_NEWMDB
+ RTM_DELMDB = 85,
+#define RTM_DELMDB RTM_DELMDB
RTM_GETMDB = 86,
#define RTM_GETMDB RTM_GETMDB
@@ -607,6 +611,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF
RTNLGRP_IPV6_NETCONF,
#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
+ RTNLGRP_MDB,
+#define RTNLGRP_MDB RTNLGRP_MDB
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index ccc43a9..a8cfbf5 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -155,6 +155,86 @@ out:
return skb->len;
}
+static int nlmsg_populate_mdb_fill(struct sk_buff *skb,
+ struct net_device *dev,
+ struct br_mdb_entry *entry, u32 pid,
+ u32 seq, int type, unsigned int flags)
+{
+ struct nlmsghdr *nlh;
+ struct br_port_msg *bpm;
+ struct nlattr *nest, *nest2;
+
+ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ bpm = nlmsg_data(nlh);
+ bpm->family = AF_BRIDGE;
+ bpm->ifindex = dev->ifindex;
+ nest = nla_nest_start(skb, MDBA_MDB);
+ if (nest == NULL)
+ goto cancel;
+ nest2 = nla_nest_start(skb, MDBA_MDB_ENTRY);
+ if (nest2 == NULL)
+ goto end;
+
+ if (nla_put(skb, MDBA_MDB_ENTRY_INFO, sizeof(*entry), entry))
+ goto end;
+
+ nla_nest_end(skb, nest2);
+ nla_nest_end(skb, nest);
+ return nlmsg_end(skb, nlh);
+
+end:
+ nla_nest_end(skb, nest);
+cancel:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static inline size_t rtnl_mdb_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct br_port_msg))
+ + nla_total_size(sizeof(struct br_mdb_entry));
+}
+
+static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
+ int type)
+{
+ struct net *net = dev_net(dev);
+ struct sk_buff *skb;
+ int err = -ENOBUFS;
+
+ skb = nlmsg_new(rtnl_mdb_nlmsg_size(), GFP_ATOMIC);
+ if (!skb)
+ goto errout;
+
+ err = nlmsg_populate_mdb_fill(skb, dev, entry, 0, 0, type, NTF_SELF);
+ if (err < 0) {
+ kfree_skb(skb);
+ goto errout;
+ }
+
+ rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC);
+ return;
+errout:
+ rtnl_set_sk_err(net, RTNLGRP_MDB, err);
+}
+
+void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+ struct br_ip *group, int type)
+{
+ struct br_mdb_entry entry;
+
+ entry.ifindex = port->dev->ifindex;
+ entry.addr.proto = group->proto;
+ entry.addr.u.ip4 = group->u.ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+ entry.addr.u.ip6 = group->u.ip6;
+#endif
+ __br_mdb_notify(dev, &entry, type);
+}
+
void br_mdb_init(void)
{
rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL);
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 847b98a1..d929586 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -681,6 +681,7 @@ static int br_multicast_add_group(struct net_bridge *br,
(unsigned long)p);
rcu_assign_pointer(*pp, p);
+ br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
found:
mod_timer(&p->timer, now + br->multicast_membership_interval);
@@ -1240,6 +1241,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
hlist_del_init(&p->mglist);
del_timer(&p->timer);
call_rcu_bh(&p->rcu, br_multicast_free_pg);
+ br_mdb_notify(br->dev, port, group, RTM_DELMDB);
if (!mp->ports && !mp->mglist &&
netif_running(br->dev))
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f95b766..2807c76 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -435,6 +435,8 @@ extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_querier(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
extern void br_mdb_init(void);
+extern void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+ struct br_ip *group, int type);
static inline bool br_multicast_is_router(struct net_bridge *br)
{
--
1.7.7.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries
2012-12-12 8:23 [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink Cong Wang
@ 2012-12-12 8:23 ` Cong Wang
2012-12-12 18:03 ` David Miller
2012-12-12 8:23 ` [Bridge] [PATCH 1/2] iproute2: implement add/del mdb entry Cong Wang
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Cong Wang @ 2012-12-12 8:23 UTC (permalink / raw)
To: netdev
Cc: Cong Wang, bridge, Herbert Xu, Thomas Graf, Stephen Hemminger,
David S. Miller
From: Cong Wang <amwang@redhat.com>
This patch implents adding/deleting mdb entries via netlink.
Currently all entries are temp, we probably need a flag to distinguish
permanent entries too.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
include/uapi/linux/if_bridge.h | 8 ++
net/bridge/br_mdb.c | 240 ++++++++++++++++++++++++++++++++++++++++
net/bridge/br_multicast.c | 55 +++++-----
net/bridge/br_private.h | 23 ++++
4 files changed, 297 insertions(+), 29 deletions(-)
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 9a0f6ff..afbb18a 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -157,6 +157,7 @@ enum {
#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
struct br_port_msg {
+ __u8 family;
__u32 ifindex;
};
@@ -171,4 +172,11 @@ struct br_mdb_entry {
} addr;
};
+enum {
+ MDBA_SET_ENTRY_UNSPEC,
+ MDBA_SET_ENTRY,
+ __MDBA_SET_ENTRY_MAX,
+};
+#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
+
#endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index a8cfbf5..6f0a2ee 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -4,6 +4,7 @@
#include <linux/netdevice.h>
#include <linux/rculist.h>
#include <linux/skbuff.h>
+#include <linux/if_ether.h>
#include <net/ip.h>
#include <net/netlink.h>
#if IS_ENABLED(CONFIG_IPV6)
@@ -235,7 +236,246 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
__br_mdb_notify(dev, &entry, type);
}
+static bool is_valid_mdb_entry(struct br_mdb_entry *entry)
+{
+ if (entry->ifindex == 0)
+ return false;
+
+ if (entry->addr.proto == htons(ETH_P_IP)) {
+ if (!ipv4_is_multicast(entry->addr.u.ip4))
+ return false;
+ if (ipv4_is_local_multicast(entry->addr.u.ip4))
+ return false;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (entry->addr.proto == htons(ETH_P_IPV6)) {
+ if (!ipv6_is_transient_multicast(&entry->addr.u.ip6))
+ return false;
+#endif
+ } else
+ return false;
+
+ return true;
+}
+
+static int br_mdb_parse(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct net_device **pdev, struct br_mdb_entry **pentry)
+{
+ struct net *net = sock_net(skb->sk);
+ struct br_mdb_entry *entry;
+ struct br_port_msg *bpm;
+ struct nlattr *tb[MDBA_SET_ENTRY_MAX+1];
+ struct net_device *dev;
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ err = nlmsg_parse(nlh, sizeof(*bpm), tb, MDBA_SET_ENTRY, NULL);
+ if (err < 0)
+ return err;
+
+ bpm = nlmsg_data(nlh);
+ if (bpm->ifindex == 0) {
+ pr_info("PF_BRIDGE: br_mdb_parse() with invalid ifindex\n");
+ return -EINVAL;
+ }
+
+ dev = __dev_get_by_index(net, bpm->ifindex);
+ if (dev == NULL) {
+ pr_info("PF_BRIDGE: br_mdb_parse() with unknown ifindex\n");
+ return -ENODEV;
+ }
+
+ if (!(dev->priv_flags & IFF_EBRIDGE)) {
+ pr_info("PF_BRIDGE: br_mdb_parse() with non-bridge\n");
+ return -EOPNOTSUPP;
+ }
+
+ *pdev = dev;
+
+ if (!tb[MDBA_SET_ENTRY] ||
+ nla_len(tb[MDBA_SET_ENTRY]) != sizeof(struct br_mdb_entry)) {
+ pr_info("PF_BRIDGE: br_mdb_parse() with invalid attr\n");
+ return -EINVAL;
+ }
+
+ entry = nla_data(tb[MDBA_SET_ENTRY]);
+ if (!is_valid_mdb_entry(entry)) {
+ pr_info("PF_BRIDGE: br_mdb_parse() with invalid entry\n");
+ return -EINVAL;
+ }
+
+ *pentry = entry;
+ return 0;
+}
+
+static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
+ struct br_ip *group)
+{
+ struct net_bridge_mdb_entry *mp;
+ struct net_bridge_port_group *p;
+ struct net_bridge_port_group __rcu **pp;
+ struct net_bridge_mdb_htable *mdb;
+ int err;
+
+ mdb = mlock_dereference(br->mdb, br);
+ mp = br_mdb_ip_get(mdb, group);
+ if (!mp) {
+ mp = br_multicast_new_group(br, port, group);
+ err = PTR_ERR(mp);
+ if (IS_ERR(mp))
+ return err;
+ }
+
+ for (pp = &mp->ports;
+ (p = mlock_dereference(*pp, br)) != NULL;
+ pp = &p->next) {
+ if (p->port == port)
+ return -EEXIST;
+ if ((unsigned long)p->port < (unsigned long)port)
+ break;
+ }
+
+ p = br_multicast_new_port_group(port, group, *pp);
+ if (unlikely(!p))
+ return -ENOMEM;
+ rcu_assign_pointer(*pp, p);
+
+ br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
+ return 0;
+}
+
+static int __br_mdb_add(struct net *net, struct net_bridge *br,
+ struct br_mdb_entry *entry)
+{
+ struct br_ip ip;
+ struct net_device *dev;
+ struct net_bridge_port *p;
+ int ret;
+
+ if (!netif_running(br->dev) || br->multicast_disabled)
+ return -EINVAL;
+
+ dev = __dev_get_by_index(net, entry->ifindex);
+ if (!dev)
+ return -ENODEV;
+
+ p = br_port_get_rtnl(dev);
+ if (!p || p->br != br || p->state == BR_STATE_DISABLED)
+ return -EINVAL;
+
+ ip.proto = entry->addr.proto;
+ if (ip.proto == htons(ETH_P_IP))
+ ip.u.ip4 = entry->addr.u.ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+ else
+ ip.u.ip6 = entry->addr.u.ip6;
+#endif
+
+ spin_lock_bh(&br->multicast_lock);
+ ret = br_mdb_add_group(br, p, &ip);
+ spin_unlock_bh(&br->multicast_lock);
+ return ret;
+}
+
+static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct net *net = sock_net(skb->sk);
+ struct br_mdb_entry *entry;
+ struct net_device *dev;
+ struct net_bridge *br;
+ int err;
+
+ err = br_mdb_parse(skb, nlh, &dev, &entry);
+ if (err < 0)
+ return err;
+
+ br = netdev_priv(dev);
+
+ err = __br_mdb_add(net, br, entry);
+ if (!err)
+ __br_mdb_notify(dev, entry, RTM_NEWMDB);
+ return err;
+}
+
+static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
+{
+ struct net_bridge_mdb_htable *mdb;
+ struct net_bridge_mdb_entry *mp;
+ struct net_bridge_port_group *p;
+ struct net_bridge_port_group __rcu **pp;
+ struct br_ip ip;
+ int err = -EINVAL;
+
+ if (!netif_running(br->dev) || br->multicast_disabled)
+ return -EINVAL;
+
+ if (timer_pending(&br->multicast_querier_timer))
+ return -EBUSY;
+
+ ip.proto = entry->addr.proto;
+ if (ip.proto == htons(ETH_P_IP))
+ ip.u.ip4 = entry->addr.u.ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+ else
+ ip.u.ip6 = entry->addr.u.ip6;
+#endif
+
+ spin_lock_bh(&br->multicast_lock);
+ mdb = mlock_dereference(br->mdb, br);
+
+ mp = br_mdb_ip_get(mdb, &ip);
+ if (!mp)
+ goto unlock;
+
+ for (pp = &mp->ports;
+ (p = mlock_dereference(*pp, br)) != NULL;
+ pp = &p->next) {
+ if (!p->port || p->port->dev->ifindex != entry->ifindex)
+ continue;
+
+ if (p->port->state == BR_STATE_DISABLED)
+ goto unlock;
+
+ rcu_assign_pointer(*pp, p->next);
+ hlist_del_init(&p->mglist);
+ del_timer(&p->timer);
+ call_rcu_bh(&p->rcu, br_multicast_free_pg);
+ err = 0;
+
+ if (!mp->ports && !mp->mglist &&
+ netif_running(br->dev))
+ mod_timer(&mp->timer, jiffies);
+ break;
+ }
+
+unlock:
+ spin_unlock_bh(&br->multicast_lock);
+ return err;
+}
+
+static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct net_device *dev;
+ struct br_mdb_entry *entry;
+ struct net_bridge *br;
+ int err;
+
+ err = br_mdb_parse(skb, nlh, &dev, &entry);
+ if (err < 0)
+ return err;
+
+ br = netdev_priv(dev);
+
+ err = __br_mdb_del(br, entry);
+ if (!err)
+ __br_mdb_notify(dev, entry, RTM_DELMDB);
+ return err;
+}
+
void br_mdb_init(void)
{
rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL);
+ rtnl_register(PF_BRIDGE, RTM_NEWMDB, br_mdb_add, NULL, NULL);
+ rtnl_register(PF_BRIDGE, RTM_DELMDB, br_mdb_del, NULL, NULL);
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index d929586..977c3ee 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -27,27 +27,14 @@
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
#include <net/mld.h>
-#include <net/addrconf.h>
#include <net/ip6_checksum.h>
#endif
#include "br_private.h"
-#define mlock_dereference(X, br) \
- rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
-
static void br_multicast_start_querier(struct net_bridge *br);
unsigned int br_mdb_rehash_seq;
-#if IS_ENABLED(CONFIG_IPV6)
-static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
-{
- if (ipv6_addr_is_multicast(addr) && IPV6_ADDR_MC_FLAG_TRANSIENT(addr))
- return 1;
- return 0;
-}
-#endif
-
static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
{
if (a->proto != b->proto)
@@ -104,8 +91,8 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(
return NULL;
}
-static struct net_bridge_mdb_entry *br_mdb_ip_get(
- struct net_bridge_mdb_htable *mdb, struct br_ip *dst)
+struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge_mdb_htable *mdb,
+ struct br_ip *dst)
{
if (!mdb)
return NULL;
@@ -208,7 +195,7 @@ static int br_mdb_copy(struct net_bridge_mdb_htable *new,
return maxlen > elasticity ? -EINVAL : 0;
}
-static void br_multicast_free_pg(struct rcu_head *head)
+void br_multicast_free_pg(struct rcu_head *head)
{
struct net_bridge_port_group *p =
container_of(head, struct net_bridge_port_group, rcu);
@@ -584,9 +571,8 @@ err:
return mp;
}
-static struct net_bridge_mdb_entry *br_multicast_new_group(
- struct net_bridge *br, struct net_bridge_port *port,
- struct br_ip *group)
+struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
+ struct net_bridge_port *port, struct br_ip *group)
{
struct net_bridge_mdb_htable *mdb;
struct net_bridge_mdb_entry *mp;
@@ -633,6 +619,26 @@ out:
return mp;
}
+struct net_bridge_port_group *br_multicast_new_port_group(
+ struct net_bridge_port *port,
+ struct br_ip *group,
+ struct net_bridge_port_group *next)
+{
+ struct net_bridge_port_group *p;
+
+ p = kzalloc(sizeof(*p), GFP_ATOMIC);
+ if (unlikely(!p))
+ return NULL;
+
+ p->addr = *group;
+ p->port = port;
+ p->next = next;
+ hlist_add_head(&p->mglist, &port->mglist);
+ setup_timer(&p->timer, br_multicast_port_group_expired,
+ (unsigned long)p);
+ return p;
+}
+
static int br_multicast_add_group(struct net_bridge *br,
struct net_bridge_port *port,
struct br_ip *group)
@@ -668,18 +674,9 @@ static int br_multicast_add_group(struct net_bridge *br,
break;
}
- p = kzalloc(sizeof(*p), GFP_ATOMIC);
- err = -ENOMEM;
+ p = br_multicast_new_port_group(port, group, *pp);
if (unlikely(!p))
goto err;
-
- p->addr = *group;
- p->port = port;
- p->next = *pp;
- hlist_add_head(&p->mglist, &port->mglist);
- setup_timer(&p->timer, br_multicast_port_group_expired,
- (unsigned long)p);
-
rcu_assign_pointer(*pp, p);
br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 2807c76..f21a739 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -434,10 +434,33 @@ extern int br_multicast_set_port_router(struct net_bridge_port *p,
extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_querier(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
+extern struct net_bridge_mdb_entry *br_mdb_ip_get(
+ struct net_bridge_mdb_htable *mdb,
+ struct br_ip *dst);
+extern struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
+ struct net_bridge_port *port, struct br_ip *group);
+extern void br_multicast_free_pg(struct rcu_head *head);
+extern struct net_bridge_port_group *br_multicast_new_port_group(
+ struct net_bridge_port *port,
+ struct br_ip *group,
+ struct net_bridge_port_group *next);
extern void br_mdb_init(void);
extern void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
struct br_ip *group, int type);
+#define mlock_dereference(X, br) \
+ rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
+
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/addrconf.h>
+static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
+{
+ if (ipv6_addr_is_multicast(addr) && IPV6_ADDR_MC_FLAG_TRANSIENT(addr))
+ return 1;
+ return 0;
+}
+#endif
+
static inline bool br_multicast_is_router(struct net_bridge *br)
{
return br->multicast_router == 2 ||
--
1.7.7.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Bridge] [PATCH 1/2] iproute2: implement add/del mdb entry
2012-12-12 8:23 [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries Cong Wang
@ 2012-12-12 8:23 ` Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH 2/2] iproute2: add support to monitor mdb entries too Cong Wang
2012-12-12 18:03 ` [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink David Miller
3 siblings, 0 replies; 7+ messages in thread
From: Cong Wang @ 2012-12-12 8:23 UTC (permalink / raw)
To: netdev; +Cc: Thomas Graf, Stephen Hemminger, bridge, Cong Wang
From: Cong Wang <amwang@redhat.com>
This patch implements:
bridge mdb { add | del } dev DEV port PORT grp GROUP
Cc: Stephen Hemminger <shemminger@vyatta.com>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
bridge/mdb.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/if_bridge.h | 8 +++++
include/linux/rtnetlink.h | 4 ++
3 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/bridge/mdb.c b/bridge/mdb.c
index 390d7f6..4d8a896 100644
--- a/bridge/mdb.c
+++ b/bridge/mdb.c
@@ -28,6 +28,7 @@ int filter_index;
static void usage(void)
{
+ fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP\n");
fprintf(stderr, " bridge mdb {show} [ dev DEV ]\n");
exit(-1);
}
@@ -153,11 +154,86 @@ static int mdb_show(int argc, char **argv)
return 0;
}
+static int mdb_modify(int cmd, int flags, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct br_port_msg bpm;
+ char buf[1024];
+ } req;
+ struct br_mdb_entry entry;
+ char *d = NULL, *p = NULL, *grp = NULL;
+
+ memset(&req, 0, sizeof(req));
+ memset(&entry, 0, sizeof(entry));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.bpm.family = PF_BRIDGE;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ d = *argv;
+ } else if (strcmp(*argv, "grp") == 0) {
+ NEXT_ARG();
+ grp = *argv;
+ } else {
+ if (strcmp(*argv, "port") == 0) {
+ NEXT_ARG();
+ p = *argv;
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ }
+ argc--; argv++;
+ }
+
+ if (d == NULL || grp == NULL || p == NULL) {
+ fprintf(stderr, "Device, group address and port name are required arguments.\n");
+ exit(-1);
+ }
+
+ req.bpm.ifindex = ll_name_to_index(d);
+ if (req.bpm.ifindex == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", d);
+ return -1;
+ }
+
+ entry.ifindex = ll_name_to_index(p);
+ if (entry.ifindex == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", p);
+ return -1;
+ }
+
+ if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
+ if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
+ fprintf(stderr, "Invalid address \"%s\"\n", grp);
+ return -1;
+ } else
+ entry.addr.proto = htons(ETH_P_IPV6);
+ } else
+ entry.addr.proto = htons(ETH_P_IP);
+
+ addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ return 0;
+}
+
int do_mdb(int argc, char **argv)
{
ll_init_map(&rth);
if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return mdb_modify(RTM_NEWMDB, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return mdb_modify(RTM_DELMDB, 0, argc-1, argv+1);
+
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 151a8bb..b3b6a67 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -157,6 +157,7 @@ enum {
#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
struct br_port_msg {
+ __u8 family;
__u32 ifindex;
};
@@ -171,4 +172,11 @@ struct br_mdb_entry {
} addr;
};
+enum {
+ MDBA_SET_ENTRY_UNSPEC,
+ MDBA_SET_ENTRY,
+ __MDBA_SET_ENTRY_MAX,
+};
+#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
+
#endif /* _LINUX_IF_BRIDGE_H */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index c82a159..3ea85dc 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -125,6 +125,10 @@ enum {
RTM_GETNETCONF = 82,
#define RTM_GETNETCONF RTM_GETNETCONF
+ RTM_NEWMDB = 84,
+#define RTM_NEWMDB RTM_NEWMDB
+ RTM_DELMDB = 85,
+#define RTM_DELMDB RTM_DELMDB
RTM_GETMDB = 86,
#define RTM_GETMDB RTM_GETMDB
--
1.7.7.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Bridge] [PATCH 2/2] iproute2: add support to monitor mdb entries too
2012-12-12 8:23 [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH 1/2] iproute2: implement add/del mdb entry Cong Wang
@ 2012-12-12 8:23 ` Cong Wang
2012-12-12 18:41 ` Stephen Hemminger
2012-12-12 18:03 ` [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink David Miller
3 siblings, 1 reply; 7+ messages in thread
From: Cong Wang @ 2012-12-12 8:23 UTC (permalink / raw)
To: netdev; +Cc: Thomas Graf, Stephen Hemminger, bridge, Cong Wang
From: Cong Wang <amwang@redhat.com>
This patch implements `bridge monitor mdb`.
Cc: Stephen Hemminger <shemminger@vyatta.com>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
bridge/br_common.h | 2 ++
bridge/mdb.c | 4 ++--
bridge/monitor.c | 14 ++++++++++++++
include/linux/rtnetlink.h | 2 ++
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/bridge/br_common.h b/bridge/br_common.h
index 892fb76..10f6ce9 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -3,6 +3,8 @@ extern int print_linkinfo(const struct sockaddr_nl *who,
void *arg);
extern int print_fdb(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
+extern int print_mdb(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
extern int do_fdb(int argc, char **argv);
extern int do_mdb(int argc, char **argv);
diff --git a/bridge/mdb.c b/bridge/mdb.c
index 4d8a896..121ce9c 100644
--- a/bridge/mdb.c
+++ b/bridge/mdb.c
@@ -82,8 +82,8 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
int len = n->nlmsg_len;
struct rtattr * tb[MDBA_MAX+1];
- if (n->nlmsg_type != RTM_GETMDB) {
- fprintf(stderr, "Not RTM_GETMDB: %08x %08x %08x\n",
+ if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
+ fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0;
diff --git a/bridge/monitor.c b/bridge/monitor.c
index 2f60655..44e14d8 100644
--- a/bridge/monitor.c
+++ b/bridge/monitor.c
@@ -68,6 +68,12 @@ int accept_msg(const struct sockaddr_nl *who,
fprintf(fp, "[NEIGH]");
return print_fdb(who, n, arg);
+ case RTM_NEWMDB:
+ case RTM_DELMDB:
+ if (prefix_banner)
+ fprintf(fp, "[MDB]");
+ return print_mdb(who, n, arg);
+
case 15:
return show_mark(fp, n);
@@ -84,6 +90,7 @@ int do_monitor(int argc, char **argv)
unsigned groups = ~RTMGRP_TC;
int llink=0;
int lneigh=0;
+ int lmdb=0;
rtnl_close(&rth);
@@ -97,6 +104,9 @@ int do_monitor(int argc, char **argv)
} else if (matches(*argv, "fdb") == 0) {
lneigh = 1;
groups = 0;
+ } else if (matches(*argv, "mdb") == 0) {
+ lmdb = 1;
+ groups = 0;
} else if (strcmp(*argv, "all") == 0) {
groups = ~RTMGRP_TC;
prefix_banner=1;
@@ -116,6 +126,10 @@ int do_monitor(int argc, char **argv)
groups |= nl_mgrp(RTNLGRP_NEIGH);
}
+ if (lmdb) {
+ groups |= nl_mgrp(RTNLGRP_MDB);
+ }
+
if (file) {
FILE *fp;
fp = fopen(file, "r");
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 3ea85dc..87452b4 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -609,6 +609,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF
RTNLGRP_IPV6_NETCONF,
#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
+ RTNLGRP_MDB,
+#define RTNLGRP_MDB RTNLGRP_MDB
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
--
1.7.7.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink
2012-12-12 8:23 [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink Cong Wang
` (2 preceding siblings ...)
2012-12-12 8:23 ` [Bridge] [PATCH 2/2] iproute2: add support to monitor mdb entries too Cong Wang
@ 2012-12-12 18:03 ` David Miller
3 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2012-12-12 18:03 UTC (permalink / raw)
To: amwang; +Cc: tgraf, netdev, shemminger, bridge, herbert
From: Cong Wang <amwang@redhat.com>
Date: Wed, 12 Dec 2012 16:23:07 +0800
> From: Cong Wang <amwang@redhat.com>
>
> As Stephen mentioned, we need to monitor the mdb
> changes in user-space, so add notifications via netlink too.
>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: Stephen Hemminger <shemminger@vyatta.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Thomas Graf <tgraf@suug.ch>
> Signed-off-by: Cong Wang <amwang@redhat.com>
Applied.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries
2012-12-12 8:23 ` [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries Cong Wang
@ 2012-12-12 18:03 ` David Miller
0 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2012-12-12 18:03 UTC (permalink / raw)
To: amwang; +Cc: tgraf, netdev, shemminger, bridge, herbert
From: Cong Wang <amwang@redhat.com>
Date: Wed, 12 Dec 2012 16:23:08 +0800
> From: Cong Wang <amwang@redhat.com>
>
> This patch implents adding/deleting mdb entries via netlink.
> Currently all entries are temp, we probably need a flag to distinguish
> permanent entries too.
>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: Stephen Hemminger <shemminger@vyatta.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Thomas Graf <tgraf@suug.ch>
> Signed-off-by: Cong Wang <amwang@redhat.com>
Applied.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Bridge] [PATCH 2/2] iproute2: add support to monitor mdb entries too
2012-12-12 8:23 ` [Bridge] [PATCH 2/2] iproute2: add support to monitor mdb entries too Cong Wang
@ 2012-12-12 18:41 ` Stephen Hemminger
0 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2012-12-12 18:41 UTC (permalink / raw)
To: Cong Wang; +Cc: Thomas Graf, netdev, bridge
On Wed, 12 Dec 2012 16:23:10 +0800
Cong Wang <amwang@redhat.com> wrote:
> From: Cong Wang <amwang@redhat.com>
>
> This patch implements `bridge monitor mdb`.
>
> Cc: Stephen Hemminger <shemminger@vyatta.com>
> Cc: Thomas Graf <tgraf@suug.ch>
> Signed-off-by: Cong Wang <amwang@redhat.com>
>
Accepted for 3.8 since Dave accepted the kernel parts. Thanks
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2012-12-12 18:41 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-12 8:23 [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH net-next 2/2] bridge: add support of adding and deleting mdb entries Cong Wang
2012-12-12 18:03 ` David Miller
2012-12-12 8:23 ` [Bridge] [PATCH 1/2] iproute2: implement add/del mdb entry Cong Wang
2012-12-12 8:23 ` [Bridge] [PATCH 2/2] iproute2: add support to monitor mdb entries too Cong Wang
2012-12-12 18:41 ` Stephen Hemminger
2012-12-12 18:03 ` [Bridge] [PATCH net-next 1/2] bridge: notify mdb changes via netlink David Miller
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.