/* * ipip.c: ipip * * 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 aipiped 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 #include ipip_main_t ipip_main; /* Packet trace structure */ typedef struct { u32 tunnel_id; u32 length; ip46_address_t src; ip46_address_t dst; } ipip_tx_trace_t; u8 * format_ipip_tx_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 *); ipip_tx_trace_t *t = va_arg (*args, ipip_tx_trace_t *); s = format (s, "IPIP: tunnel %d len %d src %U dst %U", t->tunnel_id, t->length, format_ip46_address, &t->src, IP46_TYPE_ANY, format_ip46_address, &t->dst, IP46_TYPE_ANY); return s; } static u8 * ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address) { ip4_header_t *ip4; ip6_header_t *ip6; u8 *rewrite = NULL; ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index); if (!t) /* not one of ours */ return (0); switch (t->transport) { case IPIP_TRANSPORT_IP4: vec_validate (rewrite, sizeof (*ip4) - 1); ip4 = (ip4_header_t *) rewrite; ip4->ip_version_and_header_length = 0x45; ip4->ttl = 64; /* fixup ip4 header length, protocol and checksum after-the-fact */ ip4->src_address.as_u32 = t->tunnel_src.ip4.as_u32; ip4->dst_address.as_u32 = t->tunnel_dst.ip4.as_u32; ip4->checksum = ip4_header_checksum (ip4); if (t->tc_tos != 0xFF) ip4->tos = t->tc_tos; break; case IPIP_TRANSPORT_IP6: vec_validate (rewrite, sizeof (*ip6) - 1); ip6 = (ip6_header_t *) rewrite; ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (6 << 28); if (t->tc_tos != 0xFF) ip6_set_traffic_class_network_order (ip6, t->tc_tos); ip6->hop_limit = 64; /* fixup ip6 header length and protocol after-the-fact */ ip6->src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0]; ip6->src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1]; ip6->dst_address.as_u64[0] = t->tunnel_dst.ip6.as_u64[0]; ip6->dst_address.as_u64[1] = t->tunnel_dst.ip6.as_u64[1]; break; default: /* pass through */ ; } return (rewrite); } static void ipip4_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b, const void *data) { ip4_header_t *ip4; const ipip_tunnel_t *t = data; ip4 = vlib_buffer_get_current (b); ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)); switch (adj->ia_link) { case VNET_LINK_IP6: ip4->protocol = IP_PROTOCOL_IPV6; if (t->tc_tos == 0xFF) ip4->tos = ip6_traffic_class_network_order ((const ip6_header_t *) (ip4 + 1)); break; case VNET_LINK_IP4: ip4->protocol = IP_PROTOCOL_IP_IN_IP; if (t->tc_tos == 0xFF) ip4->tos = ((ip4_header_t *) (ip4 + 1))->tos; break; default: break; } ip4->checksum = ip4_header_checksum (ip4); } static void ipip6_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b, const void *data) { ip6_header_t *ip6; const ipip_tunnel_t *t = data; /* Must set locally originated otherwise we're not allowed to fragment the packet later */ b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; ip6 = vlib_buffer_get_current (b); ip6->payload_length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip6)); switch (adj->ia_link) { case VNET_LINK_IP6: ip6->protocol = IP_PROTOCOL_IPV6; if (t->tc_tos == 0xFF) ip6_set_traffic_class_network_order (ip6, ip6_traffic_class_network_order ((const ip6_header_t *) (ip6 + 1))); break; case VNET_LINK_IP4: ip6->protocol = IP_PROTOCOL_IP_IN_IP; if (t->tc_tos == 0xFF) ip6_set_traffic_class_network_order (ip6, ((ip4_header_t *) (ip6 + 1))->tos); break; default: break; } } static void ipip_tunnel_stack (adj_index_t ai) { ip_adjacency_t *adj; ipip_tunnel_t *t; u32 sw_if_index; adj = adj_get (ai); sw_if_index = adj->rewrite_header.sw_if_index; t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index); if (!t) return; if ((vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0) { adj_nbr_midchain_unstack (ai); } else { adj_nbr_midchain_stack_on_fib_entry (ai, t->p2p.fib_entry_index, (t->transport == IPIP_TRANSPORT_IP6) ? FIB_FORW_CHAIN_TYPE_UNICAST_IP6 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4); } } static adj_walk_rc_t ipip_adj_walk_cb (adj_index_t ai, void *ctx) { ipip_tunnel_stack (ai); return (ADJ_WALK_RC_CONTINUE); } static void ipip_tunnel_restack (ipip_tunnel_t * gt) { fib_protocol_t proto; /* * walk all the adjacencies on th IPIP interface and restack them */ FOR_EACH_FIB_IP_PROTOCOL (proto) { adj_nbr_walk (gt->sw_if_index, proto, ipip_adj_walk_cb, NULL); } } void ipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai) { adj_midchain_fixup_t f; ipip_tunnel_t *t; adj_flags_t af; t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index); if (!t) return;
/** \file
    This file defines static http server control-plane API messages
*/
option version = "2.1.0";

/** \brief Configure and enable the static http server
    @param client_index - opaque cookie to identify the sender
    @param context - sender context, to match reply w/ request
    @param fifo_size - size (in bytes) of the sessio