From 732036d677b84aa8eaea45f8059783e827622b77 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Thu, 8 Jun 2017 05:24:28 -0700 Subject: NAT64: ICMP error support Added ICMP error messages translation. Added check for multi thread (not supported yet, so init failed). Added API definition for custom NAT64 refix. Change-Id: Ice2f04631af63e594aecc09087a1cf59f3b676fb Signed-off-by: Matus Fabian --- src/plugins/snat/nat64.c | 13 ++++++- src/plugins/snat/nat64_in2out.c | 75 +++++++++++++++++++++++++++++++++--- src/plugins/snat/nat64_out2in.c | 84 ++++++++++++++++++++++++++++++++++++++--- src/plugins/snat/snat.api | 39 +++++++++++++++++++ src/plugins/snat/snat.c | 6 ++- src/vnet/ip/ip4_to_ip6.h | 13 +++---- 6 files changed, 207 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/plugins/snat/nat64.c b/src/plugins/snat/nat64.c index 9b6b3c8a..ef745473 100644 --- a/src/plugins/snat/nat64.c +++ b/src/plugins/snat/nat64.c @@ -45,9 +45,19 @@ nat64_init (vlib_main_t * vm) { nat64_main_t *nm = &nat64_main; clib_error_t *error = 0; + vlib_thread_main_t *tm = vlib_get_thread_main (); + + if (tm->n_vlib_mains > 1) + { + error = clib_error_return (0, "multi thread not supported"); + goto error; + } if (nat64_db_init (&nm->db)) - error = clib_error_return (0, "NAT64 DB init failed"); + { + error = clib_error_return (0, "NAT64 DB init failed"); + goto error; + } /* set session timeouts to default values */ nm->udp_timeout = SNAT_UDP_TIMEOUT; @@ -56,6 +66,7 @@ nat64_init (vlib_main_t * vm) nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN; +error: return error; } diff --git a/src/plugins/snat/nat64_in2out.c b/src/plugins/snat/nat64_in2out.c index d9d94a97..eba69326 100644 --- a/src/plugins/snat/nat64_in2out.c +++ b/src/plugins/snat/nat64_in2out.c @@ -221,9 +221,11 @@ nat64_in2out_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg) } else { - //TODO: ICMP error - clib_warning ("not ICMP echo request/reply, %u", icmp->type); - return -1; + if (!vec_len (nm->addr_pool)) + return -1; + + ip4->src_address.as_u32 = nm->addr_pool[0].addr.as_u32; + ip4->dst_address.as_u32 = daddr.ip4.as_u32; } return 0; @@ -231,10 +233,71 @@ nat64_in2out_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg) static int nat64_in2out_inner_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, - void *ctx) + void *arg) { - //TODO: - return -1; + nat64_main_t *nm = &nat64_main; + nat64_in2out_set_ctx_t *ctx = arg; + nat64_db_st_entry_t *ste; + nat64_db_bib_entry_t *bibe; + ip46_address_t saddr, daddr; + u32 sw_if_index, fib_index; + snat_protocol_t proto = ip_proto_to_snat_proto (ip6->protocol); + + sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); + + saddr.as_u64[0] = ip6->src_address.as_u64[0]; + saddr.as_u64[1] = ip6->src_address.as_u64[1]; + daddr.as_u64[0] = ip6->dst_address.as_u64[0]; + daddr.as_u64[1] = ip6->dst_address.as_u64[1]; + + if (proto == SNAT_PROTOCOL_ICMP) + { + icmp46_header_t *icmp = ip6_next_header (ip6); + u16 in_id = ((u16 *) (icmp))[2]; + + if (! + (icmp->type == ICMP4_echo_request + || icmp->type == ICMP4_echo_reply)) + return -1; + + ste = + nat64_db_st_entry_find (&nm->db, &daddr, &saddr, in_id, 0, proto, + fib_index, 1); + if (!ste) + return -1; + + bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); + if (!bibe) + return -1; + + ip4->dst_address.as_u32 = bibe->out_addr.as_u32; + ((u16 *) (icmp))[2] = bibe->out_port; + ip4->src_address.as_u32 = saddr.ip4.as_u32; + } + else + { + udp_header_t *udp = ip6_next_header (ip6); + u16 sport = udp->src_port; + u16 dport = udp->dst_port; + + ste = + nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, + fib_index, 1); + if (!ste) + return -1; + + bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); + if (!bibe) + return -1; + + ip4->dst_address.as_u32 = bibe->out_addr.as_u32; + udp->dst_port = bibe->out_port; + ip4->src_address.as_u32 = saddr.ip4.as_u32; + } + + return 0; } static uword diff --git a/src/plugins/snat/nat64_out2in.c b/src/plugins/snat/nat64_out2in.c index 3eed9974..c11bbb5a 100644 --- a/src/plugins/snat/nat64_out2in.c +++ b/src/plugins/snat/nat64_out2in.c @@ -208,9 +208,12 @@ nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg) } else { - //TODO: ICMP error - clib_warning ("not ICMP echo request/reply, %u", icmp->type); - return -1; + ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8); + + ip6->src_address.as_u64[0] = ip6_saddr.as_u64[0]; + ip6->src_address.as_u64[1] = ip6_saddr.as_u64[1]; + ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0]; + ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1]; } return 0; @@ -218,10 +221,79 @@ nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg) static int nat64_out2in_inner_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, - void *ctx) + void *arg) { - //TODO: - return -1; + nat64_main_t *nm = &nat64_main; + nat64_out2in_set_ctx_t *ctx = arg; + nat64_db_bib_entry_t *bibe; + nat64_db_st_entry_t *ste; + ip46_address_t saddr, daddr; + ip6_address_t ip6_daddr; + u32 sw_if_index, fib_index; + snat_protocol_t proto = ip_proto_to_snat_proto (ip4->protocol); + + sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); + + memset (&saddr, 0, sizeof (saddr)); + saddr.ip4.as_u32 = ip4->src_address.as_u32; + memset (&daddr, 0, sizeof (daddr)); + daddr.ip4.as_u32 = ip4->dst_address.as_u32; + + memcpy (&ip6_daddr, well_known_prefix, sizeof (ip6_daddr)); + ip6_daddr.as_u32[3] = ip4->dst_address.as_u32; + + if (proto == SNAT_PROTOCOL_ICMP) + { + icmp46_header_t *icmp = ip4_next_header (ip4); + u16 out_id = ((u16 *) (icmp))[2]; + + if (! + (icmp->type == ICMP6_echo_request + || icmp->type == ICMP6_echo_reply)) + return -1; + + ste = + nat64_db_st_entry_find (&nm->db, &saddr, &daddr, out_id, 0, proto, + fib_index, 0); + if (!ste) + return -1; + + bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); + if (!bibe) + return -1; + + ip6->dst_address.as_u64[0] = ip6_daddr.as_u64[0]; + ip6->dst_address.as_u64[1] = ip6_daddr.as_u64[1]; + ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0]; + ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1]; + ((u16 *) (icmp))[2] = bibe->in_port; + } + else + { + udp_header_t *udp = ip4_next_header (ip4); + u16 dport = udp->dst_port; + u16 sport = udp->src_port; + + ste = + nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, + fib_index, 0); + if (!ste) + return -1; + + bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); + if (!bibe) + return -1; + + ip6->dst_address.as_u64[0] = ip6_daddr.as_u64[0]; + ip6->dst_address.as_u64[1] = ip6_daddr.as_u64[1]; + ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0]; + ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1]; + udp->src_port = bibe->in_port; + } + + return 0; } static uword diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api index e6289af2..62c96058 100644 --- a/src/plugins/snat/snat.api +++ b/src/plugins/snat/snat.api @@ -812,3 +812,42 @@ define nat64_st_details { u32 vrf_id; u8 proto; }; + +/** \brief Add/del NAT64 prefix + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param prefix - NAT64 prefix + @param prefix - NAT64 prefix length + @param vrf_id - VRF id of tenant + @param is_add - 1 if add, 0 if delete +*/ +autoreply define nat64_add_del_prefix { + u32 client_index; + u32 context; + u8 prefix[16]; + u8 prefix_len; + u32 vrf_id; + u8 is_add; +}; + +/** \brief Dump NAT64 prefix + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define nat64_prefix_dump { + u32 client_index; + u32 context; +}; + +/** \brief Dump NAT64 prefix details response + @param context - sender context, to match reply w/ request + @param prefix - NAT64 prefix + @param prefix - NAT64 prefix length + @param vrf_id - VRF id of tenant +*/ +define nat64_prefix_details { + u32 context; + u8 prefix[16]; + u8 prefix_len; + u32 vrf_id; +}; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index e95abf27..351f8dc7 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -725,7 +725,7 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im, static clib_error_t * snat_init (vlib_main_t * vm) { snat_main_t * sm = &snat_main; - clib_error_t * error = 0; + clib_error_t * error = 0, * error_nat64 = 0; ip4_main_t * im = &ip4_main; ip_lookup_main_t * lm = &im->lookup_main; uword *p; @@ -782,7 +782,9 @@ static clib_error_t * snat_init (vlib_main_t * vm) /* Init IPFIX logging */ snat_ipfix_logging_init(vm); - error = nat64_init(vm); + error_nat64 = nat64_init(vm); + if (error_nat64) + clib_warning("NAT64 init failed: %U", format_clib_error, error_nat64); return error; } diff --git a/src/vnet/ip/ip4_to_ip6.h b/src/vnet/ip/ip4_to_ip6.h index 96b8bf1e..965d27c3 100644 --- a/src/vnet/ip/ip4_to_ip6.h +++ b/src/vnet/ip/ip4_to_ip6.h @@ -310,14 +310,11 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx, else if (PREDICT_TRUE (inner_ip4->protocol == IP_PROTOCOL_UDP)) { inner_L4_checksum = &((udp_header_t *) (inner_ip4 + 1))->checksum; - if (!*inner_L4_checksum) - { - return -1; - } - *inner_L4_checksum = - ip_csum_fold (ip_csum_sub_even - (*inner_L4_checksum, - *((u64 *) (&inner_ip4->src_address)))); + if (*inner_L4_checksum) + *inner_L4_checksum = + ip_csum_fold (ip_csum_sub_even + (*inner_L4_checksum, + *((u64 *) (&inner_ip4->src_address)))); } else if (inner_ip4->protocol == IP_PROTOCOL_ICMP) { -- cgit 1.2.3-korg