-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[VRF]: submit vrf feature #943
Changes from 25 commits
f448a22
7f81135
91f1f00
5c2af28
53f2663
fa95f1e
03c0472
e456159
88e3f4f
91fdc69
7bfc853
e772a12
213bca9
771d5f1
90e8000
e47cbc4
2c64599
4874983
6a18696
40755bd
280c6d3
7617947
306a40e
340b125
c79df41
d2b835e
8396833
c584517
78c4001
778f324
8370676
3e762ac
1657824
bb61e52
ebd624d
bd187bf
a53c365
7f8e447
0652e1d
bbca607
d877f23
1618686
854a553
0f55a9b
7987477
2ee979f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ using namespace swss; | |
#define LAG_PREFIX "PortChannel" | ||
#define LOOPBACK_PREFIX "Loopback" | ||
#define VNET_PREFIX "Vnet" | ||
#define VRF_PREFIX "Vrf" | ||
|
||
IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) : | ||
Orch(cfgDb, tableNames), | ||
|
@@ -50,7 +51,7 @@ void IntfMgr::setIntfIp(const string &alias, const string &opCmd, | |
} | ||
} | ||
|
||
void IntfMgr::setIntfVrf(const string &alias, const string vrfName) | ||
void IntfMgr::setIntfVrf(const string &alias, const string &vrfName) | ||
{ | ||
stringstream cmd; | ||
string res; | ||
|
@@ -63,7 +64,90 @@ void IntfMgr::setIntfVrf(const string &alias, const string vrfName) | |
{ | ||
cmd << IP_CMD << " link set " << alias << " nomaster"; | ||
} | ||
EXEC_WITH_ERROR_THROW(cmd.str(), res); | ||
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; | ||
string res; | ||
|
||
cmd << IP_CMD << " link add " << alias << " mtu 65536 type dummy && "; | ||
cmd << IP_CMD << " link set " << alias << " up"; | ||
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::delLoopbackIntf(const string &alias) | ||
{ | ||
stringstream cmd; | ||
string res; | ||
|
||
cmd << IP_CMD << " link del " << alias; | ||
int ret = swss::exec(cmd.str(), res); | ||
if (ret) | ||
{ | ||
SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmd.str().c_str(), ret); | ||
} | ||
} | ||
|
||
int IntfMgr::getIntfIpCount(const string &alias) | ||
{ | ||
stringstream cmd; | ||
string res; | ||
|
||
cmd << IP_CMD << " address show " << alias << " | grep inet | grep -v 'inet6 fe80:' | wc -l"; | ||
int ret = swss::exec(cmd.str(), res); | ||
if (ret) | ||
{ | ||
SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmd.str().c_str(), ret); | ||
return 0; | ||
} | ||
|
||
return std::stoi(res); | ||
} | ||
|
||
bool IntfMgr::isIntfGeneralDone(const string &alias) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Name doesn't align with functionality. How about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't get a good name all along. Yours is better. |
||
{ | ||
vector<FieldValueTuple> temp; | ||
|
||
if (m_stateIntfTable.get(alias, temp)) | ||
{ | ||
SWSS_LOG_DEBUG("Intf %s is ready", alias.c_str()); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool IntfMgr::isIntfChangeVrf(const string &alias, const string &vrfName) | ||
prsunny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
vector<FieldValueTuple> temp; | ||
|
||
if (m_stateIntfTable.get(alias, temp)) | ||
{ | ||
for (auto idx : temp) | ||
{ | ||
const auto &field = fvField(idx); | ||
const auto &value = fvValue(idx); | ||
if (field == "vrf") | ||
{ | ||
if (value == vrfName) | ||
return false; | ||
else | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool IntfMgr::isIntfStateOk(const string &alias) | ||
|
@@ -94,6 +178,14 @@ bool IntfMgr::isIntfStateOk(const string &alias) | |
return true; | ||
} | ||
} | ||
else if (!alias.compare(0, strlen(VRF_PREFIX), VRF_PREFIX)) | ||
{ | ||
if (m_stateVrfTable.get(alias, temp)) | ||
{ | ||
SWSS_LOG_DEBUG("Vrf %s is ready", alias.c_str()); | ||
return true; | ||
} | ||
} | ||
else if (m_statePortTable.get(alias, temp)) | ||
{ | ||
SWSS_LOG_DEBUG("Port %s is ready", alias.c_str()); | ||
|
@@ -141,32 +233,38 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys, | |
return false; | ||
} | ||
|
||
// Set Interface VRF except for lo | ||
if (!is_lo) | ||
/* if to change vrf then skip */ | ||
if (isIntfChangeVrf(alias, vrf_name)) | ||
{ | ||
if (!vrf_name.empty()) | ||
{ | ||
setIntfVrf(alias, vrf_name); | ||
} | ||
m_appIntfTableProducer.set(alias, data); | ||
SWSS_LOG_ERROR("%s can not change to %s directly, skipping", alias.c_str(), vrf_name.c_str()); | ||
return true; | ||
} | ||
else | ||
if (is_lo) | ||
{ | ||
addLoopbackIntf(alias); | ||
} | ||
if (!vrf_name.empty()) | ||
{ | ||
m_appIntfTableProducer.set("lo", data); | ||
setIntfVrf(alias, vrf_name); | ||
} | ||
m_appIntfTableProducer.set(alias, data); | ||
m_stateIntfTable.hset(alias, "vrf", vrf_name); | ||
} | ||
else if (op == DEL_COMMAND) | ||
{ | ||
// Set Interface VRF except for lo | ||
if (!is_lo) | ||
/* make sure all ip addresses associated with interface are removed, otherwise these ip address would | ||
be set with global vrf and it may cause ip address confliction. */ | ||
if (getIntfIpCount(alias)) | ||
{ | ||
setIntfVrf(alias, ""); | ||
m_appIntfTableProducer.del(alias); | ||
return false; | ||
} | ||
else | ||
setIntfVrf(alias, ""); | ||
if (is_lo) | ||
{ | ||
m_appIntfTableProducer.del("lo"); | ||
delLoopbackIntf(alias); | ||
} | ||
m_appIntfTableProducer.del(alias); | ||
m_stateIntfTable.del(alias); | ||
} | ||
else | ||
{ | ||
|
@@ -184,26 +282,21 @@ bool IntfMgr::doIntfAddrTask(const vector<string>& keys, | |
|
||
string alias(keys[0]); | ||
IpPrefix ip_prefix(keys[1]); | ||
bool is_lo = !alias.compare(0, strlen(LOOPBACK_PREFIX), LOOPBACK_PREFIX); | ||
string appKey = (is_lo ? "lo" : keys[0]) + ":" + keys[1]; | ||
string appKey = keys[0] + ":" + keys[1]; | ||
|
||
if (op == SET_COMMAND) | ||
{ | ||
/* | ||
* Don't proceed if port/LAG/VLAN is not ready yet. | ||
* Don't proceed if port/LAG/VLAN and intfGeneral are not ready yet. | ||
* The pending task will be checked periodically and retried. | ||
*/ | ||
if (!isIntfStateOk(alias)) | ||
if (!isIntfStateOk(alias) || !isIntfGeneralDone(alias)) | ||
{ | ||
SWSS_LOG_DEBUG("Interface is not ready, skipping %s", alias.c_str()); | ||
return false; | ||
} | ||
|
||
// Set Interface IP except for lo | ||
if (!is_lo) | ||
{ | ||
setIntfIp(alias, "add", ip_prefix.to_string(), ip_prefix.isV4()); | ||
} | ||
setIntfIp(alias, "add", ip_prefix.to_string(), ip_prefix.isV4()); | ||
|
||
std::vector<FieldValueTuple> fvVector; | ||
FieldValueTuple f("family", ip_prefix.isV4() ? IPV4_NAME : IPV6_NAME); | ||
|
@@ -216,11 +309,8 @@ bool IntfMgr::doIntfAddrTask(const vector<string>& keys, | |
} | ||
else if (op == DEL_COMMAND) | ||
{ | ||
// Set Interface IP except for lo | ||
if (!is_lo) | ||
{ | ||
setIntfIp(alias, "del", ip_prefix.to_string(), ip_prefix.isV4()); | ||
} | ||
setIntfIp(alias, "del", ip_prefix.to_string(), ip_prefix.isV4()); | ||
|
||
m_appIntfTableProducer.del(appKey); | ||
m_stateIntfTable.del(keys[0] + state_db_key_delimiter + keys[1]); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ using namespace swss; | |
|
||
#define VXLAN_IF_NAME_PREFIX "Brvxlan" | ||
#define VNET_PREFIX "Vnet" | ||
#define VRF_PREFIX "Vrf" | ||
|
||
RouteSync::RouteSync(RedisPipeline *pipeline) : | ||
m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true), | ||
|
@@ -70,10 +71,40 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj) | |
{ | ||
struct rtnl_route *route_obj = (struct rtnl_route *)obj; | ||
struct nl_addr *dip; | ||
char destipprefix[MAX_ADDR_SIZE + 1] = {0}; | ||
char destipprefix[IFNAMSIZ + MAX_ADDR_SIZE + 2] = {0}; | ||
|
||
/* | ||
* Here vrf_index is not real table id but vrf_id in zebra. | ||
* It is vrf interface index in kernel for vrf route and VRF_DEFAULT(0) for global route. | ||
* Now zebra fpm only fill in a uchar, ifindex limited to 255. | ||
*/ | ||
unsigned int vrf_index = rtnl_route_get_table(route_obj); | ||
if (vrf_index) | ||
{ | ||
if (!getIfName(vrf_index, destipprefix, IFNAMSIZ)) | ||
{ | ||
SWSS_LOG_ERROR("Fail to get the VRF name (ifindex %u)", vrf_index); | ||
return; | ||
} | ||
/* | ||
* Now vrf device name is required to start with VRF_PREFIX, | ||
* it is difficult to split vrf_name:ipv6_addr. | ||
*/ | ||
if (memcmp(destipprefix, VRF_PREFIX, strlen(VRF_PREFIX))) | ||
{ | ||
SWSS_LOG_ERROR("Invalid VRF name %s (ifindex %u)", destipprefix, vrf_index); | ||
return; | ||
} | ||
destipprefix[strlen(destipprefix)] = ':'; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is already done in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will optimize it later. |
||
|
||
dip = rtnl_route_get_dst(route_obj); | ||
nl_addr2str(dip, destipprefix, MAX_ADDR_SIZE); | ||
nl_addr2str(dip, destipprefix + strlen(destipprefix), MAX_ADDR_SIZE); | ||
/* Full mask route append prefix length, or else resync cannot match. */ | ||
if (nl_addr_get_prefixlen(dip) == (8 * nl_addr_get_len(dip))) | ||
{ | ||
snprintf(destipprefix + strlen(destipprefix), sizeof(destipprefix) - strlen(destipprefix), "/%u", nl_addr_get_prefixlen(dip)); | ||
} | ||
SWSS_LOG_DEBUG("Receive new route message dest ip prefix: %s", destipprefix); | ||
|
||
/* | ||
|
@@ -186,6 +217,11 @@ void RouteSync::onVnetRouteMsg(int nlmsg_type, struct nl_object *obj, string vne | |
struct nl_addr *dip = rtnl_route_get_dst(route_obj); | ||
char destipprefix[MAX_ADDR_SIZE + 1] = {0}; | ||
nl_addr2str(dip, destipprefix, MAX_ADDR_SIZE); | ||
/* Full mask route append prefix length, or else resync cannot match. */ | ||
if (nl_addr_get_prefixlen(dip) == (8 * nl_addr_get_len(dip))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain this change? VNET routes makes some assumptions. Just want to ensure, there is no changes to VNET route handling. Please provide an example There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove this based on WG discussion |
||
{ | ||
snprintf(destipprefix + strlen(destipprefix), sizeof(destipprefix) - strlen(destipprefix), "/%u", nl_addr_get_prefixlen(dip)); | ||
} | ||
|
||
string vnet_dip = vnet + string(":") + destipprefix; | ||
SWSS_LOG_DEBUG("Receive new vnet route message %s", vnet_dip.c_str()); | ||
|
@@ -325,6 +361,17 @@ string RouteSync::getNextHopGw(struct rtnl_route *route_obj) | |
nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE); | ||
result += gw_ip; | ||
} | ||
else | ||
{ | ||
if (rtnl_route_get_family(route_obj) == AF_INET) | ||
{ | ||
result += "0.0.0.0"; | ||
} | ||
else | ||
{ | ||
result += "::"; | ||
} | ||
} | ||
|
||
if (i + 1 < rtnl_route_get_nnexthops(route_obj)) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please define
65535
and use variable.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, maybe always keep the max value.