4e85eb3fc93bf3d7e5afb815c56f8272de99d346
[vpp.git] / src / vnet / tcp / tcp.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/session/session.h>
18 #include <vnet/fib/fib.h>
19 #include <vnet/dpo/load_balance.h>
20 #include <math.h>
21
22 tcp_main_t tcp_main;
23
24 static u32
25 tcp_connection_bind (u32 session_index, ip46_address_t * ip,
26                      u16 port_host_byte_order, u8 is_ip4)
27 {
28   tcp_main_t *tm = &tcp_main;
29   tcp_connection_t *listener;
30
31   pool_get (tm->listener_pool, listener);
32   memset (listener, 0, sizeof (*listener));
33
34   listener->c_c_index = listener - tm->listener_pool;
35   listener->c_lcl_port = clib_host_to_net_u16 (port_host_byte_order);
36
37   if (is_ip4)
38     {
39       listener->c_lcl_ip4.as_u32 = ip->ip4.as_u32;
40       listener->c_is_ip4 = 1;
41       listener->c_proto = SESSION_TYPE_IP4_TCP;
42     }
43   else
44     {
45       clib_memcpy (&listener->c_lcl_ip6, &ip->ip6, sizeof (ip6_address_t));
46       listener->c_proto = SESSION_TYPE_IP6_TCP;
47     }
48
49   listener->c_s_index = session_index;
50   listener->state = TCP_STATE_LISTEN;
51
52   tcp_connection_timers_init (listener);
53
54   TCP_EVT_DBG (TCP_EVT_BIND, listener);
55
56   return listener->c_c_index;
57 }
58
59 u32
60 tcp_session_bind_ip4 (u32 session_index, ip46_address_t * ip,
61                       u16 port_host_byte_order)
62 {
63   return tcp_connection_bind (session_index, ip, port_host_byte_order, 1);
64 }
65
66 u32
67 tcp_session_bind_ip6 (u32 session_index, ip46_address_t * ip,
68                       u16 port_host_byte_order)
69 {
70   return tcp_connection_bind (session_index, ip, port_host_byte_order, 0);
71 }
72
73 static void
74 tcp_connection_unbind (u32 listener_index)
75 {
76   tcp_main_t *tm = vnet_get_tcp_main ();
77   TCP_EVT_DBG (TCP_EVT_UNBIND,
78                pool_elt_at_index (tm->listener_pool, listener_index));
79   pool_put_index (tm->listener_pool, listener_index);
80 }
81
82 u32
83 tcp_session_unbind (u32 listener_index)
84 {
85   tcp_connection_unbind (listener_index);
86   return 0;
87 }
88
89 transport_connection_t *
90 tcp_session_get_listener (u32 listener_index)
91 {
92   tcp_main_t *tm = vnet_get_tcp_main ();
93   tcp_connection_t *tc;
94   tc = pool_elt_at_index (tm->listener_pool, listener_index);
95   return &tc->connection;
96 }
97
98 /**
99  * Cleans up connection state.
100  *
101  * No notifications.
102  */
103 void
104 tcp_connection_cleanup (tcp_connection_t * tc)
105 {
106   tcp_main_t *tm = &tcp_main;
107   u32 tepi;
108   transport_endpoint_t *tep;
109
110   /* Cleanup local endpoint if this was an active connect */
111   tepi = transport_endpoint_lookup (&tm->local_endpoints_table, &tc->c_lcl_ip,
112                                     tc->c_lcl_port);
113
114   /*XXX lock */
115   if (tepi != TRANSPORT_ENDPOINT_INVALID_INDEX)
116     {
117       tep = pool_elt_at_index (tm->local_endpoints, tepi);
118       transport_endpoint_table_del (&tm->local_endpoints_table, tep);
119       pool_put (tm->local_endpoints, tep);
120     }
121
122   /* Make sure all timers are cleared */
123   tcp_connection_timers_reset (tc);
124
125   /* Check if half-open */
126   if (tc->state == TCP_STATE_SYN_SENT)
127     pool_put (tm->half_open_connections, tc);
128   else
129     pool_put (tm->connections[tc->c_thread_index], tc);
130 }
131
132 /**
133  * Connection removal.
134  *
135  * This should be called only once connection enters CLOSED state. Note
136  * that it notifies the session of the removal event, so if the goal is to
137  * just remove the connection, call tcp_connection_cleanup instead.
138  */
139 void
140 tcp_connection_del (tcp_connection_t * tc)
141 {
142   TCP_EVT_DBG (TCP_EVT_DELETE, tc);
143   stream_session_delete_notify (&tc->connection);
144   tcp_connection_cleanup (tc);
145 }
146
147 /** Notify session that connection has been reset.
148  *
149  * Switch state to closed and wait for session to call cleanup.
150  */
151 void
152 tcp_connection_reset (tcp_connection_t * tc)
153 {
154   switch (tc->state)
155     {
156     case TCP_STATE_SYN_RCVD:
157       /* Cleanup everything. App wasn't notified yet */
158       stream_session_delete_notify (&tc->connection);
159       tcp_connection_cleanup (tc);
160       break;
161     case TCP_STATE_SYN_SENT:
162     case TCP_STATE_ESTABLISHED:
163     case TCP_STATE_CLOSE_WAIT:
164     case TCP_STATE_FIN_WAIT_1:
165     case TCP_STATE_FIN_WAIT_2:
166     case TCP_STATE_CLOSING:
167       tc->state = TCP_STATE_CLOSED;
168
169       /* Make sure all timers are cleared */
170       tcp_connection_timers_reset (tc);
171
172       stream_session_reset_notify (&tc->connection);
173       break;
174     case TCP_STATE_CLOSED:
175       return;
176     }
177
178 }
179
180 /**
181  * Begin connection closing procedure.
182  *
183  * If at the end the connection is not in CLOSED state, it is not removed.
184  * Instead, we rely on on TCP to advance through state machine to either
185  * 1) LAST_ACK (passive close) whereby when the last ACK is received
186  * tcp_connection_del is called. This notifies session of the delete and
187  * calls cleanup.
188  * 2) TIME_WAIT (active close) whereby after 2MSL the 2MSL timer triggers
189  * and cleanup is called.
190  *
191  * N.B. Half-close connections are not supported
192  */
193 void
194 tcp_connection_close (tcp_connection_t * tc)
195 {
196   TCP_EVT_DBG (TCP_EVT_CLOSE, tc);
197
198   /* Send FIN if needed */
199   if (tc->state == TCP_STATE_ESTABLISHED
200       || tc->state == TCP_STATE_SYN_RCVD || tc->state == TCP_STATE_CLOSE_WAIT)
201     tcp_send_fin (tc);
202
203   /* Switch state */
204   if (tc->state == TCP_STATE_ESTABLISHED || tc->state == TCP_STATE_SYN_RCVD)
205     tc->state = TCP_STATE_FIN_WAIT_1;
206   else if (tc->state == TCP_STATE_SYN_SENT)
207     tc->state = TCP_STATE_CLOSED;
208   else if (tc->state == TCP_STATE_CLOSE_WAIT)
209     tc->state = TCP_STATE_LAST_ACK;
210
211   /* If in CLOSED and WAITCLOSE timer is not set, delete connection now */
212   if (tc->timers[TCP_TIMER_WAITCLOSE] == TCP_TIMER_HANDLE_INVALID
213       && tc->state == TCP_STATE_CLOSED)
214     tcp_connection_del (tc);
215 }
216
217 void
218 tcp_session_close (u32 conn_index, u32 thread_index)
219 {
220   tcp_connection_t *tc;
221   tc = tcp_connection_get (conn_index, thread_index);
222   tcp_connection_close (tc);
223 }
224
225 void
226 tcp_session_cleanup (u32 conn_index, u32 thread_index)
227 {
228   tcp_connection_t *tc;
229   tc = tcp_connection_get (conn_index, thread_index);
230
231   /* Wait for the session tx events to clear */
232   tc->state = TCP_STATE_CLOSED;
233   tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
234 }
235
236 void *
237 ip_interface_get_first_ip (u32 sw_if_index, u8 is_ip4)
238 {
239   ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
240   ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
241   ip_interface_address_t *ia = 0;
242
243   if (is_ip4)
244     {
245       /* *INDENT-OFF* */
246       foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
247       ({
248         return ip_interface_address_get_address (lm4, ia);
249       }));
250       /* *INDENT-ON* */
251     }
252   else
253     {
254       /* *INDENT-OFF* */
255       foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
256       ({
257         return ip_interface_address_get_address (lm6, ia);
258       }));
259       /* *INDENT-ON* */
260     }
261
262   return 0;
263 }
264
265 #define PORT_MASK ((1 << 16)- 1)
266 /**
267  * Allocate local port and add if successful add entry to local endpoint
268  * table to mark the pair as used.
269  */
270 u16
271 tcp_allocate_local_port (tcp_main_t * tm, ip46_address_t * ip)
272 {
273   transport_endpoint_t *tep;
274   u32 time_now, tei;
275   u16 min = 1024, max = 65535;  /* XXX configurable ? */
276   int tries;
277
278   tries = max - min;
279   time_now = tcp_time_now ();
280
281   /* Start at random point or max */
282   pool_get (tm->local_endpoints, tep);
283   clib_memcpy (&tep->ip, ip, sizeof (*ip));
284
285   /* Search for first free slot */
286   for (; tries >= 0; tries--)
287     {
288       u16 port = 0;
289
290       /* Find a port in the specified range */
291       while (1)
292         {
293           port = random_u32 (&time_now) & PORT_MASK;
294           if (PREDICT_TRUE (port >= min && port < max))
295             break;
296         }
297
298       tep->port = port;
299
300       /* Look it up */
301       tei = transport_endpoint_lookup (&tm->local_endpoints_table, &tep->ip,
302                                        tep->port);
303       /* If not found, we're done */
304       if (tei == TRANSPORT_ENDPOINT_INVALID_INDEX)
305         {
306           transport_endpoint_table_add (&tm->local_endpoints_table, tep,
307                                         tep - tm->local_endpoints);
308           return tep->port;
309         }
310     }
311   /* No free ports */
312   pool_put (tm->local_endpoints, tep);
313   return -1;
314 }
315
316 /**
317  * Initialize all connection timers as invalid
318  */
319 void
320 tcp_connection_timers_init (tcp_connection_t * tc)
321 {
322   int i;
323
324   /* Set all to invalid */
325   for (i = 0; i < TCP_N_TIMERS; i++)
326     {
327       tc->timers[i] = TCP_TIMER_HANDLE_INVALID;
328     }
329
330   tc->rto = TCP_RTO_INIT;
331 }
332
333 /**
334  * Stop all connection timers
335  */
336 void
337 tcp_connection_timers_reset (tcp_connection_t * tc)
338 {
339   int i;
340   for (i = 0; i < TCP_N_TIMERS; i++)
341     {
342       tcp_timer_reset (tc, i);
343     }
344 }
345
346 typedef struct ip4_tcp_hdr
347 {
348   ip4_header_t ip;
349   tcp_header_t tcp;
350 } ip4_tcp_hdr_t;
351
352 typedef struct ip6_tcp_hdr
353 {
354   ip6_header_t ip;
355   tcp_header_t tcp;
356 } ip6_tcp_hdr_t;
357
358 static void
359 tcp_connection_select_lb_bucket (tcp_connection_t * tc, const dpo_id_t * dpo,
360                                  dpo_id_t * result)
361 {
362   const dpo_id_t *choice;
363   load_balance_t *lb;
364   int hash;
365
366   lb = load_balance_get (dpo->dpoi_index);
367   if (tc->c_is_ip4)
368     {
369       ip4_tcp_hdr_t hdr;
370       memset (&hdr, 0, sizeof (hdr));
371       hdr.ip.protocol = IP_PROTOCOL_TCP;
372       hdr.ip.address_pair.src.as_u32 = tc->c_lcl_ip.ip4.as_u32;
373       hdr.ip.address_pair.dst.as_u32 = tc->c_rmt_ip.ip4.as_u32;
374       hdr.tcp.src_port = tc->c_lcl_port;
375       hdr.tcp.dst_port = tc->c_rmt_port;
376       hash = ip4_compute_flow_hash (&hdr.ip, lb->lb_hash_config);
377     }
378   else
379     {
380       ip6_tcp_hdr_t hdr;
381       memset (&hdr, 0, sizeof (hdr));
382       hdr.ip.protocol = IP_PROTOCOL_TCP;
383       clib_memcpy (&hdr.ip.src_address, &tc->c_lcl_ip.ip6,
384                    sizeof (ip6_address_t));
385       clib_memcpy (&hdr.ip.dst_address, &tc->c_rmt_ip.ip6,
386                    sizeof (ip6_address_t));
387       hdr.tcp.src_port = tc->c_lcl_port;
388       hdr.tcp.dst_port = tc->c_rmt_port;
389       hash = ip6_compute_flow_hash (&hdr.ip, lb->lb_hash_config);
390     }
391   choice = load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
392   dpo_copy (result, choice);
393 }
394
395 fib_node_index_t
396 tcp_lookup_rmt_in_fib (tcp_connection_t * tc)
397 {
398   fib_prefix_t prefix;
399
400   clib_memcpy (&prefix.fp_addr, &tc->c_rmt_ip, sizeof (prefix.fp_addr));
401   prefix.fp_proto = tc->c_is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
402   prefix.fp_len = tc->c_is_ip4 ? 32 : 128;
403   return fib_table_lookup (0, &prefix);
404 }
405
406 static int
407 tcp_connection_stack_on_fib_entry (tcp_connection_t * tc)
408 {
409   dpo_id_t choice = DPO_INVALID;
410   u32 output_node_index;
411   fib_entry_t *fe;
412
413   fe = fib_entry_get (tc->c_rmt_fei);
414   if (fe->fe_lb.dpoi_type != DPO_LOAD_BALANCE)
415     return -1;
416
417   tcp_connection_select_lb_bucket (tc, &fe->fe_lb, &choice);
418
419   output_node_index =
420     tc->c_is_ip4 ? tcp4_output_node.index : tcp6_output_node.index;
421   dpo_stack_from_node (output_node_index, &tc->c_rmt_dpo, &choice);
422   return 0;
423 }
424
425 /** Stack tcp connection on peer's fib entry.
426  *
427  * This ultimately populates the dpo the connection will use to send packets.
428  */
429 static void
430 tcp_connection_fib_attach (tcp_connection_t * tc)
431 {
432   tc->c_rmt_fei = tcp_lookup_rmt_in_fib (tc);
433
434   ASSERT (tc->c_rmt_fei != FIB_NODE_INDEX_INVALID);
435
436   tcp_connection_stack_on_fib_entry (tc);
437 }
438
439 /** Initialize tcp connection variables
440  *
441  * Should be called after having received a msg from the peer, i.e., a SYN or
442  * a SYNACK, such that connection options have already been exchanged. */
443 void
444 tcp_connection_init_vars (tcp_connection_t * tc)
445 {
446   tcp_connection_timers_init (tc);
447   tcp_init_mss (tc);
448   scoreboard_init (&tc->sack_sb);
449   tcp_cc_init (tc);
450   tcp_connection_fib_attach (tc);
451 }
452
453 int
454 tcp_connection_open (ip46_address_t * rmt_addr, u16 rmt_port, u8 is_ip4)
455 {
456   tcp_main_t *tm = vnet_get_tcp_main ();
457   tcp_connection_t *tc;
458   fib_prefix_t prefix;
459   fib_node_index_t fei;
460   u32 sw_if_index;
461   ip46_address_t lcl_addr;
462   u16 lcl_port;
463
464   /*
465    * Find the local address and allocate port
466    */
467   memset (&lcl_addr, 0, sizeof (lcl_addr));
468
469   /* Find a FIB path to the destination */
470   clib_memcpy (&prefix.fp_addr, rmt_addr, sizeof (*rmt_addr));
471   prefix.fp_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
472   prefix.fp_len = is_ip4 ? 32 : 128;
473
474   fei = fib_table_lookup (0, &prefix);
475
476   /* Couldn't find route to destination. Bail out. */
477   if (fei == FIB_NODE_INDEX_INVALID)
478     return -1;
479
480   sw_if_index = fib_entry_get_resolving_interface (fei);
481
482   if (sw_if_index == (u32) ~ 0)
483     return -1;
484
485   if (is_ip4)
486     {
487       ip4_address_t *ip4;
488       ip4 = ip_interface_get_first_ip (sw_if_index, 1);
489       lcl_addr.ip4.as_u32 = ip4->as_u32;
490     }
491   else
492     {
493       ip6_address_t *ip6;
494       ip6 = ip_interface_get_first_ip (sw_if_index, 0);
495       clib_memcpy (&lcl_addr.ip6, ip6, sizeof (*ip6));
496     }
497
498   /* Allocate source port */
499   lcl_port = tcp_allocate_local_port (tm, &lcl_addr);
500   if (lcl_port < 1)
501     {
502       clib_warning ("Failed to allocate src port");
503       return -1;
504     }
505
506   /*
507    * Create connection and send SYN
508    */
509
510   pool_get (tm->half_open_connections, tc);
511   memset (tc, 0, sizeof (*tc));
512
513   clib_memcpy (&tc->c_rmt_ip, rmt_addr, sizeof (ip46_address_t));
514   clib_memcpy (&tc->c_lcl_ip, &lcl_addr, sizeof (ip46_address_t));
515   tc->c_rmt_port = clib_host_to_net_u16 (rmt_port);
516   tc->c_lcl_port = clib_host_to_net_u16 (lcl_port);
517   tc->c_c_index = tc - tm->half_open_connections;
518   tc->c_is_ip4 = is_ip4;
519   tc->c_proto = is_ip4 ? SESSION_TYPE_IP4_TCP : SESSION_TYPE_IP6_TCP;
520
521   /* The other connection vars will be initialized after SYN ACK */
522   tcp_connection_timers_init (tc);
523
524   tcp_send_syn (tc);
525
526   tc->state = TCP_STATE_SYN_SENT;
527
528   TCP_EVT_DBG (TCP_EVT_OPEN, tc);
529
530   return tc->c_c_index;
531 }
532
533 int
534 tcp_session_open_ip4 (ip46_address_t * addr, u16 port)
535 {
536   return tcp_connection_open (addr, port, 1);
537 }
538
539 int
540 tcp_session_open_ip6 (ip46_address_t * addr, u16 port)
541 {
542   return tcp_connection_open (addr, port, 0);
543 }
544
545 const char *tcp_dbg_evt_str[] = {
546 #define _(sym, str) str,
547   foreach_tcp_dbg_evt
548 #undef _
549 };
550
551 const char *tcp_fsm_states[] = {
552 #define _(sym, str) str,
553   foreach_tcp_fsm_state
554 #undef _
555 };
556
557 u8 *
558 format_tcp_state (u8 * s, va_list * args)
559 {
560   u32 state = va_arg (*args, u32);
561
562   if (state < TCP_N_STATES)
563     s = format (s, "%s", tcp_fsm_states[state]);
564   else
565     s = format (s, "UNKNOWN (%d (0x%x))", state, state);
566   return s;
567 }
568
569 const char *tcp_conn_timers[] = {
570 #define _(sym, str) str,
571   foreach_tcp_timer
572 #undef _
573 };
574
575 u8 *
576 format_tcp_timers (u8 * s, va_list * args)
577 {
578   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
579   int i, last = -1;
580
581   for (i = 0; i < TCP_N_TIMERS; i++)
582     if (tc->timers[i] != TCP_TIMER_HANDLE_INVALID)
583       last = i;
584
585   s = format (s, "[");
586   for (i = 0; i < last; i++)
587     {
588       if (tc->timers[i] != TCP_TIMER_HANDLE_INVALID)
589         s = format (s, "%s,", tcp_conn_timers[i]);
590     }
591
592   if (last >= 0)
593     s = format (s, "%s]", tcp_conn_timers[i]);
594   else
595     s = format (s, "]");
596
597   return s;
598 }
599
600 u8 *
601 format_tcp_congestion_status (u8 * s, va_list * args)
602 {
603   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
604   if (tcp_in_recovery (tc))
605     s = format (s, "recovery");
606   else if (tcp_in_fastrecovery (tc))
607     s = format (s, "fastrecovery");
608   else
609     s = format (s, "none");
610   return s;
611 }
612
613 u8 *
614 format_tcp_vars (u8 * s, va_list * args)
615 {
616   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
617   s = format (s, " snd_una %u snd_nxt %u snd_una_max %u\n",
618               tc->snd_una - tc->iss, tc->snd_nxt - tc->iss,
619               tc->snd_una_max - tc->iss);
620   s = format (s, " rcv_nxt %u rcv_las %u\n",
621               tc->rcv_nxt - tc->irs, tc->rcv_las - tc->irs);
622   s = format (s, " snd_wnd %u rcv_wnd %u snd_wl1 %u snd_wl2 %u\n",
623               tc->snd_wnd, tc->rcv_wnd, tc->snd_wl1 - tc->irs,
624               tc->snd_wl2 - tc->iss);
625   s = format (s, " flight size %u send space %u rcv_wnd_av %d\n",
626               tcp_flight_size (tc), tcp_available_snd_space (tc),
627               tcp_rcv_wnd_available (tc));
628   s = format (s, " cong %U ", format_tcp_congestion_status, tc);
629   s = format (s, "cwnd %u ssthresh %u rtx_bytes %u bytes_acked %u\n",
630               tc->cwnd, tc->ssthresh, tc->snd_rxt_bytes, tc->bytes_acked);
631   s = format (s, " prev_ssthresh %u snd_congestion %u dupack %u\n",
632               tc->prev_ssthresh, tc->snd_congestion - tc->iss,
633               tc->rcv_dupacks);
634   s = format (s, " rto %u rto_boff %u srtt %u rttvar %u rtt_ts %u ", tc->rto,
635               tc->rto_boff, tc->srtt, tc->rttvar, tc->rtt_ts);
636   s = format (s, "rtt_seq %u\n", tc->rtt_seq);
637   s = format (s, " scoreboard: %U\n", format_tcp_scoreboard, &tc->sack_sb);
638   if (vec_len (tc->snd_sacks))
639     s = format (s, " sacks tx: %U\n", format_tcp_sacks, tc);
640
641   return s;
642 }
643
644 u8 *
645 format_tcp_connection_id (u8 * s, va_list * args)
646 {
647   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
648   if (!tc)
649     return s;
650   if (tc->c_is_ip4)
651     {
652       s = format (s, "[#%d][%s] %U:%d->%U:%d", tc->c_thread_index, "T",
653                   format_ip4_address, &tc->c_lcl_ip4,
654                   clib_net_to_host_u16 (tc->c_lcl_port), format_ip4_address,
655                   &tc->c_rmt_ip4, clib_net_to_host_u16 (tc->c_rmt_port));
656     }
657   else
658     {
659       s = format (s, "[#%d][%s] %U:%d->%U:%d", tc->c_thread_index, "T",
660                   format_ip6_address, &tc->c_lcl_ip6,
661                   clib_net_to_host_u16 (tc->c_lcl_port), format_ip6_address,
662                   &tc->c_rmt_ip6, clib_net_to_host_u16 (tc->c_rmt_port));
663     }
664
665   return s;
666 }
667
668 u8 *
669 format_tcp_connection (u8 * s, va_list * args)
670 {
671   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
672   u32 verbose = va_arg (*args, u32);
673
674   s = format (s, "%-50U", format_tcp_connection_id, tc);
675   if (verbose)
676     {
677       s = format (s, "%-15U", format_tcp_state, tc->state);
678       if (verbose > 1)
679         s = format (s, " %U\n%U", format_tcp_timers, tc, format_tcp_vars, tc);
680     }
681   return s;
682 }
683
684 u8 *
685 format_tcp_session (u8 * s, va_list * args)
686 {
687   u32 tci = va_arg (*args, u32);
688   u32 thread_index = va_arg (*args, u32);
689   u32 verbose = va_arg (*args, u32);
690   tcp_connection_t *tc;
691
692   tc = tcp_connection_get (tci, thread_index);
693   if (tc)
694     s = format (s, "%U", format_tcp_connection, tc, verbose);
695   else
696     s = format (s, "empty");
697   return s;
698 }
699
700 u8 *
701 format_tcp_listener_session (u8 * s, va_list * args)
702 {
703   u32 tci = va_arg (*args, u32);
704   tcp_connection_t *tc = tcp_listener_get (tci);
705   return format (s, "%U", format_tcp_connection_id, tc);
706 }
707
708 u8 *
709 format_tcp_half_open_session (u8 * s, va_list * args)
710 {
711   u32 tci = va_arg (*args, u32);
712   tcp_connection_t *tc = tcp_half_open_connection_get (tci);
713   return format (s, "%U", format_tcp_connection_id, tc);
714 }
715
716 u8 *
717 format_tcp_sacks (u8 * s, va_list * args)
718 {
719   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
720   sack_block_t *sacks = tc->snd_sacks;
721   sack_block_t *block;
722   vec_foreach (block, sacks)
723   {
724     s = format (s, " start %u end %u\n", block->start - tc->irs,
725                 block->end - tc->irs);
726   }
727   return s;
728 }
729
730 u8 *
731 format_tcp_sack_hole (u8 * s, va_list * args)
732 {
733   sack_scoreboard_hole_t *hole = va_arg (*args, sack_scoreboard_hole_t *);
734   s = format (s, "[%u, %u]", hole->start, hole->end);
735   return s;
736 }
737
738 u8 *
739 format_tcp_scoreboard (u8 * s, va_list * args)
740 {
741   sack_scoreboard_t *sb = va_arg (*args, sack_scoreboard_t *);
742   sack_scoreboard_hole_t *hole;
743   s = format (s, "sacked_bytes %u last_sacked_bytes %u lost_bytes %u\n",
744               sb->sacked_bytes, sb->last_sacked_bytes, sb->lost_bytes);
745   s = format (s, " last_bytes_delivered %u high_sacked %u snd_una_adv %u\n",
746               sb->last_bytes_delivered, sb->high_sacked, sb->snd_una_adv);
747   s = format (s, " cur_rxt_hole %u high_rxt %u rescue_rxt %u",
748               sb->cur_rxt_hole, sb->high_rxt, sb->rescue_rxt);
749
750   hole = scoreboard_first_hole (sb);
751   if (hole)
752     s = format (s, "\n head %u tail %u holes:\n", sb->head, sb->tail);
753
754   while (hole)
755     {
756       s = format (s, "%U", format_tcp_sack_hole, hole);
757       hole = scoreboard_next_hole (sb, hole);
758     }
759   return s;
760 }
761
762 transport_connection_t *
763 tcp_session_get_transport (u32 conn_index, u32 thread_index)
764 {
765   tcp_connection_t *tc = tcp_connection_get (conn_index, thread_index);
766   return &tc->connection;
767 }
768
769 transport_connection_t *
770 tcp_half_open_session_get_transport (u32 conn_index)
771 {
772   tcp_connection_t *tc = tcp_half_open_connection_get (conn_index);
773   return &tc->connection;
774 }
775
776 /**
777  * Compute maximum segment size for session layer.
778  *
779  * Since the result needs to be the actual data length, it first computes
780  * the tcp options to be used in the next burst and subtracts their
781  * length from the connection's snd_mss.
782  */
783 u16
784 tcp_session_send_mss (transport_connection_t * trans_conn)
785 {
786   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
787
788   /* Ensure snd_mss does accurately reflect the amount of data we can push
789    * in a segment. This also makes sure that options are updated according to
790    * the current state of the connection. */
791   tcp_update_snd_mss (tc);
792
793   return tc->snd_mss;
794 }
795
796 always_inline u32
797 tcp_round_snd_space (tcp_connection_t * tc, u32 snd_space)
798 {
799   if (tc->snd_wnd < tc->snd_mss)
800     {
801       return tc->snd_wnd <= snd_space ? tc->snd_wnd : 0;
802     }
803
804   /* If we can't write at least a segment, don't try at all */
805   if (snd_space < tc->snd_mss)
806     return 0;
807
808   /* round down to mss multiple */
809   return snd_space - (snd_space % tc->snd_mss);
810 }
811
812 /**
813  * Compute tx window session is allowed to fill.
814  *
815  * Takes into account available send space, snd_mss and the congestion
816  * state of the connection. If possible, the value returned is a multiple
817  * of snd_mss.
818  *
819  * @param tc tcp connection
820  * @return number of bytes session is allowed to write
821  */
822 u32
823 tcp_snd_space (tcp_connection_t * tc)
824 {
825   int snd_space, snt_limited;
826
827   if (PREDICT_TRUE (tcp_in_cong_recovery (tc) == 0))
828     {
829       snd_space = tcp_available_snd_space (tc);
830
831       /* If we haven't gotten dupacks or if we did and have gotten sacked
832        * bytes then we can still send as per Limited Transmit (RFC3042) */
833       if (PREDICT_FALSE (tc->rcv_dupacks != 0
834                          && (tcp_opts_sack_permitted (tc)
835                              && tc->sack_sb.last_sacked_bytes == 0)))
836         {
837           if (tc->rcv_dupacks == 1 && tc->limited_transmit != tc->snd_nxt)
838             tc->limited_transmit = tc->snd_nxt;
839           ASSERT (seq_leq (tc->limited_transmit, tc->snd_nxt));
840
841           snt_limited = tc->snd_nxt - tc->limited_transmit;
842           snd_space = clib_max (2 * tc->snd_mss - snt_limited, 0);
843         }
844       return tcp_round_snd_space (tc, snd_space);
845     }
846
847   if (tcp_in_recovery (tc))
848     {
849       tc->snd_nxt = tc->snd_una_max;
850       snd_space = tcp_available_wnd (tc) - tc->snd_rxt_bytes
851         - (tc->snd_una_max - tc->snd_congestion);
852       if (snd_space <= 0 || (tc->snd_una_max - tc->snd_una) >= tc->snd_wnd)
853         return 0;
854       return tcp_round_snd_space (tc, snd_space);
855     }
856
857   /* If in fast recovery, send 1 SMSS if wnd allows */
858   if (tcp_in_fastrecovery (tc)
859       && tcp_available_snd_space (tc) && !tcp_fastrecovery_sent_1_smss (tc))
860     {
861       tcp_fastrecovery_1_smss_on (tc);
862       return tc->snd_mss;
863     }
864
865   return 0;
866 }
867
868 u32
869 tcp_session_send_space (transport_connection_t * trans_conn)
870 {
871   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
872   return tcp_snd_space (tc);
873 }
874
875 i32
876 tcp_rcv_wnd_available (tcp_connection_t * tc)
877 {
878   return (i32) tc->rcv_wnd - (tc->rcv_nxt - tc->rcv_las);
879 }
880
881 u32
882 tcp_session_tx_fifo_offset (transport_connection_t * trans_conn)
883 {
884   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
885
886   ASSERT (seq_geq (tc->snd_nxt, tc->snd_una));
887
888   /* This still works if fast retransmit is on */
889   return (tc->snd_nxt - tc->snd_una);
890 }
891
892 /* *INDENT-OFF* */
893 const static transport_proto_vft_t tcp4_proto = {
894   .bind = tcp_session_bind_ip4,
895   .unbind = tcp_session_unbind,
896   .push_header = tcp_push_header,
897   .get_connection = tcp_session_get_transport,
898   .get_listener = tcp_session_get_listener,
899   .get_half_open = tcp_half_open_session_get_transport,
900   .open = tcp_session_open_ip4,
901   .close = tcp_session_close,
902   .cleanup = tcp_session_cleanup,
903   .send_mss = tcp_session_send_mss,
904   .send_space = tcp_session_send_space,
905   .tx_fifo_offset = tcp_session_tx_fifo_offset,
906   .format_connection = format_tcp_session,
907   .format_listener = format_tcp_listener_session,
908   .format_half_open = format_tcp_half_open_session,
909 };
910
911 const static transport_proto_vft_t tcp6_proto = {
912   .bind = tcp_session_bind_ip6,
913   .unbind = tcp_session_unbind,
914   .push_header = tcp_push_header,
915   .get_connection = tcp_session_get_transport,
916   .get_listener = tcp_session_get_listener,
917   .get_half_open = tcp_half_open_session_get_transport,
918   .open = tcp_session_open_ip6,
919   .close = tcp_session_close,
920   .cleanup = tcp_session_cleanup,
921   .send_mss = tcp_session_send_mss,
922   .send_space = tcp_session_send_space,
923   .tx_fifo_offset = tcp_session_tx_fifo_offset,
924   .format_connection = format_tcp_session,
925   .format_listener = format_tcp_listener_session,
926   .format_half_open = format_tcp_half_open_session,
927 };
928 /* *INDENT-ON* */
929
930 void
931 tcp_timer_keep_handler (u32 conn_index)
932 {
933   u32 thread_index = vlib_get_thread_index ();
934   tcp_connection_t *tc;
935
936   tc = tcp_connection_get (conn_index, thread_index);
937   tc->timers[TCP_TIMER_KEEP] = TCP_TIMER_HANDLE_INVALID;
938
939   tcp_connection_close (tc);
940 }
941
942 void
943 tcp_timer_establish_handler (u32 conn_index)
944 {
945   tcp_connection_t *tc;
946   u8 sst;
947
948   tc = tcp_half_open_connection_get (conn_index);
949   tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID;
950
951   ASSERT (tc->state == TCP_STATE_SYN_SENT);
952
953   sst = tc->c_is_ip4 ? SESSION_TYPE_IP4_TCP : SESSION_TYPE_IP6_TCP;
954   stream_session_connect_notify (&tc->connection, sst, 1 /* fail */ );
955
956   tcp_connection_cleanup (tc);
957 }
958
959 void
960 tcp_timer_waitclose_handler (u32 conn_index)
961 {
962   u32 thread_index = vlib_get_thread_index ();
963   tcp_connection_t *tc;
964
965   tc = tcp_connection_get (conn_index, thread_index);
966   tc->timers[TCP_TIMER_WAITCLOSE] = TCP_TIMER_HANDLE_INVALID;
967
968   /* Session didn't come back with a close(). Send FIN either way
969    * and switch to LAST_ACK. */
970   if (tc->state == TCP_STATE_CLOSE_WAIT)
971     {
972       if (tc->flags & TCP_CONN_FINSNT)
973         {
974           clib_warning ("FIN was sent and still in CLOSE WAIT. Weird!");
975         }
976
977       tcp_send_fin (tc);
978       tc->state = TCP_STATE_LAST_ACK;
979
980       /* Make sure we don't wait in LAST ACK forever */
981       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
982
983       /* Don't delete the connection yet */
984       return;
985     }
986
987   tcp_connection_del (tc);
988 }
989
990 /* *INDENT-OFF* */
991 static timer_expiration_handler *timer_expiration_handlers[TCP_N_TIMERS] =
992 {
993     tcp_timer_retransmit_handler,
994     tcp_timer_delack_handler,
995     tcp_timer_persist_handler,
996     tcp_timer_keep_handler,
997     tcp_timer_waitclose_handler,
998     tcp_timer_retransmit_syn_handler,
999     tcp_timer_establish_handler
1000 };
1001 /* *INDENT-ON* */
1002
1003 static void
1004 tcp_expired_timers_dispatch (u32 * expired_timers)
1005 {
1006   int i;
1007   u32 connection_index, timer_id;
1008
1009   for (i = 0; i < vec_len (expired_timers); i++)
1010     {
1011       /* Get session index and timer id */
1012       connection_index = expired_timers[i] & 0x0FFFFFFF;
1013       timer_id = expired_timers[i] >> 28;
1014
1015       TCP_EVT_DBG (TCP_EVT_TIMER_POP, connection_index, timer_id);
1016
1017       /* Handle expiration */
1018       (*timer_expiration_handlers[timer_id]) (connection_index);
1019     }
1020 }
1021
1022 void
1023 tcp_initialize_timer_wheels (tcp_main_t * tm)
1024 {
1025   tw_timer_wheel_16t_2w_512sl_t *tw;
1026   /* *INDENT-OFF* */
1027   foreach_vlib_main (({
1028     tw = &tm->timer_wheels[ii];
1029     tw_timer_wheel_init_16t_2w_512sl (tw, tcp_expired_timers_dispatch,
1030                                       100e-3 /* timer period 100ms */ , ~0);
1031     tw->last_run_time = vlib_time_now (this_vlib_main);
1032   }));
1033   /* *INDENT-ON* */
1034 }
1035
1036 clib_error_t *
1037 tcp_main_enable (vlib_main_t * vm)
1038 {
1039   tcp_main_t *tm = vnet_get_tcp_main ();
1040   ip_protocol_info_t *pi;
1041   ip_main_t *im = &ip_main;
1042   vlib_thread_main_t *vtm = vlib_get_thread_main ();
1043   clib_error_t *error = 0;
1044   u32 num_threads;
1045
1046   if ((error = vlib_call_init_function (vm, ip_main_init)))
1047     return error;
1048   if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
1049     return error;
1050   if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1051     return error;
1052
1053   /*
1054    * Registrations
1055    */
1056
1057   /* Register with IP */
1058   pi = ip_get_protocol_info (im, IP_PROTOCOL_TCP);
1059   if (pi == 0)
1060     return clib_error_return (0, "TCP protocol info AWOL");
1061   pi->format_header = format_tcp_header;
1062   pi->unformat_pg_edit = unformat_pg_tcp_header;
1063
1064   ip4_register_protocol (IP_PROTOCOL_TCP, tcp4_input_node.index);
1065
1066   /* Register as transport with URI */
1067   session_register_transport (SESSION_TYPE_IP4_TCP, &tcp4_proto);
1068   session_register_transport (SESSION_TYPE_IP6_TCP, &tcp6_proto);
1069
1070   /*
1071    * Initialize data structures
1072    */
1073
1074   num_threads = 1 /* main thread */  + vtm->n_threads;
1075   vec_validate (tm->connections, num_threads - 1);
1076
1077   /* Initialize per worker thread tx buffers (used for control messages) */
1078   vec_validate (tm->tx_buffers, num_threads - 1);
1079
1080   /* Initialize timer wheels */
1081   vec_validate (tm->timer_wheels, num_threads - 1);
1082   tcp_initialize_timer_wheels (tm);
1083
1084   /* Initialize clocks per tick for TCP timestamp. Used to compute
1085    * monotonically increasing timestamps. */
1086   tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
1087     / TCP_TSTAMP_RESOLUTION;
1088
1089   clib_bihash_init_24_8 (&tm->local_endpoints_table, "local endpoint table",
1090                          200000 /* $$$$ config parameter nbuckets */ ,
1091                          (64 << 20) /*$$$ config parameter table size */ );
1092
1093   return error;
1094 }
1095
1096 clib_error_t *
1097 vnet_tcp_enable_disable (vlib_main_t * vm, u8 is_en)
1098 {
1099   if (is_en)
1100     {
1101       if (tcp_main.is_enabled)
1102         return 0;
1103
1104       return tcp_main_enable (vm);
1105     }
1106   else
1107     {
1108       tcp_main.is_enabled = 0;
1109     }
1110
1111   return 0;
1112 }
1113
1114 clib_error_t *
1115 tcp_init (vlib_main_t * vm)
1116 {
1117   tcp_main_t *tm = vnet_get_tcp_main ();
1118
1119   tm->vlib_main = vm;
1120   tm->vnet_main = vnet_get_main ();
1121   tm->is_enabled = 0;
1122
1123   return 0;
1124 }
1125
1126 VLIB_INIT_FUNCTION (tcp_init);
1127
1128 /*
1129  * fd.io coding-style-patch-verification: ON
1130  *
1131  * Local Variables:
1132  * eval: (c-set-style "gnu")
1133  * End:
1134  */