Skip to content

Commit 84642fc

Browse files
committed
This commit contains:
1. Review comments incorporated 2. Dependency for PR #885 is resolved 3. Added test_evpn_fdb.py pytest script to verify EVPN-VXLAN-FDB 4. compiled and verified the FDB functionality with EVPN 5. Changes to handle the static mac and aging from CLI
1 parent 6d3d2b5 commit 84642fc

12 files changed

+585
-139
lines changed

cfgmgr/vlanmgr.cpp

+206-14
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ using namespace swss;
1313

1414
#define DOT1Q_BRIDGE_NAME "Bridge"
1515
#define VLAN_PREFIX "Vlan"
16+
#define SWITCH_STR "switch"
1617
#define LAG_PREFIX "PortChannel"
1718
#define DEFAULT_VLAN_ID "1"
1819
#define DEFAULT_MTU_STR "9100"
1920
#define VLAN_HLEN 4
21+
#define MAX_VLAN_ID 4095
2022

2123
extern MacAddress gMacAddress;
2224

@@ -28,6 +30,8 @@ VlanMgr::VlanMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c
2830
m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME),
2931
m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME),
3032
m_stateVlanMemberTable(stateDb, STATE_VLAN_MEMBER_TABLE_NAME),
33+
m_appFdbTableProducer(appDb, APP_FDB_TABLE_NAME),
34+
m_appSwitchTableProducer(appDb, APP_SWITCH_TABLE_NAME),
3135
m_appVlanTableProducer(appDb, APP_VLAN_TABLE_NAME),
3236
m_appVlanMemberTableProducer(appDb, APP_VLAN_MEMBER_TABLE_NAME)
3337
{
@@ -88,6 +92,10 @@ VlanMgr::VlanMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c
8892

8993
EXEC_WITH_ERROR_THROW(echo_cmd_backup, res);
9094
}
95+
/* vlan state notification from portsorch */
96+
m_VlanStateNotificationConsumer = new swss::NotificationConsumer(appDb, "VLANSTATE");
97+
auto vlanStatusNotificatier = new Notifier(m_VlanStateNotificationConsumer, this, "VLANSTATE");
98+
Orch::addExecutor(vlanStatusNotificatier);
9199
}
92100

93101
bool VlanMgr::addHostVlan(int vlan_id)
@@ -101,7 +109,7 @@ bool VlanMgr::addHostVlan(int vlan_id)
101109
+ BASH_CMD + " -c \""
102110
+ BRIDGE_CMD + " vlan add vid " + std::to_string(vlan_id) + " dev " + DOT1Q_BRIDGE_NAME + " self && "
103111
+ IP_CMD + " link add link " + DOT1Q_BRIDGE_NAME
104-
+ " up"
112+
+ " down"
105113
+ " name " + VLAN_PREFIX + std::to_string(vlan_id)
106114
+ " address " + gMacAddress.to_string()
107115
+ " type vlan id " + std::to_string(vlan_id) + "\"";
@@ -179,14 +187,29 @@ bool VlanMgr::addHostVlanMember(int vlan_id, const string &port_alias, const str
179187
// /bin/bash -c "/sbin/ip link set {{port_alias}} master Bridge &&
180188
// /sbin/bridge vlan del vid 1 dev {{ port_alias }} &&
181189
// /sbin/bridge vlan add vid {{vlan_id}} dev {{port_alias}} {{tagging_mode}}"
182-
ostringstream cmds, inner;
183-
inner << IP_CMD " link set " << shellquote(port_alias) << " master " DOT1Q_BRIDGE_NAME " && "
184-
BRIDGE_CMD " vlan del vid " DEFAULT_VLAN_ID " dev " << shellquote(port_alias) << " && "
185-
BRIDGE_CMD " vlan add vid " + std::to_string(vlan_id) + " dev " << shellquote(port_alias) << " " + tagging_cmd;
186-
cmds << BASH_CMD " -c " << shellquote(inner.str());
190+
191+
const std::string key = std::string("") + "Vlan1|" + port_alias;
187192

188-
std::string res;
189-
EXEC_WITH_ERROR_THROW(cmds.str(), res);
193+
if (isVlanMemberStateOk(key)) {
194+
ostringstream cmds, inner;
195+
inner << IP_CMD " link set " << shellquote(port_alias) << " master " DOT1Q_BRIDGE_NAME " && "
196+
BRIDGE_CMD " vlan add vid " + std::to_string(vlan_id) + " dev " << shellquote(port_alias) << " " + tagging_cmd;
197+
cmds << BASH_CMD " -c " << shellquote(inner.str());
198+
199+
std::string res;
200+
EXEC_WITH_ERROR_THROW(cmds.str(), res);
201+
}
202+
else
203+
{
204+
ostringstream cmds, inner;
205+
inner << IP_CMD " link set " << shellquote(port_alias) << " master " DOT1Q_BRIDGE_NAME " && "
206+
BRIDGE_CMD " vlan del vid " DEFAULT_VLAN_ID " dev " << shellquote(port_alias) << " && "
207+
BRIDGE_CMD " vlan add vid " + std::to_string(vlan_id) + " dev " << shellquote(port_alias) << " " + tagging_cmd;
208+
cmds << BASH_CMD " -c " << shellquote(inner.str());
209+
210+
std::string res;
211+
EXEC_WITH_ERROR_THROW(cmds.str(), res);
212+
}
190213

191214
return true;
192215
}
@@ -224,6 +247,137 @@ bool VlanMgr::isVlanMacOk()
224247
return !!gMacAddress;
225248
}
226249

250+
void VlanMgr::doSwitchTask(Consumer &consumer)
251+
{
252+
SWSS_LOG_ENTER();
253+
auto it = consumer.m_toSync.begin();
254+
255+
while (it != consumer.m_toSync.end())
256+
{
257+
KeyOpFieldsValuesTuple t = it->second;
258+
259+
string key = kfvKey(t);
260+
string op = kfvOp(t);
261+
262+
/* Ensure the key starts with "switch" otherwise ignore */
263+
if (key != SWITCH_STR)
264+
{
265+
SWSS_LOG_NOTICE("Ignoring SWITCH key %s", key.c_str());
266+
it = consumer.m_toSync.erase(it);
267+
continue;
268+
}
269+
270+
SWSS_LOG_DEBUG("key:switch");
271+
272+
for (auto i : kfvFieldsValues(t))
273+
{
274+
if (fvField(i) == "fdb_aging_time")
275+
{
276+
long agingTime = 0;
277+
SWSS_LOG_DEBUG("attribute:fdb_aging_time");
278+
if (op == SET_COMMAND)
279+
{
280+
SWSS_LOG_DEBUG("operation:set");
281+
agingTime = strtol(fvValue(i).c_str(), NULL, 0);
282+
if (agingTime < 0)
283+
{
284+
SWSS_LOG_ERROR("Invalid fdb_aging_time %s", fvValue(i).c_str());
285+
break;
286+
}
287+
SWSS_LOG_DEBUG("value:%s",fvValue(i).c_str());
288+
}
289+
else if (op == DEL_COMMAND)
290+
{
291+
SWSS_LOG_DEBUG("operation:del");
292+
agingTime = 0;
293+
}
294+
else
295+
{
296+
SWSS_LOG_ERROR("Unknown operation type %s", op.c_str());
297+
break;
298+
}
299+
300+
vector<FieldValueTuple> fvVector;
301+
FieldValueTuple aging_time("fdb_aging_time", to_string(agingTime));
302+
fvVector.push_back(aging_time);
303+
m_appSwitchTableProducer.set(key, fvVector);
304+
break;
305+
}
306+
}
307+
308+
it = consumer.m_toSync.erase(it);
309+
}
310+
}
311+
312+
void VlanMgr::doFdbTask(Consumer &consumer)
313+
{
314+
auto it = consumer.m_toSync.begin();
315+
316+
while (it != consumer.m_toSync.end())
317+
{
318+
KeyOpFieldsValuesTuple t = it->second;
319+
320+
/* format: <VLAN_name>|<MAC_address> */
321+
vector<string> keys = tokenize(kfvKey(t), config_db_key_delimiter, 1);
322+
/* keys[0] is vlan as (Vlan10) and keys[1] is mac as (00-00-00-00-00-00) */
323+
string op = kfvOp(t);
324+
325+
/* Ensure the key starts with "Vlan" otherwise ignore */
326+
if (strncmp(keys[0].c_str(), VLAN_PREFIX, 4))
327+
{
328+
SWSS_LOG_ERROR("Invalid key format. No 'Vlan' prefix: %s", keys[0].c_str());
329+
it = consumer.m_toSync.erase(it);
330+
continue;
331+
}
332+
333+
unsigned long vlan_id;
334+
vlan_id = strtoul(keys[0].substr(strlen(VLAN_PREFIX)).c_str(), NULL, 0);
335+
336+
if ((vlan_id <= 0) || (vlan_id > MAX_VLAN_ID))
337+
{
338+
SWSS_LOG_ERROR("Invalid key format. Vlan is out of range: %s", keys[0].c_str());
339+
it = consumer.m_toSync.erase(it);
340+
continue;
341+
}
342+
343+
MacAddress mac = MacAddress(keys[1]);
344+
345+
string key = VLAN_PREFIX + to_string(vlan_id);
346+
key += DEFAULT_KEY_SEPARATOR;
347+
key += mac.to_string();
348+
349+
if (op == SET_COMMAND)
350+
{
351+
string port;
352+
for (auto i : kfvFieldsValues(t))
353+
{
354+
if (fvField(i) == "port")
355+
{
356+
port = fvValue(i);
357+
break;
358+
}
359+
}
360+
361+
vector<FieldValueTuple> fvVector;
362+
FieldValueTuple p("port", port);
363+
fvVector.push_back(p);
364+
FieldValueTuple t("type", "static");
365+
fvVector.push_back(t);
366+
367+
m_appFdbTableProducer.set(key, fvVector);
368+
}
369+
else if (op == DEL_COMMAND)
370+
{
371+
m_appFdbTableProducer.del(key);
372+
}
373+
else
374+
{
375+
SWSS_LOG_ERROR("Unknown operation type %s", op.c_str());
376+
}
377+
it = consumer.m_toSync.erase(it);
378+
}
379+
}
380+
227381
void VlanMgr::doVlanTask(Consumer &consumer)
228382
{
229383
if (!isVlanMacOk())
@@ -296,12 +450,12 @@ void VlanMgr::doVlanTask(Consumer &consumer)
296450
{
297451
/* Set vlan admin status */
298452
if (fvField(i) == "admin_status")
299-
{
300-
admin_status = fvValue(i);
301-
setHostVlanAdminState(vlan_id, admin_status);
302-
fvVector.push_back(i);
303-
}
304-
/* Set vlan mtu */
453+
{
454+
admin_status = fvValue(i);
455+
setHostVlanAdminState(vlan_id, admin_status);
456+
fvVector.push_back(i);
457+
}
458+
/* Set vlan mtu */
305459
else if (fvField(i) == "mtu")
306460
{
307461
mtu = fvValue(i);
@@ -593,9 +747,47 @@ void VlanMgr::doTask(Consumer &consumer)
593747
{
594748
doVlanMemberTask(consumer);
595749
}
750+
else if (table_name == CFG_FDB_TABLE_NAME)
751+
{
752+
doFdbTask(consumer);
753+
}
754+
else if (table_name == CFG_SWITCH_TABLE_NAME)
755+
{
756+
SWSS_LOG_DEBUG("Table:SWITCH");
757+
doSwitchTask(consumer);
758+
}
596759
else
597760
{
598761
SWSS_LOG_ERROR("Unknown config table %s ", table_name.c_str());
599762
throw runtime_error("VlanMgr doTask failure.");
600763
}
601764
}
765+
766+
void VlanMgr::doTask(NotificationConsumer &consumer)
767+
{
768+
std::string op;
769+
std::string data;
770+
std::vector<swss::FieldValueTuple> values;
771+
772+
if (&consumer != m_VlanStateNotificationConsumer)
773+
{
774+
SWSS_LOG_WARN("received incorrect notification message");
775+
return;
776+
}
777+
778+
consumer.pop(op, data, values);
779+
780+
unsigned long vlan_id = strtoul(data.substr(strlen(VLAN_PREFIX)).c_str(), NULL, 0);
781+
782+
SWSS_LOG_NOTICE("vlanmgr received port status notification state %s vlan %s",
783+
op.c_str(), data.c_str());
784+
785+
if (isVlanStateOk(data))
786+
{
787+
setHostVlanAdminState((int)vlan_id, op);
788+
}
789+
else
790+
{
791+
SWSS_LOG_ERROR("received state update for vlan %s not existing", data.c_str());
792+
}
793+
}

cfgmgr/vlanmgr.h

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "dbconnector.h"
55
#include "producerstatetable.h"
66
#include "orch.h"
7+
#include "notifier.h"
78

89
#include <set>
910
#include <map>
@@ -19,14 +20,20 @@ class VlanMgr : public Orch
1920

2021
private:
2122
ProducerStateTable m_appVlanTableProducer, m_appVlanMemberTableProducer;
23+
ProducerStateTable m_appFdbTableProducer;
24+
ProducerStateTable m_appSwitchTableProducer;
2225
Table m_cfgVlanTable, m_cfgVlanMemberTable;
2326
Table m_statePortTable, m_stateLagTable;
2427
Table m_stateVlanTable, m_stateVlanMemberTable;
2528
std::set<std::string> m_vlans;
29+
NotificationConsumer* m_VlanStateNotificationConsumer;
2630

2731
void doTask(Consumer &consumer);
32+
void doTask(NotificationConsumer &consumer);
2833
void doVlanTask(Consumer &consumer);
2934
void doVlanMemberTask(Consumer &consumer);
35+
void doFdbTask(Consumer &consumer);
36+
void doSwitchTask(Consumer &consumer);
3037
void processUntaggedVlanMembers(std::string vlan, const std::string &members);
3138

3239
bool addHostVlan(int vlan_id);

cfgmgr/vlanmgrd.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ int main(int argc, char **argv)
5151
vector<string> cfg_vlan_tables = {
5252
CFG_VLAN_TABLE_NAME,
5353
CFG_VLAN_MEMBER_TABLE_NAME,
54+
CFG_FDB_TABLE_NAME,
55+
CFG_SWITCH_TABLE_NAME,
5456
};
5557

5658
DBConnector cfgDb("CONFIG_DB", 0);

orchagent/fdborch.cpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port)
469469

470470
if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, port))
471471
{
472-
SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, attr.value.oid);
472+
SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, bridge_port_id);
473473
return false;
474474
}
475475

