tcp: timestamp adjustment
[vpp.git] / src / vnet / sctp / sctp_output_node.c
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 <vnet/sctp/sctp.h>
16 #include <vnet/sctp/sctp_debug.h>
17 #include <vppinfra/random.h>
18 #include <openssl/hmac.h>
19
20 u32
21 ip6_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
22                            ip6_header_t * ip0, int *bogus_lengthp);
23
24 u32
25 ip4_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
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 <vnet/sctp/sctp_error.def>
39 #undef sctp_error
40 };
41
42 typedef enum _sctp_output_next
43 {
44   SCTP_OUTPUT_NEXT_DROP,
45   SCTP_OUTPUT_NEXT_IP_LOOKUP,
46   SCTP_OUTPUT_N_NEXT
47 } sctp_output_next_t;
48
49 typedef struct
50 {
51   sctp_header_t sctp_header;
52   sctp_connection_t sctp_connection;
53 } sctp_tx_trace_t;
54
55 always_inline u8
56 sctp_is_retransmitting (sctp_connection_t * sctp_conn, u8 idx)
57 {
58   return sctp_conn->sub_conn[idx].is_retransmitting;
59 }
60
61 always_inline uword
62 sctp46_output_inline (vlib_main_t * vm,
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 =
89             SCTP_OUTPUT_NEXT_IP_LOOKUP;
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 =
105             sctp_connection_get (vnet_buffer (b0)->sctp.connection_index,
106                                  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 = vnet_buffer (b0)->sctp.subconn_idx;
116
117           th0 = vlib_buffer_get_current (b0);
118
119           if (is_ip4)
120             {
121               ip4_header_t *iph4 = vlib_buffer_push_ip4 (vm,
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
139 #if SCTP_DEBUG_STATE_MACHINE
140               packet_length = clib_net_to_host_u16 (iph4->length);
141 #endif
142             }
143           else
144             {
145               ip6_header_t *iph6 = vlib_buffer_push_ip6 (vm,
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,
155                                                          IP_PROTOCOL_SCTP);
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
167 #if SCTP_DEBUG_STATE_MACHINE
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             {
176               clib_warning
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
216           SCTP_DBG_STATE_MACHINE
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             {
229               SCTP_DBG_STATE_MACHINE
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
302           SCTP_DBG_STATE_MACHINE
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
309           vnet_sctp_common_hdr_params_host_to_net (&full_hdr->common_hdr);
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
339 VLIB_NODE_FN (sctp4_output_node) (vlib_main_t * vm,
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
346 VLIB_NODE_FN (sctp6_output_node) (vlib_main_t * vm,
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* */
354 VLIB_REGISTER_NODE (sctp4_output_node) =
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,
364     foreach_sctp4_output_next
365 #undef _
366     },
367     .format_buffer = format_sctp_header,
368     .format_trace = format_sctp_tx_trace,
369 };
370 /* *INDENT-ON* */
371
372 /* *INDENT-OFF* */
373 VLIB_REGISTER_NODE (sctp6_output_node) =
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,
383     foreach_sctp6_output_next
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  */