From f9d0568344b4766bc1ddc1be9a7e9afd00e2d832 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 26 Apr 2018 08:26:52 -0700 Subject: tcp: handle link-local addresses Change-Id: I9ede6bc861350c7d9e78fa4d96cd584c2816d06f Signed-off-by: Florin Coras --- src/vnet/adj/adj_nbr.c | 2 +- src/vnet/adj/adj_nbr.h | 8 ++++++ src/vnet/tcp/tcp.h | 1 + src/vnet/tcp/tcp_error.def | 3 ++- src/vnet/tcp/tcp_input.c | 2 ++ src/vnet/tcp/tcp_output.c | 67 +++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/vnet/adj/adj_nbr.c b/src/vnet/adj/adj_nbr.c index 29cd8123414..eff7d4ce1fb 100644 --- a/src/vnet/adj/adj_nbr.c +++ b/src/vnet/adj/adj_nbr.c @@ -93,7 +93,7 @@ adj_nbr_remove (adj_index_t ai, BV(clib_bihash_add_del) (adj_nbr_tables[nh_proto][sw_if_index], &kv, 0); } -static adj_index_t +adj_index_t adj_nbr_find (fib_protocol_t nh_proto, vnet_link_t link_type, const ip46_address_t *nh_addr, diff --git a/src/vnet/adj/adj_nbr.h b/src/vnet/adj/adj_nbr.h index 293766b8519..5d0f8444ec3 100644 --- a/src/vnet/adj/adj_nbr.h +++ b/src/vnet/adj/adj_nbr.h @@ -161,6 +161,14 @@ adj_nbr_walk_nh6 (u32 sw_if_index, adj_walk_cb_t cb, void *ctx); +/** + * @brief Lookup neighbor adjancency. + */ +adj_index_t +adj_nbr_find (fib_protocol_t nh_proto, + vnet_link_t link_type, + const ip46_address_t *nh_addr, + u32 sw_if_index); /** * @brief * Module initialisation diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h index 8a6f74ab13a..837b5b4d0d2 100644 --- a/src/vnet/tcp/tcp.h +++ b/src/vnet/tcp/tcp.h @@ -305,6 +305,7 @@ typedef struct _tcp_connection u16 mss; /**< Our max seg size that includes options */ u32 limited_transmit; /**< snd_nxt when limited transmit starts */ u32 last_fib_check; /**< Last time we checked fib route for peer */ + u32 sw_if_index; /**< Interface for the connection */ } tcp_connection_t; struct _tcp_cc_algorithm diff --git a/src/vnet/tcp/tcp_error.def b/src/vnet/tcp/tcp_error.def index 8f006dfc287..44bf0c04168 100644 --- a/src/vnet/tcp/tcp_error.def +++ b/src/vnet/tcp/tcp_error.def @@ -44,4 +44,5 @@ tcp_error (FILTERED, "Packets filtered") tcp_error (OPTIONS, "Could not parse options") tcp_error (PAWS, "PAWS check failed") tcp_error (RCV_WND, "Segment not in receive window") -tcp_error (FIN_RCVD, "FINs received") \ No newline at end of file +tcp_error (FIN_RCVD, "FINs received") +tcp_error (LINK_LOCAL_RW, "No rewrite for link local connection") \ No newline at end of file diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index 497b709bec0..42db82e1214 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -2126,6 +2126,7 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, new_tc0->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID; new_tc0->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID; + new_tc0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; /* If this is not the owning thread, wait for syn retransmit to * expire and cleanup then */ @@ -2818,6 +2819,7 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node, child0->irs = vnet_buffer (b0)->tcp.seq_number; child0->rcv_nxt = vnet_buffer (b0)->tcp.seq_number + 1; child0->rcv_las = child0->rcv_nxt; + child0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; /* RFC1323: TSval timestamps sent on {SYN} and {SYN,ACK} * segments are used to initialize PAWS. */ diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index df882bc5ff1..fe6d09c2c0e 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -24,16 +24,22 @@ typedef enum _tcp_output_next { TCP_OUTPUT_NEXT_DROP, TCP_OUTPUT_NEXT_IP_LOOKUP, + TCP_OUTPUT_NEXT_IP_REWRITE, + TCP_OUTPUT_NEXT_IP_ARP, TCP_OUTPUT_N_NEXT } tcp_output_next_t; #define foreach_tcp4_output_next \ _ (DROP, "error-drop") \ - _ (IP_LOOKUP, "ip4-lookup") + _ (IP_LOOKUP, "ip4-lookup") \ + _ (IP_REWRITE, "ip4-rewrite") \ + _ (IP_ARP, "ip4-arp") #define foreach_tcp6_output_next \ _ (DROP, "error-drop") \ - _ (IP_LOOKUP, "ip6-lookup") + _ (IP_LOOKUP, "ip6-lookup") \ + _ (IP_REWRITE, "ip6-rewrite") \ + _ (IP_ARP, "ip6-discover-neighbor") static char *tcp_error_strings[] = { #define tcp_error(n,s) s, @@ -1747,6 +1753,53 @@ tcp_session_has_ooo_data (tcp_connection_t * tc) return svm_fifo_has_ooo_data (s->server_rx_fifo); } +typedef struct +{ + fib_protocol_t nh_proto; + vnet_link_t link_type; + ip46_address_t ip; + u32 sw_if_index; +} tcp_adj_add_args_t; + +void +tcp_output_add_adj (tcp_adj_add_args_t * args) +{ + adj_nbr_add_or_lock (args->nh_proto, args->link_type, &args->ip, + args->sw_if_index); +} + +static void +tcp_output_handle_link_local (tcp_connection_t * tc0, vlib_buffer_t * b0, + u32 * next0, u32 * error0) +{ + ip_adjacency_t *adj; + adj_index_t ai; + + ai = adj_nbr_find (FIB_PROTOCOL_IP6, VNET_LINK_IP6, &tc0->c_rmt_ip, + tc0->sw_if_index); + if (ai == ADJ_INDEX_INVALID) + { + tcp_adj_add_args_t args = { + .nh_proto = FIB_PROTOCOL_IP6, + .link_type = VNET_LINK_IP6, + .ip = tc0->c_rmt_ip, + .sw_if_index = tc0->sw_if_index + }; + vlib_rpc_call_main_thread (tcp_output_add_adj, (u8 *) & args, + sizeof (args)); + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + *next0 = TCP_OUTPUT_NEXT_DROP; + *error0 = TCP_ERROR_LINK_LOCAL_RW; + return; + } + + adj = adj_get (ai); + if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE) + *next0 = TCP_OUTPUT_NEXT_IP_REWRITE; + else if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) + *next0 = TCP_OUTPUT_NEXT_IP_ARP; +} + always_inline uword tcp46_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -1802,6 +1855,8 @@ tcp46_output_inline (vlib_main_t * vm, th0 = vlib_buffer_get_current (b0); TCP_EVT_DBG (TCP_EVT_OUTPUT, tc0, th0->flags, b0->current_length); + vnet_buffer (b0)->sw_if_index[VLIB_TX] = tc0->c_fib_index; + vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; if (is_ip4) { @@ -1820,6 +1875,10 @@ tcp46_output_inline (vlib_main_t * vm, vnet_buffer (b0)->l3_hdr_offset = (u8 *) ih0 - b0->data; vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data; th0->checksum = 0; + + if (PREDICT_FALSE + (ip6_address_is_link_local_unicast (&tc0->c_rmt_ip6))) + tcp_output_handle_link_local (tc0, b0, &next0, &error0); } /* Filter out DUPACKs if there are no OOO segments left */ @@ -1889,10 +1948,6 @@ tcp46_output_inline (vlib_main_t * vm, vnet_buffer (b0)->ip.adj_index[VLIB_TX] = tc0->c_rmt_dpo.dpoi_index; #endif - vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = tc0->c_fib_index; - - b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; done: b0->error = node->errors[error0]; if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) -- cgit 1.2.3-korg