/* * 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 ip6_fib_table_instance_t ip6_fib_table[IP6_FIB_NUM_TABLES]; /* ip6 lookup table config parameters */ u32 ip6_fib_table_nbuckets; uword ip6_fib_table_size; static void vnet_ip6_fib_init (u32 fib_index) { fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP6, .fp_len = 0, .fp_addr = { .ip6 = { { 0, 0, }, }, } }; /* * Add the default route. */ fib_table_entry_special_add(fib_index, &pfx, FIB_SOURCE_DEFAULT_ROUTE, FIB_ENTRY_FLAG_DROP); /* * all link local via the link local lookup DPO */ pfx.fp_addr.ip6.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL); pfx.fp_addr.ip6.as_u64[1] = 0; pfx.fp_len = 10; fib_table_entry_special_dpo_add(fib_index, &pfx, FIB_SOURCE_SPECIAL, FIB_ENTRY_FLAG_NONE, ip6_ll_dpo_get()); } static u32 create_fib_with_table_id (u32 table_id, fib_source_t src, fib_table_flags_t flags, u8 *desc) { fib_table_t *fib_table; ip6_fib_t *v6_fib; pool_get(ip6_main.fibs, fib_table); pool_get_aligned(ip6_main.v6_fibs, v6_fib, CLIB_CACHE_LINE_BYTES); clib_memset(fib_table, 0, sizeof(*fib_table)); clib_memset(v6_fib, 0, sizeof(*v6_fib)); ASSERT((fib_table - ip6_main.fibs) == (v6_fib - ip6_main.v6_fibs)); fib_table->ft_proto = FIB_PROTOCOL_IP6; fib_table->ft_index = v6_fib->index = (fib_table - ip6_main.fibs); hash_set(ip6_main.fib_index_by_table_id, table_id, fib_table->ft_index); fib_table->ft_table_id = v6_fib->table_id = table_id; fib_table->ft_flow_hash_config = IP_FLOW_HASH_DEFAULT; fib_table->ft_flags = flags; fib_table->ft_desc = desc; vnet_ip6_fib_init(fib_table->ft_index); fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_IP6, src); return (fib_table->ft_index); } u32 ip6_fib_table_find_or_create_and_lock (u32 table_id, fib_source_t src) { uword * p; p = hash_get (ip6_main.fib_index_by_table_id, table_id); if (NULL == p) return create_fib_with_table_id(table_id, src, FIB_TABLE_FLAG_NONE, NULL); fib_table_lock(p[0], FIB_PROTOCOL_IP6, src); return (p[0]); } u32 ip6_fib_table_create_and_lock (fib_source_t src, fib_table_flags_t flags, u8 *desc) { return (create_fib_with_table_id(~0, src, flags, desc)); } void ip6_fib_table_destroy (u32 fib_index) { /* * all link local first ... */ fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP6, .fp_len = 10, .fp_addr = { .ip6 = { .as_u8 = { [0] = 0xFE, [1] = 0x80, }, }, } }; fib_table_entry_delete(fib_index, &pfx, FIB_SOURCE_SPECIAL); /* * ... then the default route. */ pfx.fp_addr.ip6.as_u64[0] = 0; pfx.fp_len = 00; fib_table_entry_special_remove(fib_index, &pfx, FIB_SOURCE_DEFAULT_ROUTE); fib_table_t *fib_table = fib_table_get(fib_index, FIB_PROTOCOL_IP6); fib_source_t source; /* * validate no more routes. */ #if CLIB_DEBUG > 0 if (0 != fib_table->ft_total_route_counts) fib_table_assert_empty(fib_table); #endif vec_foreach_index(source, fib_table->ft_src_route_counts) { ASSERT(0 == fib_table->ft_src_route_counts[source]); } if (~0 != fib_table->ft_table_id) { hash_unset (ip6_main.fib_index_by_table_id, fib_table->ft_table_id); } vec_free(fib_table->ft_src_route_counts); pool_put_index(ip6_main.v6_fibs, fib_table->ft_index); pool_put(ip6_main.fibs, fib_table); } fib_node_index_t ip6_fib_table_lookup (u32 fib_index, const ip6_address_t *addr, u32 len) { ip6_fib_table_instance_t *table; clib_bihash_kv_24_8_t kv, value; int i, n_p, rv; u64 fib; table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING]; n_p = vec_len (table->prefix_lengths_in_search_order); kv.key[0] = addr->as_u64[0]; kv.key[1] = addr->as_u64[1]; fib = ((u64)((fib_index))<<32); /* * start search from a mask length same length or shorter. * we don't want matches longer than the mask passed */ i = 0; while (i < n_p && table->prefix_lengths_in_search_order[i] > len) { i++; } for (; i < n_p; i++) { int dst_address_length = table->prefix_lengths_in_search_order[i]; ip6_address_t * mask = &ip6_main.fib_masks[dst_address_length]; ASSERT(dst_address_length >= 0 && dst_address_length <= 128); //As lengths are decreasing, masks are increasingly specific. kv.key[0] &= mask->as_u64[0]; kv.key[1] &= mask->as_u64[1]; kv.key[2] = fib | dst_address_length; rv = clib_bihash_search_inline_2_24_8(&table->ip6_hash, &kv, &value); if (rv == 0) return value.value; } return (FIB_NODE_INDEX_INVALID); } fib_node_index_t ip6_fib_table_lookup_exact_match (u32 fib_index, const ip6_address_t *addr, u32 len) { ip6_fib_table_instance_t *table; clib_bihash_kv_24_8_t kv, value; ip6_address_t *mask; u64 fib; int rv; table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; rv = clib_bihash_search_inline_2_24_8(&table->ip6_hash, &kv, &value); if (rv == 0) return value.value; return (FIB_NODE_INDEX_INVALID); } static void compute_prefix_lengths_in_search_order (ip6_fib_table_instance_t *table) { u8 *old, *prefix_lengths_in_search_order = NULL; int i; /* * build the list in a scratch space then cutover so the workers * can continue uninterrupted. */ old = table->prefix_lengths_in_search_order; /* Note: bitmap reversed so this is in fact a longest prefix match */ clib_bitmap_foreach (i, table->non_empty_dst_address_length_bitmap) { int dst_address_length = 128 - i; vec_add1(prefix_lengths_in_search_order, dst_address_length); } table->prefix_lengths_in_search_order = prefix_lengths_in_search_order; /* * let the workers go once round the track before we free the old set */ vlib_worker_wait_one_loop(); vec_free(old); } void ip6_fib_table_entry_remove (u32 fib_index, const ip6_address_t *addr, u32 len) { ip6_fib_table_instance_t *table; clib_bihash_kv_24_8_t kv; ip6_address_t *mask; u64 fib; table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 0); /* refcount accounting */ ASSERT (table->dst_address_length_
/*
 * 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.
 */
/*
 * interface_output.c: interface output node
 *
 * Copyright (c) 2008 Eliot Dresselhaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __INTERFACE_INLINES_H__
#define __INTERFACE_INLINES_H__

#include <vnet/vnet.h>

static_always_inline void
calc_checksums (vlib_main_t * vm, vlib_buffer_t * b)
{
  ip4_header_t *ip4;
  ip6_header_t *ip6;
  tcp_header_t *th;
  udp_header_t *uh;

  int is_ip4 = (b->flags & VNET_BUFFER_F_IS_IP4) != 0;
  int is_ip6 = (b->flags & VNET_BUFFER_F_IS_IP6) != 0;

  ASSERT (!(is_ip4 && is_ip6));

  ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
  ip6 = (ip6_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
  th = (tcp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset);
  uh = (udp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset);

  if (is_ip4)
    {
      ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
      if (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
	ip4->checksum = ip4_header_checksum (ip4);
      if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
	{
	  th->checksum = 0;
	  th->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
	}
      if (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)