Skip to content

Commit ab35dfa

Browse files
authored
Add support for vlan tagged frames in virtual switch (sonic-net#417)
1 parent 145ea44 commit ab35dfa

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

vslib/src/sai_vs_hostintf.cpp

+73-1
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,11 @@ int promisc(const char *dev)
794794
return err;
795795
}
796796

797+
#define ETH_JUMBO_FRAME_SIZE (9000)
798+
#define IEEE_8021Q_ETHER_TYPE (0x8100)
799+
#define MAC_ADDRESS_SIZE (6)
800+
#define VLAN_TAG_SIZE (4)
801+
797802
void veth2tap_fun(std::shared_ptr<hostif_info_t> info)
798803
{
799804
SWSS_LOG_ENTER();
@@ -804,7 +809,26 @@ void veth2tap_fun(std::shared_ptr<hostif_info_t> info)
804809
{
805810
// TODO convert to non blocking using select
806811

807-
ssize_t size = read(info->packet_socket, buffer, sizeof(buffer));
812+
struct msghdr msg;
813+
memset(&msg, 0, sizeof(struct msghdr));
814+
815+
struct sockaddr_storage src_addr;
816+
817+
struct iovec iov[1];
818+
819+
iov[0].iov_base = buffer; // buffer for message
820+
iov[0].iov_len = sizeof(buffer);
821+
822+
char control[0x1000]; // buffer for control messages
823+
824+
msg.msg_name = &src_addr;
825+
msg.msg_namelen = sizeof(src_addr);
826+
msg.msg_iov = iov;
827+
msg.msg_iovlen = 1;
828+
msg.msg_control = control;
829+
msg.msg_controllen = sizeof(control);
830+
831+
ssize_t size = recvmsg(info->packet_socket, &msg, 0);
808832

809833
if (size < 0)
810834
{
@@ -814,6 +838,47 @@ void veth2tap_fun(std::shared_ptr<hostif_info_t> info)
814838
continue;
815839
}
816840

841+
if (size < (ssize_t)sizeof(ethhdr) || size > ETH_JUMBO_FRAME_SIZE)
842+
{
843+
SWSS_LOG_ERROR("invalid ethernet frame length: %zu", msg.msg_controllen);
844+
continue;
845+
}
846+
847+
struct cmsghdr *cmsg;
848+
849+
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
850+
{
851+
if (cmsg->cmsg_level != SOL_PACKET || cmsg->cmsg_type != PACKET_AUXDATA)
852+
continue;
853+
854+
struct tpacket_auxdata* aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
855+
856+
if ((aux->tp_status & TP_STATUS_VLAN_VALID) &&
857+
(aux->tp_status & TP_STATUS_VLAN_TPID_VALID))
858+
{
859+
SWSS_LOG_DEBUG("got vlan tci: 0x%x, vlanid: %d", aux->tp_vlan_tci, aux->tp_vlan_tci & 0xFFF);
860+
861+
// inject vlan tag into frame
862+
863+
// for overlapping buffers
864+
memmove(buffer + 2 * MAC_ADDRESS_SIZE + VLAN_TAG_SIZE,
865+
buffer + 2 * MAC_ADDRESS_SIZE,
866+
size - (2 * MAC_ADDRESS_SIZE));
867+
868+
uint16_t tci = htons(aux->tp_vlan_tci);
869+
uint16_t tpid = htons(IEEE_8021Q_ETHER_TYPE);
870+
871+
uint16_t* pvlan = (uint16_t*)(buffer + 2 * MAC_ADDRESS_SIZE);
872+
873+
pvlan[0] = tpid;
874+
pvlan[1] = tci;
875+
876+
size += VLAN_TAG_SIZE;
877+
878+
break;
879+
}
880+
}
881+
817882
process_packet_for_fdb_event(buffer, size, info);
818883

819884
if (write(info->tapfd, buffer, size) < 0)
@@ -934,6 +999,13 @@ bool hostif_create_tap_veth_forwarding(
934999
return false;
9351000
}
9361001

1002+
int val = 1;
1003+
if (setsockopt(packet_socket, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) < 0)
1004+
{
1005+
SWSS_LOG_ERROR("setsockopt() set PACKET_AUXDATA failed: %s", strerror(errno));
1006+
return false;
1007+
}
1008+
9371009
// bind to device
9381010

9391011
struct sockaddr_ll sock_address;

0 commit comments

Comments
 (0)