简述

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;
}