Fix TCP loss recovery, VPP-745
[vpp.git] / src / vnet / tcp / tcp_output.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
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
16 #include <vnet/tcp/tcp.h>
17 #include <vnet/lisp-cp/packets.h>
18
19 vlib_node_registration_t tcp4_output_node;
20 vlib_node_registration_t tcp6_output_node;
21
22 typedef enum _tcp_output_nect
23 {
24   TCP_OUTPUT_NEXT_DROP,
25   TCP_OUTPUT_NEXT_IP_LOOKUP,
26   TCP_OUTPUT_N_NEXT
27 } tcp_output_next_t;
28
29 #define foreach_tcp4_output_next                \
30   _ (DROP, "error-drop")                        \
31   _ (IP_LOOKUP, "ip4-lookup")
32
33 #define foreach_tcp6_output_next                \
34   _ (DROP, "error-drop")                        \
35   _ (IP_LOOKUP, "ip6-lookup")
36
37 static char *tcp_error_strings[] = {
38 #define tcp_error(n,s) s,
39 #include <vnet/tcp/tcp_error.def>
40 #undef tcp_error
41 };
42
43 typedef struct
44 {
45   tcp_header_t tcp_header;
46   tcp_connection_t tcp_connection;
47 } tcp_tx_trace_t;
48
49 u16 dummy_mtu = 400;
50
51 u8 *
52 format_tcp_tx_trace (u8 * s, va_list * args)
53 {
54   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
55   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
56   tcp_tx_trace_t *t = va_arg (*args, tcp_tx_trace_t *);
57   uword indent = format_get_indent (s);
58
59   s = format (s, "%U\n%U%U",
60               format_tcp_header, &t->tcp_header, 128,
61               format_white_space, indent,
62               format_tcp_connection_verbose, &t->tcp_connection);
63
64   return s;
65 }
66
67 void
68 tcp_set_snd_mss (tcp_connection_t * tc)
69 {
70   u16 snd_mss;
71
72   /* TODO find our iface MTU */
73   snd_mss = dummy_mtu;
74
75   /* TODO cache mss and consider PMTU discovery */
76   snd_mss = clib_min (tc->opt.mss, snd_mss);
77
78   tc->snd_mss = snd_mss;
79
80   if (tc->snd_mss == 0)
81     {
82       clib_warning ("snd mss is 0");
83       tc->snd_mss = dummy_mtu;
84     }
85 }
86
87 static u8
88 tcp_window_compute_scale (u32 available_space)
89 {
90   u8 wnd_scale = 0;
91   while (wnd_scale < TCP_MAX_WND_SCALE
92          && (available_space >> wnd_scale) > TCP_WND_MAX)
93     wnd_scale++;
94   return wnd_scale;
95 }
96
97 /**
98  * TCP's IW as recommended by RFC6928
99  */
100 always_inline u32
101 tcp_initial_wnd_unscaled (tcp_connection_t * tc)
102 {
103   return TCP_IW_N_SEGMENTS * dummy_mtu;
104 }
105
106 /**
107  * Compute initial window and scale factor. As per RFC1323, window field in
108  * SYN and SYN-ACK segments is never scaled.
109  */
110 u32
111 tcp_initial_window_to_advertise (tcp_connection_t * tc)
112 {
113   u32 max_fifo;
114
115   /* Initial wnd for SYN. Fifos are not allocated yet.
116    * Use some predefined value. For SYN-ACK we still want the
117    * scale to be computed in the same way */
118   max_fifo = TCP_MAX_RX_FIFO_SIZE;
119
120   tc->rcv_wscale = tcp_window_compute_scale (max_fifo);
121   tc->rcv_wnd = tcp_initial_wnd_unscaled (tc);
122
123   return clib_min (tc->rcv_wnd, TCP_WND_MAX);
124 }
125
126 /**
127  * Compute and return window to advertise, scaled as per RFC1323
128  */
129 u32
130 tcp_window_to_advertise (tcp_connection_t * tc, tcp_state_t state)
131 {
132   if (state < TCP_STATE_ESTABLISHED)
133     return tcp_initial_window_to_advertise (tc);
134
135   tcp_update_rcv_wnd (tc);
136
137   if (tc->rcv_wnd == 0)
138     {
139       tc->flags |= TCP_CONN_SENT_RCV_WND0;
140     }
141   else
142     {
143       tc->flags &= ~TCP_CONN_SENT_RCV_WND0;
144     }
145
146   return tc->rcv_wnd >> tc->rcv_wscale;
147 }
148
149 void
150 tcp_update_rcv_wnd (tcp_connection_t * tc)
151 {
152   i32 observed_wnd;
153   u32 available_space, max_fifo, wnd;
154
155   /*
156    * Figure out how much space we have available
157    */
158   available_space = stream_session_max_rx_enqueue (&tc->connection);
159   max_fifo = stream_session_fifo_size (&tc->connection);
160
161   ASSERT (tc->opt.mss < max_fifo);
162   if (available_space < tc->opt.mss && available_space < max_fifo >> 3)
163     available_space = 0;
164
165   /*
166    * Use the above and what we know about what we've previously advertised
167    * to compute the new window
168    */
169   observed_wnd = (i32) tc->rcv_wnd - (tc->rcv_nxt - tc->rcv_las);
170   if (observed_wnd < 0)
171     observed_wnd = 0;
172
173   /* Bad. Thou shalt not shrink */
174   if (available_space < observed_wnd)
175     {
176       wnd = observed_wnd;
177       TCP_EVT_DBG (TCP_EVT_RCV_WND_SHRUNK, tc, observed_wnd, available_space);
178     }
179   else
180     {
181       wnd = available_space;
182     }
183
184   /* Make sure we have a multiple of rcv_wscale */
185   if (wnd && tc->rcv_wscale)
186     {
187       wnd &= ~(1 << tc->rcv_wscale);
188       if (wnd == 0)
189         wnd = 1 << tc->rcv_wscale;
190     }
191
192   tc->rcv_wnd = clib_min (wnd, TCP_WND_MAX << tc->rcv_wscale);
193 }
194
195 /**
196  * Write TCP options to segment.
197  */
198 u32
199 tcp_options_write (u8 * data, tcp_options_t * opts)
200 {
201   u32 opts_len = 0;
202   u32 buf, seq_len = 4;
203
204   if (tcp_opts_mss (opts))
205     {
206       *data++ = TCP_OPTION_MSS;
207       *data++ = TCP_OPTION_LEN_MSS;
208       buf = clib_host_to_net_u16 (opts->mss);
209       clib_memcpy (data, &buf, sizeof (opts->mss));
210       data += sizeof (opts->mss);
211       opts_len += TCP_OPTION_LEN_MSS;
212     }
213
214   if (tcp_opts_wscale (opts))
215     {
216       *data++ = TCP_OPTION_WINDOW_SCALE;
217       *data++ = TCP_OPTION_LEN_WINDOW_SCALE;
218       *data++ = opts->wscale;
219       opts_len += TCP_OPTION_LEN_WINDOW_SCALE;
220     }
221
222   if (tcp_opts_sack_permitted (opts))
223     {
224       *data++ = TCP_OPTION_SACK_PERMITTED;
225       *data++ = TCP_OPTION_LEN_SACK_PERMITTED;
226       opts_len += TCP_OPTION_LEN_SACK_PERMITTED;
227     }
228
229   if (tcp_opts_tstamp (opts))
230     {
231       *data++ = TCP_OPTION_TIMESTAMP;
232       *data++ = TCP_OPTION_LEN_TIMESTAMP;
233       buf = clib_host_to_net_u32 (opts->tsval);
234       clib_memcpy (data, &buf, sizeof (opts->tsval));
235       data += sizeof (opts->tsval);
236       buf = clib_host_to_net_u32 (opts->tsecr);
237       clib_memcpy (data, &buf, sizeof (opts->tsecr));
238       data += sizeof (opts->tsecr);
239       opts_len += TCP_OPTION_LEN_TIMESTAMP;
240     }
241
242   if (tcp_opts_sack (opts))
243     {
244       int i;
245       u32 n_sack_blocks = clib_min (vec_len (opts->sacks),
246                                     TCP_OPTS_MAX_SACK_BLOCKS);
247
248       if (n_sack_blocks != 0)
249         {
250           *data++ = TCP_OPTION_SACK_BLOCK;
251           *data++ = 2 + n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
252           for (i = 0; i < n_sack_blocks; i++)
253             {
254               buf = clib_host_to_net_u32 (opts->sacks[i].start);
255               clib_memcpy (data, &buf, seq_len);
256               data += seq_len;
257               buf = clib_host_to_net_u32 (opts->sacks[i].end);
258               clib_memcpy (data, &buf, seq_len);
259               data += seq_len;
260             }
261           opts_len += 2 + n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
262         }
263     }
264
265   /* Terminate TCP options */
266   if (opts_len % 4)
267     {
268       *data++ = TCP_OPTION_EOL;
269       opts_len += TCP_OPTION_LEN_EOL;
270     }
271
272   /* Pad with zeroes to a u32 boundary */
273   while (opts_len % 4)
274     {
275       *data++ = TCP_OPTION_NOOP;
276       opts_len += TCP_OPTION_LEN_NOOP;
277     }
278   return opts_len;
279 }
280
281 always_inline int
282 tcp_make_syn_options (tcp_options_t * opts, u8 wnd_scale)
283 {
284   u8 len = 0;
285
286   opts->flags |= TCP_OPTS_FLAG_MSS;
287   opts->mss = dummy_mtu;        /*XXX discover that */
288   len += TCP_OPTION_LEN_MSS;
289
290   opts->flags |= TCP_OPTS_FLAG_WSCALE;
291   opts->wscale = wnd_scale;
292   len += TCP_OPTION_LEN_WINDOW_SCALE;
293
294   opts->flags |= TCP_OPTS_FLAG_TSTAMP;
295   opts->tsval = tcp_time_now ();
296   opts->tsecr = 0;
297   len += TCP_OPTION_LEN_TIMESTAMP;
298
299   opts->flags |= TCP_OPTS_FLAG_SACK_PERMITTED;
300   len += TCP_OPTION_LEN_SACK_PERMITTED;
301
302   /* Align to needed boundary */
303   len += (TCP_OPTS_ALIGN - len % TCP_OPTS_ALIGN) % TCP_OPTS_ALIGN;
304   return len;
305 }
306
307 always_inline int
308 tcp_make_synack_options (tcp_connection_t * tc, tcp_options_t * opts)
309 {
310   u8 len = 0;
311
312   opts->flags |= TCP_OPTS_FLAG_MSS;
313   opts->mss = dummy_mtu;        /*XXX discover that */
314   len += TCP_OPTION_LEN_MSS;
315
316   if (tcp_opts_wscale (&tc->opt))
317     {
318       opts->flags |= TCP_OPTS_FLAG_WSCALE;
319       opts->wscale = tc->rcv_wscale;
320       len += TCP_OPTION_LEN_WINDOW_SCALE;
321     }
322
323   if (tcp_opts_tstamp (&tc->opt))
324     {
325       opts->flags |= TCP_OPTS_FLAG_TSTAMP;
326       opts->tsval = tcp_time_now ();
327       opts->tsecr = tc->tsval_recent;
328       len += TCP_OPTION_LEN_TIMESTAMP;
329     }
330
331   if (tcp_opts_sack_permitted (&tc->opt))
332     {
333       opts->flags |= TCP_OPTS_FLAG_SACK_PERMITTED;
334       len += TCP_OPTION_LEN_SACK_PERMITTED;
335     }
336
337   /* Align to needed boundary */
338   len += (TCP_OPTS_ALIGN - len % TCP_OPTS_ALIGN) % TCP_OPTS_ALIGN;
339   return len;
340 }
341
342 always_inline int
343 tcp_make_established_options (tcp_connection_t * tc, tcp_options_t * opts)
344 {
345   u8 len = 0;
346
347   opts->flags = 0;
348
349   if (tcp_opts_tstamp (&tc->opt))
350     {
351       opts->flags |= TCP_OPTS_FLAG_TSTAMP;
352       opts->tsval = tcp_time_now ();
353       opts->tsecr = tc->tsval_recent;
354       len += TCP_OPTION_LEN_TIMESTAMP;
355     }
356   if (tcp_opts_sack_permitted (&tc->opt))
357     {
358       if (vec_len (tc->snd_sacks))
359         {
360           opts->flags |= TCP_OPTS_FLAG_SACK;
361           opts->sacks = tc->snd_sacks;
362           opts->n_sack_blocks = clib_min (vec_len (tc->snd_sacks),
363                                           TCP_OPTS_MAX_SACK_BLOCKS);
364           len += 2 + TCP_OPTION_LEN_SACK_BLOCK * opts->n_sack_blocks;
365         }
366     }
367
368   /* Align to needed boundary */
369   len += (TCP_OPTS_ALIGN - len % TCP_OPTS_ALIGN) % TCP_OPTS_ALIGN;
370   return len;
371 }
372
373 always_inline int
374 tcp_make_options (tcp_connection_t * tc, tcp_options_t * opts,
375                   tcp_state_t state)
376 {
377   switch (state)
378     {
379     case TCP_STATE_ESTABLISHED:
380     case TCP_STATE_FIN_WAIT_1:
381       return tcp_make_established_options (tc, opts);
382     case TCP_STATE_SYN_RCVD:
383       return tcp_make_synack_options (tc, opts);
384     case TCP_STATE_SYN_SENT:
385       return tcp_make_syn_options (opts, tc->rcv_wscale);
386     default:
387       clib_warning ("Not handled!");
388       return 0;
389     }
390 }
391
392 #define tcp_get_free_buffer_index(tm, bidx)                             \
393 do {                                                                    \
394   u32 *my_tx_buffers, n_free_buffers;                                   \
395   u32 thread_index = vlib_get_thread_index();                                   \
396   my_tx_buffers = tm->tx_buffers[thread_index];                            \
397   if (PREDICT_FALSE(vec_len (my_tx_buffers) == 0))                      \
398     {                                                                   \
399       n_free_buffers = 32;      /* TODO config or macro */              \
400       vec_validate (my_tx_buffers, n_free_buffers - 1);                 \
401       _vec_len(my_tx_buffers) = vlib_buffer_alloc_from_free_list (      \
402           tm->vlib_main, my_tx_buffers, n_free_buffers,                 \
403           VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);                         \
404       tm->tx_buffers[thread_index] = my_tx_buffers;                        \
405     }                                                                   \
406   /* buffer shortage */                                                 \
407   if (PREDICT_FALSE (vec_len (my_tx_buffers) == 0))                     \
408     return;                                                             \
409   *bidx = my_tx_buffers[_vec_len (my_tx_buffers)-1];                    \
410   _vec_len (my_tx_buffers) -= 1;                                        \
411 } while (0)
412
413 #define tcp_return_buffer(tm)                                           \
414 do {                                                                    \
415   u32 *my_tx_buffers;                                                   \
416   u32 thread_index = vlib_get_thread_index();                                   \
417   my_tx_buffers = tm->tx_buffers[thread_index];                                 \
418   _vec_len (my_tx_buffers) +=1;                                         \
419 } while (0)
420
421 always_inline void
422 tcp_reuse_buffer (vlib_main_t * vm, vlib_buffer_t * b)
423 {
424   vlib_buffer_t *it = b;
425   do
426     {
427       it->current_data = 0;
428       it->current_length = 0;
429       it->total_length_not_including_first_buffer = 0;
430     }
431   while ((it->flags & VLIB_BUFFER_NEXT_PRESENT)
432          && (it = vlib_get_buffer (vm, it->next_buffer)));
433
434   /* Leave enough space for headers */
435   vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
436   vnet_buffer (b)->tcp.flags = 0;
437 }
438
439 /**
440  * Prepare ACK
441  */
442 void
443 tcp_make_ack_i (tcp_connection_t * tc, vlib_buffer_t * b, tcp_state_t state,
444                 u8 flags)
445 {
446   tcp_options_t _snd_opts, *snd_opts = &_snd_opts;
447   u8 tcp_opts_len, tcp_hdr_opts_len;
448   tcp_header_t *th;
449   u16 wnd;
450
451   wnd = tcp_window_to_advertise (tc, state);
452
453   /* Make and write options */
454   tcp_opts_len = tcp_make_established_options (tc, snd_opts);
455   tcp_hdr_opts_len = tcp_opts_len + sizeof (tcp_header_t);
456
457   th = vlib_buffer_push_tcp (b, tc->c_lcl_port, tc->c_rmt_port, tc->snd_nxt,
458                              tc->rcv_nxt, tcp_hdr_opts_len, flags, wnd);
459
460   tcp_options_write ((u8 *) (th + 1), snd_opts);
461   vnet_buffer (b)->tcp.connection_index = tc->c_c_index;
462 }
463
464 /**
465  * Convert buffer to ACK
466  */
467 void
468 tcp_make_ack (tcp_connection_t * tc, vlib_buffer_t * b)
469 {
470   vlib_main_t *vm = vlib_get_main ();
471
472   tcp_reuse_buffer (vm, b);
473   tcp_make_ack_i (tc, b, TCP_STATE_ESTABLISHED, TCP_FLAG_ACK);
474   TCP_EVT_DBG (TCP_EVT_ACK_SENT, tc);
475   vnet_buffer (b)->tcp.flags = TCP_BUF_FLAG_ACK;
476   tc->rcv_las = tc->rcv_nxt;
477 }
478
479 /**
480  * Convert buffer to FIN-ACK
481  */
482 void
483 tcp_make_fin (tcp_connection_t * tc, vlib_buffer_t * b)
484 {
485   vlib_main_t *vm = vlib_get_main ();
486   u8 flags = 0;
487
488   tcp_reuse_buffer (vm, b);
489
490   flags = TCP_FLAG_FIN | TCP_FLAG_ACK;
491   tcp_make_ack_i (tc, b, TCP_STATE_ESTABLISHED, flags);
492
493   /* Reset flags, make sure ack is sent */
494   vnet_buffer (b)->tcp.flags &= ~TCP_BUF_FLAG_DUPACK;
495
496   tc->snd_nxt += 1;
497 }
498
499 /**
500  * Convert buffer to SYN-ACK
501  */
502 void
503 tcp_make_synack (tcp_connection_t * tc, vlib_buffer_t * b)
504 {
505   vlib_main_t *vm = vlib_get_main ();
506   tcp_options_t _snd_opts, *snd_opts = &_snd_opts;
507   u8 tcp_opts_len, tcp_hdr_opts_len;
508   tcp_header_t *th;
509   u16 initial_wnd;
510   u32 time_now;
511
512   memset (snd_opts, 0, sizeof (*snd_opts));
513
514   tcp_reuse_buffer (vm, b);
515
516   /* Set random initial sequence */
517   time_now = tcp_time_now ();
518
519   tc->iss = random_u32 (&time_now);
520   tc->snd_una = tc->iss;
521   tc->snd_nxt = tc->iss + 1;
522   tc->snd_una_max = tc->snd_nxt;
523
524   initial_wnd = tcp_initial_window_to_advertise (tc);
525
526   /* Make and write options */
527   tcp_opts_len = tcp_make_synack_options (tc, snd_opts);
528   tcp_hdr_opts_len = tcp_opts_len + sizeof (tcp_header_t);
529
530   th = vlib_buffer_push_tcp (b, tc->c_lcl_port, tc->c_rmt_port, tc->iss,
531                              tc->rcv_nxt, tcp_hdr_opts_len,
532                              TCP_FLAG_SYN | TCP_FLAG_ACK, initial_wnd);
533
534   tcp_options_write ((u8 *) (th + 1), snd_opts);
535
536   vnet_buffer (b)->tcp.connection_index = tc->c_c_index;
537   vnet_buffer (b)->tcp.flags = TCP_BUF_FLAG_ACK;
538
539   /* Init retransmit timer */
540   tcp_retransmit_timer_set (tc);
541 }
542
543 always_inline void
544 tcp_enqueue_to_ip_lookup (vlib_main_t * vm, vlib_buffer_t * b, u32 bi,
545                           u8 is_ip4)
546 {
547   u32 *to_next, next_index;
548   vlib_frame_t *f;
549
550   b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
551   b->error = 0;
552
553   /* Default FIB for now */
554   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
555
556   /* Send to IP lookup */
557   next_index = is_ip4 ? ip4_lookup_node.index : ip6_lookup_node.index;
558   f = vlib_get_frame_to_node (vm, next_index);
559
560   /* Enqueue the packet */
561   to_next = vlib_frame_vector_args (f);
562   to_next[0] = bi;
563   f->n_vectors = 1;
564   vlib_put_frame_to_node (vm, next_index, f);
565 }
566
567 int
568 tcp_make_reset_in_place (vlib_main_t * vm, vlib_buffer_t * b0,
569                          tcp_state_t state, u32 my_thread_index, u8 is_ip4)
570 {
571   u8 tcp_hdr_len = sizeof (tcp_header_t);
572   ip4_header_t *ih4;
573   ip6_header_t *ih6;
574   tcp_header_t *th0;
575   ip4_address_t src_ip40;
576   ip6_address_t src_ip60;
577   u16 src_port0;
578   u32 tmp;
579
580   /* Find IP and TCP headers */
581   if (is_ip4)
582     {
583       ih4 = vlib_buffer_get_current (b0);
584       th0 = ip4_next_header (ih4);
585     }
586   else
587     {
588       ih6 = vlib_buffer_get_current (b0);
589       th0 = ip6_next_header (ih6);
590     }
591
592   /* Swap src and dst ip */
593   if (is_ip4)
594     {
595       ASSERT ((ih4->ip_version_and_header_length & 0xF0) == 0x40);
596       src_ip40.as_u32 = ih4->src_address.as_u32;
597       ih4->src_address.as_u32 = ih4->dst_address.as_u32;
598       ih4->dst_address.as_u32 = src_ip40.as_u32;
599
600       /* Chop the end of the pkt */
601       b0->current_length += ip4_header_bytes (ih4) + tcp_hdr_len;
602     }
603   else
604     {
605       ASSERT ((ih6->ip_version_traffic_class_and_flow_label & 0xF0) == 0x60);
606       clib_memcpy (&src_ip60, &ih6->src_address, sizeof (ip6_address_t));
607       clib_memcpy (&ih6->src_address, &ih6->dst_address,
608                    sizeof (ip6_address_t));
609       clib_memcpy (&ih6->dst_address, &src_ip60, sizeof (ip6_address_t));
610
611       /* Chop the end of the pkt */
612       b0->current_length += sizeof (ip6_header_t) + tcp_hdr_len;
613     }
614
615   /* Try to determine what/why we're actually resetting and swap
616    * src and dst ports */
617   if (state == TCP_STATE_CLOSED)
618     {
619       if (!tcp_syn (th0))
620         return -1;
621
622       tmp = clib_net_to_host_u32 (th0->seq_number);
623
624       /* Got a SYN for no listener. */
625       th0->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
626       th0->ack_number = clib_host_to_net_u32 (tmp + 1);
627       th0->seq_number = 0;
628
629     }
630   else if (state >= TCP_STATE_SYN_SENT)
631     {
632       th0->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
633       th0->seq_number = th0->ack_number;
634       th0->ack_number = 0;
635     }
636
637   src_port0 = th0->src_port;
638   th0->src_port = th0->dst_port;
639   th0->dst_port = src_port0;
640   th0->window = 0;
641   th0->data_offset_and_reserved = (tcp_hdr_len >> 2) << 4;
642   th0->urgent_pointer = 0;
643
644   /* Compute checksum */
645   if (is_ip4)
646     {
647       th0->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ih4);
648     }
649   else
650     {
651       int bogus = ~0;
652       th0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ih6, &bogus);
653       ASSERT (!bogus);
654     }
655
656   return 0;
657 }
658
659 /**
660  *  Send reset without reusing existing buffer
661  */
662 void
663 tcp_send_reset (vlib_buffer_t * pkt, u8 is_ip4)
664 {
665   vlib_buffer_t *b;
666   u32 bi;
667   tcp_main_t *tm = vnet_get_tcp_main ();
668   vlib_main_t *vm = vlib_get_main ();
669   u8 tcp_hdr_len, flags = 0;
670   tcp_header_t *th, *pkt_th;
671   u32 seq, ack;
672   ip4_header_t *ih4, *pkt_ih4;
673   ip6_header_t *ih6, *pkt_ih6;
674
675   tcp_get_free_buffer_index (tm, &bi);
676   b = vlib_get_buffer (vm, bi);
677
678   /* Leave enough space for headers */
679   vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
680
681   /* Make and write options */
682   tcp_hdr_len = sizeof (tcp_header_t);
683
684   if (is_ip4)
685     {
686       pkt_ih4 = vlib_buffer_get_current (pkt);
687       pkt_th = ip4_next_header (pkt_ih4);
688     }
689   else
690     {
691       pkt_ih6 = vlib_buffer_get_current (pkt);
692       pkt_th = ip6_next_header (pkt_ih6);
693     }
694
695   if (tcp_ack (pkt_th))
696     {
697       flags = TCP_FLAG_RST;
698       seq = pkt_th->ack_number;
699       ack = 0;
700     }
701   else
702     {
703       flags = TCP_FLAG_RST | TCP_FLAG_ACK;
704       seq = 0;
705       ack = clib_host_to_net_u32 (vnet_buffer (pkt)->tcp.seq_end);
706     }
707
708   th = vlib_buffer_push_tcp_net_order (b, pkt_th->dst_port, pkt_th->src_port,
709                                        seq, ack, tcp_hdr_len, flags, 0);
710
711   /* Swap src and dst ip */
712   if (is_ip4)
713     {
714       ASSERT ((pkt_ih4->ip_version_and_header_length & 0xF0) == 0x40);
715       ih4 = vlib_buffer_push_ip4 (vm, b, &pkt_ih4->dst_address,
716                                   &pkt_ih4->src_address, IP_PROTOCOL_TCP);
717       th->checksum = ip4_tcp_udp_compute_checksum (vm, b, ih4);
718     }
719   else
720     {
721       int bogus = ~0;
722       pkt_ih6 = (ip6_header_t *) (pkt_th - 1);
723       ASSERT ((pkt_ih6->ip_version_traffic_class_and_flow_label & 0xF0) ==
724               0x60);
725       ih6 =
726         vlib_buffer_push_ip6 (vm, b, &pkt_ih6->dst_address,
727                               &pkt_ih6->src_address, IP_PROTOCOL_TCP);
728       th->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ih6, &bogus);
729       ASSERT (!bogus);
730     }
731
732   tcp_enqueue_to_ip_lookup (vm, b, bi, is_ip4);
733 }
734
735 void
736 tcp_push_ip_hdr (tcp_main_t * tm, tcp_connection_t * tc, vlib_buffer_t * b)
737 {
738   tcp_header_t *th = vlib_buffer_get_current (b);
739
740   if (tc->c_is_ip4)
741     {
742       ip4_header_t *ih;
743       ih = vlib_buffer_push_ip4 (tm->vlib_main, b, &tc->c_lcl_ip4,
744                                  &tc->c_rmt_ip4, IP_PROTOCOL_TCP);
745       th->checksum = ip4_tcp_udp_compute_checksum (tm->vlib_main, b, ih);
746     }
747   else
748     {
749       ip6_header_t *ih;
750       int bogus = ~0;
751
752       ih = vlib_buffer_push_ip6 (tm->vlib_main, b, &tc->c_lcl_ip6,
753                                  &tc->c_rmt_ip6, IP_PROTOCOL_TCP);
754       th->checksum = ip6_tcp_udp_icmp_compute_checksum (tm->vlib_main, b, ih,
755                                                         &bogus);
756       ASSERT (!bogus);
757     }
758 }
759
760 /**
761  *  Send SYN
762  *
763  *  Builds a SYN packet for a half-open connection and sends it to ipx_lookup.
764  *  The packet is not forwarded through tcpx_output to avoid doing lookups
765  *  in the half_open pool.
766  */
767 void
768 tcp_send_syn (tcp_connection_t * tc)
769 {
770   vlib_buffer_t *b;
771   u32 bi;
772   tcp_main_t *tm = vnet_get_tcp_main ();
773   vlib_main_t *vm = vlib_get_main ();
774   u8 tcp_hdr_opts_len, tcp_opts_len;
775   tcp_header_t *th;
776   u32 time_now;
777   u16 initial_wnd;
778   tcp_options_t snd_opts;
779
780   tcp_get_free_buffer_index (tm, &bi);
781   b = vlib_get_buffer (vm, bi);
782
783   /* Leave enough space for headers */
784   vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
785
786   /* Set random initial sequence */
787   time_now = tcp_time_now ();
788
789   tc->iss = random_u32 (&time_now);
790   tc->snd_una = tc->iss;
791   tc->snd_una_max = tc->snd_nxt = tc->iss + 1;
792
793   initial_wnd = tcp_initial_window_to_advertise (tc);
794
795   /* Make and write options */
796   memset (&snd_opts, 0, sizeof (snd_opts));
797   tcp_opts_len = tcp_make_syn_options (&snd_opts, tc->rcv_wscale);
798   tcp_hdr_opts_len = tcp_opts_len + sizeof (tcp_header_t);
799
800   th = vlib_buffer_push_tcp (b, tc->c_lcl_port, tc->c_rmt_port, tc->iss,
801                              tc->rcv_nxt, tcp_hdr_opts_len, TCP_FLAG_SYN,
802                              initial_wnd);
803
804   tcp_options_write ((u8 *) (th + 1), &snd_opts);
805
806   /* Measure RTT with this */
807   tc->rtt_ts = tcp_time_now ();
808   tc->rtt_seq = tc->snd_nxt;
809
810   /* Start retransmit trimer  */
811   tcp_timer_set (tc, TCP_TIMER_RETRANSMIT_SYN, tc->rto * TCP_TO_TIMER_TICK);
812   tc->rto_boff = 0;
813
814   /* Set the connection establishment timer */
815   tcp_timer_set (tc, TCP_TIMER_ESTABLISH, TCP_ESTABLISH_TIME);
816
817   tcp_push_ip_hdr (tm, tc, b);
818   tcp_enqueue_to_ip_lookup (vm, b, bi, tc->c_is_ip4);
819 }
820
821 always_inline void
822 tcp_enqueue_to_output (vlib_main_t * vm, vlib_buffer_t * b, u32 bi, u8 is_ip4)
823 {
824   u32 *to_next, next_index;
825   vlib_frame_t *f;
826
827   b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
828   b->error = 0;
829
830   /* Decide where to send the packet */
831   next_index = is_ip4 ? tcp4_output_node.index : tcp6_output_node.index;
832
833   /* Enqueue the packet */
834   f = vlib_get_frame_to_node (vm, next_index);
835   to_next = vlib_frame_vector_args (f);
836   to_next[0] = bi;
837   f->n_vectors = 1;
838   vlib_put_frame_to_node (vm, next_index, f);
839 }
840
841 /**
842  *  Send FIN
843  */
844 void
845 tcp_send_fin (tcp_connection_t * tc)
846 {
847   vlib_buffer_t *b;
848   u32 bi;
849   tcp_main_t *tm = vnet_get_tcp_main ();
850   vlib_main_t *vm = vlib_get_main ();
851
852   tcp_get_free_buffer_index (tm, &bi);
853   b = vlib_get_buffer (vm, bi);
854
855   /* Leave enough space for headers */
856   vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
857
858   tcp_make_fin (tc, b);
859   tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
860   tc->flags |= TCP_CONN_FINSNT;
861   TCP_EVT_DBG (TCP_EVT_FIN_SENT, tc);
862 }
863
864 always_inline u8
865 tcp_make_state_flags (tcp_state_t next_state)
866 {
867   switch (next_state)
868     {
869     case TCP_STATE_ESTABLISHED:
870       return TCP_FLAG_ACK;
871     case TCP_STATE_SYN_RCVD:
872       return TCP_FLAG_SYN | TCP_FLAG_ACK;
873     case TCP_STATE_SYN_SENT:
874       return TCP_FLAG_SYN;
875     case TCP_STATE_LAST_ACK:
876     case TCP_STATE_FIN_WAIT_1:
877       return TCP_FLAG_FIN;
878     default:
879       clib_warning ("Shouldn't be here!");
880     }
881   return 0;
882 }
883
884 /**
885  * Push TCP header and update connection variables
886  */
887 static void
888 tcp_push_hdr_i (tcp_connection_t * tc, vlib_buffer_t * b,
889                 tcp_state_t next_state)
890 {
891   u32 advertise_wnd, data_len;
892   u8 tcp_opts_len, tcp_hdr_opts_len, opts_write_len, flags;
893   tcp_options_t _snd_opts, *snd_opts = &_snd_opts;
894   tcp_header_t *th;
895
896   data_len = b->current_length;
897   vnet_buffer (b)->tcp.flags = 0;
898
899   /* Make and write options */
900   memset (snd_opts, 0, sizeof (*snd_opts));
901   tcp_opts_len = tcp_make_options (tc, snd_opts, next_state);
902   tcp_hdr_opts_len = tcp_opts_len + sizeof (tcp_header_t);
903
904   /* Get rcv window to advertise */
905   advertise_wnd = tcp_window_to_advertise (tc, next_state);
906   flags = tcp_make_state_flags (next_state);
907
908   /* Push header and options */
909   th = vlib_buffer_push_tcp (b, tc->c_lcl_port, tc->c_rmt_port, tc->snd_nxt,
910                              tc->rcv_nxt, tcp_hdr_opts_len, flags,
911                              advertise_wnd);
912
913   opts_write_len = tcp_options_write ((u8 *) (th + 1), snd_opts);
914
915   ASSERT (opts_write_len == tcp_opts_len);
916
917   /* Tag the buffer with the connection index  */
918   vnet_buffer (b)->tcp.connection_index = tc->c_c_index;
919
920   tc->snd_nxt += data_len;
921   tc->rcv_las = tc->rcv_nxt;
922
923   /* TODO this is updated in output as well ... */
924   if (tc->snd_nxt > tc->snd_una_max)
925     tc->snd_una_max = tc->snd_nxt;
926
927   if (tc->rtt_ts == 0)
928     {
929       tc->rtt_ts = tcp_time_now ();
930       tc->rtt_seq = tc->snd_nxt;
931     }
932   TCP_EVT_DBG (TCP_EVT_PKTIZE, tc);
933 }
934
935 void
936 tcp_send_ack (tcp_connection_t * tc)
937 {
938   tcp_main_t *tm = vnet_get_tcp_main ();
939   vlib_main_t *vm = vlib_get_main ();
940
941   vlib_buffer_t *b;
942   u32 bi;
943
944   /* Get buffer */
945   tcp_get_free_buffer_index (tm, &bi);
946   b = vlib_get_buffer (vm, bi);
947
948   /* Fill in the ACK */
949   tcp_make_ack (tc, b);
950   tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
951 }
952
953 /* Send delayed ACK when timer expires */
954 void
955 tcp_timer_delack_handler (u32 index)
956 {
957   u32 thread_index = vlib_get_thread_index ();
958   tcp_connection_t *tc;
959
960   tc = tcp_connection_get (index, thread_index);
961   tc->timers[TCP_TIMER_DELACK] = TCP_TIMER_HANDLE_INVALID;
962   tcp_send_ack (tc);
963 }
964
965 /** Build a retransmit segment
966  *
967  * @return the number of bytes in the segment or 0 if there's nothing to
968  *         retransmit
969  * */
970 u32
971 tcp_prepare_retransmit_segment (tcp_connection_t * tc, vlib_buffer_t * b,
972                                 u32 offset, u32 max_bytes)
973 {
974   vlib_main_t *vm = vlib_get_main ();
975   u32 n_bytes = 0;
976
977   tcp_reuse_buffer (vm, b);
978
979   ASSERT (tc->state >= TCP_STATE_ESTABLISHED);
980   ASSERT (max_bytes != 0);
981
982   max_bytes = clib_min (tc->snd_mss, max_bytes);
983
984   /* Start is beyond snd_congestion */
985   if (seq_geq (tc->snd_una + offset, tc->snd_congestion))
986     goto done;
987
988   /* Don't overshoot snd_congestion */
989   if (seq_gt (tc->snd_nxt + max_bytes, tc->snd_congestion))
990     {
991       max_bytes = tc->snd_congestion - tc->snd_nxt;
992       if (max_bytes == 0)
993         goto done;
994     }
995
996   ASSERT (max_bytes <= tc->snd_mss);
997
998   n_bytes = stream_session_peek_bytes (&tc->connection,
999                                        vlib_buffer_get_current (b), offset,
1000                                        max_bytes);
1001   ASSERT (n_bytes != 0);
1002   b->current_length = n_bytes;
1003   tcp_push_hdr_i (tc, b, tc->state);
1004   tc->rtx_bytes += n_bytes;
1005
1006 done:
1007   TCP_EVT_DBG (TCP_EVT_CC_RTX, tc, offset, n_bytes);
1008   return n_bytes;
1009 }
1010
1011 /**
1012  * Reset congestion control, switch cwnd to loss window and try again.
1013  */
1014 static void
1015 tcp_rtx_timeout_cc (tcp_connection_t * tc)
1016 {
1017   /* Cleanly recover cc (also clears up fast retransmit) */
1018   if (tcp_in_fastrecovery (tc))
1019     {
1020       tcp_cc_recover (tc);
1021     }
1022   else
1023     {
1024       tc->ssthresh = clib_max (tcp_flight_size (tc) / 2, 2 * tc->snd_mss);
1025     }
1026
1027   /* Start again from the beginning */
1028
1029   tc->cwnd = tcp_loss_wnd (tc);
1030   tc->snd_congestion = tc->snd_una_max;
1031   tcp_recovery_on (tc);
1032 }
1033
1034 static void
1035 tcp_timer_retransmit_handler_i (u32 index, u8 is_syn)
1036 {
1037   tcp_main_t *tm = vnet_get_tcp_main ();
1038   vlib_main_t *vm = vlib_get_main ();
1039   u32 thread_index = vlib_get_thread_index ();
1040   tcp_connection_t *tc;
1041   vlib_buffer_t *b;
1042   u32 bi, n_bytes;
1043
1044   if (is_syn)
1045     {
1046       tc = tcp_half_open_connection_get (index);
1047     }
1048   else
1049     {
1050       tc = tcp_connection_get (index, thread_index);
1051     }
1052
1053   /* Make sure timer handle is set to invalid */
1054   tc->timers[TCP_TIMER_RETRANSMIT] = TCP_TIMER_HANDLE_INVALID;
1055
1056   /* Increment RTO backoff (also equal to number of retries) */
1057   tc->rto_boff += 1;
1058
1059   /* Go back to first un-acked byte */
1060   tc->snd_nxt = tc->snd_una;
1061
1062   /* Get buffer */
1063   tcp_get_free_buffer_index (tm, &bi);
1064   b = vlib_get_buffer (vm, bi);
1065
1066   if (tc->state >= TCP_STATE_ESTABLISHED)
1067     {
1068       /* First retransmit timeout */
1069       if (tc->rto_boff == 1)
1070         tcp_rtx_timeout_cc (tc);
1071
1072       /* Exponential backoff */
1073       tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX);
1074
1075       TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 1);
1076
1077       /* Send one segment. No fancy recovery for now! */
1078       n_bytes = tcp_prepare_retransmit_segment (tc, b, 0, tc->snd_mss);
1079       scoreboard_clear (&tc->sack_sb);
1080
1081       if (n_bytes == 0)
1082         {
1083           clib_warning ("could not retransmit");
1084           return;
1085         }
1086     }
1087   else
1088     {
1089       /* Retransmit for SYN/SYNACK */
1090       ASSERT (tc->state == TCP_STATE_SYN_RCVD
1091               || tc->state == TCP_STATE_SYN_SENT);
1092
1093       /* Try without increasing RTO a number of times. If this fails,
1094        * start growing RTO exponentially */
1095       if (tc->rto_boff > TCP_RTO_SYN_RETRIES)
1096         tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX);
1097
1098       vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
1099
1100       tcp_push_hdr_i (tc, b, tc->state);
1101
1102       /* Account for the SYN */
1103       tc->snd_nxt += 1;
1104     }
1105
1106   if (!is_syn)
1107     {
1108       tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
1109
1110       /* Re-enable retransmit timer */
1111       tcp_retransmit_timer_set (tc);
1112     }
1113   else
1114     {
1115       ASSERT (tc->state == TCP_STATE_SYN_SENT);
1116
1117       TCP_EVT_DBG (TCP_EVT_SYN_RTX, tc);
1118
1119       /* This goes straight to ipx_lookup */
1120       tcp_push_ip_hdr (tm, tc, b);
1121       tcp_enqueue_to_ip_lookup (vm, b, bi, tc->c_is_ip4);
1122
1123       /* Re-enable retransmit timer */
1124       tcp_timer_set (tc, TCP_TIMER_RETRANSMIT_SYN,
1125                      tc->rto * TCP_TO_TIMER_TICK);
1126     }
1127 }
1128
1129 void
1130 tcp_timer_retransmit_handler (u32 index)
1131 {
1132   tcp_timer_retransmit_handler_i (index, 0);
1133 }
1134
1135 void
1136 tcp_timer_retransmit_syn_handler (u32 index)
1137 {
1138   tcp_timer_retransmit_handler_i (index, 1);
1139 }
1140
1141 /**
1142  * Got 0 snd_wnd from peer, try to do something about it.
1143  *
1144  */
1145 void
1146 tcp_timer_persist_handler (u32 index)
1147 {
1148   tcp_main_t *tm = vnet_get_tcp_main ();
1149   vlib_main_t *vm = vlib_get_main ();
1150   u32 thread_index = vlib_get_thread_index ();
1151   tcp_connection_t *tc;
1152   vlib_buffer_t *b;
1153   u32 bi, n_bytes;
1154
1155   tc = tcp_connection_get (index, thread_index);
1156
1157   /* Make sure timer handle is set to invalid */
1158   tc->timers[TCP_TIMER_PERSIST] = TCP_TIMER_HANDLE_INVALID;
1159
1160   /* Problem already solved or worse */
1161   if (tc->snd_wnd > tc->snd_mss || tcp_in_recovery (tc))
1162     return;
1163
1164   /* Increment RTO backoff */
1165   tc->rto_boff += 1;
1166   tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX);
1167
1168   /* Try to force the first unsent segment  */
1169   tcp_get_free_buffer_index (tm, &bi);
1170   b = vlib_get_buffer (vm, bi);
1171   n_bytes = stream_session_peek_bytes (&tc->connection,
1172                                        vlib_buffer_get_current (b),
1173                                        tc->snd_una_max - tc->snd_una,
1174                                        tc->snd_mss);
1175   /* Nothing to send */
1176   if (n_bytes == 0)
1177     {
1178       tcp_return_buffer (tm);
1179       return;
1180     }
1181
1182   b->current_length = n_bytes;
1183   tcp_push_hdr_i (tc, b, tc->state);
1184   tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
1185
1186   /* Re-enable persist timer */
1187   tcp_persist_timer_set (tc);
1188 }
1189
1190 /**
1191  * Retransmit first unacked segment
1192  */
1193 void
1194 tcp_retransmit_first_unacked (tcp_connection_t * tc)
1195 {
1196   tcp_main_t *tm = vnet_get_tcp_main ();
1197   vlib_main_t *vm = vlib_get_main ();
1198   vlib_buffer_t *b;
1199   u32 bi, n_bytes;
1200
1201   tc->snd_nxt = tc->snd_una;
1202
1203   /* Get buffer */
1204   tcp_get_free_buffer_index (tm, &bi);
1205   b = vlib_get_buffer (vm, bi);
1206
1207   TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 2);
1208
1209   n_bytes = tcp_prepare_retransmit_segment (tc, b, 0, tc->snd_mss);
1210   if (n_bytes == 0)
1211     goto done;
1212
1213   tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
1214
1215 done:
1216   tc->snd_nxt = tc->snd_una_max;
1217 }
1218
1219 sack_scoreboard_hole_t *
1220 scoreboard_first_rtx_hole (sack_scoreboard_t * sb)
1221 {
1222   sack_scoreboard_hole_t *hole = 0;
1223
1224 //  hole = scoreboard_first_hole (&tc->sack_sb);
1225 //  if (hole)
1226 //    {
1227 //
1228 //      offset = hole->start - tc->snd_una;
1229 //      hole_size = hole->end - hole->start;
1230 //
1231 //      ASSERT(hole_size);
1232 //
1233 //      if (hole_size < max_bytes)
1234 //      max_bytes = hole_size;
1235 //    }
1236   return hole;
1237 }
1238
1239 /**
1240  * Do fast retransmit.
1241  */
1242 void
1243 tcp_fast_retransmit (tcp_connection_t * tc)
1244 {
1245   tcp_main_t *tm = vnet_get_tcp_main ();
1246   vlib_main_t *vm = vlib_get_main ();
1247   u32 bi;
1248   int snd_space;
1249   u32 n_written = 0, offset = 0;
1250   vlib_buffer_t *b;
1251   u8 use_sacks = 0;
1252
1253   ASSERT (tcp_in_fastrecovery (tc));
1254
1255   /* Start resending from first un-acked segment */
1256   tc->snd_nxt = tc->snd_una;
1257
1258   snd_space = tcp_available_snd_space (tc);
1259   TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 0);
1260
1261   /* If we have SACKs use them */
1262   if (tcp_opts_sack_permitted (&tc->opt)
1263       && scoreboard_first_hole (&tc->sack_sb))
1264     use_sacks = 0;
1265
1266   while (snd_space > 0)
1267     {
1268       tcp_get_free_buffer_index (tm, &bi);
1269       b = vlib_get_buffer (vm, bi);
1270
1271       if (use_sacks)
1272         {
1273           scoreboard_first_rtx_hole (&tc->sack_sb);
1274         }
1275       else
1276         {
1277           offset += n_written;
1278         }
1279
1280       n_written = tcp_prepare_retransmit_segment (tc, b, offset, snd_space);
1281
1282       /* Nothing left to retransmit */
1283       if (n_written == 0)
1284         {
1285           tcp_return_buffer (tm);
1286           break;
1287         }
1288
1289       tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
1290       snd_space -= n_written;
1291     }
1292
1293   /* If window allows, send 1 SMSS of new data */
1294   if (seq_lt (tc->snd_nxt, tc->snd_congestion))
1295     tc->snd_nxt = tc->snd_congestion;
1296 }
1297
1298 always_inline u32
1299 tcp_session_has_ooo_data (tcp_connection_t * tc)
1300 {
1301   stream_session_t *s =
1302     stream_session_get (tc->c_s_index, tc->c_thread_index);
1303   return svm_fifo_has_ooo_data (s->server_rx_fifo);
1304 }
1305
1306 always_inline uword
1307 tcp46_output_inline (vlib_main_t * vm,
1308                      vlib_node_runtime_t * node,
1309                      vlib_frame_t * from_frame, int is_ip4)
1310 {
1311   u32 n_left_from, next_index, *from, *to_next;
1312   u32 my_thread_index = vm->thread_index;
1313
1314   from = vlib_frame_vector_args (from_frame);
1315   n_left_from = from_frame->n_vectors;
1316
1317   next_index = node->cached_next_index;
1318
1319   while (n_left_from > 0)
1320     {
1321       u32 n_left_to_next;
1322
1323       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1324
1325       while (n_left_from > 0 && n_left_to_next > 0)
1326         {
1327           u32 bi0;
1328           vlib_buffer_t *b0;
1329           tcp_connection_t *tc0;
1330           tcp_tx_trace_t *t0;
1331           tcp_header_t *th0 = 0;
1332           u32 error0 = TCP_ERROR_PKTS_SENT, next0 = TCP_OUTPUT_NEXT_IP_LOOKUP;
1333
1334           bi0 = from[0];
1335           to_next[0] = bi0;
1336           from += 1;
1337           to_next += 1;
1338           n_left_from -= 1;
1339           n_left_to_next -= 1;
1340
1341           b0 = vlib_get_buffer (vm, bi0);
1342           tc0 = tcp_connection_get (vnet_buffer (b0)->tcp.connection_index,
1343                                     my_thread_index);
1344           if (PREDICT_FALSE (tc0 == 0 || tc0->state == TCP_STATE_CLOSED))
1345             {
1346               error0 = TCP_ERROR_INVALID_CONNECTION;
1347               next0 = TCP_OUTPUT_NEXT_DROP;
1348               goto done;
1349             }
1350
1351           th0 = vlib_buffer_get_current (b0);
1352           TCP_EVT_DBG (TCP_EVT_OUTPUT, tc0, th0->flags, b0->current_length);
1353
1354           if (is_ip4)
1355             {
1356               ip4_header_t *ih0;
1357               ih0 = vlib_buffer_push_ip4 (vm, b0, &tc0->c_lcl_ip4,
1358                                           &tc0->c_rmt_ip4, IP_PROTOCOL_TCP);
1359               th0->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ih0);
1360             }
1361           else
1362             {
1363               ip6_header_t *ih0;
1364               int bogus = ~0;
1365
1366               ih0 = vlib_buffer_push_ip6 (vm, b0, &tc0->c_lcl_ip6,
1367                                           &tc0->c_rmt_ip6, IP_PROTOCOL_TCP);
1368               th0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ih0,
1369                                                                  &bogus);
1370               ASSERT (!bogus);
1371             }
1372
1373           /* Filter out DUPACKs if there are no OOO segments left */
1374           if (PREDICT_FALSE
1375               (vnet_buffer (b0)->tcp.flags & TCP_BUF_FLAG_DUPACK))
1376             {
1377               if (!tcp_session_has_ooo_data (tc0))
1378                 {
1379                   error0 = TCP_ERROR_FILTERED_DUPACKS;
1380                   next0 = TCP_OUTPUT_NEXT_DROP;
1381                   goto done;
1382                 }
1383             }
1384
1385           /* Stop DELACK timer and fix flags */
1386           tc0->flags &= ~(TCP_CONN_SNDACK);
1387           if (tcp_timer_is_active (tc0, TCP_TIMER_DELACK))
1388             {
1389               tcp_timer_reset (tc0, TCP_TIMER_DELACK);
1390             }
1391
1392           /* If not retransmitting
1393            * 1) update snd_una_max (SYN, SYNACK, FIN)
1394            * 2) If we're not tracking an ACK, start tracking */
1395           if (seq_lt (tc0->snd_una_max, tc0->snd_nxt))
1396             {
1397               tc0->snd_una_max = tc0->snd_nxt;
1398               if (tc0->rtt_ts == 0)
1399                 {
1400                   tc0->rtt_ts = tcp_time_now ();
1401                   tc0->rtt_seq = tc0->snd_nxt;
1402                 }
1403             }
1404
1405           /* Set the retransmit timer if not set already and not
1406            * doing a pure ACK */
1407           if (!tcp_timer_is_active (tc0, TCP_TIMER_RETRANSMIT)
1408               && tc0->snd_nxt != tc0->snd_una)
1409             {
1410               tcp_retransmit_timer_set (tc0);
1411               tc0->rto_boff = 0;
1412             }
1413
1414           /* set fib index to default and lookup node */
1415           /* XXX network virtualization (vrf/vni) */
1416           vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
1417           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1418
1419           b0->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
1420         done:
1421           b0->error = node->errors[error0];
1422           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1423             {
1424               t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
1425               if (th0)
1426                 {
1427                   clib_memcpy (&t0->tcp_header, th0, sizeof (t0->tcp_header));
1428                 }
1429               else
1430                 {
1431                   memset (&t0->tcp_header, 0, sizeof (t0->tcp_header));
1432                 }
1433               clib_memcpy (&t0->tcp_connection, tc0,
1434                            sizeof (t0->tcp_connection));
1435             }
1436
1437           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1438                                            n_left_to_next, bi0, next0);
1439         }
1440
1441       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1442     }
1443
1444   return from_frame->n_vectors;
1445 }
1446
1447 static uword
1448 tcp4_output (vlib_main_t * vm, vlib_node_runtime_t * node,
1449              vlib_frame_t * from_frame)
1450 {
1451   return tcp46_output_inline (vm, node, from_frame, 1 /* is_ip4 */ );
1452 }
1453
1454 static uword
1455 tcp6_output (vlib_main_t * vm, vlib_node_runtime_t * node,
1456              vlib_frame_t * from_frame)
1457 {
1458   return tcp46_output_inline (vm, node, from_frame, 0 /* is_ip4 */ );
1459 }
1460
1461 /* *INDENT-OFF* */
1462 VLIB_REGISTER_NODE (tcp4_output_node) =
1463 {
1464   .function = tcp4_output,.name = "tcp4-output",
1465     /* Takes a vector of packets. */
1466     .vector_size = sizeof (u32),
1467     .n_errors = TCP_N_ERROR,
1468     .error_strings = tcp_error_strings,
1469     .n_next_nodes = TCP_OUTPUT_N_NEXT,
1470     .next_nodes = {
1471 #define _(s,n) [TCP_OUTPUT_NEXT_##s] = n,
1472     foreach_tcp4_output_next
1473 #undef _
1474     },
1475     .format_buffer = format_tcp_header,
1476     .format_trace = format_tcp_tx_trace,
1477 };
1478 /* *INDENT-ON* */
1479
1480 VLIB_NODE_FUNCTION_MULTIARCH (tcp4_output_node, tcp4_output);
1481
1482 /* *INDENT-OFF* */
1483 VLIB_REGISTER_NODE (tcp6_output_node) =
1484 {
1485   .function = tcp6_output,
1486   .name = "tcp6-output",
1487     /* Takes a vector of packets. */
1488   .vector_size = sizeof (u32),
1489   .n_errors = TCP_N_ERROR,
1490   .error_strings = tcp_error_strings,
1491   .n_next_nodes = TCP_OUTPUT_N_NEXT,
1492   .next_nodes = {
1493 #define _(s,n) [TCP_OUTPUT_NEXT_##s] = n,
1494     foreach_tcp6_output_next
1495 #undef _
1496   },
1497   .format_buffer = format_tcp_header,
1498   .format_trace = format_tcp_tx_trace,
1499 };
1500 /* *INDENT-ON* */
1501
1502 VLIB_NODE_FUNCTION_MULTIARCH (tcp6_output_node, tcp6_output);
1503
1504 u32
1505 tcp_push_header (transport_connection_t * tconn, vlib_buffer_t * b)
1506 {
1507   tcp_connection_t *tc;
1508
1509   tc = (tcp_connection_t *) tconn;
1510   tcp_push_hdr_i (tc, b, TCP_STATE_ESTABLISHED);
1511   return 0;
1512 }
1513
1514 typedef enum _tcp_reset_next
1515 {
1516   TCP_RESET_NEXT_DROP,
1517   TCP_RESET_NEXT_IP_LOOKUP,
1518   TCP_RESET_N_NEXT
1519 } tcp_reset_next_t;
1520
1521 #define foreach_tcp4_reset_next         \
1522   _(DROP, "error-drop")                 \
1523   _(IP_LOOKUP, "ip4-lookup")
1524
1525 #define foreach_tcp6_reset_next         \
1526   _(DROP, "error-drop")                 \
1527   _(IP_LOOKUP, "ip6-lookup")
1528
1529 static uword
1530 tcp46_send_reset_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1531                          vlib_frame_t * from_frame, u8 is_ip4)
1532 {
1533   u32 n_left_from, next_index, *from, *to_next;
1534   u32 my_thread_index = vm->thread_index;
1535
1536   from = vlib_frame_vector_args (from_frame);
1537   n_left_from = from_frame->n_vectors;
1538
1539   next_index = node->cached_next_index;
1540
1541   while (n_left_from > 0)
1542     {
1543       u32 n_left_to_next;
1544
1545       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1546
1547       while (n_left_from > 0 && n_left_to_next > 0)
1548         {
1549           u32 bi0;
1550           vlib_buffer_t *b0;
1551           tcp_tx_trace_t *t0;
1552           tcp_header_t *th0;
1553           u32 error0 = TCP_ERROR_RST_SENT, next0 = TCP_RESET_NEXT_IP_LOOKUP;
1554
1555           bi0 = from[0];
1556           to_next[0] = bi0;
1557           from += 1;
1558           to_next += 1;
1559           n_left_from -= 1;
1560           n_left_to_next -= 1;
1561
1562           b0 = vlib_get_buffer (vm, bi0);
1563
1564           if (tcp_make_reset_in_place (vm, b0, vnet_buffer (b0)->tcp.flags,
1565                                        my_thread_index, is_ip4))
1566             {
1567               error0 = TCP_ERROR_LOOKUP_DROPS;
1568               next0 = TCP_RESET_NEXT_DROP;
1569               goto done;
1570             }
1571
1572           /* Prepare to send to IP lookup */
1573           vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;
1574           next0 = TCP_RESET_NEXT_IP_LOOKUP;
1575
1576         done:
1577           b0->error = node->errors[error0];
1578           b0->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
1579           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1580             {
1581               th0 = vlib_buffer_get_current (b0);
1582               if (is_ip4)
1583                 th0 = ip4_next_header ((ip4_header_t *) th0);
1584               else
1585                 th0 = ip6_next_header ((ip6_header_t *) th0);
1586               t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
1587               clib_memcpy (&t0->tcp_header, th0, sizeof (t0->tcp_header));
1588             }
1589
1590           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1591                                            n_left_to_next, bi0, next0);
1592         }
1593       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1594     }
1595   return from_frame->n_vectors;
1596 }
1597
1598 static uword
1599 tcp4_send_reset (vlib_main_t * vm, vlib_node_runtime_t * node,
1600                  vlib_frame_t * from_frame)
1601 {
1602   return tcp46_send_reset_inline (vm, node, from_frame, 1);
1603 }
1604
1605 static uword
1606 tcp6_send_reset (vlib_main_t * vm, vlib_node_runtime_t * node,
1607                  vlib_frame_t * from_frame)
1608 {
1609   return tcp46_send_reset_inline (vm, node, from_frame, 0);
1610 }
1611
1612 /* *INDENT-OFF* */
1613 VLIB_REGISTER_NODE (tcp4_reset_node) = {
1614   .function = tcp4_send_reset,
1615   .name = "tcp4-reset",
1616   .vector_size = sizeof (u32),
1617   .n_errors = TCP_N_ERROR,
1618   .error_strings = tcp_error_strings,
1619   .n_next_nodes = TCP_RESET_N_NEXT,
1620   .next_nodes = {
1621 #define _(s,n) [TCP_RESET_NEXT_##s] = n,
1622     foreach_tcp4_reset_next
1623 #undef _
1624   },
1625   .format_trace = format_tcp_tx_trace,
1626 };
1627 /* *INDENT-ON* */
1628
1629 VLIB_NODE_FUNCTION_MULTIARCH (tcp4_reset_node, tcp4_send_reset);
1630
1631 /* *INDENT-OFF* */
1632 VLIB_REGISTER_NODE (tcp6_reset_node) = {
1633   .function = tcp6_send_reset,
1634   .name = "tcp6-reset",
1635   .vector_size = sizeof (u32),
1636   .n_errors = TCP_N_ERROR,
1637   .error_strings = tcp_error_strings,
1638   .n_next_nodes = TCP_RESET_N_NEXT,
1639   .next_nodes = {
1640 #define _(s,n) [TCP_RESET_NEXT_##s] = n,
1641     foreach_tcp6_reset_next
1642 #undef _
1643   },
1644   .format_trace = format_tcp_tx_trace,
1645 };
1646 /* *INDENT-ON* */
1647
1648 VLIB_NODE_FUNCTION_MULTIARCH (tcp6_reset_node, tcp6_send_reset);
1649
1650 /*
1651  * fd.io coding-style-patch-verification: ON
1652  *
1653  * Local Variables:
1654  * eval: (c-set-style "gnu")
1655  * End:
1656  */