FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
sctp.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 SUSE LLC.
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 #include <vnet/plugin/plugin.h>
17 #include <vpp/app/version.h>
18 
19 #include <sctp/sctp.h>
20 #include <sctp/sctp_debug.h>
21 
23 
24 static u32
26 {
27  sctp_main_t *tm = &sctp_main;
29  void *iface_ip;
30  u32 mtu = 1460;
31 
32  pool_get (tm->listener_pool, listener);
33  clib_memset (listener, 0, sizeof (*listener));
34 
35  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
37  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
38  listener - tm->listener_pool;
39  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_port = tep->port;
40 
41  /* If we are provided a sw_if_index, bind using one of its IPs */
42  if (ip_is_zero (&tep->ip, 1) && tep->sw_if_index != ENDPOINT_INVALID_INDEX)
43  {
44  if ((iface_ip = ip_interface_get_first_ip (tep->sw_if_index,
45  tep->is_ip4)))
46  ip_set (&tep->ip, iface_ip, tep->is_ip4);
47  }
48  ip_copy (&listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_ip,
49  &tep->ip, tep->is_ip4);
50 
51  if (tep->sw_if_index != ENDPOINT_INVALID_INDEX)
52  mtu = tep->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
53  tep->sw_if_index,
54  VNET_MTU_IP4) :
55  vnet_sw_interface_get_mtu (vnet_get_main (), tep->sw_if_index,
56  VNET_MTU_IP6);
57 
58  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].PMTU = mtu;
59  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.is_ip4 = tep->is_ip4;
60  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.proto =
61  TRANSPORT_PROTO_SCTP;
62  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_s_index = session_index;
63  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.fib_index =
64  tep->fib_index;
65  listener->state = SCTP_STATE_CLOSED;
66 
67  sctp_connection_timers_init (listener);
68 
69  return listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index;
70 }
71 
72 u32
74 {
75  return sctp_connection_bind (session_index, tep);
76 }
77 
78 static void
79 sctp_connection_unbind (u32 listener_index)
80 {
82  sctp_connection_t *sctp_conn;
83 
84  sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
85 
86  /* Poison the entry */
87  if (CLIB_DEBUG > 0)
88  clib_memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
89 
90  pool_put_index (tm->listener_pool, listener_index);
91 }
92 
93 u32
94 sctp_session_unbind (u32 listener_index)
95 {
96  sctp_connection_unbind (listener_index);
97  return 0;
98 }
99 
100 void
101 sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
102 {
103  sctp_main_t *tm = &sctp_main;
104  if (is_ip4)
105  tm->punt_unknown4 = is_add;
106  else
107  tm->punt_unknown6 = is_add;
108 }
109 
110 static int
111 sctp_alloc_custom_local_endpoint (sctp_main_t * tm, ip46_address_t * lcl_addr,
112  u16 * lcl_port, u8 is_ip4)
113 {
114  int index, port;
115  if (is_ip4)
116  {
117  index = tm->last_v4_address_rotor++;
118  if (tm->last_v4_address_rotor >= vec_len (tm->ip4_src_addresses))
119  tm->last_v4_address_rotor = 0;
120  lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
121  }
122  else
123  {
124  index = tm->last_v6_address_rotor++;
125  if (tm->last_v6_address_rotor >= vec_len (tm->ip6_src_addresses))
126  tm->last_v6_address_rotor = 0;
127  clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
128  sizeof (ip6_address_t));
129  }
130  port = transport_alloc_local_port (TRANSPORT_PROTO_SCTP, lcl_addr);
131  if (port < 1)
132  {
133  clib_warning ("Failed to allocate src port");
134  return -1;
135  }
136  *lcl_port = port;
137  return 0;
138 }
139 
140 /**
141  * Initialize all connection timers as invalid
142  */
143 void
145 {
146  int i, j;
147 
148  /* Set all to invalid */
149  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
150  {
151  sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
152 
153  for (j = 0; j < SCTP_N_TIMERS; j++)
154  {
155  sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
156  }
157  }
158 }
159 
160 /**
161  * Stop all connection timers
162  */
163 void
165 {
166  int i, j;
167  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
168  {
169  for (j = 0; j < SCTP_N_TIMERS; j++)
170  sctp_timer_reset (sctp_conn, i, j);
171  }
172 }
173 
174 const char *sctp_fsm_states[] = {
175 #define _(sym, str) str,
177 #undef _
178 };
179 
180 u8 *
181 format_sctp_state (u8 * s, va_list * args)
182 {
183  u32 state = va_arg (*args, u32);
184 
185  if (state < SCTP_N_STATES)
186  s = format (s, "%s", sctp_fsm_states[state]);
187  else
188  s = format (s, "UNKNOWN (%d (0x%x))", state, state);
189  return s;
190 }
191 
192 u8 *
193 format_sctp_connection_id (u8 * s, va_list * args)
194 {
195  sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
196  if (!sctp_conn)
197  return s;
198 
199  u8 i;
200  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
201  {
202  if (i > 0 && sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
203  continue;
204  if (sctp_conn->sub_conn[i].connection.is_ip4)
205  {
206  s = format (s, "[#%d][%s] %U:%d->%U:%d",
207  sctp_conn->sub_conn[i].connection.thread_index,
208  "S",
210  &sctp_conn->sub_conn[i].connection.lcl_ip.ip4,
211  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
212  connection.lcl_port),
214  &sctp_conn->sub_conn[i].connection.rmt_ip.ip4,
215  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
216  connection.rmt_port));
217  }
218  else
219  {
220  s = format (s, "[#%d][%s] %U:%d->%U:%d",
221  sctp_conn->sub_conn[i].connection.thread_index,
222  "S",
224  &sctp_conn->sub_conn[i].connection.lcl_ip.ip6,
225  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
226  connection.lcl_port),
228  &sctp_conn->sub_conn[i].connection.rmt_ip.ip6,
229  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
230  connection.rmt_port));
231  }
232  }
233  return s;
234 }
235 
236 u8 *
237 format_sctp_connection (u8 * s, va_list * args)
238 {
239  sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
240  u32 verbose = va_arg (*args, u32);
241 
242  if (!sctp_conn)
243  return s;
244  s = format (s, "%-50U", format_sctp_connection_id, sctp_conn);
245  if (verbose)
246  {
247  s = format (s, "%-15U", format_sctp_state, sctp_conn->state);
248  if (verbose > 1)
249  s = format (s, "\n");
250  }
251 
252  return s;
253 }
254 
255 /**
256  * Initialize connection send variables.
257  */
258 void
260 {
261  u32 time_now;
262  /*
263  * We use the time to randomize iss and for setting up the initial
264  * timestamp. Make sure it's updated otherwise syn and ack in the
265  * handshake may make it look as if time has flown in the opposite
266  * direction for us.
267  */
268 
270  time_now = sctp_time_now ();
271 
272  sctp_conn->local_initial_tsn = random_u32 (&time_now);
273  sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
274  sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
275 
276  sctp_conn->remote_initial_tsn = 0x0;
277  sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
278 }
279 
282 {
284  sctp_connection_t *sctp_conn = tm->connections[thread_index];
285 
286  u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
287 
288  ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS);
289 
290  sctp_conn->sub_conn[subconn_idx].connection.c_index =
291  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index;
292  sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
293  sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
294 
295  return sctp_conn;
296 }
297 
298 u8
300  ip4_address_t * lcl_addr,
301  ip4_address_t * rmt_addr)
302 {
304 
305  u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
306 
307  if (subconn_idx == MAX_SCTP_CONNECTIONS)
308  return SCTP_ERROR_MAX_CONNECTIONS;
309 
310  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
311  &lcl_addr, sizeof (lcl_addr));
312 
313  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
314  &rmt_addr, sizeof (rmt_addr));
315 
316  sctp_conn->forming_association_changed = 1;
317 
318  return SCTP_ERROR_NONE;
319 }
320 
321 u8
323  ip4_address_t * rmt_addr)
324 {
326 
327  u32 thread_idx = vlib_get_thread_index ();
328  u8 i;
329 
330  ASSERT (thread_idx == 0);
331 
332  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
333  {
334  sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
335  sctp_sub_connection_t *sub_conn =
336  &sctp_main->connections[thread_idx]->sub_conn[i];
337  ip46_address_t *lcl_ip =
338  &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
339  ip46_address_t *rmt_ip =
340  &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
341 
342  if (!sub_conn->connection.is_ip4)
343  continue;
344  if (lcl_ip->ip4.as_u32 == lcl_addr->as_u32 &&
345  rmt_ip->ip4.as_u32 == rmt_addr->as_u32)
346  {
347  sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
348  sctp_conn->forming_association_changed = 1;
349  break;
350  }
351  }
352  return SCTP_ERROR_NONE;
353 }
354 
355 u8
357  ip6_address_t * lcl_addr,
358  ip6_address_t * rmt_addr)
359 {
361 
362  u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
363 
364  if (subconn_idx == MAX_SCTP_CONNECTIONS)
365  return SCTP_ERROR_MAX_CONNECTIONS;
366 
367  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
368  &lcl_addr, sizeof (lcl_addr));
369 
370  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
371  &rmt_addr, sizeof (rmt_addr));
372 
373  sctp_conn->forming_association_changed = 1;
374 
375  return SCTP_ERROR_NONE;
376 }
377 
378 u8
380  ip6_address_t * rmt_addr)
381 {
383 
384  u32 thread_idx = vlib_get_thread_index ();
385  u8 i;
386 
387  ASSERT (thread_idx == 0);
388 
389  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
390  {
391  sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
392  sctp_sub_connection_t *sub_conn =
393  &sctp_main->connections[thread_idx]->sub_conn[i];
394  ip46_address_t *lcl_ip =
395  &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
396  ip46_address_t *rmt_ip =
397  &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
398 
399  if (!sub_conn->connection.is_ip4)
400  continue;
401  if ((lcl_ip->ip6.as_u64[0] == lcl_addr->as_u64[0]
402  && lcl_ip->ip6.as_u64[1] == lcl_addr->as_u64[1])
403  && (rmt_ip->ip6.as_u64[0] == rmt_addr->as_u64[0]
404  && rmt_ip->ip6.as_u64[1] == rmt_addr->as_u64[1]))
405  {
406  sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
407  sctp_conn->forming_association_changed = 1;
408  break;
409  }
410  }
411  return SCTP_ERROR_NONE;
412 }
413 
414 u8
416 {
418 
419  u32 thread_idx = vlib_get_thread_index ();
420 
421  sctp_main->connections[thread_idx]->conn_config.never_delay_sack =
422  config.never_delay_sack;
423  sctp_main->connections[thread_idx]->conn_config.never_bundle =
424  config.never_bundle;
425 
426  return 0;
427 }
428 
430 sctp_connection_new (u8 thread_index)
431 {
433  sctp_connection_t *sctp_conn;
434 
435  pool_get (sctp_main->connections[thread_index], sctp_conn);
436  clib_memset (sctp_conn, 0, sizeof (*sctp_conn));
437  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
439  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
440  sctp_conn - sctp_main->connections[thread_index];
441  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_thread_index = thread_index;
442  sctp_conn->local_tag = 0;
443 
444  return sctp_conn;
445 }
446 
449 {
451  sctp_connection_t *sctp_conn = 0;
452  ASSERT (vlib_get_thread_index () == 0);
453  pool_get (tm->half_open_connections, sctp_conn);
454  clib_memset (sctp_conn, 0, sizeof (*sctp_conn));
455  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
456  sctp_conn - tm->half_open_connections;
457  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
459  return sctp_conn;
460 }
461 
462 static inline int
464 {
466  sctp_connection_t *sctp_conn;
467  ip46_address_t lcl_addr;
468  u16 lcl_port;
469  uword thread_id;
470  u32 mtu = 1460;
471  int rv;
472 
474 
475  /*
476  * Allocate local endpoint
477  */
478  if ((rmt->is_ip4 && vec_len (tm->ip4_src_addresses))
479  || (!rmt->is_ip4 && vec_len (tm->ip6_src_addresses)))
480  rv = sctp_alloc_custom_local_endpoint (tm, &lcl_addr, &lcl_port,
481  rmt->is_ip4);
482  else
483  rv = transport_alloc_local_endpoint (TRANSPORT_PROTO_SCTP,
484  rmt, &lcl_addr, &lcl_port);
485 
486  if (rv)
487  return -1;
488 
489  /*
490  * Create connection and send INIT CHUNK
491  */
492  thread_id = vlib_get_thread_index ();
493  ASSERT (thread_id == 0);
494 
495  clib_spinlock_lock_if_init (&tm->half_open_lock);
496  sctp_conn = sctp_half_open_connection_new (thread_id);
497  if (rmt->peer.sw_if_index != ENDPOINT_INVALID_INDEX)
498  mtu = rmt->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
499  rmt->peer.sw_if_index,
500  VNET_MTU_IP4) :
501  vnet_sw_interface_get_mtu (vnet_get_main (), rmt->peer.sw_if_index,
502  VNET_MTU_IP6);
503  sctp_conn->sub_conn[idx].PMTU = mtu;
504 
505  transport_connection_t *trans_conn = &sctp_conn->sub_conn[idx].connection;
506  ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
507  ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
508  sctp_conn->sub_conn[idx].subconn_idx = idx;
509  trans_conn->rmt_port = rmt->port;
510  trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
511  trans_conn->is_ip4 = rmt->is_ip4;
512  trans_conn->proto = TRANSPORT_PROTO_SCTP;
513  trans_conn->fib_index = rmt->fib_index;
514 
515  sctp_connection_timers_init (sctp_conn);
516  /* The other connection vars will be initialized after INIT_ACK chunk received */
517  sctp_init_snd_vars (sctp_conn);
518 
519  sctp_send_init (sctp_conn);
520 
521  clib_spinlock_unlock_if_init (&tm->half_open_lock);
522 
523  return sctp_conn->sub_conn[idx].connection.c_index;
524 }
525 
526 /**
527  * Cleans up connection state.
528  *
529  * No notifications.
530  */
531 void
533 {
534  sctp_main_t *tm = &sctp_main;
535  u8 i;
536 
537  /* Cleanup local endpoint if this was an active connect */
538  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
539  transport_endpoint_cleanup (TRANSPORT_PROTO_SCTP,
540  &sctp_conn->sub_conn[i].connection.lcl_ip,
541  sctp_conn->sub_conn[i].connection.lcl_port);
542 
543  int thread_index =
544  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.thread_index;
545 
546  /* Make sure all timers are cleared */
547  sctp_connection_timers_reset (sctp_conn);
548 
549  /* Poison the entry */
550  if (CLIB_DEBUG > 0)
551  clib_memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
552  pool_put (tm->connections[thread_index], sctp_conn);
553 }
554 
555 int
557 {
558  return sctp_connection_open (tep);
559 }
560 
561 u16
563 {
564  u8 i;
565  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
566  {
567  if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
568  continue;
569 
570  if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
571  sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
572  {
574  ("Connection %u has still DATA to be enqueued inboud / outboud",
575  sctp_conn->sub_conn[i].connection.c_index);
576  return 1;
577  }
578 
579  }
580  return 0; /* Indicates no more data to be read/sent */
581 }
582 
583 void
585 {
586  SCTP_DBG ("Closing connection %u...",
587  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index);
588 
589  sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
590 
591  sctp_send_shutdown (sctp_conn);
592 }
593 
594 void
595 sctp_session_close (u32 conn_index, u32 thread_index)
596 {
597  ASSERT (thread_index == 0);
598 
599  sctp_connection_t *sctp_conn =
600  sctp_connection_get (conn_index, thread_index);
601  if (sctp_conn != NULL)
602  sctp_connection_close (sctp_conn);
603 }
604 
605 void
606 sctp_session_cleanup (u32 conn_index, u32 thread_index)
607 {
608  sctp_connection_t *sctp_conn =
609  sctp_connection_get (conn_index, thread_index);
610 
611  if (sctp_conn != NULL)
612  {
613  sctp_connection_timers_reset (sctp_conn);
614  /* Wait for the session tx events to clear */
615  sctp_conn->state = SCTP_STATE_CLOSED;
616  }
617 }
618 
619 /**
620  * Compute maximum segment size for session layer.
621  */
622 u16
624 {
625  sctp_connection_t *sctp_conn =
627 
628  if (sctp_conn == NULL)
629  {
630  SCTP_DBG ("sctp_conn == NULL");
631  return 0;
632  }
633 
634  update_cwnd (sctp_conn);
635  update_smallest_pmtu_idx (sctp_conn);
636 
637  u8 idx = sctp_data_subconn_select (sctp_conn);
638  return sctp_conn->sub_conn[idx].cwnd;
639 }
640 
641 u16
643 {
644  /* RFC 4096 Section 6.1; point (A) */
645  if (sctp_conn->peer_rwnd == 0)
646  return 0;
647 
648  u8 idx = sctp_data_subconn_select (sctp_conn);
649 
650  u32 available_wnd =
651  clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
652  int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
653 
654  if (available_wnd <= flight_size)
655  return 0;
656 
657  /* Finally, let's subtract the DATA chunk headers overhead */
658  return available_wnd -
659  flight_size -
660  sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
661 }
662 
663 /**
664  * Compute TX window session is allowed to fill.
665  */
666 u32
668 {
669  sctp_connection_t *sctp_conn =
671 
672  return sctp_snd_space (sctp_conn);
673 }
674 
676 sctp_session_get_transport (u32 conn_index, u32 thread_index)
677 {
678  sctp_connection_t *sctp_conn =
679  sctp_connection_get (conn_index, thread_index);
680 
681  if (PREDICT_TRUE (sctp_conn != NULL))
682  return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
683 
684  return NULL;
685 }
686 
689 {
691  sctp_connection_t *sctp_conn;
692  sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
693  return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
694 }
695 
696 u8 *
697 format_sctp_session (u8 * s, va_list * args)
698 {
699  u32 tci = va_arg (*args, u32);
700  u32 thread_index = va_arg (*args, u32);
701  u32 verbose = va_arg (*args, u32);
702  sctp_connection_t *tc;
703 
704  tc = sctp_connection_get (tci, thread_index);
705  if (tc)
706  s = format (s, "%U", format_sctp_connection, tc, verbose);
707  else
708  s = format (s, "empty\n");
709  return s;
710 }
711 
712 u8 *
713 format_sctp_listener_session (u8 * s, va_list * args)
714 {
715  u32 tci = va_arg (*args, u32);
716  u32 __clib_unused thread_index = va_arg (*args, u32);
718  return format (s, "%U", format_sctp_connection_id, tc);
719 }
720 
721 void
722 sctp_expired_timers_cb (u32 conn_index, u32 timer_id)
723 {
724  sctp_connection_t *sctp_conn;
725 
726  SCTP_DBG ("%s expired", sctp_timer_to_string (timer_id));
727 
728  sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
729  /* note: the connection may have already disappeared */
730  if (PREDICT_FALSE (sctp_conn == 0))
731  return;
732 
733  if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
735  {
736  // The remote-peer is considered to be unreachable hence shutting down
737  u8 i, total_subs_down = 1;
738  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
739  {
740  if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
741  continue;
742 
743  u32 now = sctp_time_now ();
744  if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
745  {
746  total_subs_down += 1;
747  sctp_conn->sub_conn[i].state = SCTP_SUBCONN_STATE_DOWN;
748  }
749  }
750 
751  if (total_subs_down == MAX_SCTP_CONNECTIONS)
752  {
753  /* Start cleanup. App wasn't notified yet so use delete notify as
754  * opposed to delete to cleanup session layer state. */
755  session_transport_delete_notify (&sctp_conn->sub_conn
756  [SCTP_PRIMARY_PATH_IDX].connection);
757 
758  sctp_connection_timers_reset (sctp_conn);
759 
760  sctp_connection_cleanup (sctp_conn);
761  }
762  return;
763  }
764 
765  switch (timer_id)
766  {
767  case SCTP_TIMER_T1_INIT:
768  sctp_send_init (sctp_conn);
769  break;
770  case SCTP_TIMER_T1_COOKIE:
771  sctp_send_cookie_echo (sctp_conn);
772  break;
773  case SCTP_TIMER_T2_SHUTDOWN:
774  sctp_send_shutdown (sctp_conn);
775  break;
776  case SCTP_TIMER_T3_RXTX:
777  sctp_timer_reset (sctp_conn, conn_index, timer_id);
778  sctp_conn->flags |= SCTP_CONN_RECOVERY;
779  sctp_data_retransmit (sctp_conn);
780  break;
781  case SCTP_TIMER_T4_HEARTBEAT:
782  sctp_timer_reset (sctp_conn, conn_index, timer_id);
783  goto heartbeat;
784  }
785  return;
786 
787 heartbeat:
788  sctp_send_heartbeat (sctp_conn);
789 }
790 
791 static void
793 {
794  int i;
795  u32 connection_index, timer_id;
796 
797  for (i = 0; i < vec_len (expired_timers); i++)
798  {
799  /* Get session index and timer id */
800  connection_index = expired_timers[i] & 0x0FFFFFFF;
801  timer_id = expired_timers[i] >> 28;
802 
803  SCTP_DBG ("Expired timer ID: %u", timer_id);
804 
805  /* Handle expiration */
806  sctp_expired_timers_cb (connection_index, timer_id);
807  }
808 }
809 
810 void
812 {
813  tw_timer_wheel_16t_2w_512sl_t *tw;
814  /* *INDENT-OFF* */
816  tw = &tm->timer_wheels[ii];
817  tw_timer_wheel_init_16t_2w_512sl (tw, sctp_expired_timers_dispatch,
818  100e-3 /* timer period 100ms */ , ~0);
819  tw->last_run_time = vlib_time_now (this_vlib_main);
820  }));
821  /* *INDENT-ON* */
822 }
823 
824 clib_error_t *
826 {
829  clib_error_t *error = 0;
830  u32 num_threads;
831  int thread;
832  sctp_connection_t *sctp_conn __attribute__ ((unused));
833  u32 preallocated_connections_per_thread;
834 
835  if ((error = vlib_call_init_function (vm, ip_main_init)))
836  return error;
837  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
838  return error;
839  if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
840  return error;
841 
842  /*
843  * Registrations
844  */
845 
848 
849  /*
850  * Initialize data structures
851  */
852 
853  num_threads = 1 /* main thread */ + vtm->n_threads;
854  vec_validate (tm->connections, num_threads - 1);
855 
856  /*
857  * Preallocate connections. Assume that thread 0 won't
858  * use preallocated threads when running multi-core
859  */
860  if (num_threads == 1)
861  {
862  thread = 0;
863  preallocated_connections_per_thread = tm->preallocated_connections;
864  }
865  else
866  {
867  thread = 1;
868  preallocated_connections_per_thread =
869  tm->preallocated_connections / (num_threads - 1);
870  }
871  for (; thread < num_threads; thread++)
872  {
873  if (preallocated_connections_per_thread)
874  pool_init_fixed (tm->connections[thread],
875  preallocated_connections_per_thread);
876  }
877 
878  /* Initialize per worker thread tx buffers (used for control messages) */
879  vec_validate (tm->tx_buffers, num_threads - 1);
880 
881  /* Initialize timer wheels */
882  vec_validate (tm->timer_wheels, num_threads - 1);
884 
885  /* Initialize clocks per tick for SCTP timestamp. Used to compute
886  * monotonically increasing timestamps. */
887  tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
889 
890  if (num_threads > 1)
891  {
892  clib_spinlock_init (&tm->half_open_lock);
893  }
894 
895  vec_validate (tm->tx_frames[0], num_threads - 1);
896  vec_validate (tm->tx_frames[1], num_threads - 1);
897  vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
898  vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
899 
900  tm->bytes_per_buffer = vlib_buffer_get_default_data_size (vm);
901 
902  vec_validate (tm->time_now, num_threads - 1);
903  return error;
904 }
905 
906 clib_error_t *
908 {
909  if (is_en)
910  {
911  if (sctp_main.is_enabled)
912  return 0;
913 
914  return sctp_main_enable (vm);
915  }
916  else
917  {
918  sctp_main.is_enabled = 0;
919  }
920 
921  return 0;
922 }
923 
926 {
927  sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
928  return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
929 }
930 
931 u8 *
932 format_sctp_half_open (u8 * s, va_list * args)
933 {
934  u32 tci = va_arg (*args, u32);
935  u32 __clib_unused thread_index = va_arg (*args, u32);
937  return format (s, "%U", format_sctp_connection_id, sctp_conn);
938 }
939 
940 void
941 sctp_update_time (f64 now, u8 thread_index)
942 {
943  sctp_set_time_now (thread_index);
944  tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
945  now);
946  sctp_flush_frames_to_output (thread_index);
947 }
948 
949 /* *INDENT-OFF* */
952  .start_listen = sctp_session_bind,
953  .stop_listen = sctp_session_unbind,
954  .connect = sctp_session_open,
955  .close = sctp_session_close,
956  .cleanup = sctp_session_cleanup,
957  .push_header = sctp_push_header,
958  .send_mss = sctp_session_send_mss,
959  .send_space = sctp_session_send_space,
960  .update_time = sctp_update_time,
961  .get_connection = sctp_session_get_transport,
962  .get_listener = sctp_session_get_listener,
963  .get_half_open = sctp_half_open_session_get_transport,
964  .format_connection = format_sctp_session,
965  .format_listener = format_sctp_listener_session,
966  .format_half_open = format_sctp_half_open,
967  .transport_options = {
968  .tx_type = TRANSPORT_TX_DEQUEUE,
969  .service_type = TRANSPORT_SERVICE_VC,
970  },
971 };
972 /* *INDENT-ON* */
973 
974 clib_error_t *
976 {
978  ip_main_t *im = &ip_main;
979  ip_protocol_info_t *pi;
980  vlib_node_t *node;
981 
982  if (!sm->is_init && is_en)
983  {
984  node = vlib_get_node_by_name (vm, (u8 *) "sctp4-established");
985  sm->sctp4_established_phase_node_index = node->index;
986 
987  node = vlib_get_node_by_name (vm, (u8 *) "sctp6-established");
988  sm->sctp6_established_phase_node_index = node->index;
989 
990  sm->is_init = 1;
991 
992  /* Register with IP for header parsing */
994  if (pi == 0)
995  return clib_error_return (0, "SCTP protocol info AWOL");
998 
999  /* Register as transport with session layer */
1000  transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
1002  transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
1004  }
1005 
1006  sctp_transport_enable_disable (vm, is_en);
1007  return 0;
1008 }
1009 
1010 static u8 *
1012 {
1014 
1015  s = format (s,
1016  "sctp.connection_index: %d, sctp.sid: %d, sctp.ssn: %d, "
1017  "sctp.tsn: %d, sctp.hdr_offset: %d",
1019  (u32) (o->sctp.sid),
1020  (u32) (o->sctp.ssn),
1021  (u32) (o->sctp.tsn), (u32) (o->sctp.hdr_offset));
1022  vec_add1 (s, '\n');
1023 
1024  s = format
1025  (s, "sctp.data_offset: %d, sctp.data_len: %d, sctp.subconn_idx: %d, "
1026  "sctp.flags: 0x%x",
1027  (u32) (o->sctp.data_offset),
1028  (u32) (o->sctp.data_len),
1029  (u32) (o->sctp.subconn_idx), (u32) (o->sctp.flags));
1030  vec_add1 (s, '\n');
1031  return s;
1032 }
1033 
1034 clib_error_t *
1036 {
1038 
1039  /* Session layer, and by implication SCTP, are disabled by default */
1040  sm->is_enabled = 0;
1041  sm->is_init = 0;
1042 
1043  /* initialize binary API */
1045 
1048  return 0;
1049 }
1050 
1052 
1053 static clib_error_t *
1055  vlib_cli_command_t * cmd_arg)
1056 {
1057  sctp_main_t *tm = &sctp_main;
1059  return clib_error_return (0, "unknown input `%U'", format_unformat_error,
1060  input);
1061  vlib_cli_output (vm, "IPv4 UDP punt: %s",
1062  tm->punt_unknown4 ? "enabled" : "disabled");
1063  vlib_cli_output (vm, "IPv6 UDP punt: %s",
1064  tm->punt_unknown6 ? "enabled" : "disabled");
1065  return 0;
1066 }
1067 /* *INDENT-OFF* */
1068 VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
1069 {
1070  .path = "show sctp punt",
1071  .short_help = "show sctp punt",
1072  .function = show_sctp_punt_fn,
1073 };
1074 /* *INDENT-ON* */
1075 
1076 static clib_error_t *
1078  vlib_cli_command_t * cmd_arg)
1079 {
1080  unformat_input_t _line_input, *line_input = &_line_input;
1081  clib_error_t *error;
1082  u8 is_en;
1083 
1084  if (!unformat_user (input, unformat_line_input, line_input))
1085  return clib_error_return (0, "expected enable | disable");
1086 
1087  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1088  {
1089  if (unformat (line_input, "enable"))
1090  is_en = 1;
1091  else if (unformat (line_input, "disable"))
1092  is_en = 0;
1093  else
1094  {
1095  error = clib_error_return (0, "unknown input `%U'",
1096  format_unformat_error, line_input);
1097  unformat_free (line_input);
1098  return error;
1099  }
1100  }
1101 
1102  unformat_free (line_input);
1103 
1104  return sctp_enable_disable (vm, is_en);
1105 }
1106 
1107 /* *INDENT-OFF* */
1108 VLIB_CLI_COMMAND (show_sctp_command, static) =
1109 {
1110  .path = "sctp",
1111  .short_help = "sctp [enable | disable]",
1112  .function = sctp_fn,
1113 };
1114 
1115 /* *INDENT-OFF* */
1117 {
1118  .version = VPP_BUILD_VER,
1119  .description = "Stream Control Transmission Protocol (SCTP)",
1120  .default_disabled = 1,
1121 };
1122 /* *INDENT-ON* */
1123 
1124 /*
1125  * fd.io coding-style-patch-verification: ON
1126  *
1127  * Local Variables:
1128  * eval: (c-set-style "gnu")
1129  * End:
1130  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
static clib_error_t * sctp_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
Definition: sctp.c:1077
void sctp_connection_timers_reset(sctp_connection_t *sctp_conn)
Stop all connection timers.
Definition: sctp.c:164
u16 sctp_check_outstanding_data_chunks(sctp_connection_t *sctp_conn)
Definition: sctp.c:562
struct _sctp_main sctp_main_t
void sctp_connection_timers_init(sctp_connection_t *sctp_conn)
Initialize all connection timers as invalid.
Definition: sctp.c:144
#define ENDPOINT_INVALID_INDEX
static void update_cwnd(sctp_connection_t *sctp_conn)
Definition: sctp.h:968
clib_error_t * sctp_main_enable(vlib_main_t *vm)
Definition: sctp.c:825
clib_error_t * sctp_plugin_api_hookup(vlib_main_t *vm)
Definition: sctp_api.c:119
void sctp_flush_frames_to_output(u8 thread_index)
Flush v4 and v6 sctp and ip-lookup tx frames for thread index.
Definition: sctp_output.c:57
#define clib_min(x, y)
Definition: clib.h:302
#define SCTP_DBG(_fmt, _args...)
Definition: sctp_debug.h:38
static int sctp_alloc_custom_local_endpoint(sctp_main_t *tm, ip46_address_t *lcl_addr, u16 *lcl_port, u8 is_ip4)
Definition: sctp.c:111
void sctp_init_snd_vars(sctp_connection_t *sctp_conn)
Initialize connection send variables.
Definition: sctp.c:259
void ip_copy(ip46_address_t *dst, ip46_address_t *src, u8 is_ip4)
Definition: ip.c:81
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1581
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:1080
transport_connection_t * sctp_half_open_session_get_transport(u32 conn_index)
Definition: sctp.c:925
#define PREDICT_TRUE(x)
Definition: clib.h:113
u64 as_u64[2]
Definition: ip6_packet.h:51
u16 data_len
data len
Definition: sctp.h:36
void sctp_send_init(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1285
struct _sctp_sub_connection sctp_sub_connection_t
void ip_set(ip46_address_t *dst, void *src, u8 is_ip4)
Definition: ip.c:93
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 index
Definition: node.h:280
void session_transport_delete_notify(transport_connection_t *tc)
Notification from transport that connection is being deleted.
Definition: session.c:887
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
static u64 sctp_time_now(void)
Definition: sctp.h:702
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:110
u32 thread_index
Definition: main.h:218
#define foreach_sctp_fsm_state
SSCTP FSM state definitions as per RFC4960.
Definition: sctp.h:373
clib_error_t * sctp_transport_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: sctp.c:907
vlib_node_registration_t sctp6_output_node
(constructor) VLIB_REGISTER_NODE (sctp6_output_node)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
clib_error_t * sctp_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: sctp.c:975
u8 * format_sctp_half_open(u8 *s, va_list *args)
Definition: sctp.c:932
int i
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
u16 sctp_session_send_mss(transport_connection_t *trans_conn)
Compute maximum segment size for session layer.
Definition: sctp.c:623
void * ip_interface_get_first_ip(u32 sw_if_index, u8 is_ip4)
Definition: ip.c:140
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static void update_smallest_pmtu_idx(sctp_connection_t *sctp_conn)
Definition: sctp.h:914
static u32 vnet_sw_interface_get_mtu(vnet_main_t *vnm, u32 sw_if_index, vnet_mtu_t af)
clib_time_t clib_time
Definition: main.h:87
Definition: ip.h:107
u16 data_offset
offset relative to ip hdr
Definition: sctp.h:35
static u32 sctp_connection_bind(u32 session_index, transport_endpoint_t *tep)
Definition: sctp.c:25
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1865
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
struct _sctp_user_configuration sctp_user_configuration_t
u8 sctp_configure(sctp_user_configuration_t config)
Definition: sctp.c:415
unsigned char u8
Definition: types.h:56
void vnet_register_format_buffer_opaque_helper(vnet_buffer_opquae_formatter_t fn)
static sctp_main_t * vnet_get_sctp_main()
Definition: sctp.h:574
double f64
Definition: types.h:142
int sctp_session_open(transport_endpoint_cfg_t *tep)
Definition: sctp.c:556
vlib_node_registration_t sctp6_input_node
(constructor) VLIB_REGISTER_NODE (sctp6_input_node)
Definition: sctp_input.c:2301
#define clib_memcpy(d, s, n)
Definition: string.h:180
#define SCTP_PATH_MAX_RETRANS
Definition: sctp.h:491
sctp_main_t sctp_main
Definition: sctp.c:22
format_function_t format_ip4_address
Definition: format.h:75
unformat_function_t * unformat_pg_edit
Definition: ip.h:88
u8 * format_sctp_listener_session(u8 *s, va_list *args)
Definition: sctp.c:713
u32 sctp_session_unbind(u32 listener_index)
Definition: sctp.c:94
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define always_inline
Definition: clib.h:99
transport_connection_t * sctp_session_get_transport(u32 conn_index, u32 thread_index)
Definition: sctp.c:676
#define clib_error_return(e, args...)
Definition: error.h:99
vhost_vring_state_t state
Definition: vhost_user.h:146
static u8 * sctp_format_buffer_opaque_helper(const vlib_buffer_t *b, u8 *s)
Definition: sctp.c:1011
u8 * format_sctp_session(u8 *s, va_list *args)
Definition: sctp.c:697
static void sctp_connection_unbind(u32 listener_index)
Definition: sctp.c:79
pthread_t thread[MAX_CONNS]
Definition: main.c:142
int transport_alloc_local_endpoint(u8 proto, transport_endpoint_cfg_t *rmt_cfg, ip46_address_t *lcl_addr, u16 *lcl_port)
Definition: transport.c:526
unsigned int u32
Definition: types.h:88
sctp_connection_t * sctp_connection_new(u8 thread_index)
Definition: sctp.c:430
void sctp_session_cleanup(u32 conn_index, u32 thread_index)
Definition: sctp.c:606
#define vlib_call_init_function(vm, x)
Definition: init.h:270
void sctp_data_retransmit(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1493
static int sctp_connection_open(transport_endpoint_cfg_t *rmt)
Definition: sctp.c:463
struct _transport_proto_vft transport_proto_vft_t
unformat_function_t unformat_line_input
Definition: format.h:283
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:63
void sctp_punt_unknown(vlib_main_t *vm, u8 is_ip4, u8 is_add)
Definition: sctp.c:101
u16 sid
Stream ID.
Definition: sctp.h:31
#define SCTP_DBG_OUTPUT(_fmt, _args...)
Definition: sctp_debug.h:52
static void sctp_timer_reset(sctp_connection_t *tc, u8 conn_idx, u8 timer_id)
Definition: sctp.h:642
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
u32 connection_index
Definition: sctp.h:30
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:134
static sctp_connection_t * sctp_get_connection_from_transport(transport_connection_t *tconn)
Definition: sctp.h:683
format_function_t * format_header
Definition: ip.h:79
void sctp_initialize_timer_wheels(sctp_main_t *tm)
Definition: sctp.c:811
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u8 sctp_sub_connection_add_ip4(vlib_main_t *vm, ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
Definition: sctp.c:299
u32 sctp_session_bind(u32 session_index, transport_endpoint_t *tep)
Definition: sctp.c:73
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
#define PREDICT_FALSE(x)
Definition: clib.h:112
struct _sctp_connection sctp_connection_t
u16 port
Definition: punt.api:40
static u64 sctp_set_time_now(u32 thread_index)
Definition: sctp.h:619
f64 seconds_per_clock
Definition: time.h:58
#define SCTP_RTO_INIT
Definition: sctp.h:483
static char * sctp_timer_to_string(u8 timer_id)
Definition: sctp.h:71
u8 * format_sctp_connection_id(u8 *s, va_list *args)
Definition: sctp.c:193
#define foreach_vlib_main(body)
Definition: threads.h:241
#define MAX_SCTP_CONNECTIONS
Definition: sctp.h:106
static clib_error_t * show_sctp_punt_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
Definition: sctp.c:1054
u8 * format_sctp_state(u8 *s, va_list *args)
Definition: sctp.c:181
#define SCTP_TSTAMP_RESOLUTION
Time stamp resolution.
Definition: sctp.h:480
vlib_node_registration_t sctp4_output_node
(constructor) VLIB_REGISTER_NODE (sctp4_output_node)
u32 tsn
Transmission Sequence Number.
Definition: sctp.h:33
static u8 sctp_next_avail_subconn(sctp_connection_t *sctp_conn)
Definition: sctp.h:901
static_always_inline u32 vlib_buffer_get_default_data_size(vlib_main_t *vm)
Definition: buffer_funcs.h:96
u8 sctp_sub_connection_del_ip4(ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
Definition: sctp.c:322
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:218
format_function_t format_ip6_address
Definition: format.h:93
#define sctp_buffer_opaque(b)
Definition: sctp.h:46
vlib_main_t * vm
Definition: buffer.c:323
ip_main_t ip_main
Definition: ip_init.c:42
u8 * format_sctp_connection(u8 *s, va_list *args)
Definition: sctp.c:237
const char * sctp_fsm_states[]
Definition: sctp.c:174
transport_connection_t * sctp_session_get_listener(u32 listener_index)
Definition: sctp.c:688
virtual circuit service
#define IP_PROTOCOL_SCTP
Definition: sctp.h:370
#define clib_warning(format, args...)
Definition: error.h:59
u32 sctp_push_header(transport_connection_t *tconn, vlib_buffer_t *b)
Definition: sctp_output.c:1419
struct _transport_connection transport_connection_t
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
#define pool_init_fixed(pool, max_elts)
initialize a fixed-size, preallocated pool
Definition: pool.h:86
void transport_endpoint_cleanup(u8 proto, ip46_address_t *lcl_ip, u16 port)
Definition: transport.c:395
void transport_register_protocol(transport_proto_t transport_proto, const transport_proto_vft_t *vft, fib_protocol_t fib_proto, u32 output_node)
Register transport virtual function table.
Definition: transport.c:239
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:161
u16 hdr_offset
offset relative to ip hdr
Definition: sctp.h:34
static sctp_connection_t * sctp_half_open_connection_get(u32 conn_index)
Definition: sctp.h:591
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:311
#define ASSERT(truth)
struct sctp_buffer_opaque_t::@605 sctp
u16 sctp_snd_space(sctp_connection_t *sctp_conn)
Definition: sctp.c:642
#define SCTP_PRIMARY_PATH_IDX
Definition: sctp.h:107
u8 subconn_idx
index of the sub_connection being used
Definition: sctp.h:37
void sctp_connection_cleanup(sctp_connection_t *sctp_conn)
Cleans up connection state.
Definition: sctp.c:532
u16 ssn
Stream Sequence Number.
Definition: sctp.h:32
u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
Definition: ip.c:20
void sctp_update_time(f64 now, u8 thread_index)
Definition: sctp.c:941
static sctp_connection_t * sctp_connection_get(u32 conn_index, u32 thread_index)
Definition: sctp.h:788
void sctp_send_cookie_echo(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:569
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u8 * format_sctp_header(u8 *s, va_list *args)
Definition: sctp_format.c:20
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
VLIB_PLUGIN_REGISTER()
unreliable transport protos
clib_error_t * sctp_init(vlib_main_t *vm)
Definition: sctp.c:1035
u8 sctp_sub_connection_del_ip6(ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
Definition: sctp.c:379
void sctp_send_heartbeat(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1203
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void sctp_expired_timers_cb(u32 conn_index, u32 timer_id)
Definition: sctp.c:722
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define SCTP_HB_INTERVAL
Definition: sctp.h:493
void sctp_connection_close(sctp_connection_t *sctp_conn)
Definition: sctp.c:584
static sctp_connection_t * sctp_sub_connection_add(u8 thread_index)
Definition: sctp.c:281
unformat_function_t unformat_pg_sctp_header
Definition: sctp.h:335
static sctp_connection_t * sctp_listener_get(u32 tli)
Definition: sctp.h:780
#define SCTP_TIMER_HANDLE_INVALID
Definition: sctp.h:68
int transport_alloc_local_port(u8 proto, ip46_address_t *ip)
Allocate local port and add if successful add entry to local endpoint table to mark the pair as used...
Definition: transport.c:429
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2809
vlib_node_registration_t sctp4_input_node
(constructor) VLIB_REGISTER_NODE (sctp4_input_node)
Definition: sctp_input.c:2281
static u8 sctp_data_subconn_select(sctp_connection_t *sctp_conn)
Definition: sctp.h:799
void sctp_send_shutdown(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1019
sctp_connection_t * sctp_half_open_connection_new(u8 thread_index)
Definition: sctp.c:448
u8 sctp_sub_connection_add_ip6(vlib_main_t *vm, ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
Definition: sctp.c:356
#define SCTP_CONN_RECOVERY
Definition: sctp.h:498
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:772
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:95
void sctp_session_close(u32 conn_index, u32 thread_index)
Definition: sctp.c:595
u32 sctp_session_send_space(transport_connection_t *trans_conn)
Compute TX window session is allowed to fill.
Definition: sctp.c:667
static void sctp_expired_timers_dispatch(u32 *expired_timers)
Definition: sctp.c:792
static const transport_proto_vft_t sctp_proto
Definition: sctp.c:950
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171