LCOV - code coverage report
Current view: top level - vnet/ip - icmp4.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 175 228 76.8 %
Date: 2023-10-26 01:39:38 Functions: 16 18 88.9 %

          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/icmp4.c: ipv4 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      700738 : format_ip4_icmp_type_and_code (u8 * s, va_list * args)
      51             : {
      52      700738 :   icmp4_type_t type = va_arg (*args, int);
      53      700738 :   u8 code = va_arg (*args, int);
      54      700738 :   char *t = 0;
      55             : 
      56             : #define _(n,f) case n: t = #f; break;
      57             : 
      58      700738 :   switch (type)
      59             :     {
      60      700738 :       foreach_icmp4_type;
      61             : 
      62           0 :     default:
      63           0 :       break;
      64             :     }
      65             : 
      66             : #undef _
      67             : 
      68      700738 :   if (!t)
      69           0 :     return format (s, "unknown 0x%x", type);
      70             : 
      71      700738 :   s = format (s, "%s", t);
      72             : 
      73      700738 :   t = 0;
      74      700738 :   switch ((type << 8) | code)
      75             :     {
      76             : #define _(a,n,f) case (ICMP4_##a << 8) | (n): t = #f; break;
      77             : 
      78         742 :       foreach_icmp4_code;
      79             : 
      80             : #undef _
      81             :     }
      82             : 
      83      700738 :   if (t)
      84         742 :     s = format (s, " %s", t);
      85             : 
      86      700738 :   return s;
      87             : }
      88             : 
      89             : static u8 *
      90      700738 : format_ip4_icmp_header (u8 * s, va_list * args)
      91             : {
      92      700738 :   icmp46_header_t *icmp = va_arg (*args, icmp46_header_t *);
      93      700738 :   u32 max_header_bytes = va_arg (*args, u32);
      94             : 
      95             :   /* Nothing to do. */
      96      700738 :   if (max_header_bytes < sizeof (icmp[0]))
      97           0 :     return format (s, "ICMP header truncated");
      98             : 
      99      700738 :   s = format (s, "ICMP %U checksum 0x%x",
     100      700738 :               format_ip4_icmp_type_and_code, icmp->type, icmp->code,
     101      700738 :               clib_net_to_host_u16 (icmp->checksum));
     102             : 
     103      700738 :   if ((ICMP4_echo_request == icmp->type || ICMP4_echo_reply == icmp->type)
     104      699996 :       && sizeof (icmp[0]) + sizeof (u16) < max_header_bytes)
     105             :     {
     106      699996 :       s = format (s, " id %u", clib_net_to_host_u16 (*(u16 *) (icmp + 1)));
     107             :     }
     108             : 
     109      700738 :   return s;
     110             : }
     111             : 
     112             : static u8 *
     113       85550 : format_icmp_input_trace (u8 * s, va_list * va)
     114             : {
     115       85550 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     116       85550 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     117       85550 :   icmp_input_trace_t *t = va_arg (*va, icmp_input_trace_t *);
     118             : 
     119       85550 :   s = format (s, "%U",
     120       85550 :               format_ip4_header, t->packet_data, sizeof (t->packet_data));
     121             : 
     122       85550 :   return s;
     123             : }
     124             : 
     125             : typedef enum
     126             : {
     127             :   ICMP_INPUT_NEXT_ERROR,
     128             :   ICMP_INPUT_N_NEXT,
     129             : } icmp_input_next_t;
     130             : 
     131             : typedef struct
     132             : {
     133             :   uword *type_and_code_by_name;
     134             : 
     135             :   uword *type_by_name;
     136             : 
     137             :   /* Vector dispatch table indexed by [icmp type]. */
     138             :   u8 ip4_input_next_index_by_type[256];
     139             : } icmp4_main_t;
     140             : 
     141             : icmp4_main_t icmp4_main;
     142             : 
     143             : static uword
     144        4133 : ip4_icmp_input (vlib_main_t * vm,
     145             :                 vlib_node_runtime_t * node, vlib_frame_t * frame)
     146             : {
     147        4133 :   icmp4_main_t *im = &icmp4_main;
     148        4133 :   uword n_packets = frame->n_vectors;
     149             :   u32 *from, *to_next;
     150             :   u32 n_left_from, n_left_to_next, next;
     151             : 
     152        4133 :   from = vlib_frame_vector_args (frame);
     153        4133 :   n_left_from = n_packets;
     154        4133 :   next = node->cached_next_index;
     155             : 
     156        4133 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     157        3392 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     158             :                                    /* stride */ 1,
     159             :                                    sizeof (icmp_input_trace_t));
     160             : 
     161        8266 :   while (n_left_from > 0)
     162             :     {
     163        4133 :       vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
     164             : 
     165      131594 :       while (n_left_from > 0 && n_left_to_next > 0)
     166             :         {
     167             :           vlib_buffer_t *p0;
     168             :           ip4_header_t *ip0;
     169             :           icmp46_header_t *icmp0;
     170             :           icmp4_type_t type0;
     171             :           u32 bi0, next0;
     172             : 
     173      127461 :           if (PREDICT_TRUE (n_left_from > 2))
     174             :             {
     175      120589 :               vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
     176      120589 :               p0 = vlib_get_buffer (vm, from[1]);
     177      120589 :               ip0 = vlib_buffer_get_current (p0);
     178      120589 :               clib_prefetch_load (ip0);
     179             :             }
     180             : 
     181      127461 :           bi0 = to_next[0] = from[0];
     182             : 
     183      127461 :           from += 1;
     184      127461 :           n_left_from -= 1;
     185      127461 :           to_next += 1;
     186      127461 :           n_left_to_next -= 1;
     187             : 
     188      127461 :           p0 = vlib_get_buffer (vm, bi0);
     189      127461 :           ip0 = vlib_buffer_get_current (p0);
     190      127461 :           icmp0 = ip4_next_header (ip0);
     191      127461 :           type0 = icmp0->type;
     192      127461 :           next0 = im->ip4_input_next_index_by_type[type0];
     193             : 
     194      127461 :           p0->error = node->errors[ICMP4_ERROR_UNKNOWN_TYPE];
     195             : 
     196             :           /* Verify speculative enqueue, maybe switch current next frame */
     197      127461 :           vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next,
     198             :                                            n_left_to_next, bi0, next0);
     199             :         }
     200             : 
     201        4133 :       vlib_put_next_frame (vm, node, next, n_left_to_next);
     202             :     }
     203             : 
     204        4133 :   return frame->n_vectors;
     205             : }
     206             : 
     207             : /* *INDENT-OFF* */
     208      183788 : VLIB_REGISTER_NODE (ip4_icmp_input_node) = {
     209             :   .function = ip4_icmp_input,
     210             :   .name = "ip4-icmp-input",
     211             : 
     212             :   .vector_size = sizeof (u32),
     213             : 
     214             :   .format_trace = format_icmp_input_trace,
     215             : 
     216             :   .n_errors = ICMP4_N_ERROR,
     217             :   .error_counters = icmp4_error_counters,
     218             : 
     219             :   .n_next_nodes = 1,
     220             :   .next_nodes = {
     221             :     [ICMP_INPUT_NEXT_ERROR] = "ip4-punt",
     222             :   },
     223             : };
     224             : /* *INDENT-ON* */
     225             : 
     226             : typedef enum
     227             : {
     228             :   IP4_ICMP_ERROR_NEXT_DROP,
     229             :   IP4_ICMP_ERROR_NEXT_LOOKUP,
     230             :   IP4_ICMP_ERROR_N_NEXT,
     231             : } ip4_icmp_error_next_t;
     232             : 
     233             : static u8
     234          25 : icmp4_icmp_type_to_error (u8 type)
     235             : {
     236          25 :   switch (type)
     237             :     {
     238          14 :     case ICMP4_destination_unreachable:
     239          14 :       return ICMP4_ERROR_DEST_UNREACH_SENT;
     240          11 :     case ICMP4_time_exceeded:
     241          11 :       return ICMP4_ERROR_TTL_EXPIRE_SENT;
     242           0 :     case ICMP4_parameter_problem:
     243           0 :       return ICMP4_ERROR_PARAM_PROBLEM_SENT;
     244           0 :     default:
     245           0 :       return ICMP4_ERROR_DROP;
     246             :     }
     247             : }
     248             : 
     249             : static uword
     250          25 : ip4_icmp_error (vlib_main_t * vm,
     251             :                 vlib_node_runtime_t * node, vlib_frame_t * frame)
     252             : {
     253             :   u32 *from, *to_next;
     254             :   uword n_left_from, n_left_to_next;
     255             :   ip4_icmp_error_next_t next_index;
     256          25 :   u32 thread_index = vm->thread_index;
     257             : 
     258          25 :   from = vlib_frame_vector_args (frame);
     259          25 :   n_left_from = frame->n_vectors;
     260          25 :   next_index = node->cached_next_index;
     261             : 
     262          25 :   u64 seed = throttle_seed (&icmp_throttle, thread_index, vlib_time_now (vm));
     263             : 
     264          25 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     265          22 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     266             :                                    /* stride */ 1,
     267             :                                    sizeof (icmp_input_trace_t));
     268             : 
     269          50 :   while (n_left_from > 0)
     270             :     {
     271          25 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     272             : 
     273         605 :       while (n_left_from > 0 && n_left_to_next > 0)
     274             :         {
     275             :           /*
     276             :            * Duplicate first buffer and free the original chain.  Keep
     277             :            * as much of the original packet as possible, within the
     278             :            * minimum MTU. We chat "a little" here by keeping whatever
     279             :            * is available in the first buffer.
     280             :            */
     281             : 
     282         580 :           u32 pi0 = ~0;
     283         580 :           u32 org_pi0 = from[0];
     284         580 :           u32 next0 = IP4_ICMP_ERROR_NEXT_LOOKUP;
     285         580 :           u8 error0 = ICMP4_ERROR_NONE;
     286             :           vlib_buffer_t *p0, *org_p0;
     287             :           ip4_header_t *ip0, *out_ip0;
     288             :           icmp46_header_t *icmp0;
     289             :           u32 sw_if_index0;
     290             :           ip_csum_t sum;
     291             : 
     292         580 :           org_p0 = vlib_get_buffer (vm, org_pi0);
     293         580 :           ip0 = vlib_buffer_get_current (org_p0);
     294             : 
     295             :           /* Rate limit based on the src,dst addresses in the original packet
     296             :            */
     297         580 :           u64 r0 =
     298         580 :             (u64) ip0->dst_address.as_u32 << 32 | ip0->src_address.as_u32;
     299             : 
     300         580 :           if (throttle_check (&icmp_throttle, thread_index, r0, seed))
     301             :             {
     302         555 :               vlib_error_count (vm, node->node_index, ICMP4_ERROR_DROP, 1);
     303         555 :               from += 1;
     304         555 :               n_left_from -= 1;
     305         555 :               continue;
     306             :             }
     307             : 
     308          25 :           p0 = vlib_buffer_copy_no_chain (vm, org_p0, &pi0);
     309          25 :           if (!p0 || pi0 == ~0) /* Out of buffers */
     310           0 :             continue;
     311             : 
     312             :           /* Speculatively enqueue p0 to the current next frame */
     313          25 :           to_next[0] = pi0;
     314          25 :           from += 1;
     315          25 :           to_next += 1;
     316          25 :           n_left_from -= 1;
     317          25 :           n_left_to_next -= 1;
     318             : 
     319          25 :           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
     320             : 
     321          25 :           vlib_buffer_copy_trace_flag (vm, org_p0, pi0);
     322             : 
     323             :           /* Add IP header and ICMPv4 header including a 4 byte data field */
     324          25 :           vlib_buffer_advance (p0,
     325             :                                -sizeof (ip4_header_t) -
     326             :                                sizeof (icmp46_header_t) - 4);
     327             : 
     328          25 :           p0->current_length =
     329          25 :             p0->current_length > 576 ? 576 : p0->current_length;
     330          25 :           out_ip0 = vlib_buffer_get_current (p0);
     331          25 :           icmp0 = (icmp46_header_t *) & out_ip0[1];
     332             : 
     333             :           /* Fill ip header fields */
     334          25 :           out_ip0->ip_version_and_header_length = 0x45;
     335          25 :           out_ip0->tos = 0;
     336          25 :           out_ip0->length = clib_host_to_net_u16 (p0->current_length);
     337          25 :           out_ip0->fragment_id = 0;
     338          25 :           out_ip0->flags_and_fragment_offset = 0;
     339          25 :           out_ip0->ttl = 0xff;
     340          25 :           out_ip0->protocol = IP_PROTOCOL_ICMP;
     341          25 :           out_ip0->dst_address = ip0->src_address;
     342             :           /* Prefer a source address from "offending interface" */
     343          25 :           if (!ip4_sas_by_sw_if_index (sw_if_index0, &out_ip0->dst_address,
     344             :                                        &out_ip0->src_address))
     345             :             { /* interface has no IP6 address - should not happen */
     346           0 :               next0 = IP4_ICMP_ERROR_NEXT_DROP;
     347           0 :               error0 = ICMP4_ERROR_DROP;
     348             :             }
     349             : 
     350          25 :           out_ip0->checksum = ip4_header_checksum (out_ip0);
     351             : 
     352             :           /* Fill icmp header fields */
     353          25 :           icmp0->type = vnet_buffer (p0)->ip.icmp.type;
     354          25 :           icmp0->code = vnet_buffer (p0)->ip.icmp.code;
     355          50 :           *((u32 *) (icmp0 + 1)) =
     356          25 :             clib_host_to_net_u32 (vnet_buffer (p0)->ip.icmp.data);
     357          25 :           icmp0->checksum = 0;
     358             :           sum =
     359          25 :             ip_incremental_checksum (0, icmp0,
     360          25 :                                      p0->current_length -
     361             :                                      sizeof (ip4_header_t));
     362          25 :           icmp0->checksum = ~ip_csum_fold (sum);
     363             : 
     364             :           /* Update error status */
     365          25 :           if (error0 == ICMP4_ERROR_NONE)
     366          25 :             error0 = icmp4_icmp_type_to_error (icmp0->type);
     367             : 
     368          25 :           vlib_error_count (vm, node->node_index, error0, 1);
     369             : 
     370             :           /* Verify speculative enqueue, maybe switch current next frame */
     371          25 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     372             :                                            to_next, n_left_to_next,
     373             :                                            pi0, next0);
     374             :         }
     375          25 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     376             :     }
     377             : 
     378             :   /*
     379             :    * push the original buffers to error-drop, so that
     380             :    * they can get the error counters handled, then freed
     381             :    */
     382          25 :   vlib_buffer_enqueue_to_single_next (vm, node,
     383          25 :                                       vlib_frame_vector_args (frame),
     384             :                                       IP4_ICMP_ERROR_NEXT_DROP,
     385          25 :                                       frame->n_vectors);
     386             : 
     387          25 :   return frame->n_vectors;
     388             : }
     389             : 
     390             : /* *INDENT-OFF* */
     391      183788 : VLIB_REGISTER_NODE (ip4_icmp_error_node) = {
     392             :   .function = ip4_icmp_error,
     393             :   .name = "ip4-icmp-error",
     394             :   .vector_size = sizeof (u32),
     395             : 
     396             :   .n_errors = ICMP4_N_ERROR,
     397             :   .error_counters = icmp4_error_counters,
     398             : 
     399             :   .n_next_nodes = IP4_ICMP_ERROR_N_NEXT,
     400             :   .next_nodes = {
     401             :     [IP4_ICMP_ERROR_NEXT_DROP] = "ip4-drop",
     402             :     [IP4_ICMP_ERROR_NEXT_LOOKUP] = "ip4-lookup",
     403             :   },
     404             : 
     405             :   .format_trace = format_icmp_input_trace,
     406             : };
     407             : /* *INDENT-ON* */
     408             : 
     409             : 
     410             : static uword
     411           0 : unformat_icmp_type_and_code (unformat_input_t * input, va_list * args)
     412             : {
     413           0 :   icmp46_header_t *h = va_arg (*args, icmp46_header_t *);
     414           0 :   icmp4_main_t *cm = &icmp4_main;
     415             :   u32 i;
     416             : 
     417           0 :   if (unformat_user (input, unformat_vlib_number_by_name,
     418             :                      cm->type_and_code_by_name, &i))
     419             :     {
     420           0 :       h->type = (i >> 8) & 0xff;
     421           0 :       h->code = (i >> 0) & 0xff;
     422             :     }
     423           0 :   else if (unformat_user (input, unformat_vlib_number_by_name,
     424             :                           cm->type_by_name, &i))
     425             :     {
     426           0 :       h->type = i;
     427           0 :       h->code = 0;
     428             :     }
     429             :   else
     430           0 :     return 0;
     431             : 
     432           0 :   return 1;
     433             : }
     434             : 
     435             : static void
     436           0 : icmp4_pg_edit_function (pg_main_t * pg,
     437             :                         pg_stream_t * s,
     438             :                         pg_edit_group_t * g, u32 * packets, u32 n_packets)
     439             : {
     440           0 :   vlib_main_t *vm = vlib_get_main ();
     441             :   u32 ip_offset, icmp_offset;
     442             : 
     443           0 :   icmp_offset = g->start_byte_offset;
     444           0 :   ip_offset = (g - 1)->start_byte_offset;
     445             : 
     446           0 :   while (n_packets >= 1)
     447             :     {
     448             :       vlib_buffer_t *p0;
     449             :       ip4_header_t *ip0;
     450             :       icmp46_header_t *icmp0;
     451             :       u32 len0;
     452             : 
     453           0 :       p0 = vlib_get_buffer (vm, packets[0]);
     454           0 :       n_packets -= 1;
     455           0 :       packets += 1;
     456             : 
     457           0 :       ASSERT (p0->current_data == 0);
     458           0 :       ip0 = (void *) (p0->data + ip_offset);
     459           0 :       icmp0 = (void *) (p0->data + icmp_offset);
     460             : 
     461             :       /* if IP length has been specified, then calculate the length based on buffer */
     462           0 :       if (ip0->length == 0)
     463           0 :         len0 = vlib_buffer_length_in_chain (vm, p0) - icmp_offset;
     464             :       else
     465           0 :         len0 = clib_net_to_host_u16 (ip0->length) - icmp_offset;
     466             : 
     467           0 :       icmp0->checksum =
     468           0 :         ~ip_csum_fold (ip_incremental_checksum (0, icmp0, len0));
     469             :     }
     470           0 : }
     471             : 
     472             : typedef struct
     473             : {
     474             :   pg_edit_t type, code;
     475             :   pg_edit_t checksum;
     476             : } pg_icmp46_header_t;
     477             : 
     478             : always_inline void
     479           8 : pg_icmp_header_init (pg_icmp46_header_t * p)
     480             : {
     481             :   /* Initialize fields that are not bit fields in the IP header. */
     482             : #define _(f) pg_edit_init (&p->f, icmp46_header_t, f);
     483           8 :   _(type);
     484           8 :   _(code);
     485           8 :   _(checksum);
     486             : #undef _
     487           8 : }
     488             : 
     489             : static uword
     490           8 : unformat_pg_icmp_header (unformat_input_t * input, va_list * args)
     491             : {
     492           8 :   pg_stream_t *s = va_arg (*args, pg_stream_t *);
     493             :   pg_icmp46_header_t *p;
     494             :   u32 group_index;
     495             : 
     496           8 :   p = pg_create_edit_group (s, sizeof (p[0]), sizeof (icmp46_header_t),
     497             :                             &group_index);
     498           8 :   pg_icmp_header_init (p);
     499             : 
     500           8 :   p->checksum.type = PG_EDIT_UNSPECIFIED;
     501             : 
     502             :   {
     503             :     icmp46_header_t tmp;
     504             : 
     505           8 :     if (!unformat (input, "ICMP %U", unformat_icmp_type_and_code, &tmp))
     506           8 :       goto error;
     507             : 
     508           0 :     pg_edit_set_fixed (&p->type, tmp.type);
     509           0 :     pg_edit_set_fixed (&p->code, tmp.code);
     510             :   }
     511             : 
     512             :   /* Parse options. */
     513             :   while (1)
     514             :     {
     515           0 :       if (unformat (input, "checksum %U",
     516             :                     unformat_pg_edit, unformat_pg_number, &p->checksum))
     517             :         ;
     518             : 
     519             :       /* Can't parse input: try next protocol level. */
     520             :       else
     521           0 :         break;
     522             :     }
     523             : 
     524           0 :   if (!unformat_user (input, unformat_pg_payload, s))
     525           0 :     goto error;
     526             : 
     527           0 :   if (p->checksum.type == PG_EDIT_UNSPECIFIED)
     528             :     {
     529           0 :       pg_edit_group_t *g = pg_stream_get_group (s, group_index);
     530           0 :       g->edit_function = icmp4_pg_edit_function;
     531           0 :       g->edit_function_opaque = 0;
     532             :     }
     533             : 
     534           0 :   return 1;
     535             : 
     536           8 : error:
     537             :   /* Free up any edits we may have added. */
     538           8 :   pg_free_edit_group (s);
     539           8 :   return 0;
     540             : }
     541             : 
     542             : void
     543        1150 : ip4_icmp_register_type (vlib_main_t * vm, icmp4_type_t type, u32 node_index)
     544             : {
     545        1150 :   icmp4_main_t *im = &icmp4_main;
     546             :   u32 old_next_index;
     547             : 
     548        1150 :   ASSERT ((int) type < ARRAY_LEN (im->ip4_input_next_index_by_type));
     549        1150 :   old_next_index = im->ip4_input_next_index_by_type[type];
     550             : 
     551             :   im->ip4_input_next_index_by_type[type]
     552        1150 :     = vlib_node_add_next (vm, ip4_icmp_input_node.index, node_index);
     553             : 
     554        1150 :   if (old_next_index &&
     555           0 :       (old_next_index != im->ip4_input_next_index_by_type[type]))
     556           0 :     clib_warning ("WARNING: changed next_by_type[%d]", (int) type);
     557        1150 : }
     558             : 
     559             : static clib_error_t *
     560         575 : icmp4_init (vlib_main_t * vm)
     561             : {
     562         575 :   ip_main_t *im = &ip_main;
     563             :   ip_protocol_info_t *pi;
     564         575 :   icmp4_main_t *cm = &icmp4_main;
     565             :   clib_error_t *error;
     566             : 
     567         575 :   error = vlib_call_init_function (vm, ip_main_init);
     568             : 
     569         575 :   if (error)
     570           0 :     return error;
     571             : 
     572         575 :   pi = ip_get_protocol_info (im, IP_PROTOCOL_ICMP);
     573         575 :   pi->format_header = format_ip4_icmp_header;
     574         575 :   pi->unformat_pg_edit = unformat_pg_icmp_header;
     575             : 
     576         575 :   cm->type_by_name = hash_create_string (0, sizeof (uword));
     577             : #define _(n,t) hash_set_mem (cm->type_by_name, #t, (n));
     578       16100 :   foreach_icmp4_type;
     579             : #undef _
     580             : 
     581         575 :   cm->type_and_code_by_name = hash_create_string (0, sizeof (uword));
     582             : #define _(a,n,t) hash_set_mem (cm->type_by_name, #t, (n) | (ICMP4_##a << 8));
     583       16100 :   foreach_icmp4_code;
     584             : #undef _
     585             : 
     586         575 :   clib_memset (cm->ip4_input_next_index_by_type,
     587             :                ICMP_INPUT_NEXT_ERROR,
     588             :                sizeof (cm->ip4_input_next_index_by_type));
     589             : 
     590         575 :   vlib_thread_main_t *tm = &vlib_thread_main;
     591         575 :   u32 n_vlib_mains = tm->n_vlib_mains;
     592             : 
     593         575 :   throttle_init (&icmp_throttle, n_vlib_mains, THROTTLE_BITS, 1e-5);
     594             : 
     595         575 :   return 0;
     596             : }
     597             : 
     598       13247 : VLIB_INIT_FUNCTION (icmp4_init);
     599             : 
     600             : /*
     601             :  * fd.io coding-style-patch-verification: ON
     602             :  *
     603             :  * Local Variables:
     604             :  * eval: (c-set-style "gnu")
     605             :  * End:
     606             :  */

Generated by: LCOV version 1.14