Skip to content

Commit

Permalink
Infrastructure to support aging for L2 entries
Browse files Browse the repository at this point in the history
To support aging, there should be

. a way to indicate the activity of an entry
. a way to easily read/monitor the activity

For the first requirement, add packet statistics to each entry. If
learning is enabled, the statistics will increment for both source
and the destination L2 entries. Else, the statistics will increment
only for the destination L2 entry, since no lookup is done for the
source.

For the second requirement, bridge table is now exposed to applications
as a memory block that can be mapped and read like any other memory.
This way, the application does not have to send sandesh request for
each and every bridge entry just to see whether there is any activity
in that entry.

Change-Id: I12bb766853580805519bc04d19790bc62853fbef
Partial-Bug: #1636413
  • Loading branch information
anandhk-juniper committed Nov 28, 2016
1 parent e8e263d commit 14776a0
Show file tree
Hide file tree
Showing 20 changed files with 759 additions and 263 deletions.
394 changes: 252 additions & 142 deletions dp-core/vr_bridge.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dp-core/vr_flow.c
Expand Up @@ -43,7 +43,7 @@ unsigned char *vr_flow_path;
unsigned int vr_flow_hold_limit = VR_DEF_MAX_FLOW_TABLE_HOLD_COUNT;

#if defined(__linux__) && defined(__KERNEL__)
extern unsigned short vr_flow_major;
extern short vr_flow_major;
#endif

uint32_t vr_hashrnd = 0;
Expand Down
4 changes: 2 additions & 2 deletions dp-core/vr_htable.c
Expand Up @@ -156,7 +156,7 @@ vr_htable_get_hentry_by_index(vr_htable_t htable, unsigned int index)
vr_hentry_t *ent;

ent = __vr_htable_get_hentry_by_index(htable, index);
if(ent && (ent->hentry_flags & VR_HENTRY_FLAG_VALID))
if (ent && (ent->hentry_flags & VR_HENTRY_FLAG_VALID))
return ent;

return NULL;
Expand Down Expand Up @@ -586,7 +586,7 @@ vr_htable_find_hentry(vr_htable_t htable, void *key, unsigned int key_len)
return ent;
}

for(o_ent = ent->hentry_next; o_ent; o_ent = o_ent->hentry_next) {
for (o_ent = ent->hentry_next; o_ent; o_ent = o_ent->hentry_next) {

/* Though in the list, can be under the deletion */
if (!(o_ent->hentry_flags & VR_HENTRY_FLAG_VALID))
Expand Down
24 changes: 15 additions & 9 deletions dp-core/vr_sandesh.c
Expand Up @@ -40,27 +40,27 @@ struct sandesh_object_md sandesh_md[] = {
.obj_len = 4 * sizeof(vr_flow_req),
.obj_type_string = "vr_flow_req",
},
[VR_VRF_ASSIGN_OBJECT_ID] = {
[VR_VRF_ASSIGN_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_vrf_assign_req),
.obj_type_string = "vr_vrf_assign_req",
},
[VR_VRF_STATS_OBJECT_ID] = {
[VR_VRF_STATS_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_vrf_stats_req),
.obj_type_string = "vr_vrf_stats_req",
},
[VR_DROP_STATS_OBJECT_ID] = {
[VR_DROP_STATS_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_drop_stats_req),
.obj_type_string = "vr_drop_stats_req",
},
[VR_RESPONSE_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_response),
.obj_type_string = "vr_response",
},
[VR_VXLAN_OBJECT_ID] = {
[VR_VXLAN_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_vxlan_req),
.obj_type_string = "vr_vxlan_req",
},
[VR_VROUTER_OPS_OBJECT_ID] = {
[VR_VROUTER_OPS_OBJECT_ID] = {
.obj_len = 4 * sizeof(vrouter_ops),
.obj_type_string = "vrouter_ops",
},
Expand All @@ -69,23 +69,29 @@ struct sandesh_object_md sandesh_md[] = {
(VR_FLOW_MAX_CPUS * sizeof(unsigned int))),
.obj_type_string = "vr_flow_table_data",
},
[VR_MEM_STATS_OBJECT_ID] = {
[VR_MEM_STATS_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_mem_stats_req),
.obj_type_string = "vr_mem_stats_req",
},
[VR_QOS_MAP_OBJECT_ID] = {
[VR_QOS_MAP_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_qos_map_req),
.obj_get_size = vr_qos_map_req_get_size,
.obj_type_string = "vr_qos_map_req",
},
[VR_FC_MAP_OBJECT_ID] = {
[VR_FC_MAP_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_fc_map_req),
.obj_type_string = "vr_fc_map_req",
},
[VR_FLOW_RESPONSE_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_flow_response),
.obj_type_string = "vr_flow_response",
.obj_type_string = "vr_flow_response",
},
#if 0
[VR_BRIDGE_TABLE_DATA_OBJECT_ID] = {
.obj_len = 4 * sizeof(vr_bridge_table_data),
.obj_type_string = "vr_bridge_table_data",
},
#endif
};

