LCOV - code coverage report
Current view: top level - vnet/ip - icmp6.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 165 254 65.0 %
Date: 2023-10-26 01:39:38 Functions: 13 19 68.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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/icmp6.c: ip6 icmp
      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 <vlib/vlib.h>
      41             : #include <vnet/ip/ip.h>
      42             : #include <vnet/pg/pg.h>
      43             : #include <vnet/ip/ip_sas.h>
      44             : #include <vnet/util/throttle.h>
      45             : 
      46             : /** ICMP throttling */
      47             : static throttle_t icmp_throttle;
      48             : 
      49             : static u8 *
      50           0 : format_ip6_icmp_type_and_code (u8 * s, va_list * args)
      51             : {
      52           0 :   icmp6_type_t type = va_arg (*args, int);
      53           0 :   u8 code = va_arg (*args, int);
      54           0 :   char *t = 0;
      55             : 
      56             : #define _(n,f) case n: t = #f; break;
      57             : 
      58           0 :   switch (type)
      59             :     {
      60           0 :       foreach_icmp6_type;
      61             : 
      62           0 :     default:
      63           0 :       break;
      64             :     }
      65             : 
      66             : #undef _
      67             : 
      68           0 :   if (!t)
      69           0 :     return format (s, "unknown 0x%x", type);
      70             : 
      71           0 :   s = format (s, "%s", t);
      72             : 
      73           0 :   t = 0;
      74           0 :   switch ((type << 8) | code)
      75             :     {
      76             : #define _(a,n,f) case (ICMP6_##a << 8) | (n): t = #f; break;
      77             : 
      78           0 :       foreach_icmp6_code;
      79             : 
      80             : #undef _
      81             :     }
      82             : 
      83           0 :   if (t)
      84           0 :     s = format (s, " %s", t);
      85             : 
      86           0 :   return s;
      87             : }
      88             : 
      89             : static u8 *
      90           0 : format_icmp6_header (u8 * s, va_list * args)
      91             : {
      92           0 :   icmp46_header_t *icmp = va_arg (*args, icmp46_header_t *);
      93           0 :   u32 max_header_bytes = va_arg (*args, u32);
      94             : 
      95             :   /* Nothing to do. */
      96           0 :   if (max_header_bytes < sizeof (icmp[0]))
      97           0 :     return format (s, "ICMP header truncated");
      98             : 
      99           0 :   s = format (s, "ICMP %U checksum 0x%x",
     100           0 :               format_ip6_icmp_type_and_code, icmp->type, icmp->code,
     101           0 :               clib_net_to_host_u16 (icmp->checksum));
     102             : 
     103           0 :   if (max_header_bytes >=
     104           0 :       sizeof (icmp6_neighbor_solicitation_or_advertisement_header_t) &&
     105           0 :       (icmp->type == ICMP6_neighbor_solicitation ||
     106           0 :        icmp->type == ICMP6_neighbor_advertisement))
     107             :     {
     108           0 :       icmp6_neighbor_solicitation_or_advertisement_header_t *icmp6_nd =
     109             :         (icmp6_neighbor_solicitation_or_advertisement_header_t *) icmp;
     110           0 :       s = format (s, "\n    target address %U",
     111             :                   format_ip6_address, &icmp6_nd->target_address);
     112             :     }
     113             : 
     114           0 :   return s;
     115             : }
     116             : 
     117             : u8 *
     118       43127 : format_icmp6_input_trace (u8 * s, va_list * va)
     119             : {
     120       43127 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     121       43127 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     122       43127 :   icmp6_input_trace_t *t = va_arg (*va, icmp6_input_trace_t *);
     123             : 
     124       43127 :   s = format (s, "%U",
     125       43127 :               format_ip6_header, t->packet_data, sizeof (t->packet_data));
     126             : 
     127       43127 :   return s;
     128             : }
     129             : 
     130             : typedef enum
     131             : {
     132             :   ICMP_INPUT_NEXT_PUNT,
     133             :   ICMP_INPUT_N_NEXT,
     134             : } icmp_input_next_t;
     135             : 
     136             : typedef struct
     137             : {
     138             :   uword *type_and_code_by_name;
     139             : 
     140             :   uword *type_by_name;
     141             : 
     142             :   /* Vector dispatch table indexed by [icmp type]. */
     143             :   u8 input_next_index_by_type[256];
     144             : 
     145             :   /* Max valid code indexed by icmp type. */
     146             :   u8 max_valid_code_by_type[256];
     147             : 
     148             :   /* hop_limit must be >= this value for this icmp type. */
     149             :   u8 min_valid_hop_limit_by_type[256];
     150             : 
     151             :   u8 min_valid_length_by_type[256];
     152             : } icmp6_main_t;
     153             : 
     154             : icmp6_main_t icmp6_main;
     155             : 
     156             : static uword
     157        2654 : ip6_icmp_input (vlib_main_t * vm,
     158             :                 vlib_node_runtime_t * node, vlib_frame_t * frame)
     159             : {
     160        2654 :   icmp6_main_t *im = &icmp6_main;
     161             :   u32 *from, *to_next;
     162             :   u32 n_left_from, n_left_to_next, next_index;
     163             : 
     164        2654 :   from = vlib_frame_vector_args (frame);
     165        2654 :   n_left_from = frame->n_vectors;
     166        2654 :   next_index = node->cached_next_index;
     167             : 
     168        2654 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     169        2099 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     170             :                                    /* stride */ 1,
     171             :                                    sizeof (icmp6_input_trace_t));
     172             : 
     173        5308 :   while (n_left_from > 0)
     174             :     {
     175        2654 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     176             : 
     177       37318 :       while (n_left_from > 0 && n_left_to_next > 0)
     178             :         {
     179             :           vlib_buffer_t *b0;
     180             :           ip6_header_t *ip0;
     181             :           icmp46_header_t *icmp0;
     182             :           icmp6_type_t type0;
     183             :           u32 bi0, next0, error0, len0;
     184             : 
     185       34664 :           bi0 = to_next[0] = from[0];
     186             : 
     187       34664 :           from += 1;
     188       34664 :           n_left_from -= 1;
     189       34664 :           to_next += 1;
     190       34664 :           n_left_to_next -= 1;
     191             : 
     192       34664 :           b0 = vlib_get_buffer (vm, bi0);
     193       34664 :           ip0 = vlib_buffer_get_current (b0);
     194       34664 :           icmp0 = ip6_next_header (ip0);
     195       34664 :           type0 = icmp0->type;
     196             : 
     197       34664 :           error0 = ICMP6_ERROR_NONE;
     198             : 
     199       34664 :           next0 = im->input_next_index_by_type[type0];
     200       34664 :           error0 =
     201       34664 :             next0 == ICMP_INPUT_NEXT_PUNT ? ICMP6_ERROR_UNKNOWN_TYPE : error0;
     202             : 
     203             :           /* Check code is valid for type. */
     204       34664 :           error0 =
     205       34664 :             icmp0->code >
     206       34664 :             im->max_valid_code_by_type[type0] ?
     207       34664 :             ICMP6_ERROR_INVALID_CODE_FOR_TYPE : error0;
     208             : 
     209             :           /* Checksum is already validated by ip6_local node so we don't need to check that. */
     210             : 
     211             :           /* Check that hop limit == 255 for certain types. */
     212       34664 :           error0 =
     213       34664 :             ip0->hop_limit <
     214       34664 :             im->min_valid_hop_limit_by_type[type0] ?
     215       34664 :             ICMP6_ERROR_INVALID_HOP_LIMIT_FOR_TYPE : error0;
     216             : 
     217       34664 :           len0 = clib_net_to_host_u16 (ip0->payload_length);
     218       34664 :           error0 =
     219             :             len0 <
     220       34664 :             im->min_valid_length_by_type[type0] ?
     221       34664 :             ICMP6_ERROR_LENGTH_TOO_SMALL_FOR_TYPE : error0;
     222             : 
     223       34664 :           b0->error = node->errors[error0];
     224             : 
     225       34664 :           next0 = error0 != ICMP6_ERROR_NONE ? ICMP_INPUT_NEXT_PUNT : next0;
     226             : 
     227       34664 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     228             :                                            to_next, n_left_to_next,
     229             :                                            bi0, next0);
     230             :         }
     231             : 
     232        2654 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     233             :     }
     234             : 
     235        2654 :   return frame->n_vectors;
     236             : }
     237             : 
     238             : /* *INDENT-OFF* */
     239      183788 : VLIB_REGISTER_NODE (ip6_icmp_input_node) = {
     240             :   .function = ip6_icmp_input,
     241             :   .name = "ip6-icmp-input",
     242             : 
     243             :   .vector_size = sizeof (u32),
     244             : 
     245             :   .format_trace = format_icmp6_input_trace,
     246             : 
     247             :   .n_errors = ICMP6_N_ERROR,
     248             :   .error_counters = icmp6_error_counters,
     249             : 
     250             :   .n_next_nodes = 1,
     251             :   .next_nodes = {
     252             :     [ICMP_INPUT_NEXT_PUNT] = "ip6-punt",
     253             :   },
     254             : };
     255             : /* *INDENT-ON* */
     256             : 
     257             : typedef enum
     258             : {
     259             :   IP6_ICMP_ERROR_NEXT_DROP,
     260             :   IP6_ICMP_ERROR_NEXT_LOOKUP,
     261             :   IP6_ICMP_ERROR_N_NEXT,
     262             : } ip6_icmp_error_next_t;
     263             : 
     264             : void
     265        1187 : icmp6_error_set_vnet_buffer (vlib_buffer_t * b, u8 type, u8 code, u32 data)
     266             : {
     267        1187 :   vnet_buffer (b)->ip.icmp.type = type;
     268        1187 :   vnet_buffer (b)->ip.icmp.code = code;
     269        1187 :   vnet_buffer (b)->ip.icmp.data = data;
     270        1187 : }
     271             : 
     272             : static u8
     273          25 : icmp6_icmp_type_to_error (u8 type)
     274             : {
     275          25 :   switch (type)
     276             :     {
     277           6 :     case ICMP6_destination_unreachable:
     278           6 :       return ICMP6_ERROR_DEST_UNREACH_SENT;
     279           5 :     case ICMP6_packet_too_big:
     280           5 :       return ICMP6_ERROR_PACKET_TOO_BIG_SENT;
     281          10 :     case ICMP6_time_exceeded:
     282          10 :       return ICMP6_ERROR_TTL_EXPIRE_SENT;
     283           4 :     case ICMP6_parameter_problem:
     284           4 :       return ICMP6_ERROR_PARAM_PROBLEM_SENT;
     285           0 :     default:
     286           0 :       return ICMP6_ERROR_DROP;
     287             :     }
     288             : }
     289             : 
     290             : static uword
     291          27 : ip6_icmp_error (vlib_main_t * vm,
     292             :                 vlib_node_runtime_t * node, vlib_frame_t * frame)
     293             : {
     294             :   u32 *from, *to_next;
     295             :   uword n_left_from, n_left_to_next;
     296             :   ip6_icmp_error_next_t next_index;
     297          27 :   u32 thread_index = vm->thread_index;
     298             : 
     299          27 :   from = vlib_frame_vector_args (frame);
     300          27 :   n_left_from = frame->n_vectors;
     301          27 :   next_index = node->cached_next_index;
     302             : 
     303          27 :   u64 seed = throttle_seed (&icmp_throttle, thread_index, vlib_time_now (vm));
     304             : 
     305          27 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     306          27 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     307             :                                    /* stride */ 1,
     308             :                                    sizeof (icmp6_input_trace_t));
     309             : 
     310          54 :   while (n_left_from > 0)
     311             :     {
     312          27 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     313             : 
     314        1210 :       while (n_left_from > 0 && n_left_to_next > 0)
     315             :         {
     316             :           /*
     317             :            * Duplicate first buffer and free the original chain.  Keep
     318             :            * as much of the original packet as possible, within the
     319             :            * minimum MTU. We chat "a little" here by keeping whatever
     320             :            * is available in the first buffer.
     321             :            */
     322             : 
     323        1183 :           u32 pi0 = ~0;
     324        1183 :           u32 org_pi0 = from[0];
     325        1183 :           u32 next0 = IP6_ICMP_ERROR_NEXT_LOOKUP;
     326        1183 :           u8 error0 = ICMP6_ERROR_NONE;
     327             :           vlib_buffer_t *p0, *org_p0;
     328             :           ip6_header_t *ip0, *out_ip0;
     329             :           icmp46_header_t *icmp0;
     330             :           u32 sw_if_index0;
     331             :           int bogus_length;
     332             : 
     333        1183 :           org_p0 = vlib_get_buffer (vm, org_pi0);
     334        1183 :           ip0 = vlib_buffer_get_current (org_p0);
     335             : 
     336             :           /* Rate limit based on the src,dst addresses in the original packet
     337             :            */
     338        1183 :           u64 r0 = (ip6_address_hash_to_u64 (&ip0->dst_address) ^
     339        1183 :                     ip6_address_hash_to_u64 (&ip0->src_address));
     340             : 
     341        1183 :           if (throttle_check (&icmp_throttle, thread_index, r0, seed))
     342             :             {
     343        1158 :               vlib_error_count (vm, node->node_index, ICMP4_ERROR_DROP, 1);
     344        1158 :               from += 1;
     345        1158 :               n_left_from -= 1;
     346        1158 :               continue;
     347             :             }
     348             : 
     349          25 :           p0 = vlib_buffer_copy_no_chain (vm, org_p0, &pi0);
     350          25 :           if (!p0 || pi0 == ~0) /* Out of buffers */
     351           0 :             continue;
     352             : 
     353             :           /* Speculatively enqueue p0 to the current next frame */
     354          25 :           to_next[0] = pi0;
     355          25 :           from += 1;
     356          25 :           to_next += 1;
     357          25 :           n_left_from -= 1;
     358          25 :           n_left_to_next -= 1;
     359             : 
     360          25 :           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
     361             : 
     362          25 :           vlib_buffer_copy_trace_flag (vm, p0, pi0);
     363             : 
     364             :           /* Add IP header and ICMPv6 header including a 4 byte data field */
     365          25 :           vlib_buffer_advance (p0,
     366             :                                -(sizeof (ip6_header_t) +
     367             :                                  sizeof (icmp46_header_t) + 4));
     368             : 
     369          25 :           vnet_buffer (p0)->sw_if_index[VLIB_TX] = ~0;
     370          25 :           p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     371          25 :           p0->current_length =
     372          25 :             p0->current_length > 1280 ? 1280 : p0->current_length;
     373             : 
     374          25 :           out_ip0 = vlib_buffer_get_current (p0);
     375          25 :           icmp0 = (icmp46_header_t *) & out_ip0[1];
     376             : 
     377             :           /* Fill ip header fields */
     378          25 :           out_ip0->ip_version_traffic_class_and_flow_label =
     379          25 :             clib_host_to_net_u32 (0x6 << 28);
     380             : 
     381          25 :           out_ip0->payload_length =
     382          25 :             clib_host_to_net_u16 (p0->current_length - sizeof (ip6_header_t));
     383          25 :           out_ip0->protocol = IP_PROTOCOL_ICMP6;
     384          25 :           out_ip0->hop_limit = 0xff;
     385          25 :           out_ip0->dst_address = ip0->src_address;
     386             :           /* Prefer a source address from "offending interface" */
     387          25 :           if (!ip6_sas_by_sw_if_index (sw_if_index0, &out_ip0->dst_address,
     388             :                                        &out_ip0->src_address))
     389             :             { /* interface has no IP6 address - should not happen */
     390           0 :               next0 = IP6_ICMP_ERROR_NEXT_DROP;
     391           0 :               error0 = ICMP6_ERROR_DROP;
     392             :             }
     393             : 
     394             :           /* Fill icmp header fields */
     395          25 :           icmp0->type = vnet_buffer (p0)->ip.icmp.type;
     396          25 :           icmp0->code = vnet_buffer (p0)->ip.icmp.code;
     397          50 :           *((u32 *) (icmp0 + 1)) =
     398          25 :             clib_host_to_net_u32 (vnet_buffer (p0)->ip.icmp.data);
     399          25 :           icmp0->checksum = 0;
     400          25 :           icmp0->checksum =
     401          25 :             ip6_tcp_udp_icmp_compute_checksum (vm, p0, out_ip0,
     402             :                                                &bogus_length);
     403             : 
     404             :           /* Update error status */
     405          25 :           if (error0 == ICMP6_ERROR_NONE)
     406          25 :             error0 = icmp6_icmp_type_to_error (icmp0->type);
     407             : 
     408          25 :           vlib_error_count (vm, node->node_index, error0, 1);
     409             : 
     410             :           /* Verify speculative enqueue, maybe switch current next frame */
     411          25 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     412             :                                            to_next, n_left_to_next,
     413             :                                            pi0, next0);
     414             :         }
     415          27 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     416             :     }
     417             : 
     418             :   /*
     419             :    * push the original buffers to error-drop, so that
     420             :    * they can get the error counters handled, then freed
     421             :    */
     422          27 :   vlib_buffer_enqueue_to_single_next (vm, node,
     423          27 :                                       vlib_frame_vector_args (frame),
     424             :                                       IP6_ICMP_ERROR_NEXT_DROP,
     425          27 :                                       frame->n_vectors);
     426             : 
     427          27 :   return frame->n_vectors;
     428             : }
     429             : 
     430             : /* *INDENT-OFF* */
     431      183788 : VLIB_REGISTER_NODE (ip6_icmp_error_node) = {
     432             :   .function = ip6_icmp_error,
     433             :   .name = "ip6-icmp-error",
     434             :   .vector_size = sizeof (u32),
     435             : 
     436             :   .n_errors = ICMP6_N_ERROR,
     437             :   .error_counters = icmp6_error_counters,
     438             : 
     439             :   .n_next_nodes = IP6_ICMP_ERROR_N_NEXT,
     440             :   .next_nodes = {
     441             :     [IP6_ICMP_ERROR_NEXT_DROP] = "error-drop",
     442             :     [IP6_ICMP_ERROR_NEXT_LOOKUP] = "ip6-lookup",
     443             :   },
     444             : 
     445             :   .format_trace = format_icmp6_input_trace,
     446             : };
     447             : /* *INDENT-ON* */
     448             : 
     449             : 
     450             : static uword
     451           0 : unformat_icmp_type_and_code (unformat_input_t * input, va_list * args)
     452             : {
     453           0 :   icmp46_header_t *h = va_arg (*args, icmp46_header_t *);
     454           0 :   icmp6_main_t *cm = &icmp6_main;
     455             :   u32 i;
     456             : 
     457           0 :   if (unformat_user (input, unformat_vlib_number_by_name,
     458             :                      cm->type_and_code_by_name, &i))
     459             :     {
     460           0 :       h->type = (i >> 8) & 0xff;
     461           0 :       h->code = (i >> 0) & 0xff;
     462             :     }
     463           0 :   else if (unformat_user (input, unformat_vlib_number_by_name,
     464             :                           cm->type_by_name, &i))
     465             :     {
     466           0 :       h->type = i;
     467           0 :       h->code = 0;
     468             :     }
     469             :   else
     470           0 :     return 0;
     471             : 
     472           0 :   return 1;
     473             : }
     474             : 
     475             : static void
     476           0 : icmp6_pg_edit_function (pg_main_t * pg,
     477             :                         pg_stream_t * s,
     478             :                         pg_edit_group_t * g, u32 * packets, u32 n_packets)
     479             : {
     480           0 :   vlib_main_t *vm = vlib_get_main ();
     481             :   u32 ip_offset, icmp_offset;
     482             :   int bogus_length;
     483             : 
     484           0 :   icmp_offset = g->start_byte_offset;
     485           0 :   ip_offset = (g - 1)->start_byte_offset;
     486             : 
     487           0 :   while (n_packets >= 1)
     488             :     {
     489             :       vlib_buffer_t *p0;
     490             :       ip6_header_t *ip0;
     491             :       icmp46_header_t *icmp0;
     492             : 
     493           0 :       p0 = vlib_get_buffer (vm, packets[0]);
     494           0 :       n_packets -= 1;
     495           0 :       packets += 1;
     496             : 
     497           0 :       ASSERT (p0->current_data == 0);
     498           0 :       ip0 = (void *) (p0->data + ip_offset);
     499           0 :       icmp0 = (void *) (p0->data + icmp_offset);
     500             : 
     501           0 :       icmp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
     502             :                                                            &bogus_length);
     503           0 :       ASSERT (bogus_length == 0);
     504             :     }
     505           0 : }
     506             : 
     507             : typedef struct
     508             : {
     509             :   pg_edit_t type, code;
     510             :   pg_edit_t checksum;
     511             : } pg_icmp46_header_t;
     512             : 
     513             : always_inline void
     514           0 : pg_icmp_header_init (pg_icmp46_header_t * p)
     515             : {
     516             :   /* Initialize fields that are not bit fields in the IP header. */
     517             : #define _(f) pg_edit_init (&p->f, icmp46_header_t, f);
     518           0 :   _(type);
     519           0 :   _(code);
     520           0 :   _(checksum);
     521             : #undef _
     522           0 : }
     523             : 
     524             : static uword
     525           0 : unformat_pg_icmp_header (unformat_input_t * input, va_list * args)
     526             : {
     527           0 :   pg_stream_t *s = va_arg (*args, pg_stream_t *);
     528             :   pg_icmp46_header_t *p;
     529             :   u32 group_index;
     530             : 
     531           0 :   p = pg_create_edit_group (s, sizeof (p[0]), sizeof (icmp46_header_t),
     532             :                             &group_index);
     533           0 :   pg_icmp_header_init (p);
     534             : 
     535           0 :   p->checksum.type = PG_EDIT_UNSPECIFIED;
     536             : 
     537             :   {
     538             :     icmp46_header_t tmp;
     539             : 
     540           0 :     if (!unformat (input, "ICMP %U", unformat_icmp_type_and_code, &tmp))
     541           0 :       goto error;
     542             : 
     543           0 :     pg_edit_set_fixed (&p->type, tmp.type);
     544           0 :     pg_edit_set_fixed (&p->code, tmp.code);
     545             :   }
     546             : 
     547             :   /* Parse options. */
     548             :   while (1)
     549             :     {
     550           0 :       if (unformat (input, "checksum %U",
     551             :                     unformat_pg_edit, unformat_pg_number, &p->checksum))
     552             :         ;
     553             : 
     554             :       /* Can't parse input: try next protocol level. */
     555             :       else
     556           0 :         break;
     557             :     }
     558             : 
     559           0 :   if (!unformat_user (input, unformat_pg_payload, s))
     560           0 :     goto error;
     561             : 
     562           0 :   if (p->checksum.type == PG_EDIT_UNSPECIFIED)
     563             :     {
     564           0 :       pg_edit_group_t *g = pg_stream_get_group (s, group_index);
     565           0 :       g->edit_function = icmp6_pg_edit_function;
     566           0 :       g->edit_function_opaque = 0;
     567             :     }
     568             : 
     569           0 :   return 1;
     570             : 
     571           0 : error:
     572             :   /* Free up any edits we may have added. */
     573           0 :   pg_free_edit_group (s);
     574           0 :   return 0;
     575             : }
     576             : 
     577             : void
     578        3450 : icmp6_register_type (vlib_main_t * vm, icmp6_type_t type, u32 node_index)
     579             : {
     580        3450 :   icmp6_main_t *im = &icmp6_main;
     581             : 
     582        3450 :   ASSERT ((int) type < ARRAY_LEN (im->input_next_index_by_type));
     583             :   im->input_next_index_by_type[type]
     584        3450 :     = vlib_node_add_next (vm, ip6_icmp_input_node.index, node_index);
     585        3450 : }
     586             : 
     587             : static clib_error_t *
     588         575 : icmp6_init (vlib_main_t * vm)
     589             : {
     590         575 :   ip_main_t *im = &ip_main;
     591             :   ip_protocol_info_t *pi;
     592         575 :   icmp6_main_t *cm = &icmp6_main;
     593             :   clib_error_t *error;
     594             : 
     595         575 :   error = vlib_call_init_function (vm, ip_main_init);
     596             : 
     597         575 :   if (error)
     598           0 :     return error;
     599             : 
     600         575 :   pi = ip_get_protocol_info (im, IP_PROTOCOL_ICMP6);
     601         575 :   pi->format_header = format_icmp6_header;
     602         575 :   pi->unformat_pg_edit = unformat_pg_icmp_header;
     603             : 
     604         575 :   cm->type_by_name = hash_create_string (0, sizeof (uword));
     605             : #define _(n,t) hash_set_mem (cm->type_by_name, #t, (n));
     606       17825 :   foreach_icmp6_type;
     607             : #undef _
     608             : 
     609         575 :   cm->type_and_code_by_name = hash_create_string (0, sizeof (uword));
     610             : #define _(a,n,t) hash_set_mem (cm->type_by_name, #t, (n) | (ICMP6_##a << 8));
     611       12650 :   foreach_icmp6_code;
     612             : #undef _
     613             : 
     614         575 :   clib_memset (cm->input_next_index_by_type,
     615             :                ICMP_INPUT_NEXT_PUNT, sizeof (cm->input_next_index_by_type));
     616         575 :   clib_memset (cm->max_valid_code_by_type, 0,
     617             :                sizeof (cm->max_valid_code_by_type));
     618             : 
     619             : #define _(a,n,t) cm->max_valid_code_by_type[ICMP6_##a] = clib_max (cm->max_valid_code_by_type[ICMP6_##a], n);
     620         575 :   foreach_icmp6_code;
     621             : #undef _
     622             : 
     623         575 :   clib_memset (cm->min_valid_hop_limit_by_type, 0,
     624             :                sizeof (cm->min_valid_hop_limit_by_type));
     625         575 :   cm->min_valid_hop_limit_by_type[ICMP6_router_solicitation] = 255;
     626         575 :   cm->min_valid_hop_limit_by_type[ICMP6_router_advertisement] = 255;
     627         575 :   cm->min_valid_hop_limit_by_type[ICMP6_neighbor_solicitation] = 255;
     628         575 :   cm->min_valid_hop_limit_by_type[ICMP6_neighbor_advertisement] = 255;
     629         575 :   cm->min_valid_hop_limit_by_type[ICMP6_redirect] = 255;
     630             : 
     631         575 :   clib_memset (cm->min_valid_length_by_type, sizeof (icmp46_header_t),
     632             :                sizeof (cm->min_valid_length_by_type));
     633         575 :   cm->min_valid_length_by_type[ICMP6_router_solicitation] =
     634             :     sizeof (icmp6_neighbor_discovery_header_t);
     635         575 :   cm->min_valid_length_by_type[ICMP6_router_advertisement] =
     636             :     sizeof (icmp6_router_advertisement_header_t);
     637         575 :   cm->min_valid_length_by_type[ICMP6_neighbor_solicitation] =
     638             :     sizeof (icmp6_neighbor_solicitation_or_advertisement_header_t);
     639         575 :   cm->min_valid_length_by_type[ICMP6_neighbor_advertisement] =
     640             :     sizeof (icmp6_neighbor_solicitation_or_advertisement_header_t);
     641         575 :   cm->min_valid_length_by_type[ICMP6_redirect] =
     642             :     sizeof (icmp6_redirect_header_t);
     643             : 
     644         575 :   vlib_thread_main_t *tm = &vlib_thread_main;
     645         575 :   u32 n_vlib_mains = tm->n_vlib_mains;
     646             : 
     647         575 :   throttle_init (&icmp_throttle, n_vlib_mains, THROTTLE_BITS, 1e-3);
     648             : 
     649         575 :   return (NULL);
     650             : }
     651             : 
     652       13823 : VLIB_INIT_FUNCTION (icmp6_init);
     653             : 
     654             : /*
     655             :  * fd.io coding-style-patch-verification: ON
     656             :  *
     657             :  * Local Variables:
     658             :  * eval: (c-set-style "gnu")
     659             :  * End:
     660             :  */

Generated by: LCOV version 1.14