FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
sctp_output_node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 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 <sctp/sctp.h>
16 #include <sctp/sctp_debug.h>
17 #include <vppinfra/random.h>
18 #include <openssl/hmac.h>
19 
20 u32
22  ip6_header_t * ip0, int *bogus_lengthp);
23 
24 u32
26  ip4_header_t * ip0);
27 
28 #define foreach_sctp4_output_next \
29  _ (DROP, "error-drop") \
30  _ (IP_LOOKUP, "ip4-lookup")
31 
32 #define foreach_sctp6_output_next \
33  _ (DROP, "error-drop") \
34  _ (IP_LOOKUP, "ip6-lookup")
35 
36 static char *sctp_error_strings[] = {
37 #define sctp_error(n,s) s,
38 #include <sctp/sctp_error.def>
39 #undef sctp_error
40 };
41 
42 typedef enum _sctp_output_next
43 {
48 
49 typedef struct
50 {
54 
57 {
58  return sctp_conn->sub_conn[idx].is_retransmitting;
59 }
60 
63  vlib_node_runtime_t * node,
64  vlib_frame_t * from_frame, int is_ip4)
65 {
66  u32 n_left_from, next_index, *from, *to_next;
67  u32 my_thread_index = vm->thread_index;
68 
69  from = vlib_frame_vector_args (from_frame);
70  n_left_from = from_frame->n_vectors;
71  next_index = node->cached_next_index;
72  sctp_set_time_now (my_thread_index);
73 
74  while (n_left_from > 0)
75  {
76  u32 n_left_to_next;
77 
78  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
79 
80  while (n_left_from > 0 && n_left_to_next > 0)
81  {
82  u32 bi0;
83  vlib_buffer_t *b0;
84  sctp_header_t *sctp_hdr = 0;
85  sctp_connection_t *sctp_conn;
86  sctp_tx_trace_t *t0;
87  sctp_header_t *th0 = 0;
88  u32 error0 = SCTP_ERROR_PKTS_SENT, next0 =
90 
91 #if SCTP_DEBUG_STATE_MACHINE
92  u16 packet_length = 0;
93 #endif
94 
95  bi0 = from[0];
96  to_next[0] = bi0;
97  from += 1;
98  to_next += 1;
99  n_left_from -= 1;
100  n_left_to_next -= 1;
101 
102  b0 = vlib_get_buffer (vm, bi0);
103 
104  sctp_conn =
106  sctp.connection_index, my_thread_index);
107 
108  if (PREDICT_FALSE (sctp_conn == 0))
109  {
110  error0 = SCTP_ERROR_INVALID_CONNECTION;
111  next0 = SCTP_OUTPUT_NEXT_DROP;
112  goto done;
113  }
114 
115  u8 idx = sctp_buffer_opaque (b0)->sctp.subconn_idx;
116 
117  th0 = vlib_buffer_get_current (b0);
118 
119  if (is_ip4)
120  {
122  b0,
123  &sctp_conn->sub_conn
124  [idx].connection.
125  lcl_ip.ip4,
126  &sctp_conn->
127  sub_conn
128  [idx].connection.
129  rmt_ip.ip4,
130  IP_PROTOCOL_SCTP, 1);
131 
132  u32 checksum = ip4_sctp_compute_checksum (vm, b0, iph4);
133 
134  sctp_hdr = ip4_next_header (iph4);
135  sctp_hdr->checksum = checksum;
136 
137  vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
138 
140  packet_length = clib_net_to_host_u16 (iph4->length);
141 #endif
142  }
143  else
144  {
146  b0,
147  &sctp_conn->sub_conn
148  [idx].
149  connection.lcl_ip.
150  ip6,
151  &sctp_conn->sub_conn
152  [idx].
153  connection.rmt_ip.
154  ip6,
156 
157  int bogus = ~0;
158  u32 checksum = ip6_sctp_compute_checksum (vm, b0, iph6, &bogus);
159  ASSERT (!bogus);
160 
161  sctp_hdr = ip6_next_header (iph6);
162  sctp_hdr->checksum = checksum;
163 
164  vnet_buffer (b0)->l3_hdr_offset = (u8 *) iph6 - b0->data;
165  vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
166 
168  packet_length = clib_net_to_host_u16 (iph6->payload_length);
169 #endif
170  }
171 
172  sctp_full_hdr_t *full_hdr = (sctp_full_hdr_t *) sctp_hdr;
173  u8 chunk_type = vnet_sctp_get_chunk_type (&full_hdr->common_hdr);
174  if (chunk_type >= UNKNOWN)
175  {
177  ("Trying to send an unrecognized chunk... something is really bad.");
178  error0 = SCTP_ERROR_UNKNOWN_CHUNK;
179  next0 = SCTP_OUTPUT_NEXT_DROP;
180  goto done;
181  }
182 
183 #if SCTP_DEBUG_STATE_MACHINE
184  u8 is_valid =
185  (sctp_conn->sub_conn[idx].connection.lcl_port ==
186  sctp_hdr->src_port
187  || sctp_conn->sub_conn[idx].connection.lcl_port ==
188  sctp_hdr->dst_port)
189  && (sctp_conn->sub_conn[idx].connection.rmt_port ==
190  sctp_hdr->dst_port
191  || sctp_conn->sub_conn[idx].connection.rmt_port ==
192  sctp_hdr->src_port);
193 
194  if (!is_valid)
195  {
196  SCTP_DBG_STATE_MACHINE ("BUFFER IS INCORRECT: conn_index = %u, "
197  "packet_length = %u, "
198  "chunk_type = %u [%s], "
199  "connection.lcl_port = %u, sctp_hdr->src_port = %u, "
200  "connection.rmt_port = %u, sctp_hdr->dst_port = %u",
201  sctp_conn->sub_conn[idx].
202  connection.c_index, packet_length,
203  chunk_type,
204  sctp_chunk_to_string (chunk_type),
205  sctp_conn->sub_conn[idx].
206  connection.lcl_port, sctp_hdr->src_port,
207  sctp_conn->sub_conn[idx].
208  connection.rmt_port,
209  sctp_hdr->dst_port);
210 
211  error0 = SCTP_ERROR_UNKNOWN_CHUNK;
212  next0 = SCTP_OUTPUT_NEXT_DROP;
213  goto done;
214  }
215 #endif
217  ("SESSION_INDEX = %u, CONN_INDEX = %u, CURR_CONN_STATE = %u (%s), "
218  "CHUNK_TYPE = %s, " "SRC_PORT = %u, DST_PORT = %u",
219  sctp_conn->sub_conn[idx].connection.s_index,
220  sctp_conn->sub_conn[idx].connection.c_index,
221  sctp_conn->state, sctp_state_to_string (sctp_conn->state),
222  sctp_chunk_to_string (chunk_type), full_hdr->hdr.src_port,
223  full_hdr->hdr.dst_port);
224 
225  /* Let's make sure the state-machine does not send anything crazy */
226 #if SCTP_DEBUG_STATE_MACHINE
227  if (sctp_validate_output_state_machine (sctp_conn, chunk_type) != 0)
228  {
230  ("Sending the wrong chunk (%s) based on state-machine status (%s)",
231  sctp_chunk_to_string (chunk_type),
232  sctp_state_to_string (sctp_conn->state));
233 
234  error0 = SCTP_ERROR_UNKNOWN_CHUNK;
235  next0 = SCTP_OUTPUT_NEXT_DROP;
236  goto done;
237 
238  }
239 #endif
240 
241  /* Karn's algorithm: RTT measurements MUST NOT be made using
242  * packets that were retransmitted
243  */
244  if (!sctp_is_retransmitting (sctp_conn, idx))
245  {
246  /* Measure RTT with this */
247  if (chunk_type == DATA
248  && sctp_conn->sub_conn[idx].RTO_pending == 0)
249  {
250  sctp_conn->sub_conn[idx].RTO_pending = 1;
251  sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
252  }
253  else
254  sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
255  }
256 
257  /* Let's take care of TIMERS */
258  switch (chunk_type)
259  {
260  case COOKIE_ECHO:
261  {
262  sctp_conn->state = SCTP_STATE_COOKIE_ECHOED;
263  break;
264  }
265  case DATA:
266  {
267  SCTP_ADV_DBG_OUTPUT ("PACKET_LENGTH = %u", packet_length);
268 
269  sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX,
270  sctp_conn->sub_conn[idx].RTO);
271  break;
272  }
273  case SHUTDOWN:
274  {
275  /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
276  sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
277  sctp_conn->sub_conn[idx].RTO);
278  sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT;
279  break;
280  }
281  case SHUTDOWN_ACK:
282  {
283  /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
284  sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
285  sctp_conn->sub_conn[idx].RTO);
286  sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
287  break;
288  }
289  case SHUTDOWN_COMPLETE:
290  {
291  sctp_conn->state = SCTP_STATE_CLOSED;
292  break;
293  }
294  }
295 
296  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
297  vnet_buffer (b0)->sw_if_index[VLIB_TX] =
298  sctp_conn->sub_conn[idx].c_fib_index;
299 
300  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
301 
303  ("SESSION_INDEX = %u, CONNECTION_INDEX = %u, " "NEW_STATE = %s, "
304  "CHUNK_SENT = %s", sctp_conn->sub_conn[idx].connection.s_index,
305  sctp_conn->sub_conn[idx].connection.c_index,
306  sctp_state_to_string (sctp_conn->state),
307  sctp_chunk_to_string (chunk_type));
308 
310 
311  done:
312  b0->error = node->errors[error0];
313  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
314  {
315  t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
316  if (th0)
317  {
318  clib_memcpy_fast (&t0->sctp_header, th0,
319  sizeof (t0->sctp_header));
320  }
321  else
322  {
323  clib_memset (&t0->sctp_header, 0, sizeof (t0->sctp_header));
324  }
325  clib_memcpy_fast (&t0->sctp_connection, sctp_conn,
326  sizeof (t0->sctp_connection));
327  }
328 
329  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
330  n_left_to_next, bi0, next0);
331  }
332 
333  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
334  }
335 
336  return from_frame->n_vectors;
337 }
338 
340  vlib_node_runtime_t * node,
341  vlib_frame_t * from_frame)
342 {
343  return sctp46_output_inline (vm, node, from_frame, 1 /* is_ip4 */ );
344 }
345 
347  vlib_node_runtime_t * node,
348  vlib_frame_t * from_frame)
349 {
350  return sctp46_output_inline (vm, node, from_frame, 0 /* is_ip4 */ );
351 }
352 
353 /* *INDENT-OFF* */
355 {
356  .name = "sctp4-output",
357  /* Takes a vector of packets. */
358  .vector_size = sizeof (u32),
359  .n_errors = SCTP_N_ERROR,
360  .error_strings = sctp_error_strings,
361  .n_next_nodes = SCTP_OUTPUT_N_NEXT,
362  .next_nodes = {
363 #define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
365 #undef _
366  },
367  .format_buffer = format_sctp_header,
368  .format_trace = format_sctp_tx_trace,
369 };
370 /* *INDENT-ON* */
371 
372 /* *INDENT-OFF* */
374 {
375  .name = "sctp6-output",
376  /* Takes a vector of packets. */
377  .vector_size = sizeof (u32),
378  .n_errors = SCTP_N_ERROR,
379  .error_strings = sctp_error_strings,
380  .n_next_nodes = SCTP_OUTPUT_N_NEXT,
381  .next_nodes = {
382 #define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
384 #undef _
385  },
386  .format_buffer = format_sctp_header,
387  .format_trace = format_sctp_tx_trace,
388 };
389 /* *INDENT-ON* */
390 
391 /*
392  * fd.io coding-style-patch-verification: ON
393  *
394  * Local Variables:
395  * eval: (c-set-style "gnu")
396  * End:
397  */
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
static void sctp_timer_set(sctp_connection_t *tc, u8 conn_idx, u8 timer_id, u32 interval)
Definition: sctp.h:627
#define SCTP_ADV_DBG_OUTPUT(_fmt, _args...)
Definition: sctp_debug.h:59
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 ip4_sctp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip4_header_t *ip0)
Definition: sctp_output.c:67
static u64 sctp_time_now(void)
Definition: sctp.h:702
u32 thread_index
Definition: main.h:218
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
unsigned char u8
Definition: types.h:56
static void vnet_sctp_common_hdr_params_host_to_net(sctp_chunks_common_hdr_t *h)
Definition: sctp_packet.h:284
#define foreach_sctp6_output_next
#define always_inline
Definition: clib.h:99
enum _sctp_output_next sctp_output_next_t
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
static char * sctp_error_strings[]
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
static uword sctp46_output_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, int is_ip4)
unsigned short u16
Definition: types.h:57
u8 * format_sctp_tx_trace(u8 *s, va_list *args)
Definition: sctp_format.c:26
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:112
struct _sctp_connection sctp_connection_t
static u64 sctp_set_time_now(u32 thread_index)
Definition: sctp.h:619
vlib_node_registration_t sctp4_output_node
(constructor) VLIB_REGISTER_NODE (sctp4_output_node)
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
vlib_node_registration_t sctp6_output_node
(constructor) VLIB_REGISTER_NODE (sctp6_output_node)
static char * sctp_state_to_string(u8 state)
Definition: sctp.h:392
static u8 vnet_sctp_get_chunk_type(sctp_chunks_common_hdr_t *h)
Definition: sctp_packet.h:342
sctp_chunks_common_hdr_t common_hdr
Definition: sctp_packet.h:261
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:397
#define sctp_buffer_opaque(b)
Definition: sctp.h:46
vlib_main_t * vm
Definition: buffer.c:323
#define foreach_sctp4_output_next
#define IP_PROTOCOL_SCTP
Definition: sctp.h:370
#define clib_warning(format, args...)
Definition: error.h:59
u8 data[]
Packet data.
Definition: buffer.h:181
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:456
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:410
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
#define ASSERT(truth)
sctp_connection_t sctp_connection
u32 ip6_sctp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: sctp_output.c:124
sctp_header_t sctp_header
static void sctp_timer_update(sctp_connection_t *tc, u8 conn_idx, u8 timer_id, u32 interval)
Definition: sctp.h:763
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
Definition: defs.h:47
static sctp_connection_t * sctp_connection_get(u32 conn_index, u32 thread_index)
Definition: sctp.h:788
u16 payload_length
Definition: ip6_packet.h:374
static void * vlib_buffer_push_ip6(vlib_main_t *vm, vlib_buffer_t *b, ip6_address_t *src, ip6_address_t *dst, int proto)
Push IPv6 header to buffer.
Definition: ip6.h:663
u8 * format_sctp_header(u8 *s, va_list *args)
Definition: sctp_format.c:20
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
#define SCTP_DEBUG_STATE_MACHINE
Definition: sctp_debug.h:27
Linear Congruential Random Number Generator.
#define vnet_buffer(b)
Definition: buffer.h:365
static char * sctp_chunk_to_string(u8 type)
Definition: sctp.h:417
static u8 sctp_is_retransmitting(sctp_connection_t *sctp_conn, u8 idx)
sctp_header_t hdr
Definition: sctp_packet.h:260
static void * vlib_buffer_push_ip4(vlib_main_t *vm, vlib_buffer_t *b, ip4_address_t *src, ip4_address_t *dst, int proto, u8 csum_offload)
Push IPv4 header to buffer.
Definition: ip4.h:386
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
#define SCTP_DBG_STATE_MACHINE(_fmt, _args...)
Definition: sctp_debug.h:31
Definition: defs.h:46