From 1cc6cc900c6e01f9aa742da7a14d65d12649a803 Mon Sep 17 00:00:00 2001 From: "Anand H. Krishnan" Date: Fri, 27 Nov 2015 16:43:11 +0530 Subject: [PATCH] Combine streams of configured L4 protocol, port into a single stream Change-Id: Iaf6b5ae27fec9d58e60852aee267aacb875a773f Partial-BUG: 1518234 --- dp-core/vr_bitmap.c | 32 +++ dp-core/vr_flow.c | 21 ++ dp-core/vr_interface.c | 466 ++++++++++++++++++++++++++++++++++++++++- dp-core/vr_proto_ip.c | 23 +- include/vr_bitmap.h | 1 - include/vr_flow.h | 9 + include/vr_interface.h | 24 ++- include/vr_packet.h | 3 + sandesh/vr.sandesh | 1 + utils/vif.c | 27 ++- 10 files changed, 598 insertions(+), 9 deletions(-) diff --git a/dp-core/vr_bitmap.c b/dp-core/vr_bitmap.c index 5b6dc15e2..9c3e81b91 100644 --- a/dp-core/vr_bitmap.c +++ b/dp-core/vr_bitmap.c @@ -74,6 +74,38 @@ vr_bitmap_alloc_bit(vr_bmap_t b) return -1; } +bool +vr_bitmap_is_set_bit(vr_bmap_t b, unsigned int bit) +{ + unsigned int bit_data; + struct vr_bitmap *bmap = (struct vr_bitmap *)b; + + bit_data = bmap->bmap_data[(bit / VR_BITMAP_STRIDE_LEN)]; + if (bit_data & (1 << (bit % VR_BITMAP_STRIDE_LEN))) + return true; + + return false; +} + +bool +vr_bitmap_set_bit(vr_bmap_t b, unsigned int bit) +{ + struct vr_bitmap *bmap = (struct vr_bitmap *)b; + + if (!bmap || (bit >= bmap->bmap_bits)) + return false; + + if (vr_bitmap_is_set_bit(b, bit)) + return false; + + (void)__sync_fetch_and_or(&bmap->bmap_data[(bit / VR_BITMAP_STRIDE_LEN)], + (1 << (bit % VR_BITMAP_STRIDE_LEN))); + (void)__sync_add_and_fetch(&bmap->bmap_used_bits, 1); + + return true; +} + + bool vr_bitmap_clear_bit(vr_bmap_t b, unsigned int bit) { diff --git a/dp-core/vr_flow.c b/dp-core/vr_flow.c index fe96f0677..d677cddfc 100644 --- a/dp-core/vr_flow.c +++ b/dp-core/vr_flow.c @@ -1152,6 +1152,27 @@ __vr_flow_forward(flow_result_t result, struct vr_packet *pkt, return forward; } +fat_flow_port_mask_t +vr_flow_fat_flow_lookup(struct vrouter *router, struct vr_packet *pkt, + uint16_t l4_proto, uint16_t sport, uint16_t dport) +{ + struct vr_nexthop *nh; + struct vr_interface *vif_l = NULL; + + if (vif_is_virtual(pkt->vp_if)) { + vif_l = pkt->vp_if; + } else if (vif_is_fabric(pkt->vp_if)) { + if ((nh = pkt->vp_nh) && (nh->nh_flags & NH_FLAG_VALID)) { + vif_l = nh->nh_dev; + } + } + + if (!vif_l) + return NO_PORT_MASK; + + return vif_fat_flow_lookup(vif_l, l4_proto, sport, dport); +} + bool vr_flow_forward(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) diff --git a/dp-core/vr_interface.c b/dp-core/vr_interface.c index 9ad382a9e..92cd70bbd 100644 --- a/dp-core/vr_interface.c +++ b/dp-core/vr_interface.c @@ -23,6 +23,10 @@ static int vm_rx(struct vr_interface *, struct vr_packet *, unsigned short); static int eth_rx(struct vr_interface *, struct vr_packet *, unsigned short); static mac_response_t vm_mac_request(struct vr_interface *, struct vr_packet *, struct vr_forwarding_md *, unsigned char *); +static void vif_fat_flow_free(uint8_t **); +static int vif_fat_flow_add(struct vr_interface *, vr_interface_req *); +static bool vif_fat_flow_port_is_set(struct vr_interface *, uint8_t, + uint16_t); void vif_attach(struct vr_interface *); void vif_detach(struct vr_interface *); @@ -1279,6 +1283,8 @@ vif_get_mtu(struct vr_interface *vif) static void vif_free(struct vr_interface *vif) { + unsigned int i; + if (!vif) return; @@ -1299,6 +1305,18 @@ vif_free(struct vr_interface *vif) vif_bridge_deinit(vif); } + for (i = 0; i < VIF_FAT_FLOW_MAXPROTO_INDEX; i++) { + if (vif->vif_fat_flow_config[i]) { + vr_free(vif->vif_fat_flow_config[i]); + vif->vif_fat_flow_config[i] = NULL; + } + + if (vif->vif_fat_flow_ports[i]) { + vif_fat_flow_free(vif->vif_fat_flow_ports[i]); + vif->vif_fat_flow_ports[i] = NULL; + } + } + vr_free(vif); return; @@ -1674,6 +1692,9 @@ vr_interface_change(struct vr_interface *vif, vr_interface_req *req) vif->vif_nh_id = (unsigned short)req->vifr_nh_id; + if ((ret = vif_fat_flow_add(vif, req))) + return ret; + return 0; } @@ -1768,6 +1789,10 @@ vr_interface_add(vr_interface_req *req, bool need_response) strncpy(vif->vif_name, req->vifr_name, sizeof(vif->vif_name) - 1); } + ret = vif_fat_flow_add(vif, req); + if (ret) + goto generate_resp; + /* * the order below is probably not intuitive, but we do this because * the moment we do a drv_add, packets will start coming in and find @@ -1800,9 +1825,12 @@ vr_interface_add(vr_interface_req *req, bool need_response) } static void -vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf) +__vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf) { - unsigned int i; + uint8_t proto; + uint16_t port; + unsigned int i, j; + struct vr_interface_stats *stats; struct vr_interface_settings settings; @@ -1874,9 +1902,66 @@ vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf) } } + for (i = 0; i < VIF_FAT_FLOW_MAXPROTO_INDEX; i++) { + switch (i) { + case VIF_FAT_FLOW_TCP_INDEX: + proto = VR_IP_PROTO_TCP; + break; + + case VIF_FAT_FLOW_UDP_INDEX: + proto = VR_IP_PROTO_UDP; + break; + + case VIF_FAT_FLOW_SCTP_INDEX: + proto = VR_IP_PROTO_SCTP; + break; + + default: + proto = 0; + break; + } + + if (req->vifr_fat_flow_protocol_port && + req->vifr_fat_flow_protocol_port_size) { + for (j = 0; j < intf->vif_fat_flow_config_size[i]; j++) { + port = intf->vif_fat_flow_config[i][j]; + if (vif_fat_flow_port_is_set(intf, i, port)) { + req->vifr_fat_flow_protocol_port[j] = (proto << 16) | port; + } else { + vr_printf("vif0/%u: FatFlow port %u in configuration," + " but not in operational DB\n", + intf->vif_idx, port); + } + } + } + } + return; } +static int +vr_interface_make_req(vr_interface_req *req, struct vr_interface *vif) +{ + unsigned int i, fat_flow_config_size; + + fat_flow_config_size = 0; + for (i = 0; i < VIF_FAT_FLOW_MAXPROTO_INDEX; i++) + fat_flow_config_size += vif->vif_fat_flow_config_size[i]; + + if (fat_flow_config_size) { + req->vifr_fat_flow_protocol_port = + vr_zalloc(fat_flow_config_size * sizeof(uint32_t)); + if (!req->vifr_fat_flow_protocol_port) { + return -ENOMEM; + } + req->vifr_fat_flow_protocol_port_size = fat_flow_config_size; + } + + __vr_interface_make_req(req, vif); + + return 0; +} + static vr_interface_req * vr_interface_req_get(void) { @@ -1899,6 +1984,18 @@ vr_interface_req_get(void) } +static void +vr_interface_req_free_fat_flow_config(vr_interface_req *req) +{ + if (req->vifr_fat_flow_protocol_port) { + vr_free(req->vifr_fat_flow_protocol_port); + req->vifr_fat_flow_protocol_port = NULL; + req->vifr_fat_flow_protocol_port_size = 0; + } + + return; +} + static void vr_interface_req_destroy(vr_interface_req *req) { @@ -1918,6 +2015,8 @@ vr_interface_req_destroy(vr_interface_req *req) if (req->vifr_name) vr_free(req->vifr_name); + vr_interface_req_free_fat_flow_config(req); + vr_free(req); return; } @@ -1926,6 +2025,7 @@ static int vr_interface_get(vr_interface_req *req) { int ret = 0; + struct vr_interface *vif = NULL; struct vrouter *router; vr_interface_req *resp = NULL; @@ -1948,12 +2048,12 @@ vr_interface_get(vr_interface_req *req) goto generate_response; } - vr_interface_make_req(resp, vif); + ret = vr_interface_make_req(resp, vif); } else ret = -ENOENT; generate_response: - vr_message_response(VR_INTERFACE_OBJECT_ID, resp, ret); + vr_message_response(VR_INTERFACE_OBJECT_ID, ret ? NULL : resp, ret); if (resp) vr_interface_req_destroy(resp); @@ -1997,6 +2097,8 @@ vr_interface_dump(vr_interface_req *r) if (ret <= 0) break; } + + vr_interface_req_free_fat_flow_config(resp); } generate_response: @@ -2139,6 +2241,362 @@ vif_vrf_table_set(struct vr_interface *vif, unsigned int vlan, return 0; } +unsigned int +vif_fat_flow_get_proto_index(uint8_t proto) +{ + unsigned int proto_index = VIF_FAT_FLOW_NOPROTO_INDEX; + + switch (proto) { + case VR_IP_PROTO_TCP: + proto_index = VIF_FAT_FLOW_TCP_INDEX; + break; + + case VR_IP_PROTO_UDP: + proto_index = VIF_FAT_FLOW_UDP_INDEX; + break; + + case VR_IP_PROTO_SCTP: + proto_index = VIF_FAT_FLOW_SCTP_INDEX; + break; + + default: + break; + } + + return proto_index; +} + +static uint8_t vif_fat_flow_mem_zero[VIF_FAT_FLOW_BITMAP_BYTES]; + +static void +__vif_fat_flow_free_defer_cb(struct vrouter *router, void *data) +{ + struct vr_defer_data *vdd = (struct vr_defer_data *)data; + + if (!vdd || !vdd->vdd_data) + return; + + vr_free(vdd->vdd_data); + return; +} + +void +__vif_fat_flow_try_free(struct vr_interface *vif, unsigned int proto_index, + unsigned int port_row) +{ + uint8_t *mem_column, **mem_row; + struct vr_defer_data *vdd_row, *vdd_column; + + mem_row = vif->vif_fat_flow_ports[proto_index]; + if (!mem_row) + return; + mem_column = mem_row[port_row]; + + if (!memcmp(mem_column, vif_fat_flow_mem_zero, + sizeof(vif_fat_flow_mem_zero))) { + vdd_column = vr_get_defer_data(sizeof(*vdd_column)); + if (!vdd_column) + return; + + vif->vif_fat_flow_ports[proto_index][port_row] = NULL; + vdd_column->vdd_data = (void *)mem_column; + vr_defer(vif->vif_router, __vif_fat_flow_free_defer_cb, vdd_column); + + if (!memcmp(mem_row, vif_fat_flow_mem_zero, + VIF_FAT_FLOW_NUM_BITMAPS)) { + vdd_row = vr_get_defer_data(sizeof(*vdd_row)); + if (!vdd_row) + return; + + vif->vif_fat_flow_ports[proto_index] = NULL; + vdd_row->vdd_data = (void *)mem_row; + vr_defer(vif->vif_router, __vif_fat_flow_free_defer_cb, vdd_row); + } + + + return; + } + + return; +} + +static void +vif_fat_flow_free(uint8_t **mem) +{ + int i; + + if (!mem) + return; + + for (i = 0; i < VIF_FAT_FLOW_NUM_BITMAPS; i++) { + if (mem[i]) { + vr_free(mem[i]); + mem[i] = NULL; + } + } + + vr_free(mem); + return; +} + +int +__vif_fat_flow_delete(struct vr_interface *vif, unsigned int proto_index, + uint16_t port) +{ + unsigned int port_row, port_word, port_bit; + + if (!vif->vif_fat_flow_ports[proto_index]) + return -EINVAL; + + port_row = (port / VIF_FAT_FLOW_BITMAP_SIZE); + port_word = (port % VIF_FAT_FLOW_BITMAP_SIZE) / (sizeof(uint8_t) * 8); + port_bit = (port % VIF_FAT_FLOW_BITMAP_SIZE) % (sizeof(uint8_t) * 8); + + if (!vif->vif_fat_flow_ports[proto_index][port_row]) + return -EINVAL; + + vif->vif_fat_flow_ports[proto_index][port_row][port_word] &= + ~(1 << port_bit); + + __vif_fat_flow_try_free(vif, proto_index, port_row); + + return 0; +} + +int +vif_fat_flow_delete(struct vr_interface *vif, uint8_t proto, uint16_t port) +{ + unsigned int proto_index; + + proto_index = vif_fat_flow_get_proto_index(proto); + return __vif_fat_flow_delete(vif, proto_index, port); +} + + +int +__vif_fat_flow_add(struct vr_interface *vif, uint8_t proto, uint16_t port) +{ + unsigned int proto_index, port_row, port_word, port_bit; + + bool alloced = false; + + proto_index = vif_fat_flow_get_proto_index(proto); + + if (!vif->vif_fat_flow_ports[proto_index]) { + vif->vif_fat_flow_ports[proto_index] = + vr_zalloc(VIF_FAT_FLOW_NUM_BITMAPS * sizeof(unsigned int *)); + if (!vif->vif_fat_flow_ports) + return -ENOMEM; + alloced = true; + } + + port_row = (port / VIF_FAT_FLOW_BITMAP_SIZE); + port_word = (port % VIF_FAT_FLOW_BITMAP_SIZE) / (sizeof(uint8_t) * 8); + port_bit = (port % VIF_FAT_FLOW_BITMAP_SIZE) % (sizeof(uint8_t) * 8); + + if (!vif->vif_fat_flow_ports[proto_index][port_row]) { + vif->vif_fat_flow_ports[proto_index][port_row] = + vr_zalloc(VIF_FAT_FLOW_BITMAP_BYTES); + if (!vif->vif_fat_flow_ports[proto_index][port_row]) { + if (alloced) { + vr_free(vif->vif_fat_flow_ports[proto_index]); + return -ENOMEM; + } + } + } + + vif->vif_fat_flow_ports[proto_index][port_row][port_word] |= + (1 << port_bit); + + return 0; +} + +static int +vif_fat_flow_add(struct vr_interface *vif, vr_interface_req *req) +{ + uint8_t proto, proto_index; + uint16_t port, + old_fat_flow_config_sizes[VIF_FAT_FLOW_MAXPROTO_INDEX] = { 0 }; + uint16_t *vif_old_fat_flow_config[VIF_FAT_FLOW_MAXPROTO_INDEX] = { NULL }; + + int i, j, ret; + unsigned int size; + bool add; + + if (!req->vifr_fat_flow_protocol_port_size) { + return 0; + } else { + if (!req->vifr_fat_flow_protocol_port) + return -EINVAL; + } + + /* + * we ideally have to take a difference between the old and the new + * values and add only those that are new and delete those that are + * not present in the new, but are present in the old + * + * So, first save the old values to a local array. + */ + memcpy(old_fat_flow_config_sizes, vif->vif_fat_flow_config_size, + sizeof(old_fat_flow_config_sizes)); + memset(vif->vif_fat_flow_config_size, 0, + sizeof(vif->vif_fat_flow_config_size)); + + memcpy(vif_old_fat_flow_config, vif->vif_fat_flow_config, + sizeof(vif_old_fat_flow_config)); + memset(vif->vif_fat_flow_config, 0, sizeof(vif->vif_fat_flow_config)); + + /* + * sandesh is expensive. hence we would like to avoid adding more fields + * to sandesh, if it can be helped. now, such a constraint presents a + * challenge to know the number of ports present in the request - + * information that is needed to allocate space to store the current + * configuration. so, we loop and try to identify the number of ports + * present per protocol in the request + */ + for (i = 0; i < req->vifr_fat_flow_protocol_port_size; i++) { + proto = VIF_FAT_FLOW_PROTOCOL(req->vifr_fat_flow_protocol_port[i]); + port = VIF_FAT_FLOW_PORT(req->vifr_fat_flow_protocol_port[i]); + proto_index = vif_fat_flow_get_proto_index(proto); + + vif->vif_fat_flow_config_size[proto_index]++; + } + + /* + * ...and then use that information to allocate the array that holds the + * configuration + */ + for (i = 0; i < VIF_FAT_FLOW_MAXPROTO_INDEX; i++) { + if (vif->vif_fat_flow_config_size[i]) { + vif->vif_fat_flow_config[i] = + vr_zalloc(vif->vif_fat_flow_config_size[i] * sizeof(uint16_t)); + if (!vif->vif_fat_flow_config[i]) + return -ENOMEM; + + /* + * reset the size so that we can make use of the variable as an + * index while storing ports + */ + vif->vif_fat_flow_config_size[i] = 0; + } + } + + /* loop through the request and add the new ports */ + for (i = 0; i < req->vifr_fat_flow_protocol_port_size; i++) { + add = true; + + proto = VIF_FAT_FLOW_PROTOCOL(req->vifr_fat_flow_protocol_port[i]); + port = VIF_FAT_FLOW_PORT(req->vifr_fat_flow_protocol_port[i]); + proto_index = vif_fat_flow_get_proto_index(proto); + if (proto_index == VIF_FAT_FLOW_NOPROTO_INDEX) + port = proto; + + + /* store the port in the protocol specific config */ + if (vif->vif_fat_flow_config[proto_index]) { + size = vif->vif_fat_flow_config_size[proto_index]++; + vif->vif_fat_flow_config[proto_index][size] = port; + } + + /* + * strike out the common ports with the old configuration in the + * old configuration so that we can delete the absentees in the + * new configuration and not add ones that were already present + * in the old configuration + */ + for (j = 0; j < old_fat_flow_config_sizes[proto_index]; j++) { + if (vif_old_fat_flow_config[proto_index][j] == port) { + /* already present in the old configuration. hence no additon */ + vif_old_fat_flow_config[proto_index][j] = 0; + add = false; + break; + } + } + + /* add the new one... */ + if (add) { + ret = __vif_fat_flow_add(vif, proto, port); + if (ret) + return ret; + } + } + + /* ..and finally delete the old configuration */ + for (i = 0; i < VIF_FAT_FLOW_MAXPROTO_INDEX; i++) { + for (j = 0; j < old_fat_flow_config_sizes[i]; j++) { + if (vif_old_fat_flow_config[i] && vif_old_fat_flow_config[i][j]) + __vif_fat_flow_delete(vif, i, vif_old_fat_flow_config[i][j]); + } + + if (old_fat_flow_config_sizes[i] && vif_old_fat_flow_config[i]) { + vr_free(vif_old_fat_flow_config[i]); + vif_old_fat_flow_config[i] = NULL; + } + } + + return 0; +} + +static bool +vif_fat_flow_port_is_set(struct vr_interface *vif, uint8_t proto_index, + uint16_t port) +{ + unsigned int row, column, byte, bit; + + row = proto_index; + column = port / VIF_FAT_FLOW_BITMAP_SIZE; + + if (vif->vif_fat_flow_ports[row]) { + if (vif->vif_fat_flow_ports[row][column]) { + byte = (port % VIF_FAT_FLOW_BITMAP_SIZE) / 8; + bit = (port % VIF_FAT_FLOW_BITMAP_SIZE) % 8; + if (vif->vif_fat_flow_ports[row][column][byte] & + (1 << bit)) + return true; + } + } + + return false; +} + +fat_flow_port_mask_t +vif_fat_flow_lookup(struct vr_interface *vif, uint8_t proto, + uint16_t sport, uint16_t dport) +{ + unsigned int proto_index; + uint16_t h_sport, h_dport; + bool sport_set = false, dport_set = false; + + proto_index = vif_fat_flow_get_proto_index(proto); + if (!vif->vif_fat_flow_config[proto_index]) + return NO_PORT_MASK; + + if (proto_index == VIF_FAT_FLOW_NOPROTO_INDEX) { + h_sport = h_dport = proto; + } else { + h_sport = ntohs(sport); + h_dport = ntohs(dport); + } + + sport_set = vif_fat_flow_port_is_set(vif, proto_index, h_sport); + dport_set = vif_fat_flow_port_is_set(vif, proto_index, h_dport); + if (sport_set && dport_set) { + if (proto_index == VIF_FAT_FLOW_NOPROTO_INDEX) { + return ALL_PORT_MASK; + } else if (h_dport <= h_sport) { + return SOURCE_PORT_MASK; + } else { + return DESTINATION_PORT_MASK; + } + } else if (sport_set) { + return DESTINATION_PORT_MASK; + } else if (dport_set) { + return SOURCE_PORT_MASK; + } + + return NO_PORT_MASK; +} + int vr_gro_vif_add(struct vrouter *router, unsigned int os_idx, char *name, diff --git a/dp-core/vr_proto_ip.c b/dp-core/vr_proto_ip.c index 613961829..7c67ef74f 100644 --- a/dp-core/vr_proto_ip.c +++ b/dp-core/vr_proto_ip.c @@ -847,6 +847,7 @@ vr_inet_proto_flow(struct vrouter *router, unsigned short vrf, unsigned short nh_id; struct vr_icmp *icmph; + fat_flow_port_mask_t port_mask; t_hdr = (unsigned short *)((char *)ip + (ip->ip_hl * 4)); @@ -867,8 +868,9 @@ vr_inet_proto_flow(struct vrouter *router, unsigned short vrf, sport = 0; dport = icmph->icmp_type; } + } else if ((ip->ip_proto == VR_IP_PROTO_TCP) || - (ip->ip_proto == VR_IP_PROTO_UDP)) { + (ip->ip_proto == VR_IP_PROTO_UDP)) { sport = *t_hdr; dport = *(t_hdr + 1); } else { @@ -876,6 +878,25 @@ vr_inet_proto_flow(struct vrouter *router, unsigned short vrf, dport = 0; } + port_mask = vr_flow_fat_flow_lookup(router, pkt, ip->ip_proto, + sport, dport); + switch (port_mask) { + case SOURCE_PORT_MASK: + sport = 0; + break; + + case DESTINATION_PORT_MASK: + dport = 0; + break; + + case ALL_PORT_MASK: + sport = dport = 0; + break; + + default: + break; + } + nh_id = vr_inet_flow_nexthop(pkt, vlan); vr_inet_fill_flow(flow_p, nh_id, ip->ip_saddr, ip->ip_daddr, ip->ip_proto, sport, dport); diff --git a/include/vr_bitmap.h b/include/vr_bitmap.h index f76aaaa84..c21ef2269 100644 --- a/include/vr_bitmap.h +++ b/include/vr_bitmap.h @@ -15,6 +15,5 @@ bool vr_bitmap_clear_bit(vr_bmap_t, unsigned int); void vr_bitmap_delete(vr_bmap_t); vr_bmap_t vr_bitmap_create(unsigned int); - #endif diff --git a/include/vr_flow.h b/include/vr_flow.h index d39dff38c..8d496daa4 100644 --- a/include/vr_flow.h +++ b/include/vr_flow.h @@ -306,6 +306,13 @@ struct vr_flow_trap_arg { struct vr_flow_stats vfta_stats; }; +typedef enum { + NO_PORT_MASK, + SOURCE_PORT_MASK, + DESTINATION_PORT_MASK, + ALL_PORT_MASK, +} fat_flow_port_mask_t; + struct vr_packet; struct vrouter; @@ -339,5 +346,7 @@ int vr_flow_flush_pnode(struct vrouter *, struct vr_packet_node *, struct vr_flow_entry *, struct vr_forwarding_md *); void vr_flow_fill_pnode(struct vr_packet_node *, struct vr_packet *, struct vr_forwarding_md *); +fat_flow_port_mask_t vr_flow_fat_flow_lookup(struct vrouter *, + struct vr_packet *, uint16_t, uint16_t, uint16_t); #endif /* __VR_FLOW_H__ */ diff --git a/include/vr_interface.h b/include/vr_interface.h index f4f377bbf..76ce651c1 100644 --- a/include/vr_interface.h +++ b/include/vr_interface.h @@ -9,6 +9,7 @@ #include "vr_defs.h" #include "vr_types.h" #include "vr_htable.h" +#include "vr_flow.h" /* * 2 interfaces/VM + maximum vlan interfaces. VR_MAX_INTERFACES needs to @@ -141,6 +142,19 @@ struct vr_vrf_assign { unsigned int va_nh_id; }; +#define VIF_FAT_FLOW_NUM_BITMAPS (64) +#define VIF_FAT_FLOW_BITMAP_SIZE (1024) +#define VIF_FAT_FLOW_BITMAP_BYTES (VIF_FAT_FLOW_BITMAP_SIZE / 8) + +#define VIF_FAT_FLOW_NOPROTO_INDEX 0 +#define VIF_FAT_FLOW_TCP_INDEX 1 +#define VIF_FAT_FLOW_UDP_INDEX 2 +#define VIF_FAT_FLOW_SCTP_INDEX 3 +#define VIF_FAT_FLOW_MAXPROTO_INDEX 4 + +#define VIF_FAT_FLOW_PORT(p_p) ((p_p) && 0xFFFF) +#define VIF_FAT_FLOW_PROTOCOL(p_p) (((p_p) >> 16) & 0xFF) + struct vr_interface { unsigned short vif_type; unsigned short vif_vrf; @@ -168,6 +182,13 @@ struct vr_interface { * entries is also vital for table_users calculation. */ struct vr_vrf_assign *vif_vrf_table; + uint8_t **vif_fat_flow_ports[VIF_FAT_FLOW_MAXPROTO_INDEX]; + /* + * one for tcp, another for udp, one for sctp and one for + * everything else + */ + uint16_t *vif_fat_flow_config[VIF_FAT_FLOW_MAXPROTO_INDEX]; + uint16_t vif_fat_flow_config_size[VIF_FAT_FLOW_MAXPROTO_INDEX]; void *vif_os; int (*vif_send)(struct vr_interface *, struct vr_packet *, void *); @@ -253,5 +274,6 @@ extern int vif_vrf_table_set(struct vr_interface *, unsigned int, #if defined(__linux__) && defined(__KERNEL__) extern void vr_set_vif_ptr(struct net_device *dev, void *vif); #endif - +extern fat_flow_port_mask_t vif_fat_flow_lookup(struct vr_interface *, + uint8_t, uint16_t, uint16_t); #endif /* __VR_INTERFACE_H__ */ diff --git a/include/vr_packet.h b/include/vr_packet.h index c075a5537..cd7b28d9d 100644 --- a/include/vr_packet.h +++ b/include/vr_packet.h @@ -24,8 +24,11 @@ #define VR_IP_PROTO_UDP 17 #define VR_IP_PROTO_GRE 47 #define VR_IP_PROTO_ICMP6 58 +#define VR_IP_PROTO_SCTP 132 + #define VR_GRE_FLAG_CSUM (ntohs(0x8000)) #define VR_GRE_FLAG_KEY (ntohs(0x2000)) + #define VR_DHCP_SRC_PORT 68 #define VR_DHCP6_SRC_PORT 546 diff --git a/sandesh/vr.sandesh b/sandesh/vr.sandesh index 9e306473f..8db599e60 100644 --- a/sandesh/vr.sandesh +++ b/sandesh/vr.sandesh @@ -79,6 +79,7 @@ buffer sandesh vr_interface_req { 29: i32 vifr_bridge_idx; 30: i16 vifr_ovlan_id; 31: byte vifr_transport; + 32: list vifr_fat_flow_protocol_port; } buffer sandesh vr_vxlan_req { diff --git a/utils/vif.c b/utils/vif.c index 29aca67dd..4ae42b7f1 100644 --- a/utils/vif.c +++ b/utils/vif.c @@ -256,9 +256,10 @@ void vr_interface_req_process(void *s) { char name[50]; - vr_interface_req *req = (vr_interface_req *)s; - unsigned int printed = 0; int platform = get_platform(); + unsigned int printed = 0, i; + + vr_interface_req *req = (vr_interface_req *)s; if (add_set) vr_ifindex = req->vifr_idx; @@ -332,8 +333,30 @@ vr_interface_req_process(void *s) printf("TX packets:%" PRId64 " bytes:%" PRId64 " errors:%" PRId64 "\n", req->vifr_opackets, req->vifr_obytes, req->vifr_oerrors); + if (req->vifr_fat_flow_protocol_port_size) { + vr_interface_print_head_space(); + printed = 0; + printed += printf("FatFlows: "); + for (i = 0; i < req->vifr_fat_flow_protocol_port_size; i++) { + printed += printf("%d:%d", + VIF_FAT_FLOW_PROTOCOL(req->vifr_fat_flow_protocol_port[i]), + VIF_FAT_FLOW_PORT(req->vifr_fat_flow_protocol_port[i])); + if (i == (req->vifr_fat_flow_protocol_port_size - 1)) { + printf("\n"); + } else if (printed > 68) { + printf("\n"); + printed = 0; + vr_interface_print_head_space(); + /* %12 corresponds to "ComboFlows: " */ + printed += printf("%12c", ' '); + } else { + printf(", "); + } + } + } printf("\n"); + if (list_set) dump_marker = req->vifr_idx;