From a91cb45909642978592c7e21a8f6d2da2e44e506 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 4 Feb 2021 11:02:52 +0000 Subject: [PATCH] tunnel: support copying TTL and flow label from inner to outer Type: feature The added functionality is to support copying TTL and flow label from inner to outer. The .api was extened to support expressing this and also adding a common tunnel endpoint type. i find it best to make API changes in one patch so there are less versions of the API. Signed-off-by: Neale Ranns Change-Id: I755c1e3f4c475058792af39c1abeda92129efb76 --- src/vnet/gre/gre.c | 2 +- src/vnet/ip/ip4_packet.h | 12 +++ src/vnet/ip/ip6_packet.h | 39 ++++++-- src/vnet/ipip/ipip.c | 5 +- src/vnet/ipsec/esp_encrypt.c | 9 +- src/vnet/tunnel/tunnel.c | 189 ++++++++++++++++++++++++++++++++++++- src/vnet/tunnel/tunnel.h | 89 ++++++++++++++--- src/vnet/tunnel/tunnel_dp.h | 67 ++++++++----- src/vnet/tunnel/tunnel_types.api | 44 ++++++++- src/vnet/tunnel/tunnel_types_api.c | 82 +++++++++++++++- src/vnet/tunnel/tunnel_types_api.h | 6 ++ 11 files changed, 488 insertions(+), 56 deletions(-) diff --git a/src/vnet/gre/gre.c b/src/vnet/gre/gre.c index d842d688603..a355a224ee1 100644 --- a/src/vnet/gre/gre.c +++ b/src/vnet/gre/gre.c @@ -340,7 +340,7 @@ gre46_fixup (vlib_main_t * vm, ip0->ip6.payload_length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6)); - tunnel_encap_fixup_4o6 (flags, (ip4_header_t *) (ip0 + 1), &ip0->ip6); + tunnel_encap_fixup_4o6 (flags, b0, (ip4_header_t *) (ip0 + 1), &ip0->ip6); } static void diff --git a/src/vnet/ip/ip4_packet.h b/src/vnet/ip/ip4_packet.h index 06530926120..513a7449b54 100644 --- a/src/vnet/ip/ip4_packet.h +++ b/src/vnet/ip/ip4_packet.h @@ -359,6 +359,18 @@ ip4_header_get_ecn (const ip4_header_t * ip4) return (ip4->tos & IP_PACKET_TC_FIELD_ECN_MASK); } +always_inline u8 +ip4_header_get_ttl (const ip4_header_t *ip4) +{ + return (ip4->ttl); +} + +always_inline void +ip4_header_set_ttl (ip4_header_t *ip4, u8 ttl) +{ + ip4->ttl = ttl; +} + always_inline void ip4_header_set_df (ip4_header_t * ip4) { diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h index 1be2ceae5a1..7a8c31cee48 100644 --- a/src/vnet/ip/ip6_packet.h +++ b/src/vnet/ip/ip6_packet.h @@ -343,13 +343,6 @@ ip6_ecn_network_order (const ip6_header_t * ip6) & IP6_PACKET_ECN_MASK) >> 20; } -static_always_inline u32 -ip6_flow_label_network_order (const ip6_header_t *ip6) -{ - return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label) & - IP6_PACKET_FL_MASK); -} - static_always_inline void ip6_set_traffic_class_network_order (ip6_header_t * ip6, ip_dscp_t dscp) { @@ -376,10 +369,40 @@ ip6_set_ecn_network_order (ip6_header_t * ip6, ip_ecn_t ecn) u32 tmp = clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label); tmp &= 0xffcfffff; - tmp |= (ecn << 20); + tmp |= ((0x3 & ecn) << 20); ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp); } +static_always_inline u32 +ip6_flow_label_network_order (const ip6_header_t *ip6) +{ + u32 tmp = + clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label); + return (tmp & 0xfffff); +} + +static_always_inline void +ip6_set_flow_label_network_order (ip6_header_t *ip6, u32 flow_label) +{ + u32 tmp = + clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label); + tmp &= 0xfff00000; + tmp |= flow_label & 0x000fffff; + ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp); +} + +static_always_inline u32 +ip6_hop_limit_network_order (const ip6_header_t *ip6) +{ + return (ip6->hop_limit); +} + +static_always_inline void +ip6_set_hop_limit_network_order (ip6_header_t *ip6, u8 hop_limit) +{ + ip6->hop_limit = hop_limit; +} + always_inline void * ip6_next_header (ip6_header_t * i) { diff --git a/src/vnet/ipip/ipip.c b/src/vnet/ipip/ipip.c index ca52142f5c6..d43bcd1cb53 100644 --- a/src/vnet/ipip/ipip.c +++ b/src/vnet/ipip/ipip.c @@ -184,7 +184,7 @@ ipip46_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b, ip6->payload_length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip6)); - tunnel_encap_fixup_4o6 (flags, ((ip4_header_t *) (ip6 + 1)), ip6); + tunnel_encap_fixup_4o6 (flags, b, ((ip4_header_t *) (ip6 + 1)), ip6); } static void @@ -224,7 +224,8 @@ ipipm6_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b, ip6 = vlib_buffer_get_current (b); ip6->payload_length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip6)); - tunnel_encap_fixup_mplso6 (flags, (mpls_unicast_header_t *) (ip6 + 1), ip6); + tunnel_encap_fixup_mplso6 (flags, b, (mpls_unicast_header_t *) (ip6 + 1), + ip6); } static void diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index f291c08247a..08f82db5d58 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -768,16 +768,15 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, else if (VNET_LINK_IP4 == lt) { *next_hdr_ptr = IP_PROTOCOL_IP_IN_IP; - tunnel_encap_fixup_4o6 (sa0->tunnel_flags, - (const ip4_header_t *) payload, - ip6); + tunnel_encap_fixup_4o6 (sa0->tunnel_flags, b[0], + (const ip4_header_t *) payload, ip6); } else if (VNET_LINK_MPLS == lt) { *next_hdr_ptr = IP_PROTOCOL_MPLS_IN_IP; tunnel_encap_fixup_mplso6 ( - sa0->tunnel_flags, (const mpls_unicast_header_t *) payload, - ip6); + sa0->tunnel_flags, b[0], + (const mpls_unicast_header_t *) payload, ip6); } else ASSERT (0); diff --git a/src/vnet/tunnel/tunnel.c b/src/vnet/tunnel/tunnel.c index 38bde34e7f2..1bd03eb4a1a 100644 --- a/src/vnet/tunnel/tunnel.c +++ b/src/vnet/tunnel/tunnel.c @@ -16,6 +16,21 @@ */ #include +#include +#include + +#include + +const u8 TUNNEL_ENCAP_DECAP_FLAG_MASK = ( +#define _(a, b, c) TUNNEL_ENCAP_DECAP_FLAG_##a | + foreach_tunnel_encap_decap_flag +#undef _ + 0); +const u8 TUNNEL_FLAG_MASK = ( +#define _(a, b, c) TUNNEL_FLAG_##a | + foreach_tunnel_flag +#undef _ + 0); u8 * format_tunnel_mode (u8 * s, va_list * args) @@ -54,10 +69,11 @@ format_tunnel_encap_decap_flags (u8 * s, va_list * args) tunnel_encap_decap_flags_t f = va_arg (*args, int); if (f == TUNNEL_ENCAP_DECAP_FLAG_NONE) - return (format (s, "none")); + s = format (s, "none"); -#define _(a,b,c) if (f & TUNNEL_ENCAP_DECAP_FLAG_##a) s = format(s, "%s ", b); - forech_tunnel_encap_decap_flag +#define _(a, b, c) \ + else if (f & TUNNEL_ENCAP_DECAP_FLAG_##a) s = format (s, "%s ", b); + foreach_tunnel_encap_decap_flag #undef _ return (s); } @@ -71,11 +87,176 @@ unformat_tunnel_encap_decap_flags (unformat_input_t * input, va_list * args) *f |= TUNNEL_ENCAP_DECAP_FLAG_##a;\ return 1;\ } - forech_tunnel_encap_decap_flag; + foreach_tunnel_encap_decap_flag; +#undef _ + return 0; +} + +u8 * +format_tunnel_flags (u8 *s, va_list *args) +{ + tunnel_flags_t f = va_arg (*args, int); + + if (f == TUNNEL_FLAG_NONE) + s = format (s, "none"); + +#define _(a, b, c) else if (f & TUNNEL_FLAG_##a) s = format (s, "%s ", c); + foreach_tunnel_flag +#undef _ + return (s); +} + +uword +unformat_tunnel_flags (unformat_input_t *input, va_list *args) +{ + tunnel_flags_t *f = va_arg (*args, tunnel_flags_t *); +#define _(a, b, c) \ + if (unformat (input, c)) \ + { \ + *f |= TUNNEL_FLAG_##a; \ + return 1; \ + } + foreach_tunnel_flag; #undef _ return 0; } +ip_address_family_t +tunnel_get_af (const tunnel_t *t) +{ + return (ip_addr_version (&t->t_src)); +} + +void +tunnel_copy (const tunnel_t *src, tunnel_t *dst) +{ + ip_address_copy (&dst->t_dst, &src->t_dst); + ip_address_copy (&dst->t_src, &src->t_src); + + dst->t_encap_decap_flags = src->t_encap_decap_flags; + dst->t_flags = src->t_flags; + dst->t_mode = src->t_mode; + dst->t_table_id = src->t_table_id; + dst->t_dscp = src->t_dscp; + dst->t_hop_limit = src->t_hop_limit; + dst->t_fib_index = src->t_fib_index; + + dst->t_flags &= ~TUNNEL_FLAG_RESOLVED; + dst->t_fib_entry_index = FIB_NODE_INDEX_INVALID; + dst->t_sibling = ~0; +} + +u8 * +format_tunnel (u8 *s, va_list *args) +{ + const tunnel_t *t = va_arg (*args, tunnel_t *); + u32 indent = va_arg (*args, u32); + + s = format (s, "%Utable-ID:%d [%U->%U] hop-limit:%d %U %U [%U] [%U]", + format_white_space, indent, t->t_table_id, format_ip_address, + &t->t_src, format_ip_address, &t->t_dst, t->t_hop_limit, + format_tunnel_mode, t->t_mode, format_ip_dscp, t->t_dscp, + format_tunnel_flags, t->t_flags, format_tunnel_encap_decap_flags, + t->t_encap_decap_flags); + if (t->t_flags & TUNNEL_FLAG_RESOLVED) + s = format (s, " [resolved via fib-entry: %d]", t->t_fib_entry_index); + + return (s); +} + +uword +unformat_tunnel (unformat_input_t *input, va_list *args) +{ + tunnel_t *t = va_arg (*args, tunnel_t *); + + if (!unformat (input, "tunnel")) + return (0); + + unformat (input, "src %U", unformat_ip_address, &t->t_src); + unformat (input, "dst %U", unformat_ip_address, &t->t_dst); + unformat (input, "table-id:%d", &t->t_table_id); + unformat (input, "hop-limit:%d", &t->t_hop_limit); + unformat (input, "%U", unformat_ip_dscp, &t->t_dscp); + unformat (input, "%U", unformat_tunnel_encap_decap_flags, + &t->t_encap_decap_flags); + unformat (input, "%U", unformat_tunnel_flags, &t->t_flags); + unformat (input, "%U", unformat_tunnel_mode, &t->t_mode); + + ASSERT (!"Check not 4 and 6"); + + return (1); +} + +int +tunnel_resolve (tunnel_t *t, fib_node_type_t child_type, index_t child_index) +{ + fib_prefix_t pfx; + + ip_address_to_fib_prefix (&t->t_dst, &pfx); + + t->t_fib_index = fib_table_find (pfx.fp_proto, t->t_table_id); + + if (t->t_fib_index == ~((u32) 0)) + return VNET_API_ERROR_NO_SUCH_FIB; + + t->t_fib_entry_index = fib_entry_track (t->t_fib_index, &pfx, child_type, + child_index, &t->t_sibling); + + t->t_flags |= TUNNEL_FLAG_RESOLVED; + + return (0); +} + +void +tunnel_unresolve (tunnel_t *t) +{ + if (t->t_flags & TUNNEL_FLAG_RESOLVED) + fib_entry_untrack (t->t_fib_entry_index, t->t_sibling); + + t->t_flags &= ~TUNNEL_FLAG_RESOLVED; +} + +void +tunnel_contribute_forwarding (const tunnel_t *t, dpo_id_t *dpo) +{ + fib_forward_chain_type_t fct; + + fct = fib_forw_chain_type_from_fib_proto ( + ip_address_family_to_fib_proto (ip_addr_version (&t->t_src))); + + fib_entry_contribute_forwarding (t->t_fib_entry_index, fct, dpo); +} + +void +tunnel_build_v6_hdr (const tunnel_t *t, ip_protocol_t next_proto, + ip6_header_t *ip) +{ + ip->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (0x60000000); + ip6_set_dscp_network_order (ip, t->t_dscp); + + ip->hop_limit = 254; + ip6_address_copy (&ip->src_address, &ip_addr_v6 (&t->t_src)); + ip6_address_copy (&ip->dst_address, &ip_addr_v6 (&t->t_dst)); + + ip->protocol = next_proto; + ip->hop_limit = (t->t_hop_limit == 0 ? 254 : t->t_hop_limit); + ip6_set_flow_label_network_order ( + ip, ip6_compute_flow_hash (ip, IP_FLOW_HASH_DEFAULT)); +} + +void +tunnel_build_v4_hdr (const tunnel_t *t, ip_protocol_t next_proto, + ip4_header_t *ip) +{ + ip->ip_version_and_header_length = 0x45; + ip->ttl = (t->t_hop_limit == 0 ? 254 : t->t_hop_limit); + ip->src_address.as_u32 = t->t_src.ip.ip4.as_u32; + ip->dst_address.as_u32 = t->t_dst.ip.ip4.as_u32; + ip->tos = t->t_dscp << 2; + ip->protocol = next_proto; + ip->checksum = ip4_header_checksum (ip); +} /* * fd.io coding-style-patch-verification: ON diff --git a/src/vnet/tunnel/tunnel.h b/src/vnet/tunnel/tunnel.h index de06b6002f5..acf0e4ca4e0 100644 --- a/src/vnet/tunnel/tunnel.h +++ b/src/vnet/tunnel/tunnel.h @@ -18,7 +18,8 @@ #ifndef __TUNNEL_H__ #define __TUNNEL_H__ -#include +#include +#include #define foreach_tunnel_mode \ _(P2P, "point-to-point") \ @@ -37,28 +38,90 @@ extern uword unformat_tunnel_mode (unformat_input_t * input, va_list * args); /** * Keep these idenitical to those in ipip.api */ -#define forech_tunnel_encap_decap_flag \ - _(NONE, "none", 0x0) \ - _(ENCAP_COPY_DF, "encap-copy-df", 0x1) \ - _(ENCAP_SET_DF, "encap-set-df", 0x2) \ - _(ENCAP_COPY_DSCP, "encap-copy-dscp", 0x4) \ - _(ENCAP_COPY_ECN, "encap-copy-ecn", 0x8) \ - _(DECAP_COPY_ECN, "decap-copy-ecn", 0x10) \ - _(ENCAP_INNER_HASH, "encap-inner-hash", 0x20) +#define foreach_tunnel_encap_decap_flag \ + _ (NONE, "none", 0x0) \ + _ (ENCAP_COPY_DF, "encap-copy-df", 0x1) \ + _ (ENCAP_SET_DF, "encap-set-df", 0x2) \ + _ (ENCAP_COPY_DSCP, "encap-copy-dscp", 0x4) \ + _ (ENCAP_COPY_ECN, "encap-copy-ecn", 0x8) \ + _ (DECAP_COPY_ECN, "decap-copy-ecn", 0x10) \ + _ (ENCAP_INNER_HASH, "encap-inner-hash", 0x20) \ + _ (ENCAP_COPY_HOP_LIMIT, "encap-copy-hop-limit", 0x40) \ + _ (ENCAP_COPY_FLOW_LABEL, "encap-copy-flow-label", 0x80) typedef enum tunnel_encap_decap_flags_t_ { #define _(a,b,c) TUNNEL_ENCAP_DECAP_FLAG_##a = c, - forech_tunnel_encap_decap_flag + foreach_tunnel_encap_decap_flag #undef _ } __clib_packed tunnel_encap_decap_flags_t; -#define TUNNEL_FLAG_MASK (0x1f) +extern const u8 TUNNEL_ENCAP_DECAP_FLAG_MASK; extern u8 *format_tunnel_encap_decap_flags (u8 * s, va_list * args); -extern uword -unformat_tunnel_encap_decap_flags (unformat_input_t * input, va_list * args); +extern uword unformat_tunnel_encap_decap_flags (unformat_input_t *input, + va_list *args); + +#define foreach_tunnel_flag \ + _ (RESOLVED, 0, "resolved") \ + _ (TRACK_MTU, 1, "track-mtu") + +typedef enum tunnel_flags_t_ +{ + TUNNEL_FLAG_NONE = 0, +#define _(n, b, s) TUNNEL_FLAG_##n = (1 << b), + foreach_tunnel_flag +#undef _ +} __clib_packed tunnel_flags_t; + +extern const u8 TUNNEL_FLAG_MASK; + +extern u8 *format_tunnel_flags (u8 *s, va_list *args); +extern uword unformat_tunnel_flags (unformat_input_t *input, va_list *args); + +/** + * A representation of an IP tunnel config + */ +typedef struct tunnel_t_ +{ + ip_address_t t_src; + ip_address_t t_dst; + tunnel_encap_decap_flags_t t_encap_decap_flags; + tunnel_flags_t t_flags; + tunnel_mode_t t_mode; + u32 t_table_id; + ip_dscp_t t_dscp; + u8 t_hop_limit; + + /** + * derived data + */ + u32 t_fib_index; + + fib_node_index_t t_fib_entry_index; + u32 t_sibling; + +} tunnel_t; + +extern u8 *format_tunnel (u8 *s, va_list *args); +extern uword unformat_tunnel (unformat_input_t *input, va_list *args); + +extern void tunnel_copy (const tunnel_t *src, tunnel_t *dst); +extern int tunnel_resolve (tunnel_t *t, fib_node_type_t child_type, + index_t child_index); +extern void tunnel_unresolve (tunnel_t *t); + +extern ip_address_family_t tunnel_get_af (const tunnel_t *t); + +extern void tunnel_contribute_forwarding (const tunnel_t *t, dpo_id_t *dpo); + +extern void tunnel_build_v6_hdr (const tunnel_t *t, ip_protocol_t next_proto, + ip6_header_t *ip); +extern void tunnel_build_v4_hdr (const tunnel_t *t, ip_protocol_t next_proto, + ip4_header_t *ip); + #endif + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/tunnel/tunnel_dp.h b/src/vnet/tunnel/tunnel_dp.h index deef4085a67..3db22a838b2 100644 --- a/src/vnet/tunnel/tunnel_dp.h +++ b/src/vnet/tunnel/tunnel_dp.h @@ -19,18 +19,21 @@ #define __TUNNEL_DP_H__ #include +#include static_always_inline void tunnel_encap_fixup_4o4 (tunnel_encap_decap_flags_t flags, const ip4_header_t * inner, ip4_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)) ip4_header_set_dscp (outer, ip4_header_get_dscp (inner)); - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) ip4_header_set_ecn (outer, ip4_header_get_ecn (inner)); - if ((flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) && - ip4_header_get_df (inner)) + if (PREDICT_FALSE ((flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) && + ip4_header_get_df (inner))) ip4_header_set_df (outer); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT)) + ip4_header_set_ttl (outer, ip4_header_get_ttl (inner)); } static_always_inline void @@ -38,8 +41,8 @@ tunnel_encap_fixup_4o4_w_chksum (tunnel_encap_decap_flags_t flags, const ip4_header_t * inner, ip4_header_t * outer) { - if (flags & (TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | - TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) + if (PREDICT_FALSE (flags & (TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | + TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))) { ip_csum_t sum = outer->checksum; u8 tos = outer->tos; @@ -53,8 +56,8 @@ tunnel_encap_fixup_4o4_w_chksum (tunnel_encap_decap_flags_t flags, ip_csum_update (outer->checksum, tos, outer->tos, ip4_header_t, tos); outer->checksum = ip_csum_fold (sum); } - if ((flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) && - ip4_header_get_df (inner)) + if (PREDICT_FALSE ((flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) && + ip4_header_get_df (inner))) { ip_csum_t sum = outer->checksum; u16 tos = outer->flags_and_fragment_offset; @@ -92,10 +95,12 @@ static_always_inline void tunnel_encap_fixup_6o4 (tunnel_encap_decap_flags_t flags, const ip6_header_t * inner, ip4_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)) ip4_header_set_dscp (outer, ip6_dscp_network_order (inner)); - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) ip4_header_set_ecn (outer, ip6_ecn_network_order ((inner))); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT)) + ip4_header_set_ttl (outer, ip6_hop_limit_network_order (inner)); } static_always_inline void @@ -103,8 +108,8 @@ tunnel_encap_fixup_6o4_w_chksum (tunnel_encap_decap_flags_t flags, const ip6_header_t * inner, ip4_header_t * outer) { - if (flags & (TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | - TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) + if (PREDICT_FALSE (flags & (TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | + TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))) { ip_csum_t sum = outer->checksum; u8 tos = outer->tos; @@ -124,30 +129,50 @@ static_always_inline void tunnel_encap_fixup_6o6 (tunnel_encap_decap_flags_t flags, const ip6_header_t * inner, ip6_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)) ip6_set_dscp_network_order (outer, ip6_dscp_network_order (inner)); - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) ip6_set_ecn_network_order (outer, ip6_ecn_network_order (inner)); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_FLOW_LABEL)) + ip6_set_flow_label_network_order (outer, + ip6_flow_label_network_order (inner)); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT)) + ip6_set_hop_limit_network_order (outer, + ip6_hop_limit_network_order (inner)); } static_always_inline void tunnel_encap_fixup_4o6 (tunnel_encap_decap_flags_t flags, - const ip4_header_t * inner, ip6_header_t * outer) + const vlib_buffer_t *b, const ip4_header_t *inner, + ip6_header_t *outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)) ip6_set_dscp_network_order (outer, ip4_header_get_dscp (inner)); - if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) ip6_set_ecn_network_order (outer, ip4_header_get_ecn (inner)); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT)) + ip6_set_hop_limit_network_order (outer, ip4_header_get_ttl (inner)); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_FLOW_LABEL)) + ip6_set_flow_label_network_order ( + outer, (0 != vnet_buffer (b)->ip.flow_hash ? + vnet_buffer (b)->ip.flow_hash : + ip4_compute_flow_hash (inner, IP_FLOW_HASH_DEFAULT))); } static_always_inline void tunnel_encap_fixup_mplso6 (tunnel_encap_decap_flags_t flags, + const vlib_buffer_t *b, const mpls_unicast_header_t *inner, ip6_header_t *outer) { if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) ip6_set_dscp_network_order (outer, vnet_mpls_uc_get_exp (inner->label_exp_s_ttl)); + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_FLOW_LABEL)) + ip6_set_flow_label_network_order ( + outer, (0 != vnet_buffer (b)->ip.flow_hash ? + vnet_buffer (b)->ip.flow_hash : + mpls_compute_flow_hash (inner, IP_FLOW_HASH_DEFAULT))); } static_always_inline void @@ -163,7 +188,7 @@ static_always_inline void tunnel_decap_fixup_4o6 (tunnel_encap_decap_flags_t flags, ip4_header_t * inner, const ip6_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) ip4_header_set_ecn_w_chksum (inner, ip6_ecn_network_order (outer)); } @@ -171,7 +196,7 @@ static_always_inline void tunnel_decap_fixup_6o6 (tunnel_encap_decap_flags_t flags, ip6_header_t * inner, const ip6_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) ip6_set_ecn_network_order (inner, ip6_ecn_network_order (outer)); } @@ -179,7 +204,7 @@ static_always_inline void tunnel_decap_fixup_6o4 (tunnel_encap_decap_flags_t flags, ip6_header_t * inner, const ip4_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) ip6_set_ecn_network_order (inner, ip4_header_get_ecn (outer)); } @@ -187,7 +212,7 @@ static_always_inline void tunnel_decap_fixup_4o4 (tunnel_encap_decap_flags_t flags, ip4_header_t * inner, const ip4_header_t * outer) { - if (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN) + if (PREDICT_FALSE (flags & TUNNEL_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) ip4_header_set_ecn_w_chksum (inner, ip4_header_get_ecn (outer)); } diff --git a/src/vnet/tunnel/tunnel_types.api b/src/vnet/tunnel/tunnel_types.api index 7ce70997f36..14267173721 100644 --- a/src/vnet/tunnel/tunnel_types.api +++ b/src/vnet/tunnel/tunnel_types.api @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -option version = "1.0.0"; +option version = "1.0.1"; + +import "vnet/interface_types.api"; +import "vnet/ip/ip_types.api"; /** * Flags controlling tunnel behaviour @@ -33,6 +36,10 @@ enum tunnel_encap_decap_flags : u8 TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN = 0x10, /** at encap, compute flow hash on the inner packet for more entropy */ TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH = 0x20 [backwards_compatible], + /** at encap, copy the hop-limit/TTL of the payload into the tunnel header */ + TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT = 0x40 [backwards_compatible], + /** at encap, copy the Flow Label of the payload into the tunnel header */ + TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_FLOW_LABEL = 0x80 [backwards_compatible], }; /** @@ -46,6 +53,41 @@ enum tunnel_mode : u8 TUNNEL_API_MODE_MP, }; +/** + * tunnel mode + */ +enumflag tunnel_flags : u8 +{ + /** + * the tunnel's MTU tracks the MTU of its destination + * Currently NOT IMPLEMENTATION (this is a API place-holder) + */ + TUNNEL_API_FLAG_TRACK_MTU = 0x1, +}; + +/** + * An IP{v4,v6} tunnel. + */ +typedef tunnel +{ + /** If non-~0, specifies a custom dev instance */ + u32 instance; + /** Tunnel source and destination address */ + vl_api_address_t src; + vl_api_address_t dst; + /** ignored on create, set in details/dump */ + vl_api_interface_index_t sw_if_index; + /** The table ID in which the source and destination addresses are valid */ + u32 table_id; + vl_api_tunnel_encap_decap_flags_t encap_decap_flags; + vl_api_tunnel_mode_t mode; + vl_api_tunnel_flags_t flags; + /* DSCP value for the tunnel encap, ignored if ECNAP_COPY_DSCP flag is set */ + vl_api_ip_dscp_t dscp; + /* TTL=0 is considered 255 */ + u8 hop_limit; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/tunnel/tunnel_types_api.c b/src/vnet/tunnel/tunnel_types_api.c index 1d48178e9df..894eecb8407 100644 --- a/src/vnet/tunnel/tunnel_types_api.c +++ b/src/vnet/tunnel/tunnel_types_api.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -25,12 +27,14 @@ STATIC_ASSERT (sizeof (vl_api_tunnel_encap_decap_flags_t) == sizeof (tunnel_encap_decap_flags_t), "tunnel API and internal flags enum size differ"); +STATIC_ASSERT (sizeof (vl_api_tunnel_flags_t) == sizeof (tunnel_flags_t), + "tunnel API and internal flags enum size differ"); int tunnel_encap_decap_flags_decode (vl_api_tunnel_encap_decap_flags_t f, tunnel_encap_decap_flags_t * o) { - if (f & ~TUNNEL_FLAG_MASK) + if (f & ~TUNNEL_ENCAP_DECAP_FLAG_MASK) /* unknown flags set */ return (VNET_API_ERROR_INVALID_VALUE_2); @@ -44,6 +48,23 @@ tunnel_encap_decap_flags_encode (tunnel_encap_decap_flags_t f) return ((vl_api_tunnel_encap_decap_flags_t) f); } +int +tunnel_flags_decode (vl_api_tunnel_flags_t f, tunnel_flags_t *o) +{ + if (f & ~TUNNEL_FLAG_MASK) + /* unknown flags set */ + return (VNET_API_ERROR_INVALID_VALUE_2); + + *o = (tunnel_flags_t) f; + return (0); +} + +vl_api_tunnel_flags_t +tunnel_flags_encode (tunnel_flags_t f) +{ + return ((vl_api_tunnel_flags_t) f); +} + int tunnel_mode_decode (vl_api_tunnel_mode_t in, tunnel_mode_t * out) { @@ -78,6 +99,65 @@ tunnel_mode_encode (tunnel_mode_t in) return (out); } +int +tunnel_decode (const vl_api_tunnel_t *in, tunnel_t *out) +{ + int rv; + + ip_address_decode2 (&in->src, &out->t_src); + ip_address_decode2 (&in->dst, &out->t_dst); + + if (ip_addr_version (&out->t_src) != ip_addr_version (&out->t_dst)) + return (VNET_API_ERROR_INVALID_PROTOCOL); + + if (0 == ip_address_cmp (&out->t_src, &out->t_dst)) + return (VNET_API_ERROR_SAME_SRC_DST); + + rv = tunnel_encap_decap_flags_decode (in->encap_decap_flags, + &out->t_encap_decap_flags); + + if (rv) + return (rv); + + rv = tunnel_mode_decode (in->mode, &out->t_mode); + + if (rv) + return (rv); + + rv = tunnel_flags_decode (in->flags, &out->t_flags); + + if (rv) + return (rv); + + out->t_table_id = clib_net_to_host_u32 (in->table_id); + out->t_fib_index = fib_table_find ( + ip_address_family_to_fib_proto (ip_addr_version (&out->t_dst)), + out->t_table_id); + + if (~0 == out->t_fib_index) + return (VNET_API_ERROR_NO_SUCH_FIB); + + out->t_dscp = ip_dscp_decode (in->dscp); + out->t_hop_limit = in->hop_limit; + + return (0); +} + +void +tunnel_encode (const tunnel_t *in, vl_api_tunnel_t *out) +{ + ip_address_encode2 (&in->t_src, &out->src); + ip_address_encode2 (&in->t_dst, &out->dst); + + out->encap_decap_flags = + tunnel_encap_decap_flags_encode (in->t_encap_decap_flags); + out->mode = tunnel_mode_encode (in->t_mode); + out->flags = tunnel_flags_encode (in->t_flags); + out->table_id = clib_host_to_net_u32 (in->t_table_id); + out->dscp = ip_dscp_encode (in->t_dscp); + out->hop_limit = in->t_hop_limit; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/tunnel/tunnel_types_api.h b/src/vnet/tunnel/tunnel_types_api.h index 06439dc87c1..0d32a6875e9 100644 --- a/src/vnet/tunnel/tunnel_types_api.h +++ b/src/vnet/tunnel/tunnel_types_api.h @@ -36,6 +36,12 @@ tunnel_encap_decap_flags_encode (tunnel_encap_decap_flags_t f); extern int tunnel_mode_decode (vl_api_tunnel_mode_t in, tunnel_mode_t * out); extern vl_api_tunnel_mode_t tunnel_mode_encode (tunnel_mode_t in); +extern int tunnel_flags_decode (vl_api_tunnel_flags_t in, tunnel_flags_t *out); +extern vl_api_tunnel_flags_t tunnel_flags_encode (tunnel_flags_t in); + +extern int tunnel_decode (const vl_api_tunnel_t *in, tunnel_t *out); +extern void tunnel_encode (const tunnel_t *in, vl_api_tunnel_t *out); + #endif /* -- 2.16.6