@@ -866,14 +866,21 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const
866866
attr.id = SAI_FDB_ENTRY_ATTR_TYPE;
867867
if (origin == FDB_ORIGIN_VXLAN_ADVERTIZED)
868868
{
869-
attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE : SAI_FDB_ENTRY_TYPE_STATIC;
869+
attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC;
870870
}
871871
else
872872
{
873873
attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC;
874874
}
875875
attrs.push_back(attr);
876876

877+
if ((origin == FDB_ORIGIN_VXLAN_ADVERTIZED) && (type == "dynamic"))
878+
{
879+
attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE;
880+
attr.value.booldata = true;
881+
attrs.push_back(attr);
882+
}
883+
877884
attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID;
878885
attr.value.oid = port.m_bridge_port_id;
879886
attrs.push_back(attr);
@@ -896,7 +903,9 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const
896903
attr.value.ipaddr = ipaddr;
897904
attrs.push_back(attr);
898905
}
899-
else if(macUpdate && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED) && (origin != oldOrigin))
906+
else if(macUpdate
907+
&& (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED)
908+
&& (origin != oldOrigin))
900909
{
901910
/* origin is changed from Remote-advertized to Local-provisioned
902911
* Remove the end-point ip attribute from fdb entry
@@ -909,7 +918,16 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const
909918
attrs.push_back(attr);
910919
}
911920

912-
string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string();
921+
if(macUpdate && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED))
922+
{
923+
if((origin != oldOrigin)
924+
|| ((oldType == "dynamic") && (oldType != type)))
925+
{
926+
attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE;
927+
attr.value.booldata = false;
928+
attrs.push_back(attr);
929+
}
930+
}
913931

914932

915933
if(macUpdate)

0 commit comments

Comments
 (0)