ethernet: check destination mac for L3 in ethernet-input node
[vpp.git] / src / vnet / fib / fib_entry_src_adj.c
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_table.h"
20 #include "fib_entry_cover.h"
21 #include "fib_attached_export.h"
22 #include "fib_path_ext.h"
23
24 /**
25  * Source initialisation Function
26  */
27 static void
28 fib_entry_src_adj_init (fib_entry_src_t *src)
29 {
30     src->u.adj.fesa_cover = FIB_NODE_INDEX_INVALID;
31     src->u.adj.fesa_sibling = FIB_NODE_INDEX_INVALID;
32 }
33
34 static void
35 fib_entry_src_adj_path_add (fib_entry_src_t *src,
36                             const fib_entry_t *entry,
37                             fib_path_list_flags_t pl_flags,
38                             const fib_route_path_t *paths)
39 {
40     const fib_route_path_t *rpath;
41
42     if (FIB_NODE_INDEX_INVALID == src->fes_pl)
43     {
44         src->fes_pl = fib_path_list_create(pl_flags, paths);
45     }
46     else
47     {
48         src->fes_pl = fib_path_list_copy_and_path_add(src->fes_pl,
49                                                       pl_flags,
50                                                       paths);
51     }
52
53     /*
54      * resolve the existing extensions
55      */
56     fib_path_ext_list_resolve(&src->fes_path_exts, src->fes_pl);
57
58     /*
59      * and new extensions
60      */
61     vec_foreach(rpath, paths)
62     {
63         fib_path_ext_list_insert(&src->fes_path_exts,
64                                  src->fes_pl,
65                                  FIB_PATH_EXT_ADJ,
66                                  rpath);
67     }
68 }
69
70 static void
71 fib_entry_src_adj_path_remove (fib_entry_src_t *src,
72                                fib_path_list_flags_t pl_flags,
73                                const fib_route_path_t *rpaths)
74 {
75     const fib_route_path_t *rpath;
76
77     if (FIB_NODE_INDEX_INVALID != src->fes_pl)
78     {
79         src->fes_pl = fib_path_list_copy_and_path_remove(src->fes_pl,
80                                                          pl_flags,
81                                                          rpaths);
82     }
83
84     /*
85      * remove the path-extension for the path
86      */
87     vec_foreach(rpath, rpaths)
88     {
89         fib_path_ext_list_remove(&src->fes_path_exts, FIB_PATH_EXT_ADJ, rpath);
90     };
91     /*
92      * resolve the remaining extensions
93      */
94     fib_path_ext_list_resolve(&src->fes_path_exts, src->fes_pl);
95 }
96
97 static void
98 fib_entry_src_adj_path_swap (fib_entry_src_t *src,
99                              const fib_entry_t *entry,
100                              fib_path_list_flags_t pl_flags,
101                              const fib_route_path_t *paths)
102 {
103     const fib_route_path_t *rpath;
104
105     /*
106      * flush all the old extensions before we create a brand new path-list
107      */
108     fib_path_ext_list_flush(&src->fes_path_exts);
109
110     src->fes_pl = fib_path_list_create(pl_flags, paths);
111
112     /*
113      * and new extensions
114      */
115     vec_foreach(rpath, paths)
116     {
117         fib_path_ext_list_push_back(&src->fes_path_exts,
118                                     src->fes_pl,
119                                     FIB_PATH_EXT_ADJ,
120                                     rpath);
121     }
122 }
123
124 static void
125 fib_entry_src_adj_remove (fib_entry_src_t *src)
126 {
127     src->fes_pl = FIB_NODE_INDEX_INVALID;
128
129     if (FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover)
130     {
131         fib_entry_cover_untrack(fib_entry_get(src->u.adj.fesa_cover),
132                                 src->u.adj.fesa_sibling);
133     }
134 }
135
136 /*
137  * Add a path-extension indicating whether this path is resolved,
138  * because it passed the refinement check
139  */
140 static void
141 fib_enty_src_adj_update_path_ext (fib_entry_src_t *src,
142                                   fib_node_index_t path_index,
143                                   fib_path_ext_adj_flags_t flags)
144 {
145     fib_path_ext_t *path_ext;
146
147     path_ext = fib_path_ext_list_find_by_path_index(&src->fes_path_exts,
148                                                     path_index);
149
150     if (NULL != path_ext)
151     {
152         path_ext->fpe_adj_flags = flags;
153     }
154     else
155     {
156         ASSERT(!"no path extension");
157     }
158 }
159
160 typedef struct fib_entry_src_path_list_walk_cxt_t_
161 {
162     fib_entry_src_t *src;
163     u32 cover_itf;
164     fib_path_ext_adj_flags_t flags;
165 } fib_entry_src_path_list_walk_cxt_t;
166
167 static fib_path_list_walk_rc_t
168 fib_entry_src_adj_path_list_walk (fib_node_index_t pl_index,
169                                   fib_node_index_t path_index,
170                                   void *arg)
171 {
172     fib_entry_src_path_list_walk_cxt_t *ctx;
173     u32 adj_itf;
174
175     ctx = arg;
176     adj_itf = fib_path_get_resolving_interface(path_index);
177
178     if (ctx->cover_itf == adj_itf)
179     {
180         fib_enty_src_adj_update_path_ext(ctx->src, path_index,
181                                          FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER);
182         ctx->flags |= FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER;
183     }
184     else
185     {
186         /*
187          * if the interface the adj is on is unnumbered to the
188          * cover's, then allow that too.
189          */
190         vnet_sw_interface_t *swif;
191
192         swif = vnet_get_sw_interface (vnet_get_main(), adj_itf);
193
194         if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
195             ctx->cover_itf == swif->unnumbered_sw_if_index)
196         {
197             fib_enty_src_adj_update_path_ext(ctx->src, path_index,
198                                              FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER);
199             ctx->flags |= FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER;
200         }
201         else
202         {
203             fib_enty_src_adj_update_path_ext(ctx->src, path_index,
204                                              FIB_PATH_EXT_ADJ_FLAG_NONE);
205         }
206     }
207     return (FIB_PATH_LIST_WALK_CONTINUE);
208 }
209
210 static int
211 fib_entry_src_adj_activate (fib_entry_src_t *src,
212                             const fib_entry_t *fib_entry)
213 {
214     fib_entry_t *cover;
215
216     /*
217      * find the covering prefix. become a dependent thereof.
218      * there should always be a cover, though it may be the default route.
219      */
220     src->u.adj.fesa_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
221                                                         &fib_entry->fe_prefix);
222
223     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
224     ASSERT(fib_entry_get_index(fib_entry) != src->u.adj.fesa_cover);
225
226     cover = fib_entry_get(src->u.adj.fesa_cover);
227
228     ASSERT(cover != fib_entry);
229
230     src->u.adj.fesa_sibling =
231         fib_entry_cover_track(cover,
232                               fib_entry_get_index(fib_entry));
233
234     /*
235      * if the cover is attached on the same interface as this adj source then
236      * install the FIB entry via the adj. otherwise install a drop.
237      * This prevents ARP/ND entries that on interface X that do not belong
238      * on X's subnet from being added to the FIB. To do so would allow
239      * nefarious gratuitous ARP requests from attracting traffic to the sender.
240      *
241      * and yes, I really do mean attached and not connected.
242      * this abomination;
243      *   ip route add 10.0.0.0/24 Eth0
244      * is attached. and we want adj-fibs to install on Eth0.
245      */
246     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover) ||
247         (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_for_source(src->u.adj.fesa_cover,
248                                                                   FIB_SOURCE_INTERFACE)))
249     {
250         fib_entry_src_path_list_walk_cxt_t ctx = {
251             .cover_itf = fib_entry_get_resolving_interface(src->u.adj.fesa_cover),
252             .flags = FIB_PATH_EXT_ADJ_FLAG_NONE,
253             .src = src,
254         };
255
256         fib_path_list_walk(src->fes_pl,
257                            fib_entry_src_adj_path_list_walk,
258                            &ctx);
259
260         /*
261          * active the entry is one of the paths refines the cover.
262          */
263         return (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & ctx.flags);
264     }
265     return (0);
266 }
267
268 /*
269  * Source re-activate.
270  * Called when the source path lit has changed and the source is still
271  * the best source
272  */
273 static int
274 fib_entry_src_adj_reactivate (fib_entry_src_t *src,
275                               const fib_entry_t *fib_entry)
276 {
277     fib_entry_src_path_list_walk_cxt_t ctx = {
278         .cover_itf = fib_entry_get_resolving_interface(src->u.adj.fesa_cover),
279         .flags = FIB_PATH_EXT_ADJ_FLAG_NONE,
280         .src = src,
281     };
282
283     fib_path_list_walk(src->fes_pl,
284                        fib_entry_src_adj_path_list_walk,
285                        &ctx);
286
287     return (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & ctx.flags);
288 }
289
290 /*
291  * Source Deactivate.
292  * Called when the source is no longer best source on the entry
293  */
294 static void
295 fib_entry_src_adj_deactivate (fib_entry_src_t *src,
296                               const fib_entry_t *fib_entry)
297 {
298     fib_entry_t *cover;
299
300     /*
301      * remove the dependency on the covering entry
302      */
303     if (FIB_NODE_INDEX_INVALID == src->u.adj.fesa_cover)
304     {
305         /*
306          * this is the case if the entry is in the non-forwarding trie
307          */
308         return;
309     }
310
311     cover = fib_entry_get(src->u.adj.fesa_cover);
312     fib_entry_cover_untrack(cover, src->u.adj.fesa_sibling);
313
314     /*
315      * tell the cover this entry no longer needs exporting
316      */
317     fib_attached_export_covered_removed(cover, fib_entry_get_index(fib_entry));
318
319     src->u.adj.fesa_cover = FIB_NODE_INDEX_INVALID;
320     src->u.adj.fesa_sibling = FIB_NODE_INDEX_INVALID;
321 }
322
323 static u8*
324 fib_entry_src_adj_format (fib_entry_src_t *src,
325                          u8* s)
326 {
327     return (format(s, " cover:%d", src->u.adj.fesa_cover));
328 }
329
330 static void
331 fib_entry_src_adj_installed (fib_entry_src_t *src,
332                              const fib_entry_t *fib_entry)
333 {
334     /*
335      * The adj source now rules! poke our cover to get exported
336      */
337     fib_entry_t *cover;
338
339     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
340     cover = fib_entry_get(src->u.adj.fesa_cover);
341
342     fib_attached_export_covered_added(cover,
343                                       fib_entry_get_index(fib_entry));
344 }
345
346 static fib_entry_src_cover_res_t
347 fib_entry_src_adj_cover_change (fib_entry_src_t *src,
348                                 const fib_entry_t *fib_entry)
349 {
350     fib_entry_src_cover_res_t res = {
351         .install = 0,
352         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
353     };
354
355     /*
356      * not interested in a change to the cover if the cover
357      * is not being tracked, i.e. the source is not active
358      */
359     if (FIB_NODE_INDEX_INVALID == src->u.adj.fesa_cover)
360         return res;
361
362     fib_entry_src_adj_deactivate(src, fib_entry);
363
364     res.install = fib_entry_src_adj_activate(src, fib_entry);
365
366     if (res.install) {
367         /*
368          * ADJ fib can install
369          */
370         res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
371     }
372
373     FIB_ENTRY_DBG(fib_entry, "adj-src-cover-changed");
374     return (res);
375 }
376
377 /*
378  * fib_entry_src_adj_cover_update
379  */
380 static fib_entry_src_cover_res_t
381 fib_entry_src_adj_cover_update (fib_entry_src_t *src,
382                                 const fib_entry_t *fib_entry)
383 {
384     /*
385      * the cover has updated, i.e. its forwarding or flags
386      * have changed. don't deactivate/activate here, since this
387      * prefix is updated during the covers walk.
388      */
389     fib_entry_src_cover_res_t res = {
390         .install = 0,
391         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
392     };
393     fib_entry_t *cover;
394
395     /*
396      * If there is no cover, then the source is not active and we can ignore
397      * this update
398      */
399     if (FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover)
400     {
401         cover = fib_entry_get(src->u.adj.fesa_cover);
402
403         res.install = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover));
404
405         FIB_ENTRY_DBG(fib_entry, "adj-src-cover-updated");
406     }
407     return (res);
408 }
409
410 const static fib_entry_src_vft_t adj_src_vft = {
411     .fesv_init = fib_entry_src_adj_init,
412     .fesv_path_swap = fib_entry_src_adj_path_swap,
413     .fesv_path_add = fib_entry_src_adj_path_add,
414     .fesv_path_remove = fib_entry_src_adj_path_remove,
415     .fesv_remove = fib_entry_src_adj_remove,
416     .fesv_activate = fib_entry_src_adj_activate,
417     .fesv_deactivate = fib_entry_src_adj_deactivate,
418     .fesv_reactivate = fib_entry_src_adj_reactivate,
419     .fesv_format = fib_entry_src_adj_format,
420     .fesv_installed = fib_entry_src_adj_installed,
421     .fesv_cover_change = fib_entry_src_adj_cover_change,
422     .fesv_cover_update = fib_entry_src_adj_cover_update,
423 };
424
425 void
426 fib_entry_src_adj_register (void)
427 {
428     fib_entry_src_behaviour_register(FIB_SOURCE_BH_ADJ, &adj_src_vft);
429 }