ethernet: check destination mac for L3 in ethernet-input node
[vpp.git] / src / vnet / fib / fib_entry_src_interface.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_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 fib_entry_src_interface_init (fib_entry_src_t *src)
29 {
30     src->u.interface.fesi_cover = FIB_NODE_INDEX_INVALID;
31     src->u.interface.fesi_sibling = FIB_NODE_INDEX_INVALID;
32 }
33
34 static void
35 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     src->fes_pl = fib_path_list_create_special(
42                       proto,
43                       fib_entry_src_flags_2_path_list_flags(flags),
44                       dpo);
45 }
46
47 static void
48 fib_entry_src_interface_remove (fib_entry_src_t *src)
49 {
50     src->fes_pl = FIB_NODE_INDEX_INVALID;
51     ASSERT(src->u.interface.fesi_sibling == ~0);
52 }
53
54 static int
55 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     src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE);
62
63     if (NULL == src)
64     {
65         /*
66          * The cover is not an interface source, no work
67          */
68         return 0;
69     }
70
71     ai = fib_path_list_get_adj(src->fes_pl,
72                                fib_entry_get_default_chain_type(cover));
73
74     if (INDEX_INVALID != ai)
75     {
76         ip_adjacency_t *adj;
77
78         adj = adj_get(ai);
79
80         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             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                 local_src = fib_entry_src_find (local, FIB_SOURCE_INTERFACE);
93                 if (local_src != NULL)
94                   {
95                     adj->sub_type.glean.rx_pfx.fp_addr =
96                       local->fe_prefix.fp_addr;
97                     local_src->fes_flags |= FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN;
98                     return (1);
99                   }
100             }
101         }
102     }
103
104     return (0);
105 }
106
107 static walk_rc_t
108 fib_entry_src_interface_update_glean_walk (fib_entry_t *cover,
109                                            fib_node_index_t covered,
110                                            void *ctx)
111 {
112     if (fib_entry_src_interface_update_glean(cover, fib_entry_get(covered)))
113         return (WALK_STOP);
114
115     return (WALK_CONTINUE);
116 }
117
118 static void
119 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     src->fes_pl = fib_path_list_create(pl_flags, paths);
125 }
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 fib_entry_src_interface_find_glean_walk (fib_entry_t *cover,
133                                          fib_node_index_t covered,
134                                          void *ctx)
135 {
136   fesi_find_glean_ctx_t *find_glean_ctx = ctx;
137   fib_entry_t *covered_entry;
138   fib_entry_src_t *covered_src;
139
140   covered_entry = fib_entry_get (covered);
141   covered_src = fib_entry_src_find (covered_entry, FIB_SOURCE_INTERFACE);
142   if ((covered_src != NULL) &&
143       (covered_src->fes_flags & FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN))
144     {
145       find_glean_ctx->glean_node_index = covered;
146       return WALK_STOP;
147     }
148
149   return WALK_CONTINUE;
150 }
151
152 static fib_entry_t *
153 fib_entry_src_interface_find_glean (fib_entry_t *cover)
154 {
155   fib_entry_src_t *src;
156
157   src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE);
158   if (src == NULL)
159     /* the cover is not an interface source */
160     return NULL;
161
162   fesi_find_glean_ctx_t ctx = {
163     .glean_node_index = ~0,
164   };
165
166   fib_entry_cover_walk (cover, fib_entry_src_interface_find_glean_walk,
167                         &ctx);
168
169   return (ctx.glean_node_index == ~0) ? NULL :
170                                         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 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     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         src->u.interface.fesi_cover =
193             fib_table_get_less_specific(fib_entry->fe_fib_index,
194                                         &fib_entry->fe_prefix);
195
196         ASSERT(FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover);
197
198         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         update_glean = (fib_entry_src_interface_find_glean (cover) == NULL);
206         src->u.interface.fesi_sibling =
207             fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
208
209         if (update_glean)
210           fib_entry_src_interface_update_glean(cover, fib_entry);
211     }
212
213     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 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     if (FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover)
231     {
232         cover = fib_entry_get(src->u.interface.fesi_cover);
233         fib_entry_cover_untrack(cover, src->u.interface.fesi_sibling);
234
235         src->u.interface.fesi_cover = FIB_NODE_INDEX_INVALID;
236         src->u.interface.fesi_sibling = ~0;
237
238         /* If this was the glean address, find a new one */
239         if (src->fes_flags & FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN)
240           {
241             fib_entry_cover_walk(cover,
242                                 fib_entry_src_interface_update_glean_walk,
243                                 NULL);
244             src->fes_flags &= ~FIB_ENTRY_SRC_FLAG_PROVIDES_GLEAN;
245           }
246     }
247 }
248
249 static fib_entry_src_cover_res_t
250 fib_entry_src_interface_cover_change (fib_entry_src_t *src,
251                                       const fib_entry_t *fib_entry)
252 {
253     fib_entry_src_cover_res_t res = {
254         .install = !0,
255         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
256     };
257
258     if (FIB_NODE_INDEX_INVALID == src->u.interface.fesi_cover)
259     {
260         /*
261          * not tracking the cover. surprised we got poked?
262          */
263         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     if (src->u.interface.fesi_cover !=
272         fib_table_get_less_specific(fib_entry->fe_fib_index,
273                                     &fib_entry->fe_prefix))
274     {
275         fib_entry_src_interface_deactivate(src, fib_entry);
276         fib_entry_src_interface_activate(src, fib_entry);
277     }
278     return (res);
279 }
280
281 static void
282 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     if (FIB_NODE_INDEX_INVALID != src->u.interface.fesi_cover)
291     {
292         cover = fib_entry_get(src->u.interface.fesi_cover);
293
294         fib_attached_export_covered_added(cover,
295                                           fib_entry_get_index(fib_entry));
296     }
297 }
298
299 static u8*
300 fib_entry_src_interface_format (fib_entry_src_t *src,
301                                 u8* s)
302 {
303     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 fib_entry_src_interface_register (void)
324 {
325     fib_entry_src_behaviour_register(FIB_SOURCE_BH_INTERFACE,
326                                      &interface_src_vft);
327 }