Linux中VLAN功能
1、在linux系统中,VLAN功能实现
(1) 加载8021q模块
在Ubuntu中需用如下命令加载该模块:modprobe 8021q
在嵌入式linux中需在内核中加入8021q支持选项(Networking support -> Networking options ->802.1Q/802.1ad VLAN Support ),如编译成ko,则需手动加载8021q.ko驱动模块;
lsmod | grep 8021q //查询驱动模块;
(2) 建立VLAN虚拟网卡,在eth0网卡下加入子网络,例如命令如下:
ip link add link eth0 name eth0.20 type vlan id 20 //添加子网络;
ip link del eno1.20 //删除子网络
2、二层VLAN数据包的获取
在Linux系统中,建立socket无法直接获取二层网络数据包中带VLAN ID的数据包,但是可以通过sockopt函数设置PACKET_AUXDATA选项,将VLAN信息带上,提取,然后组成802.1q协议包,从而完成802.1q协议VLAN数据包的获取。
设置PACKET_AUXDATA选项:
int nOptLen = 1;
if( setsockopt( fd, SOL_PACKET, PACKET_AUXDATA, &nOptLen, sizeof( nOptLen ) ) < 0 )
{
perror( "setsockopt PACKET_AUXDATA fail!" );
close( fd );
return -1;
}
接收带VLAN信息数据:
struct msghdr msg;
struct iovec iov;
struct sockaddr_in Recver_addr;
struct tpacket_auxdata *aux_ptr;
struct cmsghdr *cmsg_ptr;
union
{
struct cmsghdr cmsg;
char buf[CMSG_SPACE( sizeof( struct tpacket_auxdata ) )];
}cmsg_buf;
iov.iov_base = cnRxBuf;
iov.iov_len = 2000;
msg.msg_name = &Recver_addr;
msg.msg_namelen = sizeof( Recver_addr );
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsg_buf;
msg.msg_controllen = sizeof( cmsg_buf );;
msg.msg_flags = 0;
...
nLen = recvmsg( Layer2EthFd, &msg, 0 );
if( nLen <= 0 ) continue;
for( cmsg_ptr = CMSG_FIRSTHDR( &msg ); cmsg_ptr; cmsg_ptr = CMSG_NXTHDR( &msg, cmsg_ptr ) )
{
// if( cmsg_ptr->cmsg_type != PACKET_AUXDATA ) continue;
aux_ptr = ( struct tpacket_auxdata * )CMSG_DATA( cmsg_ptr );
// printf( " tpid: %04x, tci: %04x\n", aux_ptr->tp_vlan_tpid, aux_ptr->tp_vlan_tci );
if( 0x8100 == aux_ptr->tp_vlan_tpid )
{
memcpy( cnVlanBuf, cnRxBuf, 12 );
cnVlanBuf[12] = aux_ptr->tp_vlan_tpid >> 8;
cnVlanBuf[13] = aux_ptr->tp_vlan_tpid & 0x00FF;
cnVlanBuf[14] = aux_ptr->tp_vlan_tci >> 8;
cnVlanBuf[15] = aux_ptr->tp_vlan_tci & 0x00FF;
memcpy( &cnVlanBuf[16], &cnRxBuf[12], nLen - 12 );
nLen += 4;
write( Layer2EnsFd, cnVlanBuf, nLen );
continue;
}
}
版权声明:本文为zwenqian0602原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。