tcp: fix v6 sessions 59/8059/5
authorroot <root@wasa-ucs-13.linuxfoundation.org>
Tue, 15 Aug 2017 16:58:31 +0000 (12:58 -0400)
committerFlorin Coras <florin.coras@gmail.com>
Wed, 16 Aug 2017 16:47:44 +0000 (16:47 +0000)
Change-Id: Ia6dd5e948b17b2f3866fe70838eabb09e35415e1
Signed-off-by: Dave Barach <dbarach@cisco.com>
Signed-off-by: Florin Coras <fcoras@cisco.com>
src/vnet/ip/ip6_forward.c
src/vnet/session/session.c
src/vnet/session/session_cli.c
src/vnet/session/session_lookup.c
src/vnet/tcp/tcp.c
src/vnet/tcp/tcp_input.c
src/vnet/tcp/tcp_output.c

index 8ae08a0..5832bd0 100644 (file)
@@ -1323,6 +1323,20 @@ ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
   return (fib_urpf_check_size (lb0->lb_urpf));
 }
 
+always_inline u8
+ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
+                          u32 * udp_offset0)
+{
+  u32 proto0;
+  proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
+  if (proto0 != IP_PROTOCOL_UDP)
+    {
+      proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
+      proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
+    }
+  return proto0;
+}
+
 static uword
 ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
@@ -1352,8 +1366,8 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          u32 pi0, ip_len0, udp_len0, flags0, next0;
          u32 pi1, ip_len1, udp_len1, flags1, next1;
          i32 len_diff0, len_diff1;
-         u8 error0, type0, good_l4_checksum0;
-         u8 error1, type1, good_l4_checksum1;
+         u8 error0, type0, good_l4_csum0, is_tcp_udp0;
+         u8 error1, type1, good_l4_csum1, is_tcp_udp1;
          u32 udp_offset0, udp_offset1;
 
          pi0 = to_next[0] = from[0];
@@ -1381,67 +1395,69 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          flags0 = p0->flags;
          flags1 = p1->flags;
 
-         good_l4_checksum0 =
-           (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
-         good_l4_checksum1 =
-           (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
+         is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
+         is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
+
+         good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
+         good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
          len_diff0 = 0;
          len_diff1 = 0;
 
-         if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
-                                                                 IP_PROTOCOL_UDP,
-                                                                 &udp_offset0)))
+         if (PREDICT_TRUE (is_tcp_udp0))
            {
              udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
              /* Don't verify UDP checksum for packets with explicit zero checksum. */
-             good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
+             good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
                && udp0->checksum == 0;
              /* Verify UDP length. */
-             ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
-             udp_len0 = clib_net_to_host_u16 (udp0->length);
-             len_diff0 = ip_len0 - udp_len0;
+             if (is_tcp_udp0 == IP_PROTOCOL_UDP)
+               {
+                 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
+                 udp_len0 = clib_net_to_host_u16 (udp0->length);
+                 len_diff0 = ip_len0 - udp_len0;
+               }
            }
-         if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
-                                                                 IP_PROTOCOL_UDP,
-                                                                 &udp_offset1)))
+         if (PREDICT_TRUE (is_tcp_udp1))
            {
              udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
              /* Don't verify UDP checksum for packets with explicit zero checksum. */
-             good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
+             good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
                && udp1->checksum == 0;
              /* Verify UDP length. */
-             ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
-             udp_len1 = clib_net_to_host_u16 (udp1->length);
-             len_diff1 = ip_len1 - udp_len1;
+             if (is_tcp_udp1 == IP_PROTOCOL_UDP)
+               {
+                 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
+                 udp_len1 = clib_net_to_host_u16 (udp1->length);
+                 len_diff1 = ip_len1 - udp_len1;
+               }
            }
 
-         good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
-         good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
+         good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
+         good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
 
          len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
          len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
 
          if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
