Commit 2e9542b1 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski Committed by Alessandro Rubini

userspace/wrsw_rtud: re-done register layout for N-port generic RTU

parent 00ce398d
......@@ -7,10 +7,10 @@
* Authors: Juan Luis Manas (juan.manas@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU data structures definition.
* Description: RTU data structures definition.
*
* Fixes:
* Tomasz Wlostowski
* Fixes:
* Tomasz Wlostowski
*
*
* This program is free software; you can redistribute it and/or
......@@ -39,16 +39,13 @@
#include "mac.h"
#define RTU_BANKS 2
#define RTU_ENTRIES 2048
#define RTU_BUCKETS 4
#define LAST_RTU_BUCKET ((RTU_BUCKETS)-1)
#define RTU_ENTRIES (16384/(RTU_BANKS))
#define HTAB_ENTRIES ((RTU_ENTRIES)/(RTU_BUCKETS))
#define LAST_HTAB_ENTRY ((HTAB_ENTRIES)-1)
#define LAST_RTU_BUCKET (RTU_BUCKETS-1)
#define ENTRY_WORDS 8
#define CAM_ENTRIES (((RTU_HCAM_WORDS)/(ENTRY_WORDS))/(RTU_BANKS))
#define LAST_CAM_ENTRY ((CAM_ENTRIES)-1)
#define MIN_PORT 0
#define MAX_PORT 9
......@@ -80,11 +77,11 @@
*/
struct rtu_request {
int port_id; // physical port identifier
uint8_t src[ETH_ALEN]; // source MAC address
uint8_t src[ETH_ALEN]; // source MAC address
uint8_t dst[ETH_ALEN]; // destination MAC address
uint16_t vid; // VLAN ID from the packet header
int has_vid; // non-zero: VID is present,0:untagged packet (VID=0)
uint8_t prio; // packet priority (either assigned by the port
uint8_t prio; // packet priority (either assigned by the port
// or extracted from packet header)
int has_prio; // non-zero: priority present, 0:no priority defined
};
......@@ -93,36 +90,36 @@ struct rtu_request {
* \brief RTU Filtering Database Entry Object
*/
struct filtering_entry {
int valid; // bit: 1 = entry is valid, 0: entry is
int valid; // bit: 1 = entry is valid, 0: entry is
// invalid (empty)
int end_of_bucket; // bit: 1 = last entry in current bucket, stop
// search at this point
int is_bpdu; // bit: 1 = BPDU (or other non-STP-dependent
int is_bpdu; // bit: 1 = BPDU (or other non-STP-dependent
// packet)
uint8_t mac[ETH_ALEN]; // MAC address (for searching the bucketed
uint8_t mac[ETH_ALEN]; // MAC address (for searching the bucketed
// hashtable)
uint8_t fid; // Filtering database ID (for searching the
// bucketed hashtable)
uint32_t port_mask_src; // port mask for source MAC addresses. Bits
// set to 1 indicate that packet having this
// MAC address can be forwarded from these
// corresponding ports. Ports having their
uint32_t port_mask_src; // port mask for source MAC addresses. Bits
// set to 1 indicate that packet having this
// MAC address can be forwarded from these
// corresponding ports. Ports having their
// bits set to 0 shall drop the packet.
uint32_t port_mask_dst; // port mask for destination MAC address. Bits
// set to 1 indicate to which physical ports
// the packet with matching destination MAC
// the packet with matching destination MAC
// address shall be routed
int drop_when_source; // bit: 1 = drop the packet when source
int drop_when_source; // bit: 1 = drop the packet when source
// address matches
int drop_when_dest; // bit: 1 = drop the packet when destination
int drop_when_dest; // bit: 1 = drop the packet when destination
// address matches
int drop_unmatched_src_ports; // bit: 1 = drop the packet when it comes from
// source port different than specified in
// port_mask_src
// source port different than specified in
// port_mask_src
uint32_t last_access_t; // time of last access to the rule (for aging)
......@@ -134,10 +131,10 @@ struct filtering_entry {
int has_prio_dst; // priority value valid
int prio_override_dst; // priority override (force per-MAC priority)
int go_to_cam; // 1 : there are more entries outside the
int go_to_cam; // 1 : there are more entries outside the
// bucket
uint16_t cam_addr; // address of the first entry in CAM memory
uint16_t cam_addr; // address of the first entry in CAM memory
// (2 words)
int dynamic;
......@@ -148,7 +145,7 @@ struct filtering_entry {
*/
struct vlan_table_entry {
uint32_t port_mask; // VLAN port mask: 1 = ports assigned to this VLAN
uint8_t fid; // Filtering Database Identifier
uint8_t fid; // Filtering Database Identifier
uint8_t prio; // VLAN priority
int has_prio; // priority defined;
int prio_override; // priority override (force per-VLAN priority)
......@@ -159,9 +156,9 @@ struct vlan_table_entry {
* \brief Copies src filtering entry body into dst filtering entry body.
* @return pointer to dst filtering entry.
*/
static inline
struct filtering_entry *rtu_fe_copy( struct filtering_entry *dst,
struct filtering_entry *src )
static inline
struct filtering_entry *rtu_fe_copy( struct filtering_entry *dst,
struct filtering_entry *src )
{
return memcpy( dst, src, sizeof(*src) );
}
......@@ -171,8 +168,8 @@ struct filtering_entry *rtu_fe_copy( struct filtering_entry *dst,
* @param ent pointer to entry to clean (either in HCAM or HTAB)
* @return pointer to filtering entry that was cleaned
*/
static inline
struct filtering_entry *rtu_fe_clean(struct filtering_entry *ent)
static inline
struct filtering_entry *rtu_fe_clean(struct filtering_entry *ent)
{
return memset( ent, 0, sizeof(*ent) );
}
......@@ -180,13 +177,13 @@ struct filtering_entry *rtu_fe_clean(struct filtering_entry *ent)
/**
* \brief Returns number of seconds since the epoch.
*/
static inline
unsigned long now()
static inline
unsigned long now()
{
return (unsigned long) time(NULL);
return (unsigned long) time(NULL);
}
int rtud_init_exports();
void rtud_handle_wripc();
#endif /*__WHITERABBIT_RTU_H*/
......@@ -8,18 +8,16 @@
* Miguel Baizan (miguel.baizan@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU driver module in user space. Provides read/write access
* to RTU_at_HW components including:
* - UFIFO
* Description: RTU driver module in user space. Provides read/write access
* to RTU_at_HW components including:
* - UFIFO
* - MFIFO
* - HCAM
* - Aging RAM for Main Hashtable
* - Aging Register for HCAM
* - VLAN Table
* - RTU Global Control Register
* - RTU Port settings
*
* Fixes:
* Fixes:
* Alessandro Rubini
* Tomasz Wlostowski
*
......@@ -43,7 +41,7 @@
#include <sys/ioctl.h>
#include <hw/switch_hw.h>
#include <hw/wrsw_rtu_wb.h>
#include <hw/rtu_regs.h>
#include <hal_client.h>
#include "rtu_drv.h"
......@@ -68,7 +66,6 @@ static void mac_entry_word3_r(uint32_t word, struct filtering_entry *ent);
static void mac_entry_word4_r(uint32_t word, struct filtering_entry *ent);
static uint32_t vlan_entry_word0_w(struct vlan_table_entry *ent);
static uint32_t fpga_rtu_pcr_addr(int port);
/*
* Used to communicate to RTU UFIFO IRQ handler device at kernel space
......@@ -82,17 +79,19 @@ int rtu_init(void)
{
int err;
if(halexp_client_init() < 0)
if(halexp_client_init() < 0)
TRACE(
TRACE_FATAL,
"WRSW_HAL is not responding... Are you sure it's running on your switch?\n"
"The HAL is not responding... Are you sure it's running on your switch?\n"
);
// Used to 'get' RTU IRQs from kernel
fd = open(RTU_DEVNAME, O_RDWR);
if (fd < 0)
return errno;
{
TRACE(TRACE_ERROR, "Can't open %s: is the RTU kernel driver loaded?", RTU_DEVNAME);
return errno;
}
// init IO memory map
err = shw_fpga_mmap_init();
if(err)
......@@ -107,11 +106,33 @@ void rtu_exit(void)
{
if(fd >= 0)
close(fd);
TRACE(TRACE_INFO, "module cleanup\n");
}
static inline uint32_t rtu_rd(uint32_t reg)
{
return _fpga_readl(FPGA_BASE_RTU + reg);
}
static inline void rtu_wr(uint32_t reg, uint32_t value)
{
_fpga_writel(FPGA_BASE_RTU + reg, value);
}
static inline void write_pcr(int port, uint32_t pcr)
{
rtu_wr(RTU_REG_PSR, RTU_PSR_PORT_SEL_W(port));
rtu_wr(RTU_REG_PCR, pcr);
}
static inline uint32_t read_pcr(int port)
{
rtu_wr(RTU_REG_PSR, RTU_PSR_PORT_SEL_W(port));
return rtu_rd(RTU_REG_PCR);
}
// UFIFO
/**
......@@ -120,7 +141,7 @@ void rtu_exit(void)
*/
int rtu_ufifo_is_empty(void)
{
uint32_t csr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_CSR);
uint32_t csr = rtu_rd( RTU_REG_UFIFO_CSR);
return RTU_UFIFO_CSR_EMPTY & csr;
}
......@@ -132,7 +153,7 @@ int rtu_read_learning_queue_cnt(void)
{
// Get counter from UFIFO Control-Status Register
// Fixme: USEDW returns 0 (FIFO overflow?)
uint32_t csr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_CSR);
uint32_t csr = rtu_rd( RTU_REG_UFIFO_CSR);
return RTU_UFIFO_CSR_USEDW_R(csr);
}
......@@ -142,10 +163,19 @@ int rtu_read_learning_queue_cnt(void)
* @param req pointer to unrecognised request data. Memory handled by callee.
* @return error code
*/
static int irq_disabled = 1;
int rtu_read_learning_queue(struct rtu_request *req)
{
int err;
if(irq_disabled)
{
ioctl(fd, WR_RTU_IRQENA);
irq_disabled = 0;
}
// If learning queue is empty, wait for UFIFO IRQ
if (rtu_ufifo_is_empty()) {
err = ioctl(fd, WR_RTU_IRQWAIT);
......@@ -153,27 +183,25 @@ int rtu_read_learning_queue(struct rtu_request *req)
return err;
}
// read data from mapped IO memory
uint32_t r0 = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_R0);
uint32_t r1 = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_R1);
uint32_t r2 = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_R2);
uint32_t r3 = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_R3);
uint32_t r4 = _fpga_readl(FPGA_BASE_RTU + RTU_REG_UFIFO_R4);
// read data from mapped IO memory
uint32_t r0 = rtu_rd( RTU_REG_UFIFO_R0);
uint32_t r1 = rtu_rd( RTU_REG_UFIFO_R1);
uint32_t r2 = rtu_rd( RTU_REG_UFIFO_R2);
uint32_t r3 = rtu_rd( RTU_REG_UFIFO_R3);
uint32_t r4 = rtu_rd( RTU_REG_UFIFO_R4);
// Once read: if learning queue becomes empty again, enable UFIFO IRQ
if (rtu_ufifo_is_empty())
ioctl(fd, WR_RTU_IRQENA);
// unmarshall data and populate request
uint32_t dmac_lo = RTU_UFIFO_R0_DMAC_LO_R(r0);
uint32_t dmac_hi = RTU_UFIFO_R1_DMAC_HI_R(r1);
uint32_t smac_lo = RTU_UFIFO_R2_SMAC_LO_R(r2);
uint32_t smac_hi = RTU_UFIFO_R3_SMAC_HI_R(r3);
req->port_id = RTU_UFIFO_R4_PID_R(r4);
req->has_prio = RTU_UFIFO_R4_HAS_PRIO & r4;
req->prio = RTU_UFIFO_R4_PRIO_R(r4);
req->has_vid = RTU_UFIFO_R4_HAS_VID & r4;
uint32_t smac_hi = RTU_UFIFO_R3_SMAC_HI_R(r3);
req->port_id = RTU_UFIFO_R4_PID_R(r4);
req->has_prio = RTU_UFIFO_R4_HAS_PRIO & r4;
req->prio = RTU_UFIFO_R4_PRIO_R(r4);
req->has_vid = RTU_UFIFO_R4_HAS_VID & r4;
req->vid = RTU_UFIFO_R4_VID_R(r4);
// destination mac
req->dst[5] = 0xFF & dmac_lo;
......@@ -189,6 +217,9 @@ int rtu_read_learning_queue(struct rtu_request *req)
req->src[2] = 0xFF & (smac_lo >> 24);
req->src[1] = 0xFF & smac_hi;
req->src[0] = 0xFF & (smac_hi >> 8);
ioctl(fd, WR_RTU_IRQENA);
return 0;
}
......@@ -202,7 +233,7 @@ int rtu_read_learning_queue(struct rtu_request *req)
int rtu_read_mfifo_cnt(void)
{
// Get counter from MFIFO Control-Status Register
uint32_t csr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_MFIFO_CSR);
uint32_t csr = rtu_rd( RTU_REG_MFIFO_CSR);
return RTU_MFIFO_CSR_USEDW_R(csr);
}
......@@ -212,7 +243,7 @@ int rtu_read_mfifo_cnt(void)
*/
int rtu_mfifo_is_full(void)
{
uint32_t csr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_MFIFO_CSR);
uint32_t csr = rtu_rd( RTU_REG_MFIFO_CSR);
return RTU_MFIFO_CSR_FULL & csr;
}
......@@ -222,20 +253,16 @@ int rtu_mfifo_is_full(void)
*/
int rtu_mfifo_is_empty(void)
{
uint32_t csr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_MFIFO_CSR);
uint32_t csr = rtu_rd( RTU_REG_MFIFO_CSR);
return RTU_MFIFO_CSR_EMPTY & csr;
}
/**
* \brief Cleans MFIFO
*/
void rtu_clean_mfifo(void)
static inline void flush_mfifo()
{
while(!rtu_mfifo_is_empty()) {
_fpga_writel(FPGA_BASE_RTU + RTU_REG_MFIFO_R0, RTU_MFIFO_R0_AD_SEL);
_fpga_writel(FPGA_BASE_RTU + RTU_REG_MFIFO_R1, 0);
usleep(10);
}
uint32_t gcr = rtu_rd (RTU_REG_GCR);
rtu_wr(RTU_REG_GCR, gcr | RTU_GCR_MFIFOTRIG);
while(!rtu_rd(RTU_REG_GCR) & RTU_GCR_MFIFOTRIG); /* wait while the RTU is busy flushing the MFIFO */
}
/**
......@@ -251,11 +278,12 @@ void rtu_write_htab_entry(uint16_t zbt_addr, struct filtering_entry *ent)
write_mfifo_data(mac_entry_word2_w(ent));
write_mfifo_data(mac_entry_word3_w(ent));
write_mfifo_data(mac_entry_word4_w(ent));
flush_mfifo();
TRACE_DBG(
TRACE_INFO,
"write htab entry: addr %x ent %08x %08x %08x %08x %08x",
zbt_addr,
"write htab entry [with flush]: addr %x ent %08x %08x %08x %08x %08x",
zbt_addr,
mac_entry_word0_w(ent),
mac_entry_word1_w(ent),
mac_entry_word2_w(ent),
......@@ -287,105 +315,21 @@ void rtu_clean_htab(void)
write_mfifo_data(0x00000000);
write_mfifo_data(0x00000000);
write_mfifo_data(0x00000000);
write_mfifo_data(0x00000000);
write_mfifo_data(0x00000000);
flush_mfifo();
}
}
// HCAM
/**
* \brief Reads MAC entry from HCAM Hash collisions memory
* @param ent used to store the entry read. Memory should be handled by callee.
* @param cam_addr memory address which shoud be read.
*/
void rtu_read_hcam_entry( uint16_t cam_addr, struct filtering_entry *ent )
{
// read data from mapped IO memory
uint32_t w0 = _fpga_readl(FPGA_BASE_RTU + RTU_HCAM + 4*cam_addr );
uint32_t w1 = _fpga_readl(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x1));
uint32_t w2 = _fpga_readl(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x2));
uint32_t w3 = _fpga_readl(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x3));
uint32_t w4 = _fpga_readl(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x4));
TRACE_DBG(
TRACE_INFO,
"read hcam entry: addr %x ent %08x %08x %08x %08x %08x",
cam_addr,
w0,
w1,
w2,
w3,
w4
);
// unmarshall data and populate entry
mac_entry_word0_r( w0, ent );
mac_entry_word1_r( w1, ent );
mac_entry_word2_r( w2, ent );
mac_entry_word3_r( w3, ent );
mac_entry_word4_r( w4, ent );
}
/**
* \brief Writes MAC entry to HCAM Hash collisions memory
* @param ent MAC table entry to be written to HCAM.
* @param cam_addr memory address in which MAC entry shoud be added.
*/
void rtu_write_hcam_entry( uint16_t cam_addr, struct filtering_entry *ent)
{
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*cam_addr , mac_entry_word0_w(ent));
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x1), mac_entry_word1_w(ent));
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x2), mac_entry_word2_w(ent));
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x3), mac_entry_word3_w(ent));
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x4), mac_entry_word4_w(ent));
TRACE_DBG(
TRACE_INFO,
"write hcam entry: addr %x ent %08x %08x %08x %08x %08x",
cam_addr,
mac_entry_word0_w(ent),
mac_entry_word1_w(ent),
mac_entry_word2_w(ent),
mac_entry_word3_w(ent),
mac_entry_word4_w(ent)
);
}
/**
* \brief Cleans MAC entry in HCAM Hash collisions memory
* @param addr memory address which shoud be cleaned.
*/
void rtu_clean_hcam_entry( uint8_t cam_addr )
{
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*cam_addr , 0x00000000);
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x1), 0x00000000);
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x2), 0x00000000);
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x3), 0x00000000);
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*(cam_addr + 0x4), 0x00000000);
TRACE_DBG(
TRACE_INFO,
"write hcam entry: addr %x ent 00000000 00000000 00000000 00000000 00000000", cam_addr);
}
/**
* \brief Cleans HCAM.
* Cleans all entries in HCAM inactive bank.
*/
void rtu_clean_hcam(void)
{
int addr;
for (addr = 0; addr < (RTU_HCAM_WORDS/RTU_BANKS); addr++) {
_fpga_writel(FPGA_BASE_RTU + RTU_HCAM + 4*addr, 0x00000000);
}
}
// AGING RAM - HTAB
/**
* \brief Read word from aging HTAB.
* Aging RAM Size: 256 32-bit words
*/
uint32_t rtu_read_agr_htab( uint32_t addr )
uint32_t rtu_read_agr_htab( uint32_t addr )
{
return _fpga_readl(FPGA_BASE_RTU + RTU_ARAM_MAIN + 4*addr) ;
return rtu_rd( RTU_ARAM_BASE + 4*addr) ;
}
/**
......@@ -394,32 +338,11 @@ uint32_t rtu_read_agr_htab( uint32_t addr )
void rtu_clean_agr_htab(void)
{
int addr;
for(addr=0;addr < RTU_ARAM_MAIN_WORDS;addr++) {
_fpga_writel(FPGA_BASE_RTU + RTU_ARAM_MAIN + 4*addr, 0x00000000);
for(addr=0;addr < RTU_ARAM_WORDS;addr++) {
rtu_wr(RTU_ARAM_BASE + 4*addr, 0x00000000);
}
}
// AGING RAM - HCAM
/**
* \brief Read aging register for HCAM.
* Each bit corresponds to one MAC entry in HCAM memory.
*/
uint32_t rtu_read_agr_hcam(void)
{
return _fpga_readl(FPGA_BASE_RTU + RTU_REG_AGR_HCAM);
}
/**
* \brief Clears aging register for HCAM
*/
void rtu_clean_agr_hcam(void)
{
_fpga_writel(FPGA_BASE_RTU + RTU_REG_AGR_HCAM, 0x00000000);
}
// VLAN TABLE
/**
......@@ -431,11 +354,11 @@ void rtu_write_vlan_entry(uint32_t addr, struct vlan_table_entry *ent)
{
// printf("write_VLAN_ent: addr %x val %x\n", + RTU_VLAN_TAB + 4*addr, vlan_entry_word0_w(ent));
_fpga_writel(FPGA_BASE_RTU + RTU_VLAN_TAB + 4*addr, vlan_entry_word0_w(ent));
rtu_wr(RTU_VLAN_TAB_BASE + 4*addr, vlan_entry_word0_w(ent));
TRACE_DBG(
TRACE_INFO,
"write vlan entry: addr %x ent %08x %08x %08x %08x %08x",
addr,
addr,
vlan_entry_word0_w(ent)
);
}
......@@ -447,7 +370,7 @@ void rtu_write_vlan_entry(uint32_t addr, struct vlan_table_entry *ent)
void rtu_clean_vlan_entry( uint32_t addr )
{
// Value 0x80000000 sets drop field to 1 (VLAN entry not registered)
_fpga_writel(FPGA_BASE_RTU + RTU_VLAN_TAB + 4*addr, 0x80000000);
rtu_wr(RTU_VLAN_TAB_BASE + 4*addr, 0x80000000);
}
/**
......@@ -457,7 +380,7 @@ void rtu_clean_vlan(void)
{
int addr;
for (addr = 0; addr < NUM_VLANS; addr++) {
_fpga_writel(FPGA_BASE_RTU + RTU_VLAN_TAB + 4*addr, 0x80000000);
rtu_wr(RTU_VLAN_TAB_BASE + 4*addr, 0x80000000);
}
}
......@@ -469,13 +392,9 @@ void rtu_clean_vlan(void)
*/
void rtu_enable(void)
{
// Get current GCR
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
// Set G_ENA bit value = 1
gcr = gcr | RTU_GCR_G_ENA;
// Update GCR
_fpga_writel(FPGA_BASE_RTU + RTU_REG_GCR, gcr );
TRACE_DBG(TRACE_INFO,"updated gcr (enable): %x\n", gcr);
uint32_t gcr = rtu_rd( RTU_REG_GCR);
rtu_wr(RTU_REG_GCR, gcr | RTU_GCR_G_ENA);
TRACE_DBG(TRACE_INFO,"updated gcr (enable): %x\n", gcr);
}
/**
......@@ -483,13 +402,9 @@ void rtu_enable(void)
*/
void rtu_disable(void)
{
// Get current GCR
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
// Set G_ENA bit value = 0
gcr = gcr & (~RTU_GCR_G_ENA);
// Update GCR
_fpga_writel(FPGA_BASE_RTU + RTU_REG_GCR, gcr );
TRACE_DBG(TRACE_INFO,"updated gcr (disable): %x\n", gcr);
uint32_t gcr = rtu_rd( RTU_REG_GCR);
rtu_wr(RTU_REG_GCR, gcr & (~RTU_GCR_G_ENA));
TRACE_DBG(TRACE_INFO,"updated gcr (disable): %x\n", gcr);
}
/**
......@@ -498,9 +413,8 @@ void rtu_disable(void)
*/
uint16_t rtu_read_hash_poly(void)
{
// Get current GCR
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
return RTU_GCR_POLY_VAL_R(gcr);
uint32_t gcr = rtu_rd( RTU_REG_GCR);
return RTU_GCR_POLY_VAL_R(gcr);
}
/**
......@@ -510,56 +424,14 @@ uint16_t rtu_read_hash_poly(void)
void rtu_write_hash_poly(uint16_t hash_poly)
{
// Get current GCR
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
uint32_t gcr = rtu_rd( RTU_REG_GCR);
// Clear previous hash poly and insert the new one
gcr = (gcr & (~RTU_GCR_POLY_VAL_MASK)) | RTU_GCR_POLY_VAL_W(hash_poly);
// Update GCR
_fpga_writel(FPGA_BASE_RTU + RTU_REG_GCR, gcr );
rtu_wr(RTU_REG_GCR, gcr );
TRACE_DBG(TRACE_INFO,"updated gcr (poly): %x\n", gcr);
}
/**
* \brief Set active ZBT bank.
* @param bank active ZBT bank (0 or 1). Other values will be evaluated as 1.
*/
void rtu_set_active_htab_bank(uint8_t bank)
{
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
gcr = bank ?
( RTU_GCR_HT_BSEL | gcr ) :
((~RTU_GCR_HT_BSEL) & gcr ) ;
_fpga_writel(FPGA_BASE_RTU + RTU_REG_GCR, gcr);
TRACE_DBG(TRACE_INFO,"updated gcr (htab bank): %x\n", gcr);
}
/**
* \brief Set active CAM bank.
* @param bank active CAM bank (0 or 1). Other values will be evaluated as 1.
*/
void rtu_set_active_hcam_bank(uint8_t bank)
{
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
gcr = bank ?
( RTU_GCR_HCAM_BSEL | gcr ) :
((~RTU_GCR_HCAM_BSEL) & gcr ) ;
_fpga_writel(FPGA_BASE_RTU + RTU_REG_GCR, gcr );
TRACE_DBG(TRACE_INFO,"updated gcr (hcam bank): %x\n", gcr);
}
/**
* \brief Set active ZBT and CAM banks at once.
* @param bank active ZBT and CAM bank (0 or 1). Other values will be evaluated as 1.
*/
void rtu_set_active_bank(uint8_t bank)
{
uint32_t gcr = _fpga_readl(FPGA_BASE_RTU + RTU_REG_GCR);
gcr = bank ?
( RTU_GCR_HT_BSEL | RTU_GCR_HCAM_BSEL | gcr ) :
((~RTU_GCR_HT_BSEL) & (~RTU_GCR_HCAM_BSEL) & gcr ) ;
_fpga_writel(FPGA_BASE_RTU + RTU_REG_GCR, gcr );
TRACE_DBG(TRACE_INFO,"updated gcr (htab/hcam bank): %x\n", gcr);
}
// PORT SETTINGS
......@@ -574,11 +446,9 @@ int rtu_set_fixed_prio_on_port(int port, uint8_t prio)
{
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr_addr = fpga_rtu_pcr_addr(port);
uint32_t pcr = _fpga_readl(FPGA_BASE_RTU + pcr_addr);
// Be careful! the following assumes every port control reg has same layout
pcr = pcr | RTU_PCR0_FIX_PRIO | RTU_PCR0_PRIO_VAL_W(prio);
_fpga_writel(FPGA_BASE_RTU + pcr_addr, pcr);
uint32_t pcr = read_pcr(port);
write_pcr(port, pcr | RTU_PCR_FIX_PRIO | RTU_PCR_PRIO_VAL_W(prio));
return 0;
}
......@@ -592,53 +462,51 @@ int rtu_unset_fixed_prio_on_port(int port)
{
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr_addr = fpga_rtu_pcr_addr(port);
uint32_t pcr = _fpga_readl(FPGA_BASE_RTU + pcr_addr);
// Be careful! the following assumes every port control reg has same layout
pcr = pcr & (RTU_PCR0_LEARN_EN | RTU_PCR0_PASS_ALL | RTU_PCR0_PASS_BPDU | RTU_PCR0_B_UNREC);
_fpga_writel(FPGA_BASE_RTU + pcr_addr, pcr);
uint32_t pcr = read_pcr(port);
write_pcr(port, pcr & (RTU_PCR_LEARN_EN | RTU_PCR_PASS_ALL | RTU_PCR_PASS_BPDU | RTU_PCR_B_UNREC));
return 0;
}
/**
* \brief Sets the LEARN_EN flag on indicated port.
* @param port port number (0 to 9)
* @param flag 0 disables learning. Otherwise: enables learning porcess on this port.
* @param flag 0 disables learning. Otherwise: enables learning porcess on this port.
* @return error code.
*/
int rtu_learn_enable_on_port(int port, int flag)
{
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr_addr = fpga_rtu_pcr_addr(port);
uint32_t pcr = _fpga_readl(FPGA_BASE_RTU + pcr_addr);
// Be careful! the following assumes every port control reg has same layout
pcr = flag ?
RTU_PCR0_LEARN_EN | pcr :
(~RTU_PCR0_LEARN_EN) & pcr ;
_fpga_writel(FPGA_BASE_RTU + pcr_addr, pcr);
return 0;
uint32_t pcr = read_pcr(port);
pcr = flag ?
RTU_PCR_LEARN_EN | pcr :
(~RTU_PCR_LEARN_EN) & pcr ;
write_pcr(port, pcr);
return 0;
}
/**
* \brief Sets the PASS_BPDU flag on indicated port.
* @param port port number (0 to 9)
* @param flag 0: BPDU packets are passed RTU rules only if PASS_ALL is set.
* Otherwise: BPDU packets are passed according to RTU rules.
* Otherwise: BPDU packets are passed according to RTU rules.
* @return error code.
*/
int rtu_pass_bpdu_on_port(int port, int flag)
int rtu_pass_bpdu_on_port(int port, int flag)
{
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr_addr = fpga_rtu_pcr_addr(port);
uint32_t pcr = _fpga_readl(FPGA_BASE_RTU + pcr_addr);
// Be careful! the following assumes every port control reg has same layout
pcr = flag ?
RTU_PCR0_PASS_BPDU | pcr :
(~RTU_PCR0_PASS_BPDU) & pcr ;
_fpga_writel(FPGA_BASE_RTU + pcr_addr, pcr);
return 0;
uint32_t pcr = read_pcr(port);
pcr = flag ?
RTU_PCR_PASS_BPDU | pcr :
(~RTU_PCR_PASS_BPDU) & pcr ;
write_pcr(port, pcr);
return 0;
}
/**
......@@ -647,56 +515,41 @@ int rtu_pass_bpdu_on_port(int port, int flag)
* @param flag 0: all packets are dropped. Otherwise: all packets are passed.
* @return error code.
*/
int rtu_pass_all_on_port(int port, int flag)
int rtu_pass_all_on_port(int port, int flag)
{
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr_addr = fpga_rtu_pcr_addr(port);
uint32_t pcr = _fpga_readl(FPGA_BASE_RTU + pcr_addr);
// Be careful! the following assumes every port control reg has same layout
pcr = flag ?
RTU_PCR0_PASS_ALL | pcr :
(~RTU_PCR0_PASS_ALL) & pcr ;
_fpga_writel(FPGA_BASE_RTU + pcr_addr, pcr);
return 0;
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr = read_pcr(port);
pcr = flag ?
RTU_PCR_PASS_ALL | pcr :
(~RTU_PCR_PASS_ALL) & pcr ;
write_pcr(port, pcr);
return 0;
}
/**
* \brief Sets the B_UNREC flag on indicated port.
* @param port port number (0 to 9)
* @param flag 0: packet is dropped. Otherwise: packet is broadcast.
* @param flag 0: packet is dropped. Otherwise: packet is broadcast.
* @return error code.
*/
int rtu_set_unrecognised_behaviour_on_port(int port, int flag)
int rtu_set_unrecognised_behaviour_on_port(int port, int flag)
{
if( (port < MIN_PORT) || (port > MAX_PORT) )
return -EINVAL;
uint32_t pcr_addr = fpga_rtu_pcr_addr(port);
uint32_t pcr = _fpga_readl(FPGA_BASE_RTU + pcr_addr);
// Be careful! the following assumes every port control reg has same layout
pcr = flag ?
RTU_PCR0_B_UNREC | pcr :
(~RTU_PCR0_B_UNREC) & pcr ;
_fpga_writel(FPGA_BASE_RTU + pcr_addr, pcr);
return 0;
}
// IRQs
uint32_t pcr = read_pcr(port);
void rtu_enable_irq(void)
{
_fpga_writel(FPGA_BASE_RTU + RTU_REG_EIC_IER, RTU_EIC_IER_NEMPTY);
}
pcr = flag ?
RTU_PCR_B_UNREC | pcr :
(~RTU_PCR_B_UNREC) & pcr ;
void rtu_disable_irq(void)
{
_fpga_writel(FPGA_BASE_RTU + RTU_REG_EIC_IDR, RTU_EIC_IDR_NEMPTY);
write_pcr(port, pcr);
return 0;
}
void rtu_clear_irq(void)
{
_fpga_writel(FPGA_BASE_RTU + RTU_REG_EIC_ISR, RTU_EIC_ISR_NEMPTY);
}
//---------------------------------------------
// Private Methods
......@@ -706,33 +559,28 @@ void rtu_clear_irq(void)
static void write_mfifo_addr(uint32_t zbt_addr)
{
// workaround required to solve MFIFO overflow
rtu_clean_mfifo();
_fpga_writel(FPGA_BASE_RTU + RTU_REG_MFIFO_R0, RTU_MFIFO_R0_AD_SEL);
_fpga_writel(FPGA_BASE_RTU + RTU_REG_MFIFO_R1, zbt_addr);
rtu_wr(RTU_REG_MFIFO_R0, RTU_MFIFO_R0_AD_SEL);
rtu_wr(RTU_REG_MFIFO_R1, zbt_addr);
}
static void write_mfifo_data(uint32_t word)
{
_fpga_writel(FPGA_BASE_RTU + RTU_REG_MFIFO_R0, RTU_MFIFO_R0_DATA_SEL);
_fpga_writel(FPGA_BASE_RTU + RTU_REG_MFIFO_R1, word);
// workaround required to solve MFIFO overflow
while(rtu_mfifo_is_full());
rtu_wr(RTU_REG_MFIFO_R0, RTU_MFIFO_R0_DATA_SEL);
rtu_wr(RTU_REG_MFIFO_R1, word);
}
// to marshall MAC entries
static uint32_t mac_entry_word0_w(struct filtering_entry *ent)
{
return
return
((0xFF & ent->mac[0]) << 24) |
((0xFF & ent->mac[1]) << 16) |
((0xFF & ent->fid) << 4) |
((0x1 & ent->go_to_cam) << 3) |
((0x1 & ent->is_bpdu) << 2) |
((0x1 & ent->end_of_bucket) << 1) |
((0x1 & ent->valid ) ) ;
((0xFF & ent->fid) << 4) |
((0x1 & ent->go_to_cam) << 3) |
((0x1 & ent->is_bpdu) << 2) |
((0x1 & ent->end_of_bucket) << 1) |
((0x1 & ent->valid ) ) ;
}
static uint32_t mac_entry_word1_w(struct filtering_entry *ent)
......@@ -747,28 +595,28 @@ static uint32_t mac_entry_word1_w(struct filtering_entry *ent)
static uint32_t mac_entry_word2_w(struct filtering_entry *ent)
{
return
((0x1 & ent->drop_when_dest) << 28) |
((0x1 & ent->prio_override_dst) << 27) |
((0x7 & ent->prio_dst) << 24) |
((0x1 & ent->has_prio_dst) << 23) |
((0x1 & ent->drop_unmatched_src_ports) << 22) |
((0x1 & ent->drop_when_source) << 21) |
((0x1 & ent->drop_when_dest) << 28) |
((0x1 & ent->prio_override_dst) << 27) |
((0x7 & ent->prio_dst) << 24) |
((0x1 & ent->has_prio_dst) << 23) |
((0x1 & ent->drop_unmatched_src_ports) << 22) |
((0x1 & ent->drop_when_source) << 21) |
((0x1 & ent->prio_override_src) << 20) |
((0x7 & ent->prio_src) << 17) |
((0x1 & ent->has_prio_src) << 16) |
((0x01FF & ent->cam_addr) ) ;
((0x7 & ent->prio_src) << 17) |
((0x1 & ent->has_prio_src) << 16) |
((0x01FF & ent->cam_addr) ) ;
}
static uint32_t mac_entry_word3_w(struct filtering_entry *ent)
{
return
((0xFFFF & ent->port_mask_dst) << 16) |
((0xFFFF & ent->port_mask_dst) << 16) |
((0xFFFF & ent->port_mask_src) ) ;
}
static uint32_t mac_entry_word4_w(struct filtering_entry *ent)
{
return
return
(ent->last_access_t);
}
......@@ -824,8 +672,8 @@ static void mac_entry_word4_r(uint32_t word, struct filtering_entry *ent)
static uint32_t vlan_entry_word0_w(struct vlan_table_entry *ent)
{
return
((0x1 & ent->drop) << 31) |
return
((0x1 & ent->drop) << 31) |
((0x1 & ent->prio_override) << 30) |
((0x7 & ent->prio) << 27) |
((0x1 & ent->has_prio) << 26) |
......@@ -833,21 +681,3 @@ static uint32_t vlan_entry_word0_w(struct vlan_table_entry *ent)
((0xFFFF & ent->port_mask) ) ;
}
static uint32_t fpga_rtu_pcr_addr(int port)
{
switch(port){
case 0: return RTU_REG_PCR0;
case 1: return RTU_REG_PCR1;
case 2: return RTU_REG_PCR2;
case 3: return RTU_REG_PCR3;
case 4: return RTU_REG_PCR4;
case 5: return RTU_REG_PCR5;
case 6: return RTU_REG_PCR6;
case 7: return RTU_REG_PCR7;
case 8: return RTU_REG_PCR8;
case 9: return RTU_REG_PCR9;
default:return -EINVAL;
}
}
......@@ -33,11 +33,6 @@
#include "rtu.h"
// HW RTU (should be given by wrsw_rtu_wb.h)
#define RTU_HCAM 0x4000
#define RTU_ARAM_MAIN 0x8000
#define RTU_VLAN_TAB 0xc000
#define RTU_MFIFO_R0_DATA_SEL 0x00000000
#define RTU_MFIFO_R1_ADDR_MASK 0x0007FFFF
......
/*
/*\
* White Rabbit RTU (Routing Table Unit)
* Copyright (C) 2010, CERN.
*
......@@ -8,12 +8,12 @@
* Miguel Baizan (miguel.baizan@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU Filtering database.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* Description: RTU Filtering database.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* object per Bridge (See 802.1Q - 12.7.1)
*
* Fixes:
* Fixes:
* Alessandro Rubini
* Tomasz Wlostowski
*
......@@ -36,7 +36,7 @@
#include <unistd.h>
#include <pthread.h>
#include <hw/wrsw_rtu_wb.h>
#include <hw/rtu_regs.h>
#include <hw/trace.h>
#include "rtu_fd.h"
......@@ -45,7 +45,6 @@
// Used to declare memory type at filtering database entry handles.
#define HTAB 0
#define HCAM 1
// Used to declare HW request types.
#define HW_WRITE_REQ 0
......@@ -60,7 +59,7 @@
/**
* \brief Filtering Database entry handle.
* \brief Filtering Database entry handle.
*/
struct fd_handle {
int mem_type; // HTAB or HCAM
......@@ -91,22 +90,9 @@ struct hw_req *hw_req_list;
static struct filtering_entry rtu_htab[HTAB_ENTRIES][RTU_BUCKETS];
/**
* \brief Mirror of CAM lookup table.
* For RTU entries with more than 4 matches
* \brief Mirror of Aging RAM.
*/
static struct filtering_entry rtu_hcam[CAM_ENTRIES];
/**
* \brief Table bank to write entries to.
* HTAB and HCAM banks will be handled according to this single bank value.
*/
static uint8_t bank;
/**
* \brief Mirror of Aging RAM.
*/
static uint32_t rtu_agr_htab[RTU_ARAM_MAIN_WORDS];
static uint32_t rtu_agr_hcam;
static uint32_t rtu_agr_htab[RTU_ARAM_WORDS];
/**
* \brief Max time that a dynamic MAC entry can remain
......@@ -129,26 +115,17 @@ static void clean_list(struct hw_req *head);
static int add_hw_req(int type, int mem, uint16_t addr, struct filtering_entry *ent);
static inline int write_htab_entry(uint16_t addr, struct filtering_entry *e);
static inline int write_hcam_entry(uint16_t addr, struct filtering_entry *e);
static inline int clean_htab_entry(uint16_t addr);
static inline int clean_hcam_entry(uint16_t addr);
static inline uint16_t zbt_addr(uint16_t hash, int bucket);
static inline uint16_t cam_addr(int bucket);
static inline int cam_bucket(uint16_t cam_addr);
static inline int matched(uint32_t word, int offset);
static int htab_contains(uint8_t mac[ETH_ALEN], uint8_t fid, int *bucket,
static int htab_contains(uint8_t mac[ETH_ALEN], uint8_t fid, int *bucket,
struct filtering_entry **ent);
static int hcam_contains(uint8_t mac[ETH_ALEN], uint8_t fid, int *bucket,
struct filtering_entry **ent);
static int find_empty_bucket_in_hcam(void);
static void set_active_bank(int n);
static void clean_fd(void);
static void clean_vd(void);
......@@ -160,10 +137,8 @@ static void rtu_hw_commit(void);
static void rtu_fd_commit(void);
static void shift_htab_entries(uint16_t hash, int bucket);
static int shift_hcam_entries(int bucket);
static void delete_htab_entry(uint16_t hash, int bucket);
static void delete_hcam_entry(int bucket);
static void rtu_fd_age_out(void);
static void rtu_fd_age_update(void);
......@@ -204,12 +179,12 @@ int rtu_fd_init(uint16_t poly, unsigned long aging)
* @param port_map a port map specification with a control element for each
* outbound port to specify filtering for that MAC address specification and VID
* @param dynamic it indicates whether it's a dynamic entry
* @return 0 if entry was created or updated. -ENOMEM if no space is available.
* @return 0 if entry was created or updated. -ENOMEM if no space is available.
*/
int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map, int dynamic)
{
struct filtering_entry *ent; // pointer to scan hashtable
uint16_t hash; // hashtable key
uint16_t hash; // hashtable key
uint8_t fid; // Filtering database identifier
int bucket = 0; // bucket loop index
int ret = 0; // return value
......@@ -224,8 +199,8 @@ int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map,
// Check HTAB
ent = &rtu_htab[hash][bucket];
switch(htab_contains(mac, fid, &bucket, &ent)){
case FOUND:
// update
case FOUND:
// update
mask_dst = ent->port_mask_dst | port_map;
mask_src = ent->port_mask_src | vlan_tab[vid].port_mask;
if ((ent->port_mask_dst != mask_dst) ||
......@@ -246,57 +221,10 @@ int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map,
write_htab_entry(zbt_addr(hash, bucket), ent);
break;
case NOT_FOUND_AND_FULL: // Not found and HTAB full for this hash
// Check whether HCAM was already used.
if(ent->go_to_cam){
bucket = cam_bucket(ent->cam_addr);
} else {
bucket = find_empty_bucket_in_hcam();
if (bucket < 0) {
ret = -ENOMEM;
break;
}
// update htab last entry to point to hcam entry
ent->go_to_cam = 1;
ent->cam_addr = cam_addr(bucket);
write_htab_entry(zbt_addr(hash, LAST_RTU_BUCKET), ent);
}
// Check HCAM
ent = &rtu_hcam[bucket];
switch(hcam_contains(mac, fid, &bucket, &ent)){
case FOUND:
// update
mask_dst = ent->port_mask_dst | port_map;
mask_src = ent->port_mask_src | vlan_tab[vid].port_mask;
if ((ent->port_mask_dst != mask_dst) ||
(ent->port_mask_src != mask_src)) { // something new
ent->port_mask_dst = mask_dst;
ent->port_mask_src = mask_src;
write_hcam_entry(cam_addr(bucket), ent);
}
break;
case NOT_FOUND:
// existing list does not contain the entry and is necessary to
// append new entry at the end of current list
ent->end_of_bucket = 0;
write_hcam_entry(cam_addr(bucket), ent);
ent++;
bucket++;
case NOT_FOUND_AND_FIRST:
// First entry in HCAM for this hash.
ent->valid = 1;
ent->end_of_bucket = 1;
ent->fid = fid;
ent->port_mask_src = vlan_tab[vid].port_mask;
ent->port_mask_dst = port_map;
ent->dynamic = dynamic;
ent->last_access_t = now();
mac_copy(ent->mac, mac);
write_hcam_entry(cam_addr(bucket), ent);
break;
default:
ret = -ENOMEM;
}
ret = -ENOMEM;
break;
/* fixme: allocate an entry in HTAB which is not used by any hash value */
}
}
rtu_fd_commit();
......@@ -309,24 +237,24 @@ int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map,
* Changing the hash polynomial requires removing any existing
* entry from RTU table.
* Note in case RTU table becomes full, this function may
* be used to change hash polynomial (thus leading to a different hash
* be used to change hash polynomial (thus leading to a different hash
* distribution).
* @param poly binary polynomial representation.
* CRC-16-CCITT -> 1+x^5+x^12+x^16 -> 0x1021
* @param poly binary polynomial representation.
* CRC-16-CCITT -> 1+x^5+x^12+x^16 -> 0x1021
* CRC-16-IBM -> 1+x^2+x^15+x^16 -> 0x8005
* CRC-16-DECT -> 1+x^3+x^7+x^8+x^10+x^16 -> 0x0589
*/
void rtu_fd_set_hash_poly(uint16_t poly)
{
{
pthread_mutex_lock(&fd_mutex);
rtu_write_hash_poly(poly);
rtu_hash_set_poly(poly);
pthread_mutex_unlock(&fd_mutex);
rtu_hash_set_poly(poly);
pthread_mutex_unlock(&fd_mutex);
}
/**
* \brief Sets the aging time for dynamic filtering entries.
* @param t new aging time value [seconds].
* @param t new aging time value [seconds].
* @return -EINVAL if t < 10 or t > 1000000 (802.1Q, Table 8.3); 0 otherwise.
*/
int rtu_fd_set_aging_time(unsigned long t)
......@@ -343,12 +271,12 @@ int rtu_fd_set_aging_time(unsigned long t)
* changes in active topology.
*/
void rtu_fd_flush(void)
{
{
update_aging_map(); // Work with latest access info
rtu_fd_age_update(); // Update filtering entries age
rtu_fd_age_update(); // Update filtering entries age
pthread_mutex_lock(&fd_mutex);
rtu_fd_age_out(); // Remove old entries
rtu_fd_age_out(); // Remove old entries
pthread_mutex_unlock(&fd_mutex);
clean_aging_map(); // Keep track of entries access in next period
......@@ -365,9 +293,9 @@ struct filtering_entry *rtu_fd_lookup_htab_entry(int index)
{
if(n == index) return &rtu_htab[i][j];
n++;
}
}
}
}
}
}
return NULL;
}
......@@ -408,7 +336,7 @@ static int add_hw_req(int type, int mem, uint16_t addr, struct filtering_entry *
req = (struct hw_req*) malloc(sizeof(struct hw_req));
if(!req)
return -ENOMEM;
req->type = type;
req->handle.mem_type = mem;
req->handle.addr = addr;
......@@ -423,49 +351,37 @@ static int add_hw_req(int type, int mem, uint16_t addr, struct filtering_entry *
return 0;
}
static inline
static inline
int write_htab_entry(uint16_t addr, struct filtering_entry *e)
{
return add_hw_req(HW_WRITE_REQ, HTAB, addr, e);
}
static inline
int write_hcam_entry(uint16_t addr, struct filtering_entry *e)
{
return add_hw_req(HW_WRITE_REQ, HCAM, addr, e);
}
static inline
static inline
int clean_htab_entry(uint16_t addr)
{
return add_hw_req(HW_CLEAN_REQ, HTAB, addr, NULL);
}
static inline
int clean_hcam_entry(uint16_t addr)
{
return add_hw_req(HW_CLEAN_REQ, HCAM, addr, NULL);
}
static inline
static inline
uint16_t zbt_addr(uint16_t hash, int bucket)
{
return (( 0x07FF & hash ) << 5 ) | ((0x0003 & bucket) << 3);
}
static inline
static inline
uint16_t cam_addr(int bucket)
{
return ((0x001F & bucket) << 3);
}
static inline
static inline
int cam_bucket(uint16_t cam_addr)
{
return ((cam_addr >> 3) & 0x001F);
}
static inline
static inline
int matched(uint32_t word, int offset)
{
return (word >> offset) & 0x00000001;
......@@ -481,9 +397,9 @@ int matched(uint32_t word, int offset)
* HTAB was full for the corresponding hash. -EINVAL if bucket >= RTU_BUCKETS
*/
static int htab_contains(
uint8_t mac[ETH_ALEN],
uint8_t fid,
int *bucket,
uint8_t mac[ETH_ALEN],
uint8_t fid,
int *bucket,
struct filtering_entry **ent)
{
for(; *bucket < RTU_BUCKETS; (*bucket)++, (*ent)++) {
......@@ -492,97 +408,11 @@ static int htab_contains(
if(mac_equal((*ent)->mac, mac) && ((*ent)->fid == fid))
return FOUND;
if(*bucket == LAST_RTU_BUCKET)
return NOT_FOUND_AND_FULL;
}
return -EINVAL;
}
/**
* Checks whether a given pair (mac,fid) is at HCAM
* @param mac mac address
* @param fid filtering database identifier
* @param bucket inout param.Returns the bucket number where the entry was found
* @param ent pointer to entry found.
* @return 0 if entry was not found. 1 if entry was found. -1 if entry was not
* found and the end of bucket was reached. -ENOMEM if no more entries after the
* end of bucket. -EINVAL if bucket >= CAM_ENTRIES or HCAM inconsistent.
*/
static int hcam_contains(
uint8_t mac[ETH_ALEN],
uint8_t fid,
int *bucket,
struct filtering_entry **ent)
{
for(; *bucket < CAM_ENTRIES; (*bucket)++, (*ent)++) {
if(!(*ent)->valid)
return NOT_FOUND_AND_FIRST;
if(mac_equal((*ent)->mac, mac) && ((*ent)->fid == fid))
return FOUND;
if((*ent)->end_of_bucket)
return
(*bucket+1 < CAM_ENTRIES) && !rtu_hcam[*bucket+1].valid ?
NOT_FOUND:-ENOMEM;
}
return -EINVAL;
}
/**
* \brief Find the most appropriate empty bucket to insert new hash collision
* list. The algorithm first finds the fragment which contains the max number of
* consecutive empty positions. Then divides this fragment into two parts: first
* block is still available for possible increment of any existing list; The
* second block will be available for the new list.
* The algorithm keeps a fair and uniform distribution of fragments space.
* @return bucket index or -1 if the HCAM table is full.
*/
static int find_empty_bucket_in_hcam(void)
{
int bucket = 0; // bucket loop index
int res = 0; // result bucket
int empty = 0; // consecutive empty buckets
int max = 0; // max consecutive empty buckets
// First obtain position with max consecutive empty space
for(; bucket < CAM_ENTRIES; bucket++) {
if (rtu_hcam[bucket].valid) {
if (empty > max) {
max = empty;
res = bucket - empty;
}
empty = 0;
} else {
empty++;
}
}
// Update max consecutive empty buckets if necessary
if (empty > max) {
max = empty;
res = bucket - empty;
}
if(max == 0) // bank is full
return -1;
else if(max == CAM_ENTRIES) // bank is empty
return 0;
else // Divide max space in two blocks and take address of second block
return res + max/2;
return NOT_FOUND_AND_FULL;
}
return -EINVAL;
}
/**
* \brief Set the filtering database active bank both in software and hardware.
* Note both HTAB and HCAM active banks are switched at once.
* Bank switching is delayed until MFIFO is empty (method remains blocked
* meanwhile).
*/
static void set_active_bank(int b)
{
// wait until MFIFO is empty
rtu_clean_mfifo();
// inactive bank becomes active (both banks are switched at once)
rtu_set_active_bank(b);
// active bank becomes inactive one
bank = (b == 0) ? 1:0;
}
/**
* Filtering database initialisation.
......@@ -590,18 +420,12 @@ static void set_active_bank(int b)
static void clean_fd(void)
{
memset(&rtu_htab, 0, sizeof(rtu_htab));
memset(&rtu_hcam, 0, sizeof(rtu_hcam));
set_active_bank(0);
rtu_clean_htab();
rtu_clean_hcam();
set_active_bank(1);
rtu_clean_htab();
rtu_clean_hcam();
}
/**
* VLAN database initialisation. VLANs are initially marked as disabled.
* VLAN database initialisation. VLANs are initially marked as disabled.
*/
static void clean_vd(void)
{
......@@ -629,10 +453,8 @@ static void clean_vd(void)
static void clean_aging_map(void)
{
int i;
rtu_agr_hcam = 0x00000000;
rtu_clean_agr_hcam();
for(i = 0; i < RTU_ARAM_MAIN_WORDS; i++) {
for(i = 0; i < RTU_ARAM_WORDS; i++) {
rtu_agr_htab[i] = 0x00000000;
}
rtu_clean_agr_htab();
......@@ -645,20 +467,19 @@ static void update_aging_map(void)
{
int i;
rtu_agr_hcam = rtu_read_agr_hcam();
for(i = 0; i < RTU_ARAM_MAIN_WORDS; i++) {
for(i = 0; i < RTU_ARAM_WORDS; i++) {
rtu_agr_htab[i] = rtu_read_agr_htab(i);
}
}
/**
* \brief Updates the age of filtering entries accessed in the last period.
* \brief Updates the age of filtering entries accessed in the last period.
*/
static void rtu_fd_age_update(void)
{
int i; // Aging Bitmap word loop index
int j; // Word bits loop index
uint32_t agr_word; // Aux var for manipulating aging RAM
uint32_t agr_word; // Aux var for manipulating aging RAM
uint16_t hash; // HTAB entry hash (index)
int bucket; // HTAB entry bucket
int bit_cnt; // Absolute bit counter
......@@ -667,20 +488,20 @@ static void rtu_fd_age_update(void)
// Update 'last access time' for accessed entries
t = now();
// HTAB
for(i = 0; i < RTU_ARAM_MAIN_WORDS; i++) {
for(i = 0; i < RTU_ARAM_WORDS; i++) {
agr_word = rtu_agr_htab[i];
if(agr_word != 0x00000000) {
for(j = 0; j < 32; j++){
if(matched(agr_word, j)) {
// ((word_pos x 32) + bit_pos)
bit_cnt = ((i & 0x00FF) << 5) | (j & 0x001F);
if(matched(agr_word, j)) {
// ((word_pos x 32) + bit_pos)
bit_cnt = ((i & 0x00FF) << 5) | (j & 0x001F);
hash = bit_cnt >> 2; // 4 buckets per hash
bucket = bit_cnt & 0x03; // last 2 bits
bucket = bit_cnt & 0x03; // last 2 bits
rtu_htab[hash][bucket].last_access_t = t;
TRACE(
TRACE_INFO,
"updated htab entry age: mac = %s, hash = %d, bucket = %d\n, t = %d",
TRACE_INFO,
"updated htab entry age: mac = %s, hash = %d, bucket = %d\n, t = %d",
mac_to_string(rtu_htab[hash][bucket].mac),
hash,
bucket,
......@@ -690,24 +511,11 @@ static void rtu_fd_age_update(void)
}
}
}
// HCAM
agr_word = rtu_agr_hcam;
for(j = 0; j < 32; j++){
if(matched(agr_word, j)) {
rtu_hcam[j].last_access_t = t;
TRACE(
TRACE_INFO,
"updated hcam entry age: mac = %s, bucket = %d\n",
mac_to_string(rtu_hcam[j].mac),
j
);
}
}
}
/**
* For each filtering entry in the filtering database, this method checks its
* last access time and removes it in case entry is older than the aging time.
* For each filtering entry in the filtering database, this method checks its
* last access time and removes it in case entry is older than the aging time.
*/
static void rtu_fd_age_out(void)
{
......@@ -717,26 +525,13 @@ static void rtu_fd_age_out(void)
unsigned long t; // (secs)
t = now() - aging_time;
// HCAM
for(j = CAM_ENTRIES; j-- > 0;){
ent = &rtu_hcam[j];
if(ent->valid && ent->dynamic && time_after(t, ent->last_access_t)) {
TRACE(
TRACE_INFO,
"deleting hcam entry: mac = %s, bucket = %d\n",
mac_to_string(ent->mac),
j
);
delete_hcam_entry(j);
}
}
// HTAB
// HTAB
for (i = HTAB_ENTRIES; i-- > 0;) {
for (j = RTU_BUCKETS; j-- > 0;) {
ent = &rtu_htab[i][j];
if(ent->valid && ent->dynamic && time_after(t, ent->last_access_t)){
TRACE(
TRACE_INFO,
TRACE_INFO,
"deleting htab entry: mac = %s, hash = %d, bucket = %d\n",
mac_to_string(ent->mac),
i,
......@@ -751,7 +546,7 @@ static void rtu_fd_age_out(void)
}
/**
* \brief Read changes from hw_req_list and invoke RTU driver to efectively
* \brief Read changes from hw_req_list and invoke RTU driver to efectively
* write or clean the entry.
*/
static void rtu_hw_commit(void)
......@@ -763,17 +558,13 @@ static void rtu_hw_commit(void)
case HW_WRITE_REQ:
if(req->handle.mem_type == HTAB)
rtu_write_htab_entry(req->handle.addr, req->handle.entry_ptr);
else
rtu_write_hcam_entry(req->handle.addr, req->handle.entry_ptr);
break;
case HW_CLEAN_REQ:
if(req->handle.mem_type == HTAB)
rtu_clean_htab_entry(req->handle.addr);
else
rtu_clean_hcam_entry(req->handle.addr);
break;
break;
}
}
}
}
/**
......@@ -784,11 +575,6 @@ static void rtu_fd_commit(void)
if(!hw_req_list)
return;
// write entries to inactive bank
rtu_hw_commit();
// switch bank to make entries available to RTU at HW
set_active_bank(bank);
// both banks need same content
rtu_hw_commit();
// this list no longer needed
......@@ -797,7 +583,7 @@ static void rtu_fd_commit(void)
}
/**
* \brief Shifts HTAB list one position, starting at bucket.
* \brief Shifts HTAB list one position, starting at bucket.
*/
static void shift_htab_entries(uint16_t hash, int bucket)
{
......@@ -819,74 +605,9 @@ static void shift_htab_entries(uint16_t hash, int bucket)
}
}
/**
* \brief Shifts HCAM list one position, starting at bucket.
* If entry to remove is end of bucket, marks previous one (if exists) as the
* new end of bucket.
* @return -1 if more entries remain in HCAM. Otherwise, returns the hash for
* entry, in order to help modifying the last HTAB entry
*/
static int shift_hcam_entries(int bucket)
{
struct filtering_entry *ent; // entry to remove
struct filtering_entry *next_ent; // following entry
struct filtering_entry *prev_ent; // previous entry
int ret; // return value
int i;
ret = -1;
ent = &rtu_hcam[bucket];
for(i = bucket; i < LAST_CAM_ENTRY; i++){
if(ent->end_of_bucket){
if(i > bucket) // entry to remove was not the last
break;
if(i == 0){ // entry to remove was last but there are no previous
ret = rtu_hash(ent->mac, ent->fid);
break;
}
prev_ent = ent-1;
if(!prev_ent->valid || prev_ent->end_of_bucket){
// prev entry not valid or part of another list
ret = rtu_hash(ent->mac, ent->fid);
break;
}
// mark previous as end_of_bucket
prev_ent->end_of_bucket = 1;
write_hcam_entry(cam_addr(i-1), prev_ent);
break;
}
next_ent = &rtu_hcam[i+1];
rtu_fe_copy(ent, next_ent);
write_hcam_entry(cam_addr(i), ent);
ent = next_ent;
}
rtu_fe_clean(ent);
clean_hcam_entry(cam_addr(i));
return ret;
}
/**
* \brief Deletes HCAM entry by shifting HCAM list.
* Updates HTAB last entry if neccessary.
* @param bucket CAM entry address
*/
static void delete_hcam_entry(int bucket)
{
struct filtering_entry *ent;
int hash;
hash = shift_hcam_entries(bucket);
if(hash > -1){ // no entries remain at HCAM
ent = &rtu_htab[hash][LAST_RTU_BUCKET];
ent->go_to_cam = 0;
ent->cam_addr = 0;
write_htab_entry(zbt_addr(hash, LAST_RTU_BUCKET), ent);
}
}
/**
* \brief Deletes HTAB entry by shifting HTAB list.
* \brief Deletes HTAB entry by shifting HTAB list.
* If HCAM is used, it also copies first HCAM entry to last HTAB bucket.
* @param hash hashcode for entry to remove.
* @param bucket HTAB bucket for entry to remove
......@@ -894,39 +615,13 @@ static void delete_hcam_entry(int bucket)
static void delete_htab_entry(uint16_t hash, int bucket)
{
struct filtering_entry *ent;
struct filtering_entry *prev_ent;
struct filtering_entry *cam_ent;
int hcam_bucket;
shift_htab_entries(hash, bucket);
ent = &rtu_htab[hash][LAST_RTU_BUCKET];
if(ent->go_to_cam) { // HCAM used
// go_to_cam was copied to prev_ent while shifting. clean it.
prev_ent = ent-1;
prev_ent->go_to_cam = 0;
prev_ent->cam_addr = 0;
// changes will be written to hw when shift operations are commited
// copy first cam entry into last HTAB entry
hcam_bucket = cam_bucket(ent->cam_addr);
cam_ent = &rtu_hcam[hcam_bucket];
rtu_fe_copy(ent, cam_ent);
if(ent->end_of_bucket){ // entry was the only one in HCAM
ent->go_to_cam = 0;
ent->cam_addr = 0;
ent->end_of_bucket = 0;
} else { // point to the next one
ent->go_to_cam = 1;
ent->cam_addr = cam_addr(hcam_bucket+1);
}
write_htab_entry(zbt_addr(hash, LAST_RTU_BUCKET), ent);
// clean HCAM entry
rtu_fe_clean(cam_ent);
clean_hcam_entry(cam_addr(hcam_bucket));
} else if (ent->valid) {
if (ent->valid) {
// clean last HTAB entry
rtu_fe_clean(ent);
clean_htab_entry(zbt_addr(hash, LAST_RTU_BUCKET));
......
......@@ -8,9 +8,9 @@
* Miguel Baizan (miguel.baizan@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU Filtering database header.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* Description: RTU Filtering database header.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* object per Bridge (See 802.1Q - 12.7.1)
*
* Fixes:
......@@ -40,13 +40,13 @@
#define STATIC 0
#define DYNAMIC 1
int rtu_fd_init(uint16_t poly, unsigned long aging)
int rtu_fd_init(uint16_t poly, unsigned long aging)
__attribute__((warn_unused_result));
int rtu_fd_create_entry(
uint8_t mac[ETH_ALEN],
uint16_t vid,
uint32_t port_map,
uint8_t mac[ETH_ALEN],
uint16_t vid,
uint32_t port_map,
int dynamic
) __attribute__((warn_unused_result));
......
......@@ -6,8 +6,8 @@
*
* Authors: Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* http://outputlogic.com/
*
* Fixes:
......@@ -28,6 +28,8 @@
*/
#include <hw/trace.h>
#include "rtu.h"
#include "rtu_hash.h"
......@@ -47,53 +49,53 @@ void rtu_hash_set_poly(uint16_t poly)
uint16_t rtu_hash(uint8_t mac[ETH_ALEN], uint8_t fid)
{
uint16_t hash = 0xFFFF;
hash = crc16(hash, (0xFFFF & fid));
hash = crc16(hash, ((uint16_t)mac[0] << 8) | mac[1]);
hash = crc16(hash, ((uint16_t)mac[2] << 8) | mac[3]);
hash = crc16(hash, ((uint16_t)mac[4] << 8) | mac[5]);
return hash & 0x7FF; // trim to fit in ZBT SRAM addr
return hash & (HTAB_ENTRIES - 1); /* warning: assumes that HTAB_ENTRIES is a power of 2 */
}
/*
-------------------------------------------------------------------------------
-- SOME EXPLANATION REGARDING VHDL vs C CRC IMPLEMENTATION BY ML
-------------------------------------------------------------------------------
-- C code to produce exactly the same CRC as VHDL generated
-- C code to produce exactly the same CRC as VHDL generated
-- with http://outputlogic.com/ .
-- it uses naive method, it's not optimal at all
-- but it's good enough to chech whether VHDL works OK
-- It was made (by maciej.lipinski@cern.ch) modifying source from here:
-- http://www.netrino.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
-- the website provides explanation of CRC
--
-- To get the hex representation of POLY to be used with the C function, which
-- is different than hex representation of polly used to generate VHDL code
--
-- To get the hex representation of POLY to be used with the C function, which
-- is different than hex representation of polly used to generate VHDL code
-- (i.e.:0x1021 <->0x88108), here is the trick:
--
-- 1) we are using the following poly equation: 1+x^5+x^12+x^16;
-- 2) it translates to binary: (1) 0001 0000 0010 0001 = 0x1021
-- 2) it translates to binary: (1) 0001 0000 0010 0001 = 0x1021
-- | |
-- | this is default | this you can find in
-- | this is default | this you can find in
-- |-> it's the 16th bit |-> the wiki as description
-- of the polly equation
--
--
-- 3) we include the "default" bit into the polly and add zeroes at the end
-- creating 20 bit polly, like this
-- (1) 0001 0000 0010 0001 => 1000 1000 0001 0000 1000 = 0x88108
-- (1) 0001 0000 0010 0001 => 1000 1000 0001 0000 1000 = 0x88108
--
--------------------------------------------------------------------------------
--| name | polly equation | polly (hex) | our polly | tested |
--------------------------------------------------------------------------------
--| CRC-16-CCITT | 1+x^5+x^12+x^16 | 0x1021 | 0x88108 | yes |
--| CRC-16-IBM | 1+x^2+x^15+x^16 | 0x8005 | 0xC0028 | yes |
--| CRC-16-DECT | 1+x^3+x^7+x^8+x^10+x^16 | 0x0589 | 0x82C48 | yes |
--| CRC-16-DECT | 1+x^3+x^7+x^8+x^10+x^16 | 0x0589 | 0x82C48 | yes |
--------------------------------------------------------------------------------
*/
static uint16_t crc16(uint16_t const init_crc, uint16_t const message)
{
uint32_t remainder;
uint32_t remainder;
int bit;
// Initially, the dividend is the remainder.
......
......@@ -6,8 +6,8 @@
*
* Authors: Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* http://outputlogic.com/
*
* Fixes:
......@@ -34,16 +34,16 @@
/*
Hash polynomials implemented by RTU
---------------------------------------------------------
| name | poly equation | poly (hex) |
| name | poly equation | poly (hex) |
---------------------------------------------------------
| CRC-16-CCITT | 1+x^5+x^12+x^16 | 0x1021 |
| CRC-16-IBM | 1+x^2+x^15+x^16 | 0x8005 |
| CRC-16-DECT | 1+x^3+x^7+x^8+x^10+x^16 | 0x0589 |
---------------------------------------------------------
*/
#define HW_POLYNOMIAL_CCITT 0x1021
#define HW_POLYNOMIAL_IBM 0x8005
#define HW_POLYNOMIAL_DECT 0x0589
#define HW_POLYNOMIAL_CCITT 0x1021
#define HW_POLYNOMIAL_IBM 0x8005
#define HW_POLYNOMIAL_DECT 0x0589
void rtu_hash_set_poly(uint16_t poly);
uint16_t rtu_hash(uint8_t mac[ETH_ALEN], uint8_t fid);
......
......@@ -7,14 +7,14 @@
* Authors: Juan Luis Manas (juan.manas@integrasys.es)
* Miguel Baizan (miguel.baizan@integrasys.es)
*
* Description: RTU daemon.
* Handles the learning and aging processes.
* Description: RTU daemon.
* Handles the learning and aging processes.
* Manages the filtering and VLAN databases.
*
* Fixes:
* Fixes:
* Alessandro Rubini
* Tomasz Wlostowski
*
* Tomasz Wlostowski
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -50,7 +50,7 @@ static pthread_t aging_process;
static pthread_t wripc_process;
/**
* \brief Creates the static entries in the filtering database
* \brief Creates the static entries in the filtering database
* @return error code
*/
static int rtu_create_static_entries()
......@@ -66,7 +66,7 @@ static int rtu_create_static_entries()
err = rtu_fd_create_entry(bcast_mac, 0, 0xffffffff, STATIC);
if(err)
return err;
// VLAN-aware Bridge reserved addresses (802.1Q-2005 Table 8.1)
TRACE(TRACE_INFO,"adding static routes for slow protocols...");
for(i = 0; i < NUM_RESERVED_ADDR; i++) {
......@@ -75,16 +75,16 @@ static int rtu_create_static_entries()
if(err)
return err;
}
// packets addressed to WR card interfaces are forwarded to NIC virtual port
halexp_query_ports(&plist);
halexp_query_ports(&plist);
for(i = 0; i < plist.num_ports; i++) {
halexp_get_port_state(&pstate, plist.port_names[i]);
halexp_get_port_state(&pstate, plist.port_names[i]);
TRACE(
TRACE_INFO,
"adding static route for port %s index %d [mac %s]",
plist.port_names[i],
pstate.hw_index,
"adding static route for port %s index %d [mac %s]",
plist.port_names[i],
pstate.hw_index,
mac_to_string(pstate.hw_addr)
);
err = rtu_fd_create_entry(pstate.hw_addr, 0, (1 << NIC_PORT), STATIC);
......@@ -122,18 +122,18 @@ static void *rtu_daemon_wripc_process(void *arg)
{
while(1){
rtud_handle_wripc();
sleep(1);
usleep(10000);
}
return NULL;
}
/**
* \brief Handles the learning process.
* \brief Handles the learning process.
* @return error code
*/
static int rtu_daemon_learning_process()
{
int err;
int err;
struct rtu_request req; // Request read from learning queue
uint32_t port_map; // Destination port map
uint16_t vid; // VLAN identifier
......@@ -144,8 +144,8 @@ static int rtu_daemon_learning_process()
if (!err) {
TRACE_DBG(
TRACE_INFO,
"ureq: port %d src %s VID %d priority %d",
req.port_id,
"ureq: port %d src %s VID %d priority %d",
req.port_id,
mac_to_string(req.src),
req.has_vid ? req.vid:0,
req.has_prio ? req.prio:0
......@@ -171,7 +171,7 @@ static int rtu_daemon_learning_process()
/**
* \brief RTU set up.
* \brief RTU set up.
* Initialises routing table cache and RTU at hardware.
* @param poly hash polinomial.
* @param aging_time Aging time in seconds.
......@@ -195,7 +195,6 @@ static int rtu_daemon_init(uint16_t poly, unsigned long aging_time)
TRACE(TRACE_INFO, "init port config.");
for(i = MIN_PORT; i <= MAX_PORT; i++) {
// MIN_PORT <= port <= MAX_PORT, thus no err returned
fprintf(stderr,"**4**");
err = rtu_learn_enable_on_port(i,1);
err = rtu_pass_all_on_port(i,1);
......@@ -207,7 +206,7 @@ static int rtu_daemon_init(uint16_t poly, unsigned long aging_time)
// init filtering database
TRACE(TRACE_INFO, "init fd.");
err = rtu_fd_init(poly, aging_time);
if (err)
if (err)
return err;
// create static filtering entries
......@@ -228,7 +227,7 @@ static int rtu_daemon_init(uint16_t poly, unsigned long aging_time)
* \brief RTU shutdown.
*/
static void rtu_daemon_destroy()
{
{
// Threads stuff
pthread_cancel(wripc_process);
pthread_cancel(aging_process);
......@@ -245,11 +244,11 @@ void sigint(int signum) {
/**
* \brief Starts up the learning and aging processes.
*/
*/
int main(int argc, char **argv)
{
int op, err;
char *s, *name, *optstring;
char *s, *name, *optstring;
int run_as_daemon = 0;
uint16_t poly = HW_POLYNOMIAL_CCITT; // Hash polinomial
unsigned long aging_res = DEFAULT_AGING_RES; // Aging resolution [sec.]
......@@ -272,7 +271,7 @@ int main(int argc, char **argv)
run_as_daemon = 1;
break;
case 'h':
usage(name);
usage(name);
case 'p':
if (strcmp(optarg, "CCITT") == 0) {
poly = HW_POLYNOMIAL_CCITT;
......@@ -293,7 +292,7 @@ int main(int argc, char **argv)
break;
case 't':
aging_time = atol(optarg);
if ((aging_time < MIN_AGING_TIME) ||
if ((aging_time < MIN_AGING_TIME) ||
(aging_time > MAX_AGING_TIME)) {
fprintf(stderr, "Invalid aging time\n");
usage(name);
......@@ -305,7 +304,7 @@ int main(int argc, char **argv)
}
}
// Initialise RTU.
// Initialise RTU.
if((err = rtu_daemon_init(poly, aging_time)) < 0) {
rtu_daemon_destroy();
return err;
......@@ -315,7 +314,7 @@ int main(int argc, char **argv)
signal(SIGINT, sigint);
// daemonize _before_ creating threads
if(run_as_daemon)
if(run_as_daemon)
daemonize();
// Start up aging process and auxiliary WRIPC thread
......@@ -324,7 +323,7 @@ int main(int argc, char **argv)
rtu_daemon_destroy();
return err;
}
// Start up learning process.
err = rtu_daemon_learning_process();
// On error, release RTU resources
......
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