in vslib/SwitchStateBaseFdb.cpp [387:585]
void SwitchStateBase::process_packet_for_fdb_event(
_In_ sai_object_id_t portId,
_In_ const std::string& name,
_In_ const uint8_t *buffer,
_In_ size_t size)
{
SWSS_LOG_ENTER();
// we would need hostif info here and maybe interface index, then we can
// find host info from index
uint32_t frametime = (uint32_t)time(NULL);
/*
* We add +2 in case if frame contains 1Q VLAN tag.
*/
if (size < (sizeof(ethhdr) + 2))
{
SWSS_LOG_WARN("ethernet frame is too small: %zu", size);
return;
}
const ethhdr *eh = (const ethhdr*)buffer;
uint16_t proto = htons(eh->h_proto);
uint16_t vlan_id = DEFAULT_VLAN_NUMBER;
bool tagged = (proto == ETH_P_8021Q);
if (tagged)
{
// this is tagged frame, get vlan id from frame
uint16_t tci = htons(((const uint16_t*)&eh->h_proto)[1]); // tag is after h_proto field
vlan_id = tci & 0xfff;
if (vlan_id == 0xfff)
{
SWSS_LOG_WARN("invalid vlan id %u in ethernet frame on %s", vlan_id, name.c_str());
return;
}
if (vlan_id == 0)
{
// priority packet, frame should be treated as non tagged
tagged = false;
}
}
if (tagged == false)
{
// untagged ethernet frame
sai_attribute_t attr;
#ifdef SAI_LAG_ATTR_PORT_VLAN_ID
sai_object_id_t lag_id;
if (getLagFromPort(portid, lag_id))
{
// if port belongs to lag we need to get SAI_LAG_ATTR_PORT_VLAN_ID
attr.id = SAI_LAG_ATTR_PORT_VLAN_ID
sai_status_t status = get(SAI_OBJECT_TYPE_LAG, lag_id, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("failed to get lag vlan id from lag %s",
sai_serialize_object_id(lag_id).c_str());
return;
}
vlan_id = attr.value.u16;
if (isLagOrPortRifBased(lag_id))
{
// this lag is router interface based, skip mac learning
return;
}
}
else
#endif
{
attr.id = SAI_PORT_ATTR_PORT_VLAN_ID;
sai_status_t status = get(SAI_OBJECT_TYPE_PORT, portId, 1, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("failed to get port vlan id from port %s",
sai_serialize_object_id(portId).c_str());
return;
}
// untagged port vlan (default is 1, but may change setting port attr)
vlan_id = attr.value.u16;
}
}
sai_object_id_t lag_id;
if (getLagFromPort(portId, lag_id) && isLagOrPortRifBased(lag_id))
{
SWSS_LOG_DEBUG("lag %s is rif based, skip mac learning for port %s",
sai_serialize_object_id(lag_id).c_str(),
sai_serialize_object_id(portId).c_str());
return;
}
if (isLagOrPortRifBased(portId))
{
SWSS_LOG_DEBUG("port %s is rif based, skip mac learning",
sai_serialize_object_id(portId).c_str());
return;
}
// we have vlan and mac address which is KEY, so just see if that is already defined
FdbInfo fi;
fi.setPortId((lag_id != SAI_NULL_OBJECT_ID) ? lag_id : portId);
fi.setVlanId(vlan_id);
memcpy(fi.m_fdbEntry.mac_address, eh->h_source, sizeof(sai_mac_t));
std::set<FdbInfo>::iterator it = m_fdb_info_set.find(fi);
if (it != m_fdb_info_set.end())
{
// this key was found, update timestamp
// and since iterator is const we need to reinsert
fi = *it;
fi.setTimestamp(frametime);
m_fdb_info_set.insert(fi);
return;
}
// key was not found, get additional information
fi.setTimestamp(frametime);
fi.m_fdbEntry.switch_id = m_switch_id;
findBridgeVlanForPortVlan(portId, vlan_id, fi.m_fdbEntry.bv_id, fi.m_bridgePortId);
if (fi.getFdbEntry().bv_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_WARN("skipping mac learn for %s, since BV_ID was not found for mac",
sai_serialize_fdb_entry(fi.getFdbEntry()).c_str());
// bridge was not found, skip mac learning
return;
}
sai_attribute_t attr;
attr.id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE;
sai_status_t status = get(SAI_OBJECT_TYPE_BRIDGE_PORT, fi.getBridgePortId(), 1, &attr);
if (status == SAI_STATUS_SUCCESS)
{
if (attr.value.s32 == SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW)
{
SWSS_LOG_INFO("inserting to fdb_info set: %s, vlan id: %d",
sai_serialize_fdb_entry(fi.getFdbEntry()).c_str(),
fi.getVlanId());
m_fdb_info_set.insert(fi);
processFdbInfo(fi, SAI_FDB_EVENT_LEARNED);
}
else if (attr.value.s32 == SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE)
{
// do not learn, actually linux kernel will learn that MAC
}
else
{
SWSS_LOG_WARN("not supported SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE: %d, for %s",
attr.value.s32,
sai_serialize_fdb_entry(fi.getFdbEntry()).c_str());
}
}
else
{
SWSS_LOG_ERROR("failed to get SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE for %s: %s",
sai_serialize_object_id(fi.getBridgePortId()).c_str(),
sai_serialize_status(status).c_str());
}
}