ip: change ip API enums address_family and ip_proto size to u8
[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/ip/ip_types_api.h>
20 #include <vnet/fib/fib_table.h>
21 #include <vnet/mfib/mfib_table.h>
22 #include <vnet/bier/bier_disp_table.h>
23 #include <vpp/api/types.h>
24 #include <vnet/classify/vnet_classify.h>
25
26 #include <vnet/vnet_msg_enum.h>
27
28 #define vl_typedefs             /* define message structures */
29 #include <vnet/vnet_all_api_h.h>
30 #undef vl_typedefs
31
32 #define vl_endianfun            /* define message structures */
33 #include <vnet/vnet_all_api_h.h>
34 #undef vl_endianfun
35
36 /* instantiate all the print functions we know about */
37 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
38 #define vl_printfun
39 #include <vnet/vnet_all_api_h.h>
40 #undef vl_printfun
41
42 #include <vlibapi/api_helper_macros.h>
43
44 int
45 fib_api_table_id_decode (fib_protocol_t fproto,
46                          u32 table_id,
47                          u32 *fib_index)
48 {
49     *fib_index = fib_table_find(fproto, table_id);
50
51     if (INDEX_INVALID == *fib_index)
52     {
53         return VNET_API_ERROR_NO_SUCH_FIB;
54     }
55
56     return (0);
57 }
58
59 int
60 fib_api_mtable_id_decode (fib_protocol_t fproto,
61                           u32 table_id,
62                           u32 *fib_index)
63 {
64     *fib_index = mfib_table_find(fproto, table_id);
65
66     if (~0 == *fib_index)
67     {
68         return VNET_API_ERROR_NO_SUCH_FIB;
69     }
70
71     return (0);
72 }
73
74 static void
75 fib_api_next_hop_decode (const vl_api_fib_path_t *in,
76                          ip46_address_t *out)
77 {
78     if (in->proto == FIB_API_PATH_NH_PROTO_IP4)
79         clib_memcpy (&out->ip4, &in->nh.address.ip4, sizeof (out->ip4));
80     else if (in->proto == FIB_API_PATH_NH_PROTO_IP6)
81         clib_memcpy (&out->ip6, &in->nh.address.ip6, sizeof (out->ip6));
82 }
83
84 static vl_api_fib_path_nh_proto_t
85 fib_api_path_dpo_proto_to_nh (dpo_proto_t dproto)
86 {
87     switch (dproto)
88     {
89     case DPO_PROTO_IP4:
90         return (FIB_API_PATH_NH_PROTO_IP4);
91     case DPO_PROTO_IP6:
92         return (FIB_API_PATH_NH_PROTO_IP6);
93     case DPO_PROTO_MPLS:
94         return (FIB_API_PATH_NH_PROTO_MPLS);
95     case DPO_PROTO_BIER:
96         return (FIB_API_PATH_NH_PROTO_BIER);
97     case DPO_PROTO_ETHERNET:
98         return (FIB_API_PATH_NH_PROTO_ETHERNET);
99     case DPO_PROTO_NSH:
100         ASSERT(0);
101         break;
102     }
103     return (FIB_API_PATH_NH_PROTO_IP4);
104 }
105
106
107 static void
108 fib_api_next_hop_encode (const fib_route_path_t *rpath,
109                          vl_api_fib_path_t *fp)
110 {
111     fp->proto = fib_api_path_dpo_proto_to_nh(rpath->frp_proto);
112
113     if (rpath->frp_proto == DPO_PROTO_IP4)
114         clib_memcpy (&fp->nh.address.ip4,
115                 &rpath->frp_addr.ip4,
116                 sizeof (rpath->frp_addr.ip4));
117     else if (rpath->frp_proto == DPO_PROTO_IP6)
118         clib_memcpy (&fp->nh.address.ip6,
119                 &rpath->frp_addr.ip6,
120                 sizeof (rpath->frp_addr.ip6));
121 }
122
123 static int
124 fib_api_path_nh_proto_to_dpo (vl_api_fib_path_nh_proto_t pp,
125                               dpo_proto_t *dproto)
126 {
127     switch (pp)
128     {
129     case FIB_API_PATH_NH_PROTO_IP4:
130         *dproto = DPO_PROTO_IP4;
131         break;
132     case FIB_API_PATH_NH_PROTO_IP6:
133         *dproto = DPO_PROTO_IP6;
134         break;
135     case FIB_API_PATH_NH_PROTO_MPLS:
136         *dproto = DPO_PROTO_MPLS;
137         break;
138     case FIB_API_PATH_NH_PROTO_BIER:
139         *dproto = DPO_PROTO_BIER;
140         break;
141     case FIB_API_PATH_NH_PROTO_ETHERNET:
142         *dproto = DPO_PROTO_ETHERNET;
143         break;
144     default:
145         return (-1);
146     }
147     return (0);
148 }
149
150 int
151 fib_api_path_decode (vl_api_fib_path_t *in,
152                      fib_route_path_t *out)
153 {
154     vnet_classify_main_t *cm = &vnet_classify_main;
155     int rv = 0, n_labels;
156     vnet_main_t *vnm;
157     u8 ii;
158
159     vnm = vnet_get_main ();
160     clib_memset(&out->frp_dpo, 0, sizeof(out->frp_dpo));
161
162     /* enums are u32 */
163     in->flags = ntohl (in->flags);
164     in->type = ntohl (in->type);
165     in->proto = ntohl (in->proto);
166
167     /*
168      * attributes that apply to all path types
169      */
170     out->frp_flags = 0;
171     out->frp_weight = in->weight;
172     if (0 == out->frp_weight)
173     {
174         out->frp_weight = 1;
175     }
176     out->frp_preference = in->preference;
177
178     rv = fib_api_path_nh_proto_to_dpo(in->proto, &out->frp_proto);
179
180     if (0 != rv)
181         return (rv);
182
183     /*
184      * convert the flags and the AFI to determine the path type
185      */
186     if (in->flags & FIB_API_PATH_FLAG_RESOLVE_VIA_HOST)
187         out->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
188     if (in->flags & FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED)
189         out->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
190     if (in->flags & FIB_API_PATH_FLAG_POP_PW_CW)
191         out->frp_flags |= FIB_ROUTE_PATH_POP_PW_CW;
192
193     switch (in->type)
194     {
195     case FIB_API_PATH_TYPE_DVR:
196         out->frp_sw_if_index = ntohl(in->sw_if_index);
197         out->frp_flags |= FIB_ROUTE_PATH_DVR;
198         break;
199     case FIB_API_PATH_TYPE_INTERFACE_RX:
200         out->frp_sw_if_index = ntohl(in->sw_if_index);
201         out->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
202         break;
203     case FIB_API_PATH_TYPE_DROP:
204         out->frp_flags |= FIB_ROUTE_PATH_DROP;
205         break;
206     case FIB_API_PATH_TYPE_LOCAL:
207         out->frp_flags |= FIB_ROUTE_PATH_LOCAL;
208         out->frp_sw_if_index = ntohl(in->sw_if_index);
209         break;
210     case FIB_API_PATH_TYPE_ICMP_UNREACH:
211         out->frp_flags |= FIB_ROUTE_PATH_ICMP_UNREACH;
212         break;
213     case FIB_API_PATH_TYPE_ICMP_PROHIBIT:
214         out->frp_flags |= FIB_ROUTE_PATH_ICMP_PROHIBIT;
215         break;
216     case FIB_API_PATH_TYPE_CLASSIFY:
217         out->frp_flags |= FIB_ROUTE_PATH_CLASSIFY;
218
219         if (pool_is_free_index (cm->tables, ntohl (in->nh.classify_table_index)))
220         {
221             return VNET_API_ERROR_NO_SUCH_TABLE;
222         }
223         out->frp_classify_table_id = ntohl (in->nh.classify_table_index);
224         break;
225     case FIB_API_PATH_TYPE_UDP_ENCAP:
226         out->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
227         out->frp_udp_encap_id = ntohl(in->nh.obj_id);
228         break;
229     case FIB_API_PATH_TYPE_BIER_IMP:
230         out->frp_flags |= FIB_ROUTE_PATH_BIER_IMP;
231         out->frp_bier_imp = ntohl (in->nh.obj_id);
232         break;
233
234     case FIB_API_PATH_TYPE_SOURCE_LOOKUP:
235         out->frp_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
236         /* fall through */
237     case FIB_API_PATH_TYPE_NORMAL:
238         switch (out->frp_proto)
239         {
240         case DPO_PROTO_IP4:
241         case DPO_PROTO_IP6:
242             fib_api_next_hop_decode(in, &out->frp_addr);
243             out->frp_sw_if_index = ntohl(in->sw_if_index);
244             out->frp_rpf_id = ntohl(in->rpf_id);
245
246             if (0 == out->frp_rpf_id)
247             {
248                 /* allow 0 to be an unset value on the API */
249                 out->frp_rpf_id = ~0;
250             }
251
252             if (~0 != out->frp_rpf_id)
253             {
254                 out->frp_flags |= FIB_ROUTE_PATH_RPF_ID;
255             }
256
257             if (~0 == out->frp_sw_if_index)
258             {
259                 /* recursive or deag, validate the next-hop FIB */
260                 if (~0 != out->frp_rpf_id)
261                 {
262                     rv = fib_api_mtable_id_decode(
263                         dpo_proto_to_fib(out->frp_proto),
264                         ntohl(in->table_id),
265                         &out->frp_fib_index);
266                 }
267                 else
268                 {
269                     rv = fib_api_table_id_decode(
270                         dpo_proto_to_fib(out->frp_proto),
271                         ntohl(in->table_id),
272                         &out->frp_fib_index);
273                 }
274                 if (0 != rv)
275                 {
276                     return (rv);
277                 }
278             }
279             else
280             {
281                 if (pool_is_free_index (vnm->interface_main.sw_interfaces,
282                                         out->frp_sw_if_index))
283                 {
284                     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
285                 }
286             }
287
288             if (ip46_address_is_zero(&out->frp_addr))
289             {
290                 if (~0 == out->frp_sw_if_index &&
291                     ~0 != out->frp_fib_index)
292                 {
293                     out->frp_flags |= FIB_ROUTE_PATH_DEAG;
294                 }
295             }
296
297             break;
298         case DPO_PROTO_MPLS:
299             out->frp_local_label = ntohl (in->nh.via_label);
300             out->frp_eos = MPLS_NON_EOS;
301             out->frp_sw_if_index = ~0;
302             break;
303         case DPO_PROTO_BIER:
304             out->frp_sw_if_index = ntohl(in->sw_if_index);
305             out->frp_rpf_id = ntohl(in->rpf_id);
306
307             if (!(out->frp_flags & FIB_ROUTE_PATH_BIER_IMP))
308             {
309                 fib_api_next_hop_decode(in, &out->frp_addr);
310
311                 if (ip46_address_is_zero(&out->frp_addr))
312                 {
313                     index_t bdti;
314
315                     bdti = bier_disp_table_find(ntohl(in->table_id));
316
317                     if (INDEX_INVALID != bdti)
318                     {
319                         out->frp_fib_index = bdti;
320                     }
321                     else
322                     {
323                         return (VNET_API_ERROR_NO_SUCH_FIB);
324                     }
325                 }
326             }
327             break;
328         case DPO_PROTO_ETHERNET:
329             out->frp_sw_if_index = ntohl(in->sw_if_index);
330             break;
331         case DPO_PROTO_NSH:
332             break;
333         }
334     }
335
336     n_labels = in->n_labels;
337     if (n_labels != 0)
338     {
339         vec_validate (out->frp_label_stack, n_labels - 1);
340         for (ii = 0; ii < n_labels; ii++)
341         {
342             out->frp_label_stack[ii].fml_value =
343                 ntohl(in->label_stack[ii].label);
344             out->frp_label_stack[ii].fml_ttl =
345                 in->label_stack[ii].ttl;
346             out->frp_label_stack[ii].fml_exp =
347                 in->label_stack[ii].exp;
348             out->frp_label_stack[ii].fml_mode =
349                 (in->label_stack[ii].is_uniform ?
350                  FIB_MPLS_LSP_MODE_UNIFORM :
351                  FIB_MPLS_LSP_MODE_PIPE);
352         }
353     }
354
355     return (0);
356 }
357
358 void
359 fib_api_path_encode (const fib_route_path_t * rpath,
360                      vl_api_fib_path_t *out)
361 {
362     memset (out, 0, sizeof (*out));
363
364     out->weight = rpath->frp_weight;
365     out->preference = rpath->frp_preference;
366     out->sw_if_index = htonl (rpath->frp_sw_if_index);
367     out->proto = fib_api_path_dpo_proto_to_nh(rpath->frp_proto);
368     out->rpf_id = rpath->frp_rpf_id;
369     fib_api_next_hop_encode (rpath, out);
370
371     if (0 != rpath->frp_fib_index)
372     {
373         if ((DPO_PROTO_IP6 == rpath->frp_proto) ||
374             (DPO_PROTO_IP4 == rpath->frp_proto))
375         {
376             if (rpath->frp_flags & FIB_ROUTE_PATH_RPF_ID)
377             {
378                 out->table_id = htonl (mfib_table_get_table_id(
379                                            rpath->frp_fib_index,
380                                            dpo_proto_to_fib(rpath->frp_proto)));
381             }
382             else
383             {
384                 out->table_id = htonl (fib_table_get_table_id(
385                                            rpath->frp_fib_index,
386                                            dpo_proto_to_fib(rpath->frp_proto)));
387             }
388         }
389     }
390
391     if (rpath->frp_flags & FIB_ROUTE_PATH_DVR)
392     {
393         out->type = FIB_API_PATH_TYPE_DVR;
394     }
395     else if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_UNREACH)
396     {
397         out->type = FIB_API_PATH_TYPE_ICMP_UNREACH;
398     }
399     else if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_PROHIBIT)
400     {
401         out->type = FIB_API_PATH_TYPE_ICMP_PROHIBIT;
402     }
403     else if (rpath->frp_flags & FIB_ROUTE_PATH_LOCAL)
404     {
405         out->type = FIB_API_PATH_TYPE_LOCAL;
406     }
407     else if (rpath->frp_flags & FIB_ROUTE_PATH_DROP)
408     {
409         out->type = FIB_API_PATH_TYPE_DROP;
410     }
411     else if (rpath->frp_flags & FIB_ROUTE_PATH_UDP_ENCAP)
412     {
413         out->type = FIB_API_PATH_TYPE_UDP_ENCAP;
414         out->nh.obj_id = rpath->frp_udp_encap_id;
415     }
416     else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP)
417     {
418         out->type = FIB_API_PATH_TYPE_BIER_IMP;
419         out->nh.obj_id = rpath->frp_bier_imp;
420     }
421     else if (rpath->frp_flags & FIB_ROUTE_PATH_INTF_RX)
422     {
423         out->type = FIB_API_PATH_TYPE_INTERFACE_RX;
424     }
425     else
426     {
427         out->type = FIB_API_PATH_TYPE_NORMAL;
428     }
429     if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
430     {
431         out->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_HOST;
432     }
433     if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
434     {
435         out->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED;
436     }
437
438     out->flags = htonl (out->flags);
439     out->type = htonl (out->type);
440     out->proto = htonl (out->proto);
441
442     if (rpath->frp_label_stack)
443     {
444         int ii;
445
446         for (ii = 0; ii < vec_len(rpath->frp_label_stack); ii++)
447         {
448             out->label_stack[ii].label =
449                 htonl(rpath->frp_label_stack[ii].fml_value);
450             out->label_stack[ii].ttl =
451                 rpath->frp_label_stack[ii].fml_ttl;
452             out->label_stack[ii].exp =
453                 rpath->frp_label_stack[ii].fml_exp;
454         }
455         out->n_labels = ii;
456     }
457 }
458
459 int
460 fib_api_route_add_del (u8 is_add,
461                        u8 is_multipath,
462                        u32 fib_index,
463                        const fib_prefix_t * prefix,
464                        fib_entry_flag_t entry_flags,
465                        fib_route_path_t *rpaths)
466 {
467     if (is_multipath)
468     {
469         if (vec_len(rpaths) == 0)
470             return (VNET_API_ERROR_NO_PATHS_IN_ROUTE);
471
472         /* Iterative path add/remove */
473         if (is_add)
474             fib_table_entry_path_add2 (fib_index,
475                                        prefix,
476                                        FIB_SOURCE_API,
477                                        entry_flags,
478                                        rpaths);
479         else
480             fib_table_entry_path_remove2 (fib_index,
481                                           prefix,
482                                           FIB_SOURCE_API,
483                                           rpaths);
484     }
485     else
486     {
487         if (is_add)
488         {
489             if (vec_len(rpaths) == 0)
490                 return (VNET_API_ERROR_NO_PATHS_IN_ROUTE);
491
492             /* path replacement */
493             fib_table_entry_update (fib_index,
494                                     prefix,
495                                     FIB_SOURCE_API,
496                                     entry_flags,
497                                     rpaths);
498         }
499         else
500             /* entry delete */
501             fib_table_entry_delete (fib_index,
502                                     prefix,
503                                     FIB_SOURCE_API);
504     }
505
506     return (0);
507 }
508
509 u8*
510 format_vl_api_fib_path (u8 * s, va_list * args)
511 {
512     const vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t*);
513
514     s = format (s, "sw_if_index %d", ntohl (path->sw_if_index));
515     switch (clib_net_to_host_u32(path->proto))
516     {
517     case FIB_API_PATH_NH_PROTO_IP4:
518         s = format (s, " %U", format_vl_api_address_union,
519                     &path->nh.address, ADDRESS_IP4);
520         break;
521     case FIB_API_PATH_NH_PROTO_IP6:
522         s = format (s, " %U", format_vl_api_address_union,
523                     &path->nh.address, ADDRESS_IP6);
524         break;
525     default:
526         break;
527     }
528     s = format (s, " weight %d", path->weight);
529     s = format (s, " preference %d", path->preference);
530     s = format (s, " type %d", ntohl(path->type));
531     s = format (s, " proto %d", ntohl(path->proto));
532     s = format (s, " flags %d", ntohl(path->flags));
533     s = format (s, " n_labels %d", ntohl(path->n_labels));
534     s = format (s, " table-id %d", ntohl(path->table_id));
535     s = format (s, " rpf-id %d", ntohl(path->rpf_id));
536
537     return (s);
538 }
539
540 int
541 fib_proto_from_api_address_family (vl_api_address_family_t af, fib_protocol_t * out)
542 {
543     switch (af)
544     {
545     case ADDRESS_IP4:
546         *out = (FIB_PROTOCOL_IP4);
547         return (0);
548     case ADDRESS_IP6:
549         *out = (FIB_PROTOCOL_IP6);
550         return (0);
551     }
552
553     return (VNET_API_ERROR_INVALID_ADDRESS_FAMILY);
554 }
555
556 vl_api_address_family_t
557 fib_proto_to_api_address_family (fib_protocol_t fproto)
558 {
559     switch (fproto)
560     {
561     case FIB_PROTOCOL_IP4:
562         return (ADDRESS_IP4);
563     case FIB_PROTOCOL_IP6:
564         return (ADDRESS_IP6);
565     default:
566         break;
567     }
568
569     ASSERT(0);
570     return (ADDRESS_IP4);
571 }