Adjacency refinement; check the cover's interface against the adjacency's
[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
23 /**
24  * Source initialisation Function 
25  */
26 static void
27 fib_entry_src_adj_init (fib_entry_src_t *src)
28 {
29     src->adj.fesa_cover = FIB_NODE_INDEX_INVALID;
30     src->adj.fesa_sibling = FIB_NODE_INDEX_INVALID;
31 }
32
33 static void
34 fib_entry_src_adj_path_swap (fib_entry_src_t *src,
35                              const fib_entry_t *entry,
36                              fib_path_list_flags_t pl_flags,
37                              const fib_route_path_t *paths)
38 {
39     src->fes_pl = fib_path_list_create(pl_flags, paths);
40 }
41
42 static void
43 fib_entry_src_adj_remove (fib_entry_src_t *src)
44 {
45     src->fes_pl = FIB_NODE_INDEX_INVALID;
46 }
47
48
49 /*
50  * Source activate. 
51  * Called when the source is the new longer best source on the entry
52  */
53 static int
54 fib_entry_src_adj_activate (fib_entry_src_t *src,
55                             const fib_entry_t *fib_entry)
56 {
57     fib_entry_t *cover;
58
59     /*
60      * find the covering prefix. become a dependent thereof.
61      * there should always be a cover, though it may be the default route.
62      */
63     src->adj.fesa_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
64                                                       &fib_entry->fe_prefix);
65
66     ASSERT(FIB_NODE_INDEX_INVALID != src->adj.fesa_cover);
67     ASSERT(fib_entry_get_index(fib_entry) != src->adj.fesa_cover);
68
69     cover = fib_entry_get(src->adj.fesa_cover);
70
71     ASSERT(cover != fib_entry);
72
73     src->adj.fesa_sibling =
74         fib_entry_cover_track(cover,
75                               fib_entry_get_index(fib_entry));
76
77     /*
78      * if the cover is attached on the same interface as this adj source then
79      * install the FIB entry via the adj. otherwise install a drop.
80      * This prevents ARP/ND entries that on interface X that do not belong
81      * on X's subnet from being added to the FIB. To do so would allow
82      * nefarious gratuitous ARP requests from attracting traffic to the sender.
83      *
84      * and yes, I really do mean attached and not connected.
85      * this abomination;
86      *   ip route add 10.0.0.0/24 Eth0
87      * is attached. and we want adj-fibs to install on Eth0.
88      */
89     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
90     {
91         u32 cover_itf = fib_entry_get_resolving_interface(src->adj.fesa_cover);
92         u32 adj_itf = fib_path_list_get_resolving_interface(src->fes_pl);
93
94         if (cover_itf == adj_itf)
95         {
96             return (1);
97         }
98         else
99         {
100             /*
101              * if the interface the adj is on is unnumbered to the
102              * cover's, then allow that too.
103              */
104             vnet_sw_interface_t *swif;
105
106             swif = vnet_get_sw_interface (vnet_get_main(), adj_itf);
107
108             if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
109                 cover_itf == swif->unnumbered_sw_if_index)
110             {
111                 return (1);
112             }
113         }
114     }
115     return (0);
116 }
117
118 /*
119  * Source Deactivate. 
120  * Called when the source is no longer best source on the entry
121  */
122 static void
123 fib_entry_src_adj_deactivate (fib_entry_src_t *src,
124                               const fib_entry_t *fib_entry)
125 {
126     fib_entry_t *cover;
127
128     /*
129      * remove the depednecy on the covering entry
130      */
131     ASSERT(FIB_NODE_INDEX_INVALID != src->adj.fesa_cover);
132     cover = fib_entry_get(src->adj.fesa_cover);
133
134     fib_entry_cover_untrack(cover, src->adj.fesa_sibling);
135
136     /*
137      * tell the cover this entry no longer needs exporting
138      */
139     fib_attached_export_covered_removed(cover, fib_entry_get_index(fib_entry));
140
141     src->adj.fesa_cover = FIB_NODE_INDEX_INVALID;
142 }
143
144 static u8*
145 fib_entry_src_adj_format (fib_entry_src_t *src,
146                          u8* s)
147 {
148     return (format(s, "cover:%d", src->adj.fesa_cover));
149 }
150
151 static void
152 fib_entry_src_adj_installed (fib_entry_src_t *src,
153                              const fib_entry_t *fib_entry)
154 {
155     /*
156      * The adj source now rules! poke our cover to get exported
157      */
158     fib_entry_t *cover;
159
160     ASSERT(FIB_NODE_INDEX_INVALID != src->adj.fesa_cover);
161     cover = fib_entry_get(src->adj.fesa_cover);
162
163     fib_attached_export_covered_added(cover,
164                                       fib_entry_get_index(fib_entry));
165 }
166
167 static fib_entry_src_cover_res_t
168 fib_entry_src_adj_cover_change (fib_entry_src_t *src,
169                                 const fib_entry_t *fib_entry)
170 {
171     fib_entry_src_cover_res_t res = {
172         .install = !0,
173         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
174     };
175
176     fib_entry_src_adj_deactivate(src, fib_entry);
177
178     res.install = fib_entry_src_adj_activate(src, fib_entry);
179
180     if (res.install) {
181         /*
182          * ADJ fib can install
183          */
184         res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
185     }
186
187     return (res);
188 }
189
190 /*
191  * fib_entry_src_adj_cover_update
192  */
193 static fib_entry_src_cover_res_t
194 fib_entry_src_adj_cover_update (fib_entry_src_t *src,
195                                 const fib_entry_t *fib_entry)
196 {
197     /*
198      * the cover has updated, i.e. its forwarding or flags
199      * have changed. do'nt decativate/activate here, since this
200      * prefix is updated during the covers walk.
201      */
202     fib_entry_src_cover_res_t res = {
203         .install = !0,
204         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
205     };
206     fib_entry_t *cover;
207
208     ASSERT(FIB_NODE_INDEX_INVALID != src->adj.fesa_cover);
209
210     cover = fib_entry_get(src->adj.fesa_cover);
211
212     res.install = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover));
213
214     return (res);
215 }
216
217 const static fib_entry_src_vft_t adj_src_vft = {
218     .fesv_init = fib_entry_src_adj_init,
219     .fesv_path_swap = fib_entry_src_adj_path_swap,
220     .fesv_remove = fib_entry_src_adj_remove,
221     .fesv_activate = fib_entry_src_adj_activate,
222     .fesv_deactivate = fib_entry_src_adj_deactivate,
223     .fesv_format = fib_entry_src_adj_format,
224     .fesv_installed = fib_entry_src_adj_installed,
225     .fesv_cover_change = fib_entry_src_adj_cover_change,
226     .fesv_cover_update = fib_entry_src_adj_cover_update,
227 };
228
229 void
230 fib_entry_src_adj_register (void)
231 {
232     fib_entry_src_register(FIB_SOURCE_ADJ, &adj_src_vft);
233 }