diff --git a/dp-core/vr_bitmap.c b/dp-core/vr_bitmap.c index 1e3e1c5ce..deb0704a1 100644 --- a/dp-core/vr_bitmap.c +++ b/dp-core/vr_bitmap.c @@ -78,6 +78,19 @@ vr_bitmap_get_first_free_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 / 8)]; + if (bit_data & (1 << (bit % 8))) + return true; + + return false; +} + 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 614bd08c7..2bfb45ec3 100644 --- a/dp-core/vr_flow.c +++ b/dp-core/vr_flow.c @@ -1225,6 +1225,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); +} + static flow_result_t vr_do_flow_lookup(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 9d84928a0..c4bb44526 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 *); @@ -1308,7 +1312,7 @@ vif_get_mtu(struct vr_interface *vif) static void vif_free(struct vr_interface *vif) { - int i; + unsigned int i; if (!vif) return; @@ -1342,6 +1346,19 @@ vif_free(struct vr_interface *vif) vif->vif_src_mac = NULL; } + 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], + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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, VR_INTERFACE_OBJECT); return; @@ -1718,6 +1735,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; } @@ -1821,6 +1841,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 @@ -1891,10 +1915,13 @@ vr_interface_add_response(vr_interface_req *req, } static void -vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf, - unsigned int core) +__vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf, + unsigned int core) { - unsigned int cpu, i; + uint8_t proto; + uint16_t port; + unsigned int cpu, i, j; + struct vr_interface_settings settings; req->vifr_core = core; @@ -1996,9 +2023,68 @@ 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 core) +{ + 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), + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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, core); + + return 0; +} + static vr_interface_req * vr_interface_req_get(void) { @@ -2027,6 +2113,19 @@ 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, + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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) { @@ -2052,7 +2151,10 @@ vr_interface_req_destroy(vr_interface_req *req) req->vifr_queue_ierrors_to_lcore_size = 0; } + vr_interface_req_free_fat_flow_config(req); + vr_free(req, VR_INTERFACE_REQ_OBJECT); + return; } @@ -2060,6 +2162,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; @@ -2088,7 +2191,7 @@ vr_interface_get(vr_interface_req *req) 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); @@ -2133,6 +2236,8 @@ vr_interface_dump(vr_interface_req *r) if (ret <= 0) break; } + + vr_interface_req_free_fat_flow_config(resp); } generate_response: @@ -2275,6 +2380,367 @@ 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, VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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], VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + mem[i] = NULL; + } + } + + vr_free(mem, VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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 *), + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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, + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + if (!vif->vif_fat_flow_ports[proto_index][port_row]) { + if (alloced) { + vr_free(vif->vif_fat_flow_ports[proto_index], + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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), + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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], + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT); + 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 1f264e2ba..9d0f80125 100644 --- a/dp-core/vr_proto_ip.c +++ b/dp-core/vr_proto_ip.c @@ -848,6 +848,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)); @@ -868,6 +869,7 @@ 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_SCTP)) { @@ -878,6 +880,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, (unsigned char *)&ip->ip_saddr, ip->ip_proto, sport, dport); diff --git a/dp-core/vr_proto_ip6.c b/dp-core/vr_proto_ip6.c index 413e9e5c4..aa92f7bce 100644 --- a/dp-core/vr_proto_ip6.c +++ b/dp-core/vr_proto_ip6.c @@ -143,6 +143,7 @@ vr_inet6_form_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 *)ip6 + sizeof(struct vr_ip6)); if (ip6->ip6_nxt == VR_IP_PROTO_ICMP6) { @@ -165,6 +166,25 @@ vr_inet6_form_flow(struct vrouter *router, unsigned short vrf, dport = 0; } + port_mask = vr_flow_fat_flow_lookup(router, pkt, ip6->ip6_nxt, + 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_inet6_fill_flow(flow_p, nh_id, (unsigned char *)&ip6->ip6_src, ip6->ip6_nxt, sport, dport); diff --git a/dp-core/vr_stats.c b/dp-core/vr_stats.c index b02676d95..201e3a5f9 100644 --- a/dp-core/vr_stats.c +++ b/dp-core/vr_stats.c @@ -183,6 +183,9 @@ vr_mem_stats_get(void) stats_block[VR_HTABLE_OBJECT].ms_free); response->vms_interface_object += (stats_block[VR_INTERFACE_OBJECT].ms_alloc - stats_block[VR_INTERFACE_OBJECT].ms_free); + response->vms_interface_fat_flow_config_object += + (stats_block[VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT].ms_alloc - + stats_block[VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT].ms_free); response->vms_interface_mac_object += (stats_block[VR_INTERFACE_MAC_OBJECT].ms_alloc - stats_block[VR_INTERFACE_MAC_OBJECT].ms_free); response->vms_interface_req_object += (stats_block[VR_INTERFACE_REQ_OBJECT].ms_alloc - diff --git a/include/vr_bitmap.h b/include/vr_bitmap.h index 00bdeda08..19e448d19 100644 --- a/include/vr_bitmap.h +++ b/include/vr_bitmap.h @@ -16,6 +16,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 6ac4862ae..63ed59094 100644 --- a/include/vr_flow.h +++ b/include/vr_flow.h @@ -364,6 +364,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; @@ -406,5 +413,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 e05b2afa6..15211a146 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 @@ -164,6 +165,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 int vif_flags; /* Generation number is incrementing every time a vif is added. */ @@ -184,7 +198,6 @@ struct vr_interface { struct vrouter *vif_router; struct vr_interface_stats *vif_stats; - void *vif_os; int (*vif_tx)(struct vr_interface *, struct vr_packet *, struct vr_forwarding_md *); @@ -199,6 +212,14 @@ struct vr_interface { unsigned char *(*vif_set_rewrite)(struct vr_interface *, struct vr_packet *, struct vr_forwarding_md *, unsigned char *, unsigned short); + 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]; + unsigned char vif_mac[VR_ETHER_ALEN]; uint8_t vif_transport; uint8_t vif_mirror_id; @@ -278,5 +299,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 232815b13..0d05b5579 100644 --- a/include/vr_packet.h +++ b/include/vr_packet.h @@ -26,8 +26,10 @@ #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/include/vrouter.h b/include/vrouter.h index 5cbc1cb3a..8a036315d 100644 --- a/include/vrouter.h +++ b/include/vrouter.h @@ -63,15 +63,16 @@ enum vr_malloc_objects_t { VR_HPACKET_POOL_OBJECT, VR_HTABLE_OBJECT, VR_INTERFACE_OBJECT, + VR_INTERFACE_FAT_FLOW_CONFIG_OBJECT, VR_INTERFACE_MAC_OBJECT, VR_INTERFACE_REQ_OBJECT, VR_INTERFACE_REQ_MAC_OBJECT, VR_INTERFACE_REQ_NAME_OBJECT, + VR_INTERFACE_REQ_TO_LCORE_ERRORS_OBJECT, VR_INTERFACE_STATS_OBJECT, VR_INTERFACE_TABLE_OBJECT, - VR_INTERFACE_VRF_TABLE_OBJECT, VR_INTERFACE_TO_LCORE_ERRORS_OBJECT, - VR_INTERFACE_REQ_TO_LCORE_ERRORS_OBJECT, + VR_INTERFACE_VRF_TABLE_OBJECT, VR_ITABLE_OBJECT, VR_LOG_TYPES_OBJECT, VR_MALLOC_OBJECT, diff --git a/sandesh/vr.sandesh b/sandesh/vr.sandesh index 91af29621..ebcfa5570 100644 --- a/sandesh/vr.sandesh +++ b/sandesh/vr.sandesh @@ -100,6 +100,7 @@ buffer sandesh vr_interface_req { 49: i32 vifr_bridge_idx; 50: i16 vifr_ovlan_id; 51: byte vifr_transport; + 52: list vifr_fat_flow_protocol_port; } buffer sandesh vr_vxlan_req { @@ -319,6 +320,7 @@ buffer sandesh vr_mem_stats_req { 56: i64 vms_usock_buf_object; 57: i64 vms_usock_iovec_object; 58: i64 vms_vrouter_req_object; + 59: i64 vms_interface_fat_flow_config_object; } buffer sandesh vr_drop_stats_req { diff --git a/utils/vif.c b/utils/vif.c index e39165192..9a9a35a41 100644 --- a/utils/vif.c +++ b/utils/vif.c @@ -379,6 +379,7 @@ list_get_print(vr_interface_req *req) { char name[50] = {0}; int printed = 0; + unsigned int i; bool print_zero = false; if (rate_set) { @@ -475,6 +476,27 @@ list_get_print(vr_interface_req *req) req->vifr_dev_oerrors, 0); } + 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 (get_set && req->vifr_flags & VIF_FLAG_SERVICE_IF) { diff --git a/utils/vrmemstats.c b/utils/vrmemstats.c index 1c9ac9362..073e8cb12 100644 --- a/utils/vrmemstats.c +++ b/utils/vrmemstats.c @@ -79,6 +79,8 @@ vr_mem_stats_req_process(void *s_req) stats->vms_htable_object); printf("Interface %" PRIu64 "\n", stats->vms_interface_object); + printf("Interface Fat Flow Config %" PRIu64 "\n", + stats->vms_interface_fat_flow_config_object); printf("Interface MAC %" PRIu64 "\n", stats->vms_interface_mac_object); printf("Interface Request %" PRIu64 "\n",