From 2c6639c695aebf0cd5ac74ad31fd331547fa0126 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Thu, 19 Dec 2019 11:55:54 +0100 Subject: nat: move dslite to separate sub-plugin Type: refactor Change-Id: If3d9f16f3a06c10b354f1eef674e8db5f3c44de7 Signed-off-by: Ole Troan --- src/plugins/nat/CMakeLists.txt | 51 +-- src/plugins/nat/dslite.c | 271 ---------------- src/plugins/nat/dslite.h | 161 ---------- src/plugins/nat/dslite/dslite.api | 134 ++++++++ src/plugins/nat/dslite/dslite.c | 265 ++++++++++++++++ src/plugins/nat/dslite/dslite.h | 166 ++++++++++ src/plugins/nat/dslite/dslite_api.c | 177 +++++++++++ src/plugins/nat/dslite/dslite_ce_decap.c | 142 +++++++++ src/plugins/nat/dslite/dslite_ce_encap.c | 134 ++++++++ src/plugins/nat/dslite/dslite_cli.c | 404 ++++++++++++++++++++++++ src/plugins/nat/dslite/dslite_dpo.c | 130 ++++++++ src/plugins/nat/dslite/dslite_dpo.h | 38 +++ src/plugins/nat/dslite/dslite_in2out.c | 515 +++++++++++++++++++++++++++++++ src/plugins/nat/dslite/dslite_out2in.c | 294 ++++++++++++++++++ src/plugins/nat/dslite_ce_decap.c | 142 --------- src/plugins/nat/dslite_ce_encap.c | 134 -------- src/plugins/nat/dslite_cli.c | 411 ------------------------ src/plugins/nat/dslite_dpo.c | 130 -------- src/plugins/nat/dslite_dpo.h | 38 --- src/plugins/nat/dslite_in2out.c | 503 ------------------------------ src/plugins/nat/dslite_out2in.c | 294 ------------------ src/plugins/nat/nat.api | 107 ------- src/plugins/nat/nat.c | 18 +- src/plugins/nat/nat.h | 5 - src/plugins/nat/nat_api.c | 234 +------------- src/plugins/nat/nat_inlines.h | 9 + src/plugins/nat/test/test_dslite.py | 338 ++++++++++++++++++++ src/plugins/nat/test/test_nat.py | 305 ------------------ 28 files changed, 2781 insertions(+), 2769 deletions(-) delete mode 100644 src/plugins/nat/dslite.c delete mode 100644 src/plugins/nat/dslite.h create mode 100644 src/plugins/nat/dslite/dslite.api create mode 100644 src/plugins/nat/dslite/dslite.c create mode 100644 src/plugins/nat/dslite/dslite.h create mode 100644 src/plugins/nat/dslite/dslite_api.c create mode 100644 src/plugins/nat/dslite/dslite_ce_decap.c create mode 100644 src/plugins/nat/dslite/dslite_ce_encap.c create mode 100644 src/plugins/nat/dslite/dslite_cli.c create mode 100644 src/plugins/nat/dslite/dslite_dpo.c create mode 100644 src/plugins/nat/dslite/dslite_dpo.h create mode 100644 src/plugins/nat/dslite/dslite_in2out.c create mode 100644 src/plugins/nat/dslite/dslite_out2in.c delete mode 100644 src/plugins/nat/dslite_ce_decap.c delete mode 100644 src/plugins/nat/dslite_ce_encap.c delete mode 100644 src/plugins/nat/dslite_cli.c delete mode 100644 src/plugins/nat/dslite_dpo.c delete mode 100644 src/plugins/nat/dslite_dpo.h delete mode 100644 src/plugins/nat/dslite_in2out.c delete mode 100644 src/plugins/nat/dslite_out2in.c create mode 100644 src/plugins/nat/test/test_dslite.py (limited to 'src') diff --git a/src/plugins/nat/CMakeLists.txt b/src/plugins/nat/CMakeLists.txt index edba893cafe..a1a01789240 100644 --- a/src/plugins/nat/CMakeLists.txt +++ b/src/plugins/nat/CMakeLists.txt @@ -11,21 +11,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(NAT_SRCS +set(CMAKE_VERBOSE_MAKEFILE ON) + +add_vpp_library(nat + SOURCES lib/alloc.c -) -set(NAT_HEADERS + INSTALL_HEADERS lib/alloc.h ) -add_vpp_library(nat - SOURCES ${NAT_SRCS} - LINK_LIBRARIES m - INSTALL_HEADERS ${NAT_HEADERS} - COMPONENT libnat -) - add_vpp_plugin(nat SOURCES nat.c @@ -48,13 +43,6 @@ add_vpp_plugin(nat nat64_in2out.c nat64_out2in.c nat64_db.c - dslite_dpo.c - dslite.c - dslite_in2out.c - dslite_out2in.c - dslite_cli.c - dslite_ce_encap.c - dslite_ce_decap.c nat66.c nat66_cli.c nat66_in2out.c @@ -65,10 +53,6 @@ add_vpp_plugin(nat nat_ha.c MULTIARCH_SOURCES - dslite_ce_decap.c - dslite_ce_encap.c - dslite_in2out.c - dslite_out2in.c in2out.c in2out_ed.c nat44_classify.c @@ -93,3 +77,28 @@ add_vpp_plugin(nat nat_all_api_h.h nat_msg_enum.h ) + +add_vpp_plugin(dslite + SOURCES + nat_format.c + nat_syslog.c + dslite/dslite_api.c + dslite/dslite_dpo.c + dslite/dslite.c + dslite/dslite_in2out.c + dslite/dslite_out2in.c + dslite/dslite_cli.c + dslite/dslite_ce_encap.c + dslite/dslite_ce_decap.c + + MULTIARCH_SOURCES + dslite/dslite_ce_decap.c + dslite/dslite_ce_encap.c + dslite/dslite_in2out.c + dslite/dslite_out2in.c + + API_FILES + dslite/dslite.api + + LINK_LIBRARIES nat +) diff --git a/src/plugins/nat/dslite.c b/src/plugins/nat/dslite.c deleted file mode 100644 index d9a17293fac..00000000000 --- a/src/plugins/nat/dslite.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ -#include -#include -#include - -dslite_main_t dslite_main; - -void -dslite_init (vlib_main_t * vm) -{ - dslite_main_t *dm = &dslite_main; - vlib_thread_registration_t *tr; - vlib_thread_main_t *tm = vlib_get_thread_main (); - uword *p; - vlib_node_t *node; - dslite_per_thread_data_t *td; - u32 translation_buckets = 1024; - u32 translation_memory_size = 128 << 20; - u32 b4_buckets = 128; - u32 b4_memory_size = 64 << 20; - - node = vlib_get_node_by_name (vm, (u8 *) "dslite-in2out"); - dm->dslite_in2out_node_index = node->index; - - node = vlib_get_node_by_name (vm, (u8 *) "dslite-in2out-slowpath"); - dm->dslite_in2out_slowpath_node_index = node->index; - - node = vlib_get_node_by_name (vm, (u8 *) "dslite-out2in"); - dm->dslite_out2in_node_index = node->index; - - dm->first_worker_index = 0; - dm->num_workers = 0; - - p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - if (p) - { - tr = (vlib_thread_registration_t *) p[0]; - if (tr) - { - dm->num_workers = tr->count; - dm->first_worker_index = tr->first_index; - } - } - - if (dm->num_workers) - dm->port_per_thread = (0xffff - 1024) / dm->num_workers; - else - dm->port_per_thread = 0xffff - 1024; - - vec_validate (dm->per_thread_data, tm->n_vlib_mains - 1); - - /* *INDENT-OFF* */ - vec_foreach (td, dm->per_thread_data) - { - clib_bihash_init_24_8 (&td->in2out, "in2out", translation_buckets, - translation_memory_size); - - clib_bihash_init_8_8 (&td->out2in, "out2in", translation_buckets, - translation_memory_size); - - clib_bihash_init_16_8 (&td->b4_hash, "b4s", b4_buckets, b4_memory_size); - } - /* *INDENT-ON* */ - - dm->is_ce = 0; - - /* Init counters */ - dm->total_b4s.name = "total-b4s"; - dm->total_b4s.stat_segment_name = "/dslite/total-b4s"; - vlib_validate_simple_counter (&dm->total_b4s, 0); - vlib_zero_simple_counter (&dm->total_b4s, 0); - dm->total_sessions.name = "total-sessions"; - dm->total_sessions.stat_segment_name = "/dslite/total-sessions"; - vlib_validate_simple_counter (&dm->total_sessions, 0); - vlib_zero_simple_counter (&dm->total_sessions, 0); - - dslite_dpo_module_init (); -} - -void -dslite_set_ce (dslite_main_t * dm, u8 set) -{ - dm->is_ce = (set != 0); -} - -int -dslite_set_aftr_ip6_addr (dslite_main_t * dm, ip6_address_t * addr) -{ - dpo_id_t dpo = DPO_INVALID; - - if (dm->is_ce) - { - dslite_ce_dpo_create (DPO_PROTO_IP4, 0, &dpo); - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 0, - .fp_addr.ip4.as_u32 = 0, - }; - fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, - FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); - } - else - { - dslite_dpo_create (DPO_PROTO_IP6, 0, &dpo); - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = 128, - .fp_addr.ip6.as_u64[0] = addr->as_u64[0], - .fp_addr.ip6.as_u64[1] = addr->as_u64[1], - }; - fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, - FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); - } - - dpo_reset (&dpo); - - dm->aftr_ip6_addr.as_u64[0] = addr->as_u64[0]; - dm->aftr_ip6_addr.as_u64[1] = addr->as_u64[1]; - return 0; -} - -int -dslite_set_aftr_ip4_addr (dslite_main_t * dm, ip4_address_t * addr) -{ - dm->aftr_ip4_addr.as_u32 = addr->as_u32; - return 0; -} - -int -dslite_set_b4_ip6_addr (dslite_main_t * dm, ip6_address_t * addr) -{ - if (dm->is_ce) - { - dpo_id_t dpo = DPO_INVALID; - - dslite_ce_dpo_create (DPO_PROTO_IP6, 0, &dpo); - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = 128, - .fp_addr.ip6.as_u64[0] = addr->as_u64[0], - .fp_addr.ip6.as_u64[1] = addr->as_u64[1], - }; - fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, - FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); - - dpo_reset (&dpo); - - dm->b4_ip6_addr.as_u64[0] = addr->as_u64[0]; - dm->b4_ip6_addr.as_u64[1] = addr->as_u64[1]; - } - else - { - return VNET_API_ERROR_FEATURE_DISABLED; - } - - return 0; -} - -int -dslite_set_b4_ip4_addr (dslite_main_t * dm, ip4_address_t * addr) -{ - if (dm->is_ce) - { - dm->b4_ip4_addr.as_u32 = addr->as_u32; - } - else - { - return VNET_API_ERROR_FEATURE_DISABLED; - } - - return 0; -} - -int -dslite_add_del_pool_addr (dslite_main_t * dm, ip4_address_t * addr, u8 is_add) -{ - vlib_thread_main_t *tm = vlib_get_thread_main (); - snat_address_t *a = 0; - int i = 0; - dpo_id_t dpo_v4 = DPO_INVALID; - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr.ip4.as_u32 = addr->as_u32, - }; - - for (i = 0; i < vec_len (dm->addr_pool); i++) - { - if (dm->addr_pool[i].addr.as_u32 == addr->as_u32) - { - a = dm->addr_pool + i; - break; - } - } - if (is_add) - { - if (a) - return VNET_API_ERROR_VALUE_EXIST; - vec_add2 (dm->addr_pool, a, 1); - a->addr = *addr; -#define _(N, i, n, s) \ - clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535); \ - a->busy_##n##_ports = 0; \ - vec_validate_init_empty (a->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0); - foreach_snat_protocol -#undef _ - dslite_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4); - fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, - FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4); - dpo_reset (&dpo_v4); - } - else - { - if (!a) - return VNET_API_ERROR_NO_SUCH_ENTRY; -#define _(N, id, n, s) \ - clib_bitmap_free (a->busy_##n##_port_bitmap); \ - vec_free (a->busy_##n##_ports_per_thread); - foreach_snat_protocol -#undef _ - fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi); - vec_del1 (dm->addr_pool, i); - } - return 0; -} - -u8 * -format_dslite_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - dslite_trace_t *t = va_arg (*args, dslite_trace_t *); - - s = - format (s, "next index %d, session %d", t->next_index, t->session_index); - - return s; -} - -u8 * -format_dslite_ce_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - dslite_ce_trace_t *t = va_arg (*args, dslite_ce_trace_t *); - - s = format (s, "next index %d", t->next_index); - - return s; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite.h b/src/plugins/nat/dslite.h deleted file mode 100644 index 65498eebd9d..00000000000 --- a/src/plugins/nat/dslite.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2017 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_dslite_h__ -#define __included_dslite_h__ - -#include -#include -#include -#include - -typedef struct -{ - union - { - struct - { - ip6_address_t softwire_id; - ip4_address_t addr; - u16 port; - u8 proto; - u8 pad; - }; - u64 as_u64[3]; - }; -} dslite_session_key_t; - -/* *INDENT-OFF* */ -typedef CLIB_PACKED (struct -{ - snat_session_key_t out2in; - dslite_session_key_t in2out; - u32 per_b4_index; - u32 per_b4_list_head_index; - f64 last_heard; - u64 total_bytes; - u32 total_pkts; -}) dslite_session_t; -/* *INDENT-ON* */ - -typedef struct -{ - ip6_address_t addr; - u32 sessions_per_b4_list_head_index; - u32 nsessions; -} dslite_b4_t; - -typedef struct -{ - /* Main lookup tables */ - clib_bihash_8_8_t out2in; - clib_bihash_24_8_t in2out; - - /* Find a B4 */ - clib_bihash_16_8_t b4_hash; - - /* B4 pool */ - dslite_b4_t *b4s; - - /* Session pool */ - dslite_session_t *sessions; - - /* Pool of doubly-linked list elements */ - dlist_elt_t *list_pool; -} dslite_per_thread_data_t; - -typedef struct -{ - ip6_address_t aftr_ip6_addr; - ip4_address_t aftr_ip4_addr; - ip6_address_t b4_ip6_addr; - ip4_address_t b4_ip4_addr; - dslite_per_thread_data_t *per_thread_data; - snat_address_t *addr_pool; - u32 num_workers; - u32 first_worker_index; - u16 port_per_thread; - - /* counters/gauges */ - vlib_simple_counter_main_t total_b4s; - vlib_simple_counter_main_t total_sessions; - - /* node index */ - u32 dslite_in2out_node_index; - u32 dslite_in2out_slowpath_node_index; - u32 dslite_out2in_node_index; - - /* If set then the DSLite component behaves as CPE/B4 - * otherwise it behaves as AFTR */ - u8 is_ce; -} dslite_main_t; - -typedef struct -{ - u32 next_index; - u32 session_index; -} dslite_trace_t; - -typedef struct -{ - u32 next_index; -} dslite_ce_trace_t; - -#define foreach_dslite_error \ -_(IN2OUT, "valid in2out DS-Lite packets") \ -_(OUT2IN, "valid out2in DS-Lite packets") \ -_(CE_ENCAP, "valid CE encap DS-Lite packets") \ -_(CE_DECAP, "valid CE decap DS-Lite packets") \ -_(NO_TRANSLATION, "no translation") \ -_(BAD_IP6_PROTOCOL, "bad ip6 protocol") \ -_(OUT_OF_PORTS, "out of ports") \ -_(UNSUPPORTED_PROTOCOL, "unsupported protocol") \ -_(BAD_ICMP_TYPE, "unsupported icmp type") \ -_(UNKNOWN, "unknown") - -typedef enum -{ -#define _(sym,str) DSLITE_ERROR_##sym, - foreach_dslite_error -#undef _ - DSLITE_N_ERROR, -} dslite_error_t; - -extern dslite_main_t dslite_main; -extern vlib_node_registration_t dslite_in2out_node; -extern vlib_node_registration_t dslite_in2out_slowpath_node; -extern vlib_node_registration_t dslite_out2in_node; -extern vlib_node_registration_t dslite_ce_encap_node; -extern vlib_node_registration_t dslite_ce_decap_node; - -void dslite_init (vlib_main_t * vm); -void dslite_set_ce (dslite_main_t * dm, u8 set); -int dslite_set_aftr_ip6_addr (dslite_main_t * dm, ip6_address_t * addr); -int dslite_set_b4_ip6_addr (dslite_main_t * dm, ip6_address_t * addr); -int dslite_set_aftr_ip4_addr (dslite_main_t * dm, ip4_address_t * addr); -int dslite_set_b4_ip4_addr (dslite_main_t * dm, ip4_address_t * addr); -int dslite_add_del_pool_addr (dslite_main_t * dm, ip4_address_t * addr, - u8 is_add); -u8 *format_dslite_trace (u8 * s, va_list * args); -u8 *format_dslite_ce_trace (u8 * s, va_list * args); - -#endif /* __included_dslite_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite/dslite.api b/src/plugins/nat/dslite/dslite.api new file mode 100644 index 00000000000..b5f8c5ba833 --- /dev/null +++ b/src/plugins/nat/dslite/dslite.api @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2019 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. + */ + +option version = "1.0.0"; +import "vnet/ip/ip_types.api"; +import "vnet/interface_types.api"; + +/** + * @file nat.api + * @brief VPP control-plane API messages. + * + * This file defines VPP control-plane API messages which are generally + * called through a shared memory interface. + */ + + +/* + * DS-Lite APIs + */ + +/** \brief Add/delete address range to DS-Lite pool + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param start_addr - start IPv4 address of the range + @param end_addr - end IPv4 address of the range + @param is_add - true if add, false if delete +*/ +autoreply define dslite_add_del_pool_addr_range { + u32 client_index; + u32 context; + vl_api_ip4_address_t start_addr; + vl_api_ip4_address_t end_addr; + bool is_add; +}; + +/** \brief Dump DS-Lite addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define dslite_address_dump { + u32 client_index; + u32 context; +}; + +/** \brief DS-Lite address details response + @param context - sender context, to match reply w/ request + @param ip_address - IPv4 address +*/ +define dslite_address_details { + u32 context; + vl_api_ip4_address_t ip_address; +}; + +/** \brief Set AFTR IPv6 and IPv4 addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ip4_addr - IPv4 address + @param ip6_addr - IPv6 address +*/ +autoreply define dslite_set_aftr_addr { + u32 client_index; + u32 context; + vl_api_ip4_address_t ip4_addr; + vl_api_ip6_address_t ip6_addr; +}; + +/** \brief Get AFTR IPv6 and IPv4 addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define dslite_get_aftr_addr { + u32 client_index; + u32 context; +}; + +/** \brief Response to get AFTR IPv6 and IPv4 addresses + @param context - sender context, to match reply w/ request + @param retval - return code + @param ip4_addr - IPv4 address + @param ip6_addr - IPv6 address +*/ +define dslite_get_aftr_addr_reply { + u32 context; + i32 retval; + vl_api_ip4_address_t ip4_addr; + vl_api_ip6_address_t ip6_addr; +}; + +/** \brief Set B4 IPv6 and IPv4 addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ip4_addr - IPv4 address + @param ip6_addr - IPv6 address +*/ +autoreply define dslite_set_b4_addr { + u32 client_index; + u32 context; + vl_api_ip4_address_t ip4_addr; + vl_api_ip6_address_t ip6_addr; +}; + +/** \brief Get B4 IPv6 and IPv4 addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define dslite_get_b4_addr { + u32 client_index; + u32 context; +}; + +/** \brief Response to get B4 IPv6 and IPv4 addresses + @param context - sender context, to match reply w/ request + @param retval - return code + @param ip4_addr - IPv4 address + @param ip6_addr - IPv6 address +*/ +define dslite_get_b4_addr_reply { + u32 context; + i32 retval; + vl_api_ip4_address_t ip4_addr; + vl_api_ip6_address_t ip6_addr; +}; diff --git a/src/plugins/nat/dslite/dslite.c b/src/plugins/nat/dslite/dslite.c new file mode 100644 index 00000000000..e03dd0c8431 --- /dev/null +++ b/src/plugins/nat/dslite/dslite.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2017 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. + */ +#include +#include +#include +#include +#include + +dslite_main_t dslite_main; +fib_source_t nat_fib_src_hi; + +clib_error_t *dslite_api_hookup (vlib_main_t * vm); + +void +add_del_dslite_pool_addr_cb (ip4_address_t addr, u8 is_add, void *opaque); + +static clib_error_t * +dslite_init (vlib_main_t * vm) +{ + dslite_main_t *dm = &dslite_main; + vlib_thread_registration_t *tr; + vlib_thread_main_t *tm = vlib_get_thread_main (); + uword *p; + vlib_node_t *node; + dslite_per_thread_data_t *td; + u32 translation_buckets = 1024; + u32 translation_memory_size = 128 << 20; + u32 b4_buckets = 128; + u32 b4_memory_size = 64 << 20; + + node = vlib_get_node_by_name (vm, (u8 *) "dslite-in2out"); + dm->dslite_in2out_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "dslite-in2out-slowpath"); + dm->dslite_in2out_slowpath_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "dslite-out2in"); + dm->dslite_out2in_node_index = node->index; + + dm->first_worker_index = 0; + dm->num_workers = 0; + + // init nat address pool + dm->pool.add_del_pool_addr_cb = add_del_dslite_pool_addr_cb; + dm->pool.alloc_addr_and_port_cb = nat_alloc_ip4_addr_and_port_cb_default; + + p = hash_get_mem (tm->thread_registrations_by_name, "workers"); + if (p) + { + tr = (vlib_thread_registration_t *) p[0]; + if (tr) + { + dm->num_workers = tr->count; + dm->first_worker_index = tr->first_index; + } + } + + if (dm->num_workers) + dm->port_per_thread = (0xffff - 1024) / dm->num_workers; + else + dm->port_per_thread = 0xffff - 1024; + + vec_validate (dm->per_thread_data, tm->n_vlib_mains - 1); + + /* *INDENT-OFF* */ + vec_foreach (td, dm->per_thread_data) + { + clib_bihash_init_24_8 (&td->in2out, "in2out", translation_buckets, + translation_memory_size); + + clib_bihash_init_8_8 (&td->out2in, "out2in", translation_buckets, + translation_memory_size); + + clib_bihash_init_16_8 (&td->b4_hash, "b4s", b4_buckets, b4_memory_size); + } + /* *INDENT-ON* */ + + dm->is_ce = 0; + + /* Init counters */ + dm->total_b4s.name = "total-b4s"; + dm->total_b4s.stat_segment_name = "/dslite/total-b4s"; + vlib_validate_simple_counter (&dm->total_b4s, 0); + vlib_zero_simple_counter (&dm->total_b4s, 0); + dm->total_sessions.name = "total-sessions"; + dm->total_sessions.stat_segment_name = "/dslite/total-sessions"; + vlib_validate_simple_counter (&dm->total_sessions, 0); + vlib_zero_simple_counter (&dm->total_sessions, 0); + + dslite_dpo_module_init (); + + nat_fib_src_hi = fib_source_allocate ("dslite-hi", + FIB_SOURCE_PRIORITY_HI, + FIB_SOURCE_BH_SIMPLE); + + return dslite_api_hookup (vm); +} + +void +dslite_set_ce (dslite_main_t * dm, u8 set) +{ + dm->is_ce = (set != 0); +} + +int +dslite_set_aftr_ip6_addr (dslite_main_t * dm, ip6_address_t * addr) +{ + dpo_id_t dpo = DPO_INVALID; + + if (dm->is_ce) + { + dslite_ce_dpo_create (DPO_PROTO_IP4, 0, &dpo); + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 0, + .fp_addr.ip4.as_u32 = 0, + }; + fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, + FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); + } + else + { + dslite_dpo_create (DPO_PROTO_IP6, 0, &dpo); + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = 128, + .fp_addr.ip6.as_u64[0] = addr->as_u64[0], + .fp_addr.ip6.as_u64[1] = addr->as_u64[1], + }; + fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, + FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); + } + + dpo_reset (&dpo); + + dm->aftr_ip6_addr.as_u64[0] = addr->as_u64[0]; + dm->aftr_ip6_addr.as_u64[1] = addr->as_u64[1]; + return 0; +} + +int +dslite_set_aftr_ip4_addr (dslite_main_t * dm, ip4_address_t * addr) +{ + dm->aftr_ip4_addr.as_u32 = addr->as_u32; + return 0; +} + +int +dslite_set_b4_ip6_addr (dslite_main_t * dm, ip6_address_t * addr) +{ + if (dm->is_ce) + { + dpo_id_t dpo = DPO_INVALID; + + dslite_ce_dpo_create (DPO_PROTO_IP6, 0, &dpo); + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = 128, + .fp_addr.ip6.as_u64[0] = addr->as_u64[0], + .fp_addr.ip6.as_u64[1] = addr->as_u64[1], + }; + fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, + FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); + + dpo_reset (&dpo); + + dm->b4_ip6_addr.as_u64[0] = addr->as_u64[0]; + dm->b4_ip6_addr.as_u64[1] = addr->as_u64[1]; + } + else + { + return VNET_API_ERROR_FEATURE_DISABLED; + } + + return 0; +} + +int +dslite_set_b4_ip4_addr (dslite_main_t * dm, ip4_address_t * addr) +{ + if (dm->is_ce) + { + dm->b4_ip4_addr.as_u32 = addr->as_u32; + } + else + { + return VNET_API_ERROR_FEATURE_DISABLED; + } + + return 0; +} + +void +add_del_dslite_pool_addr_cb (ip4_address_t addr, u8 is_add, void *opaque) +{ + dpo_id_t dpo_v4 = DPO_INVALID; + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr.ip4.as_u32 = addr.as_u32, + }; + + if (is_add) + { + dslite_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4); + fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi, + FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4); + dpo_reset (&dpo_v4); + } + else + { + fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi); + } +} + +u8 * +format_dslite_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + dslite_trace_t *t = va_arg (*args, dslite_trace_t *); + + s = + format (s, "next index %d, session %d", t->next_index, t->session_index); + + return s; +} + +u8 * +format_dslite_ce_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + dslite_ce_trace_t *t = va_arg (*args, dslite_ce_trace_t *); + + s = format (s, "next index %d", t->next_index); + + return s; +} + +VLIB_INIT_FUNCTION (dslite_init); + +VLIB_PLUGIN_REGISTER () = +{ +.version = VPP_BUILD_VER,.description = "Dual-Stack Lite",}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite.h b/src/plugins/nat/dslite/dslite.h new file mode 100644 index 00000000000..d512cf47c9b --- /dev/null +++ b/src/plugins/nat/dslite/dslite.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017 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_dslite_h__ +#define __included_dslite_h__ + +#include +#include +#include +#include +#include +#include + +typedef struct +{ + union + { + struct + { + ip6_address_t softwire_id; + ip4_address_t addr; + u16 port; + u8 proto; + u8 pad; + }; + u64 as_u64[3]; + }; +} dslite_session_key_t; + +/* *INDENT-OFF* */ +typedef CLIB_PACKED (struct +{ + snat_session_key_t out2in; + dslite_session_key_t in2out; + u32 per_b4_index; + u32 per_b4_list_head_index; + f64 last_heard; + u64 total_bytes; + u32 total_pkts; +}) dslite_session_t; +/* *INDENT-ON* */ + +typedef struct +{ + ip6_address_t addr; + u32 sessions_per_b4_list_head_index; + u32 nsessions; +} dslite_b4_t; + +typedef struct +{ + /* Main lookup tables */ + clib_bihash_8_8_t out2in; + clib_bihash_24_8_t in2out; + + /* Find a B4 */ + clib_bihash_16_8_t b4_hash; + + /* B4 pool */ + dslite_b4_t *b4s; + + /* Session pool */ + dslite_session_t *sessions; + + /* Pool of doubly-linked list elements */ + dlist_elt_t *list_pool; +} dslite_per_thread_data_t; + +typedef struct +{ + ip6_address_t aftr_ip6_addr; + ip4_address_t aftr_ip4_addr; + ip6_address_t b4_ip6_addr; + ip4_address_t b4_ip4_addr; + dslite_per_thread_data_t *per_thread_data; + u32 num_workers; + u32 first_worker_index; + u16 port_per_thread; + + /* nat address pool */ + nat_ip4_pool_t pool; + + /* counters/gauges */ + vlib_simple_counter_main_t total_b4s; + vlib_simple_counter_main_t total_sessions; + + /* node index */ + u32 dslite_in2out_node_index; + u32 dslite_in2out_slowpath_node_index; + u32 dslite_out2in_node_index; + + /* If set then the DSLite component behaves as CPE/B4 + * otherwise it behaves as AFTR */ + u8 is_ce; + + u16 msg_id_base; +} dslite_main_t; + +typedef struct +{ + u32 next_index; + u32 session_index; +} dslite_trace_t; + +typedef struct +{ + u32 next_index; +} dslite_ce_trace_t; + +#define foreach_dslite_error \ +_(IN2OUT, "valid in2out DS-Lite packets") \ +_(OUT2IN, "valid out2in DS-Lite packets") \ +_(CE_ENCAP, "valid CE encap DS-Lite packets") \ +_(CE_DECAP, "valid CE decap DS-Lite packets") \ +_(NO_TRANSLATION, "no translation") \ +_(BAD_IP6_PROTOCOL, "bad ip6 protocol") \ +_(OUT_OF_PORTS, "out of ports") \ +_(UNSUPPORTED_PROTOCOL, "unsupported protocol") \ +_(BAD_ICMP_TYPE, "unsupported icmp type") \ +_(UNKNOWN, "unknown") + +typedef enum +{ +#define _(sym,str) DSLITE_ERROR_##sym, + foreach_dslite_error +#undef _ + DSLITE_N_ERROR, +} dslite_error_t; + +extern dslite_main_t dslite_main; +extern vlib_node_registration_t dslite_in2out_node; +extern vlib_node_registration_t dslite_in2out_slowpath_node; +extern vlib_node_registration_t dslite_out2in_node; +extern vlib_node_registration_t dslite_ce_encap_node; +extern vlib_node_registration_t dslite_ce_decap_node; + +void dslite_set_ce (dslite_main_t * dm, u8 set); +int dslite_set_aftr_ip6_addr (dslite_main_t * dm, ip6_address_t * addr); +int dslite_set_b4_ip6_addr (dslite_main_t * dm, ip6_address_t * addr); +int dslite_set_aftr_ip4_addr (dslite_main_t * dm, ip4_address_t * addr); +int dslite_set_b4_ip4_addr (dslite_main_t * dm, ip4_address_t * addr); +int dslite_add_del_pool_addr (dslite_main_t * dm, ip4_address_t * addr, + u8 is_add); +u8 *format_dslite_trace (u8 * s, va_list * args); +u8 *format_dslite_ce_trace (u8 * s, va_list * args); + +#endif /* __included_dslite_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_api.c b/src/plugins/nat/dslite/dslite_api.c new file mode 100644 index 00000000000..420e8212ad9 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_api.c @@ -0,0 +1,177 @@ +/* + *------------------------------------------------------------------ + * dslite_api.c - DS-Lite API + * + * Copyright (c) 2019 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. + *------------------------------------------------------------------ + */ +#include +#include +#include +#include +#include +#include +#include + +#define REPLY_MSG_ID_BASE dm->msg_id_base +#include + +static void +vl_api_dslite_set_aftr_addr_t_handler (vl_api_dslite_set_aftr_addr_t * mp) +{ + vl_api_dslite_set_aftr_addr_reply_t *rmp; + dslite_main_t *dm = &dslite_main; + int rv = 0; + ip6_address_t ip6_addr; + ip4_address_t ip4_addr; + + memcpy (&ip6_addr.as_u8, mp->ip6_addr, 16); + memcpy (&ip4_addr.as_u8, mp->ip4_addr, 4); + + rv = dslite_set_aftr_ip6_addr (dm, &ip6_addr); + if (rv == 0) + rv = dslite_set_aftr_ip4_addr (dm, &ip4_addr); + + REPLY_MACRO (VL_API_DSLITE_SET_AFTR_ADDR_REPLY); +} + +static void +vl_api_dslite_get_aftr_addr_t_handler (vl_api_dslite_get_aftr_addr_t * mp) +{ + vl_api_dslite_get_aftr_addr_reply_t *rmp; + dslite_main_t *dm = &dslite_main; + int rv = 0; + + /* *INDENT-OFF* */ + REPLY_MACRO2 (VL_API_DSLITE_GET_AFTR_ADDR_REPLY, + ({ + memcpy (rmp->ip4_addr, &dm->aftr_ip4_addr.as_u8, 4); + memcpy (rmp->ip6_addr, &dm->aftr_ip6_addr.as_u8, 16); + })) + /* *INDENT-ON* */ +} + +static void +vl_api_dslite_set_b4_addr_t_handler (vl_api_dslite_set_b4_addr_t * mp) +{ + vl_api_dslite_set_b4_addr_reply_t *rmp; + dslite_main_t *dm = &dslite_main; + int rv = 0; + ip6_address_t ip6_addr; + ip4_address_t ip4_addr; + + memcpy (&ip6_addr.as_u8, mp->ip6_addr, 16); + memcpy (&ip4_addr.as_u8, mp->ip4_addr, 4); + + rv = dslite_set_b4_ip6_addr (dm, &ip6_addr); + if (rv == 0) + rv = dslite_set_b4_ip4_addr (dm, &ip4_addr); + + REPLY_MACRO (VL_API_DSLITE_SET_B4_ADDR_REPLY); +} + +static void +vl_api_dslite_get_b4_addr_t_handler (vl_api_dslite_get_b4_addr_t * mp) +{ + vl_api_dslite_get_b4_addr_reply_t *rmp; + dslite_main_t *dm = &dslite_main; + int rv = 0; + + /* *INDENT-OFF* */ + REPLY_MACRO2 (VL_API_DSLITE_GET_B4_ADDR_REPLY, + ({ + memcpy (rmp->ip4_addr, &dm->b4_ip4_addr.as_u8, 4); + memcpy (rmp->ip6_addr, &dm->b4_ip6_addr.as_u8, 16); + })) + /* *INDENT-ON* */ +} + +static void + vl_api_dslite_add_del_pool_addr_range_t_handler + (vl_api_dslite_add_del_pool_addr_range_t * mp) +{ + vl_api_dslite_add_del_pool_addr_range_reply_t *rmp; + dslite_main_t *dm = &dslite_main; + int rv = 0; + ip4_address_t this_addr; + u32 start_host_order, end_host_order; + int count; + u32 *tmp; + + tmp = (u32 *) mp->start_addr; + start_host_order = clib_host_to_net_u32 (tmp[0]); + tmp = (u32 *) mp->end_addr; + end_host_order = clib_host_to_net_u32 (tmp[0]); + + // TODO: + // end_host_order < start_host_order + + count = (end_host_order - start_host_order) + 1; + memcpy (&this_addr.as_u8, mp->start_addr, 4); + + rv = nat_add_del_ip4_pool_addrs (&dm->pool, this_addr, count, mp->is_add, 0); + + REPLY_MACRO (VL_API_DSLITE_ADD_DEL_POOL_ADDR_RANGE_REPLY); +} + +static void +send_dslite_address_details (nat_ip4_pool_addr_t * a, + vl_api_registration_t * reg, u32 context) +{ + dslite_main_t *dm = &dslite_main; + vl_api_dslite_address_details_t *rmp; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + + clib_memset (rmp, 0, sizeof (*rmp)); + + rmp->_vl_msg_id = ntohs (VL_API_DSLITE_ADDRESS_DETAILS + dm->msg_id_base); + clib_memcpy (rmp->ip_address, &(a->addr), 4); + rmp->context = context; + + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void +vl_api_dslite_address_dump_t_handler (vl_api_dslite_address_dump_t * mp) +{ + vl_api_registration_t *reg; + dslite_main_t *dm = &dslite_main; + nat_ip4_pool_addr_t *a; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + /* *INDENT-OFF* */ + vec_foreach (a, dm->pool.pool_addr) + { + send_dslite_address_details (a, reg, mp->context); + } + /* *INDENT-ON* */ +} + +/* API definitions */ +#include +#include + +/* Set up the API message handling tables */ +clib_error_t * +dslite_api_hookup (vlib_main_t * vm) +{ + dslite_main_t *dm = &dslite_main; + + dm->msg_id_base = setup_message_id_table (); + return 0; +} diff --git a/src/plugins/nat/dslite/dslite_ce_decap.c b/src/plugins/nat/dslite/dslite_ce_decap.c new file mode 100644 index 00000000000..3d6ca992e45 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_ce_decap.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2018 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. + */ +#include +#include + +typedef enum +{ + DSLITE_CE_DECAP_NEXT_IP4_LOOKUP, + DSLITE_IN2OUT_NEXT_IP6_ICMP, + DSLITE_CE_DECAP_NEXT_DROP, + DSLITE_CE_DECAP_N_NEXT, +} dslite_ce_decap_next_t; + +static char *dslite_ce_decap_error_strings[] = { +#define _(sym,string) string, + foreach_dslite_error +#undef _ +}; + +VLIB_NODE_FN (dslite_ce_decap_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + dslite_ce_decap_next_t next_index; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = DSLITE_CE_DECAP_NEXT_IP4_LOOKUP; + u8 error0 = DSLITE_ERROR_CE_DECAP; + ip4_header_t *ip40; + ip6_header_t *ip60; + u32 proto0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip60 = vlib_buffer_get_current (b0); + + if (PREDICT_FALSE (ip60->protocol != IP_PROTOCOL_IP_IN_IP)) + { + if (ip60->protocol == IP_PROTOCOL_ICMP6) + { + next0 = DSLITE_IN2OUT_NEXT_IP6_ICMP; + goto trace0; + } + error0 = DSLITE_ERROR_BAD_IP6_PROTOCOL; + next0 = DSLITE_CE_DECAP_NEXT_DROP; + goto trace0; + } + + ip40 = vlib_buffer_get_current (b0) + sizeof (ip6_header_t); + proto0 = ip_proto_to_snat_proto (ip40->protocol); + + if (PREDICT_FALSE (proto0 == ~0)) + { + error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; + next0 = DSLITE_CE_DECAP_NEXT_DROP; + goto trace0; + } + + ip40->tos = + (clib_net_to_host_u32 + (ip60->ip_version_traffic_class_and_flow_label) & 0x0ff00000) >> + 20; + vlib_buffer_advance (b0, sizeof (ip6_header_t)); + + trace0: + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + } + + b0->error = node->errors[error0]; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dslite_ce_decap_node) = { + .name = "dslite-ce-decap", + .vector_size = sizeof (u32), + .format_trace = format_dslite_ce_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (dslite_ce_decap_error_strings), + .error_strings = dslite_ce_decap_error_strings, + .n_next_nodes = DSLITE_CE_DECAP_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = { + [DSLITE_CE_DECAP_NEXT_DROP] = "error-drop", + [DSLITE_CE_DECAP_NEXT_IP4_LOOKUP] = "ip4-lookup", + [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-icmp-input", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_ce_encap.c b/src/plugins/nat/dslite/dslite_ce_encap.c new file mode 100644 index 00000000000..8cec5439243 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_ce_encap.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018 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. + */ +#include +#include + +typedef enum +{ + DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP, + DSLITE_CE_ENCAP_NEXT_DROP, + DSLITE_CE_ENCAP_N_NEXT, +} dslite_ce_encap_next_t; + +static char *dslite_ce_encap_error_strings[] = { +#define _(sym,string) string, + foreach_dslite_error +#undef _ +}; + +VLIB_NODE_FN (dslite_ce_encap_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + dslite_ce_encap_next_t next_index; + dslite_main_t *dm = &dslite_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP; + u8 error0 = DSLITE_ERROR_CE_ENCAP; + ip4_header_t *ip40; + ip6_header_t *ip60; + u32 proto0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip40 = vlib_buffer_get_current (b0); + proto0 = ip_proto_to_snat_proto (ip40->protocol); + + if (PREDICT_FALSE (proto0 == ~0)) + { + error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; + next0 = DSLITE_CE_ENCAP_NEXT_DROP; + goto trace0; + } + + /* Construct IPv6 header */ + vlib_buffer_advance (b0, -(sizeof (ip6_header_t))); + ip60 = vlib_buffer_get_current (b0); + ip60->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 ((6 << 28) + (ip40->tos << 20)); + ip60->payload_length = ip40->length; + ip60->protocol = IP_PROTOCOL_IP_IN_IP; + ip60->hop_limit = ip40->ttl; + ip60->dst_address.as_u64[0] = dm->aftr_ip6_addr.as_u64[0]; + ip60->dst_address.as_u64[1] = dm->aftr_ip6_addr.as_u64[1]; + ip60->src_address.as_u64[0] = dm->b4_ip6_addr.as_u64[0]; + ip60->src_address.as_u64[1] = dm->b4_ip6_addr.as_u64[1]; + + trace0: + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + } + + b0->error = node->errors[error0]; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dslite_ce_encap_node) = { + .name = "dslite-ce-encap", + .vector_size = sizeof (u32), + .format_trace = format_dslite_ce_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (dslite_ce_encap_error_strings), + .error_strings = dslite_ce_encap_error_strings, + .n_next_nodes = DSLITE_CE_ENCAP_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = { + [DSLITE_CE_ENCAP_NEXT_DROP] = "error-drop", + [DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_cli.c b/src/plugins/nat/dslite/dslite_cli.c new file mode 100644 index 00000000000..d5c0ca6498b --- /dev/null +++ b/src/plugins/nat/dslite/dslite_cli.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2017 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. + */ + +#include + +static clib_error_t * +dslite_add_del_pool_addr_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + unformat_input_t _line_input, *line_input = &_line_input; + ip4_address_t start_addr, end_addr, this_addr; + u32 start_host_order, end_host_order; + int count, rv; + u8 is_add = 1; + clib_error_t *error = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U - %U", + unformat_ip4_address, &start_addr, + unformat_ip4_address, &end_addr)) + ; + else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) + end_addr = start_addr; + else if (unformat (line_input, "del")) + is_add = 0; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } + + start_host_order = clib_host_to_net_u32 (start_addr.as_u32); + end_host_order = clib_host_to_net_u32 (end_addr.as_u32); + + if (end_host_order < start_host_order) + { + error = clib_error_return (0, "end address less than start address"); + goto done; + } + + count = (end_host_order - start_host_order) + 1; + this_addr = start_addr; + + rv = nat_add_del_ip4_pool_addrs (&dm->pool, this_addr, count, is_add, 0); + + switch (rv) + { + case VNET_API_ERROR_NO_SUCH_ENTRY: + error = + clib_error_return (0, "DS-Lite pool address %U not exist.", + format_ip4_address, &this_addr); + break; + case VNET_API_ERROR_VALUE_EXIST: + error = + clib_error_return (0, "DS-Lite pool address %U exist.", + format_ip4_address, &this_addr); + break; + } + +done: + unformat_free (line_input); + + return error; +} + +static clib_error_t * +dslite_show_pool_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + nat_ip4_pool_addr_t *a; + + vlib_cli_output (vm, "DS-Lite pool:"); + + /* *INDENT-OFF* */ + vec_foreach (a, dm->pool.pool_addr) + { + vlib_cli_output (vm, "%U", format_ip4_address, &a->addr); + } + /* *INDENT-ON* */ + return 0; +} + +static clib_error_t * +dslite_set_aftr_tunnel_addr_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + unformat_input_t _line_input, *line_input = &_line_input; + ip6_address_t ip6_addr; + int rv; + clib_error_t *error = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_ip6_address, &ip6_addr)) + ; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } + + rv = dslite_set_aftr_ip6_addr (dm, &ip6_addr); + + if (rv) + error = + clib_error_return (0, + "Set DS-Lite AFTR tunnel endpoint address failed."); + +done: + unformat_free (line_input); + + return error; +} + +static clib_error_t * +dslite_show_aftr_ip6_addr_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + + vlib_cli_output (vm, "%U", format_ip6_address, &dm->aftr_ip6_addr); + return 0; +} + +static clib_error_t * +dslite_set_b4_tunnel_addr_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + unformat_input_t _line_input, *line_input = &_line_input; + ip6_address_t ip6_addr; + int rv; + clib_error_t *error = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_ip6_address, &ip6_addr)) + ; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } + + rv = dslite_set_b4_ip6_addr (dm, &ip6_addr); + + if (rv) + error = + clib_error_return (0, "Set DS-Lite B4 tunnel endpoint address failed."); + +done: + unformat_free (line_input); + + return error; +} + +static clib_error_t * +dslite_show_b4_ip6_addr_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + + vlib_cli_output (vm, "%U", format_ip6_address, &dm->b4_ip6_addr); + return 0; +} + +static u8 * +format_dslite_session (u8 * s, va_list * args) +{ + dslite_session_t *session = va_arg (*args, dslite_session_t *); + u32 indent = format_get_indent (s); + + s = format (s, "%Uin %U:%u out %U:%u protocol %U\n", + format_white_space, indent + 2, + format_ip4_address, &session->in2out.addr, + clib_net_to_host_u16 (session->in2out.port), + format_ip4_address, &session->out2in.addr, + clib_net_to_host_u16 (session->out2in.port), + format_snat_protocol, session->in2out.proto); + s = format (s, "%Utotal pkts %d, total bytes %lld\n", + format_white_space, indent + 4, + session->total_pkts, session->total_bytes); + return s; +} + +static u8 * +format_dslite_b4 (u8 * s, va_list * args) +{ + dslite_per_thread_data_t *td = va_arg (*args, dslite_per_thread_data_t *); + dslite_b4_t *b4 = va_arg (*args, dslite_b4_t *); + dlist_elt_t *head, *elt; + u32 elt_index, head_index; + u32 session_index; + dslite_session_t *session; + + s = + format (s, "B4 %U %d sessions\n", format_ip6_address, &b4->addr, + b4->nsessions); + + if (b4->nsessions == 0) + return s; + + head_index = b4->sessions_per_b4_list_head_index; + head = pool_elt_at_index (td->list_pool, head_index); + elt_index = head->next; + elt = pool_elt_at_index (td->list_pool, elt_index); + session_index = elt->value; + while (session_index != ~0) + { + session = pool_elt_at_index (td->sessions, session_index); + s = format (s, "%U", format_dslite_session, session); + elt_index = elt->next; + elt = pool_elt_at_index (td->list_pool, elt_index); + session_index = elt->value; + } + + return s; +} + +static clib_error_t * +dslite_show_sessions_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dslite_main_t *dm = &dslite_main; + dslite_per_thread_data_t *td; + dslite_b4_t *b4; + + /* *INDENT-OFF* */ + vec_foreach (td, dm->per_thread_data) + { + pool_foreach (b4, td->b4s, + ({ + vlib_cli_output (vm, "%U", format_dslite_b4, td, b4); + })); + } + /* *INDENT-ON* */ + + return 0; +} + +/* *INDENT-OFF* */ + +/*? + * @cliexpar + * @cliexstart{dslite add pool address} + * Add/delete DS-Lite pool address for AFTR element. + * To add DS-Lite pool address use: + * vpp# dslite add pool address 10.1.1.3 + * To add DS-Lite pool address range use: + * vpp# dslite add pool address 10.1.1.5 - 10.1.1.7 + * @cliexend +?*/ +VLIB_CLI_COMMAND (dslite_add_pool_address_command, static) = { + .path = "dslite add pool address", + .short_help = "dslite add pool address [- ] " + " [del]", + .function = dslite_add_del_pool_addr_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{show dslite pool} + * Show DS-lite pool addresses. + * vpp# show dslite pool + * DS-Lite pool: + * 10.0.0.3 + * 10.0.0.5 + * 10.0.0.6 + * 10.0.0.7 + * @cliexend +?*/ +VLIB_CLI_COMMAND (show_dslite_pool_command, static) = { + .path = "show dslite pool", + .short_help = "show dslite pool", + .function = dslite_show_pool_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{dslite set aftr-tunnel-endpoint-address} + * Set IPv6 tunnel endpoint address of the AFTR element. + * To set AFTR tunnel endpoint address use: + * vpp# dslite set aftr-tunnel-endpoint-address 2001:db8:85a3::8a2e:370:1 + * @cliexend +?*/ +VLIB_CLI_COMMAND (dslite_set_aftr_tunnel_addr, static) = { + .path = "dslite set aftr-tunnel-endpoint-address", + .short_help = "dslite set aftr-tunnel-endpoint-address ", + .function = dslite_set_aftr_tunnel_addr_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{show dslite aftr-tunnel-endpoint-address} + * Show IPv6 tunnel endpoint address of the AFTR element. + * vpp# show dslite aftr-tunnel-endpoint-address + * 2001:db8:85a3::8a2e:370:1 + * @cliexend +?*/ +VLIB_CLI_COMMAND (dslite_show_aftr_ip6_addr, static) = { + .path = "show dslite aftr-tunnel-endpoint-address", + .short_help = "show dslite aftr-tunnel-endpoint-address", + .function = dslite_show_aftr_ip6_addr_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{dslite set b4-tunnel-endpoint-address} + * Set IPv6 tunnel endpoint address of the B4 element. + * To set B4 tunnel endpoint address use: + * vpp# dslite set b4-tunnel-endpoint-address 2001:db8:62aa::375e:f4c1:1 + * @cliexend +?*/ +VLIB_CLI_COMMAND (dslite_set_b4_tunnel_addr, static) = { + .path = "dslite set b4-tunnel-endpoint-address", + .short_help = "dslite set b4-tunnel-endpoint-address ", + .function = dslite_set_b4_tunnel_addr_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{show dslite b4-tunnel-endpoint-address} + * Show IPv6 tunnel endpoint address of the B4 element. + * vpp# show dslite b4-tunnel-endpoint-address + * 2001:db8:62aa::375e:f4c1:1 + * @cliexend +?*/ +VLIB_CLI_COMMAND (dslite_show_b4_ip6_addr, static) = { + .path = "show dslite b4-tunnel-endpoint-address", + .short_help = "show dslite b4-tunnel-endpoint-address", + .function = dslite_show_b4_ip6_addr_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{show dslite sessions} + * Show DS-Lite sessions. + * vpp# show dslite sessions + * B4 fd01:2::2 1 sessions + * in 192.168.1.1:20000 out 10.0.0.3:16253 protocol udp + * total pkts 2, total bytes 136 + * B4 fd01:2::3 2 sessions + * in 192.168.1.1:20001 out 10.0.0.3:18995 protocol tcp + * total pkts 2, total bytes 160 + * in 192.168.1.1:4000 out 10.0.0.3:53893 protocol icmp + * total pkts 2, total bytes 136 + * @cliexend +?*/ +VLIB_CLI_COMMAND (dslite_show_sessions, static) = { + .path = "show dslite sessions", + .short_help = "show dslite sessions", + .function = dslite_show_sessions_command_fn, +}; + +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_dpo.c b/src/plugins/nat/dslite/dslite_dpo.c new file mode 100644 index 00000000000..009b5536289 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_dpo.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017 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. + */ + +#include +#include + +dpo_type_t dslite_dpo_type; +dpo_type_t dslite_ce_dpo_type; + +void +dslite_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t * dpo) +{ + dpo_set (dpo, dslite_dpo_type, dproto, aftr_index); +} + +void +dslite_ce_dpo_create (dpo_proto_t dproto, u32 b4_index, dpo_id_t * dpo) +{ + dpo_set (dpo, dslite_ce_dpo_type, dproto, b4_index); +} + +u8 * +format_dslite_dpo (u8 * s, va_list * args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED (u32 indent) = va_arg (*args, u32); + + return (format (s, "DS-Lite: AFTR:%d", index)); +} + +u8 * +format_dslite_ce_dpo (u8 * s, va_list * args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED (u32 indent) = va_arg (*args, u32); + + return (format (s, "DS-Lite: B4:%d", index)); +} + +static void +dslite_dpo_lock (dpo_id_t * dpo) +{ +} + +static void +dslite_dpo_unlock (dpo_id_t * dpo) +{ +} + +static void +dslite_ce_dpo_lock (dpo_id_t * dpo) +{ +} + +static void +dslite_ce_dpo_unlock (dpo_id_t * dpo) +{ +} + +const static dpo_vft_t dslite_dpo_vft = { + .dv_lock = dslite_dpo_lock, + .dv_unlock = dslite_dpo_unlock, + .dv_format = format_dslite_dpo, +}; + +const static dpo_vft_t dslite_ce_dpo_vft = { + .dv_lock = dslite_ce_dpo_lock, + .dv_unlock = dslite_ce_dpo_unlock, + .dv_format = format_dslite_ce_dpo, +}; + +const static char *const dslite_ip4_nodes[] = { + "dslite-out2in", + NULL, +}; + +const static char *const dslite_ip6_nodes[] = { + "dslite-in2out", + NULL, +}; + +const static char *const dslite_ce_ip4_nodes[] = { + "dslite-ce-encap", + NULL, +}; + +const static char *const dslite_ce_ip6_nodes[] = { + "dslite-ce-decap", + NULL, +}; + +const static char *const *const dslite_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP4] = dslite_ip4_nodes, + [DPO_PROTO_IP6] = dslite_ip6_nodes, + [DPO_PROTO_MPLS] = NULL, +}; + +const static char *const *const dslite_ce_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP4] = dslite_ce_ip4_nodes, + [DPO_PROTO_IP6] = dslite_ce_ip6_nodes, + [DPO_PROTO_MPLS] = NULL, +}; + +void +dslite_dpo_module_init (void) +{ + dslite_dpo_type = dpo_register_new_type (&dslite_dpo_vft, dslite_nodes); + dslite_ce_dpo_type = dpo_register_new_type (&dslite_ce_dpo_vft, + dslite_ce_nodes); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_dpo.h b/src/plugins/nat/dslite/dslite_dpo.h new file mode 100644 index 00000000000..53d37b27fb4 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_dpo.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 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_dslite_dpo_h__ +#define __included_dslite_dpo_h__ + +#include +#include + +void dslite_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t * dpo); +void dslite_ce_dpo_create (dpo_proto_t dproto, u32 b4_index, dpo_id_t * dpo); + +u8 *format_dslite_dpo (u8 * s, va_list * args); +u8 *format_dslite_ce_dpo (u8 * s, va_list * args); + +void dslite_dpo_module_init (void); + +#endif /* __included_dslite_dpo_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_in2out.c b/src/plugins/nat/dslite/dslite_in2out.c new file mode 100644 index 00000000000..d1ac17509c6 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_in2out.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2017 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. + */ +#include +#include +#include + +typedef enum +{ + DSLITE_IN2OUT_NEXT_IP4_LOOKUP, + DSLITE_IN2OUT_NEXT_IP6_ICMP, + DSLITE_IN2OUT_NEXT_DROP, + DSLITE_IN2OUT_NEXT_SLOWPATH, + DSLITE_IN2OUT_N_NEXT, +} dslite_in2out_next_t; + +static char *dslite_in2out_error_strings[] = { +#define _(sym,string) string, + foreach_dslite_error +#undef _ +}; + +static u32 +slow_path (dslite_main_t * dm, dslite_session_key_t * in2out_key, + dslite_session_t ** sp, u32 next, u8 * error, u32 thread_index) +{ + dslite_b4_t *b4; + clib_bihash_kv_16_8_t b4_kv, b4_value; + clib_bihash_kv_24_8_t in2out_kv; + clib_bihash_kv_8_8_t out2in_kv; + dlist_elt_t *head_elt, *oldest_elt, *elt; + u32 oldest_index; + dslite_session_t *s; + snat_session_key_t out2in_key; + nat_ip4_addr_port_t addr_port; + u32 b4_index; + + out2in_key.protocol = in2out_key->proto; + out2in_key.fib_index = 0; + + b4_kv.key[0] = in2out_key->softwire_id.as_u64[0]; + b4_kv.key[1] = in2out_key->softwire_id.as_u64[1]; + + if (clib_bihash_search_16_8 + (&dm->per_thread_data[thread_index].b4_hash, &b4_kv, &b4_value)) + { + pool_get (dm->per_thread_data[thread_index].b4s, b4); + clib_memset (b4, 0, sizeof (*b4)); + b4->addr.as_u64[0] = in2out_key->softwire_id.as_u64[0]; + b4->addr.as_u64[1] = in2out_key->softwire_id.as_u64[1]; + + pool_get (dm->per_thread_data[thread_index].list_pool, head_elt); + b4->sessions_per_b4_list_head_index = + head_elt - dm->per_thread_data[thread_index].list_pool; + clib_dlist_init (dm->per_thread_data[thread_index].list_pool, + b4->sessions_per_b4_list_head_index); + + b4_index = b4_kv.value = b4 - dm->per_thread_data[thread_index].b4s; + clib_bihash_add_del_16_8 (&dm->per_thread_data[thread_index].b4_hash, + &b4_kv, 1); + + vlib_set_simple_counter (&dm->total_b4s, thread_index, 0, + pool_elts (dm-> + per_thread_data[thread_index].b4s)); + } + else + { + b4_index = b4_value.value; + b4 = + pool_elt_at_index (dm->per_thread_data[thread_index].b4s, + b4_value.value); + } + + //TODO configurable quota + if (b4->nsessions >= 1000) + { + oldest_index = + clib_dlist_remove_head (dm->per_thread_data[thread_index].list_pool, + b4->sessions_per_b4_list_head_index); + ASSERT (oldest_index != ~0); + clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, + b4->sessions_per_b4_list_head_index, oldest_index); + oldest_elt = + pool_elt_at_index (dm->per_thread_data[thread_index].list_pool, + oldest_index); + s = + pool_elt_at_index (dm->per_thread_data[thread_index].sessions, + oldest_elt->value); + + in2out_kv.key[0] = s->in2out.as_u64[0]; + in2out_kv.key[1] = s->in2out.as_u64[1]; + in2out_kv.key[2] = s->in2out.as_u64[2]; + clib_bihash_add_del_24_8 (&dm->per_thread_data[thread_index].in2out, + &in2out_kv, 0); + out2in_kv.key = s->out2in.as_u64; + clib_bihash_add_del_8_8 (&dm->per_thread_data[thread_index].out2in, + &out2in_kv, 0); + + addr_port.addr.as_u32 = s->out2in.addr.as_u32; + addr_port.port = s->out2in.port; + + nat_free_ip4_addr_and_port (&dm->pool, thread_index, + s->out2in.protocol, &addr_port); + + nat_syslog_dslite_apmdel (b4_index, &s->in2out.softwire_id, + &s->in2out.addr, s->in2out.port, + &s->out2in.addr, s->out2in.port, + s->in2out.proto); + + if (nat_alloc_ip4_addr_and_port + (&dm->pool, 0, thread_index, thread_index, + dm->port_per_thread, out2in_key.protocol, &addr_port)) + ASSERT (0); + + out2in_key.addr.as_u32 = addr_port.addr.as_u32; + out2in_key.port = addr_port.port; + } + else + { + if (nat_alloc_ip4_addr_and_port + (&dm->pool, 0, thread_index, thread_index, + dm->port_per_thread, out2in_key.protocol, &addr_port)) + { + *error = DSLITE_ERROR_OUT_OF_PORTS; + return DSLITE_IN2OUT_NEXT_DROP; + } + + out2in_key.addr.as_u32 = addr_port.addr.as_u32; + out2in_key.port = addr_port.port; + + pool_get (dm->per_thread_data[thread_index].sessions, s); + clib_memset (s, 0, sizeof (*s)); + b4->nsessions++; + + pool_get (dm->per_thread_data[thread_index].list_pool, elt); + clib_dlist_init (dm->per_thread_data[thread_index].list_pool, + elt - dm->per_thread_data[thread_index].list_pool); + elt->value = s - dm->per_thread_data[thread_index].sessions; + s->per_b4_index = elt - dm->per_thread_data[thread_index].list_pool; + s->per_b4_list_head_index = b4->sessions_per_b4_list_head_index; + clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, + s->per_b4_list_head_index, + elt - dm->per_thread_data[thread_index].list_pool); + + vlib_set_simple_counter (&dm->total_sessions, thread_index, 0, + pool_elts (dm->per_thread_data + [thread_index].sessions)); + } + + s->in2out = *in2out_key; + s->out2in = out2in_key; + *sp = s; + in2out_kv.key[0] = s->in2out.as_u64[0]; + in2out_kv.key[1] = s->in2out.as_u64[1]; + in2out_kv.key[2] = s->in2out.as_u64[2]; + in2out_kv.value = s - dm->per_thread_data[thread_index].sessions; + clib_bihash_add_del_24_8 (&dm->per_thread_data[thread_index].in2out, + &in2out_kv, 1); + out2in_kv.key = s->out2in.as_u64; + out2in_kv.value = s - dm->per_thread_data[thread_index].sessions; + clib_bihash_add_del_8_8 (&dm->per_thread_data[thread_index].out2in, + &out2in_kv, 1); + + nat_syslog_dslite_apmadd (b4_index, &s->in2out.softwire_id, &s->in2out.addr, + s->in2out.port, &s->out2in.addr, s->out2in.port, + s->in2out.proto); + + return next; +} + +static inline u32 +dslite_icmp_in2out (dslite_main_t * dm, ip6_header_t * ip6, + ip4_header_t * ip4, dslite_session_t ** sp, u32 next, + u8 * error, u32 thread_index) +{ + dslite_session_t *s = 0; + icmp46_header_t *icmp = ip4_next_header (ip4); + clib_bihash_kv_24_8_t kv, value; + dslite_session_key_t key; + u32 n = next; + icmp_echo_header_t *echo; + u32 new_addr, old_addr; + u16 old_id, new_id; + ip_csum_t sum; + + if (icmp_type_is_error_message (icmp->type)) + { + n = DSLITE_IN2OUT_NEXT_DROP; + *error = DSLITE_ERROR_BAD_ICMP_TYPE; + goto done; + } + + echo = (icmp_echo_header_t *) (icmp + 1); + + key.addr = ip4->src_address; + key.port = echo->identifier; + key.proto = SNAT_PROTOCOL_ICMP; + key.softwire_id.as_u64[0] = ip6->src_address.as_u64[0]; + key.softwire_id.as_u64[1] = ip6->src_address.as_u64[1]; + key.pad = 0; + kv.key[0] = key.as_u64[0]; + kv.key[1] = key.as_u64[1]; + kv.key[2] = key.as_u64[2]; + + if (clib_bihash_search_24_8 + (&dm->per_thread_data[thread_index].in2out, &kv, &value)) + { + n = slow_path (dm, &key, &s, next, error, thread_index); + if (PREDICT_FALSE (next == DSLITE_IN2OUT_NEXT_DROP)) + goto done; + } + else + { + s = + pool_elt_at_index (dm->per_thread_data[thread_index].sessions, + value.value); + } + + old_addr = ip4->src_address.as_u32; + ip4->src_address = s->out2in.addr; + new_addr = ip4->src_address.as_u32; + sum = ip4->checksum; + sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address); + ip4->checksum = ip_csum_fold (sum); + + old_id = echo->identifier; + echo->identifier = new_id = s->out2in.port; + sum = icmp->checksum; + sum = ip_csum_update (sum, old_id, new_id, icmp_echo_header_t, identifier); + icmp->checksum = ip_csum_fold (sum); + +done: + *sp = s; + return n; +} + +static inline uword +dslite_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame, u8 is_slow_path) +{ + u32 n_left_from, *from, *to_next; + dslite_in2out_next_t next_index; + u32 node_index; + vlib_node_runtime_t *error_node; + u32 thread_index = vm->thread_index; + f64 now = vlib_time_now (vm); + dslite_main_t *dm = &dslite_main; + + node_index = + is_slow_path ? dm->dslite_in2out_slowpath_node_index : + dm->dslite_in2out_node_index; + + error_node = vlib_node_get_runtime (vm, node_index); + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = DSLITE_IN2OUT_NEXT_IP4_LOOKUP; + ip4_header_t *ip40; + ip6_header_t *ip60; + u8 error0 = DSLITE_ERROR_IN2OUT; + u32 proto0; + dslite_session_t *s0 = 0; + clib_bihash_kv_24_8_t kv0, value0; + dslite_session_key_t key0; + udp_header_t *udp0; + tcp_header_t *tcp0; + ip_csum_t sum0; + u32 new_addr0, old_addr0; + u16 old_port0, new_port0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip60 = vlib_buffer_get_current (b0); + + if (PREDICT_FALSE (ip60->protocol != IP_PROTOCOL_IP_IN_IP)) + { + if (ip60->protocol == IP_PROTOCOL_ICMP6) + { + next0 = DSLITE_IN2OUT_NEXT_IP6_ICMP; + goto trace0; + } + error0 = DSLITE_ERROR_BAD_IP6_PROTOCOL; + next0 = DSLITE_IN2OUT_NEXT_DROP; + goto trace0; + } + + ip40 = vlib_buffer_get_current (b0) + sizeof (ip6_header_t); + proto0 = ip_proto_to_snat_proto (ip40->protocol); + + if (PREDICT_FALSE (proto0 == ~0)) + { + error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; + next0 = DSLITE_IN2OUT_NEXT_DROP; + goto trace0; + } + + udp0 = ip4_next_header (ip40); + tcp0 = (tcp_header_t *) udp0; + + if (is_slow_path) + { + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = + dslite_icmp_in2out (dm, ip60, ip40, &s0, next0, &error0, + thread_index); + if (PREDICT_FALSE (next0 == DSLITE_IN2OUT_NEXT_DROP)) + goto trace0; + + goto accounting0; + } + } + else + { + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = DSLITE_IN2OUT_NEXT_SLOWPATH; + goto trace0; + } + } + + key0.addr = ip40->src_address; + key0.port = udp0->src_port; + key0.proto = proto0; + key0.softwire_id.as_u64[0] = ip60->src_address.as_u64[0]; + key0.softwire_id.as_u64[1] = ip60->src_address.as_u64[1]; + key0.pad = 0; + kv0.key[0] = key0.as_u64[0]; + kv0.key[1] = key0.as_u64[1]; + kv0.key[2] = key0.as_u64[2]; + + if (clib_bihash_search_24_8 + (&dm->per_thread_data[thread_index].in2out, &kv0, &value0)) + { + if (is_slow_path) + { + next0 = + slow_path (dm, &key0, &s0, next0, &error0, thread_index); + if (PREDICT_FALSE (next0 == DSLITE_IN2OUT_NEXT_DROP)) + goto trace0; + } + else + { + next0 = DSLITE_IN2OUT_NEXT_SLOWPATH; + goto trace0; + } + } + else + { + s0 = + pool_elt_at_index (dm->per_thread_data[thread_index].sessions, + value0.value); + } + + old_addr0 = ip40->src_address.as_u32; + ip40->src_address = s0->out2in.addr; + new_addr0 = ip40->src_address.as_u32; + sum0 = ip40->checksum; + sum0 = + ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, + src_address); + ip40->checksum = ip_csum_fold (sum0); + if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->src_port; + tcp0->src_port = s0->out2in.port; + new_port0 = tcp0->src_port; + + sum0 = tcp0->checksum; + sum0 = + ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, + dst_address); + sum0 = + ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, + length); + //mss_clamping (&dslite_main, tcp0, &sum0); + tcp0->checksum = ip_csum_fold (sum0); + } + else + { + old_port0 = udp0->src_port; + udp0->src_port = s0->out2in.port; + udp0->checksum = 0; + } + + accounting0: + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-B4 LRU list maintenance */ + clib_dlist_remove (dm->per_thread_data[thread_index].list_pool, + s0->per_b4_index); + clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, + s0->per_b4_list_head_index, s0->per_b4_index); + + ip40->tos = + (clib_net_to_host_u32 + (ip60->ip_version_traffic_class_and_flow_label) & 0x0ff00000) >> + 20; + vlib_buffer_advance (b0, sizeof (ip6_header_t)); + + trace0: + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + t->session_index = ~0; + if (s0) + t->session_index = + s0 - dm->per_thread_data[thread_index].sessions; + } + + b0->error = error_node->errors[error0]; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +VLIB_NODE_FN (dslite_in2out_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return dslite_in2out_node_fn_inline (vm, node, frame, 0); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dslite_in2out_node) = { + .name = "dslite-in2out", + .vector_size = sizeof (u32), + .format_trace = format_dslite_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (dslite_in2out_error_strings), + .error_strings = dslite_in2out_error_strings, + .n_next_nodes = DSLITE_IN2OUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = { + [DSLITE_IN2OUT_NEXT_DROP] = "error-drop", + [DSLITE_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup", + [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-icmp-input", + [DSLITE_IN2OUT_NEXT_SLOWPATH] = "dslite-in2out-slowpath", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FN (dslite_in2out_slowpath_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return dslite_in2out_node_fn_inline (vm, node, frame, 1); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dslite_in2out_slowpath_node) = { + .name = "dslite-in2out-slowpath", + .vector_size = sizeof (u32), + .format_trace = format_dslite_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (dslite_in2out_error_strings), + .error_strings = dslite_in2out_error_strings, + .n_next_nodes = DSLITE_IN2OUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = { + [DSLITE_IN2OUT_NEXT_DROP] = "error-drop", + [DSLITE_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup", + [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-lookup", + [DSLITE_IN2OUT_NEXT_SLOWPATH] = "dslite-in2out-slowpath", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite/dslite_out2in.c b/src/plugins/nat/dslite/dslite_out2in.c new file mode 100644 index 00000000000..ac64a589509 --- /dev/null +++ b/src/plugins/nat/dslite/dslite_out2in.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2017 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. + */ +#include +#include + +typedef enum +{ + DSLITE_OUT2IN_NEXT_IP4_LOOKUP, + DSLITE_OUT2IN_NEXT_IP6_LOOKUP, + DSLITE_OUT2IN_NEXT_DROP, + DSLITE_OUT2IN_N_NEXT, +} dslite_out2in_next_t; + +static char *dslite_out2in_error_strings[] = { +#define _(sym,string) string, + foreach_dslite_error +#undef _ +}; + +static inline u32 +dslite_icmp_out2in (dslite_main_t * dm, ip4_header_t * ip4, + dslite_session_t ** sp, u32 next, u8 * error, + u32 thread_index) +{ + dslite_session_t *s = 0; + icmp46_header_t *icmp = ip4_next_header (ip4); + clib_bihash_kv_8_8_t kv, value; + snat_session_key_t key; + u32 n = next; + icmp_echo_header_t *echo; + u32 new_addr, old_addr; + u16 old_id, new_id; + ip_csum_t sum; + + echo = (icmp_echo_header_t *) (icmp + 1); + + if (icmp_type_is_error_message (icmp->type) + || (icmp->type != ICMP4_echo_reply)) + { + n = DSLITE_OUT2IN_NEXT_DROP; + *error = DSLITE_ERROR_BAD_ICMP_TYPE; + goto done; + } + + key.addr = ip4->dst_address; + key.port = echo->identifier; + key.protocol = SNAT_PROTOCOL_ICMP; + key.fib_index = 0; + kv.key = key.as_u64; + + if (clib_bihash_search_8_8 + (&dm->per_thread_data[thread_index].out2in, &kv, &value)) + { + next = DSLITE_OUT2IN_NEXT_DROP; + *error = DSLITE_ERROR_NO_TRANSLATION; + goto done; + } + else + { + s = + pool_elt_at_index (dm->per_thread_data[thread_index].sessions, + value.value); + } + + old_id = echo->identifier; + echo->identifier = new_id = s->in2out.port; + sum = icmp->checksum; + sum = ip_csum_update (sum, old_id, new_id, icmp_echo_header_t, identifier); + icmp->checksum = ip_csum_fold (sum); + + old_addr = ip4->dst_address.as_u32; + ip4->dst_address = s->in2out.addr; + new_addr = ip4->dst_address.as_u32; + + sum = ip4->checksum; + sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); + ip4->checksum = ip_csum_fold (sum); + +done: + *sp = s; + return n; +} + +VLIB_NODE_FN (dslite_out2in_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + dslite_out2in_next_t next_index; + vlib_node_runtime_t *error_node; + u32 thread_index = vm->thread_index; + f64 now = vlib_time_now (vm); + dslite_main_t *dm = &dslite_main; + + error_node = vlib_node_get_runtime (vm, dm->dslite_out2in_node_index); + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = DSLITE_OUT2IN_NEXT_IP6_LOOKUP; + u8 error0 = DSLITE_ERROR_OUT2IN; + ip4_header_t *ip40; + ip6_header_t *ip60; + u32 proto0; + udp_header_t *udp0; + tcp_header_t *tcp0; + clib_bihash_kv_8_8_t kv0, value0; + snat_session_key_t key0; + dslite_session_t *s0 = 0; + ip_csum_t sum0; + u32 new_addr0, old_addr0; + u16 new_port0, old_port0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip40 = vlib_buffer_get_current (b0); + proto0 = ip_proto_to_snat_proto (ip40->protocol); + + if (PREDICT_FALSE (proto0 == ~0)) + { + error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; + next0 = DSLITE_OUT2IN_NEXT_DROP; + goto trace0; + } + + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) + { + next0 = + dslite_icmp_out2in (dm, ip40, &s0, next0, &error0, + thread_index); + if (PREDICT_FALSE (next0 == DSLITE_OUT2IN_NEXT_DROP)) + goto trace0; + + goto encap0; + } + + udp0 = ip4_next_header (ip40); + tcp0 = (tcp_header_t *) udp0; + + key0.addr = ip40->dst_address; + key0.port = udp0->dst_port; + key0.protocol = proto0; + key0.fib_index = 0; + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 + (&dm->per_thread_data[thread_index].out2in, &kv0, &value0)) + { + next0 = DSLITE_OUT2IN_NEXT_DROP; + error0 = DSLITE_ERROR_NO_TRANSLATION; + goto trace0; + } + else + { + s0 = + pool_elt_at_index (dm->per_thread_data[thread_index].sessions, + value0.value); + } + + old_addr0 = ip40->dst_address.as_u32; + ip40->dst_address = s0->in2out.addr; + new_addr0 = ip40->dst_address.as_u32; + + sum0 = ip40->checksum; + sum0 = + ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, + dst_address); + ip40->checksum = ip_csum_fold (sum0); + + if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->dst_port; + tcp0->dst_port = s0->in2out.port; + new_port0 = tcp0->dst_port; + + sum0 = tcp0->checksum; + sum0 = + ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, + dst_address); + sum0 = + ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, + length); + tcp0->checksum = ip_csum_fold (sum0); + } + else + { + old_port0 = udp0->dst_port; + udp0->dst_port = s0->in2out.port; + udp0->checksum = 0; + } + + encap0: + /* Construct IPv6 header */ + vlib_buffer_advance (b0, -(sizeof (ip6_header_t))); + ip60 = vlib_buffer_get_current (b0); + ip60->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 ((6 << 28) + (ip40->tos << 20)); + ip60->payload_length = ip40->length; + ip60->protocol = IP_PROTOCOL_IP_IN_IP; + ip60->hop_limit = ip40->ttl; + ip60->src_address.as_u64[0] = dm->aftr_ip6_addr.as_u64[0]; + ip60->src_address.as_u64[1] = dm->aftr_ip6_addr.as_u64[1]; + ip60->dst_address.as_u64[0] = s0->in2out.softwire_id.as_u64[0]; + ip60->dst_address.as_u64[1] = s0->in2out.softwire_id.as_u64[1]; + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-B4 LRU list maintenance */ + clib_dlist_remove (dm->per_thread_data[thread_index].list_pool, + s0->per_b4_index); + clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, + s0->per_b4_list_head_index, s0->per_b4_index); + trace0: + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + t->session_index = ~0; + if (s0) + t->session_index = + s0 - dm->per_thread_data[thread_index].sessions; + } + + b0->error = error_node->errors[error0]; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dslite_out2in_node) = { + .name = "dslite-out2in", + .vector_size = sizeof (u32), + .format_trace = format_dslite_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (dslite_out2in_error_strings), + .error_strings = dslite_out2in_error_strings, + .n_next_nodes = DSLITE_OUT2IN_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = { + [DSLITE_OUT2IN_NEXT_DROP] = "error-drop", + [DSLITE_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup", + [DSLITE_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/dslite_ce_decap.c b/src/plugins/nat/dslite_ce_decap.c deleted file mode 100644 index 77b80ea0f45..00000000000 --- a/src/plugins/nat/dslite_ce_decap.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ -#include -#include - -typedef enum -{ - DSLITE_CE_DECAP_NEXT_IP4_LOOKUP, - DSLITE_IN2OUT_NEXT_IP6_ICMP, - DSLITE_CE_DECAP_NEXT_DROP, - DSLITE_CE_DECAP_N_NEXT, -} dslite_ce_decap_next_t; - -static char *dslite_ce_decap_error_strings[] = { -#define _(sym,string) string, - foreach_dslite_error -#undef _ -}; - -VLIB_NODE_FN (dslite_ce_decap_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - dslite_ce_decap_next_t next_index; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = DSLITE_CE_DECAP_NEXT_IP4_LOOKUP; - u8 error0 = DSLITE_ERROR_CE_DECAP; - ip4_header_t *ip40; - ip6_header_t *ip60; - u32 proto0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip60 = vlib_buffer_get_current (b0); - - if (PREDICT_FALSE (ip60->protocol != IP_PROTOCOL_IP_IN_IP)) - { - if (ip60->protocol == IP_PROTOCOL_ICMP6) - { - next0 = DSLITE_IN2OUT_NEXT_IP6_ICMP; - goto trace0; - } - error0 = DSLITE_ERROR_BAD_IP6_PROTOCOL; - next0 = DSLITE_CE_DECAP_NEXT_DROP; - goto trace0; - } - - ip40 = vlib_buffer_get_current (b0) + sizeof (ip6_header_t); - proto0 = ip_proto_to_snat_proto (ip40->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - { - error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; - next0 = DSLITE_CE_DECAP_NEXT_DROP; - goto trace0; - } - - ip40->tos = - (clib_net_to_host_u32 - (ip60->ip_version_traffic_class_and_flow_label) & 0x0ff00000) >> - 20; - vlib_buffer_advance (b0, sizeof (ip6_header_t)); - - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_index = next0; - } - - b0->error = node->errors[error0]; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dslite_ce_decap_node) = { - .name = "dslite-ce-decap", - .vector_size = sizeof (u32), - .format_trace = format_dslite_ce_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (dslite_ce_decap_error_strings), - .error_strings = dslite_ce_decap_error_strings, - .n_next_nodes = DSLITE_CE_DECAP_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [DSLITE_CE_DECAP_NEXT_DROP] = "error-drop", - [DSLITE_CE_DECAP_NEXT_IP4_LOOKUP] = "ip4-lookup", - [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-icmp-input", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite_ce_encap.c b/src/plugins/nat/dslite_ce_encap.c deleted file mode 100644 index 39ff7975c3a..00000000000 --- a/src/plugins/nat/dslite_ce_encap.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ -#include -#include - -typedef enum -{ - DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP, - DSLITE_CE_ENCAP_NEXT_DROP, - DSLITE_CE_ENCAP_N_NEXT, -} dslite_ce_encap_next_t; - -static char *dslite_ce_encap_error_strings[] = { -#define _(sym,string) string, - foreach_dslite_error -#undef _ -}; - -VLIB_NODE_FN (dslite_ce_encap_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - dslite_ce_encap_next_t next_index; - dslite_main_t *dm = &dslite_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP; - u8 error0 = DSLITE_ERROR_CE_ENCAP; - ip4_header_t *ip40; - ip6_header_t *ip60; - u32 proto0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip40 = vlib_buffer_get_current (b0); - proto0 = ip_proto_to_snat_proto (ip40->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - { - error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; - next0 = DSLITE_CE_ENCAP_NEXT_DROP; - goto trace0; - } - - /* Construct IPv6 header */ - vlib_buffer_advance (b0, -(sizeof (ip6_header_t))); - ip60 = vlib_buffer_get_current (b0); - ip60->ip_version_traffic_class_and_flow_label = - clib_host_to_net_u32 ((6 << 28) + (ip40->tos << 20)); - ip60->payload_length = ip40->length; - ip60->protocol = IP_PROTOCOL_IP_IN_IP; - ip60->hop_limit = ip40->ttl; - ip60->dst_address.as_u64[0] = dm->aftr_ip6_addr.as_u64[0]; - ip60->dst_address.as_u64[1] = dm->aftr_ip6_addr.as_u64[1]; - ip60->src_address.as_u64[0] = dm->b4_ip6_addr.as_u64[0]; - ip60->src_address.as_u64[1] = dm->b4_ip6_addr.as_u64[1]; - - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_index = next0; - } - - b0->error = node->errors[error0]; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dslite_ce_encap_node) = { - .name = "dslite-ce-encap", - .vector_size = sizeof (u32), - .format_trace = format_dslite_ce_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (dslite_ce_encap_error_strings), - .error_strings = dslite_ce_encap_error_strings, - .n_next_nodes = DSLITE_CE_ENCAP_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [DSLITE_CE_ENCAP_NEXT_DROP] = "error-drop", - [DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite_cli.c b/src/plugins/nat/dslite_cli.c deleted file mode 100644 index 515929b2135..00000000000 --- a/src/plugins/nat/dslite_cli.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ - -#include - -static clib_error_t * -dslite_add_del_pool_addr_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t start_addr, end_addr, this_addr; - u32 start_host_order, end_host_order; - int i, count, rv; - u8 is_add = 1; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U - %U", - unformat_ip4_address, &start_addr, - unformat_ip4_address, &end_addr)) - ; - else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) - end_addr = start_addr; - else if (unformat (line_input, "del")) - is_add = 0; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - start_host_order = clib_host_to_net_u32 (start_addr.as_u32); - end_host_order = clib_host_to_net_u32 (end_addr.as_u32); - - if (end_host_order < start_host_order) - { - error = clib_error_return (0, "end address less than start address"); - goto done; - } - - count = (end_host_order - start_host_order) + 1; - this_addr = start_addr; - - for (i = 0; i < count; i++) - { - rv = dslite_add_del_pool_addr (dm, &this_addr, is_add); - - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = - clib_error_return (0, "DS-Lite pool address %U not exist.", - format_ip4_address, &this_addr); - goto done; - case VNET_API_ERROR_VALUE_EXIST: - error = - clib_error_return (0, "DS-Lite pool address %U exist.", - format_ip4_address, &this_addr); - goto done; - default: - break; - - } - increment_v4_address (&this_addr); - } - -done: - unformat_free (line_input); - - return error; -} - -static clib_error_t * -dslite_show_pool_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - snat_address_t *ap; - - vlib_cli_output (vm, "DS-Lite pool:"); - - /* *INDENT-OFF* */ - vec_foreach (ap, dm->addr_pool) - { - vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); - } - /* *INDENT-ON* */ - return 0; -} - -static clib_error_t * -dslite_set_aftr_tunnel_addr_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip6_address_t ip6_addr; - int rv; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U", unformat_ip6_address, &ip6_addr)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - rv = dslite_set_aftr_ip6_addr (dm, &ip6_addr); - - if (rv) - error = - clib_error_return (0, - "Set DS-Lite AFTR tunnel endpoint address failed."); - -done: - unformat_free (line_input); - - return error; -} - -static clib_error_t * -dslite_show_aftr_ip6_addr_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - - vlib_cli_output (vm, "%U", format_ip6_address, &dm->aftr_ip6_addr); - return 0; -} - -static clib_error_t * -dslite_set_b4_tunnel_addr_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip6_address_t ip6_addr; - int rv; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U", unformat_ip6_address, &ip6_addr)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - rv = dslite_set_b4_ip6_addr (dm, &ip6_addr); - - if (rv) - error = - clib_error_return (0, "Set DS-Lite B4 tunnel endpoint address failed."); - -done: - unformat_free (line_input); - - return error; -} - -static clib_error_t * -dslite_show_b4_ip6_addr_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - - vlib_cli_output (vm, "%U", format_ip6_address, &dm->b4_ip6_addr); - return 0; -} - -static u8 * -format_dslite_session (u8 * s, va_list * args) -{ - dslite_session_t *session = va_arg (*args, dslite_session_t *); - u32 indent = format_get_indent (s); - - s = format (s, "%Uin %U:%u out %U:%u protocol %U\n", - format_white_space, indent + 2, - format_ip4_address, &session->in2out.addr, - clib_net_to_host_u16 (session->in2out.port), - format_ip4_address, &session->out2in.addr, - clib_net_to_host_u16 (session->out2in.port), - format_snat_protocol, session->in2out.proto); - s = format (s, "%Utotal pkts %d, total bytes %lld\n", - format_white_space, indent + 4, - session->total_pkts, session->total_bytes); - return s; -} - -static u8 * -format_dslite_b4 (u8 * s, va_list * args) -{ - dslite_per_thread_data_t *td = va_arg (*args, dslite_per_thread_data_t *); - dslite_b4_t *b4 = va_arg (*args, dslite_b4_t *); - dlist_elt_t *head, *elt; - u32 elt_index, head_index; - u32 session_index; - dslite_session_t *session; - - s = - format (s, "B4 %U %d sessions\n", format_ip6_address, &b4->addr, - b4->nsessions); - - if (b4->nsessions == 0) - return s; - - head_index = b4->sessions_per_b4_list_head_index; - head = pool_elt_at_index (td->list_pool, head_index); - elt_index = head->next; - elt = pool_elt_at_index (td->list_pool, elt_index); - session_index = elt->value; - while (session_index != ~0) - { - session = pool_elt_at_index (td->sessions, session_index); - s = format (s, "%U", format_dslite_session, session); - elt_index = elt->next; - elt = pool_elt_at_index (td->list_pool, elt_index); - session_index = elt->value; - } - - return s; -} - -static clib_error_t * -dslite_show_sessions_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dslite_main_t *dm = &dslite_main; - dslite_per_thread_data_t *td; - dslite_b4_t *b4; - - /* *INDENT-OFF* */ - vec_foreach (td, dm->per_thread_data) - { - pool_foreach (b4, td->b4s, - ({ - vlib_cli_output (vm, "%U", format_dslite_b4, td, b4); - })); - } - /* *INDENT-ON* */ - - return 0; -} - -/* *INDENT-OFF* */ - -/*? - * @cliexpar - * @cliexstart{dslite add pool address} - * Add/delete DS-Lite pool address for AFTR element. - * To add DS-Lite pool address use: - * vpp# dslite add pool address 10.1.1.3 - * To add DS-Lite pool address range use: - * vpp# dslite add pool address 10.1.1.5 - 10.1.1.7 - * @cliexend -?*/ -VLIB_CLI_COMMAND (dslite_add_pool_address_command, static) = { - .path = "dslite add pool address", - .short_help = "dslite add pool address [- ] " - " [del]", - .function = dslite_add_del_pool_addr_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show dslite pool} - * Show DS-lite pool addresses. - * vpp# show dslite pool - * DS-Lite pool: - * 10.0.0.3 - * 10.0.0.5 - * 10.0.0.6 - * 10.0.0.7 - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_dslite_pool_command, static) = { - .path = "show dslite pool", - .short_help = "show dslite pool", - .function = dslite_show_pool_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{dslite set aftr-tunnel-endpoint-address} - * Set IPv6 tunnel endpoint address of the AFTR element. - * To set AFTR tunnel endpoint address use: - * vpp# dslite set aftr-tunnel-endpoint-address 2001:db8:85a3::8a2e:370:1 - * @cliexend -?*/ -VLIB_CLI_COMMAND (dslite_set_aftr_tunnel_addr, static) = { - .path = "dslite set aftr-tunnel-endpoint-address", - .short_help = "dslite set aftr-tunnel-endpoint-address ", - .function = dslite_set_aftr_tunnel_addr_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show dslite aftr-tunnel-endpoint-address} - * Show IPv6 tunnel endpoint address of the AFTR element. - * vpp# show dslite aftr-tunnel-endpoint-address - * 2001:db8:85a3::8a2e:370:1 - * @cliexend -?*/ -VLIB_CLI_COMMAND (dslite_show_aftr_ip6_addr, static) = { - .path = "show dslite aftr-tunnel-endpoint-address", - .short_help = "show dslite aftr-tunnel-endpoint-address", - .function = dslite_show_aftr_ip6_addr_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{dslite set b4-tunnel-endpoint-address} - * Set IPv6 tunnel endpoint address of the B4 element. - * To set B4 tunnel endpoint address use: - * vpp# dslite set b4-tunnel-endpoint-address 2001:db8:62aa::375e:f4c1:1 - * @cliexend -?*/ -VLIB_CLI_COMMAND (dslite_set_b4_tunnel_addr, static) = { - .path = "dslite set b4-tunnel-endpoint-address", - .short_help = "dslite set b4-tunnel-endpoint-address ", - .function = dslite_set_b4_tunnel_addr_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show dslite b4-tunnel-endpoint-address} - * Show IPv6 tunnel endpoint address of the B4 element. - * vpp# show dslite b4-tunnel-endpoint-address - * 2001:db8:62aa::375e:f4c1:1 - * @cliexend -?*/ -VLIB_CLI_COMMAND (dslite_show_b4_ip6_addr, static) = { - .path = "show dslite b4-tunnel-endpoint-address", - .short_help = "show dslite b4-tunnel-endpoint-address", - .function = dslite_show_b4_ip6_addr_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show dslite sessions} - * Show DS-Lite sessions. - * vpp# show dslite sessions - * B4 fd01:2::2 1 sessions - * in 192.168.1.1:20000 out 10.0.0.3:16253 protocol udp - * total pkts 2, total bytes 136 - * B4 fd01:2::3 2 sessions - * in 192.168.1.1:20001 out 10.0.0.3:18995 protocol tcp - * total pkts 2, total bytes 160 - * in 192.168.1.1:4000 out 10.0.0.3:53893 protocol icmp - * total pkts 2, total bytes 136 - * @cliexend -?*/ -VLIB_CLI_COMMAND (dslite_show_sessions, static) = { - .path = "show dslite sessions", - .short_help = "show dslite sessions", - .function = dslite_show_sessions_command_fn, -}; - -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite_dpo.c b/src/plugins/nat/dslite_dpo.c deleted file mode 100644 index 97ebb18cf70..00000000000 --- a/src/plugins/nat/dslite_dpo.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ - -#include -#include - -dpo_type_t dslite_dpo_type; -dpo_type_t dslite_ce_dpo_type; - -void -dslite_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t * dpo) -{ - dpo_set (dpo, dslite_dpo_type, dproto, aftr_index); -} - -void -dslite_ce_dpo_create (dpo_proto_t dproto, u32 b4_index, dpo_id_t * dpo) -{ - dpo_set (dpo, dslite_ce_dpo_type, dproto, b4_index); -} - -u8 * -format_dslite_dpo (u8 * s, va_list * args) -{ - index_t index = va_arg (*args, index_t); - CLIB_UNUSED (u32 indent) = va_arg (*args, u32); - - return (format (s, "DS-Lite: AFTR:%d", index)); -} - -u8 * -format_dslite_ce_dpo (u8 * s, va_list * args) -{ - index_t index = va_arg (*args, index_t); - CLIB_UNUSED (u32 indent) = va_arg (*args, u32); - - return (format (s, "DS-Lite: B4:%d", index)); -} - -static void -dslite_dpo_lock (dpo_id_t * dpo) -{ -} - -static void -dslite_dpo_unlock (dpo_id_t * dpo) -{ -} - -static void -dslite_ce_dpo_lock (dpo_id_t * dpo) -{ -} - -static void -dslite_ce_dpo_unlock (dpo_id_t * dpo) -{ -} - -const static dpo_vft_t dslite_dpo_vft = { - .dv_lock = dslite_dpo_lock, - .dv_unlock = dslite_dpo_unlock, - .dv_format = format_dslite_dpo, -}; - -const static dpo_vft_t dslite_ce_dpo_vft = { - .dv_lock = dslite_ce_dpo_lock, - .dv_unlock = dslite_ce_dpo_unlock, - .dv_format = format_dslite_ce_dpo, -}; - -const static char *const dslite_ip4_nodes[] = { - "dslite-out2in", - NULL, -}; - -const static char *const dslite_ip6_nodes[] = { - "dslite-in2out", - NULL, -}; - -const static char *const dslite_ce_ip4_nodes[] = { - "dslite-ce-encap", - NULL, -}; - -const static char *const dslite_ce_ip6_nodes[] = { - "dslite-ce-decap", - NULL, -}; - -const static char *const *const dslite_nodes[DPO_PROTO_NUM] = { - [DPO_PROTO_IP4] = dslite_ip4_nodes, - [DPO_PROTO_IP6] = dslite_ip6_nodes, - [DPO_PROTO_MPLS] = NULL, -}; - -const static char *const *const dslite_ce_nodes[DPO_PROTO_NUM] = { - [DPO_PROTO_IP4] = dslite_ce_ip4_nodes, - [DPO_PROTO_IP6] = dslite_ce_ip6_nodes, - [DPO_PROTO_MPLS] = NULL, -}; - -void -dslite_dpo_module_init (void) -{ - dslite_dpo_type = dpo_register_new_type (&dslite_dpo_vft, dslite_nodes); - dslite_ce_dpo_type = dpo_register_new_type (&dslite_ce_dpo_vft, - dslite_ce_nodes); -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite_dpo.h b/src/plugins/nat/dslite_dpo.h deleted file mode 100644 index 53d37b27fb4..00000000000 --- a/src/plugins/nat/dslite_dpo.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017 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_dslite_dpo_h__ -#define __included_dslite_dpo_h__ - -#include -#include - -void dslite_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t * dpo); -void dslite_ce_dpo_create (dpo_proto_t dproto, u32 b4_index, dpo_id_t * dpo); - -u8 *format_dslite_dpo (u8 * s, va_list * args); -u8 *format_dslite_ce_dpo (u8 * s, va_list * args); - -void dslite_dpo_module_init (void); - -#endif /* __included_dslite_dpo_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite_in2out.c b/src/plugins/nat/dslite_in2out.c deleted file mode 100644 index 4494a77701e..00000000000 --- a/src/plugins/nat/dslite_in2out.c +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ -#include -#include -#include - -typedef enum -{ - DSLITE_IN2OUT_NEXT_IP4_LOOKUP, - DSLITE_IN2OUT_NEXT_IP6_ICMP, - DSLITE_IN2OUT_NEXT_DROP, - DSLITE_IN2OUT_NEXT_SLOWPATH, - DSLITE_IN2OUT_N_NEXT, -} dslite_in2out_next_t; - -static char *dslite_in2out_error_strings[] = { -#define _(sym,string) string, - foreach_dslite_error -#undef _ -}; - -static u32 -slow_path (dslite_main_t * dm, dslite_session_key_t * in2out_key, - dslite_session_t ** sp, u32 next, u8 * error, u32 thread_index) -{ - dslite_b4_t *b4; - clib_bihash_kv_16_8_t b4_kv, b4_value; - clib_bihash_kv_24_8_t in2out_kv; - clib_bihash_kv_8_8_t out2in_kv; - dlist_elt_t *head_elt, *oldest_elt, *elt; - u32 oldest_index; - dslite_session_t *s; - snat_session_key_t out2in_key; - u32 b4_index; - - out2in_key.protocol = in2out_key->proto; - out2in_key.fib_index = 0; - - b4_kv.key[0] = in2out_key->softwire_id.as_u64[0]; - b4_kv.key[1] = in2out_key->softwire_id.as_u64[1]; - - if (clib_bihash_search_16_8 - (&dm->per_thread_data[thread_index].b4_hash, &b4_kv, &b4_value)) - { - pool_get (dm->per_thread_data[thread_index].b4s, b4); - clib_memset (b4, 0, sizeof (*b4)); - b4->addr.as_u64[0] = in2out_key->softwire_id.as_u64[0]; - b4->addr.as_u64[1] = in2out_key->softwire_id.as_u64[1]; - - pool_get (dm->per_thread_data[thread_index].list_pool, head_elt); - b4->sessions_per_b4_list_head_index = - head_elt - dm->per_thread_data[thread_index].list_pool; - clib_dlist_init (dm->per_thread_data[thread_index].list_pool, - b4->sessions_per_b4_list_head_index); - - b4_index = b4_kv.value = b4 - dm->per_thread_data[thread_index].b4s; - clib_bihash_add_del_16_8 (&dm->per_thread_data[thread_index].b4_hash, - &b4_kv, 1); - - vlib_set_simple_counter (&dm->total_b4s, thread_index, 0, - pool_elts (dm-> - per_thread_data[thread_index].b4s)); - } - else - { - b4_index = b4_value.value; - b4 = - pool_elt_at_index (dm->per_thread_data[thread_index].b4s, - b4_value.value); - } - - //TODO configurable quota - if (b4->nsessions >= 1000) - { - oldest_index = - clib_dlist_remove_head (dm->per_thread_data[thread_index].list_pool, - b4->sessions_per_b4_list_head_index); - ASSERT (oldest_index != ~0); - clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, - b4->sessions_per_b4_list_head_index, oldest_index); - oldest_elt = - pool_elt_at_index (dm->per_thread_data[thread_index].list_pool, - oldest_index); - s = - pool_elt_at_index (dm->per_thread_data[thread_index].sessions, - oldest_elt->value); - - in2out_kv.key[0] = s->in2out.as_u64[0]; - in2out_kv.key[1] = s->in2out.as_u64[1]; - in2out_kv.key[2] = s->in2out.as_u64[2]; - clib_bihash_add_del_24_8 (&dm->per_thread_data[thread_index].in2out, - &in2out_kv, 0); - out2in_kv.key = s->out2in.as_u64; - clib_bihash_add_del_8_8 (&dm->per_thread_data[thread_index].out2in, - &out2in_kv, 0); - snat_free_outside_address_and_port (dm->addr_pool, thread_index, - &s->out2in); - - nat_syslog_dslite_apmdel (b4_index, &s->in2out.softwire_id, - &s->in2out.addr, s->in2out.port, - &s->out2in.addr, s->out2in.port, - s->in2out.proto); - - if (snat_alloc_outside_address_and_port - (dm->addr_pool, 0, thread_index, &out2in_key, - dm->port_per_thread, thread_index)) - ASSERT (0); - } - else - { - if (snat_alloc_outside_address_and_port - (dm->addr_pool, 0, thread_index, &out2in_key, - dm->port_per_thread, thread_index)) - { - *error = DSLITE_ERROR_OUT_OF_PORTS; - return DSLITE_IN2OUT_NEXT_DROP; - } - pool_get (dm->per_thread_data[thread_index].sessions, s); - clib_memset (s, 0, sizeof (*s)); - b4->nsessions++; - - pool_get (dm->per_thread_data[thread_index].list_pool, elt); - clib_dlist_init (dm->per_thread_data[thread_index].list_pool, - elt - dm->per_thread_data[thread_index].list_pool); - elt->value = s - dm->per_thread_data[thread_index].sessions; - s->per_b4_index = elt - dm->per_thread_data[thread_index].list_pool; - s->per_b4_list_head_index = b4->sessions_per_b4_list_head_index; - clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, - s->per_b4_list_head_index, - elt - dm->per_thread_data[thread_index].list_pool); - - vlib_set_simple_counter (&dm->total_sessions, thread_index, 0, - pool_elts (dm->per_thread_data - [thread_index].sessions)); - } - - s->in2out = *in2out_key; - s->out2in = out2in_key; - *sp = s; - in2out_kv.key[0] = s->in2out.as_u64[0]; - in2out_kv.key[1] = s->in2out.as_u64[1]; - in2out_kv.key[2] = s->in2out.as_u64[2]; - in2out_kv.value = s - dm->per_thread_data[thread_index].sessions; - clib_bihash_add_del_24_8 (&dm->per_thread_data[thread_index].in2out, - &in2out_kv, 1); - out2in_kv.key = s->out2in.as_u64; - out2in_kv.value = s - dm->per_thread_data[thread_index].sessions; - clib_bihash_add_del_8_8 (&dm->per_thread_data[thread_index].out2in, - &out2in_kv, 1); - - nat_syslog_dslite_apmadd (b4_index, &s->in2out.softwire_id, &s->in2out.addr, - s->in2out.port, &s->out2in.addr, s->out2in.port, - s->in2out.proto); - - return next; -} - -static inline u32 -dslite_icmp_in2out (dslite_main_t * dm, ip6_header_t * ip6, - ip4_header_t * ip4, dslite_session_t ** sp, u32 next, - u8 * error, u32 thread_index) -{ - dslite_session_t *s = 0; - icmp46_header_t *icmp = ip4_next_header (ip4); - clib_bihash_kv_24_8_t kv, value; - dslite_session_key_t key; - u32 n = next; - icmp_echo_header_t *echo; - u32 new_addr, old_addr; - u16 old_id, new_id; - ip_csum_t sum; - - if (icmp_type_is_error_message (icmp->type)) - { - n = DSLITE_IN2OUT_NEXT_DROP; - *error = DSLITE_ERROR_BAD_ICMP_TYPE; - goto done; - } - - echo = (icmp_echo_header_t *) (icmp + 1); - - key.addr = ip4->src_address; - key.port = echo->identifier; - key.proto = SNAT_PROTOCOL_ICMP; - key.softwire_id.as_u64[0] = ip6->src_address.as_u64[0]; - key.softwire_id.as_u64[1] = ip6->src_address.as_u64[1]; - key.pad = 0; - kv.key[0] = key.as_u64[0]; - kv.key[1] = key.as_u64[1]; - kv.key[2] = key.as_u64[2]; - - if (clib_bihash_search_24_8 - (&dm->per_thread_data[thread_index].in2out, &kv, &value)) - { - n = slow_path (dm, &key, &s, next, error, thread_index); - if (PREDICT_FALSE (next == DSLITE_IN2OUT_NEXT_DROP)) - goto done; - } - else - { - s = - pool_elt_at_index (dm->per_thread_data[thread_index].sessions, - value.value); - } - - old_addr = ip4->src_address.as_u32; - ip4->src_address = s->out2in.addr; - new_addr = ip4->src_address.as_u32; - sum = ip4->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address); - ip4->checksum = ip_csum_fold (sum); - - old_id = echo->identifier; - echo->identifier = new_id = s->out2in.port; - sum = icmp->checksum; - sum = ip_csum_update (sum, old_id, new_id, icmp_echo_header_t, identifier); - icmp->checksum = ip_csum_fold (sum); - -done: - *sp = s; - return n; -} - -static inline uword -dslite_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, u8 is_slow_path) -{ - u32 n_left_from, *from, *to_next; - dslite_in2out_next_t next_index; - u32 node_index; - vlib_node_runtime_t *error_node; - u32 thread_index = vm->thread_index; - f64 now = vlib_time_now (vm); - dslite_main_t *dm = &dslite_main; - - node_index = - is_slow_path ? dm->dslite_in2out_slowpath_node_index : - dm->dslite_in2out_node_index; - - error_node = vlib_node_get_runtime (vm, node_index); - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = DSLITE_IN2OUT_NEXT_IP4_LOOKUP; - ip4_header_t *ip40; - ip6_header_t *ip60; - u8 error0 = DSLITE_ERROR_IN2OUT; - u32 proto0; - dslite_session_t *s0 = 0; - clib_bihash_kv_24_8_t kv0, value0; - dslite_session_key_t key0; - udp_header_t *udp0; - tcp_header_t *tcp0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 old_port0, new_port0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip60 = vlib_buffer_get_current (b0); - - if (PREDICT_FALSE (ip60->protocol != IP_PROTOCOL_IP_IN_IP)) - { - if (ip60->protocol == IP_PROTOCOL_ICMP6) - { - next0 = DSLITE_IN2OUT_NEXT_IP6_ICMP; - goto trace0; - } - error0 = DSLITE_ERROR_BAD_IP6_PROTOCOL; - next0 = DSLITE_IN2OUT_NEXT_DROP; - goto trace0; - } - - ip40 = vlib_buffer_get_current (b0) + sizeof (ip6_header_t); - proto0 = ip_proto_to_snat_proto (ip40->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - { - error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; - next0 = DSLITE_IN2OUT_NEXT_DROP; - goto trace0; - } - - udp0 = ip4_next_header (ip40); - tcp0 = (tcp_header_t *) udp0; - - if (is_slow_path) - { - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = - dslite_icmp_in2out (dm, ip60, ip40, &s0, next0, &error0, - thread_index); - if (PREDICT_FALSE (next0 == DSLITE_IN2OUT_NEXT_DROP)) - goto trace0; - - goto accounting0; - } - } - else - { - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = DSLITE_IN2OUT_NEXT_SLOWPATH; - goto trace0; - } - } - - key0.addr = ip40->src_address; - key0.port = udp0->src_port; - key0.proto = proto0; - key0.softwire_id.as_u64[0] = ip60->src_address.as_u64[0]; - key0.softwire_id.as_u64[1] = ip60->src_address.as_u64[1]; - key0.pad = 0; - kv0.key[0] = key0.as_u64[0]; - kv0.key[1] = key0.as_u64[1]; - kv0.key[2] = key0.as_u64[2]; - - if (clib_bihash_search_24_8 - (&dm->per_thread_data[thread_index].in2out, &kv0, &value0)) - { - if (is_slow_path) - { - next0 = - slow_path (dm, &key0, &s0, next0, &error0, thread_index); - if (PREDICT_FALSE (next0 == DSLITE_IN2OUT_NEXT_DROP)) - goto trace0; - } - else - { - next0 = DSLITE_IN2OUT_NEXT_SLOWPATH; - goto trace0; - } - } - else - { - s0 = - pool_elt_at_index (dm->per_thread_data[thread_index].sessions, - value0.value); - } - - old_addr0 = ip40->src_address.as_u32; - ip40->src_address = s0->out2in.addr; - new_addr0 = ip40->src_address.as_u32; - sum0 = ip40->checksum; - sum0 = - ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - src_address); - ip40->checksum = ip_csum_fold (sum0); - if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->src_port; - tcp0->src_port = s0->out2in.port; - new_port0 = tcp0->src_port; - - sum0 = tcp0->checksum; - sum0 = - ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - dst_address); - sum0 = - ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, - length); - mss_clamping (&snat_main, tcp0, &sum0); - tcp0->checksum = ip_csum_fold (sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = s0->out2in.port; - udp0->checksum = 0; - } - - accounting0: - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-B4 LRU list maintenance */ - clib_dlist_remove (dm->per_thread_data[thread_index].list_pool, - s0->per_b4_index); - clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, - s0->per_b4_list_head_index, s0->per_b4_index); - - ip40->tos = - (clib_net_to_host_u32 - (ip60->ip_version_traffic_class_and_flow_label) & 0x0ff00000) >> - 20; - vlib_buffer_advance (b0, sizeof (ip6_header_t)); - - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = - s0 - dm->per_thread_data[thread_index].sessions; - } - - b0->error = error_node->errors[error0]; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -VLIB_NODE_FN (dslite_in2out_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dslite_in2out_node_fn_inline (vm, node, frame, 0); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dslite_in2out_node) = { - .name = "dslite-in2out", - .vector_size = sizeof (u32), - .format_trace = format_dslite_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (dslite_in2out_error_strings), - .error_strings = dslite_in2out_error_strings, - .n_next_nodes = DSLITE_IN2OUT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [DSLITE_IN2OUT_NEXT_DROP] = "error-drop", - [DSLITE_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup", - [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-icmp-input", - [DSLITE_IN2OUT_NEXT_SLOWPATH] = "dslite-in2out-slowpath", - }, -}; -/* *INDENT-ON* */ - -VLIB_NODE_FN (dslite_in2out_slowpath_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dslite_in2out_node_fn_inline (vm, node, frame, 1); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dslite_in2out_slowpath_node) = { - .name = "dslite-in2out-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_dslite_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (dslite_in2out_error_strings), - .error_strings = dslite_in2out_error_strings, - .n_next_nodes = DSLITE_IN2OUT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [DSLITE_IN2OUT_NEXT_DROP] = "error-drop", - [DSLITE_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup", - [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-lookup", - [DSLITE_IN2OUT_NEXT_SLOWPATH] = "dslite-in2out-slowpath", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/dslite_out2in.c b/src/plugins/nat/dslite_out2in.c deleted file mode 100644 index 265d79fc53e..00000000000 --- a/src/plugins/nat/dslite_out2in.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ -#include -#include - -typedef enum -{ - DSLITE_OUT2IN_NEXT_IP4_LOOKUP, - DSLITE_OUT2IN_NEXT_IP6_LOOKUP, - DSLITE_OUT2IN_NEXT_DROP, - DSLITE_OUT2IN_N_NEXT, -} dslite_out2in_next_t; - -static char *dslite_out2in_error_strings[] = { -#define _(sym,string) string, - foreach_dslite_error -#undef _ -}; - -static inline u32 -dslite_icmp_out2in (dslite_main_t * dm, ip4_header_t * ip4, - dslite_session_t ** sp, u32 next, u8 * error, - u32 thread_index) -{ - dslite_session_t *s = 0; - icmp46_header_t *icmp = ip4_next_header (ip4); - clib_bihash_kv_8_8_t kv, value; - snat_session_key_t key; - u32 n = next; - icmp_echo_header_t *echo; - u32 new_addr, old_addr; - u16 old_id, new_id; - ip_csum_t sum; - - echo = (icmp_echo_header_t *) (icmp + 1); - - if (icmp_type_is_error_message (icmp->type) - || (icmp->type != ICMP4_echo_reply)) - { - n = DSLITE_OUT2IN_NEXT_DROP; - *error = DSLITE_ERROR_BAD_ICMP_TYPE; - goto done; - } - - key.addr = ip4->dst_address; - key.port = echo->identifier; - key.protocol = SNAT_PROTOCOL_ICMP; - key.fib_index = 0; - kv.key = key.as_u64; - - if (clib_bihash_search_8_8 - (&dm->per_thread_data[thread_index].out2in, &kv, &value)) - { - next = DSLITE_OUT2IN_NEXT_DROP; - *error = DSLITE_ERROR_NO_TRANSLATION; - goto done; - } - else - { - s = - pool_elt_at_index (dm->per_thread_data[thread_index].sessions, - value.value); - } - - old_id = echo->identifier; - echo->identifier = new_id = s->in2out.port; - sum = icmp->checksum; - sum = ip_csum_update (sum, old_id, new_id, icmp_echo_header_t, identifier); - icmp->checksum = ip_csum_fold (sum); - - old_addr = ip4->dst_address.as_u32; - ip4->dst_address = s->in2out.addr; - new_addr = ip4->dst_address.as_u32; - - sum = ip4->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); - ip4->checksum = ip_csum_fold (sum); - -done: - *sp = s; - return n; -} - -VLIB_NODE_FN (dslite_out2in_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - dslite_out2in_next_t next_index; - vlib_node_runtime_t *error_node; - u32 thread_index = vm->thread_index; - f64 now = vlib_time_now (vm); - dslite_main_t *dm = &dslite_main; - - error_node = vlib_node_get_runtime (vm, dm->dslite_out2in_node_index); - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = DSLITE_OUT2IN_NEXT_IP6_LOOKUP; - u8 error0 = DSLITE_ERROR_OUT2IN; - ip4_header_t *ip40; - ip6_header_t *ip60; - u32 proto0; - udp_header_t *udp0; - tcp_header_t *tcp0; - clib_bihash_kv_8_8_t kv0, value0; - snat_session_key_t key0; - dslite_session_t *s0 = 0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip40 = vlib_buffer_get_current (b0); - proto0 = ip_proto_to_snat_proto (ip40->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - { - error0 = DSLITE_ERROR_UNSUPPORTED_PROTOCOL; - next0 = DSLITE_OUT2IN_NEXT_DROP; - goto trace0; - } - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = - dslite_icmp_out2in (dm, ip40, &s0, next0, &error0, - thread_index); - if (PREDICT_FALSE (next0 == DSLITE_OUT2IN_NEXT_DROP)) - goto trace0; - - goto encap0; - } - - udp0 = ip4_next_header (ip40); - tcp0 = (tcp_header_t *) udp0; - - key0.addr = ip40->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = 0; - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 - (&dm->per_thread_data[thread_index].out2in, &kv0, &value0)) - { - next0 = DSLITE_OUT2IN_NEXT_DROP; - error0 = DSLITE_ERROR_NO_TRANSLATION; - goto trace0; - } - else - { - s0 = - pool_elt_at_index (dm->per_thread_data[thread_index].sessions, - value0.value); - } - - old_addr0 = ip40->dst_address.as_u32; - ip40->dst_address = s0->in2out.addr; - new_addr0 = ip40->dst_address.as_u32; - - sum0 = ip40->checksum; - sum0 = - ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - dst_address); - ip40->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->dst_port; - tcp0->dst_port = s0->in2out.port; - new_port0 = tcp0->dst_port; - - sum0 = tcp0->checksum; - sum0 = - ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - dst_address); - sum0 = - ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, - length); - tcp0->checksum = ip_csum_fold (sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = s0->in2out.port; - udp0->checksum = 0; - } - - encap0: - /* Construct IPv6 header */ - vlib_buffer_advance (b0, -(sizeof (ip6_header_t))); - ip60 = vlib_buffer_get_current (b0); - ip60->ip_version_traffic_class_and_flow_label = - clib_host_to_net_u32 ((6 << 28) + (ip40->tos << 20)); - ip60->payload_length = ip40->length; - ip60->protocol = IP_PROTOCOL_IP_IN_IP; - ip60->hop_limit = ip40->ttl; - ip60->src_address.as_u64[0] = dm->aftr_ip6_addr.as_u64[0]; - ip60->src_address.as_u64[1] = dm->aftr_ip6_addr.as_u64[1]; - ip60->dst_address.as_u64[0] = s0->in2out.softwire_id.as_u64[0]; - ip60->dst_address.as_u64[1] = s0->in2out.softwire_id.as_u64[1]; - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-B4 LRU list maintenance */ - clib_dlist_remove (dm->per_thread_data[thread_index].list_pool, - s0->per_b4_index); - clib_dlist_addtail (dm->per_thread_data[thread_index].list_pool, - s0->per_b4_list_head_index, s0->per_b4_index); - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - dslite_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = - s0 - dm->per_thread_data[thread_index].sessions; - } - - b0->error = error_node->errors[error0]; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dslite_out2in_node) = { - .name = "dslite-out2in", - .vector_size = sizeof (u32), - .format_trace = format_dslite_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (dslite_out2in_error_strings), - .error_strings = dslite_out2in_error_strings, - .n_next_nodes = DSLITE_OUT2IN_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [DSLITE_OUT2IN_NEXT_DROP] = "error-drop", - [DSLITE_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup", - [DSLITE_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api index 356dd0ce8a9..58eee45d47d 100644 --- a/src/plugins/nat/nat.api +++ b/src/plugins/nat/nat.api @@ -1364,113 +1364,6 @@ autoreply define nat64_add_del_interface_addr { vl_api_interface_index_t sw_if_index; }; -/* - * DS-Lite APIs - */ - -/** \brief Add/delete address range to DS-Lite pool - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param start_addr - start IPv4 address of the range - @param end_addr - end IPv4 address of the range - @param is_add - true if add, false if delete -*/ -autoreply define dslite_add_del_pool_addr_range { - u32 client_index; - u32 context; - vl_api_ip4_address_t start_addr; - vl_api_ip4_address_t end_addr; - bool is_add; -}; - -/** \brief Dump DS-Lite addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define dslite_address_dump { - u32 client_index; - u32 context; -}; - -/** \brief DS-Lite address details response - @param context - sender context, to match reply w/ request - @param ip_address - IPv4 address -*/ -define dslite_address_details { - u32 context; - vl_api_ip4_address_t ip_address; -}; - -/** \brief Set AFTR IPv6 and IPv4 addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param ip4_addr - IPv4 address - @param ip6_addr - IPv6 address -*/ -autoreply define dslite_set_aftr_addr { - u32 client_index; - u32 context; - vl_api_ip4_address_t ip4_addr; - vl_api_ip6_address_t ip6_addr; -}; - -/** \brief Get AFTR IPv6 and IPv4 addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define dslite_get_aftr_addr { - u32 client_index; - u32 context; -}; - -/** \brief Response to get AFTR IPv6 and IPv4 addresses - @param context - sender context, to match reply w/ request - @param retval - return code - @param ip4_addr - IPv4 address - @param ip6_addr - IPv6 address -*/ -define dslite_get_aftr_addr_reply { - u32 context; - i32 retval; - vl_api_ip4_address_t ip4_addr; - vl_api_ip6_address_t ip6_addr; -}; - -/** \brief Set B4 IPv6 and IPv4 addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param ip4_addr - IPv4 address - @param ip6_addr - IPv6 address -*/ -autoreply define dslite_set_b4_addr { - u32 client_index; - u32 context; - vl_api_ip4_address_t ip4_addr; - vl_api_ip6_address_t ip6_addr; -}; - -/** \brief Get B4 IPv6 and IPv4 addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define dslite_get_b4_addr { - u32 client_index; - u32 context; -}; - -/** \brief Response to get B4 IPv6 and IPv4 addresses - @param context - sender context, to match reply w/ request - @param retval - return code - @param ip4_addr - IPv4 address - @param ip6_addr - IPv6 address -*/ -define dslite_get_b4_addr_reply { - u32 context; - i32 retval; - vl_api_ip4_address_t ip4_addr; - vl_api_ip6_address_t ip6_addr; -}; - /* * NAT66 APIs */ diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 14855323ab7..9f516586877 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -640,15 +639,6 @@ is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr) return 0; } -void -increment_v4_address (ip4_address_t * a) -{ - u32 v; - - v = clib_net_to_host_u32 (a->as_u32) + 1; - a->as_u32 = clib_host_to_net_u32 (v); -} - static void snat_add_static_mapping_when_resolved (snat_main_t * sm, ip4_address_t l_addr, @@ -2507,8 +2497,6 @@ snat_init (vlib_main_t * vm) if (error) return error; - dslite_init (vm); - nat66_init (vm); ip4_table_bind_callback_t cbt4 = { @@ -3755,7 +3743,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) { snat_main_t *sm = &snat_main; nat66_main_t *nm = &nat66_main; - dslite_main_t *dm = &dslite_main; + //dslite_main_t *dm = &dslite_main; snat_main_per_thread_data_t *tsm; u32 static_mapping_buckets = 1024; @@ -3840,8 +3828,8 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) ; else if (unformat (input, "out2in dpo")) sm->out2in_dpo = 1; - else if (unformat (input, "dslite ce")) - dslite_set_ce (dm, 1); + //else if (unformat (input, "dslite ce")) + //dslite_set_ce (dm, 1); else if (unformat (input, "endpoint-dependent")) sm->endpoint_dependent = 1; else diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index d3fa3eea38a..9cde96840f8 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -1119,11 +1119,6 @@ int nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg); int nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg); int nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg); -/** - * @brief Increment IPv4 address - */ -void increment_v4_address (ip4_address_t * a); - /** * @brief Add external address to NAT44 pool * diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index 6df1a851e48..d73a0337d2a 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -96,7 +95,7 @@ vl_api_nat_show_config_t_handler (vl_api_nat_show_config_t * mp) { vl_api_nat_show_config_reply_t *rmp; snat_main_t *sm = &snat_main; - dslite_main_t *dm = &dslite_main; + //dslite_main_t *dm = &dslite_main; nat64_main_t *n64m = &nat64_main; int rv = 0; @@ -116,7 +115,7 @@ vl_api_nat_show_config_t_handler (vl_api_nat_show_config_t * mp) rmp->deterministic = sm->deterministic; rmp->endpoint_dependent = sm->endpoint_dependent; rmp->out2in_dpo = sm->out2in_dpo; - rmp->dslite_ce = dm->is_ce; + //rmp->dslite_ce = dm->is_ce; rmp->nat64_bib_buckets = n64m->bib_buckets; rmp->nat64_bib_memory_size = n64m->bib_memory_size; rmp->nat64_st_buckets = n64m->st_buckets; @@ -2901,229 +2900,6 @@ static void *vl_api_nat64_add_del_interface_addr_t_print FINISH; } -/***************/ -/*** DS-Lite ***/ -/***************/ - -static void -vl_api_dslite_set_aftr_addr_t_handler (vl_api_dslite_set_aftr_addr_t * mp) -{ - vl_api_dslite_set_aftr_addr_reply_t *rmp; - snat_main_t *sm = &snat_main; - dslite_main_t *dm = &dslite_main; - int rv = 0; - ip6_address_t ip6_addr; - ip4_address_t ip4_addr; - - memcpy (&ip6_addr.as_u8, mp->ip6_addr, 16); - memcpy (&ip4_addr.as_u8, mp->ip4_addr, 4); - - rv = dslite_set_aftr_ip6_addr (dm, &ip6_addr); - if (rv == 0) - rv = dslite_set_aftr_ip4_addr (dm, &ip4_addr); - - REPLY_MACRO (VL_API_DSLITE_SET_AFTR_ADDR_REPLY); -} - -static void * -vl_api_dslite_set_aftr_addr_t_print (vl_api_dslite_set_aftr_addr_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dslite_set_aftr_addr "); - s = format (s, "ip6_addr %U ip4_addr %U\n", - format_ip6_address, mp->ip6_addr, - format_ip4_address, mp->ip4_addr); - - FINISH; -} - -static void -vl_api_dslite_get_aftr_addr_t_handler (vl_api_dslite_get_aftr_addr_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_dslite_get_aftr_addr_reply_t *rmp; - dslite_main_t *dm = &dslite_main; - int rv = 0; - - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_DSLITE_GET_AFTR_ADDR_REPLY, - ({ - memcpy (rmp->ip4_addr, &dm->aftr_ip4_addr.as_u8, 4); - memcpy (rmp->ip6_addr, &dm->aftr_ip6_addr.as_u8, 16); - })) - /* *INDENT-ON* */ -} - -static void * -vl_api_dslite_get_aftr_addr_t_print (vl_api_dslite_get_aftr_addr_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dslite_get_aftr_addr"); - - FINISH; -} - -static void -vl_api_dslite_set_b4_addr_t_handler (vl_api_dslite_set_b4_addr_t * mp) -{ - vl_api_dslite_set_b4_addr_reply_t *rmp; - snat_main_t *sm = &snat_main; - dslite_main_t *dm = &dslite_main; - int rv = 0; - ip6_address_t ip6_addr; - ip4_address_t ip4_addr; - - memcpy (&ip6_addr.as_u8, mp->ip6_addr, 16); - memcpy (&ip4_addr.as_u8, mp->ip4_addr, 4); - - rv = dslite_set_b4_ip6_addr (dm, &ip6_addr); - if (rv == 0) - rv = dslite_set_b4_ip4_addr (dm, &ip4_addr); - - REPLY_MACRO (VL_API_DSLITE_SET_B4_ADDR_REPLY); -} - -static void * -vl_api_dslite_set_b4_addr_t_print (vl_api_dslite_set_b4_addr_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dslite_set_b4_addr "); - s = format (s, "ip6_addr %U ip4_addr %U\n", - format_ip6_address, mp->ip6_addr, - format_ip6_address, mp->ip4_addr); - - FINISH; -} - -static void -vl_api_dslite_get_b4_addr_t_handler (vl_api_dslite_get_b4_addr_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_dslite_get_b4_addr_reply_t *rmp; - dslite_main_t *dm = &dslite_main; - int rv = 0; - - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_DSLITE_GET_B4_ADDR_REPLY, - ({ - memcpy (rmp->ip4_addr, &dm->b4_ip4_addr.as_u8, 4); - memcpy (rmp->ip6_addr, &dm->b4_ip6_addr.as_u8, 16); - })) - /* *INDENT-ON* */ -} - -static void * -vl_api_dslite_get_b4_addr_t_print (vl_api_dslite_get_b4_addr_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dslite_get_b4_addr"); - - FINISH; -} - -static void - vl_api_dslite_add_del_pool_addr_range_t_handler - (vl_api_dslite_add_del_pool_addr_range_t * mp) -{ - vl_api_dslite_add_del_pool_addr_range_reply_t *rmp; - snat_main_t *sm = &snat_main; - dslite_main_t *dm = &dslite_main; - int rv = 0; - ip4_address_t this_addr; - u32 start_host_order, end_host_order; - int i, count; - u32 *tmp; - - tmp = (u32 *) mp->start_addr; - start_host_order = clib_host_to_net_u32 (tmp[0]); - tmp = (u32 *) mp->end_addr; - end_host_order = clib_host_to_net_u32 (tmp[0]); - - count = (end_host_order - start_host_order) + 1; - memcpy (&this_addr.as_u8, mp->start_addr, 4); - - for (i = 0; i < count; i++) - { - if ((rv = dslite_add_del_pool_addr (dm, &this_addr, mp->is_add))) - goto send_reply; - - increment_v4_address (&this_addr); - } - -send_reply: - REPLY_MACRO (VL_API_DSLITE_ADD_DEL_POOL_ADDR_RANGE_REPLY); -} - -static void -send_dslite_address_details (snat_address_t * ap, - vl_api_registration_t * reg, u32 context) -{ - vl_api_dslite_address_details_t *rmp; - snat_main_t *sm = &snat_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - - clib_memset (rmp, 0, sizeof (*rmp)); - - rmp->_vl_msg_id = ntohs (VL_API_DSLITE_ADDRESS_DETAILS + sm->msg_id_base); - clib_memcpy (rmp->ip_address, &(ap->addr), 4); - rmp->context = context; - - vl_api_send_msg (reg, (u8 *) rmp); -} - -static void -vl_api_dslite_address_dump_t_handler (vl_api_dslite_address_dump_t * mp) -{ - vl_api_registration_t *reg; - dslite_main_t *dm = &dslite_main; - snat_address_t *ap; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return; - - /* *INDENT-OFF* */ - vec_foreach (ap, dm->addr_pool) - { - send_dslite_address_details (ap, reg, mp->context); - } - /* *INDENT-ON* */ -} - -static void * -vl_api_dslite_address_dump_t_print (vl_api_dslite_address_dump_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dslite_address_dump "); - - FINISH; -} - -static void *vl_api_dslite_add_del_pool_addr_range_t_print - (vl_api_dslite_add_del_pool_addr_range_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dslite_add_del_pool_addr_range "); - s = format (s, "%U - %U\n", - format_ip4_address, mp->start_addr, - format_ip4_address, mp->end_addr); - - FINISH; -} - - /*************/ /*** NAT66 ***/ /*************/ @@ -3372,12 +3148,6 @@ _(NAT64_ST_DUMP, nat64_st_dump) \ _(NAT64_ADD_DEL_PREFIX, nat64_add_del_prefix) \ _(NAT64_PREFIX_DUMP, nat64_prefix_dump) \ _(NAT64_ADD_DEL_INTERFACE_ADDR, nat64_add_del_interface_addr) \ -_(DSLITE_ADD_DEL_POOL_ADDR_RANGE, dslite_add_del_pool_addr_range) \ -_(DSLITE_ADDRESS_DUMP, dslite_address_dump) \ -_(DSLITE_SET_AFTR_ADDR, dslite_set_aftr_addr) \ -_(DSLITE_GET_AFTR_ADDR, dslite_get_aftr_addr) \ -_(DSLITE_SET_B4_ADDR, dslite_set_b4_addr) \ -_(DSLITE_GET_B4_ADDR, dslite_get_b4_addr) \ _(NAT66_ADD_DEL_INTERFACE, nat66_add_del_interface) \ _(NAT66_INTERFACE_DUMP, nat66_interface_dump) \ _(NAT66_ADD_DEL_STATIC_MAPPING, nat66_add_del_static_mapping) \ diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h index a58317acdf3..f693032a685 100644 --- a/src/plugins/nat/nat_inlines.h +++ b/src/plugins/nat/nat_inlines.h @@ -692,6 +692,15 @@ snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t * node, return 1; } +static inline void +increment_v4_address (ip4_address_t * a) +{ + u32 v; + + v = clib_net_to_host_u32 (a->as_u32) + 1; + a->as_u32 = clib_host_to_net_u32 (v); +} + #endif /* __included_nat_inlines_h__ */ /* diff --git a/src/plugins/nat/test/test_dslite.py b/src/plugins/nat/test/test_dslite.py new file mode 100644 index 00000000000..dfa7d7c7c21 --- /dev/null +++ b/src/plugins/nat/test/test_dslite.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python3 + +import socket +import unittest +import struct +import random + +from framework import VppTestCase, VppTestRunner, running_extended_tests + +import scapy.compat +from scapy.layers.inet import IP, TCP, UDP, ICMP +from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror +from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \ + ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6 +from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment +from scapy.layers.l2 import Ether, ARP, GRE +from scapy.data import IP_PROTOS +from scapy.packet import bind_layers, Raw +from util import ppp +from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder +from time import sleep +from util import ip4_range +from vpp_papi import mac_pton +from syslog_rfc5424_parser import SyslogMessage, ParseError +from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity +from io import BytesIO +from vpp_papi import VppEnum +from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathType +from vpp_neighbor import VppNeighbor +from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \ + IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \ + PacketListField +from ipaddress import IPv6Network + + +class TestDSlite(VppTestCase): + """ DS-Lite Test Cases """ + + @classmethod + def setUpClass(cls): + super(TestDSlite, cls).setUpClass() + + try: + cls.nat_addr = '10.0.0.3' + + cls.create_pg_interfaces(range(3)) + cls.pg0.admin_up() + cls.pg0.config_ip4() + cls.pg0.resolve_arp() + cls.pg1.admin_up() + cls.pg1.config_ip6() + cls.pg1.generate_remote_hosts(2) + cls.pg1.configure_ipv6_neighbors() + cls.pg2.admin_up() + cls.pg2.config_ip4() + cls.pg2.resolve_arp() + + except Exception: + super(TestDSlite, cls).tearDownClass() + raise + + @classmethod + def tearDownClass(cls): + super(TestDSlite, cls).tearDownClass() + + def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport, + sv6enc, proto): + message = data.decode('utf-8') + try: + message = SyslogMessage.parse(message) + except ParseError as e: + self.logger.error(e) + else: + self.assertEqual(message.severity, SyslogSeverity.info) + self.assertEqual(message.appname, 'NAT') + self.assertEqual(message.msgid, 'APMADD') + sd_params = message.sd.get('napmap') + self.assertTrue(sd_params is not None) + self.assertEqual(sd_params.get('IATYP'), 'IPv4') + self.assertEqual(sd_params.get('ISADDR'), isaddr) + self.assertEqual(sd_params.get('ISPORT'), "%d" % isport) + self.assertEqual(sd_params.get('XATYP'), 'IPv4') + self.assertEqual(sd_params.get('XSADDR'), xsaddr) + self.assertEqual(sd_params.get('XSPORT'), "%d" % xsport) + self.assertEqual(sd_params.get('PROTO'), "%d" % proto) + self.assertTrue(sd_params.get('SSUBIX') is not None) + self.assertEqual(sd_params.get('SV6ENC'), sv6enc) + + def test_dslite(self): + """ Test DS-Lite """ + nat_config = self.vapi.nat_show_config() + self.assertEqual(0, nat_config.dslite_ce) + + self.vapi.dslite_add_del_pool_addr_range(start_addr=self.nat_addr, + end_addr=self.nat_addr, + is_add=1) + aftr_ip4 = '192.0.0.1' + aftr_ip6 = '2001:db8:85a3::8a2e:370:1' + self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6) + self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4) + + # UDP + p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6) / + IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / + UDP(sport=20000, dport=10000)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + capture = capture[0] + self.assertFalse(capture.haslayer(IPv6)) + self.assertEqual(capture[IP].src, self.nat_addr) + self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) + self.assertNotEqual(capture[UDP].sport, 20000) + self.assertEqual(capture[UDP].dport, 10000) + self.assert_packet_checksums_valid(capture) + out_port = capture[UDP].sport + capture = self.pg2.get_capture(1) + self.verify_syslog_apmadd(capture[0][Raw].load, '192.168.1.1', + 20000, self.nat_addr, out_port, + self.pg1.remote_hosts[0].ip6, IP_PROTOS.udp) + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / + UDP(sport=10000, dport=out_port)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + capture = capture[0] + self.assertEqual(capture[IPv6].src, aftr_ip6) + self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6) + self.assertEqual(capture[IP].src, self.pg0.remote_ip4) + self.assertEqual(capture[IP].dst, '192.168.1.1') + self.assertEqual(capture[UDP].sport, 10000) + self.assertEqual(capture[UDP].dport, 20000) + self.assert_packet_checksums_valid(capture) + + # TCP + p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) / + IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / + TCP(sport=20001, dport=10001)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + capture = capture[0] + self.assertFalse(capture.haslayer(IPv6)) + self.assertEqual(capture[IP].src, self.nat_addr) + self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) + self.assertNotEqual(capture[TCP].sport, 20001) + self.assertEqual(capture[TCP].dport, 10001) + self.assert_packet_checksums_valid(capture) + out_port = capture[TCP].sport + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / + TCP(sport=10001, dport=out_port)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + capture = capture[0] + self.assertEqual(capture[IPv6].src, aftr_ip6) + self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) + self.assertEqual(capture[IP].src, self.pg0.remote_ip4) + self.assertEqual(capture[IP].dst, '192.168.1.1') + self.assertEqual(capture[TCP].sport, 10001) + self.assertEqual(capture[TCP].dport, 20001) + self.assert_packet_checksums_valid(capture) + + # ICMP + p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) / + IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / + ICMP(id=4000, type='echo-request')) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + capture = capture[0] + self.assertFalse(capture.haslayer(IPv6)) + self.assertEqual(capture[IP].src, self.nat_addr) + self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) + self.assertNotEqual(capture[ICMP].id, 4000) + self.assert_packet_checksums_valid(capture) + out_id = capture[ICMP].id + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / + ICMP(id=out_id, type='echo-reply')) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + capture = capture[0] + self.assertEqual(capture[IPv6].src, aftr_ip6) + self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) + self.assertEqual(capture[IP].src, self.pg0.remote_ip4) + self.assertEqual(capture[IP].dst, '192.168.1.1') + self.assertEqual(capture[ICMP].id, 4000) + self.assert_packet_checksums_valid(capture) + + # ping DS-Lite AFTR tunnel endpoint address + p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6) / + ICMPv6EchoRequest()) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + capture = capture[0] + self.assertEqual(capture[IPv6].src, aftr_ip6) + self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) + self.assertTrue(capture.haslayer(ICMPv6EchoReply)) + + b4s = self.statistics.get_counter('/dslite/total-b4s') + self.assertEqual(b4s[0][0], 2) + sessions = self.statistics.get_counter('/dslite/total-sessions') + self.assertEqual(sessions[0][0], 3) + + def tearDown(self): + super(TestDSlite, self).tearDown() + + def show_commands_at_teardown(self): + self.logger.info(self.vapi.cli("show dslite pool")) + self.logger.info( + self.vapi.cli("show dslite aftr-tunnel-endpoint-address")) + self.logger.info(self.vapi.cli("show dslite sessions")) + + +class TestDSliteCE(): + """ DS-Lite CE Test Cases """ + + @classmethod + def setUpConstants(cls): + super(TestDSliteCE, cls).setUpConstants() + cls.vpp_cmdline.extend(["nat", "{", "dslite ce", "}"]) + + @classmethod + def setUpClass(cls): + super(TestDSliteCE, cls).setUpClass() + + try: + cls.create_pg_interfaces(range(2)) + cls.pg0.admin_up() + cls.pg0.config_ip4() + cls.pg0.resolve_arp() + cls.pg1.admin_up() + cls.pg1.config_ip6() + cls.pg1.generate_remote_hosts(1) + cls.pg1.configure_ipv6_neighbors() + + except Exception: + super(TestDSliteCE, cls).tearDownClass() + raise + + @classmethod + def tearDownClass(cls): + super(TestDSliteCE, cls).tearDownClass() + + def test_dslite_ce(self): + """ Test DS-Lite CE """ + + nat_config = self.vapi.nat_show_config() + self.assertEqual(1, nat_config.dslite_ce) + + b4_ip4 = '192.0.0.2' + b4_ip6 = '2001:db8:62aa::375e:f4c1:1' + self.vapi.dslite_set_b4_addr(ip4_addr=b4_ip4, ip6_addr=b4_ip6) + + aftr_ip4 = '192.0.0.1' + aftr_ip6 = '2001:db8:85a3::8a2e:370:1' + aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6) + self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6) + + r1 = VppIpRoute(self, aftr_ip6, 128, + [VppRoutePath(self.pg1.remote_ip6, + self.pg1.sw_if_index)]) + r1.add_vpp_config() + + # UDP encapsulation + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4) / + UDP(sport=10000, dport=20000)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + capture = capture[0] + self.assertEqual(capture[IPv6].src, b4_ip6) + self.assertEqual(capture[IPv6].dst, aftr_ip6) + self.assertEqual(capture[IP].src, self.pg0.remote_ip4) + self.assertEqual(capture[IP].dst, self.pg1.remote_ip4) + self.assertEqual(capture[UDP].sport, 10000) + self.assertEqual(capture[UDP].dport, 20000) + self.assert_packet_checksums_valid(capture) + + # UDP decapsulation + p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=b4_ip6, src=aftr_ip6) / + IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4) / + UDP(sport=20000, dport=10000)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + capture = capture[0] + self.assertFalse(capture.haslayer(IPv6)) + self.assertEqual(capture[IP].src, self.pg1.remote_ip4) + self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) + self.assertEqual(capture[UDP].sport, 20000) + self.assertEqual(capture[UDP].dport, 10000) + self.assert_packet_checksums_valid(capture) + + # ping DS-Lite B4 tunnel endpoint address + p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6) / + ICMPv6EchoRequest()) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + capture = capture[0] + self.assertEqual(capture[IPv6].src, b4_ip6) + self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6) + self.assertTrue(capture.haslayer(ICMPv6EchoReply)) + + def tearDown(self): + super(TestDSliteCE, self).tearDown() + + def show_commands_at_teardown(self): + self.logger.info( + self.vapi.cli("show dslite aftr-tunnel-endpoint-address")) + self.logger.info( + self.vapi.cli("show dslite b4-tunnel-endpoint-address")) diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py index f87065598f1..d16204e7217 100644 --- a/src/plugins/nat/test/test_nat.py +++ b/src/plugins/nat/test/test_nat.py @@ -9186,311 +9186,6 @@ class TestNAT64(MethodHolder): self.logger.info(self.vapi.cli("show nat64 session table all")) -class TestDSlite(MethodHolder): - """ DS-Lite Test Cases """ - - @classmethod - def setUpClass(cls): - super(TestDSlite, cls).setUpClass() - - try: - cls.nat_addr = '10.0.0.3' - - cls.create_pg_interfaces(range(3)) - cls.pg0.admin_up() - cls.pg0.config_ip4() - cls.pg0.resolve_arp() - cls.pg1.admin_up() - cls.pg1.config_ip6() - cls.pg1.generate_remote_hosts(2) - cls.pg1.configure_ipv6_neighbors() - cls.pg2.admin_up() - cls.pg2.config_ip4() - cls.pg2.resolve_arp() - - except Exception: - super(TestDSlite, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestDSlite, cls).tearDownClass() - - def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport, - sv6enc, proto): - message = data.decode('utf-8') - try: - message = SyslogMessage.parse(message) - except ParseError as e: - self.logger.error(e) - else: - self.assertEqual(message.severity, SyslogSeverity.info) - self.assertEqual(message.appname, 'NAT') - self.assertEqual(message.msgid, 'APMADD') - sd_params = message.sd.get('napmap') - self.assertTrue(sd_params is not None) - self.assertEqual(sd_params.get('IATYP'), 'IPv4') - self.assertEqual(sd_params.get('ISADDR'), isaddr) - self.assertEqual(sd_params.get('ISPORT'), "%d" % isport) - self.assertEqual(sd_params.get('XATYP'), 'IPv4') - self.assertEqual(sd_params.get('XSADDR'), xsaddr) - self.assertEqual(sd_params.get('XSPORT'), "%d" % xsport) - self.assertEqual(sd_params.get('PROTO'), "%d" % proto) - self.assertTrue(sd_params.get('SSUBIX') is not None) - self.assertEqual(sd_params.get('SV6ENC'), sv6enc) - - def test_dslite(self): - """ Test DS-Lite """ - nat_config = self.vapi.nat_show_config() - self.assertEqual(0, nat_config.dslite_ce) - - self.vapi.dslite_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - is_add=1) - aftr_ip4 = '192.0.0.1' - aftr_ip6 = '2001:db8:85a3::8a2e:370:1' - self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6) - self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4) - - # UDP - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6) / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - UDP(sport=20000, dport=10000)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.nat_addr) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertNotEqual(capture[UDP].sport, 20000) - self.assertEqual(capture[UDP].dport, 10000) - self.assert_packet_checksums_valid(capture) - out_port = capture[UDP].sport - capture = self.pg2.get_capture(1) - self.verify_syslog_apmadd(capture[0][Raw].load, '192.168.1.1', - 20000, self.nat_addr, out_port, - self.pg1.remote_hosts[0].ip6, IP_PROTOS.udp) - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / - UDP(sport=10000, dport=out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, '192.168.1.1') - self.assertEqual(capture[UDP].sport, 10000) - self.assertEqual(capture[UDP].dport, 20000) - self.assert_packet_checksums_valid(capture) - - # TCP - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - TCP(sport=20001, dport=10001)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.nat_addr) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertNotEqual(capture[TCP].sport, 20001) - self.assertEqual(capture[TCP].dport, 10001) - self.assert_packet_checksums_valid(capture) - out_port = capture[TCP].sport - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / - TCP(sport=10001, dport=out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, '192.168.1.1') - self.assertEqual(capture[TCP].sport, 10001) - self.assertEqual(capture[TCP].dport, 20001) - self.assert_packet_checksums_valid(capture) - - # ICMP - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - ICMP(id=4000, type='echo-request')) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.nat_addr) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertNotEqual(capture[ICMP].id, 4000) - self.assert_packet_checksums_valid(capture) - out_id = capture[ICMP].id - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / - ICMP(id=out_id, type='echo-reply')) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, '192.168.1.1') - self.assertEqual(capture[ICMP].id, 4000) - self.assert_packet_checksums_valid(capture) - - # ping DS-Lite AFTR tunnel endpoint address - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6) / - ICMPv6EchoRequest()) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) - self.assertTrue(capture.haslayer(ICMPv6EchoReply)) - - b4s = self.statistics.get_counter('/dslite/total-b4s') - self.assertEqual(b4s[0][0], 2) - sessions = self.statistics.get_counter('/dslite/total-sessions') - self.assertEqual(sessions[0][0], 3) - - def tearDown(self): - super(TestDSlite, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show dslite pool")) - self.logger.info( - self.vapi.cli("show dslite aftr-tunnel-endpoint-address")) - self.logger.info(self.vapi.cli("show dslite sessions")) - - -class TestDSliteCE(MethodHolder): - """ DS-Lite CE Test Cases """ - - @classmethod - def setUpConstants(cls): - super(TestDSliteCE, cls).setUpConstants() - cls.vpp_cmdline.extend(["nat", "{", "dslite ce", "}"]) - - @classmethod - def setUpClass(cls): - super(TestDSliteCE, cls).setUpClass() - - try: - cls.create_pg_interfaces(range(2)) - cls.pg0.admin_up() - cls.pg0.config_ip4() - cls.pg0.resolve_arp() - cls.pg1.admin_up() - cls.pg1.config_ip6() - cls.pg1.generate_remote_hosts(1) - cls.pg1.configure_ipv6_neighbors() - - except Exception: - super(TestDSliteCE, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestDSliteCE, cls).tearDownClass() - - def test_dslite_ce(self): - """ Test DS-Lite CE """ - - nat_config = self.vapi.nat_show_config() - self.assertEqual(1, nat_config.dslite_ce) - - b4_ip4 = '192.0.0.2' - b4_ip6 = '2001:db8:62aa::375e:f4c1:1' - self.vapi.dslite_set_b4_addr(ip4_addr=b4_ip4, ip6_addr=b4_ip6) - - aftr_ip4 = '192.0.0.1' - aftr_ip6 = '2001:db8:85a3::8a2e:370:1' - aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6) - self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6) - - r1 = VppIpRoute(self, aftr_ip6, 128, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - r1.add_vpp_config() - - # UDP encapsulation - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4) / - UDP(sport=10000, dport=20000)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, b4_ip6) - self.assertEqual(capture[IPv6].dst, aftr_ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, self.pg1.remote_ip4) - self.assertEqual(capture[UDP].sport, 10000) - self.assertEqual(capture[UDP].dport, 20000) - self.assert_packet_checksums_valid(capture) - - # UDP decapsulation - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=b4_ip6, src=aftr_ip6) / - IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4) / - UDP(sport=20000, dport=10000)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.pg1.remote_ip4) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertEqual(capture[UDP].sport, 20000) - self.assertEqual(capture[UDP].dport, 10000) - self.assert_packet_checksums_valid(capture) - - # ping DS-Lite B4 tunnel endpoint address - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6) / - ICMPv6EchoRequest()) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, b4_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6) - self.assertTrue(capture.haslayer(ICMPv6EchoReply)) - - def tearDown(self): - super(TestDSliteCE, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info( - self.vapi.cli("show dslite aftr-tunnel-endpoint-address")) - self.logger.info( - self.vapi.cli("show dslite b4-tunnel-endpoint-address")) - - class TestNAT66(MethodHolder): """ NAT66 Test Cases """ -- cgit 1.2.3-korg