static unsigned int
Expand Down
13 changes: 12 additions & 1 deletion dpdk/dpdk_vrouter.c
Expand Up @@ -27,6 +27,7 @@
#include "vr_dpdk_virtio.h"
#include "vr_uvhost.h"
#include "vr_bridge.h"
#include "vr_mem.h"
#include "nl_util.h"

#include <rte_errno.h>
Expand Down Expand Up @@ -636,13 +637,23 @@ dpdk_init(void)

version_print();

ret = vr_dpdk_flow_mem_init();
ret = vr_dpdk_table_mem_init(VR_MEM_FLOW_TABLE_OBJECT, vr_flow_entries,
VR_FLOW_TABLE_SIZE, vr_oflow_entries, VR_OFLOW_TABLE_SIZE);
if (ret < 0) {
RTE_LOG(ERR, VROUTER, "Error initializing flow table: %s (%d)\n",
rte_strerror(-ret), -ret);
return ret;
}

ret = vr_dpdk_table_mem_init(VR_MEM_BRIDGE_TABLE_OBJECT, vr_bridge_entries,
VR_BRIDGE_TABLE_SIZE, vr_bridge_oentries,
VR_BRIDGE_OFLOW_TABLE_SIZE);
if (ret < 0) {
RTE_LOG(ERR, VROUTER, "Error initializing bridge table: %s (%d)\n",
rte_strerror(-ret), -ret);
return ret;
}

