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 "fib_entry.h"
17 : #include "fib_entry_src.h"
18 : #include "fib_path_list.h"
19 : #include "fib_internal.h"
20 : #include "fib_table.h"
21 : #include "fib_entry_cover.h"
22 : #include "fib_attached_export.h"
23 :
24 : /**
25 : * Source initialisation Function
26 : */
27 : static void
28 14385 : fib_entry_src_interface_init (fib_entry_src_t *src)
29 : {
30 14385 : src->u.interface.fesi_cover = FIB_NODE_INDEX_INVALID;
31 14385 : src->u.interface.fesi_sibling = FIB_NODE_INDEX_INVALID;
32 14385 : }
33 :
34 : static void
35 14385 : fib_entry_src_interface_add (fib_entry_src_t *src,
36 : const fib_entry_t *entry,
37 : fib_entry_flag_t flags,
38 : dpo_proto_t proto,
39 : const dpo_id_t *dpo)
40 : {
41 14385 : src->fes_pl = fib_path_list_create_special(
42 : proto,
43 : fib_entry_src_flags_2_path_list_flags(flags),
44 : dpo);
45 14385 : }
46 :
47 : static void
48 13114 : fib_entry_src_interface_remove (fib_entry_src_t *src)
49 : {
50 13114 : src->fes_pl = FIB_NODE_INDEX_INVALID;
51 13114 : ASSERT(src->u.interface.fesi_sibling == ~0);
52 13114 : }
53 :
54 : static int
55 7615 : fib_entry_src_interface_update_glean (fib_entry_t *cover,
56 : const fib_entry_t *local)
57 : {
58 : fib_entry_src_t *src;
59 : adj_index_t ai;
60 :
61 7615 : src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE);
62 :
63 7615 : if (NULL == src)
64 : {
65 : /*
66 : * The cover is not an interface source, no work
67 : */
68 1994 : return 0;
69 : }
70 :
71 5621 : ai = fib_path_list_get_adj(src->fes_pl,
72 5621 : fib_entry_get_default_chain_type(cover));
73 :
74 5621 : if (INDEX_INVALID != ai)
75 : {
76 : ip_adjacency_t *adj;
77 :
78 5523 : adj = adj_get(ai);
79 :
80 5523 : if (IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index)
81 : {
82 : /*
83 : * the connected prefix will link to a glean on a non-p2p
84 : * interface.
85 : * Ensure we are updating with a host in the connected's subnet
86 : */
87 5250 : if (fib_prefix_is_cover(&adj->sub_type.glean.rx_pfx,
88 : &local->fe_prefix))
89 : {
90 : fib_entry_src_t *local_src;
91 :
92 5250 : local_src = fib_entry_src_find (local, FIB_SOURCE_INTERFACE);
93 5250 : if (local_src != NULL)
94 : {
95 4299 : adj->sub_type.glean.rx_pfx.fp_addr =
96 : local->fe_prefix.fp_addr;
97 4299 : local_src->fes_flags |= FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN;
98 4299 : return (1);
99 : }
100 : }
101 : }
102 : }
103 :
104 1322 : return (0);
105 : }
106 :
107 : static walk_rc_t
108 979 : fib_entry_src_interface_update_glean_walk (fib_entry_t *cover,
109 : fib_node_index_t covered,
110 : void *ctx)
111 : {
112 979 : if (fib_entry_src_interface_update_glean(cover, fib_entry_get(covered)))
113 24 : return (WALK_STOP);
114 :
115 955 : return (WALK_CONTINUE);
116 : }
117 :
118 : static void
119 9438 : fib_entry_src_interface_path_swap (fib_entry_src_t *src,
120 : const fib_entry_t *entry,
121 : fib_path_list_flags_t pl_flags,
122 : const fib_route_path_t *paths)
123 : {
124 9438 : src->fes_pl = fib_path_list_create(pl_flags, paths);
125 9438 : }
126 :
127 : typedef struct fesi_find_glean_ctx_t_ {
128 : fib_node_index_t glean_node_index;
129 : } fesi_find_glean_ctx_t;
130 :
131 : static walk_rc_t
132 150 : fib_entry_src_interface_find_glean_walk (fib_entry_t *cover,
133 : fib_node_index_t covered,
134 : void *ctx)
135 : {
136 150 : fesi_find_glean_ctx_t *find_glean_ctx = ctx;
137 : fib_entry_t *covered_entry;
138 : fib_entry_src_t *covered_src;
139 :
140 150 : covered_entry = fib_entry_get (covered);
141 150 : covered_src = fib_entry_src_find (covered_entry, FIB_SOURCE_INTERFACE);
142 150 : if ((covered_src != NULL) &&
143 24 : (covered_src->fes_flags & FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN))
144 : {
145 24 : find_glean_ctx->glean_node_index = covered;
146 24 : return WALK_STOP;
147 : }
148 :
149 126 : return WALK_CONTINUE;
150 : }
151 :
152 : static fib_entry_t *
153 6660 : fib_entry_src_interface_find_glean (fib_entry_t *cover)
154 : {
155 : fib_entry_src_t *src;
156 :
157 6660 : src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE);
158 6660 : if (src == NULL)
159 : /* the cover is not an interface source */
160 1990 : return NULL;
161 :
162 4670 : fesi_find_glean_ctx_t ctx = {
163 : .glean_node_index = ~0,
164 : };
165 :
166 4670 : fib_entry_cover_walk (cover, fib_entry_src_interface_find_glean_walk,
167 : &ctx);
168 :
169 4694 : return (ctx.glean_node_index == ~0) ? NULL :
170 24 : fib_entry_get (ctx.glean_node_index);
171 : }
172 :
173 : /*
174 : * Source activate.
175 : * Called when the source is teh new longer best source on the entry
176 : */
177 : static int
178 16365 : fib_entry_src_interface_activate (fib_entry_src_t *src,
179 : const fib_entry_t *fib_entry)
180 : {
181 : fib_entry_t *cover;
182 :
183 16365 : if (FIB_ENTRY_FLAG_LOCAL & src->fes_entry_flags)
184 : {
185 : u8 update_glean;
186 :
187 : /*
188 : * Track the covering attached/connected cover. This is so that
189 : * during an attached export of the cover, this local prefix is
190 : * also exported
191 : */
192 6660 : src->u.interface.fesi_cover =
193 6660 : fib_table_get_less_specific(fib_entry->fe_fib_index,
194 : &fib_entry->fe_prefix);
195 :
196 6660 : ASSERT(FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover);
197 :
198 6660 : cover = fib_entry_get(src->u.interface.fesi_cover);
199 :
200 : /*
201 : * Before adding as a child of the cover, check whether an existing
202 : * child has already been used to populate the glean adjacency. If so,
203 : * we don't need to update the adjacency.
204 : */
205 6660 : update_glean = (fib_entry_src_interface_find_glean (cover) == NULL);
206 6660 : src->u.interface.fesi_sibling =
207 6660 : fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
208 :
209 6660 : if (update_glean)
210 6636 : fib_entry_src_interface_update_glean(cover, fib_entry);
211 : }
212 :
213 16365 : return (!0);
214 : }
215 :
216 :
217 : /*
218 : * Source Deactivate.
219 : * Called when the source is no longer best source on the entry
220 : */
221 : static void
222 15094 : fib_entry_src_interface_deactivate (fib_entry_src_t *src,
223 : const fib_entry_t *fib_entry)
224 : {
225 : fib_entry_t *cover;
226 :
227 : /*
228 : * remove the dependency on the covering entry
229 : */
230 15094 : if (FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover)
231 : {
232 6262 : cover = fib_entry_get(src->u.interface.fesi_cover);
233 6262 : fib_entry_cover_untrack(cover, src->u.interface.fesi_sibling);
234 :
235 6262 : src->u.interface.fesi_cover = FIB_NODE_INDEX_INVALID;
236 6262 : src->u.interface.fesi_sibling = ~0;
237 :
238 : /* If this was the glean address, find a new one */
239 6262 : if (src->fes_flags & FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN)
240 : {
241 3901 : fib_entry_cover_walk(cover,
242 : fib_entry_src_interface_update_glean_walk,
243 : NULL);
244 3901 : src->fes_flags &= ~FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN;
245 : }
246 : }
247 15094 : }
248 :
249 : static fib_entry_src_cover_res_t
250 1980 : fib_entry_src_interface_cover_change (fib_entry_src_t *src,
251 : const fib_entry_t *fib_entry)
252 : {
253 1980 : fib_entry_src_cover_res_t res = {
254 : .install = !0,
255 : .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
256 : };
257 :
258 1980 : if (FIB_NODE_INDEX_INVALID == src->u.interface.fesi_cover)
259 : {
260 : /*
261 : * not tracking the cover. surprised we got poked?
262 : */
263 0 : return (res);
264 : }
265 :
266 : /*
267 : * this function is called when this entry's cover has a more specific
268 : * entry inserted benaeth it. That does not necessarily mean that this
269 : * entry is covered by the new prefix. check that
270 : */
271 1980 : if (src->u.interface.fesi_cover !=
272 1980 : fib_table_get_less_specific(fib_entry->fe_fib_index,
273 : &fib_entry->fe_prefix))
274 : {
275 1980 : fib_entry_src_interface_deactivate(src, fib_entry);
276 1980 : fib_entry_src_interface_activate(src, fib_entry);
277 : }
278 1980 : return (res);
279 : }
280 :
281 : static void
282 16420 : fib_entry_src_interface_installed (fib_entry_src_t *src,
283 : const fib_entry_t *fib_entry)
284 : {
285 : /*
286 : * The interface source now rules! poke our cover to get exported
287 : */
288 : fib_entry_t *cover;
289 :
290 16420 : if (FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover)
291 : {
292 6662 : cover = fib_entry_get(src->u.interface.fesi_cover);
293 :
294 6662 : fib_attached_export_covered_added(cover,
295 : fib_entry_get_index(fib_entry));
296 : }
297 16420 : }
298 :
299 : static u8*
300 0 : fib_entry_src_interface_format (fib_entry_src_t *src,
301 : u8* s)
302 : {
303 0 : return (format(s, " cover:%d", src->u.interface.fesi_cover));
304 : }
305 :
306 : const static fib_entry_src_vft_t interface_src_vft = {
307 : .fesv_init = fib_entry_src_interface_init,
308 : .fesv_add = fib_entry_src_interface_add,
309 : .fesv_remove = fib_entry_src_interface_remove,
310 : .fesv_path_swap = fib_entry_src_interface_path_swap,
311 : .fesv_activate = fib_entry_src_interface_activate,
312 : .fesv_deactivate = fib_entry_src_interface_deactivate,
313 : .fesv_format = fib_entry_src_interface_format,
314 : .fesv_installed = fib_entry_src_interface_installed,
315 : .fesv_cover_change = fib_entry_src_interface_cover_change,
316 : /*
317 : * not concerned about updates to the cover. the cover will
318 : * decide to export or not
319 : */
320 : };
321 :
322 : void
323 575 : fib_entry_src_interface_register (void)
324 : {
325 575 : fib_entry_src_behaviour_register(FIB_SOURCE_BH_INTERFACE,
326 : &interface_src_vft);
327 575 : }
|