FD.io VPP  v18.04-17-g3a0d853
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 #include <vnet/sctp/sctp.h>
16 #include <vnet/sctp/sctp_debug.h>
17 
19 
20 static u32
22 {
23  sctp_main_t *tm = &sctp_main;
24  sctp_connection_t *listener;
25  void *iface_ip;
26 
27  pool_get (tm->listener_pool, listener);
28  memset (listener, 0, sizeof (*listener));
29 
30  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
32  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
33  listener - tm->listener_pool;
34  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_port = tep->port;
35 
36  /* If we are provided a sw_if_index, bind using one of its IPs */
37  if (ip_is_zero (&tep->ip, 1) && tep->sw_if_index != ENDPOINT_INVALID_INDEX)
38  {
39  if ((iface_ip = ip_interface_get_first_ip (tep->sw_if_index,
40  tep->is_ip4)))
41  ip_set (&tep->ip, iface_ip, tep->is_ip4);
42  }
43  ip_copy (&listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_ip,
44  &tep->ip, tep->is_ip4);
45 
46  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].PMTU =
47  vnet_sw_interface_get_mtu (vnet_get_main (), tep->sw_if_index, VLIB_TX);
48  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.is_ip4 = tep->is_ip4;
49  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.proto =
51  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_s_index = session_index;
52  listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.fib_index =
53  tep->fib_index;
54  listener->state = SCTP_STATE_CLOSED;
55 
56  sctp_connection_timers_init (listener);
57 
58  return listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index;
59 }
60 
61 u32
63 {
64  return sctp_connection_bind (session_index, tep);
65 }
66 
67 static void
68 sctp_connection_unbind (u32 listener_index)
69 {
71  sctp_connection_t *sctp_conn;
72 
73  sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
74 
75  /* Poison the entry */
76  if (CLIB_DEBUG > 0)
77  memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
78 
79  pool_put_index (tm->listener_pool, listener_index);
80 }
81 
82 u32
83 sctp_session_unbind (u32 listener_index)
84 {
85  sctp_connection_unbind (listener_index);
86  return 0;
87 }
88 
89 void
90 sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
91 {
92  sctp_main_t *tm = &sctp_main;
93  if (is_ip4)
94  tm->punt_unknown4 = is_add;
95  else
96  tm->punt_unknown6 = is_add;
97 }
98 
99 static int
100 sctp_alloc_custom_local_endpoint (sctp_main_t * tm, ip46_address_t * lcl_addr,
101  u16 * lcl_port, u8 is_ip4)
102 {
103  int index, port;
104  if (is_ip4)
105  {
106  index = tm->last_v4_address_rotor++;
107  if (tm->last_v4_address_rotor >= vec_len (tm->ip4_src_addresses))
108  tm->last_v4_address_rotor = 0;
109  lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
110  }
111  else
112  {
113  index = tm->last_v6_address_rotor++;
114  if (tm->last_v6_address_rotor >= vec_len (tm->ip6_src_addresses))
115  tm->last_v6_address_rotor = 0;
116  clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
117  sizeof (ip6_address_t));
118  }
120  if (port < 1)
121  {
122  clib_warning ("Failed to allocate src port");
123  return -1;
124  }
125  *lcl_port = port;
126  return 0;
127 }
128 
129 /**
130  * Initialize all connection timers as invalid
131  */
132 void
134 {
135  int i, j;
136 
137  /* Set all to invalid */
138  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
139  {
140  sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
141 
142  for (j = 0; j < SCTP_N_TIMERS; j++)
143  {
144  sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
145  }
146  }
147 }
148 
149 /**
150  * Stop all connection timers
151  */
152 void
154 {
155  int i, j;
156  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
157  {
158  for (j = 0; j < SCTP_N_TIMERS; j++)
159  sctp_timer_reset (sctp_conn, i, j);
160  }
161 }
162 
163 const char *sctp_fsm_states[] = {
164 #define _(sym, str) str,
166 #undef _
167 };
168 
169 u8 *
170 format_sctp_state (u8 * s, va_list * args)
171 {
172  u32 state = va_arg (*args, u32);
173 
174  if (state < SCTP_N_STATES)
175  s = format (s, "%s", sctp_fsm_states[state]);
176  else
177  s = format (s, "UNKNOWN (%d (0x%x))", state, state);
178  return s;
179 }
180 
181 u8 *
182 format_sctp_connection_id (u8 * s, va_list * args)
183 {
184  sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
185  if (!sctp_conn)
186  return s;
187 
188  u8 i;
189  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
190  {
191  if (sctp_conn->sub_conn[i].connection.is_ip4)
192  {
193  s = format (s, "%U[#%d][%s] %U:%d->%U:%d",
194  s,
195  sctp_conn->sub_conn[i].connection.thread_index,
196  "T",
198  &sctp_conn->sub_conn[i].connection.lcl_ip.ip4,
199  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
200  connection.lcl_port),
202  &sctp_conn->sub_conn[i].connection.rmt_ip.ip4,
203  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
204  connection.rmt_port));
205  }
206  else
207  {
208  s = format (s, "%U[#%d][%s] %U:%d->%U:%d",
209  s,
210  sctp_conn->sub_conn[i].connection.thread_index,
211  "T",
213  &sctp_conn->sub_conn[i].connection.lcl_ip.ip6,
214  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
215  connection.lcl_port),
217  &sctp_conn->sub_conn[i].connection.rmt_ip.ip6,
218  clib_net_to_host_u16 (sctp_conn->sub_conn[i].
219  connection.rmt_port));
220  }
221  }
222  return s;
223 }
224 
225 u8 *
226 format_sctp_connection (u8 * s, va_list * args)
227 {
228  sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
229  u32 verbose = va_arg (*args, u32);
230 
231  if (!sctp_conn)
232  return s;
233  s = format (s, "%-50U", format_sctp_connection_id, sctp_conn);
234  if (verbose)
235  {
236  s = format (s, "%-15U", format_sctp_state, sctp_conn->state);
237  }
238 
239  return s;
240 }
241 
242 /**
243  * Initialize connection send variables.
244  */
245 void
247 {
248  u32 time_now;
249  /*
250  * We use the time to randomize iss and for setting up the initial
251  * timestamp. Make sure it's updated otherwise syn and ack in the
252  * handshake may make it look as if time has flown in the opposite
253  * direction for us.
254  */
255 
257  time_now = sctp_time_now ();
258 
259  sctp_conn->local_initial_tsn = random_u32 (&time_now);
260  sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
261  sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
262 
263  sctp_conn->remote_initial_tsn = 0x0;
264  sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
265 }
266 
269 {
271  sctp_connection_t *sctp_conn = tm->connections[thread_index];
272 
273  u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
274 
275  ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS);
276 
277  sctp_conn->sub_conn[subconn_idx].connection.c_index =
278  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index;
279  sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
280  sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
281 
282  return sctp_conn;
283 }
284 
285 u8
287  ip4_address_t * lcl_addr,
288  ip4_address_t * rmt_addr)
289 {
291 
292  u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
293 
294  if (subconn_idx == MAX_SCTP_CONNECTIONS)
295  return SCTP_ERROR_MAX_CONNECTIONS;
296 
297  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
298  &lcl_addr, sizeof (lcl_addr));
299 
300  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
301  &rmt_addr, sizeof (rmt_addr));
302 
303  sctp_conn->forming_association_changed = 1;
304 
305  return SCTP_ERROR_NONE;
306 }
307 
308 u8
310  ip4_address_t * rmt_addr)
311 {
313 
314  u32 thread_idx = vlib_get_thread_index ();
315  u8 i;
316 
317  ASSERT (thread_idx == 0);
318 
319  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
320  {
321  sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
322  sctp_sub_connection_t *sub_conn =
323  &sctp_main->connections[thread_idx]->sub_conn[i];
324  ip46_address_t *lcl_ip =
325  &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
326  ip46_address_t *rmt_ip =
327  &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
328 
329  if (!sub_conn->connection.is_ip4)
330  continue;
331  if (lcl_ip->ip4.as_u32 == lcl_addr->as_u32 &&
332  rmt_ip->ip4.as_u32 == rmt_addr->as_u32)
333  {
334  sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
335  sctp_conn->forming_association_changed = 1;
336  break;
337  }
338  }
339  return SCTP_ERROR_NONE;
340 }
341 
342 u8
344  ip6_address_t * lcl_addr,
345  ip6_address_t * rmt_addr)
346 {
348 
349  u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
350 
351  if (subconn_idx == MAX_SCTP_CONNECTIONS)
352  return SCTP_ERROR_MAX_CONNECTIONS;
353 
354  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
355  &lcl_addr, sizeof (lcl_addr));
356 
357  clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
358  &rmt_addr, sizeof (rmt_addr));
359 
360  sctp_conn->forming_association_changed = 1;
361 
362  return SCTP_ERROR_NONE;
363 }
364 
365 u8
367  ip6_address_t * rmt_addr)
368 {
370 
371  u32 thread_idx = vlib_get_thread_index ();
372  u8 i;
373 
374  ASSERT (thread_idx == 0);
375 
376  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
377  {
378  sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
379  sctp_sub_connection_t *sub_conn =
380  &sctp_main->connections[thread_idx]->sub_conn[i];
381  ip46_address_t *lcl_ip =
382  &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
383  ip46_address_t *rmt_ip =
384  &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
385 
386  if (!sub_conn->connection.is_ip4)
387  continue;
388  if ((lcl_ip->ip6.as_u64[0] == lcl_addr->as_u64[0]
389  && lcl_ip->ip6.as_u64[1] == lcl_addr->as_u64[1])
390  && (rmt_ip->ip6.as_u64[0] == rmt_addr->as_u64[0]
391  && rmt_ip->ip6.as_u64[1] == rmt_addr->as_u64[1]))
392  {
393  sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
394  sctp_conn->forming_association_changed = 1;
395  break;
396  }
397  }
398  return SCTP_ERROR_NONE;
399 }
400 
401 u8
403 {
405 
406  u32 thread_idx = vlib_get_thread_index ();
407 
408  sctp_main->connections[thread_idx]->conn_config.never_delay_sack =
409  config.never_delay_sack;
410  sctp_main->connections[thread_idx]->conn_config.never_bundle =
411  config.never_bundle;
412 
413  return 0;
414 }
415 
417 sctp_connection_new (u8 thread_index)
418 {
420  sctp_connection_t *sctp_conn;
421 
422  pool_get (sctp_main->connections[thread_index], sctp_conn);
423  memset (sctp_conn, 0, sizeof (*sctp_conn));
424  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
426  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
427  sctp_conn - sctp_main->connections[thread_index];
428  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_thread_index = thread_index;
429  sctp_conn->local_tag = 0;
430 
431  return sctp_conn;
432 }
433 
436 {
438  sctp_connection_t *sctp_conn = 0;
439  ASSERT (vlib_get_thread_index () == 0);
440  pool_get (tm->half_open_connections, sctp_conn);
441  memset (sctp_conn, 0, sizeof (*sctp_conn));
442  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
443  sctp_conn - tm->half_open_connections;
444  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
446  return sctp_conn;
447 }
448 
449 static inline int
451 {
453  sctp_connection_t *sctp_conn;
454  ip46_address_t lcl_addr;
455  u16 lcl_port;
456  uword thread_id;
457  int rv;
458 
460 
461  /*
462  * Allocate local endpoint
463  */
464  if ((rmt->is_ip4 && vec_len (tm->ip4_src_addresses))
465  || (!rmt->is_ip4 && vec_len (tm->ip6_src_addresses)))
466  rv = sctp_alloc_custom_local_endpoint (tm, &lcl_addr, &lcl_port,
467  rmt->is_ip4);
468  else
470  rmt, &lcl_addr, &lcl_port);
471 
472  if (rv)
473  return -1;
474 
475  /*
476  * Create connection and send INIT CHUNK
477  */
478  thread_id = vlib_get_thread_index ();
479  ASSERT (thread_id == 0);
480 
481  clib_spinlock_lock_if_init (&tm->half_open_lock);
482  sctp_conn = sctp_half_open_connection_new (thread_id);
483  sctp_conn->sub_conn[idx].PMTU =
484  vnet_sw_interface_get_mtu (vnet_get_main (), rmt->sw_if_index, VLIB_TX);
485 
486  transport_connection_t *trans_conn = &sctp_conn->sub_conn[idx].connection;
487  ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
488  ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
489  sctp_conn->sub_conn[idx].subconn_idx = idx;
490  trans_conn->rmt_port = rmt->port;
491  trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
492  trans_conn->is_ip4 = rmt->is_ip4;
493  trans_conn->proto = TRANSPORT_PROTO_SCTP;
494  trans_conn->fib_index = rmt->fib_index;
495 
496  sctp_connection_timers_init (sctp_conn);
497  /* The other connection vars will be initialized after INIT_ACK chunk received */
498  sctp_init_snd_vars (sctp_conn);
499 
500  sctp_send_init (sctp_conn);
501 
502  clib_spinlock_unlock_if_init (&tm->half_open_lock);
503 
504  return sctp_conn->sub_conn[idx].connection.c_index;
505 }
506 
507 /**
508  * Cleans up connection state.
509  *
510  * No notifications.
511  */
512 void
514 {
515  sctp_main_t *tm = &sctp_main;
516  u8 i;
517 
518  /* Cleanup local endpoint if this was an active connect */
519  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
521  &sctp_conn->sub_conn[i].connection.lcl_ip,
522  sctp_conn->sub_conn[i].connection.lcl_port);
523 
524  int thread_index =
525  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.thread_index;
526 
527  /* Make sure all timers are cleared */
528  sctp_connection_timers_reset (sctp_conn);
529 
530  /* Poison the entry */
531  if (CLIB_DEBUG > 0)
532  memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
533  pool_put (tm->connections[thread_index], sctp_conn);
534 }
535 
536 int
538 {
539  return sctp_connection_open (tep);
540 }
541 
542 u16
544 {
545  u8 i;
546  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
547  {
548  if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
549  continue;
550 
551  if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
552  sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
553  {
555  ("Connection %u has still DATA to be enqueued inboud / outboud",
556  sctp_conn->sub_conn[i].connection.c_index);
557  return 1;
558  }
559 
560  }
561  return 0; /* Indicates no more data to be read/sent */
562 }
563 
564 void
566 {
567  SCTP_DBG ("Closing connection %u...",
568  sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index);
569 
570  sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
571 
572  sctp_send_shutdown (sctp_conn);
573 }
574 
575 void
576 sctp_session_close (u32 conn_index, u32 thread_index)
577 {
578  ASSERT (thread_index == 0);
579 
580  sctp_connection_t *sctp_conn =
581  sctp_connection_get (conn_index, thread_index);
582  if (sctp_conn != NULL)
583  sctp_connection_close (sctp_conn);
584 }
585 
586 void
587 sctp_session_cleanup (u32 conn_index, u32 thread_index)
588 {
589  sctp_connection_t *sctp_conn =
590  sctp_connection_get (conn_index, thread_index);
591 
592  if (sctp_conn != NULL)
593  {
594  sctp_connection_timers_reset (sctp_conn);
595  /* Wait for the session tx events to clear */
596  sctp_conn->state = SCTP_STATE_CLOSED;
597  }
598 }
599 
600 /**
601  * Compute maximum segment size for session layer.
602  */
603 u16
605 {
606  sctp_connection_t *sctp_conn =
608 
609  if (sctp_conn == NULL)
610  {
611  SCTP_DBG ("sctp_conn == NULL");
612  return 0;
613  }
614 
615  update_cwnd (sctp_conn);
616  update_smallest_pmtu_idx (sctp_conn);
617 
618  u8 idx = sctp_data_subconn_select (sctp_conn);
619 
620  return sctp_conn->sub_conn[idx].cwnd;
621 }
622 
623 u16
625 {
626  /* RFC 4096 Section 6.1; point (A) */
627  if (sctp_conn->peer_rwnd == 0)
628  return 0;
629 
630  u8 idx = sctp_data_subconn_select (sctp_conn);
631 
632  u32 available_wnd =
633  clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
634  int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
635 
636  if (available_wnd <= flight_size)
637  return 0;
638 
639  /* Finally, let's subtract the DATA chunk headers overhead */
640  return available_wnd -
641  flight_size -
642  sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
643 }
644 
645 /**
646  * Compute TX window session is allowed to fill.
647  */
648 u32
650 {
651  sctp_connection_t *sctp_conn =
653 
654  return sctp_snd_space (sctp_conn);
655 }
656 
658 sctp_session_get_transport (u32 conn_index, u32 thread_index)
659 {
660  sctp_connection_t *sctp_conn =
661  sctp_connection_get (conn_index, thread_index);
662 
663  if (PREDICT_TRUE (sctp_conn != NULL))
664  return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
665 
666  return NULL;
667 }
668 
671 {
673  sctp_connection_t *sctp_conn;
674  sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
675  return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
676 }
677 
678 u8 *
679 format_sctp_session (u8 * s, va_list * args)
680 {
681  u32 tci = va_arg (*args, u32);
682  u32 thread_index = va_arg (*args, u32);
683  u32 verbose = va_arg (*args, u32);
684  sctp_connection_t *tc;
685 
686  tc = sctp_connection_get (tci, thread_index);
687  if (tc)
688  s = format (s, "%U", format_sctp_connection, tc, verbose);
689  else
690  s = format (s, "empty\n");
691  return s;
692 }
693 
694 u8 *
695 format_sctp_listener_session (u8 * s, va_list * args)
696 {
697  u32 tci = va_arg (*args, u32);
699  return format (s, "%U", format_sctp_connection_id, tc);
700 }
701 
702 void
703 sctp_expired_timers_cb (u32 conn_index, u32 timer_id)
704 {
705  sctp_connection_t *sctp_conn;
706 
707  sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
708  /* note: the connection may have already disappeared */
709  if (PREDICT_FALSE (sctp_conn == 0))
710  return;
711 
712  SCTP_DBG ("%s expired", sctp_timer_to_string (timer_id));
713 
714  if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
716  {
717  // The remote-peer is considered to be unreachable hence shutting down
718  u8 i, total_subs_down = 1;
719  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
720  {
721  if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
722  continue;
723 
724  u32 now = sctp_time_now ();
725  if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
726  {
727  total_subs_down += 1;
728  sctp_conn->sub_conn[i].state = SCTP_SUBCONN_STATE_DOWN;
729  }
730  }
731 
732  if (total_subs_down == MAX_SCTP_CONNECTIONS)
733  {
734  /* Start cleanup. App wasn't notified yet so use delete notify as
735  * opposed to delete to cleanup session layer state. */
736  stream_session_delete_notify (&sctp_conn->sub_conn
737  [SCTP_PRIMARY_PATH_IDX].connection);
738 
739  sctp_connection_timers_reset (sctp_conn);
740 
741  sctp_connection_cleanup (sctp_conn);
742  }
743  return;
744  }
745 
746  switch (timer_id)
747  {
748  case SCTP_TIMER_T1_INIT:
749  sctp_send_init (sctp_conn);
750  break;
751  case SCTP_TIMER_T1_COOKIE:
752  sctp_send_cookie_echo (sctp_conn);
753  break;
754  case SCTP_TIMER_T2_SHUTDOWN:
755  sctp_send_shutdown (sctp_conn);
756  break;
757  case SCTP_TIMER_T3_RXTX:
758  sctp_timer_reset (sctp_conn, conn_index, timer_id);
759  sctp_conn->flags |= SCTP_CONN_RECOVERY;
760  sctp_data_retransmit (sctp_conn);
761  break;
762  case SCTP_TIMER_T4_HEARTBEAT:
763  sctp_timer_reset (sctp_conn, conn_index, timer_id);
764  goto heartbeat;
765  }
766  return;
767 
768 heartbeat:
769  sctp_send_heartbeat (sctp_conn);
770 }
771 
772 static void
774 {
775  int i;
776  u32 connection_index, timer_id;
777 
778  for (i = 0; i < vec_len (expired_timers); i++)
779  {
780  /* Get session index and timer id */
781  connection_index = expired_timers[i] & 0x0FFFFFFF;
782  timer_id = expired_timers[i] >> 28;
783 
784  SCTP_DBG ("Expired timer ID: %u", timer_id);
785 
786  /* Handle expiration */
787  sctp_expired_timers_cb (connection_index, timer_id);
788  }
789 }
790 
791 void
793 {
794  tw_timer_wheel_16t_2w_512sl_t *tw;
795  /* *INDENT-OFF* */
797  tw = &tm->timer_wheels[ii];
798  tw_timer_wheel_init_16t_2w_512sl (tw, sctp_expired_timers_dispatch,
799  100e-3 /* timer period 100ms */ , ~0);
800  tw->last_run_time = vlib_time_now (this_vlib_main);
801  }));
802  /* *INDENT-ON* */
803 }
804 
805 clib_error_t *
807 {
810  clib_error_t *error = 0;
811  u32 num_threads;
812  int thread;
813  sctp_connection_t *sctp_conn __attribute__ ((unused));
814  u32 preallocated_connections_per_thread;
815 
816  if ((error = vlib_call_init_function (vm, ip_main_init)))
817  return error;
818  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
819  return error;
820  if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
821  return error;
822 
823  /*
824  * Registrations
825  */
826 
829 
830  /*
831  * Initialize data structures
832  */
833 
834  num_threads = 1 /* main thread */ + vtm->n_threads;
835  vec_validate (tm->connections, num_threads - 1);
836 
837  /*
838  * Preallocate connections. Assume that thread 0 won't
839  * use preallocated threads when running multi-core
840  */
841  if (num_threads == 1)
842  {
843  thread = 0;
844  preallocated_connections_per_thread = tm->preallocated_connections;
845  }
846  else
847  {
848  thread = 1;
849  preallocated_connections_per_thread =
850  tm->preallocated_connections / (num_threads - 1);
851  }
852  for (; thread < num_threads; thread++)
853  {
854  if (preallocated_connections_per_thread)
855  pool_init_fixed (tm->connections[thread],
856  preallocated_connections_per_thread);
857  }
858 
859  /* Initialize per worker thread tx buffers (used for control messages) */
860  vec_validate (tm->tx_buffers, num_threads - 1);
861 
862  /* Initialize timer wheels */
863  vec_validate (tm->timer_wheels, num_threads - 1);
865 
866  /* Initialize clocks per tick for SCTP timestamp. Used to compute
867  * monotonically increasing timestamps. */
868  tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
870 
871  if (num_threads > 1)
872  {
873  clib_spinlock_init (&tm->half_open_lock);
874  }
875 
876  vec_validate (tm->tx_frames[0], num_threads - 1);
877  vec_validate (tm->tx_frames[1], num_threads - 1);
878  vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
879  vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
880 
881  tm->bytes_per_buffer = vlib_buffer_free_list_buffer_size
883 
884  vec_validate (tm->time_now, num_threads - 1);
885  return error;
886 }
887 
888 clib_error_t *
890 {
891  if (is_en)
892  {
893  if (sctp_main.is_enabled)
894  return 0;
895 
896  return sctp_main_enable (vm);
897  }
898  else
899  {
900  sctp_main.is_enabled = 0;
901  }
902 
903  return 0;
904 }
905 
908 {
909  sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
910  return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
911 }
912 
913 u8 *
914 format_sctp_half_open (u8 * s, va_list * args)
915 {
916  u32 tci = va_arg (*args, u32);
918  return format (s, "%U", format_sctp_connection_id, sctp_conn);
919 }
920 
921 void
922 sctp_update_time (f64 now, u8 thread_index)
923 {
924  sctp_set_time_now (thread_index);
925  tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
926  now);
927  sctp_flush_frames_to_output (thread_index);
928 }
929 
930 /* *INDENT OFF* */
932  .enable = sctp_enable_disable,
933  .bind = sctp_session_bind,
934  .unbind = sctp_session_unbind,
935  .open = sctp_session_open,
936  .close = sctp_session_close,
937  .cleanup = sctp_session_cleanup,
938  .push_header = sctp_push_header,
939  .send_mss = sctp_session_send_mss,
940  .send_space = sctp_session_send_space,
941  .update_time = sctp_update_time,
942  .get_connection = sctp_session_get_transport,
943  .get_listener = sctp_session_get_listener,
944  .get_half_open = sctp_half_open_session_get_transport,
945  .format_connection = format_sctp_session,
946  .format_listener = format_sctp_listener_session,
947  .format_half_open = format_sctp_half_open,
948  .tx_type = TRANSPORT_TX_DEQUEUE,
949  .service_type = TRANSPORT_SERVICE_VC,
950 };
951 
952 /* *INDENT ON* */
953 
954 clib_error_t *
956 {
958  ip_main_t *im = &ip_main;
959  ip_protocol_info_t *pi;
960  /* Session layer, and by implication SCTP, are disabled by default */
961  tm->is_enabled = 0;
962 
963  /* Register with IP for header parsing */
965  if (pi == 0)
966  return clib_error_return (0, "SCTP protocol info AWOL");
969 
970  /* Register as transport with session layer */
975 
977 
978  return 0;
979 }
980 
982 
983 /*
984  * fd.io coding-style-patch-verification: ON
985  *
986  * Local Variables:
987  * eval: (c-set-style "gnu")
988  * End:
989  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:434
void sctp_connection_timers_reset(sctp_connection_t *sctp_conn)
Stop all connection timers.
Definition: sctp.c:153
u16 sctp_check_outstanding_data_chunks(sctp_connection_t *sctp_conn)
Definition: sctp.c:543
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:133
static void update_cwnd(sctp_connection_t *sctp_conn)
Definition: sctp.h:935
clib_error_t * sctp_main_enable(vlib_main_t *vm)
Definition: sctp.c:806
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:87
#define clib_min(x, y)
Definition: clib.h:340
#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:100
void sctp_init_snd_vars(sctp_connection_t *sctp_conn)
Initialize connection send variables.
Definition: sctp.c:246
virtual circuit service
void ip_copy(ip46_address_t *dst, ip46_address_t *src, u8 is_ip4)
Definition: ip.c:81
static uword vnet_sw_interface_get_mtu(vnet_main_t *vnm, u32 sw_if_index, vlib_rx_or_tx_t dir)
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1392
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
struct _transport_connection transport_connection_t
transport_connection_t * sctp_half_open_session_get_transport(u32 conn_index)
Definition: sctp.c:907
#define PREDICT_TRUE(x)
Definition: clib.h:106
u64 as_u64[2]
Definition: ip6_packet.h:51
void sctp_send_init(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1314
struct _sctp_sub_connection sctp_sub_connection_t
void ip_set(ip46_address_t *dst, void *src, u8 is_ip4)
Definition: ip.c:90
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:98
u32 thread_index
Definition: main.h:176
#define foreach_sctp_fsm_state
SSCTP FSM state definitions as per RFC4960.
Definition: sctp.h:346
struct _transport_proto_vft transport_proto_vft_t
vlib_node_registration_t sctp6_output_node
(constructor) VLIB_REGISTER_NODE (sctp6_output_node)
Definition: sctp_output.c:1902
clib_error_t * sctp_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: sctp.c:889
u8 * format_sctp_half_open(u8 *s, va_list *args)
Definition: sctp.c:914
int i
static u32 sctp_set_time_now(u32 thread_index)
Definition: sctp.h:586
u16 sctp_session_send_mss(transport_connection_t *trans_conn)
Compute maximum segment size for session layer.
Definition: sctp.c:604
void * ip_interface_get_first_ip(u32 sw_if_index, u8 is_ip4)
Definition: ip.c:133
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static void update_smallest_pmtu_idx(sctp_connection_t *sctp_conn)
Definition: sctp.h:881
clib_time_t clib_time
Definition: main.h:63
Definition: ip.h:109
static u32 sctp_connection_bind(u32 session_index, transport_endpoint_t *tep)
Definition: sctp.c:21
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1508
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:227
struct _sctp_user_configuration sctp_user_configuration_t
u8 sctp_configure(sctp_user_configuration_t config)
Definition: sctp.c:402
static sctp_main_t * vnet_get_sctp_main()
Definition: sctp.h:542
pthread_t thread[MAX_CONNS]
Definition: main.c:125
vlib_node_registration_t sctp6_input_node
(constructor) VLIB_REGISTER_NODE (sctp6_input_node)
Definition: sctp_input.c:2327
#define SCTP_PATH_MAX_RETRANS
Definition: sctp.h:464
sctp_main_t sctp_main
Definition: sctp.c:18
format_function_t format_ip4_address
Definition: format.h:79
unformat_function_t * unformat_pg_edit
Definition: ip.h:90
u8 * format_sctp_listener_session(u8 *s, va_list *args)
Definition: sctp.c:695
u32 sctp_session_unbind(u32 listener_index)
Definition: sctp.c:83
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
#define always_inline
Definition: clib.h:92
transport_connection_t * sctp_session_get_transport(u32 conn_index, u32 thread_index)
Definition: sctp.c:658
#define clib_error_return(e, args...)
Definition: error.h:99
void stream_session_delete_notify(transport_connection_t *tc)
Notification from transport that connection is being deleted.
Definition: session.c:742
u8 * format_sctp_session(u8 *s, va_list *args)
Definition: sctp.c:679
static void sctp_connection_unbind(u32 listener_index)
Definition: sctp.c:68
sctp_connection_t * sctp_connection_new(u8 thread_index)
Definition: sctp.c:417
void sctp_session_cleanup(u32 conn_index, u32 thread_index)
Definition: sctp.c:587
#define vlib_call_init_function(vm, x)
Definition: init.h:162
void sctp_data_retransmit(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1513
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:57
void sctp_punt_unknown(vlib_main_t *vm, u8 is_ip4, u8 is_add)
Definition: sctp.c:90
static int sctp_connection_open(transport_endpoint_t *rmt)
Definition: sctp.c:450
#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:609
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:136
static sctp_connection_t * sctp_get_connection_from_transport(transport_connection_t *tconn)
Definition: sctp.h:650
static u32 sctp_time_now(void)
Definition: sctp.h:669
format_function_t * format_header
Definition: ip.h:81
void sctp_initialize_timer_wheels(sctp_main_t *tm)
Definition: sctp.c:792
u8 sctp_sub_connection_add_ip4(vlib_main_t *vm, ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
Definition: sctp.c:286
u32 sctp_session_bind(u32 session_index, transport_endpoint_t *tep)
Definition: sctp.c:62
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:446
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:273
#define PREDICT_FALSE(x)
Definition: clib.h:105
struct _sctp_connection sctp_connection_t
f64 seconds_per_clock
Definition: time.h:57
#define SCTP_RTO_INIT
Definition: sctp.h:456
static char * sctp_timer_to_string(u8 timer_id)
Definition: sctp.h:45
u8 * format_sctp_connection_id(u8 *s, va_list *args)
Definition: sctp.c:182
#define foreach_vlib_main(body)
Definition: threads.h:244
#define MAX_SCTP_CONNECTIONS
Definition: sctp.h:80
u8 * format_sctp_state(u8 *s, va_list *args)
Definition: sctp.c:170
#define SCTP_TSTAMP_RESOLUTION
Time stamp resolution.
Definition: sctp.h:453
vlib_node_registration_t sctp4_output_node
(constructor) VLIB_REGISTER_NODE (sctp4_output_node)
Definition: sctp_output.c:1881
static u8 sctp_next_avail_subconn(sctp_connection_t *sctp_conn)
Definition: sctp.h:868
unformat_function_t unformat_pg_sctp_header
Definition: format.h:104
u8 sctp_sub_connection_del_ip4(ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
Definition: sctp.c:309
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
format_function_t format_ip6_address
Definition: format.h:95
vlib_main_t * vm
Definition: buffer.c:294
ip_main_t ip_main
Definition: ip_init.c:42
u8 * format_sctp_connection(u8 *s, va_list *args)
Definition: sctp.c:226
const char * sctp_fsm_states[]
Definition: sctp.c:163
#define ENDPOINT_INVALID_INDEX
Definition: transport.h:115
transport_connection_t * sctp_session_get_listener(u32 listener_index)
Definition: sctp.c:670
void sctp_api_reference(void)
Definition: sctp_api.c:137
#define IP_PROTOCOL_SCTP
Definition: sctp.h:343
#define clib_warning(format, args...)
Definition: error.h:59
#define clib_memcpy(a, b, c)
Definition: string.h:75
u32 sctp_push_header(transport_connection_t *tconn, vlib_buffer_t *b)
Definition: sctp_output.c:1439
#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:207
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:163
static sctp_connection_t * sctp_half_open_connection_get(u32 conn_index)
Definition: sctp.h:558
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:296
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u16 sctp_snd_space(sctp_connection_t *sctp_conn)
Definition: sctp.c:624
#define SCTP_PRIMARY_PATH_IDX
Definition: sctp.h:81
vhost_vring_state_t state
Definition: vhost-user.h:82
format_function_t format_sctp_header
Definition: format.h:102
void sctp_connection_cleanup(sctp_connection_t *sctp_conn)
Cleans up connection state.
Definition: sctp.c:513
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:821
u64 uword
Definition: types.h:112
unreliable transport protos
u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
Definition: ip.c:20
Definition: defs.h:47
void sctp_update_time(f64 now, u8 thread_index)
Definition: sctp.c:922
static sctp_connection_t * sctp_connection_get(u32 conn_index, u32 thread_index)
Definition: sctp.h:755
unsigned short u16
Definition: types.h:57
int sctp_session_open(transport_endpoint_t *tep)
Definition: sctp.c:537
void sctp_send_cookie_echo(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:598
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
struct _transport_endpoint transport_endpoint_t
static u32 vlib_buffer_free_list_buffer_size(vlib_main_t *vm, vlib_buffer_free_list_index_t index)
Definition: buffer_funcs.h:533
clib_error_t * sctp_init(vlib_main_t *vm)
Definition: sctp.c:955
u8 sctp_sub_connection_del_ip6(ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
Definition: sctp.c:366
void sctp_send_heartbeat(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1232
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
void sctp_expired_timers_cb(u32 conn_index, u32 timer_id)
Definition: sctp.c:703
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define SCTP_HB_INTERVAL
Definition: sctp.h:466
void sctp_connection_close(sctp_connection_t *sctp_conn)
Definition: sctp.c:565
static sctp_connection_t * sctp_sub_connection_add(u8 thread_index)
Definition: sctp.c:268
int transport_alloc_local_endpoint(u8 proto, transport_endpoint_t *rmt, ip46_address_t *lcl_addr, u16 *lcl_port)
Definition: transport.c:273
static sctp_connection_t * sctp_listener_get(u32 tli)
Definition: sctp.h:747
#define SCTP_TIMER_HANDLE_INVALID
Definition: sctp.h:42
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:228
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2753
vlib_node_registration_t sctp4_input_node
(constructor) VLIB_REGISTER_NODE (sctp4_input_node)
Definition: sctp_input.c:2326
static u8 sctp_data_subconn_select(sctp_connection_t *sctp_conn)
Definition: sctp.h:766
void sctp_send_shutdown(sctp_connection_t *sctp_conn)
Definition: sctp_output.c:1048
sctp_connection_t * sctp_half_open_connection_new(u8 thread_index)
Definition: sctp.c:435
u8 sctp_sub_connection_add_ip6(vlib_main_t *vm, ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
Definition: sctp.c:343
#define SCTP_CONN_RECOVERY
Definition: sctp.h:471
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:82
void sctp_session_close(u32 conn_index, u32 thread_index)
Definition: sctp.c:576
u32 sctp_session_send_space(transport_connection_t *trans_conn)
Compute TX window session is allowed to fill.
Definition: sctp.c:649
static void sctp_expired_timers_dispatch(u32 *expired_timers)
Definition: sctp.c:773
static const transport_proto_vft_t sctp_proto
Definition: sctp.c:931