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