diff options
Diffstat (limited to 'src/vnet')
-rw-r--r-- | src/vnet/buffer.h | 13 | ||||
-rw-r--r-- | src/vnet/ip/format.h | 5 | ||||
-rw-r--r-- | src/vnet/ip/punt.c | 20 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_output.c | 8 | ||||
-rw-r--r-- | src/vnet/sctp/builtin_client.c | 834 | ||||
-rw-r--r-- | src/vnet/sctp/builtin_client.h | 121 | ||||
-rw-r--r-- | src/vnet/sctp/builtin_server.c | 472 | ||||
-rw-r--r-- | src/vnet/sctp/sctp.c | 848 | ||||
-rw-r--r-- | src/vnet/sctp/sctp.h | 645 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_debug.h | 62 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_error.def | 50 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_format.c | 40 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_input.c | 2202 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_output.c | 1331 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_packet.h | 1445 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_pg.c | 30 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_timer.h | 29 | ||||
-rw-r--r-- | src/vnet/session/application_interface.c | 17 | ||||
-rw-r--r-- | src/vnet/session/transport.c | 7 | ||||
-rw-r--r-- | src/vnet/session/transport.h | 3 |
20 files changed, 8170 insertions, 12 deletions
diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 317f8bb8e4a..097f68f6c06 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -329,6 +329,19 @@ typedef struct u8 flags; } tcp; + /* SCTP */ + struct + { + u32 connection_index; + u16 sid; /**< Stream ID */ + u16 ssn; /**< Stream Sequence Number */ + u32 tsn; /**< Transmission Sequence Number */ + u16 hdr_offset; /**< offset relative to ip hdr */ + u16 data_offset; /**< offset relative to ip hdr */ + u16 data_len; /**< data len */ + u8 flags; + } sctp; + /* SNAT */ struct { diff --git a/src/vnet/ip/format.h b/src/vnet/ip/format.h index c35f0f4bb74..d527e31a05e 100644 --- a/src/vnet/ip/format.h +++ b/src/vnet/ip/format.h @@ -99,9 +99,10 @@ format_function_t format_ip6_header; unformat_function_t unformat_pg_ip6_header; /* Format a TCP/UDP headers. */ -format_function_t format_tcp_header, format_udp_header; +format_function_t format_tcp_header, format_udp_header, format_sctp_header; -unformat_function_t unformat_pg_tcp_header, unformat_pg_udp_header; +unformat_function_t unformat_pg_tcp_header, unformat_pg_udp_header, + unformat_pg_sctp_header; #endif /* included_ip_format_h */ diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c index b417427288c..4a027bfdadb 100644 --- a/src/vnet/ip/punt.c +++ b/src/vnet/ip/punt.c @@ -27,6 +27,7 @@ #include <vnet/pg/pg.h> #include <vnet/udp/udp.h> #include <vnet/tcp/tcp.h> +#include <vnet/sctp/sctp.h> #include <vnet/ip/punt.h> #include <vppinfra/sparse_vec.h> #include <vlib/unix/unix.h> @@ -689,11 +690,13 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, bool is_add) { - /* For now we only support UDP punt */ - if (protocol != IP_PROTOCOL_UDP && protocol != IP_PROTOCOL_TCP) + /* For now we only support TCP, UDP and SCTP punt */ + if (protocol != IP_PROTOCOL_UDP && + protocol != IP_PROTOCOL_TCP && protocol != IP_PROTOCOL_SCTP) return clib_error_return (0, - "only UDP (%d) and TCP (%d) protocols are supported, got %d", - IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, protocol); + "only UDP (%d), TCP (%d) and SCTP (%d) protocols are supported, got %d", + IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, + IP_PROTOCOL_SCTP, protocol); if (ipv != (u8) ~ 0 && ipv != 4 && ipv != 6) return clib_error_return (0, "IP version must be 4 or 6, got %d", ipv); @@ -706,6 +709,8 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, udp_punt_unknown (vm, 1, is_add); else if (protocol == IP_PROTOCOL_TCP) tcp_punt_unknown (vm, 1, is_add); + else if (protocol == IP_PROTOCOL_SCTP) + sctp_punt_unknown (vm, 1, is_add); } if ((ipv == 6) || (ipv == (u8) ~ 0)) @@ -714,6 +719,8 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, udp_punt_unknown (vm, 0, is_add); else if (protocol == IP_PROTOCOL_TCP) tcp_punt_unknown (vm, 0, is_add); + else if (protocol == IP_PROTOCOL_SCTP) + sctp_punt_unknown (vm, 0, is_add); } return 0; @@ -721,8 +728,9 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, else if (is_add) { - if (protocol == IP_PROTOCOL_TCP) - return clib_error_return (0, "punt TCP ports is not supported yet"); + if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP) + return clib_error_return (0, + "punt TCP/SCTP ports is not supported yet"); if (ipv == 4 || ipv == (u8) ~ 0) udp_register_dst_port (vm, port, udp4_punt_node.index, 1); diff --git a/src/vnet/ipsec/ipsec_output.c b/src/vnet/ipsec/ipsec_output.c index e86292c0d17..d56b665157d 100644 --- a/src/vnet/ipsec/ipsec_output.c +++ b/src/vnet/ipsec/ipsec_output.c @@ -100,7 +100,9 @@ ipsec_output_policy_match (ipsec_spd_t * spd, u8 pr, u32 la, u32 ra, u16 lp, if (ra > clib_net_to_host_u32 (p->raddr.stop.ip4.as_u32)) continue; - if (PREDICT_FALSE ((pr != IP_PROTOCOL_TCP) && (pr != IP_PROTOCOL_UDP))) + if (PREDICT_FALSE + ((pr != IP_PROTOCOL_TCP) && (pr != IP_PROTOCOL_UDP) + && (pr != IP_PROTOCOL_SCTP))) return p; if (lp < p->lport.start) @@ -153,7 +155,9 @@ ipsec_output_ip6_policy_match (ipsec_spd_t * spd, if (!ip6_addr_match_range (la, &p->laddr.start.ip6, &p->laddr.stop.ip6)) continue; - if (PREDICT_FALSE ((pr != IP_PROTOCOL_TCP) && (pr != IP_PROTOCOL_UDP))) + if (PREDICT_FALSE + ((pr != IP_PROTOCOL_TCP) && (pr != IP_PROTOCOL_UDP) + && (pr != IP_PROTOCOL_SCTP))) return p; if (lp < p->lport.start) diff --git a/src/vnet/sctp/builtin_client.c b/src/vnet/sctp/builtin_client.c new file mode 100644 index 00000000000..4e50c0ae2ea --- /dev/null +++ b/src/vnet/sctp/builtin_client.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2018 SUSE LLC. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <vnet/vnet.h> +#include <vnet/plugin/plugin.h> +#include <vnet/sctp/builtin_client.h> + +#include <vlibapi/api.h> +#include <vlibmemory/api.h> +#include <vpp/app/version.h> + +tclient_main_t tclient_main; + +#define SCTP_BUILTIN_CLIENT_DBG (0) + +static void +signal_evt_to_cli_i (int *code) +{ + tclient_main_t *tm = &tclient_main; + ASSERT (vlib_get_thread_index () == 0); + vlib_process_signal_event (tm->vlib_main, tm->cli_node_index, *code, 0); +} + +static void +signal_evt_to_cli (int code) +{ + if (vlib_get_thread_index () != 0) + vl_api_rpc_call_main_thread (signal_evt_to_cli_i, (u8 *) & code, + sizeof (code)); + else + signal_evt_to_cli_i (&code); +} + +static void +send_test_chunk (tclient_main_t * tm, session_t * s) +{ + u8 *test_data = tm->connect_test_data; + int test_buf_offset; + u32 bytes_this_chunk; + session_fifo_event_t evt; + svm_fifo_t *txf; + int rv; + + ASSERT (vec_len (test_data) > 0); + + test_buf_offset = s->bytes_sent % vec_len (test_data); + bytes_this_chunk = vec_len (test_data) - test_buf_offset; + bytes_this_chunk = bytes_this_chunk < s->bytes_to_send + ? bytes_this_chunk : s->bytes_to_send; + + txf = s->server_tx_fifo; + rv = svm_fifo_enqueue_nowait (txf, bytes_this_chunk, + test_data + test_buf_offset); + + /* If we managed to enqueue data... */ + if (rv > 0) + { + /* Account for it... */ + s->bytes_to_send -= rv; + s->bytes_sent += rv; + + if (SCTP_BUILTIN_CLIENT_DBG) + { + /* *INDENT-OFF* */ + ELOG_TYPE_DECLARE (e) = + { + .format = "tx-enq: xfer %d bytes, sent %u remain %u", + .format_args = "i4i4i4", + }; + /* *INDENT-ON* */ + struct + { + u32 data[3]; + } *ed; + ed = ELOG_DATA (&vlib_global_main.elog_main, e); + ed->data[0] = rv; + ed->data[1] = s->bytes_sent; + ed->data[2] = s->bytes_to_send; + } + + /* Poke the session layer */ + if (svm_fifo_set_event (txf)) + { + /* Fabricate TX event, send to vpp */ + evt.fifo = txf; + evt.event_type = FIFO_EVENT_APP_TX; + + if (svm_queue_add + (tm->vpp_event_queue[txf->master_thread_index], (u8 *) & evt, + 0 /* do wait for mutex */ )) + clib_warning ("could not enqueue event"); + } + } +} + +static void +receive_test_chunk (tclient_main_t * tm, session_t * s) +{ + svm_fifo_t *rx_fifo = s->server_rx_fifo; + u32 my_thread_index = vlib_get_thread_index (); + int n_read, i; + + /* Allow enqueuing of new event */ + // svm_fifo_unset_event (rx_fifo); + + if (tm->test_bytes) + { + n_read = svm_fifo_dequeue_nowait (rx_fifo, + vec_len (tm->rx_buf[my_thread_index]), + tm->rx_buf[my_thread_index]); + } + else + { + n_read = svm_fifo_max_dequeue (rx_fifo); + svm_fifo_dequeue_drop (rx_fifo, n_read); + } + + if (SCTP_BUILTIN_CLIENT_DBG) + clib_warning ("Receiving test chunk; n_read = %d", n_read); + + if (n_read > 0) + { + if (SCTP_BUILTIN_CLIENT_DBG) + { + /* *INDENT-OFF* */ + ELOG_TYPE_DECLARE (e) = + { + .format = "rx-deq: %d bytes", + .format_args = "i4", + }; + /* *INDENT-ON* */ + struct + { + u32 data[1]; + } *ed; + ed = ELOG_DATA (&vlib_global_main.elog_main, e); + ed->data[0] = n_read; + } + + if (tm->test_bytes) + { + for (i = 0; i < n_read; i++) + { + if (tm->rx_buf[my_thread_index][i] + != ((s->bytes_received + i) & 0xff)) + { + clib_warning ("read %d error at byte %lld, 0x%x not 0x%x", + n_read, s->bytes_received + i, + tm->rx_buf[my_thread_index][i], + ((s->bytes_received + i) & 0xff)); + tm->test_failed = 1; + } + } + } + + if (s->bytes_to_receive < n_read) + { + |