/* * 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 /* * A table of pefixes to be added to tables and the sources for them */ typedef struct ip4_fib_table_special_prefix_t_ { fib_prefix_t ift_prefix; fib_source_t ift_source; fib_entry_flag_t ift_flag; } ip4_fib_table_special_prefix_t; static const ip4_fib_table_special_prefix_t ip4_specials[] = { { /* 0.0.0.0/0*/ .ift_prefix = { .fp_addr = { .ip4.data_u32 = 0, }, .fp_len = 0, .fp_proto = FIB_PROTOCOL_IP4, }, .ift_source = FIB_SOURCE_DEFAULT_ROUTE, .ift_flag = FIB_ENTRY_FLAG_DROP, }, { /* 0.0.0.0/32*/ .ift_prefix = { .fp_addr = { .ip4.data_u32 = 0, }, .fp_len = 32, .fp_proto = FIB_PROTOCOL_IP4, }, .ift_source = FIB_SOURCE_DEFAULT_ROUTE, .ift_flag = FIB_ENTRY_FLAG_DROP, }, { /* * 240.0.0.0/4 * drop class E */ .ift_prefix = { .fp_addr = { .ip4.data_u32 = 0xf0000000, }, .fp_len = 4, .fp_proto = FIB_PROTOCOL_IP4, }, .ift_source = FIB_SOURCE_SPECIAL, .ift_flag = FIB_ENTRY_FLAG_DROP, }, { /* * 224.0.0.0/4 * drop all mcast */ .ift_prefix = { .fp_addr = { .ip4.data_u32 = 0xe0000000, }, .fp_len = 4, .fp_proto = FIB_PROTOCOL_IP4, }, .ift_source = FIB_SOURCE_SPECIAL, .ift_flag = FIB_ENTRY_FLAG_DROP, }, { /* * 255.255.255.255/32 * drop, but we'll allow it to be usurped by the likes of DHCP */ .ift_prefix = { .fp_addr = { .ip4.data_u32 = 0xffffffff, }, .fp_len = 32, .fp_proto = FIB_PROTOCOL_IP4, }, .ift_source = FIB_SOURCE_DEFAULT_ROUTE, .ift_flag = FIB_ENTRY_FLAG_DROP, } }; static u32 ip4_create_fib_with_table_id (u32 table_id, fib_source_t src) { fib_table_t *fib_table; ip4_fib_t *v4_fib; void *old_heap; pool_get_aligned(ip4_main.fibs, fib_table, CLIB_CACHE_LINE_BYTES); memset(fib_table, 0, sizeof(*fib_table)); old_heap = clib_mem_set_heap (ip4_main.mtrie_mheap); pool_get_aligned(ip4_main.v4_fibs, v4_fib, CLIB_CACHE_LINE_BYTES); clib_mem_set_heap (old_heap); ASSERT((fib_table - ip4_main.fibs) == (v4_fib - ip4_main.v4_fibs)); fib_table->ft_proto = FIB_PROTOCOL_IP4; fib_table->ft_index = v4_fib->index = (fib_table - ip4_main.fibs); hash_set (ip4_main.fib_index_by_table_id, table_id, fib_table->ft_index); fib_table->ft_table_id = v4_fib->table_id = table_id; fib_table->ft_flow_hash_config = IP_FLOW_HASH_DEFAULT; v4_fib->fwd_classify_table_index = ~0; v4_fib->rev_classify_table_index = ~0; fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_IP4, src); ip4_mtrie_init(&v4_fib->mtrie); /* * add the special entries into the new FIB */ int ii; for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++) { fib_prefix_t prefix = ip4_specials[ii].ift_prefix; prefix.fp_addr.ip4.data_u32 = clib_host_to_net_u32(prefix.fp_addr.ip4.data_u32); fib_table_entry_special_add(fib_table->ft_index, &prefix, ip4_specials[ii].ift_source, ip4_specials[ii].ift_flag); } return (fib_table->ft_index); } void ip4_fib_table_destroy (u32 fib_index) { fib_table_t *fib_table = pool_elt_at_index(ip4_main.fibs, fib_index); ip4_fib_t *v4_fib = pool_elt_at_index(ip4_main.v4_fibs, fib_index); int ii; /* * remove all the specials we added when the table was created. * In reverse order so the default route is last. */ for (ii = ARRAY_LEN(ip4_specials) - 1; ii >= 0; ii--) { fib_prefix_t prefix = ip4_specials[ii].ift_prefix; prefix.fp_addr.ip4.data_u32 = clib_host_to_net_u32(prefix.fp_addr.ip4.data_u32); fib_table_entry_special_remove(fib_table->ft_index, &prefix, ip4_specials[ii].ift_source); } /* * validate no more routes. */ ASSERT(0 == fib_table->ft_total_route_counts); FOR_EACH_FIB_SOURCE(ii) { ASSERT(0 == fib_table->ft_src_route_counts[ii]); } if (~0 != fib_table->ft_table_id) { hash_unset (ip4_main.fib_index_by_table_id, fib_table->ft_table_id); } ip4_mtrie_free(&v4_fib->mtrie); pool_put(ip4_main.v4_fibs, v4_fib); pool_put(ip4_main.fibs, fib_table); } u32 ip4_fib_table_find_or_create_and_lock (u32 table_id, fib_source_t src) { u32 index; index = ip4_fib_index_from_table_id(table_id); if (~0 == index) return ip4_create_fib_with_table_id(table_id, src); fib_table_lock(index, FIB_PROTOCOL_IP4, src); return (index); } u32 ip4_fib_table_create_and_lock (fib_source_t src) { return (ip4_create_fib_with_table_id(~0, src)); } u32 ip4_fib_table_get_index_for_sw_if_index (u32 sw_if_index) { if (sw_if_index >= vec_len(ip4_main.fib_index_by_sw_if_index)) { /* * This is the case for interfaces that are not yet mapped to * a IP table */ return (~0); } return (ip4_main.fib_index_by_sw_if_index[sw_if_index]); } /* * ip4_fib_table_lookup_exact_match * * Exact match prefix lookup */ fib_node_index_t ip4_fib_table_lookup_exact_match (const ip4_fib_t *fib, const ip4_address_t *addr, u32 len) { uword * hash, * result; u32 key; hash = fib->fib_entry_by_dst_address[len]; key = (addr->data_u32 & ip4_main.fib_masks[len]); result = hash_get(hash, key); if (NULL != result) { return (result[0]); } return (FIB_NODE_INDEX_INVALID); } /* * ip4_fib_table_lookup_adj * * Longest prefix match */ index_t ip4_fib_table_lookup_lb (ip4_fib_t *fib, const ip4_address_t *addr) { fib_node_index_t fei; fei = ip4_fib_table_lookup(fib, addr, 32); if (FIB_NODE_INDEX_INVALID != fei) { const dpo_id_t *dpo; dpo = fib_entry_contribute_ip_forwarding(fei); return (dpo->dpoi_index); } return (INDEX_INVALID); } /* * ip4_fib_table_lookup * * Longest prefix match */ fib_node_index_t ip4_fib_table_lookup (const ip4_fib_t *fib, const ip4_address_t *addr, u32 len) { uword * hash, * result; i32 mask_len; u32 key; for (mask_len = len; mask_len >= 0; mask_len--) { hash = fib->fib_entry_by_dst_address[mask_len]; key = (addr->data_u32 & ip4_main.fib_masks[mask_len]); result = hash_get (hash, key); if (NULL != result) { return (result[0]); } } return (FIB_NODE_INDEX_INVALID); } void ip4_fib_table_entry_insert (ip4_fib_t *fib, const ip4_address_t *addr, u32 len, fib_node_index_t fib_entry_index) { uword * hash, * result; u32 key; key = (addr->data_u32 & ip4_main.fib_masks[len]); hash = fib->fib_entry_by_dst_address[len]; result = hash_get (hash, key); if (NULL == result) { /* * adding a new entry */ uword *old_heap; old_heap = clib_mem_set_heap (ip4_main.mtrie_mheap); if (NULL == hash) { hash = hash_create (32 /* elts */, sizeof (uword)); hash_set_flags (hash, HASH_FLAG_NO_AUTO_SHRINK); } hash = hash_set(hash, key, fib_entry_index); fib->fib_entry_by_dst_address[len] = hash; clib_mem_set_heap (old_heap); } else { ASSERT(0); } } void ip4_fib_table_entry_remove (ip4_fib_t *fib, const ip4_address_t *addr, u32 len) { uword * hash, * result; u32 key; key = (addr->data_u32 & ip4_main.fib_masks[len]); hash = fib->fib_entry_by_dst_address[len]; result = hash_get (hash, key); if (NULL == result) { /* * removing a non-existant entry. i'll allow it. */ } else { uword *old_heap; old_heap = clib_mem_set_heap (ip4_main.mtrie_mheap); hash_unset(hash, key); clib_mem_set_heap (old_heap); } fib->fib_entry_by_dst_address[len] = hash; } void ip4_fib_table_fwding_dpo_update (ip4_fib_t *fib, const ip4_address_t *addr, u32 len, const dpo_id_t *dpo) { ip4_fib_mtrie_route_add(&fib->mtrie, addr, len, dpo->dpoi_index); } void ip4_fib_table_fwding_dpo_remove (ip4_fib_t *fib, const ip4_address_t *addr, u32 len, const dpo_id_t *dpo, u32 cover_index) { fib_prefix_t cover_prefix = { .fp_len = 0, }; const dpo_id_t *cover_dpo; /* * We need to pass the MTRIE the LB index and address length of the * covering prefix, so it can fill the plys with the correct replacement * for the entry being removed */ fib_entry_get_prefix(cover_index, &cover_prefix); cover_dpo = fib_entry_contribute_ip_forwarding(cover_index); ip4_fib_mtrie_route_del(&fib->mtrie, addr, len, dpo->dpoi_index, cover_prefix.fp_len, cover_dpo->dpoi_index); } void ip4_fib_table_walk (ip4_fib_t *fib, fib_table_walk_fn_t fn, void *ctx) { fib_prefix_t root = { .fp_proto = FIB_PROTOCOL_IP4, // address and length default to all 0 }; /* * A full tree walk is the dengenerate case of a sub-tree from * the very root */ return (ip4_fib_table_sub_tree_walk(fib, &root, fn, ctx)); } void ip4_fib_table_sub_tree_walk (ip4_fib_t *fib, const fib_prefix_t *root, fib_table_walk_fn_t fn, void *ctx) { fib_prefix_t *sub_trees = NULL; int i; /* * There is no efficent way to walk this array of hash tables. * so we walk each table with a mask length greater than and equal to * the required root and check it is covered by the root. */ for (i = root->fp_len; i < ARRAY_LEN (fib->fib_entry_by_dst_address); i++) { uword * hash = fib->fib_entry_by_dst_address[i]; if (NULL != hash) { ip4_address_t key; hash_pair_t * p; hash_foreach_pair (p, hash, ({ key.as_u32 = p->key; if (ip4_destination_matches_route(&ip4_main, &key, &root->fp_addr.ip4, root->fp_len)) { const fib_prefix_t *sub_tree; int skip = 0; /* * exclude sub-trees the walk does not want to explore */ vec_foreach(sub_tree, sub_trees) { if (ip4_destination_matches_route(&ip4_main, &key, &sub_tree->fp_addr.ip4, sub_tree->fp_len)) { skip = 1; break; } } if (!skip) { switch (fn(p->value[0], ctx))
/*
 * 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.
 */
/*
  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.
*/

#include <vppinfra/elf.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#ifndef CLIB_UNIX
#error "unix only"
#endif

static clib_error_t *
elf_set_interpreter (elf_main_t * em, char *interp)
{
  elf_segment_t *g;
  elf_section_t *s;
  clib_error_t *error;

  vec_foreach (g, em->segments)
  {
    if (g->header.type == ELF_SEGMENT_INTERP)
      break;
  }

  if (g >= vec_end (em->segments))
    return clib_error_return (0, "interpreter not found");

  if (g->header.memory_size < 1 + strlen (interp))
    return clib_error_return (0,
			      "given interpreter does not fit; must be less than %d bytes (`%s' given)",
			      g->header.memory_size, interp);

  error =
    elf_get_section_by_start_address (em, g->header.virtual_address, &s);
  if (error)
    return error;

  /* Put in new null terminated string. */
  clib_memset (s->contents, 0, vec_len (s->contents));
  clib_memcpy (s->contents, interp, strlen (interp));

  return