Skip to content

Commit

Permalink
add static anycast gateway support
Browse files Browse the repository at this point in the history
Signed-off-by: yanjun deng <[email protected]>
  • Loading branch information
yanjundeng committed May 24, 2024
1 parent 3ee7361 commit 56c7dc6
Show file tree
Hide file tree
Showing 22 changed files with 1,152 additions and 47 deletions.
235 changes: 232 additions & 3 deletions cfgmgr/intfmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,25 @@ using namespace swss;

#define LOOPBACK_DEFAULT_MTU_STR "65536"
#define DEFAULT_MTU_STR 9100
extern MacAddress gMacAddress;
extern MacAddress gSagMacAddress;

IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) :
Orch(cfgDb, tableNames),
m_cfgIntfTable(cfgDb, CFG_INTF_TABLE_NAME),
m_cfgVlanIntfTable(cfgDb, CFG_VLAN_INTF_TABLE_NAME),
m_cfgLagIntfTable(cfgDb, CFG_LAG_INTF_TABLE_NAME),
m_cfgLoopbackIntfTable(cfgDb, CFG_LOOPBACK_INTERFACE_TABLE_NAME),
m_cfgSagTable(cfgDb, CFG_SAG_TABLE_NAME),
m_statePortTable(stateDb, STATE_PORT_TABLE_NAME),
m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME),
m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME),
m_stateVrfTable(stateDb, STATE_VRF_TABLE_NAME),
m_stateIntfTable(stateDb, STATE_INTERFACE_TABLE_NAME),
m_appIntfTableProducer(appDb, APP_INTF_TABLE_NAME),
m_neighTable(appDb, APP_NEIGH_TABLE_NAME)
m_appSagTableProducer(appDb, APP_SAG_TABLE_NAME),
m_neighTable(appDb, APP_NEIGH_TABLE_NAME),
m_appLagTable(appDb, APP_LAG_TABLE_NAME)
{
auto subscriberStateTable = new swss::SubscriberStateTable(stateDb,
STATE_PORT_TABLE_NAME, TableConsumable::DEFAULT_POP_BATCH_SIZE, 100);
Expand Down Expand Up @@ -132,6 +137,42 @@ void IntfMgr::setIntfIp(const string &alias, const string &opCmd,
}
}

void IntfMgr::setSagFdbEntry(const string &op, const string &alias, const string &mac_str)
{
stringstream cmd;
string res;

if (mac_str == gMacAddress.to_string())
{
// Don't add or del for global system MAC address
return;
}

if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX))
{
/* Ensure the key starts with "Vlan" otherwise ignore */
int vlan_id;
try
{
vlan_id = stoi(alias.substr(4));
}
catch (...)
{
SWSS_LOG_ERROR("Invalid Vlan alias format. Not a number after 'Vlan' prefix: %s", alias.c_str());
return;
}

// cmd format: bridge fdb add 00:11:22:33:44:55 dev Bridge vlan 3 permanent
cmd << "bridge fdb " << op << " " << mac_str << " dev Bridge vlan " << vlan_id << " permanent";

int ret = swss::exec(cmd.str(), res);
if (ret)
{
SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmd.str().c_str(), ret);
}
}
}

void IntfMgr::setIntfMac(const string &alias, const string &mac_str)
{
stringstream cmd;
Expand Down Expand Up @@ -193,6 +234,27 @@ bool IntfMgr::setIntfMpls(const string &alias, const string& mpls)
return true;
}

void IntfMgr::setIntfState(const string &alias, bool isUp)
{
stringstream cmd;
string res;

if (isUp)
{
cmd << IP_CMD << " link set " << shellquote(alias) << " up";
}
else
{
cmd << IP_CMD << " link set " << shellquote(alias) << " down";
}

int ret = swss::exec(cmd.str(), res);
if (ret)
{
SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmd.str().c_str(), ret);
}
}

