简述
VLAN(Virtual Local Area Network)即虚拟局域网,是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。VLAN内的主机间可以直接通信,而VLAN间不能直接通信,从而将广播报文限制在一个VLAN内。
本节代码主要实现vlan功能配置,将端口1、5、8划分到一个vlan下(其中,1端口通过转接板连接PC端),然后通过ping 的方式测试vlan功能,当然也可使用抓包的方法测试vlan功能。
本节代码提供SDK,调用时可以传参。参数封装为结构体,对于参数较多的可以使用结构体来封装。
交互式实现方式:变参的输入使用do…while 结构,使用getchar() != '\n’作为循环结束的标志。
do
{
scanf("%d", &num[i]);
i++;
}while(getchar() != '\n');
SDK实现方式:寄存器的宏定义和位的宏定义都在wlan.c中,对外不暴露;代码的复用,使用宏定义代替写入的数值;端口号和默认vlan ID传入时,要含有个数参数,不能使用sizeof获取。
交互方式实现
vlan.c
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "types.h"
#include "bcm8953xlib.h"
#include "spi_bcm5300x.h"
int VlanInit();
int main(int argc, char *argv[])
{
int ret = 0;
ret = hal_spi_init("/dev/spidev1.0");
if(ret < 0)
{
printf("hal_spi_init error:%d\n", ret);
}
ret = VlanInit();
hal_spi_exit();
return ret;
}
int VlanInit()
{
uint8 u8data;
uint16 u16data;
uint32 u32data;
int enable = 0;
int ports = 0;
unsigned int DefVID = 0x0b003410;
int num[128];
int count = 0;
int PortNum[128];
int DefaultID[128];
int AddressInterval[128];
int i = 0;
int j = 0;
int k = 0;
uint16 VLANID;
printf("开启VLAN功能\n");
printf("0:使用默认配置; 1:更改默认配置\n");
printf("请输入您的选择:");
scanf("%d", &enable);
if(enable == 0)
{
return enable;
}
//enable 802.1q
mgmt_spi_wr8(0x0b003400, 0xe3);
usleep(10000);
mgmt_spi_rd8(0x0b003400, &u8data);
// printf("addr:0x0b003400 read value 0x%x\n", u8data);
do
{
mgmt_spi_wr8(0x0b000580, 0x82);
usleep(10000);
mgmt_spi_rd8(0x0b000580, &u8data);
// printf("addr:0x0b000580 read value 0x%x\n", u8data);
printf("\n输入要设置的端口号(以空格分开,以回车结束):");
do
{
scanf("%d", &num[i]);
i++;
}while(getchar() != '\n');
count = i;
if(count != 0)
{
printf("输入的端口号为:");
for(i = 0; i < count; i++)
{
printf("%d\t", num[i]);
}
for(i = 0; i < count; i++)
{
ports |= (1 << num[i]);
}
// printf("\nports = 0x%x.", ports);
printf("\n\n端口属性设置:0-Untagged port;1-tagged port");
printf("\n请输入您的选择:");
scanf("%d", &enable);
if(0 == enable)
{
for(i = 0; i < count; i++)
{
ports |= (1 << (9 + num[i]));
}
// printf("ports = 0x%x.", ports);
}
}
mgmt_spi_wr32(0x0b000583, ports);
usleep(10000);
mgmt_spi_rd32(0x0b000583, &u32data);
// printf("\naddr:0x0b000583 read value 0x%x\n", u32data);
printf("\n\n0:使用端口默认VLANID; 1:更改端口默认VLANID");
printf("\n请输入您的选择:");
scanf("%d", &enable);
if(1== enable)
{
printf("输入要设置的端口号(以空格分开,以回车结束):");
do
{
scanf("%d", &PortNum[j]);
j++;
}while(getchar() != '\n');
count = j;
if(count != 0)
{
printf("输入的端口号为:");
for(j = 0; j < count; j++)
{
printf("%d\t", PortNum[j]);
}
printf("\n分别输入默认VLANID的值(16进制 范围0x1~0xffe 以空格分开,以回车结束):");
do
{
scanf("%x", &DefaultID[k]);
k++;
}while(getchar() != '\n');
for(k = 0; k < count; k++)
{
DefVID += PortNum[k] * 2;
mgmt_spi_wr16(DefVID, DefaultID[k]);
usleep(10000);
mgmt_spi_rd16(DefVID, &u16data);
// printf("addr:0x%x read value ,0x%x\n", DefVID, u16data);
DefVID = 0x0b003410;
}
}
}
printf("\n\n输入端口所属的VLANID: ");
scanf("%x", &VLANID);
mgmt_spi_wr16(0x0b000581, VLANID);
usleep(10000);
mgmt_spi_rd16(0x0b000581, &u16data);
// printf("addr:0x0b000581 read value 0x%x\n", u16data);
mgmt_spi_wr8(0x0b000580, 0x80);
usleep(10000);
mgmt_spi_rd8(0x0b000580, &u8data);
// printf("addr:0x0b000580 read value 0x%x\n", u8data);
printf("\n\n0:停止划分VLAN; 1:继续划分VLAN");
printf("\n请输入您的选择:");
scanf("%d", &enable);
}while(enable);
return 0;
}
SDK方式实现
vlan.h
/***********************************************************************
\* 文 件 名 称 : vlan.h
\* 功 能 描 述 : vlan模块头文件
\* 开 发 人 员 : gupan
\* 日期 版本 修改人 描述
\* ========== ======= ========= =======================================
\* 2022-02-09 V1.0 gupan Create
*
\* @Copyright (C) 2022 .wanji. all right reserved
***********************************************************************/
#ifndef __VLAN_H_
#define __VLAN_H_
#define Untagged_Mode 0
#define Tagged_Mode 1
#define Port_Size 9
typedef enum
{
Port_Mode0 = Untagged_Mode,
Port_Mode1 = Tagged_Mode
}Port_Mode;
typedef struct
{
int length;
int Ports_Defarray[Port_Size];
int ID_array[Port_Size];
}__attribute__((packed)) DefTag;
typedef struct
{
int len;
int Ports_array[Port_Size];
}__attribute__((packed)) PortArray;
typedef struct
{
int ID;
int count;
Port_Mode mode;
PortArray ports;
DefTag DefTagPort;
}__attribute__((packed)) Data;
/*********************************************************************
函数名称 : VLAN_Init
功 能 : vlan模块初始化
参 数 : 无;
返 回 值 : 0:成功;-1:失败
*********************************************************************/
int VLAN_Init();
/*********************************************************************
函数名称 : Clear_VlanTable
功 能 : 清除vlan table
参 数 : 无;
返 回 值 : 0:成功;-1:失败
*********************************************************************/
int Clear_VlanTable();
/*********************************************************************
函数名称 : VLAN_Set
功 能 : VLAN功能配置
参 数 : 无;
返 回 值 : 0:成功;-1:失败
*********************************************************************/
int VLAN_Set(Data *data);
#endif
vlan.c
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "types.h"
#include "bcm8953xlib.h"
#include "spi_bcm5300x.h"
#include "vlan.h"
//Register definitions
#define Dot1q_CON0_REG 0x0b003400
#define VTABLE_RWC_REG 0x0b000580
#define VTABLE_ENT_REG 0x0b000583
#define DEFAULT_TAG_REG 0x0b003410
#define VTABLE_ADDR_REG 0x0b000581
//IEEE 802.1Q VLAN Control 0 Register bit positions
#define CHANGE_1P_INNER (1 << 0)
#define CHANGE_1P_VID_OUTER (1 << 1)
#define CHANGE_1Q_VID (1 << 3)
#define VLAN_LEARN_MODE (3 << 5)
#define VLAN_EN (1 << 7)
//VLAN Table RWC Control Register bit positions
#define ARLA_VTBL_RW_CLR (2 << 0)
#define ARLA_VTBL_STDN (1 << 7)
uint8 u8data;
uint16 u16data;
uint32 u32data;
/* return 0/-3 ok/err */
int VLAN_Init()
{
int value = 0;
value |= CHANGE_1P_INNER | CHANGE_1P_VID_OUTER | VLAN_LEARN_MODE | VLAN_EN;
mgmt_spi_wr8(Dot1q_CON0_REG, value);
usleep(10000);
return mgmt_spi_rd8(Dot1q_CON0_REG, &u8data);
//printf("addr:0x0b003400 read value 0x%x\n", u8data);
}
/* return 0/-3 ok/err */
int Clear_VlanTable()
{
int value = 0;
value |= ARLA_VTBL_RW_CLR | ARLA_VTBL_STDN;
mgmt_spi_wr8(VTABLE_RWC_REG, value);
usleep(10000);
return mgmt_spi_rd8(VTABLE_RWC_REG, &u8data);
//printf("addr:0x0b000580 read value 0x%x\n", u8data);
}
int Entry_VlanTable(Port_Mode mode, int* Port_array, int n)
{
int Mode = mode;
int Ports[16];
int count = n;
int i = 0;
unsigned int Bit_Ops = 0;
for(i = 0; i < count; i++)
{
Ports[i] = Port_array[i];
//printf("%d\t", Ports[i]);
Bit_Ops |= (1 << Ports[i]);
if((Ports[i] < 0) || (Ports[i] > 8))
{
printf("\n端口号范围为0~8");
return -1;
}
}
//printf("\nBit_Ops = 0x%x", Bit_Ops);
if(Untagged_Mode == Mode)
{
for(i = 0; i < count; i++)
{
Bit_Ops |= (1 << (9 + Ports[i]));
}
//printf("\nBit_Ops = 0x%x", Bit_Ops);
}
mgmt_spi_wr32(VTABLE_ENT_REG, Bit_Ops);
usleep(10000);
mgmt_spi_rd32(VTABLE_ENT_REG,&u32data);
//printf("\naddr:0x0b000583 read value 0x%x", u32data);
return 0;
}
int Set_DefTag(int* Port_array, int* array_ID, int n)
{
unsigned int Def_Tag_Reg = DEFAULT_TAG_REG;
int Ports[16];
int Ports_ID[16];
int count = n;
int i = 0;
//printf("\n");
for(i = 0; i < count; i++)
{
Ports[i] = Port_array[i];
//printf("%d\t", Ports[i]);
Ports_ID[i] = array_ID[i];
//printf("%d\t\t", Ports_ID[i]);
if((Ports[i] < 0) || (Ports[i] > 8))
{
printf("\n端口号范围为0~8");
return -1;
}
if((Ports_ID[i] < 1) || (Ports_ID[i] > 4094))
{
printf("\nVLAN ID有效范围为1~4094");
return -1;
}
}
// printf("\n");
for(i = 0; i < count; i++)
{
Def_Tag_Reg += Ports[i] * 2;
mgmt_spi_wr16(Def_Tag_Reg, Ports_ID[i]);
usleep(10000);
mgmt_spi_rd16(Def_Tag_Reg, &u16data);
// printf("addr:0x%x read value ,0x%x\n", Def_Tag_Reg, u16data);
Def_Tag_Reg = DEFAULT_TAG_REG;
}
return 0;
}
int Set_VLANID(int i)
{
int VID = i;
int value = 0;
if((VID < 1) || (VID > 4094))
{
printf("\nVLAN ID有效范围为1~4094");
return -1;
}
mgmt_spi_wr16(VTABLE_ADDR_REG, VID);
usleep(10000);
mgmt_spi_rd16(VTABLE_ADDR_REG, &u16data);
// printf("addr:0x0b000581 read value 0x%x\n", u16data);
value |= ARLA_VTBL_STDN;
mgmt_spi_wr8(VTABLE_RWC_REG, value);
usleep(10000);
mgmt_spi_rd8(VTABLE_RWC_REG, &u8data);
//printf("addr:0x0b000580 read value 0x%x\n", u8data);
return 0;
}
int VLAN_Set(Data *data)
{
int i = 0;
int ret = -1;
int Port_num = 0;
int ID_num = 0;
int ID = 0;
int count = 0;
Port_Mode mode;
int Ports_array[Port_Size];
int Ports_Defarray[Port_Size];
int ID_array[Port_Size];
ID = data->ID;
count = data->count;
mode = data->mode;
// printf("\n%d", ID);
//printf("\n%d", mode);
Port_num = data->ports.len;
//printf("\nPort_num = %d", Port_num);
ID_num = data->DefTagPort.length;
//printf("\nID_num = %d", ID_num);
//printf("\n");
for(i = 0; i < Port_num; i++)
{
Ports_array[i] = data->ports.Ports_array[i];
// printf("%d\t", Ports_array[i]);
}
//printf("\n");
for(i = 0; i < ID_num; i++)
{
Ports_Defarray[i] =data->DefTagPort.Ports_Defarray[i];
// printf("%d\t",Ports_Defarray[i]);
}
//printf("\n");
for(i = 0; i < ID_num; i++)
{
ID_array[i] =data->DefTagPort.ID_array[i];
// printf("%d\t",ID_array[i]);
}
ret = Entry_VlanTable(mode, Ports_array, Port_num);
if(-1 == ret)
{
//printf("\nSet VLAN table fail!");
return ret;
}
ret = Set_DefTag(Ports_Defarray, ID_array, ID_num);
if(-1 == ret)
{
// printf("\nSet Default Tag fail!");
return ret;
}
ret = Set_VLANID(ID);
if(-1 == ret)
{
// printf("\nSet VLAN ID fail!");
return ret;
}
return 0;
}
main.c
#include "vlan.h"
int main(int argc, char *argv[])
{
Data data;
data.ID = 2;
data.count = 1;
data.mode = Untagged_Mode;
data.ports.len = 3;
data.ports.Ports_array[0] = 1;
data.ports.Ports_array[1] = 5;
data.ports.Ports_array[2] = 8;
data.DefTagPort.length = 3;
data.DefTagPort.Ports_Defarray[0] = 1;
data.DefTagPort.Ports_Defarray[1] = 5;
data.DefTagPort.Ports_Defarray[2] = 8;
data.DefTagPort.ID_array[0] = 2;
data.DefTagPort.ID_array[1] = 2;
data.DefTagPort.ID_array[2] = 2;
int ret = 0;
ret = hal_spi_init("/dev/spidev1.0");
if(ret < 0)
{
printf("hal_spi_init error:%d\n", ret);
}
VLAN_Init();
Clear_VlanTable();
ret = VLAN_Set(&data);
if(-1 == ret)
{
printf("vlan set fail!\n");
}
hal_spi_exit();
return ret;
}