-                            && !good_l4_checksum0
+                            && !good_l4_csum0
                             && !(flags0 &
                                  VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
            {
              flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
-             good_l4_checksum0 =
+             good_l4_csum0 =
                (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
            }
          if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
-                            && !good_l4_checksum1
+                            && !good_l4_csum1
                             && !(flags1 &
                                  VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
            {
              flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
-             good_l4_checksum1 =
+             good_l4_csum1 =
                (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
            }
 
          error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
-
          error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
          error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
 
@@ -1449,10 +1465,8 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
                  IP6_ERROR_UDP_CHECKSUM);
          ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
                  IP6_ERROR_ICMP_CHECKSUM);
-         error0 =
-           (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
-         error1 =
-           (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
+         error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
+         error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
 
          /* Drop packets from unroutable hosts. */
          /* If this is a neighbor solicitation (ICMP), skip source RPF check */
@@ -1491,8 +1505,9 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          udp_header_t *udp0;
          u32 pi0, ip_len0, udp_len0, flags0, next0;
          i32 len_diff0;
-         u8 error0, type0, good_l4_checksum0;
+         u8 error0, type0, good_l4_csum0;
          u32 udp_offset0;
+         u8 is_tcp_udp0;
 
          pi0 = to_next[0] = from[0];
          from += 1;
@@ -1501,59 +1516,55 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          n_left_to_next -= 1;
 
          p0 = vlib_get_buffer (vm, pi0);
-
          ip0 = vlib_buffer_get_current (p0);
-
          vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
 
          type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
          next0 = lm->local_next_by_ip_protocol[ip0->protocol];
-
          flags0 = p0->flags;
+         is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
+         good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
 
-         good_l4_checksum0 =
-           (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
          len_diff0 = 0;
-
-         if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
-                                                                 IP_PROTOCOL_UDP,
-                                                                 &udp_offset0)))
+         if (PREDICT_TRUE (is_tcp_udp0))
            {
              udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
-             /* Don't verify UDP checksum for packets with explicit zero checksum. */
-             good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
+             /* Don't verify UDP checksum for packets with explicit zero
+              * checksum. */
+             good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
                && udp0->checksum == 0;
              /* Verify UDP length. */
-             ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
-             udp_len0 = clib_net_to_host_u16 (udp0->length);
-             len_diff0 = ip_len0 - udp_len0;
+             if (is_tcp_udp0 == IP_PROTOCOL_UDP)
+               {
+                 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
+                 udp_len0 = clib_net_to_host_u16 (udp0->length);
+                 len_diff0 = ip_len0 - udp_len0;
+               }
            }
 
-         good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
+         good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
          len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
 
          if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
-                            && !good_l4_checksum0
+                            && !good_l4_csum0
                             && !(flags0 &
                                  VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
            {
              flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
-             good_l4_checksum0 =
+             good_l4_csum0 =
                (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
            }
 
          error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
-
          error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
 
          ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
                  IP6_ERROR_UDP_CHECKSUM);
          ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
                  IP6_ERROR_ICMP_CHECKSUM);
-         error0 =
-           (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
+         error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
 
-         /* If this is a neighbor solicitation (ICMP), skip source RPF check */
+         /* If this is a neighbor solicitation (ICMP), skip src RPF check */
          if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
              type0 != IP_BUILTIN_PROTOCOL_ICMP &&
              !ip6_address_is_link_local_unicast (&ip0->src_address))
@@ -1564,7 +1575,6 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 
          next0 =
            error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
-
          p0->error = error_node->errors[error0];
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
index 843d474..70a5cd8 100644 (file)
@@ -375,10 +375,12 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail)
   u64 handle;
   u32 opaque = 0;
   int error = 0;
+  u8 st;
 
+  st = session_type_from_proto_and_ip (tc->transport_proto, tc->is_ip4);
   handle = stream_session_half_open_lookup_handle (&tc->lcl_ip, &tc->rmt_ip,
                                                   tc->lcl_port, tc->rmt_port,
-                                                  tc->transport_proto);
+                                                  st);
   if (handle == HALF_OPEN_LOOKUP_INVALID_VALUE)
     {
       clib_warning ("This can't be good!");
index 9f3d217..f60048f 100755 (executable)
@@ -315,7 +315,7 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
 VLIB_CLI_COMMAND (vlib_cli_show_session_command) =
 {
   .path = "show session",
-  .short_help = "show session [verbose]",
+  .short_help = "show session [verbose [nnn]]",
   .function = show_session_command_fn,
 };
 /* *INDENT-ON* */
index 41f9dbf..0f9abf9 100644 (file)
@@ -106,8 +106,8 @@ make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
 always_inline void
 make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t)
 {
-  return make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port,
-                       t->rmt_port, t->transport_proto);
+  make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port, t->rmt_port,
+                session_type_from_proto_and_ip (t->transport_proto, 1));
 }
 
 always_inline void
