-
Notifications
You must be signed in to change notification settings - Fork 694
Add support for IP interface loopback action #2307
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
Changes from 7 commits
ea5a175
5dc7668
bfb61a2
f871125
25a6cae
bc7e20a
ac63f6f
abe328d
5e571ec
4849030
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 |
|---|---|---|
|
|
@@ -57,6 +57,20 @@ static const vector<sai_router_interface_stat_t> rifStatIds = | |
| SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS, | ||
| }; | ||
|
|
||
| // Translation of loopback action from string to sai type | ||
| const unordered_map<string, loopback_action_e> IntfsOrch::m_loopback_action_map = | ||
| { | ||
| {"drop", LOOPBACK_ACTION_DROP}, | ||
| {"forward", LOOPBACK_ACTION_FORWARD}, | ||
| }; | ||
|
|
||
| // Translation of loopback action from sonic to sai type | ||
| const unordered_map<loopback_action_e, sai_packet_action_t> IntfsOrch::m_sai_loopback_action_map = | ||
| { | ||
| {LOOPBACK_ACTION_DROP, SAI_PACKET_ACTION_DROP}, | ||
| {LOOPBACK_ACTION_FORWARD, SAI_PACKET_ACTION_FORWARD}, | ||
| }; | ||
|
|
||
| IntfsOrch::IntfsOrch(DBConnector *db, string tableName, VRFOrch *vrf_orch, DBConnector *chassisAppDb) : | ||
| Orch(db, tableName, intfsorch_pri), m_vrfOrch(vrf_orch) | ||
| { | ||
|
|
@@ -416,6 +430,62 @@ bool IntfsOrch::setIntfProxyArp(const string &alias, const string &proxy_arp) | |
| return true; | ||
| } | ||
|
|
||
| bool IntfsOrch::setIntfLoopbackAction(const Port &port) | ||
| { | ||
| sai_attribute_t attr; | ||
| attr.id = SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION; | ||
| attr.value.s32 = m_sai_loopback_action_map.at(port.m_loopback_action); | ||
|
|
||
| string action_str = getIntfLoopbackActionStr(port.m_loopback_action); | ||
|
|
||
| sai_status_t status = sai_router_intfs_api->set_router_interface_attribute(port.m_rif_id, &attr); | ||
| if (status != SAI_STATUS_SUCCESS) | ||
| { | ||
| SWSS_LOG_ERROR("Loopback action [%s] set failed, interface [%s], rc [%d]", | ||
| action_str.c_str(), port.m_alias.c_str(), status); | ||
|
|
||
| task_process_status handle_status = handleSaiSetStatus(SAI_API_ROUTER_INTERFACE, status); | ||
| if (handle_status != task_success) | ||
| { | ||
| return parseHandleSaiStatusFailure(handle_status); | ||
| } | ||
| } | ||
|
|
||
| SWSS_LOG_NOTICE("Loopback action [%s] set success, interface [%s]", | ||
| action_str.c_str(), port.m_alias.c_str()); | ||
| return true; | ||
| } | ||
|
|
||
| bool IntfsOrch::getIntfLoopbackAction(const std::string &actionStr, loopback_action_e &action) | ||
| { | ||
| auto it = m_loopback_action_map.find(actionStr); | ||
| if (it != m_loopback_action_map.end()) | ||
| { | ||
| action = m_loopback_action_map.at(actionStr); | ||
| return true; | ||
| } | ||
| else | ||
| { | ||
| SWSS_LOG_WARN("Unsupported loopback action [%s]", actionStr.c_str()); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| string IntfsOrch::getIntfLoopbackActionStr(loopback_action_e action) | ||
| { | ||
| for (auto it = m_loopback_action_map.begin(); it != m_loopback_action_map.end(); ++it) | ||
| { | ||
| if (it->second == action) | ||
| { | ||
| return it->first; | ||
| } | ||
| } | ||
|
|
||
| SWSS_LOG_WARN("Failed to fetch action as string for action [%u]", action); | ||
| return string(); | ||
| } | ||
|
|
||
|
|
||
| set<IpPrefix> IntfsOrch:: getSubnetRoutes() | ||
| { | ||
| SWSS_LOG_ENTER(); | ||
|
|
@@ -433,12 +503,15 @@ set<IpPrefix> IntfsOrch:: getSubnetRoutes() | |
| return subnet_routes; | ||
| } | ||
|
|
||
| bool IntfsOrch::setIntf(const string& alias, sai_object_id_t vrf_id, const IpPrefix *ip_prefix, const bool adminUp, const uint32_t mtu) | ||
| bool IntfsOrch::setIntf(const string& alias, sai_object_id_t vrf_id, const IpPrefix *ip_prefix, | ||
| const bool adminUp, const uint32_t mtu, loopback_action_e loopbackAction) | ||
|
|
||
| { | ||
| SWSS_LOG_ENTER(); | ||
|
|
||
| Port port; | ||
| gPortsOrch->getPort(alias, port); | ||
| port.m_loopback_action = loopbackAction; | ||
|
|
||
| auto it_intfs = m_syncdIntfses.find(alias); | ||
| if (it_intfs == m_syncdIntfses.end()) | ||
|
|
@@ -665,6 +738,7 @@ void IntfsOrch::doTask(Consumer &consumer) | |
| string inband_type = ""; | ||
| bool mpls = false; | ||
| string vlan = ""; | ||
| loopback_action_e loopbackAction = LOOPBACK_ACTION_NONE; | ||
|
|
||
| for (auto idx : data) | ||
| { | ||
|
|
@@ -757,6 +831,13 @@ void IntfsOrch::doTask(Consumer &consumer) | |
| { | ||
| vlan = value; | ||
| } | ||
| else if (field == "loopback_action") | ||
| { | ||
| if(!getIntfLoopbackAction(value, loopbackAction)) | ||
| { | ||
| continue; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (alias == "eth0" || alias == "docker0") | ||
|
|
@@ -874,7 +955,8 @@ void IntfsOrch::doTask(Consumer &consumer) | |
| { | ||
| adminUp = port.m_admin_state_up; | ||
| } | ||
| if (!setIntf(alias, vrf_id, ip_prefix_in_key ? &ip_prefix : nullptr, adminUp, mtu)) | ||
|
|
||
| if (!setIntf(alias, vrf_id, ip_prefix_in_key ? &ip_prefix : nullptr, adminUp, mtu, loopbackAction)) | ||
| { | ||
| it++; | ||
| continue; | ||
|
|
@@ -906,6 +988,16 @@ void IntfsOrch::doTask(Consumer &consumer) | |
| setRouterIntfsMpls(port); | ||
| gPortsOrch->setPort(alias, port); | ||
| } | ||
|
|
||
| /* Set loopback action */ | ||
| if ((loopbackAction != LOOPBACK_ACTION_NONE) and (port.m_loopback_action != loopbackAction)) | ||
| { | ||
| port.m_loopback_action = loopbackAction; | ||
| if(setIntfLoopbackAction(port)) | ||
|
||
| { | ||
| gPortsOrch->setPort(alias, port); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1067,6 +1159,13 @@ bool IntfsOrch::addRouterIntfs(sai_object_id_t vrf_id, Port &port) | |
| attr.value.oid = vrf_id; | ||
| attrs.push_back(attr); | ||
|
|
||
| if(port.m_loopback_action != LOOPBACK_ACTION_NONE) | ||
|
||
| { | ||
| attr.id = SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION; | ||
| attr.value.s32 = m_sai_loopback_action_map.at(port.m_loopback_action); | ||
| attrs.push_back(attr); | ||
| } | ||
|
|
||
| attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; | ||
| if (port.m_mac) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,6 +71,13 @@ struct SystemLagInfo | |
| int32_t spa_id = 0; | ||
| }; | ||
|
|
||
| typedef enum loopback_action | ||
| { | ||
| LOOPBACK_ACTION_NONE, | ||
| LOOPBACK_ACTION_DROP, | ||
| LOOPBACK_ACTION_FORWARD, | ||
| } loopback_action_e; | ||
|
|
||
| class Port | ||
| { | ||
| public: | ||
|
|
@@ -107,6 +114,7 @@ class Port | |
| } | ||
|
|
||
| std::string m_alias; | ||
| loopback_action_e m_loopback_action; | ||
|
||
| Type m_type; | ||
| int m_index = 0; // PHY_PORT: index | ||
| uint32_t m_mtu = DEFAULT_MTU; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,12 @@ | ||
| import time | ||
| import json | ||
| import pytest | ||
| import random | ||
|
|
||
| from swsscommon import swsscommon | ||
|
|
||
| VLAN_SUB_INTERFACE_SEPARATOR = '.' | ||
|
|
||
| class TestRouterInterface(object): | ||
| def setup_db(self, dvs): | ||
| self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) | ||
|
|
@@ -2193,6 +2196,81 @@ def test_VLanInterfaceIpv6LinkLocalOnly(self, dvs, testlog): | |
| # one loopback router interface | ||
| assert len(intf_entries) == 1 | ||
|
|
||
| def set_loopback_action(self, interface, action): | ||
| if interface.startswith("PortChannel"): | ||
| tbl_name = "PORTCHANNEL_INTERFACE" | ||
| elif interface.startswith("Vlan"): | ||
| tbl_name = "VLAN_INTERFACE" | ||
| else: | ||
| sub_intf_sep_idx = interface.find(VLAN_SUB_INTERFACE_SEPARATOR) | ||
| if sub_intf_sep_idx != -1: | ||
| tbl_name = "VLAN_SUB_INTERFACE" | ||
| else: | ||
| tbl_name = "INTERFACE" | ||
|
|
||
| fvs = swsscommon.FieldValuePairs([("loopback_action", action)]) | ||
| tbl = swsscommon.Table(self.cdb, tbl_name) | ||
| tbl.set(interface, fvs) | ||
| time.sleep(1) | ||
|
|
||
| def loopback_action_test(self, iface): | ||
| # create interface | ||
| self.create_l3_intf(iface, "") | ||
|
|
||
| # set interface loopback action in config database | ||
| action_map = {"drop": "SAI_PACKET_ACTION_DROP", "forward": "SAI_PACKET_ACTION_FORWARD"} | ||
| action = random.choice(list(action_map.keys())) | ||
|
||
| self.set_loopback_action(iface, action) | ||
|
|
||
| # check application database | ||
| tbl = swsscommon.Table(self.pdb, "INTF_TABLE") | ||
| (status, fvs) = tbl.get(iface) | ||
| assert status == True | ||
|
|
||
| action_found = False | ||
| for fv in fvs: | ||
| if fv[0] == "loopback_action": | ||
| action_found = True | ||
| assert fv[1] == action | ||
| assert action_found == True | ||
|
|
||
| # check asic database | ||
| tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE") | ||
| intf_entries = tbl.getKeys() | ||
|
|
||
| action_found = False | ||
| for key in intf_entries: | ||
| (status, fvs) = tbl.get(key) | ||
| assert status == True | ||
|
|
||
| for fv in fvs: | ||
| if fv[0] == "SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION": | ||
| action_found = True | ||
| assert fv[1] == action_map[action] | ||
| assert action_found == True | ||
|
|
||
| # remove interface | ||
| self.remove_l3_intf(iface) | ||
|
|
||
| def test_interfaceLoopbackAction(self, dvs, testlog): | ||
| self.setup_db(dvs) | ||
| self.loopback_action_test("Ethernet8") | ||
|
|
||
| def test_subInterfaceLoopbackAction(self, dvs, testlog): | ||
| self.setup_db(dvs) | ||
| self.loopback_action_test("Ethernet8.1") | ||
|
|
||
| def test_vlanInterfaceLoopbackAction(self, dvs, testlog): | ||
| self.setup_db(dvs) | ||
| self.create_vlan("10") | ||
| self.loopback_action_test("Vlan10") | ||
| self.remove_vlan("10") | ||
|
|
||
| def test_portChannelInterfaceLoopbackAction(self, dvs, testlog): | ||
| self.setup_db(dvs) | ||
| self.create_port_channel("PortChannel009") | ||
| self.loopback_action_test("PortChannel009") | ||
| self.remove_port_channel("PortChannel009") | ||
|
|
||
| # Add Dummy always-pass test at end as workaroud | ||
| # for issue when Flaky fail on final test it invokes module tear-down before retrying | ||
|
|
||
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.
if you pass loopback action as a string to this function, no need for
getIntfLoopbackActionStrThere 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.
Done.