Line data Source code
1 : /* 2 : * Copyright (c) 2016 Cisco and/or its affiliates. 3 : * Licensed under the Apache License, Version 2.0 (the "License"); 4 : * you may not use this file except in compliance with the License. 5 : * You may obtain a copy of the License at: 6 : * 7 : * http://www.apache.org/licenses/LICENSE-2.0 8 : * 9 : * Unless required by applicable law or agreed to in writing, software 10 : * distributed under the License is distributed on an "AS IS" BASIS, 11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : * See the License for the specific language governing permissions and 13 : * limitations under the License. 14 : */ 15 : 16 : #include <vnet/bfd/bfd_main.h> 17 : 18 : #include <vnet/fib/fib_entry_delegate.h> 19 : #include <vnet/fib/fib_entry.h> 20 : #include <vnet/fib/fib_table.h> 21 : #include <vnet/fib/fib_walk.h> 22 : 23 : static fib_bfd_state_t 24 4 : fib_bfd_bfd_state_to_fib (bfd_state_e bstate) 25 : { 26 4 : switch (bstate) 27 : { 28 2 : case BFD_STATE_up: 29 2 : return (FIB_BFD_STATE_UP); 30 2 : case BFD_STATE_down: 31 : case BFD_STATE_admin_down: 32 : case BFD_STATE_init: 33 2 : return (FIB_BFD_STATE_DOWN); 34 : } 35 0 : return (FIB_BFD_STATE_DOWN); 36 : } 37 : 38 : static void 39 8 : fib_bfd_update_walk (fib_node_index_t fei) 40 : { 41 : /* 42 : * initiate a backwalk of dependent children 43 : * to notify of the state change of this entry. 44 : */ 45 8 : fib_node_back_walk_ctx_t ctx = { 46 : .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE, 47 : }; 48 8 : fib_walk_sync(FIB_NODE_TYPE_ENTRY, fei, &ctx); 49 8 : } 50 : 51 : /** 52 : * @brief Callback function registered with BFD module to receive notifications 53 : * of the CRUD of BFD sessions 54 : * would be static but for the fact it's called from the unit-tests 55 : */ 56 : void 57 348 : fib_bfd_notify (bfd_listen_event_e event, 58 : const bfd_session_t *session) 59 : { 60 : fib_entry_delegate_t *fed; 61 : const bfd_udp_key_t *key; 62 : fib_node_index_t fei; 63 : 64 348 : if (BFD_HOP_TYPE_MULTI != session->hop_type) 65 : { 66 : /* 67 : * multi-hop BFD sessions attach directly to the FIB entry 68 : * single-hop adj to the associate adjacency. 69 : */ 70 336 : return; 71 : } 72 : 73 12 : key = &session->udp.key; 74 : 75 12 : fib_prefix_t pfx = { 76 : .fp_addr = key->peer_addr, 77 12 : .fp_proto = (ip46_address_is_ip4 (&key->peer_addr) ? 78 12 : FIB_PROTOCOL_IP4: 79 : FIB_PROTOCOL_IP6), 80 12 : .fp_len = (ip46_address_is_ip4 (&key->peer_addr) ? 81 : 32: 82 : 128), 83 : }; 84 : 85 : /* 86 : * get the FIB entry 87 : */ 88 12 : fei = fib_table_lookup_exact_match(key->fib_index, &pfx); 89 : 90 12 : switch (event) 91 : { 92 4 : case BFD_LISTEN_EVENT_CREATE: 93 : /* 94 : * The creation of a new session 95 : */ 96 6 : if ((FIB_NODE_INDEX_INVALID != fei) && 97 2 : (fed = fib_entry_delegate_find(fib_entry_get(fei), 98 : FIB_ENTRY_DELEGATE_BFD))) 99 : { 100 : /* 101 : * already got state for this entry 102 : */ 103 : } 104 : else 105 : { 106 : /* 107 : * source and lock the entry. add the delegate 108 : */ 109 4 : fei = fib_table_entry_special_add(key->fib_index, 110 : &pfx, 111 : FIB_SOURCE_RR, 112 : FIB_ENTRY_FLAG_NONE); 113 4 : fib_entry_lock(fei); 114 : 115 4 : fed = fib_entry_delegate_find_or_add(fib_entry_get(fei), 116 : FIB_ENTRY_DELEGATE_BFD); 117 : 118 : /* 119 : * pretend the session is up and skip the walk. 120 : * If we set it down then we get traffic loss on new children. 121 : * if we walk then we lose traffic for existing children. Wait 122 : * for the first BFD UP/DOWN before we let the session's state 123 : * influence forwarding. 124 : */ 125 4 : fed->fd_bfd_state = FIB_BFD_STATE_UP; 126 : } 127 4 : break; 128 : 129 4 : case BFD_LISTEN_EVENT_UPDATE: 130 : /* 131 : * state change up/dowm and 132 : */ 133 4 : ASSERT(FIB_NODE_INDEX_INVALID != fei); 134 : 135 4 : fed = fib_entry_delegate_find(fib_entry_get(fei), 136 : FIB_ENTRY_DELEGATE_BFD); 137 : 138 4 : if (NULL != fed) 139 : { 140 4 : fed->fd_bfd_state = fib_bfd_bfd_state_to_fib(session->local_state); 141 4 : fib_bfd_update_walk(fei); 142 : } 143 : /* 144 : * else 145 : * no BFD state 146 : */ 147 4 : break; 148 : 149 4 : case BFD_LISTEN_EVENT_DELETE: 150 : /* 151 : * session has been removed. 152 : */ 153 4 : if (FIB_NODE_INDEX_INVALID == fei) 154 : { 155 : /* 156 : * no FIB entry 157 : */ 158 : } 159 4 : else if (fib_entry_delegate_find(fib_entry_get(fei), 160 : FIB_ENTRY_DELEGATE_BFD)) 161 : { 162 : /* 163 : * has an associated BFD tracking delegate 164 : * usource the entry and remove the BFD tracking delegate 165 : */ 166 4 : fib_entry_delegate_remove(fib_entry_get(fei), 167 : FIB_ENTRY_DELEGATE_BFD); 168 4 : fib_bfd_update_walk(fei); 169 : 170 4 : fib_table_entry_special_remove(key->fib_index, 171 : &pfx, 172 : FIB_SOURCE_RR); 173 4 : fib_entry_unlock(fei); 174 : } 175 : /* 176 : * else 177 : * no BFD associated state 178 : */ 179 4 : break; 180 : } 181 12 : } 182 : 183 : static clib_error_t * 184 559 : fib_bfd_main_init (vlib_main_t * vm) 185 : { 186 559 : bfd_register_listener(fib_bfd_notify); 187 : 188 559 : return (NULL); 189 : } 190 : 191 : /* *INDENT-OFF* */ 192 81199 : VLIB_INIT_FUNCTION (fib_bfd_main_init) = 193 : { 194 : .runs_after = VLIB_INITS("bfd_main_init"), 195 : }; 196 : /* *INDENT-ON* */