LCOV - code coverage report
Current view: top level - vnet/srp - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 1 375 0.3 %
Date: 2023-10-26 01:39:38 Functions: 2 23 8.7 %

          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             :  * node.c: srp packet processing
      17             :  *
      18             :  * Copyright (c) 2011 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_packet.h>    /* for ip_csum_fold */
      42             : #include <vnet/srp/srp.h>
      43             : #include <vnet/pg/pg.h>
      44             : 
      45             : srp_main_t srp_main;
      46             : 
      47             : typedef struct {
      48             :   u8 packet_data[32];
      49             : } srp_input_trace_t;
      50             : 
      51           0 : static u8 * format_srp_input_trace (u8 * s, va_list * va)
      52             : {
      53           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
      54           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
      55           0 :   srp_input_trace_t * t = va_arg (*va, srp_input_trace_t *);
      56             : 
      57           0 :   s = format (s, "%U", format_srp_header, t->packet_data);
      58             : 
      59           0 :   return s;
      60             : }
      61             : 
      62             : typedef enum {
      63             :   SRP_INPUT_NEXT_ERROR,
      64             :   SRP_INPUT_NEXT_ETHERNET_INPUT,
      65             :   SRP_INPUT_NEXT_CONTROL,
      66             :   SRP_INPUT_N_NEXT,
      67             : } srp_input_next_t;
      68             : 
      69             : typedef struct {
      70             :   u8 next_index;
      71             :   u8 buffer_advance;
      72             :   u16 error;
      73             : } srp_input_disposition_t;
      74             : 
      75             : static srp_input_disposition_t srp_input_disposition_by_mode[8] = {
      76             :   [SRP_MODE_reserved0] = {
      77             :     .next_index = SRP_INPUT_NEXT_ERROR,
      78             :     .error = SRP_ERROR_UNKNOWN_MODE,
      79             :   },
      80             :   [SRP_MODE_reserved1] = {
      81             :     .next_index = SRP_INPUT_NEXT_ERROR,
      82             :     .error = SRP_ERROR_UNKNOWN_MODE,
      83             :   },
      84             :   [SRP_MODE_reserved2] = {
      85             :     .next_index = SRP_INPUT_NEXT_ERROR,
      86             :     .error = SRP_ERROR_UNKNOWN_MODE,
      87             :   },
      88             :   [SRP_MODE_reserved3] = {
      89             :     .next_index = SRP_INPUT_NEXT_ERROR,
      90             :     .error = SRP_ERROR_UNKNOWN_MODE,
      91             :   },
      92             :   [SRP_MODE_keep_alive] = {
      93             :     .next_index = SRP_INPUT_NEXT_ERROR,
      94             :     .error = SRP_ERROR_KEEP_ALIVE_DROPPED,
      95             :   },
      96             :   [SRP_MODE_data] = {
      97             :     .next_index = SRP_INPUT_NEXT_ETHERNET_INPUT,
      98             :     .buffer_advance = sizeof (srp_header_t),
      99             :   },
     100             :   [SRP_MODE_control_pass_to_host] = {
     101             :     .next_index = SRP_INPUT_NEXT_CONTROL,
     102             :   },
     103             :   [SRP_MODE_control_locally_buffered_for_host] = {
     104             :     .next_index = SRP_INPUT_NEXT_CONTROL,
     105             :   },
     106             : };
     107             : 
     108             : static uword
     109           0 : srp_input (vlib_main_t * vm,
     110             :            vlib_node_runtime_t * node,
     111             :            vlib_frame_t * from_frame)
     112             : {
     113           0 :   vnet_main_t * vnm = vnet_get_main();
     114           0 :   srp_main_t * sm = &srp_main;
     115             :   u32 n_left_from, next_index, * from, * to_next;
     116             : 
     117           0 :   from = vlib_frame_vector_args (from_frame);
     118           0 :   n_left_from = from_frame->n_vectors;
     119             : 
     120           0 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     121           0 :     vlib_trace_frame_buffers_only (vm, node,
     122             :                                    from,
     123             :                                    n_left_from,
     124             :                                    sizeof (from[0]),
     125             :                                    sizeof (srp_input_trace_t));
     126             : 
     127           0 :   next_index = node->cached_next_index;
     128             : 
     129           0 :   while (n_left_from > 0)
     130             :     {
     131             :       u32 n_left_to_next;
     132             : 
     133           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     134             : 
     135           0 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     136             :         {
     137             :           u32 bi0, bi1, sw_if_index0, sw_if_index1;
     138             :           vlib_buffer_t * b0, * b1;
     139             :           u8 next0, next1, error0, error1;
     140             :           srp_header_t * s0, * s1;
     141             :           srp_input_disposition_t * d0, * d1;
     142             :           vnet_hw_interface_t * hi0, * hi1;
     143             :           srp_interface_t * si0, * si1;
     144             : 
     145             :           /* Prefetch next iteration. */
     146             :           {
     147             :             vlib_buffer_t * b2, * b3;
     148             : 
     149           0 :             b2 = vlib_get_buffer (vm, from[2]);
     150           0 :             b3 = vlib_get_buffer (vm, from[3]);
     151             : 
     152           0 :             vlib_prefetch_buffer_header (b2, LOAD);
     153           0 :             vlib_prefetch_buffer_header (b3, LOAD);
     154             : 
     155           0 :             CLIB_PREFETCH (b2->data, sizeof (srp_header_t), LOAD);
     156           0 :             CLIB_PREFETCH (b3->data, sizeof (srp_header_t), LOAD);
     157             :           }
     158             : 
     159           0 :           bi0 = from[0];
     160           0 :           bi1 = from[1];
     161           0 :           to_next[0] = bi0;
     162           0 :           to_next[1] = bi1;
     163           0 :           from += 2;
     164           0 :           to_next += 2;
     165           0 :           n_left_to_next -= 2;
     166           0 :           n_left_from -= 2;
     167             : 
     168           0 :           b0 = vlib_get_buffer (vm, bi0);
     169           0 :           b1 = vlib_get_buffer (vm, bi1);
     170             : 
     171           0 :           s0 = vlib_buffer_get_current (b0);
     172           0 :           s1 = vlib_buffer_get_current (b1);
     173             : 
     174             :           /* Data packets are always assigned to side A (outer ring) interface. */
     175           0 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     176           0 :           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
     177             : 
     178           0 :           hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
     179           0 :           hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
     180             : 
     181           0 :           si0 = pool_elt_at_index (sm->interface_pool, hi0->hw_instance);
     182           0 :           si1 = pool_elt_at_index (sm->interface_pool, hi1->hw_instance);
     183             : 
     184           0 :           sw_if_index0 = (s0->mode == SRP_MODE_data
     185             :                           ? si0->rings[SRP_RING_OUTER].sw_if_index
     186           0 :                           : sw_if_index0);
     187           0 :           sw_if_index1 = (s1->mode == SRP_MODE_data
     188             :                           ? si1->rings[SRP_RING_OUTER].sw_if_index
     189           0 :                           : sw_if_index1);
     190             :             
     191           0 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] = sw_if_index0;
     192           0 :           vnet_buffer (b1)->sw_if_index[VLIB_RX] = sw_if_index1;
     193             : 
     194           0 :           d0 = srp_input_disposition_by_mode + s0->mode;
     195           0 :           d1 = srp_input_disposition_by_mode + s1->mode;
     196             : 
     197           0 :           next0 = d0->next_index;
     198           0 :           next1 = d1->next_index;
     199             : 
     200           0 :           error0 = d0->error;
     201           0 :           error1 = d1->error;
     202             : 
     203           0 :           vlib_buffer_advance (b0, d0->buffer_advance);
     204           0 :           vlib_buffer_advance (b1, d1->buffer_advance);
     205             : 
     206           0 :           b0->error = node->errors[error0];
     207           0 :           b1->error = node->errors[error1];
     208             : 
     209           0 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     210             :                                            to_next, n_left_to_next,
     211             :                                            bi0, bi1, next0, next1);
     212             :         }
     213             :     
     214           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     215             :         {
     216             :           u32 bi0, sw_if_index0;
     217             :           vlib_buffer_t * b0;
     218             :           u8 next0, error0;
     219             :           srp_header_t * s0;
     220             :           srp_input_disposition_t * d0;
     221             :           srp_interface_t * si0;
     222             :           vnet_hw_interface_t * hi0;
     223             : 
     224           0 :           bi0 = from[0];
     225           0 :           to_next[0] = bi0;
     226           0 :           from += 1;
     227           0 :           to_next += 1;
     228           0 :           n_left_to_next -= 1;
     229           0 :           n_left_from -= 1;
     230             : 
     231           0 :           b0 = vlib_get_buffer (vm, bi0);
     232             : 
     233           0 :           s0 = vlib_buffer_get_current (b0);
     234             : 
     235             :           /* Data packets are always assigned to side A (outer ring) interface. */
     236           0 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     237             : 
     238           0 :           hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
     239             : 
     240           0 :           si0 = pool_elt_at_index (sm->interface_pool, hi0->hw_instance);
     241             : 
     242           0 :           sw_if_index0 = (s0->mode == SRP_MODE_data
     243             :                           ? si0->rings[SRP_RING_OUTER].sw_if_index
     244           0 :                           : sw_if_index0);
     245             :             
     246           0 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] = sw_if_index0;
     247             : 
     248           0 :           d0 = srp_input_disposition_by_mode + s0->mode;
     249             : 
     250           0 :           next0 = d0->next_index;
     251             : 
     252           0 :           error0 = d0->error;
     253             : 
     254           0 :           vlib_buffer_advance (b0, d0->buffer_advance);
     255             : 
     256           0 :           b0->error = node->errors[error0];
     257             : 
     258           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     259             :                                            to_next, n_left_to_next,
     260             :                                            bi0, next0);
     261             :         }
     262             : 
     263           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     264             :     }
     265             : 
     266           0 :   return from_frame->n_vectors;
     267             : }
     268             : 
     269             : static char * srp_error_strings[] = {
     270             : #define _(f,s) s,
     271             :   foreach_srp_error
     272             : #undef _
     273             : };
     274             : 
     275             : static vlib_node_registration_t srp_input_node = {
     276             :   .function = srp_input,
     277             :   .name = "srp-input",
     278             :   /* Takes a vector of packets. */
     279             :   .vector_size = sizeof (u32),
     280             : 
     281             :   .n_errors = SRP_N_ERROR,
     282             :   .error_strings = srp_error_strings,
     283             : 
     284             :   .n_next_nodes = SRP_INPUT_N_NEXT,
     285             :   .next_nodes = {
     286             :     [SRP_INPUT_NEXT_ERROR] = "error-drop",
     287             :     [SRP_INPUT_NEXT_ETHERNET_INPUT] = "ethernet-input",
     288             :     [SRP_INPUT_NEXT_CONTROL] = "srp-control",
     289             :   },
     290             : 
     291             :   .format_buffer = format_srp_header_with_length,
     292             :   .format_trace = format_srp_input_trace,
     293             :   .unformat_buffer = unformat_srp_header,
     294             : };
     295             : 
     296             : static uword
     297           0 : srp_topology_packet (vlib_main_t * vm, u32 sw_if_index, u8 ** contents)
     298             : {
     299           0 :   vnet_main_t * vnm = vnet_get_main();
     300           0 :   vnet_hw_interface_t * hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     301             :   srp_topology_header_t * t;
     302             :   srp_topology_mac_binding_t * mb;
     303             :   u32 nb, nmb;
     304             : 
     305           0 :   t = (void *) *contents;
     306             : 
     307           0 :   nb = clib_net_to_host_u16 (t->n_bytes_of_data_that_follows);
     308           0 :   nmb = (nb - sizeof (t->originator_address)) / sizeof (mb[0]);
     309           0 :   if (vec_len (*contents) < sizeof (t[0]) + nmb * sizeof (mb[0]))
     310           0 :     return SRP_ERROR_TOPOLOGY_BAD_LENGTH;
     311             : 
     312             :   /* Fill in our source MAC address. */
     313           0 :   clib_memcpy_fast (t->ethernet.src_address, hi->hw_address, vec_len (hi->hw_address));
     314             : 
     315             :   /* Make space for our MAC binding. */
     316           0 :   vec_resize (*contents, sizeof (srp_topology_mac_binding_t));
     317           0 :   t = (void *) *contents;
     318           0 :   t->n_bytes_of_data_that_follows = clib_host_to_net_u16 (nb + sizeof (mb[0]));
     319             : 
     320           0 :   mb = t->bindings + nmb;
     321             : 
     322           0 :   mb->flags =
     323           0 :     ((t->srp.is_inner_ring ? SRP_TOPOLOGY_MAC_BINDING_FLAG_IS_INNER_RING : 0)
     324           0 :      | (/* is wrapped FIXME */ 0));
     325           0 :   clib_memcpy_fast (mb->address, hi->hw_address, vec_len (hi->hw_address));
     326             : 
     327             :   t->control.checksum
     328           0 :     = ~ip_csum_fold (ip_incremental_checksum (0, &t->control,
     329           0 :                                               vec_len (*contents) - STRUCT_OFFSET_OF (srp_generic_control_header_t, control)));
     330             : 
     331             :   {
     332             :     vlib_frame_t * f; 
     333             :     vlib_buffer_t * b;
     334             :     u32 * to_next;
     335           0 :     u32 bi = ~0;
     336             : 
     337           0 :     if (vlib_buffer_add_data (vm, /* buffer to append to */ &bi,
     338           0 :                               *contents, vec_len (*contents)))
     339             :       {
     340             :         /* complete or partial buffer allocation failure */
     341           0 :         if (bi != ~0)
     342           0 :           vlib_buffer_free (vm, &bi, 1);
     343           0 :         return SRP_ERROR_CONTROL_PACKETS_PROCESSED;
     344             :       }
     345           0 :     b = vlib_get_buffer (vm, bi);
     346           0 :     vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
     347           0 :     f = vlib_get_frame_to_node (vm, hi->output_node_index);
     348           0 :     to_next = vlib_frame_vector_args (f);
     349           0 :     to_next[0] = bi;
     350           0 :     f->n_vectors = 1;
     351           0 :     vlib_put_frame_to_node (vm, hi->output_node_index, f);
     352             :   }
     353             : 
     354           0 :   return SRP_ERROR_CONTROL_PACKETS_PROCESSED;
     355             : }
     356             : 
     357             : typedef uword (srp_control_handler_function_t) (vlib_main_t * vm,
     358             :                                                 u32 sw_if_index,
     359             :                                                 u8 ** contents);
     360             : 
     361             : static uword
     362           0 : srp_control_input (vlib_main_t * vm,
     363             :                    vlib_node_runtime_t * node,
     364             :                    vlib_frame_t * from_frame)
     365             : {
     366             :   u32 n_left_from, next_index, * from, * to_next;
     367             :   vlib_node_runtime_t * error_node;
     368             :   static u8 * contents;
     369             : 
     370           0 :   error_node = vlib_node_get_runtime (vm, srp_input_node.index);
     371             : 
     372           0 :   from = vlib_frame_vector_args (from_frame);
     373           0 :   n_left_from = from_frame->n_vectors;
     374             : 
     375           0 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     376           0 :     vlib_trace_frame_buffers_only (vm, node,
     377             :                                    from,
     378             :                                    n_left_from,
     379             :                                    sizeof (from[0]),
     380             :                                    sizeof (srp_input_trace_t));
     381             : 
     382           0 :   next_index = node->cached_next_index;
     383             : 
     384           0 :   while (n_left_from > 0)
     385             :     {
     386             :       u32 n_left_to_next;
     387             : 
     388           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     389             : 
     390           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     391             :         {
     392             :           u32 bi0, l2_len0, l3_len0;
     393             :           vlib_buffer_t * b0;
     394             :           u8 next0, error0;
     395             :           srp_generic_control_header_t * s0;
     396             : 
     397           0 :           bi0 = from[0];
     398           0 :           to_next[0] = bi0;
     399           0 :           from += 1;
     400           0 :           to_next += 1;
     401           0 :           n_left_to_next -= 1;
     402           0 :           n_left_from -= 1;
     403             : 
     404           0 :           b0 = vlib_get_buffer (vm, bi0);
     405             : 
     406           0 :           s0 = vlib_buffer_get_current(b0);
     407           0 :           l2_len0 = vlib_buffer_length_in_chain (vm, b0);
     408           0 :           l3_len0 = l2_len0 - STRUCT_OFFSET_OF (srp_generic_control_header_t, control);
     409             : 
     410           0 :           error0 = SRP_ERROR_CONTROL_PACKETS_PROCESSED;
     411             : 
     412           0 :           error0 = s0->control.version != 0 ? SRP_ERROR_CONTROL_VERSION_NON_ZERO : error0;
     413             : 
     414             :           {
     415           0 :             u16 save0 = s0->control.checksum;
     416             :             u16 computed0;
     417           0 :             s0->control.checksum = 0;
     418           0 :             computed0 = ~ip_csum_fold (ip_incremental_checksum (0, &s0->control, l3_len0));
     419           0 :             error0 = save0 != computed0 ? SRP_ERROR_CONTROL_BAD_CHECKSUM : error0;
     420             :           }
     421             : 
     422           0 :           if (error0 == SRP_ERROR_CONTROL_PACKETS_PROCESSED)
     423             :             {
     424             :               static srp_control_handler_function_t * t[SRP_N_CONTROL_PACKET_TYPE] = {
     425             :                 [SRP_CONTROL_PACKET_TYPE_topology] = srp_topology_packet,
     426             :               };
     427             :               srp_control_handler_function_t * f;
     428             : 
     429           0 :               f = 0;
     430           0 :               if (s0->control.type < ARRAY_LEN (t))
     431           0 :                 f = t[s0->control.type];
     432             : 
     433           0 :               if (f)
     434             :                 {
     435           0 :                   vec_validate (contents, l2_len0 - 1);
     436           0 :                   vlib_buffer_contents (vm, bi0, contents);
     437           0 :                   error0 = f (vm, vnet_buffer (b0)->sw_if_index[VLIB_RX], &contents);
     438             :                 }
     439             :               else
     440           0 :                 error0 = SRP_ERROR_UNKNOWN_CONTROL;
     441             :             }
     442             : 
     443           0 :           b0->error = error_node->errors[error0];
     444           0 :           next0 = 0;
     445             : 
     446           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     447             :                                            to_next, n_left_to_next,
     448             :                                            bi0, next0);
     449             :         }
     450             : 
     451           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     452             :     }
     453             : 
     454           0 :   return from_frame->n_vectors;
     455             : }
     456             : 
     457             : static vlib_node_registration_t srp_control_input_node = {
     458             :   .function = srp_control_input,
     459             :   .name = "srp-control",
     460             :   /* Takes a vector of packets. */
     461             :   .vector_size = sizeof (u32),
     462             : 
     463             :   .n_next_nodes = 1,
     464             :   .next_nodes = {
     465             :     [0] = "error-drop",
     466             :   },
     467             : 
     468             :   .format_buffer = format_srp_header_with_length,
     469             :   .format_trace = format_srp_input_trace,
     470             :   .unformat_buffer = unformat_srp_header,
     471             : };
     472             : 
     473           0 : static u8 * format_srp_ips_request_type (u8 * s, va_list * args)
     474             : {
     475           0 :   u32 x = va_arg (*args, u32);
     476           0 :   char * t = 0;
     477           0 :   switch (x)
     478             :     {
     479             : #define _(f,n) case SRP_IPS_REQUEST_##f: t = #f; break;
     480           0 :       foreach_srp_ips_request_type
     481             : #undef _
     482           0 :     default:
     483           0 :       return format (s, "unknown 0x%x", x);
     484             :     }
     485           0 :   return format (s, "%U", format_c_identifier, t);
     486             : }
     487             : 
     488           0 : static u8 * format_srp_ips_status (u8 * s, va_list * args)
     489             : {
     490           0 :   u32 x = va_arg (*args, u32);
     491           0 :   char * t = 0;
     492           0 :   switch (x)
     493             :     {
     494             : #define _(f,n) case SRP_IPS_STATUS_##f: t = #f; break;
     495           0 :       foreach_srp_ips_status
     496             : #undef _
     497           0 :     default:
     498           0 :       return format (s, "unknown 0x%x", x);
     499             :     }
     500           0 :   return format (s, "%U", format_c_identifier, t);
     501             : }
     502             : 
     503           0 : static u8 * format_srp_ips_state (u8 * s, va_list * args)
     504             : {
     505           0 :   u32 x = va_arg (*args, u32);
     506           0 :   char * t = 0;
     507           0 :   switch (x)
     508             :     {
     509             : #define _(f) case SRP_IPS_STATE_##f: t = #f; break;
     510           0 :       foreach_srp_ips_state
     511             : #undef _
     512           0 :     default:
     513           0 :       return format (s, "unknown 0x%x", x);
     514             :     }
     515           0 :   return format (s, "%U", format_c_identifier, t);
     516             : }
     517             : 
     518           0 : static u8 * format_srp_ring (u8 * s, va_list * args)
     519             : {
     520           0 :   u32 ring = va_arg (*args, u32);
     521           0 :   return format (s, "%s", ring == SRP_RING_INNER ? "inner" : "outer");
     522             : }
     523             : 
     524           0 : static u8 * format_srp_ips_header (u8 * s, va_list * args)
     525             : {
     526           0 :   srp_ips_header_t * h = va_arg (*args, srp_ips_header_t *);
     527             : 
     528           0 :   s = format (s, "%U, %U, %U, %s-path",
     529           0 :               format_srp_ips_request_type, h->request_type,
     530           0 :               format_ethernet_address, h->originator_address,
     531           0 :               format_srp_ips_status, h->status,
     532           0 :               h->is_long_path ? "long" : "short");
     533             : 
     534           0 :   return s;
     535             : }
     536             : 
     537           0 : static u8 * format_srp_interface (u8 * s, va_list * args)
     538             : {
     539           0 :   srp_interface_t * si = va_arg (*args, srp_interface_t *);
     540             :   srp_interface_ring_t * ir;
     541             : 
     542           0 :   s = format (s, "address %U, IPS state %U",
     543           0 :               format_ethernet_address, si->my_address,
     544           0 :               format_srp_ips_state, si->current_ips_state);
     545           0 :   for (ir = si->rings; ir < si->rings + SRP_N_RING; ir++)
     546           0 :     if (ir->rx_neighbor_address_valid)
     547           0 :       s = format (s, ", %U neighbor %U",
     548           0 :                   format_srp_ring, ir->ring,
     549           0 :                   format_ethernet_address, ir->rx_neighbor_address);
     550             : 
     551           0 :   return s;
     552             : }
     553             : 
     554           0 : u8 * format_srp_device (u8 * s, va_list * args)
     555             : {
     556           0 :   u32 hw_if_index = va_arg (*args, u32);
     557           0 :   CLIB_UNUSED (int verbose) = va_arg (*args, int);
     558           0 :   vnet_main_t * vnm = vnet_get_main();
     559           0 :   srp_main_t * sm = &srp_main;
     560           0 :   vnet_hw_interface_t * hi = vnet_get_hw_interface (vnm, hw_if_index);
     561           0 :   srp_interface_t * si = pool_elt_at_index (sm->interface_pool, hi->hw_instance);
     562           0 :   return format (s, "%U", format_srp_interface, si);
     563             : }
     564             : 
     565             : always_inline srp_interface_t *
     566           0 : srp_get_interface (u32 sw_if_index, srp_ring_type_t * ring)
     567             : {
     568           0 :   vnet_main_t * vnm = vnet_get_main();
     569           0 :   srp_main_t * sm = &srp_main;
     570           0 :   vnet_hw_interface_t * hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     571             :   srp_interface_t * si;
     572             : 
     573           0 :   ASSERT (hi->hw_class_index == srp_hw_interface_class.index);
     574           0 :   si = pool_elt_at_index (sm->interface_pool, hi->hw_instance);
     575             : 
     576           0 :   ASSERT (si->rings[SRP_RING_INNER].hw_if_index == hi->hw_if_index
     577             :           || si->rings[SRP_RING_OUTER].hw_if_index == hi->hw_if_index);
     578           0 :   if (ring)
     579           0 :     *ring =
     580           0 :       (hi->hw_if_index == si->rings[SRP_RING_INNER].hw_if_index
     581             :        ? SRP_RING_INNER
     582           0 :        : SRP_RING_OUTER);
     583             : 
     584           0 :   return si;
     585             : }
     586             : 
     587           0 : static void init_ips_packet (srp_interface_t * si,
     588             :                              srp_ring_type_t tx_ring,
     589             :                              srp_ips_header_t * i)
     590             : {
     591           0 :   clib_memset (i, 0, sizeof (i[0]));
     592             : 
     593           0 :   i->srp.ttl = 1;
     594           0 :   i->srp.is_inner_ring = tx_ring;
     595           0 :   i->srp.priority = 7;
     596           0 :   i->srp.mode = SRP_MODE_control_locally_buffered_for_host;
     597           0 :   srp_header_compute_parity (&i->srp);
     598             : 
     599           0 :   clib_memcpy_fast (&i->ethernet.src_address, &si->my_address, sizeof (si->my_address));
     600           0 :   i->ethernet.type = clib_host_to_net_u16 (ETHERNET_TYPE_SRP_CONTROL);
     601             : 
     602             :   /* Checksum will be filled in later. */
     603           0 :   i->control.version = 0;
     604           0 :   i->control.type = SRP_CONTROL_PACKET_TYPE_ips;
     605           0 :   i->control.ttl = 255;
     606             : 
     607           0 :   clib_memcpy_fast (&i->originator_address, &si->my_address, sizeof (si->my_address));
     608           0 : }
     609             : 
     610           0 : static void tx_ips_packet (srp_interface_t * si,
     611             :                            srp_ring_type_t tx_ring,
     612             :                            srp_ips_header_t * i)
     613             : {
     614           0 :   srp_main_t * sm = &srp_main;
     615           0 :   vnet_main_t * vnm = vnet_get_main();
     616           0 :   vlib_main_t * vm = sm->vlib_main;
     617           0 :   vnet_hw_interface_t * hi = vnet_get_hw_interface (vnm, si->rings[tx_ring].hw_if_index);
     618             :   vlib_frame_t * f;
     619             :   vlib_buffer_t * b;
     620           0 :   u32 * to_next, bi = ~0;
     621             : 
     622           0 :   if (! vnet_sw_interface_is_admin_up (vnm, hi->sw_if_index))
     623           0 :     return;
     624           0 :   if (hi->hw_class_index != srp_hw_interface_class.index)
     625           0 :     return;
     626             : 
     627             :   i->control.checksum
     628           0 :     = ~ip_csum_fold (ip_incremental_checksum (0, &i->control,
     629             :                                               sizeof (i[0]) - STRUCT_OFFSET_OF (srp_ips_header_t, control)));
     630             : 
     631           0 :   if (vlib_buffer_add_data (vm, /* buffer to append to */ &bi, i,
     632             :                             sizeof (i[0])))
     633             :     {
     634             :       /* complete or partial allocation failure */
     635           0 :       if (bi != ~0)
     636           0 :         vlib_buffer_free (vm, &bi, 1);
     637           0 :       return;
     638             :     }
     639             : 
     640             :   /* FIXME trace. */
     641             :   if (0)
     642             :     clib_warning ("%U %U",
     643             :                   format_vnet_sw_if_index_name, vnm, hi->sw_if_index,
     644             :                   format_srp_ips_header, i);
     645             : 
     646           0 :   b = vlib_get_buffer (vm, bi);
     647           0 :   vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = hi->sw_if_index;
     648             : 
     649           0 :   f = vlib_get_frame_to_node (vm, hi->output_node_index);
     650           0 :   to_next = vlib_frame_vector_args (f);
     651           0 :   to_next[0] = bi;
     652           0 :   f->n_vectors = 1;
     653           0 :   vlib_put_frame_to_node (vm, hi->output_node_index, f);
     654             : }
     655             : 
     656           0 : static int requests_switch (srp_ips_request_type_t r)
     657             : {
     658             :   static u8 t[16] = {
     659             :     [SRP_IPS_REQUEST_forced_switch] = 1,
     660             :     [SRP_IPS_REQUEST_manual_switch] = 1,
     661             :     [SRP_IPS_REQUEST_signal_fail] = 1,
     662             :     [SRP_IPS_REQUEST_signal_degrade] = 1,
     663             :   };
     664           0 :   return (int) r < ARRAY_LEN (t) ? t[r] : 0;
     665             : }
     666             : 
     667             : /* Called when an IPS control packet is received on given interface. */
     668           0 : void srp_ips_rx_packet (u32 sw_if_index, srp_ips_header_t * h)
     669             : {
     670           0 :   vnet_main_t * vnm = vnet_get_main();
     671           0 :   vlib_main_t * vm = srp_main.vlib_main;
     672             :   srp_ring_type_t rx_ring;
     673           0 :   srp_interface_t * si = srp_get_interface (sw_if_index, &rx_ring);
     674           0 :   srp_interface_ring_t * ir = &si->rings[rx_ring];
     675             : 
     676             :   /* FIXME trace. */
     677             :   if (0)
     678             :     clib_warning ("%U %U %U",
     679             :                   format_time_interval, "h:m:s:u", vlib_time_now (vm),
     680             :                   format_vnet_sw_if_index_name, vnm, sw_if_index,
     681             :                   format_srp_ips_header, h);
     682             : 
     683             :   /* Ignore self-generated IPS packets. */
     684           0 :   if (! memcmp (h->originator_address, si->my_address, sizeof (h->originator_address)))
     685           0 :     goto done;
     686             : 
     687             :   /* Learn neighbor address from short path messages. */
     688           0 :   if (! h->is_long_path)
     689             :     {
     690           0 :       if (ir->rx_neighbor_address_valid
     691           0 :           && memcmp (ir->rx_neighbor_address, h->originator_address, sizeof (ir->rx_neighbor_address)))
     692             :         {
     693           0 :           ASSERT (0);
     694             :         }
     695           0 :       ir->rx_neighbor_address_valid = 1;
     696           0 :       clib_memcpy_fast (ir->rx_neighbor_address, h->originator_address, sizeof (ir->rx_neighbor_address));
     697             :     }
     698             : 
     699           0 :   switch (si->current_ips_state)
     700             :     {
     701           0 :     case SRP_IPS_STATE_idle:
     702             :       /* Received {REQ,NEIGHBOR,W,S} in idle state: wrap. */
     703           0 :       if (requests_switch (h->request_type)
     704           0 :           && ! h->is_long_path
     705           0 :           && h->status == SRP_IPS_STATUS_wrapped)
     706             :         {
     707             :           srp_ips_header_t to_tx[2];
     708             : 
     709           0 :           si->current_ips_state = SRP_IPS_STATE_wrapped;
     710           0 :           si->hw_wrap_function (si->rings[SRP_SIDE_A].hw_if_index, /* enable_wrap */ 1);
     711           0 :           si->hw_wrap_function (si->rings[SRP_SIDE_B].hw_if_index, /* enable_wrap */ 1);
     712             : 
     713           0 :           init_ips_packet (si, rx_ring ^ 0, &to_tx[0]);
     714           0 :           to_tx[0].request_type = SRP_IPS_REQUEST_idle;
     715           0 :           to_tx[0].status = SRP_IPS_STATUS_wrapped;
     716           0 :           to_tx[0].is_long_path = 0;
     717           0 :           tx_ips_packet (si, rx_ring ^ 0, &to_tx[0]);
     718             : 
     719           0 :           init_ips_packet (si, rx_ring ^ 1, &to_tx[1]);
     720           0 :           to_tx[1].request_type = h->request_type;
     721           0 :           to_tx[1].status = SRP_IPS_STATUS_wrapped;
     722           0 :           to_tx[1].is_long_path = 1;
     723           0 :           tx_ips_packet (si, rx_ring ^ 1, &to_tx[1]);
     724             :         }
     725           0 :       break;
     726             : 
     727           0 :     case SRP_IPS_STATE_wrapped:
     728           0 :       if (! h->is_long_path
     729           0 :           && h->request_type == SRP_IPS_REQUEST_idle
     730           0 :           && h->status == SRP_IPS_STATUS_idle)
     731             :         {
     732           0 :           si->current_ips_state = SRP_IPS_STATE_idle;
     733           0 :           si->hw_wrap_function (si->rings[SRP_SIDE_A].hw_if_index, /* enable_wrap */ 0);
     734           0 :           si->hw_wrap_function (si->rings[SRP_SIDE_B].hw_if_index, /* enable_wrap */ 0);
     735             :         }
     736           0 :       break;
     737             : 
     738           0 :     case SRP_IPS_STATE_pass_thru:
     739             :       /* FIXME */
     740           0 :       break;
     741             : 
     742           0 :     default:
     743           0 :       abort ();
     744             :       break;
     745             :     }
     746           0 :  done:
     747             :   ;
     748           0 : }
     749             : 
     750             : /* Preform local IPS request on given interface. */
     751           0 : void srp_ips_local_request (u32 sw_if_index, srp_ips_request_type_t request)
     752             : {
     753           0 :   vnet_main_t * vnm = vnet_get_main();
     754           0 :   srp_main_t * sm = &srp_main;
     755             :   srp_ring_type_t rx_ring;
     756           0 :   srp_interface_t * si = srp_get_interface (sw_if_index, &rx_ring);
     757           0 :   srp_interface_ring_t * ir = &si->rings[rx_ring];
     758             : 
     759           0 :   if (request == SRP_IPS_REQUEST_wait_to_restore)
     760             :     {
     761           0 :       if (si->current_ips_state != SRP_IPS_STATE_wrapped)
     762           0 :         return;
     763           0 :       if (! ir->waiting_to_restore)
     764             :         {
     765           0 :           ir->wait_to_restore_start_time = vlib_time_now (sm->vlib_main);
     766           0 :           ir->waiting_to_restore = 1;
     767             :         }
     768             :     }
     769             :   else
     770             :     {
     771             :       /* FIXME handle local signal fail. */
     772           0 :       ir->wait_to_restore_start_time = 0;
     773           0 :       ir->waiting_to_restore = 0;
     774             :     }
     775             : 
     776             :   /* FIXME trace. */
     777             :   if (0)
     778             :     clib_warning ("%U %U",
     779             :                   format_vnet_sw_if_index_name, vnm, sw_if_index,
     780             :                   format_srp_ips_request_type, request);
     781             : 
     782             : }
     783             : 
     784           0 : static void maybe_send_ips_message (srp_interface_t * si)
     785             : {
     786           0 :   srp_main_t * sm = &srp_main;
     787             :   srp_ips_header_t to_tx[2];
     788           0 :   srp_ring_type_t rx_ring = SRP_RING_OUTER;
     789           0 :   srp_interface_ring_t * r0 = &si->rings[rx_ring ^ 0];
     790           0 :   srp_interface_ring_t * r1 = &si->rings[rx_ring ^ 1];
     791           0 :   f64 now = vlib_time_now (sm->vlib_main);
     792             : 
     793           0 :   if (! si->ips_process_enable)
     794           0 :     return;
     795             : 
     796           0 :   if (si->current_ips_state == SRP_IPS_STATE_wrapped
     797           0 :       && r0->waiting_to_restore
     798           0 :       && r1->waiting_to_restore
     799           0 :       && now >= r0->wait_to_restore_start_time + si->config.wait_to_restore_idle_delay
     800           0 :       && now >= r1->wait_to_restore_start_time + si->config.wait_to_restore_idle_delay)
     801             :     {
     802           0 :       si->current_ips_state = SRP_IPS_STATE_idle;
     803           0 :       r0->waiting_to_restore = r1->waiting_to_restore = 0;
     804           0 :       r0->wait_to_restore_start_time = r1->wait_to_restore_start_time = 0;
     805             :     }
     806             : 
     807           0 :   if (si->current_ips_state != SRP_IPS_STATE_idle)
     808           0 :     return;
     809             : 
     810           0 :   init_ips_packet (si, rx_ring ^ 0, &to_tx[0]);
     811           0 :   init_ips_packet (si, rx_ring ^ 1, &to_tx[1]);
     812             : 
     813           0 :   if (si->current_ips_state == SRP_IPS_STATE_idle)
     814             :     {
     815           0 :       to_tx[0].request_type = to_tx[1].request_type = SRP_IPS_REQUEST_idle;
     816           0 :       to_tx[0].status = to_tx[1].status = SRP_IPS_STATUS_idle;
     817           0 :       to_tx[0].is_long_path = to_tx[1].is_long_path = 0;
     818             :     }
     819             : 
     820           0 :   else if (si->current_ips_state == SRP_IPS_STATE_wrapped)
     821             :     {
     822           0 :       to_tx[0].request_type =
     823           0 :         (si->rings[rx_ring ^ 0].waiting_to_restore
     824             :          ? SRP_IPS_REQUEST_wait_to_restore
     825           0 :          : SRP_IPS_REQUEST_signal_fail);
     826           0 :       to_tx[1].request_type =
     827           0 :         (si->rings[rx_ring ^ 1].waiting_to_restore
     828             :          ? SRP_IPS_REQUEST_wait_to_restore
     829           0 :          : SRP_IPS_REQUEST_signal_fail);
     830           0 :       to_tx[0].status = to_tx[1].status = SRP_IPS_STATUS_wrapped;
     831           0 :       to_tx[0].is_long_path = 0;
     832           0 :       to_tx[1].is_long_path = 1;
     833             :     }
     834             : 
     835           0 :   tx_ips_packet (si, rx_ring ^ 0, &to_tx[0]);
     836           0 :   tx_ips_packet (si, rx_ring ^ 1, &to_tx[1]);
     837             : }
     838             : 
     839             : static uword
     840           0 : srp_ips_process (vlib_main_t * vm,
     841             :                  vlib_node_runtime_t * rt,
     842             :                  vlib_frame_t * f)
     843             : {
     844           0 :   srp_main_t * sm = &srp_main;
     845             :   srp_interface_t * si;
     846             : 
     847             :   while (1)
     848             :     {
     849           0 :       pool_foreach (si, sm->interface_pool)  {
     850           0 :         maybe_send_ips_message (si);
     851             :       }
     852           0 :       vlib_process_suspend (vm, 1.0);
     853             :     }
     854             : 
     855             :   return 0;
     856             : }
     857             : 
     858             : vlib_node_registration_t srp_ips_process_node = {
     859             :     .function = srp_ips_process,
     860             :     .type = VLIB_NODE_TYPE_PROCESS,
     861             :     .name = "srp-ips-process",
     862             :     .state = VLIB_NODE_STATE_DISABLED,
     863             : };
     864             : 
     865             : static void
     866           0 : srp_setup_node (vlib_main_t *vm, u32 node_index)
     867             : {
     868           0 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     869           0 :   pg_node_t *pn = pg_get_node (node_index);
     870           0 :   n->format_buffer = format_srp_header_with_length;
     871           0 :   n->unformat_buffer = unformat_srp_header;
     872           0 :   pn->unformat_edit = unformat_pg_srp_header;
     873           0 : }
     874             : 
     875           0 : static clib_error_t * srp_init (vlib_main_t * vm)
     876             : {
     877           0 :   srp_main_t * sm = &srp_main;
     878             : 
     879           0 :   sm->default_data_ttl = 255;
     880           0 :   sm->vlib_main = vm;
     881           0 :   vlib_register_node (vm, &srp_ips_process_node, "%s",
     882             :                       srp_ips_process_node.name);
     883           0 :   vlib_register_node (vm, &srp_input_node, "%s", srp_input_node.name);
     884           0 :   vlib_register_node (vm, &srp_control_input_node, "%s",
     885             :                       srp_control_input_node.name);
     886           0 :   srp_setup_node (vm, srp_input_node.index);
     887             : 
     888           0 :   return 0;
     889             : }
     890             : 
     891       25919 : VLIB_INIT_FUNCTION (srp_init);

Generated by: LCOV version 1.14