Skip to content

Commit c975c8d

Browse files
vasant17Vasant
andauthored
Flush ARP/neighbor entry on FDB flush when port L2-L3 (sonic-net#1506)
Flush ARP entries when FDB entries are flushed. *Neighbor orchagent attaches to FDB orchagent and observes. *When FDB orchagent removes/flushes a FDB entry, neighbor orchagent will be notified. *Neighbor orchagent will notifies nbrmgr to send a arp refresh. Co-authored-by: Vasant <[email protected]>
1 parent 9921b5b commit c975c8d

11 files changed

Lines changed: 245 additions & 30 deletions

File tree

cfgmgr/nbrmgr.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ NbrMgr::NbrMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, con
5959
{
6060
SWSS_LOG_ERROR("Netlink socket connect failed, error '%s'", nl_geterror(err));
6161
}
62+
63+
auto consumerStateTable = new swss::ConsumerStateTable(appDb, APP_NEIGH_RESOLVE_TABLE_NAME,
64+
TableConsumable::DEFAULT_POP_BATCH_SIZE, default_orch_pri);
65+
auto consumer = new Consumer(consumerStateTable, this, APP_NEIGH_RESOLVE_TABLE_NAME);
66+
Orch::addExecutor(consumer);
6267
}
6368

6469
bool NbrMgr::isIntfStateOk(const string &alias)
@@ -185,7 +190,28 @@ bool NbrMgr::setNeighbor(const string& alias, const IpAddress& ip, const MacAddr
185190
return send_message(m_nl_sock, msg);
186191
}
187192

188-
void NbrMgr::doTask(Consumer &consumer)
193+
void NbrMgr::doResolveNeighTask(Consumer &consumer)
194+
{
195+
SWSS_LOG_ENTER();
196+
197+
auto it = consumer.m_toSync.begin();
198+
while (it != consumer.m_toSync.end())
199+
{
200+
KeyOpFieldsValuesTuple t = it->second;
201+
vector<string> keys = tokenize(kfvKey(t),delimiter);
202+
MacAddress mac;
203+
IpAddress ip(keys[1]);
204+
string alias(keys[0]);
205+
206+
if (!setNeighbor(alias, ip, mac))
207+
{
208+
SWSS_LOG_ERROR("Neigh entry resolve failed for '%s'", kfvKey(t).c_str());
209+
}
210+
it = consumer.m_toSync.erase(it);
211+
}
212+
}
213+
214+
void NbrMgr::doSetNeighTask(Consumer &consumer)
189215
{
190216
SWSS_LOG_ENTER();
191217

@@ -257,3 +283,19 @@ void NbrMgr::doTask(Consumer &consumer)
257283
it = consumer.m_toSync.erase(it);
258284
}
259285
}
286+
287+
void NbrMgr::doTask(Consumer &consumer)
288+
{
289+
string table_name = consumer.getTableName();
290+
291+
if (table_name == CFG_NEIGH_TABLE_NAME)
292+
{
293+
doSetNeighTask(consumer);
294+
} else if (table_name == APP_NEIGH_RESOLVE_TABLE_NAME)
295+
{
296+
doResolveNeighTask(consumer);
297+
} else
298+
{
299+
SWSS_LOG_ERROR("Unknown REDIS table %s ", table_name.c_str());
300+
}
301+
}

cfgmgr/nbrmgr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class NbrMgr : public Orch
2626
bool isIntfStateOk(const std::string &alias);
2727
bool setNeighbor(const std::string& alias, const IpAddress& ip, const MacAddress& mac);
2828

29+
void doResolveNeighTask(Consumer &consumer);
30+
void doSetNeighTask(Consumer &consumer);
2931
void doTask(Consumer &consumer);
3032

3133
Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateIntfTable, m_stateNeighRestoreTable;

orchagent/fdborch.cpp

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update)
113113
}
114114
}
115115

