tcp: retry lost retransmits
[vpp.git] / src / vnet / tcp / tcp.c
1 /*
2  * Copyright (c) 2016-2019 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 /**
17  * @file
18  * @brief TCP host stack utilities
19  */
20
21 #include <vnet/tcp/tcp.h>
22 #include <vnet/session/session.h>
23 #include <vnet/fib/fib.h>
24 #include <vnet/dpo/load_balance.h>
25 #include <vnet/dpo/receive_dpo.h>
26 #include <vnet/ip/ip6_neighbor.h>
27 #include <math.h>
28 #include <vnet/ethernet/arp.h>
29
30 tcp_main_t tcp_main;
31
32 typedef struct
33 {
34   fib_protocol_t nh_proto;
35   vnet_link_t link_type;
36   ip46_address_t ip;
37   u32 sw_if_index;
38   u8 is_add;
39 } tcp_add_del_adj_args_t;
40
41 static void
42 tcp_add_del_adj_cb (tcp_add_del_adj_args_t * args)
43 {
44   u32 ai;
45   if (args->is_add)
46     {
47       adj_nbr_add_or_lock (args->nh_proto, args->link_type, &args->ip,
48                            args->sw_if_index);
49     }
50   else
51     {
52       ai = adj_nbr_find (FIB_PROTOCOL_IP6, VNET_LINK_IP6, &args->ip,
53                          args->sw_if_index);
54       if (ai != ADJ_INDEX_INVALID)
55         adj_unlock (ai);
56     }
57 }
58
59 static void
60 tcp_add_del_adjacency (tcp_connection_t * tc, u8 is_add)
61 {
62   tcp_add_del_adj_args_t args = {
63     .nh_proto = FIB_PROTOCOL_IP6,
64     .link_type = VNET_LINK_IP6,
65     .ip = tc->c_rmt_ip,
66     .sw_if_index = tc->sw_if_index,
67     .is_add = is_add
68   };
69   vlib_rpc_call_main_thread (tcp_add_del_adj_cb, (u8 *) & args,
70                              sizeof (args));
71 }
72
73 static void
74 tcp_cc_init (tcp_connection_t * tc)
75 {
76   tc->cc_algo->init (tc);
77 }
78
79 static void
80 tcp_cc_cleanup (tcp_connection_t * tc)
81 {
82   if (tc->cc_algo->cleanup)
83     tc->cc_algo->cleanup (tc);
84 }
85
86 void
87 tcp_cc_algo_register (tcp_cc_algorithm_type_e type,
88                       const tcp_cc_algorithm_t * vft)
89 {
90   tcp_main_t *tm = vnet_get_tcp_main ();
91   vec_validate (tm->cc_algos, type);
92
93   tm->cc_algos[type] = *vft;
94   hash_set_mem (tm->cc_algo_by_name, vft->name, type);
95 }
96
97 tcp_cc_algorithm_t *
98 tcp_cc_algo_get (tcp_cc_algorithm_type_e type)
99 {
100   tcp_main_t *tm = vnet_get_tcp_main ();
101   return &tm->cc_algos[type];
102 }
103
104 tcp_cc_algorithm_type_e
105 tcp_cc_algo_new_type (const tcp_cc_algorithm_t * vft)
106 {
107   tcp_main_t *tm = vnet_get_tcp_main ();
108   tcp_cc_algo_register (++tm->cc_last_type, vft);
109   return tm->cc_last_type;
110 }
111
112 static u32
113 tcp_connection_bind (u32 session_index, transport_endpoint_t * lcl)
114 {
115   tcp_main_t *tm = &tcp_main;
116   tcp_connection_t *listener;
117   void *iface_ip;
118
119   pool_get (tm->listener_pool, listener);
120   clib_memset (listener, 0, sizeof (*listener));
121
122   listener->c_c_index = listener - tm->listener_pool;
123   listener->c_lcl_port = lcl->port;
124
125   /* If we are provided a sw_if_index, bind using one of its ips */
126   if (ip_is_zero (&lcl->ip, 1) && lcl->sw_if_index != ENDPOINT_INVALID_INDEX)
127     {
128       if ((iface_ip = ip_interface_get_first_ip (lcl->sw_if_index,
129                                                  lcl->is_ip4)))
130         ip_set (&lcl->ip, iface_ip, lcl->is_ip4);
131     }
132   ip_copy (&listener->c_lcl_ip, &lcl->ip, lcl->is_ip4);
133   listener->c_is_ip4 = lcl->is_ip4;
134   listener->c_proto = TRANSPORT_PROTO_TCP;
135   listener->c_s_index = session_index;
136   listener->c_fib_index = lcl->fib_index;
137   listener->state = TCP_STATE_LISTEN;
138   listener->cc_algo = tcp_cc_algo_get (tcp_cfg.cc_algo);
139
140   tcp_connection_timers_init (listener);
141
142   TCP_EVT (TCP_EVT_BIND, listener);
143
144   return listener->c_c_index;
145 }
146
147 static u32
148 tcp_session_bind (u32 session_index, transport_endpoint_t * tep)
149 {
150   return tcp_connection_bind (session_index, tep);
151 }
152
153 static void
154 tcp_connection_unbind (u32 listener_index)
155 {
156   tcp_main_t *tm = vnet_get_tcp_main ();
157   tcp_connection_t *tc;
158
159   tc = pool_elt_at_index (tm->listener_pool, listener_index);
160
161   TCP_EVT (TCP_EVT_UNBIND, tc);
162
163   /* Poison the entry */
164   if (CLIB_DEBUG > 0)
165     clib_memset (tc, 0xFA, sizeof (*tc));
166
167   pool_put_index (tm->listener_pool, listener_index);
168 }
169
170 static u32
171 tcp_session_unbind (u32 listener_index)
172 {
173   tcp_connection_unbind (listener_index);
174   return 0;
175 }
176
177 static transport_connection_t *
178 tcp_session_get_listener (u32 listener_index)
179 {
180   tcp_main_t *tm = vnet_get_tcp_main ();
181   tcp_connection_t *tc;
182   tc = pool_elt_at_index (tm->listener_pool, listener_index);
183   return &tc->connection;
184 }
185
186 /**
187  * Cleanup half-open connection
188  *
189  */
190 static void
191 tcp_half_open_connection_del (tcp_connection_t * tc)
192 {
193   tcp_main_t *tm = vnet_get_tcp_main ();
194   clib_spinlock_lock_if_init (&tm->half_open_lock);
195   if (CLIB_DEBUG)
196     clib_memset (tc, 0xFA, sizeof (*tc));
197   pool_put (tm->half_open_connections, tc);
198   clib_spinlock_unlock_if_init (&tm->half_open_lock);
199 }
200
201 /**
202  * Try to cleanup half-open connection
203  *
204  * If called from a thread that doesn't own tc, the call won't have any
205  * effect.
206  *
207  * @param tc - connection to be cleaned up
208  * @return non-zero if cleanup failed.
209  */
210 int
211 tcp_half_open_connection_cleanup (tcp_connection_t * tc)
212 {
213   /* Make sure this is the owning thread */
214   if (tc->c_thread_index != vlib_get_thread_index ())
215     return 1;
216   tcp_timer_reset (tc, TCP_TIMER_RETRANSMIT_SYN);
217   tcp_half_open_connection_del (tc);
218   return 0;
219 }
220
221 static tcp_connection_t *
222 tcp_half_open_connection_new (void)
223 {
224   tcp_main_t *tm = vnet_get_tcp_main ();
225   tcp_connection_t *tc = 0;
226   ASSERT (vlib_get_thread_index () == 0);
227   pool_get (tm->half_open_connections, tc);
228   clib_memset (tc, 0, sizeof (*tc));
229   tc->c_c_index = tc - tm->half_open_connections;
230   return tc;
231 }
232
233 /**
234  * Cleans up connection state.
235  *
236  * No notifications.
237  */
238 void
239 tcp_connection_cleanup (tcp_connection_t * tc)
240 {
241   tcp_main_t *tm = &tcp_main;
242
243   TCP_EVT (TCP_EVT_DELETE, tc);
244
245   /* Cleanup local endpoint if this was an active connect */
246   transport_endpoint_cleanup (TRANSPORT_PROTO_TCP, &tc->c_lcl_ip,
247                               tc->c_lcl_port);
248
249   /* Check if connection is not yet fully established */
250   if (tc->state == TCP_STATE_SYN_SENT)
251     {
252       /* Try to remove the half-open connection. If this is not the owning
253        * thread, tc won't be removed. Retransmit or establish timers will
254        * eventually expire and call again cleanup on the right thread. */
255       if (tcp_half_open_connection_cleanup (tc))
256         tc->flags |= TCP_CONN_HALF_OPEN_DONE;
257     }
258   else
259     {
260       int thread_index = tc->c_thread_index;
261
262       /* Make sure all timers are cleared */
263       tcp_connection_timers_reset (tc);
264
265       if (!tc->c_is_ip4 && ip6_address_is_link_local_unicast (&tc->c_rmt_ip6))
266         tcp_add_del_adjacency (tc, 0);
267
268       tcp_cc_cleanup (tc);
269       vec_free (tc->snd_sacks);
270       vec_free (tc->snd_sacks_fl);
271       vec_free (tc->rcv_opts.sacks);
272       pool_free (tc->sack_sb.holes);
273
274       if (tc->flags & TCP_CONN_RATE_SAMPLE)
275         tcp_bt_cleanup (tc);
276
277       /* Poison the entry */
278       if (CLIB_DEBUG > 0)
279         clib_memset (tc, 0xFA, sizeof (*tc));
280       pool_put (tm->connections[thread_index], tc);
281     }
282 }
283
284 /**
285  * Connection removal.
286  *
287  * This should be called only once connection enters CLOSED state. Note
288  * that it notifies the session of the removal event, so if the goal is to
289  * just remove the connection, call tcp_connection_cleanup instead.
290  */
291 void
292 tcp_connection_del (tcp_connection_t * tc)
293 {
294   session_transport_delete_notify (&tc->connection);
295   tcp_connection_cleanup (tc);
296 }
297
298 tcp_connection_t *
299 tcp_connection_alloc (u8 thread_index)
300 {
301   tcp_main_t *tm = vnet_get_tcp_main ();
302   tcp_connection_t *tc;
303
304   pool_get (tm->connections[thread_index], tc);
305   clib_memset (tc, 0, sizeof (*tc));
306   tc->c_c_index = tc - tm->connections[thread_index];
307   tc->c_thread_index = thread_index;
308   return tc;
309 }
310
311 tcp_connection_t *
312 tcp_connection_alloc_w_base (u8 thread_index, tcp_connection_t * base)
313 {
314   tcp_main_t *tm = vnet_get_tcp_main ();
315   tcp_connection_t *tc;
316
317   pool_get (tm->connections[thread_index], tc);
318   clib_memcpy_fast (tc, base, sizeof (*tc));
319   tc->c_c_index = tc - tm->connections[thread_index];
320   tc->c_thread_index = thread_index;
321   return tc;
322 }
323
324 void
325 tcp_connection_free (tcp_connection_t * tc)
326 {
327   tcp_main_t *tm = &tcp_main;
328   if (CLIB_DEBUG)
329     {
330       u8 thread_index = tc->c_thread_index;
331       clib_memset (tc, 0xFA, sizeof (*tc));
332       pool_put (tm->connections[thread_index], tc);
333       return;
334     }
335   pool_put (tm->connections[tc->c_thread_index], tc);
336 }
337
338 /** Notify session that connection has been reset.
339  *
340  * Switch state to closed and wait for session to call cleanup.
341  */
342 void
343 tcp_connection_reset (tcp_connection_t * tc)
344 {
345   TCP_EVT (TCP_EVT_RST_RCVD, tc);
346   switch (tc->state)
347     {
348     case TCP_STATE_SYN_RCVD:
349       /* Cleanup everything. App wasn't notified yet */
350       session_transport_delete_notify (&tc->connection);
351       tcp_connection_cleanup (tc);
352       break;
353     case TCP_STATE_SYN_SENT:
354       session_stream_connect_notify (&tc->connection, 1 /* fail */ );
355       tcp_connection_cleanup (tc);
356       break;
357     case TCP_STATE_ESTABLISHED:
358       tcp_connection_timers_reset (tc);
359       /* Set the cleanup timer, in case the session layer/app don't
360        * cleanly close the connection */
361       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.closewait_time);
362       session_transport_reset_notify (&tc->connection);
363       tcp_connection_set_state (tc, TCP_STATE_CLOSED);
364       session_transport_closed_notify (&tc->connection);
365       break;
366     case TCP_STATE_CLOSE_WAIT:
367     case TCP_STATE_FIN_WAIT_1:
368     case TCP_STATE_FIN_WAIT_2:
369     case TCP_STATE_CLOSING:
370     case TCP_STATE_LAST_ACK:
371       tcp_connection_timers_reset (tc);
372       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.closewait_time);
373       /* Make sure we mark the session as closed. In some states we may
374        * be still trying to send data */
375       tcp_connection_set_state (tc, TCP_STATE_CLOSED);
376       session_transport_closed_notify (&tc->connection);
377       break;
378     case TCP_STATE_CLOSED:
379     case TCP_STATE_TIME_WAIT:
380       break;
381     default:
382       TCP_DBG ("reset state: %u", tc->state);
383     }
384 }
385
386 /**
387  * Begin connection closing procedure.
388  *
389  * If at the end the connection is not in CLOSED state, it is not removed.
390  * Instead, we rely on on TCP to advance through state machine to either
391  * 1) LAST_ACK (passive close) whereby when the last ACK is received
392  * tcp_connection_del is called. This notifies session of the delete and
393  * calls cleanup.
394  * 2) TIME_WAIT (active close) whereby after 2MSL the 2MSL timer triggers
395  * and cleanup is called.
396  *
397  * N.B. Half-close connections are not supported
398  */
399 void
400 tcp_connection_close (tcp_connection_t * tc)
401 {
402   TCP_EVT (TCP_EVT_CLOSE, tc);
403
404   /* Send/Program FIN if needed and switch state */
405   switch (tc->state)
406     {
407     case TCP_STATE_SYN_SENT:
408       /* Try to cleanup. If not on the right thread, mark as half-open done.
409        * Connection will be cleaned up when establish timer pops */
410       tcp_connection_cleanup (tc);
411       break;
412     case TCP_STATE_SYN_RCVD:
413       tcp_connection_timers_reset (tc);
414       tcp_send_fin (tc);
415       tcp_connection_set_state (tc, TCP_STATE_FIN_WAIT_1);
416       tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.finwait1_time);
417       break;
418     case TCP_STATE_ESTABLISHED:
419       /* If closing with unread data, reset the connection */
420       if (transport_max_rx_dequeue (&tc->connection))
421         {
422           tcp_send_reset (tc);
423           tcp_connection_timers_reset (tc);
424           tcp_connection_set_state (tc, TCP_STATE_CLOSED);
425           tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.closewait_time);
426           session_transport_closed_notify (&tc->connection);
427           break;
428         }
429       if (!transport_max_tx_dequeue (&tc->connection))
430         tcp_send_fin (tc);
431       else
432         tc->flags |= TCP_CONN_FINPNDG;
433       tcp_connection_set_state (tc, TCP_STATE_FIN_WAIT_1);
434       /* Set a timer in case the peer stops responding. Otherwise the
435        * connection will be stuck here forever. */
436       ASSERT (tc->timers[TCP_TIMER_WAITCLOSE] == TCP_TIMER_HANDLE_INVALID);
437       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.finwait1_time);
438       break;
439     case TCP_STATE_CLOSE_WAIT:
440       if (!transport_max_tx_dequeue (&tc->connection))
441         {
442           tcp_send_fin (tc);
443           tcp_connection_timers_reset (tc);
444           tcp_connection_set_state (tc, TCP_STATE_LAST_ACK);
445           tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.lastack_time);
446         }
447       else
448         tc->flags |= TCP_CONN_FINPNDG;
449       break;
450     case TCP_STATE_FIN_WAIT_1:
451       tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.finwait1_time);
452       break;
453     case TCP_STATE_CLOSED:
454       tcp_connection_timers_reset (tc);
455       /* Delete connection but instead of doing it now wait until next
456        * dispatch cycle to give the session layer a chance to clear
457        * unhandled events */
458       tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
459       break;
460     default:
461       TCP_DBG ("state: %u", tc->state);
462     }
463 }
464
465 static void
466 tcp_session_close (u32 conn_index, u32 thread_index)
467 {
468   tcp_connection_t *tc;
469   tc = tcp_connection_get (conn_index, thread_index);
470   tcp_connection_close (tc);
471 }
472
473 static void
474 tcp_session_cleanup (u32 conn_index, u32 thread_index)
475 {
476   tcp_connection_t *tc;
477   tc = tcp_connection_get (conn_index, thread_index);
478   if (!tc)
479     return;
480   tcp_connection_set_state (tc, TCP_STATE_CLOSED);
481   tcp_connection_cleanup (tc);
482 }
483
484 static void
485 tcp_session_reset (u32 conn_index, u32 thread_index)
486 {
487   tcp_connection_t *tc;
488   tc = tcp_connection_get (conn_index, thread_index);
489   session_transport_closed_notify (&tc->connection);
490   tcp_send_reset (tc);
491   tcp_connection_timers_reset (tc);
492   tcp_connection_set_state (tc, TCP_STATE_CLOSED);
493   tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
494 }
495
496 /**
497  * Initialize all connection timers as invalid
498  */
499 void
500 tcp_connection_timers_init (tcp_connection_t * tc)
501 {
502   int i;
503
504   /* Set all to invalid */
505   for (i = 0; i < TCP_N_TIMERS; i++)
506     {
507       tc->timers[i] = TCP_TIMER_HANDLE_INVALID;
508     }
509
510   tc->rto = TCP_RTO_INIT;
511 }
512
513 /**
514  * Stop all connection timers
515  */
516 void
517 tcp_connection_timers_reset (tcp_connection_t * tc)
518 {
519   int i;
520   for (i = 0; i < TCP_N_TIMERS; i++)
521     {
522       tcp_timer_reset (tc, i);
523     }
524 }
525
526 #if 0
527 typedef struct ip4_tcp_hdr
528 {
529   ip4_header_t ip;
530   tcp_header_t tcp;
531 } ip4_tcp_hdr_t;
532
533 typedef struct ip6_tcp_hdr
534 {
535   ip6_header_t ip;
536   tcp_header_t tcp;
537 } ip6_tcp_hdr_t;
538
539 static void
540 tcp_connection_select_lb_bucket (tcp_connection_t * tc, const dpo_id_t * dpo,
541                                  dpo_id_t * result)
542 {
543   const dpo_id_t *choice;
544   load_balance_t *lb;
545   int hash;
546
547   lb = load_balance_get (dpo->dpoi_index);
548   if (tc->c_is_ip4)
549     {
550       ip4_tcp_hdr_t hdr;
551       clib_memset (&hdr, 0, sizeof (hdr));
552       hdr.ip.protocol = IP_PROTOCOL_TCP;
553       hdr.ip.address_pair.src.as_u32 = tc->c_lcl_ip.ip4.as_u32;
554       hdr.ip.address_pair.dst.as_u32 = tc->c_rmt_ip.ip4.as_u32;
555       hdr.tcp.src_port = tc->c_lcl_port;
556       hdr.tcp.dst_port = tc->c_rmt_port;
557       hash = ip4_compute_flow_hash (&hdr.ip, lb->lb_hash_config);
558     }
559   else
560     {
561       ip6_tcp_hdr_t hdr;
562       clib_memset (&hdr, 0, sizeof (hdr));
563       hdr.ip.protocol = IP_PROTOCOL_TCP;
564       clib_memcpy_fast (&hdr.ip.src_address, &tc->c_lcl_ip.ip6,
565                         sizeof (ip6_address_t));
566       clib_memcpy_fast (&hdr.ip.dst_address, &tc->c_rmt_ip.ip6,
567                         sizeof (ip6_address_t));
568       hdr.tcp.src_port = tc->c_lcl_port;
569       hdr.tcp.dst_port = tc->c_rmt_port;
570       hash = ip6_compute_flow_hash (&hdr.ip, lb->lb_hash_config);
571     }
572   choice = load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
573   dpo_copy (result, choice);
574 }
575
576 fib_node_index_t
577 tcp_lookup_rmt_in_fib (tcp_connection_t * tc)
578 {
579   fib_prefix_t prefix;
580   u32 fib_index;
581
582   clib_memcpy_fast (&prefix.fp_addr, &tc->c_rmt_ip, sizeof (prefix.fp_addr));
583   prefix.fp_proto = tc->c_is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
584   prefix.fp_len = tc->c_is_ip4 ? 32 : 128;
585   fib_index = fib_table_find (prefix.fp_proto, tc->c_fib_index);
586   return fib_table_lookup (fib_index, &prefix);
587 }
588
589 static int
590 tcp_connection_stack_on_fib_entry (tcp_connection_t * tc)
591 {
592   dpo_id_t choice = DPO_INVALID;
593   u32 output_node_index;
594   fib_entry_t *fe;
595
596   fe = fib_entry_get (tc->c_rmt_fei);
597   if (fe->fe_lb.dpoi_type != DPO_LOAD_BALANCE)
598     return -1;
599
600   tcp_connection_select_lb_bucket (tc, &fe->fe_lb, &choice);
601
602   output_node_index =
603     tc->c_is_ip4 ? tcp4_output_node.index : tcp6_output_node.index;
604   dpo_stack_from_node (output_node_index, &tc->c_rmt_dpo, &choice);
605   return 0;
606 }
607
608 /** Stack tcp connection on peer's fib entry.
609  *
610  * This ultimately populates the dpo the connection will use to send packets.
611  */
612 static void
613 tcp_connection_fib_attach (tcp_connection_t * tc)
614 {
615   tc->c_rmt_fei = tcp_lookup_rmt_in_fib (tc);
616
617   ASSERT (tc->c_rmt_fei != FIB_NODE_INDEX_INVALID);
618
619   tcp_connection_stack_on_fib_entry (tc);
620 }
621 #endif /* 0 */
622
623 /**
624  * Generate random iss as per rfc6528
625  */
626 static u32
627 tcp_generate_random_iss (tcp_connection_t * tc)
628 {
629   tcp_main_t *tm = &tcp_main;
630   u64 tmp;
631
632   if (tc->c_is_ip4)
633     tmp = (u64) tc->c_lcl_ip.ip4.as_u32 << 32 | (u64) tc->c_rmt_ip.ip4.as_u32;
634   else
635     tmp = tc->c_lcl_ip.ip6.as_u64[0] ^ tc->c_lcl_ip.ip6.as_u64[1]
636       ^ tc->c_rmt_ip.ip6.as_u64[0] ^ tc->c_rmt_ip.ip6.as_u64[1];
637
638   tmp ^= tm->iss_seed.first | ((u64) tc->c_lcl_port << 16 | tc->c_rmt_port);
639   tmp ^= tm->iss_seed.second;
640   tmp = clib_xxhash (tmp) + clib_cpu_time_now ();
641   return ((tmp >> 32) ^ (tmp & 0xffffffff));
642 }
643
644 /**
645  * Initialize max segment size we're able to process.
646  *
647  * The value is constrained by the output interface's MTU and by the size
648  * of the IP and TCP headers (see RFC6691). It is also what we advertise
649  * to our peer.
650  */
651 static void
652 tcp_init_rcv_mss (tcp_connection_t * tc)
653 {
654   u8 ip_hdr_len;
655
656   ip_hdr_len = tc->c_is_ip4 ? sizeof (ip4_header_t) : sizeof (ip6_header_t);
657   tc->mss = tcp_cfg.default_mtu - sizeof (tcp_header_t) - ip_hdr_len;
658 }
659
660 static void
661 tcp_init_mss (tcp_connection_t * tc)
662 {
663   u16 default_min_mss = 536;
664
665   tcp_init_rcv_mss (tc);
666
667   /* TODO consider PMTU discovery */
668   tc->snd_mss = clib_min (tc->rcv_opts.mss, tc->mss);
669
670   if (tc->snd_mss < 45)
671     {
672       /* Assume that at least the min default mss works */
673       tc->snd_mss = default_min_mss;
674       tc->rcv_opts.mss = default_min_mss;
675     }
676
677   /* We should have enough space for 40 bytes of options */
678   ASSERT (tc->snd_mss > 45);
679
680   /* If we use timestamp option, account for it */
681   if (tcp_opts_tstamp (&tc->rcv_opts))
682     tc->snd_mss -= TCP_OPTION_LEN_TIMESTAMP;
683 }
684
685 /**
686  * Initialize connection send variables.
687  */
688 void
689 tcp_init_snd_vars (tcp_connection_t * tc)
690 {
691   /*
692    * We use the time to randomize iss and for setting up the initial
693    * timestamp. Make sure it's updated otherwise syn and ack in the
694    * handshake may make it look as if time has flown in the opposite
695    * direction for us.
696    */
697   tcp_set_time_now (tcp_get_worker (vlib_get_thread_index ()));
698
699   tcp_init_rcv_mss (tc);
700   tc->iss = tcp_generate_random_iss (tc);
701   tc->snd_una = tc->iss;
702   tc->snd_nxt = tc->iss + 1;
703   tc->snd_una_max = tc->snd_nxt;
704   tc->srtt = 100;               /* 100 ms */
705 }
706
707 void
708 tcp_enable_pacing (tcp_connection_t * tc)
709 {
710   u32 byte_rate;
711   byte_rate = tc->cwnd / (tc->srtt * TCP_TICK);
712   transport_connection_tx_pacer_init (&tc->connection, byte_rate, tc->cwnd);
713   tc->mrtt_us = (u32) ~ 0;
714 }
715
716 /** Initialize tcp connection variables
717  *
718  * Should be called after having received a msg from the peer, i.e., a SYN or
719  * a SYNACK, such that connection options have already been exchanged. */
720 void
721 tcp_connection_init_vars (tcp_connection_t * tc)
722 {
723   tcp_connection_timers_init (tc);
724   tcp_init_mss (tc);
725   scoreboard_init (&tc->sack_sb);
726   if (tc->state == TCP_STATE_SYN_RCVD)
727     tcp_init_snd_vars (tc);
728
729   tcp_cc_init (tc);
730
731   if (!tc->c_is_ip4 && ip6_address_is_link_local_unicast (&tc->c_rmt_ip6))
732     tcp_add_del_adjacency (tc, 1);
733
734   /*  tcp_connection_fib_attach (tc); */
735
736   if (transport_connection_is_tx_paced (&tc->connection)
737       || tcp_cfg.enable_tx_pacing)
738     tcp_enable_pacing (tc);
739
740   if (tc->flags & TCP_CONN_RATE_SAMPLE)
741     tcp_bt_init (tc);
742
743   tc->start_ts = tcp_time_now_us (tc->c_thread_index);
744 }
745
746 static int
747 tcp_alloc_custom_local_endpoint (tcp_main_t * tm, ip46_address_t * lcl_addr,
748                                  u16 * lcl_port, u8 is_ip4)
749 {
750   int index, port;
751   if (is_ip4)
752     {
753       index = tm->last_v4_addr_rotor++;
754       if (tm->last_v4_addr_rotor >= vec_len (tcp_cfg.ip4_src_addrs))
755         tm->last_v4_addr_rotor = 0;
756       lcl_addr->ip4.as_u32 = tcp_cfg.ip4_src_addrs[index].as_u32;
757     }
758   else
759     {
760       index = tm->last_v6_addr_rotor++;
761       if (tm->last_v6_addr_rotor >= vec_len (tcp_cfg.ip6_src_addrs))
762         tm->last_v6_addr_rotor = 0;
763       clib_memcpy_fast (&lcl_addr->ip6, &tcp_cfg.ip6_src_addrs[index],
764                         sizeof (ip6_address_t));
765     }
766   port = transport_alloc_local_port (TRANSPORT_PROTO_TCP, lcl_addr);
767   if (port < 1)
768     {
769       clib_warning ("Failed to allocate src port");
770       return -1;
771     }
772   *lcl_port = port;
773   return 0;
774 }
775
776 static int
777 tcp_session_open (transport_endpoint_cfg_t * rmt)
778 {
779   tcp_main_t *tm = vnet_get_tcp_main ();
780   tcp_connection_t *tc;
781   ip46_address_t lcl_addr;
782   u16 lcl_port;
783   int rv;
784
785   /*
786    * Allocate local endpoint
787    */
788   if ((rmt->is_ip4 && vec_len (tcp_cfg.ip4_src_addrs))
789       || (!rmt->is_ip4 && vec_len (tcp_cfg.ip6_src_addrs)))
790     rv = tcp_alloc_custom_local_endpoint (tm, &lcl_addr, &lcl_port,
791                                           rmt->is_ip4);
792   else
793     rv = transport_alloc_local_endpoint (TRANSPORT_PROTO_TCP,
794                                          rmt, &lcl_addr, &lcl_port);
795
796   if (rv)
797     return -1;
798
799   /*
800    * Create connection and send SYN
801    */
802   clib_spinlock_lock_if_init (&tm->half_open_lock);
803   tc = tcp_half_open_connection_new ();
804   ip_copy (&tc->c_rmt_ip, &rmt->ip, rmt->is_ip4);
805   ip_copy (&tc->c_lcl_ip, &lcl_addr, rmt->is_ip4);
806   tc->c_rmt_port = rmt->port;
807   tc->c_lcl_port = clib_host_to_net_u16 (lcl_port);
808   tc->c_is_ip4 = rmt->is_ip4;
809   tc->c_proto = TRANSPORT_PROTO_TCP;
810   tc->c_fib_index = rmt->fib_index;
811   tc->cc_algo = tcp_cc_algo_get (tcp_cfg.cc_algo);
812   /* The other connection vars will be initialized after SYN ACK */
813   tcp_connection_timers_init (tc);
814
815   TCP_EVT (TCP_EVT_OPEN, tc);
816   tc->state = TCP_STATE_SYN_SENT;
817   tcp_init_snd_vars (tc);
818   tcp_send_syn (tc);
819   clib_spinlock_unlock_if_init (&tm->half_open_lock);
820
821   return tc->c_c_index;
822 }
823
824 const char *tcp_fsm_states[] = {
825 #define _(sym, str) str,
826   foreach_tcp_fsm_state
827 #undef _
828 };
829
830 u8 *
831 format_tcp_state (u8 * s, va_list * args)
832 {
833   u32 state = va_arg (*args, u32);
834
835   if (state < TCP_N_STATES)
836     s = format (s, "%s", tcp_fsm_states[state]);
837   else
838     s = format (s, "UNKNOWN (%d (0x%x))", state, state);
839   return s;
840 }
841
842 const char *tcp_connection_flags_str[] = {
843 #define _(sym, str) str,
844   foreach_tcp_connection_flag
845 #undef _
846 };
847
848 static u8 *
849 format_tcp_connection_flags (u8 * s, va_list * args)
850 {
851   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
852   int i, last = -1;
853
854   for (i = 0; i < TCP_CONN_N_FLAG_BITS; i++)
855     if (tc->flags & (1 << i))
856       last = i;
857   for (i = 0; i < last; i++)
858     {
859       if (tc->flags & (1 << i))
860         s = format (s, "%s, ", tcp_connection_flags_str[i]);
861     }
862   if (last >= 0)
863     s = format (s, "%s", tcp_connection_flags_str[last]);
864   return s;
865 }
866
867 const char *tcp_conn_timers[] = {
868 #define _(sym, str) str,
869   foreach_tcp_timer
870 #undef _
871 };
872
873 static u8 *
874 format_tcp_timers (u8 * s, va_list * args)
875 {
876   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
877   int i, last = -1;
878
879   for (i = 0; i < TCP_N_TIMERS; i++)
880     if (tc->timers[i] != TCP_TIMER_HANDLE_INVALID)
881       last = i;
882
883   for (i = 0; i < last; i++)
884     {
885       if (tc->timers[i] != TCP_TIMER_HANDLE_INVALID)
886         s = format (s, "%s,", tcp_conn_timers[i]);
887     }
888
889   if (last >= 0)
890     s = format (s, "%s", tcp_conn_timers[i]);
891
892   return s;
893 }
894
895 static u8 *
896 format_tcp_congestion_status (u8 * s, va_list * args)
897 {
898   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
899   if (tcp_in_recovery (tc))
900     s = format (s, "recovery");
901   else if (tcp_in_fastrecovery (tc))
902     s = format (s, "fastrecovery");
903   else
904     s = format (s, "none");
905   return s;
906 }
907
908 static i32
909 tcp_rcv_wnd_available (tcp_connection_t * tc)
910 {
911   return (i32) tc->rcv_wnd - (tc->rcv_nxt - tc->rcv_las);
912 }
913
914 static u8 *
915 format_tcp_congestion (u8 * s, va_list * args)
916 {
917   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
918   u32 indent = format_get_indent (s), prr_space = 0;
919
920   s = format (s, "%U ", format_tcp_congestion_status, tc);
921   s = format (s, "algo %s cwnd %u ssthresh %u bytes_acked %u\n",
922               tc->cc_algo->name, tc->cwnd, tc->ssthresh, tc->bytes_acked);
923   s = format (s, "%Ucc space %u prev_cwnd %u prev_ssthresh %u\n",
924               format_white_space, indent, tcp_available_cc_snd_space (tc),
925               tc->prev_cwnd, tc->prev_ssthresh);
926   s = format (s, "%Usnd_cong %u dupack %u limited_tx %u\n",
927               format_white_space, indent, tc->snd_congestion - tc->iss,
928               tc->rcv_dupacks, tc->limited_transmit - tc->iss);
929   s = format (s, "%Urxt_bytes %u rxt_delivered %u rxt_head %u rxt_ts %u\n",
930               format_white_space, indent, tc->snd_rxt_bytes,
931               tc->rxt_delivered, tc->rxt_head - tc->iss,
932               tcp_time_now_w_thread (tc->c_thread_index) - tc->snd_rxt_ts);
933   if (tcp_in_fastrecovery (tc))
934     prr_space = tcp_fastrecovery_prr_snd_space (tc);
935   s = format (s, "%Uprr_start %u prr_delivered %u prr space %u\n",
936               format_white_space, indent, tc->prr_start - tc->iss,
937               tc->prr_delivered, prr_space);
938   return s;
939 }
940
941 static u8 *
942 format_tcp_stats (u8 * s, va_list * args)
943 {
944   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
945   u32 indent = format_get_indent (s);
946   s = format (s, "in segs %lu dsegs %lu bytes %lu dupacks %u\n",
947               tc->segs_in, tc->data_segs_in, tc->bytes_in, tc->dupacks_in);
948   s = format (s, "%Uout segs %lu dsegs %lu bytes %lu dupacks %u\n",
949               format_white_space, indent, tc->segs_out,
950               tc->data_segs_out, tc->bytes_out, tc->dupacks_out);
951   s = format (s, "%Ufr %u tr %u rxt segs %lu bytes %lu duration %.3f\n",
952               format_white_space, indent, tc->fr_occurences,
953               tc->tr_occurences, tc->segs_retrans, tc->bytes_retrans,
954               tcp_time_now_us (tc->c_thread_index) - tc->start_ts);
955   s = format (s, "%Uerr wnd data below %u above %u ack below %u above %u",
956               format_white_space, indent, tc->errors.below_data_wnd,
957               tc->errors.above_data_wnd, tc->errors.below_ack_wnd,
958               tc->errors.above_ack_wnd);
959   return s;
960 }
961
962 static u8 *
963 format_tcp_vars (u8 * s, va_list * args)
964 {
965   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
966   s = format (s, " index: %u flags: %U timers: %U\n", tc->c_c_index,
967               format_tcp_connection_flags, tc, format_tcp_timers, tc);
968   s = format (s, " snd_una %u snd_nxt %u snd_una_max %u",
969               tc->snd_una - tc->iss, tc->snd_nxt - tc->iss,
970               tc->snd_una_max - tc->iss);
971   s = format (s, " rcv_nxt %u rcv_las %u\n",
972               tc->rcv_nxt - tc->irs, tc->rcv_las - tc->irs);
973   s = format (s, " snd_wnd %u rcv_wnd %u rcv_wscale %u ",
974               tc->snd_wnd, tc->rcv_wnd, tc->rcv_wscale);
975   s = format (s, "snd_wl1 %u snd_wl2 %u\n", tc->snd_wl1 - tc->irs,
976               tc->snd_wl2 - tc->iss);
977   s = format (s, " flight size %u out space %u rcv_wnd_av %u",
978               tcp_flight_size (tc), tcp_available_output_snd_space (tc),
979               tcp_rcv_wnd_available (tc));
980   s = format (s, " tsval_recent %u\n", tc->tsval_recent);
981   s = format (s, " tsecr %u tsecr_last_ack %u tsval_recent_age %u",
982               tc->rcv_opts.tsecr, tc->tsecr_last_ack,
983               tcp_time_now () - tc->tsval_recent_age);
984   s = format (s, " snd_mss %u\n", tc->snd_mss);
985   s = format (s, " rto %u rto_boff %u srtt %u us %.3f rttvar %u rtt_ts %.4f",
986               tc->rto, tc->rto_boff, tc->srtt, tc->mrtt_us * 1000, tc->rttvar,
987               tc->rtt_ts);
988   s = format (s, " rtt_seq %u\n", tc->rtt_seq - tc->iss);
989   s = format (s, " cong:   %U", format_tcp_congestion, tc);
990
991   if (tc->state >= TCP_STATE_ESTABLISHED)
992     {
993       s = format (s, " sboard: %U\n", format_tcp_scoreboard, &tc->sack_sb,
994                   tc);
995       s = format (s, " stats: %U\n", format_tcp_stats, tc);
996     }
997   if (vec_len (tc->snd_sacks))
998     s = format (s, " sacks tx: %U\n", format_tcp_sacks, tc);
999
1000   return s;
1001 }
1002
1003 static u8 *
1004 format_tcp_connection_id (u8 * s, va_list * args)
1005 {
1006   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
1007   if (!tc)
1008     return s;
1009   if (tc->c_is_ip4)
1010     {
1011       s = format (s, "[%d:%d][%s] %U:%d->%U:%d", tc->c_thread_index,
1012                   tc->c_s_index, "T", format_ip4_address, &tc->c_lcl_ip4,
1013                   clib_net_to_host_u16 (tc->c_lcl_port), format_ip4_address,
1014                   &tc->c_rmt_ip4, clib_net_to_host_u16 (tc->c_rmt_port));
1015     }
1016   else
1017     {
1018       s = format (s, "[%d:%d][%s] %U:%d->%U:%d", tc->c_thread_index,
1019                   tc->c_s_index, "T", format_ip6_address, &tc->c_lcl_ip6,
1020                   clib_net_to_host_u16 (tc->c_lcl_port), format_ip6_address,
1021                   &tc->c_rmt_ip6, clib_net_to_host_u16 (tc->c_rmt_port));
1022     }
1023
1024   return s;
1025 }
1026
1027 u8 *
1028 format_tcp_connection (u8 * s, va_list * args)
1029 {
1030   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
1031   u32 verbose = va_arg (*args, u32);
1032
1033   if (!tc)
1034     return s;
1035   s = format (s, "%-50U", format_tcp_connection_id, tc);
1036   if (verbose)
1037     {
1038       s = format (s, "%-15U", format_tcp_state, tc->state);
1039       if (verbose > 1)
1040         s = format (s, "\n%U", format_tcp_vars, tc);
1041     }
1042
1043   return s;
1044 }
1045
1046 static u8 *
1047 format_tcp_session (u8 * s, va_list * args)
1048 {
1049   u32 tci = va_arg (*args, u32);
1050   u32 thread_index = va_arg (*args, u32);
1051   u32 verbose = va_arg (*args, u32);
1052   tcp_connection_t *tc;
1053
1054   tc = tcp_connection_get (tci, thread_index);
1055   if (tc)
1056     s = format (s, "%U", format_tcp_connection, tc, verbose);
1057   else
1058     s = format (s, "empty\n");
1059   return s;
1060 }
1061
1062 static u8 *
1063 format_tcp_listener_session (u8 * s, va_list * args)
1064 {
1065   u32 tci = va_arg (*args, u32);
1066   u32 __clib_unused thread_index = va_arg (*args, u32);
1067   u32 verbose = va_arg (*args, u32);
1068   tcp_connection_t *tc = tcp_listener_get (tci);
1069   s = format (s, "%-50U", format_tcp_connection_id, tc);
1070   if (verbose)
1071     s = format (s, "%-15U", format_tcp_state, tc->state);
1072   return s;
1073 }
1074
1075 static u8 *
1076 format_tcp_half_open_session (u8 * s, va_list * args)
1077 {
1078   u32 tci = va_arg (*args, u32);
1079   u32 __clib_unused thread_index = va_arg (*args, u32);
1080   tcp_connection_t *tc = tcp_half_open_connection_get (tci);
1081   return format (s, "%U", format_tcp_connection_id, tc);
1082 }
1083
1084 u8 *
1085 format_tcp_sacks (u8 * s, va_list * args)
1086 {
1087   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
1088   sack_block_t *sacks = tc->snd_sacks;
1089   sack_block_t *block;
1090   int i, len = 0;
1091
1092   len = vec_len (sacks);
1093   for (i = 0; i < len - 1; i++)
1094     {
1095       block = &sacks[i];
1096       s = format (s, " start %u end %u\n", block->start - tc->irs,
1097                   block->end - tc->irs);
1098     }
1099   if (len)
1100     {
1101       block = &sacks[len - 1];
1102       s = format (s, " start %u end %u", block->start - tc->irs,
1103                   block->end - tc->irs);
1104     }
1105   return s;
1106 }
1107
1108 u8 *
1109 format_tcp_rcv_sacks (u8 * s, va_list * args)
1110 {
1111   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
1112   sack_block_t *sacks = tc->rcv_opts.sacks;
1113   sack_block_t *block;
1114   int i, len = 0;
1115
1116   len = vec_len (sacks);
1117   for (i = 0; i < len - 1; i++)
1118     {
1119       block = &sacks[i];
1120       s = format (s, " start %u end %u\n", block->start - tc->iss,
1121                   block->end - tc->iss);
1122     }
1123   if (len)
1124     {
1125       block = &sacks[len - 1];
1126       s = format (s, " start %u end %u", block->start - tc->iss,
1127                   block->end - tc->iss);
1128     }
1129   return s;
1130 }
1131
1132 static u8 *
1133 format_tcp_sack_hole (u8 * s, va_list * args)
1134 {
1135   sack_scoreboard_hole_t *hole = va_arg (*args, sack_scoreboard_hole_t *);
1136   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
1137   if (tc)
1138     s = format (s, "  [%u, %u]", hole->start - tc->iss, hole->end - tc->iss);
1139   else
1140     s = format (s, "  [%u, %u]", hole->start, hole->end);
1141   return s;
1142 }
1143
1144 u8 *
1145 format_tcp_scoreboard (u8 * s, va_list * args)
1146 {
1147   sack_scoreboard_t *sb = va_arg (*args, sack_scoreboard_t *);
1148   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
1149   sack_scoreboard_hole_t *hole;
1150   u32 indent = format_get_indent (s);
1151
1152   s = format (s, "sacked %u last_sacked %u lost %u last_lost %u"
1153               " rxt_sacked %u\n",
1154               sb->sacked_bytes, sb->last_sacked_bytes, sb->lost_bytes,
1155               sb->last_lost_bytes, sb->rxt_sacked);
1156   s = format (s, "%Ulast_delivered %u high_sacked %u is_reneging %u\n",
1157               format_white_space, indent, sb->last_bytes_delivered,
1158               sb->high_sacked - tc->iss, sb->is_reneging);
1159   s = format (s, "%Ucur_rxt_hole %u high_rxt %u rescue_rxt %u",
1160               format_white_space, indent, sb->cur_rxt_hole,
1161               sb->high_rxt - tc->iss, sb->rescue_rxt - tc->iss);
1162
1163   hole = scoreboard_first_hole (sb);
1164   if (hole)
1165     s = format (s, "\n%Uhead %u tail %u %u holes:\n%U", format_white_space,
1166                 indent, sb->head, sb->tail, pool_elts (sb->holes),
1167                 format_white_space, indent);
1168
1169   while (hole)
1170     {
1171       s = format (s, "%U", format_tcp_sack_hole, hole, tc);
1172       hole = scoreboard_next_hole (sb, hole);
1173     }
1174
1175   return s;
1176 }
1177
1178 static transport_connection_t *
1179 tcp_session_get_transport (u32 conn_index, u32 thread_index)
1180 {
1181   tcp_connection_t *tc = tcp_connection_get (conn_index, thread_index);
1182   if (PREDICT_FALSE (!tc))
1183     return 0;
1184   return &tc->connection;
1185 }
1186
1187 static transport_connection_t *
1188 tcp_half_open_session_get_transport (u32 conn_index)
1189 {
1190   tcp_connection_t *tc = tcp_half_open_connection_get (conn_index);
1191   return &tc->connection;
1192 }
1193
1194 static u16
1195 tcp_session_cal_goal_size (tcp_connection_t * tc)
1196 {
1197   u16 goal_size = tc->snd_mss;
1198
1199   goal_size = TCP_MAX_GSO_SZ - tc->snd_mss % TCP_MAX_GSO_SZ;
1200   goal_size = clib_min (goal_size, tc->snd_wnd / 2);
1201
1202   return goal_size > tc->snd_mss ? goal_size : tc->snd_mss;
1203 }
1204
1205 /**
1206  * Compute maximum segment size for session layer.
1207  *
1208  * Since the result needs to be the actual data length, it first computes
1209  * the tcp options to be used in the next burst and subtracts their
1210  * length from the connection's snd_mss.
1211  */
1212 static u16
1213 tcp_session_send_mss (transport_connection_t * trans_conn)
1214 {
1215   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
1216
1217   /* Ensure snd_mss does accurately reflect the amount of data we can push
1218    * in a segment. This also makes sure that options are updated according to
1219    * the current state of the connection. */
1220   tcp_update_burst_snd_vars (tc);
1221
1222   if (PREDICT_FALSE (tc->is_tso))
1223     {
1224       return tcp_session_cal_goal_size (tc);
1225     }
1226
1227   return tc->snd_mss;
1228 }
1229
1230 always_inline u32
1231 tcp_round_snd_space (tcp_connection_t * tc, u32 snd_space)
1232 {
1233   if (PREDICT_FALSE (tc->snd_wnd < tc->snd_mss))
1234     {
1235       return tc->snd_wnd <= snd_space ? tc->snd_wnd : 0;
1236     }
1237
1238   /* If not snd_wnd constrained and we can't write at least a segment,
1239    * don't try at all */
1240   if (PREDICT_FALSE (snd_space < tc->snd_mss))
1241     return snd_space < tc->cwnd ? 0 : snd_space;
1242
1243   /* round down to mss multiple */
1244   return snd_space - (snd_space % tc->snd_mss);
1245 }
1246
1247 /**
1248  * Compute tx window session is allowed to fill.
1249  *
1250  * Takes into account available send space, snd_mss and the congestion
1251  * state of the connection. If possible, the value returned is a multiple
1252  * of snd_mss.
1253  *
1254  * @param tc tcp connection
1255  * @return number of bytes session is allowed to write
1256  */
1257 static inline u32
1258 tcp_snd_space_inline (tcp_connection_t * tc)
1259 {
1260   int snd_space;
1261
1262   if (PREDICT_FALSE (tcp_in_fastrecovery (tc)
1263                      || tc->state == TCP_STATE_CLOSED))
1264     return 0;
1265
1266   snd_space = tcp_available_output_snd_space (tc);
1267
1268   /* If we got dupacks or sacked bytes but we're not yet in recovery, try
1269    * to force the peer to send enough dupacks to start retransmitting as
1270    * per Limited Transmit (RFC3042)
1271    */
1272   if (PREDICT_FALSE (tc->rcv_dupacks != 0 || tc->sack_sb.sacked_bytes))
1273     {
1274       if (tc->limited_transmit != tc->snd_nxt
1275           && (seq_lt (tc->limited_transmit, tc->snd_nxt - 2 * tc->snd_mss)
1276               || seq_gt (tc->limited_transmit, tc->snd_nxt)))
1277         tc->limited_transmit = tc->snd_nxt;
1278
1279       ASSERT (seq_leq (tc->limited_transmit, tc->snd_nxt));
1280
1281       int snt_limited = tc->snd_nxt - tc->limited_transmit;
1282       snd_space = clib_max ((int) 2 * tc->snd_mss - snt_limited, 0);
1283     }
1284   return tcp_round_snd_space (tc, snd_space);
1285 }
1286
1287 u32
1288 tcp_snd_space (tcp_connection_t * tc)
1289 {
1290   return tcp_snd_space_inline (tc);
1291 }
1292
1293 static u32
1294 tcp_session_send_space (transport_connection_t * trans_conn)
1295 {
1296   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
1297   return clib_min (tcp_snd_space_inline (tc),
1298                    tc->snd_wnd - (tc->snd_nxt - tc->snd_una));
1299 }
1300
1301 static u32
1302 tcp_session_tx_fifo_offset (transport_connection_t * trans_conn)
1303 {
1304   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
1305
1306   ASSERT (seq_geq (tc->snd_nxt, tc->snd_una));
1307
1308   /* This still works if fast retransmit is on */
1309   return (tc->snd_nxt - tc->snd_una);
1310 }
1311
1312 static void
1313 tcp_update_time (f64 now, u8 thread_index)
1314 {
1315   tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
1316
1317   tcp_set_time_now (wrk);
1318   tw_timer_expire_timers_16t_2w_512sl (&wrk->timer_wheel, now);
1319   tcp_flush_frames_to_output (wrk);
1320 }
1321
1322 static void
1323 tcp_session_flush_data (transport_connection_t * tconn)
1324 {
1325   tcp_connection_t *tc = (tcp_connection_t *) tconn;
1326   if (tc->flags & TCP_CONN_PSH_PENDING)
1327     return;
1328   tc->flags |= TCP_CONN_PSH_PENDING;
1329   tc->psh_seq = tc->snd_una + transport_max_tx_dequeue (tconn) - 1;
1330 }
1331
1332 /* *INDENT-OFF* */
1333 const static transport_proto_vft_t tcp_proto = {
1334   .enable = vnet_tcp_enable_disable,
1335   .start_listen = tcp_session_bind,
1336   .stop_listen = tcp_session_unbind,
1337   .push_header = tcp_session_push_header,
1338   .get_connection = tcp_session_get_transport,
1339   .get_listener = tcp_session_get_listener,
1340   .get_half_open = tcp_half_open_session_get_transport,
1341   .connect = tcp_session_open,
1342   .close = tcp_session_close,
1343   .cleanup = tcp_session_cleanup,
1344   .reset = tcp_session_reset,
1345   .send_mss = tcp_session_send_mss,
1346   .send_space = tcp_session_send_space,
1347   .update_time = tcp_update_time,
1348   .tx_fifo_offset = tcp_session_tx_fifo_offset,
1349   .flush_data = tcp_session_flush_data,
1350   .custom_tx = tcp_session_custom_tx,
1351   .format_connection = format_tcp_session,
1352   .format_listener = format_tcp_listener_session,
1353   .format_half_open = format_tcp_half_open_session,
1354   .transport_options = {
1355     .tx_type = TRANSPORT_TX_PEEK,
1356     .service_type = TRANSPORT_SERVICE_VC,
1357   },
1358 };
1359 /* *INDENT-ON* */
1360
1361 void
1362 tcp_connection_tx_pacer_update (tcp_connection_t * tc)
1363 {
1364   if (!transport_connection_is_tx_paced (&tc->connection))
1365     return;
1366
1367   transport_connection_tx_pacer_update (&tc->connection,
1368                                         tcp_cc_get_pacing_rate (tc));
1369 }
1370
1371 void
1372 tcp_connection_tx_pacer_reset (tcp_connection_t * tc, u32 window,
1373                                u32 start_bucket)
1374 {
1375   tcp_worker_ctx_t *wrk = tcp_get_worker (tc->c_thread_index);
1376   f64 srtt = clib_min ((f64) tc->srtt * TCP_TICK, tc->mrtt_us);
1377   u64 last_time = wrk->vm->clib_time.last_cpu_time;
1378   transport_connection_tx_pacer_reset (&tc->connection, window / srtt,
1379                                        start_bucket, last_time);
1380 }
1381
1382 static void
1383 tcp_timer_waitclose_handler (u32 conn_index)
1384 {
1385   u32 thread_index = vlib_get_thread_index ();
1386   tcp_connection_t *tc;
1387
1388   tc = tcp_connection_get (conn_index, thread_index);
1389   if (!tc)
1390     return;
1391
1392   tc->timers[TCP_TIMER_WAITCLOSE] = TCP_TIMER_HANDLE_INVALID;
1393
1394   switch (tc->state)
1395     {
1396     case TCP_STATE_CLOSE_WAIT:
1397       tcp_connection_timers_reset (tc);
1398       session_transport_closed_notify (&tc->connection);
1399
1400       if (!(tc->flags & TCP_CONN_FINPNDG))
1401         {
1402           tcp_connection_set_state (tc, TCP_STATE_CLOSED);
1403           tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
1404           break;
1405         }
1406
1407       /* Session didn't come back with a close. Send FIN either way
1408        * and switch to LAST_ACK. */
1409       tcp_cong_recovery_off (tc);
1410       /* Make sure we don't try to send unsent data */
1411       tc->snd_nxt = tc->snd_una;
1412       tcp_send_fin (tc);
1413       tcp_connection_set_state (tc, TCP_STATE_LAST_ACK);
1414
1415       /* Make sure we don't wait in LAST ACK forever */
1416       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.lastack_time);
1417
1418       /* Don't delete the connection yet */
1419       break;
1420     case TCP_STATE_FIN_WAIT_1:
1421       tcp_connection_timers_reset (tc);
1422       session_transport_closed_notify (&tc->connection);
1423       if (tc->flags & TCP_CONN_FINPNDG)
1424         {
1425           /* If FIN pending, we haven't sent everything, but we did try.
1426            * Notify session layer that transport is closed. */
1427           tcp_connection_set_state (tc, TCP_STATE_CLOSED);
1428           tcp_send_reset (tc);
1429           tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
1430         }
1431       else
1432         {
1433           /* We've sent the fin but no progress. Close the connection and
1434            * to make sure everything is flushed, setup a cleanup timer */
1435           tcp_connection_set_state (tc, TCP_STATE_CLOSED);
1436           tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
1437         }
1438       break;
1439     case TCP_STATE_LAST_ACK:
1440     case TCP_STATE_CLOSING:
1441       tcp_connection_timers_reset (tc);
1442       tcp_connection_set_state (tc, TCP_STATE_CLOSED);
1443       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
1444       session_transport_closed_notify (&tc->connection);
1445       break;
1446     default:
1447       tcp_connection_del (tc);
1448       break;
1449     }
1450 }
1451
1452 /* *INDENT-OFF* */
1453 static timer_expiration_handler *timer_expiration_handlers[TCP_N_TIMERS] =
1454 {
1455     tcp_timer_retransmit_handler,
1456     tcp_timer_delack_handler,
1457     tcp_timer_persist_handler,
1458     tcp_timer_waitclose_handler,
1459     tcp_timer_retransmit_syn_handler,
1460 };
1461 /* *INDENT-ON* */
1462
1463 static void
1464 tcp_expired_timers_dispatch (u32 * expired_timers)
1465 {
1466   int i;
1467   u32 connection_index, timer_id;
1468
1469   for (i = 0; i < vec_len (expired_timers); i++)
1470     {
1471       /* Get session index and timer id */
1472       connection_index = expired_timers[i] & 0x0FFFFFFF;
1473       timer_id = expired_timers[i] >> 28;
1474
1475       TCP_EVT (TCP_EVT_TIMER_POP, connection_index, timer_id);
1476
1477       /* Handle expiration */
1478       (*timer_expiration_handlers[timer_id]) (connection_index);
1479     }
1480 }
1481
1482 static void
1483 tcp_initialize_timer_wheels (tcp_main_t * tm)
1484 {
1485   tw_timer_wheel_16t_2w_512sl_t *tw;
1486   /* *INDENT-OFF* */
1487   foreach_vlib_main (({
1488     tw = &tm->wrk_ctx[ii].timer_wheel;
1489     tw_timer_wheel_init_16t_2w_512sl (tw, tcp_expired_timers_dispatch,
1490                                       TCP_TIMER_TICK, ~0);
1491     tw->last_run_time = vlib_time_now (this_vlib_main);
1492   }));
1493   /* *INDENT-ON* */
1494 }
1495
1496 static void
1497 tcp_initialize_iss_seed (tcp_main_t * tm)
1498 {
1499   u32 default_seed = random_default_seed ();
1500   u64 time_now = clib_cpu_time_now ();
1501
1502   tm->iss_seed.first = (u64) random_u32 (&default_seed) << 32;
1503   tm->iss_seed.second = random_u64 (&time_now);
1504 }
1505
1506 static clib_error_t *
1507 tcp_main_enable (vlib_main_t * vm)
1508 {
1509   vlib_thread_main_t *vtm = vlib_get_thread_main ();
1510   u32 num_threads, n_workers, prealloc_conn_per_wrk;
1511   tcp_connection_t *tc __attribute__ ((unused));
1512   tcp_main_t *tm = vnet_get_tcp_main ();
1513   clib_error_t *error = 0;
1514   int thread;
1515
1516   if ((error = vlib_call_init_function (vm, ip_main_init)))
1517     return error;
1518   if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
1519     return error;
1520   if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1521     return error;
1522
1523   /*
1524    * Registrations
1525    */
1526
1527   ip4_register_protocol (IP_PROTOCOL_TCP, tcp4_input_node.index);
1528   ip6_register_protocol (IP_PROTOCOL_TCP, tcp6_input_node.index);
1529
1530   /*
1531    * Initialize data structures
1532    */
1533
1534   num_threads = 1 /* main thread */  + vtm->n_threads;
1535   vec_validate (tm->connections, num_threads - 1);
1536   vec_validate (tm->wrk_ctx, num_threads - 1);
1537   n_workers = num_threads == 1 ? 1 : vtm->n_threads;
1538   prealloc_conn_per_wrk = tcp_cfg.preallocated_connections / n_workers;
1539
1540   for (thread = 0; thread < num_threads; thread++)
1541     {
1542       vec_validate (tm->wrk_ctx[thread].pending_deq_acked, 255);
1543       vec_validate (tm->wrk_ctx[thread].pending_disconnects, 255);
1544       vec_reset_length (tm->wrk_ctx[thread].pending_deq_acked);
1545       vec_reset_length (tm->wrk_ctx[thread].pending_disconnects);
1546       tm->wrk_ctx[thread].vm = vlib_mains[thread];
1547
1548       /*
1549        * Preallocate connections. Assume that thread 0 won't
1550        * use preallocated threads when running multi-core
1551        */
1552       if ((thread > 0 || num_threads == 1) && prealloc_conn_per_wrk)
1553         pool_init_fixed (tm->connections[thread], prealloc_conn_per_wrk);
1554     }
1555
1556   /*
1557    * Use a preallocated half-open connection pool?
1558    */
1559   if (tcp_cfg.preallocated_half_open_connections)
1560     pool_init_fixed (tm->half_open_connections,
1561                      tcp_cfg.preallocated_half_open_connections);
1562
1563   /* Initialize clocks per tick for TCP timestamp. Used to compute
1564    * monotonically increasing timestamps. */
1565   tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
1566     / TCP_TSTAMP_RESOLUTION;
1567
1568   if (num_threads > 1)
1569     {
1570       clib_spinlock_init (&tm->half_open_lock);
1571     }
1572
1573   tcp_initialize_timer_wheels (tm);
1574   tcp_initialize_iss_seed (tm);
1575
1576   tm->bytes_per_buffer = vlib_buffer_get_default_data_size (vm);
1577   tm->cc_last_type = TCP_CC_LAST;
1578   return error;
1579 }
1580
1581 clib_error_t *
1582 vnet_tcp_enable_disable (vlib_main_t * vm, u8 is_en)
1583 {
1584   if (is_en)
1585     {
1586       if (tcp_main.is_enabled)
1587         return 0;
1588
1589       return tcp_main_enable (vm);
1590     }
1591   else
1592     {
1593       tcp_main.is_enabled = 0;
1594     }
1595
1596   return 0;
1597 }
1598
1599 void
1600 tcp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
1601 {
1602   tcp_main_t *tm = &tcp_main;
1603   if (is_ip4)
1604     tm->punt_unknown4 = is_add;
1605   else
1606     tm->punt_unknown6 = is_add;
1607 }
1608
1609 /**
1610  * Initialize default values for tcp parameters
1611  */
1612 static void
1613 tcp_configuration_init (void)
1614 {
1615   /* Initial wnd for SYN. Fifos are not allocated at that point so use some
1616    * predefined value. For SYN-ACK we still want the scale to be computed in
1617    * the same way */
1618   tcp_cfg.max_rx_fifo = 32 << 20;
1619   tcp_cfg.min_rx_fifo = 4 << 10;
1620
1621   tcp_cfg.default_mtu = 1500;
1622   tcp_cfg.initial_cwnd_multiplier = 0;
1623   tcp_cfg.enable_tx_pacing = 1;
1624   tcp_cfg.cc_algo = TCP_CC_NEWRENO;
1625   tcp_cfg.rwnd_min_update_ack = 1;
1626
1627   /* Time constants defined as timer tick (100ms) multiples */
1628   tcp_cfg.delack_time = 1;      /* 0.1s */
1629   tcp_cfg.closewait_time = 20;  /* 2s */
1630   tcp_cfg.timewait_time = 100;  /* 10s */
1631   tcp_cfg.finwait1_time = 600;  /* 60s */
1632   tcp_cfg.lastack_time = 300;   /* 30s */
1633   tcp_cfg.finwait2_time = 300;  /* 30s */
1634   tcp_cfg.closing_time = 300;   /* 30s */
1635   tcp_cfg.cleanup_time = 1;     /* 0.1s */
1636 }
1637
1638 static clib_error_t *
1639 tcp_init (vlib_main_t * vm)
1640 {
1641   tcp_main_t *tm = vnet_get_tcp_main ();
1642   ip_main_t *im = &ip_main;
1643   ip_protocol_info_t *pi;
1644
1645   /* Session layer, and by implication tcp, are disabled by default */
1646   tm->is_enabled = 0;
1647
1648   /* Register with IP for header parsing */
1649   pi = ip_get_protocol_info (im, IP_PROTOCOL_TCP);
1650   if (pi == 0)
1651     return clib_error_return (0, "TCP protocol info AWOL");
1652   pi->format_header = format_tcp_header;
1653   pi->unformat_pg_edit = unformat_pg_tcp_header;
1654
1655   /* Register as transport with session layer */
1656   transport_register_protocol (TRANSPORT_PROTO_TCP, &tcp_proto,
1657                                FIB_PROTOCOL_IP4, tcp4_output_node.index);
1658   transport_register_protocol (TRANSPORT_PROTO_TCP, &tcp_proto,
1659                                FIB_PROTOCOL_IP6, tcp6_output_node.index);
1660
1661   tcp_api_reference ();
1662   tcp_configuration_init ();
1663
1664   tm->cc_algo_by_name = hash_create_string (0, sizeof (uword));
1665
1666   return 0;
1667 }
1668
1669 VLIB_INIT_FUNCTION (tcp_init);
1670
1671 uword
1672 unformat_tcp_cc_algo (unformat_input_t * input, va_list * va)
1673 {
1674   tcp_cc_algorithm_type_e *result = va_arg (*va, tcp_cc_algorithm_type_e *);
1675   tcp_main_t *tm = &tcp_main;
1676   char *cc_algo_name;
1677   u8 found = 0;
1678   uword *p;
1679
1680   if (unformat (input, "%s", &cc_algo_name)
1681       && ((p = hash_get_mem (tm->cc_algo_by_name, cc_algo_name))))
1682     {
1683       *result = *p;
1684       found = 1;
1685     }
1686
1687   vec_free (cc_algo_name);
1688   return found;
1689 }
1690
1691 uword
1692 unformat_tcp_cc_algo_cfg (unformat_input_t * input, va_list * va)
1693 {
1694   tcp_main_t *tm = vnet_get_tcp_main ();
1695   tcp_cc_algorithm_t *cc_alg;
1696   unformat_input_t sub_input;
1697   int found = 0;
1698
1699   vec_foreach (cc_alg, tm->cc_algos)
1700   {
1701     if (!unformat (input, cc_alg->name))
1702       continue;
1703
1704     if (cc_alg->unformat_cfg
1705         && unformat (input, "%U", unformat_vlib_cli_sub_input, &sub_input))
1706       {
1707         if (cc_alg->unformat_cfg (&sub_input))
1708           found = 1;
1709       }
1710   }
1711   return found;
1712 }
1713
1714 static clib_error_t *
1715 tcp_config_fn (vlib_main_t * vm, unformat_input_t * input)
1716 {
1717   u32 cwnd_multiplier, tmp_time;
1718   uword memory_size;
1719
1720   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1721     {
1722       if (unformat (input, "preallocated-connections %d",
1723                     &tcp_cfg.preallocated_connections))
1724         ;
1725       else if (unformat (input, "preallocated-half-open-connections %d",
1726                          &tcp_cfg.preallocated_half_open_connections))
1727         ;
1728       else if (unformat (input, "buffer-fail-fraction %f",
1729                          &tcp_cfg.buffer_fail_fraction))
1730         ;
1731       else if (unformat (input, "max-rx-fifo %U", unformat_memory_size,
1732                          &memory_size))
1733         tcp_cfg.max_rx_fifo = memory_size;
1734       else if (unformat (input, "min-rx-fifo %U", unformat_memory_size,
1735                          &memory_size))
1736         tcp_cfg.min_rx_fifo = memory_size;
1737       else if (unformat (input, "mtu %u", &tcp_cfg.default_mtu))
1738         ;
1739       else if (unformat (input, "rwnd-min-update-ack %d",
1740                          &tcp_cfg.rwnd_min_update_ack))
1741         ;
1742       else if (unformat (input, "initial-cwnd-multiplier %u",
1743                          &cwnd_multiplier))
1744         tcp_cfg.initial_cwnd_multiplier = cwnd_multiplier;
1745       else if (unformat (input, "no-tx-pacing"))
1746         tcp_cfg.enable_tx_pacing = 0;
1747       else if (unformat (input, "cc-algo %U", unformat_tcp_cc_algo,
1748                          &tcp_cfg.cc_algo))
1749         ;
1750       else if (unformat (input, "%U", unformat_tcp_cc_algo_cfg))
1751         ;
1752       else if (unformat (input, "closewait-time %u", &tmp_time))
1753         tcp_cfg.closewait_time = tmp_time / TCP_TIMER_TICK;
1754       else if (unformat (input, "timewait-time %u", &tmp_time))
1755         tcp_cfg.timewait_time = tmp_time / TCP_TIMER_TICK;
1756       else if (unformat (input, "finwait1-time %u", &tmp_time))
1757         tcp_cfg.finwait1_time = tmp_time / TCP_TIMER_TICK;
1758       else if (unformat (input, "finwait2-time %u", &tmp_time))
1759         tcp_cfg.finwait2_time = tmp_time / TCP_TIMER_TICK;
1760       else if (unformat (input, "lastack-time %u", &tmp_time))
1761         tcp_cfg.lastack_time = tmp_time / TCP_TIMER_TICK;
1762       else if (unformat (input, "closing-time %u", &tmp_time))
1763         tcp_cfg.closing_time = tmp_time / TCP_TIMER_TICK;
1764       else if (unformat (input, "cleanup-time %u", &tmp_time))
1765         tcp_cfg.cleanup_time = tmp_time / TCP_TIMER_TICK;
1766       else
1767         return clib_error_return (0, "unknown input `%U'",
1768                                   format_unformat_error, input);
1769     }
1770   return 0;
1771 }
1772
1773 VLIB_CONFIG_FUNCTION (tcp_config_fn, "tcp");
1774
1775
1776 /**
1777  * \brief Configure an ipv4 source address range
1778  * @param vm vlib_main_t pointer
1779  * @param start first ipv4 address in the source address range
1780  * @param end last ipv4 address in the source address range
1781  * @param table_id VRF / table ID, 0 for the default FIB
1782  * @return 0 if all OK, else an error indication from api_errno.h
1783  */
1784
1785 int
1786 tcp_configure_v4_source_address_range (vlib_main_t * vm,
1787                                        ip4_address_t * start,
1788                                        ip4_address_t * end, u32 table_id)
1789 {
1790   vnet_main_t *vnm = vnet_get_main ();
1791   u32 start_host_byte_order, end_host_byte_order;
1792   fib_prefix_t prefix;
1793   fib_node_index_t fei;
1794   u32 fib_index = 0;
1795   u32 sw_if_index;
1796   int rv;
1797
1798   clib_memset (&prefix, 0, sizeof (prefix));
1799
1800   fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
1801
1802   if (fib_index == ~0)
1803     return VNET_API_ERROR_NO_SUCH_FIB;
1804
1805   start_host_byte_order = clib_net_to_host_u32 (start->as_u32);
1806   end_host_byte_order = clib_net_to_host_u32 (end->as_u32);
1807
1808   /* sanity check for reversed args or some such */
1809   if ((end_host_byte_order - start_host_byte_order) > (10 << 10))
1810     return VNET_API_ERROR_INVALID_ARGUMENT;
1811
1812   /* Lookup the last address, to identify the interface involved */
1813   prefix.fp_len = 32;
1814   prefix.fp_proto = FIB_PROTOCOL_IP4;
1815   memcpy (&prefix.fp_addr.ip4, end, sizeof (ip4_address_t));
1816
1817   fei = fib_table_lookup (fib_index, &prefix);
1818
1819   /* Couldn't find route to destination. Bail out. */
1820   if (fei == FIB_NODE_INDEX_INVALID)
1821     return VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB;
1822
1823   sw_if_index = fib_entry_get_resolving_interface (fei);
1824
1825   /* Configure proxy arp across the range */
1826   rv = vnet_proxy_arp_add_del (start, end, fib_index, 0 /* is_del */ );
1827
1828   if (rv)
1829     return rv;
1830
1831   rv = vnet_proxy_arp_enable_disable (vnm, sw_if_index, 1);
1832
1833   if (rv)
1834     return rv;
1835
1836   do
1837     {
1838       dpo_id_t dpo = DPO_INVALID;
1839
1840       vec_add1 (tcp_cfg.ip4_src_addrs, start[0]);
1841
1842       /* Add local adjacencies for the range */
1843
1844       receive_dpo_add_or_lock (DPO_PROTO_IP4, ~0 /* sw_if_index */ ,
1845                                NULL, &dpo);
1846       prefix.fp_len = 32;
1847       prefix.fp_proto = FIB_PROTOCOL_IP4;
1848       prefix.fp_addr.ip4.as_u32 = start->as_u32;
1849
1850       fib_table_entry_special_dpo_update (fib_index,
1851                                           &prefix,
1852                                           FIB_SOURCE_API,
1853                                           FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
1854       dpo_reset (&dpo);
1855
1856       start_host_byte_order++;
1857       start->as_u32 = clib_host_to_net_u32 (start_host_byte_order);
1858     }
1859   while (start_host_byte_order <= end_host_byte_order);
1860
1861   return 0;
1862 }
1863
1864 /**
1865  * \brief Configure an ipv6 source address range
1866  * @param vm vlib_main_t pointer
1867  * @param start first ipv6 address in the source address range
1868  * @param end last ipv6 address in the source address range
1869  * @param table_id VRF / table ID, 0 for the default FIB
1870  * @return 0 if all OK, else an error indication from api_errno.h
1871  */
1872
1873 int
1874 tcp_configure_v6_source_address_range (vlib_main_t * vm,
1875                                        ip6_address_t * start,
1876                                        ip6_address_t * end, u32 table_id)
1877 {
1878   fib_prefix_t prefix;
1879   u32 fib_index = 0;
1880   fib_node_index_t fei;
1881   u32 sw_if_index;
1882
1883   clib_memset (&prefix, 0, sizeof (prefix));
1884
1885   fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
1886
1887   if (fib_index == ~0)
1888     return VNET_API_ERROR_NO_SUCH_FIB;
1889
1890   while (1)
1891     {
1892       int i;
1893       ip6_address_t tmp;
1894       dpo_id_t dpo = DPO_INVALID;
1895
1896       /* Remember this address */
1897       vec_add1 (tcp_cfg.ip6_src_addrs, start[0]);
1898
1899       /* Lookup the prefix, to identify the interface involved */
1900       prefix.fp_len = 128;
1901       prefix.fp_proto = FIB_PROTOCOL_IP6;
1902       memcpy (&prefix.fp_addr.ip6, start, sizeof (ip6_address_t));
1903
1904       fei = fib_table_lookup (fib_index, &prefix);
1905
1906       /* Couldn't find route to destination. Bail out. */
1907       if (fei == FIB_NODE_INDEX_INVALID)
1908         return VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB;
1909
1910       sw_if_index = fib_entry_get_resolving_interface (fei);
1911
1912       if (sw_if_index == (u32) ~ 0)
1913         return VNET_API_ERROR_NO_MATCHING_INTERFACE;
1914
1915       /* Add a proxy neighbor discovery entry for this address */
1916       ip6_neighbor_proxy_add_del (sw_if_index, start, 0 /* is_del */ );
1917
1918       /* Add a receive adjacency for this address */
1919       receive_dpo_add_or_lock (DPO_PROTO_IP6, ~0 /* sw_if_index */ ,
1920                                NULL, &dpo);
1921
1922       fib_table_entry_special_dpo_update (fib_index,
1923                                           &prefix,
1924                                           FIB_SOURCE_API,
1925                                           FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
1926       dpo_reset (&dpo);
1927
1928       /* Done with the entire range? */
1929       if (!memcmp (start, end, sizeof (start[0])))
1930         break;
1931
1932       /* Increment the address. DGMS. */
1933       tmp = start[0];
1934       for (i = 15; i >= 0; i--)
1935         {
1936           tmp.as_u8[i] += 1;
1937           if (tmp.as_u8[i] != 0)
1938             break;
1939         }
1940       start[0] = tmp;
1941     }
1942   return 0;
1943 }
1944
1945 static clib_error_t *
1946 tcp_src_address (vlib_main_t * vm,
1947                  unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1948 {
1949   ip4_address_t v4start, v4end;
1950   ip6_address_t v6start, v6end;
1951   u32 table_id = 0;
1952   int v4set = 0;
1953   int v6set = 0;
1954   int rv;
1955
1956   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1957     {
1958       if (unformat (input, "%U - %U", unformat_ip4_address, &v4start,
1959                     unformat_ip4_address, &v4end))
1960         v4set = 1;
1961       else if (unformat (input, "%U", unformat_ip4_address, &v4start))
1962         {
1963           memcpy (&v4end, &v4start, sizeof (v4start));
1964           v4set = 1;
1965         }
1966       else if (unformat (input, "%U - %U", unformat_ip6_address, &v6start,
1967                          unformat_ip6_address, &v6end))
1968         v6set = 1;
1969       else if (unformat (input, "%U", unformat_ip6_address, &v6start))
1970         {
1971           memcpy (&v6end, &v6start, sizeof (v6start));
1972           v6set = 1;
1973         }
1974       else if (unformat (input, "fib-table %d", &table_id))
1975         ;
1976       else
1977         break;
1978     }
1979
1980   if (!v4set && !v6set)
1981     return clib_error_return (0, "at least one v4 or v6 address required");
1982
1983   if (v4set)
1984     {
1985       rv = tcp_configure_v4_source_address_range (vm, &v4start, &v4end,
1986                                                   table_id);
1987       switch (rv)
1988         {
1989         case 0:
1990           break;
1991
1992         case VNET_API_ERROR_NO_SUCH_FIB:
1993           return clib_error_return (0, "Invalid table-id %d", table_id);
1994
1995         case VNET_API_ERROR_INVALID_ARGUMENT:
1996           return clib_error_return (0, "Invalid address range %U - %U",
1997                                     format_ip4_address, &v4start,
1998                                     format_ip4_address, &v4end);
1999         default:
2000           return clib_error_return (0, "error %d", rv);
2001           break;
2002         }
2003     }
2004   if (v6set)
2005     {
2006       rv = tcp_configure_v6_source_address_range (vm, &v6start, &v6end,
2007                                                   table_id);
2008       switch (rv)
2009         {
2010         case 0:
2011           break;
2012
2013         case VNET_API_ERROR_NO_SUCH_FIB:
2014           return clib_error_return (0, "Invalid table-id %d", table_id);
2015
2016         default:
2017           return clib_error_return (0, "error %d", rv);
2018           break;
2019         }
2020     }
2021   return 0;
2022 }
2023
2024 /* *INDENT-OFF* */
2025 VLIB_CLI_COMMAND (tcp_src_address_command, static) =
2026 {
2027   .path = "tcp src-address",
2028   .short_help = "tcp src-address <ip-addr> [- <ip-addr>] add src address range",
2029   .function = tcp_src_address,
2030 };
2031 /* *INDENT-ON* */
2032
2033 static u8 *
2034 tcp_scoreboard_dump_trace (u8 * s, sack_scoreboard_t * sb)
2035 {
2036 #if TCP_SCOREBOARD_TRACE
2037
2038   scoreboard_trace_elt_t *block;
2039   int i = 0;
2040
2041   if (!sb->trace)
2042     return s;
2043
2044   s = format (s, "scoreboard trace:");
2045   vec_foreach (block, sb->trace)
2046   {
2047     s = format (s, "{%u, %u, %u, %u, %u}, ", block->start, block->end,
2048                 block->ack, block->snd_una_max, block->group);
2049     if ((++i % 3) == 0)
2050       s = format (s, "\n");
2051   }
2052   return s;
2053 #else
2054   return 0;
2055 #endif
2056 }
2057
2058 static clib_error_t *
2059 tcp_show_scoreboard_trace_fn (vlib_main_t * vm, unformat_input_t * input,
2060                               vlib_cli_command_t * cmd_arg)
2061 {
2062   transport_connection_t *tconn = 0;
2063   tcp_connection_t *tc;
2064   u8 *s = 0;
2065   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2066     {
2067       if (unformat (input, "%U", unformat_transport_connection, &tconn,
2068                     TRANSPORT_PROTO_TCP))
2069         ;
2070       else
2071         return clib_error_return (0, "unknown input `%U'",
2072                                   format_unformat_error, input);
2073     }
2074
2075   if (!TCP_SCOREBOARD_TRACE)
2076     {
2077       vlib_cli_output (vm, "scoreboard tracing not enabled");
2078       return 0;
2079     }
2080
2081   tc = tcp_get_connection_from_transport (tconn);
2082   s = tcp_scoreboard_dump_trace (s, &tc->sack_sb);
2083   vlib_cli_output (vm, "%v", s);
2084   return 0;
2085 }
2086
2087 /* *INDENT-OFF* */
2088 VLIB_CLI_COMMAND (tcp_show_scoreboard_trace_command, static) =
2089 {
2090   .path = "show tcp scoreboard trace",
2091   .short_help = "show tcp scoreboard trace <connection>",
2092   .function = tcp_show_scoreboard_trace_fn,
2093 };
2094 /* *INDENT-ON* */
2095
2096 u8 *
2097 tcp_scoreboard_replay (u8 * s, tcp_connection_t * tc, u8 verbose)
2098 {
2099   int i, trace_len;
2100   scoreboard_trace_elt_t *trace;
2101   u32 next_ack, left, group, has_new_ack = 0;
2102   tcp_connection_t _dummy_tc, *dummy_tc = &_dummy_tc;
2103   sack_block_t *block;
2104
2105   if (!TCP_SCOREBOARD_TRACE)
2106     {
2107       s = format (s, "scoreboard tracing not enabled");
2108       return s;
2109     }
2110
2111   if (!tc)
2112     return s;
2113
2114   clib_memset (dummy_tc, 0, sizeof (*dummy_tc));
2115   tcp_connection_timers_init (dummy_tc);
2116   scoreboard_init (&dummy_tc->sack_sb);
2117   dummy_tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
2118
2119 #if TCP_SCOREBOARD_TRACE
2120   trace = tc->sack_sb.trace;
2121   trace_len = vec_len (tc->sack_sb.trace);
2122 #endif
2123
2124   for (i = 0; i < trace_len; i++)
2125     {
2126       if (trace[i].ack != 0)
2127         {
2128           dummy_tc->snd_una = trace[i].ack - 1448;
2129           dummy_tc->snd_una_max = trace[i].ack;
2130         }
2131     }
2132
2133   left = 0;
2134   while (left < trace_len)
2135     {
2136       group = trace[left].group;
2137       vec_reset_length (dummy_tc->rcv_opts.sacks);
2138       has_new_ack = 0;
2139       while (trace[left].group == group)
2140         {
2141           if (trace[left].ack != 0)
2142             {
2143               if (verbose)
2144                 s = format (s, "Adding ack %u, snd_una_max %u, segs: ",
2145                             trace[left].ack, trace[left].snd_una_max);
2146               dummy_tc->snd_una_max = trace[left].snd_una_max;
2147               next_ack = trace[left].ack;
2148               has_new_ack = 1;
2149             }
2150           else
2151             {
2152               if (verbose)
2153                 s = format (s, "[%u, %u], ", trace[left].start,
2154                             trace[left].end);
2155               vec_add2 (dummy_tc->rcv_opts.sacks, block, 1);
2156               block->start = trace[left].start;
2157               block->end = trace[left].end;
2158             }
2159           left++;
2160         }
2161
2162       /* Push segments */
2163       tcp_rcv_sacks (dummy_tc, next_ack);
2164       if (has_new_ack)
2165         dummy_tc->snd_una = next_ack;
2166
2167       if (verbose)
2168         s = format (s, "result: %U", format_tcp_scoreboard,
2169                     &dummy_tc->sack_sb);
2170
2171     }
2172   s = format (s, "result: %U", format_tcp_scoreboard, &dummy_tc->sack_sb);
2173
2174   return s;
2175 }
2176
2177 static clib_error_t *
2178 tcp_scoreboard_trace_fn (vlib_main_t * vm, unformat_input_t * input,
2179                          vlib_cli_command_t * cmd_arg)
2180 {
2181   transport_connection_t *tconn = 0;
2182   tcp_connection_t *tc = 0;
2183   u8 *str = 0;
2184   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2185     {
2186       if (unformat (input, "%U", unformat_transport_connection, &tconn,
2187                     TRANSPORT_PROTO_TCP))
2188         ;
2189       else
2190         return clib_error_return (0, "unknown input `%U'",
2191                                   format_unformat_error, input);
2192     }
2193
2194   if (!TCP_SCOREBOARD_TRACE)
2195     {
2196       vlib_cli_output (vm, "scoreboard tracing not enabled");
2197       return 0;
2198     }
2199
2200   tc = tcp_get_connection_from_transport (tconn);
2201   if (!tc)
2202     {
2203       vlib_cli_output (vm, "connection not found");
2204       return 0;
2205     }
2206   str = tcp_scoreboard_replay (str, tc, 1);
2207   vlib_cli_output (vm, "%v", str);
2208   return 0;
2209 }
2210
2211 /* *INDENT-OFF* */
2212 VLIB_CLI_COMMAND (tcp_replay_scoreboard_command, static) =
2213 {
2214   .path = "tcp replay scoreboard",
2215   .short_help = "tcp replay scoreboard <connection>",
2216   .function = tcp_scoreboard_trace_fn,
2217 };
2218 /* *INDENT-ON* */
2219
2220 static clib_error_t *
2221 show_tcp_punt_fn (vlib_main_t * vm, unformat_input_t * input,
2222                   vlib_cli_command_t * cmd_arg)
2223 {
2224   tcp_main_t *tm = vnet_get_tcp_main ();
2225   if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2226     return clib_error_return (0, "unknown input `%U'", format_unformat_error,
2227                               input);
2228   vlib_cli_output (vm, "IPv4 TCP punt: %s",
2229                    tm->punt_unknown4 ? "enabled" : "disabled");
2230   vlib_cli_output (vm, "IPv6 TCP punt: %s",
2231                    tm->punt_unknown6 ? "enabled" : "disabled");
2232   return 0;
2233 }
2234 /* *INDENT-OFF* */
2235 VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
2236 {
2237   .path = "show tcp punt",
2238   .short_help = "show tcp punt",
2239   .function = show_tcp_punt_fn,
2240 };
2241 /* *INDENT-ON* */
2242
2243 /*
2244  * fd.io coding-style-patch-verification: ON
2245  *
2246  * Local Variables:
2247  * eval: (c-set-style "gnu")
2248  * End:
2249  */