@@ -149,8 +149,8 @@ make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
 always_inline void
 make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
 {
-  make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port,
-                t->rmt_port, t->transport_proto);
+  make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port, t->rmt_port,
+                session_type_from_proto_and_ip (t->transport_proto, 0));
 }
 
 /*
index 75c9d8d..d169002 100644 (file)
@@ -362,7 +362,11 @@ ip_interface_get_first_ip (u32 sw_if_index, u8 is_ip4)
       /* *INDENT-OFF* */
       foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
       ({
-        return ip_interface_address_get_address (lm6, ia);
+        ip6_address_t *rv;
+        rv = ip_interface_address_get_address (lm6, ia);
+        /* Trying to use a link-local ip6 src address is a fool's errand */
+        if (!ip6_address_is_link_local_unicast (rv))
+          return rv;
       }));
       /* *INDENT-ON* */
     }
@@ -635,6 +639,14 @@ tcp_connection_open (transport_endpoint_t * rmt)
       else
        {
          ip6 = ip_interface_get_first_ip (sw_if_index, 0);
+         if (ip6 == 0)
+           {
+             clib_warning ("no routable ip6 addresses on %U",
+                           format_vnet_sw_if_index_name, vnet_get_main (),
+                           sw_if_index);
+             return -1;
+           }
+
          clib_memcpy (&lcl_addr.ip6, ip6, sizeof (*ip6));
        }
     }
@@ -1109,7 +1121,6 @@ tcp_timer_establish_handler (u32 conn_index)
   if (tc)
     {
       ASSERT (tc->state == TCP_STATE_SYN_SENT);
-      tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID;
       stream_session_connect_notify (&tc->connection, 1 /* fail */ );
     }
   else
@@ -1117,6 +1128,7 @@ tcp_timer_establish_handler (u32 conn_index)
       tc = tcp_connection_get (conn_index, vlib_get_thread_index ());
       ASSERT (tc->state == TCP_STATE_SYN_RCVD);
     }
+  tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID;
   tcp_connection_cleanup (tc);
 }
 
@@ -1231,6 +1243,7 @@ tcp_main_enable (vlib_main_t * vm)
   pi->unformat_pg_edit = unformat_pg_tcp_header;
 
   ip4_register_protocol (IP_PROTOCOL_TCP, tcp4_input_node.index);
+  ip6_register_protocol (IP_PROTOCOL_TCP, tcp6_input_node.index);
 
   /* Register as transport with session layer */
   session_register_transport (TRANSPORT_PROTO_TCP, 1, &tcp_proto);
index a3c4f1d..6f9e4c7 100644 (file)
@@ -1877,26 +1877,12 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          tc0 =
            tcp_half_open_connection_get (vnet_buffer (b0)->
                                          tcp.connection_index);
+         ASSERT (tc0);
 
          ack0 = vnet_buffer (b0)->tcp.ack_number;
          seq0 = vnet_buffer (b0)->tcp.seq_number;
          tcp0 = tcp_buffer_hdr (b0);
 
-         if (!tc0)
-           {
-             ip4_header_t *ip40 = vlib_buffer_get_current (b0);
-             tcp0 = ip4_next_header (ip40);
-             tc0 =
-               (tcp_connection_t *)
-               stream_session_lookup_transport_wt4 (&ip40->dst_address,
-                                                    &ip40->src_address,
-                                                    tcp0->dst_port,
-                                                    tcp0->src_port,
-                                                    SESSION_TYPE_IP4_TCP,
-                                                    my_thread_index);
-             ASSERT (0);
-             goto drop;
-           }
          if (PREDICT_FALSE
              (!tcp_ack (tcp0) && !tcp_rst (tcp0) && !tcp_syn (tcp0)))
            goto drop;
index 5a395b9..e6a211b 100644 (file)
@@ -775,12 +775,10 @@ tcp_send_reset (tcp_connection_t * tc, vlib_buffer_t * pkt, u8 is_ip4)
   else
     {
       int bogus = ~0;
-      pkt_ih6 = (ip6_header_t *) (pkt_th - 1);
       ASSERT ((pkt_ih6->ip_version_traffic_class_and_flow_label & 0xF0) ==
              0x60);
-      ih6 =
-       vlib_buffer_push_ip6 (vm, b, &pkt_ih6->dst_address,
-                             &pkt_ih6->src_address, IP_PROTOCOL_TCP);
+      ih6 = vlib_buffer_push_ip6 (vm, b, &pkt_ih6->dst_address,
+                                 &pkt_ih6->src_address, IP_PROTOCOL_TCP);
       th->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ih6, &bogus);
       ASSERT (!bogus);
     }