blob: 7c4df309906939cd15c5dee6e2684f83e800c889 [file] [log] [blame]
Marco Varlese191a5942017-10-30 18:17:21 +01001/*
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#ifndef included_vnet_sctp_h
16#define included_vnet_sctp_h
17
18#include <vnet/vnet.h>
19#include <vnet/ip/ip.h>
20#include <vnet/sctp/sctp_timer.h>
21#include <vnet/sctp/sctp_packet.h>
22#include <vnet/session/transport.h>
23#include <vnet/session/session.h>
24
25/* SCTP timers */
26#define foreach_sctp_timer \
27 _(T1_INIT, "T1_INIT") \
28 _(T1_COOKIE, "T1_COOKIE") \
29 _(T2_SHUTDOWN, "T2_SHUTDOWN") \
30 _(T3_RXTX, "T3_RXTX") \
31 _(T5_SHUTDOWN_GUARD, "T5_SHUTDOWN_GUARD")
32
33typedef enum _sctp_timers
34{
35#define _(sym, str) SCTP_TIMER_##sym,
36 foreach_sctp_timer
37#undef _
38 SCTP_N_TIMERS
39} sctp_timers_e;
40
41#define SCTP_TIMER_HANDLE_INVALID ((u32) ~0)
42
43typedef enum _sctp_error
44{
45#define sctp_error(n,s) SCTP_ERROR_##n,
46#include <vnet/sctp/sctp_error.def>
47#undef sctp_error
48 SCTP_N_ERROR,
49} sctp_error_t;
50
51#define NO_FLAG 0
52
53#define IS_T_BIT_SET(var) ((var) & (1))
54#define IS_E_BIT_SET(var) ((var) & (1))
55#define IS_B_BIT_SET(var) ((var) & (1<<1))
56#define IS_U_BIT_SET(var) ((var) & (1<<2))
57
58#define MAX_SCTP_CONNECTIONS 32
59#define MAIN_SCTP_SUB_CONN_IDX 0
60
61#if (VLIB_BUFFER_TRACE_TRAJECTORY)
62#define sctp_trajectory_add_start(b, start) \
63{ \
64 (*vlib_buffer_trace_trajectory_cb) (b, start); \
65}
66#else
67#define sctp_trajectory_add_start(b, start)
68#endif
69
70typedef struct _sctp_sub_connection
71{
72 transport_connection_t connection; /**< Common transport data. First! */
73 void *parent; /**< Link to the parent-super connection */
74 u32 timers[SCTP_N_TIMERS]; /**< Timer handles into timer wheel */
75
76} sctp_sub_connection_t;
77
78typedef struct
79{
80 u32 a_rwnd; /**< Maximum segment size advertised */
81
82} sctp_options_t;
83
84typedef struct _sctp_connection
85{
86 sctp_sub_connection_t sub_conn[MAX_SCTP_CONNECTIONS]; /**< Common transport data. First! */
87
88 u8 state; /**< SCTP state as per sctp_state_t */
89 u16 flags; /**< Chunk flag (see sctp_chunks_common_hdr_t) */
90 u32 local_tag; /**< INIT_TAG generated locally */
91 u32 remote_tag; /**< INIT_TAG generated by the remote peer */
92 u16 life_span_inc;
93
94 /** Send sequence variables RFC4960 */
95 u32 snd_una; /**< oldest unacknowledged sequence number */
96 u32 snd_una_max; /**< newest unacknowledged sequence number + 1*/
97 u32 snd_wl1; /**< seq number used for last snd.wnd update */
98 u32 snd_wl2; /**< ack number used for last snd.wnd update */
99 u32 snd_nxt; /**< next seq number to be sent */
100
101 /** Receive sequence variables RFC4960 */
102 u32 rcv_nxt; /**< next sequence number expected */
103 u32 rcv_las; /**< rcv_nxt at last ack sent/rcv_wnd update */
104 u32 iss; /**< initial sent sequence */
105 u32 irs; /**< initial remote sequence */
106
107 /* RTT and RTO */
108 u32 rto; /**< Retransmission timeout */
109 u32 rto_boff; /**< Index for RTO backoff */
110 u32 srtt; /**< Smoothed RTT */
111 u32 rttvar; /**< Smoothed mean RTT difference. Approximates variance */
112 u32 rtt_ts; /**< Timestamp for tracked ACK */
113 u32 rtt_seq; /**< Sequence number for tracked ACK */
114
115 u32 a_rwnd; /** Constrained by medium / IP / etc. */
116 u32 rcv_a_rwnd; /**< LOCAL max seg size that includes options. To be updated by congestion algos, etc. */
117 u32 snd_a_rwnd; /**< REMOTE max seg size that includes options. To be updated if peer pushes back on window, etc.*/
118 sctp_options_t rcv_opts;
119 sctp_options_t snd_opts;
120 u32 snd_hdr_length; /**< BASE HEADER LENGTH for the DATA chunk when sending */
121
122 u8 next_avail_sub_conn; /**< Represent the index of the next free slot in sub_conn */
123} sctp_connection_t;
124
125typedef void (timer_expiration_handler) (u32 index);
126
127sctp_connection_t *sctp_connection_new (u8 thread_index);
128void sctp_sub_connection_add_ip4 (u8 thread_index,
129 sctp_ipv4_addr_param_t * ipv4_addr);
130void sctp_sub_connection_add_ip6 (u8 thread_index,
131 sctp_ipv6_addr_param_t * ipv6_addr);
132void sctp_connection_close (sctp_connection_t * tc);
133void sctp_connection_cleanup (sctp_connection_t * tc);
134void sctp_connection_del (sctp_connection_t * tc);
135
136u32 sctp_push_header (transport_connection_t * tconn, vlib_buffer_t * b);
137void sctp_send_init (sctp_connection_t * tc);
138void sctp_send_shutdown (sctp_connection_t * tc);
139void sctp_send_shutdown_ack (sctp_connection_t * tc);
140void sctp_send_shutdown_complete (sctp_connection_t * tc);
141void sctp_flush_frame_to_output (vlib_main_t * vm, u8 thread_index,
142 u8 is_ip4);
143void sctp_flush_frames_to_output (u8 thread_index);
144void sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
145
146format_function_t format_sctp_state;
147
148u8 *format_sctp_connection_id (u8 * s, va_list * args);
149u8 *format_sctp_connection (u8 * s, va_list * args);
150u8 *format_sctp_scoreboard (u8 * s, va_list * args);
151u8 *format_sctp_header (u8 * s, va_list * args);
152u8 *format_sctp_tx_trace (u8 * s, va_list * args);
153
154clib_error_t *sctp_init (vlib_main_t * vm);
155void sctp_connection_timers_init (sctp_connection_t * tc);
156void sctp_connection_timers_reset (sctp_connection_t * tc);
157void sctp_init_snd_vars (sctp_connection_t * tc);
158void sctp_connection_init_vars (sctp_connection_t * tc);
159
160void sctp_prepare_initack_chunk (sctp_connection_t * ts, vlib_buffer_t * b,
161 ip4_address_t * ip4_addr,
162 ip6_address_t * ip6_addr);
163void sctp_prepare_cookie_echo_chunk (sctp_connection_t * tc,
164 vlib_buffer_t * b,
165 sctp_state_cookie_param_t * sc);
166void sctp_prepare_cookie_ack_chunk (sctp_connection_t * tc,
167 vlib_buffer_t * b);
168void sctp_prepare_sack_chunk (sctp_connection_t * tc, vlib_buffer_t * b);
169
170u16 sctp_check_outstanding_data_chunks (sctp_connection_t * tc);
171
172#define SCTP_TICK 0.001 /**< SCTP tick period (s) */
173#define STHZ (u32) (1/SCTP_TICK) /**< SCTP tick frequency */
174#define SCTP_TSTAMP_RESOLUTION SCTP_TICK /**< Time stamp resolution */
175#define SCTP_PAWS_IDLE 24 * 24 * 60 * 60 * THZ /**< 24 days */
176#define SCTP_FIB_RECHECK_PERIOD 1 * THZ /**< Recheck every 1s */
177#define SCTP_MAX_OPTION_SPACE 40
178
179#define SCTP_DUPACK_THRESHOLD 3
180#define SCTP_MAX_RX_FIFO_SIZE 4 << 20
181#define SCTP_MIN_RX_FIFO_SIZE 4 << 10
182#define SCTP_IW_N_SEGMENTS 10
183#define SCTP_ALWAYS_ACK 1 /**< On/off delayed acks */
184#define SCTP_USE_SACKS 1 /**< Disable only for testing */
185
186#define IP_PROTOCOL_SCTP 132
187
188/** SSCTP FSM state definitions as per RFC4960. */
189#define foreach_sctp_fsm_state \
190 _(CLOSED, "CLOSED") \
191 _(COOKIE_WAIT, "COOKIE_WAIT") \
192 _(COOKIE_ECHOED, "COOKIE_ECHOED") \
193 _(ESTABLISHED, "ESTABLISHED") \
194 _(SHUTDOWN_PENDING, "SHUTDOWN_PENDING") \
195 _(SHUTDOWN_SENT, "SHUTDOWN_SENT") \
196 _(SHUTDOWN_RECEIVED, "SHUTDOWN_RECEIVED") \
197 _(SHUTDOWN_ACK_SENT, "SHUTDOWN_ACK_SENT")
198
199typedef enum _sctp_state
200{
201#define _(sym, str) SCTP_STATE_##sym,
202 foreach_sctp_fsm_state
203#undef _
204 SCTP_N_STATES
205} sctp_state_t;
206
207always_inline char *
208sctp_state_to_string (u8 state)
209{
210 switch (state)
211 {
212 case SCTP_STATE_CLOSED:
213 return "SCTP_STATE_CLOSED";
214 case SCTP_STATE_COOKIE_WAIT:
215 return "SCTP_STATE_COOKIE_WAIT";
216 case SCTP_STATE_COOKIE_ECHOED:
217 return "SCTP_STATE_COOKIE_ECHOED";
218 case SCTP_STATE_ESTABLISHED:
219 return "SCTP_STATE_ESTABLISHED";
220 case SCTP_STATE_SHUTDOWN_PENDING:
221 return "SCTP_STATE_SHUTDOWN_PENDING";
222 case SCTP_STATE_SHUTDOWN_SENT:
223 return "SCTP_STATE_SHUTDOWN_SENT";
224 case SCTP_STATE_SHUTDOWN_RECEIVED:
225 return "SCTP_STATE_SHUTDOWN_RECEIVED";
226 case SCTP_STATE_SHUTDOWN_ACK_SENT:
227 return "SCTP_STATE_SHUTDOWN_ACK_SENT";
228 }
229 return NULL;
230}
231
232always_inline char *
233sctp_chunk_to_string (u8 type)
234{
235 switch (type)
236 {
237 case DATA:
238 return "DATA";
239 case INIT:
240 return "INIT";
241 case INIT_ACK:
242 return "INIT_ACK";
243 case SACK:
244 return "SACK";
245 case HEARTBEAT:
246 return "HEARTBEAT";
247 case HEARTBEAT_ACK:
248 return "HEARTBEAT_ACK";
249 case ABORT:
250 return "ABORT";
251 case SHUTDOWN:
252 return "SHUTDOWN";
253 case SHUTDOWN_ACK:
254 return "SHUTDOWN_ACK";
255 case OPERATION_ERROR:
256 return "OPERATION_ERROR";
257 case COOKIE_ECHO:
258 return "COOKIE_ECHO";
259 case COOKIE_ACK:
260 return "COOKIE_ACK";
261 case ECNE:
262 return "ECNE";
263 case CWR:
264 return "CWR";
265 case SHUTDOWN_COMPLETE:
266 return "SHUTDOWN_COMPLETE";
267 }
268 return NULL;
269}
270
271always_inline char *
272sctp_optparam_type_to_string (u8 type)
273{
274 switch (type)
275 {
276 case SCTP_IPV4_ADDRESS_TYPE:
277 return "SCTP_IPV4_ADDRESS_TYPE";
278 case SCTP_IPV6_ADDRESS_TYPE:
279 return "SCTP_IPV6_ADDRESS_TYPE";
280 case SCTP_STATE_COOKIE_TYPE:
281 return "SCTP_STATE_COOKIE_TYPE";
282 case SCTP_UNRECOGNIZED_TYPE:
283 return "SCTP_UNRECOGNIZED_TYPE";
284 case SCTP_COOKIE_PRESERVATIVE_TYPE:
285 return "SCTP_COOKIE_PRESERVATIVE_TYPE";
286 case SCTP_HOSTNAME_ADDRESS_TYPE:
287 return "SCTP_HOSTNAME_ADDRESS_TYPE";
288 case SCTP_SUPPORTED_ADDRESS_TYPES:
289 return "SCTP_SUPPORTED_ADDRESS_TYPES";
290 }
291 return NULL;
292}
293
294#define SCTP_TICK 0.001 /**< SCTP tick period (s) */
295#define SHZ (u32) (1/SCTP_TICK) /**< SCTP tick frequency */
296
297/* As per RFC4960, page 83 */
298#define SCTP_RTO_INIT 3 * SHZ /* 3 seconds */
299#define SCTP_RTO_MIN 1 * SHZ /* 1 second */
300#define SCTP_RTO_MAX 60 * SHZ /* 60 seconds */
301#define SCTP_RTO_BURST 4
302#define SCTP_RTO_ALPHA 1/8
303#define SCTP_RTO_BETA 1/4
304#define SCTP_VALID_COOKIE_LIFE 60 * SHZ /* 60 seconds */
305#define SCTP_ASSOCIATION_MAX_RETRANS 10
306
307#define SCTP_TO_TIMER_TICK SCTP_TICK*10 /* Period for converting from SCTP_TICK */
308
309typedef struct _sctp_lookup_dispatch
310{
311 u8 next, error;
312} sctp_lookup_dispatch_t;
313
314typedef struct _sctp_main
315{
316 /* Per-worker thread SCTP connection pools */
317 sctp_connection_t **connections;
318
319 /* Pool of listeners. */
320 sctp_connection_t *listener_pool;
321
322 /** Dispatch table by state and flags */
323 sctp_lookup_dispatch_t dispatch_table[SCTP_N_STATES][64];
324
325 u8 log2_tstamp_clocks_per_tick;
326 f64 tstamp_ticks_per_clock;
327 u32 *time_now;
328
329 /** per-worker tx buffer free lists */
330 u32 **tx_buffers;
331 /** per-worker tx frames to SCTP 4/6 output nodes */
332 vlib_frame_t **tx_frames[2];
333 /** per-worker tx frames to ip 4/6 lookup nodes */
334 vlib_frame_t **ip_lookup_tx_frames[2];
335
336 /* Per worker-thread timer wheel for connections timers */
337 tw_timer_wheel_16t_2w_512sl_t *timer_wheels;
338
339 /* Pool of half-open connections on which we've sent a SYN */
340 sctp_connection_t *half_open_connections;
341 clib_spinlock_t half_open_lock;
342
343 /* TODO: Congestion control algorithms registered */
344 /* sctp_cc_algorithm_t *cc_algos; */
345
346 /* Flag that indicates if stack is on or off */
347 u8 is_enabled;
348
349 /** Number of preallocated connections */
350 u32 preallocated_connections;
351
352 /** Transport table (preallocation) size parameters */
353 u32 local_endpoints_table_memory;
354 u32 local_endpoints_table_buckets;
355
356 /** Vectors of src addresses. Optional unless one needs > 63K active-opens */
357 ip4_address_t *ip4_src_addresses;
358 u32 last_v4_address_rotor;
359 u32 last_v6_address_rotor;
360 ip6_address_t *ip6_src_addresses;
361
362 /** vlib buffer size */
363 u32 bytes_per_buffer;
364
365 u8 punt_unknown4;
366 u8 punt_unknown6;
367
368} sctp_main_t;
369
370extern sctp_main_t sctp_main;
371extern vlib_node_registration_t sctp4_input_node;
372extern vlib_node_registration_t sctp6_input_node;
373extern vlib_node_registration_t sctp4_output_node;
374extern vlib_node_registration_t sctp6_output_node;
375
376always_inline sctp_main_t *
377vnet_get_sctp_main ()
378{
379 return &sctp_main;
380}
381
382always_inline sctp_header_t *
383sctp_buffer_hdr (vlib_buffer_t * b)
384{
385 ASSERT ((signed) b->current_data >= (signed) -VLIB_BUFFER_PRE_DATA_SIZE);
386 return (sctp_header_t *) (b->data + b->current_data
387 + vnet_buffer (b)->sctp.hdr_offset);
388}
389
390clib_error_t *vnet_sctp_enable_disable (vlib_main_t * vm, u8 is_en);
391
392always_inline sctp_connection_t *
393sctp_half_open_connection_get (u32 conn_index)
394{
395 sctp_connection_t *tc = 0;
396 clib_spinlock_lock_if_init (&sctp_main.half_open_lock);
397 if (!pool_is_free_index (sctp_main.half_open_connections, conn_index))
398 tc = pool_elt_at_index (sctp_main.half_open_connections, conn_index);
399 tc->sub_conn[MAIN_SCTP_SUB_CONN_IDX].parent = tc;
400 clib_spinlock_unlock_if_init (&sctp_main.half_open_lock);
401 return tc;
402}
403
404/**
405 * Cleanup half-open connection
406 *
407 */
408always_inline void
409sctp_half_open_connection_del (sctp_connection_t * tc)
410{
411 sctp_main_t *tm = vnet_get_sctp_main ();
412 clib_spinlock_lock_if_init (&tm->half_open_lock);
413 pool_put_index (tm->half_open_connections,
414 tc->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_c_index);
415 if (CLIB_DEBUG)
416 memset (tc, 0xFA, sizeof (*tc));
417 clib_spinlock_unlock_if_init (&tm->half_open_lock);
418}
419
420always_inline u32
421sctp_set_time_now (u32 thread_index)
422{
423 sctp_main.time_now[thread_index] = clib_cpu_time_now ()
424 * sctp_main.tstamp_ticks_per_clock;
425 return sctp_main.time_now[thread_index];
426}
427
428always_inline void
429sctp_timer_set (sctp_connection_t * tc, u8 conn_idx, u8 timer_id,
430 u32 interval)
431{
432 ASSERT (tc->sub_conn[conn_idx].connection.thread_index ==
433 vlib_get_thread_index ());
434 ASSERT (tc->sub_conn[conn_idx].timers[timer_id] ==
435 SCTP_TIMER_HANDLE_INVALID);
436
437 sctp_sub_connection_t *sub = &tc->sub_conn[conn_idx];
438 tc->sub_conn[conn_idx].timers[timer_id] =
439 tw_timer_start_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
440 sub->c_c_index, timer_id, interval);
441}
442
443always_inline void
444sctp_timer_reset (sctp_connection_t * tc, u8 conn_idx, u8 timer_id)
445{
446 ASSERT (tc->sub_conn[conn_idx].c_thread_index == vlib_get_thread_index ());
447 if (tc->sub_conn[conn_idx].timers[timer_id] == SCTP_TIMER_HANDLE_INVALID)
448 return;
449
450 sctp_sub_connection_t *sub = &tc->sub_conn[conn_idx];
451
452 tw_timer_stop_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
453 sub->timers[timer_id]);
454 sub->timers[timer_id] = SCTP_TIMER_HANDLE_INVALID;
455}
456
457always_inline void
458sctp_update_time (f64 now, u32 thread_index)
459{
460 sctp_set_time_now (thread_index);
461 tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
462 now);
463 sctp_flush_frames_to_output (thread_index);
464}
465
466/**
467 * Try to cleanup half-open connection
468 *
469 * If called from a thread that doesn't own tc, the call won't have any
470 * effect.
471 *
472 * @param tc - connection to be cleaned up
473 * @return non-zero if cleanup failed.
474 */
475always_inline int
476sctp_half_open_connection_cleanup (sctp_connection_t * tc)
477{
478 /* Make sure this is the owning thread */
479 if (tc->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_thread_index !=
480 vlib_get_thread_index ())
481 return 1;
482 sctp_timer_reset (tc, MAIN_SCTP_SUB_CONN_IDX, SCTP_TIMER_T1_INIT);
483 sctp_half_open_connection_del (tc);
484 return 0;
485}
486
487always_inline u32
488sctp_header_bytes ()
489{
490 return sizeof (sctp_header_t);
491}
492
493always_inline sctp_connection_t *
494sctp_get_connection_from_transport (transport_connection_t * tconn)
495{
496 ASSERT (tconn != NULL);
497
498 sctp_sub_connection_t *sub = (sctp_sub_connection_t *) tconn;
499#if SCTP_ADV_DEBUG
500 if (sub == NULL)
501 SCTP_ADV_DBG ("sub == NULL");
502 if (sub->parent == NULL)
503 SCTP_ADV_DBG ("sub->parent == NULL");
504#endif
505 return (sctp_connection_t *) sub->parent;
506}
507
508always_inline u32
509sctp_time_now (void)
510{
511 return sctp_main.time_now[vlib_get_thread_index ()];
512}
513
514always_inline void
515sctp_timer_update (sctp_connection_t * tc, u8 conn_idx, u8 timer_id,
516 u32 interval)
517{
518 ASSERT (tc->sub_conn[conn_idx].connection.thread_index ==
519 vlib_get_thread_index ());
520 sctp_sub_connection_t *sub = &tc->sub_conn[conn_idx];
521
522 if (tc->sub_conn[conn_idx].timers[timer_id] != SCTP_TIMER_HANDLE_INVALID)
523 tw_timer_stop_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
524 sub->timers[timer_id]);
525 tc->sub_conn[conn_idx].timers[timer_id] =
526 tw_timer_start_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
527 sub->c_c_index, timer_id, interval);
528}
529
530always_inline sctp_connection_t *
531sctp_listener_get (u32 tli)
532{
533 return pool_elt_at_index (sctp_main.listener_pool, tli);
534}
535
536#endif
537
538always_inline sctp_connection_t *
539sctp_connection_get (u32 conn_index, u32 thread_index)
540{
541 if (PREDICT_FALSE
542 (pool_is_free_index (sctp_main.connections[thread_index], conn_index)))
543 return 0;
544 return pool_elt_at_index (sctp_main.connections[thread_index], conn_index);
545}
546
547always_inline u8
548sctp_pick_conn_idx_on_chunk (sctp_chunk_type chunk_type)
549{
550 u8 idx = MAIN_SCTP_SUB_CONN_IDX;
551
552 switch (chunk_type)
553 {
554 case DATA:
555 case INIT:
556 case INIT_ACK:
557 case SACK:
558 case HEARTBEAT:
559 case HEARTBEAT_ACK:
560 case ABORT:
561 case SHUTDOWN:
562 case SHUTDOWN_ACK:
563 case OPERATION_ERROR:
564 case COOKIE_ECHO:
565 case COOKIE_ACK:
566 case ECNE:
567 case CWR:
568 case SHUTDOWN_COMPLETE:
569 idx = MAIN_SCTP_SUB_CONN_IDX;
570 }
571 return idx;
572}
573
574always_inline u8
575sctp_pick_conn_idx_on_state (sctp_state_t state)
576{
577 u8 idx = MAIN_SCTP_SUB_CONN_IDX;
578
579 switch (state)
580 {
581 case SCTP_STATE_CLOSED:
582 case SCTP_STATE_COOKIE_WAIT:
583 case SCTP_STATE_COOKIE_ECHOED:
584 case SCTP_STATE_ESTABLISHED:
585 case SCTP_STATE_SHUTDOWN_PENDING:
586 case SCTP_STATE_SHUTDOWN_SENT:
587 case SCTP_STATE_SHUTDOWN_RECEIVED:
588 case SCTP_STATE_SHUTDOWN_ACK_SENT:
589 idx = MAIN_SCTP_SUB_CONN_IDX;
590 default:
591 idx = MAIN_SCTP_SUB_CONN_IDX;
592 }
593 return idx;
594}
595
596/**
597 * Push SCTP header to buffer
598 *
599 * @param vm - vlib_main
600 * @param b - buffer to write the header to
601 * @param sp_net - source port net order
602 * @param dp_net - destination port net order
603 * @param sctp_hdr_opts_len - header and options length in bytes
604 *
605 * @return - pointer to start of SCTP header
606 */
607always_inline void *
608vlib_buffer_push_sctp_net_order (vlib_buffer_t * b, u16 sp, u16 dp,
609 u8 sctp_hdr_opts_len)
610{
611 sctp_full_hdr_t *full_hdr;
612
613 full_hdr = vlib_buffer_push_uninit (b, sctp_hdr_opts_len);
614
615 full_hdr->hdr.src_port = sp;
616 full_hdr->hdr.dst_port = dp;
617 full_hdr->hdr.checksum = 0;
618 return full_hdr;
619}
620
621/**
622 * Push SCTP header to buffer
623 *
624 * @param b - buffer to write the header to
625 * @param sp_net - source port net order
626 * @param dp_net - destination port net order
627 * @param sctp_hdr_opts_len - header and options length in bytes
628 *
629 * @return - pointer to start of SCTP header
630 */
631always_inline void *
632vlib_buffer_push_sctp (vlib_buffer_t * b, u16 sp_net, u16 dp_net,
633 u8 sctp_hdr_opts_len)
634{
635 return vlib_buffer_push_sctp_net_order (b, sp_net, dp_net,
636 sctp_hdr_opts_len);
637}
638
639/*
640 * fd.io coding-style-patch-verification: ON
641 *
642 * Local Variables:
643 * eval: (c-set-style "gnu")
644 * End:
645 */