X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fipsec%2Fipsec_output.c;h=787da9359e09b049d141366270e5ecbb310a5539;hb=HEAD;hp=2ab98e7e14085cc387ca96d6319de1294de650b8;hpb=057b3565a09b62c9415a44a99f43ad891d864ca5;p=vpp.git diff --git a/src/vnet/ipsec/ipsec_output.c b/src/vnet/ipsec/ipsec_output.c index 2ab98e7e140..787da9359e0 100644 --- a/src/vnet/ipsec/ipsec_output.c +++ b/src/vnet/ipsec/ipsec_output.c @@ -20,8 +20,8 @@ #include #include - -#if WITH_LIBSSL > 0 +#include +#include #define foreach_ipsec_output_error \ _(RX_PKTS, "IPSec pkts received") \ @@ -48,6 +48,7 @@ static char *ipsec_output_error_strings[] = { typedef struct { u32 spd_id; + u32 policy_id; } ipsec_output_trace_t; /* packet trace format function */ @@ -58,121 +59,9 @@ format_ipsec_output_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ipsec_output_trace_t *t = va_arg (*args, ipsec_output_trace_t *); - if (t->spd_id != ~0) - { - s = format (s, "spd %u ", t->spd_id); - } - else - { - s = format (s, "no spd"); - } - return s; -} - -always_inline ipsec_policy_t * -ipsec_output_policy_match (ipsec_spd_t * spd, u8 pr, u32 la, u32 ra, u16 lp, - u16 rp) -{ - ipsec_policy_t *p; - u32 *i; - - if (!spd) - return 0; - - vec_foreach (i, spd->ipv4_outbound_policies) - { - p = pool_elt_at_index (spd->policies, *i); - if (PREDICT_FALSE (p->protocol && (p->protocol != pr))) - continue; - - if (ra < clib_net_to_host_u32 (p->raddr.start.ip4.as_u32)) - continue; + s = format (s, "spd %u policy %d", t->spd_id, t->policy_id); - if (ra > clib_net_to_host_u32 (p->raddr.stop.ip4.as_u32)) - continue; - - if (la < clib_net_to_host_u32 (p->laddr.start.ip4.as_u32)) - continue; - - if (la > clib_net_to_host_u32 (p->laddr.stop.ip4.as_u32)) - continue; - - if (PREDICT_FALSE - ((pr != IP_PROTOCOL_TCP) && (pr != IP_PROTOCOL_UDP) - && (pr != IP_PROTOCOL_SCTP))) - return p; - - if (lp < p->lport.start) - continue; - - if (lp > p->lport.stop) - continue; - - if (rp < p->rport.start) - continue; - - if (rp > p->rport.stop) - continue; - - return p; - } - return 0; -} - -always_inline uword -ip6_addr_match_range (ip6_address_t * a, ip6_address_t * la, - ip6_address_t * ua) -{ - if ((memcmp (a->as_u64, la->as_u64, 2 * sizeof (u64)) >= 0) && - (memcmp (a->as_u64, ua->as_u64, 2 * sizeof (u64)) <= 0)) - return 1; - return 0; -} - -always_inline ipsec_policy_t * -ipsec6_output_policy_match (ipsec_spd_t * spd, - ip6_address_t * la, - ip6_address_t * ra, u16 lp, u16 rp, u8 pr) -{ - ipsec_policy_t *p; - u32 *i; - - if (!spd) - return 0; - - vec_foreach (i, spd->ipv6_outbound_policies) - { - p = pool_elt_at_index (spd->policies, *i); - if (PREDICT_FALSE (p->protocol && (p->protocol != pr))) - continue; - - if (!ip6_addr_match_range (ra, &p->raddr.start.ip6, &p->raddr.stop.ip6)) - continue; - - if (!ip6_addr_match_range (la, &p->laddr.start.ip6, &p->laddr.stop.ip6)) - continue; - - if (PREDICT_FALSE - ((pr != IP_PROTOCOL_TCP) && (pr != IP_PROTOCOL_UDP) - && (pr != IP_PROTOCOL_SCTP))) - return p; - - if (lp < p->lport.start) - continue; - - if (lp > p->lport.stop) - continue; - - if (rp < p->rport.start) - continue; - - if (rp > p->rport.stop) - continue; - - return p; - } - - return 0; + return s; } static inline uword @@ -181,7 +70,7 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { ipsec_main_t *im = &ipsec_main; - u32 *from, *to_next = 0; + u32 *from, *to_next = 0, thread_index; u32 n_left_from, sw_if_index0, last_sw_if_index = (u32) ~ 0; u32 next_node_index = (u32) ~ 0, last_next_node_index = (u32) ~ 0; vlib_frame_t *f = 0; @@ -189,23 +78,33 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, ipsec_spd_t *spd0 = 0; int bogus; u64 nc_protect = 0, nc_bypass = 0, nc_discard = 0, nc_nomatch = 0; + u8 flow_cache_enabled = im->output_flow_cache_flag; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; + thread_index = vm->thread_index; while (n_left_from > 0) { - u32 bi0; - vlib_buffer_t *b0; - ipsec_policy_t *p0; + u32 bi0, pi0, bi1; + vlib_buffer_t *b0, *b1; + ipsec_policy_t *p0 = NULL; ip4_header_t *ip0; ip6_header_t *ip6_0 = 0; udp_header_t *udp0; u32 iph_offset = 0; tcp_header_t *tcp0; + u64 bytes0; bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); + if (n_left_from > 1) + { + bi1 = from[1]; + b1 = vlib_get_buffer (vm, bi1); + CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES * 2, STORE); + vlib_prefetch_buffer_data (b1, LOAD); + } sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; iph_offset = vnet_buffer (b0)->ip.save_rewrite_length; ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) @@ -215,7 +114,7 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (PREDICT_FALSE (last_sw_if_index != sw_if_index0)) { uword *p = hash_get (im->spd_index_by_sw_if_index, sw_if_index0); - ASSERT (p); + ALWAYS_ASSERT (p); spd_index0 = p[0]; spd0 = pool_elt_at_index (im->spds, spd_index0); last_sw_if_index = sw_if_index0; @@ -257,25 +156,51 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, sw_if_index0, spd_index0, spd0->id); #endif - p0 = ipsec_output_policy_match (spd0, ip0->protocol, - clib_net_to_host_u32 - (ip0->src_address.as_u32), - clib_net_to_host_u32 - (ip0->dst_address.as_u32), - clib_net_to_host_u16 - (udp0->src_port), - clib_net_to_host_u16 - (udp0->dst_port)); + /* + * Check whether flow cache is enabled. + */ + if (flow_cache_enabled) + { + p0 = ipsec4_out_spd_find_flow_cache_entry ( + im, ip0->protocol, ip0->src_address.as_u32, + ip0->dst_address.as_u32, udp0->src_port, udp0->dst_port); + } + + /* Fall back to linear search if flow cache lookup fails */ + if (p0 == NULL) + { + p0 = ipsec_output_policy_match ( + spd0, ip0->protocol, + clib_net_to_host_u32 (ip0->src_address.as_u32), + clib_net_to_host_u32 (ip0->dst_address.as_u32), + clib_net_to_host_u16 (udp0->src_port), + clib_net_to_host_u16 (udp0->dst_port), flow_cache_enabled); + } } tcp0 = (void *) udp0; if (PREDICT_TRUE (p0 != NULL)) { + pi0 = p0 - im->policies; + + vlib_prefetch_combined_counter (&ipsec_spd_policy_counters, + thread_index, pi0); + + if (is_ipv6) + { + bytes0 = clib_net_to_host_u16 (ip6_0->payload_length); + bytes0 += sizeof (ip6_header_t); + } + else + { + bytes0 = clib_net_to_host_u16 (ip0->length); + } + if (p0->policy == IPSEC_POLICY_ACTION_PROTECT) { ipsec_sa_t *sa = 0; nc_protect++; - sa = pool_elt_at_index (im->sad, p0->sa_index); + sa = ipsec_sa_get (p0->sa_index); if (sa->protocol == IPSEC_PROTOCOL_ESP) if (is_ipv6) next_node_index = im->esp6_encrypt_node_index; @@ -286,50 +211,51 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, else next_node_index = im->ah4_encrypt_node_index; vnet_buffer (b0)->ipsec.sad_index = p0->sa_index; - p0->counter.packets++; - if (is_ipv6) - { - p0->counter.bytes += - clib_net_to_host_u16 (ip6_0->payload_length); - p0->counter.bytes += sizeof (ip6_header_t); - if (PREDICT_FALSE - (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)) - { - tcp0->checksum = - ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip6_0, - &bogus); - b0->flags &= ~VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; - } - if (PREDICT_FALSE - (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) - { - udp0->checksum = - ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip6_0, - &bogus); - b0->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; - } - } - else + + if (PREDICT_FALSE (b0->flags & VNET_BUFFER_F_OFFLOAD)) { - p0->counter.bytes += clib_net_to_host_u16 (ip0->length); - if (b0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM) - { - ip0->checksum = ip4_header_checksum (ip0); - b0->flags &= ~VNET_BUFFER_F_OFFLOAD_IP_CKSUM; - } - if (PREDICT_FALSE - (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)) + vnet_buffer_oflags_t oflags = vnet_buffer (b0)->oflags; + + /* + * Clearing offload flags before checksum is computed + * It guarantees the cache hit! + */ + vnet_buffer_offload_flags_clear (b0, oflags); + + if (is_ipv6) { - tcp0->checksum = - ip4_tcp_udp_compute_checksum (vm, b0, ip0); - b0->flags &= ~VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; + if (PREDICT_FALSE (oflags & + VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)) + { + tcp0->checksum = ip6_tcp_udp_icmp_compute_checksum ( + vm, b0, ip6_0, &bogus); + } + if (PREDICT_FALSE (oflags & + VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)) + { + udp0->checksum = ip6_tcp_udp_icmp_compute_checksum ( + vm, b0, ip6_0, &bogus); + } } - if (PREDICT_FALSE - (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) + else { - udp0->checksum = - ip4_tcp_udp_compute_checksum (vm, b0, ip0); - b0->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; + if (PREDICT_FALSE (oflags & + VNET_BUFFER_OFFLOAD_F_IP_CKSUM)) + { + ip0->checksum = ip4_header_checksum (ip0); + } + if (PREDICT_FALSE (oflags & + VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)) + { + tcp0->checksum = + ip4_tcp_udp_compute_checksum (vm, b0, ip0); + } + if (PREDICT_FALSE (oflags & + VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)) + { + udp0->checksum = + ip4_tcp_udp_compute_checksum (vm, b0, ip0); + } } } vlib_buffer_advance (b0, iph_offset); @@ -338,37 +264,18 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { nc_bypass++; next_node_index = get_next_output_feature_node_index (b0, node); - p0->counter.packets++; - if (is_ipv6) - { - p0->counter.bytes += - clib_net_to_host_u16 (ip6_0->payload_length); - p0->counter.bytes += sizeof (ip6_header_t); - } - else - { - p0->counter.bytes += clib_net_to_host_u16 (ip0->length); - } } else { nc_discard++; - p0->counter.packets++; - if (is_ipv6) - { - p0->counter.bytes += - clib_net_to_host_u16 (ip6_0->payload_length); - p0->counter.bytes += sizeof (ip6_header_t); - } - else - { - p0->counter.bytes += clib_net_to_host_u16 (ip0->length); - } next_node_index = im->error_drop_node_index; } + vlib_increment_combined_counter + (&ipsec_spd_policy_counters, thread_index, pi0, 1, bytes0); } else { + pi0 = ~0; nc_nomatch++; next_node_index = im->error_drop_node_index; } @@ -397,12 +304,14 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, to_next += 1; f->n_vectors++; - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) && + PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { ipsec_output_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); if (spd0) tr->spd_id = spd0->id; + tr->policy_id = pi0; } } @@ -426,7 +335,6 @@ VLIB_NODE_FN (ipsec4_output_node) (vlib_main_t * vm, return ipsec_output_inline (vm, node, frame, 0); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ipsec4_output_node) = { .name = "ipsec4-output-feature", .vector_size = sizeof (u32), @@ -443,7 +351,6 @@ VLIB_REGISTER_NODE (ipsec4_output_node) = { #undef _ }, }; -/* *INDENT-ON* */ VLIB_NODE_FN (ipsec6_output_node) (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -452,7 +359,6 @@ VLIB_NODE_FN (ipsec6_output_node) (vlib_main_t * vm, return ipsec_output_inline (vm, node, frame, 1); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ipsec6_output_node) = { .name = "ipsec6-output-feature", .vector_size = sizeof (u32), @@ -469,39 +375,4 @@ VLIB_REGISTER_NODE (ipsec6_output_node) = { #undef _ }, }; -/* *INDENT-ON* */ - -#else /* IPSEC > 1 */ - -/* Dummy ipsec output node, in case when IPSec is disabled */ -static uword -ipsec_output_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - clib_warning ("IPSec disabled"); - return 0; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (ipsec4_output_node) = { - .vector_size = sizeof (u32), - .function = ipsec_output_node_fn, - .name = "ipsec4-output-feature", -}; - -VLIB_REGISTER_NODE (ipsec6_output_node) = { - .vector_size = sizeof (u32), - .function = ipsec_output_node_fn, - .name = "ipsec6-output-feature", -}; -/* *INDENT-ON* */ -#endif - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */