Commit ce6644c0 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

userspace/tools: adding tool for configuring VLANs, still misses ioctl calls to endpoints

parent 37bc6592
......@@ -14,3 +14,4 @@ wr_management
lm32-vuart
tru_mon
wrsw_pstats
wrsw_vlans
TOOLS = rtu_stat wr_mon wr_phytool spll_dbg_proxy load-lm32 load-virtex com
TOOLS += mapper wmapper shw_ver wr_date wr_management lm32-vuart wrsw_pstats
TOOLS += wrsw_vlans
# # Standard stanza for cross-compilation (courtesy of the linux makefile)
......@@ -76,6 +77,9 @@ wrsw_pstats: wrsw_pstats.o
lm32-vuart: lm32-vuart.o
${CC} -o $@ $^ $(LDFLAGS)
wrsw_vlans: wrsw_vlans.o
${CC} -o $@ $^ $(LDFLAGS)
clean:
rm -f $(TOOLS) *.o *~
......
/*
* Copyright (c) 2014, CERN
*
* Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <minipc.h>
#include <rtud_exports.h>
#include "wrsw_vlans.h"
int debug = 0;
struct minipc_ch *rtud_ch;
struct rtu_vlans_t *rtu_vlans = NULL;
int main(int argc, char *argv[])
{
/* runtime options */
struct option ropts[NOPTS+1] = {
{"help", 0, NULL, OPT_HELP},
{"debug", 0, &debug, 1},
{"clear", 0, NULL, OPT_CLEAR},
{"list", 0, NULL, OPT_LIST},
{"ep", 1, NULL, OPT_EP_PORT},
{"emode", 1, NULL, OPT_EP_QMODE},
{"evid", 1, NULL, OPT_EP_VID},
{"eprio", 1, NULL, OPT_EP_PRIO},
{"eumask", 1, NULL, OPT_EP_UMASK},
{"rvid", 1, NULL, OPT_RTU_VID},
{"rfid", 1, NULL, OPT_RTU_FID},
{"rmask", 1, NULL, OPT_RTU_PMASK},
{"rdrop", 1, NULL, OPT_RTU_DROP},
{"rprio", 1, NULL, OPT_RTU_PRIO},
{"del", 0, NULL, OPT_RTU_DEL},
{0, 0, 0, 0}};
/*******************/
int c, i;
struct s_port_vlans vlans[MAXPORTS];
char *prgname;
char *pidpart;
int pid = -1; //is a port ID (Endpoint ID)
int pid_e = -1; //for the range of pids
prgname = argv[0];
bzero( vlans, MAXPORTS*sizeof(struct s_port_vlans) );
rtud_ch = minipc_client_create("rtud", 0);
if(!rtud_ch) {
fprintf(stderr, "Can't connect to RTUd mini-rpc server\n");
return -1;
}
if(debug)
minipc_set_logfile(rtud_ch,stderr);
/*parse parameters*/
while( (c = getopt_long(argc, argv, "h", ropts, NULL)) != -1) {
switch(c) {
case OPT_EP_PORT:
//port number
pidpart = strtok(optarg, "-");
pid = atoi(pidpart);
pidpart = strtok(NULL, "-");
if(pidpart == NULL) {
//it's not a range, it's a single pid
pid_e = pid;
}
else
pid_e = atoi(pidpart);
if(pid >= MAXPORTS || pid_e >= MAXPORTS) {
fprintf(stderr, "Port ID outside range\n");
return 0;
}
for(i=pid; i<=pid_e; ++i)
vlans[i].valid_mask = VALID_CONFIG;
break;
case OPT_EP_QMODE:
//qmode for port
for(i=pid; i<=pid_e; ++i) {
vlans[i].qmode = atoi(optarg);
vlans[i].valid_mask |= VALID_QMODE;
}
break;
case OPT_EP_PRIO:
//priority value for port, forces fix_prio=1
for(i=pid; i<=pid_e; ++i) {
vlans[i].prio_val = atoi(optarg);
vlans[i].fix_prio = 1;
vlans[i].valid_mask |= VALID_PRIO;
}
break;
case OPT_EP_VID:
//VID for port
for(i=pid; i<=pid_e; ++i) {
vlans[i].vid = atoi(optarg);
vlans[i].valid_mask |= VALID_VID;
}
break;
case OPT_EP_UMASK:
//untag mask
for(i=pid; i<=pid_e; ++i) {
vlans[i].untag_mask = (int) strtol(optarg, NULL, 16);
vlans[i].valid_mask |= VALID_UNTAG;
}
break;
/****************************************************/
/* RTU settings */
case OPT_RTU_VID:
set_rtu_vlan(atoi(optarg), -1, -1, 0, -1, 0, VALID_VID);
break;
case OPT_RTU_FID:
set_rtu_vlan(-1, atoi(optarg), -1, 0, -1, 0, VALID_FID);
break;
case OPT_RTU_PMASK:
set_rtu_vlan(-1, -1, (int) strtol(optarg, NULL, 16), 0, -1, 0, VALID_PMASK);
break;
case OPT_RTU_DROP:
set_rtu_vlan(-1, -1, -1, atoi(optarg), -1, 0, VALID_DROP);
break;
case OPT_RTU_PRIO:
set_rtu_vlan(-1, -1, -1, 0, atoi(optarg), 0, VALID_PRIO);
break;
case OPT_RTU_DEL:
set_rtu_vlan(-1, -1, -1, 0, -1, 1, 0);
break;
/****************************************************/
/* Other settings */
case OPT_CLEAR:
clear_all();
break;
case OPT_DEBUG:
case 0:
break;
case OPT_LIST:
list_rtu_vlans();
break;
case '?':
case OPT_HELP:
default:
print_help(prgname);
}
}
if(debug)
print_config(vlans);
apply_settings(vlans);
free_rtu_vlans(rtu_vlans);
return 0;
}
int print_help(char *prgname)
{
fprintf(stderr, "Use: %s [--ep <port number> <EP options> --ep <port number> "
"<EP options> ...] [--rvid <vid> --rfid <fid> --rmask <mask> --rdrop "
"--rprio <prio> --rvid <vid>...] [--debug]\n", prgname);
fprintf(stderr,
"Endpoint options:\n"
"\t --emode <mode No.> sets qmode for a port, possible values:\n"
"\t \t 0: ACCESS - tags untagged frames, drops tagged frames not belinging to configured VLAN\n"
"\t \t 1: TRUNK - passes only tagged frames, drops all untagged frames\n"
"\t \t 2: VLANs disabled - passess all frames as is\n"
"\t \t 3: Unqualified port - passess all frames regardless VLAN config\n"
"\t --eprio <priority> sets priority for retagging\n"
"\t --evid <vid> sets VLAN Id for port\n"
"\t --eumask <hex mask> sets untag mask for port\n"
"RTU options:\n"
"\t --rvid <vid> configure VLAN <vid> in rtud\n"
"\t --del delete selected VLAN from rtud\n"
"\t --rfid <fid> assign <fid> to configured VLAN\n"
"\t --rmask <hex mask> ports belonging to configured VLAN\n"
"\t --rdrop <1/0> drop/don't drop frames on VLAN\n"
"\t --rprio <prio> force priority for VLAN (-1 cancels priority override\n"
"Other options:\n"
"\t --clear clears RTUd VLAN table\n"
"\t --list prints the content of RTUd VLAN table\n"
"\t --debug debug mode, prints VLAN config before writing Endpoint registers\n"
"\t --help prints this help message\n");
return 0;
}
void print_config(struct s_port_vlans *vlans)
{
int i;
for(i=0; i<MAXPORTS; ++i) {
if( vlans[i].valid_mask & VALID_CONFIG ) {
printf("port: %d, qmode: %d, qmode_valid: %d, fix_prio: %d, prio_val: %d, "
"prio_valid: %d, vid: %d, vid_valid: %d, untag_mask: 0x%X, untag_valid: %d\n",
i, vlans[i].qmode, ((vlans[i].valid_mask & VALID_QMODE) != 0), vlans[i].fix_prio,
vlans[i].prio_val, ((vlans[i].valid_mask & VALID_PRIO) != 0),vlans[i].vid,
((vlans[i].valid_mask & VALID_VID) != 0), vlans[i].untag_mask,
((vlans[i].valid_mask & VALID_UNTAG) != 0) );
}
}
}
int apply_settings(struct s_port_vlans *vlans)
{
int i;
for(i=0; i<MAXPORTS; ++i) {
if( vlans[i].valid_mask & VALID_CONFIG ) {
//TODO: call apropriate ioctls to configure tagging/untagging
}
}
config_rtud();
return 0;
}
int config_rtud(void)
{
struct rtu_vlans_t *cur;
struct rtu_vlans_t *old_list, *old_entry;
int ret, val;
old_list = rtu_read_config();
cur = rtu_vlans;
while(cur) {
old_entry = rtu_find_vlan(old_list, cur->vid, cur->flags & VALID_FID?cur->fid:-1);
/*preserve previous settings if not overwritten*/
if(old_entry!=NULL && !(cur->flags & VALID_FID))
cur->fid = old_entry->fid;
if(old_entry!=NULL && !(cur->flags & VALID_PMASK))
cur->pmask = old_entry->pmask;
if(old_entry!=NULL && !(cur->flags & VALID_DROP))
cur->drop = old_entry->drop;
if(old_entry!=NULL && !(cur->flags & VALID_PRIO)) {
cur->prio = old_entry->prio;
cur->has_prio = old_entry->has_prio;
cur->prio_override = old_entry->prio_override;
}
ret = minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_vlan_entry, &val,
cur->vid, cur->fid, cur->pmask, cur->drop, cur->prio, cur->has_prio,
cur->prio_override);
cur = cur->next;
}
free_rtu_vlans(old_list);
return 0;
}
void list_rtu_vlans(void)
{
rtudexp_vd_list_t vlist;
rtudexp_vd_entry_t *ventry;
int idx = 0, i;
printf(" VID FID MASK DROP PRIO PRIO_OVERRIDE\n");
printf("-----------------------------------------------------------\n");
do {
minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_get_vd_list, &vlist, idx);
for(i=0; i<vlist.num_entries; ++i) {
ventry = &vlist.list[i];
printf("%4d %4d 0x%8x ", ventry->vid, ventry->fid, ventry->port_mask);
if(ventry->drop == 0) printf("NO ");
else printf("YES");
if(ventry->has_prio == 0) printf(" -- ");
else printf(" %1d ", ventry->prio);
if(ventry->prio_override == 0) printf(" NO ");
else printf(" YES ");
printf("\n");
}
idx = vlist.next;
} while(idx>0);
printf("\n");
}
int clear_all()
{
rtudexp_vd_list_t vlist;
rtudexp_vd_entry_t *ventry;
int idx = 0, i, val;
do {
minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_get_vd_list, &vlist, idx);
/*remove vlans from the list*/
for(i=0; i<vlist.num_entries; ++i) {
ventry = &vlist.list[i];
if(ventry->vid != 0)
minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_vlan_entry, &val, ventry->vid,
ventry->fid, 0, 1, 0, 0, 0);
else
minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_vlan_entry, &val, 0, 0,
0xffffffff, 0, 0, 0, 0);
}
idx = vlist.next;
} while(idx>0);
/*TODO: cancel tagging/untagging in all endpoints*/
return 0;
}
int set_rtu_vlan(int vid, int fid, int pmask, int drop, int prio, int del, int flags)
{
static struct rtu_vlans_t *cur;
if ( vid > 0 && rtu_vlans == NULL) {
/* allocate first element of the list */
rtu_vlans = (struct rtu_vlans_t*) malloc( sizeof(struct rtu_vlans_t) );
if (rtu_vlans == NULL) {
fprintf(stderr, "Could not allocate rtu_vlans\n");
return -1;
}
cur = rtu_vlans;
}
else if( vid > 0 ) {
/* allocate next element of the list */
cur->next = (struct rtu_vlans_t*) malloc( sizeof(struct rtu_vlans_t) );
if (cur->next == NULL) {
fprintf(stderr, "Could not allocate next rtu_vlans\n");
return -1;
}
cur = cur->next;
}
if(vid > 0) {
bzero(cur, sizeof(struct rtu_vlans_t));
cur->vid = vid;
cur->fid = vid;
cur->flags |= VALID_VID;
}
if(flags & VALID_FID)
cur->fid = fid;
if(flags & VALID_PMASK)
cur->pmask = pmask;
if(flags & VALID_DROP)
cur->drop = drop;
if(flags & VALID_PRIO && prio >= 0) {
cur->prio = prio;
cur->has_prio = 1;
cur->prio_override = 1;
}
else if(flags & VALID_PRIO) {
cur->prio = prio;
cur->has_prio = 0;
cur->prio_override = 0;
}
if(del) {
/*delete this vlan*/
cur->pmask = 0;
cur->drop = 1;
cur->prio = 0;
cur->has_prio = 0;
cur->prio_override = 0;
flags |= (VALID_PMASK | VALID_DROP | VALID_PRIO);
}
cur->flags |= flags;
return 0;
}
void free_rtu_vlans(struct rtu_vlans_t *ptr)
{
struct rtu_vlans_t *next = NULL;
while(ptr) {
next = ptr->next;
free(ptr);
ptr = next;
}
}
struct rtu_vlans_t* rtu_read_config()
{
rtudexp_vd_list_t vlist;
rtudexp_vd_entry_t *ventry;
int idx = 0, i;
struct rtu_vlans_t *config = NULL, *cur = NULL;
do {
minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_get_vd_list, &vlist, idx);
for(i=0; i<vlist.num_entries; ++i) {
ventry = &vlist.list[i];
if(config == NULL) {
config = (struct rtu_vlans_t*) malloc(sizeof(struct rtu_vlans_t));
cur = config;
if(config == NULL) {
fprintf(stderr, "Could not allocate memory for reading RTUd VLAN tab\n");
return NULL;
}
}
else {
cur->next = (struct rtu_vlans_t*) malloc(sizeof(struct rtu_vlans_t));
if(cur->next == NULL) {
fprintf(stderr, "Could not allocate memory for reading RTUd VLAN tab\n");
free_rtu_vlans(config);
return NULL;
}
cur = cur->next;
}
cur->vid = ventry->vid;
cur->fid = ventry->fid;
cur->pmask = ventry->port_mask;
cur->drop = ventry->drop;
cur->prio = ventry->prio;
cur->has_prio = ventry->has_prio;
cur->prio_override = ventry->prio_override;
}
idx = vlist.next;
} while(idx>0);
return config;
}
struct rtu_vlans_t* rtu_find_vlan(struct rtu_vlans_t *conf, int vid, int fid)
{
struct rtu_vlans_t *cur;
cur = conf;
while(cur) {
if((cur->vid == vid && cur->fid == fid) || (cur->vid == vid && fid == -1))
break;
cur = cur->next;
}
return cur;
}
/*
* Copyright (c) 2014, CERN
*
* Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __WR_VLANS_H__
#define __WR_VLANS_H__
#define MAXPORTS 18
#define QMODE_ACCESS 0
#define QMODE_TRUNK 1
#define QMODE_DISABLED 2
#define QMODE_UNQ 3
#define MINIPC_TIMEOUT 200
#define VALID_CONFIG 1<<31
#define VALID_QMODE 1<<0
#define VALID_PRIO 1<<1
#define VALID_VID 1<<2
#define VALID_FID 1<<3
#define VALID_UNTAG 1<<4
#define VALID_PMASK 1<<5
#define VALID_DROP 1<<6
#define PORT_MASK(x) (1<<(x))
#define NOPTS 15
#define OPT_HELP 'h'
#define OPT_DEBUG 'd'
#define OPT_CLEAR 3
#define OPT_LIST 4
#define OPT_EP_PORT 10
#define OPT_EP_QMODE 11
#define OPT_EP_VID 12
#define OPT_EP_PRIO 13
#define OPT_EP_UMASK 14
#define OPT_RTU_VID 20
#define OPT_RTU_FID 21
#define OPT_RTU_PMASK 22
#define OPT_RTU_DROP 23
#define OPT_RTU_PRIO 24
#define OPT_RTU_DEL 25
struct s_port_vlans
{
int valid_mask;
char qmode;
char fix_prio;
char prio_val;
int vid;
int untag_mask;
};
struct rtu_vlans_t
{
int vid;
int fid;
int pmask;
int drop;
int prio;
int has_prio;
int prio_override;
int flags;
struct rtu_vlans_t *next;
};
int print_help();
void print_config(struct s_port_vlans *vlans);
int apply_settings(struct s_port_vlans *vlans);
int clear_all();
int set_rtu_vlan(int vid, int fid, int pmask, int drop, int prio, int del, int flags);
void free_rtu_vlans(struct rtu_vlans_t *ptr);
void list_rtu_vlans(void);
struct rtu_vlans_t* rtu_read_config();
struct rtu_vlans_t* rtu_find_vlan(struct rtu_vlans_t *conf, int vid, int fid);
int config_rtud(void);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment