Skip to content

Commit

Permalink
vrouter changes to support fat flow exclude list.
Browse files Browse the repository at this point in the history
Change-Id: I6b808454ae5fd7692adedbbf4d43cbcbcab37d39
Partial-Bug: #1762452
  • Loading branch information
anandrao79 committed Aug 5, 2018
1 parent f6e6ed4 commit 29bd76d
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 7 deletions.
3 changes: 2 additions & 1 deletion dp-core/vr_flow.c
Expand Up @@ -1577,6 +1577,7 @@ vr_flow_is_fat_flow(struct vrouter *router, struct vr_packet *pkt,

uint16_t
vr_flow_fat_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
struct vr_ip *ip, struct vr_ip6 *ip6,
uint16_t l4_proto, uint16_t sport, uint16_t dport)
{
uint8_t fat_flow_mask, tmp_mask = 0;
Expand All @@ -1594,7 +1595,7 @@ vr_flow_fat_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
if (!vif_l)
return VR_FAT_FLOW_NO_MASK;

fat_flow_mask = vif_fat_flow_lookup(vif_l, l4_proto, sport, dport);
fat_flow_mask = vif_fat_flow_lookup(vif_l, ip, ip6, l4_proto, sport, dport);
if (pkt->vp_if != vif_l) {

if (fat_flow_mask & VR_FAT_FLOW_SRC_IP_MASK)
Expand Down
189 changes: 188 additions & 1 deletion dp-core/vr_interface.c
Expand Up @@ -54,6 +54,39 @@ extern void vr_drop_stats_get_vif_stats(vr_drop_stats_req *, struct vr_interface

#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))

static inline uint64_t
vr_htonll (uint64_t n)
{
uint64_t t = 1;
uint8_t *p, out[8];

if (*((uint8_t *) &t) == 1) {
p = (uint8_t *) &n;
out[0] = *(p + 7);
out[1] = *(p + 6);
out[2] = *(p + 5);
out[3] = *(p + 4);
out[4] = *(p + 3);
out[5] = *(p + 2);
out[6] = *(p + 1);
out[7] = *(p + 0);
return (*((uint64_t *) out));
}
return n;
}

static inline void
fat_flow_ipv6_plen_to_mask (uint16_t plen, uint64_t *high_mask, uint64_t *low_mask)
{
if (plen > 64) {
*high_mask = 0xFFFFFFFFFFFFFFFF;
*low_mask = vr_htonll((0xFFFFFFFFFFFFFFFF << (128 - plen)));
} else {
*low_mask = 0;
*high_mask = vr_htonll((0xFFFFFFFFFFFFFFFF << (64 - plen)));
}
}

struct vr_interface_stats *
vif_get_stats(struct vr_interface *vif, unsigned short cpu)
{
Expand Down Expand Up @@ -2610,6 +2643,16 @@ __vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf,
}
}

/* Fill the ipv4 & ipv6 exclude lists; NOTE: The prefix lengths are not filled */
for (i = 0; i < req->vifr_fat_flow_exclude_ip_list_size; i++) {
req->vifr_fat_flow_exclude_ip_list[i] = (uint64_t) intf->vif_fat_flow_ipv4_exclude_list[i];
}

for (i = 0; i < req->vifr_fat_flow_exclude_ip6_u_list_size; i++) {
req->vifr_fat_flow_exclude_ip6_u_list[i] = intf->vif_fat_flow_ipv6_high_exclude_list[i];
req->vifr_fat_flow_exclude_ip6_l_list[i] = intf->vif_fat_flow_ipv6_low_exclude_list[i];
}

req->vifr_qos_map_index = intf->vif_qos_map_index;
req->vifr_dpackets = vr_interface_get_drops(intf);
return;
Expand All @@ -2635,6 +2678,30 @@ vr_interface_make_req(vr_interface_req *req, struct vr_interface *vif,
req->vifr_fat_flow_protocol_port_size = fat_flow_config_size;
}

if (vif->vif_fat_flow_ipv4_exclude_list_size) {
req->vifr_fat_flow_exclude_ip_list = vr_zalloc(vif->vif_fat_flow_ipv4_exclude_list_size * sizeof(uint64_t),
VR_INTERFACE_FAT_FLOW_IPV4_EXCLUDE_LIST_OBJECT);
if (!req->vifr_fat_flow_exclude_ip_list) {
return -ENOMEM;
}
req->vifr_fat_flow_exclude_ip_list_size = vif->vif_fat_flow_ipv4_exclude_list_size;
}

if (vif->vif_fat_flow_ipv6_exclude_list_size) {
req->vifr_fat_flow_exclude_ip6_u_list = vr_zalloc(vif->vif_fat_flow_ipv6_exclude_list_size * sizeof(uint64_t),
VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT);
if (!req->vifr_fat_flow_exclude_ip6_u_list) {
return -ENOMEM;
}
req->vifr_fat_flow_exclude_ip6_u_list_size = vif->vif_fat_flow_ipv6_exclude_list_size;
req->vifr_fat_flow_exclude_ip6_l_list = vr_zalloc(vif->vif_fat_flow_ipv6_exclude_list_size * sizeof(uint64_t),
VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT);
if (!req->vifr_fat_flow_exclude_ip6_l_list) {
return -ENOMEM;
}
req->vifr_fat_flow_exclude_ip6_l_list_size = vif->vif_fat_flow_ipv6_exclude_list_size;
}

__vr_interface_make_req(req, vif, core);

return 0;
Expand Down Expand Up @@ -2712,6 +2779,22 @@ vr_interface_req_free_fat_flow_config(vr_interface_req *req)
req->vifr_fat_flow_protocol_port_size = 0;
}

if (req->vifr_fat_flow_exclude_ip_list) {
vr_free(req->vifr_fat_flow_exclude_ip_list, VR_INTERFACE_FAT_FLOW_IPV4_EXCLUDE_LIST_OBJECT);
req->vifr_fat_flow_exclude_ip_list = NULL;
req->vifr_fat_flow_exclude_ip_list_size = 0;
}
if (req->vifr_fat_flow_exclude_ip6_u_list) {
vr_free(req->vifr_fat_flow_exclude_ip6_u_list, VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT);
req->vifr_fat_flow_exclude_ip6_u_list = NULL;
req->vifr_fat_flow_exclude_ip6_u_list_size = 0;
}
if (req->vifr_fat_flow_exclude_ip6_l_list) {
vr_free(req->vifr_fat_flow_exclude_ip6_l_list, VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT);
req->vifr_fat_flow_exclude_ip6_l_list = NULL;
req->vifr_fat_flow_exclude_ip6_l_list_size = 0;
}

return;
}

Expand Down Expand Up @@ -3255,6 +3338,60 @@ vif_fat_flow_add(struct vr_interface *vif, vr_interface_req *req)
int i, j, ret;
unsigned int size;
bool add;
uint32_t v4_prefix, v4_prefix_len, v4_mask;
uint64_t v6_prefix_h, v6_prefix_l, v6_mask_l, v6_mask_h;
uint16_t v6_prefix_len;

/* Populate the ipv4 & ipv6 exclude lists */
if (!req->vifr_fat_flow_exclude_ip_list_size) {
memset(vif->vif_fat_flow_ipv4_exclude_list, 0,
FAT_FLOW_IPV4_EXCLUDE_LIST_MAX_SIZE * sizeof(uint32_t));
memset(vif->vif_fat_flow_ipv4_exclude_plen_list, 0,
FAT_FLOW_IPV4_EXCLUDE_LIST_MAX_SIZE * sizeof(uint8_t));
vif->vif_fat_flow_ipv4_exclude_list_size = 0;
} else {
if (req->vifr_fat_flow_exclude_ip_list_size > FAT_FLOW_IPV4_EXCLUDE_LIST_MAX_SIZE) {
return -EINVAL;
}
/* copy the exclude list and size */
for (i = 0; i < req->vifr_fat_flow_exclude_ip_list_size; i++) {
v4_prefix_len = FAT_FLOW_EXCLUDE_IPV4_PREFIX_LEN(req->vifr_fat_flow_exclude_ip_list[i]);
v4_prefix = FAT_FLOW_EXCLUDE_IPV4_PREFIX(req->vifr_fat_flow_exclude_ip_list[i]);
v4_mask = FAT_FLOW_IPV4_PLEN_TO_MASK(v4_prefix_len);
vif->vif_fat_flow_ipv4_exclude_list[i] = v4_prefix & v4_mask;
vif->vif_fat_flow_ipv4_exclude_plen_list[i] = (uint8_t) v4_prefix_len;
}
vif->vif_fat_flow_ipv4_exclude_list_size = req->vifr_fat_flow_exclude_ip_list_size;
}

