/* * Copyright (c) 2019 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 <vnet/fib/fib_entry_track.h> #include <vnet/fib/fib_table.h> #include <vnet/fib/fib_entry_delegate.h> #include <vnet/fib/fib_walk.h> static fib_entry_delegate_t * fib_entry_track_delegate_add (u32 fib_index, const fib_prefix_t *prefix) { fib_entry_delegate_t *fed; fib_node_index_t fei; fei = fib_table_entry_special_add(fib_index, prefix, FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE); fed = fib_entry_delegate_find_or_add(fib_entry_get(fei), FIB_ENTRY_DELEGATE_TRACK); fib_node_init(&fed->fd_track.fedt_node, FIB_NODE_TYPE_ENTRY_TRACK); fed->fd_entry_index = fei; fed->fd_track.fedt_sibling = fib_entry_child_add(fei, FIB_NODE_TYPE_ENTRY_TRACK, fib_entry_delegate_get_index(fed)); return (fed); } fib_node_index_t fib_entry_track (u32 fib_index, const fib_prefix_t *prefix, fib_node_type_t child_type, index_t child_index, u32 *sibling) { fib_entry_delegate_t *fed; fib_node_index_t fei; fei = fib_table_lookup_exact_match(fib_index, prefix); if (INDEX_INVALID == fei || NULL == (fed = fib_entry_delegate_find(fib_entry_get(fei), FIB_ENTRY_DELEGATE_TRACK))) { fed = fib_entry_track_delegate_add(fib_index, prefix); } /* * add this child to the entry's delegate */ *sibling = fib_node_child_add(FIB_NODE_TYPE_ENTRY_TRACK, fib_entry_delegate_get_index(fed), child_type, child_index); return (fed->fd_entry_index); } void fib_entry_untrack (fib_node_index_t fei, u32 sibling) { fib_entry_delegate_t *fed; fed = fib_entry_delegate_find(fib_entry_get(fei), FIB_ENTRY_DELEGATE_TRACK); if (NULL != fed) { fib_node_child_remove(FIB_NODE_TYPE_ENTRY_TRACK, fib_entry_delegate_get_index(fed), sibling); /* if this is the last child the delegate will be removed. */ } /* else untracked */ } static fib_node_t * fib_entry_track_get_node (fib_node_index_t index) { fib_entry_delegate_t *fed; fed = fib_entry_delegate_get(index); return (&fed->fd_track.fedt_node); } static fib_entry_delegate_t* fib_entry_delegate_from_fib_node (fib_node_t *node) { ASSERT(FIB_NODE_TYPE_ENTRY_TRACK == node->fn_type); return ((fib_entry_delegate_t *) (((char *) node) - STRUCT_OFFSET_OF (fib_entry_delegate_t, fd_track.fedt_node))); } static void fib_entry_track_last_lock_gone (fib_node_t *node) { fib_entry_delegate_t *fed; fib_node_index_t fei; u32 sibling; fed = fib_entry_delegate_from_fib_node(node); fei = fed->fd_entry_index; sibling = fed->fd_track.fedt_sibling; /* * the tracker has no more children so it can be removed, * and the FIB entry unsourced. * remove the delegate first, then unlock the fib entry, * since the delegate may be holding the last lock */ fib_entry_delegate_remove(fib_entry_get(fei), FIB_ENTRY_DELEGATE_TRACK); /* having removed the deletegate the fed object is now toast */ fib_entry_child_remove(fei, sibling); fib_table_entry_delete_index(fei, FIB_SOURCE_RR); } static fib_node_back_walk_rc_t fib_entry_track_back_walk_notify (fib_node_t *node, fib_node_back_walk_ctx_t *ctx) { fib_entry_delegate_t *fed; fed = fib_entry_delegate_from_fib_node(node); /* * propagate the walk to the delgate's children */ fib_walk_sync(FIB_NODE_TYPE_ENTRY_TRACK, fib_entry_delegate_get_index(fed), ctx); return (FIB_NODE_BACK_WALK_CONTINUE); } static void fib_entry_track_show_memory (void) { } /* * The FIB entry tracker's graph node virtual function table */ static const fib_node_vft_t fib_entry_track_vft = { .fnv_get = fib_entry_track_get_node, .fnv_last_lock = fib_entry_track_last_lock_gone, .fnv_back_walk = fib_entry_track_back_walk_notify, .fnv_mem_show = fib_entry_track_show_memory, }; void fib_entry_track_module_init (void) { fib_node_register_type(FIB_NODE_TYPE_ENTRY_TRACK, &fib_entry_track_vft); }