7eeb79fffa58e26d8251631212bd2d8ee0aed69e
[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/fib/fib_table.h>
21 #include <vnet/mfib/mfib_types.h>
22 #include <vnet/mpls/mpls.h>
23
24 /*
25  * arrays of protocol and link names
26  */
27 static const char* fib_protocol_names[] = FIB_PROTOCOLS;
28 static const char* vnet_link_names[] = VNET_LINKS;
29 static const char* fib_forw_chain_names[] = FIB_FORW_CHAINS;
30 static const char* fib_mpls_lsp_mode_names[] = FIB_MPLS_LSP_MODES;
31
32 u8 *
33 format_fib_protocol (u8 * s, va_list * ap)
34 {
35     fib_protocol_t proto = va_arg(*ap, int); // fib_protocol_t promotion
36
37     return (format (s, "%s", fib_protocol_names[proto]));
38 }
39
40 u8 *
41 format_vnet_link (u8 * s, va_list * ap)
42 {
43     vnet_link_t link = va_arg(*ap, int); // vnet_link_t promotion
44
45     return (format (s, "%s", vnet_link_names[link]));
46 }
47
48 u8 *
49 format_fib_forw_chain_type (u8 * s, va_list * args)
50 {
51     fib_forward_chain_type_t fct = va_arg(*args, int);
52
53     return (format (s, "%s", fib_forw_chain_names[fct]));
54 }
55
56 u8 *
57 format_fib_mpls_lsp_mode(u8 *s, va_list *ap)
58 {
59     fib_mpls_lsp_mode_t mode = va_arg(*ap, int);
60
61     return (format (s, "%s", fib_mpls_lsp_mode_names[mode])); 
62 }
63
64 u8 *
65 format_fib_mpls_label (u8 *s, va_list *ap)
66 {
67     fib_mpls_label_t *label = va_arg(*ap, fib_mpls_label_t *);
68
69     s = format(s, "%U %U ttl:%d exp:%d",
70                format_mpls_unicast_label,
71                label->fml_value,
72                format_fib_mpls_lsp_mode,
73                label->fml_mode,
74                label->fml_ttl,
75                label->fml_exp);
76
77     return (s);
78 }
79
80 void
81 fib_prefix_from_ip46_addr (const ip46_address_t *addr,
82                            fib_prefix_t *pfx)
83 {
84     ASSERT(!ip46_address_is_zero(addr));
85
86     pfx->fp_proto = ((ip46_address_is_ip4(addr) ?
87                       FIB_PROTOCOL_IP4 :
88                       FIB_PROTOCOL_IP6));
89     pfx->fp_len = ((ip46_address_is_ip4(addr) ?
90                     32 : 128));
91     pfx->fp_addr = *addr;
92     pfx->___fp___pad = 0;
93 }
94
95 u8 *
96 format_fib_route_path_flags (u8 *s, va_list *ap)
97 {
98     fib_route_path_flags_t flags = va_arg (*ap, fib_route_path_flags_t);
99
100     if (flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
101         s = format (s, "via-host");
102     if (flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
103         s = format (s, "via-attached,");
104     if (flags & FIB_ROUTE_PATH_LOCAL)
105         s = format (s, "local,");
106     if (flags & FIB_ROUTE_PATH_ATTACHED)
107         s = format (s, "attached,");
108     if (flags & FIB_ROUTE_PATH_DROP)
109          s = format (s, "drop,");
110    if (flags & FIB_ROUTE_PATH_EXCLUSIVE)
111         s = format (s, "exclusive,");
112     if (flags & FIB_ROUTE_PATH_INTF_RX)
113         s = format (s, "intf-rx,");
114     if (flags & FIB_ROUTE_PATH_RPF_ID)
115         s = format (s, "rpf-id,");
116     if (flags & FIB_ROUTE_PATH_SOURCE_LOOKUP)
117         s = format (s, "src-lkup,");
118     if (flags & FIB_ROUTE_PATH_UDP_ENCAP)
119         s = format (s, "udp-encap,");
120     if (flags & FIB_ROUTE_PATH_BIER_FMASK)
121         s = format (s, "bier-fmask,");
122     if (flags & FIB_ROUTE_PATH_BIER_TABLE)
123         s = format (s, "bier-table,");
124     if (flags & FIB_ROUTE_PATH_BIER_IMP)
125         s = format (s, "bier-imp,");
126     if (flags & FIB_ROUTE_PATH_DEAG)
127         s = format (s, "deag,");
128     if (flags & FIB_ROUTE_PATH_DVR)
129         s = format (s, "dvr,");
130     if (flags & FIB_ROUTE_PATH_ICMP_UNREACH)
131         s = format (s, "imcp-unreach,");
132     if (flags & FIB_ROUTE_PATH_ICMP_PROHIBIT)
133         s = format (s, "icmp-prohibit,");
134     if (flags & FIB_ROUTE_PATH_CLASSIFY)
135         s = format (s, "classify,");
136     if (flags & FIB_ROUTE_PATH_POP_PW_CW)
137         s = format (s, "pop-pw-cw,");
138
139     return (s);
140 }
141
142 u8 *
143 format_fib_route_path (u8 *s, va_list *ap)
144 {
145     fib_route_path_t *rpath = va_arg (*ap, fib_route_path_t*);
146
147     s = format (s, "%U %U, %U, [%U]",
148                 format_dpo_proto, rpath->frp_proto,
149                 format_ip46_address, &rpath->frp_addr, IP46_TYPE_ANY,
150                 format_vnet_sw_if_index_name, vnet_get_main (),
151                 rpath->frp_sw_if_index,
152                 format_fib_route_path_flags, rpath->frp_flags);
153
154     return (s);
155 }
156
157 void
158 fib_prefix_from_mpls_label (mpls_label_t label,
159                             mpls_eos_bit_t eos,
160                             fib_prefix_t *pfx)
161 {
162     pfx->fp_proto = FIB_PROTOCOL_MPLS;
163     pfx->fp_len = 21;
164     pfx->fp_label = label;
165     pfx->fp_eos = eos;
166     pfx->___fp___pad = 0;
167 }
168
169 void
170 fib_prefix_copy (fib_prefix_t *dst,
171                  const fib_prefix_t *src)
172 {
173     clib_memcpy(dst, src, sizeof(*dst));
174 }
175
176 int
177 fib_prefix_cmp (const fib_prefix_t *p1,
178                 const fib_prefix_t *p2)
179 {
180     int res;
181
182     res = (p1->fp_proto - p2->fp_proto);
183
184     if (0 == res)
185     {
186         switch (p1->fp_proto)
187         {
188         case FIB_PROTOCOL_IP4:
189         case FIB_PROTOCOL_IP6:
190             res = (p1->fp_len - p2->fp_len);
191
192             if (0 == res)
193             {
194                 res = ip46_address_cmp(&p1->fp_addr, &p2->fp_addr);
195             }
196             break;
197         case FIB_PROTOCOL_MPLS:
198             res = (p1->fp_label - p2->fp_label);
199
200             if (0 == res)
201             {
202                 res = (p1->fp_eos - p2->fp_eos);
203             }
204             break;
205         }
206     }
207
208     return (res);
209 }
210
211 int
212 fib_prefix_is_cover (const fib_prefix_t *p1,
213                      const fib_prefix_t *p2)
214 {
215     switch (p1->fp_proto)
216     {
217     case FIB_PROTOCOL_IP4:
218         return (ip4_destination_matches_route(&ip4_main,
219                                               &p1->fp_addr.ip4,
220                                               &p2->fp_addr.ip4,
221                                               p1->fp_len));
222     case FIB_PROTOCOL_IP6:
223         return (ip6_destination_matches_route(&ip6_main,
224                                               &p1->fp_addr.ip6,
225                                               &p2->fp_addr.ip6,
226                                               p1->fp_len));
227     case FIB_PROTOCOL_MPLS:
228         break;
229     }
230     return (0);
231 }
232
233 u8
234 fib_prefix_get_host_length (fib_protocol_t proto)
235 {
236     switch (proto)
237     {
238     case FIB_PROTOCOL_IP4:
239         return (32);
240     case FIB_PROTOCOL_IP6:
241         return (128);
242     case FIB_PROTOCOL_MPLS:
243         return (21);
244     }
245     return (0);
246 }
247
248 int
249 fib_prefix_is_host (const fib_prefix_t *prefix)
250 {
251     switch (prefix->fp_proto)
252     {
253     case FIB_PROTOCOL_IP4:
254         return (prefix->fp_len == 32);
255     case FIB_PROTOCOL_IP6:
256         return (prefix->fp_len == 128);
257     case FIB_PROTOCOL_MPLS:
258         return (!0);
259     }
260     return (0);
261 }
262
263 void
264 fib_prefix_normalize (const fib_prefix_t *p,
265                       fib_prefix_t *out)
266 {
267     fib_prefix_copy (out, p);
268
269     switch (p->fp_proto)
270     {
271     case FIB_PROTOCOL_IP4:
272         ip4_address_normalize(&out->fp_addr.ip4, out->fp_len);
273         break;
274     case FIB_PROTOCOL_IP6:
275         ip6_address_normalize(&out->fp_addr.ip6, out->fp_len);
276         break;
277     case FIB_PROTOCOL_MPLS:
278         break;
279     }
280 }
281
282 u8 *
283 format_fib_prefix (u8 * s, va_list * args)
284 {
285     fib_prefix_t *fp = va_arg (*args, fib_prefix_t *);
286
287     /*
288      * protocol specific so it prints ::/0 correctly.
289      */
290     switch (fp->fp_proto)
291     {
292     case FIB_PROTOCOL_IP6:
293     {
294         ip6_address_t p6 = fp->fp_addr.ip6;
295
296         ip6_address_mask(&p6, &(ip6_main.fib_masks[fp->fp_len]));
297         s = format (s, "%U", format_ip6_address, &p6);
298         break;
299     }
300     case FIB_PROTOCOL_IP4:
301     {
302         ip4_address_t p4 = fp->fp_addr.ip4;
303         p4.as_u32 &= ip4_main.fib_masks[fp->fp_len];
304
305         s = format (s, "%U", format_ip4_address, &p4);
306         break;
307     }
308     case FIB_PROTOCOL_MPLS:
309         s = format (s, "%U:%U",
310                     format_mpls_unicast_label, fp->fp_label,
311                     format_mpls_eos_bit, fp->fp_eos);
312         break;
313     }
314     s = format (s, "/%d", fp->fp_len);
315
316     return (s);
317 }
318
319 int
320 fib_route_path_cmp (const fib_route_path_t *rpath1,
321                     const fib_route_path_t *rpath2)
322 {
323     int res;
324
325     res = ip46_address_cmp(&rpath1->frp_addr,
326                            &rpath2->frp_addr);
327
328     if (0 != res) return (res);
329
330     res = (rpath1->frp_sw_if_index - rpath2->frp_sw_if_index);
331
332     if (0 != res) return (res);
333
334     if (ip46_address_is_zero(&rpath1->frp_addr))
335     {
336         res = rpath1->frp_fib_index - rpath2->frp_fib_index;
337     }
338
339     return (res);
340 }
341
342 dpo_proto_t
343 fib_proto_to_dpo (fib_protocol_t fib_proto)
344 {
345     switch (fib_proto)
346     {
347     case FIB_PROTOCOL_IP6:
348         return (DPO_PROTO_IP6);
349     case FIB_PROTOCOL_IP4:
350         return (DPO_PROTO_IP4);
351     case FIB_PROTOCOL_MPLS:
352         return (DPO_PROTO_MPLS);
353     }
354     ASSERT(0);
355     return (0);
356 }
357
358 fib_protocol_t
359 dpo_proto_to_fib (dpo_proto_t dpo_proto)
360 {
361     switch (dpo_proto)
362     {
363     case DPO_PROTO_IP6:
364         return (FIB_PROTOCOL_IP6);
365     case DPO_PROTO_IP4:
366         return (FIB_PROTOCOL_IP4);
367     case DPO_PROTO_MPLS:
368         return (FIB_PROTOCOL_MPLS);
369     default:
370         break;
371     }
372     ASSERT(0);
373     return (0);
374 }
375
376 vnet_link_t
377 fib_proto_to_link (fib_protocol_t proto)
378 {
379     switch (proto)
380     {
381     case FIB_PROTOCOL_IP4:
382         return (VNET_LINK_IP4);
383     case FIB_PROTOCOL_IP6:
384         return (VNET_LINK_IP6);
385     case FIB_PROTOCOL_MPLS:
386         return (VNET_LINK_MPLS);
387     }
388     ASSERT(0);
389     return (0);
390 }
391
392 ip46_type_t
393 fib_proto_to_ip46 (fib_protocol_t fproto)
394 {
395     switch (fproto)
396     {
397     case FIB_PROTOCOL_IP4:
398         return (IP46_TYPE_IP4);
399     case FIB_PROTOCOL_IP6:
400         return (IP46_TYPE_IP6);
401     case FIB_PROTOCOL_MPLS:
402         return (IP46_TYPE_ANY);
403     }
404     ASSERT(0);
405     return (IP46_TYPE_ANY);
406 }
407
408 fib_protocol_t
409 fib_proto_from_ip46 (ip46_type_t iproto)
410 {
411     switch (iproto)
412     {
413     case IP46_TYPE_IP4:
414         return FIB_PROTOCOL_IP4;
415     case IP46_TYPE_IP6:
416         return FIB_PROTOCOL_IP6;
417     case IP46_TYPE_ANY:
418         ASSERT(0);
419         return FIB_PROTOCOL_IP4;
420     }
421
422     ASSERT(0);
423     return FIB_PROTOCOL_IP4;
424 }
425
426 fib_forward_chain_type_t
427 fib_forw_chain_type_from_dpo_proto (dpo_proto_t proto)
428 {
429     switch (proto)
430     {
431     case DPO_PROTO_IP4:
432         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
433     case DPO_PROTO_IP6:
434         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
435     case DPO_PROTO_MPLS:
436         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
437     case DPO_PROTO_ETHERNET:
438         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
439     case DPO_PROTO_NSH:
440         return (FIB_FORW_CHAIN_TYPE_NSH);
441     case DPO_PROTO_BIER:
442         return (FIB_FORW_CHAIN_TYPE_BIER);
443     }
444     ASSERT(0);
445     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
446 }
447
448 fib_forward_chain_type_t
449 fib_forw_chain_type_from_fib_proto (fib_protocol_t proto)
450 {
451     switch (proto)
452     {
453     case FIB_PROTOCOL_IP4:
454         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
455     case FIB_PROTOCOL_IP6:
456         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
457     case FIB_PROTOCOL_MPLS:
458         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
459     }
460     ASSERT(0);
461     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
462 }
463
464 vnet_link_t
465 fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct)
466 {
467     switch (fct)
468     {
469     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
470     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
471         return (VNET_LINK_IP4);
472     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
473     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
474         return (VNET_LINK_IP6);
475     case FIB_FORW_CHAIN_TYPE_ETHERNET:
476         return (VNET_LINK_ETHERNET);
477     case FIB_FORW_CHAIN_TYPE_NSH:
478         return (VNET_LINK_NSH);
479     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
480     case FIB_FORW_CHAIN_TYPE_BIER:
481         /*
482          * insufficient information to to convert
483          */
484         ASSERT(0);
485         break;
486     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
487         return (VNET_LINK_MPLS);
488     }
489     return (VNET_LINK_IP4);
490 }
491
492 fib_forward_chain_type_t
493 fib_forw_chain_type_from_link_type (vnet_link_t link_type)
494 {
495     switch (link_type)
496     {
497     case VNET_LINK_IP4:
498         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
499     case VNET_LINK_IP6:
500         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
501     case VNET_LINK_MPLS:
502         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
503     case VNET_LINK_ETHERNET:
504         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
505     case VNET_LINK_NSH:
506         return (FIB_FORW_CHAIN_TYPE_NSH);
507     case VNET_LINK_ARP:
508         break;
509     }
510
511     ASSERT(0);
512     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
513 }
514
515 dpo_proto_t
516 fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct)
517 {
518     switch (fct)
519     {
520     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
521     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
522         return (DPO_PROTO_IP4);
523     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
524     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
525         return (DPO_PROTO_IP6);
526     case FIB_FORW_CHAIN_TYPE_ETHERNET:
527         return (DPO_PROTO_ETHERNET);
528     case FIB_FORW_CHAIN_TYPE_NSH:
529         return (DPO_PROTO_NSH);
530     case FIB_FORW_CHAIN_TYPE_BIER:
531         return (DPO_PROTO_BIER);
532     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
533     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
534         return (DPO_PROTO_MPLS);
535     }
536     return (DPO_PROTO_IP4);
537 }
538
539 uword
540 unformat_fib_route_path (unformat_input_t * input, va_list * args)
541 {
542     fib_route_path_t *rpath = va_arg (*args, fib_route_path_t *);
543     dpo_proto_t *payload_proto = va_arg (*args, void*);
544     dpo_proto_t explicit_proto = DPO_PROTO_NONE;
545     u32 weight, preference, udp_encap_id, fi;
546     mpls_label_t out_label;
547     vnet_main_t *vnm;
548
549     vnm = vnet_get_main ();
550     clib_memset(rpath, 0, sizeof(*rpath));
551     rpath->frp_weight = 1;
552     rpath->frp_sw_if_index = ~0;
553
554     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
555     {
556         if (unformat (input, "%U %U",
557                       unformat_ip4_address,
558                       &rpath->frp_addr.ip4,
559                       unformat_vnet_sw_interface, vnm,
560                       &rpath->frp_sw_if_index))
561         {
562             rpath->frp_proto = DPO_PROTO_IP4;
563         }
564         else if (unformat (input, "%U %U",
565                            unformat_ip6_address,
566                            &rpath->frp_addr.ip6,
567                            unformat_vnet_sw_interface, vnm,
568                            &rpath->frp_sw_if_index))
569         {
570             rpath->frp_proto = DPO_PROTO_IP6;
571         }
572         else if (unformat (input, "weight %u", &weight))
573         {
574             rpath->frp_weight = weight;
575         }
576         else if (unformat (input, "preference %u", &preference))
577         {
578             rpath->frp_preference = preference;
579         }
580         else if (unformat (input, "%U next-hop-table %d",
581                            unformat_ip4_address,
582                            &rpath->frp_addr.ip4,
583                            &rpath->frp_fib_index))
584         {
585             rpath->frp_sw_if_index = ~0;
586             rpath->frp_proto = DPO_PROTO_IP4;
587
588             /*
589              * the user enter table-ids, convert to index
590              */
591             fi = fib_table_find (FIB_PROTOCOL_IP4, rpath->frp_fib_index);
592             if (~0 == fi)
593                 return 0;
594             rpath->frp_fib_index = fi;
595         }
596         else if (unformat (input, "%U next-hop-table %d",
597                            unformat_ip6_address,
598                            &rpath->frp_addr.ip6,
599                            &rpath->frp_fib_index))
600         {
601             rpath->frp_sw_if_index = ~0;
602             rpath->frp_proto = DPO_PROTO_IP6;
603             fi = fib_table_find (FIB_PROTOCOL_IP6, rpath->frp_fib_index);
604             if (~0 == fi)
605                 return 0;
606             rpath->frp_fib_index = fi;
607         }
608         else if (unformat (input, "%U",
609                            unformat_ip4_address,
610                            &rpath->frp_addr.ip4))
611         {
612             /*
613              * the recursive next-hops are by default in the default table
614              */
615             rpath->frp_fib_index = 0;
616             rpath->frp_sw_if_index = ~0;
617             rpath->frp_proto = DPO_PROTO_IP4;
618         }
619         else if (unformat (input, "%U",
620                            unformat_ip6_address,
621                            &rpath->frp_addr.ip6))
622         {
623             rpath->frp_fib_index = 0;
624             rpath->frp_sw_if_index = ~0;
625             rpath->frp_proto = DPO_PROTO_IP6;
626         }
627         else if (unformat (input, "udp-encap %d", &udp_encap_id))
628         {
629             rpath->frp_udp_encap_id = udp_encap_id;
630             rpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
631             rpath->frp_proto = *payload_proto;
632         }
633         else if (unformat (input, "lookup in table %d", &rpath->frp_fib_index))
634         {
635             rpath->frp_proto = *payload_proto;
636             rpath->frp_sw_if_index = ~0;
637             rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
638         }
639         else if (unformat (input, "resolve-via-host"))
640         {
641             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
642         }
643         else if (unformat (input, "resolve-via-attached"))
644         {
645             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
646         }
647         else if (unformat (input, "pop-pw-cw"))
648         {
649             rpath->frp_flags |= FIB_ROUTE_PATH_POP_PW_CW;
650         }
651         else if (unformat (input,
652                            "ip4-lookup-in-table %d",
653                            &rpath->frp_fib_index))
654         {
655             rpath->frp_proto = DPO_PROTO_IP4;
656             *payload_proto = DPO_PROTO_IP4;
657             fi = fib_table_find (FIB_PROTOCOL_IP4, rpath->frp_fib_index);
658             if (~0 == fi)
659                 return 0;
660             rpath->frp_fib_index = fi;
661         }
662         else if (unformat (input,
663                            "ip6-lookup-in-table %d",
664                            &rpath->frp_fib_index))
665         {
666             rpath->frp_proto = DPO_PROTO_IP6;
667             *payload_proto = DPO_PROTO_IP6;
668             fi = fib_table_find (FIB_PROTOCOL_IP6, rpath->frp_fib_index);
669             if (~0 == fi)
670                 return 0;
671             rpath->frp_fib_index = fi;
672         }
673         else if (unformat (input,
674                            "mpls-lookup-in-table %d",
675                            &rpath->frp_fib_index))
676         {
677             rpath->frp_proto = DPO_PROTO_MPLS;
678             *payload_proto = DPO_PROTO_MPLS;
679             fi = fib_table_find (FIB_PROTOCOL_MPLS, rpath->frp_fib_index);
680             if (~0 == fi)
681                 return 0;
682             rpath->frp_fib_index = fi;
683         }
684         else if (unformat (input, "src-lookup"))
685         {
686             rpath->frp_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
687         }
688         else if (unformat (input,
689                            "l2-input-on %U",
690                            unformat_vnet_sw_interface, vnm,
691                            &rpath->frp_sw_if_index))
692         {
693             rpath->frp_proto = DPO_PROTO_ETHERNET;
694             *payload_proto = DPO_PROTO_ETHERNET;
695             rpath->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
696         }
697         else if (unformat (input, "via-label %U",
698                            unformat_mpls_unicast_label,
699                            &rpath->frp_local_label))
700         {
701             rpath->frp_eos = MPLS_NON_EOS;
702             rpath->frp_proto = DPO_PROTO_MPLS;
703             rpath->frp_sw_if_index = ~0;
704         }
705         else if (unformat (input, "rx-ip4 %U",
706                            unformat_vnet_sw_interface, vnm,
707                            &rpath->frp_sw_if_index))
708         {
709             rpath->frp_proto = DPO_PROTO_IP4;
710             rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX;
711         }
712       else if (unformat (input, "local"))
713         {
714           clib_memset (&rpath->frp_addr, 0, sizeof (rpath->frp_addr));
715           rpath->frp_sw_if_index = ~0;
716           rpath->frp_weight = 1;
717           rpath->frp_flags |= FIB_ROUTE_PATH_LOCAL;
718         }
719       else if (unformat (input, "out-labels"))
720         {
721             while (unformat (input, "%U",
722                              unformat_mpls_unicast_label, &out_label))
723             {
724                 fib_mpls_label_t fml = {
725                     .fml_value = out_label,
726                 };
727                 vec_add1(rpath->frp_label_stack, fml);
728             }
729         }
730       else if (unformat (input, "ip4"))
731         {
732           explicit_proto = DPO_PROTO_IP4;
733         }
734       else if (unformat (input, "ip6"))
735         {
736           explicit_proto = DPO_PROTO_IP6;
737         }
738         else if (unformat (input, "%U",
739                            unformat_vnet_sw_interface, vnm,
740                            &rpath->frp_sw_if_index))
741         {
742             rpath->frp_proto = *payload_proto;
743         }
744         else if (unformat (input, "%U",
745                          unformat_mfib_itf_flags, &rpath->frp_mitf_flags))
746         ;
747         else if (unformat (input, "via"))
748         {
749             /* new path, back up and return */
750             unformat_put_input (input);
751             unformat_put_input (input);
752             unformat_put_input (input);
753             unformat_put_input (input);
754             break;
755         }
756         else
757         {
758             return (0);
759         }
760     }
761
762     if (DPO_PROTO_NONE != explicit_proto)
763       *payload_proto = rpath->frp_proto = explicit_proto;
764
765     return (1);
766 }
767
768 /*
769  * Return true if the path is attached
770  */
771 int
772 fib_route_path_is_attached (const fib_route_path_t *rpath)
773 {
774     /*
775      * DVR paths are not attached, since we are not playing the
776      * L3 game with these
777      */
778     if (rpath->frp_flags & (FIB_ROUTE_PATH_DVR |
779                             FIB_ROUTE_PATH_UDP_ENCAP))
780     {
781         return (0);
782     }
783
784     /*
785      * - All zeros next-hop
786      * - a valid interface
787      */
788     if (ip46_address_is_zero(&rpath->frp_addr) &&
789         (~0 != rpath->frp_sw_if_index))
790     {
791         return (!0);
792     }
793     else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED ||
794              rpath->frp_flags & FIB_ROUTE_PATH_GLEAN)
795     {
796         return (!0);
797     }
798     return (0);
799 }
800
801 static void
802 fib_prefix_ip4_addr_increment (fib_prefix_t *pfx)
803 {
804     /* Calculate the addend based on the host length of address */
805     u32 incr = 1ULL << (32 - pfx->fp_len);
806     ip4_address_t dst = (pfx->fp_addr).ip4;
807     dst.as_u32 = clib_host_to_net_u32 (incr + clib_net_to_host_u32 (dst.as_u32));
808     pfx->fp_addr.ip4.as_u32 = dst.as_u32;
809 }
810
811 static void
812 fib_prefix_ip6_addr_increment (fib_prefix_t *pfx)
813 {
814     /*
815      * Calculate the addend based on the host length of address
816      * and which part(lower 64 bits or higher 64 bits) it lies
817      * in
818      */
819     u32 host_len = 128 - pfx->fp_len;
820     u64 incr = 1ULL << ((host_len > 64) ? (host_len - 64) : host_len);
821     i32 bucket = (host_len < 64 ? 1 : 0);
822     ip6_address_t dst = (pfx->fp_addr).ip6;
823     u64 tmp = incr + clib_net_to_host_u64 (dst.as_u64[bucket]);
824     /* Handle overflow */
825     if (bucket && (tmp < incr))
826     {
827         dst.as_u64[1] = clib_host_to_net_u64 (tmp);
828         dst.as_u64[0] = clib_host_to_net_u64 (1ULL + clib_net_to_host_u64 (dst.as_u64[0]));
829     }
830     else
831         dst.as_u64[bucket] = clib_host_to_net_u64 (tmp);
832
833     pfx->fp_addr.ip6.as_u128 = dst.as_u128;
834 }
835
836 /*
837  * Increase IPv4/IPv6 address according to the prefix length
838  */
839 void fib_prefix_increment (fib_prefix_t *pfx)
840 {
841     switch (pfx->fp_proto)
842     {
843     case FIB_PROTOCOL_IP4:
844         fib_prefix_ip4_addr_increment (pfx);
845         break;
846     case FIB_PROTOCOL_IP6:
847         fib_prefix_ip6_addr_increment (pfx);
848         break;
849     case FIB_PROTOCOL_MPLS:
850         break;
851     }
852 }