Commit 3e630d08 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'vlan-support'

parents dd612fb9 29b77fb9
......@@ -37,6 +37,29 @@ config WRC_VERBOSE
boolean
default y if WR_SWITCH
config VLAN
boolean
config VLAN_NR
int
default 10 if VLAN
default 0
config VLAN_1_FOR_CLASS7
int
default 20 if VLAN
default 0
config VLAN_2_FOR_CLASS7
int
default 30 if VLAN
default 0
config VLAN_FOR_CLASS6
int
default 100 if VLAN
default 0
# CONFIG_WR_SWITCH has no further options at all at this point
......@@ -301,7 +324,25 @@ config WRC_VERBOSE
help
This enables some more diagnostic messages. Normally off.
config VLAN
depends on DEVELOPER
boolean "Filter and rx/tx frames in a VLAN (as opposed to untagged)"
config VLAN_NR
depends on VLAN
int "Use this VLAN number for filter/tx/rx"
config VLAN_1_FOR_CLASS7
depends on VLAN
int "Route this VLAN to fabric class 7 (Etherbone)"
config VLAN_2_FOR_CLASS7
depends on VLAN
int "Route this VLAN too to fabric class 7 (Etherbone)"
config VLAN_FOR_CLASS6
depends on VLAN
int "Route this VLAN too to fabric class 6 (Streamer/NIC)"
config SDB_STORAGE
depends on WR_NODE
......
......@@ -59,8 +59,9 @@ CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
LDFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled \
-nostdlib -T $(LDS-y)
# packet-filter rules depend on configuration; default is rules-plain
pfilter-y := rules-default.bin
# packet-filter rules: for CONFIG_VLAN we use both sets
pfilter-y := rules-novlan.bin
pfilter-$(CONFIG_VLAN) += rules-vlan.bin
export pfilter-y
all:
......
......@@ -67,4 +67,8 @@ SECTIONS
/* This may be missing, according to .config */
PROVIDE(fifo_log = 0);
/* A vlan rule-set may be missing (if no CONFIG_VLAN) */
PROVIDE(_binary_rules_vlan_bin_start = 0);
PROVIDE(_binary_rules_vlan_bin_end = 0);
}
......@@ -9,6 +9,11 @@ CONFIG_RAMSIZE=131072
CONFIG_PLL_VERBOSE=y
CONFIG_PFILTER_VERBOSE=y
CONFIG_WRC_VERBOSE=y
CONFIG_VLAN=y
CONFIG_VLAN_NR=10
CONFIG_VLAN_1_FOR_CLASS7=20
CONFIG_VLAN_2_FOR_CLASS7=30
CONFIG_VLAN_FOR_CLASS6=100
# CONFIG_WR_NODE_PCS16 is not set
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
......
obj-$(CONFIG_WR_NODE) += \
dev/endpoint.o \
dev/ep_pfilter.o \
dev/pfilter-rules.o \
dev/i2c.o \
dev/minic.o \
dev/pps_gen.o \
......@@ -21,11 +20,13 @@ obj-$(CONFIG_W1) += dev/w1-temp.o dev/w1-eeprom.o
obj-$(CONFIG_UART) += dev/uart.o
obj-$(CONFIG_UART_SW) += dev/uart-sw.o
# Filter rules are selected according to configuration, see toplevel Makefile,
# but the filename is reflected in symbol names, so use a symlink here.
dev/pfilter-rules.o: $(pfilter-y)
ln -sf $(pfilter-y) rules-pfilter.bin
$(OBJCOPY) -I binary -O elf32-lm32 -B lm32 rules-pfilter.bin $@
# Filter rules are selected according to configuration, but we may
# have more than one. Note: the filename is reflected in symbol names,
# so they are hardwired in ../Makefile (and ../tools/pfilter-builder too)
obj-y += $(pfilter-y:.bin=.o)
rules-%.o: rules-%.bin
$(OBJCOPY) -I binary -O elf32-lm32 -B lm32 $< $@
$(pfilter-y): tools/pfilter-builder
$^
......
......@@ -20,8 +20,24 @@
#include <endpoint.h>
#include <hw/endpoint_regs.h>
extern uint32_t _binary_rules_pfilter_bin_start[];
extern uint32_t _binary_rules_pfilter_bin_end[];
extern uint32_t _binary_rules_novlan_bin_start[];
extern uint32_t _binary_rules_novlan_bin_end[];
extern uint32_t _binary_rules_vlan_bin_start[];
extern uint32_t _binary_rules_vlan_bin_end[];
struct rule_set {
uint32_t *ini;
uint32_t *end;
} rule_sets[2] = {
{
_binary_rules_novlan_bin_start,
_binary_rules_novlan_bin_end,
}, {
_binary_rules_vlan_bin_start,
_binary_rules_vlan_bin_end,
}
};
extern volatile struct EP_WB *EP;
......@@ -38,16 +54,23 @@ static uint32_t swap32(uint32_t v)
void pfilter_init_default(void)
{
/* Use shorter names to avoid getting mad */
uint32_t *vini = _binary_rules_pfilter_bin_start;
uint32_t *vend = _binary_rules_pfilter_bin_end;
struct rule_set *s;
uint8_t mac[6];
char buf[20];
uint32_t m, *v;
uint32_t m, *vini, *vend, *v, *v_vlan = NULL;
uint64_t cmd_word;
int i;
static int inited;
/* If vlan, use rule-set 1, else rule-set 0 */
s = rule_sets + (wrc_vlan_number != 0);
if (!s->ini) {
pp_printf("no pfilter rule-set!\n");
return;
}
vini = s->ini;
vend = s->end;
/*
* The array of words starts with 0x11223344 so we
* can fix endianness. Do it.
......@@ -91,9 +114,21 @@ void pfilter_init_default(void)
pfilter_verbose("fixing MAC adress in rule: use %s\n",
format_mac(buf, mac));
/* If this is the VLAN rule-set, patch the vlan number too */
for (v = vini + 1; v < vend; v += 2) {
if (((*v >> 13) & 0xffff) == 0x0aaa
&& ((*v >> 7) & 0x1f) == 7) {
pfilter_verbose("fixing VLAN number in rule: use %i\n",
wrc_vlan_number);
v_vlan = v;
*v &= ~(0xffff << 13);
*v |= wrc_vlan_number << 13;
}
}
EP->PFCR0 = 0; // disable pfilter
for (i = 0;v < vend; v += 2, i++) {
for (i = 0, v = vini + 1; v < vend; v += 2, i++) {
uint32_t cr0, cr1;
cmd_word = v[0] | ((uint64_t)v[1] << 32);
......@@ -109,5 +144,11 @@ void pfilter_init_default(void)
EP->PFCR0 = cr0;
}
/* Restore the 0xaaa vlan number, so we can re-patch next time */
if (v_vlan) {
*v_vlan &= ~(0xffff << 13);
*v_vlan |= 0x0aaa << 13;
}
EP->PFCR0 = EP_PFCR0_ENABLE;
}
......@@ -10,6 +10,7 @@
#include <stdio.h>
#include <string.h>
#include <wrc.h>
#include <wrpc.h>
#include "types.h"
#include "board.h"
......@@ -191,7 +192,7 @@ int minic_poll_rx()
return (isr & MINIC_EIC_ISR_RX) ? 1 : 0;
}
int minic_rx_frame(uint8_t * hdr, uint8_t * payload, uint32_t buf_size,
int minic_rx_frame(struct wr_ethhdr *hdr, uint8_t * payload, uint32_t buf_size,
struct hw_timestamp *hwts)
{
uint32_t frame_size, payload_size, num_words;
......@@ -262,7 +263,7 @@ int minic_rx_frame(uint8_t * hdr, uint8_t * payload, uint32_t buf_size,
n_recvd = (buf_size < payload_size ? buf_size : payload_size);
minic.rx_count++;
minic_rx_memcpy(hdr, (void *)minic.rx_head + 4,
minic_rx_memcpy((void *)hdr, (void *)minic.rx_head + 4,
ETH_HEADER_SIZE);
minic_rx_memcpy(payload, (void *)minic.rx_head + 4
+ ETH_HEADER_SIZE, n_recvd);
......@@ -288,20 +289,25 @@ int minic_rx_frame(uint8_t * hdr, uint8_t * payload, uint32_t buf_size,
return n_recvd;
}
int minic_tx_frame(uint8_t * hdr, uint8_t * payload, uint32_t size,
int minic_tx_frame(struct wr_ethhdr_vlan *hdr, uint8_t *payload, uint32_t size,
struct hw_timestamp *hwts)
{
uint32_t d_hdr, mcr, nwords;
uint8_t ts_valid;
int i;
int i, hsize;
minic_new_tx_buffer();
memset((void *)minic.tx_head, 0x0, size + 16);
memset((void *)minic.tx_head + 4, 0, size < 60 ? 60 : size);
memcpy((void *)minic.tx_head + 4, hdr, ETH_HEADER_SIZE);
memcpy((void *)minic.tx_head + 4 + ETH_HEADER_SIZE, payload, size);
if (hdr->ethtype == htons(0x8100))
hsize = sizeof(struct wr_ethhdr_vlan);
else
hsize = sizeof(struct wr_ethhdr);
memset((void *)minic.tx_head, 0x0, size + hsize + 4);
memcpy((void *)minic.tx_head + 4, hdr, hsize);
memcpy((void *)minic.tx_head + 4 + hsize, payload, size);
size += hsize;
size += ETH_HEADER_SIZE;
if (size < 60)
size = 60;
......
......@@ -19,9 +19,23 @@ void minic_disable(void);
int minic_poll_rx(void);
void minic_get_stats(int *tx_frames, int *rx_frames);
int minic_rx_frame(uint8_t * hdr, uint8_t * payload, uint32_t buf_size,
struct wr_ethhdr {
uint8_t dstmac[6];
uint8_t srcmac[6];
uint16_t ethtype;
};
struct wr_ethhdr_vlan {
uint8_t dstmac[6];
uint8_t srcmac[6];
uint16_t ethtype;
uint16_t tag;
uint16_t ethtype_2;
};
int minic_rx_frame(struct wr_ethhdr *hdr, uint8_t * payload, uint32_t buf_size,
struct hw_timestamp *hwts);
int minic_tx_frame(uint8_t * hdr, uint8_t * payload, uint32_t size,
int minic_tx_frame(struct wr_ethhdr_vlan *hdr, uint8_t * payload, uint32_t size,
struct hw_timestamp *hwts);
#endif
......@@ -43,6 +43,7 @@ struct wr_sockaddr {
// RAW ethertype
uint16_t ethertype;
uint16_t udpport;
uint16_t vlan;
};
struct sockq {
......@@ -80,7 +81,6 @@ PACKED struct wr_timestamp {
int correct;
};
// Creates UDP or Ethernet RAW socket (determined by sock_type) bound
// to bind_addr. If PTPD_FLAG_MULTICAST is set, the socket is
// automatically added to multicast group. User can specify
......
......@@ -35,6 +35,8 @@
# define is_wr_node 1
#endif
extern int wrc_vlan_number;
int wrc_mon_gui(void);
void shell_init(void);
int wrc_log_stats(void);
......
......@@ -26,12 +26,6 @@
#define min(x,y) ((x) < (y) ? (x) : (y))
struct ethhdr {
uint8_t dstmac[6];
uint8_t srcmac[6];
uint16_t ethtype;
};
static struct wrpc_socket *socks[NET_MAX_SOCKETS];
//#define net_verbose pp_printf
......@@ -231,7 +225,7 @@ int ptpd_netif_recvfrom(struct wrpc_socket *s, struct wr_sockaddr *from, void *d
struct sockq *q = &s->queue;
uint16_t size;
struct ethhdr hdr;
struct wr_ethhdr hdr;
struct hw_timestamp hwts;
uint8_t spll_busy;
......@@ -243,10 +237,11 @@ int ptpd_netif_recvfrom(struct wrpc_socket *s, struct wr_sockaddr *from, void *d
q->avail += wrap_copy_in(&size, q, 2, 0);
q->avail += wrap_copy_in(&hwts, q, sizeof(struct hw_timestamp), 0);
q->avail += wrap_copy_in(&hdr, q, sizeof(struct ethhdr), 0);
q->avail += wrap_copy_in(&hdr, q, sizeof(struct wr_ethhdr), 0);
q->avail += wrap_copy_in(data, q, size, data_length);
from->ethertype = ntohs(hdr.ethtype);
from->vlan = wrc_vlan_number; /* has been checked in rcvd frame */
memcpy(from->mac, hdr.srcmac, 6);
memcpy(from->mac_dest, hdr.dstmac, 6);
......@@ -282,19 +277,25 @@ int ptpd_netif_sendto(struct wrpc_socket * sock, struct wr_sockaddr *to, void *d
{
struct wrpc_socket *s = (struct wrpc_socket *)sock;
struct hw_timestamp hwts;
struct ethhdr hdr;
struct wr_ethhdr_vlan hdr;
int rval;
memcpy(hdr.dstmac, to->mac, 6);
memcpy(hdr.srcmac, s->local_mac, 6);
hdr.ethtype = sock->bind_addr.ethertype;
if (wrc_vlan_number) {
hdr.ethtype = htons(0x8100);
hdr.tag = htons(wrc_vlan_number);
hdr.ethtype_2 = sock->bind_addr.ethertype; /* net order */
} else {
hdr.ethtype = sock->bind_addr.ethertype;
}
net_verbose("TX: socket %04x:%04x, len %i\n",
ntohs(s->bind_addr.ethertype),
s->bind_addr.udpport,
data_length);
rval =
minic_tx_frame((uint8_t *) & hdr, (uint8_t *) data,
minic_tx_frame(&hdr, (uint8_t *) data,
data_length, &hwts);
......@@ -313,18 +314,36 @@ int update_rx_queues()
struct wrpc_socket *s = NULL;
struct sockq *q;
struct hw_timestamp hwts;
static struct ethhdr hdr;
static struct wr_ethhdr hdr;
int recvd, i, q_required;
static uint8_t payload[NET_MAX_SKBUF_SIZE - 32];
static uint8_t buffer[NET_MAX_SKBUF_SIZE - 32];
uint8_t *payload = buffer;
uint16_t size, port;
uint16_t ethtype, tag;
recvd =
minic_rx_frame((uint8_t *) & hdr, payload, sizeof(payload),
minic_rx_frame(&hdr, buffer, sizeof(buffer),
&hwts);
if (recvd <= 0) /* No data received? */
return 0;
/* Remove the vlan tag, but make sure it's the right one */
ethtype = hdr.ethtype;
tag = 0;
if (ntohs(ethtype) == 0x8100) {
memcpy(&tag, buffer, 2);
memcpy(&hdr.ethtype, buffer + 2, 2);
payload += 4;
recvd -= 4;
}
if ((ntohs(tag) & 0xfff) != wrc_vlan_number) {
net_verbose("%s: want vlan %i, got %i: discard\n",
__func__, wrc_vlan_number,
ntohs(tag) & 0xfff);
return 0;
}
for (i = 0; i < ARRAY_SIZE(socks); i++) {
s = socks[i];
if (!s)
......@@ -357,7 +376,7 @@ int update_rx_queues()
q = &s->queue;
q_required =
sizeof(struct ethhdr) + recvd + sizeof(struct hw_timestamp) + 2;
sizeof(struct wr_ethhdr) + recvd + sizeof(struct hw_timestamp) + 2;
if (q->avail < q_required) {
net_verbose
......@@ -370,7 +389,7 @@ int update_rx_queues()
q->avail -= wrap_copy_out(q, &size, 2);
q->avail -= wrap_copy_out(q, &hwts, sizeof(struct hw_timestamp));
q->avail -= wrap_copy_out(q, &hdr, sizeof(struct ethhdr));
q->avail -= wrap_copy_out(q, &hdr, sizeof(struct wr_ethhdr));
q->avail -= wrap_copy_out(q, payload, size);
q->n++;
......
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2016 GSI (www.gsi.de)
* Author: Alessandro Rubini <a.rubini@gsi.de>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <wrc.h>
#include <string.h>
#include <errno.h>
#include <shell.h>
#include <endpoint.h>
static int cmd_vlan(const char *args[])
{
int i;
if (!args[0] || !strcasecmp(args[0], "get")) {
/* nothing... */
} else if (!strcasecmp(args[0], "set") && args[1]) {
fromdec(args[1], &i);
if (i < 1 || i > 4095) {
pp_printf("%i (\"%s\") out of range\n", i, args[1]);
return -EINVAL;
}
wrc_vlan_number = i;
pfilter_init_default();
} else if (!strcasecmp(args[0], "off")) {
wrc_vlan_number = 0;
pfilter_init_default();
} else {
return -EINVAL;
}
pp_printf("current vlan: %i (0x%x)\n",
wrc_vlan_number, wrc_vlan_number);
return 0;
}
DEFINE_WRC_COMMAND(vlan) = {
.name = "vlan",
.exec = cmd_vlan,
};
......@@ -22,3 +22,4 @@ obj-$(CONFIG_CMD_CONFIG) += shell/cmd_config.o
obj-$(CONFIG_CMD_SLEEP) += shell/cmd_sleep.o
obj-$(CONFIG_CMD_LL) += shell/cmd_ll.o
obj-$(CONFIG_FLASH_INIT) += shell/cmd_init.o
obj-$(CONFIG_VLAN) += shell/cmd_vlan.o
......@@ -47,6 +47,9 @@ wrpc-dump: wrpc-dump.c dump-info-host.o
-I ../softpll \
$^ -o $@
pfilter-builder: pfilter-builder.c
$(CC) $(CFLAGS) -include ../include/generated/autoconf.h \
$@.c $(LDFLAGS) -o $@
dump-info-host.o: ../dump-info.o
......
......@@ -212,7 +212,7 @@ enum pf_symbolic_regs {
/* The first set is used for straight comparisons */
FRAME_BROADCAST = R_1,
FRAME_OUR_MAC,
FRAME_TAGGED,
FRAME_OUR_VLAN,
FRAME_TYPE_IPV4,
FRAME_TYPE_PTP2,
FRAME_TYPE_ARP,
......@@ -363,7 +363,7 @@ static void pfilter_output(char *fname)
}
void pfilter_init(int mode, char *fname)
void pfilter_init_novlan(char *fname)
{
pfilter_new();
pfilter_nop();
......@@ -384,8 +384,8 @@ void pfilter_init(int mode, char *fname)
pfilter_cmp(2, 0xffff, 0xffff, AND, FRAME_BROADCAST);
/* Tagged is dropped. We'll invert the check in the vlan rule-set */
pfilter_cmp(6, 0x8100, 0xffff, MOV, FRAME_TAGGED);
pfilter_logic2(R_DROP, FRAME_TAGGED, MOV, R_ZERO);
pfilter_cmp(6, 0x8100, 0xffff, MOV, R_TMP);
pfilter_logic2(R_DROP, R_TMP, MOV, R_ZERO);
/* Identify some Ethertypes used later. */
pfilter_cmp(6, 0x88f7, 0xffff, MOV, FRAME_TYPE_PTP2);
......@@ -436,10 +436,70 @@ void pfilter_init(int mode, char *fname)
}
void pfilter_init_vlan(char *fname)
{
pfilter_new();
pfilter_nop();
/*
* This is a simplified set, for development,
* to allow me write vlan support in software.
* Mostly a subset of above set
*/
/* Local frame, using fake MAC: 12:34:56:78:9a:bc */
pfilter_cmp(0, 0x1234, 0xffff, MOV, FRAME_OUR_MAC);
pfilter_cmp(1, 0x5678, 0xffff, AND, FRAME_OUR_MAC);
pfilter_cmp(2, 0x9abc, 0xffff, AND, FRAME_OUR_MAC);
/* Broadcast frame */
pfilter_cmp(0, 0xffff, 0xffff, MOV, FRAME_BROADCAST);
pfilter_cmp(1, 0xffff, 0xffff, AND, FRAME_BROADCAST);
pfilter_cmp(2, 0xffff, 0xffff, AND, FRAME_BROADCAST);
/* Untagged is dropped. */
pfilter_cmp(6, 0x8100, 0xffff, MOV, R_TMP);
pfilter_logic2(R_DROP, R_TMP, NOT, R_ZERO);
/* Compare with our vlan (fake number 0xaaa) */
pfilter_cmp(7, 0x0aaa, 0x0fff, MOV, FRAME_OUR_VLAN);
/* Identify some Ethertypes used later. */
pfilter_cmp(8, 0x88f7, 0xffff, MOV, FRAME_TYPE_PTP2);
pfilter_cmp(8, 0x0800, 0xffff, MOV, FRAME_TYPE_IPV4);
pfilter_cmp(8, 0x0806, 0xffff, MOV, FRAME_TYPE_ARP);
/* Loose match: keep all bcast, all our mac and all ptp ... */
pfilter_logic3(FRAME_FOR_CPU,
FRAME_OUR_MAC, OR, FRAME_BROADCAST, OR, FRAME_TYPE_PTP2);
/* .... but only for our current VLAN */
pfilter_logic2(R_CLASS(0), FRAME_FOR_CPU, AND, FRAME_OUR_VLAN);
/*
* And route these build-time selected vlans to fabric 7 and 6.
* Class 7 is etherbone and class 6 is streamer or nic (or whatever).
* We get all broadcast and all frames for our mac.
*
* We reuse FRAME_OUR_VLAN, even if it's not OUR as in "this CPU"
*/
pfilter_logic2(R_TMP, FRAME_OUR_MAC, OR, FRAME_BROADCAST);
pfilter_cmp(7, CONFIG_VLAN_1_FOR_CLASS7, 0x0fff, MOV, FRAME_OUR_VLAN);
pfilter_cmp(7, CONFIG_VLAN_2_FOR_CLASS7, 0x0fff, OR, FRAME_OUR_VLAN);
pfilter_logic2(R_CLASS(7), R_TMP, AND, FRAME_OUR_VLAN);
pfilter_cmp(7, CONFIG_VLAN_FOR_CLASS6, 0x0fff, MOV, FRAME_OUR_VLAN);
pfilter_logic2(R_CLASS(6), R_TMP, AND, FRAME_OUR_VLAN);
pfilter_output(fname);
}
int main(int argc, char **argv) /* no arguments used currently */
{
prgname = argv[0];
pfilter_init(0, "rules-default.bin");
pfilter_init_novlan("rules-novlan.bin");
pfilter_init_vlan("rules-vlan.bin");
exit(0);
}
......@@ -44,6 +44,8 @@ int32_t sfp_deltaTx = 0;
int32_t sfp_deltaRx = 0;
uint32_t cal_phase_transition = 2389;
int wrc_vlan_number = CONFIG_VLAN_NR;
static uint32_t prev_nanos_for_profile;
static void wrc_initialize(void)
......
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