/* * 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
/*
 * Copyright (c) 2015 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.
 */
vxlan_error (DECAPSULATED, "good packets decapsulated")
vxlan_error (NO_SUCH_TUNNEL, "no such tunnel packets")
vxlan_error (BAD_FLAGS, "packets with bad flags field in vxlan header")
_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: */