Commit a0578979 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'greg-mirroring' into proposed_master

parents 21ce8654 50eaccbd
......@@ -12,6 +12,9 @@
/* Maximum number of supported VLANs */
#define NUM_VLANS 4096
/* Currently only one port mirror setup is allowed */
#define NUM_MIRROR 1
#define ETH_ALEN 6
#define ETH_ALEN_STR 18
......@@ -124,13 +127,25 @@ struct rtu_vlan_table_entry {
int drop; /* 1: drop the packet (VLAN not registered) */
};
/**
* \brief RTU mirroring configuration
*/
struct rtu_mirror_info {
int en; /* Mirroring enabled flag */
uint32_t imask; /* Ingress source port mask */
uint32_t emask; /* Egress source port mask */
uint32_t dmask; /* Destination port mask */
};
/* This is the overall structure stored in shared memory */
#define RTU_SHMEM_VERSION 3 /* Version 3, changed wrs_shm_head */
#define RTU_SHMEM_VERSION 4 /* Version 3, changed wrs_shm_head */
struct rtu_shmem_header {
struct rtu_filtering_entry *filters;
struct rtu_vlan_table_entry *vlans;
struct rtu_mirror_info *mirror;
unsigned long filters_offset;
unsigned long vlans_offset;
unsigned long mirror_offset;
};
#endif /* __LIBWR_RTU_SHMEM_H__ */
......@@ -43,6 +43,7 @@ static struct minipc_ch *rtud_ch;
struct wrs_shm_head *rtu_port_shmem;
static struct rtu_vlan_table_entry vlan_tab_local[NUM_VLANS];
static struct rtu_filtering_entry rtu_htab_local[RTU_BUCKETS * HTAB_ENTRIES];
static struct rtu_mirror_info mirror_local;
int rtudexp_clear_entries(int port, int type)
{
......@@ -177,6 +178,11 @@ void show_help(char *prgname)
fprintf(stderr, " vlan <vid> <fid> <port_mask> [<drop>, <prio>, <has_prio>, <prio_override>]:\n"
" Add VLAN entry with vid, fid, mask and drop flag;\n"
" write mask=0x0 and drop=1 to remove the VLAN\n");
fprintf(stderr, " mirror ingress <src_port> <dst_port>: Enable mirroring of ingress traffic\n"
" from src_port to dst_port\n");
fprintf(stderr, " mirror egress <src_port> <dst_port>: Enable mirroring of egress traffic\n"
" from src_port to dst_port\n");
fprintf(stderr, " mirror off: Turn off port mirroring\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where:\n");
fprintf(stderr, " <mac> MAC address to be used in the RTU rule;\n"
......@@ -332,6 +338,32 @@ int read_htab(int *read_entries)
return 0;
}
int read_mirror(void)
{
unsigned int ii;
unsigned int retries = 0;
struct rtu_mirror_info *mirror_shm;
struct rtu_shmem_header *rtu_hdr;
rtu_hdr = (void *)rtu_port_shmem + rtu_port_shmem->data_off;
mirror_shm = wrs_shm_follow(rtu_port_shmem, rtu_hdr->mirror);
if (!mirror_shm)
return -2;
/* read data, with the sequential lock to have all data consistent */
while (1) {
ii = wrs_shm_seqbegin(rtu_port_shmem);
memcpy(&mirror_local, mirror_shm, sizeof(*mirror_shm));
retries++;
if (retries > 100)
return -1;
if (!wrs_shm_seqretry(rtu_port_shmem, ii))
break; /* consistent read */
usleep(1000);
}
return 0;
}
int open_rtu_shm(void)
{
int n_wait = 0;
......@@ -401,6 +433,96 @@ int read_port_mask(char *mask, int nports)
return -1;
}
int port_to_mask(char *port, int nports)
{
int portnum;
portnum = read_port(port, nports);
if (portnum >= 0)
return 1 << (portnum-1);
else
return -1;
}
int set_mirroring(int nports, int argc, char **argv)
{
int val, ret;
int imask, emask, dmask;
int s_port, d_port;
/* mirror ingress <src_port> <dst_port> */
/* mirror egress <src_port> <dst_port> */
/* mirror off */
/* mirror <imask> <emask> <dmask> */
/*------------------------------------------*/
/* mirror off */
if (argc == 1 && !strcmp(argv[0], "off")) {
printf("Turning off port mirroring\n");
ret = minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_mirror,
&val, 0, 0, 0, 0);
/*------------------------------------------*/
/* ingress <src_port> <dst_port> */
} else if (argc == 3 && !strcmp(argv[0], "ingress")) {
s_port = read_port(argv[1], nports);
if (s_port < 0)
return s_port;
imask = 1 << (s_port - 1);
d_port = read_port(argv[2], nports);
if (d_port < 0)
return d_port;
dmask = 1 << (d_port - 1);
printf("Configuring ingress mirroring from port %d to port "
"%d\n", s_port, d_port);
ret = minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_mirror,
&val, 1, imask, 0, dmask);
/*------------------------------------------*/
/* egress <src_port> <dst_port> */
} else if (argc == 3 && !strcmp(argv[0], "egress")) {
s_port = read_port(argv[1], nports);
if (s_port < 0)
return s_port;
emask = 1 << (s_port - 1);
d_port = read_port(argv[2], nports);
if (d_port < 0)
return d_port;
dmask = 1 << (d_port - 1);
printf("Configuring egress mirroring from port %d to port %d\n",
s_port, d_port);
ret = minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_mirror,
&val, 1, 0, emask, dmask);
/*------------------------------------------*/
/* advanced usecase */
/* mirror <imask> <emask> <dmask> */
} else if (argc == 3) {
imask = read_port_mask(argv[0], nports);
emask = read_port_mask(argv[1], nports);
dmask = read_port_mask(argv[2], nports);
if (imask < 0 || emask < 0 || dmask < 0) {
fprintf(stderr, "Mirror: incorrect mask\n");
return -1;
}
printf("Configuring mirroring with custom masks: ingress 0x%05X"
" egress 0x%05X destination 0x%05X\n", imask,
emask, dmask);
ret = minipc_call(rtud_ch, MINIPC_TIMEOUT, &rtud_export_mirror,
&val, 1, imask, emask, dmask);
/*------------------------------------------*/
/* incorrect parameters */
} else {
fprintf(stderr, "Mirror: incorrect parameters\n");
return -1;
}
return (ret < 0) ? ret : 1;
}
int main(int argc, char **argv)
{
int i, isok;
......@@ -819,6 +941,10 @@ int main(int argc, char **argv)
printf("Vlan command error\n");
exit(1);
}
/* ****************** mirror ************************************************ */
} else if (argc >= 3 && !strcmp(argv[1], "mirror")) {
/* pass only parameters to mirror command */
isok = set_mirroring(nports, argc-2, argv+2);
} else if (argc >= 2
&& !strcmp(argv[1], "list"))
isok = 1;
......@@ -902,5 +1028,39 @@ int main(int argc, char **argv)
printf("%d active VIDs defined\n", vid_active);
printf("\n");
if (read_mirror()) {
printf("Too many retries while reading mirroring config from "
"RTUd shmem\n");
return -1;
}
printf("RTU Port Mirroring Config Dump:\n");
printf(" Status: %s\n", mirror_local.en ? "Enabled" : "Disabled");
if (mirror_local.imask != 0) {
printf(" Ingress: port ");
for (i = 0; i < nports; ++i) {
if ((mirror_local.imask & (1 << i)) != 0)
printf("%d ", i + 1);
}
printf("-> port ");
for (i = 0; i < nports; ++i) {
if ((mirror_local.dmask & (1 << i)) != 0)
printf("%d ", i + 1);
}
printf("\n");
}
if (mirror_local.emask != 0) {
printf(" Egress: port ");
for (i = 0; i < nports; ++i) {
if ((mirror_local.emask & (1 << i)) != 0)
printf("%d ", i + 1);
}
printf("-> port ");
for (i = 0; i < nports; ++i) {
if ((mirror_local.dmask & (1 << i)) != 0)
printf("%d ", i + 1);
}
printf("\n");
}
return 0;
}
......@@ -518,12 +518,22 @@ struct dump_info vlan_info[] = {
DUMP_FIELD(int, drop),
};
#undef DUMP_STRUCT
#define DUMP_STRUCT struct rtu_mirror_info
struct dump_info mirror_info[] = {
DUMP_FIELD(int, en),
DUMP_FIELD(uint32_t, imask),
DUMP_FIELD(uint32_t, emask),
DUMP_FIELD(uint32_t, dmask),
};
int dump_rtu_mem(struct wrs_shm_head *head)
{
struct rtu_shmem_header *rtu_h;
struct rtu_filtering_entry *rtu_filters;
struct rtu_filtering_entry *rtu_filters_cur;
struct rtu_vlan_table_entry *rtu_vlans;
struct rtu_mirror_info *rtu_mirror;
int i, j;
char prefix[64];
......@@ -535,8 +545,9 @@ int dump_rtu_mem(struct wrs_shm_head *head)
rtu_h = (void *)head + head->data_off;
rtu_filters = wrs_shm_follow(head, rtu_h->filters);
rtu_vlans = wrs_shm_follow(head, rtu_h->vlans);
rtu_mirror = wrs_shm_follow(head, rtu_h->mirror);
if ((!rtu_filters) || (!rtu_vlans)) {
if ((!rtu_filters) || (!rtu_vlans) || (!rtu_mirror)) {
fprintf(stderr, "dump rtu: cannot follow pointer in shm\n");
return -1;
}
......@@ -562,6 +573,11 @@ int dump_rtu_mem(struct wrs_shm_head *head)
sprintf(prefix,"rtu.vlan.%d",i);
dump_many_fields(rtu_vlans, vlan_info, ARRAY_SIZE(vlan_info),prefix);
}
sprintf(prefix, "rtu.mirror");
dump_many_fields(rtu_mirror, mirror_info, ARRAY_SIZE(mirror_info),
prefix);
return 0;
}
......
......@@ -616,6 +616,86 @@ int rtu_read_unrecognised_behaviour_on_port(int port)
return read_pcr(port) & RTU_PCR_B_UNREC ? 1 : 0;
}
/**
* \brief Enables/disables port mirroring
* @param ena Enable flag
* @return error code.
*/
int rtu_enable_mirroring(int ena)
{
uint32_t ctr = rtu_rd(RX_CTR);
if (ena == 1)
ctr = ctr | RTU_RX_CTR_MR_ENA;
else
ctr = ctr & (~RTU_RX_CTR_MR_ENA);
rtu_wr(RX_CTR, ctr);
return 0;
}
/**
* \brief Configures port mirroring
* @param imask Ingress port mask
* @param emask Egress port mask
* @param dmask Destination port mask
* @return error code.
*/
int rtu_cfg_mirroring(struct rtu_mirror_info *cfg)
{
/* if mirroring disabled (en == 0) zero all masks */
/* if mirroring enabled (en == 1) write only non-zero masks */
/* write destination port mask - to which port/-s mirrored traffic will
* be sent
*/
if (cfg->en == 0 || cfg->dmask != 0) {
rtu_wr(RX_MP_R0, 0);
rtu_wr(RX_MP_R1, RTU_RX_MP_R1_MASK_W(cfg->dmask));
}
/* write ingress port mask - source of mirrored traffic */
if (cfg->en == 0 || cfg->imask != 0) {
rtu_wr(RX_MP_R0, RTU_RX_MP_R0_DST_SRC);
rtu_wr(RX_MP_R1, RTU_RX_MP_R1_MASK_W(cfg->imask));
}
/* write egress port mask - source of mirrored traffic */
if (cfg->en == 0 || cfg->emask != 0) {
rtu_wr(RX_MP_R0, RTU_RX_MP_R0_DST_SRC | RTU_RX_MP_R0_RX_TX);
rtu_wr(RX_MP_R1, RTU_RX_MP_R1_MASK_W(cfg->emask));
}
return 0;
}
/**
* \brief Gets port mirroring configuration
* @param en Enabled flag mirroring pointer
* @param imask Ingress port mask pointer
* @param emask Egress port mask pointer
* @param dmask Destination port mask pointer
* @return error code.
*/
int rtu_get_mirroring(int *en, uint32_t *imask, uint32_t *emask, uint32_t *dmask)
{
/* Enabled flag */
if (rtu_rd(RX_CTR) & RTU_RX_CTR_MR_ENA != 0)
*en = 1;
else
*en = 0;
/* destination port mask */
rtu_wr(RX_MP_R0, 0);
*dmask = RTU_RX_MP_R1_MASK_R(rtu_rd(RX_MP_R1));
/* ingress port mask */
rtu_wr(RX_MP_R0, RTU_RX_MP_R0_DST_SRC);
*imask = RTU_RX_MP_R1_MASK_R(rtu_rd(RX_MP_R1));
/* write egress port mask - source of mirrored traffic */
rtu_wr(RX_MP_R0, RTU_RX_MP_R0_DST_SRC | RTU_RX_MP_R0_RX_TX);
*emask = RTU_RX_MP_R1_MASK_R(rtu_rd(RX_MP_R1));
return 0;
}
//---------------------------------------------
// Private Methods
//---------------------------------------------
......
......@@ -96,4 +96,9 @@ void rtu_enable_irq(void);
void rtu_disable_irq(void);
void rtu_clear_irq(void);
// PORT MIRRORING
int rtu_enable_mirroring(int ena);
int rtu_cfg_mirroring(struct rtu_mirror_info *cfg);
int rtu_get_mirroring(int *en, uint32_t *imask, uint32_t *emask, uint32_t *dmask);
#endif /*__WHITERABBIT_RTU_DRV_H*/
......@@ -93,6 +93,11 @@ static unsigned long aging_time = DEFAULT_AGING_TIME;
*/
static struct rtu_vlan_table_entry *vlan_tab;
/**
* Mirror of port mirroring configuration
*/
static struct rtu_mirror_info *mirror_cfg;
/**
* \brief Mutex used to synchronise concurrent access to the filtering database.
*/
......@@ -110,6 +115,7 @@ static int hw_request(int type, struct rtu_addr addr,
static void clean_fd(void);
static void clean_vd(void);
static void clean_mc(void);
static void rtu_hw_commit(void);
static void rtu_fd_commit(void);
......@@ -200,7 +206,31 @@ int rtu_fd_init(uint16_t poly, unsigned long aging)
(sizeof(*vlan_tab) * NUM_VLANS + 7) & ~7;
}
if ((!rtu_htab) || (!vlan_tab)) {
if (!rtu_hdr->mirror) {
/* for first RTUd run */
pr_info("Allocating a new, port mirroring config\n");
mirror_cfg = wrs_shm_alloc(rtu_port_shmem,
sizeof(*mirror_cfg) * NUM_MIRROR);
rtu_hdr->mirror = mirror_cfg;
rtu_hdr->mirror_offset =
(void *)mirror_cfg - (void *)rtu_port_shmem;
pr_debug("Clean vlan database.\n");
clean_mc(); /* clean port mirroring config */
} else {
pr_info("Using existing port mirroring config.\n");
/* next RTUd runs */
rtu_hdr->mirror =
(void *)rtu_port_shmem + rtu_hdr->mirror_offset;
mirror_cfg = (void *)rtu_hdr->mirror;
/* move data_size to have have similar behavior like
* wrs_shm_alloc, needed for future allocations
* force 8-alignment
*/
rtu_port_shmem->data_size +=
(sizeof(*mirror_cfg) * NUM_MIRROR + 7) & ~7;
}
if ((!rtu_htab) || (!vlan_tab) || (!mirror_cfg)) {
pr_error("%s: Cannot allocate mem in shmem\n", __func__);
return -1;
}
......@@ -503,6 +533,23 @@ static void clean_vd(void)
wrs_shm_write(rtu_port_shmem, WRS_SHM_WRITE_END);
}
/**
* Port mirroring config initialization (disabled by default).
*/
static void clean_mc(void)
{
wrs_shm_write(rtu_port_shmem, WRS_SHM_WRITE_BEGIN);
mirror_cfg[0].en = 0;
mirror_cfg[0].imask = 0x0;
mirror_cfg[0].emask = 0x0;
mirror_cfg[0].dmask = 0x0;
rtu_enable_mirroring(mirror_cfg[0].en);
rtu_cfg_mirroring(mirror_cfg);
wrs_shm_write(rtu_port_shmem, WRS_SHM_WRITE_END);
}
/**
* \brief Updates the age of filtering entries accessed in the last period.
*/
......@@ -777,3 +824,23 @@ void rtu_fd_create_vlan_entry(int vid, uint32_t port_mask, uint8_t fid,
rtu_write_vlan_entry(vid, &vlan_tab[vid]);
wrs_shm_write(rtu_port_shmem, WRS_SHM_WRITE_END);
}
void rtu_fd_write_mirror_config(int en, uint32_t imask, uint32_t emask,
uint32_t dmask)
{
wrs_shm_write(rtu_port_shmem, WRS_SHM_WRITE_BEGIN);
mirror_cfg[0].en = en;
/* update masks in SHM only if non-zero, or if disabling mirroring */
if (en == 0 || imask != 0)
mirror_cfg[0].imask = imask;
if (en == 0 || emask != 0)
mirror_cfg[0].emask = emask;
if (en == 0 || dmask != 0)
mirror_cfg[0].dmask = dmask;
rtu_enable_mirroring(0);
rtu_cfg_mirroring(mirror_cfg);
rtu_enable_mirroring(en);
wrs_shm_write(rtu_port_shmem, WRS_SHM_WRITE_END);
}
......@@ -336,6 +336,41 @@ int rtudexp_vlan_entry(const struct minipc_pd *pd, uint32_t * args, void *ret)
return *p_ret;
}
int rtudexp_mirror(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
int oper;
int enable;
uint32_t imask, emask, dmask;
int *p_ret = (int *)ret;
enable = (int)args[0];
imask = (int)args[1];
emask = (int)args[2];
dmask = (int)args[3];
*p_ret = 0;
pr_debug("Request for mirroring configuration\n");
if (imask < 0 || imask > 0x3ffff) { /* 18 ports */
pr_error("Wrong ingress port mask 0x%x\n", imask);
*p_ret = -1;
return *p_ret;
}
if (emask < 0 || emask > 0x3ffff) { /* 18 ports */
pr_error("Wrong egress port mask 0x%x\n", emask);
*p_ret = -1;
return *p_ret;
}
if (enable == 1 && (dmask < 1 || dmask > 0x3ffff)) { /* 18 ports */
pr_error("Wrong destination port mask 0x%x\n", dmask);
*p_ret = -1;
return *p_ret;
}
rtu_fd_write_mirror_config(enable, imask, emask, dmask);
return *p_ret;
}
int rtud_init_exports()
{
rtud_ch = minipc_server_create("rtud", 0);
......@@ -355,6 +390,7 @@ int rtud_init_exports()
MINIPC_EXP_FUNC(rtud_export_unrec, rtudexp_unrec);
MINIPC_EXP_FUNC(rtud_export_vlan_entry, rtudexp_vlan_entry);
MINIPC_EXP_FUNC(rtud_export_hp_mask, rtudexp_hp_mask);
MINIPC_EXP_FUNC(rtud_export_mirror, rtudexp_mirror);
return 0;
}
......
......@@ -133,4 +133,17 @@ struct minipc_pd rtud_export_hp_mask = {
},
};
/* Export of a function to configure port mirroring in rtu */
struct minipc_pd rtud_export_mirror = {
.name = "mirror",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int), /* enable */
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int), /* ingress mask */
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int), /* egress mask */
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int), /* destination mask */
MINIPC_ARG_END,
},
};
#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