From 6810a77da36c6750938800314c15e840ee2a8c93 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 18 Sep 2020 14:05:45 +0000 Subject: misc: Move l2tp to plugin Type: refactor Change-Id: Ifb36eeb146b87e9e305881429d32d6879e955e1e Signed-off-by: Neale Ranns --- src/plugins/l2tp/CMakeLists.txt | 38 ++ src/plugins/l2tp/FEATURE.yaml | 8 + src/plugins/l2tp/decap.c | 301 +++++++++++++++ src/plugins/l2tp/encap.c | 235 ++++++++++++ src/plugins/l2tp/l2tp.api | 115 ++++++ src/plugins/l2tp/l2tp.c | 764 +++++++++++++++++++++++++++++++++++++ src/plugins/l2tp/l2tp.h | 148 +++++++ src/plugins/l2tp/l2tp_api.c | 251 ++++++++++++ src/plugins/l2tp/l2tp_test.c | 315 +++++++++++++++ src/plugins/l2tp/packet.h | 44 +++ src/plugins/l2tp/pg.c | 106 +++++ src/plugins/l2tp/test/test_l2tp.py | 47 +++ src/vat/api_format.c | 324 ---------------- src/vnet/CMakeLists.txt | 23 -- src/vnet/l2tp/FEATURE.yaml | 8 - src/vnet/l2tp/decap.c | 301 --------------- src/vnet/l2tp/encap.c | 235 ------------ src/vnet/l2tp/l2tp.api | 115 ------ src/vnet/l2tp/l2tp.c | 764 ------------------------------------- src/vnet/l2tp/l2tp.h | 148 ------- src/vnet/l2tp/l2tp_api.c | 273 ------------- src/vnet/l2tp/packet.h | 44 --- src/vnet/l2tp/pg.c | 106 ----- src/vnet/vnet_all_api_h.h | 1 - src/vpp/api/custom_dump.c | 100 ----- test/test_l2tp.py | 47 --- 26 files changed, 2372 insertions(+), 2489 deletions(-) create mode 100644 src/plugins/l2tp/CMakeLists.txt create mode 100644 src/plugins/l2tp/FEATURE.yaml create mode 100644 src/plugins/l2tp/decap.c create mode 100644 src/plugins/l2tp/encap.c create mode 100644 src/plugins/l2tp/l2tp.api create mode 100644 src/plugins/l2tp/l2tp.c create mode 100644 src/plugins/l2tp/l2tp.h create mode 100644 src/plugins/l2tp/l2tp_api.c create mode 100644 src/plugins/l2tp/l2tp_test.c create mode 100644 src/plugins/l2tp/packet.h create mode 100644 src/plugins/l2tp/pg.c create mode 100644 src/plugins/l2tp/test/test_l2tp.py delete mode 100644 src/vnet/l2tp/FEATURE.yaml delete mode 100644 src/vnet/l2tp/decap.c delete mode 100644 src/vnet/l2tp/encap.c delete mode 100644 src/vnet/l2tp/l2tp.api delete mode 100644 src/vnet/l2tp/l2tp.c delete mode 100644 src/vnet/l2tp/l2tp.h delete mode 100644 src/vnet/l2tp/l2tp_api.c delete mode 100644 src/vnet/l2tp/packet.h delete mode 100644 src/vnet/l2tp/pg.c delete mode 100644 test/test_l2tp.py diff --git a/src/plugins/l2tp/CMakeLists.txt b/src/plugins/l2tp/CMakeLists.txt new file mode 100644 index 00000000000..c8261abcd9c --- /dev/null +++ b/src/plugins/l2tp/CMakeLists.txt @@ -0,0 +1,38 @@ +# 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. + +############################################################################## +# Tunnel protocol: l2tpv3 +############################################################################## +add_vpp_plugin(l2tp + SOURCES + l2tp.c + encap.c + decap.c + pg.c + l2tp_api.c + + MULTIARCH_SOURCES + encap.c + decap.c + + INSTALL_HEADERS + l2tp.h + packet.h + + API_FILES + l2tp.api + + API_TEST_SOURCES + l2tp_test.c +) diff --git a/src/plugins/l2tp/FEATURE.yaml b/src/plugins/l2tp/FEATURE.yaml new file mode 100644 index 00000000000..58df9b2215e --- /dev/null +++ b/src/plugins/l2tp/FEATURE.yaml @@ -0,0 +1,8 @@ +--- +name: L2TPv3 +maintainer: unmaintained +features: + - L2TPv3 over IPv6 +description: "An initial and incomplete implementation of L2TPv3 (RFC3931)." +state: experimental +properties: [API, CLI] diff --git a/src/plugins/l2tp/decap.c b/src/plugins/l2tp/decap.c new file mode 100644 index 00000000000..8c41bdd2357 --- /dev/null +++ b/src/plugins/l2tp/decap.c @@ -0,0 +1,301 @@ +/* + * decap.c : L2TPv3 tunnel decapsulation + * + * Copyright (c) 2013 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 + +/* Statistics (not really errors) */ +#define foreach_l2t_decap_error \ +_(USER_TO_NETWORK, "L2TP user (ip6) to L2 network pkts") \ +_(SESSION_ID_MISMATCH, "l2tpv3 local session id mismatches") \ +_(COOKIE_MISMATCH, "l2tpv3 local cookie mismatches") \ +_(NO_SESSION, "l2tpv3 session not found") \ +_(ADMIN_DOWN, "l2tpv3 tunnel is down") + +static char *l2t_decap_error_strings[] = { +#define _(sym,string) string, + foreach_l2t_decap_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) L2T_DECAP_ERROR_##sym, + foreach_l2t_decap_error +#undef _ + L2T_DECAP_N_ERROR, +} l2t_DECAP_error_t; + +typedef enum +{ + L2T_DECAP_NEXT_DROP, + L2T_DECAP_NEXT_L2_INPUT, + L2T_DECAP_N_NEXT, + /* Pseudo next index */ + L2T_DECAP_NEXT_NO_INTERCEPT = L2T_DECAP_N_NEXT, +} l2t_decap_next_t; + +#define NSTAGES 3 + +static inline void +stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) +{ + vlib_prefetch_buffer_header (b, STORE); + /* l2tpv3 header is a long way away, need 2 cache lines */ + CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE); +} + +static inline void +stage1 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) +{ + l2t_main_t *lm = &l2t_main; + ip6_header_t *ip6 = vlib_buffer_get_current (b); + u32 session_index; + uword *p = 0; + l2tpv3_header_t *l2t; + + /* Not L2tpv3 (0x73, 0t115)? Use the normal path. */ + if (PREDICT_FALSE (ip6->protocol != IP_PROTOCOL_L2TP)) + { + vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_NO_INTERCEPT; + return; + } + + /* Make up your minds, people... */ + switch (lm->lookup_type) + { + case L2T_LOOKUP_SRC_ADDRESS: + p = hash_get_mem (lm->session_by_src_address, &ip6->src_address); + break; + case L2T_LOOKUP_DST_ADDRESS: + p = hash_get_mem (lm->session_by_dst_address, &ip6->dst_address); + break; + case L2T_LOOKUP_SESSION_ID: + l2t = (l2tpv3_header_t *) (ip6 + 1); + p = hash_get (lm->session_by_session_id, l2t->session_id); + break; + default: + ASSERT (0); + } + + if (PREDICT_FALSE (p == 0)) + { + vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_NO_INTERCEPT; + return; + } + else + { + session_index = p[0]; + } + + /* Remember mapping index, prefetch the mini counter */ + vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_L2_INPUT; + vnet_buffer (b)->l2t.session_index = session_index; + + /* $$$$$ prefetch counter */ +} + +static inline u32 +last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) +{ + l2t_main_t *lm = &l2t_main; + ip6_header_t *ip6 = vlib_buffer_get_current (b); + vlib_node_t *n = vlib_get_node (vm, node->node_index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + l2tpv3_header_t *l2tp; + u32 counter_index; + l2t_session_t *session = 0; + u32 session_index; + u32 next_index; + u8 l2tp_decap_local = (l2t_decap_local_node.index == n->index); + + /* Other-than-output pkt? We're done... */ + if (vnet_buffer (b)->l2t.next_index != L2T_DECAP_NEXT_L2_INPUT) + { + next_index = vnet_buffer (b)->l2t.next_index; + goto done; + } + + em->counters[node_counter_base_index + L2T_DECAP_ERROR_USER_TO_NETWORK] += + 1; + + session_index = vnet_buffer (b)->l2t.session_index; + + counter_index = + session_index_to_counter_index (session_index, + SESSION_COUNTER_USER_TO_NETWORK); + + /* per-mapping byte stats include the ethernet header */ + vlib_increment_combined_counter (&lm->counter_main, + vlib_get_thread_index (), + counter_index, 1 /* packet_increment */ , + vlib_buffer_length_in_chain (vm, b) + + sizeof (ethernet_header_t)); + + session = pool_elt_at_index (lm->sessions, session_index); + + l2tp = vlib_buffer_get_current (b) + sizeof (*ip6); + + if (PREDICT_FALSE (l2tp->session_id != session->local_session_id)) + { + /* Key matched but session id does not. Assume packet is not for us. */ + em->counters[node_counter_base_index + + L2T_DECAP_ERROR_SESSION_ID_MISMATCH] += 1; + next_index = L2T_DECAP_NEXT_NO_INTERCEPT; + goto done; + } + + if (PREDICT_FALSE (l2tp->cookie != session->local_cookie[0])) + { + if (l2tp->cookie != session->local_cookie[1]) + { + /* Key and session ID matched, but cookie doesn't. Drop this packet. */ + b->error = node->errors[L2T_DECAP_ERROR_COOKIE_MISMATCH]; + next_index = L2T_DECAP_NEXT_DROP; + goto done; + } + } + + vnet_buffer (b)->sw_if_index[VLIB_RX] = session->sw_if_index; + + if (PREDICT_FALSE (!(session->admin_up))) + { + b->error = node->errors[L2T_DECAP_ERROR_ADMIN_DOWN]; + next_index = L2T_DECAP_NEXT_DROP; + goto done; + } + + /* strip the ip6 and L2TP header */ + vlib_buffer_advance (b, sizeof (*ip6) + session->l2tp_hdr_size); + + /* Required to make the l2 tag push / pop code work on l2 subifs */ + vnet_update_l2_len (b); + + if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) + { + l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); + t->is_user_to_network = 1; + t->our_address.as_u64[0] = ip6->dst_address.as_u64[0]; + t->our_address.as_u64[1] = ip6->dst_address.as_u64[1]; + t->client_address.as_u64[0] = ip6->src_address.as_u64[0]; + t->client_address.as_u64[1] = ip6->src_address.as_u64[1]; + t->session_index = session_index; + } + + return L2T_DECAP_NEXT_L2_INPUT; + +done: + if (next_index == L2T_DECAP_NEXT_NO_INTERCEPT) + { + /* Small behavioral change between l2tp-decap and l2tp-decap-local */ + if (l2tp_decap_local) + { + b->error = node->errors[L2T_DECAP_ERROR_NO_SESSION]; + next_index = L2T_DECAP_NEXT_DROP; + } + else + { + /* Go to next node on the ip6 configuration chain */ + if (PREDICT_TRUE (session != 0)) + vnet_feature_next (&next_index, b); + } + } + + if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) + { + l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); + t->is_user_to_network = 1; + t->our_address.as_u64[0] = ip6->dst_address.as_u64[0]; + t->our_address.as_u64[1] = ip6->dst_address.as_u64[1]; + t->client_address.as_u64[0] = ip6->src_address.as_u64[0]; + t->client_address.as_u64[1] = ip6->src_address.as_u64[1]; + t->session_index = ~0; + } + return next_index; +} + +#include + +VLIB_NODE_FN (l2t_decap_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return dispatch_pipeline (vm, node, frame); +} + +/* + * l2tp-decap and l2tp-decap-local have very slightly different behavior. + * When a packet has no associated session l2tp-decap let it go to ip6 forward, + * while l2tp-decap-local drops it. + */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2t_decap_node) = { + .name = "l2tp-decap", + .vector_size = sizeof (u32), + .format_trace = format_l2t_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2t_decap_error_strings), + .error_strings = l2t_decap_error_strings, + + .n_next_nodes = L2T_DECAP_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2T_DECAP_NEXT_L2_INPUT] = "l2-input", + [L2T_DECAP_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +extern vlib_node_function_t l2t_decap_node_fn; + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2t_decap_local_node) = { + .function = l2t_decap_node_fn, + .name = "l2tp-decap-local", + .vector_size = sizeof (u32), + .format_trace = format_l2t_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2t_decap_error_strings), + .error_strings = l2t_decap_error_strings, + + .n_next_nodes = L2T_DECAP_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2T_DECAP_NEXT_L2_INPUT] = "l2-input", + [L2T_DECAP_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/encap.c b/src/plugins/l2tp/encap.c new file mode 100644 index 00000000000..fbb5fc6ea46 --- /dev/null +++ b/src/plugins/l2tp/encap.c @@ -0,0 +1,235 @@ +/* + * encap.c : L2TPv3 tunnel encapsulation + * + * Copyright (c) 2013 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 + +/* Statistics (not really errors) */ +#define foreach_l2t_encap_error \ +_(NETWORK_TO_USER, "L2TP L2 network to user (ip6) pkts") \ +_(LOOKUP_FAIL_TO_L3, "L2TP L2 session lookup failed pkts") \ +_(ADMIN_DOWN, "L2TP tunnel is down") + +static char *l2t_encap_error_strings[] = { +#define _(sym,string) string, + foreach_l2t_encap_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) L2T_ENCAP_ERROR_##sym, + foreach_l2t_encap_error +#undef _ + L2T_ENCAP_N_ERROR, +} l2t_encap_error_t; + + +typedef enum +{ + L2T_ENCAP_NEXT_DROP, + L2T_ENCAP_NEXT_IP6_LOOKUP, + L2T_ENCAP_N_NEXT, +} l2t_encap_next_t; + +typedef struct +{ + u32 cached_session_index; + u32 cached_sw_if_index; + vnet_main_t *vnet_main; +} l2tp_encap_runtime_t; + +extern vlib_node_registration_t l2t_encap_node; + +#define NSTAGES 3 + +static inline void +stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) +{ + vlib_prefetch_buffer_header (b, STORE); + CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE); +} + +static inline void +stage1 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) +{ + l2tp_encap_runtime_t *rt = (void *) node->runtime_data; + vnet_hw_interface_t *hi; + + u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX]; + u32 session_index = rt->cached_session_index; + + if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index)) + { + hi = vnet_get_sup_hw_interface (rt->vnet_main, sw_if_index); + session_index = rt->cached_session_index = hi->dev_instance; + rt->cached_sw_if_index = sw_if_index; + } + + /* Remember mapping index, prefetch the mini counter */ + vnet_buffer (b)->l2t.next_index = L2T_ENCAP_NEXT_IP6_LOOKUP; + vnet_buffer (b)->l2t.session_index = session_index; + + /* $$$$ prefetch counter... */ +} + +static inline u32 +last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) +{ + l2t_main_t *lm = &l2t_main; + vlib_node_t *n = vlib_get_node (vm, l2t_encap_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + l2tpv3_header_t *l2tp; + u32 session_index; + u32 counter_index; + l2t_session_t *s; + ip6_header_t *ip6; + u16 payload_length; + u32 next_index = L2T_ENCAP_NEXT_IP6_LOOKUP; + + /* Other-than-output pkt? We're done... */ + if (vnet_buffer (b)->l2t.next_index != L2T_ENCAP_NEXT_IP6_LOOKUP) + return vnet_buffer (b)->l2t.next_index; + + em->counters[node_counter_base_index + L2T_ENCAP_ERROR_NETWORK_TO_USER] += + 1; + + session_index = vnet_buffer (b)->l2t.session_index; + + counter_index = + session_index_to_counter_index (session_index, + SESSION_COUNTER_NETWORK_TO_USER); + + /* per-mapping byte stats include the ethernet header */ + vlib_increment_combined_counter (&lm->counter_main, + vlib_get_thread_index (), + counter_index, 1 /* packet_increment */ , + vlib_buffer_length_in_chain (vm, b)); + + s = pool_elt_at_index (lm->sessions, session_index); + + vnet_buffer (b)->sw_if_index[VLIB_TX] = s->encap_fib_index; + + /* Paint on an l2tpv3 hdr */ + vlib_buffer_advance (b, -(s->l2tp_hdr_size)); + l2tp = vlib_buffer_get_current (b); + + l2tp->session_id = s->remote_session_id; + l2tp->cookie = s->remote_cookie; + if (PREDICT_FALSE (s->l2_sublayer_present)) + { + l2tp->l2_specific_sublayer = 0; + } + + /* Paint on an ip6 header */ + vlib_buffer_advance (b, -(sizeof (*ip6))); + ip6 = vlib_buffer_get_current (b); + + if (PREDICT_FALSE (!(s->admin_up))) + { + b->error = node->errors[L2T_ENCAP_ERROR_ADMIN_DOWN]; + next_index = L2T_ENCAP_NEXT_DROP; + goto done; + } + + ip6->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (0x6 << 28); + + /* calculate ip6 payload length */ + payload_length = vlib_buffer_length_in_chain (vm, b); + payload_length -= sizeof (*ip6); + + ip6->payload_length = clib_host_to_net_u16 (payload_length); + ip6->protocol = IP_PROTOCOL_L2TP; + ip6->hop_limit = 0xff; + ip6->src_address.as_u64[0] = s->our_address.as_u64[0]; + ip6->src_address.as_u64[1] = s->our_address.as_u64[1]; + ip6->dst_address.as_u64[0] = s->client_address.as_u64[0]; + ip6->dst_address.as_u64[1] = s->client_address.as_u64[1]; + + +done: + if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) + { + l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); + t->is_user_to_network = 0; + t->our_address.as_u64[0] = ip6->src_address.as_u64[0]; + t->our_address.as_u64[1] = ip6->src_address.as_u64[1]; + t->client_address.as_u64[0] = ip6->dst_address.as_u64[0]; + t->client_address.as_u64[1] = ip6->dst_address.as_u64[1]; + t->session_index = session_index; + } + + return next_index; +} + +#include + +VLIB_NODE_FN (l2t_encap_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return dispatch_pipeline (vm, node, frame); +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2t_encap_node) = { + .name = "l2tp-encap", + .vector_size = sizeof (u32), + .format_trace = format_l2t_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .runtime_data_bytes = sizeof (l2tp_encap_runtime_t), + + .n_errors = ARRAY_LEN(l2t_encap_error_strings), + .error_strings = l2t_encap_error_strings, + + .n_next_nodes = L2T_ENCAP_N_NEXT, + + /* add dispositions here */ + .next_nodes = { + [L2T_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup", + [L2T_ENCAP_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +#ifndef CLIB_MARCH_VARIANT +void +l2tp_encap_init (vlib_main_t * vm) +{ + l2tp_encap_runtime_t *rt; + + rt = vlib_node_get_runtime_data (vm, l2t_encap_node.index); + rt->vnet_main = vnet_get_main (); + rt->cached_sw_if_index = (u32) ~ 0; + rt->cached_session_index = (u32) ~ 0; +} +#endif /* CLIB_MARCH_VARIANT */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/l2tp.api b/src/plugins/l2tp/l2tp.api new file mode 100644 index 00000000000..618c4122fd6 --- /dev/null +++ b/src/plugins/l2tp/l2tp.api @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +option version = "2.0.0"; + +import "vnet/interface_types.api"; +import "vnet/ethernet/ethernet_types.api"; +import "vnet/ip/ip_types.api"; + +/** \brief l2tpv3 tunnel interface create request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param client_address - remote client tunnel ip address + @param client_address - local tunnel ip address + @param is_ipv6 - ipv6 if non-zero, else ipv4 + @param local_session_id - local tunnel session id + @param remote_session_id - remote tunnel session id + @param local_cookie - local tunnel cookie + @param l2_sublayer_present - l2 sublayer is present in packets if non-zero + @param encap_vrf_id - fib identifier used for outgoing encapsulated packets +*/ +define l2tpv3_create_tunnel +{ + u32 client_index; + u32 context; + vl_api_address_t client_address; + vl_api_address_t our_address; + u32 local_session_id; + u32 remote_session_id; + u64 local_cookie; + u64 remote_cookie; + bool l2_sublayer_present; + u32 encap_vrf_id; +}; + +/** \brief l2tpv3 tunnel interface create response + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param sw_if_index - index of the new tunnel interface +*/ +define l2tpv3_create_tunnel_reply +{ + u32 context; + i32 retval; + vl_api_interface_index_t sw_if_index; +}; + +autoreply define l2tpv3_set_tunnel_cookies +{ + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; + u64 new_local_cookie; + u64 new_remote_cookie; +}; + +define sw_if_l2tpv3_tunnel_details +{ + u32 context; + vl_api_interface_index_t sw_if_index; + string interface_name[64]; + vl_api_address_t client_address; + vl_api_address_t our_address; + u32 local_session_id; + u32 remote_session_id; + u64 local_cookie[2]; + u64 remote_cookie; + bool l2_sublayer_present; +}; + +define sw_if_l2tpv3_tunnel_dump +{ + u32 client_index; + u32 context; +}; + +autoreply define l2tpv3_interface_enable_disable +{ + u32 client_index; + u32 context; + bool enable_disable; + vl_api_interface_index_t sw_if_index; +}; + +enum l2t_lookup_key : u8 +{ + L2T_LOOKUP_KEY_API_SRC_ADDR = 0, + L2T_LOOKUP_KEY_API_DST_ADDR = 1, + L2T_LOOKUP_KEY_API_SESSION_ID = 2, +}; + +autoreply define l2tpv3_set_lookup_key +{ + u32 client_index; + u32 context; + vl_api_l2t_lookup_key_t key; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/l2tp.c b/src/plugins/l2tp/l2tp.c new file mode 100644 index 00000000000..242f4323e37 --- /dev/null +++ b/src/plugins/l2tp/l2tp.c @@ -0,0 +1,764 @@ +/* + * l2tp.c : L2TPv3 tunnel support + * + * Copyright (c) 2013 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 + +l2t_main_t l2t_main; + +/* packet trace format function */ +u8 * +format_l2t_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 *); + l2t_trace_t *t = va_arg (*args, l2t_trace_t *); + + if (t->is_user_to_network) + s = format (s, "L2T: %U (client) -> %U (our) session %d", + format_ip6_address, &t->client_address, + format_ip6_address, &t->our_address, t->session_index); + else + s = format (s, "L2T: %U (our) -> %U (client) session %d)", + format_ip6_address, &t->our_address, + format_ip6_address, &t->client_address, t->session_index); + return s; +} + +u8 * +format_l2t_session (u8 * s, va_list * args) +{ + l2t_session_t *session = va_arg (*args, l2t_session_t *); + l2t_main_t *lm = &l2t_main; + u32 counter_index; + vlib_counter_t v; + + s = format (s, "[%d] %U (our) %U (client) %U (sw_if_index %d)\n", + session - lm->sessions, + format_ip6_address, &session->our_address, + format_ip6_address, &session->client_address, + format_vnet_sw_interface_name, lm->vnet_main, + vnet_get_sw_interface (lm->vnet_main, session->sw_if_index), + session->sw_if_index); + + s = format (s, " local cookies %016llx %016llx remote cookie %016llx\n", + clib_net_to_host_u64 (session->local_cookie[0]), + clib_net_to_host_u64 (session->local_cookie[1]), + clib_net_to_host_u64 (session->remote_cookie)); + + s = format (s, " local session-id %d remote session-id %d\n", + clib_net_to_host_u32 (session->local_session_id), + clib_net_to_host_u32 (session->remote_session_id)); + + s = format (s, " l2 specific sublayer %s\n", + session->l2_sublayer_present ? "preset" : "absent"); + + counter_index = + session_index_to_counter_index (session - lm->sessions, + SESSION_COUNTER_USER_TO_NETWORK); + + vlib_get_combined_counter (&lm->counter_main, counter_index, &v); + if (v.packets != 0) + s = format (s, " user-to-net: %llu pkts %llu bytes\n", + v.packets, v.bytes); + + vlib_get_combined_counter (&lm->counter_main, counter_index + 1, &v); + + if (v.packets != 0) + s = format (s, " net-to-user: %llu pkts %llu bytes\n", + v.packets, v.bytes); + return s; +} + +static clib_error_t * +show_l2tp_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2t_session_t *session; + l2t_main_t *lm = &l2t_main; + char *keystr = 0; + int verbose = 0; + + if (unformat (input, "verbose") || unformat (input, "v")) + verbose = 1; + + if (pool_elts (lm->sessions) == 0) + vlib_cli_output (vm, "No l2tp sessions..."); + else + vlib_cli_output (vm, "%u l2tp sessions...", pool_elts (lm->sessions)); + + if (verbose) + { + switch (lm->lookup_type) + { + case L2T_LOOKUP_SRC_ADDRESS: + keystr = "src address"; + break; + + case L2T_LOOKUP_DST_ADDRESS: + keystr = "dst address"; + break; + + case L2T_LOOKUP_SESSION_ID: + keystr = "session id"; + break; + + default: + keystr = "BOGUS!"; + break; + } + + vlib_cli_output (vm, "L2tp session lookup on %s", keystr); + + /* *INDENT-OFF* */ + pool_foreach (session, lm->sessions, + ({ + vlib_cli_output (vm, "%U", format_l2t_session, session); + })); + /* *INDENT-ON* */ + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_session_detail_command, static) = { + .path = "show l2tpv3", + .short_help = "show l2tpv3 [verbose]", + .function = show_l2tp_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +test_counters_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2t_session_t *session; + l2t_main_t *lm = &l2t_main; + u32 session_index; + u32 counter_index; + u32 nincr = 0; + u32 thread_index = vm->thread_index; + + /* *INDENT-OFF* */ + pool_foreach (session, lm->sessions, + ({ + session_index = session - lm->sessions; + counter_index = + session_index_to_counter_index (session_index, + SESSION_COUNTER_USER_TO_NETWORK); + vlib_increment_combined_counter (&lm->counter_main, + thread_index, + counter_index, + 1/*pkt*/, 1111 /*bytes*/); + vlib_increment_combined_counter (&lm->counter_main, + thread_index, + counter_index+1, + 1/*pkt*/, 2222 /*bytes*/); + nincr++; + + })); + /* *INDENT-ON* */ + vlib_cli_output (vm, "Incremented %d active counters\n", nincr); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (test_counters_command, static) = { + .path = "test lt2p counters", + .short_help = "increment all active counters", + .function = test_counters_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +clear_counters_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2t_session_t *session; + l2t_main_t *lm = &l2t_main; + u32 session_index; + u32 counter_index; + u32 nincr = 0; + + /* *INDENT-OFF* */ + pool_foreach (session, lm->sessions, + ({ + session_index = session - lm->sessions; + counter_index = + session_index_to_counter_index (session_index, + SESSION_COUNTER_USER_TO_NETWORK); + vlib_zero_combined_counter (&lm->counter_main, counter_index); + vlib_zero_combined_counter (&lm->counter_main, counter_index+1); + nincr++; + })); + /* *INDENT-ON* */ + vlib_cli_output (vm, "Cleared %d active counters\n", nincr); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_counters_command, static) = { + .path = "clear l2tp counters", + .short_help = "clear all active counters", + .function = clear_counters_command_fn, +}; +/* *INDENT-ON* */ + +static u8 * +format_l2tpv3_name (u8 * s, va_list * args) +{ + l2t_main_t *lm = &l2t_main; + u32 i = va_arg (*args, u32); + u32 show_dev_instance = ~0; + + if (i < vec_len (lm->dev_inst_by_real)) + show_dev_instance = lm->dev_inst_by_real[i]; + + if (show_dev_instance != ~0) + i = show_dev_instance; + + return format (s, "l2tpv3_tunnel%d", i); +} + +static int +l2tpv3_name_renumber (vnet_hw_interface_t * hi, u32 new_dev_instance) +{ + l2t_main_t *lm = &l2t_main; + + vec_validate_init_empty (lm->dev_inst_by_real, hi->dev_instance, ~0); + + lm->dev_inst_by_real[hi->dev_instance] = new_dev_instance; + + return 0; +} + +/* *INDENT-OFF* */ +VNET_DEVICE_CLASS (l2tpv3_device_class,static) = { + .name = "L2TPv3", + .format_device_name = format_l2tpv3_name, + .name_renumber = l2tpv3_name_renumber, +}; +/* *INDENT-ON* */ + +static u8 * +format_l2tp_header_with_length (u8 * s, va_list * args) +{ + u32 dev_instance = va_arg (*args, u32); + s = format (s, "unimplemented dev %u", dev_instance); + return s; +} + +/* *INDENT-OFF* */ +VNET_HW_INTERFACE_CLASS (l2tpv3_hw_class) = { + .name = "L2TPV3", + .format_header = format_l2tp_header_with_length, + .build_rewrite = default_build_rewrite, + .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, +}; +/* *INDENT-ON* */ + +int +create_l2tpv3_ipv6_tunnel (l2t_main_t * lm, + ip6_address_t * client_address, + ip6_address_t * our_address, + u32 local_session_id, + u32 remote_session_id, + u64 local_cookie, + u64 remote_cookie, + int l2_sublayer_present, + u32 encap_fib_index, u32 * sw_if_index) +{ + l2t_session_t *s = 0; + vnet_main_t *vnm = lm->vnet_main; + vnet_hw_interface_t *hi; + uword *p = (uword *) ~ 0; + u32 hw_if_index; + l2tpv3_header_t l2tp_hdr; + ip6_address_t *dst_address_copy, *src_address_copy; + u32 counter_index; + + remote_session_id = clib_host_to_net_u32 (remote_session_id); + local_session_id = clib_host_to_net_u32 (local_session_id); + + switch (lm->lookup_type) + { + case L2T_LOOKUP_SRC_ADDRESS: + p = hash_get_mem (lm->session_by_src_address, client_address); + break; + + case L2T_LOOKUP_DST_ADDRESS: + p = hash_get_mem (lm->session_by_dst_address, our_address); + break; + + case L2T_LOOKUP_SESSION_ID: + p = hash_get (lm->session_by_session_id, local_session_id); + break; + + default: + ASSERT (0); + } + + /* adding a session: session must not already exist */ + if (p) + return VNET_API_ERROR_INVALID_VALUE; + + pool_get (lm->sessions, s); + clib_memset (s, 0, sizeof (*s)); + clib_memcpy (&s->our_address, our_address, sizeof (s->our_address)); + clib_memcpy (&s->client_address, client_address, + sizeof (s->client_address)); + s->local_cookie[0] = clib_host_to_net_u64 (local_cookie); + s->remote_cookie = clib_host_to_net_u64 (remote_cookie); + s->local_session_id = local_session_id; + s->remote_session_id = remote_session_id; + s->l2_sublayer_present = l2_sublayer_present; + /* precompute l2tp header size */ + s->l2tp_hdr_size = l2_sublayer_present ? + sizeof (l2tpv3_header_t) : + sizeof (l2tpv3_header_t) - sizeof (l2tp_hdr.l2_specific_sublayer); + s->admin_up = 0; + s->encap_fib_index = encap_fib_index; + + /* Setup hash table entries */ + switch (lm->lookup_type) + { + case L2T_LOOKUP_SRC_ADDRESS: + src_address_copy = clib_mem_alloc (sizeof (*src_address_copy)); + clib_memcpy (src_address_copy, client_address, + sizeof (*src_address_copy)); + hash_set_mem (lm->session_by_src_address, src_address_copy, + s - lm->sessions); + break; + case L2T_LOOKUP_DST_ADDRESS: + dst_address_copy = clib_mem_alloc (sizeof (*dst_address_copy)); + clib_memcpy (dst_address_copy, our_address, sizeof (*dst_address_copy)); + hash_set_mem (lm->session_by_dst_address, dst_address_copy, + s - lm->sessions); + break; + case L2T_LOOKUP_SESSION_ID: + hash_set (lm->session_by_session_id, local_session_id, + s - lm->sessions); + break; + + default: + ASSERT (0); + } + + /* validate counters */ + counter_index = + session_index_to_counter_index (s - lm->sessions, + SESSION_COUNTER_USER_TO_NETWORK); + vlib_validate_combined_counter (&lm->counter_main, counter_index); + vlib_validate_combined_counter (&lm->counter_main, counter_index + 1); + + if (vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) > 0) + { + hw_if_index = lm->free_l2tpv3_tunnel_hw_if_indices + [vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) - 1]; + _vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) -= 1; + + hi = vnet_get_hw_interface (vnm, hw_if_index); + hi->dev_instance = s - lm->sessions; + hi->hw_instance = hi->dev_instance; + } + else + { + hw_if_index = vnet_register_interface + (vnm, l2tpv3_device_class.index, s - lm->sessions, + l2tpv3_hw_class.index, s - lm->sessions); + hi = vnet_get_hw_interface (vnm, hw_if_index); + hi->output_node_index = l2t_encap_node.index; + /* $$$$ initialize custom dispositions, if needed */ + } + + s->hw_if_index = hw_if_index; + s->sw_if_index = hi->sw_if_index; + + if (sw_if_index) + *sw_if_index = hi->sw_if_index; + + if (!lm->proto_registered) + { + ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_local_node.index); + lm->proto_registered = true; + } + + return 0; +} + +static clib_error_t * +create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip6_address_t client_address, our_address; + unformat_input_t _line_input, *line_input = &_line_input; + l2t_main_t *lm = &l2t_main; + u64 local_cookie = (u64) ~ 0, remote_cookie = (u64) ~ 0; + u32 local_session_id = 1, remote_session_id = 1; + int our_address_set = 0, client_address_set = 0; + int l2_sublayer_present = 0; + int rv; + u32 sw_if_index; + u32 encap_fib_id = ~0; + u32 encap_fib_index = ~0; + clib_error_t *error = NULL; + + /* 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, "client %U", + unformat_ip6_address, &client_address)) + client_address_set = 1; + else if (unformat (line_input, "our %U", + unformat_ip6_address, &our_address)) + our_address_set = 1; + else if (unformat (line_input, "local-cookie %llx", &local_cookie)) + ; + else if (unformat (line_input, "remote-cookie %llx", &remote_cookie)) + ; + else if (unformat (line_input, "local-session-id %d", + &local_session_id)) + ; + else if (unformat (line_input, "remote-session-id %d", + &remote_session_id)) + ; + else if (unformat (line_input, "fib-id %d", &encap_fib_id)) + ; + else if (unformat (line_input, "l2-sublayer-present")) + l2_sublayer_present = 1; + else + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } + } + + if (encap_fib_id != ~0) + { + uword *p; + ip6_main_t *im = &ip6_main; + if (!(p = hash_get (im->fib_index_by_table_id, encap_fib_id))) + { + error = clib_error_return (0, "No fib with id %d", encap_fib_id); + goto done; + } + encap_fib_index = p[0]; + } + else + { + encap_fib_index = ~0; + } + + if (our_address_set == 0) + { + error = clib_error_return (0, "our address not specified"); + goto done; + } + if (client_address_set == 0) + { + error = clib_error_return (0, "client address not specified"); + goto done; + } + + rv = create_l2tpv3_ipv6_tunnel (lm, &client_address, &our_address, + local_session_id, remote_session_id, + local_cookie, remote_cookie, + l2_sublayer_present, + encap_fib_index, &sw_if_index); + switch (rv) + { + case 0: + vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, + vnet_get_main (), sw_if_index); + break; + case VNET_API_ERROR_INVALID_VALUE: + error = clib_error_return (0, "session already exists..."); + goto done; + + case VNET_API_ERROR_NO_SUCH_ENTRY: + error = clib_error_return (0, "session does not exist..."); + goto done; + + default: + error = clib_error_return (0, "l2tp_session_add_del returned %d", rv); + goto done; + } + +done: + unformat_free (line_input); + + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (create_l2tpv3_tunnel_command, static) = +{ + .path = "create l2tpv3 tunnel", + .short_help = + "create l2tpv3 tunnel client our local-cookie remote-cookie local-session remote-session ", + .function = create_l2tpv3_tunnel_command_fn, +}; +/* *INDENT-ON* */ + +int +l2tpv3_set_tunnel_cookies (l2t_main_t * lm, + u32 sw_if_index, + u64 new_local_cookie, u64 new_remote_cookie) +{ + l2t_session_t *s; + vnet_hw_interface_t *hi; + vnet_main_t *vnm = vnet_get_main (); + hi = vnet_get_sup_hw_interface (vnm, sw_if_index); + + if (pool_is_free_index (lm->sessions, hi->dev_instance)) + return VNET_API_ERROR_INVALID_VALUE; + + s = pool_elt_at_index (lm->sessions, hi->dev_instance); + + s->local_cookie[1] = s->local_cookie[0]; + s->local_cookie[0] = clib_host_to_net_u64 (new_local_cookie); + s->remote_cookie = clib_host_to_net_u64 (new_remote_cookie); + + return 0; +} + + +static clib_error_t * +set_l2tp_tunnel_cookie_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + l2t_main_t *lm = &l2t_main; + vnet_main_t *vnm = vnet_get_main (); + u32 sw_if_index = ~0; + u64 local_cookie = (u64) ~ 0, remote_cookie = (u64) ~ 0; + + int rv; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, + &sw_if_index)) + ; + else if (unformat (input, "local %llx", &local_cookie)) + ; + else if (unformat (input, "remote %llx", &remote_cookie)) + ; + else + break; + } + if (sw_if_index == ~0) + return clib_error_return (0, "unknown interface"); + if (local_cookie == ~0) + return clib_error_return (0, "local cookie required"); + if (remote_cookie == ~0) + return clib_error_return (0, "remote cookie required"); + + rv = l2tpv3_set_tunnel_cookies (lm, sw_if_index, + local_cookie, remote_cookie); + + switch (rv) + { + case 0: + break; + + case VNET_API_ERROR_INVALID_SW_IF_INDEX: + return clib_error_return (0, "invalid interface"); + + default: + return clib_error_return (0, "l2tp_session_set_cookies returned %d", + rv); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_l2tp_tunnel_cookie_command, static) = +{ + .path = "set l2tpv3 tunnel cookie", + .short_help = + "set l2tpv3 tunnel cookie local remote ", + .function = set_l2tp_tunnel_cookie_command_fn, +}; +/* *INDENT-ON* */ + +int +l2tpv3_interface_enable_disable (vnet_main_t * vnm, + u32 sw_if_index, int enable_disable) +{ + + if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index)) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + vnet_feature_enable_disable ("ip6-unicast", "l2tp-decap", sw_if_index, + enable_disable, 0, 0); + return 0; +} + +/* Enable/disable L2TPv3 intercept on IP6 forwarding path */ +static clib_error_t * +set_ip6_l2tpv3 (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u32 sw_if_index = ~0; + int is_add = 1; + int rv; + vnet_main_t *vnm = vnet_get_main (); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, + &sw_if_index)) + ; + else if (unformat (input, "del")) + is_add = 0; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, "interface required"); + + rv = l2tpv3_interface_enable_disable (vnm, sw_if_index, is_add); + + switch (rv) + { + case 0: + break; + + case VNET_API_ERROR_INVALID_SW_IF_INDEX: + return clib_error_return (0, "invalid interface"); + + default: + return clib_error_return (0, + "l2tp_interface_enable_disable returned %d", + rv); + } + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_ip6_l2tpv3, static) = +{ + .path = "set interface ip6 l2tpv3", + .function = set_ip6_l2tpv3, + .short_help = "set interface ip6 l2tpv3 [del]", +}; +/* *INDENT-ON* */ + +static clib_error_t * +l2tp_config (vlib_main_t * vm, unformat_input_t * input) +{ + l2t_main_t *lm = &l2t_main; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "lookup-v6-src")) + lm->lookup_type = L2T_LOOKUP_SRC_ADDRESS; + else if (unformat (input, "lookup-v6-dst")) + lm->lookup_type = L2T_LOOKUP_DST_ADDRESS; + else if (unformat (input, "lookup-session-id")) + lm->lookup_type = L2T_LOOKUP_SESSION_ID; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + return 0; +} + +VLIB_CONFIG_FUNCTION (l2tp_config, "l2tp"); + + +clib_error_t * +l2tp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) +{ + l2t_main_t *lm = &l2t_main; + vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index); + if (hi->hw_class_index != l2tpv3_hw_class.index) + return 0; + + u32 session_index = hi->dev_instance; + l2t_session_t *s = pool_elt_at_index (lm->sessions, session_index); + s->admin_up = ! !(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP); + return 0; +} + +VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2tp_sw_interface_up_down); + +clib_error_t * +l2tp_init (vlib_main_t * vm) +{ + l2t_main_t *lm = &l2t_main; + ip_main_t *im = &ip_main; + ip_protocol_info_t *pi; + + lm->vnet_main = vnet_get_main (); + lm->vlib_main = vm; + lm->lookup_type = L2T_LOOKUP_DST_ADDRESS; + + lm->session_by_src_address = hash_create_mem + (0, sizeof (ip6_address_t) /* key bytes */ , + sizeof (u32) /* value bytes */ ); + lm->session_by_dst_address = hash_create_mem + (0, sizeof (ip6_address_t) /* key bytes */ , + sizeof (u32) /* value bytes */ ); + lm->session_by_session_id = hash_create (0, sizeof (uword)); + + pi = ip_get_protocol_info (im, IP_PROTOCOL_L2TP); + pi->unformat_pg_edit = unformat_pg_l2tp_header; + + lm->proto_registered = false; + + /* insure these nodes are included in build */ + l2tp_encap_init (vm); + + return 0; +} + +VLIB_INIT_FUNCTION (l2tp_init); + +clib_error_t * +l2tp_worker_init (vlib_main_t * vm) +{ + l2tp_encap_init (vm); + + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (l2tp_worker_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/l2tp.h b/src/plugins/l2tp/l2tp.h new file mode 100644 index 00000000000..949d5d369bd --- /dev/null +++ b/src/plugins/l2tp/l2tp.h @@ -0,0 +1,148 @@ +/* + * l2tp.h : L2TPv3 tunnel support + * + * Copyright (c) 2013 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_l2tp_h__ +#define __included_l2tp_h__ + +#include +#include +#include + +typedef struct +{ + /* ip6 addresses */ + ip6_address_t our_address; + ip6_address_t client_address; + + /* l2tpv3 header parameters */ + u64 local_cookie[2]; + u64 remote_cookie; + u32 local_session_id; + u32 remote_session_id; + + /* tunnel interface */ + u32 hw_if_index; + u32 sw_if_index; + + /* fib index used for outgoing encapsulated packets */ + u32 encap_fib_index; + + u8 l2tp_hdr_size; + u8 l2_sublayer_present; + u8 cookie_flags; /* in host byte order */ + + u8 admin_up; +} l2t_session_t; + +typedef enum +{ + L2T_LOOKUP_SRC_ADDRESS = 0, + L2T_LOOKUP_DST_ADDRESS, + L2T_LOOKUP_SESSION_ID, +} ip6_to_l2_lookup_t; + +typedef struct +{ + /* session pool */ + l2t_session_t *sessions; + + /* ip6 -> l2 hash tables. Make up your minds, people... */ + uword *session_by_src_address; + uword *session_by_dst_address; + uword *session_by_session_id; + + ip6_to_l2_lookup_t lookup_type; + + /* Counters */ + vlib_combined_counter_main_t counter_main; + + /* vector of free l2tpv3 tunnel interfaces */ + u32 *free_l2tpv3_tunnel_hw_if_indices; + + /* show device instance by real device instance */ + u32 *dev_inst_by_real; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; + + bool proto_registered; + +} l2t_main_t; + +/* Packet trace structure */ +typedef struct +{ + int is_user_to_network; + u32 session_index; + ip6_address_t our_address; + ip6_address_t client_address; +} l2t_trace_t; + +extern l2t_main_t l2t_main; +extern vlib_node_registration_t l2t_encap_node; +extern vlib_node_registration_t l2t_decap_node; +extern vlib_node_registration_t l2t_decap_local_node; + +enum +{ + SESSION_COUNTER_USER_TO_NETWORK = 0, + SESSION_COUNTER_NETWORK_TO_USER, +}; + +static inline u32 +session_index_to_counter_index (u32 session_index, u32 counter_id) +{ + return ((session_index << 1) + counter_id); +} + +u8 *format_l2t_trace (u8 * s, va_list * args); + +typedef struct +{ + /* Any per-interface config would go here */ +} ip6_l2tpv3_config_t; + +uword unformat_pg_l2tp_header (unformat_input_t * input, va_list * args); + +void l2tp_encap_init (vlib_main_t * vm); +int create_l2tpv3_ipv6_tunnel (l2t_main_t * lm, + ip6_address_t * client_address, + ip6_address_t * our_address, + u32 local_session_id, + u32 remote_session_id, + u64 local_cookie, + u64 remote_cookie, + int l2_sublayer_present, + u32 encap_fib_index, u32 * sw_if_index); + +int l2tpv3_set_tunnel_cookies (l2t_main_t * lm, + u32 sw_if_index, + u64 new_local_cookie, u64 new_remote_cookie); + +int l2tpv3_interface_enable_disable (vnet_main_t * vnm, + u32 sw_if_index, int enable_disable); + +#endif /* __included_l2tp_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/l2tp_api.c b/src/plugins/l2tp/l2tp_api.c new file mode 100644 index 00000000000..fb675ddff5e --- /dev/null +++ b/src/plugins/l2tp/l2tp_api.c @@ -0,0 +1,251 @@ +/* + *------------------------------------------------------------------ + * l2tp_api.c - l2tpv3 api + * + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include + +#include +#include +#include +#include + +/* define message IDs */ +#include +#include +#include + +/** + * Base message ID fot the plugin + */ +static u32 l2tp_base_msg_id; +#define REPLY_MSG_ID_BASE l2tp_base_msg_id + +#include + +static void +send_sw_if_l2tpv3_tunnel_details (vpe_api_main_t * am, + vl_api_registration_t * reg, + l2t_session_t * s, + l2t_main_t * lm, u32 context) +{ + vl_api_sw_if_l2tpv3_tunnel_details_t *mp; + u8 *if_name = NULL; + vnet_sw_interface_t *si = NULL; + + si = vnet_get_hw_sw_interface (lm->vnet_main, s->hw_if_index); + + if_name = format (if_name, "%U", + format_vnet_sw_interface_name, lm->vnet_main, si); + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = + ntohs (VL_API_SW_IF_L2TPV3_TUNNEL_DETAILS + REPLY_MSG_ID_BASE); + strncpy ((char *) mp->interface_name, (char *) if_name, + ARRAY_LEN (mp->interface_name) - 1); + mp->sw_if_index = ntohl (si->sw_if_index); + mp->local_session_id = s->local_session_id; + mp->remote_session_id = s->remote_session_id; + mp->local_cookie[0] = s->local_cookie[0]; + mp->local_cookie[1] = s->local_cookie[1]; + mp->remote_cookie = s->remote_cookie; + ip_address_encode ((ip46_address_t *) & s->client_address, IP46_TYPE_IP6, + &mp->client_address); + ip_address_encode ((ip46_address_t *) & s->our_address, IP46_TYPE_IP6, + &mp->our_address); + mp->l2_sublayer_present = s->l2_sublayer_present; + mp->context = context; + + vl_api_send_msg (reg, (u8 *) mp); +} + + +static void +vl_api_sw_if_l2tpv3_tunnel_dump_t_handler (vl_api_sw_if_l2tpv3_tunnel_dump_t * + mp) +{ + vpe_api_main_t *am = &vpe_api_main; + l2t_main_t *lm = &l2t_main; + vl_api_registration_t *reg; + l2t_session_t *session; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + /* *INDENT-OFF* */ + pool_foreach (session, lm->sessions, + ({ + send_sw_if_l2tpv3_tunnel_details (am, reg, session, lm, mp->context); + })); + /* *INDENT-ON* */ +} + +static void vl_api_l2tpv3_create_tunnel_t_handler + (vl_api_l2tpv3_create_tunnel_t * mp) +{ + vl_api_l2tpv3_create_tunnel_reply_t *rmp; + l2t_main_t *lm = &l2t_main; + u32 sw_if_index = (u32) ~ 0; + int rv; + ip46_address_t client, our; + + if (mp->our_address.af == ADDRESS_IP4) + { + rv = VNET_API_ERROR_UNIMPLEMENTED; + goto out; + } + + u32 encap_fib_index; + + if (mp->encap_vrf_id != ~0) + { + uword *p; + ip6_main_t *im = &ip6_main; + if (! + (p = + hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)))) + { + rv = VNET_API_ERROR_NO_SUCH_FIB; + goto out; + } + encap_fib_index = p[0]; + } + else + { + encap_fib_index = ~0; + } + + ip_address_decode (&mp->client_address, &client); + ip_address_decode (&mp->our_address, &our); + + rv = create_l2tpv3_ipv6_tunnel (lm, + &client.ip6, + &our.ip6, + ntohl (mp->local_session_id), + ntohl (mp->remote_session_id), + clib_net_to_host_u64 (mp->local_cookie), + clib_net_to_host_u64 (mp->remote_cookie), + mp->l2_sublayer_present, + encap_fib_index, &sw_if_index); + +out: + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_L2TPV3_CREATE_TUNNEL_REPLY, + ({ + rmp->sw_if_index = ntohl (sw_if_index); + })); + /* *INDENT-ON* */ +} + +static void vl_api_l2tpv3_set_tunnel_cookies_t_handler + (vl_api_l2tpv3_set_tunnel_cookies_t * mp) +{ + vl_api_l2tpv3_set_tunnel_cookies_reply_t *rmp; + l2t_main_t *lm = &l2t_main; + int rv; + + VALIDATE_SW_IF_INDEX (mp); + + rv = l2tpv3_set_tunnel_cookies (lm, ntohl (mp->sw_if_index), + clib_net_to_host_u64 (mp->new_local_cookie), + clib_net_to_host_u64 + (mp->new_remote_cookie)); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_L2TPV3_SET_TUNNEL_COOKIES_REPLY); +} + +static void vl_api_l2tpv3_interface_enable_disable_t_handler + (vl_api_l2tpv3_interface_enable_disable_t * mp) +{ + int rv; + vnet_main_t *vnm = vnet_get_main (); + vl_api_l2tpv3_interface_enable_disable_reply_t *rmp; + + VALIDATE_SW_IF_INDEX (mp); + + rv = l2tpv3_interface_enable_disable + (vnm, ntohl (mp->sw_if_index), mp->enable_disable); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_L2TPV3_INTERFACE_ENABLE_DISABLE_REPLY); +} + +static void vl_api_l2tpv3_set_lookup_key_t_handler + (vl_api_l2tpv3_set_lookup_key_t * mp) +{ + int rv = 0; + l2t_main_t *lm = &l2t_main; + vl_api_l2tpv3_set_lookup_key_reply_t *rmp; + + if (mp->key > L2T_LOOKUP_KEY_API_SESSION_ID) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto out; + } + + lm->lookup_type = (ip6_to_l2_lookup_t) mp->key; + +out: + REPLY_MACRO (VL_API_L2TPV3_SET_LOOKUP_KEY_REPLY); +} + +/* + * l2tp_api_hookup + * Add vpe's API message handlers to the table. + * vlib has already mapped shared memory and + * added the client registration handlers. + * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() + */ +#include + +static clib_error_t * +l2tp_api_hookup (vlib_main_t * vm) +{ + /* + * Set up the (msg_name, crc, message-id) table + */ + l2tp_base_msg_id = setup_message_id_table (); + + return 0; +} + +VLIB_API_INIT_FUNCTION (l2tp_api_hookup); + +#include +#include + +/* *INDENT-OFF* */ +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "Layer 2 Tunneling Protocol v3 (L2TP)", +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/l2tp_test.c b/src/plugins/l2tp/l2tp_test.c new file mode 100644 index 00000000000..87abf5d0a2a --- /dev/null +++ b/src/plugins/l2tp/l2tp_test.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2020 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 +#include + +/* define message IDs */ +#include +#include +#include + +typedef struct +{ + /* API message ID base */ + u16 msg_id_base; + u32 ping_id; + vat_main_t *vat_main; +} l2tp_test_main_t; + +l2tp_test_main_t l2tp_test_main; + +#define __plugin_msg_base l2tp_test_main.msg_id_base +#include + +/* Macro to finish up custom dump fns */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define FINISH \ + vec_add1 (s, 0); \ + vl_print (handle, (char *)s); \ + vec_free (s); \ + return handle; + +static void vl_api_l2tpv3_create_tunnel_reply_t_handler + (vl_api_l2tpv3_create_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static int +api_l2tpv3_create_tunnel (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + ip6_address_t client_address, our_address; + int client_address_set = 0; + int our_address_set = 0; + u32 local_session_id = 0; + u32 remote_session_id = 0; + u64 local_cookie = 0; + u64 remote_cookie = 0; + u8 l2_sublayer_present = 0; + vl_api_l2tpv3_create_tunnel_t *mp; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "client_address %U", unformat_ip6_address, + &client_address)) + client_address_set = 1; + else if (unformat (i, "our_address %U", unformat_ip6_address, + &our_address)) + our_address_set = 1; + else if (unformat (i, "local_session_id %d", &local_session_id)) + ; + else if (unformat (i, "remote_session_id %d", &remote_session_id)) + ; + else if (unformat (i, "local_cookie %lld", &local_cookie)) + ; + else if (unformat (i, "remote_cookie %lld", &remote_cookie)) + ; + else if (unformat (i, "l2-sublayer-present")) + l2_sublayer_present = 1; + else + break; + } + + if (client_address_set == 0) + { + errmsg ("client_address required"); + return -99; + } + + if (our_address_set == 0) + { + errmsg ("our_address required"); + return -99; + } + + M (L2TPV3_CREATE_TUNNEL, mp); + + clib_memcpy (mp->client_address.un.ip6, client_address.as_u8, + sizeof (ip6_address_t)); + + clib_memcpy (mp->our_address.un.ip6, our_address.as_u8, + sizeof (ip6_address_t)); + + mp->local_session_id = ntohl (local_session_id); + mp->remote_session_id = ntohl (remote_session_id); + mp->local_cookie = clib_host_to_net_u64 (local_cookie); + mp->remote_cookie = clib_host_to_net_u64 (remote_cookie); + mp->l2_sublayer_present = l2_sublayer_present; + + S (mp); + W (ret); + return ret; +} + +static int +api_l2tpv3_set_tunnel_cookies (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u64 new_local_cookie = 0; + u64 new_remote_cookie = 0; + vl_api_l2tpv3_set_tunnel_cookies_t *mp; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "new_local_cookie %lld", &new_local_cookie)) + ; + else if (unformat (i, "new_remote_cookie %lld", &new_remote_cookie)) + ; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2TPV3_SET_TUNNEL_COOKIES, mp); + + mp->sw_if_index = ntohl (sw_if_index); + mp->new_local_cookie = clib_host_to_net_u64 (new_local_cookie); + mp->new_remote_cookie = clib_host_to_net_u64 (new_remote_cookie); + + S (mp); + W (ret); + return ret; +} + +static int +api_l2tpv3_interface_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2tpv3_interface_enable_disable_t *mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable_disable = 1; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + enable_disable = 1; + else if (unformat (i, "disable")) + enable_disable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2TPV3_INTERFACE_ENABLE_DISABLE, mp); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable_disable; + + S (mp); + W (ret); + return ret; +} + +static int +api_l2tpv3_set_lookup_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2tpv3_set_lookup_key_t *mp; + u8 key = ~0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "lookup_v6_src")) + key = L2T_LOOKUP_SRC_ADDRESS; + else if (unformat (i, "lookup_v6_dst")) + key = L2T_LOOKUP_DST_ADDRESS; + else if (unformat (i, "lookup_session_id")) + key = L2T_LOOKUP_SESSION_ID; + else + break; + } + + if (key == (u8) ~ 0) + { + errmsg ("l2tp session lookup key unset"); + return -99; + } + + M (L2TPV3_SET_LOOKUP_KEY, mp); + + mp->key = key; + + S (mp); + W (ret); + return ret; +} + +static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler + (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "* %U (our) %U (client) (sw_if_index %d)", + format_ip6_address, mp->our_address, + format_ip6_address, mp->client_address, + clib_net_to_host_u32 (mp->sw_if_index)); + + print (vam->ofp, + " local cookies %016llx %016llx remote cookie %016llx", + clib_net_to_host_u64 (mp->local_cookie[0]), + clib_net_to_host_u64 (mp->local_cookie[1]), + clib_net_to_host_u64 (mp->remote_cookie)); + + print (vam->ofp, " local session-id %d remote session-id %d", + clib_net_to_host_u32 (mp->local_session_id), + clib_net_to_host_u32 (mp->remote_session_id)); + + print (vam->ofp, " l2 specific sublayer %s\n", + mp->l2_sublayer_present ? "preset" : "absent"); + +} + +static int +api_sw_if_l2tpv3_tunnel_dump (vat_main_t * vam) +{ + vl_api_sw_if_l2tpv3_tunnel_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + + /* Get list of l2tpv3-tunnel interfaces */ + M (SW_IF_L2TPV3_TUNNEL_DUMP, mp); + S (mp); + + /* Use a control ping for synchronization */ + if (!l2tp_test_main.ping_id) + l2tp_test_main.ping_id = + vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); + mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping)); + mp_ping->_vl_msg_id = htons (l2tp_test_main.ping_id); + mp_ping->client_index = vam->my_client_index; + + fformat (vam->ofp, "Sending ping id=%d\n", l2tp_test_main.ping_id); + + vam->result_ready = 0; + S (mp_ping); + + W (ret); + return ret; +} + +#include + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/packet.h b/src/plugins/l2tp/packet.h new file mode 100644 index 00000000000..66dfea2194c --- /dev/null +++ b/src/plugins/l2tp/packet.h @@ -0,0 +1,44 @@ +/* + * packet.h : L2TPv3 packet header format + * + * Copyright (c) 2013 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_l2tp_packet_h__ +#define __included_l2tp_packet_h__ + +/* + * See RFC4719 for packet format. + * Note: the l2_specific_sublayer is present in current Linux l2tpv3 + * tunnels. It is not present in IOS XR l2tpv3 tunnels. + * The Linux implementation is almost certainly wrong. + */ +/* *INDENT-OFF* */ +typedef CLIB_PACKED (struct +{ + u32 session_id; + u64 cookie; u32 + l2_specific_sublayer; /* set to 0 (if present) */ +}) l2tpv3_header_t; +/* *INDENT-ON* */ + +#endif /* __included_l2tp_packet_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/pg.c b/src/plugins/l2tp/pg.c new file mode 100644 index 00000000000..f8edb6908aa --- /dev/null +++ b/src/plugins/l2tp/pg.c @@ -0,0 +1,106 @@ +/* + * pg.c: packet generator for L2TPv3 header + * + * Copyright (c) 2013 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 struct +{ + pg_edit_t session_id; + pg_edit_t cookie; +} pg_l2tp_header_t; + +typedef struct +{ + pg_edit_t l2_sublayer; +} pg_l2tp_header_l2_sublayer_t; + +static inline void +pg_l2tp_header_init (pg_l2tp_header_t * e) +{ + pg_edit_init (&e->session_id, l2tpv3_header_t, session_id); + pg_edit_init (&e->cookie, l2tpv3_header_t, cookie); +} + +uword +unformat_pg_l2tp_header (unformat_input_t * input, va_list * args) +{ + pg_stream_t *s = va_arg (*args, pg_stream_t *); + pg_l2tp_header_t *h; + u32 group_index, error; + vlib_main_t *vm = vlib_get_main (); + + h = pg_create_edit_group (s, sizeof (h[0]), + sizeof (l2tpv3_header_t) - sizeof (u32), + &group_index); + pg_l2tp_header_init (h); + + error = 1; + + /* session id and cookie are required */ + if (!unformat (input, "L2TP: session_id %U cookie %U", + unformat_pg_edit, unformat_pg_number, &h->session_id, + unformat_pg_edit, unformat_pg_number, &h->cookie)) + { + goto done; + } + + /* "l2_sublayer " is optional */ + if (unformat (input, "l2_sublayer")) + { + pg_l2tp_header_l2_sublayer_t *h2; + + h2 = pg_add_edits (s, sizeof (h2[0]), sizeof (u32), group_index); + pg_edit_init (&h2->l2_sublayer, l2tpv3_header_t, l2_specific_sublayer); + if (!unformat_user (input, unformat_pg_edit, + unformat_pg_number, &h2->l2_sublayer)) + { + goto done; + } + } + + /* Parse an ethernet header if it is present */ + { + pg_node_t *pg_node = 0; + vlib_node_t *eth_lookup_node; + + eth_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ethernet-input"); + ASSERT (eth_lookup_node); + + pg_node = pg_get_node (eth_lookup_node->index); + + if (pg_node && pg_node->unformat_edit + && unformat_user (input, pg_node->unformat_edit, s)) + ; + } + + error = 0; + +done: + if (error) + pg_free_edit_group (s); + return error == 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/l2tp/test/test_l2tp.py b/src/plugins/l2tp/test/test_l2tp.py new file mode 100644 index 00000000000..c57b5912de1 --- /dev/null +++ b/src/plugins/l2tp/test/test_l2tp.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import unittest + +from scapy.layers.l2 import Ether +from scapy.layers.inet6 import IPv6 + +from framework import VppTestCase + + +class TestL2tp(VppTestCase): + """ L2TP Test Case """ + + @classmethod + def setUpClass(cls): + super(TestL2tp, cls).setUpClass() + + cls.create_pg_interfaces(range(1)) + cls.pg0.admin_up() + cls.pg0.config_ip6() + + def test_l2tp_decap_local(self): + """ L2TP don't accept packets unless configured """ + + pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=115)) + + self.pg0.add_stream(pkt) + self.pg_start() + + # l2tp should not accept packets + err = self.statistics.get_counter( + '/err/l2tp-decap-local/l2tpv3 session not found')[0] + self.assertEqual(err, 0) + err_count = err + + self.vapi.l2tpv3_create_tunnel(client_address=self.pg0.local_ip6, + our_address=self.pg0.remote_ip6) + + self.pg0.add_stream(pkt) + self.pg_start() + + # l2tp accepts packets + err = self.statistics.get_counter( + '/err/l2tp-decap-local/l2tpv3 session not found')[0] + self.assertEqual(err, 1) + err_count = err diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 0d0ec59d1f8..926f65dcd86 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -2296,40 +2295,6 @@ static void vl_api_mpls_tunnel_add_del_reply_t_handler_json vam->result_ready = 1; } -static void vl_api_l2tpv3_create_tunnel_reply_t_handler - (vl_api_l2tpv3_create_tunnel_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - if (vam->async_mode) - { - vam->async_errors += (retval < 0); - } - else - { - vam->retval = retval; - vam->sw_if_index = ntohl (mp->sw_if_index); - vam->result_ready = 1; - } -} - -static void vl_api_l2tpv3_create_tunnel_reply_t_handler_json - (vl_api_l2tpv3_create_tunnel_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); - vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - static void vl_api_gpe_add_del_fwd_entry_reply_t_handler (vl_api_gpe_add_del_fwd_entry_reply_t * mp) { @@ -5121,9 +5086,6 @@ _(sr_steering_add_del_reply) \ _(classify_add_del_session_reply) \ _(classify_set_interface_ip_table_reply) \ _(classify_set_interface_l2_tables_reply) \ -_(l2tpv3_set_tunnel_cookies_reply) \ -_(l2tpv3_interface_enable_disable_reply) \ -_(l2tpv3_set_lookup_key_reply) \ _(l2_fib_clear_table_reply) \ _(l2_interface_efp_filter_reply) \ _(l2_interface_vlan_tag_rewrite_reply) \ @@ -5320,12 +5282,6 @@ _(CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY, \ classify_set_interface_l2_tables_reply) \ _(GET_NODE_INDEX_REPLY, get_node_index_reply) \ _(ADD_NODE_NEXT_REPLY, add_node_next_reply) \ -_(L2TPV3_CREATE_TUNNEL_REPLY, l2tpv3_create_tunnel_reply) \ -_(L2TPV3_SET_TUNNEL_COOKIES_REPLY, l2tpv3_set_tunnel_cookies_reply) \ -_(L2TPV3_INTERFACE_ENABLE_DISABLE_REPLY, \ - l2tpv3_interface_enable_disable_reply) \ -_(L2TPV3_SET_LOOKUP_KEY_REPLY, l2tpv3_set_lookup_key_reply) \ -_(SW_IF_L2TPV3_TUNNEL_DETAILS, sw_if_l2tpv3_tunnel_details) \ _(VXLAN_ADD_DEL_TUNNEL_REPLY, vxlan_add_del_tunnel_reply) \ _(VXLAN_OFFLOAD_RX_REPLY, vxlan_offload_rx_reply) \ _(VXLAN_TUNNEL_DETAILS, vxlan_tunnel_details) \ @@ -11146,274 +11102,6 @@ api_add_node_next (vat_main_t * vam) return ret; } -static int -api_l2tpv3_create_tunnel (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - ip6_address_t client_address, our_address; - int client_address_set = 0; - int our_address_set = 0; - u32 local_session_id = 0; - u32 remote_session_id = 0; - u64 local_cookie = 0; - u64 remote_cookie = 0; - u8 l2_sublayer_present = 0; - vl_api_l2tpv3_create_tunnel_t *mp; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "client_address %U", unformat_ip6_address, - &client_address)) - client_address_set = 1; - else if (unformat (i, "our_address %U", unformat_ip6_address, - &our_address)) - our_address_set = 1; - else if (unformat (i, "local_session_id %d", &local_session_id)) - ; - else if (unformat (i, "remote_session_id %d", &remote_session_id)) - ; - else if (unformat (i, "local_cookie %lld", &local_cookie)) - ; - else if (unformat (i, "remote_cookie %lld", &remote_cookie)) - ; - else if (unformat (i, "l2-sublayer-present")) - l2_sublayer_present = 1; - else - break; - } - - if (client_address_set == 0) - { - errmsg ("client_address required"); - return -99; - } - - if (our_address_set == 0) - { - errmsg ("our_address required"); - return -99; - } - - M (L2TPV3_CREATE_TUNNEL, mp); - - clib_memcpy (mp->client_address.un.ip6, client_address.as_u8, - sizeof (ip6_address_t)); - - clib_memcpy (mp->our_address.un.ip6, our_address.as_u8, - sizeof (ip6_address_t)); - - mp->local_session_id = ntohl (local_session_id); - mp->remote_session_id = ntohl (remote_session_id); - mp->local_cookie = clib_host_to_net_u64 (local_cookie); - mp->remote_cookie = clib_host_to_net_u64 (remote_cookie); - mp->l2_sublayer_present = l2_sublayer_present; - - S (mp); - W (ret); - return ret; -} - -static int -api_l2tpv3_set_tunnel_cookies (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u64 new_local_cookie = 0; - u64 new_remote_cookie = 0; - vl_api_l2tpv3_set_tunnel_cookies_t *mp; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "new_local_cookie %lld", &new_local_cookie)) - ; - else if (unformat (i, "new_remote_cookie %lld", &new_remote_cookie)) - ; - else - break; - } - - if (sw_if_index_set == 0) - { - errmsg ("missing interface name or sw_if_index"); - return -99; - } - - M (L2TPV3_SET_TUNNEL_COOKIES, mp); - - mp->sw_if_index = ntohl (sw_if_index); - mp->new_local_cookie = clib_host_to_net_u64 (new_local_cookie); - mp->new_remote_cookie = clib_host_to_net_u64 (new_remote_cookie); - - S (mp); - W (ret); - return ret; -} - -static int -api_l2tpv3_interface_enable_disable (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_l2tpv3_interface_enable_disable_t *mp; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u8 enable_disable = 1; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "enable")) - enable_disable = 1; - else if (unformat (i, "disable")) - enable_disable = 0; - else - break; - } - - if (sw_if_index_set == 0) - { - errmsg ("missing interface name or sw_if_index"); - return -99; - } - - M (L2TPV3_INTERFACE_ENABLE_DISABLE, mp); - - mp->sw_if_index = ntohl (sw_if_index); - mp->enable_disable = enable_disable; - - S (mp); - W (ret); - return ret; -} - -static int -api_l2tpv3_set_lookup_key (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_l2tpv3_set_lookup_key_t *mp; - u8 key = ~0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "lookup_v6_src")) - key = L2T_LOOKUP_SRC_ADDRESS; - else if (unformat (i, "lookup_v6_dst")) - key = L2T_LOOKUP_DST_ADDRESS; - else if (unformat (i, "lookup_session_id")) - key = L2T_LOOKUP_SESSION_ID; - else - break; - } - - if (key == (u8) ~ 0) - { - errmsg ("l2tp session lookup key unset"); - return -99; - } - - M (L2TPV3_SET_LOOKUP_KEY, mp); - - mp->key = key; - - S (mp); - W (ret); - return ret; -} - -static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler - (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) -{ - vat_main_t *vam = &vat_main; - - print (vam->ofp, "* %U (our) %U (client) (sw_if_index %d)", - format_ip6_address, mp->our_address, - format_ip6_address, mp->client_address, - clib_net_to_host_u32 (mp->sw_if_index)); - - print (vam->ofp, - " local cookies %016llx %016llx remote cookie %016llx", - clib_net_to_host_u64 (mp->local_cookie[0]), - clib_net_to_host_u64 (mp->local_cookie[1]), - clib_net_to_host_u64 (mp->remote_cookie)); - - print (vam->ofp, " local session-id %d remote session-id %d", - clib_net_to_host_u32 (mp->local_session_id), - clib_net_to_host_u32 (mp->remote_session_id)); - - print (vam->ofp, " l2 specific sublayer %s\n", - mp->l2_sublayer_present ? "preset" : "absent"); - -} - -static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler_json - (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t *node = NULL; - struct in6_addr addr; - - if (VAT_JSON_ARRAY != vam->json_tree.type) - { - ASSERT (VAT_JSON_NONE == vam->json_tree.type); - vat_json_init_array (&vam->json_tree); - } - node = vat_json_array_add (&vam->json_tree); - - vat_json_init_object (node); - - clib_memcpy (&addr, mp->our_address.un.ip6, sizeof (addr)); - vat_json_object_add_ip6 (node, "our_address", addr); - clib_memcpy (&addr, mp->client_address.un.ip6, sizeof (addr)); - vat_json_object_add_ip6 (node, "client_address", addr); - - vat_json_node_t *lc = vat_json_object_add (node, "local_cookie"); - vat_json_init_array (lc); - vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[0])); - vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[1])); - vat_json_object_add_uint (node, "remote_cookie", - clib_net_to_host_u64 (mp->remote_cookie)); - - printf ("local id: %u", clib_net_to_host_u32 (mp->local_session_id)); - vat_json_object_add_uint (node, "local_session_id", - clib_net_to_host_u32 (mp->local_session_id)); - vat_json_object_add_uint (node, "remote_session_id", - clib_net_to_host_u32 (mp->remote_session_id)); - vat_json_object_add_string_copy (node, "l2_sublayer", - mp->l2_sublayer_present ? (u8 *) "present" - : (u8 *) "absent"); -} - -static int -api_sw_if_l2tpv3_tunnel_dump (vat_main_t * vam) -{ - vl_api_sw_if_l2tpv3_tunnel_dump_t *mp; - vl_api_control_ping_t *mp_ping; - int ret; - - /* Get list of l2tpv3-tunnel interfaces */ - M (SW_IF_L2TPV3_TUNNEL_DUMP, mp); - S (mp); - - /* Use a control ping for synchronization */ - MPING (CONTROL_PING, mp_ping); - S (mp_ping); - - W (ret); - return ret; -} - - static void vl_api_sw_interface_tap_v2_details_t_handler (vl_api_sw_interface_tap_v2_details_t * mp) { @@ -20425,18 +20113,6 @@ _(classify_set_interface_l2_tables, \ " [other-table ]") \ _(get_node_index, "node next ") \ -_(l2tpv3_create_tunnel, \ - "client_address our_address \n" \ - "[local_session_id ][remote_session_id ][local_cookie ]\n" \ - "[remote_cookie ]\n[l2-sublayer-preset]\n") \ -_(l2tpv3_set_tunnel_cookies, \ - " | sw_if_index [new_local_cookie ]\n" \ - "[new_remote_cookie ]\n") \ -_(l2tpv3_interface_enable_disable, \ - " | sw_if_index enable | disable") \ -_(l2tpv3_set_lookup_key, \ - "lookup_v6_src | lookup_v6_dst | lookup_session_id") \ -_(sw_if_l2tpv3_tunnel_dump, "") \ _(vxlan_offload_rx, \ "hw { | hw_if_index } " \ "rx { | sw_if_index } [del]") \ diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 8c315ce5d73..579302c4687 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -761,29 +761,6 @@ list(APPEND VNET_HEADERS tunnel/tunnel_dp.h ) -############################################################################## -# Tunnel protocol: l2tpv3 -############################################################################## -list(APPEND VNET_SOURCES - l2tp/l2tp.c - l2tp/encap.c - l2tp/decap.c - l2tp/pg.c - l2tp/l2tp_api.c -) - -list(APPEND VNET_MULTIARCH_SOURCES - l2tp/encap.c - l2tp/decap.c -) - -list(APPEND VNET_HEADERS - l2tp/l2tp.h - l2tp/packet.h -) - -list(APPEND VNET_API_FILES l2tp/l2tp.api) - ############################################################################## # Tunnel protocol: gre+mpls ############################################################################## diff --git a/src/vnet/l2tp/FEATURE.yaml b/src/vnet/l2tp/FEATURE.yaml deleted file mode 100644 index 58df9b2215e..00000000000 --- a/src/vnet/l2tp/FEATURE.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: L2TPv3 -maintainer: unmaintained -features: - - L2TPv3 over IPv6 -description: "An initial and incomplete implementation of L2TPv3 (RFC3931)." -state: experimental -properties: [API, CLI] diff --git a/src/vnet/l2tp/decap.c b/src/vnet/l2tp/decap.c deleted file mode 100644 index 787cc115a7e..00000000000 --- a/src/vnet/l2tp/decap.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * decap.c : L2TPv3 tunnel decapsulation - * - * Copyright (c) 2013 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 - -/* Statistics (not really errors) */ -#define foreach_l2t_decap_error \ -_(USER_TO_NETWORK, "L2TP user (ip6) to L2 network pkts") \ -_(SESSION_ID_MISMATCH, "l2tpv3 local session id mismatches") \ -_(COOKIE_MISMATCH, "l2tpv3 local cookie mismatches") \ -_(NO_SESSION, "l2tpv3 session not found") \ -_(ADMIN_DOWN, "l2tpv3 tunnel is down") - -static char *l2t_decap_error_strings[] = { -#define _(sym,string) string, - foreach_l2t_decap_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) L2T_DECAP_ERROR_##sym, - foreach_l2t_decap_error -#undef _ - L2T_DECAP_N_ERROR, -} l2t_DECAP_error_t; - -typedef enum -{ - L2T_DECAP_NEXT_DROP, - L2T_DECAP_NEXT_L2_INPUT, - L2T_DECAP_N_NEXT, - /* Pseudo next index */ - L2T_DECAP_NEXT_NO_INTERCEPT = L2T_DECAP_N_NEXT, -} l2t_decap_next_t; - -#define NSTAGES 3 - -static inline void -stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) -{ - vlib_prefetch_buffer_header (b, STORE); - /* l2tpv3 header is a long way away, need 2 cache lines */ - CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE); -} - -static inline void -stage1 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) -{ - l2t_main_t *lm = &l2t_main; - ip6_header_t *ip6 = vlib_buffer_get_current (b); - u32 session_index; - uword *p = 0; - l2tpv3_header_t *l2t; - - /* Not L2tpv3 (0x73, 0t115)? Use the normal path. */ - if (PREDICT_FALSE (ip6->protocol != IP_PROTOCOL_L2TP)) - { - vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_NO_INTERCEPT; - return; - } - - /* Make up your minds, people... */ - switch (lm->lookup_type) - { - case L2T_LOOKUP_SRC_ADDRESS: - p = hash_get_mem (lm->session_by_src_address, &ip6->src_address); - break; - case L2T_LOOKUP_DST_ADDRESS: - p = hash_get_mem (lm->session_by_dst_address, &ip6->dst_address); - break; - case L2T_LOOKUP_SESSION_ID: - l2t = (l2tpv3_header_t *) (ip6 + 1); - p = hash_get (lm->session_by_session_id, l2t->session_id); - break; - default: - ASSERT (0); - } - - if (PREDICT_FALSE (p == 0)) - { - vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_NO_INTERCEPT; - return; - } - else - { - session_index = p[0]; - } - - /* Remember mapping index, prefetch the mini counter */ - vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_L2_INPUT; - vnet_buffer (b)->l2t.session_index = session_index; - - /* $$$$$ prefetch counter */ -} - -static inline u32 -last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) -{ - l2t_main_t *lm = &l2t_main; - ip6_header_t *ip6 = vlib_buffer_get_current (b); - vlib_node_t *n = vlib_get_node (vm, node->node_index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t *em = &vm->error_main; - l2tpv3_header_t *l2tp; - u32 counter_index; - l2t_session_t *session = 0; - u32 session_index; - u32 next_index; - u8 l2tp_decap_local = (l2t_decap_local_node.index == n->index); - - /* Other-than-output pkt? We're done... */ - if (vnet_buffer (b)->l2t.next_index != L2T_DECAP_NEXT_L2_INPUT) - { - next_index = vnet_buffer (b)->l2t.next_index; - goto done; - } - - em->counters[node_counter_base_index + L2T_DECAP_ERROR_USER_TO_NETWORK] += - 1; - - session_index = vnet_buffer (b)->l2t.session_index; - - counter_index = - session_index_to_counter_index (session_index, - SESSION_COUNTER_USER_TO_NETWORK); - - /* per-mapping byte stats include the ethernet header */ - vlib_increment_combined_counter (&lm->counter_main, - vlib_get_thread_index (), - counter_index, 1 /* packet_increment */ , - vlib_buffer_length_in_chain (vm, b) + - sizeof (ethernet_header_t)); - - session = pool_elt_at_index (lm->sessions, session_index); - - l2tp = vlib_buffer_get_current (b) + sizeof (*ip6); - - if (PREDICT_FALSE (l2tp->session_id != session->local_session_id)) - { - /* Key matched but session id does not. Assume packet is not for us. */ - em->counters[node_counter_base_index + - L2T_DECAP_ERROR_SESSION_ID_MISMATCH] += 1; - next_index = L2T_DECAP_NEXT_NO_INTERCEPT; - goto done; - } - - if (PREDICT_FALSE (l2tp->cookie != session->local_cookie[0])) - { - if (l2tp->cookie != session->local_cookie[1]) - { - /* Key and session ID matched, but cookie doesn't. Drop this packet. */ - b->error = node->errors[L2T_DECAP_ERROR_COOKIE_MISMATCH]; - next_index = L2T_DECAP_NEXT_DROP; - goto done; - } - } - - vnet_buffer (b)->sw_if_index[VLIB_RX] = session->sw_if_index; - - if (PREDICT_FALSE (!(session->admin_up))) - { - b->error = node->errors[L2T_DECAP_ERROR_ADMIN_DOWN]; - next_index = L2T_DECAP_NEXT_DROP; - goto done; - } - - /* strip the ip6 and L2TP header */ - vlib_buffer_advance (b, sizeof (*ip6) + session->l2tp_hdr_size); - - /* Required to make the l2 tag push / pop code work on l2 subifs */ - vnet_update_l2_len (b); - - if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) - { - l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); - t->is_user_to_network = 1; - t->our_address.as_u64[0] = ip6->dst_address.as_u64[0]; - t->our_address.as_u64[1] = ip6->dst_address.as_u64[1]; - t->client_address.as_u64[0] = ip6->src_address.as_u64[0]; - t->client_address.as_u64[1] = ip6->src_address.as_u64[1]; - t->session_index = session_index; - } - - return L2T_DECAP_NEXT_L2_INPUT; - -done: - if (next_index == L2T_DECAP_NEXT_NO_INTERCEPT) - { - /* Small behavioral change between l2tp-decap and l2tp-decap-local */ - if (l2tp_decap_local) - { - b->error = node->errors[L2T_DECAP_ERROR_NO_SESSION]; - next_index = L2T_DECAP_NEXT_DROP; - } - else - { - /* Go to next node on the ip6 configuration chain */ - if (PREDICT_TRUE (session != 0)) - vnet_feature_next (&next_index, b); - } - } - - if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) - { - l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); - t->is_user_to_network = 1; - t->our_address.as_u64[0] = ip6->dst_address.as_u64[0]; - t->our_address.as_u64[1] = ip6->dst_address.as_u64[1]; - t->client_address.as_u64[0] = ip6->src_address.as_u64[0]; - t->client_address.as_u64[1] = ip6->src_address.as_u64[1]; - t->session_index = ~0; - } - return next_index; -} - -#include - -VLIB_NODE_FN (l2t_decap_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - -/* - * l2tp-decap and l2tp-decap-local have very slightly different behavior. - * When a packet has no associated session l2tp-decap let it go to ip6 forward, - * while l2tp-decap-local drops it. - */ - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (l2t_decap_node) = { - .name = "l2tp-decap", - .vector_size = sizeof (u32), - .format_trace = format_l2t_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(l2t_decap_error_strings), - .error_strings = l2t_decap_error_strings, - - .n_next_nodes = L2T_DECAP_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [L2T_DECAP_NEXT_L2_INPUT] = "l2-input", - [L2T_DECAP_NEXT_DROP] = "error-drop", - }, -}; -/* *INDENT-ON* */ - -extern vlib_node_function_t l2t_decap_node_fn; - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (l2t_decap_local_node) = { - .function = l2t_decap_node_fn, - .name = "l2tp-decap-local", - .vector_size = sizeof (u32), - .format_trace = format_l2t_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(l2t_decap_error_strings), - .error_strings = l2t_decap_error_strings, - - .n_next_nodes = L2T_DECAP_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [L2T_DECAP_NEXT_L2_INPUT] = "l2-input", - [L2T_DECAP_NEXT_DROP] = "error-drop", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/encap.c b/src/vnet/l2tp/encap.c deleted file mode 100644 index 8863ddfa20d..00000000000 --- a/src/vnet/l2tp/encap.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * encap.c : L2TPv3 tunnel encapsulation - * - * Copyright (c) 2013 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 - -/* Statistics (not really errors) */ -#define foreach_l2t_encap_error \ -_(NETWORK_TO_USER, "L2TP L2 network to user (ip6) pkts") \ -_(LOOKUP_FAIL_TO_L3, "L2TP L2 session lookup failed pkts") \ -_(ADMIN_DOWN, "L2TP tunnel is down") - -static char *l2t_encap_error_strings[] = { -#define _(sym,string) string, - foreach_l2t_encap_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) L2T_ENCAP_ERROR_##sym, - foreach_l2t_encap_error -#undef _ - L2T_ENCAP_N_ERROR, -} l2t_encap_error_t; - - -typedef enum -{ - L2T_ENCAP_NEXT_DROP, - L2T_ENCAP_NEXT_IP6_LOOKUP, - L2T_ENCAP_N_NEXT, -} l2t_encap_next_t; - -typedef struct -{ - u32 cached_session_index; - u32 cached_sw_if_index; - vnet_main_t *vnet_main; -} l2tp_encap_runtime_t; - -extern vlib_node_registration_t l2t_encap_node; - -#define NSTAGES 3 - -static inline void -stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) -{ - vlib_prefetch_buffer_header (b, STORE); - CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE); -} - -static inline void -stage1 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) -{ - l2tp_encap_runtime_t *rt = (void *) node->runtime_data; - vnet_hw_interface_t *hi; - - u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX]; - u32 session_index = rt->cached_session_index; - - if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index)) - { - hi = vnet_get_sup_hw_interface (rt->vnet_main, sw_if_index); - session_index = rt->cached_session_index = hi->dev_instance; - rt->cached_sw_if_index = sw_if_index; - } - - /* Remember mapping index, prefetch the mini counter */ - vnet_buffer (b)->l2t.next_index = L2T_ENCAP_NEXT_IP6_LOOKUP; - vnet_buffer (b)->l2t.session_index = session_index; - - /* $$$$ prefetch counter... */ -} - -static inline u32 -last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b) -{ - l2t_main_t *lm = &l2t_main; - vlib_node_t *n = vlib_get_node (vm, l2t_encap_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t *em = &vm->error_main; - l2tpv3_header_t *l2tp; - u32 session_index; - u32 counter_index; - l2t_session_t *s; - ip6_header_t *ip6; - u16 payload_length; - u32 next_index = L2T_ENCAP_NEXT_IP6_LOOKUP; - - /* Other-than-output pkt? We're done... */ - if (vnet_buffer (b)->l2t.next_index != L2T_ENCAP_NEXT_IP6_LOOKUP) - return vnet_buffer (b)->l2t.next_index; - - em->counters[node_counter_base_index + L2T_ENCAP_ERROR_NETWORK_TO_USER] += - 1; - - session_index = vnet_buffer (b)->l2t.session_index; - - counter_index = - session_index_to_counter_index (session_index, - SESSION_COUNTER_NETWORK_TO_USER); - - /* per-mapping byte stats include the ethernet header */ - vlib_increment_combined_counter (&lm->counter_main, - vlib_get_thread_index (), - counter_index, 1 /* packet_increment */ , - vlib_buffer_length_in_chain (vm, b)); - - s = pool_elt_at_index (lm->sessions, session_index); - - vnet_buffer (b)->sw_if_index[VLIB_TX] = s->encap_fib_index; - - /* Paint on an l2tpv3 hdr */ - vlib_buffer_advance (b, -(s->l2tp_hdr_size)); - l2tp = vlib_buffer_get_current (b); - - l2tp->session_id = s->remote_session_id; - l2tp->cookie = s->remote_cookie; - if (PREDICT_FALSE (s->l2_sublayer_present)) - { - l2tp->l2_specific_sublayer = 0; - } - - /* Paint on an ip6 header */ - vlib_buffer_advance (b, -(sizeof (*ip6))); - ip6 = vlib_buffer_get_current (b); - - if (PREDICT_FALSE (!(s->admin_up))) - { - b->error = node->errors[L2T_ENCAP_ERROR_ADMIN_DOWN]; - next_index = L2T_ENCAP_NEXT_DROP; - goto done; - } - - ip6->ip_version_traffic_class_and_flow_label = - clib_host_to_net_u32 (0x6 << 28); - - /* calculate ip6 payload length */ - payload_length = vlib_buffer_length_in_chain (vm, b); - payload_length -= sizeof (*ip6); - - ip6->payload_length = clib_host_to_net_u16 (payload_length); - ip6->protocol = IP_PROTOCOL_L2TP; - ip6->hop_limit = 0xff; - ip6->src_address.as_u64[0] = s->our_address.as_u64[0]; - ip6->src_address.as_u64[1] = s->our_address.as_u64[1]; - ip6->dst_address.as_u64[0] = s->client_address.as_u64[0]; - ip6->dst_address.as_u64[1] = s->client_address.as_u64[1]; - - -done: - if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) - { - l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); - t->is_user_to_network = 0; - t->our_address.as_u64[0] = ip6->src_address.as_u64[0]; - t->our_address.as_u64[1] = ip6->src_address.as_u64[1]; - t->client_address.as_u64[0] = ip6->dst_address.as_u64[0]; - t->client_address.as_u64[1] = ip6->dst_address.as_u64[1]; - t->session_index = session_index; - } - - return next_index; -} - -#include - -VLIB_NODE_FN (l2t_encap_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return dispatch_pipeline (vm, node, frame); -} - - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (l2t_encap_node) = { - .name = "l2tp-encap", - .vector_size = sizeof (u32), - .format_trace = format_l2t_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .runtime_data_bytes = sizeof (l2tp_encap_runtime_t), - - .n_errors = ARRAY_LEN(l2t_encap_error_strings), - .error_strings = l2t_encap_error_strings, - - .n_next_nodes = L2T_ENCAP_N_NEXT, - - /* add dispositions here */ - .next_nodes = { - [L2T_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup", - [L2T_ENCAP_NEXT_DROP] = "error-drop", - }, -}; -/* *INDENT-ON* */ - -#ifndef CLIB_MARCH_VARIANT -void -l2tp_encap_init (vlib_main_t * vm) -{ - l2tp_encap_runtime_t *rt; - - rt = vlib_node_get_runtime_data (vm, l2t_encap_node.index); - rt->vnet_main = vnet_get_main (); - rt->cached_sw_if_index = (u32) ~ 0; - rt->cached_session_index = (u32) ~ 0; -} -#endif /* CLIB_MARCH_VARIANT */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/l2tp.api b/src/vnet/l2tp/l2tp.api deleted file mode 100644 index 618c4122fd6..00000000000 --- a/src/vnet/l2tp/l2tp.api +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2015-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -option version = "2.0.0"; - -import "vnet/interface_types.api"; -import "vnet/ethernet/ethernet_types.api"; -import "vnet/ip/ip_types.api"; - -/** \brief l2tpv3 tunnel interface create request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param client_address - remote client tunnel ip address - @param client_address - local tunnel ip address - @param is_ipv6 - ipv6 if non-zero, else ipv4 - @param local_session_id - local tunnel session id - @param remote_session_id - remote tunnel session id - @param local_cookie - local tunnel cookie - @param l2_sublayer_present - l2 sublayer is present in packets if non-zero - @param encap_vrf_id - fib identifier used for outgoing encapsulated packets -*/ -define l2tpv3_create_tunnel -{ - u32 client_index; - u32 context; - vl_api_address_t client_address; - vl_api_address_t our_address; - u32 local_session_id; - u32 remote_session_id; - u64 local_cookie; - u64 remote_cookie; - bool l2_sublayer_present; - u32 encap_vrf_id; -}; - -/** \brief l2tpv3 tunnel interface create response - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param sw_if_index - index of the new tunnel interface -*/ -define l2tpv3_create_tunnel_reply -{ - u32 context; - i32 retval; - vl_api_interface_index_t sw_if_index; -}; - -autoreply define l2tpv3_set_tunnel_cookies -{ - u32 client_index; - u32 context; - vl_api_interface_index_t sw_if_index; - u64 new_local_cookie; - u64 new_remote_cookie; -}; - -define sw_if_l2tpv3_tunnel_details -{ - u32 context; - vl_api_interface_index_t sw_if_index; - string interface_name[64]; - vl_api_address_t client_address; - vl_api_address_t our_address; - u32 local_session_id; - u32 remote_session_id; - u64 local_cookie[2]; - u64 remote_cookie; - bool l2_sublayer_present; -}; - -define sw_if_l2tpv3_tunnel_dump -{ - u32 client_index; - u32 context; -}; - -autoreply define l2tpv3_interface_enable_disable -{ - u32 client_index; - u32 context; - bool enable_disable; - vl_api_interface_index_t sw_if_index; -}; - -enum l2t_lookup_key : u8 -{ - L2T_LOOKUP_KEY_API_SRC_ADDR = 0, - L2T_LOOKUP_KEY_API_DST_ADDR = 1, - L2T_LOOKUP_KEY_API_SESSION_ID = 2, -}; - -autoreply define l2tpv3_set_lookup_key -{ - u32 client_index; - u32 context; - vl_api_l2t_lookup_key_t key; -}; - -/* - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/l2tp.c b/src/vnet/l2tp/l2tp.c deleted file mode 100644 index fa112ee7986..00000000000 --- a/src/vnet/l2tp/l2tp.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * l2tp.c : L2TPv3 tunnel support - * - * Copyright (c) 2013 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 - -l2t_main_t l2t_main; - -/* packet trace format function */ -u8 * -format_l2t_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 *); - l2t_trace_t *t = va_arg (*args, l2t_trace_t *); - - if (t->is_user_to_network) - s = format (s, "L2T: %U (client) -> %U (our) session %d", - format_ip6_address, &t->client_address, - format_ip6_address, &t->our_address, t->session_index); - else - s = format (s, "L2T: %U (our) -> %U (client) session %d)", - format_ip6_address, &t->our_address, - format_ip6_address, &t->client_address, t->session_index); - return s; -} - -u8 * -format_l2t_session (u8 * s, va_list * args) -{ - l2t_session_t *session = va_arg (*args, l2t_session_t *); - l2t_main_t *lm = &l2t_main; - u32 counter_index; - vlib_counter_t v; - - s = format (s, "[%d] %U (our) %U (client) %U (sw_if_index %d)\n", - session - lm->sessions, - format_ip6_address, &session->our_address, - format_ip6_address, &session->client_address, - format_vnet_sw_interface_name, lm->vnet_main, - vnet_get_sw_interface (lm->vnet_main, session->sw_if_index), - session->sw_if_index); - - s = format (s, " local cookies %016llx %016llx remote cookie %016llx\n", - clib_net_to_host_u64 (session->local_cookie[0]), - clib_net_to_host_u64 (session->local_cookie[1]), - clib_net_to_host_u64 (session->remote_cookie)); - - s = format (s, " local session-id %d remote session-id %d\n", - clib_net_to_host_u32 (session->local_session_id), - clib_net_to_host_u32 (session->remote_session_id)); - - s = format (s, " l2 specific sublayer %s\n", - session->l2_sublayer_present ? "preset" : "absent"); - - counter_index = - session_index_to_counter_index (session - lm->sessions, - SESSION_COUNTER_USER_TO_NETWORK); - - vlib_get_combined_counter (&lm->counter_main, counter_index, &v); - if (v.packets != 0) - s = format (s, " user-to-net: %llu pkts %llu bytes\n", - v.packets, v.bytes); - - vlib_get_combined_counter (&lm->counter_main, counter_index + 1, &v); - - if (v.packets != 0) - s = format (s, " net-to-user: %llu pkts %llu bytes\n", - v.packets, v.bytes); - return s; -} - -static clib_error_t * -show_l2tp_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - l2t_session_t *session; - l2t_main_t *lm = &l2t_main; - char *keystr = 0; - int verbose = 0; - - if (unformat (input, "verbose") || unformat (input, "v")) - verbose = 1; - - if (pool_elts (lm->sessions) == 0) - vlib_cli_output (vm, "No l2tp sessions..."); - else - vlib_cli_output (vm, "%u l2tp sessions...", pool_elts (lm->sessions)); - - if (verbose) - { - switch (lm->lookup_type) - { - case L2T_LOOKUP_SRC_ADDRESS: - keystr = "src address"; - break; - - case L2T_LOOKUP_DST_ADDRESS: - keystr = "dst address"; - break; - - case L2T_LOOKUP_SESSION_ID: - keystr = "session id"; - break; - - default: - keystr = "BOGUS!"; - break; - } - - vlib_cli_output (vm, "L2tp session lookup on %s", keystr); - - /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, - ({ - vlib_cli_output (vm, "%U", format_l2t_session, session); - })); - /* *INDENT-ON* */ - } - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_session_detail_command, static) = { - .path = "show l2tpv3", - .short_help = "show l2tpv3 [verbose]", - .function = show_l2tp_command_fn, -}; -/* *INDENT-ON* */ - -static clib_error_t * -test_counters_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - l2t_session_t *session; - l2t_main_t *lm = &l2t_main; - u32 session_index; - u32 counter_index; - u32 nincr = 0; - u32 thread_index = vm->thread_index; - - /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, - ({ - session_index = session - lm->sessions; - counter_index = - session_index_to_counter_index (session_index, - SESSION_COUNTER_USER_TO_NETWORK); - vlib_increment_combined_counter (&lm->counter_main, - thread_index, - counter_index, - 1/*pkt*/, 1111 /*bytes*/); - vlib_increment_combined_counter (&lm->counter_main, - thread_index, - counter_index+1, - 1/*pkt*/, 2222 /*bytes*/); - nincr++; - - })); - /* *INDENT-ON* */ - vlib_cli_output (vm, "Incremented %d active counters\n", nincr); - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (test_counters_command, static) = { - .path = "test lt2p counters", - .short_help = "increment all active counters", - .function = test_counters_command_fn, -}; -/* *INDENT-ON* */ - -static clib_error_t * -clear_counters_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - l2t_session_t *session; - l2t_main_t *lm = &l2t_main; - u32 session_index; - u32 counter_index; - u32 nincr = 0; - - /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, - ({ - session_index = session - lm->sessions; - counter_index = - session_index_to_counter_index (session_index, - SESSION_COUNTER_USER_TO_NETWORK); - vlib_zero_combined_counter (&lm->counter_main, counter_index); - vlib_zero_combined_counter (&lm->counter_main, counter_index+1); - nincr++; - })); - /* *INDENT-ON* */ - vlib_cli_output (vm, "Cleared %d active counters\n", nincr); - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (clear_counters_command, static) = { - .path = "clear l2tp counters", - .short_help = "clear all active counters", - .function = clear_counters_command_fn, -}; -/* *INDENT-ON* */ - -static u8 * -format_l2tpv3_name (u8 * s, va_list * args) -{ - l2t_main_t *lm = &l2t_main; - u32 i = va_arg (*args, u32); - u32 show_dev_instance = ~0; - - if (i < vec_len (lm->dev_inst_by_real)) - show_dev_instance = lm->dev_inst_by_real[i]; - - if (show_dev_instance != ~0) - i = show_dev_instance; - - return format (s, "l2tpv3_tunnel%d", i); -} - -static int -l2tpv3_name_renumber (vnet_hw_interface_t * hi, u32 new_dev_instance) -{ - l2t_main_t *lm = &l2t_main; - - vec_validate_init_empty (lm->dev_inst_by_real, hi->dev_instance, ~0); - - lm->dev_inst_by_real[hi->dev_instance] = new_dev_instance; - - return 0; -} - -/* *INDENT-OFF* */ -VNET_DEVICE_CLASS (l2tpv3_device_class,static) = { - .name = "L2TPv3", - .format_device_name = format_l2tpv3_name, - .name_renumber = l2tpv3_name_renumber, -}; -/* *INDENT-ON* */ - -static u8 * -format_l2tp_header_with_length (u8 * s, va_list * args) -{ - u32 dev_instance = va_arg (*args, u32); - s = format (s, "unimplemented dev %u", dev_instance); - return s; -} - -/* *INDENT-OFF* */ -VNET_HW_INTERFACE_CLASS (l2tpv3_hw_class) = { - .name = "L2TPV3", - .format_header = format_l2tp_header_with_length, - .build_rewrite = default_build_rewrite, - .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, -}; -/* *INDENT-ON* */ - -int -create_l2tpv3_ipv6_tunnel (l2t_main_t * lm, - ip6_address_t * client_address, - ip6_address_t * our_address, - u32 local_session_id, - u32 remote_session_id, - u64 local_cookie, - u64 remote_cookie, - int l2_sublayer_present, - u32 encap_fib_index, u32 * sw_if_index) -{ - l2t_session_t *s = 0; - vnet_main_t *vnm = lm->vnet_main; - vnet_hw_interface_t *hi; - uword *p = (uword *) ~ 0; - u32 hw_if_index; - l2tpv3_header_t l2tp_hdr; - ip6_address_t *dst_address_copy, *src_address_copy; - u32 counter_index; - - remote_session_id = clib_host_to_net_u32 (remote_session_id); - local_session_id = clib_host_to_net_u32 (local_session_id); - - switch (lm->lookup_type) - { - case L2T_LOOKUP_SRC_ADDRESS: - p = hash_get_mem (lm->session_by_src_address, client_address); - break; - - case L2T_LOOKUP_DST_ADDRESS: - p = hash_get_mem (lm->session_by_dst_address, our_address); - break; - - case L2T_LOOKUP_SESSION_ID: - p = hash_get (lm->session_by_session_id, local_session_id); - break; - - default: - ASSERT (0); - } - - /* adding a session: session must not already exist */ - if (p) - return VNET_API_ERROR_INVALID_VALUE; - - pool_get (lm->sessions, s); - clib_memset (s, 0, sizeof (*s)); - clib_memcpy (&s->our_address, our_address, sizeof (s->our_address)); - clib_memcpy (&s->client_address, client_address, - sizeof (s->client_address)); - s->local_cookie[0] = clib_host_to_net_u64 (local_cookie); - s->remote_cookie = clib_host_to_net_u64 (remote_cookie); - s->local_session_id = local_session_id; - s->remote_session_id = remote_session_id; - s->l2_sublayer_present = l2_sublayer_present; - /* precompute l2tp header size */ - s->l2tp_hdr_size = l2_sublayer_present ? - sizeof (l2tpv3_header_t) : - sizeof (l2tpv3_header_t) - sizeof (l2tp_hdr.l2_specific_sublayer); - s->admin_up = 0; - s->encap_fib_index = encap_fib_index; - - /* Setup hash table entries */ - switch (lm->lookup_type) - { - case L2T_LOOKUP_SRC_ADDRESS: - src_address_copy = clib_mem_alloc (sizeof (*src_address_copy)); - clib_memcpy (src_address_copy, client_address, - sizeof (*src_address_copy)); - hash_set_mem (lm->session_by_src_address, src_address_copy, - s - lm->sessions); - break; - case L2T_LOOKUP_DST_ADDRESS: - dst_address_copy = clib_mem_alloc (sizeof (*dst_address_copy)); - clib_memcpy (dst_address_copy, our_address, sizeof (*dst_address_copy)); - hash_set_mem (lm->session_by_dst_address, dst_address_copy, - s - lm->sessions); - break; - case L2T_LOOKUP_SESSION_ID: - hash_set (lm->session_by_session_id, local_session_id, - s - lm->sessions); - break; - - default: - ASSERT (0); - } - - /* validate counters */ - counter_index = - session_index_to_counter_index (s - lm->sessions, - SESSION_COUNTER_USER_TO_NETWORK); - vlib_validate_combined_counter (&lm->counter_main, counter_index); - vlib_validate_combined_counter (&lm->counter_main, counter_index + 1); - - if (vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) > 0) - { - hw_if_index = lm->free_l2tpv3_tunnel_hw_if_indices - [vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) - 1]; - _vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) -= 1; - - hi = vnet_get_hw_interface (vnm, hw_if_index); - hi->dev_instance = s - lm->sessions; - hi->hw_instance = hi->dev_instance; - } - else - { - hw_if_index = vnet_register_interface - (vnm, l2tpv3_device_class.index, s - lm->sessions, - l2tpv3_hw_class.index, s - lm->sessions); - hi = vnet_get_hw_interface (vnm, hw_if_index); - hi->output_node_index = l2t_encap_node.index; - /* $$$$ initialize custom dispositions, if needed */ - } - - s->hw_if_index = hw_if_index; - s->sw_if_index = hi->sw_if_index; - - if (sw_if_index) - *sw_if_index = hi->sw_if_index; - - if (!lm->proto_registered) - { - ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_local_node.index); - lm->proto_registered = true; - } - - return 0; -} - -static clib_error_t * -create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip6_address_t client_address, our_address; - unformat_input_t _line_input, *line_input = &_line_input; - l2t_main_t *lm = &l2t_main; - u64 local_cookie = (u64) ~ 0, remote_cookie = (u64) ~ 0; - u32 local_session_id = 1, remote_session_id = 1; - int our_address_set = 0, client_address_set = 0; - int l2_sublayer_present = 0; - int rv; - u32 sw_if_index; - u32 encap_fib_id = ~0; - u32 encap_fib_index = ~0; - clib_error_t *error = NULL; - - /* 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, "client %U", - unformat_ip6_address, &client_address)) - client_address_set = 1; - else if (unformat (line_input, "our %U", - unformat_ip6_address, &our_address)) - our_address_set = 1; - else if (unformat (line_input, "local-cookie %llx", &local_cookie)) - ; - else if (unformat (line_input, "remote-cookie %llx", &remote_cookie)) - ; - else if (unformat (line_input, "local-session-id %d", - &local_session_id)) - ; - else if (unformat (line_input, "remote-session-id %d", - &remote_session_id)) - ; - else if (unformat (line_input, "fib-id %d", &encap_fib_id)) - ; - else if (unformat (line_input, "l2-sublayer-present")) - l2_sublayer_present = 1; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (encap_fib_id != ~0) - { - uword *p; - ip6_main_t *im = &ip6_main; - if (!(p = hash_get (im->fib_index_by_table_id, encap_fib_id))) - { - error = clib_error_return (0, "No fib with id %d", encap_fib_id); - goto done; - } - encap_fib_index = p[0]; - } - else - { - encap_fib_index = ~0; - } - - if (our_address_set == 0) - { - error = clib_error_return (0, "our address not specified"); - goto done; - } - if (client_address_set == 0) - { - error = clib_error_return (0, "client address not specified"); - goto done; - } - - rv = create_l2tpv3_ipv6_tunnel (lm, &client_address, &our_address, - local_session_id, remote_session_id, - local_cookie, remote_cookie, - l2_sublayer_present, - encap_fib_index, &sw_if_index); - switch (rv) - { - case 0: - vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, - vnet_get_main (), sw_if_index); - break; - case VNET_API_ERROR_INVALID_VALUE: - error = clib_error_return (0, "session already exists..."); - goto done; - - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = clib_error_return (0, "session does not exist..."); - goto done; - - default: - error = clib_error_return (0, "l2tp_session_add_del returned %d", rv); - goto done; - } - -done: - unformat_free (line_input); - - return error; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (create_l2tpv3_tunnel_command, static) = -{ - .path = "create l2tpv3 tunnel", - .short_help = - "create l2tpv3 tunnel client our local-cookie remote-cookie local-session remote-session ", - .function = create_l2tpv3_tunnel_command_fn, -}; -/* *INDENT-ON* */ - -int -l2tpv3_set_tunnel_cookies (l2t_main_t * lm, - u32 sw_if_index, - u64 new_local_cookie, u64 new_remote_cookie) -{ - l2t_session_t *s; - vnet_hw_interface_t *hi; - vnet_main_t *vnm = vnet_get_main (); - hi = vnet_get_sup_hw_interface (vnm, sw_if_index); - - if (pool_is_free_index (lm->sessions, hi->dev_instance)) - return VNET_API_ERROR_INVALID_VALUE; - - s = pool_elt_at_index (lm->sessions, hi->dev_instance); - - s->local_cookie[1] = s->local_cookie[0]; - s->local_cookie[0] = clib_host_to_net_u64 (new_local_cookie); - s->remote_cookie = clib_host_to_net_u64 (new_remote_cookie); - - return 0; -} - - -static clib_error_t * -set_l2tp_tunnel_cookie_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - l2t_main_t *lm = &l2t_main; - vnet_main_t *vnm = vnet_get_main (); - u32 sw_if_index = ~0; - u64 local_cookie = (u64) ~ 0, remote_cookie = (u64) ~ 0; - - int rv; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, - &sw_if_index)) - ; - else if (unformat (input, "local %llx", &local_cookie)) - ; - else if (unformat (input, "remote %llx", &remote_cookie)) - ; - else - break; - } - if (sw_if_index == ~0) - return clib_error_return (0, "unknown interface"); - if (local_cookie == ~0) - return clib_error_return (0, "local cookie required"); - if (remote_cookie == ~0) - return clib_error_return (0, "remote cookie required"); - - rv = l2tpv3_set_tunnel_cookies (lm, sw_if_index, - local_cookie, remote_cookie); - - switch (rv) - { - case 0: - break; - - case VNET_API_ERROR_INVALID_SW_IF_INDEX: - return clib_error_return (0, "invalid interface"); - - default: - return clib_error_return (0, "l2tp_session_set_cookies returned %d", - rv); - } - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_l2tp_tunnel_cookie_command, static) = -{ - .path = "set l2tpv3 tunnel cookie", - .short_help = - "set l2tpv3 tunnel cookie local remote ", - .function = set_l2tp_tunnel_cookie_command_fn, -}; -/* *INDENT-ON* */ - -int -l2tpv3_interface_enable_disable (vnet_main_t * vnm, - u32 sw_if_index, int enable_disable) -{ - - if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index)) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; - - vnet_feature_enable_disable ("ip6-unicast", "l2tp-decap", sw_if_index, - enable_disable, 0, 0); - return 0; -} - -/* Enable/disable L2TPv3 intercept on IP6 forwarding path */ -static clib_error_t * -set_ip6_l2tpv3 (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - u32 sw_if_index = ~0; - int is_add = 1; - int rv; - vnet_main_t *vnm = vnet_get_main (); - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, - &sw_if_index)) - ; - else if (unformat (input, "del")) - is_add = 0; - else - break; - } - - if (sw_if_index == ~0) - return clib_error_return (0, "interface required"); - - rv = l2tpv3_interface_enable_disable (vnm, sw_if_index, is_add); - - switch (rv) - { - case 0: - break; - - case VNET_API_ERROR_INVALID_SW_IF_INDEX: - return clib_error_return (0, "invalid interface"); - - default: - return clib_error_return (0, - "l2tp_interface_enable_disable returned %d", - rv); - } - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_interface_ip6_l2tpv3, static) = -{ - .path = "set interface ip6 l2tpv3", - .function = set_ip6_l2tpv3, - .short_help = "set interface ip6 l2tpv3 [del]", -}; -/* *INDENT-ON* */ - -static clib_error_t * -l2tp_config (vlib_main_t * vm, unformat_input_t * input) -{ - l2t_main_t *lm = &l2t_main; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "lookup-v6-src")) - lm->lookup_type = L2T_LOOKUP_SRC_ADDRESS; - else if (unformat (input, "lookup-v6-dst")) - lm->lookup_type = L2T_LOOKUP_DST_ADDRESS; - else if (unformat (input, "lookup-session-id")) - lm->lookup_type = L2T_LOOKUP_SESSION_ID; - else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - } - return 0; -} - -VLIB_CONFIG_FUNCTION (l2tp_config, "l2tp"); - - -clib_error_t * -l2tp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) -{ - l2t_main_t *lm = &l2t_main; - vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index); - if (hi->hw_class_index != l2tpv3_hw_class.index) - return 0; - - u32 session_index = hi->dev_instance; - l2t_session_t *s = pool_elt_at_index (lm->sessions, session_index); - s->admin_up = ! !(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP); - return 0; -} - -VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2tp_sw_interface_up_down); - -clib_error_t * -l2tp_init (vlib_main_t * vm) -{ - l2t_main_t *lm = &l2t_main; - ip_main_t *im = &ip_main; - ip_protocol_info_t *pi; - - lm->vnet_main = vnet_get_main (); - lm->vlib_main = vm; - lm->lookup_type = L2T_LOOKUP_DST_ADDRESS; - - lm->session_by_src_address = hash_create_mem - (0, sizeof (ip6_address_t) /* key bytes */ , - sizeof (u32) /* value bytes */ ); - lm->session_by_dst_address = hash_create_mem - (0, sizeof (ip6_address_t) /* key bytes */ , - sizeof (u32) /* value bytes */ ); - lm->session_by_session_id = hash_create (0, sizeof (uword)); - - pi = ip_get_protocol_info (im, IP_PROTOCOL_L2TP); - pi->unformat_pg_edit = unformat_pg_l2tp_header; - - lm->proto_registered = false; - - /* insure these nodes are included in build */ - l2tp_encap_init (vm); - - return 0; -} - -VLIB_INIT_FUNCTION (l2tp_init); - -clib_error_t * -l2tp_worker_init (vlib_main_t * vm) -{ - l2tp_encap_init (vm); - - return 0; -} - -VLIB_WORKER_INIT_FUNCTION (l2tp_worker_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/l2tp.h b/src/vnet/l2tp/l2tp.h deleted file mode 100644 index 49873380057..00000000000 --- a/src/vnet/l2tp/l2tp.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * l2tp.h : L2TPv3 tunnel support - * - * Copyright (c) 2013 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_l2tp_h__ -#define __included_l2tp_h__ - -#include -#include -#include - -typedef struct -{ - /* ip6 addresses */ - ip6_address_t our_address; - ip6_address_t client_address; - - /* l2tpv3 header parameters */ - u64 local_cookie[2]; - u64 remote_cookie; - u32 local_session_id; - u32 remote_session_id; - - /* tunnel interface */ - u32 hw_if_index; - u32 sw_if_index; - - /* fib index used for outgoing encapsulated packets */ - u32 encap_fib_index; - - u8 l2tp_hdr_size; - u8 l2_sublayer_present; - u8 cookie_flags; /* in host byte order */ - - u8 admin_up; -} l2t_session_t; - -typedef enum -{ - L2T_LOOKUP_SRC_ADDRESS = 0, - L2T_LOOKUP_DST_ADDRESS, - L2T_LOOKUP_SESSION_ID, -} ip6_to_l2_lookup_t; - -typedef struct -{ - /* session pool */ - l2t_session_t *sessions; - - /* ip6 -> l2 hash tables. Make up your minds, people... */ - uword *session_by_src_address; - uword *session_by_dst_address; - uword *session_by_session_id; - - ip6_to_l2_lookup_t lookup_type; - - /* Counters */ - vlib_combined_counter_main_t counter_main; - - /* vector of free l2tpv3 tunnel interfaces */ - u32 *free_l2tpv3_tunnel_hw_if_indices; - - /* show device instance by real device instance */ - u32 *dev_inst_by_real; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; - - bool proto_registered; - -} l2t_main_t; - -/* Packet trace structure */ -typedef struct -{ - int is_user_to_network; - u32 session_index; - ip6_address_t our_address; - ip6_address_t client_address; -} l2t_trace_t; - -extern l2t_main_t l2t_main; -extern vlib_node_registration_t l2t_encap_node; -extern vlib_node_registration_t l2t_decap_node; -extern vlib_node_registration_t l2t_decap_local_node; - -enum -{ - SESSION_COUNTER_USER_TO_NETWORK = 0, - SESSION_COUNTER_NETWORK_TO_USER, -}; - -static inline u32 -session_index_to_counter_index (u32 session_index, u32 counter_id) -{ - return ((session_index << 1) + counter_id); -} - -u8 *format_l2t_trace (u8 * s, va_list * args); - -typedef struct -{ - /* Any per-interface config would go here */ -} ip6_l2tpv3_config_t; - -uword unformat_pg_l2tp_header (unformat_input_t * input, va_list * args); - -void l2tp_encap_init (vlib_main_t * vm); -int create_l2tpv3_ipv6_tunnel (l2t_main_t * lm, - ip6_address_t * client_address, - ip6_address_t * our_address, - u32 local_session_id, - u32 remote_session_id, - u64 local_cookie, - u64 remote_cookie, - int l2_sublayer_present, - u32 encap_fib_index, u32 * sw_if_index); - -int l2tpv3_set_tunnel_cookies (l2t_main_t * lm, - u32 sw_if_index, - u64 new_local_cookie, u64 new_remote_cookie); - -int l2tpv3_interface_enable_disable (vnet_main_t * vnm, - u32 sw_if_index, int enable_disable); - -#endif /* __included_l2tp_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/l2tp_api.c b/src/vnet/l2tp/l2tp_api.c deleted file mode 100644 index 3a31372253f..00000000000 --- a/src/vnet/l2tp/l2tp_api.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - *------------------------------------------------------------------ - * l2tp_api.c - l2tpv3 api - * - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include -#include - -#include -#include -#include -#include - -#include - -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include -#undef vl_printfun - -#include - -#define foreach_vpe_api_msg \ -_(L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel) \ -_(L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies) \ -_(L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable) \ -_(L2TPV3_SET_LOOKUP_KEY, l2tpv3_set_lookup_key) \ -_(SW_IF_L2TPV3_TUNNEL_DUMP, sw_if_l2tpv3_tunnel_dump) - -static void -send_sw_if_l2tpv3_tunnel_details (vpe_api_main_t * am, - vl_api_registration_t * reg, - l2t_session_t * s, - l2t_main_t * lm, u32 context) -{ - vl_api_sw_if_l2tpv3_tunnel_details_t *mp; - u8 *if_name = NULL; - vnet_sw_interface_t *si = NULL; - - si = vnet_get_hw_sw_interface (lm->vnet_main, s->hw_if_index); - - if_name = format (if_name, "%U", - format_vnet_sw_interface_name, lm->vnet_main, si); - - mp = vl_msg_api_alloc (sizeof (*mp)); - clib_memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_SW_IF_L2TPV3_TUNNEL_DETAILS); - strncpy ((char *) mp->interface_name, - (char *) if_name, ARRAY_LEN (mp->interface_name) - 1); - mp->sw_if_index = ntohl (si->sw_if_index); - mp->local_session_id = s->local_session_id; - mp->remote_session_id = s->remote_session_id; - mp->local_cookie[0] = s->local_cookie[0]; - mp->local_cookie[1] = s->local_cookie[1]; - mp->remote_cookie = s->remote_cookie; - ip_address_encode ((ip46_address_t *) & s->client_address, IP46_TYPE_IP6, - &mp->client_address); - ip_address_encode ((ip46_address_t *) & s->our_address, IP46_TYPE_IP6, - &mp->our_address); - mp->l2_sublayer_present = s->l2_sublayer_present; - mp->context = context; - - vl_api_send_msg (reg, (u8 *) mp); -} - - -static void -vl_api_sw_if_l2tpv3_tunnel_dump_t_handler (vl_api_sw_if_l2tpv3_tunnel_dump_t * - mp) -{ - vpe_api_main_t *am = &vpe_api_main; - l2t_main_t *lm = &l2t_main; - vl_api_registration_t *reg; - l2t_session_t *session; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return; - - /* *INDENT-OFF* */ - pool_foreach (session, lm->sessions, - ({ - send_sw_if_l2tpv3_tunnel_details (am, reg, session, lm, mp->context); - })); - /* *INDENT-ON* */ -} - -static void vl_api_l2tpv3_create_tunnel_t_handler - (vl_api_l2tpv3_create_tunnel_t * mp) -{ - vl_api_l2tpv3_create_tunnel_reply_t *rmp; - l2t_main_t *lm = &l2t_main; - u32 sw_if_index = (u32) ~ 0; - int rv; - ip46_address_t client, our; - - if (mp->our_address.af == ADDRESS_IP4) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto out; - } - - u32 encap_fib_index; - - if (mp->encap_vrf_id != ~0) - { - uword *p; - ip6_main_t *im = &ip6_main; - if (! - (p = - hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)))) - { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; - } - encap_fib_index = p[0]; - } - else - { - encap_fib_index = ~0; - } - - ip_address_decode (&mp->client_address, &client); - ip_address_decode (&mp->our_address, &our); - - rv = create_l2tpv3_ipv6_tunnel (lm, - &client.ip6, - &our.ip6, - ntohl (mp->local_session_id), - ntohl (mp->remote_session_id), - clib_net_to_host_u64 (mp->local_cookie), - clib_net_to_host_u64 (mp->remote_cookie), - mp->l2_sublayer_present, - encap_fib_index, &sw_if_index); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_L2TPV3_CREATE_TUNNEL_REPLY, - ({ - rmp->sw_if_index = ntohl (sw_if_index); - })); - /* *INDENT-ON* */ -} - -static void vl_api_l2tpv3_set_tunnel_cookies_t_handler - (vl_api_l2tpv3_set_tunnel_cookies_t * mp) -{ - vl_api_l2tpv3_set_tunnel_cookies_reply_t *rmp; - l2t_main_t *lm = &l2t_main; - int rv; - - VALIDATE_SW_IF_INDEX (mp); - - rv = l2tpv3_set_tunnel_cookies (lm, ntohl (mp->sw_if_index), - clib_net_to_host_u64 (mp->new_local_cookie), - clib_net_to_host_u64 - (mp->new_remote_cookie)); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_L2TPV3_SET_TUNNEL_COOKIES_REPLY); -} - -static void vl_api_l2tpv3_interface_enable_disable_t_handler - (vl_api_l2tpv3_interface_enable_disable_t * mp) -{ - int rv; - vnet_main_t *vnm = vnet_get_main (); - vl_api_l2tpv3_interface_enable_disable_reply_t *rmp; - - VALIDATE_SW_IF_INDEX (mp); - - rv = l2tpv3_interface_enable_disable - (vnm, ntohl (mp->sw_if_index), mp->enable_disable); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_L2TPV3_INTERFACE_ENABLE_DISABLE_REPLY); -} - -static void vl_api_l2tpv3_set_lookup_key_t_handler - (vl_api_l2tpv3_set_lookup_key_t * mp) -{ - int rv = 0; - l2t_main_t *lm = &l2t_main; - vl_api_l2tpv3_set_lookup_key_reply_t *rmp; - - if (mp->key > L2T_LOOKUP_KEY_API_SESSION_ID) - { - rv = VNET_API_ERROR_INVALID_VALUE; - goto out; - } - - lm->lookup_type = (ip6_to_l2_lookup_t) mp->key; - -out: - REPLY_MACRO (VL_API_L2TPV3_SET_LOOKUP_KEY_REPLY); -} - -/* - * l2tp_api_hookup - * Add vpe's API message handlers to the table. - * vlib has already mapped shared memory and - * added the client registration handlers. - * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() - */ -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (api_main_t * am) -{ -#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); - foreach_vl_msg_name_crc_l2tp; -#undef _ -} - -static clib_error_t * -l2tp_api_hookup (vlib_main_t * vm) -{ - api_main_t *am = vlibapi_get_main (); - -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_vpe_api_msg; -#undef _ - - /* - * Set up the (msg_name, crc, message-id) table - */ - setup_message_id_table (am); - - return 0; -} - -VLIB_API_INIT_FUNCTION (l2tp_api_hookup); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/packet.h b/src/vnet/l2tp/packet.h deleted file mode 100644 index 66dfea2194c..00000000000 --- a/src/vnet/l2tp/packet.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * packet.h : L2TPv3 packet header format - * - * Copyright (c) 2013 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_l2tp_packet_h__ -#define __included_l2tp_packet_h__ - -/* - * See RFC4719 for packet format. - * Note: the l2_specific_sublayer is present in current Linux l2tpv3 - * tunnels. It is not present in IOS XR l2tpv3 tunnels. - * The Linux implementation is almost certainly wrong. - */ -/* *INDENT-OFF* */ -typedef CLIB_PACKED (struct -{ - u32 session_id; - u64 cookie; u32 - l2_specific_sublayer; /* set to 0 (if present) */ -}) l2tpv3_header_t; -/* *INDENT-ON* */ - -#endif /* __included_l2tp_packet_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/l2tp/pg.c b/src/vnet/l2tp/pg.c deleted file mode 100644 index 1e523d3bbb0..00000000000 --- a/src/vnet/l2tp/pg.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * pg.c: packet generator for L2TPv3 header - * - * Copyright (c) 2013 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 struct -{ - pg_edit_t session_id; - pg_edit_t cookie; -} pg_l2tp_header_t; - -typedef struct -{ - pg_edit_t l2_sublayer; -} pg_l2tp_header_l2_sublayer_t; - -static inline void -pg_l2tp_header_init (pg_l2tp_header_t * e) -{ - pg_edit_init (&e->session_id, l2tpv3_header_t, session_id); - pg_edit_init (&e->cookie, l2tpv3_header_t, cookie); -} - -uword -unformat_pg_l2tp_header (unformat_input_t * input, va_list * args) -{ - pg_stream_t *s = va_arg (*args, pg_stream_t *); - pg_l2tp_header_t *h; - u32 group_index, error; - vlib_main_t *vm = vlib_get_main (); - - h = pg_create_edit_group (s, sizeof (h[0]), - sizeof (l2tpv3_header_t) - sizeof (u32), - &group_index); - pg_l2tp_header_init (h); - - error = 1; - - /* session id and cookie are required */ - if (!unformat (input, "L2TP: session_id %U cookie %U", - unformat_pg_edit, unformat_pg_number, &h->session_id, - unformat_pg_edit, unformat_pg_number, &h->cookie)) - { - goto done; - } - - /* "l2_sublayer " is optional */ - if (unformat (input, "l2_sublayer")) - { - pg_l2tp_header_l2_sublayer_t *h2; - - h2 = pg_add_edits (s, sizeof (h2[0]), sizeof (u32), group_index); - pg_edit_init (&h2->l2_sublayer, l2tpv3_header_t, l2_specific_sublayer); - if (!unformat_user (input, unformat_pg_edit, - unformat_pg_number, &h2->l2_sublayer)) - { - goto done; - } - } - - /* Parse an ethernet header if it is present */ - { - pg_node_t *pg_node = 0; - vlib_node_t *eth_lookup_node; - - eth_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ethernet-input"); - ASSERT (eth_lookup_node); - - pg_node = pg_get_node (eth_lookup_node->index); - - if (pg_node && pg_node->unformat_edit - && unformat_user (input, pg_node->unformat_edit, s)) - ; - } - - error = 0; - -done: - if (error) - pg_free_edit_group (s); - return error == 0; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/vnet_all_api_h.h b/src/vnet/vnet_all_api_h.h index 9daf5e95b4d..86edc88ac49 100644 --- a/src/vnet/vnet_all_api_h.h +++ b/src/vnet/vnet_all_api_h.h @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 46beb685810..b17e7ded2b2 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -1429,100 +1428,6 @@ static void *vl_api_add_node_next_t_print FINISH; } -static void *vl_api_l2tpv3_create_tunnel_t_print - (vl_api_l2tpv3_create_tunnel_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: l2tpv3_create_tunnel "); - - s = format (s, "client_address %U our_address %U ", - format_ip6_address, - (ip6_address_t *) (mp->client_address.un.ip6), - format_ip6_address, (ip6_address_t *) (mp->our_address.un.ip6)); - s = format (s, "local_session_id %d ", (mp->local_session_id)); - s = format (s, "remote_session_id %d ", (mp->remote_session_id)); - s = format (s, "local_cookie %lld ", - clib_net_to_host_u64 (mp->local_cookie)); - s = format (s, "remote_cookie %lld ", - clib_net_to_host_u64 (mp->remote_cookie)); - if (mp->l2_sublayer_present) - s = format (s, "l2-sublayer-present "); - - FINISH; -} - -static void *vl_api_l2tpv3_set_tunnel_cookies_t_print - (vl_api_l2tpv3_set_tunnel_cookies_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: l2tpv3_set_tunnel_cookies "); - - s = format (s, "sw_if_index %d ", (mp->sw_if_index)); - - s = format (s, "new_local_cookie %llu ", - clib_net_to_host_u64 (mp->new_local_cookie)); - - s = format (s, "new_remote_cookie %llu ", - clib_net_to_host_u64 (mp->new_remote_cookie)); - - FINISH; -} - -static void *vl_api_l2tpv3_interface_enable_disable_t_print - (vl_api_l2tpv3_interface_enable_disable_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: l2tpv3_interface_enable_disable "); - - s = format (s, "sw_if_index %d ", (mp->sw_if_index)); - - if (mp->enable_disable == 0) - s = format (s, "del "); - - FINISH; -} - -static void *vl_api_l2tpv3_set_lookup_key_t_print - (vl_api_l2tpv3_set_lookup_key_t * mp, void *handle) -{ - u8 *s; - char *str = "unknown"; - - s = format (0, "SCRIPT: l2tpv3_set_lookup_key "); - - switch (mp->key) - { - case L2T_LOOKUP_SRC_ADDRESS: - str = "lookup_v6_src"; - break; - case L2T_LOOKUP_DST_ADDRESS: - str = "lookup_v6_dst"; - break; - case L2T_LOOKUP_SESSION_ID: - str = "lookup_session_id"; - break; - default: - break; - } - - s = format (s, "%s ", str); - - FINISH; -} - -static void *vl_api_sw_if_l2tpv3_tunnel_dump_t_print - (vl_api_sw_if_l2tpv3_tunnel_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: sw_if_l2tpv3_tunnel_dump "); - - FINISH; -} - static void *vl_api_vxlan_add_del_tunnel_t_print (vl_api_vxlan_add_del_tunnel_t * mp, void *handle) { @@ -3552,11 +3457,6 @@ _(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(ADD_NODE_NEXT, add_node_next) \ -_(L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel) \ -_(L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies) \ -_(L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable) \ -_(L2TPV3_SET_LOOKUP_KEY, l2tpv3_set_lookup_key) \ -_(SW_IF_L2TPV3_TUNNEL_DUMP, sw_if_l2tpv3_tunnel_dump) \ _(VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \ _(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \ _(VXLAN_OFFLOAD_RX, vxlan_offload_rx) \ diff --git a/test/test_l2tp.py b/test/test_l2tp.py deleted file mode 100644 index c57b5912de1..00000000000 --- a/test/test_l2tp.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 - -import unittest - -from scapy.layers.l2 import Ether -from scapy.layers.inet6 import IPv6 - -from framework import VppTestCase - - -class TestL2tp(VppTestCase): - """ L2TP Test Case """ - - @classmethod - def setUpClass(cls): - super(TestL2tp, cls).setUpClass() - - cls.create_pg_interfaces(range(1)) - cls.pg0.admin_up() - cls.pg0.config_ip6() - - def test_l2tp_decap_local(self): - """ L2TP don't accept packets unless configured """ - - pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=115)) - - self.pg0.add_stream(pkt) - self.pg_start() - - # l2tp should not accept packets - err = self.statistics.get_counter( - '/err/l2tp-decap-local/l2tpv3 session not found')[0] - self.assertEqual(err, 0) - err_count = err - - self.vapi.l2tpv3_create_tunnel(client_address=self.pg0.local_ip6, - our_address=self.pg0.remote_ip6) - - self.pg0.add_stream(pkt) - self.pg_start() - - # l2tp accepts packets - err = self.statistics.get_counter( - '/err/l2tp-decap-local/l2tpv3 session not found')[0] - self.assertEqual(err, 1) - err_count = err -- cgit 1.2.3-korg