if (!req->vifr_fat_flow_exclude_ip6_l_list_size) {
memset(vif->vif_fat_flow_ipv6_low_exclude_list, 0,
FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE * sizeof(uint64_t));
memset(vif->vif_fat_flow_ipv6_high_exclude_list, 0,
FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE * sizeof(uint64_t));
memset(vif->vif_fat_flow_ipv6_exclude_plen_list, 0,
FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE * sizeof(uint8_t));
vif->vif_fat_flow_ipv6_exclude_list_size = 0;
} else {
if ((req->vifr_fat_flow_exclude_ip6_l_list_size != req->vifr_fat_flow_exclude_ip6_u_list_size) ||
(req->vifr_fat_flow_exclude_ip6_l_list_size != req->vifr_fat_flow_exclude_ip6_plen_list_size) ||
(req->vifr_fat_flow_exclude_ip6_l_list_size > FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE)) {
return -EINVAL;
}
/* copy the exclude list and size */
for (i = 0; i < req->vifr_fat_flow_exclude_ip6_l_list_size; i++) {
v6_prefix_l = req->vifr_fat_flow_exclude_ip6_l_list[i];
v6_prefix_h = req->vifr_fat_flow_exclude_ip6_u_list[i];
v6_prefix_len = req->vifr_fat_flow_exclude_ip6_plen_list[i];
fat_flow_ipv6_plen_to_mask(v6_prefix_len, &v6_mask_h, &v6_mask_l);
vif->vif_fat_flow_ipv6_low_exclude_list[i] = v6_prefix_l & v6_mask_l;
vif->vif_fat_flow_ipv6_high_exclude_list[i] = v6_prefix_h & v6_mask_h;
vif->vif_fat_flow_ipv6_exclude_plen_list[i] = (uint8_t) v6_prefix_len;
}
vif->vif_fat_flow_ipv6_exclude_list_size = req->vifr_fat_flow_exclude_ip6_l_list_size;
}

/* Do rest of fat flow config processing */