116-
void FdbOrch::update(sai_fdb_event_t type,
117-
const sai_fdb_entry_t* entry,
116+
void FdbOrch::update(sai_fdb_event_t type,
117+
const sai_fdb_entry_t* entry,
118118
sai_object_id_t bridge_port_id)
119119
{
120120
SWSS_LOG_ENTER();
@@ -124,11 +124,11 @@ void FdbOrch::update(sai_fdb_event_t type,
124124
update.entry.bv_id = entry->bv_id;
125125

126126
SWSS_LOG_INFO("FDB event:%d, MAC: %s , BVID: 0x%" PRIx64 " , \
127-
bridge port ID: 0x%" PRIx64 ".",
128-
type, update.entry.mac.to_string().c_str(),
127+
bridge port ID: 0x%" PRIx64 ".",
128+
type, update.entry.mac.to_string().c_str(),
129129
entry->bv_id, bridge_port_id);
130130

131-
if (bridge_port_id &&
131+
if (bridge_port_id &&
132132
!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port))
133133
{
134134
SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64 ".",
@@ -199,7 +199,7 @@ void FdbOrch::update(sai_fdb_event_t type,
199199
}
200200

201201

202-
if (bridge_port_id == SAI_NULL_OBJECT_ID &&
202+
if (bridge_port_id == SAI_NULL_OBJECT_ID &&
203203
entry->bv_id == SAI_NULL_OBJECT_ID)
204204
{
205205
SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: - }",
@@ -491,6 +491,18 @@ void FdbOrch::doTask(NotificationConsumer& consumer)
491491
}
492492
}
493493

494+
/*
495+
* Name: flushFDBEntries
496+
* Params:
497+
* bridge_port_oid - SAI object ID of bridge port associated with the port
498+
* vlan_oid - SAI object ID of the VLAN
499+
* Description:
500+
* Flushes FDB entries based on bridge_port_oid, or vlan_oid or both.
501+
* This function is called in three cases.
502+
* 1. Port is reoved from VLAN (via SUBJECT_TYPE_VLAN_MEMBER_CHANGE)
503+
* 2. Bridge port OID is removed (Direct call)
504+
* 3. Port is shut down (via SUBJECT_TYPE_
505+
*/
494506
void FdbOrch::flushFDBEntries(sai_object_id_t bridge_port_oid,
495507
sai_object_id_t vlan_oid)
496508
{
@@ -531,13 +543,56 @@ void FdbOrch::flushFDBEntries(sai_object_id_t bridge_port_oid,
531543
}
532544
}
533545

546+
void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid)
547+
{
548+
FdbFlushUpdate flushUpdate;
549+
flushUpdate.port = port;
550+
551+
for (auto itr = m_entries.begin(); itr != m_entries.end(); ++itr)
552+
{
553+
if ((itr->port_name == port.m_alias) &&
554+
(itr->bv_id == bvid))
555+
{
556+
SWSS_LOG_INFO("Adding MAC learnt on [ port:%s , bvid:0x%" PRIx64 "]\
557+
to ARP flush", port.m_alias.c_str(), bvid);
558+
FdbEntry entry;
559+
entry.mac = itr->mac;
560+
entry.bv_id = itr->bv_id;
561+
flushUpdate.entries.push_back(entry);
562+
}
563+
}
564+
565+
if (!flushUpdate.entries.empty())
566+
{
567+
for (auto observer: m_observers)
568+
{
569+
observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &flushUpdate);
570+
}
571+
}
572+
}
573+
534574
void FdbOrch::updatePortOperState(const PortOperStateUpdate& update)
535575
{
536576
SWSS_LOG_ENTER();
537577
if (update.operStatus == SAI_PORT_OPER_STATUS_DOWN)
538578
{
539579
swss::Port p = update.port;
540580
flushFDBEntries(p.m_bridge_port_id, SAI_NULL_OBJECT_ID);
581+
582+
// Get BVID of each VLAN that this port is a member of
583+
// and call notifyObserversFDBFlush
584+
for (const auto& vlan_member: p.m_vlan_members)
585+
{
586+
swss::Port vlan;
587+
string vlan_alias = VLAN_PREFIX + to_string(vlan_member.first);
588+
if (!m_portsOrch->getPort(vlan_alias, vlan))
589+
{
590+
SWSS_LOG_INFO("Failed to locate VLAN %s", vlan_alias.c_str());
591+
continue;
592+
}
593+
notifyObserversFDBFlush(p, vlan.m_vlan_info.vlan_oid);
594+
}
595+
541596
}
542597
return;
543598
}
@@ -551,6 +606,7 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update)
551606
swss::Port vlan = update.vlan;
552607
swss::Port port = update.member;
553608
flushFDBEntries(port.m_bridge_port_id, vlan.m_vlan_info.vlan_oid);
609+
notifyObserversFDBFlush(port, vlan.m_vlan_info.vlan_oid);
554610
return;
555611
}
556612

