vslib/SwitchStateBaseHostif.cpp (654 lines of code) (raw):
#include "SwitchStateBase.h"
#include "HostInterfaceInfo.h"
#include "EventPayloadNotification.h"
#include "meta/sai_serialize.h"
#include "meta/NotificationPortStateChange.h"
#include "swss/logger.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <netlink/route/link.h>
#include <netlink/route/addr.h>
#include <linux/if.h>
#include <algorithm>
#include <fstream>
using namespace saivs;
// XXX set must also be supported when we change operational status up/down and
// probably also generate notification then
#define ETH_FRAME_BUFFER_SIZE (0x4000)
#define MAX_INTERFACE_NAME_LEN (IFNAMSIZ-1)
#define SAI_VS_VETH_PREFIX "v"
int SwitchStateBase::vs_create_tap_device(
_In_ const char *dev,
_In_ int flags)
{
SWSS_LOG_ENTER();
const char *tundev = "/dev/net/tun";
int fd = open(tundev, O_RDWR);
if (fd < 0)
{
SWSS_LOG_ERROR("failed to open %s", tundev);
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = (short int)flags; // IFF_TUN or IFF_TAP, IFF_NO_PI
strncpy(ifr.ifr_name, dev, MAX_INTERFACE_NAME_LEN);
int err = ioctl(fd, TUNSETIFF, (void *) &ifr);
if (err < 0)
{
SWSS_LOG_ERROR("ioctl TUNSETIFF on fd %d %s failed, err %d", fd, dev, err);
close(fd);
return err;
}
return fd;
}
int SwitchStateBase::vs_set_dev_mac_address(
_In_ const char *dev,
_In_ const sai_mac_t& mac)
{
SWSS_LOG_ENTER();
int s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
SWSS_LOG_ERROR("failed to create socket, errno: %d", errno);
return -1;
}
struct ifreq ifr;
strncpy(ifr.ifr_name, dev, MAX_INTERFACE_NAME_LEN);
memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
int err = ioctl(s, SIOCSIFHWADDR, &ifr);
if (err < 0)
{
SWSS_LOG_ERROR("ioctl SIOCSIFHWADDR on socket %d %s failed, err %d", s, dev, err);
}
close(s);
return err;
}
void SwitchStateBase::update_port_oper_status(
_In_ sai_object_id_t port_id,
_In_ sai_port_oper_status_t port_oper_status)
{
SWSS_LOG_ENTER();
sai_attribute_t attr;
attr.id = SAI_PORT_ATTR_OPER_STATUS;
attr.value.s32 = port_oper_status;
sai_status_t status = set(SAI_OBJECT_TYPE_PORT, port_id, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to update port status %s: %s",
sai_serialize_object_id(port_id).c_str(),
sai_serialize_port_oper_status(port_oper_status).c_str());
}
}
void SwitchStateBase::send_port_oper_status_notification(
_In_ sai_object_id_t portId,
_In_ sai_port_oper_status_t status,
_In_ bool force)
{
SWSS_LOG_ENTER();
sai_port_oper_status_notification_t data;
data.port_id = portId;
data.port_state = status;
auto meta = getMeta();
if (meta)
{
meta->meta_sai_on_port_state_change(1, &data);
}
auto objectType = objectTypeQuery(portId); // can be port, bridge port, lag
if (objectType != SAI_OBJECT_TYPE_PORT)
{
SWSS_LOG_ERROR("object type %s not supported on portId %s",
sai_serialize_object_type(objectType).c_str(),
sai_serialize_object_id(portId).c_str());
return;
}
sai_attribute_t attr;
attr.id = SAI_PORT_ATTR_OPER_STATUS;
if (get(objectType, portId, 1, &attr) != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to get port attribute SAI_PORT_ATTR_OPER_STATUS");
}
else
{
if (force)
{
SWSS_LOG_NOTICE("explicitly send SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY for port %s: %s (port was UP)",
sai_serialize_object_id(data.port_id).c_str(),
sai_serialize_port_oper_status(data.port_state).c_str());
}
else if ((sai_port_oper_status_t)attr.value.s32 == data.port_state)
{
SWSS_LOG_INFO("port oper status didn't changed, will not send notification");
return;
}
}
attr.id = SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY;
if (get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr) != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to get SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY for switch %s",
sai_serialize_object_id(m_switch_id).c_str());
return;
}
if (attr.value.ptr == NULL)
{
SWSS_LOG_INFO("SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY callback is NULL");
return;
}
sai_switch_notifications_t sn = { };
sn.on_port_state_change = (sai_port_state_change_notification_fn)attr.value.ptr;
attr.id = SAI_PORT_ATTR_OPER_STATUS;
update_port_oper_status(portId, data.port_state);
SWSS_LOG_NOTICE("send event SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY for port %s: %s",
sai_serialize_object_id(data.port_id).c_str(),
sai_serialize_port_oper_status(data.port_state).c_str());
auto str = sai_serialize_port_oper_status_ntf(1, &data);
auto ntf = std::make_shared<sairedis::NotificationPortStateChange>(str);
auto payload = std::make_shared<EventPayloadNotification>(ntf, sn);
m_switchConfig->m_eventQueue->enqueue(std::make_shared<Event>(EVENT_TYPE_NOTIFICATION, payload));
}
int SwitchStateBase::ifup(
_In_ const char *dev,
_In_ sai_object_id_t port_id,
_In_ bool up,
_In_ bool explicitNotification)
{
SWSS_LOG_ENTER();
int s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
SWSS_LOG_ERROR("failed to open socket: %d", s);
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof ifr);
strncpy(ifr.ifr_name, dev , MAX_INTERFACE_NAME_LEN);
int err = ioctl(s, SIOCGIFFLAGS, &ifr);
if (err < 0)
{
SWSS_LOG_ERROR("ioctl SIOCGIFFLAGS on socket %d %s failed, err %d", s, dev, err);
close(s);
return err;
}
if (up && explicitNotification && (ifr.ifr_flags & IFF_UP))
{
close(s);
// interface status didn't changed, we need to send manual notification
// that interface status is UP but that notification would need to be
// sent after actual interface creation, since user may receive that
// notification before hostif create function will actually return,
// this can happen when syncd will be operating in synchronous mode
send_port_oper_status_notification(port_id, SAI_PORT_OPER_STATUS_UP, true);
return 0;
}
if (up)
{
ifr.ifr_flags |= IFF_UP;
}
else
{
ifr.ifr_flags &= ~IFF_UP;
}
err = ioctl(s, SIOCSIFFLAGS, &ifr);
if (err < 0)
{
SWSS_LOG_ERROR("ioctl SIOCSIFFLAGS on socket %d %s failed, err %d", s, dev, err);
}
close(s);
return err;
}
int SwitchStateBase::promisc(
_In_ const char *dev)
{
SWSS_LOG_ENTER();
int s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
SWSS_LOG_ERROR("failed to open socket: %d", s);
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof ifr);
strncpy(ifr.ifr_name, dev , MAX_INTERFACE_NAME_LEN);
int err = ioctl(s, SIOCGIFFLAGS, &ifr);
if (err < 0)
{
SWSS_LOG_ERROR("ioctl SIOCGIFFLAGS on socket %d %s failed, err %d", s, dev, err);
close(s);
return err;
}
if (ifr.ifr_flags & IFF_PROMISC)
{
close(s);
return 0;
}
ifr.ifr_flags |= IFF_PROMISC;
err = ioctl(s, SIOCSIFFLAGS, &ifr);
if (err < 0)
{
SWSS_LOG_ERROR("ioctl SIOCSIFFLAGS on socket %d %s failed, err %d", s, dev, err);
}
close(s);
return err;
}
int SwitchStateBase::vs_set_dev_mtu(
_In_ const char*name,
_In_ int mtu)
{
SWSS_LOG_ENTER();
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sock < 0)
{
SWSS_LOG_ERROR("create socket failed: %s", strerror(errno));
return sock;
}
struct ifreq ifr;
strncpy(ifr.ifr_name, name, MAX_INTERFACE_NAME_LEN);
ifr.ifr_mtu = mtu;
int err = ioctl(sock, SIOCSIFMTU, &ifr);
if (err == 0)
{
SWSS_LOG_INFO("success set mtu on %s to %d", name, mtu);
return 0;
}
SWSS_LOG_WARN("failed to set mtu on %s to %d: %s", name, mtu, strerror(errno));
return err;
}
std::string SwitchStateBase::vs_get_veth_name(
_In_ const std::string& tapname,
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
std::string vethname = SAI_VS_VETH_PREFIX + tapname;
// check if user override interface names
sai_attribute_t attr;
uint32_t lanes[8];
attr.id = SAI_PORT_ATTR_HW_LANE_LIST;
attr.value.u32list.count = 8;
attr.value.u32list.list = lanes;
if (get(SAI_OBJECT_TYPE_PORT, port_id, 1, &attr) != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("failed to get port %s lanes, using veth: %s",
sai_serialize_object_id(port_id).c_str(),
vethname.c_str());
}
else
{
if (m_switchConfig->m_laneMap)
{
auto ifname = m_switchConfig->m_laneMap->getInterfaceFromLaneNumber(lanes[0]);
if (ifname == "")
{
SWSS_LOG_WARN("failed to get ifname from lane number %u", lanes[0]);
}
else
{
SWSS_LOG_NOTICE("using %s instead of %s", ifname.c_str(), vethname.c_str());
vethname = ifname;
}
}
else
{
SWSS_LOG_WARN("laneMap is NULL for switch %s, index: %u",
sai_serialize_object_id(m_switch_id).c_str(),
m_switchConfig->m_switchIndex);
}
}
return vethname;
}
bool SwitchStateBase::hostif_create_tap_veth_forwarding(
_In_ const std::string &tapname,
_In_ int tapfd,
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
// we assume here that veth devices were added by user before creating this
// host interface, vEthernetX will be used for packet transfer between ip
// namespaces or ethernet device name used in lane map if provided
std::string vethname = vs_get_veth_name(tapname, port_id);
int packet_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (packet_socket < 0)
{
SWSS_LOG_ERROR("failed to open packet socket, errno: %d", errno);
return false;
}
int val = 1;
if (setsockopt(packet_socket, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) < 0)
{
SWSS_LOG_ERROR("setsockopt() set PACKET_AUXDATA failed: %s", strerror(errno));
return false;
}
// bind to device
struct sockaddr_ll sock_address;
memset(&sock_address, 0, sizeof(sock_address));
sock_address.sll_family = PF_PACKET;
sock_address.sll_protocol = htons(ETH_P_ALL);
sock_address.sll_ifindex = if_nametoindex(vethname.c_str());
if (sock_address.sll_ifindex == 0)
{
SWSS_LOG_ERROR("failed to get interface index for %s", vethname.c_str());
close(packet_socket);
return false;
}
SWSS_LOG_NOTICE("interface index = %d, %s\n", sock_address.sll_ifindex, vethname.c_str());
if (promisc(vethname.c_str()))
{
SWSS_LOG_ERROR("promisc failed on %s", vethname.c_str());
close(packet_socket);
return false;
}
if (bind(packet_socket, (struct sockaddr*) &sock_address, sizeof(sock_address)) < 0)
{
SWSS_LOG_ERROR("bind failed on %s", vethname.c_str());
close(packet_socket);
return false;
}
m_hostif_info_map[tapname] =
std::make_shared<HostInterfaceInfo>(
sock_address.sll_ifindex,
packet_socket,
tapfd,
tapname,
port_id,
m_switchConfig->m_eventQueue);
SWSS_LOG_NOTICE("setup forward rule for %s succeeded", tapname.c_str());
return true;
}
sai_status_t SwitchStateBase::vs_create_hostif_tap_interface(
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
// validate SAI_HOSTIF_ATTR_TYPE
auto attr_type = sai_metadata_get_attr_by_id(SAI_HOSTIF_ATTR_TYPE, attr_count, attr_list);
if (attr_type == NULL)
{
SWSS_LOG_ERROR("attr SAI_HOSTIF_ATTR_TYPE was not passed");
return SAI_STATUS_FAILURE;
}
/* The genetlink host interface is created to associate trap group to genetlink family and multicast group
* created by driver. It does not create any netdev interface. Hence skipping tap interface creation
*/
if (attr_type->value.s32 == SAI_HOSTIF_TYPE_GENETLINK)
{
SWSS_LOG_DEBUG("Skipping tap create for hostif type genetlink");
return SAI_STATUS_SUCCESS;
}
if (attr_type->value.s32 != SAI_HOSTIF_TYPE_NETDEV)
{
SWSS_LOG_ERROR("only SAI_HOSTIF_TYPE_NETDEV is supported");
return SAI_STATUS_FAILURE;
}
// validate SAI_HOSTIF_ATTR_OBJ_ID
auto attr_obj_id = sai_metadata_get_attr_by_id(SAI_HOSTIF_ATTR_OBJ_ID, attr_count, attr_list);
if (attr_obj_id == NULL)
{
SWSS_LOG_ERROR("attr SAI_HOSTIF_ATTR_OBJ_ID was not passed");
return SAI_STATUS_FAILURE;
}
sai_object_id_t obj_id = attr_obj_id->value.oid;
sai_object_type_t ot = objectTypeQuery(obj_id);
if (ot == SAI_OBJECT_TYPE_VLAN)
{
SWSS_LOG_DEBUG("Skipping tap creation for hostif with object type VLAN");
return SAI_STATUS_SUCCESS;
}
if (ot != SAI_OBJECT_TYPE_PORT)
{
SWSS_LOG_ERROR("SAI_HOSTIF_ATTR_OBJ_ID=%s expected to be PORT but is: %s",
sai_serialize_object_id(obj_id).c_str(),
sai_serialize_object_type(ot).c_str());
return SAI_STATUS_FAILURE;
}
// validate SAI_HOSTIF_ATTR_NAME
auto attr_name = sai_metadata_get_attr_by_id(SAI_HOSTIF_ATTR_NAME, attr_count, attr_list);
if (attr_name == NULL)
{
SWSS_LOG_ERROR("attr SAI_HOSTIF_ATTR_NAME was not passed");
return SAI_STATUS_FAILURE;
}
if (strnlen(attr_name->value.chardata, sizeof(attr_name->value.chardata)) >= MAX_INTERFACE_NAME_LEN)
{
SWSS_LOG_ERROR("interface name is too long: %.*s", MAX_INTERFACE_NAME_LEN, attr_name->value.chardata);
return SAI_STATUS_FAILURE;
}
std::string name = std::string(attr_name->value.chardata);
// create TAP device
SWSS_LOG_INFO("creating hostif %s", name.c_str());
int tapfd = vs_create_tap_device(name.c_str(), IFF_TAP | IFF_MULTI_QUEUE | IFF_NO_PI);
if (tapfd < 0)
{
SWSS_LOG_ERROR("failed to create TAP device for %s", name.c_str());
return SAI_STATUS_FAILURE;
}
SWSS_LOG_INFO("created TAP device for %s, fd: %d", name.c_str(), tapfd);
sai_attribute_t attr;
memset(&attr, 0, sizeof(attr));
attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS;
sai_status_t status = get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to get SAI_SWITCH_ATTR_SRC_MAC_ADDRESS on switch %s: %s",
sai_serialize_object_id(m_switch_id).c_str(),
sai_serialize_status(status).c_str());
}
int err = vs_set_dev_mac_address(name.c_str(), attr.value.mac);
if (err < 0)
{
SWSS_LOG_ERROR("failed to set MAC address %s for %s",
sai_serialize_mac(attr.value.mac).c_str(),
name.c_str());
close(tapfd);
return SAI_STATUS_FAILURE;
}
std::string vname = vs_get_veth_name(name, obj_id);
int mtu = ETH_FRAME_BUFFER_SIZE;
sai_attribute_t attrmtu;
attrmtu.id = SAI_PORT_ATTR_MTU;
if (get(SAI_OBJECT_TYPE_PORT, obj_id, 1, &attrmtu) == SAI_STATUS_SUCCESS)
{
mtu = attrmtu.value.u32;
SWSS_LOG_INFO("setting new MTU: %d on %s", mtu, vname.c_str());
}
vs_set_dev_mtu(vname.c_str(), mtu);
attr.id = SAI_PORT_ATTR_ADMIN_STATE;
status = get(SAI_OBJECT_TYPE_PORT, obj_id, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to get admin state for port %s",
sai_serialize_object_id(obj_id).c_str());
return status;
}
if (ifup(vname.c_str(), obj_id, attr.value.booldata, false))
{
SWSS_LOG_ERROR("ifup failed on %s", vname.c_str());
return SAI_STATUS_FAILURE;
}
if (!hostif_create_tap_veth_forwarding(name, tapfd, obj_id))
{
SWSS_LOG_ERROR("forwarding rule on %s was not added", name.c_str());
}
SWSS_LOG_INFO("mapping interface %s to port id %s",
vname.c_str(),
sai_serialize_object_id(obj_id).c_str());
setIfNameToPortId(vname, obj_id);
setPortIdToTapName(obj_id, name);
SWSS_LOG_INFO("created tap interface %s", name.c_str());
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchStateBase::vs_recreate_hostif_tap_interfaces()
{
SWSS_LOG_ENTER();
if (m_switchConfig->m_useTapDevice == false)
{
return SAI_STATUS_SUCCESS;
}
auto &objectHash = m_objectHash.at(SAI_OBJECT_TYPE_HOSTIF);
SWSS_LOG_NOTICE("attempt to recreate %zu tap devices for host interfaces", objectHash.size());
for (auto okvp: objectHash)
{
std::vector<sai_attribute_t> attrs;
for (auto akvp: okvp.second)
{
attrs.push_back(*akvp.second->getAttr());
}
vs_create_hostif_tap_interface((uint32_t)attrs.size(), attrs.data());
}
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchStateBase::vs_remove_hostif_tap_interface(
_In_ sai_object_id_t hostif_id)
{
SWSS_LOG_ENTER();
// get tap interface name
sai_attribute_t attr;
attr.id = SAI_HOSTIF_ATTR_TYPE;
sai_status_t status = get(SAI_OBJECT_TYPE_HOSTIF, hostif_id, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to get attr type for hostif %s",
sai_serialize_object_id(hostif_id).c_str());
return status;
}
/* The genetlink host interface is created to associate trap group to genetlink family and multicast group
* created by driver. It does not create any netdev interface. Hence skipping tap interface deletion
*/
if (attr.value.s32 == SAI_HOSTIF_TYPE_GENETLINK)
{
SWSS_LOG_DEBUG("Skipping tap delete for hostif type genetlink");
return SAI_STATUS_SUCCESS;
}
attr.id = SAI_HOSTIF_ATTR_OBJ_ID;
status = get(SAI_OBJECT_TYPE_HOSTIF, hostif_id, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to get object ID for hostif %s", sai_serialize_object_id(hostif_id).c_str());
return status;
}
if (objectTypeQuery(attr.value.oid) == SAI_OBJECT_TYPE_VLAN)
{
SWSS_LOG_DEBUG("Skipping tap deletion for hostif with object type VLAN");
return SAI_STATUS_SUCCESS;
}
attr.id = SAI_HOSTIF_ATTR_NAME;
status = get(SAI_OBJECT_TYPE_HOSTIF, hostif_id, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("failed to get attr name for hostif %s",
sai_serialize_object_id(hostif_id).c_str());
return status;
}
if (strnlen(attr.value.chardata, sizeof(attr.value.chardata)) >= MAX_INTERFACE_NAME_LEN)
{
SWSS_LOG_ERROR("interface name is too long: %.*s", MAX_INTERFACE_NAME_LEN, attr.value.chardata);
return SAI_STATUS_FAILURE;
}
// TODO this should be hosif_id or if index ?
std::string name = std::string(attr.value.chardata);
auto it = m_hostif_info_map.find(name);
if (it == m_hostif_info_map.end())
{
SWSS_LOG_ERROR("failed to find host info entry for tap device: %s", name.c_str());
return SAI_STATUS_FAILURE;
}
SWSS_LOG_NOTICE("attempting to remove tap device: %s", name.c_str());
auto info = it->second; // destructor will stop threads
// remove host info entry from map
m_hostif_info_map.erase(it);
// remove interface mapping
std::string vname = vs_get_veth_name(name, info->m_portId);
removeIfNameToPortId(vname);
removePortIdToTapName(info->m_portId);
SWSS_LOG_NOTICE("successfully removed hostif tap device: %s", name.c_str());
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchStateBase::createHostif(
_In_ sai_object_id_t object_id,
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
if (m_switchConfig->m_useTapDevice == true)
{
auto status = vs_create_hostif_tap_interface(attr_count, attr_list);
CHECK_STATUS(status);
}
auto sid = sai_serialize_object_id(object_id);
CHECK_STATUS(create_internal(SAI_OBJECT_TYPE_HOSTIF, sid, switch_id, attr_count, attr_list));
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchStateBase::removeHostif(
_In_ sai_object_id_t objectId)
{
SWSS_LOG_ENTER();
if (m_switchConfig->m_useTapDevice == true)
{
auto status = vs_remove_hostif_tap_interface(objectId);
CHECK_STATUS(status);
}
auto sid = sai_serialize_object_id(objectId);
CHECK_STATUS(remove_internal(SAI_OBJECT_TYPE_HOSTIF, sid));
return SAI_STATUS_SUCCESS;
}
bool SwitchStateBase::hasIfIndex(
_In_ int ifindex) const
{
SWSS_LOG_ENTER();
for (auto& kvp: m_hostif_info_map)
{
if (kvp.second->m_ifindex == ifindex)
{
return true;
}
}
return false;
}
bool SwitchStateBase::vs_get_oper_speed(
_In_ sai_object_id_t port_id,
_Out_ uint32_t& speed)
{
SWSS_LOG_ENTER();
auto info = findHostInterfaceInfoByPort(port_id);
if (!info)
{
SWSS_LOG_ERROR("Port %s don't exists",
sai_serialize_object_id(port_id).c_str());
return false;
}
auto veth_name = vs_get_veth_name(info->m_name, port_id);
std::string veth_speed_filename = "/sys/class/net/";
veth_speed_filename += veth_name;
veth_speed_filename += "/speed";
std::ifstream ifs(veth_speed_filename);
if (!ifs.is_open())
{
SWSS_LOG_ERROR("Failed to open %s", veth_speed_filename.c_str());
return false;
}
ifs >> speed;
ifs.close();
return true;
}
void SwitchStateBase::syncOnLinkMsg(
_In_ std::shared_ptr<EventPayloadNetLinkMsg> payload)
{
SWSS_LOG_ENTER();
// XXX if during switch shutdown lane map changed (port added/removed)
// then loaded lane map will point to wrong mapping
auto ifindex = payload->getIfIndex();
auto ifflags = payload->getIfFlags();
auto ifname = payload->getIfName();
auto msgtype = payload->getNlmsgType();
if (msgtype != RTM_NEWLINK)
{
// ignore delete message
return;
}
if (!hasIfIndex(ifindex))
{
// since we will receive messages from all indexes and all switches
// then we only need to check messages addressed for us and since
// ifindex is unique across system, then we will use that
return;
}
auto map = m_switchConfig->m_laneMap;
if (!map)
{
SWSS_LOG_ERROR("lane map for switch %s don't exists",
sai_serialize_object_id(m_switch_id).c_str());
return;
}
if (strncmp(ifname.c_str(), SAI_VS_VETH_PREFIX, sizeof(SAI_VS_VETH_PREFIX) - 1) != 0 &&
!map->hasInterface(ifname))
{
SWSS_LOG_ERROR("skipping newlink for %s, name not found in map", ifname.c_str());
return;
}
SWSS_LOG_NOTICE("newlink: ifindex: %d, ifflags: 0x%x, ifname: %s",
ifindex,
ifflags,
ifname.c_str());
auto state = (ifflags & IFF_LOWER_UP) ? SAI_PORT_OPER_STATUS_UP : SAI_PORT_OPER_STATUS_DOWN;
auto portId = getPortIdFromIfName(ifname);
send_port_oper_status_notification(portId, state, false);
}