void IntfMgr::addLoopbackIntf(const string &alias)
{
stringstream cmd;
Expand Down Expand Up @@ -765,6 +827,7 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
string grat_arp = "";
string mpls = "";
string ipv6_link_local_mode = "";
string sag = "";
string loopback_action = "";

for (auto idx : data)
Expand Down Expand Up @@ -804,6 +867,10 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
{
ipv6_link_local_mode = value;
}
else if (field == "static_anycast_gateway")
{
sag = value;
}
else if (field == "vlan")
{
vlanId = value;
Expand Down Expand Up @@ -979,8 +1046,52 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
}
else
{
FieldValueTuple fvTuple("mac_addr", MacAddress().to_string());
data.push_back(fvTuple);
if (!sag.empty())
{
// only VLAN interface can set static anycast gateway
if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX))
{
string gwmac = "";
if (m_cfgSagTable.hget("GLOBAL", "gateway_mac", gwmac))
{
// before change interface MAC, set interface down and up to regenerate IPv6 LL by MAC
if (sag == "true")
{
m_sagIntfList[alias] = true;

setIntfState(alias, false);
setIntfMac(alias, gwmac);
setIntfState(alias, true);
// add this MAC fdb into bridge
setSagFdbEntry("replace", alias, gwmac);

FieldValueTuple fvTuple("mac_addr", gwmac);
data.push_back(fvTuple);
}
else if (sag == "false")
{
m_sagIntfList[alias] = false;

// del the sag MAC fdb from bridge
setSagFdbEntry("del", alias, gSagMacAddress.to_string());

setIntfState(alias, false);
setIntfMac(alias, gMacAddress.to_string());
setIntfState(alias, true);

FieldValueTuple fvTuple("mac_addr", MacAddress().to_string());
data.push_back(fvTuple);
} else {
SWSS_LOG_ERROR("invalid SAG config \"%s\", it should be \"true\" or \"false\"", sag.c_str());
}
}
}
}
else
{
FieldValueTuple fvTuple("mac_addr", MacAddress().to_string());
data.push_back(fvTuple);
}
}

if (!proxy_arp.empty())
Expand Down Expand Up @@ -1048,6 +1159,21 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
SWSS_LOG_INFO("Erased ipv6 link local mode list for %s", alias.c_str());
}

if (m_sagIntfList.find(alias) != m_sagIntfList.end())
{
if (m_sagIntfList[alias] == true)
{
// del the sag MAC fdb from bridge
setSagFdbEntry("del", alias, gSagMacAddress.to_string());

// recover to global mac address
setIntfState(alias, false);
setIntfMac(alias, gMacAddress.to_string());
setIntfState(alias, true);
}
m_sagIntfList.erase(alias);
}

m_appIntfTableProducer.del(alias);
m_stateIntfTable.del(alias);
}
Expand Down Expand Up @@ -1115,6 +1241,42 @@ bool IntfMgr::doIntfAddrTask(const vector<string>& keys,
return true;
}

void IntfMgr::doSagTask(const vector<string>& keys,
const vector<FieldValueTuple> &data,
const string& op)
{
SWSS_LOG_ENTER();

string mac = "";
for (auto idx : data)
{
const auto &field = fvField(idx);
const auto &value = fvValue(idx);

if (field == "gateway_mac")
{
mac = value;
}
}

vector<FieldValueTuple> fvAppSag;
if (op == SET_COMMAND)
{
FieldValueTuple gwmac("gateway_mac", MacAddress(mac).to_string());
fvAppSag.push_back(gwmac);
m_appSagTableProducer.set("GLOBAL", fvAppSag);

updateSagMac(mac);
}
else if (op == DEL_COMMAND)
{
m_appSagTableProducer.del("GLOBAL");

// reset mac address for enabled static-anycast-gateway's VLAN interfaces
updateSagMac(gMacAddress.to_string());
}
}

void IntfMgr::doTask(Consumer &consumer)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -1147,6 +1309,14 @@ void IntfMgr::doTask(Consumer &consumer)
it = consumer.m_toSync.erase(it);
continue;
}

if (table_name == CFG_SAG_TABLE_NAME)
{
doSagTask(keys, data, op);
it = consumer.m_toSync.erase(it);
continue;
}

if (!doIntfGeneralTask(keys, data, op))
{
it++;
Expand Down Expand Up @@ -1209,6 +1379,65 @@ void IntfMgr::doPortTableTask(const string& key, vector<FieldValueTuple> data, s
}
}

void IntfMgr::updateSagMac(const std::string &macAddr)
{
vector<string> keys;
m_cfgVlanIntfTable.getKeys(keys);
for (auto &key: keys)
{
vector<string> entryKeys = tokenize(key, config_db_key_delimiter);
if (key.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX))
{
continue;
}

// only process the entry includes the SAG's config
// e.g. VLAN_INTERFACE|Vlan201
if (entryKeys.size() != 1)
{
continue;
}

string value = "";
if (m_cfgVlanIntfTable.hget(key, "static_anycast_gateway", value))
{
if (value == "true")
{
SWSS_LOG_NOTICE("set %s mac address to %s", key.c_str(), macAddr.c_str());

// enable SAG, set device down and up to regenerate IPv6 LL by MAC
setIntfState(key, false);
setIntfMac(key, macAddr);
setIntfState(key, true);

// remove the previous sag MAC fdb from bridge
setSagFdbEntry("del", key, gSagMacAddress.to_string());
// add this new MAC fdb into bridge, the "replace" could cover both "add" and "replace" cases.
setSagFdbEntry("replace", key, macAddr);

vector<FieldValueTuple> vlanIntFv;

// Get other fields to set them all together
m_cfgVlanIntfTable.get(key, vlanIntFv);

// keep consistent with default MAC 00:00:00:00:00:00
string entryMac = MacAddress().to_string();
if (macAddr != gMacAddress.to_string())
{
entryMac = macAddr;
}

FieldValueTuple fvTuple("mac_addr", entryMac);
vlanIntFv.push_back(fvTuple);
m_appIntfTableProducer.set(key, vlanIntFv);
}
} else {
SWSS_LOG_INFO("can't get %s in VLAN_INTERFACE table", key.c_str());
}
}
gSagMacAddress = MacAddress(macAddr);
}

