LCOV - code coverage report
Current view: top level - vnet/ip - ip6_forward.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 944 1216 77.6 %
Date: 2023-10-26 01:39:38 Functions: 156 200 78.0 %

          Line data    Source code
       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             :  * ip/ip6_forward.c: IP v6 forwarding
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vnet/vnet.h>
      41             : #include <vnet/ip/ip.h>
      42             : #include <vnet/ip/ip_frag.h>
      43             : #include <vnet/ip/ip6_link.h>
      44             : #include <vnet/ethernet/ethernet.h>       /* for ethernet_header_t */
      45             : #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
      46             : #include <vppinfra/cache.h>
      47             : #include <vnet/fib/fib_urpf_list.h>       /* for FIB uRPF check */
      48             : #include <vnet/fib/ip6_fib.h>
      49             : #include <vnet/mfib/ip6_mfib.h>
      50             : #include <vnet/dpo/load_balance_map.h>
      51             : #include <vnet/dpo/receive_dpo.h>
      52             : #include <vnet/dpo/classify_dpo.h>
      53             : #include <vnet/classify/vnet_classify.h>
      54             : #include <vnet/pg/pg.h>
      55             : 
      56             : #ifndef CLIB_MARCH_VARIANT
      57             : #include <vppinfra/bihash_template.c>
      58             : #endif
      59             : #include <vnet/ip/ip6_forward.h>
      60             : #include <vnet/interface_output.h>
      61             : 
      62             : /* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
      63             : #define OI_DECAP   0x80000000
      64             : 
      65             : static void
      66        2158 : ip6_add_interface_prefix_routes (ip6_main_t * im,
      67             :                                  u32 sw_if_index,
      68             :                                  u32 fib_index,
      69             :                                  ip6_address_t * address, u32 address_length)
      70             : {
      71        2158 :   ip_lookup_main_t *lm = &im->lookup_main;
      72             :   ip_interface_prefix_t *if_prefix;
      73             : 
      74             :   /* *INDENT-OFF* */
      75        2158 :   ip_interface_prefix_key_t key = {
      76             :     .prefix = {
      77             :       .fp_len = address_length,
      78             :       .fp_proto = FIB_PROTOCOL_IP6,
      79             :       .fp_addr.ip6 = {
      80             :         .as_u64 = {
      81        2158 :           address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
      82        2158 :           address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
      83             :         },
      84             :       },
      85             :     },
      86             :     .sw_if_index = sw_if_index,
      87             :   };
      88             :   /* *INDENT-ON* */
      89             : 
      90             :   /* If prefix already set on interface, just increment ref count & return */
      91        2158 :   if_prefix = ip_get_interface_prefix (lm, &key);
      92        2158 :   if (if_prefix)
      93             :     {
      94          11 :       if_prefix->ref_count += 1;
      95          11 :       return;
      96             :     }
      97             : 
      98             :   /* New prefix - allocate a pool entry, initialize it, add to the hash */
      99        2147 :   pool_get (lm->if_prefix_pool, if_prefix);
     100        2147 :   if_prefix->ref_count = 1;
     101        2147 :   clib_memcpy (&if_prefix->key, &key, sizeof (key));
     102        2147 :   mhash_set (&lm->prefix_to_if_prefix_index, &key,
     103        2147 :              if_prefix - lm->if_prefix_pool, 0 /* old value */ );
     104             : 
     105             :   /* length < 128 - add glean */
     106        2147 :   if (address_length < 128)
     107             :     {
     108             :       /* set the glean route for the prefix */
     109        2137 :       fib_table_entry_update_one_path (fib_index, &key.prefix,
     110             :                                        FIB_SOURCE_INTERFACE,
     111             :                                        (FIB_ENTRY_FLAG_CONNECTED |
     112             :                                         FIB_ENTRY_FLAG_ATTACHED),
     113             :                                        DPO_PROTO_IP6,
     114             :                                        /* No next-hop address */
     115             :                                        NULL, sw_if_index,
     116             :                                        /* invalid FIB index */
     117             :                                        ~0, 1,
     118             :                                        /* no out-label stack */
     119             :                                        NULL, FIB_ROUTE_PATH_FLAG_NONE);
     120             :     }
     121             : }
     122             : 
     123             : static void
     124        2158 : ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
     125             :                           ip6_main_t * im, u32 fib_index,
     126             :                           ip_interface_address_t * a)
     127             : {
     128        2158 :   ip_lookup_main_t *lm = &im->lookup_main;
     129        2158 :   ip6_address_t *address = ip_interface_address_get_address (lm, a);
     130        2158 :   fib_prefix_t pfx = {
     131        2158 :     .fp_len = a->address_length,
     132             :     .fp_proto = FIB_PROTOCOL_IP6,
     133             :     .fp_addr.ip6 = *address,
     134             :   };
     135             : 
     136             :   /* set special routes for the prefix if needed */
     137        2158 :   ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
     138        2158 :                                    address, a->address_length);
     139             : 
     140        2158 :   pfx.fp_len = 128;
     141        2158 :   if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
     142             :     {
     143           0 :       u32 classify_table_index =
     144           0 :         lm->classify_table_index_by_sw_if_index[sw_if_index];
     145           0 :       if (classify_table_index != (u32) ~ 0)
     146             :         {
     147           0 :           dpo_id_t dpo = DPO_INVALID;
     148             : 
     149           0 :           dpo_set (&dpo,
     150             :                    DPO_CLASSIFY,
     151             :                    DPO_PROTO_IP6,
     152             :                    classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
     153             : 
     154           0 :           fib_table_entry_special_dpo_add (fib_index,
     155             :                                            &pfx,
     156             :                                            FIB_SOURCE_CLASSIFY,
     157             :                                            FIB_ENTRY_FLAG_NONE, &dpo);
     158           0 :           dpo_reset (&dpo);
     159             :         }
     160             :     }
     161             : 
     162        2158 :   fib_table_entry_update_one_path (fib_index, &pfx,
     163             :                                    FIB_SOURCE_INTERFACE,
     164             :                                    (FIB_ENTRY_FLAG_CONNECTED |
     165             :                                     FIB_ENTRY_FLAG_LOCAL),
     166             :                                    DPO_PROTO_IP6,
     167             :                                    &pfx.fp_addr,
     168             :                                    sw_if_index, ~0,
     169             :                                    1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
     170        2158 : }
     171             : 
     172             : static void
     173        1997 : ip6_del_interface_prefix_routes (ip6_main_t * im,
     174             :                                  u32 sw_if_index,
     175             :                                  u32 fib_index,
     176             :                                  ip6_address_t * address, u32 address_length)
     177             : {
     178        1997 :   ip_lookup_main_t *lm = &im->lookup_main;
     179             :   ip_interface_prefix_t *if_prefix;
     180             : 
     181             :   /* *INDENT-OFF* */
     182        1997 :   ip_interface_prefix_key_t key = {
     183             :     .prefix = {
     184             :       .fp_len = address_length,
     185             :       .fp_proto = FIB_PROTOCOL_IP6,
     186             :       .fp_addr.ip6 = {
     187             :         .as_u64 = {
     188        1997 :           address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
     189        1997 :           address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
     190             :         },
     191             :       },
     192             :     },
     193             :     .sw_if_index = sw_if_index,
     194             :   };
     195             :   /* *INDENT-ON* */
     196             : 
     197        1997 :   if_prefix = ip_get_interface_prefix (lm, &key);
     198        1997 :   if (!if_prefix)
     199             :     {
     200           0 :       clib_warning ("Prefix not found while deleting %U",
     201             :                     format_ip4_address_and_length, address, address_length);
     202          11 :       return;
     203             :     }
     204             : 
     205             :   /* If not deleting last intf addr in prefix, decrement ref count & return */
     206        1997 :   if_prefix->ref_count -= 1;
     207        1997 :   if (if_prefix->ref_count > 0)
     208          11 :     return;
     209             : 
     210             :   /* length <= 128, delete glean route */
     211        1986 :   if (address_length <= 128)
     212             :     {
     213             :       /* remove glean route for prefix */
     214        1986 :       fib_table_entry_delete (fib_index, &key.prefix, FIB_SOURCE_INTERFACE);
     215             :     }
     216             : 
     217        1986 :   mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
     218        1986 :   pool_put (lm->if_prefix_pool, if_prefix);
     219             : }
     220             : 
     221             : static void
     222        1997 : ip6_del_interface_routes (u32 sw_if_index, ip6_main_t * im,
     223             :                           u32 fib_index,
     224             :                           ip6_address_t * address, u32 address_length)
     225             : {
     226        1997 :   fib_prefix_t pfx = {
     227             :     .fp_len = 128,
     228             :     .fp_proto = FIB_PROTOCOL_IP6,
     229             :     .fp_addr.ip6 = *address,
     230             :   };
     231             : 
     232             :   /* delete special routes for the prefix if needed */
     233        1997 :   ip6_del_interface_prefix_routes (im, sw_if_index, fib_index,
     234             :                                    address, address_length);
     235             : 
     236        1997 :   fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
     237        1997 : }
     238             : 
     239             : #ifndef CLIB_MARCH_VARIANT
     240             : void
     241        8244 : ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
     242             : {
     243        8244 :   ip6_main_t *im = &ip6_main;
     244        8244 :   vnet_main_t *vnm = vnet_get_main ();
     245        8244 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     246             : 
     247        9830 :   vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
     248             : 
     249             :   /*
     250             :    * enable/disable only on the 1<->0 transition
     251             :    */
     252        8244 :   if (is_enable)
     253             :     {
     254        4296 :       if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
     255        2142 :         return;
     256             :     }
     257             :   else
     258             :     {
     259             :       /* The ref count is 0 when an address is removed from an interface that has
     260             :        * no address - this is not a ciritical error */
     261        3948 :       if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
     262        3948 :           0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
     263        1974 :         return;
     264             :     }
     265             : 
     266        4128 :   vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
     267             :                                !is_enable, 0, 0);
     268             : 
     269        4128 :   vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
     270             :                                sw_if_index, !is_enable, 0, 0);
     271             : 
     272        4128 :   if (is_enable)
     273        2154 :     hi->l3_if_count++;
     274        1974 :   else if (hi->l3_if_count)
     275        1974 :     hi->l3_if_count--;
     276             : }
     277             : 
     278             : /* get first interface address */
     279             : ip6_address_t *
     280          23 : ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
     281             : {
     282          23 :   ip_lookup_main_t *lm = &im->lookup_main;
     283          23 :   ip_interface_address_t *ia = 0;
     284          23 :   ip6_address_t *result = 0;
     285             : 
     286             :   /* *INDENT-OFF* */
     287          23 :   foreach_ip_interface_address (lm, ia, sw_if_index,
     288             :                                 1 /* honor unnumbered */,
     289             :   ({
     290             :     ip6_address_t * a = ip_interface_address_get_address (lm, ia);
     291             :     result = a;
     292             :     break;
     293             :   }));
     294             :   /* *INDENT-ON* */
     295          23 :   return result;
     296             : }
     297             : 
     298             : clib_error_t *
     299        4127 : ip6_add_del_interface_address (vlib_main_t * vm,
     300             :                                u32 sw_if_index,
     301             :                                ip6_address_t * address,
     302             :                                u32 address_length, u32 is_del)
     303             : {
     304        4127 :   vnet_main_t *vnm = vnet_get_main ();
     305        4127 :   ip6_main_t *im = &ip6_main;
     306        4127 :   ip_lookup_main_t *lm = &im->lookup_main;
     307        4127 :   clib_error_t *error = NULL;
     308             :   u32 if_address_index;
     309        4127 :   ip6_address_fib_t ip6_af, *addr_fib = 0;
     310             :   const ip6_address_t *ll_addr;
     311             : 
     312        4127 :   error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
     313        4127 :   if (error)
     314             :     {
     315           0 :       vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
     316           0 :       return error;
     317             :     }
     318             : 
     319        4127 :   if (ip6_address_is_link_local_unicast (address))
     320             :     {
     321           5 :       if (address_length != 128)
     322             :         {
     323           0 :           vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
     324             :           return
     325           0 :             clib_error_create
     326             :             ("prefix length of link-local address must be 128");
     327             :         }
     328           5 :       if (!is_del)
     329             :         {
     330             :           int rv;
     331             : 
     332           4 :           rv = ip6_link_set_local_address (sw_if_index, address);
     333             : 
     334           4 :           if (rv)
     335             :             {
     336           0 :               vnm->api_errno = rv;
     337           0 :               return clib_error_create ("address not assignable");
     338             :             }
     339             :         }
     340             :       else
     341             :         {
     342           1 :           ll_addr = ip6_get_link_local_address (sw_if_index);
     343           1 :           if (ip6_address_is_equal (ll_addr, address))
     344             :             {
     345           1 :               vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
     346           1 :               return clib_error_create ("address not deletable");
     347             :             }
     348             :           else
     349             :             {
     350           0 :               vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
     351           0 :               return clib_error_create ("address not found");
     352             :             }
     353             :         }
     354             : 
     355           4 :       return (NULL);
     356             :     }
     357             : 
     358        4122 :   ip6_addr_fib_init (&ip6_af, address,
     359        4122 :                      vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
     360        4122 :   vec_add1 (addr_fib, ip6_af);
     361             : 
     362             :   /* *INDENT-OFF* */
     363        4122 :   if (!is_del)
     364             :     {
     365             :       /* When adding an address check that it does not conflict
     366             :          with an existing address on any interface in this table. */
     367             :       ip_interface_address_t *ia;
     368             :       vnet_sw_interface_t *sif;
     369             : 
     370       12741 :       pool_foreach (sif, vnm->interface_main.sw_interfaces)
     371             :        {
     372       10594 :           if (im->fib_index_by_sw_if_index[sw_if_index] ==
     373       10594 :               im->fib_index_by_sw_if_index[sif->sw_if_index])
     374             :             {
     375       12177 :               foreach_ip_interface_address
     376             :                 (&im->lookup_main, ia, sif->sw_if_index,
     377             :                  0 /* honor unnumbered */ ,
     378             :                  ({
     379             :                    ip6_address_t * x =
     380             :                      ip_interface_address_get_address
     381             :                      (&im->lookup_main, ia);
     382             : 
     383             :                    if (ip6_destination_matches_route
     384             :                        (im, address, x, ia->address_length) ||
     385             :                        ip6_destination_matches_route (im,
     386             :                                                       x,
     387             :                                                       address,
     388             :                                                       address_length))
     389             :                      {
     390             :                        /* an intf may have >1 addr from the same prefix */
     391             :                        if ((sw_if_index == sif->sw_if_index) &&
     392             :                            (ia->address_length == address_length) &&
     393             :                            !ip6_address_is_equal (x, address))
     394             :                          continue;
     395             : 
     396             :                        if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
     397             :                          /* if the address we're comparing against is stale
     398             :                           * then the CP has not added this one back yet, maybe
     399             :                           * it never will, so we have to assume it won't and
     400             :                           * ignore it. if it does add it back, then it will fail
     401             :                           * because this one is now present */
     402             :                          continue;
     403             : 
     404             :                        /* error if the length or intf was different */
     405             :                        vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
     406             :                        error =  clib_error_create
     407             :                          ("failed to add %U which conflicts with %U for interface %U",
     408             :                           format_ip6_address_and_length, address,
     409             :                           address_length,
     410             :                           format_ip6_address_and_length, x,
     411             :                           ia->address_length,
     412             :                           format_vnet_sw_if_index_name, vnm,
     413             :                           sif->sw_if_index);
     414             :                        goto done;
     415             :                      }
     416             :                  }));
     417             :             }
     418             :       }
     419             :     }
     420             :   /* *INDENT-ON* */
     421             : 
     422        4122 :   if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
     423             : 
     424        4122 :   if (is_del)
     425             :     {
     426        1975 :       if (~0 == if_address_index)
     427             :         {
     428           0 :           vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
     429           0 :           error = clib_error_create ("%U not found for interface %U",
     430             :                                      lm->format_address_and_length,
     431             :                                      addr_fib, address_length,
     432             :                                      format_vnet_sw_if_index_name, vnm,
     433             :                                      sw_if_index);
     434           0 :           goto done;
     435             :         }
     436             : 
     437        1975 :       error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
     438             :                                         address_length, sw_if_index);
     439        1975 :       if (error)
     440           1 :         goto done;
     441             :     }
     442             :   else
     443             :     {
     444        2147 :       if (~0 != if_address_index)
     445             :         {
     446             :           ip_interface_address_t *ia;
     447             : 
     448           9 :           ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
     449             : 
     450           9 :           if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
     451             :             {
     452           9 :               if (ia->sw_if_index == sw_if_index)
     453             :                 {
     454             :                   /* re-adding an address during the replace action.
     455             :                    * consdier this the update. clear the flag and
     456             :                    * we're done */
     457           6 :                   ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
     458           6 :                   goto done;
     459             :                 }
     460             :               else
     461             :                 {
     462             :                   /* The prefix is moving from one interface to another.
     463             :                    * delete the stale and add the new */
     464           3 :                   ip6_add_del_interface_address (vm,
     465             :                                                  ia->sw_if_index,
     466             :                                                  address, address_length, 1);
     467           3 :                   ia = NULL;
     468           3 :                   error = ip_interface_address_add (lm, sw_if_index,
     469             :                                                     addr_fib, address_length,
     470             :                                                     &if_address_index);
     471             :                 }
     472             :             }
     473             :           else
     474             :             {
     475           0 :               vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
     476           0 :               error = clib_error_create
     477             :                 ("Prefix %U already found on interface %U",
     478             :                  lm->format_address_and_length, addr_fib, address_length,
     479             :                  format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
     480             :             }
     481             :         }
     482             :       else
     483        2138 :         error = ip_interface_address_add (lm, sw_if_index,
     484             :                                           addr_fib, address_length,
     485             :                                           &if_address_index);
     486             :     }
     487             : 
     488        4115 :   if (error)
     489           0 :     goto done;
     490             : 
     491        4115 :   ip6_sw_interface_enable_disable (sw_if_index, !is_del);
     492        4115 :   if (!is_del)
     493        2141 :     ip6_link_enable (sw_if_index, NULL);
     494             : 
     495             :   /* intf addr routes are added/deleted on admin up/down */
     496        4115 :   if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
     497             :     {
     498        2867 :       if (is_del)
     499         805 :         ip6_del_interface_routes (sw_if_index,
     500             :                                   im, ip6_af.fib_index, address,
     501             :                                   address_length);
     502             :       else
     503        2062 :         ip6_add_interface_routes (vnm, sw_if_index,
     504             :                                   im, ip6_af.fib_index,
     505        2062 :                                   pool_elt_at_index (lm->if_address_pool,
     506             :                                                      if_address_index));
     507             :     }
     508             : 
     509             :   ip6_add_del_interface_address_callback_t *cb;
     510       20587 :   vec_foreach (cb, im->add_del_interface_address_callbacks)
     511       16472 :     cb->function (im, cb->function_opaque, sw_if_index,
     512             :                   address, address_length, if_address_index, is_del);
     513             : 
     514        4115 :   if (is_del)
     515        1974 :     ip6_link_disable (sw_if_index);
     516             : 
     517        2141 : done:
     518        4122 :   vec_free (addr_fib);
     519        4122 :   return error;
     520             : }
     521             : 
     522             : #endif
     523             : 
     524             : static clib_error_t *
     525       13514 : ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
     526             : {
     527       13514 :   ip6_main_t *im = &ip6_main;
     528             :   ip_interface_address_t *ia;
     529             :   ip6_address_t *a;
     530             :   u32 is_admin_up, fib_index;
     531             : 
     532       13514 :   vec_validate_init_empty (im->
     533             :                            lookup_main.if_address_pool_index_by_sw_if_index,
     534             :                            sw_if_index, ~0);
     535             : 
     536       13514 :   is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
     537             : 
     538       13514 :   fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
     539             : 
     540             :   /* *INDENT-OFF* */
     541       14802 :   foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
     542             :                                 0 /* honor unnumbered */,
     543             :   ({
     544             :     a = ip_interface_address_get_address (&im->lookup_main, ia);
     545             :     if (is_admin_up)
     546             :       ip6_add_interface_routes (vnm, sw_if_index,
     547             :                                 im, fib_index,
     548             :                                 ia);
     549             :     else
     550             :       ip6_del_interface_routes (sw_if_index, im, fib_index,
     551             :                                 a, ia->address_length);
     552             :   }));
     553             :   /* *INDENT-ON* */
     554             : 
     555       13514 :   return 0;
     556             : }
     557             : 
     558        2881 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
     559             : 
     560             : /* Built-in ip6 unicast rx feature path definition */
     561             : /* *INDENT-OFF* */
     562        1151 : VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
     563             : {
     564             :   .arc_name  = "ip6-unicast",
     565             :   .start_nodes = VNET_FEATURES ("ip6-input"),
     566             :   .last_in_arc = "ip6-lookup",
     567             :   .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
     568             : };
     569             : 
     570       76635 : VNET_FEATURE_INIT (ip6_flow_classify, static) =
     571             : {
     572             :   .arc_name = "ip6-unicast",
     573             :   .node_name = "ip6-flow-classify",
     574             :   .runs_before = VNET_FEATURES ("ip6-inacl"),
     575             : };
     576             : 
     577       76635 : VNET_FEATURE_INIT (ip6_inacl, static) =
     578             : {
     579             :   .arc_name = "ip6-unicast",
     580             :   .node_name = "ip6-inacl",
     581             :   .runs_before = VNET_FEATURES ("ip6-policer-classify"),
     582             : };
     583             : 
     584       76635 : VNET_FEATURE_INIT (ip6_policer_classify, static) =
     585             : {
     586             :   .arc_name = "ip6-unicast",
     587             :   .node_name = "ip6-policer-classify",
     588             :   .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
     589             : };
     590             : 
     591       76635 : VNET_FEATURE_INIT (ip6_ipsec, static) =
     592             : {
     593             :   .arc_name = "ip6-unicast",
     594             :   .node_name = "ipsec6-input-feature",
     595             :   .runs_before = VNET_FEATURES ("l2tp-decap"),
     596             : };
     597             : 
     598       76635 : VNET_FEATURE_INIT (ip6_l2tp, static) =
     599             : {
     600             :   .arc_name = "ip6-unicast",
     601             :   .node_name = "l2tp-decap",
     602             :   .runs_before = VNET_FEATURES ("vpath-input-ip6"),
     603             : };
     604             : 
     605       76635 : VNET_FEATURE_INIT (ip6_vpath, static) =
     606             : {
     607             :   .arc_name = "ip6-unicast",
     608             :   .node_name = "vpath-input-ip6",
     609             :   .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
     610             : };
     611             : 
     612       76635 : VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
     613             : {
     614             :   .arc_name = "ip6-unicast",
     615             :   .node_name = "ip6-vxlan-bypass",
     616             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
     617             : };
     618             : 
     619       76635 : VNET_FEATURE_INIT (ip6_not_enabled, static) =
     620             : {
     621             :   .arc_name = "ip6-unicast",
     622             :   .node_name = "ip6-not-enabled",
     623             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
     624             : };
     625             : 
     626       76635 : VNET_FEATURE_INIT (ip6_lookup, static) =
     627             : {
     628             :   .arc_name = "ip6-unicast",
     629             :   .node_name = "ip6-lookup",
     630             :   .runs_before = 0,  /*last feature*/
     631             : };
     632             : 
     633             : /* Built-in ip6 multicast rx feature path definition (none now) */
     634        1151 : VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
     635             : {
     636             :   .arc_name  = "ip6-multicast",
     637             :   .start_nodes = VNET_FEATURES ("ip6-input"),
     638             :   .last_in_arc = "ip6-mfib-forward-lookup",
     639             :   .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
     640             : };
     641             : 
     642       76635 : VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
     643             :   .arc_name = "ip6-multicast",
     644             :   .node_name = "vpath-input-ip6",
     645             :   .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
     646             : };
     647             : 
     648       76635 : VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
     649             :   .arc_name = "ip6-multicast",
     650             :   .node_name = "ip6-not-enabled",
     651             :   .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
     652             : };
     653             : 
     654       76635 : VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
     655             :   .arc_name = "ip6-multicast",
     656             :   .node_name = "ip6-mfib-forward-lookup",
     657             :   .runs_before = 0, /* last feature */
     658             : };
     659             : 
     660             : /* Built-in ip4 tx feature path definition */
     661        1151 : VNET_FEATURE_ARC_INIT (ip6_output, static) =
     662             : {
     663             :   .arc_name  = "ip6-output",
     664             :   .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
     665             :   .last_in_arc = "interface-output",
     666             :   .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
     667             : };
     668             : 
     669       76635 : VNET_FEATURE_INIT (ip6_outacl, static) = {
     670             :   .arc_name = "ip6-output",
     671             :   .node_name = "ip6-outacl",
     672             :   .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
     673             : };
     674             : 
     675       76635 : VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
     676             :   .arc_name = "ip6-output",
     677             :   .node_name = "ipsec6-output-feature",
     678             :   .runs_before = VNET_FEATURES ("interface-output"),
     679             : };
     680             : 
     681       76635 : VNET_FEATURE_INIT (ip6_interface_output, static) = {
     682             :   .arc_name = "ip6-output",
     683             :   .node_name = "interface-output",
     684             :   .runs_before = 0, /* not before any other features */
     685             : };
     686             : /* *INDENT-ON* */
     687             : 
     688             : static clib_error_t *
     689       11798 : ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
     690             : {
     691       11798 :   ip6_main_t *im = &ip6_main;
     692             : 
     693       15752 :   vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
     694       15752 :   vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
     695             : 
     696       11798 :   if (is_add)
     697             :     {
     698             :       /* Fill in lookup tables with default table (0). */
     699        7547 :       im->fib_index_by_sw_if_index[sw_if_index] = 0;
     700        7547 :       im->mfib_index_by_sw_if_index[sw_if_index] = 0;
     701             :     }
     702             :   else
     703             :     {
     704             :       /* Ensure that IPv6 is disabled */
     705        4251 :       ip6_main_t *im6 = &ip6_main;
     706        4251 :       ip_lookup_main_t *lm6 = &im6->lookup_main;
     707        4251 :       ip_interface_address_t *ia = 0;
     708             :       ip6_address_t *address;
     709        4251 :       vlib_main_t *vm = vlib_get_main ();
     710             : 
     711        4251 :       vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
     712             :       /* *INDENT-OFF* */
     713        4251 :       foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
     714             :       ({
     715             :         address = ip_interface_address_get_address (lm6, ia);
     716             :         ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
     717             :       }));
     718             :       /* *INDENT-ON* */
     719        4251 :       ip6_mfib_interface_enable_disable (sw_if_index, 0);
     720             : 
     721        4251 :       if (0 != im6->fib_index_by_sw_if_index[sw_if_index])
     722         109 :         fib_table_bind (FIB_PROTOCOL_IP6, sw_if_index, 0);
     723        4251 :       if (0 != im6->mfib_index_by_sw_if_index[sw_if_index])
     724         108 :         mfib_table_bind (FIB_PROTOCOL_IP6, sw_if_index, 0);
     725             : 
     726             :       /* Erase the lookup tables just in case */
     727        4251 :       im6->fib_index_by_sw_if_index[sw_if_index] = ~0;
     728        4251 :       im6->mfib_index_by_sw_if_index[sw_if_index] = ~0;
     729             :     }
     730             : 
     731       11798 :   vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
     732             :                                is_add, 0, 0);
     733             : 
     734       11798 :   vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
     735             :                                sw_if_index, is_add, 0, 0);
     736             : 
     737       11798 :   return /* no error */ 0;
     738             : }
     739             : 
     740        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
     741             : 
     742      232002 : VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
     743             :                                 vlib_node_runtime_t * node,
     744             :                                 vlib_frame_t * frame)
     745             : {
     746      229702 :   return ip6_lookup_inline (vm, node, frame);
     747             : }
     748             : 
     749             : static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
     750             : 
     751             : /* *INDENT-OFF* */
     752      183788 : VLIB_REGISTER_NODE (ip6_lookup_node) =
     753             : {
     754             :   .name = "ip6-lookup",
     755             :   .vector_size = sizeof (u32),
     756             :   .format_trace = format_ip6_lookup_trace,
     757             :   .n_next_nodes = IP6_LOOKUP_N_NEXT,
     758             :   .next_nodes = IP6_LOOKUP_NEXT_NODES,
     759             : };
     760             : /* *INDENT-ON* */
     761             : 
     762        3616 : VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
     763             :                                       vlib_node_runtime_t * node,
     764             :                                       vlib_frame_t * frame)
     765             : {
     766        1316 :   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
     767             :   u32 n_left, *from;
     768        1316 :   u32 thread_index = vm->thread_index;
     769        1316 :   ip6_main_t *im = &ip6_main;
     770        1316 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     771             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     772             : 
     773        1316 :   from = vlib_frame_vector_args (frame);
     774        1316 :   n_left = frame->n_vectors;
     775        1316 :   next = nexts;
     776             : 
     777        1316 :   vlib_get_buffers (vm, from, bufs, n_left);
     778             : 
     779       37069 :   while (n_left >= 4)
     780             :     {
     781             :       const load_balance_t *lb0, *lb1;
     782             :       const ip6_header_t *ip0, *ip1;
     783             :       u32 lbi0, hc0, lbi1, hc1;
     784             :       const dpo_id_t *dpo0, *dpo1;
     785             : 
     786             :       /* Prefetch next iteration. */
     787             :       {
     788       35753 :         vlib_prefetch_buffer_header (b[2], STORE);
     789       35753 :         vlib_prefetch_buffer_header (b[3], STORE);
     790             : 
     791       35753 :         CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
     792       35753 :         CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
     793             :       }
     794             : 
     795       35753 :       ip0 = vlib_buffer_get_current (b[0]);
     796       35753 :       ip1 = vlib_buffer_get_current (b[1]);
     797       35753 :       lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
     798       35753 :       lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
     799             : 
     800       35753 :       lb0 = load_balance_get (lbi0);
     801       35753 :       lb1 = load_balance_get (lbi1);
     802             : 
     803             :       /*
     804             :        * this node is for via FIBs we can re-use the hash value from the
     805             :        * to node if present.
     806             :        * We don't want to use the same hash value at each level in the recursion
     807             :        * graph as that would lead to polarisation
     808             :        */
     809       35753 :       hc0 = hc1 = 0;
     810             : 
     811       35753 :       if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     812             :         {
     813         254 :           if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
     814             :             {
     815         254 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     816         254 :                 vnet_buffer (b[0])->ip.flow_hash >> 1;
     817             :             }
     818             :           else
     819             :             {
     820           0 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     821           0 :                 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
     822             :             }
     823         254 :           dpo0 = load_balance_get_fwd_bucket
     824         254 :             (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
     825             :         }
     826             :       else
     827             :         {
     828       35499 :           dpo0 = load_balance_get_bucket_i (lb0, 0);
     829             :         }
     830       35753 :       if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
     831             :         {
     832         254 :           if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
     833             :             {
     834         254 :               hc1 = vnet_buffer (b[1])->ip.flow_hash =
     835         254 :                 vnet_buffer (b[1])->ip.flow_hash >> 1;
     836             :             }
     837             :           else
     838             :             {
     839           0 :               hc1 = vnet_buffer (b[1])->ip.flow_hash =
     840           0 :                 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
     841             :             }
     842         254 :           dpo1 = load_balance_get_fwd_bucket
     843         254 :             (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
     844             :         }
     845             :       else
     846             :         {
     847       35499 :           dpo1 = load_balance_get_bucket_i (lb1, 0);
     848             :         }
     849             : 
     850       35753 :       next[0] = dpo0->dpoi_next_node;
     851       35753 :       next[1] = dpo1->dpoi_next_node;
     852             : 
     853             :       /* Only process the HBH Option Header if explicitly configured to do so */
     854       35753 :       if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
     855             :         {
     856           0 :           next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
     857             :             (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
     858             :         }
     859             :       /* Only process the HBH Option Header if explicitly configured to do so */
     860       35753 :       if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
     861             :         {
     862           0 :           next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
     863             :             (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[1];
     864             :         }
     865             : 
     866       35753 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     867       35753 :       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
     868             : 
     869       35753 :       vlib_increment_combined_counter
     870             :         (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
     871       35753 :       vlib_increment_combined_counter
     872       35753 :         (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
     873             : 
     874       35753 :       b += 2;
     875       35753 :       next += 2;
     876       35753 :       n_left -= 2;
     877             :     }
     878             : 
     879        4989 :   while (n_left > 0)
     880             :     {
     881             :       const load_balance_t *lb0;
     882             :       const ip6_header_t *ip0;
     883             :       const dpo_id_t *dpo0;
     884             :       u32 lbi0, hc0;
     885             : 
     886        3673 :       ip0 = vlib_buffer_get_current (b[0]);
     887        3673 :       lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
     888             : 
     889        3673 :       lb0 = load_balance_get (lbi0);
     890             : 
     891        3673 :       hc0 = 0;
     892        3673 :       if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     893             :         {
     894           6 :           if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
     895             :             {
     896           6 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     897           6 :                 vnet_buffer (b[0])->ip.flow_hash >> 1;
     898             :             }
     899             :           else
     900             :             {
     901           0 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     902           0 :                 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
     903             :             }
     904           6 :           dpo0 = load_balance_get_fwd_bucket
     905           6 :             (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
     906             :         }
     907             :       else
     908             :         {
     909        3667 :           dpo0 = load_balance_get_bucket_i (lb0, 0);
     910             :         }
     911             : 
     912        3673 :       next[0] = dpo0->dpoi_next_node;
     913        3673 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     914             : 
     915             :       /* Only process the HBH Option Header if explicitly configured to do so */
     916        3673 :       if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
     917             :         {
     918           0 :           next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
     919             :             (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
     920             :         }
     921             : 
     922        3673 :       vlib_increment_combined_counter
     923             :         (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
     924             : 
     925        3673 :       b += 1;
     926        3673 :       next += 1;
     927        3673 :       n_left -= 1;
     928             :     }
     929             : 
     930        1316 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     931             : 
     932        1316 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     933        1116 :     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
     934             : 
     935        1316 :   return frame->n_vectors;
     936             : }
     937             : 
     938             : /* *INDENT-OFF* */
     939      183788 : VLIB_REGISTER_NODE (ip6_load_balance_node) =
     940             : {
     941             :   .name = "ip6-load-balance",
     942             :   .vector_size = sizeof (u32),
     943             :   .sibling_of = "ip6-lookup",
     944             :   .format_trace = format_ip6_lookup_trace,
     945             : };
     946             : /* *INDENT-ON* */
     947             : 
     948             : typedef struct
     949             : {
     950             :   /* Adjacency taken. */
     951             :   u32 adj_index;
     952             :   u32 flow_hash;
     953             :   u32 fib_index;
     954             : 
     955             :   /* Packet data, possibly *after* rewrite. */
     956             :   u8 packet_data[128 - 1 * sizeof (u32)];
     957             : }
     958             : ip6_forward_next_trace_t;
     959             : 
     960             : #ifndef CLIB_MARCH_VARIANT
     961             : u8 *
     962       47361 : format_ip6_forward_next_trace (u8 * s, va_list * args)
     963             : {
     964       47361 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     965       47361 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     966       47361 :   ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
     967       47361 :   u32 indent = format_get_indent (s);
     968             : 
     969       47361 :   s = format (s, "%Ufib:%d adj:%d flow:%d",
     970             :               format_white_space, indent,
     971             :               t->fib_index, t->adj_index, t->flow_hash);
     972       47361 :   s = format (s, "\n%U%U",
     973             :               format_white_space, indent,
     974       47361 :               format_ip6_header, t->packet_data, sizeof (t->packet_data));
     975       47361 :   return s;
     976             : }
     977             : #endif
     978             : 
     979             : static u8 *
     980      173784 : format_ip6_lookup_trace (u8 * s, va_list * args)
     981             : {
     982      173784 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     983      173784 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     984      173784 :   ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
     985      173784 :   u32 indent = format_get_indent (s);
     986             : 
     987      173784 :   s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
     988             :               t->fib_index, t->adj_index, t->flow_hash);
     989      173784 :   s = format (s, "\n%U%U",
     990             :               format_white_space, indent,
     991      173784 :               format_ip6_header, t->packet_data, sizeof (t->packet_data));
     992      173784 :   return s;
     993             : }
     994             : 
     995             : 
     996             : static u8 *
     997      112898 : format_ip6_rewrite_trace (u8 * s, va_list * args)
     998             : {
     999      112898 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1000      112898 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1001      112898 :   ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
    1002      112898 :   u32 indent = format_get_indent (s);
    1003             : 
    1004      112898 :   s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
    1005             :               t->fib_index, t->adj_index, format_ip_adjacency,
    1006             :               t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
    1007      112898 :   s = format (s, "\n%U%U",
    1008             :               format_white_space, indent,
    1009             :               format_ip_adjacency_packet_data,
    1010      112898 :               t->packet_data, sizeof (t->packet_data));
    1011      112898 :   return s;
    1012             : }
    1013             : 
    1014             : /* Common trace function for all ip6-forward next nodes. */
    1015             : #ifndef CLIB_MARCH_VARIANT
    1016             : void
    1017       10156 : ip6_forward_next_trace (vlib_main_t * vm,
    1018             :                         vlib_node_runtime_t * node,
    1019             :                         vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
    1020             : {
    1021             :   u32 *from, n_left;
    1022       10156 :   ip6_main_t *im = &ip6_main;
    1023             : 
    1024       10156 :   n_left = frame->n_vectors;
    1025       10156 :   from = vlib_frame_vector_args (frame);
    1026             : 
    1027      245126 :   while (n_left >= 4)
    1028             :     {
    1029             :       u32 bi0, bi1;
    1030             :       vlib_buffer_t *b0, *b1;
    1031             :       ip6_forward_next_trace_t *t0, *t1;
    1032             : 
    1033             :       /* Prefetch next iteration. */
    1034      234970 :       vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
    1035      234970 :       vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
    1036             : 
    1037      234970 :       bi0 = from[0];
    1038      234970 :       bi1 = from[1];
    1039             : 
    1040      234970 :       b0 = vlib_get_buffer (vm, bi0);
    1041      234970 :       b1 = vlib_get_buffer (vm, bi1);
    1042             : 
    1043      234970 :       if (b0->flags & VLIB_BUFFER_IS_TRACED)
    1044             :         {
    1045      234541 :           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
    1046      234541 :           t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
    1047      234541 :           t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
    1048      234541 :           t0->fib_index =
    1049      234541 :             (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
    1050      234541 :              (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
    1051      137722 :             vec_elt (im->fib_index_by_sw_if_index,
    1052             :                      vnet_buffer (b0)->sw_if_index[VLIB_RX]);
    1053             : 
    1054      234541 :           clib_memcpy_fast (t0->packet_data,
    1055      234541 :                             vlib_buffer_get_current (b0),
    1056             :                             sizeof (t0->packet_data));
    1057             :         }
    1058      234970 :       if (b1->flags & VLIB_BUFFER_IS_TRACED)
    1059             :         {
    1060      234540 :           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
    1061      234540 :           t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
    1062      234540 :           t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
    1063      234540 :           t1->fib_index =
    1064      234540 :             (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
    1065      234540 :              (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
    1066      137721 :             vec_elt (im->fib_index_by_sw_if_index,
    1067             :                      vnet_buffer (b1)->sw_if_index[VLIB_RX]);
    1068             : 
    1069      234540 :           clib_memcpy_fast (t1->packet_data,
    1070      234540 :                             vlib_buffer_get_current (b1),
    1071             :                             sizeof (t1->packet_data));
    1072             :         }
    1073      234970 :       from += 2;
    1074      234970 :       n_left -= 2;
    1075             :     }
    1076             : 
    1077       33588 :   while (n_left >= 1)
    1078             :     {
    1079             :       u32 bi0;
    1080             :       vlib_buffer_t *b0;
    1081             :       ip6_forward_next_trace_t *t0;
    1082             : 
    1083       23431 :       bi0 = from[0];
    1084             : 
    1085       23431 :       b0 = vlib_get_buffer (vm, bi0);
    1086             : 
    1087       23431 :       if (b0->flags & VLIB_BUFFER_IS_TRACED)
    1088             :         {
    1089       23273 :           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
    1090       23274 :           t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
    1091       23274 :           t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
    1092       23274 :           t0->fib_index =
    1093       23274 :             (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
    1094       23274 :              (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
    1095       13864 :             vec_elt (im->fib_index_by_sw_if_index,
    1096             :                      vnet_buffer (b0)->sw_if_index[VLIB_RX]);
    1097             : 
    1098       23274 :           clib_memcpy_fast (t0->packet_data,
    1099       23274 :                             vlib_buffer_get_current (b0),
    1100             :                             sizeof (t0->packet_data));
    1101             :         }
    1102       23432 :       from += 1;
    1103       23432 :       n_left -= 1;
    1104             :     }
    1105       10157 : }
    1106             : 
    1107             : /* Compute TCP/UDP/ICMP6 checksum in software. */
    1108             : u16
    1109    10843700 : ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
    1110             :                                    ip6_header_t * ip0, int *bogus_lengthp)
    1111             : {
    1112    10843700 :   ip_csum_t sum0 = 0;
    1113             :   u16 payload_length, payload_length_host_byte_order;
    1114             :   u32 i;
    1115    10843700 :   u32 headers_size = sizeof (ip0[0]);
    1116             :   u8 *data_this_buffer;
    1117    10843700 :   u8 next_hdr = ip0->protocol;
    1118             : 
    1119    10843700 :   ASSERT (bogus_lengthp);
    1120    10843700 :   *bogus_lengthp = 0;
    1121             : 
    1122    10843700 :   payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
    1123    10843700 :   data_this_buffer = (u8 *) (ip0 + 1);
    1124    10843700 :   payload_length = ip0->payload_length;
    1125             : 
    1126             :   /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
    1127             :    * or UDP-Ping packets */
    1128    10843700 :   if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
    1129             :     {
    1130             :       u32 skip_bytes;
    1131        1794 :       ip6_hop_by_hop_ext_t *ext_hdr =
    1132             :         (ip6_hop_by_hop_ext_t *) data_this_buffer;
    1133             : 
    1134             :       /* validate really icmp6 next */
    1135        1794 :       ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
    1136             :               || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
    1137             : 
    1138        1794 :       skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
    1139        1794 :       data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
    1140             : 
    1141        1794 :       payload_length_host_byte_order -= skip_bytes;
    1142        1794 :       headers_size += skip_bytes;
    1143             : 
    1144             :       /* pseudo-header adjustments:
    1145             :        *   exclude ext header bytes from payload length
    1146             :        *   use payload IP proto rather than ext header IP proto
    1147             :        */
    1148        1794 :       payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
    1149        1794 :       next_hdr = ext_hdr->next_hdr;
    1150             :     }
    1151             : 
    1152             :   /* Initialize checksum with ip pseudo-header. */
    1153    10843700 :   sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
    1154             : 
    1155    32531200 :   for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
    1156             :     {
    1157    21687400 :       sum0 = ip_csum_with_carry
    1158    21687400 :         (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
    1159    21687400 :       sum0 = ip_csum_with_carry
    1160    21687400 :         (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
    1161             :     }
    1162             : 
    1163    10843700 :   if (p0)
    1164    10843600 :     return ip_calculate_l4_checksum (vm, p0, sum0,
    1165             :                                      payload_length_host_byte_order,
    1166             :                                      (u8 *) ip0, headers_size, NULL);
    1167             :   else
    1168         150 :     return ip_calculate_l4_checksum (vm, 0, sum0,
    1169             :                                      payload_length_host_byte_order, NULL, 0,
    1170             :                                      data_this_buffer);
    1171             : }
    1172             : 
    1173             : u32
    1174    10515400 : ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
    1175             : {
    1176    10515400 :   ip6_header_t *ip0 = vlib_buffer_get_current (p0);
    1177             :   udp_header_t *udp0;
    1178             :   u16 sum16;
    1179             :   int bogus_length;
    1180             : 
    1181             :   /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
    1182    10515400 :   ASSERT (ip0->protocol == IP_PROTOCOL_TCP
    1183             :           || ip0->protocol == IP_PROTOCOL_ICMP6
    1184             :           || ip0->protocol == IP_PROTOCOL_UDP
    1185             :           || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
    1186             : 
    1187    10515400 :   udp0 = (void *) (ip0 + 1);
    1188    10515400 :   if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
    1189             :     {
    1190           0 :       p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
    1191             :                     | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
    1192           0 :       return p0->flags;
    1193             :     }
    1194             : 
    1195    10515400 :   sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
    1196             : 
    1197    21030700 :   p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
    1198    10515400 :                 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
    1199             : 
    1200    10515400 :   return p0->flags;
    1201             : }
    1202             : #endif
    1203             : 
    1204             : /**
    1205             :  * @brief returns number of links on which src is reachable.
    1206             :  */
    1207             : always_inline int
    1208       25686 : ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
    1209             : {
    1210             :   const load_balance_t *lb0;
    1211             :   index_t lbi;
    1212             :   u32 fib_index;
    1213             : 
    1214       25686 :   fib_index = vec_elt (im->fib_index_by_sw_if_index,
    1215             :                        vnet_buffer (b)->sw_if_index[VLIB_RX]);
    1216       25686 :   fib_index =
    1217       25686 :     (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
    1218       25686 :     fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
    1219             : 
    1220       25686 :   lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
    1221       25686 :   lb0 = load_balance_get (lbi);
    1222             : 
    1223       25686 :   return (fib_urpf_check_size (lb0->lb_urpf));
    1224             : }
    1225             : 
    1226             : always_inline u8
    1227       60615 : ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
    1228             :                            u32 * udp_offset0)
    1229             : {
    1230       60615 :   int nh = ip6_locate_header (p0, ip0, -1, udp_offset0);
    1231       60615 :   if (nh > 0)
    1232       60613 :     if (nh == IP_PROTOCOL_UDP || nh == IP_PROTOCOL_TCP)
    1233       13523 :       return nh;
    1234       47092 :   return 0;
    1235             : }
    1236             : 
    1237             : /* *INDENT-OFF* */
    1238        1151 : VNET_FEATURE_ARC_INIT (ip6_local) = {
    1239             :   .arc_name = "ip6-local",
    1240             :   .start_nodes = VNET_FEATURES ("ip6-local", "ip6-receive"),
    1241             : };
    1242             : /* *INDENT-ON* */
    1243             : 
    1244             : static_always_inline u8
    1245       18538 : ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
    1246             : {
    1247             : 
    1248             :   u16 payload_length_host_byte_order;
    1249             :   u32 n_this_buffer, n_bytes_left;
    1250       18538 :   ip6_header_t *ip0 = vlib_buffer_get_current (p0);
    1251       18538 :   u32 headers_size = sizeof (ip0[0]);
    1252             :   u8 *data_this_buffer;
    1253             : 
    1254             : 
    1255       18538 :   data_this_buffer = (u8 *) (ip0 + 1);
    1256             : 
    1257       18538 :   ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
    1258             : 
    1259             :   /* validate really icmp6 next */
    1260             : 
    1261       18538 :   if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
    1262         255 :       || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
    1263       18283 :     return 0;
    1264             : 
    1265             : 
    1266         255 :   payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
    1267         255 :   n_bytes_left = n_this_buffer = payload_length_host_byte_order;
    1268             : 
    1269             : 
    1270         255 :   u32 n_ip_bytes_this_buffer =
    1271         255 :     p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
    1272         255 :   if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
    1273             :     {
    1274           0 :       n_this_buffer = p0->current_length > headers_size ?
    1275           0 :         n_ip_bytes_this_buffer - headers_size : 0;
    1276             :     }
    1277             : 
    1278         255 :   n_bytes_left -= n_this_buffer;
    1279         255 :   n_bytes_left -= vlib_buffer_length_in_chain (vm, p0) - p0->current_length;
    1280             : 
    1281         255 :   if (n_bytes_left == 0)
    1282         255 :     return 0;
    1283             :   else
    1284           0 :     return 1;
    1285             : }
    1286             : 
    1287             : always_inline uword
    1288        3249 : ip6_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
    1289             :                   vlib_frame_t *frame, int head_of_feature_arc,
    1290             :                   int is_receive_dpo)
    1291             : {
    1292        3249 :   ip6_main_t *im = &ip6_main;
    1293        3249 :   ip_lookup_main_t *lm = &im->lookup_main;
    1294             :   u32 *from, n_left_from;
    1295             :   vlib_node_runtime_t *error_node =
    1296        3249 :     vlib_node_get_runtime (vm, ip6_input_node.index);
    1297        3249 :   u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
    1298             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
    1299             :   u16 nexts[VLIB_FRAME_SIZE], *next;
    1300             : 
    1301        3249 :   from = vlib_frame_vector_args (frame);
    1302        3249 :   n_left_from = frame->n_vectors;
    1303             : 
    1304        3249 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
    1305        2505 :     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
    1306             : 
    1307        3249 :   vlib_get_buffers (vm, from, bufs, n_left_from);
    1308        3249 :   b = bufs;
    1309        3249 :   next = nexts;
    1310             : 
    1311       31786 :   while (n_left_from > 2)
    1312             :     {
    1313             :       /* Prefetch next iteration. */
    1314       28537 :       if (n_left_from >= 6)
    1315             :         {
    1316       27234 :           vlib_prefetch_buffer_header (b[4], STORE);
    1317       27234 :           vlib_prefetch_buffer_header (b[5], STORE);
    1318       27234 :           vlib_prefetch_buffer_data (b[2], LOAD);
    1319       27234 :           vlib_prefetch_buffer_data (b[3], LOAD);
    1320             :         }
    1321             : 
    1322             :       vl_counter_ip6_enum_t error[2];
    1323       28537 :       error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
    1324       28537 :       error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
    1325             : 
    1326             :       ip6_header_t *ip[2];
    1327       28537 :       ip[0] = vlib_buffer_get_current (b[0]);
    1328       28537 :       ip[1] = vlib_buffer_get_current (b[1]);
    1329             : 
    1330       28537 :       if (head_of_feature_arc)
    1331             :         {
    1332       28537 :           vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
    1333       28537 :           vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
    1334             : 
    1335             :           u8 type[2];
    1336       28537 :           type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
    1337       28537 :           type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
    1338             : 
    1339             :           u32 flags[2];
    1340       28537 :           flags[0] = b[0]->flags;
    1341       28537 :           flags[1] = b[1]->flags;
    1342             : 
    1343             :           vnet_buffer_oflags_t oflags[2];
    1344       28537 :           oflags[0] = vnet_buffer (b[0])->oflags;
    1345       28537 :           oflags[1] = vnet_buffer (b[1])->oflags;
    1346             : 
    1347             :           u32 l4_offload[2];
    1348       28537 :           l4_offload[0] = (flags[0] & VNET_BUFFER_F_OFFLOAD) &&
    1349           0 :                           (oflags[0] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
    1350             :                                         VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
    1351       28537 :           l4_offload[1] = (flags[1] & VNET_BUFFER_F_OFFLOAD) &&
    1352           0 :                           (oflags[1] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
    1353             :                                         VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
    1354             : 
    1355             :           u32 good_l4_csum[2];
    1356       28537 :           good_l4_csum[0] =
    1357       28537 :             (flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[0];
    1358       28537 :           good_l4_csum[1] =
    1359       28537 :             (flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[1];
    1360             : 
    1361       28537 :           u32 udp_offset[2] = { };
    1362             :           u8 is_tcp_udp[2];
    1363       28537 :           is_tcp_udp[0] =
    1364       28537 :             ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
    1365       28537 :           is_tcp_udp[1] =
    1366       28537 :             ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
    1367       28537 :           i16 len_diff[2] = { 0 };
    1368       28537 :           if (PREDICT_TRUE (is_tcp_udp[0]))
    1369             :             {
    1370        6579 :               udp_header_t *udp =
    1371        6579 :                 (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
    1372       13158 :               good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
    1373        6579 :                 && udp->checksum == 0;
    1374             :               /* optimistically verify UDP length. */
    1375             :               u16 ip_len, udp_len;
    1376        6579 :               ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
    1377        6579 :               udp_len = clib_net_to_host_u16 (udp->length);
    1378        6579 :               len_diff[0] = ip_len - udp_len;
    1379             :             }
    1380       28537 :           if (PREDICT_TRUE (is_tcp_udp[1]))
    1381             :             {
    1382        6579 :               udp_header_t *udp =
    1383        6579 :                 (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
    1384       13158 :               good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
    1385        6579 :                 && udp->checksum == 0;
    1386             :               /* optimistically verify UDP length. */
    1387             :               u16 ip_len, udp_len;
    1388        6579 :               ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
    1389        6579 :               udp_len = clib_net_to_host_u16 (udp->length);
    1390        6579 :               len_diff[1] = ip_len - udp_len;
    1391             :             }
    1392             : 
    1393       28537 :           good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
    1394       28537 :           good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
    1395             : 
    1396       28537 :           len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
    1397       28537 :           len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
    1398             : 
    1399             :           u8 need_csum[2];
    1400       57074 :           need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
    1401       19793 :             && !good_l4_csum[0]
    1402       48330 :             && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
    1403       57074 :           need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
    1404       19792 :             && !good_l4_csum[1]
    1405       48329 :             && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
    1406       28537 :           if (PREDICT_FALSE (need_csum[0]))
    1407             :             {
    1408       19521 :               flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
    1409       19521 :               good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
    1410       19521 :               error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
    1411             :             }
    1412             :           else
    1413             :             {
    1414        9016 :               if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
    1415           0 :                 error[0] = IP6_ERROR_BAD_LENGTH;
    1416             :             }
    1417       28537 :           if (PREDICT_FALSE (need_csum[1]))
    1418             :             {
    1419       19520 :               flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
    1420       19520 :               good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
    1421       19520 :               error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
    1422             :             }
    1423             :           else
    1424             :             {
    1425        9017 :               if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
    1426           0 :                 error[1] = IP6_ERROR_BAD_LENGTH;
    1427             :             }
    1428             : 
    1429             : 
    1430       28537 :           error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
    1431             : 
    1432       28537 :           error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
    1433             : 
    1434             :           STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
    1435             :                          IP6_ERROR_UDP_CHECKSUM,
    1436             :                          "Wrong IP6 errors constants");
    1437             :           STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
    1438             :                          IP6_ERROR_ICMP_CHECKSUM,
    1439             :                          "Wrong IP6 errors constants");
    1440             : 
    1441       28537 :           error[0] =
    1442       28537 :             !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
    1443       28537 :           error[1] =
    1444       28537 :             !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
    1445             : 
    1446             :           /* Drop packets from unroutable hosts. */
    1447             :           /* If this is a neighbor solicitation (ICMP), skip source RPF check */
    1448             :           u8 unroutable[2];
    1449       57074 :           unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
    1450       28513 :             && type[0] != IP_BUILTIN_PROTOCOL_ICMP
    1451       57050 :             && !ip6_address_is_link_local_unicast (&ip[0]->src_address);
    1452       57074 :           unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
    1453       28513 :             && type[1] != IP_BUILTIN_PROTOCOL_ICMP
    1454       57050 :             && !ip6_address_is_link_local_unicast (&ip[1]->src_address);
    1455       28537 :           if (PREDICT_FALSE (unroutable[0]))
    1456             :             {
    1457       12561 :               error[0] =
    1458       12561 :                 !ip6_urpf_loose_check (im, b[0],
    1459             :                                        ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
    1460       12561 :                 : error[0];
    1461             :             }
    1462       28537 :           if (PREDICT_FALSE (unroutable[1]))
    1463             :             {
    1464       12560 :               error[1] =
    1465       12560 :                 !ip6_urpf_loose_check (im, b[1],
    1466             :                                        ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
    1467       12560 :                 : error[1];
    1468             :             }
    1469             : 
    1470       28537 :           vnet_buffer (b[0])->ip.fib_index =
    1471       28537 :             vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
    1472       28537 :             vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
    1473       28410 :             vnet_buffer (b[0])->ip.fib_index;
    1474       28537 :           vnet_buffer (b[1])->ip.fib_index =
    1475       28537 :             vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
    1476       28537 :             vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
    1477       28410 :             vnet_buffer (b[1])->ip.fib_index;
    1478             : 
    1479       28537 :           vnet_buffer (b[0])->ip.rx_sw_if_index =
    1480       28537 :             vnet_buffer (b[0])->sw_if_index[VLIB_RX];
    1481       28537 :           vnet_buffer (b[1])->ip.rx_sw_if_index =
    1482       28537 :             vnet_buffer (b[1])->sw_if_index[VLIB_RX];
    1483       28537 :           if (is_receive_dpo)
    1484             :             {
    1485             :               const receive_dpo_t *rd0, *rd1;
    1486             :               rd0 =
    1487       28537 :                 receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
    1488             :               rd1 =
    1489       28537 :                 receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
    1490       28537 :               if (rd0->rd_sw_if_index != ~0)
    1491       28516 :                 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
    1492       28537 :               if (rd1->rd_sw_if_index != ~0)
    1493       28516 :                 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
    1494             :             }
    1495             :         }                       /* head_of_feature_arc */
    1496             : 
    1497       28537 :       next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
    1498       28537 :       next[0] =
    1499       28537 :         error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
    1500       28537 :       next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
    1501       28537 :       next[1] =
    1502       28537 :         error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
    1503             : 
    1504       28537 :       b[0]->error = error_node->errors[error[0]];
    1505       28537 :       b[1]->error = error_node->errors[error[1]];
    1506             : 
    1507       28537 :       if (head_of_feature_arc)
    1508             :         {
    1509             :           u8 ip6_unknown[2];
    1510       28537 :           ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
    1511       28537 :           ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
    1512       28537 :           if (PREDICT_TRUE (ip6_unknown[0]))
    1513             :             {
    1514       28501 :               u32 next32 = next[0];
    1515       28501 :               vnet_feature_arc_start (arc_index,
    1516       28501 :                                       vnet_buffer (b[0])->ip.rx_sw_if_index,
    1517             :                                       &next32, b[0]);
    1518       28501 :               next[0] = next32;
    1519             :             }
    1520       28537 :           if (PREDICT_TRUE (ip6_unknown[1]))
    1521             :             {
    1522       28501 :               u32 next32 = next[1];
    1523       28501 :               vnet_feature_arc_start (arc_index,
    1524       28501 :                                       vnet_buffer (b[1])->ip.rx_sw_if_index,
    1525       28501 :                                       &next32, b[1]);
    1526       28501 :               next[1] = next32;
    1527             :             }
    1528             :         }
    1529             : 
    1530             :       /* next */
    1531       28537 :       b += 2;
    1532       28537 :       next += 2;
    1533       28537 :       n_left_from -= 2;
    1534             :     }
    1535             : 
    1536        6790 :   while (n_left_from)
    1537             :     {
    1538             :       u8 error;
    1539        3541 :       error = IP6_ERROR_UNKNOWN_PROTOCOL;
    1540             : 
    1541             :       ip6_header_t *ip;
    1542        3541 :       ip = vlib_buffer_get_current (b[0]);
    1543             : 
    1544        3541 :       if (head_of_feature_arc)
    1545             :         {
    1546        3541 :           vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
    1547        3541 :           u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
    1548             : 
    1549        3541 :           u32 flags = b[0]->flags;
    1550             : 
    1551        3541 :           vnet_buffer_oflags_t oflags = vnet_buffer (b[0])->oflags;
    1552             : 
    1553        3558 :           u32 l4_offload = (flags & VNET_BUFFER_F_OFFLOAD) &&
    1554          17 :                            (oflags & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
    1555             :                                       VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
    1556             : 
    1557        3541 :           u32 good_l4_csum =
    1558        3541 :             (flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload;
    1559             :           u32 udp_offset;
    1560        3541 :           i16 len_diff = 0;
    1561        3541 :           u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
    1562        3541 :           if (PREDICT_TRUE (is_tcp_udp))
    1563             :             {
    1564         365 :               udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
    1565             :               /* Don't verify UDP checksum for packets with explicit zero checksum. */
    1566         365 :               good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
    1567         365 :                 && udp->checksum == 0;
    1568             :               /* optimistically verify UDP length. */
    1569             :               u16 ip_len, udp_len;
    1570         365 :               ip_len = clib_net_to_host_u16 (ip->payload_length);
    1571         365 :               udp_len = clib_net_to_host_u16 (udp->length);
    1572         365 :               len_diff = ip_len - udp_len;
    1573             :             }
    1574             : 
    1575        3541 :           good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
    1576        3541 :           len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
    1577             : 
    1578        3054 :           u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN &&
    1579        6595 :                          !good_l4_csum &&
    1580        3036 :                          !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
    1581        3541 :           if (PREDICT_FALSE (need_csum))
    1582             :             {
    1583        3036 :               flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
    1584        3036 :               good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
    1585        3036 :               error = IP6_ERROR_UNKNOWN_PROTOCOL;
    1586             :             }
    1587             :           else
    1588             :             {
    1589         505 :               if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
    1590           0 :                 error = IP6_ERROR_BAD_LENGTH;
    1591             :             }
    1592             : 
    1593             : 
    1594             : 
    1595        3541 :           error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
    1596             :           STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
    1597             :                          IP6_ERROR_UDP_CHECKSUM,
    1598             :                          "Wrong IP6 errors constants");
    1599             :           STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
    1600             :                          IP6_ERROR_ICMP_CHECKSUM,
    1601             :                          "Wrong IP6 errors constants");
    1602             : 
    1603        3541 :           error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
    1604             : 
    1605             :           /* Drop packets from unroutable hosts. */
    1606             :           /* If this is a neighbor solicitation (ICMP), skip source RPF check */
    1607        3541 :           u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
    1608        3539 :             && type != IP_BUILTIN_PROTOCOL_ICMP
    1609        7080 :             && !ip6_address_is_link_local_unicast (&ip->src_address);
    1610        3541 :           if (PREDICT_FALSE (unroutable))
    1611             :             {
    1612         565 :               error =
    1613         565 :                 !ip6_urpf_loose_check (im, b[0],
    1614             :                                        ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
    1615             :                 error;
    1616             :             }
    1617             : 
    1618        3541 :           vnet_buffer (b[0])->ip.fib_index =
    1619        3541 :             vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
    1620        3541 :             vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
    1621        3446 :             vnet_buffer (b[0])->ip.fib_index;
    1622             : 
    1623        3541 :           vnet_buffer (b[0])->ip.rx_sw_if_index =
    1624        3541 :             vnet_buffer (b[0])->sw_if_index[VLIB_RX];
    1625        3541 :           if (is_receive_dpo)
    1626             :             {
    1627             :               receive_dpo_t *rd;
    1628        3541 :               rd = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
    1629        3541 :               if (rd->rd_sw_if_index != ~0)
    1630        1300 :                 vnet_buffer (b[0])->ip.rx_sw_if_index = rd->rd_sw_if_index;
    1631             :             }
    1632             :         }                       /* head_of_feature_arc */
    1633             : 
    1634        3541 :       next[0] = lm->local_next_by_ip_protocol[ip->protocol];
    1635        3541 :       next[0] =
    1636             :         error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
    1637             : 
    1638        3541 :       b[0]->error = error_node->errors[error];
    1639             : 
    1640        3541 :       if (head_of_feature_arc)
    1641             :         {
    1642        3541 :           if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
    1643             :             {
    1644        3457 :               u32 next32 = next[0];
    1645        3457 :               vnet_feature_arc_start (arc_index,
    1646        3457 :                                       vnet_buffer (b[0])->ip.rx_sw_if_index,
    1647             :                                       &next32, b[0]);
    1648        3457 :               next[0] = next32;
    1649             :             }
    1650             :         }
    1651             : 
    1652             :       /* next */
    1653        3541 :       b += 1;
    1654        3541 :       next += 1;
    1655        3541 :       n_left_from -= 1;
    1656             :     }
    1657             : 
    1658        3249 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
    1659        3249 :   return frame->n_vectors;
    1660             : }
    1661             : 
    1662        2300 : VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
    1663             :                                vlib_frame_t * frame)
    1664             : {
    1665           0 :   return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */,
    1666             :                            0 /* ip6_local_inline */);
    1667             : }
    1668             : 
    1669      183788 : VLIB_REGISTER_NODE (ip6_local_node) =
    1670             : {
    1671             :   .name = "ip6-local",
    1672             :   .vector_size = sizeof (u32),
    1673             :   .format_trace = format_ip6_forward_next_trace,
    1674             :   .n_errors = IP6_N_ERROR,
    1675             :   .error_counters = ip6_error_counters,
    1676             :   .n_next_nodes = IP_LOCAL_N_NEXT,
    1677             :   .next_nodes =
    1678             :   {
    1679             :     [IP_LOCAL_NEXT_DROP] = "ip6-drop",
    1680             :     [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
    1681             :     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
    1682             :     [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
    1683             :     [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-local-full-reassembly",
    1684             :   },
    1685             : };
    1686             : 
    1687        5549 : VLIB_NODE_FN (ip6_receive_local_node)
    1688             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
    1689             : {
    1690        3249 :   return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */,
    1691             :                            1 /* is_receive_dpo */);
    1692             : }
    1693             : 
    1694      183788 : VLIB_REGISTER_NODE (ip6_receive_local_node) = {
    1695             :   .name = "ip6-receive",
    1696             :   .vector_size = sizeof (u32),
    1697             :   .format_trace = format_ip6_forward_next_trace,
    1698             :   .sibling_of = "ip6-local"
    1699             : };
    1700             : 
    1701        2300 : VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
    1702             :                                           vlib_node_runtime_t * node,
    1703             :                                           vlib_frame_t * frame)
    1704             : {
    1705           0 :   return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */,
    1706             :                            0 /* ip6_local_inline */);
    1707             : }
    1708             : 
    1709      183788 : VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
    1710             :   .name = "ip6-local-end-of-arc",
    1711             :   .vector_size = sizeof (u32),
    1712             : 
    1713             :   .format_trace = format_ip6_forward_next_trace,
    1714             :   .sibling_of = "ip6-local",
    1715             : };
    1716             : 
    1717       76635 : VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
    1718             :   .arc_name = "ip6-local",
    1719             :   .node_name = "ip6-local-end-of-arc",
    1720             :   .runs_before = 0, /* not before any other features */
    1721             : };
    1722             : 
    1723             : #ifdef CLIB_MARCH_VARIANT
    1724             : extern vlib_node_registration_t ip6_local_node;
    1725             : #else
    1726             : void
    1727        1927 : ip6_register_protocol (u32 protocol, u32 node_index)
    1728             : {
    1729        1927 :   vlib_main_t *vm = vlib_get_main ();
    1730        1927 :   ip6_main_t *im = &ip6_main;
    1731        1927 :   ip_lookup_main_t *lm = &im->lookup_main;
    1732             : 
    1733        1927 :   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
    1734        1927 :   lm->local_next_by_ip_protocol[protocol] =
    1735        1927 :     vlib_node_add_next (vm, ip6_local_node.index, node_index);
    1736        1927 : }
    1737             : 
    1738             : void
    1739          62 : ip6_unregister_protocol (u32 protocol)
    1740             : {
    1741          62 :   ip6_main_t *im = &ip6_main;
    1742          62 :   ip_lookup_main_t *lm = &im->lookup_main;
    1743             : 
    1744          62 :   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
    1745          62 :   lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
    1746          62 : }
    1747             : #endif
    1748             : 
    1749             : typedef enum
    1750             : {
    1751             :   IP6_REWRITE_NEXT_DROP,
    1752             :   IP6_REWRITE_NEXT_ICMP_ERROR,
    1753             :   IP6_REWRITE_NEXT_FRAGMENT,
    1754             :   IP6_REWRITE_N_NEXT            /* Last */
    1755             : } ip6_rewrite_next_t;
    1756             : 
    1757             : /**
    1758             :  * This bits of an IPv6 address to mask to construct a multicast
    1759             :  * MAC address
    1760             :  */
    1761             : #define IP6_MCAST_ADDR_MASK 0xffffffff
    1762             : 
    1763             : always_inline void
    1764     9992210 : ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
    1765             :                u16 adj_packet_bytes, bool is_locally_generated,
    1766             :                u32 * next, u8 is_midchain, u32 * error)
    1767             : {
    1768     9992210 :   if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
    1769             :     {
    1770          45 :       if (is_locally_generated)
    1771             :         {
    1772             :           /* IP fragmentation */
    1773          21 :           ip_frag_set_vnet_buffer (b, adj_packet_bytes,
    1774             :                                    (is_midchain ?
    1775             :                                     IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
    1776             :                                     IP_FRAG_NEXT_IP_REWRITE), 0);
    1777          21 :           *next = IP6_REWRITE_NEXT_FRAGMENT;
    1778          21 :           *error = IP6_ERROR_MTU_EXCEEDED;
    1779             :         }
    1780             :       else
    1781             :         {
    1782          24 :           *error = IP6_ERROR_MTU_EXCEEDED;
    1783          24 :           icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
    1784             :                                        adj_packet_bytes);
    1785          24 :           *next = IP6_REWRITE_NEXT_ICMP_ERROR;
    1786             :         }
    1787             :     }
    1788     9992210 : }
    1789             : 
    1790             : always_inline uword
    1791      231310 : ip6_rewrite_inline_with_gso (vlib_main_t * vm,
    1792             :                              vlib_node_runtime_t * node,
    1793             :                              vlib_frame_t * frame,
    1794             :                              int do_counters, int is_midchain, int is_mcast)
    1795             : {
    1796      231310 :   ip_lookup_main_t *lm = &ip6_main.lookup_main;
    1797      231310 :   u32 *from = vlib_frame_vector_args (frame);
    1798             :   u32 n_left_from, n_left_to_next, *to_next, next_index;
    1799             :   vlib_node_runtime_t *error_node =
    1800      231310 :     vlib_node_get_runtime (vm, ip6_input_node.index);
    1801             : 
    1802      231310 :   n_left_from = frame->n_vectors;
    1803      231310 :   next_index = node->cached_next_index;
    1804      231310 :   u32 thread_index = vm->thread_index;
    1805             : 
    1806      462621 :   while (n_left_from > 0)
    1807             :     {
    1808      231311 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1809             : 
    1810     4971480 :       while (n_left_from >= 4 && n_left_to_next >= 2)
    1811             :         {
    1812             :           const ip_adjacency_t *adj0, *adj1;
    1813             :           vlib_buffer_t *p0, *p1;
    1814             :           ip6_header_t *ip0, *ip1;
    1815             :           u32 pi0, rw_len0, next0, error0, adj_index0;
    1816             :           u32 pi1, rw_len1, next1, error1, adj_index1;
    1817             :           u32 tx_sw_if_index0, tx_sw_if_index1;
    1818             :           bool is_locally_originated0, is_locally_originated1;
    1819             : 
    1820             :           /* Prefetch next iteration. */
    1821             :           {
    1822             :             vlib_buffer_t *p2, *p3;
    1823             : 
    1824     4740170 :             p2 = vlib_get_buffer (vm, from[2]);
    1825     4740170 :             p3 = vlib_get_buffer (vm, from[3]);
    1826             : 
    1827     4740170 :             vlib_prefetch_buffer_header (p2, LOAD);
    1828     4740170 :             vlib_prefetch_buffer_header (p3, LOAD);
    1829             : 
    1830     4740170 :             clib_prefetch_store (p2->pre_data);
    1831     4740170 :             clib_prefetch_store (p3->pre_data);
    1832             : 
    1833     4740170 :             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
    1834     4740170 :             CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
    1835             :           }
    1836             : 
    1837     4740170 :           pi0 = to_next[0] = from[0];
    1838     4740170 :           pi1 = to_next[1] = from[1];
    1839             : 
    1840     4740170 :           from += 2;
    1841     4740170 :           n_left_from -= 2;
    1842     4740170 :           to_next += 2;
    1843     4740170 :           n_left_to_next -= 2;
    1844             : 
    1845     4740170 :           p0 = vlib_get_buffer (vm, pi0);
    1846     4740170 :           p1 = vlib_get_buffer (vm, pi1);
    1847             : 
    1848     4740170 :           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
    1849     4740170 :           adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
    1850             : 
    1851     4740170 :           ip0 = vlib_buffer_get_current (p0);
    1852     4740170 :           ip1 = vlib_buffer_get_current (p1);
    1853             : 
    1854     4740170 :           error0 = error1 = IP6_ERROR_NONE;
    1855     4740170 :           next0 = next1 = IP6_REWRITE_NEXT_DROP;
    1856             : 
    1857     4740170 :           is_locally_originated0 =
    1858     4740170 :             p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
    1859     4740170 :           if (PREDICT_TRUE (!is_locally_originated0))
    1860             :             {
    1861     4702800 :               i32 hop_limit0 = ip0->hop_limit;
    1862             : 
    1863             :               /* Input node should have reject packets with hop limit 0. */
    1864     4702800 :               ASSERT (ip0->hop_limit > 0);
    1865             : 
    1866     4702800 :               hop_limit0 -= 1;
    1867             : 
    1868     4702800 :               ip0->hop_limit = hop_limit0;
    1869             : 
    1870             :               /*
    1871             :                * If the hop count drops below 1 when forwarding, generate
    1872             :                * an ICMP response.
    1873             :                */
    1874     4702800 :               if (PREDICT_FALSE (hop_limit0 <= 0))
    1875             :                 {
    1876         286 :                   error0 = IP6_ERROR_TIME_EXPIRED;
    1877         286 :                   next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
    1878         286 :                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1879         286 :                   icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
    1880             :                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
    1881             :                                                0);
    1882             :                 }
    1883             :             }
    1884             : 
    1885     4740170 :           is_locally_originated1 =
    1886     4740170 :             p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
    1887     4740170 :           if (PREDICT_TRUE (!is_locally_originated1))
    1888             :             {
    1889     4702800 :               i32 hop_limit1 = ip1->hop_limit;
    1890             : 
    1891             :               /* Input node should have reject packets with hop limit 0. */
    1892     4702800 :               ASSERT (ip1->hop_limit > 0);
    1893             : 
    1894     4702800 :               hop_limit1 -= 1;
    1895             : 
    1896     4702800 :               ip1->hop_limit = hop_limit1;
    1897             : 
    1898             :               /*
    1899             :                * If the hop count drops below 1 when forwarding, generate
    1900             :                * an ICMP response.
    1901             :                */
    1902     4702800 :               if (PREDICT_FALSE (hop_limit1 <= 0))
    1903             :                 {
    1904         286 :                   error1 = IP6_ERROR_TIME_EXPIRED;
    1905         286 :                   next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
    1906         286 :                   vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1907         286 :                   icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
    1908             :                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
    1909             :                                                0);
    1910             :                 }
    1911             :             }
    1912             : 
    1913     4740170 :           adj0 = adj_get (adj_index0);
    1914     4740170 :           adj1 = adj_get (adj_index1);
    1915             : 
    1916     4740170 :           rw_len0 = adj0[0].rewrite_header.data_bytes;
    1917     4740170 :           rw_len1 = adj1[0].rewrite_header.data_bytes;
    1918     4740170 :           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
    1919     4740170 :           vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
    1920             : 
    1921     4740170 :           if (do_counters)
    1922             :             {
    1923          46 :               vlib_increment_combined_counter
    1924             :                 (&adjacency_counters,
    1925             :                  thread_index, adj_index0, 1,
    1926          46 :                  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
    1927          46 :               vlib_increment_combined_counter
    1928             :                 (&adjacency_counters,
    1929             :                  thread_index, adj_index1, 1,
    1930          46 :                  vlib_buffer_length_in_chain (vm, p1) + rw_len1);
    1931             :             }
    1932             : 
    1933             :           /* Check MTU of outgoing interface. */
    1934     4740170 :           u16 ip0_len =
    1935     4740170 :             clib_net_to_host_u16 (ip0->payload_length) +
    1936             :             sizeof (ip6_header_t);
    1937     4740170 :           u16 ip1_len =
    1938     4740170 :             clib_net_to_host_u16 (ip1->payload_length) +
    1939             :             sizeof (ip6_header_t);
    1940     4740170 :           if (p0->flags & VNET_BUFFER_F_GSO)
    1941       47806 :             ip0_len = gso_mtu_sz (p0);
    1942     4740170 :           if (p1->flags & VNET_BUFFER_F_GSO)
    1943       53785 :             ip1_len = gso_mtu_sz (p1);
    1944             : 
    1945     4740170 :           ip6_mtu_check (p0, ip0_len,
    1946     4740170 :                          adj0[0].rewrite_header.max_l3_packet_bytes,
    1947             :                          is_locally_originated0, &next0, is_midchain,
    1948             :                          &error0);
    1949     4740170 :           ip6_mtu_check (p1, ip1_len,
    1950     4740170 :                          adj1[0].rewrite_header.max_l3_packet_bytes,
    1951             :                          is_locally_originated1, &next1, is_midchain,
    1952             :                          &error1);
    1953             :           /* Don't adjust the buffer for hop count issue; icmp-error node
    1954             :            * wants to see the IP header */
    1955     4740170 :           if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
    1956             :             {
    1957     4739880 :               p0->current_data -= rw_len0;
    1958     4739880 :               p0->current_length += rw_len0;
    1959     4739880 :               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
    1960     4739880 :               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
    1961     4739880 :               next0 = adj0[0].rewrite_header.next_index;
    1962     4739880 :               if (PREDICT_FALSE
    1963             :                   (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    1964     2321930 :                 vnet_feature_arc_start_w_cfg_index
    1965     2321930 :                   (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
    1966             :                    adj0->ia_cfg_index);
    1967             :             }
    1968             :           else
    1969             :             {
    1970         294 :               p0->error = error_node->errors[error0];
    1971             :             }
    1972     4740170 :           if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
    1973             :             {
    1974     4739880 :               p1->current_data -= rw_len1;
    1975     4739880 :               p1->current_length += rw_len1;
    1976             : 
    1977     4739880 :               tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
    1978     4739880 :               vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
    1979     4739880 :               next1 = adj1[0].rewrite_header.next_index;
    1980             : 
    1981     4739880 :               if (PREDICT_FALSE
    1982             :                   (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    1983     2329800 :                 vnet_feature_arc_start_w_cfg_index
    1984     2329800 :                   (lm->output_feature_arc_index, tx_sw_if_index1, &next1, p1,
    1985             :                    adj1->ia_cfg_index);
    1986             :             }
    1987             :           else
    1988             :             {
    1989         294 :               p1->error = error_node->errors[error1];
    1990             :             }
    1991             : 
    1992     4740170 :           if (is_midchain)
    1993             :             {
    1994             :               /* before we paint on the next header, update the L4
    1995             :                * checksums if required, since there's no offload on a tunnel */
    1996        7110 :               vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
    1997             :                                           1 /* is_ip6 */ );
    1998        7110 :               vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ ,
    1999             :                                           1 /* is_ip6 */ );
    2000             : 
    2001             :               /* Guess we are only writing on ipv6 header. */
    2002        7110 :               vnet_rewrite_two_headers (adj0[0], adj1[0],
    2003             :                                         ip0, ip1, sizeof (ip6_header_t));
    2004             :             }
    2005             :           else
    2006             :             /* Guess we are only writing on simple Ethernet header. */
    2007     4733060 :             vnet_rewrite_two_headers (adj0[0], adj1[0],
    2008             :                                       ip0, ip1, sizeof (ethernet_header_t));
    2009             : 
    2010     4740170 :           if (is_midchain)
    2011             :             {
    2012        7110 :               if (adj0->sub_type.midchain.fixup_func)
    2013        6166 :                 adj0->sub_type.midchain.fixup_func
    2014             :                   (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
    2015        7110 :               if (adj1->sub_type.midchain.fixup_func)
    2016        6166 :                 adj1->sub_type.midchain.fixup_func
    2017             :                   (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
    2018             :             }
    2019     4740170 :           if (is_mcast)
    2020             :             {
    2021             :               /*
    2022             :                * copy bytes from the IP address into the MAC rewrite
    2023             :                */
    2024         664 :               vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
    2025             :                                           adj0->
    2026         664 :                                           rewrite_header.dst_mcast_offset,
    2027             :                                           &ip0->dst_address.as_u32[3],
    2028             :                                           (u8 *) ip0);
    2029         664 :               vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
    2030             :                                           adj1->
    2031         664 :                                           rewrite_header.dst_mcast_offset,
    2032             :                                           &ip1->dst_address.as_u32[3],
    2033             :                                           (u8 *) ip1);
    2034             :             }
    2035             : 
    2036     4740170 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
    2037             :                                            to_next, n_left_to_next,
    2038             :                                            pi0, pi1, next0, next1);
    2039             :         }
    2040             : 
    2041      743169 :       while (n_left_from > 0 && n_left_to_next > 0)
    2042             :         {
    2043             :           ip_adjacency_t *adj0;
    2044             :           vlib_buffer_t *p0;
    2045             :           ip6_header_t *ip0;
    2046             :           u32 pi0, rw_len0;
    2047             :           u32 adj_index0, next0, error0;
    2048             :           u32 tx_sw_if_index0;
    2049             :           bool is_locally_originated0;
    2050             : 
    2051      511858 :           pi0 = to_next[0] = from[0];
    2052             : 
    2053      511858 :           p0 = vlib_get_buffer (vm, pi0);
    2054             : 
    2055      511858 :           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
    2056             : 
    2057      511858 :           adj0 = adj_get (adj_index0);
    2058             : 
    2059      511858 :           ip0 = vlib_buffer_get_current (p0);
    2060             : 
    2061      511858 :           error0 = IP6_ERROR_NONE;
    2062      511858 :           next0 = IP6_REWRITE_NEXT_DROP;
    2063             : 
    2064             :           /* Check hop limit */
    2065      511858 :           is_locally_originated0 =
    2066      511858 :             p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
    2067      511858 :           if (PREDICT_TRUE (!is_locally_originated0))
    2068             :             {
    2069      506116 :               i32 hop_limit0 = ip0->hop_limit;
    2070             : 
    2071      506116 :               ASSERT (ip0->hop_limit > 0);
    2072             : 
    2073      506116 :               hop_limit0 -= 1;
    2074             : 
    2075      506116 :               ip0->hop_limit = hop_limit0;
    2076             : 
    2077      506116 :               if (PREDICT_FALSE (hop_limit0 <= 0))
    2078             :                 {
    2079             :                   /*
    2080             :                    * If the hop count drops below 1 when forwarding, generate
    2081             :                    * an ICMP response.
    2082             :                    */
    2083           9 :                   error0 = IP6_ERROR_TIME_EXPIRED;
    2084           9 :                   next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
    2085           9 :                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    2086           9 :                   icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
    2087             :                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
    2088             :                                                0);
    2089             :                 }
    2090             :             }
    2091             : 
    2092      511858 :           if (is_midchain)
    2093             :             {
    2094         429 :               vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
    2095             :                                           1 /* is_ip6 */ );
    2096             : 
    2097             :               /* Guess we are only writing on ip6 header. */
    2098         429 :               vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t));
    2099             :             }
    2100             :           else
    2101             :             /* Guess we are only writing on simple Ethernet header. */
    2102      511429 :             vnet_rewrite_one_header (adj0[0], ip0,
    2103             :                                      sizeof (ethernet_header_t));
    2104             : 
    2105             :           /* Update packet buffer attributes/set output interface. */
    2106      511858 :           rw_len0 = adj0[0].rewrite_header.data_bytes;
    2107      511858 :           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
    2108             : 
    2109      511858 :           if (do_counters)
    2110             :             {
    2111          11 :               vlib_increment_combined_counter
    2112             :                 (&adjacency_counters,
    2113             :                  thread_index, adj_index0, 1,
    2114          11 :                  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
    2115             :             }
    2116             : 
    2117             :           /* Check MTU of outgoing interface. */
    2118      511858 :           u16 ip0_len =
    2119      511858 :             clib_net_to_host_u16 (ip0->payload_length) +
    2120             :             sizeof (ip6_header_t);
    2121      511858 :           if (p0->flags & VNET_BUFFER_F_GSO)
    2122       74946 :             ip0_len = gso_mtu_sz (p0);
    2123             : 
    2124      511858 :           ip6_mtu_check (p0, ip0_len,
    2125      511858 :                          adj0[0].rewrite_header.max_l3_packet_bytes,
    2126             :                          is_locally_originated0, &next0, is_midchain,
    2127             :                          &error0);
    2128             :           /* Don't adjust the buffer for hop count issue; icmp-error node
    2129             :            * wants to see the IP header */
    2130      511858 :           if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
    2131             :             {
    2132      511820 :               p0->current_data -= rw_len0;
    2133      511820 :               p0->current_length += rw_len0;
    2134             : 
    2135      511820 :               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
    2136             : 
    2137      511820 :               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
    2138      511820 :               next0 = adj0[0].rewrite_header.next_index;
    2139             : 
    2140      511820 :               if (PREDICT_FALSE
    2141             :                   (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    2142      347875 :                 vnet_feature_arc_start_w_cfg_index
    2143      347875 :                   (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
    2144             :                    adj0->ia_cfg_index);
    2145             :             }
    2146             :           else
    2147             :             {
    2148          38 :               p0->error = error_node->errors[error0];
    2149             :             }
    2150             : 
    2151      511858 :           if (is_midchain)
    2152             :             {
    2153         429 :               if (adj0->sub_type.midchain.fixup_func)
    2154         368 :                 adj0->sub_type.midchain.fixup_func
    2155             :                   (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
    2156             :             }
    2157      511858 :           if (is_mcast)
    2158             :             {
    2159        1966 :               vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
    2160             :                                           adj0->
    2161        1966 :                                           rewrite_header.dst_mcast_offset,
    2162             :                                           &ip0->dst_address.as_u32[3],
    2163             :                                           (u8 *) ip0);
    2164             :             }
    2165             : 
    2166      511858 :           from += 1;
    2167      511858 :           n_left_from -= 1;
    2168      511858 :           to_next += 1;
    2169      511858 :           n_left_to_next -= 1;
    2170             : 
    2171      511858 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
    2172             :                                            to_next, n_left_to_next,
    2173             :                                            pi0, next0);
    2174             :         }
    2175             : 
    2176      231311 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    2177             :     }
    2178             : 
    2179             :   /* Need to do trace after rewrites to pick up new packet data. */
    2180      231310 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
    2181        2997 :     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
    2182             : 
    2183      231310 :   return frame->n_vectors;
    2184             : }
    2185             : 
    2186             : always_inline uword
    2187      231310 : ip6_rewrite_inline (vlib_main_t * vm,
    2188             :                     vlib_node_runtime_t * node,
    2189             :                     vlib_frame_t * frame,
    2190             :                     int do_counters, int is_midchain, int is_mcast)
    2191             : {
    2192      231310 :   return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
    2193             :                                       is_midchain, is_mcast);
    2194             : }
    2195             : 
    2196      231443 : VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
    2197             :                                  vlib_node_runtime_t * node,
    2198             :                                  vlib_frame_t * frame)
    2199             : {
    2200      229143 :   if (adj_are_counters_enabled ())
    2201           3 :     return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
    2202             :   else
    2203      229140 :     return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
    2204             : }
    2205             : 
    2206        2300 : VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
    2207             :                                        vlib_node_runtime_t * node,
    2208             :                                        vlib_frame_t * frame)
    2209             : {
    2210           0 :   if (adj_are_counters_enabled ())
    2211           0 :     return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
    2212             :   else
    2213           0 :     return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
    2214             : }
    2215             : 
    2216        4253 : VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
    2217             :                                        vlib_node_runtime_t * node,
    2218             :                                        vlib_frame_t * frame)
    2219             : {
    2220        1953 :   if (adj_are_counters_enabled ())
    2221           4 :     return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
    2222             :   else
    2223        1949 :     return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
    2224             : }
    2225             : 
    2226        2514 : VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
    2227             :                                   vlib_node_runtime_t * node,
    2228             :                                   vlib_frame_t * frame)
    2229             : {
    2230         214 :   if (adj_are_counters_enabled ())
    2231           0 :     return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
    2232             :   else
    2233         214 :     return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
    2234             : }
    2235             : 
    2236        2300 : VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
    2237             :                                         vlib_node_runtime_t * node,
    2238             :                                         vlib_frame_t * frame)
    2239             : {
    2240           0 :   if (adj_are_counters_enabled ())
    2241           0 :     return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
    2242             :   else
    2243           0 :     return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
    2244             : }
    2245             : 
    2246             : /* *INDENT-OFF* */
    2247      183788 : VLIB_REGISTER_NODE (ip6_midchain_node) = {
    2248             :   .name = "ip6-midchain",
    2249             :   .vector_size = sizeof (u32),
    2250             :   .format_trace = format_ip6_forward_next_trace,
    2251             :   .sibling_of = "ip6-rewrite",
    2252             : };
    2253             : 
    2254      183788 : VLIB_REGISTER_NODE (ip6_rewrite_node) =
    2255             : {
    2256             :   .name = "ip6-rewrite",
    2257             :   .vector_size = sizeof (u32),
    2258             :   .format_trace = format_ip6_rewrite_trace,
    2259             :   .n_errors = IP6_N_ERROR,
    2260             :   .error_counters = ip6_error_counters,
    2261             :   .n_next_nodes = IP6_REWRITE_N_NEXT,
    2262             :   .next_nodes =
    2263             :   {
    2264             :     [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
    2265             :     [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
    2266             :     [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
    2267             :   },
    2268             : };
    2269             : 
    2270      183788 : VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
    2271             :   .name = "ip6-rewrite-bcast",
    2272             :   .vector_size = sizeof (u32),
    2273             : 
    2274             :   .format_trace = format_ip6_rewrite_trace,
    2275             :   .sibling_of = "ip6-rewrite",
    2276             : };
    2277             : 
    2278      183788 : VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
    2279             : {
    2280             :   .name = "ip6-rewrite-mcast",
    2281             :   .vector_size = sizeof (u32),
    2282             :   .format_trace = format_ip6_rewrite_trace,
    2283             :   .sibling_of = "ip6-rewrite",
    2284             : };
    2285             : 
    2286             : 
    2287      183788 : VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
    2288             : {
    2289             :   .name = "ip6-mcast-midchain",
    2290             :   .vector_size = sizeof (u32),
    2291             :   .format_trace = format_ip6_rewrite_trace,
    2292             :   .sibling_of = "ip6-rewrite",
    2293             : };
    2294             : 
    2295             : /* *INDENT-ON* */
    2296             : 
    2297             : /*
    2298             :  * Hop-by-Hop handling
    2299             :  */
    2300             : #ifndef CLIB_MARCH_VARIANT
    2301             : ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
    2302             : #endif /* CLIB_MARCH_VARIANT */
    2303             : 
    2304             : #define foreach_ip6_hop_by_hop_error \
    2305             : _(PROCESSED, "pkts with ip6 hop-by-hop options") \
    2306             : _(FORMAT, "incorrectly formatted hop-by-hop options") \
    2307             : _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
    2308             : 
    2309             : /* *INDENT-OFF* */
    2310             : typedef enum
    2311             : {
    2312             : #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
    2313             :   foreach_ip6_hop_by_hop_error
    2314             : #undef _
    2315             :   IP6_HOP_BY_HOP_N_ERROR,
    2316             : } ip6_hop_by_hop_error_t;
    2317             : /* *INDENT-ON* */
    2318             : 
    2319             : /*
    2320             :  * Primary h-b-h handler trace support
    2321             :  * We work pretty hard on the problem for obvious reasons
    2322             :  */
    2323             : typedef struct
    2324             : {
    2325             :   u32 next_index;
    2326             :   u32 trace_len;
    2327             :   u8 option_data[256];
    2328             : } ip6_hop_by_hop_trace_t;
    2329             : 
    2330             : extern vlib_node_registration_t ip6_hop_by_hop_node;
    2331             : 
    2332             : static char *ip6_hop_by_hop_error_strings[] = {
    2333             : #define _(sym,string) string,
    2334             :   foreach_ip6_hop_by_hop_error
    2335             : #undef _
    2336             : };
    2337             : 
    2338             : #ifndef CLIB_MARCH_VARIANT
    2339             : u8 *
    2340           0 : format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
    2341             : {
    2342           0 :   ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
    2343           0 :   int total_len = va_arg (*args, int);
    2344             :   ip6_hop_by_hop_option_t *opt0, *limit0;
    2345           0 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2346             :   u8 type0;
    2347           0 :   s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
    2348           0 :               hbh0->protocol, (hbh0->length + 1) << 3, total_len);
    2349             : 
    2350           0 :   opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
    2351           0 :   limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
    2352             : 
    2353           0 :   while (opt0 < limit0)
    2354             :     {
    2355           0 :       type0 = opt0->type;
    2356           0 :       switch (type0)
    2357             :         {
    2358           0 :         case 0:         /* Pad, just stop */
    2359           0 :           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
    2360           0 :           break;
    2361             : 
    2362           0 :         default:
    2363           0 :           if (hm->trace[type0])
    2364             :             {
    2365           0 :               s = (*hm->trace[type0]) (s, opt0);
    2366             :             }
    2367             :           else
    2368             :             {
    2369           0 :               s = format (s, "\n    unrecognized option %d length %d", type0,
    2370           0 :                           opt0->length);
    2371             :             }
    2372           0 :           opt0 =
    2373           0 :             (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
    2374             :                                          sizeof (ip6_hop_by_hop_option_t));
    2375           0 :           break;
    2376             :         }
    2377             :     }
    2378           0 :   return s;
    2379             : }
    2380             : #endif
    2381             : 
    2382             : static u8 *
    2383           3 : format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
    2384             : {
    2385           3 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    2386           3 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    2387           3 :   ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
    2388             :   ip6_hop_by_hop_header_t *hbh0;
    2389             :   ip6_hop_by_hop_option_t *opt0, *limit0;
    2390           3 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2391             : 
    2392             :   u8 type0;
    2393             : 
    2394           3 :   hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
    2395             : 
    2396           3 :   s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
    2397           3 :               t->next_index, (hbh0->length + 1) << 3, t->trace_len);
    2398             : 
    2399           3 :   opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
    2400           3 :   limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
    2401             : 
    2402          18 :   while (opt0 < limit0)
    2403             :     {
    2404          15 :       type0 = opt0->type;
    2405          15 :       switch (type0)
    2406             :         {
    2407          12 :         case 0:         /* Pad, just stop */
    2408          12 :           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
    2409          12 :           break;
    2410             : 
    2411           3 :         default:
    2412           3 :           if (hm->trace[type0])
    2413             :             {
    2414           0 :               s = (*hm->trace[type0]) (s, opt0);
    2415             :             }
    2416             :           else
    2417             :             {
    2418           3 :               s = format (s, "\n    unrecognized option %d length %d", type0,
    2419           3 :                           opt0->length);
    2420             :             }
    2421           3 :           opt0 =
    2422           3 :             (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
    2423             :                                          sizeof (ip6_hop_by_hop_option_t));
    2424           3 :           break;
    2425             :         }
    2426             :     }
    2427           3 :   return s;
    2428             : }
    2429             : 
    2430             : always_inline u8
    2431           2 : ip6_scan_hbh_options (vlib_buffer_t * b0,
    2432             :                       ip6_header_t * ip0,
    2433             :                       ip6_hop_by_hop_header_t * hbh0,
    2434             :                       ip6_hop_by_hop_option_t * opt0,
    2435             :                       ip6_hop_by_hop_option_t * limit0, u32 * next0)
    2436             : {
    2437           2 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2438             :   u8 type0;
    2439           2 :   u8 error0 = 0;
    2440             : 
    2441           4 :   while (opt0 < limit0)
    2442             :     {
    2443           2 :       type0 = opt0->type;
    2444           2 :       switch (type0)
    2445             :         {
    2446           0 :         case 0:         /* Pad1 */
    2447           0 :           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
    2448           0 :           continue;
    2449           2 :         case 1:         /* PadN */
    2450           2 :           break;
    2451           0 :         default:
    2452           0 :           if (hm->options[type0])
    2453             :             {
    2454           0 :               if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
    2455             :                 {
    2456           0 :                   error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
    2457           0 :                   return (error0);
    2458             :                 }
    2459             :             }
    2460             :           else
    2461             :             {
    2462             :               /* Unrecognized mandatory option, check the two high order bits */
    2463           0 :               switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
    2464             :                 {
    2465           0 :                 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
    2466           0 :                   break;
    2467           0 :                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
    2468           0 :                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
    2469           0 :                   *next0 = IP_LOOKUP_NEXT_DROP;
    2470           0 :                   break;
    2471           0 :                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
    2472           0 :                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
    2473           0 :                   *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
    2474           0 :                   icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
    2475             :                                                ICMP6_parameter_problem_unrecognized_option,
    2476           0 :                                                (u8 *) opt0 - (u8 *) ip0);
    2477           0 :                   break;
    2478           0 :                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
    2479           0 :                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
    2480           0 :                   if (!ip6_address_is_multicast (&ip0->dst_address))
    2481             :                     {
    2482           0 :                       *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
    2483           0 :                       icmp6_error_set_vnet_buffer (b0,
    2484             :                                                    ICMP6_parameter_problem,
    2485             :                                                    ICMP6_parameter_problem_unrecognized_option,
    2486           0 :                                                    (u8 *) opt0 - (u8 *) ip0);
    2487             :                     }
    2488             :                   else
    2489             :                     {
    2490           0 :                       *next0 = IP_LOOKUP_NEXT_DROP;
    2491             :                     }
    2492           0 :                   break;
    2493             :                 }
    2494           0 :               return (error0);
    2495             :             }
    2496             :         }
    2497           2 :       opt0 =
    2498           2 :         (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
    2499             :                                      sizeof (ip6_hop_by_hop_option_t));
    2500             :     }
    2501           2 :   return (error0);
    2502             : }
    2503             : 
    2504             : /*
    2505             :  * Process the Hop-by-Hop Options header
    2506             :  */
    2507        2302 : VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
    2508             :                                     vlib_node_runtime_t * node,
    2509             :                                     vlib_frame_t * frame)
    2510             : {
    2511             :   vlib_node_runtime_t *error_node =
    2512           2 :     vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
    2513           2 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2514             :   u32 n_left_from, *from, *to_next;
    2515             :   ip_lookup_next_t next_index;
    2516             : 
    2517           2 :   from = vlib_frame_vector_args (frame);
    2518           2 :   n_left_from = frame->n_vectors;
    2519           2 :   next_index = node->cached_next_index;
    2520             : 
    2521           4 :   while (n_left_from > 0)
    2522             :     {
    2523             :       u32 n_left_to_next;
    2524             : 
    2525           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    2526             : 
    2527           2 :       while (n_left_from >= 4 && n_left_to_next >= 2)
    2528             :         {
    2529             :           u32 bi0, bi1;
    2530             :           vlib_buffer_t *b0, *b1;
    2531             :           u32 next0, next1;
    2532             :           ip6_header_t *ip0, *ip1;
    2533             :           ip6_hop_by_hop_header_t *hbh0, *hbh1;
    2534             :           ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
    2535           0 :           u8 error0 = 0, error1 = 0;
    2536             : 
    2537             :           /* Prefetch next iteration. */
    2538             :           {
    2539             :             vlib_buffer_t *p2, *p3;
    2540             : 
    2541           0 :             p2 = vlib_get_buffer (vm, from[2]);
    2542           0 :             p3 = vlib_get_buffer (vm, from[3]);
    2543             : 
    2544           0 :             vlib_prefetch_buffer_header (p2, LOAD);
    2545           0 :             vlib_prefetch_buffer_header (p3, LOAD);
    2546             : 
    2547           0 :             CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
    2548           0 :             CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
    2549             :           }
    2550             : 
    2551             :           /* Speculatively enqueue b0, b1 to the current next frame */
    2552           0 :           to_next[0] = bi0 = from[0];
    2553           0 :           to_next[1] = bi1 = from[1];
    2554           0 :           from += 2;
    2555           0 :           to_next += 2;
    2556           0 :           n_left_from -= 2;
    2557           0 :           n_left_to_next -= 2;
    2558             : 
    2559           0 :           b0 = vlib_get_buffer (vm, bi0);
    2560           0 :           b1 = vlib_get_buffer (vm, bi1);
    2561             : 
    2562             :           /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
    2563           0 :           u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
    2564           0 :           ip_adjacency_t *adj0 = adj_get (adj_index0);
    2565           0 :           u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
    2566           0 :           ip_adjacency_t *adj1 = adj_get (adj_index1);
    2567             : 
    2568             :           /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
    2569           0 :           next0 = adj0->lookup_next_index;
    2570           0 :           next1 = adj1->lookup_next_index;
    2571             : 
    2572           0 :           ip0 = vlib_buffer_get_current (b0);
    2573           0 :           ip1 = vlib_buffer_get_current (b1);
    2574           0 :           hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
    2575           0 :           hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
    2576           0 :           opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
    2577           0 :           opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
    2578           0 :           limit0 =
    2579             :             (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
    2580           0 :                                          ((hbh0->length + 1) << 3));
    2581           0 :           limit1 =
    2582             :             (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
    2583           0 :                                          ((hbh1->length + 1) << 3));
    2584             : 
    2585             :           /*
    2586             :            * Basic validity checks
    2587             :            */
    2588           0 :           if ((hbh0->length + 1) << 3 >
    2589           0 :               clib_net_to_host_u16 (ip0->payload_length))
    2590             :             {
    2591           0 :               error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
    2592           0 :               next0 = IP_LOOKUP_NEXT_DROP;
    2593           0 :               goto outdual;
    2594             :             }
    2595             :           /* Scan the set of h-b-h options, process ones that we understand */
    2596           0 :           error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
    2597             : 
    2598           0 :           if ((hbh1->length + 1) << 3 >
    2599           0 :               clib_net_to_host_u16 (ip1->payload_length))
    2600             :             {
    2601           0 :               error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
    2602           0 :               next1 = IP_LOOKUP_NEXT_DROP;
    2603           0 :               goto outdual;
    2604             :             }
    2605             :           /* Scan the set of h-b-h options, process ones that we understand */
    2606           0 :           error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
    2607             : 
    2608           0 :         outdual:
    2609             :           /* Has the classifier flagged this buffer for special treatment? */
    2610           0 :           if (PREDICT_FALSE
    2611             :               ((error0 == 0)
    2612             :                && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
    2613           0 :             next0 = hm->next_override;
    2614             : 
    2615             :           /* Has the classifier flagged this buffer for special treatment? */
    2616           0 :           if (PREDICT_FALSE
    2617             :               ((error1 == 0)
    2618             :                && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
    2619           0 :             next1 = hm->next_override;
    2620             : 
    2621           0 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    2622             :             {
    2623           0 :               if (b0->flags & VLIB_BUFFER_IS_TRACED)
    2624             :                 {
    2625             :                   ip6_hop_by_hop_trace_t *t =
    2626           0 :                     vlib_add_trace (vm, node, b0, sizeof (*t));
    2627           0 :                   u32 trace_len = (hbh0->length + 1) << 3;
    2628           0 :                   t->next_index = next0;
    2629             :                   /* Capture the h-b-h option verbatim */
    2630           0 :                   trace_len =
    2631             :                     trace_len <
    2632             :                     ARRAY_LEN (t->option_data) ? trace_len :
    2633             :                     ARRAY_LEN (t->option_data);
    2634           0 :                   t->trace_len = trace_len;
    2635           0 :                   clib_memcpy_fast (t->option_data, hbh0, trace_len);
    2636             :                 }
    2637           0 :               if (b1->flags & VLIB_BUFFER_IS_TRACED)
    2638             :                 {
    2639             :                   ip6_hop_by_hop_trace_t *t =
    2640           0 :                     vlib_add_trace (vm, node, b1, sizeof (*t));
    2641           0 :                   u32 trace_len = (hbh1->length + 1) << 3;
    2642           0 :                   t->next_index = next1;
    2643             :                   /* Capture the h-b-h option verbatim */
    2644           0 :                   trace_len =
    2645             :                     trace_len <
    2646             :                     ARRAY_LEN (t->option_data) ? trace_len :
    2647             :                     ARRAY_LEN (t->option_data);
    2648           0 :                   t->trace_len = trace_len;
    2649           0 :                   clib_memcpy_fast (t->option_data, hbh1, trace_len);
    2650             :                 }
    2651             : 
    2652             :             }
    2653             : 
    2654           0 :           b0->error = error_node->errors[error0];
    2655           0 :           b1->error = error_node->errors[error1];
    2656             : 
    2657             :           /* verify speculative enqueue, maybe switch current next frame */
    2658           0 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
    2659             :                                            n_left_to_next, bi0, bi1, next0,
    2660             :                                            next1);
    2661             :         }
    2662             : 
    2663           4 :       while (n_left_from > 0 && n_left_to_next > 0)
    2664             :         {
    2665             :           u32 bi0;
    2666             :           vlib_buffer_t *b0;
    2667             :           u32 next0;
    2668             :           ip6_header_t *ip0;
    2669             :           ip6_hop_by_hop_header_t *hbh0;
    2670             :           ip6_hop_by_hop_option_t *opt0, *limit0;
    2671           2 :           u8 error0 = 0;
    2672             : 
    2673             :           /* Speculatively enqueue b0 to the current next frame */
    2674           2 :           bi0 = from[0];
    2675           2 :           to_next[0] = bi0;
    2676           2 :           from += 1;
    2677           2 :           to_next += 1;
    2678           2 :           n_left_from -= 1;
    2679           2 :           n_left_to_next -= 1;
    2680             : 
    2681           2 :           b0 = vlib_get_buffer (vm, bi0);
    2682             :           /*
    2683             :            * Default use the next_index from the adjacency.
    2684             :            * A HBH option rarely redirects to a different node
    2685             :            */
    2686           2 :           u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
    2687           2 :           ip_adjacency_t *adj0 = adj_get (adj_index0);
    2688           2 :           next0 = adj0->lookup_next_index;
    2689             : 
    2690           2 :           ip0 = vlib_buffer_get_current (b0);
    2691           2 :           hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
    2692           2 :           opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
    2693           2 :           limit0 =
    2694             :             (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
    2695           2 :                                          ((hbh0->length + 1) << 3));
    2696             : 
    2697             :           /*
    2698             :            * Basic validity checks
    2699             :            */
    2700           4 :           if ((hbh0->length + 1) << 3 >
    2701           2 :               clib_net_to_host_u16 (ip0->payload_length))
    2702             :             {
    2703           0 :               error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
    2704           0 :               next0 = IP_LOOKUP_NEXT_DROP;
    2705           0 :               goto out0;
    2706             :             }
    2707             : 
    2708             :           /* Scan the set of h-b-h options, process ones that we understand */
    2709           2 :           error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
    2710             : 
    2711           2 :         out0:
    2712             :           /* Has the classifier flagged this buffer for special treatment? */
    2713           2 :           if (PREDICT_FALSE
    2714             :               ((error0 == 0)
    2715             :                && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
    2716           0 :             next0 = hm->next_override;
    2717             : 
    2718           2 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2719             :             {
    2720             :               ip6_hop_by_hop_trace_t *t =
    2721           2 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
    2722           2 :               u32 trace_len = (hbh0->length + 1) << 3;
    2723           2 :               t->next_index = next0;
    2724             :               /* Capture the h-b-h option verbatim */
    2725           2 :               trace_len =
    2726             :                 trace_len <
    2727             :                 ARRAY_LEN (t->option_data) ? trace_len :
    2728             :                 ARRAY_LEN (t->option_data);
    2729           2 :               t->trace_len = trace_len;
    2730           2 :               clib_memcpy_fast (t->option_data, hbh0, trace_len);
    2731             :             }
    2732             : 
    2733           2 :           b0->error = error_node->errors[error0];
    2734             : 
    2735             :           /* verify speculative enqueue, maybe switch current next frame */
    2736           2 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    2737             :                                            n_left_to_next, bi0, next0);
    2738             :         }
    2739           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    2740             :     }
    2741           2 :   return frame->n_vectors;
    2742             : }
    2743             : 
    2744             : /* *INDENT-OFF* */
    2745      183788 : VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
    2746             : {
    2747             :   .name = "ip6-hop-by-hop",
    2748             :   .sibling_of = "ip6-lookup",
    2749             :   .vector_size = sizeof (u32),
    2750             :   .format_trace = format_ip6_hop_by_hop_trace,
    2751             :   .type = VLIB_NODE_TYPE_INTERNAL,
    2752             :   .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
    2753             :   .error_strings = ip6_hop_by_hop_error_strings,
    2754             :   .n_next_nodes = 0,
    2755             : };
    2756             : /* *INDENT-ON* */
    2757             : 
    2758             : static clib_error_t *
    2759         575 : ip6_hop_by_hop_init (vlib_main_t * vm)
    2760             : {
    2761         575 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2762         575 :   clib_memset (hm->options, 0, sizeof (hm->options));
    2763         575 :   clib_memset (hm->trace, 0, sizeof (hm->trace));
    2764         575 :   hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
    2765         575 :   return (0);
    2766             : }
    2767             : 
    2768       15551 : VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
    2769             : 
    2770             : #ifndef CLIB_MARCH_VARIANT
    2771             : void
    2772           0 : ip6_hbh_set_next_override (uword next)
    2773             : {
    2774           0 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2775             : 
    2776           0 :   hm->next_override = next;
    2777           0 : }
    2778             : 
    2779             : int
    2780        1150 : ip6_hbh_register_option (u8 option,
    2781             :                          int options (vlib_buffer_t * b, ip6_header_t * ip,
    2782             :                                       ip6_hop_by_hop_option_t * opt),
    2783             :                          u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
    2784             : {
    2785        1150 :   ip6_main_t *im = &ip6_main;
    2786        1150 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2787             : 
    2788             :   ASSERT ((u32) option < ARRAY_LEN (hm->options));
    2789             : 
    2790             :   /* Already registered */
    2791        1150 :   if (hm->options[option])
    2792           0 :     return (-1);
    2793             : 
    2794        1150 :   hm->options[option] = options;
    2795        1150 :   hm->trace[option] = trace;
    2796             : 
    2797             :   /* Set global variable */
    2798        1150 :   im->hbh_enabled = 1;
    2799             : 
    2800        1150 :   return (0);
    2801             : }
    2802             : 
    2803             : int
    2804           0 : ip6_hbh_unregister_option (u8 option)
    2805             : {
    2806           0 :   ip6_main_t *im = &ip6_main;
    2807           0 :   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
    2808             : 
    2809             :   ASSERT ((u32) option < ARRAY_LEN (hm->options));
    2810             : 
    2811             :   /* Not registered */
    2812           0 :   if (!hm->options[option])
    2813           0 :     return (-1);
    2814             : 
    2815           0 :   hm->options[option] = NULL;
    2816           0 :   hm->trace[option] = NULL;
    2817             : 
    2818             :   /* Disable global knob if this was the last option configured */
    2819             :   int i;
    2820           0 :   bool found = false;
    2821           0 :   for (i = 0; i < 256; i++)
    2822             :     {
    2823           0 :       if (hm->options[option])
    2824             :         {
    2825           0 :           found = true;
    2826           0 :           break;
    2827             :         }
    2828             :     }
    2829           0 :   if (!found)
    2830           0 :     im->hbh_enabled = 0;
    2831             : 
    2832           0 :   return (0);
    2833             : }
    2834             : 
    2835             : /* Global IP6 main. */
    2836             : ip6_main_t ip6_main;
    2837             : #endif
    2838             : 
    2839             : static clib_error_t *
    2840         575 : ip6_lookup_init (vlib_main_t * vm)
    2841             : {
    2842         575 :   ip6_main_t *im = &ip6_main;
    2843             :   clib_error_t *error;
    2844             :   uword i;
    2845             : 
    2846         575 :   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
    2847           0 :     return error;
    2848             : 
    2849       74750 :   for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
    2850             :     {
    2851             :       u32 j, i0, i1;
    2852             : 
    2853       74175 :       i0 = i / 32;
    2854       74175 :       i1 = i % 32;
    2855             : 
    2856      186875 :       for (j = 0; j < i0; j++)
    2857      112700 :         im->fib_masks[i].as_u32[j] = ~0;
    2858             : 
    2859       74175 :       if (i1)
    2860       71300 :         im->fib_masks[i].as_u32[i0] =
    2861       71300 :           clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
    2862             :     }
    2863             : 
    2864         575 :   ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
    2865             : 
    2866             :   /* Create FIB with index 0 and table id of 0. */
    2867         575 :   fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
    2868             :                                      FIB_SOURCE_DEFAULT_ROUTE);
    2869         575 :   mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
    2870             :                                       MFIB_SOURCE_DEFAULT_ROUTE);
    2871             : 
    2872             :   {
    2873             :     pg_node_t *pn;
    2874         575 :     pn = pg_get_node (ip6_lookup_node.index);
    2875         575 :     pn->unformat_edit = unformat_pg_ip6_header;
    2876             :   }
    2877             : 
    2878             :   /* Unless explicitly configured, don't process HBH options */
    2879         575 :   im->hbh_enabled = 0;
    2880             : 
    2881         575 :   return error;
    2882             : }
    2883             : 
    2884       13247 : VLIB_INIT_FUNCTION (ip6_lookup_init);
    2885             : 
    2886             : static clib_error_t *
    2887           0 : set_ip6_flow_hash_command_fn (vlib_main_t * vm,
    2888             :                               unformat_input_t * input,
    2889             :                               vlib_cli_command_t * cmd)
    2890             : {
    2891           0 :   int matched = 0;
    2892           0 :   u32 table_id = 0;
    2893           0 :   u32 flow_hash_config = 0;
    2894             :   int rv;
    2895             : 
    2896           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2897             :     {
    2898           0 :       if (unformat (input, "table %d", &table_id))
    2899           0 :         matched = 1;
    2900             : #define _(a, b, v)                                                            \
    2901             :   else if (unformat (input, #a))                                              \
    2902             :   {                                                                           \
    2903             :     flow_hash_config |= v;                                                    \
    2904             :     matched = 1;                                                              \
    2905             :   }
    2906           0 :       foreach_flow_hash_bit
    2907             : #undef _
    2908             :         else
    2909           0 :         break;
    2910             :     }
    2911             : 
    2912           0 :   if (matched == 0)
    2913           0 :     return clib_error_return (0, "unknown input `%U'",
    2914             :                               format_unformat_error, input);
    2915             : 
    2916           0 :   rv = ip_flow_hash_set (AF_IP6, table_id, flow_hash_config);
    2917           0 :   switch (rv)
    2918             :     {
    2919           0 :     case 0:
    2920           0 :       break;
    2921             : 
    2922           0 :     case -1:
    2923           0 :       return clib_error_return (0, "no such FIB table %d", table_id);
    2924             : 
    2925           0 :     default:
    2926           0 :       clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
    2927           0 :       break;
    2928             :     }
    2929             : 
    2930           0 :   return 0;
    2931             : }
    2932             : 
    2933             : /*?
    2934             :  * Configure the set of IPv6 fields used by the flow hash.
    2935             :  *
    2936             :  * @cliexpar
    2937             :  * @parblock
    2938             :  * Example of how to set the flow hash on a given table:
    2939             :  * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
    2940             :  *
    2941             :  * Example of display the configured flow hash:
    2942             :  * @cliexstart{show ip6 fib}
    2943             :  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
    2944             :  * @::/0
    2945             :  *   unicast-ip6-chain
    2946             :  *   [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
    2947             :  *     [0] [@0]: dpo-drop ip6
    2948             :  * fe80::/10
    2949             :  *   unicast-ip6-chain
    2950             :  *   [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
    2951             :  *     [0] [@2]: dpo-receive
    2952             :  * ff02::1/128
    2953             :  *   unicast-ip6-chain
    2954             :  *   [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
    2955             :  *     [0] [@2]: dpo-receive
    2956             :  * ff02::2/128
    2957             :  *   unicast-ip6-chain
    2958             :  *   [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
    2959             :  *     [0] [@2]: dpo-receive
    2960             :  * ff02::16/128
    2961             :  *   unicast-ip6-chain
    2962             :  *   [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
    2963             :  *     [0] [@2]: dpo-receive
    2964             :  * ff02::1:ff00:0/104
    2965             :  *   unicast-ip6-chain
    2966             :  *   [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
    2967             :  *     [0] [@2]: dpo-receive
    2968             :  * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
    2969             :  * @::/0
    2970             :  *   unicast-ip6-chain
    2971             :  *   [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
    2972             :  *     [0] [@0]: dpo-drop ip6
    2973             :  * @::a:1:1:0:4/126
    2974             :  *   unicast-ip6-chain
    2975             :  *   [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
    2976             :  *     [0] [@4]: ipv6-glean: af_packet0
    2977             :  * @::a:1:1:0:7/128
    2978             :  *   unicast-ip6-chain
    2979             :  *   [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
    2980             :  *     [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
    2981             :  * fe80::/10
    2982             :  *   unicast-ip6-chain
    2983             :  *   [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
    2984             :  *     [0] [@2]: dpo-receive
    2985             :  * fe80::fe:3eff:fe3e:9222/128
    2986             :  *   unicast-ip6-chain
    2987             :  *   [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
    2988             :  *     [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
    2989             :  * ff02::1/128
    2990             :  *   unicast-ip6-chain
    2991             :  *   [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
    2992             :  *     [0] [@2]: dpo-receive
    2993             :  * ff02::2/128
    2994             :  *   unicast-ip6-chain
    2995             :  *   [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
    2996             :  *     [0] [@2]: dpo-receive
    2997             :  * ff02::16/128
    2998             :  *   unicast-ip6-chain
    2999             :  *   [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
    3000             :  *     [0] [@2]: dpo-receive
    3001             :  * ff02::1:ff00:0/104
    3002             :  *   unicast-ip6-chain
    3003             :  *   [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
    3004             :  *     [0] [@2]: dpo-receive
    3005             :  * @cliexend
    3006             :  * @endparblock
    3007             : ?*/
    3008             : /* *INDENT-OFF* */
    3009      285289 : VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) = {
    3010             :   .path = "set ip6 flow-hash",
    3011             :   .short_help = "set ip6 flow-hash table <table-id> [src] [dst] [sport] "
    3012             :                 "[dport] [proto] [reverse] [flowlabel]",
    3013             :   .function = set_ip6_flow_hash_command_fn,
    3014             : };
    3015             : /* *INDENT-ON* */
    3016             : 
    3017             : static clib_error_t *
    3018           0 : show_ip6_local_command_fn (vlib_main_t * vm,
    3019             :                            unformat_input_t * input, vlib_cli_command_t * cmd)
    3020             : {
    3021           0 :   ip6_main_t *im = &ip6_main;
    3022           0 :   ip_lookup_main_t *lm = &im->lookup_main;
    3023             :   int i;
    3024             : 
    3025           0 :   vlib_cli_output (vm, "Protocols handled by ip6_local");
    3026           0 :   for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
    3027             :     {
    3028           0 :       if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
    3029             :         {
    3030             : 
    3031           0 :           u32 node_index = vlib_get_node (vm,
    3032           0 :                                           ip6_local_node.index)->
    3033           0 :             next_nodes[lm->local_next_by_ip_protocol[i]];
    3034           0 :           vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
    3035             :                            node_index);
    3036             :         }
    3037             :     }
    3038           0 :   return 0;
    3039             : }
    3040             : 
    3041             : 
    3042             : 
    3043             : /*?
    3044             :  * Display the set of protocols handled by the local IPv6 stack.
    3045             :  *
    3046             :  * @cliexpar
    3047             :  * Example of how to display local protocol table:
    3048             :  * @cliexstart{show ip6 local}
    3049             :  * Protocols handled by ip6_local
    3050             :  * 17
    3051             :  * 43
    3052             :  * 58
    3053             :  * 115
    3054             :  * @cliexend
    3055             : ?*/
    3056             : /* *INDENT-OFF* */
    3057      285289 : VLIB_CLI_COMMAND (show_ip6_local, static) =
    3058             : {
    3059             :   .path = "show ip6 local",
    3060             :   .function = show_ip6_local_command_fn,
    3061             :   .short_help = "show ip6 local",
    3062             : };
    3063             : /* *INDENT-ON* */
    3064             : 
    3065             : #ifndef CLIB_MARCH_VARIANT
    3066             : int
    3067           0 : vnet_set_ip6_classify_intfc (vlib_main_t *vm, u32 sw_if_index, u32 table_index)
    3068             : {
    3069           0 :   vnet_main_t *vnm = vnet_get_main ();
    3070           0 :   vnet_interface_main_t *im = &vnm->interface_main;
    3071           0 :   ip6_main_t *ipm = &ip6_main;
    3072           0 :   ip_lookup_main_t *lm = &ipm->lookup_main;
    3073           0 :   vnet_classify_main_t *cm = &vnet_classify_main;
    3074             :   ip6_address_t *if_addr;
    3075             : 
    3076           0 :   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
    3077           0 :     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
    3078             : 
    3079           0 :   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
    3080           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
    3081             : 
    3082           0 :   vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
    3083           0 :   lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
    3084             : 
    3085           0 :   if_addr = ip6_interface_first_address (ipm, sw_if_index);
    3086             : 
    3087           0 :   if (NULL != if_addr)
    3088             :     {
    3089           0 :       fib_prefix_t pfx = {
    3090             :         .fp_len = 128,
    3091             :         .fp_proto = FIB_PROTOCOL_IP6,
    3092             :         .fp_addr.ip6 = *if_addr,
    3093             :       };
    3094             :       u32 fib_index;
    3095             : 
    3096           0 :       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
    3097             :                                                        sw_if_index);
    3098           0 :       if (table_index != (u32) ~ 0)
    3099             :         {
    3100           0 :           dpo_id_t dpo = DPO_INVALID;
    3101           0 :           dpo_set (&dpo,
    3102             :                    DPO_CLASSIFY,
    3103             :                    DPO_PROTO_IP6,
    3104             :                    classify_dpo_create (DPO_PROTO_IP6, table_index));
    3105           0 :           fib_table_entry_special_dpo_add (fib_index,
    3106             :                                            &pfx,
    3107             :                                            FIB_SOURCE_CLASSIFY,
    3108             :                                            FIB_ENTRY_FLAG_NONE, &dpo);
    3109           0 :           dpo_reset (&dpo);
    3110             :         }
    3111             :       else
    3112             :         {
    3113           0 :           fib_table_entry_special_remove (fib_index,
    3114             :                                           &pfx, FIB_SOURCE_CLASSIFY);
    3115             :         }
    3116             :     }
    3117             : 
    3118           0 :   return 0;
    3119             : }
    3120             : #endif
    3121             : 
    3122             : static clib_error_t *
    3123           0 : set_ip6_classify_command_fn (vlib_main_t * vm,
    3124             :                              unformat_input_t * input,
    3125             :                              vlib_cli_command_t * cmd)
    3126             : {
    3127           0 :   u32 table_index = ~0;
    3128           0 :   int table_index_set = 0;
    3129           0 :   u32 sw_if_index = ~0;
    3130             :   int rv;
    3131             : 
    3132           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    3133             :     {
    3134           0 :       if (unformat (input, "table-index %d", &table_index))
    3135           0 :         table_index_set = 1;
    3136           0 :       else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
    3137             :                          vnet_get_main (), &sw_if_index))
    3138             :         ;
    3139             :       else
    3140           0 :         break;
    3141             :     }
    3142             : 
    3143           0 :   if (table_index_set == 0)
    3144           0 :     return clib_error_return (0, "classify table-index must be specified");
    3145             : 
    3146           0 :   if (sw_if_index == ~0)
    3147           0 :     return clib_error_return (0, "interface / subif must be specified");
    3148             : 
    3149           0 :   rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
    3150             : 
    3151           0 :   switch (rv)
    3152             :     {
    3153           0 :     case 0:
    3154           0 :       break;
    3155             : 
    3156           0 :     case VNET_API_ERROR_NO_MATCHING_INTERFACE:
    3157           0 :       return clib_error_return (0, "No such interface");
    3158             : 
    3159           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
    3160           0 :       return clib_error_return (0, "No such classifier table");
    3161             :     }
    3162           0 :   return 0;
    3163             : }
    3164             : 
    3165             : /*?
    3166             :  * Assign a classification table to an interface. The classification
    3167             :  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
    3168             :  * commands. Once the table is create, use this command to filter packets
    3169             :  * on an interface.
    3170             :  *
    3171             :  * @cliexpar
    3172             :  * Example of how to assign a classification table to an interface:
    3173             :  * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
    3174             : ?*/
    3175             : /* *INDENT-OFF* */
    3176      285289 : VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
    3177             : {
    3178             :   .path = "set ip6 classify",
    3179             :   .short_help =
    3180             :   "set ip6 classify intfc <interface> table-index <classify-idx>",
    3181             :   .function = set_ip6_classify_command_fn,
    3182             : };
    3183             : /* *INDENT-ON* */
    3184             : 
    3185             : /*
    3186             :  * fd.io coding-style-patch-verification: ON
    3187             :  *
    3188             :  * Local Variables:
    3189             :  * eval: (c-set-style "gnu")
    3190             :  * End:
    3191             :  */

Generated by: LCOV version 1.14