1cb9cadadSEd Warnicke/*
2cb9cadadSEd Warnicke * Copyright (c) 2015 Cisco and/or its affiliates.
3cb9cadadSEd Warnicke * Licensed under the Apache License, Version 2.0 (the "License");
4cb9cadadSEd Warnicke * you may not use this file except in compliance with the License.
5cb9cadadSEd Warnicke * You may obtain a copy of the License at:
6cb9cadadSEd Warnicke *
7cb9cadadSEd Warnicke *     http://www.apache.org/licenses/LICENSE-2.0
8cb9cadadSEd Warnicke *
9cb9cadadSEd Warnicke * Unless required by applicable law or agreed to in writing, software
10cb9cadadSEd Warnicke * distributed under the License is distributed on an "AS IS" BASIS,
11cb9cadadSEd Warnicke * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb9cadadSEd Warnicke * See the License for the specific language governing permissions and
13cb9cadadSEd Warnicke * limitations under the License.
14cb9cadadSEd Warnicke */
15cb9cadadSEd Warnicke/*
16cb9cadadSEd Warnicke * ppp_node.c: ppp packet processing
17cb9cadadSEd Warnicke *
18cb9cadadSEd Warnicke * Copyright (c) 2010 Eliot Dresselhaus
19cb9cadadSEd Warnicke *
20cb9cadadSEd Warnicke * Permission is hereby granted, free of charge, to any person obtaining
21cb9cadadSEd Warnicke * a copy of this software and associated documentation files (the
22cb9cadadSEd Warnicke * "Software"), to deal in the Software without restriction, including
23cb9cadadSEd Warnicke * without limitation the rights to use, copy, modify, merge, publish,
24cb9cadadSEd Warnicke * distribute, sublicense, and/or sell copies of the Software, and to
25cb9cadadSEd Warnicke * permit persons to whom the Software is furnished to do so, subject to
26cb9cadadSEd Warnicke * the following conditions:
27cb9cadadSEd Warnicke *
28cb9cadadSEd Warnicke * The above copyright notice and this permission notice shall be
29cb9cadadSEd Warnicke * included in all copies or substantial portions of the Software.
30cb9cadadSEd Warnicke *
31cb9cadadSEd Warnicke *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32cb9cadadSEd Warnicke *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33cb9cadadSEd Warnicke *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34cb9cadadSEd Warnicke *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35cb9cadadSEd Warnicke *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36cb9cadadSEd Warnicke *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37cb9cadadSEd Warnicke *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38cb9cadadSEd Warnicke */
39cb9cadadSEd Warnicke
40cb9cadadSEd Warnicke#include <vlib/vlib.h>
41cb9cadadSEd Warnicke#include <vnet/pg/pg.h>
42cb9cadadSEd Warnicke#include <vnet/ppp/ppp.h>
43cb9cadadSEd Warnicke#include <vppinfra/sparse_vec.h>
44cb9cadadSEd Warnicke
45cb9cadadSEd Warnicke#define foreach_ppp_input_next			\
46cb9cadadSEd Warnicke  _ (PUNT, "error-punt")			\
47cb9cadadSEd Warnicke  _ (DROP, "error-drop")
48cb9cadadSEd Warnicke
49aba0fe49SCalvintypedef enum
50aba0fe49SCalvin{
51cb9cadadSEd Warnicke#define _(s,n) PPP_INPUT_NEXT_##s,
52cb9cadadSEd Warnicke  foreach_ppp_input_next
53cb9cadadSEd Warnicke#undef _
54aba0fe49SCalvin    PPP_INPUT_N_NEXT,
55cb9cadadSEd Warnicke} ppp_input_next_t;
56cb9cadadSEd Warnicke
57aba0fe49SCalvintypedef struct
58aba0fe49SCalvin{
59cb9cadadSEd Warnicke  u8 packet_data[32];
60cb9cadadSEd Warnicke} ppp_input_trace_t;
61cb9cadadSEd Warnicke
62aba0fe49SCalvinstatic u8 *
63aba0fe49SCalvinformat_ppp_input_trace (u8 * s, va_list * va)
64cb9cadadSEd Warnicke{
65cb9cadadSEd Warnicke  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
66cb9cadadSEd Warnicke  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
67aba0fe49SCalvin  ppp_input_trace_t *t = va_arg (*va, ppp_input_trace_t *);
68cb9cadadSEd Warnicke
69cb9cadadSEd Warnicke  s = format (s, "%U", format_ppp_header, t->packet_data);
70cb9cadadSEd Warnicke
71cb9cadadSEd Warnicke  return s;
72cb9cadadSEd Warnicke}
73cb9cadadSEd Warnicke
74aba0fe49SCalvintypedef struct
75aba0fe49SCalvin{
76cb9cadadSEd Warnicke  /* Sparse vector mapping ppp protocol in network byte order
77cb9cadadSEd Warnicke     to next index. */
78aba0fe49SCalvin  u16 *next_by_protocol;
79cb9cadadSEd Warnicke
80aba0fe49SCalvin  u32 *sparse_index_by_next_index;
81cb9cadadSEd Warnicke} ppp_input_runtime_t;
82cb9cadadSEd Warnicke
83cb9cadadSEd Warnickestatic uword
84cb9cadadSEd Warnickeppp_input (vlib_main_t * vm,
85aba0fe49SCalvin	   vlib_node_runtime_t * node, vlib_frame_t * from_frame)
86cb9cadadSEd Warnicke{
87aba0fe49SCalvin  ppp_input_runtime_t *rt = (void *) node->runtime_data;
88aba0fe49SCalvin  u32 n_left_from, next_index, i_next, *from, *to_next;
89cb9cadadSEd Warnicke
90cb9cadadSEd Warnicke  from = vlib_frame_vector_args (from_frame);
91cb9cadadSEd Warnicke  n_left_from = from_frame->n_vectors;
92cb9cadadSEd Warnicke
93cb9cadadSEd Warnicke  if (node->flags & VLIB_NODE_FLAG_TRACE)
94cb9cadadSEd Warnicke    vlib_trace_frame_buffers_only (vm, node,
95cb9cadadSEd Warnicke				   from,
96cb9cadadSEd Warnicke				   n_left_from,
97cb9cadadSEd Warnicke				   sizeof (from[0]),
98cb9cadadSEd Warnicke				   sizeof (ppp_input_trace_t));
99cb9cadadSEd Warnicke
100cb9cadadSEd Warnicke  next_index = node->cached_next_index;
101cb9cadadSEd Warnicke  i_next = vec_elt (rt->sparse_index_by_next_index, next_index);
102cb9cadadSEd Warnicke
103cb9cadadSEd Warnicke  while (n_left_from > 0)
104cb9cadadSEd Warnicke    {
105cb9cadadSEd Warnicke      u32 n_left_to_next;
106cb9cadadSEd Warnicke
107aba0fe49SCalvin      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
108cb9cadadSEd Warnicke
109cb9cadadSEd Warnicke      while (n_left_from >= 4 && n_left_to_next >= 2)
110cb9cadadSEd Warnicke	{
111cb9cadadSEd Warnicke	  u32 bi0, bi1;
112aba0fe49SCalvin	  vlib_buffer_t *b0, *b1;
113aba0fe49SCalvin	  ppp_header_t *h0, *h1;
114cb9cadadSEd Warnicke	  u32 i0, i1, protocol0, protocol1, enqueue_code;
115cb9cadadSEd Warnicke
116cb9cadadSEd Warnicke	  /* Prefetch next iteration. */
117cb9cadadSEd Warnicke	  {
118aba0fe49SCalvin	    vlib_buffer_t *p2, *p3;
119cb9cadadSEd Warnicke
120cb9cadadSEd Warnicke	    p2 = vlib_get_buffer (vm, from[2]);
121cb9cadadSEd Warnicke	    p3 = vlib_get_buffer (vm, from[3]);
122cb9cadadSEd Warnicke
123cb9cadadSEd Warnicke	    vlib_prefetch_buffer_header (p2, LOAD);
124cb9cadadSEd Warnicke	    vlib_prefetch_buffer_header (p3, LOAD);
125cb9cadadSEd Warnicke
126cb9cadadSEd Warnicke	    CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
127cb9cadadSEd Warnicke	    CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
128cb9cadadSEd Warnicke	  }
129cb9cadadSEd Warnicke
130cb9cadadSEd Warnicke	  bi0 = from[0];
131cb9cadadSEd Warnicke	  bi1 = from[1];
132cb9cadadSEd Warnicke	  to_next[0] = bi0;
133cb9cadadSEd Warnicke	  to_next[1] = bi1;
134cb9cadadSEd Warnicke	  from += 2;
135cb9cadadSEd Warnicke	  to_next += 2;
136cb9cadadSEd Warnicke	  n_left_to_next -= 2;
137cb9cadadSEd Warnicke	  n_left_from -= 2;
138cb9cadadSEd Warnicke
139cb9cadadSEd Warnicke	  b0 = vlib_get_buffer (vm, bi0);
140cb9cadadSEd Warnicke	  b1 = vlib_get_buffer (vm, bi1);
141cb9cadadSEd Warnicke
1427107d7efSZhiyong Yang	  h0 = vlib_buffer_get_current (b0);
1437107d7efSZhiyong Yang	  h1 = vlib_buffer_get_current (b1);
144cb9cadadSEd Warnicke
1457107d7efSZhiyong Yang	  vlib_buffer_advance (b0, sizeof (ppp_header_t));
1467107d7efSZhiyong Yang	  vlib_buffer_advance (b1, sizeof (ppp_header_t));
147cb9cadadSEd Warnicke
148cb9cadadSEd Warnicke	  /* Index sparse array with network byte order. */
149cb9cadadSEd Warnicke	  protocol0 = h0->protocol;
150cb9cadadSEd Warnicke	  protocol1 = h1->protocol;
151aba0fe49SCalvin	  sparse_vec_index2 (rt->next_by_protocol, protocol0, protocol1, &i0,
152aba0fe49SCalvin			     &i1);
153cb9cadadSEd Warnicke
154aba0fe49SCalvin	  b0->error =
155aba0fe49SCalvin	    node->errors[i0 ==
156aba0fe49SCalvin			 SPARSE_VEC_INVALID_INDEX ? PPP_ERROR_UNKNOWN_PROTOCOL
157aba0fe49SCalvin			 : PPP_ERROR_NONE];
158aba0fe49SCalvin	  b1->error =
159aba0fe49SCalvin	    node->errors[i1 ==
160aba0fe49SCalvin			 SPARSE_VEC_INVALID_INDEX ? PPP_ERROR_UNKNOWN_PROTOCOL
161aba0fe49SCalvin			 : PPP_ERROR_NONE];
162cb9cadadSEd Warnicke
163aba0fe49SCalvin	  enqueue_code = (i0 != i_next) + 2 * (i1 != i_next);
164cb9cadadSEd Warnicke
165cb9cadadSEd Warnicke	  if (PREDICT_FALSE (enqueue_code != 0))
166cb9cadadSEd Warnicke	    {
167cb9cadadSEd Warnicke	      switch (enqueue_code)
168cb9cadadSEd Warnicke		{
169cb9cadadSEd Warnicke		case 1:
170cb9cadadSEd Warnicke		  /* A B A */
171cb9cadadSEd Warnicke		  to_next[-2] = bi1;
172cb9cadadSEd Warnicke		  to_next -= 1;
173cb9cadadSEd Warnicke		  n_left_to_next += 1;
174aba0fe49SCalvin		  vlib_set_next_frame_buffer (vm, node,
175aba0fe49SCalvin					      vec_elt (rt->next_by_protocol,
176aba0fe49SCalvin						       i0), bi0);
177cb9cadadSEd Warnicke		  break;
178cb9cadadSEd Warnicke
179cb9cadadSEd Warnicke		case 2:
180cb9cadadSEd Warnicke		  /* A A B */
181cb9cadadSEd Warnicke		  to_next -= 1;
182cb9cadadSEd Warnicke		  n_left_to_next += 1;
183aba0fe49SCalvin		  vlib_set_next_frame_buffer (vm, node,
184aba0fe49SCalvin					      vec_elt (rt->next_by_protocol,
185aba0fe49SCalvin						       i1), bi1);
186cb9cadadSEd Warnicke		  break;
187cb9cadadSEd Warnicke
188cb9cadadSEd Warnicke		case 3:
189cb9cadadSEd Warnicke		  /* A B B or A B C */
190cb9cadadSEd Warnicke		  to_next -= 2;
191cb9cadadSEd Warnicke		  n_left_to_next += 2;
192aba0fe49SCalvin		  vlib_set_next_frame_buffer (vm, node,
193aba0fe49SCalvin					      vec_elt (rt->next_by_protocol,
194aba0fe49SCalvin						       i0), bi0);
195aba0fe49SCalvin		  vlib_set_next_frame_buffer (vm, node,
196aba0fe49SCalvin					      vec_elt (rt->next_by_protocol,
197aba0fe49SCalvin						       i1), bi1);
198cb9cadadSEd Warnicke		  if (i0 == i1)
199cb9cadadSEd Warnicke		    {
200cb9cadadSEd Warnicke		      vlib_put_next_frame (vm, node, next_index,
201cb9cadadSEd Warnicke					   n_left_to_next);
202cb9cadadSEd Warnicke		      i_next = i1;
203cb9cadadSEd Warnicke		      next_index = vec_elt (rt->next_by_protocol, i_next);
204aba0fe49SCalvin		      vlib_get_next_frame (vm, node, next_index, to_next,
205aba0fe49SCalvin					   n_left_to_next);
206cb9cadadSEd Warnicke		    }
207cb9cadadSEd Warnicke		}
208cb9cadadSEd Warnicke	    }
209cb9cadadSEd Warnicke	}
210aba0fe49SCalvin
211cb9cadadSEd Warnicke      while (n_left_from > 0 && n_left_to_next > 0)
212cb9cadadSEd Warnicke	{
213cb9cadadSEd Warnicke	  u32 bi0;
214aba0fe49SCalvin	  vlib_buffer_t *b0;
215aba0fe49SCalvin	  ppp_header_t *h0;
216cb9cadadSEd Warnicke	  u32 i0, protocol0;
217cb9cadadSEd Warnicke
218cb9cadadSEd Warnicke	  bi0 = from[0];
219cb9cadadSEd Warnicke	  to_next[0] = bi0;
220cb9cadadSEd Warnicke	  from += 1;
221cb9cadadSEd Warnicke	  to_next += 1;
222cb9cadadSEd Warnicke	  n_left_from -= 1;
223cb9cadadSEd Warnicke	  n_left_to_next -= 1;
224cb9cadadSEd Warnicke
225cb9cadadSEd Warnicke	  b0 = vlib_get_buffer (vm, bi0);
226cb9cadadSEd Warnicke
2277107d7efSZhiyong Yang	  h0 = vlib_buffer_get_current (b0);
228cb9cadadSEd Warnicke
2297107d7efSZhiyong Yang	  vlib_buffer_advance (b0, sizeof (ppp_header_t));
230cb9cadadSEd Warnicke
231cb9cadadSEd Warnicke	  protocol0 = h0->protocol;
232cb9cadadSEd Warnicke	  i0 = sparse_vec_index (rt->next_by_protocol, protocol0);
233cb9cadadSEd Warnicke
234aba0fe49SCalvin	  b0->error =
235aba0fe49SCalvin	    node->errors[i0 ==
236aba0fe49SCalvin			 SPARSE_VEC_INVALID_INDEX ? PPP_ERROR_UNKNOWN_PROTOCOL
237aba0fe49SCalvin			 : PPP_ERROR_NONE];
238aba0fe49SCalvin
239cb9cadadSEd Warnicke	  /* Sent packet to wrong next? */
240cb9cadadSEd Warnicke	  if (PREDICT_FALSE (i0 != i_next))
241cb9cadadSEd Warnicke	    {
242cb9cadadSEd Warnicke	      /* Return old frame; remove incorrectly enqueued packet. */
243cb9cadadSEd Warnicke	      vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);
244cb9cadadSEd Warnicke
245cb9cadadSEd Warnicke	      /* Send to correct next. */
246cb9cadadSEd Warnicke	      i_next = i0;
247cb9cadadSEd Warnicke	      next_index = vec_elt (rt->next_by_protocol, i_next);
248cb9cadadSEd Warnicke	      vlib_get_next_frame (vm, node, next_index,
249cb9cadadSEd Warnicke				   to_next, n_left_to_next);
250cb9cadadSEd Warnicke	      to_next[0] = bi0;
251cb9cadadSEd Warnicke	      to_next += 1;
252cb9cadadSEd Warnicke	      n_left_to_next -= 1;
253cb9cadadSEd Warnicke	    }
254cb9cadadSEd Warnicke	}
255cb9cadadSEd Warnicke
256cb9cadadSEd Warnicke      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
257cb9cadadSEd Warnicke    }
258cb9cadadSEd Warnicke
259cb9cadadSEd Warnicke  return from_frame->n_vectors;
260cb9cadadSEd Warnicke}
261cb9cadadSEd Warnicke
262aba0fe49SCalvinstatic char *ppp_error_strings[] = {
263cb9cadadSEd Warnicke#define ppp_error(n,s) s,
264cb9cadadSEd Warnicke#include "error.def"
265cb9cadadSEd Warnicke#undef ppp_error
266cb9cadadSEd Warnicke};
267cb9cadadSEd Warnicke
268aba0fe49SCalvin/* *INDENT-OFF* */
269cb9cadadSEd WarnickeVLIB_REGISTER_NODE (ppp_input_node) = {
270cb9cadadSEd Warnicke  .function = ppp_input,
271cb9cadadSEd Warnicke  .name = "ppp-input",
272cb9cadadSEd Warnicke  /* Takes a vector of packets. */
273cb9cadadSEd Warnicke  .vector_size = sizeof (u32),
274cb9cadadSEd Warnicke
275cb9cadadSEd Warnicke  .runtime_data_bytes = sizeof (ppp_input_runtime_t),
276cb9cadadSEd Warnicke
277cb9cadadSEd Warnicke  .n_errors = PPP_N_ERROR,
278cb9cadadSEd Warnicke  .error_strings = ppp_error_strings,
279cb9cadadSEd Warnicke
280cb9cadadSEd Warnicke  .n_next_nodes = PPP_INPUT_N_NEXT,
281cb9cadadSEd Warnicke  .next_nodes = {
282cb9cadadSEd Warnicke#define _(s,n) [PPP_INPUT_NEXT_##s] = n,
283cb9cadadSEd Warnicke    foreach_ppp_input_next
284cb9cadadSEd Warnicke#undef _
285cb9cadadSEd Warnicke  },
286cb9cadadSEd Warnicke
287cb9cadadSEd Warnicke  .format_buffer = format_ppp_header_with_length,
288cb9cadadSEd Warnicke  .format_trace = format_ppp_input_trace,
289cb9cadadSEd Warnicke  .unformat_buffer = unformat_ppp_header,
290cb9cadadSEd Warnicke};
291aba0fe49SCalvin/* *INDENT-ON* */
292cb9cadadSEd Warnicke
293aba0fe49SCalvinstatic clib_error_t *
294e9f929b5SDamjan Marionppp_input_runtime_init (vlib_main_t * vm)
295cb9cadadSEd Warnicke{
296aba0fe49SCalvin  ppp_input_runtime_t *rt;
297cb9cadadSEd Warnicke
298cb9cadadSEd Warnicke  rt = vlib_node_get_runtime_data (vm, ppp_input_node.index);
299cb9cadadSEd Warnicke
300cb9cadadSEd Warnicke  rt->next_by_protocol = sparse_vec_new
301aba0fe49SCalvin    ( /* elt bytes */ sizeof (rt->next_by_protocol[0]),
302cb9cadadSEd Warnicke     /* bits in index */ BITS (((ppp_header_t *) 0)->protocol));
303cb9cadadSEd Warnicke
304cb9cadadSEd Warnicke  vec_validate (rt->sparse_index_by_next_index, PPP_INPUT_NEXT_DROP);
305cb9cadadSEd Warnicke  vec_validate (rt->sparse_index_by_next_index, PPP_INPUT_NEXT_PUNT);
306cb9cadadSEd Warnicke  rt->sparse_index_by_next_index[PPP_INPUT_NEXT_DROP]
307cb9cadadSEd Warnicke    = SPARSE_VEC_INVALID_INDEX;
308cb9cadadSEd Warnicke  rt->sparse_index_by_next_index[PPP_INPUT_NEXT_PUNT]
309cb9cadadSEd Warnicke    = SPARSE_VEC_INVALID_INDEX;
310cb9cadadSEd Warnicke
311cb9cadadSEd Warnicke  return 0;
312cb9cadadSEd Warnicke}
313cb9cadadSEd Warnicke
314e9f929b5SDamjan Marionstatic clib_error_t *
315e9f929b5SDamjan Marionppp_input_init (vlib_main_t * vm)
316e9f929b5SDamjan Marion{
317e9f929b5SDamjan Marion
318e9f929b5SDamjan Marion  {
319e9f929b5SDamjan Marion    clib_error_t *error = vlib_call_init_function (vm, ppp_init);
320e9f929b5SDamjan Marion    if (error)
321e9f929b5SDamjan Marion      clib_error_report (error);
322e9f929b5SDamjan Marion  }
323e9f929b5SDamjan Marion
324e9f929b5SDamjan Marion  ppp_setup_node (vm, ppp_input_node.index);
325e9f929b5SDamjan Marion  ppp_input_runtime_init (vm);
326e9f929b5SDamjan Marion
327e9f929b5SDamjan Marion  return 0;
328e9f929b5SDamjan Marion}
329e9f929b5SDamjan Marion
330cb9cadadSEd WarnickeVLIB_INIT_FUNCTION (ppp_input_init);
331e9f929b5SDamjan MarionVLIB_WORKER_INIT_FUNCTION (ppp_input_runtime_init);
332cb9cadadSEd Warnicke
333cb9cadadSEd Warnickevoid
334cb9cadadSEd Warnickeppp_register_input_protocol (vlib_main_t * vm,
335aba0fe49SCalvin			     ppp_protocol_t protocol, u32 node_index)
336cb9cadadSEd Warnicke{
337aba0fe49SCalvin  ppp_main_t *em = &ppp_main;
338aba0fe49SCalvin  ppp_protocol_info_t *pi;
339aba0fe49SCalvin  ppp_input_runtime_t *rt;
340aba0fe49SCalvin  u16 *n;
341cb9cadadSEd Warnicke  u32 i;
342cb9cadadSEd Warnicke
343cb9cadadSEd Warnicke  {
344aba0fe49SCalvin    clib_error_t *error = vlib_call_init_function (vm, ppp_input_init);
345cb9cadadSEd Warnicke    if (error)
346cb9cadadSEd Warnicke      clib_error_report (error);
347cb9cadadSEd Warnicke  }
348cb9cadadSEd Warnicke
349cb9cadadSEd Warnicke  pi = ppp_get_protocol_info (em, protocol);
350cb9cadadSEd Warnicke  pi->node_index = node_index;
351aba0fe49SCalvin  pi->next_index = vlib_node_add_next (vm, ppp_input_node.index, node_index);
352cb9cadadSEd Warnicke
353cb9cadadSEd Warnicke  /* Setup ppp protocol -> next index sparse vector mapping. */
354cb9cadadSEd Warnicke  rt = vlib_node_get_runtime_data (vm, ppp_input_node.index);
355aba0fe49SCalvin  n =
356aba0fe49SCalvin    sparse_vec_validate (rt->next_by_protocol,
357aba0fe49SCalvin			 clib_host_to_net_u16 (protocol));
358cb9cadadSEd Warnicke  n[0] = pi->next_index;
359cb9cadadSEd Warnicke
360cb9cadadSEd Warnicke  /* Rebuild next index -> sparse index inverse mapping when sparse vector
361cb9cadadSEd Warnicke     is updated. */
362cb9cadadSEd Warnicke  vec_validate (rt->sparse_index_by_next_index, pi->next_index);
363cb9cadadSEd Warnicke  for (i = 1; i < vec_len (rt->next_by_protocol); i++)
364cb9cadadSEd Warnicke    rt->sparse_index_by_next_index[rt->next_by_protocol[i]] = i;
365cb9cadadSEd Warnicke}
366aba0fe49SCalvin
367aba0fe49SCalvin/*
368aba0fe49SCalvin * fd.io coding-style-patch-verification: ON
369aba0fe49SCalvin *
370aba0fe49SCalvin * Local Variables:
371aba0fe49SCalvin * eval: (c-set-style "gnu")
372aba0fe49SCalvin * End:
373aba0fe49SCalvin */
374