bool IntfMgr::enableIpv6Flag(const string &alias)
{
stringstream cmd;
Expand Down
13 changes: 10 additions & 3 deletions cfgmgr/intfmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct SubIntfInfo
};

typedef std::map<std::string, SubIntfInfo> SubIntfMap;
typedef std::map<std::string, bool> SagIntfMap;

namespace swss {

Expand All @@ -28,12 +29,14 @@ class IntfMgr : public Orch
using Orch::doTask;

private:
ProducerStateTable m_appIntfTableProducer;
Table m_cfgIntfTable, m_cfgVlanIntfTable, m_cfgLagIntfTable, m_cfgLoopbackIntfTable;
Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateVrfTable, m_stateIntfTable;
ProducerStateTable m_appIntfTableProducer, m_appSagTableProducer;
Table m_cfgIntfTable, m_cfgVlanIntfTable, m_cfgLagIntfTable, m_cfgLoopbackIntfTable, m_cfgSagTable;
Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateVrfTable, m_stateIntfTable, m_appLagTable;

Table m_neighTable;

SubIntfMap m_subIntfList;
SagIntfMap m_sagIntfList;
std::set<std::string> m_loopbackIntfList;
std::set<std::string> m_pendingReplayIntfList;
std::set<std::string> m_ipv6LinkLocalModeList;
Expand All @@ -43,9 +46,12 @@ class IntfMgr : public Orch
void setIntfVrf(const std::string &alias, const std::string &vrfName);
void setIntfMac(const std::string &alias, const std::string &macAddr);
bool setIntfMpls(const std::string &alias, const std::string &mpls);
void setIntfState(const std::string &alias, bool isUp);
void setSagFdbEntry(const std::string &op, const std::string &alias, const std::string &mac_str);

bool doIntfGeneralTask(const std::vector<std::string>& keys, std::vector<FieldValueTuple> data, const std::string& op);
bool doIntfAddrTask(const std::vector<std::string>& keys, const std::vector<FieldValueTuple>& data, const std::string& op);
void doSagTask(const std::vector<std::string>& keys, const std::vector<FieldValueTuple>& data, const std::string& op);
void doTask(Consumer &consumer);
void doPortTableTask(const std::string& key, std::vector<FieldValueTuple> data, std::string op);

Expand Down Expand Up @@ -75,6 +81,7 @@ class IntfMgr : public Orch

void updateSubIntfAdminStatus(const std::string &alias, const std::string &admin);
void updateSubIntfMtu(const std::string &alias, const std::string &mtu);
void updateSagMac(const std::string &macAddr);
bool enableIpv6Flag(const std::string&);

bool m_replayDone {false};
Expand Down
14 changes: 14 additions & 0 deletions cfgmgr/intfmgrd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ using namespace swss;
/* select() function timeout retry time, in millisecond */
#define SELECT_TIMEOUT 1000

MacAddress gMacAddress;
MacAddress gSagMacAddress;

int main(int argc, char **argv)
{
Logger::linkToDbNative("intfmgrd");
Expand All @@ -32,6 +35,7 @@ int main(int argc, char **argv)
CFG_LOOPBACK_INTERFACE_TABLE_NAME,
CFG_VLAN_SUB_INTF_TABLE_NAME,
CFG_VOQ_INBAND_INTERFACE_TABLE_NAME,
CFG_SAG_TABLE_NAME,
};

DBConnector cfgDb("CONFIG_DB", 0);
Expand All @@ -50,6 +54,16 @@ int main(int argc, char **argv)
s.addSelectables(o->getSelectables());
}

Table table(&cfgDb, "DEVICE_METADATA");
string mac = "";
if (!table.hget("localhost", "mac", mac))
{
throw runtime_error("couldn't find MAC address of the device from config DB");
}

gMacAddress = MacAddress(mac);
gSagMacAddress = gMacAddress;

SWSS_LOG_NOTICE("starting main loop");
while (true)
{
Expand Down
Loading

0 comments on commit 56c7dc6

Please sign in to comment.