From c9ed2c4efb1973e4b6659e57068e2b3446ef4a20 Mon Sep 17 00:00:00 2001 From: Shuotian Cheng Date: Mon, 13 Aug 2018 10:29:43 -0700 Subject: [PATCH] [intfmgr]: Support configuring IPs for all regular interfaces (#544) Enable configuring IPv4 and IPv6 addresses on regular ports Add tests to test IPv4 add/remove to regular ports Signed-off-by: Shu0T1an ChenG --- cfgmgr/intfmgr.cpp | 49 ++++++++++++++---------------- cfgmgr/intfmgr.h | 2 +- tests/test_interface.py | 67 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 28 deletions(-) diff --git a/cfgmgr/intfmgr.cpp b/cfgmgr/intfmgr.cpp index 7e30fa1bd9..fb14df97da 100644 --- a/cfgmgr/intfmgr.cpp +++ b/cfgmgr/intfmgr.cpp @@ -25,12 +25,20 @@ IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c { } -bool IntfMgr::setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr) +bool IntfMgr::setIntfIp(const string &alias, const string &opCmd, + const string &ipPrefixStr, const bool ipv4) { stringstream cmd; string res; - cmd << IP_CMD << " address " << opCmd << " " << ipPrefixStr << " dev " << alias;; + if (ipv4) + { + cmd << IP_CMD << " address " << opCmd << " " << ipPrefixStr << " dev " << alias; + } + else + { + cmd << IP_CMD << " -6 address " << opCmd << " " << ipPrefixStr << " dev " << alias; + } int ret = swss::exec(cmd.str(), res); return (ret == 0); } @@ -72,34 +80,24 @@ void IntfMgr::doTask(Consumer &consumer) { KeyOpFieldsValuesTuple t = it->second; - string keySeparator = CONFIGDB_KEY_SEPARATOR; - vector keys = tokenize(kfvKey(t), keySeparator[0]); - string alias(keys[0]); + vector keys = tokenize(kfvKey(t), config_db_key_delimiter); - if (alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) + if (keys.size() != 2) { - /* handle IP over vlan Only for now, skip the rest */ + SWSS_LOG_ERROR("Invalid key %s", kfvKey(t).c_str()); it = consumer.m_toSync.erase(it); continue; } - size_t pos = kfvKey(t).find(CONFIGDB_KEY_SEPARATOR); - if (pos == string::npos) - { - SWSS_LOG_DEBUG("Invalid key %s", kfvKey(t).c_str()); - it = consumer.m_toSync.erase(it); - continue; - } - IpPrefix ip_prefix(kfvKey(t).substr(pos+1)); - - SWSS_LOG_DEBUG("intfs doTask: %s", (dumpTuple(consumer, t)).c_str()); + string alias(keys[0]); + IpPrefix ip_prefix(keys[1]); string op = kfvOp(t); if (op == SET_COMMAND) { /* - * Don't proceed if port/lag/VLAN is not ready yet. - * The pending task will be checked periodially and retried. + * Don't proceed if port/LAG/VLAN is not ready yet. + * The pending task will be checked periodically and retried. * TODO: Subscribe to stateDB for port/lag/VLAN state and retry * pending tasks immediately upon state change. */ @@ -109,18 +107,17 @@ void IntfMgr::doTask(Consumer &consumer) it++; continue; } - string opCmd("add"); - string ipPrefixStr = ip_prefix.to_string(); - setIntfIp(alias, opCmd, ipPrefixStr); + setIntfIp(alias, "add", ip_prefix.to_string(), ip_prefix.isV4()); } else if (op == DEL_COMMAND) { - string opCmd("del"); - string ipPrefixStr = ip_prefix.to_string(); - setIntfIp(alias, opCmd, ipPrefixStr); + setIntfIp(alias, "del", ip_prefix.to_string(), ip_prefix.isV4()); + } + else + { + SWSS_LOG_ERROR("Unknown operation: %s", op.c_str()); } it = consumer.m_toSync.erase(it); - continue; } } diff --git a/cfgmgr/intfmgr.h b/cfgmgr/intfmgr.h index b7460cb3ac..3d79d6d477 100644 --- a/cfgmgr/intfmgr.h +++ b/cfgmgr/intfmgr.h @@ -21,7 +21,7 @@ class IntfMgr : public Orch Table m_cfgIntfTable, m_cfgVlanIntfTable; Table m_statePortTable, m_stateLagTable, m_stateVlanTable; - bool setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr); + bool setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr, const bool ipv4 = true); void doTask(Consumer &consumer); bool isIntfStateOk(const string &alias); }; diff --git a/tests/test_interface.py b/tests/test_interface.py index 32202cae79..b7ee4998c2 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -1,8 +1,73 @@ from swsscommon import swsscommon + import time -import re import json +class TestInterfaceIpv4Addresses(object): + def test_InterfaceAddIpv4Address(self, dvs): + pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # assign IP to interface + tbl = swsscommon.Table(cdb, "INTERFACE") + fvs = swsscommon.FieldValuePairs([("NULL", "NULL")]) + tbl.set("Ethernet8|10.0.0.4/31", fvs) + time.sleep(1) + + # check application database + tbl = swsscommon.Table(pdb, "INTF_TABLE:Ethernet8") + intf_entries = tbl.getKeys() + assert len(intf_entries) == 1 + assert intf_entries[0] == "10.0.0.4/31" + + (status, fvs) = tbl.get(tbl.getKeys()[0]) + assert status == True + assert len(fvs) == 2 + for fv in fvs: + if fv[0] == "scope": + assert fv[1] == "global" + elif fv[0] == "family": + assert fv[1] == "IPv4" + else: + assert False + + # check asic database + tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") + for key in tbl.getKeys(): + route = json.loads(key) + if route["dest"] == "10.0.0.4/31": + subnet_found = True + if route["dest"] == "10.0.0.4/32": + ip2me_found = True + + assert subnet_found and ip2me_found + + def test_InterfaceRemoveIpv4Address(self, dvs): + pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # assign IP to interface + tbl = swsscommon.Table(cdb, "INTERFACE") + tbl._del("Ethernet8|10.0.0.4/31") + time.sleep(1) + + # check application database + tbl = swsscommon.Table(pdb, "INTF_TABLE:Ethernet8") + intf_entries = tbl.getKeys() + assert len(intf_entries) == 0 + + # check asic database + tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") + for key in tbl.getKeys(): + route = json.loads(key) + if route["dest"] == "10.0.0.4/31": + assert False + if route["dest"] == "10.0.0.4/32": + assert False + + def test_InterfaceIpChange(dvs): dvs.runcmd("ifconfig Ethernet0 10.0.0.0/31 up")