Skip to content

Commit

Permalink
Do a route table lookup post vrf translation
Browse files Browse the repository at this point in the history
In the most common packet path, a route lookup always happens after
flow lookup. But there can be cases when a flow lookup happens post
a route table lookup. In such cases, if a translation happens, then
the destination ip should be looked up in the new route table.
Exception to this case is when packets come from fabric where the
label already points to the destination nexthop and no further lookup
is needed (which is what happens today).

Change-Id: If2191dc73b9764107900119cffa4eabbfc23c899
Closes-Bug: #1435746
  • Loading branch information
anandhk-juniper committed Mar 27, 2015
1 parent 51b96de commit b6a64ec
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 39 deletions.
9 changes: 8 additions & 1 deletion dp-core/vr_datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,15 @@ vr_reinject_packet(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
struct vr_interface *vif = pkt->vp_if;
int handled;

if (pkt->vp_nh)
if (pkt->vp_nh) {
/* If nexthop does not have valid data, drop it */
if (!(pkt->vp_nh->nh_flags & NH_FLAG_VALID)) {
vr_pfree(pkt, VP_DROP_INVALID_NH);
return 0;
}

return pkt->vp_nh->nh_reach_nh(pkt, pkt->vp_nh, fmd);
}

if (vif_is_vhost(vif)) {
handled = vr_l3_input(pkt, fmd);
Expand Down
27 changes: 18 additions & 9 deletions dp-core/vr_nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
extern bool vr_has_to_fragment(struct vr_interface *, struct vr_packet *,
unsigned int);
extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short, unsigned int);
extern struct vr_nexthop *vr_inet6_sip_lookup(unsigned short, uint8_t *);
extern struct vr_nexthop *vr_inet_sip_lookup(unsigned short, uint32_t);
extern struct vr_nexthop *vr_inet_src_lookup(unsigned short ,
struct vr_ip *, struct vr_packet *);
extern struct vr_nexthop *vr_inet6_ip_lookup(unsigned short, uint8_t *);
extern struct vr_nexthop *vr_inet_ip_lookup(unsigned short, uint32_t);
extern struct vr_nexthop *vr_inet_src_lookup(unsigned short,
struct vr_packet *);
extern l4_pkt_type_t vr_ip6_well_known_packet(struct vr_packet *);
extern l4_pkt_type_t vr_ip_well_known_packet(struct vr_packet *);

Expand Down Expand Up @@ -659,7 +659,7 @@ nh_composite_mcast_l2(struct vr_packet *pkt, struct vr_nexthop *nh,

if (pkt_src) {
sarp = (struct vr_arp *)pkt_data(pkt);
src_nh = vr_inet_sip_lookup(fmd->fmd_dvrf, sarp->arp_spa);
src_nh = vr_inet_ip_lookup(fmd->fmd_dvrf, sarp->arp_spa);
if (vr_gateway_nexthop(src_nh)) {
flood_to_vms = false;
}
Expand Down Expand Up @@ -713,7 +713,7 @@ nh_composite_mcast_l2(struct vr_packet *pkt, struct vr_nexthop *nh,

if (pkt_src) {
ip6 = (struct vr_ip6 *)pkt_data(pkt);
src_nh = vr_inet6_sip_lookup(fmd->fmd_dvrf, ip6->ip6_src);
src_nh = vr_inet6_ip_lookup(fmd->fmd_dvrf, ip6->ip6_src);
if (vr_gateway_nexthop(src_nh)) {
flood_to_vms = false;
}
Expand Down Expand Up @@ -1604,7 +1604,6 @@ nh_output(struct vr_packet *pkt, struct vr_nexthop *nh,
struct vr_forwarding_md *fmd)
{
struct vr_nexthop *src_nh = NULL;
struct vr_ip *ip;
bool need_flow_lookup = false;

if (!pkt->vp_ttl) {
Expand Down Expand Up @@ -1634,26 +1633,36 @@ nh_output(struct vr_packet *pkt, struct vr_nexthop *nh,
* Typical example for this situation is when the packet reaches the
* target VM's server from an ECMP-ed service chain.
*/
ip = (struct vr_ip *)pkt_network_header(pkt);
if (!(pkt->vp_flags & VP_FLAG_FLOW_SET)) {
if (nh->nh_flags & NH_FLAG_POLICY_ENABLED) {
need_flow_lookup = true;
} else {
src_nh = vr_inet_src_lookup(fmd->fmd_dvrf, ip, pkt);
src_nh = vr_inet_src_lookup(fmd->fmd_dvrf, pkt);
if (src_nh && src_nh->nh_type == NH_COMPOSITE &&
src_nh->nh_flags & NH_FLAG_COMPOSITE_ECMP) {
need_flow_lookup = true;
}
}

if (need_flow_lookup) {
pkt->vp_flags |= VP_FLAG_FLOW_GET;
/*
* after vr_flow_forward returns, pkt->vp_nh could have changed
* since in NAT cases the new destination should have been
* looked up.
*/
if (!vr_flow_forward(nh->nh_router, pkt, fmd))
return 0;

/* pkt->vp_nh could have changed after vr_flow_forward */
if (!pkt->vp_nh) {
vr_pfree(pkt, VP_DROP_INVALID_NH);
return 0;
}

if (nh != pkt->vp_nh) {
return nh_output(pkt, pkt->vp_nh, fmd);
}
}
}
}
Expand Down
49 changes: 20 additions & 29 deletions dp-core/vr_proto_ip.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
#include "vr_bridge.h"

static unsigned short vr_ip_id;
extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short,
unsigned int);

extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short, unsigned int);
extern struct vr_nexthop *vr_inet6_ip_lookup(unsigned short, uint8_t *);

unsigned short
vr_generate_unique_ip_id()
Expand All @@ -30,34 +31,15 @@ vr_generate_unique_ip_id()
}

struct vr_nexthop *
vr_inet6_sip_lookup(unsigned short vrf, uint8_t *sip6)
{
uint32_t rt_prefix[4];

struct vr_route_req rt;

rt.rtr_req.rtr_vrf_id = vrf;
rt.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
memcpy(rt.rtr_req.rtr_prefix, sip6, 16);
rt.rtr_req.rtr_prefix_size = 16;
rt.rtr_req.rtr_prefix_len = IP6_PREFIX_LEN;
rt.rtr_req.rtr_family = AF_INET6;
rt.rtr_req.rtr_marker_size = 0;
rt.rtr_req.rtr_nh_id = 0;

return vr_inet_route_lookup(vrf, &rt);
}

struct vr_nexthop *
vr_inet_sip_lookup(unsigned short vrf, uint32_t sip)
vr_inet_ip_lookup(unsigned short vrf, uint32_t ip)
{
uint32_t rt_prefix;

struct vr_route_req rt;

rt.rtr_req.rtr_vrf_id = vrf;
rt.rtr_req.rtr_prefix = (uint8_t *)&rt_prefix;
*(uint32_t*)rt.rtr_req.rtr_prefix = sip;
*(uint32_t*)rt.rtr_req.rtr_prefix = ip;
rt.rtr_req.rtr_prefix_size = 4;
rt.rtr_req.rtr_prefix_len = IP4_PREFIX_LEN;
rt.rtr_req.rtr_family = AF_INET;
Expand All @@ -68,18 +50,26 @@ vr_inet_sip_lookup(unsigned short vrf, uint32_t sip)
}

struct vr_nexthop *
vr_inet_src_lookup(unsigned short vrf, struct vr_ip *ip, struct vr_packet *pkt)
vr_inet_src_lookup(unsigned short vrf, struct vr_packet *pkt)
{
struct vr_ip *ip;
struct vr_ip6 *ip6;

if (!ip || !pkt)
if (!pkt)
return NULL;

if (pkt->vp_type == VP_TYPE_IP) {
return vr_inet_sip_lookup(vrf, ip->ip_saddr);
ip = (struct vr_ip *)pkt_network_header(pkt);
if (!ip)
return NULL;

return vr_inet_ip_lookup(vrf, ip->ip_saddr);
} else if (pkt->vp_type == VP_TYPE_IP6) {
ip6 = (struct vr_ip6 *)pkt_data(pkt);
return vr_inet6_sip_lookup(vrf, ip6->ip6_src);
ip6 = (struct vr_ip6 *)pkt_network_header(pkt);
if (!ip6)
return NULL;

return vr_inet6_ip_lookup(vrf, ip6->ip6_src);
}

return NULL;
Expand Down Expand Up @@ -745,7 +735,8 @@ vr_inet_flow_nat(struct vr_flow_entry *fe, struct vr_packet *pkt,

if ((fe->fe_flags & VR_FLOW_FLAG_VRFT) &&
pkt->vp_nh && pkt->vp_nh->nh_vrf != fmd->fmd_dvrf) {
pkt->vp_nh = NULL;
/* only if pkt->vp_nh was set before... */
pkt->vp_nh = vr_inet_ip_lookup(fmd->fmd_dvrf, ip->ip_daddr);
}

return FLOW_FORWARD;
Expand Down
19 changes: 19 additions & 0 deletions dp-core/vr_proto_ip6.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@
#include <vr_ip_mtrie.h>
#include <vr_bridge.h>

struct vr_nexthop *
vr_inet6_ip_lookup(unsigned short vrf, uint8_t *ip6)
{
uint32_t rt_prefix[4];

struct vr_route_req rt;

rt.rtr_req.rtr_vrf_id = vrf;
rt.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
memcpy(rt.rtr_req.rtr_prefix, ip6, 16);
rt.rtr_req.rtr_prefix_size = 16;
rt.rtr_req.rtr_prefix_len = IP6_PREFIX_LEN;
rt.rtr_req.rtr_family = AF_INET6;
rt.rtr_req.rtr_marker_size = 0;
rt.rtr_req.rtr_nh_id = 0;

return vr_inet_route_lookup(vrf, &rt);
}

static int
vr_v6_prefix_is_ll(uint8_t prefix[])
{
Expand Down

0 comments on commit b6a64ec

Please sign in to comment.