aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/fib/fib_entry_src_rr.c
blob: 9f4f68d88f58d71e04313b137d5c74ba98681f9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
 * 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) 2001, 2002, 2003 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 included_vm_unix_h
#define included_vm_unix_h

#include <unistd.h>
#include <sys/mman.h>

/* Allocate virtual address space. */
always_inline void *
clib_mem_vm_alloc (uword size)
{
  void *mmap_addr;
  uword flags = MAP_PRIVATE;

#ifdef MAP_ANONYMOUS
  flags |= MAP_ANONYMOUS;
#endif

  mmap_addr = mmap (0, size, PROT_READ | PROT_WRITE, flags, -1, 0);
  if (mmap_addr == (void *) -1)
    mmap_addr = 0;

  return mmap_addr;
}

always_inline void
clib_mem_vm_free (void *addr, uword size)
{
  munmap (addr, size);
}

always_inline void *
clib_mem_vm_unmap (void *addr, uword size)
{
  void *mmap_addr;
  uword flags = MAP_PRIVATE | MAP_FIXED;

  /* To unmap we "map" with no protection.  If we actually called
     munmap then other callers could steal the address space.  By
     changing to PROT_NONE the kernel can free up the pages which is
     really what we want "unmap" to mean. */
  mmap_addr = mmap (addr, size, PROT_NONE, flags, -1, 0);
  if (mmap_addr == (void *) -1)
    mmap_addr = 0;

  return mmap_addr;
}

always_inline void *
clib_mem_vm_map (void *addr, uword size)
{
  void *mmap_addr;
  uword flags = MAP_PRIVATE | MAP_FIXED;

  mmap_addr = mmap (addr, size, (PROT_READ | PROT_WRITE), flags, -1, 0);
  if (mmap_addr == (void *) -1)
    mmap_addr = 0;

  return mmap_addr;
}

