diff options
Diffstat (limited to 'src/vnet/handoff.h')
-rw-r--r-- | src/vnet/handoff.h | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/src/vnet/handoff.h b/src/vnet/handoff.h new file mode 100644 index 00000000000..815206a9f8c --- /dev/null +++ b/src/vnet/handoff.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef included_vnet_handoff_h +#define included_vnet_handoff_h + +#include <vlib/vlib.h> +#include <vnet/ethernet/ethernet.h> +#include <vnet/ip/ip4_packet.h> +#include <vnet/ip/ip6_packet.h> +#include <vnet/mpls/packet.h> + +typedef enum +{ + HANDOFF_DISPATCH_NEXT_IP4_INPUT, + HANDOFF_DISPATCH_NEXT_IP6_INPUT, + HANDOFF_DISPATCH_NEXT_MPLS_INPUT, + HANDOFF_DISPATCH_NEXT_ETHERNET_INPUT, + HANDOFF_DISPATCH_NEXT_DROP, + HANDOFF_DISPATCH_N_NEXT, +} handoff_dispatch_next_t; + + +static inline u64 +ipv4_get_key (ip4_header_t * ip) +{ + u64 hash_key; + + hash_key = *((u64 *) (&ip->address_pair)) ^ ip->protocol; + + return hash_key; +} + +static inline u64 +ipv6_get_key (ip6_header_t * ip) +{ + u64 hash_key; + + hash_key = ip->src_address.as_u64[0] ^ + rotate_left (ip->src_address.as_u64[1], 13) ^ + rotate_left (ip->dst_address.as_u64[0], 26) ^ + rotate_left (ip->dst_address.as_u64[1], 39) ^ ip->protocol; + + return hash_key; +} + +#define MPLS_BOTTOM_OF_STACK_BIT_MASK 0x00000100U +#define MPLS_LABEL_MASK 0xFFFFF000U + +static inline u64 +mpls_get_key (mpls_unicast_header_t * m) +{ + u64 hash_key; + u8 ip_ver; + + + /* find the bottom of the MPLS label stack. */ + if (PREDICT_TRUE (m->label_exp_s_ttl & + clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))) + { + goto bottom_lbl_found; + } + m++; + + if (PREDICT_TRUE (m->label_exp_s_ttl & + clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))) + { + goto bottom_lbl_found; + } + m++; + + if (m->label_exp_s_ttl & + clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)) + { + goto bottom_lbl_found; + } + m++; + + if (m->label_exp_s_ttl & + clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)) + { + goto bottom_lbl_found; + } + m++; + + if (m->label_exp_s_ttl & + clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)) + { + goto bottom_lbl_found; + } + + /* the bottom label was not found - use the last label */ + hash_key = m->label_exp_s_ttl & clib_net_to_host_u32 (MPLS_LABEL_MASK); + + return hash_key; + +bottom_lbl_found: + m++; + ip_ver = (*((u8 *) m) >> 4); + + /* find out if it is IPV4 or IPV6 header */ + if (PREDICT_TRUE (ip_ver == 4)) + { + hash_key = ipv4_get_key ((ip4_header_t *) m); + } + else if (PREDICT_TRUE (ip_ver == 6)) + { + hash_key = ipv6_get_key ((ip6_header_t *) m); + } + else + { + /* use the bottom label */ + hash_key = + (m - 1)->label_exp_s_ttl & clib_net_to_host_u32 (MPLS_LABEL_MASK); + } + + return hash_key; + +} + +static inline u64 +eth_get_sym_key (ethernet_header_t * h0) +{ + u64 hash_key; + + if (PREDICT_TRUE (h0->type) == clib_host_to_net_u16 (ETHERNET_TYPE_IP4)) + { + ip4_header_t *ip = (ip4_header_t *) (h0 + 1); + hash_key = + (u64) (ip->src_address.as_u32 ^ + ip->dst_address.as_u32 ^ ip->protocol); + } + else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6)) + { + ip6_header_t *ip = (ip6_header_t *) (h0 + 1); + hash_key = (u64) (ip->src_address.as_u64[0] ^ + ip->src_address.as_u64[1] ^ + ip->dst_address.as_u64[0] ^ + ip->dst_address.as_u64[1] ^ ip->protocol); + } + else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST)) + { + hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1)); + } + else + if (PREDICT_FALSE + ((h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) + || (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD)))) + { + ethernet_vlan_header_t *outer = (ethernet_vlan_header_t *) (h0 + 1); + + outer = (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ? + outer + 1 : outer; + if (PREDICT_TRUE (outer->type) == + clib_host_to_net_u16 (ETHERNET_TYPE_IP4)) + { + ip4_header_t *ip = (ip4_header_t *) (outer + 1); + hash_key = + (u64) (ip->src_address.as_u32 ^ + ip->dst_address.as_u32 ^ ip->protocol); + } + else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6)) + { + ip6_header_t *ip = (ip6_header_t *) (outer + 1); + hash_key = + (u64) (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1] ^ + ip->dst_address.as_u64[0] ^ + ip->dst_address.as_u64[1] ^ ip->protocol); + } + else if (outer->type == + clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST)) + { + hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1)); + } + else + { + hash_key = outer->type; + } + } + else + { + hash_key = 0; + } + + return hash_key; +} + +static inline u64 +eth_get_key (ethernet_header_t * h0) +{ + u64 hash_key; + + if (PREDICT_TRUE (h0->type) == clib_host_to_net_u16 (ETHERNET_TYPE_IP4)) + { + hash_key = ipv4_get_key ((ip4_header_t *) (h0 + 1)); + } + else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6)) + { + hash_key = ipv6_get_key ((ip6_header_t *) (h0 + 1)); + } + else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST)) + { + hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1)); + } + else if ((h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) || + (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD))) + { + ethernet_vlan_header_t *outer = (ethernet_vlan_header_t *) (h0 + 1); + + outer = (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ? + outer + 1 : outer; + if (PREDICT_TRUE (outer->type) == + clib_host_to_net_u16 (ETHERNET_TYPE_IP4)) + { + hash_key = ipv4_get_key ((ip4_header_t *) (outer + 1)); + } + else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6)) + { + hash_key = ipv6_get_key ((ip6_header_t *) (outer + 1)); + } + else if (outer->type == + clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST)) + { + hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1)); + } + else + { + hash_key = outer->type; + } + } + else + { + hash_key = 0; + } + + return hash_key; +} + +#endif /* included_vnet_handoff_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |