Skip to content

Commit

Permalink
'GET' option for 'rt' command
Browse files Browse the repository at this point in the history
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
  • Loading branch information
anandhk-juniper committed Mar 16, 2016
1 parent dcc9184 commit 91e2d3a
Show file tree
Hide file tree
Showing 9 changed files with 417 additions and 180 deletions.
4 changes: 3 additions & 1 deletion dp-core/vr_bridge.c
Expand Up @@ -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;
}
Expand Down
140 changes: 99 additions & 41 deletions dp-core/vr_ip_mtrie.c
Expand Up @@ -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.
Expand All @@ -883,36 +952,22 @@ 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;
return default_nh;
}

ent = &table->root;

ptr = ent->entry_long_i;
if (!ptr) {
rt->rtr_nh = default_nh;
Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
28 changes: 24 additions & 4 deletions dp-core/vr_route.c
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
}

Expand Down
6 changes: 6 additions & 0 deletions include/nl_util.h
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion include/vrouter.h
Expand Up @@ -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;

Expand Down

0 comments on commit 91e2d3a

Please sign in to comment.