http: fix client parse error handling
[vpp.git] / src / vnet / fib / fib_entry_src_rr.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 <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 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     const fib_route_path_t path = {
40         .frp_proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto),
41         .frp_addr = fib_entry->fe_prefix.fp_addr,
42         .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     fib_route_path_t *paths = NULL;
48     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     src->fes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NONE, paths);
58     src->fes_entry_flags |= (fib_entry_get_flags(fib_entry_get_index(cover)) &
59                              FIB_ENTRY_FLAGS_RR_INHERITED);
60
61     vec_free(paths);
62 }
63
64
65 /**
66  * Source initialisation Function 
67  */
68 static void
69 fib_entry_src_rr_init (fib_entry_src_t *src)
70 {
71     src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID;
72     src->u.rr.fesr_sibling = FIB_NODE_INDEX_INVALID;
73 }
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 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     fib_node_index_t *entries = NULL;
96     dpo_proto_t proto;
97     fib_entry_src_t *s;
98
99     proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto);
100     vec_add1(entries, fib_entry_get_index(fib_entry));
101
102     if (fib_path_list_recursive_loop_detect(cover->fe_parent,
103                                             &entries))
104     {
105         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         src->fes_pl = cover->fe_parent;
112         vec_foreach (s,cover->fe_srcs)
113           {
114             if (s->fes_pl != cover->fe_parent)
115               continue;
116
117             src->fes_path_exts.fpel_exts = vec_dup (s->fes_path_exts.fpel_exts);
118             break;
119           }
120     }
121     vec_free(entries);
122 }
123
124 /*
125  * Source activation. Called when the source is the new best source on the entry
126  */
127 static int
128 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     if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
139     {
140         src->fes_pl = fib_path_list_create_special(DPO_PROTO_MPLS,
141                                                    FIB_PATH_LIST_FLAG_DROP,
142                                                    NULL);
143         fib_path_list_lock(src->fes_pl);
144         return (!0);
145     }
146
147     src->u.rr.fesr_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
148                                                      &fib_entry->fe_prefix);
149
150     ASSERT(FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover);
151
152     cover = fib_entry_get(src->u.rr.fesr_cover);
153
154     src->u.rr.fesr_sibling =
155         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     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
162     {
163         fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
164     }
165     else
166     {
167         fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
168     }
169     fib_path_list_lock(src->fes_pl);
170
171     /*
172      * return go for install
173      */
174     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 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     if (FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover)
191     {
192         fib_node_index_t *entries = NULL;
193
194         cover = fib_entry_get(src->u.rr.fesr_cover);
195         fib_entry_cover_untrack(cover, src->u.rr.fesr_sibling);
196         src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID;
197
198         if (FIB_NODE_INDEX_INVALID != cover->fe_parent)
199         {
200             fib_path_list_recursive_loop_detect(cover->fe_parent, &entries);
201
202             vec_free(entries);
203         }
204     }
205
206     fib_path_list_unlock(src->fes_pl);
207     src->fes_pl = FIB_NODE_INDEX_INVALID;
208     vec_free (src->fes_path_exts.fpel_exts);
209     src->fes_entry_flags = FIB_ENTRY_FLAG_NONE;
210 }
211
212 fib_entry_src_cover_res_t
213 fib_entry_src_rr_cover_change (fib_entry_src_t *src,
214                                const fib_entry_t *fib_entry)
215 {
216     fib_entry_src_cover_res_t res = {
217         .install = !0,
218         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
219     };
220
221     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         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     if (src->u.rr.fesr_cover != fib_table_get_less_specific(fib_entry->fe_fib_index,
236                                                           &fib_entry->fe_prefix))
237     {
238         fib_entry_src_rr_deactivate(src, fib_entry);
239         fib_entry_src_rr_activate(src, fib_entry);
240
241         /*
242          * dependent children need to re-resolve to the new forwarding info
243          */
244         res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
245     }
246     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 fib_entry_src_rr_cover_update (fib_entry_src_t *src,
257                                const fib_entry_t *fib_entry)
258 {
259     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     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         return (res);
273     }
274
275     cover = fib_entry_get(src->u.rr.fesr_cover);
276     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     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
283     {
284         fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
285     }
286     else
287     {
288         fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
289     }
290     fib_path_list_lock(src->fes_pl);
291     fib_path_list_unlock(old_path_list);
292
293     /*
294      * dependent children need to re-resolve to the new forwarding info
295      */
296     res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
297
298     return (res);
299 }
300
301 static u8*
302 fib_entry_src_rr_format (fib_entry_src_t *src,
303                          u8* s)
304 {
305     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 fib_entry_src_rr_register (void)
319 {
320     fib_entry_src_behaviour_register(FIB_SOURCE_BH_RR, &rr_src_vft);
321 }