From 91e2d3a2327695330ef5fb76fca4d45dab4a1265 Mon Sep 17 00:00:00 2001 From: "Anand H. Krishnan" Date: Tue, 23 Feb 2016 16:34:30 +0530 Subject: [PATCH] 'GET' option for 'rt' command A '--get' switch for the 'rt' to match a particular route and dump it. Currently, only for inet and inet6 routes. Change-Id: I3b53dda635f4f4af5b7f79ddf47e14313f372f81 Partial-BUG: #1548757 Support GET for L2 routes Support 'GET' operation for a specific route in the vRouter bridge table too. Also, support giving a specific prefix length to the route and return a match based on that specific prefix. Change-Id: I93980925e70f45482c372ba3beeca8bfbd3028b2 Closes-BUG: #1548757 --- dp-core/vr_bridge.c | 4 +- dp-core/vr_ip_mtrie.c | 140 ++++++++++++++++++++++++----------- dp-core/vr_route.c | 28 ++++++- include/nl_util.h | 6 ++ include/vrouter.h | 1 - utils/flow.c | 119 ++---------------------------- utils/rt.c | 165 ++++++++++++++++++++++++++++++++++++++---- utils/vr_util.c | 132 ++++++++++++++++++++++++++++++++- utils/vrmemstats.c | 2 + 9 files changed, 417 insertions(+), 180 deletions(-) diff --git a/dp-core/vr_bridge.c b/dp-core/vr_bridge.c index b4ea5a55c..9afcb21fb 100644 --- a/dp-core/vr_bridge.c +++ b/dp-core/vr_bridge.c @@ -270,8 +270,10 @@ bridge_table_get(unsigned int vrf_id, struct vr_route_req *rt) struct vr_nexthop *nh; nh = bridge_table_lookup(vrf_id, rt); - if (nh) + if (nh) { rt->rtr_req.rtr_nh_id = rt->rtr_nh->nh_id; + return 0; + } return -ENOENT; } diff --git a/dp-core/vr_ip_mtrie.c b/dp-core/vr_ip_mtrie.c index 74a8f2ce9..a7edeac66 100644 --- a/dp-core/vr_ip_mtrie.c +++ b/dp-core/vr_ip_mtrie.c @@ -874,6 +874,75 @@ mtrie_stats_dump(struct vr_rtable *rtable, vr_vrf_stats_req *req) return 0; } + +static struct vr_nexthop * +__mtrie_lookup(struct vr_route_req *rt, struct ip_bucket *bkt, unsigned int level) +{ + unsigned int i, limit, index; + unsigned long ptr; + + struct ip_bucket_entry *ent; + struct mtrie_bkt_info *ip_bkt_info; + struct vr_nexthop *ret_nh = NULL; + + if (!bkt || level >= ip_bkt_get_max_level(rt->rtr_req.rtr_family)) + return NULL; + + ip_bkt_info = ip_bkt_info_get(rt->rtr_req.rtr_family); + index = rt_to_index(rt, level); + + if (rt->rtr_req.rtr_prefix_len > ip_bkt_info[level].bi_pfx_len) { + limit = ip_bkt_info[level].bi_size; + } else { + limit = (1 << + (ip_bkt_info[level].bi_pfx_len - rt->rtr_req.rtr_prefix_len)); + } + + /* + * ideally, we would have just followed the calculated index to the + * bottom of the tree and returned. however, what happens when the + * bottom of the tree is populated with a more specific route? for + * e.g.: we are searching for 1.1.0.0/16, but we also have a more + * specific route for 1.1.0.0/24. So, to get around that case, we + * need to loop the whole bucket, searching for a prefix length match. + * + * So what happens if all of the prefixes below have a more specific + * route. For e.g.: 1.1.0, 1.1.1, 1.1.2, ... 1.1.255. While there are + * no practical applications of such a route, for correctness, in such + * a case, we loop around the current bucket: i.e. in this case, we will + * loop around the bucket that holds 1.1/16. Maybe 1.2/16 was inherited + * from a lesser specific prefix and hence a match. + */ + for (i = 0; i < ip_bkt_info[level].bi_size; i++) { + ent = index_to_entry(bkt, (index + i) % ip_bkt_info[level].bi_size); + ptr = ent->entry_long_i; + if (PTR_IS_NEXTHOP(ptr)) { + if (i >= limit) { + if (ent->entry_prefix_len >= rt->rtr_req.rtr_prefix_len) + continue; + } + + if (ent->entry_prefix_len > rt->rtr_req.rtr_prefix_len) + continue; + + rt->rtr_req.rtr_label_flags = ent->entry_label_flags; + rt->rtr_req.rtr_label = ent->entry_label; + rt->rtr_req.rtr_prefix_len = ent->entry_prefix_len; + rt->rtr_req.rtr_index = ent->entry_bridge_index; + ret_nh = PTR_TO_NEXTHOP(ptr); + rt->rtr_nh = ret_nh; + break; + } else { + bkt = PTR_TO_BUCKET(ptr); + ret_nh = __mtrie_lookup(rt, bkt, level + 1); + if (ret_nh) + break; + } + } + + return ret_nh; +} + /* * longest prefix match. go down the tree till you encounter a next-hop. * if no nexthop, there is something wrong with the tree which was built. @@ -883,28 +952,15 @@ mtrie_stats_dump(struct vr_rtable *rtable, vr_vrf_stats_req *req) static struct vr_nexthop * mtrie_lookup(unsigned int vrf_id, struct vr_route_req *rt) { - unsigned int level, index; - unsigned long ptr; - struct ip_mtrie *table; - struct ip_bucket *bkt; + unsigned int level = 0; + unsigned long ptr; + + struct ip_mtrie *table; + struct ip_bucket *bkt; struct ip_bucket_entry *ent; struct vr_nexthop *default_nh, *ret_nh; default_nh = ip4_default_nh; - - /* we do not support any thing other than /32 route lookup */ - if ((rt->rtr_req.rtr_family == AF_INET) && - (rt->rtr_req.rtr_prefix_len != IP4_PREFIX_LEN)) { - rt->rtr_nh = default_nh; - return default_nh; - } - - if ((rt->rtr_req.rtr_family == AF_INET6) && - (rt->rtr_req.rtr_prefix_len != IP6_PREFIX_LEN)) { - rt->rtr_nh = default_nh; - return default_nh; - } - table = vrfid_to_mtrie(vrf_id, rt->rtr_req.rtr_family); if (!table) { rt->rtr_nh = default_nh; @@ -912,7 +968,6 @@ mtrie_lookup(unsigned int vrf_id, struct vr_route_req *rt) } ent = &table->root; - ptr = ent->entry_long_i; if (!ptr) { rt->rtr_nh = default_nh; @@ -935,30 +990,16 @@ mtrie_lookup(unsigned int vrf_id, struct vr_route_req *rt) return default_nh; } - for (level = 0; level < ip_bkt_get_max_level(rt->rtr_req.rtr_family); level++) { - index = rt_to_index(rt, level); - ent = index_to_entry(bkt, index); - ptr = ent->entry_long_i; - if (PTR_IS_NEXTHOP(ptr)) { - rt->rtr_req.rtr_label_flags = ent->entry_label_flags; - rt->rtr_req.rtr_label = ent->entry_label; - rt->rtr_req.rtr_prefix_len = ent->entry_prefix_len; - rt->rtr_req.rtr_index = ent->entry_bridge_index; - ret_nh = PTR_TO_NEXTHOP(ptr); - rt->rtr_nh = ret_nh; - return ret_nh; - } - - bkt = PTR_TO_BUCKET(ptr); - } - - /* no nexthop; assert */ - ASSERT(0); + ret_nh = __mtrie_lookup(rt, bkt, level); + if (!ret_nh) + ret_nh = default_nh; rt->rtr_nh = ret_nh; - return NULL; + + return ret_nh; } + /* * adds a route to the corresponding vrf table. returns 0 on * success and non-zero otherwise @@ -1012,12 +1053,29 @@ static int mtrie_get(unsigned int vrf_id, struct vr_route_req *rt) { struct vr_nexthop *nh; + struct vr_route_req breq; + vr_route_req *req = &rt->rtr_req; nh = mtrie_lookup(vrf_id, rt); if (nh) - rt->rtr_req.rtr_nh_id = nh->nh_id; + req->rtr_nh_id = nh->nh_id; else - rt->rtr_req.rtr_nh_id = -1; + req->rtr_nh_id = -1; + + if (req->rtr_index != VR_BE_INVALID_INDEX) { + req->rtr_mac = vr_zalloc(VR_ETHER_ALEN, VR_ROUTE_REQ_MAC_OBJECT); + req->rtr_mac_size = VR_ETHER_ALEN; + + breq.rtr_req.rtr_mac = req->rtr_mac; + breq.rtr_req.rtr_index = req->rtr_index; + breq.rtr_req.rtr_mac_size = VR_ETHER_ALEN; + vr_bridge_lookup(req->rtr_vrf_id, &breq); + + } else { + req->rtr_mac_size = 0; + req->rtr_mac = NULL; + } + return 0; } diff --git a/dp-core/vr_route.c b/dp-core/vr_route.c index a0cdbd17c..ac88740f2 100644 --- a/dp-core/vr_route.c +++ b/dp-core/vr_route.c @@ -119,11 +119,22 @@ vr_route_add(vr_route_req *req) int vr_route_get(vr_route_req *req) { - struct vr_route_req vr_req; - struct vrouter *router; int ret = 0; uint32_t rt_prefix[4]; - struct vr_rtable *rtable; + bool mac_mem_free = false; + + struct vr_route_req vr_req; + struct vrouter *router; + struct vr_rtable *rtable = NULL; + + if (!req->rtr_mac) + mac_mem_free = true; + + if ((req->rtr_family != AF_INET) && (req->rtr_family != AF_INET6) && + (req->rtr_family != AF_BRIDGE)) { + ret = -EINVAL; + goto generate_response; + } vr_req.rtr_req = *req; @@ -140,8 +151,12 @@ vr_route_get(vr_route_req *req) ret = -ENOENT; goto generate_response; } else { + if ((req->rtr_family == AF_INET) || (req->rtr_family == AF_INET6)) { + rtable = router->vr_inet_rtable; + } else if (req->rtr_family == AF_BRIDGE) { + rtable = router->vr_bridge_rtable; + } - rtable = router->vr_inet_rtable; if (!rtable) { ret = -ENOENT; goto generate_response; @@ -152,6 +167,11 @@ vr_route_get(vr_route_req *req) generate_response: vr_message_response(VR_ROUTE_OBJECT_ID, ret ? NULL : &vr_req, ret); + if (mac_mem_free && vr_req.rtr_req.rtr_mac) { + vr_free(vr_req.rtr_req.rtr_mac, VR_ROUTE_REQ_MAC_OBJECT); + vr_req.rtr_req.rtr_mac = NULL; + } + return ret; } diff --git a/include/nl_util.h b/include/nl_util.h index 6261b8206..581026a05 100644 --- a/include/nl_util.h +++ b/include/nl_util.h @@ -110,6 +110,10 @@ extern void nl_build_attr(struct nl_client *cl, int len, int attr); extern int vrouter_get_family_id(struct nl_client *cl); extern int get_vrouter_pid(void); +extern char *vr_extract_token(char *, char); +extern bool vr_valid_ipv6_address(const char *); +extern bool vr_valid_ipv4_address(const char *); + extern int vr_recvmsg(struct nl_client *cl, bool dump); extern int vr_sendmsg(struct nl_client *, void *, char *); extern struct nl_client *vr_get_nl_client(unsigned int); @@ -156,6 +160,8 @@ extern int vr_send_nexthop_add(struct nl_client *, unsigned int, extern int vr_send_route_dump(struct nl_client *, unsigned int, unsigned int, unsigned int, uint8_t *, unsigned int); +extern int vr_send_route_get(struct nl_client *, unsigned int, unsigned int, + unsigned int family, uint8_t *, unsigned int, uint8_t *); extern int vr_send_route_delete(struct nl_client *, unsigned int, unsigned int, unsigned int family, uint8_t *, unsigned int, unsigned int, int, uint8_t *, uint32_t, unsigned ints); diff --git a/include/vrouter.h b/include/vrouter.h index 0bf5275b6..86c89d86b 100644 --- a/include/vrouter.h +++ b/include/vrouter.h @@ -267,7 +267,6 @@ struct vrouter { unsigned int vr_max_nexthops; struct vr_btable *vr_nexthops; struct vr_rtable *vr_inet_rtable; - struct vr_rtable *vr_inet6_rtable; struct vr_rtable *vr_inet_mcast_rtable; struct vr_rtable *vr_bridge_rtable; diff --git a/utils/flow.c b/utils/flow.c index c06c87861..bbc856631 100644 --- a/utils/flow.c +++ b/utils/flow.c @@ -1052,86 +1052,6 @@ validate_options(void) return; } -static void -flow_remove_trailing_space(char *addr) -{ - unsigned int len = strlen(addr); - - len -= 1; - while ((*(addr + len) == ' ') && --len); - *(addr + len + 1) = '\0'; - - return; -} - -static bool -valid_ipv6_address(const char *addr) -{ - unsigned int i = 0, j = 0, sep_count = 0; - - /* a '*' is treated as a valid address */ - if (!strncmp(addr, "*", 1) && (strlen(addr) == 1)) - return true; - - while (*(addr + i)) { - if (isalnum(*(addr + i))) { - j++; - } else if (*(addr + i) == ':') { - j = 0; - sep_count++; - } else { - printf("match: \"%s\" is not a valid ipv6 address format\n", addr); - return false; - } - - if ((j > 4) || (sep_count > 7)) { - printf("match: \"%s\" is not a valid ipv6 address format\n", addr); - return false; - } - - i++; - } - - return true; -} - -static bool -valid_ipv4_address(const char *addr) -{ - unsigned int i = 0, j = 0, sep_count = 0; - - /* a '*' is treated as a valid address */ - if (!strncmp(addr, "*", 1) && (strlen(addr) == 1)) - return true; - - /* every character should be either a digit or a '.' */ - while (*(addr + i)) { - if (isdigit(*(addr + i))) { - j++; - } else if (i && (*(addr + i) == '.')) { - j = 0; - ++sep_count; - } else { - printf("match: \"%s\" is not a valid ipv4 address format\n", addr); - return false; - } - - if ((j > 3) || (sep_count > 3)) { - printf("match: \"%s\" is not a valid ipv4 address format\n", addr); - return false; - } - - i++; - } - - if (sep_count != 3) { - printf("match: \"%s\" is not a valid ipv4 address format\n", addr); - return false; - } - - return true; -} - static int flow_set_family(unsigned int family, char *addr, const char *port) { @@ -1144,18 +1064,16 @@ flow_set_family(unsigned int family, char *addr, const char *port) return -EINVAL; } - flow_remove_trailing_space(addr); - switch (family) { case AF_INET: mem_size = VR_IP_ADDRESS_LEN; - if (!valid_ipv4_address(addr)) + if (!vr_valid_ipv4_address(addr)) return -EINVAL; break; case AF_INET6: mem_size = VR_IP6_ADDRESS_LEN; - if (!valid_ipv6_address(addr)) + if (!vr_valid_ipv6_address(addr)) return -EINVAL; break; @@ -1279,33 +1197,6 @@ flow_set_tuple(char *ip_port) return 0; } -static char * -flow_extract_token(char *string, char token_separator) -{ - int ret; - unsigned int length; - - char *sep; - - /* skip over leading white spaces */ - while ((*string == ' ') && string++); - - /* if there is nothing left after the spaces, return */ - if (!strlen(string)) { - return NULL; - } - - /* start searching for the token */ - sep = strchr(string, token_separator); - if (sep) { - length = sep - string; - /* terminate the token with NULL */ - string[sep - string] = '\0'; - } - - return string; -} - static int flow_set_ip(char *match_string) { @@ -1315,14 +1206,14 @@ flow_set_ip(char *match_string) char *token, *string = match_string; do { - token = flow_extract_token(match_string, ','); + token = vr_extract_token(match_string, ','); if (token) { token_length = strlen(token) + 1; /* ...and use it to set the match tuple */ if (ret = flow_set_tuple(token)) return ret; } else { - token = flow_extract_token(match_string, '&'); + token = vr_extract_token(match_string, '&'); if (token) { token_length = strlen(token) + 1; if (ret = flow_set_tuple(token)) @@ -1382,7 +1273,7 @@ flow_set_match(char *match_string) char *token, *string = match_string; do { - token = flow_extract_token(match_string, '&'); + token = vr_extract_token(match_string, '&'); if (token) { token_length = strlen(token) + 1; if (!strncmp(token, "proto", strlen("proto"))) { diff --git a/utils/rt.c b/utils/rt.c index 2dc99e383..885667383 100644 --- a/utils/rt.c +++ b/utils/rt.c @@ -26,6 +26,7 @@ #endif #include "vr_types.h" +#include "vr_packet.h" #include "vr_nexthop.h" #include "nl_util.h" #include "vr_mpls.h" @@ -44,8 +45,8 @@ static bool cmd_proxy_set = false; static bool cmd_trap_set = false; static bool cmd_flood_set = false; -static int cmd_set, dump_set; -static int family_set, help_set; +static int cmd_set, dump_set, get_set; +static int family_set, help_set, vrf_set; static int cmd_prefix_set; static int cmd_dst_mac_set; @@ -54,6 +55,7 @@ static int cmd_vrf_id = -1, cmd_family_id; static int cmd_op = -1; static int cmd_nh_id = -1; +static char *cmd_prefix_string, *cmd_plen_string; static uint8_t cmd_prefix[16], cmd_src[16]; static uint32_t cmd_plen = 0; static int32_t cmd_label; @@ -110,7 +112,7 @@ dump_legend(int family) printf(", "); } - printf("\n\n"); + printf("\n"); return; } @@ -127,6 +129,31 @@ family_string_to_id(char *fname) return -1; } +static void +address_mask(uint8_t *addr, uint8_t plen, unsigned int family) +{ + int i; + uint8_t address_bits; + uint8_t mask[VR_IP6_ADDRESS_LEN]; + + if (family == AF_INET) { + address_bits = VR_IP_ADDRESS_LEN * 8; + } else { + address_bits = VR_IP6_ADDRESS_LEN * 8; + } + + memset(mask, 0xFF, sizeof(mask)); + for (i = address_bits - 1; i >= plen; i--) { + mask[i / 8] ^= (1 << (7 - (i % 8))); + } + + for (i = 0; i < (address_bits / 8); i++) { + addr[i] &= mask[i]; + } + + return; +} + void vr_route_req_process(void *s_req) { @@ -141,6 +168,8 @@ vr_route_req_process(void *s_req) rt_marker_plen = rt->rtr_prefix_len; if (rt->rtr_prefix_size) { + if (cmd_op == SANDESH_OP_GET) + address_mask(rt->rtr_prefix, rt->rtr_prefix_len, rt->rtr_family); inet_ntop(rt->rtr_family, rt->rtr_prefix, addr, sizeof(addr)); ret = printf("%s/%-2d", addr, rt->rtr_prefix_len); } @@ -232,6 +261,35 @@ vr_response_process(void *s) } +static void +vr_print_rtable_header(unsigned int family, unsigned int vrf) +{ + char addr[INET6_ADDRSTRLEN]; + + dump_legend(family); + switch (family) { + case AF_INET: + case AF_INET6: + printf("vRouter inet%c routing table %d/%d/unicast\n", + (family == AF_INET) ? '4' : '6', + 0, cmd_vrf_id); + printf("Destination PPL Flags Label " + "Nexthop Stitched MAC(Index)\n"); + break; + + case AF_BRIDGE: + printf("vRouter bridge table %d/%d\n", 0, cmd_vrf_id); + printf("Index DestMac Flags " + "Label/VNID Nexthop\n"); + break; + + default: + break; + } + + return; +} + static int vr_route_op(struct nl_client *cl) { @@ -239,19 +297,12 @@ vr_route_op(struct nl_client *cl) bool dump = false; unsigned int flags = 0; uint8_t *dst_mac = NULL; + char addr[INET6_ADDRSTRLEN]; - if (cmd_op == SANDESH_OP_DUMP) { - if ((cmd_family_id == AF_INET) || (cmd_family_id == AF_INET6)) { - printf("Vrouter inet%c routing table %d/%d/unicast\n", - (cmd_family_id == AF_INET) ? '4' : '6', - 0, cmd_vrf_id); - dump_legend(cmd_family_id); - printf("Destination PPL Flags Label Nexthop Stitched MAC(Index)\n"); - } else { + if (cmd_op == SANDESH_OP_DUMP || cmd_op == SANDESH_OP_GET) { + vr_print_rtable_header(cmd_family_id, cmd_vrf_id); + if (cmd_family_id == AF_BRIDGE) { rt_marker_plen = VR_ETHER_ALEN; - printf("Kernel L2 Bridge table %d/%d\n\n", 0, cmd_vrf_id); - dump_legend(cmd_family_id); - printf("Index DestMac Flags Label/VNID Nexthop\n"); } } @@ -287,6 +338,11 @@ vr_route_op(struct nl_client *cl) cmd_replace_plen, flags); break; + case SANDESH_OP_GET: + ret = vr_send_route_get(cl, 0, cmd_vrf_id, cmd_family_id, + cmd_prefix, cmd_plen, cmd_dst_mac); + break; + default: ret = -EINVAL; break; @@ -332,6 +388,9 @@ validate_options(void) { unsigned int set = dump_set + family_set + cmd_set + help_set; + char addr[INET6_ADDRSTRLEN]; + struct ether_addr *eth; + if (cmd_op < 0) goto usage; @@ -370,6 +429,60 @@ validate_options(void) goto usage_internal; } + break; + + case SANDESH_OP_GET: + if (cmd_vrf_id < 0 || !cmd_prefix_string) + goto usage; + + switch (cmd_family_id) { + case AF_INET: + case AF_INET6: + if (cmd_family_id == AF_INET) { + if (!vr_valid_ipv4_address(cmd_prefix_string)) + goto usage; + } else { + if (!vr_valid_ipv6_address(cmd_prefix_string)) + goto usage; + } + + + if (inet_pton(cmd_family_id, cmd_prefix_string, cmd_prefix) != 1) { + printf("%s: inet_pton fails for %s\n", __FUNCTION__, cmd_prefix_string); + exit(EINVAL); + } + + if (!cmd_plen_string) + goto usage; + + cmd_plen = strtoul(cmd_plen_string, NULL, 0); + address_mask(cmd_prefix, cmd_plen, cmd_family_id); + printf("Match %s/%u in vRouter inet%c table %u/%u/unicast\n\n", + inet_ntop(cmd_family_id, &cmd_prefix, addr, sizeof(addr)), + cmd_plen, (cmd_family_id == AF_INET) ? '4' : '6', + 0, cmd_vrf_id); + break; + + case AF_BRIDGE: + eth = ether_aton(cmd_prefix_string); + if (!eth) { + printf("%s: ether_aton fails on %s\n", + __FUNCTION__, cmd_prefix_string); + exit(EINVAL); + } + + memcpy(cmd_dst_mac, eth, sizeof(cmd_dst_mac)); + printf("Match %s in vRouter bridge table %u/%u/unicast\n\n", + ether_ntoa((const struct ether_addr *)cmd_dst_mac), + 0, cmd_vrf_id); + break; + + default: + printf("Address family %d not supported\n", cmd_family_id); + exit(EINVAL); + } + + break; default: @@ -391,6 +504,8 @@ enum opt_flow_index { COMMAND_OPT_INDEX, DUMP_OPT_INDEX, FAMILY_OPT_INDEX, + GET_OPT_INDEX, + VRF_OPT_INDEX, HELP_OPT_INDEX, MAX_OPT_INDEX, }; @@ -399,6 +514,8 @@ static struct option long_options[] = { [COMMAND_OPT_INDEX] = {"cmd", no_argument, &cmd_set, 1}, [DUMP_OPT_INDEX] = {"dump", required_argument, &dump_set, 1}, [FAMILY_OPT_INDEX] = {"family", required_argument, &family_set, 1}, + [GET_OPT_INDEX] = {"get", required_argument, &get_set, 1}, + [VRF_OPT_INDEX] = {"vrf", required_argument, &vrf_set, 1}, [HELP_OPT_INDEX] = {"help", no_argument, &help_set, 1}, [MAX_OPT_INDEX] = { NULL, 0, 0, 0}, }; @@ -406,7 +523,8 @@ static struct option long_options[] = { static void Usage(void) { - printf("Usage: rt --dump [--family ]>\n"); + printf("Usage: rt --dump [--family ]>\n"); + printf(" rt --get
--vrf [--family ]\n"); printf(" rt --help\n"); printf("\n"); printf("--dump Dumps the routing table corresponding to vrf_id\n"); @@ -421,6 +539,8 @@ static void parse_long_opts(int opt_flow_index, char *opt_arg) { errno = 0; + unsigned int arg_len, tok_len; + switch (opt_flow_index) { case COMMAND_OPT_INDEX: usage_internal(); @@ -441,6 +561,21 @@ parse_long_opts(int opt_flow_index, char *opt_arg) Usage(); break; + case GET_OPT_INDEX: + cmd_op = SANDESH_OP_GET; + arg_len = strlen(opt_arg); + cmd_prefix_string = vr_extract_token(opt_arg, '/'); + tok_len = strlen(cmd_prefix_string); + if (tok_len != arg_len) { + cmd_plen_string = vr_extract_token(cmd_prefix_string + tok_len + 1, '\0'); + } + + break; + + case VRF_OPT_INDEX: + cmd_vrf_id = strtoul(opt_arg, NULL, 0); + break; + case HELP_OPT_INDEX: default: Usage(); diff --git a/utils/vr_util.c b/utils/vr_util.c index 536c58f98..a3694601d 100644 --- a/utils/vr_util.c +++ b/utils/vr_util.c @@ -30,11 +30,120 @@ #include "vr_interface.h" #include "vr_nexthop.h" #include "vr_route.h" +#include "vr_bridge.h" #include "ini_parser.h" /* Suppress NetLink error messages */ bool vr_ignore_nl_errors = false; +char * +vr_extract_token(char *string, char token_separator) +{ + int ret; + unsigned int length; + + char *sep; + + /* skip over leading white spaces */ + while ((*string == ' ') && string++); + + /* if there is nothing left after the spaces, return */ + if (!(length = strlen(string))) { + return NULL; + } + + /* start searching for the token */ + sep = strchr(string, token_separator); + if (sep) { + length = sep - string; + /* terminate the token with NULL */ + string[sep - string] = '\0'; + length = strlen(string); + } + + /* remove trailing spaces */ + length -= 1; + while ((*(string + length) == ' ') && --length); + *(string + length + 1) = '\0'; + + /* + * reset the separator to space, since a space at the beginning + * will be snipped + */ + if (sep && (((sep - string)) != strlen(string))) + string[sep - string] = ' '; + + return string; +} + +bool +vr_valid_ipv6_address(const char *addr) +{ + unsigned int i = 0, j = 0, sep_count = 0; + + /* a '*' is treated as a valid address */ + if (!strncmp(addr, "*", 1) && (strlen(addr) == 1)) + return true; + + while (*(addr + i)) { + if (isalnum(*(addr + i))) { + j++; + } else if (*(addr + i) == ':') { + j = 0; + sep_count++; + } else { + printf("match: \"%s\" is not a valid ipv6 address format\n", addr); + return false; + } + + if ((j > 4) || (sep_count > 7)) { + printf("match: \"%s\" is not a valid ipv6 address format\n", addr); + return false; + } + + i++; + } + + return true; +} + +bool +vr_valid_ipv4_address(const char *addr) +{ + unsigned int i = 0, j = 0, sep_count = 0; + + /* a '*' is treated as a valid address */ + if (!strncmp(addr, "*", 1) && (strlen(addr) == 1)) + return true; + + /* every character should be either a digit or a '.' */ + while (*(addr + i)) { + if (isdigit(*(addr + i))) { + j++; + } else if (i && (*(addr + i) == '.')) { + j = 0; + ++sep_count; + } else { + printf("match: \"%s\" is not a valid ipv4 address format\n", addr); + return false; + } + + if ((j > 3) || (sep_count > 3)) { + printf("match: \"%s\" is not a valid ipv4 address format\n", addr); + return false; + } + + i++; + } + + if (sep_count != 3) { + printf("match: \"%s\" is not a valid ipv4 address format\n", addr); + return false; + } + + return true; +} + /* send and receive */ int vr_recvmsg(struct nl_client *cl, bool dump) @@ -597,18 +706,24 @@ vr_send_route_common(struct nl_client *cl, unsigned int op, vr_route_req req; memset(&req, 0, sizeof(req)); - req.h_op = SANDESH_OP_ADD; + req.h_op = op; req.rtr_rid = router_id; req.rtr_vrf_id = vrf; req.rtr_family = family; - req.rtr_prefix = prefix; - req.rtr_prefix_size = RT_IP_ADDR_SIZE(family); - req.rtr_prefix_len = prefix_len; + if ((family == AF_INET) || (family == AF_INET6)) { + req.rtr_prefix = prefix; + req.rtr_prefix_size = RT_IP_ADDR_SIZE(family); + req.rtr_prefix_len = prefix_len; + } else if (family == AF_BRIDGE) { + req.rtr_index = VR_BE_INVALID_INDEX; + } + if (mac) { req.rtr_mac = mac; req.rtr_mac_size = VR_ETHER_ALEN; } + req.rtr_replace_plen = replace_len; req.rtr_label_flags = flags; req.rtr_label = label; @@ -620,6 +735,15 @@ vr_send_route_common(struct nl_client *cl, unsigned int op, return vr_sendmsg(cl, &req, "vr_route_req"); } +int +vr_send_route_get(struct nl_client *cl, + unsigned int router_id, unsigned int vrf, unsigned int family, + uint8_t *prefix, unsigned int prefix_len, uint8_t *mac) +{ + return vr_send_route_common(cl, SANDESH_OP_GET, router_id, vrf, + family, prefix, prefix_len, 0, 0, mac, 0, 0); +} + int vr_send_route_delete(struct nl_client *cl, unsigned int router_id, unsigned int vrf, unsigned int family, diff --git a/utils/vrmemstats.c b/utils/vrmemstats.c index af22d464a..ed7a8d6a8 100644 --- a/utils/vrmemstats.c +++ b/utils/vrmemstats.c @@ -135,6 +135,8 @@ vr_mem_stats_req_process(void *s_req) stats->vms_nexthop_req_object); printf("Route Table %" PRIu64 "\n", stats->vms_route_table_object); + printf("Route Request MAC object %" PRIu64 "\n", + stats->vms_route_req_mac_object); printf("Timer %" PRIu64 "\n", stats->vms_timer_object); printf("Usock %" PRIu64 "\n",