@@ -580,7 +636,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& type)
580636
if (!m_portsOrch->getPort(entry.port_name, port))
581637
{
582638
SWSS_LOG_DEBUG("Saving a fdb entry until port %s becomes active",
583-
entry. port_name.c_str());
639+
entry.port_name.c_str());
584640
saved_fdb_entries[entry.port_name].push_back({entry, type});
585641

586642
return true;
@@ -589,7 +645,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& type)
589645
/* Retry until port is added to the VLAN */
590646
if (!port.m_bridge_port_id)
591647
{
592-
SWSS_LOG_DEBUG("Saving a fdb entry until port %s has got a bridge port ID",
648+
SWSS_LOG_DEBUG("Saving a fdb entry until port %s has got a bridge port ID",
593649
entry.port_name.c_str());
594650
saved_fdb_entries[entry.port_name].push_back({entry, type});
595651

orchagent/fdborch.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ struct FdbUpdate
2424
bool add;
2525
};
2626

27+
struct FdbFlushUpdate
28+
{
29+
vector<FdbEntry> entries;
30+
Port port;
31+
};
32+
2733
struct SavedFdbEntry
2834
{
2935
FdbEntry entry;
@@ -49,6 +55,7 @@ class FdbOrch: public Orch, public Subject, public Observer
4955
bool getPort(const MacAddress&, uint16_t, Port&);
5056
void flushFDBEntries(sai_object_id_t bridge_port_oid,
5157
sai_object_id_t vlan_oid);
58+
void notifyObserversFDBFlush(Port &p, sai_object_id_t&);
5259

5360
private:
5461
PortsOrch *m_portsOrch;

orchagent/neighorch.cpp

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,107 @@ extern FgNhgOrch *gFgNhgOrch;
1616

1717
const int neighorch_pri = 30;
1818

19-
NeighOrch::NeighOrch(DBConnector *db, string tableName, IntfsOrch *intfsOrch) :
20-
Orch(db, tableName, neighorch_pri), m_intfsOrch(intfsOrch)
19+
NeighOrch::NeighOrch(DBConnector *appDb, string tableName, IntfsOrch *intfsOrch, FdbOrch *fdbOrch, PortsOrch *portsOrch) :
20+
Orch(appDb, tableName, neighorch_pri),
21+
m_intfsOrch(intfsOrch),
22+
m_fdbOrch(fdbOrch),
23+
m_portsOrch(portsOrch),
24+
m_appNeighResolveProducer(appDb, APP_NEIGH_RESOLVE_TABLE_NAME)
2125
{
2226
SWSS_LOG_ENTER();
27+
28+
m_fdbOrch->attach(this);
29+
}
30+
31+
NeighOrch::~NeighOrch()
32+
{
33+
if (m_fdbOrch)
34+
{
35+
m_fdbOrch->detach(this);
36+
}
37+
}
38+
39+
bool NeighOrch::resolveNeighborEntry(const NeighborEntry &entry, const MacAddress &mac)
40+
{
41+
vector<FieldValueTuple> data;
42+
IpAddress ip = entry.ip_address;
43+
string key, alias = entry.alias;
44+
45+
key = alias + ":" + entry.ip_address.to_string();
46+
// We do NOT need to populate mac field as its NOT
47+
// even used in nbrmgr during ARP resolve. But just keeping here.
48+
FieldValueTuple fvTuple("mac", mac.to_string().c_str());
49+
data.push_back(fvTuple);
50+
51+
SWSS_LOG_INFO("Flushing ARP entry '%s:%s --> %s'",
52+
alias.c_str(), ip.to_string().c_str(), mac.to_string().c_str());
53+
m_appNeighResolveProducer.set(key, data);
54+
return true;
55+
}
56+
57+
/*
58+
* Function Name: processFDBFlushUpdate
59+
* Description:
60+
* Goal of this function is to delete neighbor/ARP entries
61+
* when a port belonging to a VLAN gets removed.
62+
* This function is called whenever neighbor orchagent receives
63+
* SUBJECT_TYPE_FDB_FLUSH_CHANGE notification. Currently we only care for
64+
* deleted FDB entries. We flush neighbor entry that matches its
65+
* in-coming interface and MAC with FDB entry's VLAN name and MAC
66+
* respectively.
67+
*/
68+
void NeighOrch::processFDBFlushUpdate(const FdbFlushUpdate& update)
69+
{
70+
SWSS_LOG_INFO("processFDBFlushUpdate port: %s",
71+
update.port.m_alias.c_str());
72+
73+
for (auto entry : update.entries)
74+
{
75+
// Get Vlan object
76+
Port vlan;
77+
if (!m_portsOrch->getPort(entry.bv_id, vlan))
78+
{
79+
SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan port \
80+
from bv_id 0x%" PRIx64 ".", entry.bv_id);
81+
continue;
82+
}
83+
SWSS_LOG_INFO("Flushing ARP for port: %s, VLAN: %s",
84+
vlan.m_alias.c_str(), update.port.m_alias.c_str());
85+
86+
// If the FDB entry MAC matches with neighbor/ARP entry MAC,
87+
// and ARP entry incoming interface matches with VLAN name,
88+
// flush neighbor/arp entry.
89+
for (const auto &neighborEntry : m_syncdNeighbors)
90+
{
91+
if (neighborEntry.first.alias == vlan.m_alias &&
92+
neighborEntry.second == entry.mac)
93+
{
94+
resolveNeighborEntry(neighborEntry.first, neighborEntry.second);
95+
}
96+
}
97+
}
98+
return;
2399
}
24100

101+
void NeighOrch::update(SubjectType type, void *cntx)
102+
{
103+
SWSS_LOG_ENTER();
104+
105+
assert(cntx);
106+
107+
switch(type) {
108+
case SUBJECT_TYPE_FDB_FLUSH_CHANGE:
109+
{
110+
FdbFlushUpdate *update = reinterpret_cast<FdbFlushUpdate *>(cntx);
111+
processFDBFlushUpdate(*update);
112+
break;
113+
}
114+
default:
115+
break;
116+
}
117+
118+
return;
119+
}
25120
bool NeighOrch::hasNextHop(const NextHopKey &nexthop)
26121
{
27122
return m_syncdNextHops.find(nexthop) != m_syncdNextHops.end();

orchagent/neighorch.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
#include "observer.h"
66
#include "portsorch.h"
77
#include "intfsorch.h"
8+
#include "fdborch.h"
89

910
#include "ipaddress.h"
1011
#include "nexthopkey.h"
12+
#include "producerstatetable.h"
13+
#include "schema.h"
1114

1215
#define NHFLAGS_IFDOWN 0x1 // nexthop's outbound i/f is down
1316

@@ -32,10 +35,11 @@ struct NeighborUpdate
3235
bool add;
3336
};
3437

35-
class NeighOrch : public Orch, public Subject
38+
class NeighOrch : public Orch, public Subject, public Observer
3639
{
3740
public:
38-
NeighOrch(DBConnector *db, string tableName, IntfsOrch *intfsOrch);
41+
NeighOrch(DBConnector *db, string tableName, IntfsOrch *intfsOrch, FdbOrch *fdbOrch, PortsOrch *portsOrch);
42+
~NeighOrch();
3943

4044
bool hasNextHop(const NextHopKey&);
4145

@@ -51,8 +55,13 @@ class NeighOrch : public Orch, public Subject
5155
bool ifChangeInformNextHop(const string &, bool);
5256
bool isNextHopFlagSet(const NextHopKey &, const uint32_t);
5357

58+
void update(SubjectType, void *);
59+
5460
private:
61+
PortsOrch *m_portsOrch;
5562
IntfsOrch *m_intfsOrch;
63+
FdbOrch *m_fdbOrch;
64+
ProducerStateTable m_appNeighResolveProducer;
5665

5766
NeighborTable m_syncdNeighbors;
5867
NextHopTable m_syncdNextHops;
@@ -66,6 +75,9 @@ class NeighOrch : public Orch, public Subject
6675
bool setNextHopFlag(const NextHopKey &, const uint32_t);
6776
bool clearNextHopFlag(const NextHopKey &, const uint32_t);
6877

78+
void processFDBFlushUpdate(const FdbFlushUpdate &);
79+
bool resolveNeighborEntry(const NeighborEntry &, const MacAddress &);
80+
6981
void doTask(Consumer &consumer);
7082
};
7183

orchagent/observer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ enum SubjectType
1717
SUBJECT_TYPE_INT_SESSION_CHANGE,
1818
SUBJECT_TYPE_PORT_CHANGE,
1919
SUBJECT_TYPE_PORT_OPER_STATE_CHANGE,
20+
SUBJECT_TYPE_FDB_FLUSH_CHANGE,
2021
};
2122

2223
class Observer

0 commit comments

Comments
 (0)