diff options
author | stephen hemminger <shemminger@vyatta.com> | 2011-11-09 18:30:08 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-14 00:41:54 -0500 |
commit | 292d1398983f3514a0eab13b7606df7f4730b498 (patch) | |
tree | 4d62bdf2fd88b56432d8b9ec38dcf31e3e2e2a47 /net/bridge | |
parent | 23020ab35364f2c91133b099c2b1f7458e29aa96 (diff) |
bridge: add NTF_USE support
More changes to the recent code to support control of forwarding
database via netlink.
* Support NTF_USE like neighbour table
* Validate state bits from application
* Only send notifications (and change bits) if new entry is
different.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_fdb.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index c8e7861b88b..973813e3442 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -556,7 +556,7 @@ skip: return skb->len; } -/* Create new static fdb entry */ +/* Update (create or replace) forwarding database entry */ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, __u16 state, __u16 flags) { @@ -575,16 +575,21 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, } else { if (flags & NLM_F_EXCL) return -EEXIST; + } + + if (fdb_to_nud(fdb) != state) { + if (state & NUD_PERMANENT) + fdb->is_local = fdb->is_static = 1; + else if (state & NUD_NOARP) { + fdb->is_local = 0; + fdb->is_static = 1; + } else + fdb->is_local = fdb->is_static = 0; - if (flags & NLM_F_REPLACE) - fdb->updated = fdb->used = jiffies; - fdb->is_local = fdb->is_static = 0; + fdb->updated = fdb->used = jiffies; + fdb_notify(fdb, RTM_NEWNEIGH); } - if (state & NUD_PERMANENT) - fdb->is_local = fdb->is_static = 1; - else if (state & NUD_NOARP) - fdb->is_static = 1; return 0; } @@ -627,6 +632,11 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return -EINVAL; } + if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) { + pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state); + return -EINVAL; + } + p = br_port_get_rtnl(dev); if (p == NULL) { pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n", @@ -634,9 +644,15 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return -EINVAL; } - spin_lock_bh(&p->br->hash_lock); - err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags); - spin_unlock_bh(&p->br->hash_lock); + if (ndm->ndm_flags & NTF_USE) { + rcu_read_lock(); + br_fdb_update(p->br, p, addr); + rcu_read_unlock(); + } else { + spin_lock_bh(&p->br->hash_lock); + err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags); + spin_unlock_bh(&p->br->hash_lock); + } return err; } |