Use IP address types on UDP encap API
[vpp.git] / src / vnet / fib / fib_types.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/ip/ip.h>
17
18 #include <vnet/fib/fib_types.h>
19 #include <vnet/fib/fib_internal.h>
20 #include <vnet/mpls/mpls.h>
21
22 /*
23  * arrays of protocol and link names
24  */
25 static const char* fib_protocol_names[] = FIB_PROTOCOLS;
26 static const char* vnet_link_names[] = VNET_LINKS;
27 static const char* fib_forw_chain_names[] = FIB_FORW_CHAINS;
28 static const char* fib_mpls_lsp_mode_names[] = FIB_MPLS_LSP_MODES;
29
30 u8 *
31 format_fib_protocol (u8 * s, va_list * ap)
32 {
33     fib_protocol_t proto = va_arg(*ap, int); // fib_protocol_t promotion
34
35     return (format (s, "%s", fib_protocol_names[proto]));
36 }
37
38 u8 *
39 format_vnet_link (u8 * s, va_list * ap)
40 {
41     vnet_link_t link = va_arg(*ap, int); // vnet_link_t promotion
42
43     return (format (s, "%s", vnet_link_names[link]));
44 }
45
46 u8 *
47 format_fib_forw_chain_type (u8 * s, va_list * args)
48 {
49     fib_forward_chain_type_t fct = va_arg(*args, int);
50
51     return (format (s, "%s", fib_forw_chain_names[fct]));
52 }
53
54 u8 *
55 format_fib_mpls_lsp_mode(u8 *s, va_list *ap)
56 {
57     fib_mpls_lsp_mode_t mode = va_arg(*ap, int);
58
59     return (format (s, "%s", fib_mpls_lsp_mode_names[mode])); 
60 }
61
62 u8 *
63 format_fib_mpls_label (u8 *s, va_list *ap)
64 {
65     fib_mpls_label_t *label = va_arg(*ap, fib_mpls_label_t *);
66
67     s = format(s, "%U %U ttl:%d exp:%d",
68                format_mpls_unicast_label,
69                label->fml_value,
70                format_fib_mpls_lsp_mode,
71                label->fml_mode,
72                label->fml_ttl,
73                label->fml_exp);
74
75     return (s);
76 }
77
78 void
79 fib_prefix_from_ip46_addr (const ip46_address_t *addr,
80                            fib_prefix_t *pfx)
81 {
82     ASSERT(!ip46_address_is_zero(addr));
83
84     pfx->fp_proto = ((ip46_address_is_ip4(addr) ?
85                       FIB_PROTOCOL_IP4 :
86                       FIB_PROTOCOL_IP6));
87     pfx->fp_len = ((ip46_address_is_ip4(addr) ?
88                     32 : 128));
89     pfx->fp_addr = *addr;
90 }
91
92 void
93 fib_prefix_from_mpls_label (mpls_label_t label,
94                             mpls_eos_bit_t eos,
95                             fib_prefix_t *pfx)
96 {
97     pfx->fp_proto = FIB_PROTOCOL_MPLS;
98     pfx->fp_len = 21;
99     pfx->fp_label = label;
100     pfx->fp_eos = eos;
101 }
102
103 int
104 fib_prefix_cmp (const fib_prefix_t *p1,
105                 const fib_prefix_t *p2)
106 {
107     int res;
108
109     res = (p1->fp_proto - p2->fp_proto);
110
111     if (0 == res)
112     {
113         switch (p1->fp_proto)
114         {
115         case FIB_PROTOCOL_IP4:
116         case FIB_PROTOCOL_IP6:
117             res = (p1->fp_len - p2->fp_len);
118
119             if (0 == res)
120             {
121                 res = ip46_address_cmp(&p1->fp_addr, &p2->fp_addr);
122             }
123             break;
124         case FIB_PROTOCOL_MPLS:
125             res = (p1->fp_label - p2->fp_label);
126
127             if (0 == res)
128             {
129                 res = (p1->fp_eos - p2->fp_eos);
130             }
131             break;
132         }
133     }
134
135     return (res);
136 }
137
138 int
139 fib_prefix_is_cover (const fib_prefix_t *p1,
140                      const fib_prefix_t *p2)
141 {
142     switch (p1->fp_proto)
143     {
144     case FIB_PROTOCOL_IP4:
145         return (ip4_destination_matches_route(&ip4_main,
146                                               &p1->fp_addr.ip4,
147                                               &p2->fp_addr.ip4,
148                                               p1->fp_len));
149     case FIB_PROTOCOL_IP6:
150         return (ip6_destination_matches_route(&ip6_main,
151                                               &p1->fp_addr.ip6,
152                                               &p2->fp_addr.ip6,
153                                               p1->fp_len));
154     case FIB_PROTOCOL_MPLS:
155         break;
156     }
157     return (0);
158 }
159
160 int
161 fib_prefix_is_host (const fib_prefix_t *prefix)
162 {
163     switch (prefix->fp_proto)
164     {
165     case FIB_PROTOCOL_IP4:
166         return (prefix->fp_len == 32);
167     case FIB_PROTOCOL_IP6:
168         return (prefix->fp_len == 128);
169     case FIB_PROTOCOL_MPLS:
170         return (!0);
171     }
172     return (0);
173 }
174
175 u8 *
176 format_fib_prefix (u8 * s, va_list * args)
177 {
178     fib_prefix_t *fp = va_arg (*args, fib_prefix_t *);
179
180     /*
181      * protocol specific so it prints ::/0 correctly.
182      */
183     switch (fp->fp_proto)
184     {
185     case FIB_PROTOCOL_IP6:
186     {
187         ip6_address_t p6 = fp->fp_addr.ip6;
188
189         ip6_address_mask(&p6, &(ip6_main.fib_masks[fp->fp_len]));
190         s = format (s, "%U", format_ip6_address, &p6);
191         break;
192     }
193     case FIB_PROTOCOL_IP4:
194     {
195         ip4_address_t p4 = fp->fp_addr.ip4;
196         p4.as_u32 &= ip4_main.fib_masks[fp->fp_len];
197
198         s = format (s, "%U", format_ip4_address, &p4);
199         break;
200     }
201     case FIB_PROTOCOL_MPLS:
202         s = format (s, "%U:%U",
203                     format_mpls_unicast_label, fp->fp_label,
204                     format_mpls_eos_bit, fp->fp_eos);
205         break;
206     }
207     s = format (s, "/%d", fp->fp_len);
208
209     return (s);
210 }
211
212 int
213 fib_route_path_cmp (const fib_route_path_t *rpath1,
214                     const fib_route_path_t *rpath2)
215 {
216     int res;
217
218     res = ip46_address_cmp(&rpath1->frp_addr,
219                            &rpath2->frp_addr);
220
221     if (0 != res) return (res);
222
223     res = (rpath1->frp_sw_if_index - rpath2->frp_sw_if_index);
224
225     if (0 != res) return (res);
226
227     if (ip46_address_is_zero(&rpath1->frp_addr))
228     {
229         res = rpath1->frp_fib_index - rpath2->frp_fib_index;
230     }
231
232     return (res);
233 }
234
235 dpo_proto_t
236 fib_proto_to_dpo (fib_protocol_t fib_proto)
237 {
238     switch (fib_proto)
239     {
240     case FIB_PROTOCOL_IP6:
241         return (DPO_PROTO_IP6);
242     case FIB_PROTOCOL_IP4:
243         return (DPO_PROTO_IP4);
244     case FIB_PROTOCOL_MPLS:
245         return (DPO_PROTO_MPLS);
246     }
247     ASSERT(0);
248     return (0);
249 }
250
251 fib_protocol_t
252 dpo_proto_to_fib (dpo_proto_t dpo_proto)
253 {
254     switch (dpo_proto)
255     {
256     case DPO_PROTO_IP6:
257         return (FIB_PROTOCOL_IP6);
258     case DPO_PROTO_IP4:
259         return (FIB_PROTOCOL_IP4);
260     case DPO_PROTO_MPLS:
261         return (FIB_PROTOCOL_MPLS);
262     default:
263         break;
264     }
265     ASSERT(0);
266     return (0);
267 }
268
269 vnet_link_t
270 fib_proto_to_link (fib_protocol_t proto)
271 {
272     switch (proto)
273     {
274     case FIB_PROTOCOL_IP4:
275         return (VNET_LINK_IP4);
276     case FIB_PROTOCOL_IP6:
277         return (VNET_LINK_IP6);
278     case FIB_PROTOCOL_MPLS:
279         return (VNET_LINK_MPLS);
280     }
281     ASSERT(0);
282     return (0);
283 }
284
285 ip46_type_t
286 fib_proto_to_ip46 (fib_protocol_t fproto)
287 {
288     switch (fproto)
289     {
290     case FIB_PROTOCOL_IP4:
291         return (IP46_TYPE_IP4);
292     case FIB_PROTOCOL_IP6:
293         return (IP46_TYPE_IP6);
294     case FIB_PROTOCOL_MPLS:
295         return (IP46_TYPE_ANY);
296     }
297     ASSERT(0);
298     return (IP46_TYPE_ANY);
299 }
300
301 fib_protocol_t
302 fib_proto_from_ip46 (ip46_type_t iproto)
303 {
304     switch (iproto)
305     {
306     case IP46_TYPE_IP4:
307         return FIB_PROTOCOL_IP4;
308     case IP46_TYPE_IP6:
309         return FIB_PROTOCOL_IP6;
310     case IP46_TYPE_ANY:
311         ASSERT(0);
312         return FIB_PROTOCOL_IP4;
313     }
314
315     ASSERT(0);
316     return FIB_PROTOCOL_IP4;
317 }
318
319 fib_forward_chain_type_t
320 fib_forw_chain_type_from_dpo_proto (dpo_proto_t proto)
321 {
322     switch (proto)
323     {
324     case DPO_PROTO_IP4:
325         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
326     case DPO_PROTO_IP6:
327         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
328     case DPO_PROTO_MPLS:
329         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
330     case DPO_PROTO_ETHERNET:
331         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
332     case DPO_PROTO_NSH:
333         return (FIB_FORW_CHAIN_TYPE_NSH);
334     case DPO_PROTO_BIER:
335         return (FIB_FORW_CHAIN_TYPE_BIER);
336     }
337     ASSERT(0);
338     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
339 }
340
341 vnet_link_t
342 fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct)
343 {
344     switch (fct)
345     {
346     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
347     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
348         return (VNET_LINK_IP4);
349     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
350     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
351         return (VNET_LINK_IP6);
352     case FIB_FORW_CHAIN_TYPE_ETHERNET:
353         return (VNET_LINK_ETHERNET);
354     case FIB_FORW_CHAIN_TYPE_NSH:
355         return (VNET_LINK_NSH);
356     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
357     case FIB_FORW_CHAIN_TYPE_BIER:
358         /*
359          * insufficient information to to convert
360          */
361         ASSERT(0);
362         break;
363     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
364         return (VNET_LINK_MPLS);
365     }
366     return (VNET_LINK_IP4);
367 }
368
369 fib_forward_chain_type_t
370 fib_forw_chain_type_from_link_type (vnet_link_t link_type)
371 {
372     switch (link_type)
373     {
374     case VNET_LINK_IP4:
375         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
376     case VNET_LINK_IP6:
377         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
378     case VNET_LINK_MPLS:
379         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
380     case VNET_LINK_ETHERNET:
381         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
382     case VNET_LINK_NSH:
383         return (FIB_FORW_CHAIN_TYPE_NSH);
384     case VNET_LINK_ARP:
385         break;
386     }
387
388     ASSERT(0);
389     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
390 }
391
392 dpo_proto_t
393 fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct)
394 {
395     switch (fct)
396     {
397     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
398     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
399         return (DPO_PROTO_IP4);
400     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
401     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
402         return (DPO_PROTO_IP6);
403     case FIB_FORW_CHAIN_TYPE_ETHERNET:
404         return (DPO_PROTO_ETHERNET);
405     case FIB_FORW_CHAIN_TYPE_NSH:
406         return (DPO_PROTO_NSH);
407     case FIB_FORW_CHAIN_TYPE_BIER:
408         return (DPO_PROTO_BIER);
409     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
410     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
411         return (DPO_PROTO_MPLS);
412     }
413     return (DPO_PROTO_IP4);
414 }
415
416 uword
417 unformat_fib_route_path (unformat_input_t * input, va_list * args)
418 {
419     fib_route_path_t *rpath = va_arg (*args, fib_route_path_t *);
420     u32 *payload_proto = va_arg (*args, u32*);
421     u32 weight, preference, udp_encap_id;
422     mpls_label_t out_label;
423     vnet_main_t *vnm;
424
425     vnm = vnet_get_main ();
426     memset(rpath, 0, sizeof(*rpath));
427     rpath->frp_weight = 1;
428     rpath->frp_sw_if_index = ~0;
429
430     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
431     {
432         if (unformat (input, "%U %U",
433                       unformat_ip4_address,
434                       &rpath->frp_addr.ip4,
435                       unformat_vnet_sw_interface, vnm,
436                       &rpath->frp_sw_if_index))
437         {
438             rpath->frp_proto = DPO_PROTO_IP4;
439         }
440         else if (unformat (input, "%U %U",
441                            unformat_ip6_address,
442                            &rpath->frp_addr.ip6,
443                            unformat_vnet_sw_interface, vnm,
444                            &rpath->frp_sw_if_index))
445         {
446             rpath->frp_proto = DPO_PROTO_IP6;
447         }
448         else if (unformat (input, "weight %u", &weight))
449         {
450             rpath->frp_weight = weight;
451         }
452         else if (unformat (input, "preference %u", &preference))
453         {
454             rpath->frp_preference = preference;
455         }
456         else if (unformat (input, "%U next-hop-table %d",
457                            unformat_ip4_address,
458                            &rpath->frp_addr.ip4,
459                            &rpath->frp_fib_index))
460         {
461             rpath->frp_sw_if_index = ~0;
462             rpath->frp_proto = DPO_PROTO_IP4;
463         }
464         else if (unformat (input, "%U next-hop-table %d",
465                            unformat_ip6_address,
466                            &rpath->frp_addr.ip6,
467                            &rpath->frp_fib_index))
468         {
469             rpath->frp_sw_if_index = ~0;
470             rpath->frp_proto = DPO_PROTO_IP6;
471         }
472         else if (unformat (input, "%U",
473                            unformat_ip4_address,
474                            &rpath->frp_addr.ip4))
475         {
476             /*
477              * the recursive next-hops are by default in the default table
478              */
479             rpath->frp_fib_index = 0;
480             rpath->frp_sw_if_index = ~0;
481             rpath->frp_proto = DPO_PROTO_IP4;
482         }
483         else if (unformat (input, "%U",
484                            unformat_ip6_address,
485                            &rpath->frp_addr.ip6))
486         {
487             rpath->frp_fib_index = 0;
488             rpath->frp_sw_if_index = ~0;
489             rpath->frp_proto = DPO_PROTO_IP6;
490         }
491         else if (unformat (input, "udp-encap %d", &udp_encap_id))
492         {
493             rpath->frp_udp_encap_id = udp_encap_id;
494             rpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
495             rpath->frp_proto = *payload_proto;
496         }
497         else if (unformat (input, "lookup in table %d", &rpath->frp_fib_index))
498         {
499             rpath->frp_proto = *payload_proto;
500             rpath->frp_sw_if_index = ~0;
501             rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
502         }
503         else if (unformat (input, "resolve-via-host"))
504         {
505             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
506         }
507         else if (unformat (input, "resolve-via-attached"))
508         {
509             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
510         }
511         else if (unformat (input,
512                            "ip4-lookup-in-table %d",
513                            &rpath->frp_fib_index))
514         {
515             rpath->frp_proto = DPO_PROTO_IP4;
516             *payload_proto = DPO_PROTO_IP4;
517         }
518         else if (unformat (input,
519                            "ip6-lookup-in-table %d",
520                            &rpath->frp_fib_index))
521         {
522             rpath->frp_proto = DPO_PROTO_IP6;
523             *payload_proto = DPO_PROTO_IP6;
524         }
525         else if (unformat (input,
526                            "mpls-lookup-in-table %d",
527                            &rpath->frp_fib_index))
528         {
529             rpath->frp_proto = DPO_PROTO_MPLS;
530             *payload_proto = DPO_PROTO_MPLS;
531         }
532         else if (unformat (input, "src-lookup"))
533         {
534             rpath->frp_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
535         }
536         else if (unformat (input,
537                            "l2-input-on %U",
538                            unformat_vnet_sw_interface, vnm,
539                            &rpath->frp_sw_if_index))
540         {
541             rpath->frp_proto = DPO_PROTO_ETHERNET;
542             *payload_proto = DPO_PROTO_ETHERNET;
543             rpath->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
544         }
545         else if (unformat (input, "via-label %U",
546                            unformat_mpls_unicast_label,
547                            &rpath->frp_local_label))
548         {
549             rpath->frp_eos = MPLS_NON_EOS;
550             rpath->frp_proto = DPO_PROTO_MPLS;
551             rpath->frp_sw_if_index = ~0;
552         }
553         else if (unformat (input, "rx-ip4 %U",
554                            unformat_vnet_sw_interface, vnm,
555                            &rpath->frp_sw_if_index))
556         {
557             rpath->frp_proto = DPO_PROTO_IP4;
558             rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX;
559         }
560         else if (unformat (input, "out-labels"))
561         {
562             while (unformat (input, "%U",
563                              unformat_mpls_unicast_label, &out_label))
564             {
565                 fib_mpls_label_t fml = {
566                     .fml_value = out_label,
567                 };
568                 vec_add1(rpath->frp_label_stack, fml);
569             }
570         }
571         else if (unformat (input, "%U",
572                            unformat_vnet_sw_interface, vnm,
573                            &rpath->frp_sw_if_index))
574         {
575             rpath->frp_proto = *payload_proto;
576         }
577         else
578         {
579             return (0);
580         }
581     }
582
583     return (1);
584 }