ret = dpdk_argv_update();
if (ret == -1) {
RTE_LOG(ERR, VROUTER, "Error updating EAL arguments\n");
Expand Down
5 changes: 5 additions & 0 deletions dpdk/vr_dpdk_host.c
Expand Up @@ -1444,9 +1444,14 @@ vr_dpdk_host_init(void)

if (!vrouter_host) {
vrouter_host = vrouter_get_host();

if (vr_dpdk_flow_init()) {
return -1;
}

if (vr_dpdk_bridge_init()) {
return -1;
}
}

/*
Expand Down
95 changes: 69 additions & 26 deletions dpdk/vr_dpdk_flow_mem.c → dpdk/vr_dpdk_table_mem.c
Expand Up @@ -14,6 +14,7 @@

#include "vr_dpdk.h"
#include "vr_btable.h"
#include "vr_mem.h"
#include "nl_util.h"

#include <rte_errno.h>
Expand All @@ -29,9 +30,9 @@ struct vr_hugepage_info {
uint32_t num_pages;
} vr_hugepage_md[HPI_MAX];

extern void *vr_flow_table;
extern void *vr_oflow_table;
extern unsigned char *vr_flow_path;
extern void *vr_flow_table, *vr_oflow_table;
extern void *vr_bridge_table, *vr_bridge_otable;
extern unsigned char *vr_flow_path, *vr_bridge_table_path;

static int
vr_hugepage_info_init(void)
Expand Down Expand Up @@ -135,24 +136,54 @@ vr_hugepage_info_init(void)
return 0;
}


int
vr_dpdk_flow_mem_init(void)
vr_dpdk_table_mem_init(unsigned int table, unsigned int entries,
unsigned long size, unsigned int oentries, unsigned long osize)
{
int ret, i, fd;
size_t size, flow_table_size;
struct vr_hugepage_info *hpi;

void **table_p;
char shm_file[VR_UNIX_PATH_MAX];
char *file_name, *touse_file_name = NULL;
char *shmem_name, *hp_file_name;
unsigned char **path;

struct stat f_stat;
char shm_file[VR_UNIX_PATH_MAX];
struct vr_hugepage_info *hpi;

if (!vr_oflow_entries)
vr_oflow_entries = ((vr_flow_entries / 5) + 1023) & ~1023;
if (!oentries) {
oentries = (entries / 5 + 1023) & ~1023;
osize = (size / entries) * oentries;
}

flow_table_size = VR_FLOW_TABLE_SIZE + VR_OFLOW_TABLE_SIZE;
size += osize;

switch (table) {
case VR_MEM_FLOW_TABLE_OBJECT:
shmem_name = "flow.shmem";
hp_file_name = "flow";
table_p = &vr_dpdk.flow_table;
path = &vr_flow_path;
vr_oflow_entries = oentries;
break;

case VR_MEM_BRIDGE_TABLE_OBJECT:
shmem_name = "bridge.shmem";
hp_file_name = "bridge";
table_p = &vr_dpdk.bridge_table;
path = &vr_bridge_table_path;
vr_bridge_oentries = oentries;
break;

default:
return -EINVAL;
}

if (no_huge_set) {
/* Create a shared memory under the socket directory. */
ret = snprintf(shm_file, sizeof(shm_file), "%s/flow.shmem", vr_socket_dir);
ret = snprintf(shm_file, sizeof(shm_file), "%s/%s",
vr_socket_dir, shmem_name);
if (ret >= sizeof(shm_file)) {
RTE_LOG(ERR, VROUTER, "Error creating shared memory file\n");
return -ENOMEM;
Expand All @@ -170,12 +201,11 @@ vr_dpdk_flow_mem_init(void)
hpi = &vr_hugepage_md[i];
if (!hpi->mnt)
continue;
file_name = malloc(strlen(hpi->mnt) + strlen("/flow") + 1);
sprintf(file_name, "%s/flow", hpi->mnt);
file_name = malloc(strlen(hpi->mnt) + strlen(hp_file_name) + 1);
sprintf(file_name, "%s/%s", hpi->mnt, hp_file_name);
if (stat(file_name, &f_stat) == -1) {
if (!touse_file_name) {
size = hpi->size;
if (size >= flow_table_size) {
if (hpi->size >= size) {
touse_file_name = file_name;
} else {
free(file_name);
Expand All @@ -196,46 +226,59 @@ vr_dpdk_flow_mem_init(void)
touse_file_name, rte_strerror(errno), errno);
return -errno;
}
if (no_huge_set){
ret = ftruncate(fd, flow_table_size);

if (no_huge_set) {
ret = ftruncate(fd, size);
if (ret == -1) {
RTE_LOG(ERR, VROUTER, "Error truncating file %s: %s (%d)\n",
touse_file_name, rte_strerror(errno), errno);
return -errno;
}
}
vr_dpdk.flow_table = mmap(NULL, flow_table_size, PROT_READ | PROT_WRITE,

*table_p = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
/* the file descriptor is no longer needed */
close(fd);
if (vr_dpdk.flow_table == MAP_FAILED) {
if (*table_p == MAP_FAILED) {
RTE_LOG(ERR, VROUTER, "Error mmapping file %s: %s (%d)\n",
touse_file_name, rte_strerror(errno), errno);
return -errno;
}
memset(vr_dpdk.flow_table, 0, flow_table_size);
vr_flow_path = (unsigned char *)touse_file_name;
memset(*table_p, 0, size);
*path = (unsigned char *)touse_file_name;
}

if (!vr_dpdk.flow_table)
return -ENOMEM;
return 0;
}

vr_flow_hold_limit = VR_DPDK_MAX_FLOW_TABLE_HOLD_COUNT;
RTE_LOG(INFO, VROUTER, "Max HOLD flow entries set to %u\n",
vr_flow_hold_limit);
int
vr_dpdk_bridge_init(void)
{
if (!vr_dpdk.bridge_table)
return -1;

vr_bridge_table = vr_dpdk.bridge_table;
vr_bridge_otable = vr_dpdk.bridge_table + VR_BRIDGE_TABLE_SIZE;

return 0;
}

int
vr_dpdk_flow_init(void)
{
if (!vr_dpdk.flow_table)
return -1;

vr_flow_table = vr_dpdk.flow_table;
vr_oflow_table = vr_dpdk.flow_table + VR_FLOW_TABLE_SIZE;

if (!vr_flow_table)
return -1;

vr_flow_hold_limit = VR_DPDK_MAX_FLOW_TABLE_HOLD_COUNT;
RTE_LOG(INFO, VROUTER, "Max HOLD flow entries set to %u\n",
vr_flow_hold_limit);

return 0;
}
4 changes: 4 additions & 0 deletions include/nl_util.h
Expand Up @@ -29,6 +29,9 @@ extern "C" {
#define VR_NETLINK_PROTO_DEFAULT -1
#define VR_NETLINK_PROTO_TEST -2

#define BRIDGE_TABLE_DEV "/dev/vr_bridge"
#define FLOW_TABLE_DEV "/dev/flow"

struct nl_response {
uint8_t *nl_data;
unsigned int nl_type;
Expand Down Expand Up @@ -151,6 +154,7 @@ extern struct nl_client *vr_get_nl_client(int);

extern int vr_response_common_process(vr_response *, bool *);

extern void *vr_table_map(int, unsigned int, char *, size_t);
extern unsigned long vr_sum_drop_stats(vr_drop_stats_req *);
extern void vr_drop_stats_req_destroy(vr_drop_stats_req *);
extern vr_drop_stats_req *vr_drop_stats_req_get_copy(vr_drop_stats_req *);
Expand Down
41 changes: 40 additions & 1 deletion include/vr_bridge.h
Expand Up @@ -5,7 +5,7 @@
#define __VR_BRIDGE_H__

#include "vr_defs.h"
#include "vrouter.h"
#include "vr_htable.h"

#define VR_DEF_BRIDGE_ENTRIES (256 * 1024)

Expand Down Expand Up @@ -41,9 +41,48 @@

#define VR_BE_INVALID_INDEX ((unsigned int)-1)

struct vr_bridge_entry_key {
unsigned char be_mac[VR_ETHER_ALEN];
unsigned short be_vrf_id;
}__attribute__((packed));

struct vr_bridge_entry;

struct vr_dummy_bridge_entry {
vr_hentry_t be_hentry;
struct vr_bridge_entry_key be_key;
struct vr_nexthop *be_nh;
uint64_t be_packets;
uint32_t be_label;
uint32_t be_nh_id;
unsigned short be_flags;
} __attribute__((packed));

#define VR_BRIDGE_ENTRY_PACK (64 - sizeof(struct vr_dummy_bridge_entry))

struct vr_bridge_entry {
vr_hentry_t be_hentry;
struct vr_bridge_entry_key be_key;
struct vr_nexthop *be_nh;
uint64_t be_packets;
uint32_t be_label;
int32_t be_nh_id;
unsigned short be_flags;
unsigned char be_pack[VR_BRIDGE_ENTRY_PACK];
} __attribute__((packed));


extern unsigned int vr_bridge_entries, vr_bridge_oentries;
#define VR_BRIDGE_TABLE_SIZE (vr_bridge_entries *\
sizeof(struct vr_bridge_entry))
#define VR_BRIDGE_OFLOW_TABLE_SIZE (vr_bridge_oentries *\
sizeof(struct vr_bridge_entry))

extern char vr_bcast_mac[];

unsigned int vr_bridge_table_used_oflow_entries(struct vrouter *);
unsigned int vr_bridge_table_used_total_entries(struct vrouter *);
void *vr_bridge_get_va(struct vrouter *, uint64_t);
unsigned int vr_bridge_table_size(struct vrouter *);

#endif

0 comments on commit 14776a0

Please sign in to comment.