FIB: encode the label stack in the FIB path during table dump
[vpp.git] / src / vnet / fib / fib_api.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 <vnet/vnet.h>
17 #include <vlibmemory/api.h>
18 #include <vnet/fib/fib_api.h>
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/mfib/mfib_table.h>
21 #include <vnet/bier/bier_disp_table.h>
22 #include <vnet/dpo/ip_null_dpo.h>
23
24 #include <vnet/vnet_msg_enum.h>
25
26 #define vl_typedefs             /* define message structures */
27 #include <vnet/vnet_all_api_h.h>
28 #undef vl_typedefs
29
30 #define vl_endianfun            /* define message structures */
31 #include <vnet/vnet_all_api_h.h>
32 #undef vl_endianfun
33
34 /* instantiate all the print functions we know about */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
36 #define vl_printfun
37 #include <vnet/vnet_all_api_h.h>
38 #undef vl_printfun
39
40 #include <vlibapi/api_helper_macros.h>
41
42 int
43 fib_path_api_parse (const vl_api_fib_path_t *in,
44                     fib_route_path_t *out)
45 {
46     fib_route_path_flags_t path_flags;
47     mpls_label_t next_hop_via_label;
48     int rv = 0, n_labels;
49     u8 ii;
50
51     path_flags = FIB_ROUTE_PATH_FLAG_NONE;
52     next_hop_via_label = ntohl (in->via_label);
53     clib_memset(out, 0, sizeof(*out));
54     out->frp_sw_if_index = ~0;
55
56     out->frp_proto = in->afi;
57     // .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
58     out->frp_sw_if_index = ntohl(in->sw_if_index);
59     out->frp_fib_index = ntohl(in->table_id);
60     out->frp_weight = in->weight;
61     out->frp_preference = in->preference;
62
63     /*
64      * the special INVALID label meams we are not recursing via a
65      * label. Exp-null value is never a valid via-label so that
66      * also means it's not a via-label and means clients that set
67      * it to 0 by default get the expected behaviour
68      */
69     if ((MPLS_LABEL_INVALID != next_hop_via_label) &&
70         (0 != next_hop_via_label))
71     {
72         out->frp_proto = DPO_PROTO_MPLS;
73         out->frp_local_label = next_hop_via_label;
74         out->frp_eos = MPLS_NON_EOS;
75     }
76
77     n_labels = in->n_labels;
78     if (n_labels == 0)
79         ;
80     else
81     {
82         vec_validate (out->frp_label_stack, n_labels - 1);
83         for (ii = 0; ii < n_labels; ii++)
84         {
85             out->frp_label_stack[ii].fml_value =
86                 ntohl(in->label_stack[ii].label);
87             out->frp_label_stack[ii].fml_ttl =
88                 in->label_stack[ii].ttl;
89             out->frp_label_stack[ii].fml_exp =
90                 in->label_stack[ii].exp;
91             out->frp_label_stack[ii].fml_mode =
92                 (in->label_stack[ii].is_uniform ?
93                  FIB_MPLS_LSP_MODE_UNIFORM :
94                  FIB_MPLS_LSP_MODE_PIPE);
95         }
96     }
97
98     if (in->is_dvr)
99         path_flags |= FIB_ROUTE_PATH_DVR;
100     if (in->is_resolve_host)
101         path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
102     if (in->is_resolve_attached)
103         path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
104     /* if (in->is_interface_rx) */
105     /*     path_flags |= FIB_ROUTE_PATH_INTF_RX; */
106     /* if (in->is_rpf_id) */
107     /*     path_flags |= FIB_ROUTE_PATH_RPF_ID; */
108     if (in->is_source_lookup)
109         path_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
110
111     if (in->is_udp_encap)
112     {
113         path_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
114         out->frp_udp_encap_id = ntohl(in->next_hop_id);
115     }
116     else
117     {
118         if (DPO_PROTO_IP4 == in->afi)
119         {
120             clib_memcpy (&out->frp_addr.ip4,
121                          in->next_hop,
122                          sizeof (out->frp_addr.ip4));
123         }
124         else if (DPO_PROTO_IP6 == in->afi)
125         {
126             clib_memcpy (&out->frp_addr.ip6,
127                          in->next_hop,
128                          sizeof (out->frp_addr.ip6));
129         }
130
131         if (ip46_address_is_zero(&out->frp_addr))
132         {
133             if (DPO_PROTO_BIER == in->afi)
134             {
135                 index_t bdti;
136
137                 bdti = bier_disp_table_find(ntohl(in->table_id));
138
139                 if (INDEX_INVALID != bdti)
140                 {
141                     out->frp_fib_index = bdti;
142                     out->frp_proto = DPO_PROTO_BIER;
143                 }
144                 else
145                 {
146                     rv = VNET_API_ERROR_NO_SUCH_FIB;
147                 }
148             }
149             else if (out->frp_sw_if_index == ~0 &&
150                      out->frp_fib_index != ~0)
151             {
152                 path_flags |= FIB_ROUTE_PATH_DEAG;
153             }
154         }
155     }
156
157     out->frp_flags = path_flags;
158
159     return (rv);
160 }
161
162 void
163 fib_prefix_to_api (const fib_prefix_t *pfx,
164                    u8 address[16],
165                    u8 *length,
166                    u8 *is_ip6)
167 {
168     *length = pfx->fp_len;
169     *is_ip6 = (FIB_PROTOCOL_IP6 == pfx->fp_proto ? 1 : 0);
170
171     if (FIB_PROTOCOL_IP6 == pfx->fp_proto)
172     {
173         memcpy (address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
174     }
175     else
176     {
177         memcpy (address, &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
178     }
179 }
180
181 static void
182 fib_api_path_copy_next_hop (const fib_route_path_encode_t * api_rpath, void *fp_arg)
183 {
184   int is_ip4;
185   vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg;
186
187   if (api_rpath->rpath.frp_proto == DPO_PROTO_IP4)
188     fp->afi = IP46_TYPE_IP4;
189   else if (api_rpath->rpath.frp_proto == DPO_PROTO_IP6)
190     fp->afi = IP46_TYPE_IP6;
191   else
192     {
193       is_ip4 = ip46_address_is_ip4 (&api_rpath->rpath.frp_addr);
194       if (is_ip4)
195         fp->afi = IP46_TYPE_IP4;
196       else
197         fp->afi = IP46_TYPE_IP6;
198     }
199   if (fp->afi == IP46_TYPE_IP4)
200     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip4,
201             sizeof (api_rpath->rpath.frp_addr.ip4));
202   else
203     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip6,
204             sizeof (api_rpath->rpath.frp_addr.ip6));
205 }
206
207 void
208 fib_api_path_encode (const fib_route_path_encode_t * api_rpath,
209                      vl_api_fib_path_t *out)
210 {
211     int ii;
212
213     clib_memset (out, 0, sizeof (*out));
214     switch (api_rpath->dpo.dpoi_type)
215     {
216     case DPO_RECEIVE:
217         out->is_local = true;
218         break;
219     case DPO_DROP:
220         out->is_drop = true;
221         break;
222     case DPO_IP_NULL:
223         switch (ip_null_dpo_get_action(api_rpath->dpo.dpoi_index))
224         {
225         case IP_NULL_ACTION_NONE:
226             out->is_drop = true;
227             break;
228         case IP_NULL_ACTION_SEND_ICMP_UNREACH:
229             out->is_unreach = true;
230             break;
231         case IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
232             out->is_prohibit = true;
233             break;
234         default:
235             break;
236         }
237         break;
238     default:
239         break;
240     }
241     out->weight = api_rpath->rpath.frp_weight;
242     out->preference = api_rpath->rpath.frp_preference;
243     out->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
244     out->afi = api_rpath->rpath.frp_proto;
245     fib_api_path_copy_next_hop (api_rpath, out);
246
247     if (0 != api_rpath->rpath.frp_fib_index)
248     {
249         if ((DPO_PROTO_IP6 == api_rpath->rpath.frp_proto) ||
250             (DPO_PROTO_IP4 == api_rpath->rpath.frp_proto))
251         {
252             if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RPF_ID)
253             {
254                 out->table_id =
255                     htonl(mfib_table_get_table_id(
256                               api_rpath->rpath.frp_fib_index,
257                               dpo_proto_to_fib(api_rpath->rpath.frp_proto)));
258             }
259             else
260             {
261                 out->table_id =
262                     htonl(fib_table_get_table_id(
263                               api_rpath->rpath.frp_fib_index,
264                               dpo_proto_to_fib(api_rpath->rpath.frp_proto)));
265             }
266         }
267     }
268
269     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_DVR)
270     {
271         out->is_dvr = 1;
272     }
273     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_UDP_ENCAP)
274     {
275         out->is_udp_encap = 1;
276         out->next_hop_id = api_rpath->rpath.frp_udp_encap_id;
277     }
278     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_INTF_RX)
279     {
280         out->is_interface_rx = 1;
281     }
282     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_LOCAL)
283     {
284         out->is_local = 1;
285     }
286     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
287     {
288         out->is_resolve_host = 1;
289     }
290     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
291     {
292         out->is_resolve_attached = 1;
293     }
294     /* if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_ATTACHED) { */
295     /*     out->is_attached = 1; */
296     /* } */
297     /* if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_CONNECTED) { */
298     /*     out->is_connected = 1; */
299     /* } */
300     if (api_rpath->rpath.frp_label_stack)
301     {
302         for (ii = 0; ii < vec_len(api_rpath->rpath.frp_label_stack); ii++)
303         {
304             out->label_stack[ii].label =
305                 htonl(api_rpath->rpath.frp_label_stack[ii].fml_value);
306             out->label_stack[ii].ttl =
307                 api_rpath->rpath.frp_label_stack[ii].fml_ttl;
308             out->label_stack[ii].exp =
309                 api_rpath->rpath.frp_label_stack[ii].fml_exp;
310         }
311         out->n_labels = ii;
312     }
313 }
314
315 fib_protocol_t
316 fib_proto_from_api_address_family (int af)
317 {
318     switch (clib_net_to_host_u32 (af))
319     {
320     case ADDRESS_IP4:
321         return (FIB_PROTOCOL_IP4);
322     case ADDRESS_IP6:
323         return (FIB_PROTOCOL_IP6);
324     }
325
326     ASSERT(0);
327     return (FIB_PROTOCOL_IP4);
328 }
329
330 int
331 fib_proto_to_api_address_family (fib_protocol_t fproto)
332 {
333     switch (fproto)
334     {
335     case FIB_PROTOCOL_IP4:
336         return (clib_net_to_host_u32 (ADDRESS_IP4));
337     case FIB_PROTOCOL_IP6:
338         return (clib_net_to_host_u32 (ADDRESS_IP6));
339     default:
340         break;
341     }
342
343     ASSERT(0);
344     return (clib_net_to_host_u32 (ADDRESS_IP4));
345 }