if (!req->vifr_fat_flow_protocol_port_size) {
if (!memcmp(vif->vif_fat_flow_config_size, old_fat_flow_config_sizes,
Expand Down Expand Up @@ -3403,14 +3540,64 @@ vif_fat_flow_port_get(struct vr_interface *vif, uint8_t proto_index,
return 0;
}


static uint8_t
vif_fat_flow_exclude_list_lookup (struct vr_interface *vif, struct vr_ip *ip, struct vr_ip6 *ip6)
{
int i;
uint64_t v6_prefix_h, v6_prefix_l, v6_mask_h, v6_mask_l;
uint32_t v4_mask;


if (ip) {
if (!vif->vif_fat_flow_ipv4_exclude_list_size) {
return 0;
}
for (i = 0; i < vif->vif_fat_flow_ipv4_exclude_list_size; i++) {
v4_mask = FAT_FLOW_IPV4_PLEN_TO_MASK(vif->vif_fat_flow_ipv4_exclude_plen_list[i]);
if (((ip->ip_saddr & v4_mask) == vif->vif_fat_flow_ipv4_exclude_list[i]) ||
((ip->ip_daddr & v4_mask) == vif->vif_fat_flow_ipv4_exclude_list[i])) {
return 1;
}
}
} else if (ip6) {
if (!vif->vif_fat_flow_ipv6_exclude_list_size) {
return 0;
}
for (i = 0; i < vif->vif_fat_flow_ipv6_exclude_list_size; i++) {
fat_flow_ipv6_plen_to_mask(vif->vif_fat_flow_ipv6_exclude_plen_list[i], &v6_mask_h, &v6_mask_l);
/* compare src ip */
memcpy(&v6_prefix_h, (uint8_t *) ip6->ip6_src, 8);
memcpy(&v6_prefix_l, ((uint8_t *) ip6->ip6_src) + 8, 8);
if (((v6_prefix_l & v6_mask_l) == vif->vif_fat_flow_ipv6_low_exclude_list[i]) &&
((v6_prefix_h & v6_mask_h) == vif->vif_fat_flow_ipv6_high_exclude_list[i])) {
return 1;
}
/* compare dst ip */
memcpy(&v6_prefix_h, (uint8_t *) ip6->ip6_dst, 8);
memcpy(&v6_prefix_l, ((uint8_t *) ip6->ip6_dst) + 8, 8);
if (((v6_prefix_l & v6_mask_l) == vif->vif_fat_flow_ipv6_low_exclude_list[i]) &&
((v6_prefix_h & v6_mask_h) == vif->vif_fat_flow_ipv6_high_exclude_list[i])) {
return 1;
}
}
}
return 0;
}

uint16_t
vif_fat_flow_lookup(struct vr_interface *vif, uint8_t proto,
vif_fat_flow_lookup(struct vr_interface *vif, struct vr_ip *ip, struct vr_ip6 *ip6, uint8_t proto,
uint16_t sport, uint16_t dport)
{
uint8_t fat_flow_mask = 0, sport_mask = 0, dport_mask = 0;
uint16_t h_sport, h_dport;
unsigned int proto_index;

/* Check if the IPs belong to exclude list, if so return NO_MASK */
if (vif_fat_flow_exclude_list_lookup(vif, ip, ip6)) {
return fat_flow_mask;
}

proto_index = vif_fat_flow_get_proto_index(proto);
if (!vif->vif_fat_flow_config[proto_index])
return fat_flow_mask;
Expand Down
3 changes: 1 addition & 2 deletions dp-core/vr_proto_ip.c
Expand Up @@ -934,9 +934,8 @@ vr_inet_proto_flow(struct vrouter *router, unsigned short vrf,
* the IP packet which has caused the ICMP error
*/
if (!icmp_error_payload) {
fat_flow_mask = vr_flow_fat_flow_lookup(router, pkt, proto,
fat_flow_mask = vr_flow_fat_flow_lookup(router, pkt, ip, NULL, proto,
sport, dport);

for (i = 1; i < VR_FAT_FLOW_MAX_MASK; i = i << 1) {
switch (fat_flow_mask & i) {
case VR_FAT_FLOW_SRC_PORT_MASK:
Expand Down
2 changes: 1 addition & 1 deletion dp-core/vr_proto_ip6.c
Expand Up @@ -295,7 +295,7 @@ vr_inet6_proto_flow(struct vrouter *router, unsigned short vrf,
ip6_dst = ip6_addr;
}

fat_flow_mask = vr_flow_fat_flow_lookup(router, pkt, ip6_nxt,
fat_flow_mask = vr_flow_fat_flow_lookup(router, pkt, NULL, ip6, ip6_nxt,
sport, dport);
for (i = 1; i < VR_FAT_FLOW_MAX_MASK; i = i << 1) {
switch (fat_flow_mask & i) {
Expand Down
6 changes: 6 additions & 0 deletions dp-core/vr_stats.c
Expand Up @@ -317,6 +317,12 @@ vr_mem_stats_get(void)
response->vms_interface_req_mirror_meta_object +=
(stats_block[VR_INTERFACE_REQ_MIRROR_META_OBJECT].ms_alloc -
stats_block[VR_INTERFACE_REQ_MIRROR_META_OBJECT].ms_free);
response->vms_interface_fat_flow_ipv4_exclude_list_object +=
(stats_block[VR_INTERFACE_FAT_FLOW_IPV4_EXCLUDE_LIST_OBJECT].ms_alloc -
stats_block[VR_INTERFACE_FAT_FLOW_IPV4_EXCLUDE_LIST_OBJECT].ms_free);
response->vms_interface_fat_flow_ipv6_exclude_list_object +=
(stats_block[VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT].ms_alloc -
stats_block[VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT].ms_free);
for (i = 0; i < VR_VROUTER_MAX_OBJECT; i++) {
alloced += stats_block[i].ms_alloc;
freed += stats_block[i].ms_free;
Expand Down
3 changes: 2 additions & 1 deletion include/vr_flow.h
Expand Up @@ -447,6 +447,7 @@ struct vr_flow_trap_arg {

struct vr_packet;
struct vrouter;
struct vr_ip;
struct vr_ip6;

extern int vr_flow_init(struct vrouter *);
Expand Down Expand Up @@ -508,7 +509,7 @@ int vr_flow_flush_pnode(struct vrouter *, struct vr_packet_node *,
void vr_flow_fill_pnode(struct vr_packet_node *, struct vr_packet *,
struct vr_forwarding_md *);
uint16_t vr_flow_fat_flow_lookup(struct vrouter *,
struct vr_packet *, uint16_t, uint16_t, uint16_t);
struct vr_packet *, struct vr_ip *, struct vr_ip6 *, uint16_t, uint16_t, uint16_t);
extern int16_t vr_flow_get_qos(struct vrouter *, struct vr_packet *,
struct vr_forwarding_md *);
unsigned int vr_flow_table_used_oflow_entries(struct vrouter *);
Expand Down
18 changes: 17 additions & 1 deletion include/vr_interface.h
Expand Up @@ -234,6 +234,14 @@ struct vr_vrf_assign {
#define VIF_FAT_FLOW_PORT_SIP_IGNORE 1
#define VIF_FAT_FLOW_PORT_DIP_IGNORE 2

#define FAT_FLOW_IPV4_EXCLUDE_LIST_MAX_SIZE 3 /* support for 3 internal addresses for now */
#define FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE 3 /* support for 3 internal addresses for now */

#define FAT_FLOW_EXCLUDE_IPV4_PREFIX_LEN(a) ((uint32_t) ((a) >> 32))
#define FAT_FLOW_EXCLUDE_IPV4_PREFIX(a) ((uint32_t) ((a) & 0x00000000FFFFFFFF))

#define FAT_FLOW_IPV4_PLEN_TO_MASK(plen) (htonl((0xFFFFFFFF << (32-(plen)))))

struct vr_interface {
unsigned int vif_flags;
/* Generation number is incrementing every time a vif is added. */
Expand Down Expand Up @@ -336,6 +344,14 @@ struct vr_interface {
uint8_t vif_pbb_mac[VR_ETHER_ALEN];
uint16_t vif_mcast_vrf;
vhostuser_mode_t vif_vhostuser_mode;
/* fat flow exclude prefix list for v4 & v6 */
uint64_t vif_fat_flow_ipv6_high_exclude_list[FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE];
uint64_t vif_fat_flow_ipv6_low_exclude_list[FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE];
uint32_t vif_fat_flow_ipv4_exclude_list[FAT_FLOW_IPV4_EXCLUDE_LIST_MAX_SIZE];
uint8_t vif_fat_flow_ipv6_exclude_plen_list[FAT_FLOW_IPV6_EXCLUDE_LIST_MAX_SIZE];
uint8_t vif_fat_flow_ipv4_exclude_plen_list[FAT_FLOW_IPV4_EXCLUDE_LIST_MAX_SIZE];
uint8_t vif_fat_flow_ipv6_exclude_list_size;
uint8_t vif_fat_flow_ipv4_exclude_list_size;
};

struct vr_interface_settings {
Expand Down Expand Up @@ -387,7 +403,7 @@ extern unsigned int vr_interface_req_get_size(void *);
#if defined(__linux__) && defined(__KERNEL__)
extern void vr_set_vif_ptr(struct net_device *dev, void *vif);
#endif
extern uint16_t vif_fat_flow_lookup(struct vr_interface *,
extern uint16_t vif_fat_flow_lookup(struct vr_interface *, struct vr_ip *, struct vr_ip6 *,
uint8_t, uint16_t, uint16_t);
extern unsigned int vr_interface_req_get_size(void *);
#endif /* __VR_INTERFACE_H__ */
2 changes: 2 additions & 0 deletions include/vrouter.h
Expand Up @@ -119,6 +119,8 @@ enum vr_malloc_objects_t {
VR_BITMAP_OBJECT,
VR_QOS_MAP_OBJECT,
VR_FC_OBJECT,
VR_INTERFACE_FAT_FLOW_IPV4_EXCLUDE_LIST_OBJECT,
VR_INTERFACE_FAT_FLOW_IPV6_EXCLUDE_LIST_OBJECT,
VR_VROUTER_MAX_OBJECT,
};

Expand Down
2 changes: 2 additions & 0 deletions sandesh/vr.sandesh
Expand Up @@ -374,6 +374,8 @@ buffer sandesh vr_mem_stats_req {
68: i64 vms_interface_req_pbb_mac_object;
69: i64 vms_nexthop_req_bmac_object;
70: i64 vms_interface_req_bridge_id_object;
71: i64 vms_interface_fat_flow_ipv4_exclude_list_object;
72: i64 vms_interface_fat_flow_ipv6_exclude_list_object;
}

/* any new addition needs update to vr_util.c & flow.c */
Expand Down
21 changes: 21 additions & 0 deletions utils/vif.c
Expand Up @@ -636,6 +636,27 @@ list_get_print(vr_interface_req *req)
}
}
printf("\n");
if (req->vifr_fat_flow_exclude_ip_list_size) {
vr_interface_print_head_space();
printf("FatFlows IPv4 exclude prefix list:\n");
for (i = 0; i < req->vifr_fat_flow_exclude_ip_list_size; i++) {
vr_interface_print_head_space();
printf("\t%s\n", inet_ntop(AF_INET, &req->vifr_fat_flow_exclude_ip_list[i], ip_addr, INET_ADDRSTRLEN));
}
printf("\n");
}
if (req->vifr_fat_flow_exclude_ip6_u_list_size) {
vr_interface_print_head_space();
printf("FatFlows IPv6 exclude prefix list:\n");
for (i = 0; i < req->vifr_fat_flow_exclude_ip6_u_list_size; i++) {
tmp = (uint64_t *)ip6_ip;
*tmp = req->vifr_fat_flow_exclude_ip6_u_list[i];
*(tmp + 1) = req->vifr_fat_flow_exclude_ip6_l_list[i];
vr_interface_print_head_space();
printf("\t%s\n", inet_ntop(AF_INET6, ip6_ip, ip6_addr, INET6_ADDRSTRLEN));
}
printf("\n");
}

if (get_set && req->vifr_flags & VIF_FLAG_SERVICE_IF) {
vr_vrf_assign_dump = true;
Expand Down

0 comments on commit 29bd76d

Please sign in to comment.