diff --git a/vslib/vpp/SwitchVpp.cpp b/vslib/vpp/SwitchVpp.cpp index 890c6e8b80..3c6a443fb3 100644 --- a/vslib/vpp/SwitchVpp.cpp +++ b/vslib/vpp/SwitchVpp.cpp @@ -803,6 +803,38 @@ void SwitchVpp::setPortStats( debugSetStats(oid, stats); } +void SwitchVpp::setRifStats( + _In_ sai_object_id_t oid) +{ + SWSS_LOG_ENTER(); + + std::string if_name; + + // Resolve the RIF to its backing VPP interface: the port/LAG/sub-port + // hwif, or the bridge BVI (bvi) for a VLAN RIF. Only these are + // backed by a VPP hardware interface whose counters we can read here. + if (!vpp_get_rif_hwif_name(oid, if_name)) + { + return; + } + + vpp_interface_stats_t rif_stats; + + if (vpp_intf_stats_query(if_name.c_str(), &rif_stats) == 0) + { + std::map stats; + + stats[SAI_ROUTER_INTERFACE_STAT_IN_PACKETS] = rif_stats.rx; + stats[SAI_ROUTER_INTERFACE_STAT_IN_OCTETS] = rif_stats.rx_bytes; + stats[SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS] = rif_stats.tx; + stats[SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS] = rif_stats.tx_bytes; + stats[SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS] = rif_stats.rx_error; + stats[SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS] = rif_stats.tx_error; + + debugSetStats(oid, stats); + } +} + sai_status_t SwitchVpp::getRouteCounterStats( _In_ sai_object_id_t oid, _Out_ std::map& stats, @@ -1163,6 +1195,10 @@ sai_status_t SwitchVpp::getStatsExt( { setPortStats(object_id); } + else if (object_type == SAI_OBJECT_TYPE_ROUTER_INTERFACE) + { + setRifStats(object_id); + } else if (object_type == SAI_OBJECT_TYPE_COUNTER) { std::string route; diff --git a/vslib/vpp/SwitchVpp.h b/vslib/vpp/SwitchVpp.h index 26eab9f10e..1b6e74b9d7 100644 --- a/vslib/vpp/SwitchVpp.h +++ b/vslib/vpp/SwitchVpp.h @@ -95,6 +95,9 @@ namespace saivs void setPortStats( _In_ sai_object_id_t oid); + void setRifStats( + _In_ sai_object_id_t oid); + sai_status_t getRouteStatsExt( _In_ sai_object_id_t oid, _In_ uint32_t number_of_counters, @@ -709,6 +712,23 @@ namespace saivs _In_ uint32_t vlan_id, _In_ uint32_t mtu); + sai_status_t vpp_apply_loopback_action ( + _In_ const std::string& ifname, + _In_ int32_t packet_action); + + sai_status_t vpp_set_interface_loopback_action ( + _In_ sai_object_id_t object_id, + _In_ uint32_t vlan_id, + _In_ int32_t packet_action); + + sai_status_t vpp_set_rif_loopback_action ( + _In_ sai_object_id_t rif_oid, + _In_ int32_t packet_action); + + bool vpp_get_rif_hwif_name ( + _In_ sai_object_id_t rif_oid, + _Out_ std::string& ifname); + sai_status_t UpdatePort( _In_ sai_object_id_t object_id, _In_ uint32_t attr_count, diff --git a/vslib/vpp/SwitchVppFdb.cpp b/vslib/vpp/SwitchVppFdb.cpp index 0ecfbd9072..c872d9c786 100644 --- a/vslib/vpp/SwitchVppFdb.cpp +++ b/vslib/vpp/SwitchVppFdb.cpp @@ -862,6 +862,15 @@ sai_status_t SwitchVpp::vpp_create_bvi_interface( interface_set_state(tap_name.c_str(), true); } + // Create-path parity with vpp_update_router_interface: if the VLAN RIF is created + // with SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION, apply it on the BVI now. + // Otherwise the action would only take effect on a later set. + auto attr_loopback = sai_metadata_get_attr_by_id(SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION, attr_count, attr_list); + if (attr_loopback != NULL && is_ip_nbr_active()) + { + vpp_apply_loopback_action(hw_ifname, attr_loopback->value.s32); + } + return SAI_STATUS_SUCCESS; } @@ -1032,10 +1041,21 @@ uint32_t SwitchVpp::find_new_bond_id() bool found_new_bond_id = false; while (std::getline(iss, line)) { std::string portchannel_name = line.substr(0, line.find('\n')); - bond_id = std::stoi(portchannel_name.substr(strlen(PORTCHANNEL_PREFIX))); + // A base PortChannel is named "PortChannel". Sub-interfaces ("PortChannelX.Y" + // or the short "PoX.Y" form) and any malformed entry must not be mistaken for a new + // bond: a '.' or non-digit right after the prefix parses to a bogus id (often 0 via + // the safe-stoi fallback), which previously got assigned to a real LAG and left its + // RIF/neighbor on the wrong BondEthernet. + std::string suffix = portchannel_name.substr(strlen(PORTCHANNEL_PREFIX)); + if (suffix.empty() || suffix[0] < '0' || suffix[0] > '9' || + suffix.find('.') != std::string::npos || suffix.find('@') != std::string::npos) { + SWSS_LOG_DEBUG("Skipping non-base PortChannel entry for bond id: %s", portchannel_name.c_str()); + continue; + } + bond_id = (uint32_t) vpp_safe_stoi(suffix, "find_new_bond_id"); if (existing_bond_ids.find(bond_id) == existing_bond_ids.end()) { - SWSS_LOG_NOTICE("Found new bond id from PortChannel name: %d", bond_id); + SWSS_LOG_NOTICE("Found new bond id from PortChannel name: %u", bond_id); found_new_bond_id = true; break; } diff --git a/vslib/vpp/SwitchVppNbr.cpp b/vslib/vpp/SwitchVppNbr.cpp index 8bf84cb911..a106f58ce8 100644 --- a/vslib/vpp/SwitchVppNbr.cpp +++ b/vslib/vpp/SwitchVppNbr.cpp @@ -31,37 +31,19 @@ sai_status_t SwitchVpp::addRemoveIpNbr( sai_deserialize_neighbor_entry(serializedObjectId, nbr_entry); - attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; - - CHECK_STATUS(get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, nbr_entry.rif_id, 1, &attr)); - - auto port_obj_type = objectTypeQuery(attr.value.oid); - if (port_obj_type != SAI_OBJECT_TYPE_PORT && port_obj_type != SAI_OBJECT_TYPE_LAG) - { - return SAI_STATUS_SUCCESS; - } - auto port_oid = attr.value.oid; - - attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; - - CHECK_STATUS(get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, nbr_entry.rif_id, 1, &attr)); - if (attr.value.s32 != SAI_ROUTER_INTERFACE_TYPE_SUB_PORT && - attr.value.s32 != SAI_ROUTER_INTERFACE_TYPE_PORT) + // Resolve the VPP interface backing this RIF. vpp_get_rif_hwif_name handles + // PORT, LAG, SUB_PORT (hwif.vlan) and VLAN (bvi) RIFs. The previous + // logic only accepted a PORT/LAG PORT_ID with PORT/SUB_PORT type, so VLAN RIF + // neighbors were silently skipped and never programmed into VPP -- the DUT then + // ARPed instead of forwarding looped traffic on a VLAN RIF. + std::string hwif_name; + if (vpp_get_rif_hwif_name(nbr_entry.rif_id, hwif_name) == false) { - SWSS_LOG_NOTICE("Skipping neighbor add for attr type %d", attr.value.s32); - + SWSS_LOG_NOTICE("Skipping neighbor add: no VPP hwif for rif %s", + sai_serialize_object_id(nbr_entry.rif_id).c_str()); return SAI_STATUS_SUCCESS; } - uint16_t vlan_id = 0; - if (attr.value.s32 == SAI_ROUTER_INTERFACE_TYPE_SUB_PORT) - { - attr.id = SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID; - - CHECK_STATUS(get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, nbr_entry.rif_id, 1, &attr)); - vlan_id = attr.value.u16; - } - sai_mac_t nbr_mac; bool no_mac = true; @@ -95,14 +77,6 @@ sai_status_t SwitchVpp::addRemoveIpNbr( return SAI_STATUS_FAILURE; } - std::string hwif_name; - bool found = vpp_get_hwif_name(port_oid, vlan_id, hwif_name); - if (found == false) - { - SWSS_LOG_ERROR("hw interface for port/lag id %s not found", serializedObjectId.c_str()); - return SAI_STATUS_FAILURE; - } - const char *vpp_ifname = hwif_name.c_str(); init_vpp_client(); diff --git a/vslib/vpp/SwitchVppRif.cpp b/vslib/vpp/SwitchVppRif.cpp index af1aa7f712..3645812e46 100644 --- a/vslib/vpp/SwitchVppRif.cpp +++ b/vslib/vpp/SwitchVppRif.cpp @@ -572,6 +572,115 @@ sai_status_t SwitchVpp::vpp_set_interface_mtu ( return SAI_STATUS_SUCCESS; } +bool SwitchVpp::vpp_get_rif_hwif_name ( + _In_ sai_object_id_t rif_oid, + _Out_ std::string& ifname) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + + attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + if (get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_oid, 1, &attr) != SAI_STATUS_SUCCESS) { + return false; + } + int32_t rif_type = attr.value.s32; + + if (rif_type == SAI_ROUTER_INTERFACE_TYPE_VLAN) { + // VLAN RIF is backed by the bridge's BVI interface (bvi). + attr.id = SAI_ROUTER_INTERFACE_ATTR_VLAN_ID; + if (get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_oid, 1, &attr) != SAI_STATUS_SUCCESS) { + return false; + } + sai_object_id_t vlan_oid = attr.value.oid; + if (objectTypeQuery(vlan_oid) != SAI_OBJECT_TYPE_VLAN) { + return false; + } + sai_attribute_t vattr; + vattr.id = SAI_VLAN_ATTR_VLAN_ID; + if (get(SAI_OBJECT_TYPE_VLAN, vlan_oid, 1, &vattr) != SAI_STATUS_SUCCESS) { + return false; + } + ifname = std::string("bvi") + std::to_string(vattr.value.u16); + return true; + } + + attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; + if (get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_oid, 1, &attr) != SAI_STATUS_SUCCESS) { + return false; + } + sai_object_id_t port_oid = attr.value.oid; + + sai_object_type_t ot = objectTypeQuery(port_oid); + if (ot != SAI_OBJECT_TYPE_PORT && ot != SAI_OBJECT_TYPE_LAG) { + return false; + } + + uint16_t vlan_id = 0; + if (rif_type == SAI_ROUTER_INTERFACE_TYPE_SUB_PORT) { + attr.id = SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID; + if (get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_oid, 1, &attr) != SAI_STATUS_SUCCESS) { + return false; + } + vlan_id = attr.value.u16; + } + + return vpp_get_hwif_name(port_oid, vlan_id, ifname); +} + +sai_status_t SwitchVpp::vpp_apply_loopback_action ( + _In_ const std::string& ifname, + _In_ int32_t packet_action) +{ + SWSS_LOG_ENTER(); + + const char *hwif_name = ifname.c_str(); + int action = (packet_action == SAI_PACKET_ACTION_DROP) ? 1 : 0; + + int ret = vpp_iface_loopback_set_action(hwif_name, action); + SWSS_LOG_NOTICE("Setting router interface loopback action %s to %s (ret %d)", + hwif_name, action ? "drop" : "forward", ret); + + return (ret != 0) ? SAI_STATUS_FAILURE : SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchVpp::vpp_set_interface_loopback_action ( + _In_ sai_object_id_t object_id, + _In_ uint32_t vlan_id, + _In_ int32_t packet_action) +{ + SWSS_LOG_ENTER(); + + if (is_ip_nbr_active() == false) { + return SAI_STATUS_SUCCESS; + } + + std::string ifname; + + if (vpp_get_hwif_name(object_id, vlan_id, ifname) == true) { + return vpp_apply_loopback_action(ifname, packet_action); + } + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchVpp::vpp_set_rif_loopback_action ( + _In_ sai_object_id_t rif_oid, + _In_ int32_t packet_action) +{ + SWSS_LOG_ENTER(); + + if (is_ip_nbr_active() == false) { + return SAI_STATUS_SUCCESS; + } + + std::string ifname; + + if (vpp_get_rif_hwif_name(rif_oid, ifname) == true) { + return vpp_apply_loopback_action(ifname, packet_action); + } + return SAI_STATUS_SUCCESS; +} + sai_status_t SwitchVpp::UpdatePort( _In_ sai_object_id_t object_id, _In_ uint32_t attr_count, @@ -833,7 +942,7 @@ static void get_intf_vlanid (std::string& sub_ifname, int *vlan_id, std::string& } else { if_name = sub_ifname.substr(0, pos); std::string vlan = sub_ifname.substr(pos+1); - *vlan_id = std::stoi(vlan); + *vlan_id = vpp_safe_stoi(vlan, "sub_port_vlan_id"); } } static void get_vlan_intf_vlanid(std::string& if_name, std::string& vlan_prefix, int* vlan_id) @@ -861,7 +970,7 @@ static void get_vlan_intf_vlanid(std::string& if_name, std::string& vlan_prefix, std::string numeric_part = if_name.substr(pos); // Convert the numeric part to an integer using stoi - *vlan_id = std::stoi(numeric_part); + *vlan_id = vpp_safe_stoi(numeric_part, "vlan_intf_id"); } static void vpp_serialize_intf_data (std::string& k1, std::string& k2, std::string &serializedData) { @@ -1024,8 +1133,29 @@ sai_status_t SwitchVpp::vpp_add_del_intf_ip_addr_norif ( snprintf(hw_bviifname, sizeof(hw_bviifname), "%s%d","bvi",vlan_id); hw_ifname = hw_bviifname; } else if (full_if_name.compare(0, strlen(PORTCHANNEL_PREFIX), PORTCHANNEL_PREFIX) == 0) { - uint32_t bond_id = std::stoi(full_if_name.substr(strlen(PORTCHANNEL_PREFIX))); - snprintf(hw_bondifname, sizeof(hw_bondifname), "%s%d", BONDETHERNET_PREFIX, bond_id); + uint32_t bond_id = (uint32_t)vpp_safe_stoi(full_if_name.substr(strlen(PORTCHANNEL_PREFIX)), "portchannel_bond_id"); + if (vlan_id) { + // PortChannel sub-port RIF (e.g. PortChannel54.54): the IP must be added on the + // bond sub-interface (BondEthernet.), not the base bond. Without the + // . suffix the connected route/adjacency is never programmed, leaving the + // FIB entry UNRESOLVED and traffic dropped. + snprintf(hw_bondifname, sizeof(hw_bondifname), "%s%u.%d", BONDETHERNET_PREFIX, bond_id, vlan_id); + } else { + snprintf(hw_bondifname, sizeof(hw_bondifname), "%s%u", BONDETHERNET_PREFIX, bond_id); + } + hw_ifname = hw_bondifname; + } else if (full_if_name.compare(0, 2, "Po") == 0 && full_if_name.length() > 2 && + full_if_name[2] >= '0' && full_if_name[2] <= '9') { + // SONiC uses the short form "Po." (e.g. Po54.54) for PortChannel + // sub-interfaces. Map it to the VPP bond sub-interface BondEthernet. + // so the RIF IP / connected route is programmed (the base bond name here would + // leave the sub-interface without an IP and the FIB entry UNRESOLVED). + uint32_t bond_id = (uint32_t)vpp_safe_stoi(if_name.substr(2), "portchannel_short_bond_id"); + if (vlan_id) { + snprintf(hw_bondifname, sizeof(hw_bondifname), "%s%u.%d", BONDETHERNET_PREFIX, bond_id, vlan_id); + } else { + snprintf(hw_bondifname, sizeof(hw_bondifname), "%s%u", BONDETHERNET_PREFIX, bond_id); + } hw_ifname = hw_bondifname; } else { hwifname = tap_to_hwif_name(if_name.c_str()); @@ -1503,7 +1633,7 @@ int SwitchVpp::vpp_get_vrf_id (const char *linux_ifname, uint32_t *vrf_id) if (res.length() != 0) { - *vrf_id = std::stoi(res); + *vrf_id = vpp_safe_stoi(res, "vrf_id"); } else { *vrf_id = 0; } @@ -1670,6 +1800,13 @@ sai_status_t SwitchVpp::vpp_create_router_interface( vpp_set_interface_mtu(obj_id, vlan_id, attr_type_mtu->value.u32); } + auto attr_loopback = sai_metadata_get_attr_by_id(SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION, attr_count, attr_list); + + if (attr_loopback != NULL) + { + vpp_set_interface_loopback_action(obj_id, vlan_id, attr_loopback->value.s32); + } + bool v4_is_up = false, v6_is_up = false; auto attr_type_v4 = sai_metadata_get_attr_by_id(SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE, attr_count, attr_list); @@ -1714,6 +1851,20 @@ sai_status_t SwitchVpp::vpp_update_router_interface( } rif_type = attr.value.s32; + if (rif_type == SAI_ROUTER_INTERFACE_TYPE_VLAN) + { + // VLAN RIFs carry no PORT_ID; they are backed by the bridge BVI + // (bvi). Apply the attributes we support on the BVI. + auto attr_loopback = sai_metadata_get_attr_by_id(SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION, attr_count, attr_list); + + if (attr_loopback != NULL) + { + vpp_set_rif_loopback_action(object_id, attr_loopback->value.s32); + } + + return SAI_STATUS_SUCCESS; + } + attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; status = get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, object_id, 1, &attr); @@ -1767,6 +1918,13 @@ sai_status_t SwitchVpp::vpp_update_router_interface( vpp_set_interface_mtu(obj_id, vlan_id, attr_type_mtu->value.u32); } + auto attr_loopback = sai_metadata_get_attr_by_id(SAI_ROUTER_INTERFACE_ATTR_LOOPBACK_PACKET_ACTION, attr_count, attr_list); + + if (attr_loopback != NULL) + { + vpp_set_interface_loopback_action(obj_id, vlan_id, attr_loopback->value.s32); + } + bool v4_is_up = false, v6_is_up = false; auto attr_type_v4 = sai_metadata_get_attr_by_id(SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE, attr_count, attr_list); @@ -1854,6 +2012,11 @@ sai_status_t SwitchVpp::vpp_remove_router_interface(sai_object_id_t rif_id) return SAI_STATUS_FAILURE; } + // Clear any loopback (hairpin) drop action first so the underlying port/LAG/BVI + // does not retain the DROP output-arc feature after this RIF is removed; a later + // RIF reusing the same VPP interface would otherwise inherit a stale DROP. + vpp_set_rif_loopback_action(rif_id, SAI_PACKET_ACTION_FORWARD); + if (attr.value.s32 == SAI_ROUTER_INTERFACE_TYPE_VLAN) { SWSS_LOG_NOTICE("Invoking BVI interface create for attr type %d", attr.value.s32); diff --git a/vslib/vpp/SwitchVppUtils.cpp b/vslib/vpp/SwitchVppUtils.cpp index 1648931128..7553e6404c 100644 --- a/vslib/vpp/SwitchVppUtils.cpp +++ b/vslib/vpp/SwitchVppUtils.cpp @@ -4,8 +4,22 @@ #include "vppxlate/SaiVppXlate.h" +#include +#include + using namespace saivs; +int saivs::vpp_safe_stoi(const std::string& s, const char* tag) +{ + try { + return std::stoi(s); + } catch (const std::exception& e) { + SWSS_LOG_ERROR("vpp_safe_stoi: failed to parse '%s' as int (%s): %s", + s.c_str(), tag, e.what()); + return 0; + } +} + sai_status_t saivs::find_attrib_in_list( _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list, diff --git a/vslib/vpp/SwitchVppUtils.h b/vslib/vpp/SwitchVppUtils.h index aca8a342b2..41b025cddf 100644 --- a/vslib/vpp/SwitchVppUtils.h +++ b/vslib/vpp/SwitchVppUtils.h @@ -38,6 +38,16 @@ extern "C" { namespace saivs { + /* + * Parse a decimal integer, guarding against std::stoi throwing on malformed + * input. An uncaught std::invalid_argument/out_of_range here propagates to + * Syncd::run's handler, which drops syncd into shutdown-wait mode and stops + * answering any request. On failure this logs and returns 0; callers that + * cannot tolerate a 0 fallback must validate the input before calling. + * 'tag' is a short descriptive context string for the error log. + */ + int vpp_safe_stoi(const std::string& s, const char* tag); + sai_status_t find_attrib_in_list( _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list, diff --git a/vslib/vpp/vppxlate/SaiVppXlate.c b/vslib/vpp/vppxlate/SaiVppXlate.c index a868050f21..662d2e27a7 100644 --- a/vslib/vpp/vppxlate/SaiVppXlate.c +++ b/vslib/vpp/vppxlate/SaiVppXlate.c @@ -56,6 +56,9 @@ #include #include +#include +#include + #include #include @@ -166,6 +169,24 @@ #include #undef vl_api_version +/* sonic_ext (RIF loopback) API inclusion */ + +#define vl_typedefs +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_calcsizefun +#include +#undef vl_calcsizefun + +#define vl_api_version(n, v) static u32 sonic_ext_api_version = v; +#include +#undef vl_api_version + /* interface API inclusion */ #define vl_typedefs @@ -1375,6 +1396,13 @@ vl_api_tunterm_acl_interface_add_del_reply_t_handler(vl_api_tunterm_acl_interfac set_reply_status(retval); } +static void +vl_api_iface_loopback_set_action_reply_t_handler(vl_api_iface_loopback_set_action_reply_t *msg) +{ + int retval = (int)ntohl((uint32_t)msg->retval); + set_reply_status(retval); +} + static void vl_api_bond_create_reply_t_handler (vl_api_bond_create_reply_t *msg) { @@ -1526,6 +1554,7 @@ static void vl_api_add_node_next_reply_t_handler( static u16 interface_msg_id_base, memclnt_msg_id_base, __plugin_msg_base; static u16 l2_msg_id_base, vxlan_msg_id_base, ipip_msg_id_base; static u16 tunterm_msg_id_base; +static u16 iface_loopback_msg_id_base; static u16 bfd_msg_id_base; static u16 sr_msg_id_base; static u16 bond_msg_id_base; @@ -1706,6 +1735,9 @@ vl_api_acl_interface_add_del_reply_t_handler(vl_api_acl_interface_add_del_reply_ #define TUNTERM_MSG_ID(id) \ (VL_API_##id + tunterm_msg_id_base) +#define IFACE_LOOPBACK_MSG_ID(id) \ + (VL_API_##id + iface_loopback_msg_id_base) + #define VXLAN_MSG_ID(id) \ (VL_API_##id + vxlan_msg_id_base) @@ -1734,7 +1766,8 @@ vl_api_acl_interface_add_del_reply_t_handler(vl_api_acl_interface_add_del_reply_ _(SFLOW_MSG_ID(SFLOW_ENABLE_DISABLE_REPLY), sflow_enable_disable_reply) \ _(SFLOW_MSG_ID(SFLOW_SAMPLING_RATE_SET_REPLY), sflow_sampling_rate_set_reply) \ _(IPIP_MSG_ID(IPIP_ADD_TUNNEL_REPLY), ipip_add_tunnel_reply) \ - _(IPIP_MSG_ID(IPIP_DEL_TUNNEL_REPLY), ipip_del_tunnel_reply) + _(IPIP_MSG_ID(IPIP_DEL_TUNNEL_REPLY), ipip_del_tunnel_reply) \ + _(IFACE_LOOPBACK_MSG_ID(IFACE_LOOPBACK_SET_ACTION_REPLY), iface_loopback_set_action_reply) static void vpp_plugin_vpe_init(void) { @@ -1818,6 +1851,10 @@ static void get_base_msg_id() msg_base_lookup_name = format (0, "sflow_%08x%c", sflow_api_version, 0); sflow_msg_id_base = vl_client_get_first_plugin_msg_id ((char *) msg_base_lookup_name); assert(sflow_msg_id_base != (u16) ~0); + + msg_base_lookup_name = format (0, "sonic_ext_%08x%c", sonic_ext_api_version, 0); + iface_loopback_msg_id_base = vl_client_get_first_plugin_msg_id ((char *) msg_base_lookup_name); + assert(iface_loopback_msg_id_base != (u16) ~0); } #define API_SOCKET_FILE "/run/vpp/api.sock" @@ -2073,6 +2110,40 @@ static int __delete_loopback (vat_main_t *vam, const char *hwif_name, u32 instan return ret; } +int vpp_iface_loopback_set_action (const char *hwif_name, int action) +{ + vat_main_t *vam = &vat_main; + vl_api_iface_loopback_set_action_t *mp; + u32 idx; + int ret; + + VPP_LOCK(); + + __plugin_msg_base = iface_loopback_msg_id_base; + + idx = get_swif_idx(vam, hwif_name); + if (idx == (u32) -1) { + SAIVPP_ERROR("Unable to get sw_index for %s", hwif_name); + VPP_UNLOCK(); + return -EINVAL; + } + + M (IFACE_LOOPBACK_SET_ACTION, mp); + mp->sw_if_index = htonl(idx); + mp->action = (u8) action; + + S (mp); + + WR (ret); + + if (ret) { SAIVPP_ERROR("%s failed(%d) %s action %d", __func__, ret, hwif_name, action); } + else { SAIVPP_INFO("%s %s action %d", __func__, hwif_name, action); } + + VPP_UNLOCK(); + + return ret; +} + static int __create_sub_interface (vat_main_t *vam, vl_api_interface_index_t if_idx, u32 sub_id, u16 vlan_id, u32 *new_sw_if_index) { vl_api_create_subif_t *mp; diff --git a/vslib/vpp/vppxlate/SaiVppXlate.h b/vslib/vpp/vppxlate/SaiVppXlate.h index ecf98cad21..da9501c71f 100644 --- a/vslib/vpp/vppxlate/SaiVppXlate.h +++ b/vslib/vpp/vppxlate/SaiVppXlate.h @@ -399,6 +399,7 @@ typedef enum { extern int vpp_sw_interface_find_by_ip(vpp_ip_addr_t *search_ip, uint32_t vrf_id, uint32_t *out_sw_if_index); + extern int vpp_iface_loopback_set_action(const char *hwif_name, int action); /* VPP Classify API for L2 punt */ extern int vpp_classify_table_create(uint32_t nbuckets, uint32_t memory_size,