#endif /* included_vm_unix_h */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
* fib_entry_src_rr_resolve_via_connected * * Resolve via a connected cover. */ void fib_entry_src_rr_resolve_via_connected (fib_entry_src_t *src, const fib_entry_t *fib_entry, const fib_entry_t *cover) { const fib_route_path_t path = { .frp_proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto), .frp_addr = fib_entry->fe_prefix.fp_addr, .frp_sw_if_index = fib_entry_get_resolving_interface( fib_entry_get_index(cover)), .frp_fib_index = ~0, .frp_weight = 1, }; fib_route_path_t *paths = NULL; vec_add1(paths, path); /* * since the cover is connected, the address this entry corresponds * to is a peer (ARP-able for) on the interface to which the cover is * connected. The fact we resolve via the cover, just means this RR * source is the first SRC to use said peer. The ARP source will be along * shortly to over-rule this RR source. */ src->fes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NONE, paths); src->fes_entry_flags |= (fib_entry_get_flags(fib_entry_get_index(cover)) & FIB_ENTRY_FLAGS_RR_INHERITED); vec_free(paths); } /** * Source initialisation Function */ static void fib_entry_src_rr_init (fib_entry_src_t *src) { src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID; src->u.rr.fesr_sibling = FIB_NODE_INDEX_INVALID; } /* * use the path-list of the cover, unless it would form a loop. * that is unless the cover is via this entry. * If a loop were to form it would be a 1 level loop (i.e. X via X), * and there would be 2 locks on the path-list; one since its used * by the cover, and 1 from here. The first lock will go when the * cover is removed, the second, and last, when the covered walk * occurs during the cover's removal - this is not a place where * we can handle last lock gone. * In short, don't let the loop form. The usual rules of 'we must * let it form so we know when it breaks' don't apply here, since * the loop will break when the cover changes, and this function * will be called again when that happens. */ void fib_entry_src_rr_use_covers_pl (fib_entry_src_t *src, const fib_entry_t *fib_entry, const fib_entry_t *cover) { fib_node_index_t *entries = NULL; dpo_proto_t proto; proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto); vec_add1(entries, fib_entry_get_index(fib_entry)); if (fib_path_list_recursive_loop_detect(cover->fe_parent, &entries)) { src->fes_pl = fib_path_list_create_special(proto, FIB_PATH_LIST_FLAG_DROP, drop_dpo_get(proto)); } else { src->fes_pl = cover->fe_parent; } vec_free(entries); } /* * Source activation. Called when the source is the new best source on the entry */ static int fib_entry_src_rr_activate (fib_entry_src_t *src, const fib_entry_t *fib_entry) { fib_entry_t *cover; /* * find the covering prefix. become a dependent thereof. * for IP there should always be a cover, though it may be the default route. * For MPLS there is never a cover. */ if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto) { src->fes_pl = fib_path_list_create_special(DPO_PROTO_MPLS, FIB_PATH_LIST_FLAG_DROP, NULL); fib_path_list_lock(src->fes_pl); return (!0); } src->u.rr.fesr_cover = fib_table_get_less_specific(fib_entry->fe_fib_index, &fib_entry->fe_prefix); ASSERT(FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover); cover = fib_entry_get(src->u.rr.fesr_cover); src->u.rr.fesr_sibling = fib_entry_cover_track(cover, fib_entry_get_index(fib_entry)); /* * if the cover is attached then install an attached-host path * (like an adj-fib). Otherwise inherit the forwarding from the cover */ if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover)) { fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover); } else { fib_entry_src_rr_use_covers_pl(src, fib_entry, cover); } fib_path_list_lock(src->fes_pl); /* * return go for install */ return (!0); } /** * Source Deactivate. * Called when the source is no longer best source on the entry */ static void fib_entry_src_rr_deactivate (fib_entry_src_t *src, const fib_entry_t *fib_entry) { fib_entry_t *cover; /* * remove the dependency on the covering entry */ if (FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover) { fib_node_index_t *entries = NULL; cover = fib_entry_get(src->u.rr.fesr_cover); fib_entry_cover_untrack(cover, src->u.rr.fesr_sibling); src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID; if (FIB_NODE_INDEX_INVALID != cover->fe_parent) { fib_path_list_recursive_loop_detect(cover->fe_parent, &entries); vec_free(entries); } } fib_path_list_unlock(src->fes_pl); src->fes_pl = FIB_NODE_INDEX_INVALID; src->fes_entry_flags = FIB_ENTRY_FLAG_NONE; } fib_entry_src_cover_res_t fib_entry_src_rr_cover_change (fib_entry_src_t *src, const fib_entry_t *fib_entry) { fib_entry_src_cover_res_t res = { .install = !0, .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE, }; if (FIB_NODE_INDEX_INVALID == src->u.rr.fesr_cover) { /* * the source may be added, but it is not active * if it is not tracking the cover. */ return (res); } /* * this function is called when this entry's cover has a more specific * entry inserted benaeth it. That does not necessarily mean that this * entry is covered by the new prefix. check that */ if (src->u.rr.fesr_cover != fib_table_get_less_specific(fib_entry->fe_fib_index, &fib_entry->fe_prefix)) { fib_entry_src_rr_deactivate(src, fib_entry); fib_entry_src_rr_activate(src, fib_entry); /* * dependent children need to re-resolve to the new forwarding info */ res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE; } return (res); } /* * fib_entry_src_rr_cover_update * * This entry's cover has updated its forwarding info. This entry * will need to re-inheret. */ fib_entry_src_cover_res_t fib_entry_src_rr_cover_update (fib_entry_src_t *src, const fib_entry_t *fib_entry) { fib_entry_src_cover_res_t res = { .install = !0, .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE, }; fib_node_index_t old_path_list; fib_entry_t *cover; if (FIB_NODE_INDEX_INVALID == src->u.rr.fesr_cover) { /* * the source may be added, but it is not active * if it is not tracking the cover. */ return (res); } cover = fib_entry_get(src->u.rr.fesr_cover); old_path_list = src->fes_pl; /* * if the ocver is attached then install an attached-host path * (like an adj-fib). Otherwise inherit the forwarding from the cover */ if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover)) { fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover); } else { fib_entry_src_rr_use_covers_pl(src, fib_entry, cover); } fib_path_list_lock(src->fes_pl); fib_path_list_unlock(old_path_list); /* * dependent children need to re-resolve to the new forwarding info */ res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE; return (res); } static u8* fib_entry_src_rr_format (fib_entry_src_t *src, u8* s) { return (format(s, " cover:%d", src->u.rr.fesr_cover)); } const static fib_entry_src_vft_t rr_src_vft = { .fesv_init = fib_entry_src_rr_init, .fesv_activate = fib_entry_src_rr_activate, .fesv_deactivate = fib_entry_src_rr_deactivate, .fesv_cover_change = fib_entry_src_rr_cover_change, .fesv_cover_update = fib_entry_src_rr_cover_update, .fesv_format = fib_entry_src_rr_format, }; void fib_entry_src_rr_register (void) { fib_entry_src_register(FIB_SOURCE_RR, &rr_src_vft); fib_entry_src_register(FIB_SOURCE_URPF_EXEMPT, &rr_src_vft); }