Skip to content

Commit

Permalink
The following changes are made to support flow-lookup for IPv6.
Browse files Browse the repository at this point in the history
1.  Change vr_flow Sandesh message to include family (AF_INET/AF_INET6) and <list> for IP addresses (instead of uint32 for SrcIP and DstIP). The list of IP address will pack both SrcIP and Dst IP (8 bytes for IPv4 and 32 bytes for IPv6, identified by the family field .
2. Defined a 'union' to describe how the flow entry looks for V4 and V6.
3. Added flow_key data structure for V6 addresses. Changed order of fields in flow_key (moved IP addresses to the end), added #defines to access generic/V4/V6 fileds in the flow_key
4. Updated hash/lookup logic to use different key size based on key_family.
5. Other related changes in dp-core and utils

Change-Id: I0147c54b8e5a8f5a046a097a39581c899fa6f972
Closes-bug: 1398625
  • Loading branch information
prabix76 committed Mar 30, 2015
1 parent b0e7389 commit c387561
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 98 deletions.
92 changes: 54 additions & 38 deletions dp-core/vr_flow.c
Expand Up @@ -201,7 +201,7 @@ vr_reset_flow_entry(struct vrouter *router, struct vr_flow_entry *fe,
{
memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
memset(&fe->fe_hold_list, 0, sizeof(fe->fe_hold_list));;
fe->fe_key.key_len = 0;
fe->fe_key.flow_key_len = 0;
fe->fe_type = VP_TYPE_NULL;
memset(&fe->fe_key, 0, sizeof(fe->fe_key));

Expand Down Expand Up @@ -334,7 +334,7 @@ vr_find_free_entry(struct vrouter *router, struct vr_flow *key, uint8_t type,

*fe_index = 0;

hash = vr_hash(key, key->key_len, 0);
hash = vr_hash(key, key->flow_key_len, 0);

index = (hash % vr_flow_entries) & ~(VR_FLOW_ENTRIES_PER_BUCKET - 1);
for (i = 0; i < VR_FLOW_ENTRIES_PER_BUCKET; i++) {
Expand Down Expand Up @@ -381,8 +381,8 @@ vr_find_free_entry(struct vrouter *router, struct vr_flow *key, uint8_t type,

if (fe) {
fe->fe_type = type;
fe->fe_key.key_len = key->key_len;
memcpy(&fe->fe_key, key, key->key_len);
fe->fe_key.flow_key_len = key->flow_key_len;
memcpy(&fe->fe_key, key, key->flow_key_len);
}
}

Expand Down Expand Up @@ -411,7 +411,7 @@ vr_flow_table_lookup(struct vr_flow *key, uint16_t type,
if (flow_e &&
(flow_e->fe_flags & VR_FLOW_FLAG_ACTIVE) &&
(flow_e->fe_type == type)) {
if (!memcmp(&flow_e->fe_key, key, key->key_len)) {
if (!memcmp(&flow_e->fe_key, key, key->flow_key_len)) {
*fe_index = (hash + i) % table_size;
return flow_e;
}
Expand All @@ -429,7 +429,7 @@ vr_find_flow(struct vrouter *router, struct vr_flow *key,
unsigned int hash;
struct vr_flow_entry *flow_e;

hash = vr_hash(key, key->key_len, 0);
hash = vr_hash(key, key->flow_key_len, 0);

/* first look in the regular flow table */
flow_e = vr_flow_table_lookup(key, type, router->vr_flow_table,
Expand Down Expand Up @@ -642,8 +642,8 @@ vr_trap_flow(struct vrouter *router, struct vr_flow_entry *fe,
default:
trap_reason = AGENT_TRAP_FLOW_MISS;
ta.vfta_index = index;
if (fe->fe_type == VP_TYPE_IP)
ta.vfta_nh_index = fe->fe_key.flow4_nh_id;
if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6))
ta.vfta_nh_index = fe->fe_key.flow_nh_id;
break;
}

Expand Down Expand Up @@ -783,18 +783,30 @@ __vr_flow_forward(flow_result_t result, struct vr_packet *pkt,
return forward;
}

static flow_result_t
__vr_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
struct vr_forwarding_md *fmd)
{
flow_result_t result = FLOW_FORWARD;

/* Flow processig is only for untagged unicast IP packets */
if (pkt->vp_type == VP_TYPE_IP)
result = vr_inet_flow_lookup(router, pkt, fmd);
else if (pkt->vp_type == VP_TYPE_IP6)
result = vr_inet6_flow_lookup(router, pkt, fmd);

return result;
}

bool
vr_flow_forward(struct vrouter *router, struct vr_packet *pkt,
struct vr_forwarding_md *fmd)
{
flow_result_t result;
flow_result_t result = FLOW_FORWARD;

/* Flow processig is only for untagged unicast IP packets */
if ((pkt->vp_type == VP_TYPE_IP) && (!(pkt->vp_flags & VP_FLAG_MULTICAST))
if ((!(pkt->vp_flags & VP_FLAG_MULTICAST))
&& ((fmd->fmd_vlan == VLAN_ID_INVALID) || vif_is_service(pkt->vp_if)))
result = vr_inet_flow_lookup(router, pkt, fmd);
else
result = FLOW_FORWARD;
result = __vr_flow_lookup(router, pkt, fmd);

return __vr_flow_forward(result, pkt, fmd);
}
Expand Down Expand Up @@ -988,10 +1000,15 @@ vr_add_flow_req(vr_flow_req *req, unsigned int *fe_index)
struct vr_flow key;
struct vr_flow_entry *fe;

vr_inet_fill_flow(&key, req->fr_flow_nh_id, req->fr_flow_sip,
req->fr_flow_dip, req->fr_flow_proto,
req->fr_flow_sport, req->fr_flow_dport);
type = VP_TYPE_IP;
if (req->fr_family == AF_INET6) {
type = VP_TYPE_IP6;
vr_inet6_fill_flow(&key, req->fr_flow_nh_id, req->fr_flow_ip,
req->fr_flow_proto, req->fr_flow_sport, req->fr_flow_dport);
} else {
type = VP_TYPE_IP;
vr_inet_fill_flow(&key, req->fr_flow_nh_id, req->fr_flow_ip,
req->fr_flow_proto, req->fr_flow_sport, req->fr_flow_dport);
}

if (req->fr_action == VR_FLOW_ACTION_HOLD)
need_hold_queue = true;
Expand All @@ -1014,13 +1031,13 @@ vr_flow_req_is_invalid(struct vrouter *router, vr_flow_req *req,
struct vr_flow_entry *rfe;

if (fe) {
if (fe->fe_type == VP_TYPE_IP) {
if ((unsigned int)req->fr_flow_sip != fe->fe_key.flow4_sip ||
(unsigned int)req->fr_flow_dip != fe->fe_key.flow4_dip ||
(unsigned short)req->fr_flow_sport != fe->fe_key.flow4_sport ||
(unsigned short)req->fr_flow_dport != fe->fe_key.flow4_dport||
(unsigned short)req->fr_flow_nh_id != fe->fe_key.flow4_nh_id ||
(unsigned char)req->fr_flow_proto != fe->fe_key.flow4_proto) {
if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6)) {
if (memcmp(req->fr_flow_ip, fe->fe_key.flow_ip,
2 * VR_FLOW_IP_ADDR_SIZE(fe->fe_type)) ||
(unsigned short)req->fr_flow_sport != fe->fe_key.flow_sport ||
(unsigned short)req->fr_flow_dport != fe->fe_key.flow_dport||
(unsigned short)req->fr_flow_nh_id != fe->fe_key.flow_nh_id ||
(unsigned char)req->fr_flow_proto != fe->fe_key.flow_proto) {
return -EBADF;
}
}
Expand Down Expand Up @@ -1086,8 +1103,8 @@ vr_flow_delete(struct vrouter *router, vr_flow_req *req,
struct vr_flow_entry *fe)
{
if (fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL)
vr_clear_link_local_port(router, AF_INET, fe->fe_key.flow4_proto,
ntohs(fe->fe_key.flow4_dport));
vr_clear_link_local_port(router, AF_INET, fe->fe_key.flow_proto,
ntohs(fe->fe_key.flow_dport));

fe->fe_action = VR_FLOW_ACTION_DROP;
vr_flow_reset_mirror(router, fe, req->fr_index);
Expand All @@ -1098,7 +1115,7 @@ vr_flow_delete(struct vrouter *router, vr_flow_req *req,
static void
vr_flow_udp_src_port (struct vrouter *router, struct vr_flow_entry *fe)
{
uint32_t hash_key[5], hashval, port_range;
uint32_t hash_key[10], hashval, port_range, hash_len;
uint16_t port;

if (fe->fe_udp_src_port)
Expand All @@ -1109,13 +1126,12 @@ vr_flow_udp_src_port (struct vrouter *router, struct vr_flow_entry *fe)
hashrnd_inited = 1;
}

hash_key[0] = fe->fe_key.flow4_sip;
hash_key[1] = fe->fe_key.flow4_dip;
hash_key[2] = fe->fe_vrf;
hash_key[3] = fe->fe_key.flow4_sport;
hash_key[4] = fe->fe_key.flow4_dport;
hash_key[0] = fe->fe_vrf;
hash_key[1] = (fe->fe_key.flow_sport << 16) | fe->fe_key.flow_dport;
memcpy(&hash_key[2], fe->fe_key.flow_ip, 2*VR_FLOW_IP_ADDR_SIZE(fe->fe_type));
hash_len = VR_FLOW_KEY_SIZE(fe->fe_type);

hashval = jhash(hash_key, 20, vr_hashrnd);
hashval = jhash(hash_key, hash_len, vr_hashrnd);
port_range = VR_MUDP_PORT_RANGE_END - VR_MUDP_PORT_RANGE_START;
port = (uint16_t ) (((uint64_t ) hashval * port_range) >> 32);

Expand Down Expand Up @@ -1198,13 +1214,13 @@ vr_flow_set(struct vrouter *router, vr_flow_req *req)
if (req->fr_flags & VR_FLOW_FLAG_LINK_LOCAL) {
if (!(fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL))
vr_set_link_local_port(router, AF_INET,
fe->fe_key.flow4_proto,
ntohs(fe->fe_key.flow4_dport));
fe->fe_key.flow_proto,
ntohs(fe->fe_key.flow_dport));
} else {
if (fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL)
vr_clear_link_local_port(router, AF_INET,
fe->fe_key.flow4_proto,
ntohs(fe->fe_key.flow4_dport));
fe->fe_key.flow_proto,
ntohs(fe->fe_key.flow_dport));
}
}

Expand Down
14 changes: 5 additions & 9 deletions dp-core/vr_nexthop.c
Expand Up @@ -340,11 +340,9 @@ nh_vxlan_tunnel_helper(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
udp_src_port = fmd->fmd_udp_src_port;

/*
* The UDP source port is a hash of the inner headers. For IPV6
* the standard port is used till flow processing is done
* The UDP source port is a hash of the inner headers
*/
if ((!fmd->fmd_udp_src_port) && (pkt->vp_type != VP_TYPE_IP6) &&
vr_get_udp_src_port) {
if ((!fmd->fmd_udp_src_port) && vr_get_udp_src_port) {
udp_src_port = vr_get_udp_src_port(pkt, fmd, fmd->fmd_dvrf);
if (udp_src_port == 0) {
return false;
Expand Down Expand Up @@ -1359,11 +1357,9 @@ nh_mpls_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,

/*
* The UDP source port is a hash of the inner IP src/dst address and
* vrf. For the IPV6 standard source port is used till flow
* procesing is done
* vrf.
*/
if ((!fmd->fmd_udp_src_port) && (pkt->vp_type != VP_TYPE_IP6) &&
vr_get_udp_src_port) {
if ((!fmd->fmd_udp_src_port) && vr_get_udp_src_port) {
udp_src_port = vr_get_udp_src_port(pkt, fmd, fmd->fmd_dvrf);
if (udp_src_port == 0) {
reason = VP_DROP_PULL;
Expand Down Expand Up @@ -1618,7 +1614,7 @@ nh_output(struct vr_packet *pkt, struct vr_nexthop *nh,
return 0;
}

if (pkt->vp_type == VP_TYPE_IP) {
if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
/*
* If the packet has not gone through flow lookup once
* (!VP_FLAG_FLOW_SET), we need to determine whether it has to undergo
Expand Down
17 changes: 8 additions & 9 deletions dp-core/vr_proto_ip.c
Expand Up @@ -763,7 +763,7 @@ vr_inet_flow_swap(struct vr_flow *key_p)
return;
}

static unsigned short
unsigned short
vr_inet_flow_nexthop(struct vr_packet *pkt, unsigned short vlan)
{
unsigned short nh_id;
Expand All @@ -785,19 +785,18 @@ vr_inet_flow_nexthop(struct vr_packet *pkt, unsigned short vlan)
}

void
vr_inet_fill_flow(struct vr_flow *flow_p, unsigned short nh_id,
uint32_t sip, uint32_t dip, uint8_t proto,
uint16_t sport, uint16_t dport)
vr_inet_fill_flow(struct vr_flow *flow_p, unsigned short nh_id,
unsigned char *ip, uint8_t proto, uint16_t sport, uint16_t dport)
{
/* copy both source and destinations */
flow_p->flow4_sip = sip;
flow_p->flow4_dip = dip;
memcpy(flow_p->flow_ip, ip, 2*VR_FLOW_IPV4_ADDR_SIZE);
flow_p->flow4_proto = proto;
flow_p->flow4_nh_id = nh_id;
flow_p->flow4_sport = sport;
flow_p->flow4_dport = dport;
flow_p->flow4_family = AF_INET;

flow_p->key_len = sizeof(struct vr_inet_flow);
flow_p->flow_key_len = VR_FLOW_IPV4_KEY_SIZE;

return;
}
Expand All @@ -823,7 +822,7 @@ vr_inet_fragment_flow(struct vrouter *router, unsigned short vrf,
vr_fragment_del(frag);

nh_id = vr_inet_flow_nexthop(pkt, vlan);
vr_inet_fill_flow(flow_p, nh_id, ip->ip_saddr, ip->ip_daddr,
vr_inet_fill_flow(flow_p, nh_id, (unsigned char *)&ip->ip_saddr,
ip->ip_proto, sport, dport);
return 0;
}
Expand Down Expand Up @@ -863,7 +862,7 @@ vr_inet_proto_flow(struct vrouter *router, unsigned short vrf,
}

nh_id = vr_inet_flow_nexthop(pkt, vlan);
vr_inet_fill_flow(flow_p, nh_id, ip->ip_saddr, ip->ip_daddr,
vr_inet_fill_flow(flow_p, nh_id, (unsigned char *)&ip->ip_saddr,
ip->ip_proto, sport, dport);

return 0;
Expand Down
93 changes: 93 additions & 0 deletions dp-core/vr_proto_ip6.c
Expand Up @@ -116,6 +116,99 @@ vr_icmp6_input(struct vrouter *router, struct vr_packet *pkt,
return handled;
}

void
vr_inet6_fill_flow(struct vr_flow *flow_p, unsigned short nh_id,
unsigned char *ip, uint8_t proto, uint16_t sport, uint16_t dport)
{
/* copy both source and destinations */
memcpy(flow_p->flow_ip, ip, 2*VR_FLOW_IPV6_ADDR_SIZE);
flow_p->flow6_proto = proto;
flow_p->flow6_nh_id = nh_id;
flow_p->flow6_sport = sport;
flow_p->flow6_dport = dport;
flow_p->flow6_family = AF_INET6;

flow_p->flow_key_len = VR_FLOW_IPV6_KEY_SIZE;

return;
}

static int
vr_inet6_form_flow(struct vrouter *router, unsigned short vrf,
struct vr_packet *pkt, uint16_t vlan, struct vr_ip6 *ip6,
struct vr_flow *flow_p)
{
unsigned short *t_hdr, sport, dport;
unsigned short nh_id;

struct vr_icmp *icmph;

/* Skip flow lookup for V6 frags */
if (ip6->ip6_nxt == VR_IP6_PROTO_FRAG)
return 1;

t_hdr = (unsigned short *)((char *)ip6 + sizeof(struct vr_ip6));
if (ip6->ip6_nxt == VR_IP_PROTO_ICMP6) {
icmph = (struct vr_icmp *)t_hdr;
if ((icmph->icmp_type == VR_ICMP6_TYPE_ECHO_REQ) ||
(icmph->icmp_type == VR_ICMP6_TYPE_ECHO_REPLY)) {
sport = icmph->icmp_eid;
dport = ntohs(VR_ICMP6_TYPE_ECHO_REPLY);
} else {
sport = 0;
dport = icmph->icmp_type;
}
} else {
sport = *t_hdr;
dport = *(t_hdr + 1);
}

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);

return 0;
}

flow_result_t
vr_inet6_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
struct vr_forwarding_md *fmd)
{
int ret;
bool lookup = false;
struct vr_flow flow, *flow_p = &flow;
struct vr_ip6 *ip6 = (struct vr_ip6 *)pkt_network_header(pkt);

/*
* if the packet has already done one round of flow lookup, there
* is no point in doing it again, eh?
*/
if (pkt->vp_flags & VP_FLAG_FLOW_SET)
return FLOW_FORWARD;

ret = vr_inet6_form_flow(router, fmd->fmd_dvrf, pkt, fmd->fmd_vlan, ip6, flow_p);
if (ret < 0)
return FLOW_CONSUMED;

/*
* if the interface is policy enabled, or if somebody else (eg:nexthop)
* has requested for a policy lookup, packet has to go through a lookup
*/
if ((pkt->vp_if->vif_flags & VIF_FLAG_POLICY_ENABLED) ||
(pkt->vp_flags & VP_FLAG_FLOW_GET)) {
lookup = true;
}


if (lookup) {

return vr_flow_lookup(router, flow_p, pkt, fmd);
}

return FLOW_FORWARD;
}


int
vr_ip6_input(struct vrouter *router, struct vr_packet *pkt,
struct vr_forwarding_md *fmd)
Expand Down

0 comments on commit c387561

Please sign in to comment.