net: bridge: add support for sticky fdb entries
Add support for entries which are "sticky", i.e. will not change their port if they show up from a different one. A new ndm flag is introduced for that purpose - NTF_STICKY. We allow to set it only to non-local entries. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
15665342d4
Коммит
435f2e7cc0
|
@ -43,6 +43,7 @@ enum {
|
|||
#define NTF_PROXY 0x08 /* == ATF_PUBL */
|
||||
#define NTF_EXT_LEARNED 0x10
|
||||
#define NTF_OFFLOADED 0x20
|
||||
#define NTF_STICKY 0x40
|
||||
#define NTF_ROUTER 0x80
|
||||
|
||||
/*
|
||||
|
|
|
@ -584,7 +584,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
|
|||
unsigned long now = jiffies;
|
||||
|
||||
/* fastpath: update of existing entry */
|
||||
if (unlikely(source != fdb->dst)) {
|
||||
if (unlikely(source != fdb->dst && !fdb->is_sticky)) {
|
||||
fdb->dst = source;
|
||||
fdb_modified = true;
|
||||
/* Take over HW learned entry */
|
||||
|
@ -656,6 +656,8 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
|
|||
ndm->ndm_flags |= NTF_OFFLOADED;
|
||||
if (fdb->added_by_external_learn)
|
||||
ndm->ndm_flags |= NTF_EXT_LEARNED;
|
||||
if (fdb->is_sticky)
|
||||
ndm->ndm_flags |= NTF_STICKY;
|
||||
|
||||
if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
|
||||
goto nla_put_failure;
|
||||
|
@ -772,8 +774,10 @@ skip:
|
|||
|
||||
/* Update (create or replace) forwarding database entry */
|
||||
static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
|
||||
const __u8 *addr, __u16 state, __u16 flags, __u16 vid)
|
||||
const u8 *addr, u16 state, u16 flags, u16 vid,
|
||||
u8 ndm_flags)
|
||||
{
|
||||
u8 is_sticky = !!(ndm_flags & NTF_STICKY);
|
||||
struct net_bridge_fdb_entry *fdb;
|
||||
bool modified = false;
|
||||
|
||||
|
@ -789,6 +793,9 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_sticky && (state & NUD_PERMANENT))
|
||||
return -EINVAL;
|
||||
|
||||
fdb = br_fdb_find(br, addr, vid);
|
||||
if (fdb == NULL) {
|
||||
if (!(flags & NLM_F_CREATE))
|
||||
|
@ -832,6 +839,12 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
|
|||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (is_sticky != fdb->is_sticky) {
|
||||
fdb->is_sticky = is_sticky;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
fdb->added_by_user = 1;
|
||||
|
||||
fdb->used = jiffies;
|
||||
|
@ -865,7 +878,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
|
|||
} else {
|
||||
spin_lock_bh(&br->hash_lock);
|
||||
err = fdb_add_entry(br, p, addr, ndm->ndm_state,
|
||||
nlh_flags, vid);
|
||||
nlh_flags, vid, ndm->ndm_flags);
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ struct net_bridge_fdb_entry {
|
|||
struct hlist_node fdb_node;
|
||||
unsigned char is_local:1,
|
||||
is_static:1,
|
||||
is_sticky:1,
|
||||
added_by_user:1,
|
||||
added_by_external_learn:1,
|
||||
offloaded:1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче