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 <vlib/vlib.h>
17 : #include <vnet/ip/format.h>
18 : #include <vnet/ip/lookup.h>
19 : #include <vnet/adj/adj.h>
20 : #include <vnet/dpo/drop_dpo.h>
21 :
22 : #include "fib_entry_src.h"
23 : #include "fib_entry_src_rr.h"
24 : #include "fib_entry_cover.h"
25 : #include "fib_entry.h"
26 : #include "fib_table.h"
27 : #include "fib_path_ext.h"
28 :
29 : /*
30 : * fib_entry_src_rr_resolve_via_connected
31 : *
32 : * Resolve via a connected cover.
33 : */
34 : void
35 270 : fib_entry_src_rr_resolve_via_connected (fib_entry_src_t *src,
36 : const fib_entry_t *fib_entry,
37 : const fib_entry_t *cover)
38 : {
39 810 : const fib_route_path_t path = {
40 270 : .frp_proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto),
41 : .frp_addr = fib_entry->fe_prefix.fp_addr,
42 270 : .frp_sw_if_index = fib_entry_get_resolving_interface(
43 : fib_entry_get_index(cover)),
44 : .frp_fib_index = ~0,
45 : .frp_weight = 1,
46 : };
47 270 : fib_route_path_t *paths = NULL;
48 270 : vec_add1(paths, path);
49 :
50 : /*
51 : * since the cover is connected, the address this entry corresponds
52 : * to is a peer (ARP-able for) on the interface to which the cover is
53 : * connected. The fact we resolve via the cover, just means this RR
54 : * source is the first SRC to use said peer. The ARP source will be along
55 : * shortly to over-rule this RR source.
56 : */
57 270 : src->fes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NONE, paths);
58 270 : src->fes_entry_flags |= (fib_entry_get_flags(fib_entry_get_index(cover)) &
59 : FIB_ENTRY_FLAGS_RR_INHERITED);
60 :
61 270 : vec_free(paths);
62 270 : }
63 :
64 :
65 : /**
66 : * Source initialisation Function
67 : */
68 : static void
69 4234 : fib_entry_src_rr_init (fib_entry_src_t *src)
70 : {
71 4234 : src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID;
72 4234 : src->u.rr.fesr_sibling = FIB_NODE_INDEX_INVALID;
73 4234 : }
74 :
75 :
76 : /*
77 : * use the path-list of the cover, unless it would form a loop.
78 : * that is unless the cover is via this entry.
79 : * If a loop were to form it would be a 1 level loop (i.e. X via X),
80 : * and there would be 2 locks on the path-list; one since its used
81 : * by the cover, and 1 from here. The first lock will go when the
82 : * cover is removed, the second, and last, when the covered walk
83 : * occurs during the cover's removal - this is not a place where
84 : * we can handle last lock gone.
85 : * In short, don't let the loop form. The usual rules of 'we must
86 : * let it form so we know when it breaks' don't apply here, since
87 : * the loop will break when the cover changes, and this function
88 : * will be called again when that happens.
89 : */
90 : void
91 335 : fib_entry_src_rr_use_covers_pl (fib_entry_src_t *src,
92 : const fib_entry_t *fib_entry,
93 : const fib_entry_t *cover)
94 : {
95 335 : fib_node_index_t *entries = NULL;
96 : dpo_proto_t proto;
97 : fib_entry_src_t *s;
98 :
99 335 : proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto);
100 335 : vec_add1(entries, fib_entry_get_index(fib_entry));
101 :
102 335 : if (fib_path_list_recursive_loop_detect(cover->fe_parent,
103 : &entries))
104 : {
105 4 : src->fes_pl = fib_path_list_create_special(proto,
106 : FIB_PATH_LIST_FLAG_DROP,
107 : drop_dpo_get(proto));
108 : }
109 : else
110 : {
111 331 : src->fes_pl = cover->fe_parent;
112 333 : vec_foreach (s,cover->fe_srcs)
113 : {
114 333 : if (s->fes_pl != cover->fe_parent)
115 2 : continue;
116 :
117 331 : src->fes_path_exts.fpel_exts = vec_dup (s->fes_path_exts.fpel_exts);
118 331 : break;
119 : }
120 : }
121 335 : vec_free(entries);
122 335 : }
123 :
124 : /*
125 : * Source activation. Called when the source is the new best source on the entry
126 : */
127 : static int
128 597 : fib_entry_src_rr_activate (fib_entry_src_t *src,
129 : const fib_entry_t *fib_entry)
130 : {
131 : fib_entry_t *cover;
132 :
133 : /*
134 : * find the covering prefix. become a dependent thereof.
135 : * for IP there should always be a cover, though it may be the default route.
136 : * For MPLS there is never a cover.
137 : */
138 597 : if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
139 : {
140 4 : src->fes_pl = fib_path_list_create_special(DPO_PROTO_MPLS,
141 : FIB_PATH_LIST_FLAG_DROP,
142 : NULL);
143 4 : fib_path_list_lock(src->fes_pl);
144 4 : return (!0);
145 : }
146 :
147 593 : src->u.rr.fesr_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
148 : &fib_entry->fe_prefix);
149 :
150 593 : ASSERT(FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover);
151 :
152 593 : cover = fib_entry_get(src->u.rr.fesr_cover);
153 :
154 593 : src->u.rr.fesr_sibling =
155 593 : fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
156 :
157 : /*
158 : * if the cover is attached then install an attached-host path
159 : * (like an adj-fib). Otherwise inherit the forwarding from the cover
160 : */
161 593 : if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
162 : {
163 269 : fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
164 : }
165 : else
166 : {
167 324 : fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
168 : }
169 593 : fib_path_list_lock(src->fes_pl);
170 :
171 : /*
172 : * return go for install
173 : */
174 593 : return (!0);
175 : }
176 :
177 : /**
178 : * Source Deactivate.
179 : * Called when the source is no longer best source on the entry
180 : */
181 : static void
182 576 : fib_entry_src_rr_deactivate (fib_entry_src_t *src,
183 : const fib_entry_t *fib_entry)
184 : {
185 : fib_entry_t *cover;
186 :
187 : /*
188 : * remove the dependency on the covering entry
189 : */
190 576 : if (FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover)
191 : {
192 572 : fib_node_index_t *entries = NULL;
193 :
194 572 : cover = fib_entry_get(src->u.rr.fesr_cover);
195 572 : fib_entry_cover_untrack(cover, src->u.rr.fesr_sibling);
196 572 : src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID;
197 :
198 572 : if (FIB_NODE_INDEX_INVALID != cover->fe_parent)
199 : {
200 491 : fib_path_list_recursive_loop_detect(cover->fe_parent, &entries);
201 :
202 491 : vec_free(entries);
203 : }
204 : }
205 :
206 576 : fib_path_list_unlock(src->fes_pl);
207 576 : src->fes_pl = FIB_NODE_INDEX_INVALID;
208 576 : vec_free (src->fes_path_exts.fpel_exts);
209 576 : src->fes_entry_flags = FIB_ENTRY_FLAG_NONE;
210 576 : }
211 :
212 : fib_entry_src_cover_res_t
213 179 : fib_entry_src_rr_cover_change (fib_entry_src_t *src,
214 : const fib_entry_t *fib_entry)
215 : {
216 179 : fib_entry_src_cover_res_t res = {
217 : .install = !0,
218 : .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
219 : };
220 :
221 179 : if (FIB_NODE_INDEX_INVALID == src->u.rr.fesr_cover)
222 : {
223 : /*
224 : * the source may be added, but it is not active
225 : * if it is not tracking the cover.
226 : */
227 48 : return (res);
228 : }
229 :
230 : /*
231 : * this function is called when this entry's cover has a more specific
232 : * entry inserted benaeth it. That does not necessarily mean that this
233 : * entry is covered by the new prefix. check that
234 : */
235 131 : if (src->u.rr.fesr_cover != fib_table_get_less_specific(fib_entry->fe_fib_index,
236 : &fib_entry->fe_prefix))
237 : {
238 131 : fib_entry_src_rr_deactivate(src, fib_entry);
239 131 : fib_entry_src_rr_activate(src, fib_entry);
240 :
241 : /*
242 : * dependent children need to re-resolve to the new forwarding info
243 : */
244 131 : res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
245 : }
246 131 : return (res);
247 : }
248 :
249 : /*
250 : * fib_entry_src_rr_cover_update
251 : *
252 : * This entry's cover has updated its forwarding info. This entry
253 : * will need to re-inheret.
254 : */
255 : fib_entry_src_cover_res_t
256 5 : fib_entry_src_rr_cover_update (fib_entry_src_t *src,
257 : const fib_entry_t *fib_entry)
258 : {
259 5 : fib_entry_src_cover_res_t res = {
260 : .install = !0,
261 : .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
262 : };
263 : fib_node_index_t old_path_list;
264 : fib_entry_t *cover;
265 :
266 5 : if (FIB_NODE_INDEX_INVALID == src->u.rr.fesr_cover)
267 : {
268 : /*
269 : * the source may be added, but it is not active
270 : * if it is not tracking the cover.
271 : */
272 1 : return (res);
273 : }
274 :
275 4 : cover = fib_entry_get(src->u.rr.fesr_cover);
276 4 : old_path_list = src->fes_pl;
277 :
278 : /*
279 : * if the ocver is attached then install an attached-host path
280 : * (like an adj-fib). Otherwise inherit the forwarding from the cover
281 : */
282 4 : if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
283 : {
284 1 : fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
285 : }
286 : else
287 : {
288 3 : fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
289 : }
290 4 : fib_path_list_lock(src->fes_pl);
291 4 : fib_path_list_unlock(old_path_list);
292 :
293 : /*
294 : * dependent children need to re-resolve to the new forwarding info
295 : */
296 4 : res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
297 :
298 4 : return (res);
299 : }
300 :
301 : static u8*
302 1 : fib_entry_src_rr_format (fib_entry_src_t *src,
303 : u8* s)
304 : {
305 1 : return (format(s, " cover:%d", src->u.rr.fesr_cover));
306 : }
307 :
308 : const static fib_entry_src_vft_t rr_src_vft = {
309 : .fesv_init = fib_entry_src_rr_init,
310 : .fesv_activate = fib_entry_src_rr_activate,
311 : .fesv_deactivate = fib_entry_src_rr_deactivate,
312 : .fesv_cover_change = fib_entry_src_rr_cover_change,
313 : .fesv_cover_update = fib_entry_src_rr_cover_update,
314 : .fesv_format = fib_entry_src_rr_format,
315 : };
316 :
317 : void
318 575 : fib_entry_src_rr_register (void)
319 : {
320 575 : fib_entry_src_behaviour_register(FIB_SOURCE_BH_RR, &rr_src_vft);
321 575 : }
|