From fa786a03eb259134a1775f2f7dfeb52cb6ba3032 Mon Sep 17 00:00:00 2001 From: Simon Cao Date: Mon, 22 Aug 2016 08:38:11 -0700 Subject: [PATCH] Added support for tunneling and updated tunnel schema (#49) * Added support for tunneling and updated tunnel schema: - added tunneldecaporch - changed orchdaemon and main to include tunneldecaporch - updated orchagent Makefile --- doc/swss-schema.md | 16 + orchagent/Makefile.am | 2 +- orchagent/main.cpp | 20 + orchagent/orchdaemon.cpp | 5 +- orchagent/orchdaemon.h | 1 + orchagent/tunneldecaporch.cpp | 527 +++++++++++++++++++++++ orchagent/tunneldecaporch.h | 51 +++ swssconfig/sample/netbouncer.json | 12 + swssconfig/sample/netbouncer.json.output | 12 + swssconfig/sample/sample.json.output.txt | 2 +- 10 files changed, 644 insertions(+), 4 deletions(-) create mode 100644 orchagent/tunneldecaporch.cpp create mode 100644 orchagent/tunneldecaporch.h create mode 100644 swssconfig/sample/netbouncer.json create mode 100644 swssconfig/sample/netbouncer.json.output diff --git a/doc/swss-schema.md b/doc/swss-schema.md index ccaafb14a6c4..372240af1063 100644 --- a/doc/swss-schema.md +++ b/doc/swss-schema.md @@ -289,12 +289,28 @@ and reflects the LAG ports into the redis under: `LAG_TABLE::port` ###TUNNEL_DECAP_TABLE ; Stores tunnel decap rules key = TUNNEL_DECAP_TABLE:name + ;field value tunnel_type = "IPINIP" dst_ip = IP1,IP2 ;IP addresses separated by "," dscp_mode = "uniform" / "pipe" ecn_mode = "copy_from_outer" / "standard" ;standard: Behavior defined in RFC 6040 section 4.2 ttl_mode = "uniform" / "pipe" + IP = dec-octet "." dec-octet "." dec-octet "." dec-octet + + Example: + 127.0.0.1:6379> hgetall TUNNEL_DECAP_TABLE:NETBOUNCER + 1) "dscp_mode" + 2) "uniform" + 3) "dst_ip" + 4) "127.0.0.1" + 5) "ecn_mode" + 6) "copy_from_outer" + 7) "ttl_mode" + 8) "uniform" + 9) "tunnel_type" + 10) "IPINIP" + --------------------------------------------- ###LLDP_ENTRY_TABLE diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 28a9d565c9da..b74dc0e1f7e6 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -10,7 +10,7 @@ else DBGFLAGS = -g endif -orchagent_SOURCES = main.cpp orchdaemon.cpp orch.cpp routeorch.cpp neighorch.cpp intfsorch.cpp portsorch.cpp copporch.cpp +orchagent_SOURCES = main.cpp orchdaemon.cpp orch.cpp routeorch.cpp neighorch.cpp intfsorch.cpp portsorch.cpp copporch.cpp tunneldecaporch.cpp orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) diff --git a/orchagent/main.cpp b/orchagent/main.cpp index d610b45ef9e9..d26878b0f8e3 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -32,9 +32,11 @@ sai_next_hop_group_api_t* sai_next_hop_group_api; sai_route_api_t* sai_route_api; sai_lag_api_t* sai_lag_api; sai_policer_api_t* sai_policer_api; +sai_tunnel_api_t* sai_tunnel_api; map gProfileMap; sai_object_id_t gVirtualRouterId; +sai_object_id_t underlayIfId; MacAddress gMacAddress; const char *test_profile_get_value ( @@ -86,6 +88,7 @@ void initSaiApi() sai_api_query(SAI_API_ROUTE, (void **)&sai_route_api); sai_api_query(SAI_API_LAG, (void **)&sai_lag_api); sai_api_query(SAI_API_POLICER, (void **)&sai_policer_api); + sai_api_query(SAI_API_TUNNEL, (void **)&sai_tunnel_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_NOTICE); sai_log_set(SAI_API_VIRTUAL_ROUTER, SAI_LOG_NOTICE); @@ -99,6 +102,7 @@ void initSaiApi() sai_log_set(SAI_API_ROUTE, SAI_LOG_NOTICE); sai_log_set(SAI_API_LAG, SAI_LOG_NOTICE); sai_log_set(SAI_API_POLICER, SAI_LOG_NOTICE); + sai_log_set(SAI_API_TUNNEL, SAI_LOG_NOTICE); } int main(int argc, char **argv) @@ -174,6 +178,22 @@ int main(int argc, char **argv) SWSS_LOG_NOTICE("Get switch virtual router ID %llx\n", gVirtualRouterId); + // create the underlay router interface to create a LOOPBACK type router interface (encap) + sai_attribute_t underlay_intf_attrs[2]; + underlay_intf_attrs[0].id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + underlay_intf_attrs[0].value.oid = gVirtualRouterId; + underlay_intf_attrs[1].id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + underlay_intf_attrs[1].value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; + + status = sai_router_intfs_api->create_router_interface(&underlayIfId, 2, underlay_intf_attrs); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create underlay router interface %d", status); + return false; + } + + SWSS_LOG_NOTICE("Created underlay router interface ID %llx\n", underlayIfId); + OrchDaemon *orchDaemon = new OrchDaemon(); if (!orchDaemon->init()) { diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index d5f4b09d91f7..35a55d097820 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -42,8 +42,9 @@ bool OrchDaemon::init() NeighOrch *neigh_orch = new NeighOrch(m_applDb, APP_NEIGH_TABLE_NAME, ports_orch); RouteOrch *route_orch = new RouteOrch(m_applDb, APP_ROUTE_TABLE_NAME, ports_orch, neigh_orch); CoppOrch *copp_orch = new CoppOrch(m_applDb, APP_COPP_TABLE_NAME); - - m_orchList = { ports_orch, intfs_orch, neigh_orch, route_orch, copp_orch }; + TunnelDecapOrch *tunnel_decap_orch = new TunnelDecapOrch(m_applDb, APP_TUNNEL_DECAP_TABLE_NAME); + + m_orchList = { ports_orch, intfs_orch, neigh_orch, route_orch, copp_orch, tunnel_decap_orch }; m_select = new Select(); return true; diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 3a4b4a0588f4..b9365d835734 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -11,6 +11,7 @@ #include "neighorch.h" #include "routeorch.h" #include "copporch.h" +#include "tunneldecaporch.h" using namespace swss; diff --git a/orchagent/tunneldecaporch.cpp b/orchagent/tunneldecaporch.cpp new file mode 100644 index 000000000000..061f1d5ae752 --- /dev/null +++ b/orchagent/tunneldecaporch.cpp @@ -0,0 +1,527 @@ +#include "tunneldecaporch.h" +#include +#include "logger.h" + +extern sai_tunnel_api_t* sai_tunnel_api; +extern sai_router_interface_api_t* sai_router_intfs_api; + +extern sai_object_id_t gVirtualRouterId; +extern sai_object_id_t underlayIfId; + +TunnelDecapOrch::TunnelDecapOrch(DBConnector *db, string tableName) : Orch(db, tableName) +{ + SWSS_LOG_ENTER(); +} + +/** + * Function Description: + * @brief reads from APP_DB and creates tunnel + */ +void TunnelDecapOrch::doTask(Consumer& consumer) +{ + + auto it = consumer.m_toSync.begin(); + + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + string key = kfvKey(t); + string op = kfvOp(t); + + IpAddresses ip_addresses; + string tunnel_type; + string dscp_mode; + string ecn_mode; + string ttl_mode; + bool valid = true; + + // checking to see if the tunnel already exists + bool exists = (tunnelTable.find(key) != tunnelTable.end()); + + if (op == SET_COMMAND) + { + + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "tunnel_type") + { + tunnel_type = fvValue(i); + if (tunnel_type != "IPINIP") + { + SWSS_LOG_ERROR("Invalid tunnel type %s", tunnel_type.c_str()); + valid = false; + break; + } + } + if (fvField(i) == "dst_ip") + { + try + { + ip_addresses = IpAddresses(fvValue(i)); + } + catch (const std::invalid_argument &e) + { + SWSS_LOG_ERROR("%s", e.what()); + valid = false; + break; + } + if (exists) + { + setIpAttribute(key, ip_addresses, tunnelTable.find(key)->second.tunnel_id); + } + } + if (fvField(i) == "dscp_mode") + { + dscp_mode = fvValue(i); + if (dscp_mode != "uniform" && dscp_mode != "pipe") + { + SWSS_LOG_ERROR("Invalid dscp mode %s\n", dscp_mode.c_str()); + valid = false; + break; + } + if (exists) + { + setTunnelAttribute(fvField(i), dscp_mode, tunnelTable.find(key)->second.tunnel_id); + } + } + if (fvField(i) == "ecn_mode") + { + ecn_mode = fvValue(i); + if (ecn_mode != "copy_from_outer" && ecn_mode != "standard") + { + SWSS_LOG_ERROR("Invalid ecn mode %s\n", ecn_mode.c_str()); + valid = false; + break; + } + if (exists) + { + setTunnelAttribute(fvField(i), ecn_mode, tunnelTable.find(key)->second.tunnel_id); + } + } + if (fvField(i) == "ttl_mode") + { + ttl_mode = fvValue(i); + if (ttl_mode != "uniform" && ttl_mode != "pipe") + { + SWSS_LOG_ERROR("Invalid ttl mode %s\n", ttl_mode.c_str()); + valid = false; + break; + } + if (exists) + { + setTunnelAttribute(fvField(i), ttl_mode, tunnelTable.find(key)->second.tunnel_id); + } + } + } + // create new tunnel if it doesn't exists already + if (valid && !exists) + { + if (addDecapTunnel(key, tunnel_type, ip_addresses, dscp_mode, ecn_mode, ttl_mode)) + { + SWSS_LOG_NOTICE("Tunnel(s) added to ASIC_DB."); + } + else + { + SWSS_LOG_ERROR("Failed to add tunnels to ASIC_DB."); + } + } + } + + if (op == DEL_COMMAND) + { + if (exists) + { + removeDecapTunnel(key); + } + else + { + SWSS_LOG_ERROR("Tunnel cannot be removed since it doesn't exist."); + } + } + + it = consumer.m_toSync.erase(it); + } +} + +/** + * Function Description: + * @brief adds a decap tunnel to ASIC_DB + * + * Arguments: + * @param[in] type - type of tunnel + * @param[in] dst_ip - destination ip address to decap + * @param[in] dscp - dscp mode (uniform/pipe) + * @param[in] ecn - ecn mode (copy_from_outer/standard) + * @param[in] ttl - ttl mode (uniform/pipe) + * + * Return Values: + * @return true on success and false if there's an error + */ +bool TunnelDecapOrch::addDecapTunnel(string key, string type, IpAddresses dst_ip, string dscp, string ecn, string ttl) +{ + + SWSS_LOG_ENTER(); + + sai_status_t status; + + // adding tunnel attributes to array and writing to ASIC_DB + sai_attribute_t attr; + vector tunnel_attrs; + sai_object_id_t overlayIfId; + + // create the overlay router interface to create a LOOPBACK type router interface (decap) + sai_attribute_t overlay_intf_attrs[2]; + overlay_intf_attrs[0].id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + overlay_intf_attrs[0].value.oid = gVirtualRouterId; + overlay_intf_attrs[1].id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + overlay_intf_attrs[1].value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; + + status = sai_router_intfs_api->create_router_interface(&overlayIfId, 2, overlay_intf_attrs); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create overlay router interface %d", status); + return false; + } + + SWSS_LOG_NOTICE("Created overlay router interface ID %llx\n", overlayIfId); + + // tunnel type (only ipinip for now) + attr.id = SAI_TUNNEL_ATTR_TYPE; + attr.value.s32 = SAI_TUNNEL_IPINIP; + tunnel_attrs.push_back(attr); + attr.id = SAI_TUNNEL_ATTR_OVERLAY_INTERFACE; + attr.value.oid = overlayIfId; + tunnel_attrs.push_back(attr); + attr.id = SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE; + attr.value.oid = underlayIfId; + tunnel_attrs.push_back(attr); + + // decap ecn mode (copy from outer/standard) + attr.id = SAI_TUNNEL_ATTR_DECAP_ECN_MODE; + if (ecn == "copy_from_outer") + { + attr.value.s32 = SAI_TUNNEL_DECAP_ECN_MODE_COPY_FROM_OUTER; + } + else if (ecn == "standard") + { + attr.value.s32 = SAI_TUNNEL_DECAP_ECN_MODE_STANDARD; + } + tunnel_attrs.push_back(attr); + + // ttl mode (uniform/pipe) + attr.id = SAI_TUNNEL_ATTR_DECAP_TTL_MODE; + if (ttl == "uniform") + { + attr.value.s32 = SAI_TUNNEL_TTL_UNIFORM_MODEL; + } + else if (ttl == "pipe") + { + attr.value.s32 = SAI_TUNNEL_TTL_PIPE_MODEL; + } + tunnel_attrs.push_back(attr); + + // dscp mode (uniform/pipe) + attr.id = SAI_TUNNEL_ATTR_DECAP_DSCP_MODE; + if (dscp == "uniform") + { + attr.value.s32 = SAI_TUNNEL_DSCP_UNIFORM_MODEL; + } + else if (dscp == "pipe") + { + attr.value.s32 = SAI_TUNNEL_DSCP_PIPE_MODEL; + } + tunnel_attrs.push_back(attr); + + // write attributes to ASIC_DB + sai_object_id_t tunnel_id; + status = sai_tunnel_api->create_tunnel(&tunnel_id, tunnel_attrs.size(), tunnel_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create tunnel"); + return false; + } + + tunnelTable[key] = { tunnel_id, {} }; + + // TODO: + // there should also be "business logic" for netbouncer in the "tunnel application" code, which is a different source file and daemon process + + // create a decap tunnel entry for every ip + if (!addDecapTunnelTermEntries(key, dst_ip, tunnel_id)) + { + return false; + } + + return true; +} + +/** + * Function Description: + * @brief adds a decap tunnel termination entry to ASIC_DB + * + * Arguments: + * @param[in] tunnelKey - key of the tunnel from APP_DB + * @param[in] dst_ip - destination ip addresses to decap + * @param[in] tunnel_id - the id of the tunnel + * + * Return Values: + * @return true on success and false if there's an error + */ +bool TunnelDecapOrch::addDecapTunnelTermEntries(string tunnelKey, IpAddresses dst_ip, sai_object_id_t tunnel_id) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + + // adding tunnel table entry attributes to array and writing to ASIC_DB + vector tunnel_table_entry_attrs; + attr.id = SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID; + attr.value.oid = gVirtualRouterId; + tunnel_table_entry_attrs.push_back(attr); + attr.id = SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE; + attr.value.u32 = SAI_TUNNEL_TERM_TABLE_ENTRY_P2MP; + tunnel_table_entry_attrs.push_back(attr); + attr.id = SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE; + attr.value.s32 = SAI_TUNNEL_IPINIP; + tunnel_table_entry_attrs.push_back(attr); + attr.id = SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID; + attr.value.oid = tunnel_id; + tunnel_table_entry_attrs.push_back(attr); + + sai_ip_address_t tunnel_dst_ip; + tunnel_dst_ip.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + + set tunnel_ips = dst_ip.getIpAddresses(); + struct sockaddr_in tunnel_ip_struct; + string ip; + + TunnelEntry *tunnel_info = &tunnelTable.find(tunnelKey)->second; + + // loop through the IP list and create a new tunnel table entry for every IP (in network byte order) + for (auto it = tunnel_ips.begin(); it != tunnel_ips.end(); ++it) + { + ip = it->to_string(); + + // check if the there's an entry already for the ip + if (existingIps.find(ip) != existingIps.end()) + { + SWSS_LOG_ERROR("%s already exists. Did not create entry.", ip.c_str()); + } + + else + { + // turn string ip into network byte order + inet_pton(AF_INET, ip.c_str(), &(tunnel_ip_struct.sin_addr)); + tunnel_dst_ip.addr.ip4 = tunnel_ip_struct.sin_addr.s_addr; + + attr.id = SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP; + attr.value.ipaddr = tunnel_dst_ip; + tunnel_table_entry_attrs.push_back(attr); + + // create the tunnel table entry + sai_object_id_t tunnel_term_table_entry_id; + sai_status_t status = sai_tunnel_api->create_tunnel_term_table_entry(&tunnel_term_table_entry_id, tunnel_table_entry_attrs.size(), tunnel_table_entry_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create tunnel entry table for ip: %s", ip.c_str()); + return false; + } + + // insert into ip to entry mapping + existingIps.insert(ip); + + // insert entry id and ip into tunnel mapping + tunnel_info->tunnel_term_info.push_back({ tunnel_term_table_entry_id, ip }); + + // pop the last element for the next loop + tunnel_table_entry_attrs.pop_back(); + + SWSS_LOG_NOTICE("Created tunnel entry for ip: %s", ip.c_str()); + } + + } + return true; +} + +/** + * Function Description: + * @brief sets attributes for a tunnel + * + * Arguments: + * @param[in] field - field to set the attribute for + * @param[in] value - value to set the attribute to + * @param[in] existing_tunnel_id - the id of the tunnel you want to set the attribute for + * + * Return Values: + * @return true on success and false if there's an error + */ +bool TunnelDecapOrch::setTunnelAttribute(string field, string value, sai_object_id_t existing_tunnel_id) +{ + + sai_attribute_t attr; + + if (field == "ecn_mode") + { + // decap ecn mode (copy from outer/standard) + attr.id = SAI_TUNNEL_ATTR_DECAP_ECN_MODE; + if (value == "copy_from_outer") + { + attr.value.s32 = SAI_TUNNEL_DECAP_ECN_MODE_COPY_FROM_OUTER; + } + else if (value == "standard") + { + attr.value.s32 = SAI_TUNNEL_DECAP_ECN_MODE_STANDARD; + } + } + + if (field == "ttl_mode") + { + // ttl mode (uniform/pipe) + attr.id = SAI_TUNNEL_ATTR_DECAP_TTL_MODE; + if (value == "uniform") + { + attr.value.s32 = SAI_TUNNEL_TTL_UNIFORM_MODEL; + } + else if (value == "pipe") + { + attr.value.s32 = SAI_TUNNEL_TTL_PIPE_MODEL; + } + } + + if (field == "dscp_mode") + { + // dscp mode (uniform/pipe) + attr.id = SAI_TUNNEL_ATTR_DECAP_DSCP_MODE; + if (value == "uniform") + { + attr.value.s32 = SAI_TUNNEL_DSCP_UNIFORM_MODEL; + } + else if (value == "pipe") + { + attr.value.s32 = SAI_TUNNEL_DSCP_PIPE_MODEL; + } + } + + sai_status_t status = sai_tunnel_api->set_tunnel_attribute(existing_tunnel_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set attribute %s with value %s\n", field.c_str(), value.c_str()); + return false; + } + SWSS_LOG_NOTICE("Set attribute %s with value %s\n", field.c_str(), value.c_str()); + return true; +} + +/** + * Function Description: + * @brief sets ips for a particular tunnel. deletes ips that are old and adds new ones + * + * Arguments: + * @param[in] key - key of the tunnel from APP_DB + * @param[in] new_ip_addresses - new destination ip addresses to decap (comes from APP_DB) + * @param[in] tunnel_id - the id of the tunnel + * + * Return Values: + * @return true on success and false if there's an error + */ +bool TunnelDecapOrch::setIpAttribute(string key, IpAddresses new_ip_addresses, sai_object_id_t tunnel_id) +{ + TunnelEntry *tunnel_info = &tunnelTable.find(key)->second; + + // make a copy of tunnel_term_info to loop through + vector tunnel_term_info_copy(tunnel_info->tunnel_term_info); + + tunnel_info->tunnel_term_info.clear(); + + // loop through original ips and remove ips not in the new ip_addresses + for (auto it = tunnel_term_info_copy.begin(); it != tunnel_term_info_copy.end(); ++it) + { + TunnelTermEntry tunnel_entry_info = *it; + string ip = tunnel_entry_info.ip_address; + if (!new_ip_addresses.contains(ip)) + { + if (!removeDecapTunnelTermEntry(tunnel_entry_info.tunnel_term_id, ip)) + { + return false; + } + } + else + { + // add the data into the tunnel_term_info + tunnel_info->tunnel_term_info.push_back({ tunnel_entry_info.tunnel_term_id, ip }); + } + } + + // add all the new ip addresses + if(!addDecapTunnelTermEntries(key, new_ip_addresses, tunnel_id)) + { + return false; + } + + return true; +} + +/** + * Function Description: + * @brief remove decap tunnel + * + * Arguments: + * @param[in] key - key of the tunnel from APP_DB + * + * Return Values: + * @return true on success and false if there's an error + */ +bool TunnelDecapOrch::removeDecapTunnel(string key) +{ + sai_status_t status; + TunnelEntry *tunnel_info = &tunnelTable.find(key)->second; + + // loop through the tunnel entry ids related to the tunnel and remove them before removing the tunnel + for (auto it = tunnel_info->tunnel_term_info.begin(); it != tunnel_info->tunnel_term_info.end(); ++it) + { + TunnelTermEntry tunnel_entry_info = *it; + if (!removeDecapTunnelTermEntry(tunnel_entry_info.tunnel_term_id, tunnel_entry_info.ip_address)) + { + return false; + } + } + + tunnel_info->tunnel_term_info = {}; + + status = sai_tunnel_api->remove_tunnel(tunnel_info->tunnel_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove tunnel: %llu", tunnel_info->tunnel_id); + return false; + } + tunnelTable.erase(key); + return true; +} + +/** + * Function Description: + * @brief remove decap tunnel termination entry + * + * Arguments: + * @param[in] key - key of the tunnel from APP_DB + * + * Return Values: + * @return true on success and false if there's an error + */ +bool TunnelDecapOrch::removeDecapTunnelTermEntry(sai_object_id_t tunnel_term_id, string ip) +{ + sai_status_t status; + + status = sai_tunnel_api->remove_tunnel_term_table_entry(tunnel_term_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove tunnel table entry: %llu", tunnel_term_id); + return false; + } + + // making sure to remove all instances of the ip address + existingIps.erase(ip); + SWSS_LOG_NOTICE("Removed decap tunnel term entry with ip address: %s", ip.c_str()); + return true; +} diff --git a/orchagent/tunneldecaporch.h b/orchagent/tunneldecaporch.h new file mode 100644 index 000000000000..9fd86a2784d3 --- /dev/null +++ b/orchagent/tunneldecaporch.h @@ -0,0 +1,51 @@ +#ifndef SWSS_TUNNELDECAPORCH_H +#define SWSS_TUNNELDECAPORCH_H + +#include +#include + +#include "orch.h" +#include "sai.h" +#include "ipaddress.h" +#include "ipaddresses.h" + +struct TunnelTermEntry +{ + sai_object_id_t tunnel_term_id; + string ip_address; +}; + +struct TunnelEntry +{ + sai_object_id_t tunnel_id; // tunnel id + vector tunnel_term_info; // tunnel_entry ids related to the tunnel abd ips related to the tunnel (all ips for tunnel entries that refer to this tunnel) +}; + +/* TunnelTable: key string, tunnel object id */ +typedef map TunnelTable; + +/* ExistingIps: ips that currently have term entries */ +typedef unordered_set ExistingIps; + +class TunnelDecapOrch : public Orch +{ +public: + TunnelDecapOrch(DBConnector *db, string tableName); + +private: + + TunnelTable tunnelTable; + ExistingIps existingIps; + + bool addDecapTunnel(string key, string type, IpAddresses dst_ip, string dscp, string ecn, string ttl); + bool removeDecapTunnel(string key); + + bool addDecapTunnelTermEntries(string tunnelKey, IpAddresses dst_ip, sai_object_id_t tunnel_id); + bool removeDecapTunnelTermEntry(sai_object_id_t tunnel_term_id, string ip); + + bool setTunnelAttribute(string field, string value, sai_object_id_t existing_tunnel_id); + bool setIpAttribute(string key, IpAddresses new_ip_addresses, sai_object_id_t tunnel_id); + + void doTask(Consumer& consumer); +}; +#endif diff --git a/swssconfig/sample/netbouncer.json b/swssconfig/sample/netbouncer.json new file mode 100644 index 000000000000..60168f8e4f74 --- /dev/null +++ b/swssconfig/sample/netbouncer.json @@ -0,0 +1,12 @@ +[ + { + "TUNNEL_DECAP_TABLE:NETBOUNCER" : { + "tunnel_type":"IPINIP", + "dst_ip":"10.0.0.1", + "dscp_mode":"uniform", + "ecn_mode":"copy_from_outer", + "ttl_mode":"uniform" + }, + "OP": "SET" + } +] diff --git a/swssconfig/sample/netbouncer.json.output b/swssconfig/sample/netbouncer.json.output new file mode 100644 index 000000000000..c679a90fe087 --- /dev/null +++ b/swssconfig/sample/netbouncer.json.output @@ -0,0 +1,12 @@ +127.0.0.1:6379> hgetall TUNNEL_DECAP_TABLE:NETBOUNCER +1) "dscp_mode" +2) "uniform" +3) "dst_ip" +4) "10.0.0.1" +5) "ecn_mode" +6) "copy_from_outer" +7) "ttl_mode" +8) "uniform" +9) "tunnel_type" +10) "IPINIP" +127.0.0.1:6379> diff --git a/swssconfig/sample/sample.json.output.txt b/swssconfig/sample/sample.json.output.txt index 19a1f00caa9e..8508de60c6fe 100644 --- a/swssconfig/sample/sample.json.output.txt +++ b/swssconfig/sample/sample.json.output.txt @@ -75,7 +75,7 @@ hgetall WRED_PROFILE_TABLE:AZURE 2) "[DSCP_TO_TC_MAP_TABLE:AZURE]" 3) "tc_to_queue_map" 4) "[TC_TO_QUEUE_MAP_TABLE:AZURE]" -127.0.0.1:6379> +127.0.0.1:6379> hgetall TC_TO_QUEUE_MAP_TABLE:AZURE hgetall SCHEDULER_TABLE:BEST_EFFORT