From fb6d7684194241826c8b4618aef3ede6b506a6c8 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Wed, 9 Sep 2020 21:54:44 +0000 Subject: [PATCH 001/129] misc: Initial changes for stable/2009 branch Change-Id: Ibb982c877427c8382a30ee561c23d878adc9c28d Type: docs Signed-off-by: Andrew Yourtchenko --- .gitreview | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitreview b/.gitreview index 1db08df202d3..7be606e7e19b 100644 --- a/.gitreview +++ b/.gitreview @@ -2,3 +2,4 @@ host=gerrit.fd.io port=29418 project=vpp +defaultbranch=stable/2009 From f96ce156b574e22455258aa84215f310b688596e Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Fri, 11 Sep 2020 15:54:43 +0000 Subject: [PATCH 002/129] misc: edit the MAINTAINERS entries for crypto plugins for common style Change-Id: Ic40bf11210cf1c36420578281f5a42668bad9801 Type: docs Signed-off-by: Andrew Yourtchenko (cherry picked from commit f8b319359cd2a24271dbe7cebfc8a4147ab89727) --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e929020fe78c..7fdc59a4aa39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -200,17 +200,17 @@ I: span M: N/A F: src/vnet/span -Crypto native Plugin +Plugin - Crypto - native I: crypto-native M: Damjan Marion F: src/plugins/crypto_native/ -Crypto openssl Plugin +Plugin - Crypto - OpenSSL I: crypto-openssl M: Damjan Marion F: src/plugins/crypto_openssl/ -Crypto ipsecmb Plugin +Plugin - Crypto - ipsecmb I: crypto-ipsecmb M: Neale Ranns F: src/plugins/crypto_ipsecmb/ From f1b7953449b5ec5a21b359c35ad4d587d02da788 Mon Sep 17 00:00:00 2001 From: Chenmin Sun Date: Fri, 11 Sep 2020 22:32:51 +0800 Subject: [PATCH 003/129] dpdk: fix coverity defect #214232, #182930 Type: fix Signed-off-by: Chenmin Sun Change-Id: Ie328834159687cdb4314c37d36697f2fb9081fbd (cherry picked from commit 504bcb7c29da6ab45656f54cda394cccb0d97dae) --- src/plugins/dpdk/device/device.c | 7 +++++++ src/plugins/dpdk/device/init.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c index e58dd6f4228e..532987c31308 100644 --- a/src/plugins/dpdk/device/device.c +++ b/src/plugins/dpdk/device/device.c @@ -639,6 +639,13 @@ dpdk_interface_set_rss_queues (struct vnet_main_t *vnm, })); /* *INDENT-ON* */ + /* check valid_queue_count not zero, make coverity happy */ + if (valid_queue_count == 0) + { + err = clib_error_return (0, "must assign at least one valid rss queue"); + goto done; + } + valid_queue = reta; for (i = valid_queue_count, j = 0; i < dev_info.reta_size; i++, j++) { diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c index 81803ab1cb4b..d07acd644a29 100644 --- a/src/plugins/dpdk/device/init.c +++ b/src/plugins/dpdk/device/init.c @@ -759,7 +759,7 @@ dpdk_lib_init (dpdk_main_t * dm) dpdk_device_setup (xd); /* rss queues should be configured after dpdk_device_setup() */ - if (devconf->rss_queues != NULL) + if ((hi != NULL) && (devconf->rss_queues != NULL)) { if (vnet_hw_interface_set_rss_queues (vnet_get_main (), hi, devconf->rss_queues)) From 758e6776a8f58782a8603fb9b5cc8d120dbe6ba2 Mon Sep 17 00:00:00 2001 From: Mohammed Hawari Date: Thu, 10 Sep 2020 15:10:45 +0200 Subject: [PATCH 004/129] af_xdp: documents incompatibility with 1GB hugepages and high buffers-per-numa. Type: docs Change-Id: If8602d4b73cc1f04e42d19b8df60a05f67aa90c9 Signed-off-by: Mohammed Hawari (cherry picked from commit 5d2091da2a96cb1092b0744cdee8bb481788a6dc) --- src/plugins/af_xdp/af_xdp_doc.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/af_xdp/af_xdp_doc.md b/src/plugins/af_xdp/af_xdp_doc.md index 6d2dae550557..40a3596be7ca 100644 --- a/src/plugins/af_xdp/af_xdp_doc.md +++ b/src/plugins/af_xdp/af_xdp_doc.md @@ -17,6 +17,8 @@ Because of AF_XDP restrictions, the MTU is limited to below PAGE_SIZE (4096-bytes on most systems) minus 256-bytes, and they are additional limitations depending upon specific Linux device drivers. As a rule of thumb, a MTU of 3000-bytes or less should be safe. +Furthermore, upon UMEM creation, the kernel allocates a physically-contiguous structure, whose size is proportional to the number of 4KB pages contained in the UMEM. That allocation might fail when the number of buffers allocated by VPP is too high. That number can be controlled with the `buffers { buffers-per-numa }` configuration option. +Finally, note that because of this limitation, this plugin is unlikely to be compatible with the use of 1GB hugepages. ## Requirements The Linux kernel interface must be up and have enough queues before From 6f1a86f1874261817618da086c7158b7646efebb Mon Sep 17 00:00:00 2001 From: Aloys Augustin Date: Thu, 10 Sep 2020 15:28:18 +0000 Subject: [PATCH 005/129] quic: fix coverity warning Change-Id: Ic31cde8564a0705710d91e0a7b90dcc6cf2f8db6 Type: fix Signed-off-by: Aloys Augustin --- src/plugins/quic/quic_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/quic/quic_crypto.c b/src/plugins/quic/quic_crypto.c index d8fd4a916e61..daf39e870329 100644 --- a/src/plugins/quic/quic_crypto.c +++ b/src/plugins/quic/quic_crypto.c @@ -208,7 +208,7 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, Exit: if (ret != 0) { - if (aead_ctx && *aead_ctx != NULL) + if (*aead_ctx != NULL) { ptls_aead_free (*aead_ctx); *aead_ctx = NULL; From cb94290d5f5aeec35ea3015ce19ac246b8479046 Mon Sep 17 00:00:00 2001 From: Martin Millnert Date: Fri, 11 Sep 2020 01:02:26 +0200 Subject: [PATCH 006/129] misc: selinux fixes (packet_socket r/w) vpp-20.05 on up-to-date Centos 7.8 host with enforcing SELinux fails to create a host-interface due to two missing SELinux-permissions: vpp_t self:packet_socket { read write } This simple patch adds these two permissions. Tested successfully on local installation. The steps to reproduce: $ ip link add vpeer-host type veth peer name vpeer-vpp vpp# create host-interface name vpeer-vpp create host-interface: Permission denied (errno 13) [...] $ semodule -i vpp-packet-socket.pp vpp# create host-interface name vpeer-vpp host-vpeer-vpp Type: fix Ticket: VPP-1931 Change-Id: I2b3d92b27b9a9f26aa1c85af2946b15e83e27944 Signed-off-by: Martin Millnert (cherry picked from commit 68849350c56b0258d21fc906b09df71a1951f694) --- extras/selinux/vpp-custom.te | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/selinux/vpp-custom.te b/extras/selinux/vpp-custom.te index 7cc2d55412a7..6f183f687ad5 100644 --- a/extras/selinux/vpp-custom.te +++ b/extras/selinux/vpp-custom.te @@ -46,7 +46,7 @@ files_tmp_file(vpp_tmp_t) allow vpp_t self:capability { dac_override ipc_lock setgid sys_rawio net_raw sys_admin net_admin chown }; # too benevolent dontaudit vpp_t self:capability2 block_suspend; allow vpp_t self:process { execmem execstack setsched signal }; # too benevolent -allow vpp_t self:packet_socket { bind create setopt ioctl map }; +allow vpp_t self:packet_socket { bind create setopt ioctl map read write }; allow vpp_t self:tun_socket { create relabelto relabelfrom }; allow vpp_t self:udp_socket { create ioctl }; allow vpp_t self:unix_dgram_socket { connect create ioctl }; From c13aab8ca1d6fcf0e662628433cafda85dc591bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Thu, 10 Sep 2020 13:54:49 +0200 Subject: [PATCH 007/129] ikev2: fix memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - make sure everything is freed on cleanup - reuse already allocated vectors where possible Type: fix Change-Id: Ibd8da1edb37126522dc2d525596521d32dceb73a Signed-off-by: Benoît Ganne (cherry picked from commit 730cec8c0697627cc1fb6a34acd094c77ba07622) --- src/plugins/ikev2/ikev2.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index a9e78a3dfc3c..57eea010109c 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -296,9 +296,12 @@ static void ikev2_sa_free_all_vec (ikev2_sa_t * sa) { vec_free (sa->i_nonce); - vec_free (sa->i_dh_data); + vec_free (sa->r_nonce); + vec_free (sa->dh_shared_key); vec_free (sa->dh_private_key); + vec_free (sa->i_dh_data); + vec_free (sa->r_dh_data); ikev2_sa_free_proposal_vector (&sa->r_proposals); ikev2_sa_free_proposal_vector (&sa->i_proposals); @@ -312,14 +315,24 @@ ikev2_sa_free_all_vec (ikev2_sa_t * sa) vec_free (sa->sk_pr); vec_free (sa->i_id.data); - vec_free (sa->i_auth.data); vec_free (sa->r_id.data); + + vec_free (sa->i_auth.data); + if (sa->r_auth.key) + EVP_PKEY_free (sa->i_auth.key); vec_free (sa->r_auth.data); if (sa->r_auth.key) EVP_PKEY_free (sa->r_auth.key); vec_free (sa->del); + vec_free (sa->rekey); + + vec_free (sa->last_sa_init_req_packet_data); + vec_free (sa->last_sa_init_res_packet_data); + + vec_free (sa->last_res_packet_data); + ikev2_sa_free_all_child_sa (&sa->childs); } @@ -641,7 +654,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, sa->ispi = clib_net_to_host_u64 (ike->ispi); /* store whole IKE payload - needed for PSK auth */ - vec_free (sa->last_sa_init_req_packet_data); + vec_reset_length (sa->last_sa_init_req_packet_data); vec_add (sa->last_sa_init_req_packet_data, ike, len); while (p < len && payload != IKEV2_PAYLOAD_NONE) @@ -743,7 +756,7 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, sa->raddr.as_u32); /* store whole IKE payload - needed for PSK auth */ - vec_free (sa->last_sa_init_res_packet_data); + vec_reset_length (sa->last_sa_init_res_packet_data); vec_add (sa->last_sa_init_res_packet_data, ike, len); while (p < len && payload != IKEV2_PAYLOAD_NONE) @@ -2323,7 +2336,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, clib_memcpy_fast (ike->payload, chain->data, vec_len (chain->data)); /* store whole IKE payload - needed for PSK auth */ - vec_free (sa->last_sa_init_res_packet_data); + vec_reset_length (sa->last_sa_init_res_packet_data); vec_add (sa->last_sa_init_res_packet_data, ike, tlen); } else @@ -2372,7 +2385,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, } /* store whole IKE payload - needed for retransmit */ - vec_free (sa->last_res_packet_data); + vec_reset_length (sa->last_res_packet_data); vec_add (sa->last_res_packet_data, ike, tlen); } @@ -3780,7 +3793,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) ike0->msgid = 0; /* store whole IKE payload - needed for PSK auth */ - vec_free (sa.last_sa_init_req_packet_data); + vec_reset_length (sa.last_sa_init_req_packet_data); vec_add (sa.last_sa_init_req_packet_data, ike0, len); /* add data to the SA then add it to the pool */ From 649ba152cbd335ce644c04c9f00140aba35f81e8 Mon Sep 17 00:00:00 2001 From: Matthew Smith Date: Thu, 10 Sep 2020 10:09:01 -0500 Subject: [PATCH 008/129] l2: fix null deref in l2_to_bvi() Type: fix Static analysis identified a possible null pointer dereference. It was introduced by a recent patch which expanded the DMAC comparison on inbound packets on a BVI interface to include any secondary MAC addresses which were added to an interface. Check if the pointer is null before dereferencing. Change-Id: Ic2afe2b062eda32977e05bf3f98d82c1fe64620c Signed-off-by: Matthew Smith (cherry picked from commit 78681def21b931309a779dfc6a5cbc6ff8b1f814) --- src/vnet/l2/l2_bvi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vnet/l2/l2_bvi.h b/src/vnet/l2/l2_bvi.h index 300ea81bbf06..697e25bf3dea 100644 --- a/src/vnet/l2/l2_bvi.h +++ b/src/vnet/l2/l2_bvi.h @@ -72,7 +72,7 @@ l2_to_bvi (vlib_main_t * vlib_main, ethernet_interface_t *ei = ethernet_get_interface (em, hi->hw_if_index); u32 rv; - if (PREDICT_FALSE (vec_len (ei->secondary_addrs) > 0)) + if (PREDICT_FALSE (ei && (vec_len (ei->secondary_addrs) > 0))) rv = l2_to_bvi_dmac_check (hi, e0->dst_address, ei, 1 /* have_sec_dmac */ ); else From a238082a8a74aee63620df1c4151157dd0003087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Thu, 10 Sep 2020 14:12:06 +0200 Subject: [PATCH 009/129] vlib: fix call to vlib_get_node_by_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: I1b4f52e186165b04db5bd5f11058dc77b647bc94 Signed-off-by: Benoît Ganne (cherry picked from commit 268e3b647733807dbecf402fcebedceff4c85544) --- src/vlib/node.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vlib/node.c b/src/vlib/node.c index 119b4718090f..169c67b0888e 100644 --- a/src/vlib/node.c +++ b/src/vlib/node.c @@ -347,7 +347,10 @@ register_node (vlib_main_t * vm, vlib_node_registration_t * r) /* Node names must be unique. */ { - vlib_node_t *o = vlib_get_node_by_name (vm, n->name); + /* vlib_get_node_by_name() expects NULL-terminated strings */ + u8 *name = format (0, "%v%c", n->name, 0); + vlib_node_t *o = vlib_get_node_by_name (vm, name); + vec_free (name); if (o) clib_error ("more than one node named `%v'", n->name); } From ec8a577ed98beb8ec88de57d39309af4f908eb01 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Mon, 14 Sep 2020 13:28:42 +0000 Subject: [PATCH 010/129] wireguard: coverity fixes Type: fix Signed-off-by: Neale Ranns Change-Id: Ib1eabbc87a573c660ac251602d631f167928259b (cherry picked from commit 76770fd659420c23e43422d672a55e268f042129) --- src/plugins/wireguard/wireguard_api.c | 4 ++-- src/plugins/wireguard/wireguard_if.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/plugins/wireguard/wireguard_api.c b/src/plugins/wireguard/wireguard_api.c index e107cb56b4b1..8bbacddaf45d 100755 --- a/src/plugins/wireguard/wireguard_api.c +++ b/src/plugins/wireguard/wireguard_api.c @@ -39,7 +39,7 @@ static void wg_main_t *wmp = &wg_main; u8 private_key[NOISE_PUBLIC_KEY_LEN]; ip_address_t src; - u32 sw_if_index; + u32 sw_if_index = ~0; int rv = 0; ip_address_decode2 (&mp->interface.src_ip, &src); @@ -140,7 +140,7 @@ vl_api_wireguard_peer_add_t_handler (vl_api_wireguard_peer_add_t * mp) { vl_api_wireguard_peer_add_reply_t *rmp; wg_main_t *wmp = &wg_main; - index_t peeri; + index_t peeri = INDEX_INVALID; int ii, rv = 0; ip_address_t endpoint; diff --git a/src/plugins/wireguard/wireguard_if.c b/src/plugins/wireguard/wireguard_if.c index ff8ed35477ee..522e9b6665a0 100644 --- a/src/plugins/wireguard/wireguard_if.c +++ b/src/plugins/wireguard/wireguard_if.c @@ -244,10 +244,14 @@ wg_if_create (u32 user_instance, wg_if_index_by_port[port] = wg_if - wg_if_pool; wg_if->port = port; - struct noise_upcall upcall; - upcall.u_remote_get = wg_remote_get; - upcall.u_index_set = wg_index_set; - upcall.u_index_drop = wg_index_drop; + + /* *INDENT-OFF* */ + struct noise_upcall upcall = { + .u_remote_get = wg_remote_get, + .u_index_set = wg_index_set, + .u_index_drop = wg_index_drop, + }; + /* *INDENT-ON* */ noise_local_init (&wg_if->local, &upcall); noise_local_set_private (&wg_if->local, private_key); From 89bdb836f9c580b94119b4bff5ab20abd3bd94e5 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 10 Sep 2020 12:27:14 -0700 Subject: [PATCH 011/129] vcl: always fill buffer or drain rx fifo Type: improvement Signed-off-by: Florin Coras Change-Id: Ibbe438aa6f2fe6d9f55c56ca6d3aec1a29b32cad (cherry picked from commit 4a2c794c431c72364e241fa14327f03e35b886b7) --- src/vcl/vppcom.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 9174e5d6d2f4..dd8ffb46e1bd 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -1892,7 +1892,7 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n, u8 peek) { vcl_worker_t *wrk = vcl_worker_get_current (); - int n_read = 0, is_nonblocking; + int rv, n_read = 0, is_nonblocking; vcl_session_t *s = 0; svm_fifo_t *rx_fifo; svm_msg_q_msg_t msg; @@ -1949,10 +1949,15 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n, } } +read_again: + if (s->is_dgram) - n_read = app_recv_dgram_raw (rx_fifo, buf, n, &s->transport, 0, peek); + rv = app_recv_dgram_raw (rx_fifo, buf, n, &s->transport, 0, peek); else - n_read = app_recv_stream_raw (rx_fifo, buf, n, 0, peek); + rv = app_recv_stream_raw (rx_fifo, buf, n, 0, peek); + + ASSERT (rv >= 0); + n_read += rv; if (svm_fifo_is_empty_cons (rx_fifo)) { @@ -1960,12 +1965,19 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n, if (!svm_fifo_is_empty_cons (rx_fifo) && svm_fifo_set_event (s->rx_fifo) && is_nonblocking) { - session_event_t *e; vec_add2 (wrk->unhandled_evts_vector, e, 1); e->event_type = SESSION_IO_EVT_RX; e->session_index = s->session_index; } } + else if (PREDICT_FALSE (rv < n)) + { + /* More data enqueued while reading. Try to drain it + * or fill the buffer */ + buf += rv; + n -= rv; + goto read_again; + } if (PREDICT_FALSE (svm_fifo_needs_deq_ntf (rx_fifo, n_read))) { From 047eebfa976eb8c8fc3162c3ccdd5683d23452dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 9 Sep 2020 12:50:07 +0200 Subject: [PATCH 012/129] build: fix build for Debian 9 and Debian 10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: Ic07d0ae313b32e420ba93693cb75960a86f752a9 Signed-off-by: Benoît Ganne (cherry picked from commit 3f0ae664faf33578515ffa1fd5287ad692f16c6f) --- Makefile | 2 ++ src/tools/vppapigen/vppapigen.py | 9 +++++---- src/vnet/devices/virtio/virtio.h | 10 +++++++++- src/vnet/devices/virtio/virtio_pci_modern.c | 10 ++++------ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 29c4c9622546..cac1ed770d9b 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,8 @@ else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-9) DEB_DEPENDS += libssl1.0-dev DEB_DEPENDS += python-all python-pip DEB_DEPENDS += python-dev python-all python-pip python-virtualenv +else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-10) + DEB_DEPENDS += libelf-dev # for libbpf (af_xdp) else DEB_DEPENDS += libssl-dev endif diff --git a/src/tools/vppapigen/vppapigen.py b/src/tools/vppapigen/vppapigen.py index 9d74a5b0357f..bfc77ca7019d 100755 --- a/src/tools/vppapigen/vppapigen.py +++ b/src/tools/vppapigen/vppapigen.py @@ -11,7 +11,7 @@ import sys from subprocess import Popen, PIPE -assert sys.version_info >= (3, 6), \ +assert sys.version_info >= (3, 5), \ "Not supported Python version: {}".format(sys.version) log = logging.getLogger('vppapigen') @@ -780,12 +780,13 @@ def parse_fd(self, fd, debug=0): def parse_filename(self, filename, debug=0): if self.revision: - git_show = f'git show {self.revision}:{filename}' + git_show = 'git show {}:{}'.format(self.revision, filename) proc = Popen(git_show.split(), stdout=PIPE, encoding='utf-8') try: data, errs = proc.communicate() if proc.returncode != 0: - print(f'File not found: {self.revision}:{filename}', file=sys.stderr) + print('File not found: {}:{}'.format(self.revision, + filename), file=sys.stderr) sys.exit(2) return self.parse_string(data, debug=debug) except Exception as e: @@ -795,7 +796,7 @@ def parse_filename(self, filename, debug=0): with open(filename, encoding='utf-8') as fd: return self.parse_fd(fd, None) except FileNotFoundError: - print(f'File not found: {filename}', file=sys.stderr) + print('File not found: {}'.format(filename), file=sys.stderr) sys.exit(2) def autoreply_block(self, name, parent): diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h index f1eaa07fe5d7..b00e1eceb858 100644 --- a/src/vnet/devices/virtio/virtio.h +++ b/src/vnet/devices/virtio/virtio.h @@ -129,7 +129,15 @@ typedef struct /* error */ clib_error_t *error; - u8 mac_addr[6]; + union + { + struct + { + u32 mac_addr32; + u16 mac_addr16; + }; + u8 mac_addr[6]; + }; union { struct /* tun/tap interface */ diff --git a/src/vnet/devices/virtio/virtio_pci_modern.c b/src/vnet/devices/virtio/virtio_pci_modern.c index 0d86ff2acda4..4eb0ff102aee 100644 --- a/src/vnet/devices/virtio/virtio_pci_modern.c +++ b/src/vnet/devices/virtio/virtio_pci_modern.c @@ -311,19 +311,17 @@ virtio_pci_modern_del_queue (vlib_main_t * vm, virtio_if_t * vif, static void virtio_pci_modern_get_device_mac (vlib_main_t * vm, virtio_if_t * vif) { - *((u32 *) vif->mac_addr) = - virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif)); - *((u16 *) (vif->mac_addr + 4)) = + vif->mac_addr32 = virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif)); + vif->mac_addr16 = virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4); } static void virtio_pci_modern_set_device_mac (vlib_main_t * vm, virtio_if_t * vif) { - virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif), - *((u32 *) vif->mac_addr)); + virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif), vif->mac_addr32); virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4, - *((u16 *) (vif->mac_addr + 4))); + vif->mac_addr16); } static u16 From 57b16c694cf5c52a9070c39eb931a1b5ea250b91 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 10 Sep 2020 03:37:37 +0000 Subject: [PATCH 013/129] ikev2: fix copy-paste error when freeing memory Type: fix Change-Id: If44c807d188b3e88d819f4132d73e6a34402a525 Signed-off-by: Filip Tehlar (cherry picked from commit 999395cd6644a297c01dd6de033cf1ffb4e9951b) --- src/plugins/ikev2/ikev2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 57eea010109c..34c54f3d8485 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -318,7 +318,7 @@ ikev2_sa_free_all_vec (ikev2_sa_t * sa) vec_free (sa->r_id.data); vec_free (sa->i_auth.data); - if (sa->r_auth.key) + if (sa->i_auth.key) EVP_PKEY_free (sa->i_auth.key); vec_free (sa->r_auth.data); if (sa->r_auth.key) From 748bf82a500ee594733af4d005ffe3191027ebaf Mon Sep 17 00:00:00 2001 From: Yichen Wang Date: Tue, 30 Jun 2020 23:14:23 -0700 Subject: [PATCH 014/129] build: fix the the build on centos/rhel 8 1. Remove uncessary runtime dependency; 2. Add missing build dependency; 3. Fix runtime dependency for api-python3 RPM; Type: make Change-Id: I2700f1a15112effba8d1527aca6467158f81f486 Signed-off-by: Yichen Wang (cherry picked from commit 466872f0896139b34ef8ccf12f7fcc0093d7cb19) --- Makefile | 1 + extras/rpm/vpp.spec | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cac1ed770d9b..cf4cfadecc72 100644 --- a/Makefile +++ b/Makefile @@ -110,6 +110,7 @@ RPM_DEPENDS += libuuid-devel RPM_DEPENDS += mbedtls-devel RPM_DEPENDS += ccache RPM_DEPENDS += xmlto +RPM_DEPENDS += elfutils-libelf-devel ifeq ($(OS_ID),fedora) RPM_DEPENDS += dnf-utils diff --git a/extras/rpm/vpp.spec b/extras/rpm/vpp.spec index 538c071caea3..038c10bc9ff4 100644 --- a/extras/rpm/vpp.spec +++ b/extras/rpm/vpp.spec @@ -60,7 +60,6 @@ BuildRequires: python3, python36-devel, python3-virtualenv BuildRequires: cmake %else %if 0%{rhel} >= 7 -Requires: epel-release Requires: vpp-lib = %{_version}-%{_release}, vpp-selinux-policy = %{_version}-%{_release}, net-tools, pciutils, python36 Requires: boost-filesystem mbedtls libffi-devel BuildRequires: epel-release @@ -150,7 +149,7 @@ This package contains the python bindings for the vpp api Summary: VPP api python3 bindings Group: Development/Libraries Requires: vpp = %{_version}-%{_release}, vpp-lib = %{_version}-%{_release}, libffi-devel -Requires: python-setuptools +Requires: python3-setuptools %description api-python3 This package contains the python3 bindings for the vpp api From ddd8c0fe59f838e1fd2f0317d319963951964ab5 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Tue, 15 Sep 2020 11:05:23 +0200 Subject: [PATCH 015/129] crypto-native: fix issues detected by coiverity Type: fix Change-Id: Id61aa407eeeb4d44cf47ed39283a0c79ed3abbee Signed-off-by: Damjan Marion (cherry picked from commit 139a6ae0dd460a6b8a5884e65cfd96f0c409f69e) --- src/plugins/crypto_native/aes_gcm.c | 10 +++++++--- src/plugins/crypto_native/crypto_native.h | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/crypto_native/aes_gcm.c b/src/plugins/crypto_native/aes_gcm.c index 9aeed9dee2e3..e0c1e6c12c3e 100644 --- a/src/plugins/crypto_native/aes_gcm.c +++ b/src/plugins/crypto_native/aes_gcm.c @@ -63,6 +63,7 @@ typedef enum static const u32x4 ctr_inv_1 = { 0, 0, 0, 1 << 24 }; +#ifndef __VAES__ static_always_inline void aes_gcm_enc_first_round (u8x16 * r, aes_gcm_counter_t * ctr, u8x16 k, int n_blocks) @@ -106,6 +107,7 @@ aes_gcm_enc_last_round (u8x16 * r, u8x16 * d, u8x16 const *k, for (int i = 0; i < n_blocks; i++) d[i] ^= aes_enc_last_round (r[i], k[rounds]); } +#endif static_always_inline u8x16 aes_gcm_ghash_blocks (u8x16 T, aes_gcm_key_data_t * kd, @@ -161,6 +163,7 @@ aes_gcm_ghash (u8x16 T, aes_gcm_key_data_t * kd, u8x16u * in, u32 n_left) return T; } +#ifndef __VAES__ static_always_inline u8x16 aes_gcm_calc (u8x16 T, aes_gcm_key_data_t * kd, u8x16 * d, aes_gcm_counter_t * ctr, u8x16u * inv, u8x16u * outv, @@ -414,6 +417,7 @@ aes_gcm_ghash_last (u8x16 T, aes_gcm_key_data_t * kd, u8x16 * d, ghash_reduce2 (gd); return ghash_final (gd); } +#endif #ifdef __VAES__ static const u32x16 ctr_inv_1234 = { @@ -748,7 +752,6 @@ static_always_inline u8x16 aes_gcm_enc (u8x16 T, aes_gcm_key_data_t * kd, aes_gcm_counter_t * ctr, u8x16u * inv, u8x16u * outv, u32 n_left, int rounds) { - u8x16 d[4]; aes_gcm_flags_t f = AES_GCM_F_ENCRYPT; if (n_left == 0) @@ -841,8 +844,8 @@ aes_gcm_enc (u8x16 T, aes_gcm_key_data_t * kd, aes_gcm_counter_t * ctr, T = aes4_gcm_calc (T, kd, d4, ctr, inv, outv, rounds, 1, n_left, f); return aes4_gcm_ghash_last (T, kd, d4, 1, n_left); -#endif - +#else + u8x16 d[4]; if (n_left < 64) { f |= AES_GCM_F_LAST_ROUND; @@ -928,6 +931,7 @@ aes_gcm_enc (u8x16 T, aes_gcm_key_data_t * kd, aes_gcm_counter_t * ctr, T = aes_gcm_calc (T, kd, d, ctr, inv, outv, rounds, 1, n_left, f); return aes_gcm_ghash_last (T, kd, d, 1, n_left); +#endif } static_always_inline u8x16 diff --git a/src/plugins/crypto_native/crypto_native.h b/src/plugins/crypto_native/crypto_native.h index f1153737deae..5b774b302dea 100644 --- a/src/plugins/crypto_native/crypto_native.h +++ b/src/plugins/crypto_native/crypto_native.h @@ -23,7 +23,11 @@ typedef void *(crypto_native_key_fn_t) (vnet_crypto_key_t * key); typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); +#if __VAES__ + u8x16 cbc_iv[16]; +#else u8x16 cbc_iv[4]; +#endif } crypto_native_per_thread_data_t; typedef struct From c71dad4a2dd06aa379ed2ad02df3327622bfea80 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 15 Sep 2020 07:13:46 +0000 Subject: [PATCH 016/129] crypto: Crypto SW Scheduler Coverity Warnings Type: fix Signed-off-by: Neale Ranns Change-Id: I7f98d0c7847ecc40b90b78e5ae83f320575be310 (cherry picked from commit 69f77a3a3cca70876bd27c84b5ae932ca942d8de) --- src/plugins/crypto_sw_scheduler/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/crypto_sw_scheduler/main.c b/src/plugins/crypto_sw_scheduler/main.c index a450bc16e8e8..7de84ff12001 100644 --- a/src/plugins/crypto_sw_scheduler/main.c +++ b/src/plugins/crypto_sw_scheduler/main.c @@ -543,7 +543,7 @@ sw_scheduler_show_workers (vlib_main_t * vm, unformat_input_t * input, u32 i; vlib_cli_output (vm, "%-7s%-20s%-8s", "ID", "Name", "Crypto"); - for (i = vlib_num_workers () >= 0; i < vlib_thread_main.n_vlib_mains; i++) + for (i = 1; i < vlib_thread_main.n_vlib_mains; i++) { vlib_cli_output (vm, "%-7d%-20s%-8s", vlib_get_worker_index (i), (vlib_worker_threads + i)->name, From 58db34c2ca491cb949ab046cccbd73be14b90647 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Mon, 14 Sep 2020 08:29:05 +0000 Subject: [PATCH 017/129] wireguard: increase FIB source priority Type: fix Signed-off-by: Neale Ranns Change-Id: Icc1c458474d357c7d9b3b4df1897500de0c314a1 (cherry picked from commit a26b0d11e91e9abca6220e50f0240ab6ae09c6d3) --- src/plugins/wireguard/wireguard_peer.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c index 0dcc4e20e41e..3985f4347b45 100755 --- a/src/plugins/wireguard/wireguard_peer.c +++ b/src/plugins/wireguard/wireguard_peer.c @@ -401,8 +401,13 @@ format_wg_peer (u8 * s, va_list * va) static clib_error_t * wg_peer_module_init (vlib_main_t * vm) { - wg_fib_source = fib_source_allocate ("wireguard", 0xb0, // - FIB_SOURCE_BH_SIMPLE); + /* + * use a priority better than interface source, so that + * if the same subnet is added to the wg interface and is + * used as an allowed IP, then the wireguard soueced prefix + * wins and traffic is routed to the endpoint rather than dropped + */ + wg_fib_source = fib_source_allocate ("wireguard", 0x2, FIB_SOURCE_BH_API); return (NULL); } From 911d7563cb7b6c2c6168c0d4a041dd82dcb80fb9 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Thu, 10 Sep 2020 13:13:29 +0700 Subject: [PATCH 018/129] wireguard: fix handshake procedure Type: fix Change-Id: I96e8c5c9c792b1d9aefd39ce3e240d220827b7d1 Signed-off-by: Artem Glazychev (cherry picked from commit cf527882e2fe49eda108cd63af175431222beebe) --- src/plugins/wireguard/wireguard_noise.c | 25 +++++++++++++++---------- src/plugins/wireguard/wireguard_send.h | 4 ++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/plugins/wireguard/wireguard_noise.c b/src/plugins/wireguard/wireguard_noise.c index 666618a2a513..dc7d5060fe5c 100755 --- a/src/plugins/wireguard/wireguard_noise.c +++ b/src/plugins/wireguard/wireguard_noise.c @@ -547,29 +547,34 @@ chacha20poly1305_calc (vlib_main_t * vm, vnet_crypto_op_id_t op_id, vnet_crypto_key_index_t key_index) { + vnet_crypto_op_t _op, *op = &_op; u8 iv[12]; + u8 tag_[NOISE_AUTHTAG_LEN] = { }; + u8 src_[] = { }; + clib_memset (iv, 0, 12); clib_memcpy (iv + 4, &nonce, sizeof (nonce)); - vnet_crypto_op_t _op, *op = &_op; + vnet_crypto_op_init (op, op_id); - u8 _tag[16] = { }; + op->tag_len = NOISE_AUTHTAG_LEN; if (op_id == VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC) { - clib_memcpy (_tag, src + src_len - NOISE_AUTHTAG_LEN, - NOISE_AUTHTAG_LEN); + op->tag = src + src_len - NOISE_AUTHTAG_LEN; src_len -= NOISE_AUTHTAG_LEN; } - vnet_crypto_op_init (op, op_id); - op->key_index = key_index; - op->src = src; - op->dst = dst; + else + op->tag = tag_; + + op->src = !src ? src_ : src; op->len = src_len; + + op->dst = dst; + op->key_index = key_index; op->aad = aad; op->aad_len = aad_len; op->iv = iv; - op->tag_len = NOISE_AUTHTAG_LEN; - op->tag = _tag; + vnet_crypto_process_ops (vm, op, 1); if (op_id == VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC) { diff --git a/src/plugins/wireguard/wireguard_send.h b/src/plugins/wireguard/wireguard_send.h index 8f5e7ab87652..4ea1f6effea5 100755 --- a/src/plugins/wireguard/wireguard_send.h +++ b/src/plugins/wireguard/wireguard_send.h @@ -26,8 +26,8 @@ always_inline void ip4_header_set_len_w_chksum (ip4_header_t * ip4, u16 len) { ip_csum_t sum = ip4->checksum; - u8 old = ip4->length; - u8 new = len; + u16 old = ip4->length; + u16 new = len; sum = ip_csum_update (sum, old, new, ip4_header_t, length); ip4->checksum = ip_csum_fold (sum); From 7bae4911bfbff80e9fa8865f6a81d1cd8755b384 Mon Sep 17 00:00:00 2001 From: Onong Tayeng Date: Fri, 4 Sep 2020 17:16:23 +0530 Subject: [PATCH 019/129] lisp: fix crash with arp and packet trace on With packet trace on, VPP crashes when an arp packet arrives. This patch fixes the crash and also ensures that the packet trace displays the eid info. Type: fix Signed-off-by: Onong Tayeng Change-Id: Iaad09a5e2b33e931ab9bd7bc3d4573b5ed5e4bfd (cherry picked from commit a3960a8b74de5cef51db2c7575f8f2d71a013d0a) --- src/vnet/lisp-cp/control.c | 6 +++++- src/vnet/lisp-cp/lisp_types.c | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 7e9d059f9ed9..60d85619dc51 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -3552,7 +3552,11 @@ lisp_cp_lookup_inline (vlib_main_t * vm, sizeof (*tr)); clib_memset (tr, 0, sizeof (*tr)); - gid_address_copy (&tr->dst_eid, &dst); + if ((gid_address_type (&dst) == GID_ADDR_NDP) || + (gid_address_type (&dst) == GID_ADDR_ARP)) + clib_memcpy (&tr->dst_eid, &dst, sizeof (gid_address_t)); + else + gid_address_copy (&tr->dst_eid, &dst); ip_address_copy (&tr->map_resolver_ip, &lcm->active_map_resolver); } diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 971d3071b6a0..6ff3b4ebf4b7 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -41,7 +41,7 @@ serdes_fct write_fcts[GID_ADDR_TYPES] = }; cast_fct cast_fcts[GID_ADDR_TYPES] = - { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast, nsh_cast, 0 /* arp */ , + { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast, nsh_cast, no_addr_cast, no_addr_cast }; @@ -51,7 +51,7 @@ addr_len_fct addr_len_fcts[GID_ADDR_TYPES] = }; copy_fct copy_fcts[GID_ADDR_TYPES] = - { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy, nsh_copy, 0 /* arp */ , + { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy, nsh_copy, no_addr_copy, no_addr_copy }; From 6c25154e9544810afc1179ce8b0977a9786a8027 Mon Sep 17 00:00:00 2001 From: Nathan Skrzypczak Date: Fri, 11 Sep 2020 09:47:41 +0200 Subject: [PATCH 020/129] quic: Clean quic_crypto_setup_cipher Type: fix Change-Id: I4c19636c2be8a577c6cba272708cb04bcc24785b Signed-off-by: Nathan Skrzypczak (cherry picked from commit 8847749269ffd591c7fb6c290b4a311f186fb7c5) --- src/plugins/quic/quic_crypto.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/plugins/quic/quic_crypto.c b/src/plugins/quic/quic_crypto.c index daf39e870329..35dddf63c711 100644 --- a/src/plugins/quic/quic_crypto.c +++ b/src/plugins/quic/quic_crypto.c @@ -161,20 +161,19 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, int ret; *aead_ctx = NULL; - /* generate new header protection key */ if (hp_ctx != NULL) { *hp_ctx = NULL; - if ((ret = - ptls_hkdf_expand_label (hash, hpkey, aead->ctr_cipher->key_size, - ptls_iovec_init (secret, - hash->digest_size), - "quic hp", ptls_iovec_init (NULL, 0), - NULL)) != 0) + ret = ptls_hkdf_expand_label (hash, hpkey, aead->ctr_cipher->key_size, + ptls_iovec_init (secret, + hash->digest_size), + "quic hp", ptls_iovec_init (NULL, 0), + NULL); + if (ret) goto Exit; - if ((*hp_ctx = - ptls_cipher_new (aead->ctr_cipher, is_enc, hpkey)) == NULL) + *hp_ctx = ptls_cipher_new (aead->ctr_cipher, is_enc, hpkey); + if (NULL == *hp_ctx) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; @@ -182,9 +181,9 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, } /* generate new AEAD context */ - if ((*aead_ctx = - ptls_aead_new (aead, hash, is_enc, secret, - QUICLY_AEAD_BASE_LABEL)) == NULL) + *aead_ctx = ptls_aead_new (aead, hash, is_enc, secret, + QUICLY_AEAD_BASE_LABEL); + if (NULL == *aead_ctx) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; @@ -194,9 +193,7 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, { quic_ctx_t *qctx = quic_get_conn_ctx (conn); if (qctx->ingress_keys.aead_ctx != NULL) - { - qctx->key_phase_ingress++; - } + qctx->key_phase_ingress++; qctx->ingress_keys.aead_ctx = *aead_ctx; if (hp_ctx != NULL) @@ -206,7 +203,7 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, ret = 0; Exit: - if (ret != 0) + if (ret) { if (*aead_ctx != NULL) { From 1f18c50174fcc0013e85f7f867e550c1e1871080 Mon Sep 17 00:00:00 2001 From: Filip Varga Date: Tue, 8 Sep 2020 16:22:44 +0200 Subject: [PATCH 021/129] nat: endian mismatch Type: fix Change-Id: Icf6ce0ddb5fe9d078503e9d9ff7e7b26423f53f8 Signed-off-by: Filip Varga (cherry picked from commit 2fe25370ba0deed78c1240fa6788c5b5f14d6f97) --- src/plugins/nat/nat_format.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/plugins/nat/nat_format.c b/src/plugins/nat/nat_format.c index 3dfe6046969f..f0e7a5d5cd00 100644 --- a/src/plugins/nat/nat_format.c +++ b/src/plugins/nat/nat_format.c @@ -230,7 +230,8 @@ format_snat_static_mapping (u8 * s, va_list * args) else s = format (s, "identity mapping %U %U:%d", format_nat_protocol, m->proto, - format_ip4_address, &m->local_addr, m->local_port); + format_ip4_address, &m->local_addr, + clib_net_to_host_u16 (m->local_port)); /* *INDENT-OFF* */ pool_foreach (local, m->locals, @@ -256,7 +257,8 @@ format_snat_static_mapping (u8 * s, va_list * args) { s = format (s, "%U external %U:%d %s %s", format_nat_protocol, m->proto, - format_ip4_address, &m->external_addr, m->external_port, + format_ip4_address, &m->external_addr, + clib_net_to_host_u16 (m->external_port), m->twice_nat == TWICE_NAT ? "twice-nat" : m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", is_out2in_only_static_mapping (m) ? "out2in-only" : ""); @@ -265,7 +267,8 @@ format_snat_static_mapping (u8 * s, va_list * args) pool_foreach (local, m->locals, ({ s = format (s, "\n local %U:%d vrf %d probability %d\%", - format_ip4_address, &local->addr, local->port, + format_ip4_address, &local->addr, + clib_net_to_host_u16 (local->port), local->vrf_id, local->probability); })); /* *INDENT-ON* */ @@ -274,8 +277,10 @@ format_snat_static_mapping (u8 * s, va_list * args) else s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s", format_nat_protocol, m->proto, - format_ip4_address, &m->local_addr, m->local_port, - format_ip4_address, &m->external_addr, m->external_port, + format_ip4_address, &m->local_addr, + clib_net_to_host_u16 (m->local_port), + format_ip4_address, &m->external_addr, + clib_net_to_host_u16 (m->external_port), m->vrf_id, m->twice_nat == TWICE_NAT ? "twice-nat" : m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", @@ -297,9 +302,10 @@ format_snat_static_map_to_resolve (u8 * s, va_list * args) else s = format (s, "%U local %U:%d external %U:%d vrf %d", format_nat_protocol, m->proto, - format_ip4_address, &m->l_addr, m->l_port, + format_ip4_address, &m->l_addr, + clib_net_to_host_u16 (m->l_port), format_vnet_sw_if_index_name, vnm, m->sw_if_index, - m->e_port, m->vrf_id); + clib_net_to_host_u16 (m->e_port), m->vrf_id); return s; } From 95a77a2360c4315ab8a1178202d71d59e3b8c21f Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Thu, 27 Aug 2020 13:34:50 +0300 Subject: [PATCH 022/129] nat: Fix next feature for ED with multiple workers Multiple (> 1) workers leads to handoff node being enabled. This node pops next feature index to nat.arc_next to make sure that packet will be pushed to the next feature in the arc. But node nat44-ed-in2out-output also pops next feature and changes arc_next. So actual next feature will be skipped in that case. It leads to all nat44-ed-in2out packets being dropped if we have multiple workers (handoff node enabled). To resolve this a new node was added (nat-pre-in2out-output) to fill arc_next in single worker case and multiple worker case is already handled by handoff node. Type: fix Signed-off-by: Vladimir Isaev Change-Id: I9dfba68f00164d2d5ab867224871811bef4411ed (cherry picked from commit 8fb4d10dc208fb3f284fe79e838343797cb2d813) --- src/plugins/nat/in2out_ed.c | 17 ++++++++++++++++- src/plugins/nat/nat.c | 9 ++++++++- src/plugins/nat/nat.h | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c index 448e967b8ae3..d43caef46d93 100644 --- a/src/plugins/nat/in2out_ed.c +++ b/src/plugins/nat/in2out_ed.c @@ -964,7 +964,6 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, if (is_output_feature) { - vnet_feature_next (&vnet_buffer2 (b0)->nat.arc_next, b0); iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length; } @@ -1586,6 +1585,13 @@ VLIB_NODE_FN (nat_pre_in2out_node) NAT_NEXT_IN2OUT_ED_FAST_PATH); } +VLIB_NODE_FN (nat_pre_in2out_output_node) + (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return nat_pre_node_fn_inline (vm, node, frame, + NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH); +} + /* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat_pre_in2out_node) = { .name = "nat-pre-in2out", @@ -1595,6 +1601,15 @@ VLIB_REGISTER_NODE (nat_pre_in2out_node) = { .type = VLIB_NODE_TYPE_INTERNAL, .n_errors = 0, }; + +VLIB_REGISTER_NODE (nat_pre_in2out_output_node) = { + .name = "nat-pre-in2out-output", + .vector_size = sizeof (u32), + .sibling_of = "nat-default", + .format_trace = format_nat_pre_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = 0, +}; /* *INDENT-ON* */ /* diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 61a36ec4e906..15c767c82c3e 100644 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -142,6 +142,12 @@ VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = { .node_name = "nat44-hairpin-src", .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"), }; +VNET_FEATURE_INIT (nat_pre_in2out_output, static) = { + .arc_name = "ip4-output", + .node_name = "nat-pre-in2out-output", + .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), + .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), +}; VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = { .arc_name = "ip4-output", .node_name = "nat44-ed-in2out-output", @@ -2249,7 +2255,7 @@ snat_interface_add_del_output_feature (u32 sw_if_index, return rv; vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in", sw_if_index, !is_del, 0, 0); - vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output", + vnet_feature_enable_disable ("ip4-output", "nat-pre-in2out-output", sw_if_index, !is_del, 0, 0); } else @@ -4662,6 +4668,7 @@ VLIB_REGISTER_NODE (nat_default_node) = { [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error", [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out", [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath", + [NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH] = "nat44-ed-in2out-output", [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath", [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in", [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath", diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index ab699221e698..fc5d32059ed2 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -54,6 +54,7 @@ typedef enum NAT_NEXT_ICMP_ERROR, NAT_NEXT_IN2OUT_ED_FAST_PATH, NAT_NEXT_IN2OUT_ED_SLOW_PATH, + NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH, NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH, NAT_NEXT_OUT2IN_ED_FAST_PATH, NAT_NEXT_OUT2IN_ED_SLOW_PATH, From 2ee0098dee4e4130ae350ccfe526d88a826160c5 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 20 Aug 2020 17:28:20 +0200 Subject: [PATCH 023/129] avf: fix race between avf process node and avf_delete_if(...) It may happen that process node is suspended while it waits for response from adminq and during that time CLI or API process can call avf_delete_if. When avf process node resumes, it may happen that device is not there anymeore. This patch delegates interface deletion to process node, so CLI/API process just sends signal instead of deleting device instance itself. Type: fix Change-Id: I7f12e12df3071650f6e60ad7eb5af23b7acfe335 Signed-off-by: Damjan Marion (cherry picked from commit 66bb7dd64ee2377103e18b96f1e6bf6405de44b5) --- src/plugins/avf/avf.h | 4 ++-- src/plugins/avf/avf_api.c | 9 +++++---- src/plugins/avf/cli.c | 8 +++----- src/plugins/avf/device.c | 31 ++++++++++++++++++++++++------- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/plugins/avf/avf.h b/src/plugins/avf/avf.h index 5d5178260097..4b35899da381 100644 --- a/src/plugins/avf/avf.h +++ b/src/plugins/avf/avf.h @@ -200,7 +200,7 @@ typedef struct typedef enum { AVF_PROCESS_EVENT_START = 1, - AVF_PROCESS_EVENT_STOP = 2, + AVF_PROCESS_EVENT_DELETE_IF = 2, AVF_PROCESS_EVENT_AQ_INT = 3, } avf_process_event_t; @@ -246,9 +246,9 @@ typedef struct } avf_create_if_args_t; void avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args); -void avf_delete_if (vlib_main_t * vm, avf_device_t * ad); extern vlib_node_registration_t avf_input_node; +extern vlib_node_registration_t avf_process_node; extern vnet_device_class_t avf_device_class; /* format.c */ diff --git a/src/plugins/avf/avf_api.c b/src/plugins/avf/avf_api.c index 1ddc45f23484..504fa31eb3de 100644 --- a/src/plugins/avf/avf_api.c +++ b/src/plugins/avf/avf_api.c @@ -66,7 +66,6 @@ vl_api_avf_delete_t_handler (vl_api_avf_delete_t * mp) vnet_main_t *vnm = vnet_get_main (); avf_main_t *am = &avf_main; vl_api_avf_delete_reply_t *rmp; - avf_device_t *ad; vnet_hw_interface_t *hw; int rv = 0; @@ -79,9 +78,8 @@ vl_api_avf_delete_t_handler (vl_api_avf_delete_t * mp) goto reply; } - ad = pool_elt_at_index (am->devices, hw->dev_instance); - - avf_delete_if (vm, ad); + vlib_process_signal_event (vm, avf_process_node.index, + AVF_PROCESS_EVENT_DELETE_IF, hw->dev_instance); reply: REPLY_MACRO (VL_API_AVF_DELETE_REPLY + am->msg_id_base); @@ -93,6 +91,9 @@ static clib_error_t * avf_plugin_api_hookup (vlib_main_t * vm) { avf_main_t *avm = &avf_main; + api_main_t *am = vlibapi_get_main (); + + am->is_mp_safe[VL_API_AVF_DELETE] = 1; /* ask for a correctly-sized block of API message decode slots */ avm->msg_id_base = setup_message_id_table (); diff --git a/src/plugins/avf/cli.c b/src/plugins/avf/cli.c index 414163ac8a25..29c2a6b1f6ea 100644 --- a/src/plugins/avf/cli.c +++ b/src/plugins/avf/cli.c @@ -84,8 +84,6 @@ avf_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, unformat_input_t _line_input, *line_input = &_line_input; u32 sw_if_index = ~0; vnet_hw_interface_t *hw; - avf_main_t *am = &avf_main; - avf_device_t *ad; vnet_main_t *vnm = vnet_get_main (); /* Get a line of input. */ @@ -113,9 +111,8 @@ avf_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, if (hw == NULL || avf_device_class.index != hw->dev_class_index) return clib_error_return (0, "not an AVF interface"); - ad = pool_elt_at_index (am->devices, hw->dev_instance); - - avf_delete_if (vm, ad); + vlib_process_signal_event (vm, avf_process_node.index, + AVF_PROCESS_EVENT_DELETE_IF, hw->dev_instance); return 0; } @@ -126,6 +123,7 @@ VLIB_CLI_COMMAND (avf_delete_command, static) = { .short_help = "delete interface avf " "{ | sw_if_index }", .function = avf_delete_command_fn, + .is_mp_safe = 1, }; /* *INDENT-ON* */ diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c index f086cd67741f..62a18cc3c5c5 100644 --- a/src/plugins/avf/device.c +++ b/src/plugins/avf/device.c @@ -35,6 +35,7 @@ #define PCI_DEVICE_ID_INTEL_X722_VF 0x37cd avf_main_t avf_main; +void avf_delete_if (vlib_main_t * vm, avf_device_t * ad, int with_barrier); static pci_device_id_t avf_pci_device_ids[] = { {.vendor_id = PCI_VENDOR_ID_INTEL,.device_id = PCI_DEVICE_ID_INTEL_AVF}, @@ -1202,7 +1203,6 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) vlib_process_wait_for_event (vm); event_type = vlib_process_get_events (vm, &event_data); - vec_reset_length (event_data); irq = 0; switch (event_type) @@ -1213,9 +1213,15 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) case AVF_PROCESS_EVENT_START: enabled = 1; break; - case AVF_PROCESS_EVENT_STOP: - enabled = 0; - continue; + case AVF_PROCESS_EVENT_DELETE_IF: + for (int i = 0; i < vec_len (event_data); i++) + { + ad = pool_elt_at_index (am->devices, event_data[i]); + avf_delete_if (vm, ad, /* with_barrier */ 1); + } + if (pool_elts (am->devices) < 1) + enabled = 0; + break; case AVF_PROCESS_EVENT_AQ_INT: irq = 1; break; @@ -1223,6 +1229,11 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) ASSERT (0); } + vec_reset_length (event_data); + + if (enabled == 0) + continue; + /* *INDENT-OFF* */ pool_foreach (ad, am->devices, { @@ -1235,7 +1246,7 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) } /* *INDENT-OFF* */ -VLIB_REGISTER_NODE (avf_process_node, static) = { +VLIB_REGISTER_NODE (avf_process_node) = { .function = avf_process, .type = VLIB_NODE_TYPE_PROCESS, .name = "avf-process", @@ -1316,17 +1327,23 @@ avf_irq_n_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line) } void -avf_delete_if (vlib_main_t * vm, avf_device_t * ad) +avf_delete_if (vlib_main_t * vm, avf_device_t * ad, int with_barrier) { vnet_main_t *vnm = vnet_get_main (); avf_main_t *am = &avf_main; int i; + ad->flags &= ~AVF_DEVICE_F_ADMIN_UP; + if (ad->hw_if_index) { + if (with_barrier) + vlib_worker_thread_barrier_sync (vm); vnet_hw_interface_set_flags (vnm, ad->hw_if_index, 0); vnet_hw_interface_unassign_rx_thread (vnm, ad->hw_if_index, 0); ethernet_delete_interface (vnm, ad->hw_if_index); + if (with_barrier) + vlib_worker_thread_barrier_release (vm); } vlib_pci_device_close (vm, ad->pci_dev_handle); @@ -1530,7 +1547,7 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args) return; error: - avf_delete_if (vm, ad); + avf_delete_if (vm, ad, /* with_barrier */ 0); args->rv = VNET_API_ERROR_INVALID_INTERFACE; args->error = clib_error_return (error, "pci-addr %U", format_vlib_pci_addr, &args->addr); From d5f713ce60b2ccc4838ed07fa83ad061e159af94 Mon Sep 17 00:00:00 2001 From: Onong Tayeng Date: Tue, 15 Sep 2020 13:55:29 +0530 Subject: [PATCH 024/129] lisp: fix lisp|one_eid_table_dump's local|remote options in vat The local|remote options to vat's lisp|one_eid_table_dump api command does not print the eid details instead it produces the following error messages: Filter error, unknown filter: 1 Filter error, unknown filter: 2 Type: fix Signed-off-by: Onong Tayeng Change-Id: I000c290b400dbf39bd883d57115923167092c9bd (cherry picked from commit 2237cc8ce1e0eb7222a34bb30bdeb2f3f1df9a81) --- src/vnet/lisp-cp/one_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index f7a972be7a29..452a756ee800 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -840,7 +840,7 @@ send_one_eid_table_details (mapping_t * mapit, if (mapit->pitr_set || mapit->nsh_set) return; - switch (ntohl (filter)) + switch (filter) { case ONE_FILTER_API_ALL: /* all mappings */ break; From c669272949f96b7e8a565c17d6a165094f8483bc Mon Sep 17 00:00:00 2001 From: Onong Tayeng Date: Fri, 11 Sep 2020 17:22:07 +0530 Subject: [PATCH 025/129] lisp: fix spelling mistake in option name In the vat help msg for one_add_del_l2_arp_entry the IP address option is misspelled as "ip4 " when it should have been "ip ". Type: fix Signed-off-by: Onong Tayeng Change-Id: Id4058a3ddfdb78b840d7e5a3c330e67b393f5d3b (cherry picked from commit 8c6ba2957c985a1670e9fca6bc869008e6722364) --- src/vat/api_format.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index f1935dee33a5..48a4a3fbe5d4 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -21031,7 +21031,7 @@ _(one_eid_table_dump, "[eid / | ] [vni] " \ _(one_add_del_ndp_entry, "[del] mac bd ip6 ") \ _(one_ndp_bd_get, "") \ _(one_ndp_entries_get, "bd ") \ -_(one_add_del_l2_arp_entry, "[del] mac bd ip4 ") \ +_(one_add_del_l2_arp_entry, "[del] mac bd ip ") \ _(one_l2_arp_bd_get, "") \ _(one_l2_arp_entries_get, "bd ") \ _(one_stats_enable_disable, "enable|disable") \ From a14f367e27f9340da1e15d0a6dd871d7af2a695d Mon Sep 17 00:00:00 2001 From: Onong Tayeng Date: Fri, 11 Sep 2020 15:38:20 +0530 Subject: [PATCH 026/129] lisp: fix help msg of show eid-table command The lisp|one show eid-table command's help msg does not display the available options. This patch fixes that. show lisp eid-table [local|remote|eid ] show one eid-table [local|remote|eid ] Type: fix Signed-off-by: Onong Tayeng Change-Id: Id39148db2ff291a7fe859830c1488b69ccd15c05 (cherry picked from commit b418c397dc8c870c6561ea1d7565067333db9df4) --- src/vnet/lisp-cp/lisp_cli.c | 4 ++-- src/vnet/lisp-cp/one_cli.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vnet/lisp-cp/lisp_cli.c b/src/vnet/lisp-cp/lisp_cli.c index 817fb50156b6..93422fe2de7e 100644 --- a/src/vnet/lisp-cp/lisp_cli.c +++ b/src/vnet/lisp-cp/lisp_cli.c @@ -887,7 +887,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (lisp_cp_show_eid_table_command) = { .path = "show lisp eid-table", - .short_help = "Shows EID table", + .short_help = "show lisp eid-table [local|remote|eid ]", .function = lisp_show_eid_table_command_fn, }; /* *INDENT-ON* */ @@ -1128,7 +1128,7 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = { .path = "show lisp eid-table map", - .short_help = "show lisp eid-table l2|l3", + .short_help = "show lisp eid-table map l2|l3", .function = lisp_show_eid_table_map_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index e44632f97603..70de0c1a5549 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -1203,7 +1203,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (one_cp_show_eid_table_command) = { .path = "show one eid-table", - .short_help = "Shows EID table", + .short_help = "show one eid-table [local|remote|eid ]", .function = lisp_show_eid_table_command_fn, }; /* *INDENT-ON* */ @@ -1670,7 +1670,7 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (one_show_eid_table_map_command) = { .path = "show one eid-table map", - .short_help = "show one eid-table l2|l3", + .short_help = "show one eid-table map l2|l3", .function = lisp_show_eid_table_map_command_fn, }; /* *INDENT-ON* */ From 21cbdc75f21cde6ea83382e647c9da081d7d5f5b Mon Sep 17 00:00:00 2001 From: Onong Tayeng Date: Thu, 10 Sep 2020 21:16:55 +0530 Subject: [PATCH 027/129] lisp: fix vat crash with one_add_del_local_eid api VAT crashes when the one_add_del_local_eid api is invoked with mac address as eid. Type: fix Signed-off-by: Onong Tayeng Change-Id: I29e246f6cad4b350fec52d54e94dbed586d488c4 (cherry picked from commit 5f473c0efc9e0ff068273520b058b8ac498dc597) --- src/vat/api_format.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 48a4a3fbe5d4..e3a2fe734bef 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -14305,7 +14305,7 @@ unformat_lisp_eid_vat (unformat_input_t * input, va_list * args) { a->type = 0; /* ip prefix type */ } - else if (unformat (input, "%U", unformat_ethernet_address, a->addr.mac)) + else if (unformat (input, "%U", unformat_ethernet_address, &a->addr.mac)) { a->type = 1; /* mac type */ } From 6efd393965317d7c27fbd0a7f0046a7b29d37a9e Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 10 Sep 2020 08:49:10 +0000 Subject: [PATCH 028/129] wireguard: Fix for tunnel encap Type: fix add UT for sneding handshale init and transport packets Signed-off-by: Neale Ranns Change-Id: Iab1ed8864c666d5a0ae0b2364a9ca4de3c8770dc (cherry picked from commit d75a2d12c431fcffba2a2b4d59f18c9cec483ed9) --- src/plugins/wireguard/test/test_wireguard.py | 491 ++++++++++++++++--- src/plugins/wireguard/wireguard_cookie.c | 2 +- src/plugins/wireguard/wireguard_if.c | 22 +- src/plugins/wireguard/wireguard_input.c | 12 +- src/plugins/wireguard/wireguard_noise.c | 16 +- src/plugins/wireguard/wireguard_output_tun.c | 7 +- src/plugins/wireguard/wireguard_peer.c | 7 +- 7 files changed, 468 insertions(+), 89 deletions(-) diff --git a/src/plugins/wireguard/test/test_wireguard.py b/src/plugins/wireguard/test/test_wireguard.py index cd124f3e2460..77349396ec69 100755 --- a/src/plugins/wireguard/test/test_wireguard.py +++ b/src/plugins/wireguard/test/test_wireguard.py @@ -1,15 +1,24 @@ #!/usr/bin/env python3 """ Wg tests """ +import datetime +import base64 + +from hashlib import blake2s from scapy.packet import Packet from scapy.packet import Raw -from scapy.layers.l2 import Ether +from scapy.layers.l2 import Ether, ARP from scapy.layers.inet import IP, UDP from scapy.contrib.wireguard import Wireguard, WireguardResponse, \ - WireguardInitiation -from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey + WireguardInitiation, WireguardTransport +from cryptography.hazmat.primitives.asymmetric.x25519 import \ + X25519PrivateKey, X25519PublicKey from cryptography.hazmat.primitives.serialization import Encoding, \ PrivateFormat, PublicFormat, NoEncryption +from cryptography.hazmat.primitives.hashes import BLAKE2s, Hash +from cryptography.hazmat.primitives.hmac import HMAC +from cryptography.hazmat.backends import default_backend +from noise.connection import NoiseConnection, Keypair from vpp_ipip_tun_interface import VppIpIpTunInterface from vpp_interface import VppInterface @@ -25,41 +34,48 @@ """ +def private_key_bytes(k): + return k.private_bytes(Encoding.Raw, + PrivateFormat.Raw, + NoEncryption()) + + +def public_key_bytes(k): + return k.public_bytes(Encoding.Raw, + PublicFormat.Raw) + + class VppWgInterface(VppInterface): """ VPP WireGuard interface """ - def __init__(self, test, src, port, key=None): + def __init__(self, test, src, port): super(VppWgInterface, self).__init__(test) - self.key = key - if not self.key: - self.generate = True - else: - self.generate = False self.port = port self.src = src + self.private_key = X25519PrivateKey.generate() + self.public_key = self.private_key.public_key() + + def public_key_bytes(self): + return public_key_bytes(self.public_key) + + def private_key_bytes(self): + return private_key_bytes(self.private_key) def add_vpp_config(self): r = self.test.vapi.wireguard_interface_create(interface={ 'user_instance': 0xffffffff, 'port': self.port, 'src_ip': self.src, - 'private_key': self.key_bytes() + 'private_key': private_key_bytes(self.private_key), + 'generate_key': False }) self.set_sw_if_index(r.sw_if_index) self.test.registry.register(self, self.test.logger) return self - def key_bytes(self): - if self.key: - return self.key.private_bytes(Encoding.Raw, - PrivateFormat.Raw, - NoEncryption()) - else: - return bytearray(32) - def remove_vpp_config(self): self.test.vapi.wireguard_interface_delete( sw_if_index=self._sw_if_index) @@ -70,7 +86,7 @@ def query_vpp_config(self): if t.interface.sw_if_index == self._sw_if_index and \ str(t.interface.src_ip) == self.src and \ t.interface.port == self.port and \ - t.interface.private_key == self.key_bytes(): + t.interface.private_key == private_key_bytes(self.private_key): return True return False @@ -91,6 +107,10 @@ def find_route(test, prefix, table_id=0): return False +NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s" +NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com" + + class VppWgPeer(VppObject): def __init__(self, @@ -106,9 +126,12 @@ def __init__(self, self.port = port self.allowed_ips = allowed_ips self.persistent_keepalive = persistent_keepalive + + # remote peer's public self.private_key = X25519PrivateKey.generate() self.public_key = self.private_key.public_key() - self.hash = bytearray(16) + + self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME) def validate_routing(self): for a in self.allowed_ips: @@ -129,6 +152,7 @@ def add_vpp_config(self): 'sw_if_index': self.itf.sw_if_index, 'persistent_keepalive': self.persistent_keepalive}) self.index = rv.peer_index + self.receiver_index = self.index + 1 self._test.registry.register(self, self._test.logger) self.validate_routing() return self @@ -141,13 +165,7 @@ def object_id(self): return ("wireguard-peer-%s" % self.index) def public_key_bytes(self): - return self.public_key.public_bytes(Encoding.Raw, - PublicFormat.Raw) - - def private_key_bytes(self): - return self.private_key.private_bytes(Encoding.Raw, - PrivateFormat.Raw, - NoEncryption()) + return public_key_bytes(self.public_key) def query_vpp_config(self): peers = self._test.vapi.wireguard_peers_dump() @@ -167,6 +185,148 @@ def query_vpp_config(self): return True return False + def set_responder(self): + self.noise.set_as_responder() + + def mk_tunnel_header(self, tx_itf): + return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) / + IP(src=self.endpoint, dst=self.itf.src) / + UDP(sport=self.port, dport=self.itf.port)) + + def noise_init(self, public_key=None): + self.noise.set_prologue(NOISE_IDENTIFIER_NAME) + self.noise.set_psks(psk=bytes(bytearray(32))) + + if not public_key: + public_key = self.itf.public_key + + # local/this private + self.noise.set_keypair_from_private_bytes( + Keypair.STATIC, + private_key_bytes(self.private_key)) + # remote's public + self.noise.set_keypair_from_public_bytes( + Keypair.REMOTE_STATIC, + public_key_bytes(public_key)) + + self.noise.start_handshake() + + def mk_handshake(self, tx_itf, public_key=None): + self.noise.set_as_initiator() + self.noise_init(public_key) + + p = (Wireguard() / WireguardInitiation()) + + p[Wireguard].message_type = 1 + p[Wireguard].reserved_zero = 0 + p[WireguardInitiation].sender_index = self.receiver_index + + # some random data for the message + # lifted from the noise protocol's wireguard example + now = datetime.datetime.now() + tai = struct.pack('!qi', 4611686018427387914 + int(now.timestamp()), + int(now.microsecond * 1e3)) + b = self.noise.write_message(payload=tai) + + # load noise into init message + p[WireguardInitiation].unencrypted_ephemeral = b[0:32] + p[WireguardInitiation].encrypted_static = b[32:80] + p[WireguardInitiation].encrypted_timestamp = b[80:108] + + # generate the mac1 hash + mac_key = blake2s(b'mac1----' + + self.itf.public_key_bytes()).digest() + p[WireguardInitiation].mac1 = blake2s(bytes(p)[0:116], + digest_size=16, + key=mac_key).digest() + p[WireguardInitiation].mac2 = bytearray(16) + + p = (self.mk_tunnel_header(tx_itf) / p) + + return p + + def verify_header(self, p): + self._test.assertEqual(p[IP].src, self.itf.src) + self._test.assertEqual(p[IP].dst, self.endpoint) + self._test.assertEqual(p[UDP].sport, self.itf.port) + self._test.assertEqual(p[UDP].dport, self.port) + self._test.assert_packet_checksums_valid(p) + + def consume_init(self, p, tx_itf): + self.noise.set_as_responder() + self.noise_init(self.itf.public_key) + self.verify_header(p) + + init = Wireguard(p[Raw]) + + self._test.assertEqual(init[Wireguard].message_type, 1) + self._test.assertEqual(init[Wireguard].reserved_zero, 0) + + self.sender = init[WireguardInitiation].sender_index + + # validate the hash + mac_key = blake2s(b'mac1----' + + public_key_bytes(self.public_key)).digest() + mac1 = blake2s(bytes(init)[0:-32], + digest_size=16, + key=mac_key).digest() + self._test.assertEqual(init[WireguardInitiation].mac1, mac1) + + # this passes only unencrypted_ephemeral, encrypted_static, + # encrypted_timestamp fields of the init + payload = self.noise.read_message(bytes(init)[8:-32]) + + # build the response + b = self.noise.write_message() + mac_key = blake2s(b'mac1----' + + public_key_bytes(self.itf.public_key)).digest() + resp = (Wireguard(message_type=2, reserved_zero=0) / + WireguardResponse(sender_index=self.receiver_index, + receiver_index=self.sender, + unencrypted_ephemeral=b[0:32], + encrypted_nothing=b[32:])) + mac1 = blake2s(bytes(resp)[:-32], + digest_size=16, + key=mac_key).digest() + resp[WireguardResponse].mac1 = mac1 + + resp = (self.mk_tunnel_header(tx_itf) / resp) + self._test.assertTrue(self.noise.handshake_finished) + + return resp + + def consume_response(self, p): + self.verify_header(p) + + resp = Wireguard(p[Raw]) + + self._test.assertEqual(resp[Wireguard].message_type, 2) + self._test.assertEqual(resp[Wireguard].reserved_zero, 0) + self._test.assertEqual(resp[WireguardResponse].receiver_index, + self.receiver_index) + + self.sender = resp[Wireguard].sender_index + + payload = self.noise.read_message(bytes(resp)[12:60]) + self._test.assertEqual(payload, b'') + self._test.assertTrue(self.noise.handshake_finished) + + def decrypt_transport(self, p): + self.verify_header(p) + + p = Wireguard(p[Raw]) + self._test.assertEqual(p[Wireguard].message_type, 4) + self._test.assertEqual(p[Wireguard].reserved_zero, 0) + self._test.assertEqual(p[WireguardTransport].receiver_index, + self.receiver_index) + + d = self.noise.decrypt( + p[WireguardTransport].encrypted_encapsulated_packet) + return d + + def encrypt_transport(self, p): + return self.noise.encrypt(bytes(p)) + class TestWg(VppTestCase): """ Wireguard Test Case """ @@ -192,6 +352,7 @@ def tearDownClass(cls): super(TestWg, cls).tearDownClass() def test_wg_interface(self): + """ Simple interface creation """ port = 12312 # Create interface @@ -204,7 +365,51 @@ def test_wg_interface(self): # delete interface wg0.remove_vpp_config() - def test_wg_peer(self): + def test_handshake_hash(self): + """ test hashing an init message """ + # a init packet generated by linux given the key below + h = "0100000098b9032b" \ + "55cc4b39e73c3d24" \ + "a2a1ab884b524a81" \ + "1808bb86640fb70d" \ + "e93154fec1879125" \ + "ab012624a27f0b75" \ + "c0a2582f438ddb5f" \ + "8e768af40b4ab444" \ + "02f9ff473e1b797e" \ + "80d39d93c5480c82" \ + "a3d4510f70396976" \ + "586fb67300a5167b" \ + "ae6ca3ff3dfd00eb" \ + "59be198810f5aa03" \ + "6abc243d2155ee4f" \ + "2336483900aef801" \ + "08752cd700000000" \ + "0000000000000000" \ + "00000000" + + b = bytearray.fromhex(h) + tgt = Wireguard(b) + + pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=") + pub = X25519PublicKey.from_public_bytes(pubb) + + self.assertEqual(pubb, public_key_bytes(pub)) + + # strip the macs and build a new packet + init = b[0:-32] + mac_key = blake2s(b'mac1----' + public_key_bytes(pub)).digest() + init += blake2s(init, + digest_size=16, + key=mac_key).digest() + init += b'\x00' * 16 + + act = Wireguard(init) + + self.assertEqual(tgt, act) + + def test_wg_peer_resp(self): + """ Send handshake response """ wg_output_node_name = '/err/wg-output-tun/' wg_input_node_name = '/err/wg-input/' @@ -213,16 +418,9 @@ def test_wg_peer(self): # Create interfaces wg0 = VppWgInterface(self, self.pg1.local_ip4, - port, - key=X25519PrivateKey.generate()).add_vpp_config() - wg1 = VppWgInterface(self, - self.pg2.local_ip4, - port+1).add_vpp_config() + port).add_vpp_config() wg0.admin_up() - wg1.admin_up() - - # Check peer counter - self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0) + wg0.config_ip4() self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -236,43 +434,210 @@ def test_wg_peer(self): self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) # wait for the peer to send a handshake - capture = self.pg1.get_capture(1, timeout=2) - handshake = capture[0] + rx = self.pg1.get_capture(1, timeout=2) + + # consume the handshake in the noise protocol and + # generate the response + resp = peer_1.consume_init(rx[0], self.pg1) + + # send the response, get keepalive + rxs = self.send_and_expect(self.pg1, [resp], self.pg1) + + for rx in rxs: + b = peer_1.decrypt_transport(rx) + self.assertEqual(0, len(b)) + + # send a packets that are routed into the tunnel + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / + UDP(sport=555, dport=556) / + Raw(b'\x00' * 80)) + + rxs = self.send_and_expect(self.pg0, p * 255, self.pg1) + + for rx in rxs: + rx = IP(peer_1.decrypt_transport(rx)) + # chech the oringial packet is present + self.assertEqual(rx[IP].dst, p[IP].dst) + self.assertEqual(rx[IP].ttl, p[IP].ttl-1) + + # send packets into the tunnel, expect to receive them on + # the other side + p = [(peer_1.mk_tunnel_header(self.pg1) / + Wireguard(message_type=4, reserved_zero=0) / + WireguardTransport( + receiver_index=peer_1.sender, + counter=ii, + encrypted_encapsulated_packet=peer_1.encrypt_transport( + (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / + UDP(sport=222, dport=223) / + Raw())))) for ii in range(255)] + + rxs = self.send_and_expect(self.pg1, p, self.pg0) + + for rx in rxs: + self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) + self.assertEqual(rx[IP].ttl, 19) + + def test_wg_peer_init(self): + """ Send handshake init """ + wg_output_node_name = '/err/wg-output-tun/' + wg_input_node_name = '/err/wg-input/' - self.assertEqual(handshake[IP].src, wg0.src) - self.assertEqual(handshake[IP].dst, peer_1.endpoint) - self.assertEqual(handshake[UDP].sport, wg0.port) - self.assertEqual(handshake[UDP].dport, peer_1.port) - handshake = Wireguard(handshake[Raw]) - self.assertEqual(handshake.message_type, 1) # "initiate") - init = handshake[WireguardInitiation] + port = 12323 + + # Create interfaces + wg0 = VppWgInterface(self, + self.pg1.local_ip4, + port).add_vpp_config() + wg0.admin_up() + wg0.config_ip4() + + peer_1 = VppWgPeer(self, + wg0, + self.pg1.remote_ip4, + port+1, + ["10.11.2.0/24", + "10.11.3.0/24"]).add_vpp_config() + self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) # route a packet into the wg interface # use the allowed-ip prefix + # this is dropped because the peer is not initiated + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / + UDP(sport=555, dport=556) / + Raw()) + self.send_and_assert_no_replies(self.pg0, [p]) + + kp_error = wg_output_node_name + "Keypair error" + self.assertEqual(1, self.statistics.get_err_counter(kp_error)) + + # send a handsake from the peer with an invalid MAC + p = peer_1.mk_handshake(self.pg1) + p[WireguardInitiation].mac1 = b'foobar' + self.send_and_assert_no_replies(self.pg1, [p]) + self.assertEqual(1, self.statistics.get_err_counter( + wg_input_node_name + "Invalid MAC handshake")) + + # send a handsake from the peer but signed by the wrong key. + p = peer_1.mk_handshake(self.pg1, + X25519PrivateKey.generate().public_key()) + self.send_and_assert_no_replies(self.pg1, [p]) + self.assertEqual(1, self.statistics.get_err_counter( + wg_input_node_name + "Peer error")) + + # send a valid handsake init for which we expect a response + p = peer_1.mk_handshake(self.pg1) + + rx = self.send_and_expect(self.pg1, [p], self.pg1) + + peer_1.consume_response(rx[0]) + + # route a packet into the wg interface + # this is dropped because the peer is still not initiated p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / UDP(sport=555, dport=556) / Raw()) - # rx = self.send_and_expect(self.pg0, [p], self.pg1) - rx = self.send_and_assert_no_replies(self.pg0, [p]) + self.send_and_assert_no_replies(self.pg0, [p]) + self.assertEqual(2, self.statistics.get_err_counter(kp_error)) + + # send a data packet from the peer through the tunnel + # this completes the handshake + p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / + UDP(sport=222, dport=223) / + Raw()) + d = peer_1.encrypt_transport(p) + p = (peer_1.mk_tunnel_header(self.pg1) / + (Wireguard(message_type=4, reserved_zero=0) / + WireguardTransport(receiver_index=peer_1.sender, + counter=0, + encrypted_encapsulated_packet=d))) + rxs = self.send_and_expect(self.pg1, [p], self.pg0) + + for rx in rxs: + self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) + self.assertEqual(rx[IP].ttl, 19) + + # send a packets that are routed into the tunnel + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / + UDP(sport=555, dport=556) / + Raw(b'\x00' * 80)) + + rxs = self.send_and_expect(self.pg0, p * 255, self.pg1) - self.logger.info(self.vapi.cli("sh error")) - init_sent = wg_output_node_name + "Keypair error" - self.assertEqual(1, self.statistics.get_err_counter(init_sent)) + for rx in rxs: + rx = IP(peer_1.decrypt_transport(rx)) + + # chech the oringial packet is present + self.assertEqual(rx[IP].dst, p[IP].dst) + self.assertEqual(rx[IP].ttl, p[IP].ttl-1) + + # send packets into the tunnel, expect to receive them on + # the other side + p = [(peer_1.mk_tunnel_header(self.pg1) / + Wireguard(message_type=4, reserved_zero=0) / + WireguardTransport( + receiver_index=peer_1.sender, + counter=ii+1, + encrypted_encapsulated_packet=peer_1.encrypt_transport( + (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / + UDP(sport=222, dport=223) / + Raw())))) for ii in range(255)] + + rxs = self.send_and_expect(self.pg1, p, self.pg0) + + for rx in rxs: + self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) + self.assertEqual(rx[IP].ttl, 19) + + peer_1.remove_vpp_config() + wg0.remove_vpp_config() + + def test_wg_multi_peer(self): + """ multiple peer setup """ + port = 12323 + + # Create interfaces + wg0 = VppWgInterface(self, + self.pg1.local_ip4, + port).add_vpp_config() + wg1 = VppWgInterface(self, + self.pg2.local_ip4, + port+1).add_vpp_config() + wg0.admin_up() + wg1.admin_up() + + # Check peer counter + self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() # Create many peers on sencond interface NUM_PEERS = 16 self.pg2.generate_remote_hosts(NUM_PEERS) self.pg2.configure_ipv4_neighbors() + self.pg1.generate_remote_hosts(NUM_PEERS) + self.pg1.configure_ipv4_neighbors() - peers = [] + peers_1 = [] + peers_2 = [] for i in range(NUM_PEERS): - peers.append(VppWgPeer(self, - wg1, - self.pg2.remote_hosts[i].ip4, - port+1+i, - ["10.10.%d.4/32" % i]).add_vpp_config()) - self.assertEqual(len(self.vapi.wireguard_peers_dump()), i+2) + peers_1.append(VppWgPeer(self, + wg0, + self.pg1.remote_hosts[i].ip4, + port+1+i, + ["10.0.%d.4/32" % i]).add_vpp_config()) + peers_2.append(VppWgPeer(self, + wg1, + self.pg2.remote_hosts[i].ip4, + port+100+i, + ["10.100.%d.4/32" % i]).add_vpp_config()) + + self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS*2) self.logger.info(self.vapi.cli("show wireguard peer")) self.logger.info(self.vapi.cli("show wireguard interface")) @@ -281,12 +646,12 @@ def test_wg_peer(self): self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0")) # remove peers - for p in peers: + for p in peers_1: + self.assertTrue(p.query_vpp_config()) + p.remove_vpp_config() + for p in peers_2: self.assertTrue(p.query_vpp_config()) p.remove_vpp_config() - self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) - peer_1.remove_vpp_config() - self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0) wg0.remove_vpp_config() - # wg1.remove_vpp_config() + wg1.remove_vpp_config() diff --git a/src/plugins/wireguard/wireguard_cookie.c b/src/plugins/wireguard/wireguard_cookie.c index aa476f792a1e..f54ce715906a 100755 --- a/src/plugins/wireguard/wireguard_cookie.c +++ b/src/plugins/wireguard/wireguard_cookie.c @@ -86,7 +86,7 @@ cookie_checker_validate_macs (vlib_main_t * vm, cookie_checker_t * cc, len = len - sizeof (message_macs_t); cookie_macs_mac1 (&our_cm, buf, len, cc->cc_mac1_key); - /* If mac1 is invald, we want to drop the packet */ + /* If mac1 is invalid, we want to drop the packet */ if (clib_memcmp (our_cm.mac1, cm->mac1, COOKIE_MAC_SIZE) != 0) return INVALID_MAC; diff --git a/src/plugins/wireguard/wireguard_if.c b/src/plugins/wireguard/wireguard_if.c index 522e9b6665a0..c91667bb2342 100644 --- a/src/plugins/wireguard/wireguard_if.c +++ b/src/plugins/wireguard/wireguard_if.c @@ -42,11 +42,21 @@ format_wg_if (u8 * s, va_list * args) key_to_base64 (wgi->local.l_private, NOISE_PUBLIC_KEY_LEN, key); s = format (s, " private-key:%s", key); + s = + format (s, " %U", format_hex_bytes, wgi->local.l_private, + NOISE_PUBLIC_KEY_LEN); key_to_base64 (wgi->local.l_public, NOISE_PUBLIC_KEY_LEN, key); s = format (s, " public-key:%s", key); + s = + format (s, " %U", format_hex_bytes, wgi->local.l_public, + NOISE_PUBLIC_KEY_LEN); + + s = format (s, " mac-key: %U", format_hex_bytes, + &wgi->cookie_checker.cc_mac1_key, NOISE_PUBLIC_KEY_LEN); + return (s); } @@ -235,9 +245,6 @@ wg_if_create (u32 user_instance, if (~0 == wg_if->user_instance) wg_if->user_instance = t_idx; - udp_dst_port_info_t *pi = udp_get_dst_port_info (&udp_main, port, UDP_IP4); - if (pi) - return (VNET_API_ERROR_VALUE_EXIST); udp_register_dst_port (vlib_get_main (), port, wg_input_node.index, 1); vec_validate_init_empty (wg_if_index_by_port, port, INDEX_INVALID); @@ -284,16 +291,17 @@ wg_if_delete (u32 sw_if_index) vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index); if (hw == 0 || hw->dev_class_index != wg_if_device_class.index) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; + return VNET_API_ERROR_INVALID_VALUE; wg_if_t *wg_if; wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index)); if (NULL == wg_if) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; + return VNET_API_ERROR_INVALID_SW_IF_INDEX_2; - if (wg_if_instance_free (hw->dev_instance) < 0) - return VNET_API_ERROR_INVALID_SW_IF_INDEX; + if (wg_if_instance_free (wg_if->user_instance) < 0) + return VNET_API_ERROR_INVALID_VALUE_2; + udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1); wg_if_index_by_port[wg_if->port] = INDEX_INVALID; vnet_delete_hw_interface (vnm, hw->hw_if_index); pool_put (wg_if_pool, wg_if); diff --git a/src/plugins/wireguard/wireguard_input.c b/src/plugins/wireguard/wireguard_input.c index 832ad031daa0..cdd65f87b516 100755 --- a/src/plugins/wireguard/wireguard_input.c +++ b/src/plugins/wireguard/wireguard_input.c @@ -313,12 +313,12 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, if (entry) { peer = pool_elt_at_index (wmp->peers, *entry); - if (!peer) - { - next[0] = WG_INPUT_NEXT_ERROR; - b[0]->error = node->errors[WG_INPUT_ERROR_PEER]; - goto out; - } + } + else + { + next[0] = WG_INPUT_NEXT_ERROR; + b[0]->error = node->errors[WG_INPUT_ERROR_PEER]; + goto out; } u16 encr_len = b[0]->current_length - sizeof (message_data_t); diff --git a/src/plugins/wireguard/wireguard_noise.c b/src/plugins/wireguard/wireguard_noise.c index dc7d5060fe5c..b47bb5747b97 100755 --- a/src/plugins/wireguard/wireguard_noise.c +++ b/src/plugins/wireguard/wireguard_noise.c @@ -536,7 +536,7 @@ noise_remote_ready (noise_remote_t * r) return ret; } -static void +static bool chacha20poly1305_calc (vlib_main_t * vm, u8 * src, u32 src_len, @@ -580,6 +580,8 @@ chacha20poly1305_calc (vlib_main_t * vm, { clib_memcpy (dst + src_len, op->tag, NOISE_AUTHTAG_LEN); } + + return (op->status == VNET_CRYPTO_OP_STATUS_COMPLETED); } enum noise_state_crypt @@ -668,9 +670,10 @@ noise_remote_decrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t r_idx, /* Decrypt, then validate the counter. We don't want to validate the * counter before decrypting as we do not know the message is authentic * prior to decryption. */ - chacha20poly1305_calc (vm, src, srclen, dst, NULL, 0, nonce, - VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, - kp->kp_recv_index); + if (!chacha20poly1305_calc (vm, src, srclen, dst, NULL, 0, nonce, + VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, + kp->kp_recv_index)) + goto error; if (!noise_counter_recv (&kp->kp_ctr, nonce)) goto error; @@ -936,8 +939,9 @@ noise_msg_decrypt (vlib_main_t * vm, uint8_t * dst, uint8_t * src, uint8_t hash[NOISE_HASH_LEN]) { /* Nonce always zero for Noise_IK */ - chacha20poly1305_calc (vm, src, src_len, dst, hash, NOISE_HASH_LEN, 0, - VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, key_idx); + if (!chacha20poly1305_calc (vm, src, src_len, dst, hash, NOISE_HASH_LEN, 0, + VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, key_idx)) + return false; noise_mix_hash (hash, src, src_len); return true; } diff --git a/src/plugins/wireguard/wireguard_output_tun.c b/src/plugins/wireguard/wireguard_output_tun.c index daec7a4a2f19..cdfd9d730f65 100755 --- a/src/plugins/wireguard/wireguard_output_tun.c +++ b/src/plugins/wireguard/wireguard_output_tun.c @@ -115,7 +115,8 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, while (n_left_from > 0) { ip4_udp_header_t *hdr = vlib_buffer_get_current (b[0]); - u8 *plain_data = vlib_buffer_get_current (b[0]) + sizeof (ip4_header_t); + u8 *plain_data = (vlib_buffer_get_current (b[0]) + + sizeof (ip4_udp_header_t)); u16 plain_data_len = clib_net_to_host_u16 (((ip4_header_t *) plain_data)->length); @@ -144,8 +145,8 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, * Ensure there is enough space to write the encrypted data * into the packet */ - if (PREDICT_FALSE (encrypted_packet_len > WG_OUTPUT_SCRATCH_SIZE) || - PREDICT_FALSE ((b[0]->current_data + encrypted_packet_len) < + if (PREDICT_FALSE (encrypted_packet_len >= WG_OUTPUT_SCRATCH_SIZE) || + PREDICT_FALSE ((b[0]->current_data + encrypted_packet_len) >= vlib_buffer_get_default_data_size (vm))) { b[0]->error = node->errors[WG_OUTPUT_ERROR_TOO_BIG]; diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c index 3985f4347b45..30adea82647a 100755 --- a/src/plugins/wireguard/wireguard_peer.c +++ b/src/plugins/wireguard/wireguard_peer.c @@ -380,15 +380,16 @@ format_wg_peer (u8 * s, va_list * va) peer = wg_peer_get (peeri); key_to_base64 (peer->remote.r_public, NOISE_PUBLIC_KEY_LEN, key); - s = format (s, "[%d] key:%=45s endpoint:[%U->%U] %U keep-alive:%d adj:%d", + s = format (s, "[%d] endpoint:[%U->%U] %U keep-alive:%d adj:%d", peeri, - key, format_wg_peer_endpoint, &peer->src, format_wg_peer_endpoint, &peer->dst, format_vnet_sw_if_index_name, vnet_get_main (), peer->wg_sw_if_index, peer->persistent_keepalive_interval, peer->adj_index); - + s = format (s, "\n key:%=s %U", + key, format_hex_bytes, peer->remote.r_public, + NOISE_PUBLIC_KEY_LEN); s = format (s, "\n allowed-ips:"); vec_foreach (allowed_ip, peer->allowed_ips) { From 97109b1ad8548d04f149c516297c36314227e8c6 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Fri, 11 Sep 2020 14:11:11 +0200 Subject: [PATCH 029/129] avf: add assert to ensure that adminq is used only from avf process Type: improvement Change-Id: Ib64c9b8207776986656e5a26c13a221edc6cc950 Signed-off-by: Damjan Marion (cherry picked from commit 698eeb126d01427313949241b961c27347db8c72) --- src/plugins/avf/device.c | 5 +++++ src/vlib/node_funcs.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c index 62a18cc3c5c5..8a7d74abc743 100644 --- a/src/plugins/avf/device.c +++ b/src/plugins/avf/device.c @@ -399,6 +399,11 @@ avf_send_to_pf (vlib_main_t * vm, avf_device_t * ad, virtchnl_ops_t op, u32 head; f64 t0, suspend_time = AVF_SEND_TO_PF_SUSPEND_TIME; + /* adminq operations should be only done from process node after device + * is initialized */ + ASSERT ((ad->flags & AVF_DEVICE_F_INITIALIZED) == 0 || + vlib_get_current_process_node_index (vm) == avf_process_node.index); + /* suppress interrupt in the next adminq receive slot as we are going to wait for response we only need interrupts when event is received */ diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h index dfeba17ab09b..33bdc795816a 100644 --- a/src/vlib/node_funcs.h +++ b/src/vlib/node_funcs.h @@ -455,6 +455,13 @@ vlib_current_process (vlib_main_t * vm) return vlib_get_current_process (vm)->node_runtime.node_index; } +always_inline u32 +vlib_get_current_process_node_index (vlib_main_t * vm) +{ + vlib_process_t *process = vlib_get_current_process (vm); + return process->node_runtime.node_index; +} + /** Returns TRUE if a process suspend time is less than 10us @param dt - remaining poll time in seconds @returns 1 if dt < 10e-6, 0 otherwise From ec7e8d8598d9957e5b87e37bee4ca59a28ccc088 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Fri, 11 Sep 2020 17:40:52 +0000 Subject: [PATCH 030/129] vppapigen: crcchecker: report deprecated messages Report if the messages were marked as deprecated, but not yet deleted. Useful for building the release notes and comparing between the releases. Also, put the dict_compare() call into the report(), since latter always consumes the output of the former. Change-Id: Iceab3e94ff66da931a4669b612026bd162dd5d1a Type: improvement Signed-off-by: Andrew Yourtchenko (cherry picked from commit 62bd50de97cd90cc09559a09fe46f98211279a1e) --- extras/scripts/crcchecker.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/extras/scripts/crcchecker.py b/extras/scripts/crcchecker.py index 7f83d2e6d856..c25510d08e4e 100755 --- a/extras/scripts/crcchecker.py +++ b/extras/scripts/crcchecker.py @@ -107,7 +107,8 @@ def is_in_progress(d, k): except: return False -def report(old, new, added, removed, modified, same): +def report(new, old): + added, removed, modified, same = dict_compare(new, old) backwards_incompatible = 0 for k in added: print(f'added: {k}') @@ -126,6 +127,17 @@ def report(old, new, added, removed, modified, same): print(f'modified: ** {k}') else: print(f'modified: {k}') + + # check which messages are still there but were marked for deprecation + for k in new.keys(): + newversion = int(new[k]['version']) + if newversion > 0 and is_deprecated(new, k): + if k in old: + if not is_deprecated(old, k): + print(f'deprecated: {k}') + else: + print(f'added+deprecated: {k}') + return backwards_incompatible @@ -150,8 +162,7 @@ def main(): if args.diff: oldcrcs = crc_from_apigen(None, args.diff[0]) newcrcs = crc_from_apigen(None, args.diff[1]) - added, removed, modified, same = dict_compare(newcrcs, oldcrcs) - backwards_incompatible = report(oldcrcs, newcrcs, added, removed, modified, same) + backwards_incompatible = report(newcrcs, oldcrcs) sys.exit(0) # Dump CRC for messages in given files / revision @@ -186,8 +197,7 @@ def main(): newcrcs.update(crc_from_apigen(None, f)) oldcrcs.update(crc_from_apigen(revision, f)) - added, removed, modified, same = dict_compare(newcrcs, oldcrcs) - backwards_incompatible = report(oldcrcs, newcrcs, added, removed, modified, same) + backwards_incompatible = report(newcrcs, oldcrcs) if args.check_patchset: if backwards_incompatible: From 00f21fb2fed0b6cf10eda45913b98a20e7b4cd3f Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Tue, 15 Sep 2020 11:37:16 +0200 Subject: [PATCH 031/129] api: clean up use of deprecated flag The syntax of the deprecated flag has evolved. Clean up usage to be "option deprecated;". Type: fix Signed-off-by: Ole Troan Change-Id: If2b639f275eb8db58b36c457f9245fe35a4d8cb1 (cherry picked from commit f916414b383afd37ec78509ee613df8878160406) --- src/plugins/map/map.api | 2 +- src/plugins/nat/det44/det44.api | 22 +++++++++++----------- src/plugins/nsim/nsim.api | 2 +- src/vnet/cop/cop.api | 4 ++-- src/vnet/devices/virtio/virtio.api | 4 ++-- src/vnet/geneve/geneve.api | 2 +- src/vnet/ipsec/ipsec.api | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/plugins/map/map.api b/src/plugins/map/map.api index adf4d0a5bbd6..fa32978591c4 100644 --- a/src/plugins/map/map.api +++ b/src/plugins/map/map.api @@ -112,7 +112,7 @@ define map_domains_get_reply define map_domain_dump { - option deprecated="v21.01"; + option deprecated; u32 client_index; u32 context; }; diff --git a/src/plugins/nat/det44/det44.api b/src/plugins/nat/det44/det44.api index 818d46a1d5ad..f9c38007288d 100644 --- a/src/plugins/nat/det44/det44.api +++ b/src/plugins/nat/det44/det44.api @@ -311,7 +311,7 @@ autoreply define nat_det_add_del_map { u8 in_plen; vl_api_ip4_address_t out_addr; u8 out_plen; - option status="deprecated"; + option deprecated; }; /** \brief Get outside address and port range from inside address @@ -323,7 +323,7 @@ define nat_det_forward { u32 client_index; u32 context; vl_api_ip4_address_t in_addr; - option status="deprecated"; + option deprecated; }; /** \brief Get outside address and port range from inside address @@ -339,7 +339,7 @@ define nat_det_forward_reply { u16 out_port_lo; u16 out_port_hi; vl_api_ip4_address_t out_addr; - option status="deprecated"; + option deprecated; }; /** \brief Get inside address from outside address and port @@ -353,7 +353,7 @@ define nat_det_reverse { u32 context; u16 out_port; vl_api_ip4_address_t out_addr; - option status="deprecated"; + option deprecated; }; /** \brief Get inside address from outside address and port reply @@ -365,7 +365,7 @@ define nat_det_reverse_reply { u32 context; i32 retval; vl_api_ip4_address_t in_addr; - option status="deprecated"; + option deprecated; }; /** \brief Dump NAT deterministic mappings @@ -375,7 +375,7 @@ define nat_det_reverse_reply { define nat_det_map_dump { u32 client_index; u32 context; - option status="deprecated"; + option deprecated; }; /** \brief NAT users response @@ -397,7 +397,7 @@ define nat_det_map_details { u32 sharing_ratio; u16 ports_per_host; u32 ses_num; - option status="deprecated"; + option deprecated; }; /** \brief Close deterministic NAT session by outside address and port @@ -415,7 +415,7 @@ autoreply define nat_det_close_session_out { u16 out_port; vl_api_ip4_address_t ext_addr; u16 ext_port; - option status="deprecated"; + option deprecated; }; /** \brief Close deterministic NAT session by inside address and port @@ -433,7 +433,7 @@ autoreply define nat_det_close_session_in { u16 in_port; vl_api_ip4_address_t ext_addr; u16 ext_port; - option status="deprecated"; + option deprecated; }; /** \brief Dump determinstic NAT sessions @@ -445,7 +445,7 @@ define nat_det_session_dump { u32 client_index; u32 context; vl_api_ip4_address_t user_addr; - option status="deprecated"; + option deprecated; }; /** \brief Deterministic NAT sessions reply @@ -465,5 +465,5 @@ define nat_det_session_details { u16 out_port; u8 state; u32 expire; - option status="deprecated"; + option deprecated; }; diff --git a/src/plugins/nsim/nsim.api b/src/plugins/nsim/nsim.api index 654932520228..f0ae02a70bda 100644 --- a/src/plugins/nsim/nsim.api +++ b/src/plugins/nsim/nsim.api @@ -61,7 +61,7 @@ autoreply define nsim_output_feature_enable_disable */ autoreply define nsim_configure { - option deprecated="v21.01"; + option deprecated; /* Client identifier, set from api_main.my_client_index */ u32 client_index; diff --git a/src/vnet/cop/cop.api b/src/vnet/cop/cop.api index 39677a266739..75fd15bbb9fb 100644 --- a/src/vnet/cop/cop.api +++ b/src/vnet/cop/cop.api @@ -26,7 +26,7 @@ import "vnet/interface_types.api"; autoreply define cop_interface_enable_disable { - option deprecated="v21.01"; + option deprecated; u32 client_index; u32 context; vl_api_interface_index_t sw_if_index; @@ -47,7 +47,7 @@ autoreply define cop_interface_enable_disable autoreply define cop_whitelist_enable_disable { - option deprecated="v21.01"; + option deprecated; u32 client_index; u32 context; vl_api_interface_index_t sw_if_index; diff --git a/src/vnet/devices/virtio/virtio.api b/src/vnet/devices/virtio/virtio.api index 143d25b73ab0..3c8aed2e1591 100644 --- a/src/vnet/devices/virtio/virtio.api +++ b/src/vnet/devices/virtio/virtio.api @@ -32,7 +32,7 @@ import "vlib/pci/pci_types.api"; */ define virtio_pci_create { - option deprecated="21.01"; + option deprecated; u32 client_index; u32 context; vl_api_pci_address_t pci_addr; @@ -50,7 +50,7 @@ define virtio_pci_create */ define virtio_pci_create_reply { - option deprecated="21.01"; + option deprecated; u32 context; i32 retval; vl_api_interface_index_t sw_if_index; diff --git a/src/vnet/geneve/geneve.api b/src/vnet/geneve/geneve.api index 4502d8907976..ef2cd5ed8ae9 100644 --- a/src/vnet/geneve/geneve.api +++ b/src/vnet/geneve/geneve.api @@ -21,7 +21,7 @@ import "vnet/ip/ip_types.api"; define geneve_add_del_tunnel { - option deprecated="20.06"; + option deprecated; u32 client_index; u32 context; bool is_add; diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 52a16ede1aac..89dcdb761de6 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -343,7 +343,7 @@ define ipsec_spd_interface_details { @param salt - for use with counter mode ciphers */ define ipsec_tunnel_if_add_del { - option deprecated="20.09"; + option deprecated; u32 client_index; u32 context; bool is_add; @@ -491,7 +491,7 @@ define ipsec_sa_details { @param is_outbound - 1 if outbound (local) SA, 0 if inbound (remote) */ autoreply define ipsec_tunnel_if_set_sa { - option deprecated="20.09"; + option deprecated; u32 client_index; u32 context; vl_api_interface_index_t sw_if_index; From 4b952f85bd24c8dfe72d3173f6bfbb27f67c2e2c Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Wed, 9 Sep 2020 17:40:02 +0200 Subject: [PATCH 032/129] avf: fix race between avf and cli/api process device pool my grow during suspemd which will cause crash in avf process after it exits from suspend. Type: fix Change-Id: I51fec90088c909cfbaaca6c245272a28c0827ca0 Signed-off-by: Damjan Marion (cherry picked from commit 171d6aceb039a7f0b0d67c837ff74359dae01ae4) --- src/plugins/avf/avf.h | 8 +++++- src/plugins/avf/cli.c | 3 +-- src/plugins/avf/device.c | 55 ++++++++++++++++++++++------------------ src/plugins/avf/format.c | 6 ++--- src/plugins/avf/input.c | 3 +-- src/plugins/avf/output.c | 3 +-- 6 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/plugins/avf/avf.h b/src/plugins/avf/avf.h index 4b35899da381..c4c0c13ebb9a 100644 --- a/src/plugins/avf/avf.h +++ b/src/plugins/avf/avf.h @@ -223,7 +223,7 @@ typedef struct { u16 msg_id_base; - avf_device_t *devices; + avf_device_t **devices; avf_per_thread_data_t *per_thread_data; vlib_log_class_t log_class; @@ -256,6 +256,12 @@ format_function_t format_avf_device; format_function_t format_avf_device_name; format_function_t format_avf_input_trace; +static_always_inline avf_device_t * +avf_get_device (u32 dev_instance) +{ + return pool_elt_at_index (avf_main.devices, dev_instance)[0]; +} + static inline u32 avf_get_u32 (void *start, int offset) { diff --git a/src/plugins/avf/cli.c b/src/plugins/avf/cli.c index 29c2a6b1f6ea..32c19f46590a 100644 --- a/src/plugins/avf/cli.c +++ b/src/plugins/avf/cli.c @@ -134,7 +134,6 @@ avf_test_command_fn (vlib_main_t * vm, unformat_input_t * input, unformat_input_t _line_input, *line_input = &_line_input; u32 sw_if_index = ~0; vnet_hw_interface_t *hw; - avf_main_t *am = &avf_main; avf_device_t *ad; vnet_main_t *vnm = vnet_get_main (); int test_irq = 0, enable_elog = 0, disable_elog = 0; @@ -170,7 +169,7 @@ avf_test_command_fn (vlib_main_t * vm, unformat_input_t * input, if (hw == NULL || avf_device_class.index != hw->dev_class_index) return clib_error_return (0, "not a AVF interface"); - ad = pool_elt_at_index (am->devices, hw->dev_instance); + ad = avf_get_device (hw->dev_instance); if (enable_elog) ad->flags |= AVF_DEVICE_F_ELOG; diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c index 8a7d74abc743..8b6451e89984 100644 --- a/src/plugins/avf/device.c +++ b/src/plugins/avf/device.c @@ -1162,8 +1162,7 @@ static u32 avf_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags) { vlib_main_t *vm = vlib_get_main (); - avf_main_t *am = &avf_main; - avf_device_t *ad = vec_elt_at_index (am->devices, hw->dev_instance); + avf_device_t *ad = avf_get_device (hw->dev_instance); clib_error_t *error; u8 promisc_enabled; @@ -1194,11 +1193,12 @@ static uword avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { avf_main_t *am = &avf_main; - avf_device_t *ad; uword *event_data = 0, event_type; int enabled = 0, irq; f64 last_run_duration = 0; f64 last_periodic_time = 0; + avf_device_t **dev_pointers = 0; + u32 i; while (1) { @@ -1221,7 +1221,7 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) case AVF_PROCESS_EVENT_DELETE_IF: for (int i = 0; i < vec_len (event_data); i++) { - ad = pool_elt_at_index (am->devices, event_data[i]); + avf_device_t *ad = avf_get_device (event_data[i]); avf_delete_if (vm, ad, /* with_barrier */ 1); } if (pool_elts (am->devices) < 1) @@ -1239,11 +1239,19 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) if (enabled == 0) continue; + /* create local list of device pointers as device pool may grow + * during suspend */ + vec_reset_length (dev_pointers); /* *INDENT-OFF* */ - pool_foreach (ad, am->devices, + pool_foreach_index (i, am->devices, + { + vec_add1 (dev_pointers, avf_get_device (i)); + }); + + vec_foreach_index (i, dev_pointers) { - avf_process_one_device (vm, ad, irq); - }); + avf_process_one_device (vm, dev_pointers[i], irq); + }; /* *INDENT-ON* */ last_run_duration = vlib_time_now (vm) - last_periodic_time; } @@ -1261,9 +1269,8 @@ VLIB_REGISTER_NODE (avf_process_node) = { static void avf_irq_0_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line) { - avf_main_t *am = &avf_main; uword pd = vlib_pci_get_private_data (vm, h); - avf_device_t *ad = pool_elt_at_index (am->devices, pd); + avf_device_t *ad = avf_get_device (pd); u32 icr0; icr0 = avf_reg_read (ad, AVFINT_ICR0); @@ -1300,9 +1307,8 @@ static void avf_irq_n_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line) { vnet_main_t *vnm = vnet_get_main (); - avf_main_t *am = &avf_main; uword pd = vlib_pci_get_private_data (vm, h); - avf_device_t *ad = pool_elt_at_index (am->devices, pd); + avf_device_t *ad = avf_get_device (pd); if (ad->flags & AVF_DEVICE_F_ELOG) { @@ -1391,7 +1397,8 @@ avf_delete_if (vlib_main_t * vm, avf_device_t * ad, int with_barrier) clib_error_free (ad->error); clib_memset (ad, 0, sizeof (*ad)); - pool_put (am->devices, ad); + pool_put_index (am->devices, ad->dev_instance); + clib_mem_free (ad); } void @@ -1399,7 +1406,7 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args) { vnet_main_t *vnm = vnet_get_main (); avf_main_t *am = &avf_main; - avf_device_t *ad; + avf_device_t *ad, **adp; vlib_pci_dev_handle_t h; clib_error_t *error = 0; int i; @@ -1417,8 +1424,11 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args) return; } - pool_get (am->devices, ad); - ad->dev_instance = ad - am->devices; + pool_get (am->devices, adp); + adp[0] = ad = clib_mem_alloc_aligned (sizeof (avf_device_t), + CLIB_CACHE_LINE_BYTES); + clib_memset (ad, 0, sizeof (avf_device_t)); + ad->dev_instance = adp - am->devices; ad->per_interface_next_index = ~0; ad->name = vec_dup (args->name); @@ -1428,7 +1438,8 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args) if ((error = vlib_pci_device_open (vm, &args->addr, avf_pci_device_ids, &h))) { - pool_put (am->devices, ad); + pool_put (am->devices, adp); + clib_mem_free (ad); args->rv = VNET_API_ERROR_INVALID_INTERFACE; args->error = clib_error_return (error, "pci-addr %U", format_vlib_pci_addr, @@ -1563,8 +1574,7 @@ static clib_error_t * avf_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags) { vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index); - avf_main_t *am = &avf_main; - avf_device_t *ad = vec_elt_at_index (am->devices, hi->dev_instance); + avf_device_t *ad = avf_get_device (hi->dev_instance); uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0; if (ad->flags & AVF_DEVICE_F_ERROR) @@ -1588,9 +1598,8 @@ static clib_error_t * avf_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid, vnet_hw_interface_rx_mode mode) { - avf_main_t *am = &avf_main; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); - avf_device_t *ad = pool_elt_at_index (am->devices, hw->dev_instance); + avf_device_t *ad = avf_get_device (hw->dev_instance); avf_rxq_t *rxq = vec_elt_at_index (ad->rxqs, qid); if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING) @@ -1620,9 +1629,8 @@ static void avf_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index, u32 node_index) { - avf_main_t *am = &avf_main; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); - avf_device_t *ad = pool_elt_at_index (am->devices, hw->dev_instance); + avf_device_t *ad = avf_get_device (hw->dev_instance); /* Shut off redirection */ if (node_index == ~0) @@ -1644,8 +1652,7 @@ static char *avf_tx_func_error_strings[] = { static void avf_clear_hw_interface_counters (u32 instance) { - avf_main_t *am = &avf_main; - avf_device_t *ad = vec_elt_at_index (am->devices, instance); + avf_device_t *ad = avf_get_device (instance); clib_memcpy_fast (&ad->last_cleared_eth_stats, &ad->eth_stats, sizeof (ad->eth_stats)); } diff --git a/src/plugins/avf/format.c b/src/plugins/avf/format.c index bc2b94ecc46c..e5da0e2bbf60 100644 --- a/src/plugins/avf/format.c +++ b/src/plugins/avf/format.c @@ -27,8 +27,7 @@ format_avf_device_name (u8 * s, va_list * args) { vlib_main_t *vm = vlib_get_main (); u32 i = va_arg (*args, u32); - avf_main_t *am = &avf_main; - avf_device_t *ad = vec_elt_at_index (am->devices, i); + avf_device_t *ad = avf_get_device (i); vlib_pci_addr_t *addr = vlib_pci_get_addr (vm, ad->pci_dev_handle); if (ad->name) @@ -88,8 +87,7 @@ u8 * format_avf_device (u8 * s, va_list * args) { u32 i = va_arg (*args, u32); - avf_main_t *am = &avf_main; - avf_device_t *ad = vec_elt_at_index (am->devices, i); + avf_device_t *ad = avf_get_device (i); u32 indent = format_get_indent (s); u8 *a = 0; diff --git a/src/plugins/avf/input.c b/src/plugins/avf/input.c index da5556a391e1..0ccf7721835c 100644 --- a/src/plugins/avf/input.c +++ b/src/plugins/avf/input.c @@ -444,14 +444,13 @@ VLIB_NODE_FN (avf_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_rx = 0; - avf_main_t *am = &avf_main; vnet_device_input_runtime_t *rt = (void *) node->runtime_data; vnet_device_and_queue_t *dq; foreach_device_and_queue (dq, rt->devices_and_queues) { avf_device_t *ad; - ad = vec_elt_at_index (am->devices, dq->dev_instance); + ad = avf_get_device (dq->dev_instance); if ((ad->flags & AVF_DEVICE_F_ADMIN_UP) == 0) continue; n_rx += avf_device_input_inline (vm, node, frame, ad, dq->queue_id); diff --git a/src/plugins/avf/output.c b/src/plugins/avf/output.c index 6c43885569e6..e5b53ba54577 100644 --- a/src/plugins/avf/output.c +++ b/src/plugins/avf/output.c @@ -267,9 +267,8 @@ VNET_DEVICE_CLASS_TX_FN (avf_device_class) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - avf_main_t *am = &avf_main; vnet_interface_output_runtime_t *rd = (void *) node->runtime_data; - avf_device_t *ad = pool_elt_at_index (am->devices, rd->dev_instance); + avf_device_t *ad = avf_get_device (rd->dev_instance); u32 thread_index = vm->thread_index; u8 qid = thread_index; avf_txq_t *txq = vec_elt_at_index (ad->txqs, qid % ad->num_queue_pairs); From fb66fcf3fb7de414534650b3fce9627fefbe6a13 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Fri, 11 Sep 2020 14:10:35 +0200 Subject: [PATCH 033/129] avf: change promisc mode from the avf process node Avoid situations where promisc mode is chaged while avf process is suspended in the middle of adminq operation. Type: fix Change-Id: Ia1fc6551e83218b5938630ad3a15d4f3f0ceceff Signed-off-by: Damjan Marion (cherry picked from commit 160a2a9a8c5c4e054dcc0e8ebeb3de7654718582) --- src/plugins/avf/avf.h | 2 ++ src/plugins/avf/device.c | 31 ++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/plugins/avf/avf.h b/src/plugins/avf/avf.h index c4c0c13ebb9a..43741dcad835 100644 --- a/src/plugins/avf/avf.h +++ b/src/plugins/avf/avf.h @@ -202,6 +202,8 @@ typedef enum AVF_PROCESS_EVENT_START = 1, AVF_PROCESS_EVENT_DELETE_IF = 2, AVF_PROCESS_EVENT_AQ_INT = 3, + AVF_PROCESS_EVENT_SET_PROMISC_ENABLE = 4, + AVF_PROCESS_EVENT_SET_PROMISC_DISABLE = 5, } avf_process_event_t; typedef struct diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c index 8b6451e89984..2b4801e2c814 100644 --- a/src/plugins/avf/device.c +++ b/src/plugins/avf/device.c @@ -1163,7 +1163,6 @@ avf_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags) { vlib_main_t *vm = vlib_get_main (); avf_device_t *ad = avf_get_device (hw->dev_instance); - clib_error_t *error; u8 promisc_enabled; switch (flags) @@ -1179,13 +1178,12 @@ avf_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags) } promisc_enabled = ((ad->flags & AVF_DEVICE_F_PROMISC) != 0); - if ((error = avf_config_promisc_mode (vm, ad, promisc_enabled))) - { - avf_log_err (ad, "%s: %U", format_clib_error, error); - clib_error_free (error); - return ~0; - } + vlib_process_signal_event (vm, avf_process_node.index, + promisc_enabled ? + AVF_PROCESS_EVENT_SET_PROMISC_ENABLE : + AVF_PROCESS_EVENT_SET_PROMISC_DISABLE, + hw->dev_instance); return 0; } @@ -1230,6 +1228,25 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) case AVF_PROCESS_EVENT_AQ_INT: irq = 1; break; + case AVF_PROCESS_EVENT_SET_PROMISC_ENABLE: + case AVF_PROCESS_EVENT_SET_PROMISC_DISABLE: + for (int i = 0; i < vec_len (event_data); i++) + { + avf_device_t *ad = avf_get_device (event_data[i]); + clib_error_t *err; + int is_enable = 0; + + if (event_type == AVF_PROCESS_EVENT_SET_PROMISC_ENABLE) + is_enable = 1; + + if ((err = avf_config_promisc_mode (vm, ad, is_enable))) + { + avf_log_err (ad, "%s: %U", format_clib_error, err); + clib_error_free (err); + } + } + break; + default: ASSERT (0); } From 4035daffd540c23db1195216303cba79e8ca17c3 Mon Sep 17 00:00:00 2001 From: Yulong Pei Date: Mon, 14 Sep 2020 19:45:03 -0700 Subject: [PATCH 034/129] crypto: Crypto set handler API to support set all as CLI Type: improvement Signed-off-by: Yulong Pei Change-Id: I43556f8c76c7aae64d9c927e1fda3c1774d7e49d (cherry picked from commit 8c91b2ae2b32d428ef35605707788fe064621cb3) --- src/vnet/crypto/crypto.api | 2 +- src/vnet/crypto/crypto_api.c | 39 +++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/vnet/crypto/crypto.api b/src/vnet/crypto/crypto.api index 04b0cfdeaa34..6eccd8524ba9 100644 --- a/src/vnet/crypto/crypto.api +++ b/src/vnet/crypto/crypto.api @@ -41,7 +41,7 @@ autoreply define crypto_set_async_dispatch vl_api_crypto_dispatch_mode_t mode; }; - /** \brief crypto: use polling or interrupt dispatch + /** \brief crypto: set crypto handler @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param alg_name - Name of the algorithm to add diff --git a/src/vnet/crypto/crypto_api.c b/src/vnet/crypto/crypto_api.c index 49b12a3d377b..8766614c02d9 100644 --- a/src/vnet/crypto/crypto_api.c +++ b/src/vnet/crypto/crypto_api.c @@ -54,6 +54,7 @@ vl_api_crypto_set_async_dispatch_t_handler (vl_api_crypto_set_async_dispatch_t static void vl_api_crypto_set_handler_t_handler (vl_api_crypto_set_handler_t * mp) { + vnet_crypto_main_t *cm = &crypto_main; vl_api_crypto_set_handler_reply_t *rmp; int rv = 0; char *engine; @@ -64,10 +65,42 @@ vl_api_crypto_set_handler_t_handler (vl_api_crypto_set_handler_t * mp) alg_name = (char *) mp->alg_name; oct = (crypto_op_class_type_t) mp->oct; - if (mp->is_async) - rv = vnet_crypto_set_async_handler2 (alg_name, engine); + if (strcmp ("all", alg_name) == 0) + { + if (mp->is_async) + { + char *key; + u8 *value; + + /* *INDENT-OFF* */ + hash_foreach_mem (key, value, cm->async_alg_index_by_name, + ({ + (void) value; + rv += vnet_crypto_set_async_handler2 (key, engine); + })); + /* *INDENT-ON* */ + } + else + { + char *key; + u8 *value; + + /* *INDENT-OFF* */ + hash_foreach_mem (key, value, cm->alg_index_by_name, + ({ + (void) value; + rv += vnet_crypto_set_handler2 (key, engine, oct); + })); + /* *INDENT-ON* */ + } + } else - rv = vnet_crypto_set_handler2 (alg_name, engine, oct); + { + if (mp->is_async) + rv = vnet_crypto_set_async_handler2 (alg_name, engine); + else + rv = vnet_crypto_set_handler2 (alg_name, engine, oct); + } REPLY_MACRO (VL_API_CRYPTO_SET_HANDLER_REPLY); } From a87deb77da4bd4a0aa85721f7a400590bcecd348 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Wed, 16 Sep 2020 09:48:59 +0000 Subject: [PATCH 035/129] vppapigen: crcchecker: report in-progress messages in-progress messages do not give any API stability guarantees, by design, to allow easy iteration. Provide an easy way to know which messages are in-progress. If as a user you see "in-progress" message that you want to use in production, please contact the feature owner and discuss the path to removing the "in-progress" status before that. Change-Id: I27729995e26a70af373e642b871dbb5cc5526959 Type: improvement Signed-off-by: Andrew Yourtchenko (cherry picked from commit 8b0cd69d31a50e7f4a454d45e903c6cdaf23fbfe) --- extras/scripts/crcchecker.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extras/scripts/crcchecker.py b/extras/scripts/crcchecker.py index c25510d08e4e..7929374c5c8d 100755 --- a/extras/scripts/crcchecker.py +++ b/extras/scripts/crcchecker.py @@ -110,6 +110,12 @@ def is_in_progress(d, k): def report(new, old): added, removed, modified, same = dict_compare(new, old) backwards_incompatible = 0 + # print the full list of in-progress messages + # they should eventually either disappear of become supported + for k in new.keys(): + newversion = int(new[k]['version']) + if newversion == 0 or is_in_progress(new, k): + print(f'in-progress: {k}') for k in added: print(f'added: {k}') for k in removed: From 56eed87058b730fbc7c2976a1ae1ac5e76585d72 Mon Sep 17 00:00:00 2001 From: Steven Luong Date: Tue, 15 Sep 2020 09:48:38 -0700 Subject: [PATCH 036/129] vmxnet3: gso fixes outbound: wrong header len computation gso size and header length need to be set in the first segment of the chain inbound: EOP may have zero length descriptor to terminate the chain missing endian conversion for ethertype Type: fix Signed-off-by: Steven Luong Change-Id: Iaa003c0e9af3ead4df6c6c0d5772a179d2ff15c4 (cherry picked from commit 007abe751f2ee86528d0ccc005a3da1c90850868) --- src/plugins/vmxnet3/FEATURE.yaml | 1 + src/plugins/vmxnet3/input.c | 20 +++++++++++++------- src/plugins/vmxnet3/output.c | 18 +++++++++++++----- src/plugins/vmxnet3/vmxnet3.c | 3 ++- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/plugins/vmxnet3/FEATURE.yaml b/src/plugins/vmxnet3/FEATURE.yaml index 1e303f6d6ee6..d204659fb34e 100644 --- a/src/plugins/vmxnet3/FEATURE.yaml +++ b/src/plugins/vmxnet3/FEATURE.yaml @@ -4,6 +4,7 @@ maintainer: Steven Luong features: - vmxnet3 device driver to connect to ESXi server, VMWare Fusion, and VMWare Workstation + - Supports GSO. It was tested on ESXi 6.7 description: "vmxnet3 device driver support" state: production properties: [API, CLI, STATS, MULTITHREAD] diff --git a/src/plugins/vmxnet3/input.c b/src/plugins/vmxnet3/input.c index 173ab915b2bf..f182409ac593 100644 --- a/src/plugins/vmxnet3/input.c +++ b/src/plugins/vmxnet3/input.c @@ -269,7 +269,6 @@ vmxnet3_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, b0->flags = 0; b0->error = 0; b0->current_config_index = 0; - ASSERT (b0->current_length != 0); if (PREDICT_FALSE ((rx_comp->index & VMXNET3_RXCI_EOP) && (rx_comp->len & VMXNET3_RXCL_ERROR))) @@ -317,12 +316,19 @@ vmxnet3_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, else if (rx_comp->index & VMXNET3_RXCI_EOP) { /* end of segment */ - if (prev_b0) + if (PREDICT_TRUE (prev_b0 != 0)) { - prev_b0->flags |= VLIB_BUFFER_NEXT_PRESENT; - prev_b0->next_buffer = bi0; - hb->total_length_not_including_first_buffer += - b0->current_length; + if (PREDICT_TRUE (b0->current_length != 0)) + { + prev_b0->flags |= VLIB_BUFFER_NEXT_PRESENT; + prev_b0->next_buffer = bi0; + hb->total_length_not_including_first_buffer += + b0->current_length; + } + else + { + vlib_buffer_free_one (vm, bi0); + } prev_b0 = 0; got_packet = 1; } @@ -387,7 +393,7 @@ vmxnet3_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, ethernet_header_t *e = (ethernet_header_t *) hb->data; next[0] = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT; - if (!ethernet_frame_is_tagged (e->type)) + if (!ethernet_frame_is_tagged (ntohs (e->type))) vmxnet3_handle_offload (rx_comp, hb, gso_size); } diff --git a/src/plugins/vmxnet3/output.c b/src/plugins/vmxnet3/output.c index 81a1afb190c8..4c9b7093f737 100644 --- a/src/plugins/vmxnet3/output.c +++ b/src/plugins/vmxnet3/output.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include @@ -128,6 +130,7 @@ VNET_DEVICE_CLASS_TX_FN (vmxnet3_device_class) (vlib_main_t * vm, { u16 space_needed = 1, i; u32 gso_size = 0; + u32 l4_hdr_sz; vlib_buffer_t *b; u32 hdr_len = 0; @@ -193,8 +196,13 @@ VNET_DEVICE_CLASS_TX_FN (vmxnet3_device_class) (vlib_main_t * vm, */ ASSERT (vd->gso_enable == 1); gso_size = vnet_buffer2 (b0)->gso_size; - hdr_len = vnet_buffer (b0)->l4_hdr_offset + - sizeof (ethernet_header_t); + l4_hdr_sz = vnet_buffer2 (b0)->gso_l4_hdr_sz; + if (b0->flags & VNET_BUFFER_F_IS_IP6) + hdr_len = sizeof (ethernet_header_t) + sizeof (ip6_header_t) + + l4_hdr_sz; + else + hdr_len = sizeof (ethernet_header_t) + sizeof (ip4_header_t) + + l4_hdr_sz; } generation = txq->tx_ring.gen; @@ -202,9 +210,9 @@ VNET_DEVICE_CLASS_TX_FN (vmxnet3_device_class) (vlib_main_t * vm, } if (PREDICT_FALSE (gso_size != 0)) { - txd->flags[1] = hdr_len; - txd->flags[1] |= VMXNET3_TXF_OM (VMXNET3_OM_TSO); - txd->flags[0] |= VMXNET3_TXF_MSSCOF (gso_size); + txq->tx_desc[first_idx].flags[1] = hdr_len; + txq->tx_desc[first_idx].flags[1] |= VMXNET3_TXF_OM (VMXNET3_OM_TSO); + txq->tx_desc[first_idx].flags[0] |= VMXNET3_TXF_MSSCOF (gso_size); } txd->flags[1] |= VMXNET3_TXF_CQ | VMXNET3_TXF_EOP; asm volatile ("":::"memory"); diff --git a/src/plugins/vmxnet3/vmxnet3.c b/src/plugins/vmxnet3/vmxnet3.c index 731a34a99e1b..9209c3e2f906 100644 --- a/src/plugins/vmxnet3/vmxnet3.c +++ b/src/plugins/vmxnet3/vmxnet3.c @@ -809,7 +809,8 @@ vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args) vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vd->hw_if_index); hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE; if (vd->gso_enable) - hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO; + hw->flags |= (VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO | + VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD); vnet_hw_interface_set_input_node (vnm, vd->hw_if_index, vmxnet3_input_node.index); From ef51f3696e0f13cf692f7d55e27f3bb81bb5aff9 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Wed, 16 Sep 2020 21:04:24 +0000 Subject: [PATCH 037/129] build: touch files when extracting rpm tarballs Type: fix - Long story short, intermittently centos jobs have been failing with clock skew issues. When someone commits a patch on a machine with the date ahead of UTC, then clock skew will be encountered when extracting the RPM source tarball. See [0] and [1] for details. - Replace 'make bootstrap' with 'make install-dep' in RPM package build specfile. [0] https://unix.stackexchange.com/questions/164807/does-git-archive-use-the-wrong-file-timestamp [1] https://git.fd.io/vpp/tree/Makefile#n380 Change-Id: Iebfb9eb2e26c1f2e4488e871da86d0c60b9f4048 Signed-off-by: Dave Wallace (cherry picked from commit 27b50fea143f2d45613ef982870cd2052e21fb0f) --- extras/rpm/vpp.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extras/rpm/vpp.spec b/extras/rpm/vpp.spec index 038c10bc9ff4..1bb78af8cf7a 100644 --- a/extras/rpm/vpp.spec +++ b/extras/rpm/vpp.spec @@ -168,7 +168,10 @@ Requires(post): python3-policycoreutils This package contains a tailored VPP SELinux policy %prep -%setup -q -n %{name}-%{_version} +%setup -q -c -T -n %{name}-%{_version} +cd .. +unxz --stdout ./SOURCES/%{name}-%{_version}-%{_release}.tar.xz | tar --extract --touch +cd - %pre # Add the vpp group @@ -179,7 +182,7 @@ groupadd -f -r vpp . /opt/rh/devtoolset-9/enable %endif %if %{with aesni} - make bootstrap + make install-dep make -C build-root PLATFORM=vpp TAG=%{_vpp_tag} install-packages %else make bootstrap AESNI=n From dd49451845c19f803858429b58b1b95298b93fff Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Fri, 18 Sep 2020 20:23:55 +0000 Subject: [PATCH 038/129] build: missing deb pkg on ubuntu-20.04 - The vpp build on the ubuntu-20.04 executor failed due to the package 'dh-python' not getting installed by 'make install-dep' Type: fix Signed-off-by: Dave Wallace Change-Id: Id9307ad1b4e34c413d90258c6bde2aa5afafec63 (cherry picked from commit 5cc11b1210910d6e56025d87688a52111f730469) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cf4cfadecc72..8fd0b91da21a 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ endif # +libganglia1-dev if building the gmond plugin DEB_DEPENDS = curl build-essential autoconf automake ccache -DEB_DEPENDS += debhelper dkms git libtool libapr1-dev dh-systemd +DEB_DEPENDS += debhelper dkms git libtool libapr1-dev dh-systemd dh-python DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config DEB_DEPENDS += lcov chrpath autoconf indent clang-format libnuma-dev DEB_DEPENDS += python3-all python3-setuptools check From d88c9a13e82986b3e3d477beaa7f528e819868b6 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Fri, 18 Sep 2020 15:35:01 +0000 Subject: [PATCH 039/129] build: remove opensuse build infra - VPP on opensuse has not been supported for several releases. Type: fix Signed-off-by: Dave Wallace Change-Id: I2b5316ad5c20a843b8936f4ceb473f932a5338d9 (cherry picked from commit bc35f469c89daf0126937580b6972516b5007d3a) --- Makefile | 49 +-- docs/gettingstarted/index.rst | 2 +- docs/gettingstarted/installing/index.rst | 13 +- docs/gettingstarted/installing/opensuse.rst | 57 ---- docs/reference/vppvagrant/Vagrantfile | 3 - docs/reference/vppvagrant/boxSetup.rst | 3 - doxygen/Makefile | 3 - extras/rpm/Makefile | 11 - extras/rpm/vpp-suse.spec | 325 -------------------- extras/vagrant/Vagrantfile | 3 - extras/vagrant/build.sh | 2 - extras/vagrant/run.sh | 6 +- test/ext/Makefile | 2 +- 13 files changed, 9 insertions(+), 470 deletions(-) delete mode 100644 docs/gettingstarted/installing/opensuse.rst delete mode 100644 extras/rpm/vpp-suse.spec diff --git a/Makefile b/Makefile index 8fd0b91da21a..dd8522294894 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ endif ifeq ($(filter ubuntu debian,$(OS_ID)),$(OS_ID)) PKG=deb -else ifeq ($(filter rhel centos fedora opensuse opensuse-leap opensuse-tumbleweed,$(OS_ID)),$(OS_ID)) +else ifeq ($(filter rhel centos fedora,$(OS_ID)),$(OS_ID)) PKG=rpm endif @@ -147,42 +147,6 @@ RPM_DEPENDS_DEBUG = glibc-debuginfo e2fsprogs-debuginfo RPM_DEPENDS_DEBUG += krb5-debuginfo openssl-debuginfo RPM_DEPENDS_DEBUG += zlib-debuginfo nss-softokn-debuginfo RPM_DEPENDS_DEBUG += yum-plugin-auto-update-debug-info -# lowercase- replace spaces with dashes. -SUSE_NAME= $(shell grep '^NAME=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g' | sed -e 's/ /-/' | awk '{print tolower($$0)}') -SUSE_ID= $(shell grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g' | cut -d' ' -f2) -RPM_SUSE_BUILDTOOLS_DEPS = autoconf automake ccache check-devel chrpath -RPM_SUSE_BUILDTOOLS_DEPS += clang cmake indent libtool make ninja python3-ply - -RPM_SUSE_DEVEL_DEPS = glibc-devel-static libnuma-devel -RPM_SUSE_DEVEL_DEPS += libopenssl-devel openssl-devel mbedtls-devel libuuid-devel - -RPM_SUSE_PYTHON_DEPS = python-devel python3-devel python-pip python3-pip -RPM_SUSE_PYTHON_DEPS += python-rpm-macros python3-rpm-macros - -RPM_SUSE_PLATFORM_DEPS = distribution-release shadow rpm-build - -ifeq ($(OS_ID),opensuse) -ifeq ($(SUSE_NAME),tumbleweed) - RPM_SUSE_DEVEL_DEPS = libboost_headers1_68_0-devel-1.68.0 libboost_thread1_68_0-devel-1.68.0 gcc - RPM_SUSE_PYTHON_DEPS += python3-ply python2-virtualenv -endif -ifeq ($(SUSE_ID),15.0) - RPM_SUSE_DEVEL_DEPS += libboost_headers-devel libboost_thread-devel gcc - RPM_SUSE_PYTHON_DEPS += python3-ply python2-virtualenv -else - RPM_SUSE_DEVEL_DEPS += libboost_headers1_68_0-devel-1.68.0 gcc6 - RPM_SUSE_PYTHON_DEPS += python-virtualenv -endif -endif - -ifeq ($(OS_ID),opensuse-leap) -ifeq ($(SUSE_ID),15.0) - RPM_SUSE_DEVEL_DEPS += libboost_headers-devel libboost_thread-devel gcc git curl - RPM_SUSE_PYTHON_DEPS += python3-ply python2-virtualenv -endif -endif - -RPM_SUSE_DEPENDS += $(RPM_SUSE_BUILDTOOLS_DEPS) $(RPM_SUSE_DEVEL_DEPS) $(RPM_SUSE_PYTHON_DEPS) $(RPM_SUSE_PLATFORM_DEPS) ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),) STARTUP_CONF ?= $(STARTUP_DIR)/startup.conf @@ -343,17 +307,8 @@ else ifeq ($(OS_ID),fedora) @sudo -E dnf install $(CONFIRM) $(RPM_DEPENDS) @sudo -E debuginfo-install $(CONFIRM) glibc openssl-libs mbedtls-devel zlib endif -else ifeq ($(filter opensuse-tumbleweed,$(OS_ID)),$(OS_ID)) - @sudo -E zypper refresh - @sudo -E zypper install -y $(RPM_SUSE_DEPENDS) -else ifeq ($(filter opensuse-leap,$(OS_ID)),$(OS_ID)) - @sudo -E zypper refresh - @sudo -E zypper install -y $(RPM_SUSE_DEPENDS) -else ifeq ($(filter opensuse,$(OS_ID)),$(OS_ID)) - @sudo -E zypper refresh - @sudo -E zypper install -y $(RPM_SUSE_DEPENDS) else - $(error "This option currently works only on Ubuntu, Debian, RHEL, CentOS or openSUSE systems") + $(error "This option currently works only on Ubuntu, Debian, RHEL, or CentOS systems") endif git config commit.template .git_commit_template.txt diff --git a/docs/gettingstarted/index.rst b/docs/gettingstarted/index.rst index 2efe372b4dc2..08fc1cd329ee 100644 --- a/docs/gettingstarted/index.rst +++ b/docs/gettingstarted/index.rst @@ -11,7 +11,7 @@ code that provides tools that are used in a development environment. This section covers the following: -* Describes how to manually install VPP Binaries on different OS platforms (Ubuntu, Centos, openSUSE) and then how to configure and use VPP. +* Describes how to manually install VPP Binaries on different OS platforms (Ubuntu, Centos) and then how to configure and use VPP. * Describes the different types of VPP packages, which are used in both basic and developer installs. * A VPP tutorial which is a great way to learn VPP basics. diff --git a/docs/gettingstarted/installing/index.rst b/docs/gettingstarted/installing/index.rst index 6326247e95a8..b482ea651466 100644 --- a/docs/gettingstarted/installing/index.rst +++ b/docs/gettingstarted/installing/index.rst @@ -10,8 +10,8 @@ Downloading and Installing VPP If you want to use VPP it can be convenient to install the binaries from existing packages. This guide describes how to pull, install and run the VPP packages. -This section provides directions on how to Install VPP binaries on Ubuntu, Centos, -and openSUSE platforms. +This section provides directions on how to Install VPP binaries on +Ubuntu, and Centos platforms. FD.io VPP is installed using Package Cloud. For a complete set of instructions on how to install VPP with package cloud please refer @@ -36,15 +36,6 @@ The following are instructions on how to install VPP on Centos. centos -Installing on openSUSE --------------------------------------- - -The following are instructions on how to install VPP on openSUSE. - -.. toctree:: - - opensuse - Package Descriptions ---------------------------------- diff --git a/docs/gettingstarted/installing/opensuse.rst b/docs/gettingstarted/installing/opensuse.rst deleted file mode 100644 index 6d7873820dc3..000000000000 --- a/docs/gettingstarted/installing/opensuse.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. _opensuse: - -.. toctree:: - -Installing -========== - -To install VPP on openSUSE, first install the following release, and then execute -the associated commands. - -openSUSE Tumbleweed (rolling release) ------------------------------------------------------------- - -.. code-block:: console - - sudo zypper install vpp vpp-plugins - -openSUSE Leap 42.3 --------------------------------- - -.. code-block:: console - - sudo zypper addrepo --name network https://download.opensuse.org/repositories/network/openSUSE_Leap_42.3/network.repo - sudo zypper install vpp vpp-plugins - -Uninstall -========= - -To uninstall the vpp plugins, run the following command: - -.. code-block:: console - - sudo zypper remove -u vpp vpp-plugins - -openSUSE Tumbleweed (rolling release) -------------------------------------- - -To uninstall the openSUSE Tumbleweed, run the following command: - -.. code-block:: console - - sudo zypper remove -u vpp vpp-plugins - -openSUSE Leap 42.3 ------------------- - -.. code-block:: console - - sudo zypper remove -u vpp vpp-plugins - sudo zypper removerepo network - -For More Information -==================== -For more information on VPP with openSUSE, please look at the following post. - -* https://www.suse.com/communities/blog/vector-packet-processing-vpp-opensuse/ - diff --git a/docs/reference/vppvagrant/Vagrantfile b/docs/reference/vppvagrant/Vagrantfile index 457e37c82741..642969faa630 100644 --- a/docs/reference/vppvagrant/Vagrantfile +++ b/docs/reference/vppvagrant/Vagrantfile @@ -9,9 +9,6 @@ Vagrant.configure(2) do |config| config.vm.box = "centos/7" config.vm.box_version = "1708.01" config.ssh.insert_key = false - elsif distro == 'opensuse' - config.vm.box = "opensuse/openSUSE-42.3-x86_64" - config.vm.box_version = "1.0.4.20170726" else config.vm.box = "puppetlabs/ubuntu-16.04-64-nocm" end diff --git a/docs/reference/vppvagrant/boxSetup.rst b/docs/reference/vppvagrant/boxSetup.rst index a8aa1f3c1321..ed20c9d37c16 100644 --- a/docs/reference/vppvagrant/boxSetup.rst +++ b/docs/reference/vppvagrant/boxSetup.rst @@ -34,9 +34,6 @@ Looking at the :ref:`vppVagrantfile`, we can see that the default OS is Ubuntu 1 config.vm.box = "centos/7" config.vm.box_version = "1708.01" config.ssh.insert_key = false - elsif distro == 'opensuse' - config.vm.box = "opensuse/openSUSE-42.3-x86_64" - config.vm.box_version = "1.0.4.20170726" else config.vm.box = "puppetlabs/ubuntu-16.04-64-nocm" diff --git a/doxygen/Makefile b/doxygen/Makefile index 40646148ec6a..e399b404a260 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -35,7 +35,6 @@ OS_ID ?= $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') # Package dependencies DOC_DEB_DEPENDS = doxygen graphviz python3-pyparsing python3-jinja2 DOC_RPM_DEPENDS = doxygen graphviz python3-pyparsing python3-jinja2 -DOC_SUSE_RPM_DEPENDS = doxygen graphviz python3-pyparsing python3-Jinja2 DOC_MAC_BIN_DEPENDS = doxygen dot git DOC_MAC_PY_DEPENDS = pyparsing jinja2 @@ -156,8 +155,6 @@ else ifeq ($(OS_ID),darwin) false; \ ); \ done -else ifeq ($(OS_ID),opensuse) - @sudo zypper install $(CONFIRM) $(DOC_SUSE_RPM_DEPENDS) else $(error "Building documentation currently works only on Ubuntu, CentOS, MacOS and OpenSUSE systems.") endif diff --git a/extras/rpm/Makefile b/extras/rpm/Makefile index 423c4207b020..0736b7f6a4b0 100644 --- a/extras/rpm/Makefile +++ b/extras/rpm/Makefile @@ -26,18 +26,7 @@ PC=% all: RPM -# SUSE rolling-release (a.k.a. Tumbleweed) -ifeq ($(filter opensuse-tumbleweed,$(OS_ID)),$(OS_ID)) -SPEC_FILE='vpp-suse.spec' -# SUSE osleap15 -else ifeq ($(filter opensuse-leap,$(OS_ID)),$(OS_ID)) -SPEC_FILE='vpp-suse.spec' -# SUSE leap42.x -else ifeq ($(filter opensuse,$(OS_ID)),$(OS_ID)) -SPEC_FILE='vpp-suse.spec' -else SPEC_FILE='vpp.spec' -endif spec: @echo $(TARBALL) diff --git a/extras/rpm/vpp-suse.spec b/extras/rpm/vpp-suse.spec deleted file mode 100644 index 4bb354cda90b..000000000000 --- a/extras/rpm/vpp-suse.spec +++ /dev/null @@ -1,325 +0,0 @@ -# -# spec file for package vpp -# -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. -# -# All modifications and additions to the file contributed by third parties -# remain the property of their copyright owners, unless otherwise agreed -# upon. The license for this file, and modifications and additions to the -# file, is the same license as for the pristine package itself (unless the -# license for the pristine package is not an Open Source License, in which -# case the license is the MIT License). An "Open Source License" is a -# license that conforms to the Open Source Definition (Version 1.9) -# published by the Open Source Initiative. - -# Please submit bugfixes or comments via http://bugs.opensuse.org/ -# - - -%define _vpp_build_dir %{buildroot}/../../BUILD/vpp-%{version}/build-root -%define _vpp_install_dir %{_vpp_build_dir}/install-vpp-native/ -%define _vpp_plugins_lib_dir %{_vpp_install_dir}/vpp/lib - -%define lname libvpp0 - -Name: vpp -Version: %{_version} -Release: %{_release} -Summary: Set of libraries and drivers for fast packet processing -License: Apache-2.0 -Group: Productivity/Networking/Routing -Url: https://wiki.fd.io/view/VPP -Source0: %{name}-%{version}-%{_release}.tar.xz -BuildRequires: autoconf -BuildRequires: automake -BuildRequires: bison -BuildRequires: ccache -BuildRequires: check-devel -BuildRequires: chrpath -BuildRequires: distribution-release -BuildRequires: gcc -BuildRequires: gcc-c++ -BuildRequires: glibc-devel -BuildRequires: glibc-devel-static -BuildRequires: libboost_headers-devel -BuildRequires: libboost_thread-devel -BuildRequires: libnuma-devel -BuildRequires: libopenssl-devel -BuildRequires: libtool -BuildRequires: lsb-release -BuildRequires: make -BuildRequires: mbedtls-devel -BuildRequires: openssl-devel -BuildRequires: python-devel -BuildRequires: python-pip -BuildRequires: python-rpm-macros -BuildRequires: python2-ply -BuildRequires: python3-devel -BuildRequires: python3-pip -BuildRequires: shadow -Conflicts: otherproviders(vpp-any) -Provides: %{name}-any = %{version} -ExclusiveArch: x86_64 aarch64 -%if 0%{?suse_version} >= 1210 -BuildRequires: systemd-rpm-macros -%endif - -%description -The Vector Packet Processing platform is a framework that provides -switch/router functionality. It is based on Cisco's packet processing -stack that can run on commodity CPUs. -This package provides VPP executables: vpp, vpp_api_test, vpp_json_test -vpp - the vector packet engine -vpp_api_test - vector packet engine API test tool -vpp_json_test - vector packet engine JSON test tool - -%package -n %{lname} -Summary: VPP libraries -Group: System/Libraries -Provides: %{lname}-any = %{version} - -%description -n %{lname} -This package contains the VPP shared libraries, including: -vppinfra - foundation library supporting vectors, hashes, bitmaps, pools, and string formatting. -svm - vm library -vlib - vector processing library -vlib-api - binary API library -vnet - network stack library - -%package devel -Summary: VPP header files, static libraries -Group: Development/Libraries/C and C++ -Requires: %{lname} = %{version} -Conflicts: otherproviders(%{name}-any-devel) -Provides: %{name}-any-devel = %{version} - -%description devel -This package contains the header files for VPP. -Install this package if you want to write a -program for compilation and linking with vpp lib. -vlib -vlibmemory -vnet - devices, classify, dhcp, ethernet flow, gre, ip, etc. -vpp-api -vppinfra - -%package plugins -Summary: Vector Packet Processing--runtime plugins -Group: Productivity/Networking/Routing -Conflicts: otherproviders(%{name}-any-plugins) -Provides: %{name}-any-plugins = %{version} - -%description plugins -This package contains the VPP plugins which are loaded by VPP at startup - -%package api-lua -Summary: VPP api lua bindings -Group: Development/Libraries/Other -Requires: %{lname} = %{version} -Requires: %{name} = %{version} -Requires: %{name}-devel = %{version} -Conflicts: otherproviders(%{name}-any-api-lua) -Provides: %{name}-any-api-lua = %{version} - -%description api-lua -This package contains the lua bindings for the vpp api - -%package api-python -Summary: VPP api python bindings -Group: Development/Libraries/Python -Requires: %{lname} = %{version} -Requires: %{name} = %{version} -Requires: %{name}-devel = %{version} -Requires: python-setuptools -Conflicts: otherproviders(%{name}-any-python-api) -Provides: %{name}-any-python-api = %{version} - -%description api-python -This package contains the python bindings for the vpp api - -%prep -%setup -q -n %{name}-%{version} - -%build -export VPP_BUILD_USER=suse -export VPP_BUILD_HOST=SUSE - -make -C build-root V=1 CC=gcc-7 CXX=g++-7 PLATFORM=vpp TAG=vpp install-packages - -cd %{_vpp_build_dir}/../src/vpp-api/python && %{py2_build} - -%pre -# Add the vpp group -getent group vpp >/dev/null || groupadd -r vpp -%service_add_pre vpp.service - -%install -# -# binaries -# -mkdir -p -m755 %{buildroot}%{_bindir} -mkdir -p -m755 %{buildroot}%{_unitdir} -install -m 755 %{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir} - -# api -mkdir -p -m755 %{buildroot}%{_datadir}/vpp/api - -# -# core api -# -mkdir -p -m755 %{buildroot}%{_datadir}/vpp/api -install -p -m 644 %{_vpp_install_dir}/vpp/share/vpp/api/core/*.api.json %{buildroot}%{_datadir}/vpp/api - -# -# configs -# -mkdir -p -m755 %{buildroot}%{_sysconfdir}/vpp -mkdir -p -m755 %{buildroot}%{_sysconfdir}/sysctl.d -install -p -m 644 %{_vpp_build_dir}/../extras/rpm/vpp.service %{buildroot}%{_unitdir} -install -p -m 644 %{_vpp_build_dir}/../src/vpp/conf/startup.conf %{buildroot}%{_sysconfdir}/vpp/startup.conf -install -p -m 644 %{_vpp_build_dir}/../src/vpp/conf/80-vpp.conf %{buildroot}%{_sysconfdir}/sysctl.d -# -# libraries -# -mkdir -p -m755 %{buildroot}%{_libdir} -mkdir -p -m755 %{buildroot}%{_sysconfdir}/bash_completion.d -mkdir -p -m755 %{buildroot}%{_datadir}/vpp -for file in $(find %{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*' -print ) -do - install -p -m 755 $file %{buildroot}%{_libdir} -done -for file in $(cd %{buildroot}%{_libdir} && find . -type f -print | sed -e 's/^\.\///') -do - # make lib symlinks - ( cd %{buildroot}%{_libdir} && - ln -fs $file $(echo $file | sed -e 's/\(\.so\.[0-9]\+\).*/\1/') ) - ( cd %{buildroot}%{_libdir} && - ln -fs $file $(echo $file | sed -e 's/\(\.so\)\.[0-9]\+.*/\1/') ) -done -for file in $(find %{_vpp_install_dir}/vpp/share/vpp/api -type f -name '*.api.json' -print ) -do - install -p -m 644 $file %{buildroot}%{_datadir}/vpp/api -done - -# Lua bindings -mkdir -p -m755 %{buildroot}%{_datadir}/doc/vpp/examples/lua/examples/cli -mkdir -p -m755 %{buildroot}%{_datadir}/doc/vpp/examples/lua/examples/lute -for file in $(cd %{_vpp_install_dir}/../../src/vpp-api/lua && git ls-files .) -do - install -p -m 644 %{_vpp_install_dir}/../../src/vpp-api/lua/$file \ - %{buildroot}%{_datadir}/doc/vpp/examples/lua/$file -done - -# Python bindings -cd %{_vpp_build_dir}/../src/vpp-api/python && %{py2_install} - -mkdir -p -m755 %{buildroot}%{python_sitelib}/vpp_papi -for file in $(find %{_vpp_install_dir}/*/lib/python2.7/site-packages/ -type f -print | grep -v pyc | grep -v pyo) -do - install -p -m755 $file %{buildroot}%{python_sitelib}/vpp_papi/ -done -chmod -x %{buildroot}%{python_sitelib}/vpp_papi/*.txt - -# -# devel -# -for dir in %{_vpp_install_dir}/{vom,vpp}/include/ -do - for subdir in $(cd ${dir} && find . -type d -print) - do - mkdir -p -m755 %{buildroot}%{_includedir}/${subdir} - done - for file in $(cd ${dir} && find . -type f -print) - do - install -p -m 644 $dir/$file %{buildroot}%{_includedir}/$file - done -done - -# sample plugin -mkdir -p -m755 %{buildroot}%{_datadir}/doc/vpp/examples/sample-plugin/sample -for file in $(cd %{_vpp_install_dir}/../../sample-plugin && find -type f -print) -do - install -p -m 644 %{_vpp_install_dir}/../../sample-plugin/$file \ - %{buildroot}%{_datadir}/doc/vpp/examples/sample-plugin/$file -done - -# -# vpp-plugins -# -mkdir -p -m755 %{buildroot}%{_libdir}/vpp_plugins -mkdir -p -m755 %{buildroot}%{_libdir}/vpp_api_test_plugins -for file in $(cd %{_vpp_plugins_lib_dir}/vpp_plugins && find -type f -print) -do - install -p -m 644 %{_vpp_plugins_lib_dir}/vpp_plugins/$file \ - %{buildroot}/%{_libdir}/vpp_plugins/$file -done - -for file in $(cd %{_vpp_plugins_lib_dir}/vpp_api_test_plugins && find -type f -print) -do - install -p -m 644 %{_vpp_plugins_lib_dir}/vpp_api_test_plugins/$file \ - %{buildroot}/%{_libdir}/vpp_api_test_plugins/$file -done - -for file in $(find %{_vpp_install_dir}/vpp/share/vpp/api/plugins -type f -name '*.api.json' -print ) -do - install -p -m 644 $file %{buildroot}%{_datadir}/vpp/api -done - -# -# remove RPATH from ELF binaries -# -%{_vpp_build_dir}/scripts/remove-rpath %{buildroot} - -export NO_BRP_CHECK_RPATH=true - -%post -%service_add_post vpp.service - -%post -n %{lname} -p /sbin/ldconfig - -%preun -%service_del_preun vpp.service - -%postun -%service_del_postun vpp.service - -%postun -n %{lname} -p /sbin/ldconfig - -%files -%{_unitdir}/vpp.service -%{_bindir}/vpp* -%{_bindir}/svm* -%dir %{_sysconfdir}/vpp -%config %{_sysconfdir}/sysctl.d/80-vpp.conf -%config %{_sysconfdir}/vpp/startup.conf -%license LICENSE - -%files -n %{lname} -%exclude %{_libdir}/vpp_plugins -%exclude %{_libdir}/vpp_api_test_plugins -%{_libdir}/*.so.* - -%files api-lua -%{_datadir}/doc/vpp/examples/lua - -%files api-python -%dir %{python_sitelib}/vpp_papi* -%{python_sitelib}/vpp_papi* - -%files devel -%dir %{_datadir}/doc/vpp -%dir %{_datadir}/doc/vpp/examples -%{_libdir}/*.so -%{_includedir}/* -%{_datadir}/doc/vpp/examples/sample-plugin -%dir %{_datadir}/vpp -%dir %{_datadir}/vpp/api -%{_datadir}/vpp/api/* - -%files plugins -%dir %{_libdir}/vpp_plugins -%dir %{_libdir}/vpp_api_test_plugins -%{_libdir}/vpp_plugins/*.so* -%{_libdir}/vpp_api_test_plugins/*.so* - -%changelog diff --git a/extras/vagrant/Vagrantfile b/extras/vagrant/Vagrantfile index a97a3dc38fc0..8a2454ae0afc 100644 --- a/extras/vagrant/Vagrantfile +++ b/extras/vagrant/Vagrantfile @@ -9,9 +9,6 @@ Vagrant.configure(2) do |config| config.vm.box = "centos/7" config.vm.box_version = "1708.01" config.ssh.insert_key = false - elsif distro == 'opensuse' - config.vm.box = "opensuse/openSUSE-42.3-x86_64" - config.vm.box_version = "1.0.4.20170726" elsif distro == 'ubuntu1804' config.vm.box = "bento/ubuntu-18.04" else diff --git a/extras/vagrant/build.sh b/extras/vagrant/build.sh index 3a10e707fb9f..ea32ffe90c3c 100755 --- a/extras/vagrant/build.sh +++ b/extras/vagrant/build.sh @@ -66,7 +66,5 @@ elif [ "$OS_ID" == "debian" ]; then elif [ "$OS_ID" == "centos" ]; then (cd $VPP_DIR/vnet ;$SUDOCMD aclocal;$SUDOCMD automake -a) $SUDOCMD make pkg-rpm -elif [ "$OS_ID" == "opensuse" ]; then - $SUDOCMD make pkg-rpm fi diff --git a/extras/vagrant/run.sh b/extras/vagrant/run.sh index 61c9261fe2f2..3e87e259442c 100755 --- a/extras/vagrant/run.sh +++ b/extras/vagrant/run.sh @@ -1,16 +1,16 @@ #!/bin/bash # Figure out what system we are running on -if [ "$(uname)" <> "Darwin" ]; then +if [ "$(uname)" <> "Darwin" ] ; then OS_ID=$(grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') OS_VERSION_ID=$(grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') fi -if [ "$OS_ID" == "ubuntu" ]; then +if [ "$OS_ID" == "ubuntu" ] ; then $OS_CODENAME=$UBUNTU_CODENAME fi -if [ "$OS_ID" == "centos" ] || [ "$OS_ID" == "opensuse" ]; then +if [ "$OS_ID" == "centos" ] ; then # Install uio-pci-generic sudo -E modprobe uio_pci_generic fi diff --git a/test/ext/Makefile b/test/ext/Makefile index d7acb7bc2b28..a0dc3e7736ca 100644 --- a/test/ext/Makefile +++ b/test/ext/Makefile @@ -8,7 +8,7 @@ VAPI_LIBS = \ -L$(VPP_INSTALL_PATH)/vpp/lib \ -lvppinfra -lvlibmemoryclient -lsvm -lpthread -lcheck -lrt -lm -lvapiclient -ifneq ($(filter centos opensuse opensuse-tumbleweed opensuse-leap,$(OS_ID)),$(OS_ID)) +ifneq ($(filter centos,$(OS_ID)),$(OS_ID)) VAPI_LIBS += -lsubunit endif From d69b12a7bf1c5d5e8e8ae1d986ee756ad9bfd07e Mon Sep 17 00:00:00 2001 From: Yulong Pei Date: Mon, 21 Sep 2020 13:41:56 -0700 Subject: [PATCH 040/129] crypto: revert crypto set handler all API This reverts commit 8c91b2ae2b32d428ef35605707788fe064621cb3, but keep a comment fix. Type: fix Signed-off-by: Yulong Pei Change-Id: Ia66941bf18d3efac96f41bdf905d877cfb3ab211 (cherry picked from commit 6816c3b3df8c91a319cca56784dca07f842ef178) --- src/vnet/crypto/crypto_api.c | 39 +++--------------------------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/src/vnet/crypto/crypto_api.c b/src/vnet/crypto/crypto_api.c index 8766614c02d9..49b12a3d377b 100644 --- a/src/vnet/crypto/crypto_api.c +++ b/src/vnet/crypto/crypto_api.c @@ -54,7 +54,6 @@ vl_api_crypto_set_async_dispatch_t_handler (vl_api_crypto_set_async_dispatch_t static void vl_api_crypto_set_handler_t_handler (vl_api_crypto_set_handler_t * mp) { - vnet_crypto_main_t *cm = &crypto_main; vl_api_crypto_set_handler_reply_t *rmp; int rv = 0; char *engine; @@ -65,42 +64,10 @@ vl_api_crypto_set_handler_t_handler (vl_api_crypto_set_handler_t * mp) alg_name = (char *) mp->alg_name; oct = (crypto_op_class_type_t) mp->oct; - if (strcmp ("all", alg_name) == 0) - { - if (mp->is_async) - { - char *key; - u8 *value; - - /* *INDENT-OFF* */ - hash_foreach_mem (key, value, cm->async_alg_index_by_name, - ({ - (void) value; - rv += vnet_crypto_set_async_handler2 (key, engine); - })); - /* *INDENT-ON* */ - } - else - { - char *key; - u8 *value; - - /* *INDENT-OFF* */ - hash_foreach_mem (key, value, cm->alg_index_by_name, - ({ - (void) value; - rv += vnet_crypto_set_handler2 (key, engine, oct); - })); - /* *INDENT-ON* */ - } - } + if (mp->is_async) + rv = vnet_crypto_set_async_handler2 (alg_name, engine); else - { - if (mp->is_async) - rv = vnet_crypto_set_async_handler2 (alg_name, engine); - else - rv = vnet_crypto_set_handler2 (alg_name, engine, oct); - } + rv = vnet_crypto_set_handler2 (alg_name, engine, oct); REPLY_MACRO (VL_API_CRYPTO_SET_HANDLER_REPLY); } From f72b1aff7d9cc90b22291dadd684435ebbefa789 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 22 Sep 2020 11:24:18 +0000 Subject: [PATCH 041/129] vxlan-gbp: Mark APIs as in-progress Type: fix The GBP plugin that uses this module is also in-ptogress, hence so is this module. Signed-off-by: Neale Ranns Change-Id: I3cb5dd124afac05da013d92d67b2abf6cdf9b769 (cherry picked from commit b468773aa4164bf52e0751fdf780f67248037cc0) --- src/vnet/vxlan-gbp/vxlan_gbp.api | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vnet/vxlan-gbp/vxlan_gbp.api b/src/vnet/vxlan-gbp/vxlan_gbp.api index c3a8845dec34..685666970003 100644 --- a/src/vnet/vxlan-gbp/vxlan_gbp.api +++ b/src/vnet/vxlan-gbp/vxlan_gbp.api @@ -56,6 +56,7 @@ define vxlan_gbp_tunnel_add_del u32 context; bool is_add [default=true]; vl_api_vxlan_gbp_tunnel_t tunnel; + option in_progress; }; define vxlan_gbp_tunnel_add_del_reply @@ -63,6 +64,7 @@ define vxlan_gbp_tunnel_add_del_reply u32 context; i32 retval; vl_api_interface_index_t sw_if_index; + option in_progress; }; define vxlan_gbp_tunnel_dump @@ -70,12 +72,14 @@ define vxlan_gbp_tunnel_dump u32 client_index; u32 context; vl_api_interface_index_t sw_if_index [default=0xffffffff]; + option in_progress; }; define vxlan_gbp_tunnel_details { u32 context; vl_api_vxlan_gbp_tunnel_t tunnel; + option in_progress; }; /** \brief Interface set vxlan-bypass request @@ -92,4 +96,5 @@ autoreply define sw_interface_set_vxlan_gbp_bypass vl_api_interface_index_t sw_if_index; bool is_ipv6; bool enable [default=true]; + option in_progress; }; From 73903d7e8a6141237637b2011386c7ee6ac969ee Mon Sep 17 00:00:00 2001 From: Mohammed Hawari Date: Tue, 15 Sep 2020 14:05:11 +0200 Subject: [PATCH 042/129] dpdk: call the meson-based build instead of Makefiles Type: feature Signed-off-by: Mohammed Hawari Change-Id: I576d92605da6d43e9b9f12238b18a518a0d69385 (cherry picked from commit 4c4633cad1019d9aa28669ddfedc612f768d71a8) --- build/external/packages/dpdk.mk | 403 ++++++------------ .../0002-build-system-selective-libs.patch | 88 ++++ 2 files changed, 220 insertions(+), 271 deletions(-) create mode 100644 build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch diff --git a/build/external/packages/dpdk.mk b/build/external/packages/dpdk.mk index beabf48e94ea..ef84383d55a7 100644 --- a/build/external/packages/dpdk.mk +++ b/build/external/packages/dpdk.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Cisco and/or its affiliates. +# Copyright (c) 2020 Cisco and/or its affiliates. # 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: @@ -12,295 +12,156 @@ # limitations under the License. DPDK_PKTMBUF_HEADROOM ?= 128 -DPDK_CACHE_LINE_SIZE ?= 64 -DPDK_DOWNLOAD_DIR ?= $(DL_CACHE_DIR) DPDK_DEBUG ?= n -DPDK_AARCH64_GENERIC ?= y DPDK_MLX4_PMD ?= n DPDK_MLX5_PMD ?= n +DPDK_MLX5_COMMON_PMD ?= n DPDK_TAP_PMD ?= n DPDK_FAILSAFE_PMD ?= n +DPDK_MACHINE ?= default -DPDK_VERSION ?= 20.08 -DPDK_BASE_URL ?= http://fast.dpdk.org/rel -DPDK_TARBALL := dpdk-$(DPDK_VERSION).tar.xz -DPDK_TAR_URL := $(DPDK_BASE_URL)/$(DPDK_TARBALL) -DPDK_18.11_TARBALL_MD5_CKSUM := 04b86f4a77f4f81a7fbd26467dd2ea9f -DPDK_20.05_TARBALL_MD5_CKSUM := 7c6f3e7f7de2422775c4cba116012c4d -DPDK_20.08_TARBALL_MD5_CKSUM := 64badd32cd6bc0761befc8f2402c2148 -MACHINE=$(shell uname -m) +dpdk_version ?= 20.08 +dpdk_base_url ?= http://fast.dpdk.org/rel +dpdk_tarball := dpdk-$(dpdk_version).tar.xz +dpdk_tarball_md5sum_20.08 := 64badd32cd6bc0761befc8f2402c2148 +dpdk_tarball_md5sum := $(dpdk_tarball_md5sum_$(dpdk_version)) +dpdk_url := $(dpdk_base_url)/$(dpdk_tarball) +dpdk_tarball_strip_dirs := 1 -# replace dot with space, and if 3rd word exists we deal with stable dpdk rel -ifeq ($(word 3,$(subst ., ,$(DPDK_VERSION))),) -DPDK_SOURCE := $(B)/dpdk-$(DPDK_VERSION) -else -DPDK_SOURCE := $(B)/dpdk-stable-$(DPDK_VERSION) -endif - -ifeq ($(MACHINE),$(filter $(MACHINE),x86_64)) - AESNI ?= y - DPDK_BUILD_DEPS := ipsec-mb-install -else - AESNI ?= n -endif - -ifneq (,$(findstring clang,$(CC))) -DPDK_CC=clang -else ifneq (,$(findstring icc,$(CC))) -DPDK_CC=icc -else -DPDK_CC=gcc -endif - -############################################################################## -# Intel x86 -############################################################################## -ifeq ($(MACHINE),$(filter $(MACHINE),x86_64 i686)) -DPDK_TARGET ?= $(MACHINE)-native-linuxapp-$(DPDK_CC) -DPDK_MACHINE ?= nhm -DPDK_TUNE ?= core-avx2 - -############################################################################## -# ARM64 -############################################################################## -else ifeq ($(MACHINE),aarch64) -CROSS := -export CROSS -DPDK_TARGET ?= arm64-armv8a-linuxapp-$(DPDK_CC) -DPDK_MACHINE ?= armv8a -DPDK_TUNE ?= generic -ifeq (y, $(DPDK_AARCH64_GENERIC)) -DPDK_CACHE_LINE_SIZE := 128 -# assign aarch64 variant specific options -else -CPU_IMP_ARM = 0x41 -CPU_IMP_CAVIUM = 0x43 - -CPU_PART_ARM_CORTEX_A53 = 0xd03 -CPU_PART_ARM_CORTEX_A57 = 0xd07 -CPU_PART_ARM_CORTEX_A72 = 0xd08 -CPU_PART_ARM_CORTEX_A73 = 0xd09 - -CPU_PART_CAVIUM_THUNDERX = 0x0a1 -CPU_PART_CAVIUM_THUNDERX_81XX = 0x0a2 -CPU_PART_CAVIUM_THUNDERX_83XX = 0x0a3 +# Debug or release -MIDR_IMPLEMENTER=$(shell awk '/implementer/ {print $$4;exit}' /proc/cpuinfo) -MIDR_PARTNUM=$(shell awk '/part/ {print $$4;exit}' /proc/cpuinfo) - -ifeq ($(MIDR_IMPLEMENTER),$(CPU_IMP_ARM)) -############################################################################## -# Arm Cortex -############################################################################## -CPU_PART_ARM_TUNE := $(CPU_PART_ARM_CORTEX_A53)/cortex-a53 \ - $(CPU_PART_ARM_CORTEX_A57)/cortex-a57 \ - $(CPU_PART_ARM_CORTEX_A72)/cortex-a72 \ - $(CPU_PART_ARM_CORTEX_A73)/cortex-a73 -CPU_TUNE = $(notdir $(filter $(MIDR_PARTNUM)/%,$(CPU_PART_ARM_TUNE))) -ifneq ($(CPU_TUNE),) -DPDK_TUNE = $(CPU_TUNE) -else -$(warning Unknown Arm CPU) +DPDK_BUILD_TYPE:=release +ifeq ($(DPDK_DEBUG), y) +DPDK_BUILD_TYPE:=debug endif -else ifeq ($(MIDR_IMPLEMENTER),$(CPU_IMP_CAVIUM)) -############################################################################## -# Cavium ThunderX -############################################################################## -ifneq (,$(findstring $(MIDR_PARTNUM),$(CPU_PART_CAVIUM_THUNDERX) \ - $(CPU_PART_CAVIUM_THUNDERX_81XX) $(CPU_PART_CAVIUM_THUNDERX_83XX))) -DPDK_TARGET = arm64-thunderx-linuxapp-$(DPDK_CC) -DPDK_MACHINE = thunderx -DPDK_CACHE_LINE_SIZE := 128 -else -$(warning Unknown Cavium CPU) +DPDK_DRIVERS_DISABLED := baseband/\*, \ + bus/dpaa, \ + bus/ifpga, \ + compress/\*, \ + crypto/ccp, \ + crypto/dpaa_sec, \ + crypto/openssl, \ + event/\*, \ + mempool/dpaa, \ + net/af_packet, \ + net/bnx2x, \ + net/bonding, \ + net/ipn3ke, \ + net/liquidio, \ + net/pcap, \ + net/pfe, \ + net/sfc, \ + net/softnic, \ + net/thunderx, \ + raw/ifpga, \ + net/af_xdp + +DPDK_LIBS_DISABLED := acl, \ + bbdev, \ + bitratestats, \ + bpf, \ + cfgfile, \ + distributor, \ + efd, \ + fib, \ + flow_classify, \ + graph, \ + gro, \ + gso, \ + jobstats, \ + kni, \ + latencystats, \ + lpm, \ + member, \ + node, \ + pipeline, \ + port, \ + power, \ + rawdev, \ + rib, \ + table + +# Adjust disabled pmd and libs depending on user provided variables +ifeq ($(DPDK_MLX4_PMD), n) + DPDK_DRIVERS_DISABLED += ,net/mlx4 endif +ifeq ($(DPDK_MLX5_PMD), n) + DPDK_DRIVERS_DISABLED += ,net/mlx5 endif - -# finish of assigning aarch64 variant specific options +ifeq ($(DPDK_MLX5_COMMON_PMD), n) + DPDK_DRIVERS_DISABLED += ,common/mlx5 endif - -############################################################################## -# Unknown platform -############################################################################## -else -$(error Unknown platform) +ifeq ($(DPDK_TAP_PMD), n) + DPDK_DRIVERS_DISABLED += ,net/tap endif - -# compiler/linker custom arguments -ifeq ($(DPDK_CC),clang) -DPDK_CPU_CFLAGS := -fPIE -fPIC -else -DPDK_CPU_CFLAGS := -pie -fPIC +ifeq ($(DPDK_FAILSAFE_PMD), n) + DPDK_DRIVERS_DISABLED += ,net/failsafe endif -ifeq ($(DPDK_DEBUG),n) -DPDK_EXTRA_CFLAGS := -g -mtune=$(DPDK_TUNE) -else -DPDK_EXTRA_CFLAGS := -g -O0 -endif - -# -Wimplicit-fallthrough was introduced starting from GCC 7, -# and it requires newer version of ccache. -# Disable fallthrough warning for old ccache version. -ifeq ($(DPDK_CC),gcc) -GCC_VER_V = "7.0.0" -CCACHE_VER_V = "3.4.1" -GCC_VER = $(shell gcc --version | grep ^gcc | sed 's/^.* //g') -CCACHE_VER = $(shell ccache --version | grep ^ccache | sed 's/^.* //g') -ifeq ($(shell expr "$(GCC_VER)" ">=" "$(GCC_VER_V)"),1) -ifeq ($(shell expr "$(CCACHE_VER)" "<" "$(CCACHE_VER_V)"),1) -DPDK_EXTRA_CFLAGS += -Wimplicit-fallthrough=0 -endif -endif -endif - -DPDK_EXTRA_CFLAGS += -I$(I)/include -DPDK_EXTRA_LDFLAGS += -L$(I)/lib - -# assemble DPDK make arguments -DPDK_MAKE_ARGS := -C $(DPDK_SOURCE) -j $(JOBS) \ - T=$(DPDK_TARGET) \ - RTE_CONFIG_TEMPLATE=../custom-config \ - EXTRA_CFLAGS="$(DPDK_EXTRA_CFLAGS)" \ - EXTRA_LDFLAGS="$(DPDK_EXTRA_LDFLAGS)" \ - CPU_CFLAGS="$(DPDK_CPU_CFLAGS)" \ - DESTDIR=$(I) \ - MAKE_PAUSE=n \ - $(DPDK_MAKE_EXTRA_ARGS) - -define set -@if grep -q CONFIG_$1 $@ ; \ - then sed -i -e 's/.*\(CONFIG_$1=\).*/\1$2/' $@ ; \ - else echo CONFIG_$1=$2 >> $@ ; \ +# Sanitize DPDK_DRIVERS_DISABLED and DPDK_LIBS_DISABLED +DPDK_DRIVERS_DISABLED := $(shell echo $(DPDK_DRIVERS_DISABLED) | tr -d '\\\t ') +DPDK_LIBS_DISABLED := $(shell echo $(DPDK_LIBS_DISABLED) | tr -d '\\\t ') + +HASH := \# +# post-meson-setup snippet to alter rte_build_config.h +define dpdk_config +if grep -q RTE_$(1) $(dpdk_src_dir)/config/rte_config.h ; then \ +sed -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ + $(dpdk_src_dir)/config/rte_config.h; \ +elif grep -q RTE_$(1) $(dpdk_build_dir)/rte_build_config.h ; then \ +sed -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ + $(dpdk_build_dir)/rte_build_config.h; \ +else \ +echo '$(HASH)define RTE_$(1) $(DPDK_$(1))' \ + >> $(dpdk_build_dir)/rte_build_config.h ; \ fi endef -$(B)/custom-config: $(B)/.dpdk-patch.ok Makefile - @echo --- generating custom config from $(DPDK_SOURCE)/config/defconfig_$(DPDK_TARGET) --- - @cpp -undef -ffreestanding -x assembler-with-cpp $(DPDK_SOURCE)/config/defconfig_$(DPDK_TARGET) $@ - $(call set,RTE_MACHINE,$(DPDK_MACHINE)) - @# modify options - $(call set,RTE_MAX_LCORE,256) - $(call set,RTE_PKTMBUF_HEADROOM,$(DPDK_PKTMBUF_HEADROOM)) - $(call set,RTE_CACHE_LINE_SIZE,$(DPDK_CACHE_LINE_SIZE)) - $(call set,RTE_BUILD_COMBINE_LIBS,y) - $(call set,RTE_PCI_CONFIG,y) - $(call set,RTE_PCI_EXTENDED_TAG,"on") - $(call set,RTE_PCI_MAX_READ_REQUEST_SIZE,4096) - $(call set,RTE_LIBRTE_PMD_BOND,n) - $(call set,RTE_LIBRTE_IP_FRAG,y) - $(call set,RTE_LIBRTE_PMD_QAT,y) - $(call set,RTE_LIBRTE_PMD_QAT_SYM,y) - $(call set,RTE_LIBRTE_PMD_AESNI_MB,$(AESNI)) - $(call set,RTE_LIBRTE_PMD_AESNI_GCM,$(AESNI)) - $(call set,RTE_LIBRTE_MLX4_PMD,$(DPDK_MLX4_PMD)) - $(call set,RTE_LIBRTE_MLX5_PMD,$(DPDK_MLX5_PMD)) - $(call set,RTE_LIBRTE_BNXT_PMD,y) - $(call set,RTE_LIBRTE_PMD_SOFTNIC,n) - $(call set,RTE_IBVERBS_LINK_DLOPEN,y) - $(call set,RTE_LIBRTE_PMD_TAP,$(DPDK_TAP_PMD)) - $(call set,RTE_LIBRTE_GSO,$(DPDK_TAP_PMD)) - $(call set,RTE_LIBRTE_PMD_FAILSAFE,$(DPDK_FAILSAFE_PMD)) - @# not needed - $(call set,RTE_ETHDEV_RXTX_CALLBACKS,n) - $(call set,RTE_LIBRTE_CFGFILE,n) - $(call set,RTE_LIBRTE_LPM,n) - $(call set,RTE_LIBRTE_ACL,n) - $(call set,RTE_LIBRTE_JOBSTATS,n) - $(call set,RTE_LIBRTE_EFD,n) - $(call set,RTE_LIBRTE_MEMBER,n) - $(call set,RTE_LIBRTE_BITRATE,n) - $(call set,RTE_LIBRTE_LATENCY_STATS,n) - $(call set,RTE_LIBRTE_POWER,n) - $(call set,RTE_LIBRTE_DISTRIBUTOR,n) - $(call set,RTE_LIBRTE_PORT,n) - $(call set,RTE_LIBRTE_TABLE,n) - $(call set,RTE_LIBRTE_PIPELINE,n) - $(call set,RTE_LIBRTE_PMD_SOFTNIC,n) - $(call set,RTE_LIBRTE_FLOW_CLASSIFY,n) - $(call set,RTE_LIBRTE_ACL,n) - $(call set,RTE_LIBRTE_GRO,n) - $(call set,RTE_LIBRTE_KNI,n) - $(call set,RTE_LIBRTE_BPF,n) - $(call set,RTE_LIBRTE_RAWDEV,n) - $(call set,RTE_LIBRTE_PMD_IFPGA_RAWDEV,n) - $(call set,RTE_LIBRTE_IPN3KE_PMD,n) - $(call set,RTE_LIBRTE_IFPGA_BUS,n) - $(call set,RTE_LIBRTE_BBDEV,n) - $(call set,RTE_LIBRTE_BBDEV_NULL,n) - $(call set,RTE_LIBRTE_GRAPH,n) - $(call set,RTE_LIBRTE_NODE,n) - $(call set,RTE_LIBRTE_FIB,n) - $(call set,RTE_LIBRTE_RIB,n) - $(call set,RTE_TEST_PMD,n) - $(call set,RTE_KNI_KMOD,n) - $(call set,RTE_EAL_IGB_UIO,n) - @# currently broken in 18.02 - $(call set,RTE_LIBRTE_DPAA_BUS,n) - $(call set,RTE_LIBRTE_DPAA_MEMPOOL,n) - $(call set,RTE_LIBRTE_DPAA_PMD,n) - $(call set,RTE_LIBRTE_PMD_DPAA_SEC,n) - $(call set,RTE_LIBRTE_PMD_DPAA_EVENTDEV,n) - @rm -f .dpdk-config.ok - -DPDK_DOWNLOADS = $(CURDIR)/downloads/$(DPDK_TARBALL) - -$(DPDK_DOWNLOADS): - mkdir -p downloads - @if [ -e $(DPDK_DOWNLOAD_DIR)/$(DPDK_TARBALL) ] ; \ - then cp $(DPDK_DOWNLOAD_DIR)/$(DPDK_TARBALL) $@ ; \ - else curl -o $@ -LO $(DPDK_TAR_URL) ; \ - fi - @rm -f $(B)/.dpdk-download.ok - -$(B)/.dpdk-download.ok: $(DPDK_DOWNLOADS) - @mkdir -p $(B) - @openssl md5 $< | cut -f 2 -d " " - > $(B)/$(DPDK_TARBALL).md5sum - @([ "$$(<$(B)/$(DPDK_TARBALL).md5sum)" = "$(DPDK_$(DPDK_VERSION)_TARBALL_MD5_CKSUM)" ] || \ - ( echo "Bad Checksum! Please remove $< and retry" && \ - rm $(B)/$(DPDK_TARBALL).md5sum && false )) - @touch $@ - -.PHONY: dpdk-download -dpdk-download: $(B)/.dpdk-download.ok - -$(B)/.dpdk-extract.ok: $(B)/.dpdk-download.ok - @echo --- extracting $(DPDK_TARBALL) --- - @tar --directory $(B) --extract --file $(DPDK_DOWNLOADS) - @touch $@ - -.PHONY: dpdk-extract -dpdk-extract: $(B)/.dpdk-extract.ok - -$(B)/.dpdk-patch.ok: $(B)/.dpdk-extract.ok -ifneq ($(wildcard $(CURDIR)/patches/dpdk_$(DPDK_VERSION)/*.patch),) - @echo --- patching --- - @for f in $(CURDIR)/patches/dpdk_$(DPDK_VERSION)/*.patch ; do \ - echo Applying patch: $$(basename $$f) ; \ - patch -p1 -d $(DPDK_SOURCE) < $$f ; \ - done -endif - @touch $@ - -.PHONY: dpdk-patch -dpdk-patch: $(B)/.dpdk-patch.ok - -$(B)/.dpdk-config.ok: $(B)/.dpdk-patch.ok $(B)/custom-config - @make $(DPDK_MAKE_ARGS) config - @touch $@ - -.PHONY: dpdk-config -dpdk-config: $(B)/.dpdk-config.ok +DPDK_MESON_ARGS = \ + --default-library static \ + --libdir lib \ + --prefix $(dpdk_install_dir) \ + -Dtests=false \ + "-Ddisable_drivers=$(DPDK_DRIVERS_DISABLED)" \ + "-Ddisable_libs=$(DPDK_LIBS_DISABLED)" \ + -Db_pie=true \ + -Dmachine=$(DPDK_MACHINE) \ + --buildtype=$(DPDK_BUILD_TYPE) + +define dpdk_config_cmds + cd $(dpdk_build_dir) && \ + rm -rf ../dpdk-meson-venv && \ + mkdir -p ../dpdk-meson-venv && \ + python3 -m venv ../dpdk-meson-venv && \ + source ../dpdk-meson-venv/bin/activate && \ + pip3 install meson==0.54 && \ + meson setup $(dpdk_src_dir) \ + $(dpdk_build_dir) \ + $(DPDK_MESON_ARGS) \ + | tee $(dpdk_config_log) && \ + deactivate && \ + echo "DPDK post meson configuration" && \ + echo "Altering rte_build_config.h" && \ + $(call dpdk_config,PKTMBUF_HEADROOM) +endef -$(B)/.dpdk-build.ok: dpdk-config $(DPDK_BUILD_DEPS) - @if [ ! -e $(B)/.dpdk-config.ok ] ; then echo 'Please run "make config" first' && false ; fi - @rm -f $(B)/.*.install.ok #deals with build-root/Makefile line 709 - @make $(DPDK_MAKE_ARGS) install - @touch $@ +define dpdk_build_cmds + cd $(dpdk_build_dir) && \ + source ../dpdk-meson-venv/bin/activate && \ + meson compile -C . | tee $(dpdk_build_log) && \ + deactivate +endef -.PHONY: dpdk-build -dpdk-build: $(B)/.dpdk-build.ok +define dpdk_install_cmds + cd $(dpdk_build_dir) && \ + source ../dpdk-meson-venv/bin/activate && \ + meson install && \ + cd $(dpdk_install_dir)/lib && \ + echo "GROUP ( $$(ls librte*.a ) )" > libdpdk.a && \ + rm -rf librte*.so librte*.so.* dpdk/*/librte*.so dpdk/*/librte*.so.* && \ + deactivate && \ + rm -rf $(dpdk_build_dir)/../dpdk-meson-venv +endef -.PHONY: dpdk-install -dpdk-install: $(B)/.dpdk-build.ok +$(eval $(call package,dpdk)) diff --git a/build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch b/build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch new file mode 100644 index 000000000000..62094846a3e0 --- /dev/null +++ b/build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch @@ -0,0 +1,88 @@ +diff --git a/app/meson.build b/app/meson.build +index eb74f215a..93affefa3 100644 +--- a/app/meson.build ++++ b/app/meson.build +@@ -42,7 +42,17 @@ foreach app:apps + + subdir(name) + +- if build ++ foreach d:deps ++ if dpdk_libs_disabled.contains(d) ++ build = false ++ reason = 'missing dependency, "@0@" '.format (d) ++ endif ++ endforeach ++ ++ if not build ++ dpdk_apps_disabled += name ++ set_variable(name.underscorify() + '_disable_reason', reason) ++ else + dep_objs = [] + foreach d:deps + dep_objs += get_variable(get_option('default_library') +diff --git a/lib/meson.build b/lib/meson.build +index 3852c0156..76996544d 100644 +--- a/lib/meson.build ++++ b/lib/meson.build +@@ -44,6 +44,8 @@ if is_windows + ] # only supported libraries for windows + endif + ++disabled_libs = get_option('disable_libs').split(',') ++ + default_cflags = machine_args + default_cflags += ['-DALLOW_EXPERIMENTAL_API'] + default_cflags += ['-DALLOW_INTERNAL_API'] +@@ -78,6 +80,11 @@ foreach l:libraries + dir_name = 'librte_' + l + subdir(dir_name) + ++ if disabled_libs.contains(l) ++ build = false ++ reason = 'Explicitly disabled via build config' ++ endif ++ + if build + shared_deps = ext_deps + static_deps = ext_deps +diff --git a/meson.build b/meson.build +index 61d9a4f5f..cf04f0e0e 100644 +--- a/meson.build ++++ b/meson.build +@@ -21,6 +21,7 @@ dpdk_drivers = [] + dpdk_extra_ldflags = [] + dpdk_libs_disabled = [] + dpdk_drvs_disabled = [] ++dpdk_apps_disabled = [] + abi_version_file = files('ABI_VERSION') + + if host_machine.cpu_family().startswith('x86') +@@ -106,6 +107,14 @@ foreach class:dpdk_driver_classes + endforeach + message(output_message + '\n') + ++output_message = '\n===============\nApplications Disabled\n===============\n' ++foreach app:dpdk_apps_disabled ++ reason = get_variable(app.underscorify() + '_disable_reason') ++ output_message += app + ':\t' + reason + '\n\t' ++endforeach ++ ++message(output_message + '\n') ++ + output_message = '\n=================\nContent Skipped\n=================\n' + output_message += '\nlibs:\n\t' + foreach lib:dpdk_libs_disabled +diff --git a/meson_options.txt b/meson_options.txt +index 9bf18ab6b..d1aa46b8d 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -4,6 +4,8 @@ option('armv8_crypto_dir', type: 'string', value: '', + description: 'path to the armv8_crypto library installation directory') + option('disable_drivers', type: 'string', value: '', + description: 'Comma-separated list of drivers to explicitly disable.') ++option('disable_libs', type: 'string', value: '', ++ description: 'Comma-separated list of libs to explicitly disable.') + option('drivers_install_subdir', type: 'string', value: 'dpdk/pmds-', + description: 'Subdirectory of libdir where to install PMDs. Defaults to using a versioned subdirectory.') + option('enable_docs', type: 'boolean', value: false, From 1aa63b83f90487db5a4fb9953d284f796801608f Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Tue, 22 Sep 2020 16:04:35 +0000 Subject: [PATCH 043/129] build: allow for rc3/rc4 style tags Historically, there was only rc1/rc2 tags, fix in case we tag rc3/rc4 during longer release windows. Type: fix Change-Id: I4243a1c03663a877f96a06d647e89adb74abd977 Signed-off-by: Andrew Yourtchenko (cherry picked from commit bc31247c921d9bad94f2d4aeca9041aee518e7a6) --- src/scripts/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/version b/src/scripts/version index 7e7711637cb0..455ab760352a 100755 --- a/src/scripts/version +++ b/src/scripts/version @@ -36,7 +36,7 @@ if [ -z "${POINT}" ]; then # verify that we are not: # - directly on the XX.YY tag (then ADD will equal "0" by its construction) # - not on any of the builds past "-rc[123]" but before releases - then ADD will be "rc[123]" - if [ "${ADD}" != "0" -a "${ADD}" != "rc0" -a "${ADD}" != "rc1" -a "${ADD}" != "rc2" ]; then + if [ "${ADD}" != "0" -a "${ADD}" != "rc0" -a "${ADD}" != "rc1" -a "${ADD}" != "rc2" -a "${ADD}" != "rc3" -a "${ADD}" != "rc4" ]; then TAG="${TAG}.0" fi fi From 226e8e65bc378ac63af3c88bb51c0c79d5a075d1 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Tue, 22 Sep 2020 15:11:51 +0000 Subject: [PATCH 044/129] vppapigen: crcchecker: harmonize the in_progress marking The format for deprecation is "option deprecated" now, so harmonize the in-progress marking to logically be "option in_progress" At the same time recognize the legacy/erroneous types of marking, print the warning. Change-Id: If418dfadd69ffb112550164d63d13420e51cefd7 Type: fix Signed-off-by: Andrew Yourtchenko (cherry picked from commit 6a3d4cc9a11efbe73a1cda35a64c619eebde0b24) --- extras/scripts/crcchecker.py | 20 ++++++++++++----- extras/scripts/tests/test_crcchecker.sh | 30 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/extras/scripts/crcchecker.py b/extras/scripts/crcchecker.py index 7929374c5c8d..2b026338129f 100755 --- a/extras/scripts/crcchecker.py +++ b/extras/scripts/crcchecker.py @@ -96,16 +96,24 @@ def filelist_from_patchset(): return set(filelist) def is_deprecated(d, k): - if 'options' in d[k] and 'deprecated' in d[k]['options']: - return True + if 'options' in d[k]: + if 'deprecated' in d[k]['options']: + return True + # recognize the deprecated format + if 'status' in d[k]['options'] and d[k]['options']['status'] == 'deprecated': + print("WARNING: please use 'option deprecated;'") + return True return False def is_in_progress(d, k): - try: - if d[k]['options']['status'] == 'in_progress': + if 'options' in d[k]: + if 'in_progress' in d[k]['options']: + return True + # recognize the deprecated format + if 'status' in d[k]['options'] and d[k]['options']['status'] == 'in_progress': + print("WARNING: please use 'option in_progress;'") return True - except: - return False + return False def report(new, old): added, removed, modified, same = dict_compare(new, old) diff --git a/extras/scripts/tests/test_crcchecker.sh b/extras/scripts/tests/test_crcchecker.sh index 07b6bbf7f4b7..9cfc66ae5232 100755 --- a/extras/scripts/tests/test_crcchecker.sh +++ b/extras/scripts/tests/test_crcchecker.sh @@ -77,6 +77,29 @@ git add crccheck.api git commit -m "deprecated api"; extras/scripts/crcchecker.py --check-patchset +echo "TEST 7.1: Verify we can delete deprecated message (old/confused style)" +cat >crccheck_dep.api <crccheck_dep.api < Date: Fri, 18 Sep 2020 21:47:04 +0200 Subject: [PATCH 045/129] dpdk: prevent linking dpdk against libbsd If libbsd is detected by the DPDK build system, DPDK does not provide implementations for strlcpy and dynamically link against the one provided by libbsd. When the DPDK plugin is loaded by VPP, a crash occurs because libbsd is not loaded by VPP. Type: fix Change-Id: Ib691bbe27edcf0f6f0a3d39952e439027cef72cb Signed-off-by: Mohammed Hawari (cherry picked from commit 1f799bc3cb7a3826395e544cafe587174393e2f0) --- build/external/packages/dpdk.mk | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/build/external/packages/dpdk.mk b/build/external/packages/dpdk.mk index ef84383d55a7..49761cd56a47 100644 --- a/build/external/packages/dpdk.mk +++ b/build/external/packages/dpdk.mk @@ -12,6 +12,7 @@ # limitations under the License. DPDK_PKTMBUF_HEADROOM ?= 128 +DPDK_USE_LIBBSD ?= n DPDK_DEBUG ?= n DPDK_MLX4_PMD ?= n DPDK_MLX5_PMD ?= n @@ -118,6 +119,19 @@ echo '$(HASH)define RTE_$(1) $(DPDK_$(1))' \ fi endef +define dpdk_config_def +if [[ "$(DPDK_$(1))" == "y" ]]; then \ + if ! grep -q "RTE_$(1)" $(dpdk_build_dir)/rte_build_config.h \ + $(dpdk_src_dir)/config/rte_config.h ; then \ + echo '$(HASH)define RTE_$(1) 1' \ + >> $(dpdk_build_dir)/rte_build_config.h ; \ + fi; \ +elif [[ "$(DPDK_$(1))" == "n" ]]; then \ + sed -i '/$(HASH)define RTE_$(1) .*/d' $(dpdk_build_dir)/rte_build_config.h \ + $(dpdk_src_dir)/config/rte_config.h ; \ +fi +endef + DPDK_MESON_ARGS = \ --default-library static \ --libdir lib \ @@ -143,7 +157,8 @@ define dpdk_config_cmds deactivate && \ echo "DPDK post meson configuration" && \ echo "Altering rte_build_config.h" && \ - $(call dpdk_config,PKTMBUF_HEADROOM) + $(call dpdk_config,PKTMBUF_HEADROOM) && \ + $(call dpdk_config_def,USE_LIBBSD) endef define dpdk_build_cmds From ef73a0725d17c2251348e4f54aebe71afd7cc24f Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Wed, 23 Sep 2020 11:38:25 -0400 Subject: [PATCH 046/129] build: fix fts.py to run on debian-9/python3.5 Type: fix Change-Id: I1404e73dd2ee62b51746e9f4760c7c3ca3b5989e Signed-off-by: Dave Wallace (cherry picked from commit a079844cf01eea8a7085c2c03226ceb3d942838a) --- src/scripts/fts.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/scripts/fts.py b/src/scripts/fts.py index 249970405c40..b579190e433e 100755 --- a/src/scripts/fts.py +++ b/src/scripts/fts.py @@ -99,10 +99,10 @@ def print_maintainer(self, o): write = self.stream.write if type(o) is list: write('Maintainers: ' + - ', '.join(f'{m}' for m in + ', '.join('{m}'.format(m=m) for m in o) + ' \n') else: - write(f'Maintainer: {o} \n') + write('Maintainer: {o} \n'.format(o=o)) _dispatch['maintainer'] = print_maintainer @@ -112,39 +112,39 @@ def print_features(self, o, indent=0): indentstr = ' ' * indent if type(f) is dict: for k, v in f.items(): - write(f'{indentstr}- {k}\n') + write('{indentstr}- {k}\n'.format(indentstr=indentstr, k=k)) self.print_features(v, indent + 2) else: - write(f'{indentstr}- {f}\n') + write('{indentstr}- {f}\n'.format(indentstr=indentstr, f=f)) write('\n') _dispatch['features'] = print_features def print_markdown_header(self, o): write = self.stream.write - write(f'## {o}\n') + write('## {o}\n'.format(o=o)) version = version_from_git() - write(f'VPP version: {version}\n\n') + write('VPP version: {version}\n\n'.format(version=version)) _dispatch['markdown_header'] = print_markdown_header def print_name(self, o): write = self.stream.write - write(f'### {o}\n') + write('### {o}\n'.format(o=o)) self.toc.append(o) _dispatch['name'] = print_name def print_description(self, o): write = self.stream.write - write(f'\n{o}\n\n') + write('\n{o}\n\n'.format(o=o)) _dispatch['description'] = print_description def print_state(self, o): write = self.stream.write - write(f'Feature maturity level: {o} \n') + write('Feature maturity level: {o} \n'.format(o=o)) _dispatch['state'] = print_state def print_properties(self, o): write = self.stream.write - write(f'Supports: {" ".join(o)} \n') + write('Supports: {s} \n'.format(s=" ".join(o))) _dispatch['properties'] = print_properties def print_missing(self, o): @@ -155,7 +155,7 @@ def print_missing(self, o): def print_code(self, o): write = self.stream.write - write(f'Source Code: [{o}]({o}) \n') + write('Source Code: [{o}]({o}) \n'.format(o=o)) _dispatch['code'] = print_code def print(self, t, o): @@ -171,7 +171,7 @@ def output_toc(toc, stream): for t in toc: ref = t.lower().replace(' ', '-') - write(f'[{t}](#{ref}) \n') + write('[{t}](#{ref}) \n'.format(t=t, ref=ref)) def featuresort(k): return k[1]['name'] @@ -194,7 +194,8 @@ def output_markdown(features, fields, notfields): m = MarkDown(stream) m.print('markdown_header', 'Feature Details:') for path, featuredef in sorted(features.items(), key=featuresort): - codeurl = 'https://git.fd.io/vpp/tree/src/' + '/'.join(os.path.normpath(path).split('/')[1:-1]) + codeurl = 'https://git.fd.io/vpp/tree/src/' + \ + '/'.join(os.path.normpath(path).split('/')[1:-1]) featuredef['code'] = codeurl for k, v in sorted(featuredef.items(), key=featurelistsort): if notfields: @@ -253,8 +254,8 @@ def main(): try: validate(instance=cfg, schema=schema) except exceptions.ValidationError: - print(f'File does not validate: {featurefile}', - file=sys.stderr) + print('File does not validate: {featurefile}' \ + .format(featurefile=featurefile), file=sys.stderr) raise features[featurefile] = cfg From cc4f3d9102f250628ccceb644682b33fc8d878ad Mon Sep 17 00:00:00 2001 From: Steven Luong Date: Wed, 16 Sep 2020 13:10:53 -0700 Subject: [PATCH 047/129] avf: wrong argument passed to avf_log_err Type: fix Signed-off-by: Steven Luong Change-Id: Ica4601c9d17e182cbc348989a9f75ab1cb18b78a (cherry picked from commit ba3a20082d8e17388bfeca6c2b422e3a11a4eb69) --- src/plugins/avf/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c index 2b4801e2c814..0481e61b2949 100644 --- a/src/plugins/avf/device.c +++ b/src/plugins/avf/device.c @@ -1241,7 +1241,7 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) if ((err = avf_config_promisc_mode (vm, ad, is_enable))) { - avf_log_err (ad, "%s: %U", format_clib_error, err); + avf_log_err (ad, "error: %U", format_clib_error, err); clib_error_free (err); } } From dccf863d79ee59ff1e86b3b308671648a1d5642c Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 17 Sep 2020 09:54:07 +0200 Subject: [PATCH 048/129] vppinfra: allow handoff to main thread Type: improvement Change-Id: If2e907967c9b75997b581ff0c058bd5c15e823f5 Signed-off-by: Damjan Marion (cherry picked from commit f6e6c788070e1421bbe7b10d449d9b65918ba561) --- src/vlib/main.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/vlib/main.c b/src/vlib/main.c index bada9bcfdff8..bfe97953a031 100644 --- a/src/vlib/main.c +++ b/src/vlib/main.c @@ -1771,28 +1771,26 @@ vlib_main_or_worker_loop (vlib_main_t * vm, int is_main) } if (!is_main) + vlib_worker_thread_barrier_check (); + + if (PREDICT_FALSE (vm->check_frame_queues + frame_queue_check_counter)) { - vlib_worker_thread_barrier_check (); - if (PREDICT_FALSE (vm->check_frame_queues + - frame_queue_check_counter)) - { - u32 processed = 0; + u32 processed = 0; - if (vm->check_frame_queues) - { - frame_queue_check_counter = 100; - vm->check_frame_queues = 0; - } + if (vm->check_frame_queues) + { + frame_queue_check_counter = 100; + vm->check_frame_queues = 0; + } - vec_foreach (fqm, tm->frame_queue_mains) - processed += vlib_frame_queue_dequeue (vm, fqm); + vec_foreach (fqm, tm->frame_queue_mains) + processed += vlib_frame_queue_dequeue (vm, fqm); - /* No handoff queue work found? */ - if (processed) - frame_queue_check_counter = 100; - else - frame_queue_check_counter--; - } + /* No handoff queue work found? */ + if (processed) + frame_queue_check_counter = 100; + else + frame_queue_check_counter--; } if (PREDICT_FALSE (vec_len (vm->worker_thread_main_loop_callbacks))) From c359dfa1869d888d934fd0fd362ece21f9ffc26c Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Wed, 23 Sep 2020 20:19:37 -0400 Subject: [PATCH 049/129] build: fix missing openssl package on debian-10 - libssl-dev missing on debian-10 breaks 'make install-ext-deps' Type: fix Signed-off-by: Dave Wallace Change-Id: Ib6a6f120147e8ae0dcfead6fae9f0a7a3434d687 (cherry picked from commit 17569cbeb25c7eba9cd818bea98448b11b05532c) --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index dd8522294894..6a4886ff6676 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,7 @@ else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-9) DEB_DEPENDS += python-all python-pip DEB_DEPENDS += python-dev python-all python-pip python-virtualenv else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-10) + DEB_DEPENDS += libssl-dev DEB_DEPENDS += libelf-dev # for libbpf (af_xdp) else DEB_DEPENDS += libssl-dev From 48d81b58dfc1b4c93a44e07ed61cbe73458623a2 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Mon, 14 Sep 2020 11:36:01 +0700 Subject: [PATCH 050/129] wireguard: add handoff node All timer and control plane functions happen from main thread Type: fix Change-Id: I4fc333c644485cd17e6f426493feef91688d9b24 Signed-off-by: Artem Glazychev (cherry picked from commit 8eb69407c8075e101b773d5a27ea21bd3fc906d7) --- src/plugins/wireguard/CMakeLists.txt | 1 + src/plugins/wireguard/test/test_wireguard.py | 101 +++++++- src/plugins/wireguard/wireguard.c | 12 +- src/plugins/wireguard/wireguard.h | 18 +- src/plugins/wireguard/wireguard_api.c | 4 +- src/plugins/wireguard/wireguard_handoff.c | 197 ++++++++++++++ src/plugins/wireguard/wireguard_if.c | 86 ++++--- src/plugins/wireguard/wireguard_if.h | 5 +- src/plugins/wireguard/wireguard_input.c | 255 ++++++++++--------- src/plugins/wireguard/wireguard_noise.c | 131 ++++------ src/plugins/wireguard/wireguard_noise.h | 23 +- src/plugins/wireguard/wireguard_output_tun.c | 94 +++---- src/plugins/wireguard/wireguard_peer.c | 58 +++-- src/plugins/wireguard/wireguard_peer.h | 40 ++- src/plugins/wireguard/wireguard_send.c | 89 ++++--- src/plugins/wireguard/wireguard_send.h | 1 + src/plugins/wireguard/wireguard_timer.c | 220 ++++++++++------ src/plugins/wireguard/wireguard_timer.h | 2 +- 18 files changed, 889 insertions(+), 448 deletions(-) create mode 100644 src/plugins/wireguard/wireguard_handoff.c diff --git a/src/plugins/wireguard/CMakeLists.txt b/src/plugins/wireguard/CMakeLists.txt index db5bb2d8910e..db74f9cdce03 100755 --- a/src/plugins/wireguard/CMakeLists.txt +++ b/src/plugins/wireguard/CMakeLists.txt @@ -30,6 +30,7 @@ add_vpp_plugin(wireguard wireguard_if.h wireguard_input.c wireguard_output_tun.c + wireguard_handoff.c wireguard_key.c wireguard_key.h wireguard_cli.c diff --git a/src/plugins/wireguard/test/test_wireguard.py b/src/plugins/wireguard/test/test_wireguard.py index 77349396ec69..cee1e938bb0a 100755 --- a/src/plugins/wireguard/test/test_wireguard.py +++ b/src/plugins/wireguard/test/test_wireguard.py @@ -327,6 +327,14 @@ def decrypt_transport(self, p): def encrypt_transport(self, p): return self.noise.encrypt(bytes(p)) + def validate_encapped(self, rxs, tx): + for rx in rxs: + rx = IP(self.decrypt_transport(rx)) + + # chech the oringial packet is present + self._test.assertEqual(rx[IP].dst, tx[IP].dst) + self._test.assertEqual(rx[IP].ttl, tx[IP].ttl-1) + class TestWg(VppTestCase): """ Wireguard Test Case """ @@ -455,11 +463,7 @@ def test_wg_peer_resp(self): rxs = self.send_and_expect(self.pg0, p * 255, self.pg1) - for rx in rxs: - rx = IP(peer_1.decrypt_transport(rx)) - # chech the oringial packet is present - self.assertEqual(rx[IP].dst, p[IP].dst) - self.assertEqual(rx[IP].ttl, p[IP].ttl-1) + peer_1.validate_encapped(rxs, p) # send packets into the tunnel, expect to receive them on # the other side @@ -655,3 +659,90 @@ def test_wg_multi_peer(self): wg0.remove_vpp_config() wg1.remove_vpp_config() + + +class WireguardHandoffTests(TestWg): + """ Wireguard Tests in multi worker setup """ + worker_config = "workers 2" + + def test_wg_peer_init(self): + """ Handoff """ + wg_output_node_name = '/err/wg-output-tun/' + wg_input_node_name = '/err/wg-input/' + + port = 12323 + + # Create interfaces + wg0 = VppWgInterface(self, + self.pg1.local_ip4, + port).add_vpp_config() + wg0.admin_up() + wg0.config_ip4() + + peer_1 = VppWgPeer(self, + wg0, + self.pg1.remote_ip4, + port+1, + ["10.11.2.0/24", + "10.11.3.0/24"]).add_vpp_config() + self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) + + # send a valid handsake init for which we expect a response + p = peer_1.mk_handshake(self.pg1) + + rx = self.send_and_expect(self.pg1, [p], self.pg1) + + peer_1.consume_response(rx[0]) + + # send a data packet from the peer through the tunnel + # this completes the handshake and pins the peer to worker 0 + p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / + UDP(sport=222, dport=223) / + Raw()) + d = peer_1.encrypt_transport(p) + p = (peer_1.mk_tunnel_header(self.pg1) / + (Wireguard(message_type=4, reserved_zero=0) / + WireguardTransport(receiver_index=peer_1.sender, + counter=0, + encrypted_encapsulated_packet=d))) + rxs = self.send_and_expect(self.pg1, [p], self.pg0, + worker=0) + + for rx in rxs: + self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) + self.assertEqual(rx[IP].ttl, 19) + + # send a packets that are routed into the tunnel + # and pins the peer tp worker 1 + pe = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / + UDP(sport=555, dport=556) / + Raw(b'\x00' * 80)) + rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1) + peer_1.validate_encapped(rxs, pe) + + # send packets into the tunnel, from the other worker + p = [(peer_1.mk_tunnel_header(self.pg1) / + Wireguard(message_type=4, reserved_zero=0) / + WireguardTransport( + receiver_index=peer_1.sender, + counter=ii+1, + encrypted_encapsulated_packet=peer_1.encrypt_transport( + (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / + UDP(sport=222, dport=223) / + Raw())))) for ii in range(255)] + + rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1) + + for rx in rxs: + self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) + self.assertEqual(rx[IP].ttl, 19) + + # send a packets that are routed into the tunnel + # from owrker 0 + rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0) + + peer_1.validate_encapped(rxs, pe) + + peer_1.remove_vpp_config() + wg0.remove_vpp_config() diff --git a/src/plugins/wireguard/wireguard.c b/src/plugins/wireguard/wireguard.c index 00921811e4a6..9510a0ad385b 100755 --- a/src/plugins/wireguard/wireguard.c +++ b/src/plugins/wireguard/wireguard.c @@ -32,7 +32,17 @@ wg_init (vlib_main_t * vm) wg_main_t *wmp = &wg_main; wmp->vlib_main = vm; - wmp->peers = 0; + + wmp->in_fq_index = vlib_frame_queue_main_init (wg_input_node.index, 0); + wmp->out_fq_index = + vlib_frame_queue_main_init (wg_output_tun_node.index, 0); + + vlib_thread_main_t *tm = vlib_get_thread_main (); + + vec_validate_aligned (wmp->per_thread_data, tm->n_vlib_mains, + CLIB_CACHE_LINE_BYTES); + + wg_timer_wheel_init (); return (NULL); } diff --git a/src/plugins/wireguard/wireguard.h b/src/plugins/wireguard/wireguard.h index 70a692e602f2..2c892a374b8d 100755 --- a/src/plugins/wireguard/wireguard.h +++ b/src/plugins/wireguard/wireguard.h @@ -17,13 +17,17 @@ #include #include -#include +#include + +#define WG_DEFAULT_DATA_SIZE 2048 extern vlib_node_registration_t wg_input_node; extern vlib_node_registration_t wg_output_tun_node; - - +typedef struct wg_per_thread_data_t_ +{ + u8 data[WG_DEFAULT_DATA_SIZE]; +} wg_per_thread_data_t; typedef struct { /* convenience */ @@ -31,10 +35,14 @@ typedef struct u16 msg_id_base; - // Peers pool - wg_peer_t *peers; wg_index_table_t index_table; + u32 in_fq_index; + u32 out_fq_index; + + wg_per_thread_data_t *per_thread_data; + + tw_timer_wheel_16t_2w_512sl_t timer_wheel; } wg_main_t; extern wg_main_t wg_main; diff --git a/src/plugins/wireguard/wireguard_api.c b/src/plugins/wireguard/wireguard_api.c index 8bbacddaf45d..27ed6ea05da6 100755 --- a/src/plugins/wireguard/wireguard_api.c +++ b/src/plugins/wireguard/wireguard_api.c @@ -97,15 +97,17 @@ wireguard_if_send_details (index_t wgii, void *data) vl_api_wireguard_interface_details_t *rmp; wg_deatils_walk_t *ctx = data; const wg_if_t *wgi; + const noise_local_t *local; wgi = wg_if_get (wgii); + local = noise_local_get (wgi->local_idx); rmp = vl_msg_api_alloc_zero (sizeof (*rmp)); rmp->_vl_msg_id = htons (VL_API_WIREGUARD_INTERFACE_DETAILS + wg_main.msg_id_base); clib_memcpy (rmp->interface.private_key, - wgi->local.l_private, NOISE_PUBLIC_KEY_LEN); + local->l_private, NOISE_PUBLIC_KEY_LEN); rmp->interface.sw_if_index = htonl (wgi->sw_if_index); rmp->interface.port = htons (wgi->port); ip_address_encode2 (&wgi->src_ip, &rmp->interface.src_ip); diff --git a/src/plugins/wireguard/wireguard_handoff.c b/src/plugins/wireguard/wireguard_handoff.c new file mode 100644 index 000000000000..b0b742294520 --- /dev/null +++ b/src/plugins/wireguard/wireguard_handoff.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 Doc.ai and/or its affiliates. + * 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 +#include + +#define foreach_wg_handoff_error \ +_(CONGESTION_DROP, "congestion drop") + +typedef enum +{ +#define _(sym,str) WG_HANDOFF_ERROR_##sym, + foreach_wg_handoff_error +#undef _ + HANDOFF_N_ERROR, +} ipsec_handoff_error_t; + +static char *wg_handoff_error_strings[] = { +#define _(sym,string) string, + foreach_wg_handoff_error +#undef _ +}; + +typedef enum +{ + WG_HANDOFF_HANDSHAKE, + WG_HANDOFF_INP_DATA, + WG_HANDOFF_OUT_TUN, +} wg_handoff_mode_t; + +typedef struct wg_handoff_trace_t_ +{ + u32 next_worker_index; + index_t peer; +} wg_handoff_trace_t; + +static u8 * +format_wg_handoff_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + wg_handoff_trace_t *t = va_arg (*args, wg_handoff_trace_t *); + + s = format (s, "next-worker %d peer %d", t->next_worker_index, t->peer); + + return s; +} + +static_always_inline uword +wg_handoff (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, u32 fq_index, wg_handoff_mode_t mode) +{ + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + u16 thread_indices[VLIB_FRAME_SIZE], *ti; + u32 n_enq, n_left_from, *from; + wg_main_t *wmp; + + wmp = &wg_main; + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + vlib_get_buffers (vm, from, bufs, n_left_from); + + b = bufs; + ti = thread_indices; + + while (n_left_from > 0) + { + const wg_peer_t *peer; + index_t peeri; + + if (PREDICT_FALSE (mode == WG_HANDOFF_HANDSHAKE)) + { + ti[0] = 0; + } + else if (mode == WG_HANDOFF_INP_DATA) + { + message_data_t *data = vlib_buffer_get_current (b[0]); + u32 *entry = + wg_index_table_lookup (&wmp->index_table, data->receiver_index); + peeri = *entry; + peer = wg_peer_get (peeri); + + ti[0] = peer->input_thread_index; + } + else + { + peeri = + wg_peer_get_by_adj_index (vnet_buffer (b[0])-> + ip.adj_index[VLIB_TX]); + peer = wg_peer_get (peeri); + ti[0] = peer->output_thread_index; + } + + if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED)) + { + wg_handoff_trace_t *t = + vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->next_worker_index = ti[0]; + t->peer = peeri; + } + + n_left_from -= 1; + ti += 1; + b += 1; + } + + n_enq = vlib_buffer_enqueue_to_thread (vm, fq_index, from, + thread_indices, frame->n_vectors, 1); + + if (n_enq < frame->n_vectors) + vlib_node_increment_counter (vm, node->node_index, + WG_HANDOFF_ERROR_CONGESTION_DROP, + frame->n_vectors - n_enq); + + return n_enq; +} + +VLIB_NODE_FN (wg_handshake_handoff) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + wg_main_t *wmp = &wg_main; + + return wg_handoff (vm, node, from_frame, wmp->in_fq_index, + WG_HANDOFF_HANDSHAKE); +} + +VLIB_NODE_FN (wg_input_data_handoff) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + wg_main_t *wmp = &wg_main; + + return wg_handoff (vm, node, from_frame, wmp->in_fq_index, + WG_HANDOFF_INP_DATA); +} + +VLIB_NODE_FN (wg_output_tun_handoff) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + wg_main_t *wmp = &wg_main; + + return wg_handoff (vm, node, from_frame, wmp->out_fq_index, + WG_HANDOFF_OUT_TUN); +} + +VLIB_REGISTER_NODE (wg_handshake_handoff) = +{ + .name = "wg-handshake-handoff",.vector_size = sizeof (u32),.format_trace = + format_wg_handoff_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = + ARRAY_LEN (wg_handoff_error_strings),.error_strings = + wg_handoff_error_strings,.n_next_nodes = 1,.next_nodes = + { + [0] = "error-drop",} +,}; + +VLIB_REGISTER_NODE (wg_input_data_handoff) = +{ + .name = "wg-input-data-handoff",.vector_size = sizeof (u32),.format_trace = + format_wg_handoff_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = + ARRAY_LEN (wg_handoff_error_strings),.error_strings = + wg_handoff_error_strings,.n_next_nodes = 1,.next_nodes = + { + [0] = "error-drop",} +,}; + +VLIB_REGISTER_NODE (wg_output_tun_handoff) = +{ + .name = "wg-output-tun-handoff",.vector_size = sizeof (u32),.format_trace = + format_wg_handoff_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = + ARRAY_LEN (wg_handoff_error_strings),.error_strings = + wg_handoff_error_strings,.n_next_nodes = 1,.next_nodes = + { + [0] = "error-drop",} +,}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/wireguard/wireguard_if.c b/src/plugins/wireguard/wireguard_if.c index c91667bb2342..7509923a1bfc 100644 --- a/src/plugins/wireguard/wireguard_if.c +++ b/src/plugins/wireguard/wireguard_if.c @@ -5,6 +5,7 @@ #include #include #include +#include /* pool of interfaces */ wg_if_t *wg_if_pool; @@ -30,28 +31,28 @@ format_wg_if (u8 * s, va_list * args) { index_t wgii = va_arg (*args, u32); wg_if_t *wgi = wg_if_get (wgii); + noise_local_t *local = noise_local_get (wgi->local_idx); u8 key[NOISE_KEY_LEN_BASE64]; - key_to_base64 (wgi->local.l_private, NOISE_PUBLIC_KEY_LEN, key); s = format (s, "[%d] %U src:%U port:%d", wgii, format_vnet_sw_if_index_name, vnet_get_main (), wgi->sw_if_index, format_ip_address, &wgi->src_ip, wgi->port); - key_to_base64 (wgi->local.l_private, NOISE_PUBLIC_KEY_LEN, key); + key_to_base64 (local->l_private, NOISE_PUBLIC_KEY_LEN, key); s = format (s, " private-key:%s", key); s = - format (s, " %U", format_hex_bytes, wgi->local.l_private, + format (s, " %U", format_hex_bytes, local->l_private, NOISE_PUBLIC_KEY_LEN); - key_to_base64 (wgi->local.l_public, NOISE_PUBLIC_KEY_LEN, key); + key_to_base64 (local->l_public, NOISE_PUBLIC_KEY_LEN, key); s = format (s, " public-key:%s", key); s = - format (s, " %U", format_hex_bytes, wgi->local.l_public, + format (s, " %U", format_hex_bytes, local->l_public, NOISE_PUBLIC_KEY_LEN); s = format (s, " mac-key: %U", format_hex_bytes, @@ -72,23 +73,28 @@ wg_if_find_by_sw_if_index (u32 sw_if_index) return (ti); } +static walk_rc_t +wg_if_find_peer_by_public_key (index_t peeri, void *data) +{ + uint8_t *public = data; + wg_peer_t *peer = wg_peer_get (peeri); + + if (!memcmp (peer->remote.r_public, public, NOISE_PUBLIC_KEY_LEN)) + return (WALK_STOP); + return (WALK_CONTINUE); +} + static noise_remote_t * -wg_remote_get (uint8_t public[NOISE_PUBLIC_KEY_LEN]) +wg_remote_get (const uint8_t public[NOISE_PUBLIC_KEY_LEN]) { - wg_main_t *wmp = &wg_main; - wg_peer_t *peer = NULL; - wg_peer_t *peer_iter; - /* *INDENT-OFF* */ - pool_foreach (peer_iter, wmp->peers, - ({ - if (!memcmp (peer_iter->remote.r_public, public, NOISE_PUBLIC_KEY_LEN)) - { - peer = peer_iter; - break; - } - })); - /* *INDENT-ON* */ - return peer ? &peer->remote : NULL; + index_t peeri; + + peeri = wg_peer_walk (wg_if_find_peer_by_public_key, (void *) public); + + if (INDEX_INVALID != peeri) + return &wg_peer_get (peeri)->remote; + + return NULL; } static uint32_t @@ -223,6 +229,7 @@ wg_if_create (u32 user_instance, u32 instance, hw_if_index; vnet_hw_interface_t *hi; wg_if_t *wg_if; + noise_local_t *local; ASSERT (sw_if_indexp); @@ -236,6 +243,24 @@ wg_if_create (u32 user_instance, if (instance == ~0) return VNET_API_ERROR_INVALID_REGISTRATION; + /* *INDENT-OFF* */ + struct noise_upcall upcall = { + .u_remote_get = wg_remote_get, + .u_index_set = wg_index_set, + .u_index_drop = wg_index_drop, + }; + /* *INDENT-ON* */ + + pool_get (noise_local_pool, local); + + noise_local_init (local, &upcall); + if (!noise_local_set_private (local, private_key)) + { + pool_put (noise_local_pool, local); + wg_if_instance_free (instance); + return VNET_API_ERROR_INVALID_REGISTRATION; + } + pool_get (wg_if_pool, wg_if); /* tunnel index (or instance) */ @@ -251,18 +276,8 @@ wg_if_create (u32 user_instance, wg_if_index_by_port[port] = wg_if - wg_if_pool; wg_if->port = port; - - /* *INDENT-OFF* */ - struct noise_upcall upcall = { - .u_remote_get = wg_remote_get, - .u_index_set = wg_index_set, - .u_index_drop = wg_index_drop, - }; - /* *INDENT-ON* */ - - noise_local_init (&wg_if->local, &upcall); - noise_local_set_private (&wg_if->local, private_key); - cookie_checker_update (&wg_if->cookie_checker, wg_if->local.l_public); + wg_if->local_idx = local - noise_local_pool; + cookie_checker_update (&wg_if->cookie_checker, local->l_public); hw_if_index = vnet_register_interface (vnm, wg_if_device_class.index, @@ -304,6 +319,7 @@ wg_if_delete (u32 sw_if_index) udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1); wg_if_index_by_port[wg_if->port] = INDEX_INVALID; vnet_delete_hw_interface (vnm, hw->hw_if_index); + pool_put_index (noise_local_pool, wg_if->local_idx); pool_put (wg_if_pool, wg_if); return 0; @@ -343,7 +359,7 @@ wg_if_walk (wg_if_walk_cb_t fn, void *data) /* *INDENT-ON* */ } -void +index_t wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data) { index_t peeri, val; @@ -352,9 +368,11 @@ wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data) hash_foreach (peeri, val, wgi->peers, { if (WALK_STOP == fn(wgi, peeri, data)) - break; + return peeri; }); /* *INDENT-ON* */ + + return INDEX_INVALID; } diff --git a/src/plugins/wireguard/wireguard_if.h b/src/plugins/wireguard/wireguard_if.h index 9e6b6190e0e0..d8c2a87dc71e 100644 --- a/src/plugins/wireguard/wireguard_if.h +++ b/src/plugins/wireguard/wireguard_if.h @@ -25,7 +25,8 @@ typedef struct wg_if_t_ u32 sw_if_index; // Interface params - noise_local_t local; + /* noise_local_pool elt index */ + u32 local_idx; cookie_checker_t cookie_checker; u16 port; @@ -52,7 +53,7 @@ void wg_if_walk (wg_if_walk_cb_t fn, void *data); typedef walk_rc_t (*wg_if_peer_walk_cb_t) (wg_if_t * wgi, index_t peeri, void *data); -void wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data); +index_t wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data); void wg_if_peer_add (wg_if_t * wgi, index_t peeri); void wg_if_peer_remove (wg_if_t * wgi, index_t peeri); diff --git a/src/plugins/wireguard/wireguard_input.c b/src/plugins/wireguard/wireguard_input.c index cdd65f87b516..b15c265cdac0 100755 --- a/src/plugins/wireguard/wireguard_input.c +++ b/src/plugins/wireguard/wireguard_input.c @@ -30,6 +30,7 @@ _(DECRYPTION, "Failed during decryption") \ _(KEEPALIVE_SEND, "Failed while sending Keepalive") \ _(HANDSHAKE_SEND, "Failed while sending Handshake") \ + _(TOO_BIG, "Packet too big") \ _(UNDEFINED, "Undefined error") typedef enum @@ -51,7 +52,7 @@ typedef struct message_type_t type; u16 current_length; bool is_keepalive; - + index_t peer; } wg_input_trace_t; u8 * @@ -79,6 +80,7 @@ format_wg_input_trace (u8 * s, va_list * args) s = format (s, "WG input: \n"); s = format (s, " Type: %U\n", format_wg_message_type, t->type); + s = format (s, " peer: %d\n", t->peer); s = format (s, " Length: %d\n", t->current_length); s = format (s, " Keepalive: %s", t->is_keepalive ? "true" : "false"); @@ -87,6 +89,8 @@ format_wg_input_trace (u8 * s, va_list * args) typedef enum { + WG_INPUT_NEXT_HANDOFF_HANDSHAKE, + WG_INPUT_NEXT_HANDOFF_DATA, WG_INPUT_NEXT_IP4_INPUT, WG_INPUT_NEXT_PUNT, WG_INPUT_NEXT_ERROR, @@ -106,6 +110,8 @@ typedef enum static wg_input_error_t wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) { + ASSERT (vm->thread_index == 0); + enum cookie_mac_state mac_state; bool packet_needs_cookie; bool under_load; @@ -129,17 +135,15 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) if (NULL == wg_if) return WG_INPUT_ERROR_INTERFACE; - if (header->type == MESSAGE_HANDSHAKE_COOKIE) + if (PREDICT_FALSE (header->type == MESSAGE_HANDSHAKE_COOKIE)) { message_handshake_cookie_t *packet = (message_handshake_cookie_t *) current_b_data; u32 *entry = wg_index_table_lookup (&wmp->index_table, packet->receiver_index); if (entry) - { - peer = pool_elt_at_index (wmp->peers, *entry); - } - if (!peer) + peer = wg_peer_get (*entry); + else return WG_INPUT_ERROR_PEER; // TODO: Implement cookie_maker_consume_payload @@ -178,17 +182,17 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) // TODO: Add processing } noise_remote_t *rp; - if (noise_consume_initiation - (wmp->vlib_main, &wg_if->local, &rp, message->sender_index, - message->unencrypted_ephemeral, message->encrypted_static, - message->encrypted_timestamp)) + (vm, noise_local_get (wg_if->local_idx), &rp, + message->sender_index, message->unencrypted_ephemeral, + message->encrypted_static, message->encrypted_timestamp)) { - peer = pool_elt_at_index (wmp->peers, rp->r_peer_idx); + peer = wg_peer_get (rp->r_peer_idx); + } + else + { + return WG_INPUT_ERROR_PEER; } - - if (!peer) - return WG_INPUT_ERROR_PEER; // set_peer_address (peer, ip4_src, udp_src_port); if (PREDICT_FALSE (!wg_send_handshake_response (vm, peer))) @@ -203,15 +207,18 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) message_handshake_response_t *resp = current_b_data; u32 *entry = wg_index_table_lookup (&wmp->index_table, resp->receiver_index); - if (entry) + + if (PREDICT_TRUE (entry != NULL)) { - peer = pool_elt_at_index (wmp->peers, *entry); - if (!peer || peer->is_dead) + peer = wg_peer_get (*entry); + if (peer->is_dead) return WG_INPUT_ERROR_PEER; } + else + return WG_INPUT_ERROR_PEER; if (!noise_consume_response - (wmp->vlib_main, &peer->remote, resp->sender_index, + (vm, &peer->remote, resp->sender_index, resp->receiver_index, resp->unencrypted_ephemeral, resp->encrypted_nothing)) { @@ -223,8 +230,9 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) } // set_peer_address (peer, ip4_src, udp_src_port); - if (noise_remote_begin_session (wmp->vlib_main, &peer->remote)) + if (noise_remote_begin_session (vm, &peer->remote)) { + wg_timers_session_derived (peer); wg_timers_handshake_complete (peer); if (PREDICT_FALSE (!wg_send_keepalive (vm, peer))) @@ -272,6 +280,7 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, u32 *from; vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; u16 nexts[VLIB_FRAME_SIZE], *next; + u32 thread_index = vm->thread_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -289,120 +298,132 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, next[0] = WG_INPUT_NEXT_PUNT; header_type = ((message_header_t *) vlib_buffer_get_current (b[0]))->type; + u32 *peer_idx; - switch (header_type) + if (PREDICT_TRUE (header_type == MESSAGE_DATA)) { - case MESSAGE_HANDSHAKE_INITIATION: - case MESSAGE_HANDSHAKE_RESPONSE: - case MESSAGE_HANDSHAKE_COOKIE: - { - wg_input_error_t ret = wg_handshake_process (vm, wmp, b[0]); - if (ret != WG_INPUT_ERROR_NONE) - { - next[0] = WG_INPUT_NEXT_ERROR; - b[0]->error = node->errors[ret]; - } - break; - } - case MESSAGE_DATA: - { - message_data_t *data = vlib_buffer_get_current (b[0]); - u32 *entry = - wg_index_table_lookup (&wmp->index_table, data->receiver_index); - - if (entry) - { - peer = pool_elt_at_index (wmp->peers, *entry); - } - else - { - next[0] = WG_INPUT_NEXT_ERROR; - b[0]->error = node->errors[WG_INPUT_ERROR_PEER]; - goto out; - } + message_data_t *data = vlib_buffer_get_current (b[0]); - u16 encr_len = b[0]->current_length - sizeof (message_data_t); - u16 decr_len = encr_len - NOISE_AUTHTAG_LEN; - u8 *decr_data = clib_mem_alloc (decr_len); + peer_idx = wg_index_table_lookup (&wmp->index_table, + data->receiver_index); - enum noise_state_crypt state_cr = - noise_remote_decrypt (wmp->vlib_main, - &peer->remote, - data->receiver_index, - data->counter, - data->encrypted_data, - encr_len, - decr_data); + if (peer_idx) + { + peer = wg_peer_get (*peer_idx); + } + else + { + next[0] = WG_INPUT_NEXT_ERROR; + b[0]->error = node->errors[WG_INPUT_ERROR_PEER]; + goto out; + } - switch (state_cr) - { - case SC_OK: - break; - case SC_CONN_RESET: - wg_timers_handshake_complete (peer); - break; - case SC_KEEP_KEY_FRESH: - if (PREDICT_FALSE (!wg_send_handshake (vm, peer, false))) - { - vlib_node_increment_counter (vm, wg_input_node.index, - WG_INPUT_ERROR_HANDSHAKE_SEND, - 1); - } - break; - case SC_FAILED: - next[0] = WG_INPUT_NEXT_ERROR; - b[0]->error = node->errors[WG_INPUT_ERROR_DECRYPTION]; - goto out; - default: - break; - } + if (PREDICT_FALSE (~0 == peer->input_thread_index)) + { + /* this is the first packet to use this peer, claim the peer + * for this thread. + */ + clib_atomic_cmp_and_swap (&peer->input_thread_index, ~0, + wg_peer_assign_thread (thread_index)); + } - clib_memcpy (vlib_buffer_get_current (b[0]), decr_data, decr_len); - b[0]->current_length = decr_len; - b[0]->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; + if (PREDICT_TRUE (thread_index != peer->input_thread_index)) + { + next[0] = WG_INPUT_NEXT_HANDOFF_DATA; + goto next; + } - clib_mem_free (decr_data); + u16 encr_len = b[0]->current_length - sizeof (message_data_t); + u16 decr_len = encr_len - NOISE_AUTHTAG_LEN; + if (PREDICT_FALSE (decr_len >= WG_DEFAULT_DATA_SIZE)) + { + b[0]->error = node->errors[WG_INPUT_ERROR_TOO_BIG]; + goto out; + } - wg_timers_any_authenticated_packet_received (peer); - wg_timers_any_authenticated_packet_traversal (peer); + u8 *decr_data = wmp->per_thread_data[thread_index].data; - if (decr_len == 0) - { - is_keepalive = true; - goto out; - } + enum noise_state_crypt state_cr = noise_remote_decrypt (vm, + &peer->remote, + data->receiver_index, + data->counter, + data->encrypted_data, + encr_len, + decr_data); - wg_timers_data_received (peer); + if (PREDICT_FALSE (state_cr == SC_CONN_RESET)) + { + wg_timers_handshake_complete (peer); + } + else if (PREDICT_FALSE (state_cr == SC_KEEP_KEY_FRESH)) + { + wg_send_handshake_from_mt (*peer_idx, false); + } + else if (PREDICT_FALSE (state_cr == SC_FAILED)) + { + next[0] = WG_INPUT_NEXT_ERROR; + b[0]->error = node->errors[WG_INPUT_ERROR_DECRYPTION]; + goto out; + } - ip4_header_t *iph = vlib_buffer_get_current (b[0]); + clib_memcpy (vlib_buffer_get_current (b[0]), decr_data, decr_len); + b[0]->current_length = decr_len; + b[0]->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; - const wg_peer_allowed_ip_t *allowed_ip; - bool allowed = false; + wg_timers_any_authenticated_packet_received (peer); + wg_timers_any_authenticated_packet_traversal (peer); - /* - * we could make this into an ACL, but the expectation - * is that there aren't many allowed IPs and thus a linear - * walk is fater than an ACL - */ - vec_foreach (allowed_ip, peer->allowed_ips) + /* Keepalive packet has zero length */ + if (decr_len == 0) { - if (fib_prefix_is_cover_addr_4 (&allowed_ip->prefix, - &iph->src_address)) - { - allowed = true; - break; - } + is_keepalive = true; + goto out; } - if (allowed) + + wg_timers_data_received (peer); + + ip4_header_t *iph = vlib_buffer_get_current (b[0]); + + const wg_peer_allowed_ip_t *allowed_ip; + bool allowed = false; + + /* + * we could make this into an ACL, but the expectation + * is that there aren't many allowed IPs and thus a linear + * walk is fater than an ACL + */ + vec_foreach (allowed_ip, peer->allowed_ips) + { + if (fib_prefix_is_cover_addr_4 (&allowed_ip->prefix, + &iph->src_address)) { - vnet_buffer (b[0])->sw_if_index[VLIB_RX] = - peer->wg_sw_if_index; - next[0] = WG_INPUT_NEXT_IP4_INPUT; + allowed = true; + break; } - break; } - default: - break; + if (allowed) + { + vnet_buffer (b[0])->sw_if_index[VLIB_RX] = peer->wg_sw_if_index; + next[0] = WG_INPUT_NEXT_IP4_INPUT; + } + } + else + { + peer_idx = NULL; + + /* Handshake packets should be processed in main thread */ + if (thread_index != 0) + { + next[0] = WG_INPUT_NEXT_HANDOFF_HANDSHAKE; + goto next; + } + + wg_input_error_t ret = wg_handshake_process (vm, wmp, b[0]); + if (ret != WG_INPUT_ERROR_NONE) + { + next[0] = WG_INPUT_NEXT_ERROR; + b[0]->error = node->errors[ret]; + } } out: @@ -413,7 +434,9 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, t->type = header_type; t->current_length = b[0]->current_length; t->is_keepalive = is_keepalive; + t->peer = peer_idx ? *peer_idx : INDEX_INVALID; } + next: n_left_from -= 1; next += 1; b += 1; @@ -435,6 +458,8 @@ VLIB_REGISTER_NODE (wg_input_node) = .n_next_nodes = WG_INPUT_N_NEXT, /* edit / add dispositions here */ .next_nodes = { + [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg-handshake-handoff", + [WG_INPUT_NEXT_HANDOFF_DATA] = "wg-input-data-handoff", [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum", [WG_INPUT_NEXT_PUNT] = "error-punt", [WG_INPUT_NEXT_ERROR] = "error-drop", diff --git a/src/plugins/wireguard/wireguard_noise.c b/src/plugins/wireguard/wireguard_noise.c index b47bb5747b97..00b67109de48 100755 --- a/src/plugins/wireguard/wireguard_noise.c +++ b/src/plugins/wireguard/wireguard_noise.c @@ -26,6 +26,8 @@ * <- e, ee, se, psk, {} */ +noise_local_t *noise_local_pool; + /* Private functions */ static noise_keypair_t *noise_remote_keypair_allocate (noise_remote_t *); static void noise_remote_keypair_free (vlib_main_t * vm, noise_remote_t *, @@ -80,81 +82,31 @@ noise_local_set_private (noise_local_t * l, const uint8_t private[NOISE_PUBLIC_KEY_LEN]) { clib_memcpy (l->l_private, private, NOISE_PUBLIC_KEY_LEN); - l->l_has_identity = curve25519_gen_public (l->l_public, private); - - return l->l_has_identity; -} -bool -noise_local_keys (noise_local_t * l, uint8_t public[NOISE_PUBLIC_KEY_LEN], - uint8_t private[NOISE_PUBLIC_KEY_LEN]) -{ - if (l->l_has_identity) - { - if (public != NULL) - clib_memcpy (public, l->l_public, NOISE_PUBLIC_KEY_LEN); - if (private != NULL) - clib_memcpy (private, l->l_private, NOISE_PUBLIC_KEY_LEN); - } - else - { - return false; - } - return true; + return curve25519_gen_public (l->l_public, private); } void noise_remote_init (noise_remote_t * r, uint32_t peer_pool_idx, const uint8_t public[NOISE_PUBLIC_KEY_LEN], - noise_local_t * l) + u32 noise_local_idx) { clib_memset (r, 0, sizeof (*r)); clib_memcpy (r->r_public, public, NOISE_PUBLIC_KEY_LEN); + clib_rwlock_init (&r->r_keypair_lock); r->r_peer_idx = peer_pool_idx; - - ASSERT (l != NULL); - r->r_local = l; + r->r_local_idx = noise_local_idx; r->r_handshake.hs_state = HS_ZEROED; - noise_remote_precompute (r); -} - -bool -noise_remote_set_psk (noise_remote_t * r, - uint8_t psk[NOISE_SYMMETRIC_KEY_LEN]) -{ - int same; - same = !clib_memcmp (r->r_psk, psk, NOISE_SYMMETRIC_KEY_LEN); - if (!same) - { - clib_memcpy (r->r_psk, psk, NOISE_SYMMETRIC_KEY_LEN); - } - return same == 0; -} - -bool -noise_remote_keys (noise_remote_t * r, uint8_t public[NOISE_PUBLIC_KEY_LEN], - uint8_t psk[NOISE_SYMMETRIC_KEY_LEN]) -{ - static uint8_t null_psk[NOISE_SYMMETRIC_KEY_LEN]; - int ret; - if (public != NULL) - clib_memcpy (public, r->r_public, NOISE_PUBLIC_KEY_LEN); - - if (psk != NULL) - clib_memcpy (psk, r->r_psk, NOISE_SYMMETRIC_KEY_LEN); - ret = clib_memcmp (r->r_psk, null_psk, NOISE_SYMMETRIC_KEY_LEN); - - return ret; + noise_remote_precompute (r); } void noise_remote_precompute (noise_remote_t * r) { - noise_local_t *l = r->r_local; - if (!l->l_has_identity) - clib_memset (r->r_ss, 0, NOISE_PUBLIC_KEY_LEN); - else if (!curve25519_gen_shared (r->r_ss, l->l_private, r->r_public)) + noise_local_t *l = noise_local_get (r->r_local_idx); + + if (!curve25519_gen_shared (r->r_ss, l->l_private, r->r_public)) clib_memset (r->r_ss, 0, NOISE_PUBLIC_KEY_LEN); noise_remote_handshake_index_drop (r); @@ -169,7 +121,7 @@ noise_create_initiation (vlib_main_t * vm, noise_remote_t * r, uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN]) { noise_handshake_t *hs = &r->r_handshake; - noise_local_t *l = r->r_local; + noise_local_t *l = noise_local_get (r->r_local_idx); uint8_t _key[NOISE_SYMMETRIC_KEY_LEN]; uint32_t key_idx; uint8_t *key; @@ -180,8 +132,6 @@ noise_create_initiation (vlib_main_t * vm, noise_remote_t * r, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; - if (!l->l_has_identity) - goto error; noise_param_init (hs->hs_ck, hs->hs_hash, r->r_public); /* e */ @@ -239,8 +189,6 @@ noise_consume_initiation (vlib_main_t * vm, noise_local_t * l, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; - if (!l->l_has_identity) - goto error; noise_param_init (hs.hs_ck, hs.hs_hash, l->l_public); /* e */ @@ -294,6 +242,7 @@ noise_consume_initiation (vlib_main_t * vm, noise_local_t * l, r->r_handshake = hs; *rp = r; ret = true; + error: vnet_crypto_key_del (vm, key_idx); secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); @@ -359,7 +308,7 @@ noise_consume_response (vlib_main_t * vm, noise_remote_t * r, uint32_t s_idx, uint32_t r_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t en[0 + NOISE_AUTHTAG_LEN]) { - noise_local_t *l = r->r_local; + noise_local_t *l = noise_local_get (r->r_local_idx); noise_handshake_t hs; uint8_t _key[NOISE_SYMMETRIC_KEY_LEN]; uint8_t preshared_key[NOISE_PUBLIC_KEY_LEN]; @@ -372,9 +321,6 @@ noise_consume_response (vlib_main_t * vm, noise_remote_t * r, uint32_t s_idx, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; - if (!l->l_has_identity) - goto error; - hs = r->r_handshake; clib_memcpy (preshared_key, r->r_psk, NOISE_SYMMETRIC_KEY_LEN); @@ -460,6 +406,7 @@ noise_remote_begin_session (vlib_main_t * vm, noise_remote_t * r) clib_memset (&kp.kp_ctr, 0, sizeof (kp.kp_ctr)); /* Now we need to add_new_keypair */ + clib_rwlock_writer_lock (&r->r_keypair_lock); next = r->r_next; current = r->r_current; previous = r->r_previous; @@ -491,7 +438,10 @@ noise_remote_begin_session (vlib_main_t * vm, noise_remote_t * r) r->r_next = noise_remote_keypair_allocate (r); *r->r_next = kp; } + clib_rwlock_writer_unlock (&r->r_keypair_lock); + secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake)); + secure_zero_memory (&kp, sizeof (kp)); return true; } @@ -502,21 +452,25 @@ noise_remote_clear (vlib_main_t * vm, noise_remote_t * r) noise_remote_handshake_index_drop (r); secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake)); + clib_rwlock_writer_lock (&r->r_keypair_lock); noise_remote_keypair_free (vm, r, &r->r_next); noise_remote_keypair_free (vm, r, &r->r_current); noise_remote_keypair_free (vm, r, &r->r_previous); r->r_next = NULL; r->r_current = NULL; r->r_previous = NULL; + clib_rwlock_writer_unlock (&r->r_keypair_lock); } void noise_remote_expire_current (noise_remote_t * r) { + clib_rwlock_writer_lock (&r->r_keypair_lock); if (r->r_next != NULL) r->r_next->kp_valid = 0; if (r->r_current != NULL) r->r_current->kp_valid = 0; + clib_rwlock_writer_unlock (&r->r_keypair_lock); } bool @@ -525,6 +479,7 @@ noise_remote_ready (noise_remote_t * r) noise_keypair_t *kp; int ret; + clib_rwlock_reader_lock (&r->r_keypair_lock); if ((kp = r->r_current) == NULL || !kp->kp_valid || wg_birthdate_has_expired (kp->kp_birthdate, REJECT_AFTER_TIME) || @@ -533,6 +488,7 @@ noise_remote_ready (noise_remote_t * r) ret = false; else ret = true; + clib_rwlock_reader_unlock (&r->r_keypair_lock); return ret; } @@ -592,6 +548,7 @@ noise_remote_encrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t * r_idx, noise_keypair_t *kp; enum noise_state_crypt ret = SC_FAILED; + clib_rwlock_reader_lock (&r->r_keypair_lock); if ((kp = r->r_current) == NULL) goto error; @@ -631,6 +588,7 @@ noise_remote_encrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t * r_idx, ret = SC_OK; error: + clib_rwlock_reader_unlock (&r->r_keypair_lock); return ret; } @@ -641,6 +599,7 @@ noise_remote_decrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t r_idx, { noise_keypair_t *kp; enum noise_state_crypt ret = SC_FAILED; + clib_rwlock_reader_lock (&r->r_keypair_lock); if (r->r_current != NULL && r->r_current->kp_local_index == r_idx) { @@ -682,18 +641,26 @@ noise_remote_decrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t r_idx, * next keypair into current. If we do slide the next keypair in, then * we skip the REKEY_AFTER_TIME_RECV check. This is safe to do as a * data packet can't confirm a session that we are an INITIATOR of. */ - if (kp == r->r_next && kp->kp_local_index == r_idx) + if (kp == r->r_next) { - noise_remote_keypair_free (vm, r, &r->r_previous); - r->r_previous = r->r_current; - r->r_current = r->r_next; - r->r_next = NULL; + clib_rwlock_reader_unlock (&r->r_keypair_lock); + clib_rwlock_writer_lock (&r->r_keypair_lock); + if (kp == r->r_next && kp->kp_local_index == r_idx) + { + noise_remote_keypair_free (vm, r, &r->r_previous); + r->r_previous = r->r_current; + r->r_current = r->r_next; + r->r_next = NULL; - ret = SC_CONN_RESET; - goto error; + ret = SC_CONN_RESET; + clib_rwlock_writer_unlock (&r->r_keypair_lock); + clib_rwlock_reader_lock (&r->r_keypair_lock); + goto error; + } + clib_rwlock_writer_unlock (&r->r_keypair_lock); + clib_rwlock_reader_lock (&r->r_keypair_lock); } - /* Similar to when we encrypt, we want to notify the caller when we * are approaching our tolerances. We notify if: * - we're the initiator and the current keypair is older than @@ -708,6 +675,7 @@ noise_remote_decrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t r_idx, ret = SC_OK; error: + clib_rwlock_reader_unlock (&r->r_keypair_lock); return ret; } @@ -725,7 +693,8 @@ static void noise_remote_keypair_free (vlib_main_t * vm, noise_remote_t * r, noise_keypair_t ** kp) { - struct noise_upcall *u = &r->r_local->l_upcall; + noise_local_t *local = noise_local_get (r->r_local_idx); + struct noise_upcall *u = &local->l_upcall; if (*kp) { u->u_index_drop ((*kp)->kp_local_index); @@ -738,7 +707,8 @@ noise_remote_keypair_free (vlib_main_t * vm, noise_remote_t * r, static uint32_t noise_remote_handshake_index_get (noise_remote_t * r) { - struct noise_upcall *u = &r->r_local->l_upcall; + noise_local_t *local = noise_local_get (r->r_local_idx); + struct noise_upcall *u = &local->l_upcall; return u->u_index_set (r); } @@ -746,7 +716,8 @@ static void noise_remote_handshake_index_drop (noise_remote_t * r) { noise_handshake_t *hs = &r->r_handshake; - struct noise_upcall *u = &r->r_local->l_upcall; + noise_local_t *local = noise_local_get (r->r_local_idx); + struct noise_upcall *u = &local->l_upcall; if (hs->hs_state != HS_ZEROED) u->u_index_drop (hs->hs_local_index); } @@ -754,7 +725,8 @@ noise_remote_handshake_index_drop (noise_remote_t * r) static uint64_t noise_counter_send (noise_counter_t * ctr) { - uint64_t ret = ctr->c_send++; + uint64_t ret; + ret = ctr->c_send++; return ret; } @@ -765,7 +737,6 @@ noise_counter_recv (noise_counter_t * ctr, uint64_t recv) unsigned long bit; bool ret = false; - /* Check that the recv counter is valid */ if (ctr->c_recv >= REJECT_AFTER_MESSAGES || recv >= REJECT_AFTER_MESSAGES) goto error; diff --git a/src/plugins/wireguard/wireguard_noise.h b/src/plugins/wireguard/wireguard_noise.h index 1f6804c59ca3..5b5a88fa2509 100755 --- a/src/plugins/wireguard/wireguard_noise.h +++ b/src/plugins/wireguard/wireguard_noise.h @@ -100,7 +100,7 @@ typedef struct noise_remote { uint32_t r_peer_idx; uint8_t r_public[NOISE_PUBLIC_KEY_LEN]; - noise_local_t *r_local; + uint32_t r_local_idx; uint8_t r_ss[NOISE_PUBLIC_KEY_LEN]; noise_handshake_t r_handshake; @@ -108,37 +108,40 @@ typedef struct noise_remote uint8_t r_timestamp[NOISE_TIMESTAMP_LEN]; f64 r_last_init; + clib_rwlock_t r_keypair_lock; noise_keypair_t *r_next, *r_current, *r_previous; } noise_remote_t; typedef struct noise_local { - bool l_has_identity; uint8_t l_public[NOISE_PUBLIC_KEY_LEN]; uint8_t l_private[NOISE_PUBLIC_KEY_LEN]; struct noise_upcall { void *u_arg; - noise_remote_t *(*u_remote_get) (uint8_t[NOISE_PUBLIC_KEY_LEN]); + noise_remote_t *(*u_remote_get) (const uint8_t[NOISE_PUBLIC_KEY_LEN]); uint32_t (*u_index_set) (noise_remote_t *); void (*u_index_drop) (uint32_t); } l_upcall; } noise_local_t; +/* pool of noise_local */ +extern noise_local_t *noise_local_pool; + /* Set/Get noise parameters */ +static_always_inline noise_local_t * +noise_local_get (uint32_t locali) +{ + return (pool_elt_at_index (noise_local_pool, locali)); +} + void noise_local_init (noise_local_t *, struct noise_upcall *); bool noise_local_set_private (noise_local_t *, const uint8_t[NOISE_PUBLIC_KEY_LEN]); -bool noise_local_keys (noise_local_t *, uint8_t[NOISE_PUBLIC_KEY_LEN], - uint8_t[NOISE_PUBLIC_KEY_LEN]); void noise_remote_init (noise_remote_t *, uint32_t, - const uint8_t[NOISE_PUBLIC_KEY_LEN], noise_local_t *); -bool noise_remote_set_psk (noise_remote_t *, - uint8_t[NOISE_SYMMETRIC_KEY_LEN]); -bool noise_remote_keys (noise_remote_t *, uint8_t[NOISE_PUBLIC_KEY_LEN], - uint8_t[NOISE_SYMMETRIC_KEY_LEN]); + const uint8_t[NOISE_PUBLIC_KEY_LEN], uint32_t); /* Should be called anytime noise_local_set_private is called */ void noise_remote_precompute (noise_remote_t *); diff --git a/src/plugins/wireguard/wireguard_output_tun.c b/src/plugins/wireguard/wireguard_output_tun.c index cdfd9d730f65..9a8710b77db3 100755 --- a/src/plugins/wireguard/wireguard_output_tun.c +++ b/src/plugins/wireguard/wireguard_output_tun.c @@ -15,10 +15,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -28,19 +24,8 @@ _(NONE, "No error") \ _(PEER, "Peer error") \ _(KEYPAIR, "Keypair error") \ - _(HANDSHAKE_SEND, "Handshake sending failed") \ _(TOO_BIG, "packet too big") \ -#define WG_OUTPUT_SCRATCH_SIZE 2048 - -typedef struct wg_output_scratch_t_ -{ - u8 scratch[WG_OUTPUT_SCRATCH_SIZE]; -} wg_output_scratch_t; - -/* Cache line aligned per-thread scratch space */ -static wg_output_scratch_t *wg_output_scratchs; - typedef enum { #define _(sym,str) WG_OUTPUT_ERROR_##sym, @@ -58,6 +43,7 @@ static char *wg_output_error_strings[] = { typedef enum { WG_OUTPUT_NEXT_ERROR, + WG_OUTPUT_NEXT_HANDOFF, WG_OUTPUT_NEXT_INTERFACE_OUTPUT, WG_OUTPUT_N_NEXT, } wg_output_next_t; @@ -65,6 +51,7 @@ typedef enum typedef struct { ip4_udp_header_t hdr; + index_t peer; } wg_output_tun_trace_t; u8 * @@ -87,7 +74,8 @@ format_wg_output_tun_trace (u8 * s, va_list * args) wg_output_tun_trace_t *t = va_arg (*args, wg_output_tun_trace_t *); - s = format (s, "Encrypted packet: %U\n", format_ip4_udp_header, &t->hdr); + s = format (s, "peer: %d\n", t->peer); + s = format (s, " Encrypted packet: %U", format_ip4_udp_header, &t->hdr); return s; } @@ -109,7 +97,6 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, vlib_get_buffers (vm, from, bufs, n_left_from); wg_main_t *wmp = &wg_main; - u32 handsh_fails = 0; wg_peer_t *peer = NULL; while (n_left_from > 0) @@ -119,11 +106,12 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, sizeof (ip4_udp_header_t)); u16 plain_data_len = clib_net_to_host_u16 (((ip4_header_t *) plain_data)->length); + index_t peeri; next[0] = WG_OUTPUT_NEXT_ERROR; - - peer = + peeri = wg_peer_get_by_adj_index (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]); + peer = wg_peer_get (peeri); if (!peer || peer->is_dead) { @@ -131,21 +119,34 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, goto out; } + if (PREDICT_FALSE (~0 == peer->output_thread_index)) + { + /* this is the first packet to use this peer, claim the peer + * for this thread. + */ + clib_atomic_cmp_and_swap (&peer->output_thread_index, ~0, + wg_peer_assign_thread (thread_index)); + } + + if (PREDICT_TRUE (thread_index != peer->output_thread_index)) + { + next[0] = WG_OUTPUT_NEXT_HANDOFF; + goto next; + } + if (PREDICT_FALSE (!peer->remote.r_current)) { - if (PREDICT_FALSE (!wg_send_handshake (vm, peer, false))) - handsh_fails++; + wg_send_handshake_from_mt (peeri, false); b[0]->error = node->errors[WG_OUTPUT_ERROR_KEYPAIR]; goto out; } - size_t encrypted_packet_len = message_data_len (plain_data_len); /* * Ensure there is enough space to write the encrypted data * into the packet */ - if (PREDICT_FALSE (encrypted_packet_len >= WG_OUTPUT_SCRATCH_SIZE) || + if (PREDICT_FALSE (encrypted_packet_len >= WG_DEFAULT_DATA_SIZE) || PREDICT_FALSE ((b[0]->current_data + encrypted_packet_len) >= vlib_buffer_get_default_data_size (vm))) { @@ -154,35 +155,29 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, } message_data_t *encrypted_packet = - (message_data_t *) wg_output_scratchs[thread_index].scratch; + (message_data_t *) wmp->per_thread_data[thread_index].data; enum noise_state_crypt state; state = - noise_remote_encrypt (wmp->vlib_main, + noise_remote_encrypt (vm, &peer->remote, &encrypted_packet->receiver_index, &encrypted_packet->counter, plain_data, plain_data_len, encrypted_packet->encrypted_data); - switch (state) + + if (PREDICT_FALSE (state == SC_KEEP_KEY_FRESH)) + { + wg_send_handshake_from_mt (peeri, false); + } + else if (PREDICT_FALSE (state == SC_FAILED)) { - case SC_OK: - break; - case SC_KEEP_KEY_FRESH: - if (PREDICT_FALSE (!wg_send_handshake (vm, peer, false))) - handsh_fails++; - break; - case SC_FAILED: //TODO: Maybe wrong - if (PREDICT_FALSE (!wg_send_handshake (vm, peer, false))) - handsh_fails++; - clib_mem_free (encrypted_packet); + wg_send_handshake_from_mt (peeri, false); goto out; - default: - break; } - // Here we are sure that can send packet to next node. + /* Here we are sure that can send packet to next node */ next[0] = WG_OUTPUT_NEXT_INTERFACE_OUTPUT; encrypted_packet->header.type = MESSAGE_DATA; @@ -195,9 +190,9 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, ip4_header_set_len_w_chksum (&hdr->ip4, clib_host_to_net_u16 (b[0]->current_length)); - wg_timers_any_authenticated_packet_traversal (peer); wg_timers_any_authenticated_packet_sent (peer); wg_timers_data_sent (peer); + wg_timers_any_authenticated_packet_traversal (peer); out: if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) @@ -206,17 +201,15 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm, wg_output_tun_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t)); t->hdr = *hdr; + t->peer = peeri; } + next: n_left_from -= 1; next += 1; b += 1; } vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); - - vlib_node_increment_counter (vm, node->node_index, - WG_OUTPUT_ERROR_HANDSHAKE_SEND, handsh_fails); - return frame->n_vectors; } @@ -231,24 +224,13 @@ VLIB_REGISTER_NODE (wg_output_tun_node) = .error_strings = wg_output_error_strings, .n_next_nodes = WG_OUTPUT_N_NEXT, .next_nodes = { + [WG_OUTPUT_NEXT_HANDOFF] = "wg-output-tun-handoff", [WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx", [WG_OUTPUT_NEXT_ERROR] = "error-drop", }, }; /* *INDENT-ON* */ -static clib_error_t * -wireguard_output_module_init (vlib_main_t * vm) -{ - vlib_thread_main_t *tm = vlib_get_thread_main (); - - vec_validate_aligned (wg_output_scratchs, tm->n_vlib_mains, - CLIB_CACHE_LINE_BYTES); - return (NULL); -} - -VLIB_INIT_FUNCTION (wireguard_output_module_init); - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c index 30adea82647a..b41118f83d1f 100755 --- a/src/plugins/wireguard/wireguard_peer.c +++ b/src/plugins/wireguard/wireguard_peer.c @@ -23,15 +23,10 @@ #include static fib_source_t wg_fib_source; +wg_peer_t *wg_peer_pool; index_t *wg_peer_by_adj_index; -wg_peer_t * -wg_peer_get (index_t peeri) -{ - return (pool_elt_at_index (wg_main.peers, peeri)); -} - static void wg_peer_endpoint_reset (wg_peer_endpoint_t * ep) { @@ -82,7 +77,11 @@ static void wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) { wg_timers_stop (peer); - noise_remote_clear (vm, &peer->remote); + for (int i = 0; i < WG_N_TIMERS; i++) + { + peer->timers[i] = ~0; + } + peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1); clib_memset (&peer->cookie_maker, 0, sizeof (peer->cookie_maker)); @@ -97,9 +96,18 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) } wg_peer_fib_flush (peer); + peer->input_thread_index = ~0; + peer->output_thread_index = ~0; peer->adj_index = INDEX_INVALID; + peer->timer_wheel = 0; peer->persistent_keepalive_interval = 0; peer->timer_handshake_attempts = 0; + peer->last_sent_packet = 0; + peer->last_received_packet = 0; + peer->session_derived = 0; + peer->rehandshake_started = 0; + peer->new_handshake_interval_tick = 0; + peer->rehandshake_interval_tick = 0; peer->timer_need_another_keepalive = false; peer->is_dead = true; vec_free (peer->allowed_ips); @@ -108,7 +116,7 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) static void wg_peer_init (vlib_main_t * vm, wg_peer_t * peer) { - wg_timers_init (peer, vlib_time_now (vm)); + peer->adj_index = INDEX_INVALID; wg_peer_clear (vm, peer); } @@ -205,8 +213,9 @@ wg_peer_fill (vlib_main_t * vm, wg_peer_t * peer, wg_peer_endpoint_init (&peer->dst, dst, port); peer->table_id = table_id; - peer->persistent_keepalive_interval = persistent_keepalive_interval; peer->wg_sw_if_index = wg_sw_if_index; + peer->timer_wheel = &wg_main.timer_wheel; + peer->persistent_keepalive_interval = persistent_keepalive_interval; peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1); peer->is_dead = false; @@ -230,7 +239,7 @@ wg_peer_fill (vlib_main_t * vm, wg_peer_t * peer, vec_validate_init_empty (wg_peer_by_adj_index, peer->adj_index, INDEX_INVALID); - wg_peer_by_adj_index[peer->adj_index] = peer - wg_main.peers; + wg_peer_by_adj_index[peer->adj_index] = peer - wg_peer_pool; adj_nbr_midchain_update_rewrite (peer->adj_index, NULL, @@ -280,7 +289,7 @@ wg_peer_add (u32 tun_sw_if_index, return (VNET_API_ERROR_INVALID_SW_IF_INDEX); /* *INDENT-OFF* */ - pool_foreach (peer, wg_main.peers, + pool_foreach (peer, wg_peer_pool, ({ if (!memcmp (peer->remote.r_public, public_key, NOISE_PUBLIC_KEY_LEN)) { @@ -289,10 +298,10 @@ wg_peer_add (u32 tun_sw_if_index, })); /* *INDENT-ON* */ - if (pool_elts (wg_main.peers) > MAX_PEERS) + if (pool_elts (wg_peer_pool) > MAX_PEERS) return (VNET_API_ERROR_LIMIT_EXCEEDED); - pool_get (wg_main.peers, peer); + pool_get (wg_peer_pool, peer); wg_peer_init (vm, peer); @@ -302,12 +311,12 @@ wg_peer_add (u32 tun_sw_if_index, if (rv) { wg_peer_clear (vm, peer); - pool_put (wg_main.peers, peer); + pool_put (wg_peer_pool, peer); return (rv); } - noise_remote_init (&peer->remote, peer - wg_main.peers, public_key, - &wg_if->local); + noise_remote_init (&peer->remote, peer - wg_peer_pool, public_key, + wg_if->local_idx); cookie_maker_init (&peer->cookie_maker, public_key); if (peer->persistent_keepalive_interval != 0) @@ -315,7 +324,7 @@ wg_peer_add (u32 tun_sw_if_index, wg_send_keepalive (vm, peer); } - *peer_index = peer - wg_main.peers; + *peer_index = peer - wg_peer_pool; wg_if_peer_add (wg_if, *peer_index); return (0); @@ -328,34 +337,37 @@ wg_peer_remove (index_t peeri) wg_peer_t *peer = NULL; wg_if_t *wgi; - if (pool_is_free_index (wmp->peers, peeri)) + if (pool_is_free_index (wg_peer_pool, peeri)) return VNET_API_ERROR_NO_SUCH_ENTRY; - peer = pool_elt_at_index (wmp->peers, peeri); + peer = pool_elt_at_index (wg_peer_pool, peeri); wgi = wg_if_get (wg_if_find_by_sw_if_index (peer->wg_sw_if_index)); wg_if_peer_remove (wgi, peeri); vnet_feature_enable_disable ("ip4-output", "wg-output-tun", peer->wg_sw_if_index, 0, 0, 0); + + noise_remote_clear (wmp->vlib_main, &peer->remote); wg_peer_clear (wmp->vlib_main, peer); - pool_put (wmp->peers, peer); + pool_put (wg_peer_pool, peer); return (0); } -void +index_t wg_peer_walk (wg_peer_walk_cb_t fn, void *data) { index_t peeri; /* *INDENT-OFF* */ - pool_foreach_index(peeri, wg_main.peers, + pool_foreach_index(peeri, wg_peer_pool, { if (WALK_STOP == fn(peeri, data)) - break; + return peeri; }); /* *INDENT-ON* */ + return INDEX_INVALID; } static u8 * diff --git a/src/plugins/wireguard/wireguard_peer.h b/src/plugins/wireguard/wireguard_peer.h index 99c73f3a0edd..009a6f67aeb4 100755 --- a/src/plugins/wireguard/wireguard_peer.h +++ b/src/plugins/wireguard/wireguard_peer.h @@ -49,6 +49,9 @@ typedef struct wg_peer noise_remote_t remote; cookie_maker_t cookie_maker; + u32 input_thread_index; + u32 output_thread_index; + /* Peer addresses */ wg_peer_endpoint_t dst; wg_peer_endpoint_t src; @@ -65,11 +68,22 @@ typedef struct wg_peer u32 wg_sw_if_index; /* Timers */ - tw_timer_wheel_16t_2w_512sl_t timer_wheel; + tw_timer_wheel_16t_2w_512sl_t *timer_wheel; u32 timers[WG_N_TIMERS]; u32 timer_handshake_attempts; u16 persistent_keepalive_interval; + + /* Timestamps */ f64 last_sent_handshake; + f64 last_sent_packet; + f64 last_received_packet; + f64 session_derived; + f64 rehandshake_started; + + /* Variable intervals */ + u32 new_handshake_interval_tick; + u32 rehandshake_interval_tick; + bool timer_need_another_keepalive; bool is_dead; @@ -91,10 +105,9 @@ int wg_peer_add (u32 tun_sw_if_index, int wg_peer_remove (u32 peer_index); typedef walk_rc_t (*wg_peer_walk_cb_t) (index_t peeri, void *arg); -void wg_peer_walk (wg_peer_walk_cb_t fn, void *data); +index_t wg_peer_walk (wg_peer_walk_cb_t fn, void *data); u8 *format_wg_peer (u8 * s, va_list * va); -wg_peer_t *wg_peer_get (index_t peeri); walk_rc_t wg_peer_if_admin_state_change (wg_if_t * wgi, index_t peeri, void *data); @@ -104,11 +117,30 @@ walk_rc_t wg_peer_if_table_change (wg_if_t * wgi, index_t peeri, void *data); * Expoed for the data-plane */ extern index_t *wg_peer_by_adj_index; +extern wg_peer_t *wg_peer_pool; static inline wg_peer_t * +wg_peer_get (index_t peeri) +{ + return (pool_elt_at_index (wg_peer_pool, peeri)); +} + +static inline index_t wg_peer_get_by_adj_index (index_t ai) { - return wg_peer_get (wg_peer_by_adj_index[ai]); + return (wg_peer_by_adj_index[ai]); +} + +/* + * Makes choice for thread_id should be assigned. +*/ +static inline u32 +wg_peer_assign_thread (u32 thread_id) +{ + return ((thread_id) ? thread_id + : (vlib_num_workers ()? + ((unix_time_now_nsec () % vlib_num_workers ()) + + 1) : thread_id)); } #endif // __included_wg_peer_h__ diff --git a/src/plugins/wireguard/wireguard_send.c b/src/plugins/wireguard/wireguard_send.c index a5d8aaf69009..2e29a9b4b763 100755 --- a/src/plugins/wireguard/wireguard_send.c +++ b/src/plugins/wireguard/wireguard_send.c @@ -14,13 +14,11 @@ */ #include -#include -#include -#include #include #include #include #include +#include #include #include @@ -86,7 +84,8 @@ wg_create_buffer (vlib_main_t * vm, bool wg_send_handshake (vlib_main_t * vm, wg_peer_t * peer, bool is_retry) { - wg_main_t *wmp = &wg_main; + ASSERT (vm->thread_index == 0); + message_handshake_initiation_t packet; if (!is_retry) @@ -94,41 +93,73 @@ wg_send_handshake (vlib_main_t * vm, wg_peer_t * peer, bool is_retry) if (!wg_birthdate_has_expired (peer->last_sent_handshake, REKEY_TIMEOUT) || peer->is_dead) - { - return true; - } - if (noise_create_initiation (wmp->vlib_main, + return true; + + if (noise_create_initiation (vm, &peer->remote, &packet.sender_index, packet.unencrypted_ephemeral, packet.encrypted_static, packet.encrypted_timestamp)) { - f64 now = vlib_time_now (vm); packet.header.type = MESSAGE_HANDSHAKE_INITIATION; cookie_maker_mac (&peer->cookie_maker, &packet.macs, &packet, sizeof (packet)); - wg_timers_any_authenticated_packet_traversal (peer); wg_timers_any_authenticated_packet_sent (peer); - peer->last_sent_handshake = now; wg_timers_handshake_initiated (peer); + wg_timers_any_authenticated_packet_traversal (peer); + + peer->last_sent_handshake = vlib_time_now (vm); } else return false; + u32 bi0 = 0; if (!wg_create_buffer (vm, peer, (u8 *) & packet, sizeof (packet), &bi0)) return false; - ip46_enqueue_packet (vm, bi0, false); + ip46_enqueue_packet (vm, bi0, false); return true; } +typedef struct +{ + u32 peer_idx; + bool is_retry; +} wg_send_args_t; + +static void * +wg_send_handshake_thread_fn (void *arg) +{ + wg_send_args_t *a = arg; + + wg_main_t *wmp = &wg_main; + wg_peer_t *peer = wg_peer_get (a->peer_idx); + + wg_send_handshake (wmp->vlib_main, peer, a->is_retry); + return 0; +} + +void +wg_send_handshake_from_mt (u32 peer_idx, bool is_retry) +{ + wg_send_args_t a = { + .peer_idx = peer_idx, + .is_retry = is_retry, + }; + + vl_api_rpc_call_main_thread (wg_send_handshake_thread_fn, + (u8 *) & a, sizeof (a)); +} + bool wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer) { - wg_main_t *wmp = &wg_main; + ASSERT (vm->thread_index == 0); + u32 size_of_packet = message_data_len (0); - message_data_t *packet = clib_mem_alloc (size_of_packet); + message_data_t *packet = + (message_data_t *) wg_main.per_thread_data[vm->thread_index].data; u32 bi0 = 0; bool ret = true; enum noise_state_crypt state; @@ -140,23 +171,21 @@ wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer) } state = - noise_remote_encrypt (wmp->vlib_main, + noise_remote_encrypt (vm, &peer->remote, &packet->receiver_index, &packet->counter, NULL, 0, packet->encrypted_data); - switch (state) + + if (PREDICT_FALSE (state == SC_KEEP_KEY_FRESH)) { - case SC_OK: - break; - case SC_KEEP_KEY_FRESH: wg_send_handshake (vm, peer, false); - break; - case SC_FAILED: + } + else if (PREDICT_FALSE (state == SC_FAILED)) + { ret = false; goto out; - default: - break; } + packet->header.type = MESSAGE_DATA; if (!wg_create_buffer (vm, peer, (u8 *) packet, size_of_packet, &bi0)) @@ -166,22 +195,19 @@ wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer) } ip46_enqueue_packet (vm, bi0, false); - wg_timers_any_authenticated_packet_traversal (peer); + wg_timers_any_authenticated_packet_sent (peer); + wg_timers_any_authenticated_packet_traversal (peer); out: - clib_mem_free (packet); return ret; } bool wg_send_handshake_response (vlib_main_t * vm, wg_peer_t * peer) { - wg_main_t *wmp = &wg_main; message_handshake_response_t packet; - peer->last_sent_handshake = vlib_time_now (vm); - if (noise_create_response (vm, &peer->remote, &packet.sender_index, @@ -189,17 +215,16 @@ wg_send_handshake_response (vlib_main_t * vm, wg_peer_t * peer) packet.unencrypted_ephemeral, packet.encrypted_nothing)) { - f64 now = vlib_time_now (vm); packet.header.type = MESSAGE_HANDSHAKE_RESPONSE; cookie_maker_mac (&peer->cookie_maker, &packet.macs, &packet, sizeof (packet)); - if (noise_remote_begin_session (wmp->vlib_main, &peer->remote)) + if (noise_remote_begin_session (vm, &peer->remote)) { wg_timers_session_derived (peer); - wg_timers_any_authenticated_packet_traversal (peer); wg_timers_any_authenticated_packet_sent (peer); - peer->last_sent_handshake = now; + wg_timers_any_authenticated_packet_traversal (peer); + peer->last_sent_handshake = vlib_time_now (vm); u32 bi0 = 0; if (!wg_create_buffer (vm, peer, (u8 *) & packet, diff --git a/src/plugins/wireguard/wireguard_send.h b/src/plugins/wireguard/wireguard_send.h index 4ea1f6effea5..efe419494282 100755 --- a/src/plugins/wireguard/wireguard_send.h +++ b/src/plugins/wireguard/wireguard_send.h @@ -20,6 +20,7 @@ bool wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer); bool wg_send_handshake (vlib_main_t * vm, wg_peer_t * peer, bool is_retry); +void wg_send_handshake_from_mt (u32 peer_index, bool is_retry); bool wg_send_handshake_response (vlib_main_t * vm, wg_peer_t * peer); always_inline void diff --git a/src/plugins/wireguard/wireguard_timer.c b/src/plugins/wireguard/wireguard_timer.c index e4d4030bb185..b7fd6891d149 100755 --- a/src/plugins/wireguard/wireguard_timer.c +++ b/src/plugins/wireguard/wireguard_timer.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include #include #include #include @@ -30,31 +31,77 @@ stop_timer (wg_peer_t * peer, u32 timer_id) { if (peer->timers[timer_id] != ~0) { - tw_timer_stop_16t_2w_512sl (&peer->timer_wheel, peer->timers[timer_id]); + tw_timer_stop_16t_2w_512sl (peer->timer_wheel, peer->timers[timer_id]); peer->timers[timer_id] = ~0; } } static void -start_or_update_timer (wg_peer_t * peer, u32 timer_id, u32 interval) +start_timer (wg_peer_t * peer, u32 timer_id, u32 interval_ticks) { + ASSERT (vlib_get_thread_index () == 0); + if (peer->timers[timer_id] == ~0) { - wg_main_t *wmp = &wg_main; peer->timers[timer_id] = - tw_timer_start_16t_2w_512sl (&peer->timer_wheel, peer - wmp->peers, - timer_id, interval); - } - else - { - tw_timer_update_16t_2w_512sl (&peer->timer_wheel, - peer->timers[timer_id], interval); + tw_timer_start_16t_2w_512sl (peer->timer_wheel, peer - wg_peer_pool, + timer_id, interval_ticks); } } +typedef struct +{ + u32 peer_idx; + u32 timer_id; + u32 interval_ticks; + +} wg_timers_args; + +static void * +start_timer_thread_fn (void *arg) +{ + wg_timers_args *a = arg; + wg_peer_t *peer = wg_peer_get (a->peer_idx); + + start_timer (peer, a->timer_id, a->interval_ticks); + return 0; +} + +static void +start_timer_from_mt (u32 peer_idx, u32 timer_id, u32 interval_ticks) +{ + wg_timers_args a = { + .peer_idx = peer_idx, + .timer_id = timer_id, + .interval_ticks = interval_ticks, + }; + + vl_api_rpc_call_main_thread (start_timer_thread_fn, (u8 *) & a, sizeof (a)); +} + +static inline u32 +timer_ticks_left (vlib_main_t * vm, f64 init_time_sec, u32 interval_ticks) +{ + static const int32_t rounding = (int32_t) (WHZ / 2); + int32_t ticks_remain; + + ticks_remain = (init_time_sec - vlib_time_now (vm)) * WHZ + interval_ticks; + return (ticks_remain > rounding) ? (u32) ticks_remain : 0; +} + static void wg_expired_retransmit_handshake (vlib_main_t * vm, wg_peer_t * peer) { + if (peer->rehandshake_started == ~0) + return; + + u32 ticks = timer_ticks_left (vm, peer->rehandshake_started, + peer->rehandshake_interval_tick); + if (ticks) + { + start_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE, ticks); + return; + } if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) { @@ -63,17 +110,8 @@ wg_expired_retransmit_handshake (vlib_main_t * vm, wg_peer_t * peer) /* We set a timer for destroying any residue that might be left * of a partial exchange. */ + start_timer (peer, WG_TIMER_KEY_ZEROING, REJECT_AFTER_TIME * 3 * WHZ); - if (peer->timers[WG_TIMER_KEY_ZEROING] == ~0) - { - wg_main_t *wmp = &wg_main; - - peer->timers[WG_TIMER_KEY_ZEROING] = - tw_timer_start_16t_2w_512sl (&peer->timer_wheel, - peer - wmp->peers, - WG_TIMER_KEY_ZEROING, - REJECT_AFTER_TIME * 3 * WHZ); - } } else { @@ -85,13 +123,23 @@ wg_expired_retransmit_handshake (vlib_main_t * vm, wg_peer_t * peer) static void wg_expired_send_keepalive (vlib_main_t * vm, wg_peer_t * peer) { - wg_send_keepalive (vm, peer); - - if (peer->timer_need_another_keepalive) + if (peer->last_sent_packet < peer->last_received_packet) { - peer->timer_need_another_keepalive = false; - start_or_update_timer (peer, WG_TIMER_SEND_KEEPALIVE, - KEEPALIVE_TIMEOUT * WHZ); + u32 ticks = timer_ticks_left (vm, peer->last_received_packet, + KEEPALIVE_TIMEOUT * WHZ); + if (ticks) + { + start_timer (peer, WG_TIMER_SEND_KEEPALIVE, ticks); + return; + } + + wg_send_keepalive (vm, peer); + if (peer->timer_need_another_keepalive) + { + peer->timer_need_another_keepalive = false; + start_timer (peer, WG_TIMER_SEND_KEEPALIVE, + KEEPALIVE_TIMEOUT * WHZ); + } } } @@ -100,6 +148,18 @@ wg_expired_send_persistent_keepalive (vlib_main_t * vm, wg_peer_t * peer) { if (peer->persistent_keepalive_interval) { + f64 latest_time = peer->last_sent_packet > peer->last_received_packet + ? peer->last_sent_packet : peer->last_received_packet; + + u32 ticks = timer_ticks_left (vm, latest_time, + peer->persistent_keepalive_interval * + WHZ); + if (ticks) + { + start_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE, ticks); + return; + } + wg_send_keepalive (vm, peer); } } @@ -107,64 +167,81 @@ wg_expired_send_persistent_keepalive (vlib_main_t * vm, wg_peer_t * peer) static void wg_expired_new_handshake (vlib_main_t * vm, wg_peer_t * peer) { + u32 ticks = timer_ticks_left (vm, peer->last_sent_packet, + peer->new_handshake_interval_tick); + if (ticks) + { + start_timer (peer, WG_TIMER_NEW_HANDSHAKE, ticks); + return; + } + wg_send_handshake (vm, peer, false); } static void wg_expired_zero_key_material (vlib_main_t * vm, wg_peer_t * peer) { + u32 ticks = + timer_ticks_left (vm, peer->session_derived, REJECT_AFTER_TIME * 3 * WHZ); + if (ticks) + { + start_timer (peer, WG_TIMER_KEY_ZEROING, ticks); + return; + } + if (!peer->is_dead) { noise_remote_clear (vm, &peer->remote); } } - void wg_timers_any_authenticated_packet_traversal (wg_peer_t * peer) { if (peer->persistent_keepalive_interval) { - start_or_update_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE, - peer->persistent_keepalive_interval * WHZ); + start_timer_from_mt (peer - wg_peer_pool, + WG_TIMER_PERSISTENT_KEEPALIVE, + peer->persistent_keepalive_interval * WHZ); } } void wg_timers_any_authenticated_packet_sent (wg_peer_t * peer) { - stop_timer (peer, WG_TIMER_SEND_KEEPALIVE); + peer->last_sent_packet = vlib_time_now (vlib_get_main ()); } void wg_timers_handshake_initiated (wg_peer_t * peer) { - u32 interval = + peer->rehandshake_started = vlib_time_now (vlib_get_main ()); + peer->rehandshake_interval_tick = REKEY_TIMEOUT * WHZ + get_random_u32_max (REKEY_TIMEOUT_JITTER); - start_or_update_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE, interval); + + start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_RETRANSMIT_HANDSHAKE, + peer->rehandshake_interval_tick); } void wg_timers_session_derived (wg_peer_t * peer) { - start_or_update_timer (peer, WG_TIMER_KEY_ZEROING, - REJECT_AFTER_TIME * 3 * WHZ); + peer->session_derived = vlib_time_now (vlib_get_main ()); + + start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_KEY_ZEROING, + REJECT_AFTER_TIME * 3 * WHZ); } /* Should be called after an authenticated data packet is sent. */ void wg_timers_data_sent (wg_peer_t * peer) { - u32 interval = (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * WHZ + + peer->new_handshake_interval_tick = + (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * WHZ + get_random_u32_max (REKEY_TIMEOUT_JITTER); - if (peer->timers[WG_TIMER_NEW_HANDSHAKE] == ~0) - { - wg_main_t *wmp = &wg_main; - peer->timers[WG_TIMER_NEW_HANDSHAKE] = - tw_timer_start_16t_2w_512sl (&peer->timer_wheel, peer - wmp->peers, - WG_TIMER_NEW_HANDSHAKE, interval); - } + start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_NEW_HANDSHAKE, + peer->new_handshake_interval_tick); } /* Should be called after an authenticated data packet is received. */ @@ -173,16 +250,11 @@ wg_timers_data_received (wg_peer_t * peer) { if (peer->timers[WG_TIMER_SEND_KEEPALIVE] == ~0) { - wg_main_t *wmp = &wg_main; - peer->timers[WG_TIMER_SEND_KEEPALIVE] = - tw_timer_start_16t_2w_512sl (&peer->timer_wheel, peer - wmp->peers, - WG_TIMER_SEND_KEEPALIVE, - KEEPALIVE_TIMEOUT * WHZ); + start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_SEND_KEEPALIVE, + KEEPALIVE_TIMEOUT * WHZ); } else - { - peer->timer_need_another_keepalive = true; - } + peer->timer_need_another_keepalive = true; } /* Should be called after a handshake response message is received and processed @@ -191,15 +263,14 @@ wg_timers_data_received (wg_peer_t * peer) void wg_timers_handshake_complete (wg_peer_t * peer) { - stop_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE); - + peer->rehandshake_started = ~0; peer->timer_handshake_attempts = 0; } void wg_timers_any_authenticated_packet_received (wg_peer_t * peer) { - stop_timer (peer, WG_TIMER_NEW_HANDSHAKE); + peer->last_received_packet = vlib_time_now (vlib_get_main ()); } static vlib_node_registration_t wg_timer_mngr_node; @@ -222,7 +293,7 @@ expired_timer_callback (u32 * expired_timers) pool_index = expired_timers[i] & 0x0FFFFFFF; timer_id = expired_timers[i] >> 28; - peer = pool_elt_at_index (wmp->peers, pool_index); + peer = wg_peer_get (pool_index); peer->timers[timer_id] = ~0; } @@ -231,7 +302,7 @@ expired_timer_callback (u32 * expired_timers) pool_index = expired_timers[i] & 0x0FFFFFFF; timer_id = expired_timers[i] >> 28; - peer = pool_elt_at_index (wmp->peers, pool_index); + peer = wg_peer_get (pool_index); switch (timer_id) { case WG_TIMER_RETRANSMIT_HANDSHAKE: @@ -256,18 +327,14 @@ expired_timer_callback (u32 * expired_timers) } void -wg_timers_init (wg_peer_t * peer, f64 now) +wg_timer_wheel_init () { - for (int i = 0; i < WG_N_TIMERS; i++) - { - peer->timers[i] = ~0; - } - tw_timer_wheel_16t_2w_512sl_t *tw = &peer->timer_wheel; + wg_main_t *wmp = &wg_main; + tw_timer_wheel_16t_2w_512sl_t *tw = &wmp->timer_wheel; tw_timer_wheel_init_16t_2w_512sl (tw, expired_timer_callback, WG_TICK /* timer period in s */ , ~0); - tw->last_run_time = now; - peer->adj_index = INDEX_INVALID; + tw->last_run_time = vlib_time_now (wmp->vlib_main); } static uword @@ -275,22 +342,13 @@ wg_timer_mngr_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { wg_main_t *wmp = &wg_main; - wg_peer_t *peers; - wg_peer_t *peer; - while (1) { vlib_process_wait_for_event_or_clock (vm, WG_TICK); vlib_process_get_events (vm, NULL); - peers = wmp->peers; - /* *INDENT-OFF* */ - pool_foreach (peer, peers, - ({ - tw_timer_expire_timers_16t_2w_512sl - (&peer->timer_wheel, vlib_time_now (vm)); - })); - /* *INDENT-ON* */ + tw_timer_expire_timers_16t_2w_512sl (&wmp->timer_wheel, + vlib_time_now (vm)); } return 0; @@ -299,11 +357,15 @@ wg_timer_mngr_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, void wg_timers_stop (wg_peer_t * peer) { - stop_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE); - stop_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE); - stop_timer (peer, WG_TIMER_SEND_KEEPALIVE); - stop_timer (peer, WG_TIMER_NEW_HANDSHAKE); - stop_timer (peer, WG_TIMER_KEY_ZEROING); + ASSERT (vlib_get_thread_index () == 0); + if (peer->timer_wheel) + { + stop_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE); + stop_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE); + stop_timer (peer, WG_TIMER_SEND_KEEPALIVE); + stop_timer (peer, WG_TIMER_NEW_HANDSHAKE); + stop_timer (peer, WG_TIMER_KEY_ZEROING); + } } /* *INDENT-OFF* */ diff --git a/src/plugins/wireguard/wireguard_timer.h b/src/plugins/wireguard/wireguard_timer.h index 457dce286744..2cc5dd012844 100755 --- a/src/plugins/wireguard/wireguard_timer.h +++ b/src/plugins/wireguard/wireguard_timer.h @@ -38,7 +38,7 @@ typedef enum _wg_timers typedef struct wg_peer wg_peer_t; -void wg_timers_init (wg_peer_t * peer, f64 now); +void wg_timer_wheel_init (); void wg_timers_stop (wg_peer_t * peer); void wg_timers_data_sent (wg_peer_t * peer); void wg_timers_data_received (wg_peer_t * peer); From df143bf7054a1db94816ae6c8c59ccf34405af46 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 24 Sep 2020 17:18:13 -0700 Subject: [PATCH 051/129] wireguard: fix uninitialized peer index in handoff Type: fix Signed-off-by: Florin Coras Change-Id: I41513b9aa6ca0db1fb9392a15e5ac329a635ebfa --- src/plugins/wireguard/wireguard_handoff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/wireguard/wireguard_handoff.c b/src/plugins/wireguard/wireguard_handoff.c index b0b742294520..8a2efa508b35 100644 --- a/src/plugins/wireguard/wireguard_handoff.c +++ b/src/plugins/wireguard/wireguard_handoff.c @@ -79,7 +79,7 @@ wg_handoff (vlib_main_t * vm, while (n_left_from > 0) { const wg_peer_t *peer; - index_t peeri; + index_t peeri = INDEX_INVALID; if (PREDICT_FALSE (mode == WG_HANDOFF_HANDSHAKE)) { From a26b40af90d315bee9a53d39a6d4b6102b981551 Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Fri, 25 Sep 2020 09:43:45 +0000 Subject: [PATCH 052/129] bfd: add missing unlock Thanks to Martin Sustrik for spotting the bug introduced by a316744 and submitting the fix. Type: fix Signed-off-by: Klement Sekera Change-Id: I4984fc32503b0c7b6db3543834dfbbfed2a1f23c --- src/vnet/bfd/bfd_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vnet/bfd/bfd_main.c b/src/vnet/bfd/bfd_main.c index 4b8975732af2..807221637624 100644 --- a/src/vnet/bfd/bfd_main.c +++ b/src/vnet/bfd/bfd_main.c @@ -1190,6 +1190,7 @@ bfd_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) } else { + bfd_unlock (bm); (void) vlib_process_wait_for_event (vm); } event_type = vlib_process_get_events (vm, &event_data); From c7b359ff538f53a974b88ab1447bef9736495f4f Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Fri, 25 Sep 2020 13:07:32 +0000 Subject: [PATCH 053/129] misc: documentation fixes Change-Id: Id7ae7bbc53e89777892b973008baa93f1a083aac Type: docs Signed-off-by: Andrew Yourtchenko --- doxygen/user_doc.md | 5 ++--- src/plugins/wireguard/README.md | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md index 009af67cf1a7..0610adc74583 100644 --- a/doxygen/user_doc.md +++ b/doxygen/user_doc.md @@ -4,24 +4,22 @@ User Documentation {#user_doc} Several modules provide operational, dataplane-user focused documentation. - [GUI guided user demo](https://wiki.fd.io/view/VPP_Sandbox/vpp-userdemo) +- @subpage af_xdp_doc - @subpage avf_plugin_doc - @subpage bfd_doc - @subpage dpdk_crypto_ipsec_doc - @subpage dhcp6_pd_doc - @subpage flowprobe_plugin_doc - @subpage ioam_plugin_doc -- @subpage kp_plugin_doc - @subpage lacp_plugin_doc - @subpage lb_plugin_doc - @subpage lldp_doc - @subpage map_doc - @subpage marvel_plugin_doc -- @subpage srv6_mobile_plugin - @subpage mtu_doc - @subpage nat64_doc - @subpage nat_ha_doc - @subpage qos_doc -- @subpage quic_doc - @subpage rdma_doc - @subpage selinux_doc - @subpage span_doc @@ -29,3 +27,4 @@ Several modules provide operational, dataplane-user focused documentation. - @subpage srv6_doc - @subpage vcl_ldpreload_doc - @subpage vmxnet3_doc +- @subpage wireguard_plugin_doc diff --git a/src/plugins/wireguard/README.md b/src/plugins/wireguard/README.md index a11356cfde2d..e313a32142ce 100755 --- a/src/plugins/wireguard/README.md +++ b/src/plugins/wireguard/README.md @@ -1,4 +1,4 @@ -# Wireguard vpp-plugin +# Wireguard vpp-plugin {#wireguard_plugin_doc} ## Overview This plugin is an implementation of [wireguard protocol](https://www.wireguard.com/) for VPP. It allows one to create secure VPN tunnels. From a0b1329aa66a66841f52b923693490f95d4fb1ef Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Mon, 28 Sep 2020 12:14:51 +0000 Subject: [PATCH 054/129] dpdk: Revert "prevent linking dpdk against libbsd" This reverts commit 7a7601795171665eb71461c705f3fbb4b6c6f1ad. After discussion with Damjan, the change is more risky than it seemed, so revert. Type: fix Signed-off-by: Andrew Yourtchenko Change-Id: I67defb01a0bebb8ff4231c27690b694f608fcb8e --- build/external/packages/dpdk.mk | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/build/external/packages/dpdk.mk b/build/external/packages/dpdk.mk index 49761cd56a47..ef84383d55a7 100644 --- a/build/external/packages/dpdk.mk +++ b/build/external/packages/dpdk.mk @@ -12,7 +12,6 @@ # limitations under the License. DPDK_PKTMBUF_HEADROOM ?= 128 -DPDK_USE_LIBBSD ?= n DPDK_DEBUG ?= n DPDK_MLX4_PMD ?= n DPDK_MLX5_PMD ?= n @@ -119,19 +118,6 @@ echo '$(HASH)define RTE_$(1) $(DPDK_$(1))' \ fi endef -define dpdk_config_def -if [[ "$(DPDK_$(1))" == "y" ]]; then \ - if ! grep -q "RTE_$(1)" $(dpdk_build_dir)/rte_build_config.h \ - $(dpdk_src_dir)/config/rte_config.h ; then \ - echo '$(HASH)define RTE_$(1) 1' \ - >> $(dpdk_build_dir)/rte_build_config.h ; \ - fi; \ -elif [[ "$(DPDK_$(1))" == "n" ]]; then \ - sed -i '/$(HASH)define RTE_$(1) .*/d' $(dpdk_build_dir)/rte_build_config.h \ - $(dpdk_src_dir)/config/rte_config.h ; \ -fi -endef - DPDK_MESON_ARGS = \ --default-library static \ --libdir lib \ @@ -157,8 +143,7 @@ define dpdk_config_cmds deactivate && \ echo "DPDK post meson configuration" && \ echo "Altering rte_build_config.h" && \ - $(call dpdk_config,PKTMBUF_HEADROOM) && \ - $(call dpdk_config_def,USE_LIBBSD) + $(call dpdk_config,PKTMBUF_HEADROOM) endef define dpdk_build_cmds From 29fd163e1c4182dc19d8e4e1032538cc9a5d4a04 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Mon, 28 Sep 2020 12:18:05 +0000 Subject: [PATCH 055/129] dpdk: Revert "call the meson-based build instead of Makefiles" This reverts commit 73903d7e8a6141237637b2011386c7ee6ac969ee. After discussion with Damjan, the change is more risky than it seemed, so revert. Type: fix Signed-off-by: Andrew Yourtchenko Change-Id: Idee82806cd4a12a92540f904397d259b531770d1 Signed-off-by: Andrew Yourtchenko --- build/external/packages/dpdk.mk | 403 ++++++++++++------ .../0002-build-system-selective-libs.patch | 88 ---- 2 files changed, 271 insertions(+), 220 deletions(-) delete mode 100644 build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch diff --git a/build/external/packages/dpdk.mk b/build/external/packages/dpdk.mk index ef84383d55a7..beabf48e94ea 100644 --- a/build/external/packages/dpdk.mk +++ b/build/external/packages/dpdk.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Cisco and/or its affiliates. +# Copyright (c) 2018 Cisco and/or its affiliates. # 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: @@ -12,156 +12,295 @@ # limitations under the License. DPDK_PKTMBUF_HEADROOM ?= 128 +DPDK_CACHE_LINE_SIZE ?= 64 +DPDK_DOWNLOAD_DIR ?= $(DL_CACHE_DIR) DPDK_DEBUG ?= n +DPDK_AARCH64_GENERIC ?= y DPDK_MLX4_PMD ?= n DPDK_MLX5_PMD ?= n -DPDK_MLX5_COMMON_PMD ?= n DPDK_TAP_PMD ?= n DPDK_FAILSAFE_PMD ?= n -DPDK_MACHINE ?= default -dpdk_version ?= 20.08 -dpdk_base_url ?= http://fast.dpdk.org/rel -dpdk_tarball := dpdk-$(dpdk_version).tar.xz -dpdk_tarball_md5sum_20.08 := 64badd32cd6bc0761befc8f2402c2148 -dpdk_tarball_md5sum := $(dpdk_tarball_md5sum_$(dpdk_version)) -dpdk_url := $(dpdk_base_url)/$(dpdk_tarball) -dpdk_tarball_strip_dirs := 1 +DPDK_VERSION ?= 20.08 +DPDK_BASE_URL ?= http://fast.dpdk.org/rel +DPDK_TARBALL := dpdk-$(DPDK_VERSION).tar.xz +DPDK_TAR_URL := $(DPDK_BASE_URL)/$(DPDK_TARBALL) +DPDK_18.11_TARBALL_MD5_CKSUM := 04b86f4a77f4f81a7fbd26467dd2ea9f +DPDK_20.05_TARBALL_MD5_CKSUM := 7c6f3e7f7de2422775c4cba116012c4d +DPDK_20.08_TARBALL_MD5_CKSUM := 64badd32cd6bc0761befc8f2402c2148 +MACHINE=$(shell uname -m) -# Debug or release +# replace dot with space, and if 3rd word exists we deal with stable dpdk rel +ifeq ($(word 3,$(subst ., ,$(DPDK_VERSION))),) +DPDK_SOURCE := $(B)/dpdk-$(DPDK_VERSION) +else +DPDK_SOURCE := $(B)/dpdk-stable-$(DPDK_VERSION) +endif + +ifeq ($(MACHINE),$(filter $(MACHINE),x86_64)) + AESNI ?= y + DPDK_BUILD_DEPS := ipsec-mb-install +else + AESNI ?= n +endif + +ifneq (,$(findstring clang,$(CC))) +DPDK_CC=clang +else ifneq (,$(findstring icc,$(CC))) +DPDK_CC=icc +else +DPDK_CC=gcc +endif + +############################################################################## +# Intel x86 +############################################################################## +ifeq ($(MACHINE),$(filter $(MACHINE),x86_64 i686)) +DPDK_TARGET ?= $(MACHINE)-native-linuxapp-$(DPDK_CC) +DPDK_MACHINE ?= nhm +DPDK_TUNE ?= core-avx2 + +############################################################################## +# ARM64 +############################################################################## +else ifeq ($(MACHINE),aarch64) +CROSS := +export CROSS +DPDK_TARGET ?= arm64-armv8a-linuxapp-$(DPDK_CC) +DPDK_MACHINE ?= armv8a +DPDK_TUNE ?= generic +ifeq (y, $(DPDK_AARCH64_GENERIC)) +DPDK_CACHE_LINE_SIZE := 128 +# assign aarch64 variant specific options +else +CPU_IMP_ARM = 0x41 +CPU_IMP_CAVIUM = 0x43 + +CPU_PART_ARM_CORTEX_A53 = 0xd03 +CPU_PART_ARM_CORTEX_A57 = 0xd07 +CPU_PART_ARM_CORTEX_A72 = 0xd08 +CPU_PART_ARM_CORTEX_A73 = 0xd09 + +CPU_PART_CAVIUM_THUNDERX = 0x0a1 +CPU_PART_CAVIUM_THUNDERX_81XX = 0x0a2 +CPU_PART_CAVIUM_THUNDERX_83XX = 0x0a3 -DPDK_BUILD_TYPE:=release -ifeq ($(DPDK_DEBUG), y) -DPDK_BUILD_TYPE:=debug +MIDR_IMPLEMENTER=$(shell awk '/implementer/ {print $$4;exit}' /proc/cpuinfo) +MIDR_PARTNUM=$(shell awk '/part/ {print $$4;exit}' /proc/cpuinfo) + +ifeq ($(MIDR_IMPLEMENTER),$(CPU_IMP_ARM)) +############################################################################## +# Arm Cortex +############################################################################## +CPU_PART_ARM_TUNE := $(CPU_PART_ARM_CORTEX_A53)/cortex-a53 \ + $(CPU_PART_ARM_CORTEX_A57)/cortex-a57 \ + $(CPU_PART_ARM_CORTEX_A72)/cortex-a72 \ + $(CPU_PART_ARM_CORTEX_A73)/cortex-a73 +CPU_TUNE = $(notdir $(filter $(MIDR_PARTNUM)/%,$(CPU_PART_ARM_TUNE))) +ifneq ($(CPU_TUNE),) +DPDK_TUNE = $(CPU_TUNE) +else +$(warning Unknown Arm CPU) endif -DPDK_DRIVERS_DISABLED := baseband/\*, \ - bus/dpaa, \ - bus/ifpga, \ - compress/\*, \ - crypto/ccp, \ - crypto/dpaa_sec, \ - crypto/openssl, \ - event/\*, \ - mempool/dpaa, \ - net/af_packet, \ - net/bnx2x, \ - net/bonding, \ - net/ipn3ke, \ - net/liquidio, \ - net/pcap, \ - net/pfe, \ - net/sfc, \ - net/softnic, \ - net/thunderx, \ - raw/ifpga, \ - net/af_xdp - -DPDK_LIBS_DISABLED := acl, \ - bbdev, \ - bitratestats, \ - bpf, \ - cfgfile, \ - distributor, \ - efd, \ - fib, \ - flow_classify, \ - graph, \ - gro, \ - gso, \ - jobstats, \ - kni, \ - latencystats, \ - lpm, \ - member, \ - node, \ - pipeline, \ - port, \ - power, \ - rawdev, \ - rib, \ - table - -# Adjust disabled pmd and libs depending on user provided variables -ifeq ($(DPDK_MLX4_PMD), n) - DPDK_DRIVERS_DISABLED += ,net/mlx4 +else ifeq ($(MIDR_IMPLEMENTER),$(CPU_IMP_CAVIUM)) +############################################################################## +# Cavium ThunderX +############################################################################## +ifneq (,$(findstring $(MIDR_PARTNUM),$(CPU_PART_CAVIUM_THUNDERX) \ + $(CPU_PART_CAVIUM_THUNDERX_81XX) $(CPU_PART_CAVIUM_THUNDERX_83XX))) +DPDK_TARGET = arm64-thunderx-linuxapp-$(DPDK_CC) +DPDK_MACHINE = thunderx +DPDK_CACHE_LINE_SIZE := 128 +else +$(warning Unknown Cavium CPU) endif -ifeq ($(DPDK_MLX5_PMD), n) - DPDK_DRIVERS_DISABLED += ,net/mlx5 endif -ifeq ($(DPDK_MLX5_COMMON_PMD), n) - DPDK_DRIVERS_DISABLED += ,common/mlx5 + +# finish of assigning aarch64 variant specific options endif -ifeq ($(DPDK_TAP_PMD), n) - DPDK_DRIVERS_DISABLED += ,net/tap + +############################################################################## +# Unknown platform +############################################################################## +else +$(error Unknown platform) endif -ifeq ($(DPDK_FAILSAFE_PMD), n) - DPDK_DRIVERS_DISABLED += ,net/failsafe + +# compiler/linker custom arguments +ifeq ($(DPDK_CC),clang) +DPDK_CPU_CFLAGS := -fPIE -fPIC +else +DPDK_CPU_CFLAGS := -pie -fPIC endif -# Sanitize DPDK_DRIVERS_DISABLED and DPDK_LIBS_DISABLED -DPDK_DRIVERS_DISABLED := $(shell echo $(DPDK_DRIVERS_DISABLED) | tr -d '\\\t ') -DPDK_LIBS_DISABLED := $(shell echo $(DPDK_LIBS_DISABLED) | tr -d '\\\t ') - -HASH := \# -# post-meson-setup snippet to alter rte_build_config.h -define dpdk_config -if grep -q RTE_$(1) $(dpdk_src_dir)/config/rte_config.h ; then \ -sed -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ - $(dpdk_src_dir)/config/rte_config.h; \ -elif grep -q RTE_$(1) $(dpdk_build_dir)/rte_build_config.h ; then \ -sed -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ - $(dpdk_build_dir)/rte_build_config.h; \ -else \ -echo '$(HASH)define RTE_$(1) $(DPDK_$(1))' \ - >> $(dpdk_build_dir)/rte_build_config.h ; \ +ifeq ($(DPDK_DEBUG),n) +DPDK_EXTRA_CFLAGS := -g -mtune=$(DPDK_TUNE) +else +DPDK_EXTRA_CFLAGS := -g -O0 +endif + +# -Wimplicit-fallthrough was introduced starting from GCC 7, +# and it requires newer version of ccache. +# Disable fallthrough warning for old ccache version. +ifeq ($(DPDK_CC),gcc) +GCC_VER_V = "7.0.0" +CCACHE_VER_V = "3.4.1" +GCC_VER = $(shell gcc --version | grep ^gcc | sed 's/^.* //g') +CCACHE_VER = $(shell ccache --version | grep ^ccache | sed 's/^.* //g') +ifeq ($(shell expr "$(GCC_VER)" ">=" "$(GCC_VER_V)"),1) +ifeq ($(shell expr "$(CCACHE_VER)" "<" "$(CCACHE_VER_V)"),1) +DPDK_EXTRA_CFLAGS += -Wimplicit-fallthrough=0 +endif +endif +endif + +DPDK_EXTRA_CFLAGS += -I$(I)/include +DPDK_EXTRA_LDFLAGS += -L$(I)/lib + +# assemble DPDK make arguments +DPDK_MAKE_ARGS := -C $(DPDK_SOURCE) -j $(JOBS) \ + T=$(DPDK_TARGET) \ + RTE_CONFIG_TEMPLATE=../custom-config \ + EXTRA_CFLAGS="$(DPDK_EXTRA_CFLAGS)" \ + EXTRA_LDFLAGS="$(DPDK_EXTRA_LDFLAGS)" \ + CPU_CFLAGS="$(DPDK_CPU_CFLAGS)" \ + DESTDIR=$(I) \ + MAKE_PAUSE=n \ + $(DPDK_MAKE_EXTRA_ARGS) + +define set +@if grep -q CONFIG_$1 $@ ; \ + then sed -i -e 's/.*\(CONFIG_$1=\).*/\1$2/' $@ ; \ + else echo CONFIG_$1=$2 >> $@ ; \ fi endef -DPDK_MESON_ARGS = \ - --default-library static \ - --libdir lib \ - --prefix $(dpdk_install_dir) \ - -Dtests=false \ - "-Ddisable_drivers=$(DPDK_DRIVERS_DISABLED)" \ - "-Ddisable_libs=$(DPDK_LIBS_DISABLED)" \ - -Db_pie=true \ - -Dmachine=$(DPDK_MACHINE) \ - --buildtype=$(DPDK_BUILD_TYPE) - -define dpdk_config_cmds - cd $(dpdk_build_dir) && \ - rm -rf ../dpdk-meson-venv && \ - mkdir -p ../dpdk-meson-venv && \ - python3 -m venv ../dpdk-meson-venv && \ - source ../dpdk-meson-venv/bin/activate && \ - pip3 install meson==0.54 && \ - meson setup $(dpdk_src_dir) \ - $(dpdk_build_dir) \ - $(DPDK_MESON_ARGS) \ - | tee $(dpdk_config_log) && \ - deactivate && \ - echo "DPDK post meson configuration" && \ - echo "Altering rte_build_config.h" && \ - $(call dpdk_config,PKTMBUF_HEADROOM) -endef +$(B)/custom-config: $(B)/.dpdk-patch.ok Makefile + @echo --- generating custom config from $(DPDK_SOURCE)/config/defconfig_$(DPDK_TARGET) --- + @cpp -undef -ffreestanding -x assembler-with-cpp $(DPDK_SOURCE)/config/defconfig_$(DPDK_TARGET) $@ + $(call set,RTE_MACHINE,$(DPDK_MACHINE)) + @# modify options + $(call set,RTE_MAX_LCORE,256) + $(call set,RTE_PKTMBUF_HEADROOM,$(DPDK_PKTMBUF_HEADROOM)) + $(call set,RTE_CACHE_LINE_SIZE,$(DPDK_CACHE_LINE_SIZE)) + $(call set,RTE_BUILD_COMBINE_LIBS,y) + $(call set,RTE_PCI_CONFIG,y) + $(call set,RTE_PCI_EXTENDED_TAG,"on") + $(call set,RTE_PCI_MAX_READ_REQUEST_SIZE,4096) + $(call set,RTE_LIBRTE_PMD_BOND,n) + $(call set,RTE_LIBRTE_IP_FRAG,y) + $(call set,RTE_LIBRTE_PMD_QAT,y) + $(call set,RTE_LIBRTE_PMD_QAT_SYM,y) + $(call set,RTE_LIBRTE_PMD_AESNI_MB,$(AESNI)) + $(call set,RTE_LIBRTE_PMD_AESNI_GCM,$(AESNI)) + $(call set,RTE_LIBRTE_MLX4_PMD,$(DPDK_MLX4_PMD)) + $(call set,RTE_LIBRTE_MLX5_PMD,$(DPDK_MLX5_PMD)) + $(call set,RTE_LIBRTE_BNXT_PMD,y) + $(call set,RTE_LIBRTE_PMD_SOFTNIC,n) + $(call set,RTE_IBVERBS_LINK_DLOPEN,y) + $(call set,RTE_LIBRTE_PMD_TAP,$(DPDK_TAP_PMD)) + $(call set,RTE_LIBRTE_GSO,$(DPDK_TAP_PMD)) + $(call set,RTE_LIBRTE_PMD_FAILSAFE,$(DPDK_FAILSAFE_PMD)) + @# not needed + $(call set,RTE_ETHDEV_RXTX_CALLBACKS,n) + $(call set,RTE_LIBRTE_CFGFILE,n) + $(call set,RTE_LIBRTE_LPM,n) + $(call set,RTE_LIBRTE_ACL,n) + $(call set,RTE_LIBRTE_JOBSTATS,n) + $(call set,RTE_LIBRTE_EFD,n) + $(call set,RTE_LIBRTE_MEMBER,n) + $(call set,RTE_LIBRTE_BITRATE,n) + $(call set,RTE_LIBRTE_LATENCY_STATS,n) + $(call set,RTE_LIBRTE_POWER,n) + $(call set,RTE_LIBRTE_DISTRIBUTOR,n) + $(call set,RTE_LIBRTE_PORT,n) + $(call set,RTE_LIBRTE_TABLE,n) + $(call set,RTE_LIBRTE_PIPELINE,n) + $(call set,RTE_LIBRTE_PMD_SOFTNIC,n) + $(call set,RTE_LIBRTE_FLOW_CLASSIFY,n) + $(call set,RTE_LIBRTE_ACL,n) + $(call set,RTE_LIBRTE_GRO,n) + $(call set,RTE_LIBRTE_KNI,n) + $(call set,RTE_LIBRTE_BPF,n) + $(call set,RTE_LIBRTE_RAWDEV,n) + $(call set,RTE_LIBRTE_PMD_IFPGA_RAWDEV,n) + $(call set,RTE_LIBRTE_IPN3KE_PMD,n) + $(call set,RTE_LIBRTE_IFPGA_BUS,n) + $(call set,RTE_LIBRTE_BBDEV,n) + $(call set,RTE_LIBRTE_BBDEV_NULL,n) + $(call set,RTE_LIBRTE_GRAPH,n) + $(call set,RTE_LIBRTE_NODE,n) + $(call set,RTE_LIBRTE_FIB,n) + $(call set,RTE_LIBRTE_RIB,n) + $(call set,RTE_TEST_PMD,n) + $(call set,RTE_KNI_KMOD,n) + $(call set,RTE_EAL_IGB_UIO,n) + @# currently broken in 18.02 + $(call set,RTE_LIBRTE_DPAA_BUS,n) + $(call set,RTE_LIBRTE_DPAA_MEMPOOL,n) + $(call set,RTE_LIBRTE_DPAA_PMD,n) + $(call set,RTE_LIBRTE_PMD_DPAA_SEC,n) + $(call set,RTE_LIBRTE_PMD_DPAA_EVENTDEV,n) + @rm -f .dpdk-config.ok -define dpdk_build_cmds - cd $(dpdk_build_dir) && \ - source ../dpdk-meson-venv/bin/activate && \ - meson compile -C . | tee $(dpdk_build_log) && \ - deactivate -endef +DPDK_DOWNLOADS = $(CURDIR)/downloads/$(DPDK_TARBALL) -define dpdk_install_cmds - cd $(dpdk_build_dir) && \ - source ../dpdk-meson-venv/bin/activate && \ - meson install && \ - cd $(dpdk_install_dir)/lib && \ - echo "GROUP ( $$(ls librte*.a ) )" > libdpdk.a && \ - rm -rf librte*.so librte*.so.* dpdk/*/librte*.so dpdk/*/librte*.so.* && \ - deactivate && \ - rm -rf $(dpdk_build_dir)/../dpdk-meson-venv -endef +$(DPDK_DOWNLOADS): + mkdir -p downloads + @if [ -e $(DPDK_DOWNLOAD_DIR)/$(DPDK_TARBALL) ] ; \ + then cp $(DPDK_DOWNLOAD_DIR)/$(DPDK_TARBALL) $@ ; \ + else curl -o $@ -LO $(DPDK_TAR_URL) ; \ + fi + @rm -f $(B)/.dpdk-download.ok + +$(B)/.dpdk-download.ok: $(DPDK_DOWNLOADS) + @mkdir -p $(B) + @openssl md5 $< | cut -f 2 -d " " - > $(B)/$(DPDK_TARBALL).md5sum + @([ "$$(<$(B)/$(DPDK_TARBALL).md5sum)" = "$(DPDK_$(DPDK_VERSION)_TARBALL_MD5_CKSUM)" ] || \ + ( echo "Bad Checksum! Please remove $< and retry" && \ + rm $(B)/$(DPDK_TARBALL).md5sum && false )) + @touch $@ + +.PHONY: dpdk-download +dpdk-download: $(B)/.dpdk-download.ok + +$(B)/.dpdk-extract.ok: $(B)/.dpdk-download.ok + @echo --- extracting $(DPDK_TARBALL) --- + @tar --directory $(B) --extract --file $(DPDK_DOWNLOADS) + @touch $@ + +.PHONY: dpdk-extract +dpdk-extract: $(B)/.dpdk-extract.ok + +$(B)/.dpdk-patch.ok: $(B)/.dpdk-extract.ok +ifneq ($(wildcard $(CURDIR)/patches/dpdk_$(DPDK_VERSION)/*.patch),) + @echo --- patching --- + @for f in $(CURDIR)/patches/dpdk_$(DPDK_VERSION)/*.patch ; do \ + echo Applying patch: $$(basename $$f) ; \ + patch -p1 -d $(DPDK_SOURCE) < $$f ; \ + done +endif + @touch $@ + +.PHONY: dpdk-patch +dpdk-patch: $(B)/.dpdk-patch.ok + +$(B)/.dpdk-config.ok: $(B)/.dpdk-patch.ok $(B)/custom-config + @make $(DPDK_MAKE_ARGS) config + @touch $@ + +.PHONY: dpdk-config +dpdk-config: $(B)/.dpdk-config.ok + +$(B)/.dpdk-build.ok: dpdk-config $(DPDK_BUILD_DEPS) + @if [ ! -e $(B)/.dpdk-config.ok ] ; then echo 'Please run "make config" first' && false ; fi + @rm -f $(B)/.*.install.ok #deals with build-root/Makefile line 709 + @make $(DPDK_MAKE_ARGS) install + @touch $@ + +.PHONY: dpdk-build +dpdk-build: $(B)/.dpdk-build.ok -$(eval $(call package,dpdk)) +.PHONY: dpdk-install +dpdk-install: $(B)/.dpdk-build.ok diff --git a/build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch b/build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch deleted file mode 100644 index 62094846a3e0..000000000000 --- a/build/external/patches/dpdk_20.08/0002-build-system-selective-libs.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/app/meson.build b/app/meson.build -index eb74f215a..93affefa3 100644 ---- a/app/meson.build -+++ b/app/meson.build -@@ -42,7 +42,17 @@ foreach app:apps - - subdir(name) - -- if build -+ foreach d:deps -+ if dpdk_libs_disabled.contains(d) -+ build = false -+ reason = 'missing dependency, "@0@" '.format (d) -+ endif -+ endforeach -+ -+ if not build -+ dpdk_apps_disabled += name -+ set_variable(name.underscorify() + '_disable_reason', reason) -+ else - dep_objs = [] - foreach d:deps - dep_objs += get_variable(get_option('default_library') -diff --git a/lib/meson.build b/lib/meson.build -index 3852c0156..76996544d 100644 ---- a/lib/meson.build -+++ b/lib/meson.build -@@ -44,6 +44,8 @@ if is_windows - ] # only supported libraries for windows - endif - -+disabled_libs = get_option('disable_libs').split(',') -+ - default_cflags = machine_args - default_cflags += ['-DALLOW_EXPERIMENTAL_API'] - default_cflags += ['-DALLOW_INTERNAL_API'] -@@ -78,6 +80,11 @@ foreach l:libraries - dir_name = 'librte_' + l - subdir(dir_name) - -+ if disabled_libs.contains(l) -+ build = false -+ reason = 'Explicitly disabled via build config' -+ endif -+ - if build - shared_deps = ext_deps - static_deps = ext_deps -diff --git a/meson.build b/meson.build -index 61d9a4f5f..cf04f0e0e 100644 ---- a/meson.build -+++ b/meson.build -@@ -21,6 +21,7 @@ dpdk_drivers = [] - dpdk_extra_ldflags = [] - dpdk_libs_disabled = [] - dpdk_drvs_disabled = [] -+dpdk_apps_disabled = [] - abi_version_file = files('ABI_VERSION') - - if host_machine.cpu_family().startswith('x86') -@@ -106,6 +107,14 @@ foreach class:dpdk_driver_classes - endforeach - message(output_message + '\n') - -+output_message = '\n===============\nApplications Disabled\n===============\n' -+foreach app:dpdk_apps_disabled -+ reason = get_variable(app.underscorify() + '_disable_reason') -+ output_message += app + ':\t' + reason + '\n\t' -+endforeach -+ -+message(output_message + '\n') -+ - output_message = '\n=================\nContent Skipped\n=================\n' - output_message += '\nlibs:\n\t' - foreach lib:dpdk_libs_disabled -diff --git a/meson_options.txt b/meson_options.txt -index 9bf18ab6b..d1aa46b8d 100644 ---- a/meson_options.txt -+++ b/meson_options.txt -@@ -4,6 +4,8 @@ option('armv8_crypto_dir', type: 'string', value: '', - description: 'path to the armv8_crypto library installation directory') - option('disable_drivers', type: 'string', value: '', - description: 'Comma-separated list of drivers to explicitly disable.') -+option('disable_libs', type: 'string', value: '', -+ description: 'Comma-separated list of libs to explicitly disable.') - option('drivers_install_subdir', type: 'string', value: 'dpdk/pmds-', - description: 'Subdirectory of libdir where to install PMDs. Defaults to using a versioned subdirectory.') - option('enable_docs', type: 'boolean', value: false, From 6cb106314b69df68a320a4a36d7d8ee6c76ec854 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Thu, 24 Sep 2020 12:30:46 -0400 Subject: [PATCH 056/129] build: remove OS distros which are EOL Type: fix Signed-off-by: Dave Wallace Change-Id: If80ff6bfbd42779a663af1e7dcfff80d75f47f1e --- Makefile | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Makefile b/Makefile index 6a4886ff6676..5af0d5707e00 100644 --- a/Makefile +++ b/Makefile @@ -83,10 +83,6 @@ else ifeq ($(OS_VERSION_ID),20.04) DEB_DEPENDS += libssl-dev DEB_DEPENDS += libelf-dev # for libbpf (af_xdp) LIBFFI=libffi7 -else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-8) - DEB_DEPENDS += libssl-dev - DEB_DEPENDS += python-dev python-all python-pip python-virtualenv - APT_ARGS = -t jessie-backports else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-9) DEB_DEPENDS += libssl1.0-dev DEB_DEPENDS += python-all python-pip @@ -278,13 +274,6 @@ bootstrap: .PHONY: install-dep install-dep: ifeq ($(filter ubuntu debian,$(OS_ID)),$(OS_ID)) -ifeq ($(OS_VERSION_ID),14.04) - @sudo -E apt-get $(CONFIRM) $(FORCE) install software-properties-common -endif -ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-8) - @grep -q jessie-backports /etc/apt/sources.list /etc/apt/sources.list.d/* 2> /dev/null \ - || ( echo "Please install jessie-backports" ; exit 1 ) -endif @sudo -E apt-get update @sudo -E apt-get $(APT_ARGS) $(CONFIRM) $(FORCE) install $(DEB_DEPENDS) else ifneq ("$(wildcard /etc/redhat-release)","") From db17fa2fb81aa14efc2e306e4984d5e98252fc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Thu, 17 Sep 2020 17:08:07 +0200 Subject: [PATCH 057/129] ikev2: fix memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: I5be19a4923b37e2636621d36155178ac348ee41c Signed-off-by: Benoît Ganne (cherry picked from commit a8af7cf253c4e8ab9ba1a2cfed50f6236fea3a62) --- src/plugins/ikev2/ikev2.c | 23 ++++++++++++++++++++--- src/plugins/ikev2/ikev2_crypto.c | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 34c54f3d8485..c69ac913c48e 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -3210,6 +3210,8 @@ ikev2_set_local_key (vlib_main_t * vm, u8 * file) { ikev2_main_t *km = &ikev2_main; + if (km->pkey) + EVP_PKEY_free (km->pkey); km->pkey = ikev2_load_key_file (file); if (km->pkey == NULL) return clib_error_return (0, "load key '%s' failed", file); @@ -3358,6 +3360,19 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p) vec_free (del_sai); } +static void +ikev2_profile_free (ikev2_profile_t * p) +{ + vec_free (p->name); + + vec_free (p->auth.data); + if (p->auth.key) + EVP_PKEY_free (p->auth.key); + + vec_free (p->loc_id.data); + vec_free (p->rem_id.data); +} + clib_error_t * ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add) { @@ -3387,7 +3402,7 @@ ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add) ikev2_unregister_udp_port (p); ikev2_cleanup_profile_sessions (km, p); - vec_free (p->name); + ikev2_profile_free (p); pool_put (km->profiles, p); mhash_unset (&km->profile_index_by_name, name, 0); } @@ -3408,7 +3423,11 @@ ikev2_set_profile_auth (vlib_main_t * vm, u8 * name, u8 auth_method, r = clib_error_return (0, "unknown profile %v", name); return r; } + + if (p->auth.key) + EVP_PKEY_free (p->auth.key); vec_free (p->auth.data); + p->auth.method = auth_method; p->auth.data = vec_dup (auth_data); p->auth.hex = data_hex_format; @@ -3416,8 +3435,6 @@ ikev2_set_profile_auth (vlib_main_t * vm, u8 * name, u8 auth_method, if (auth_method == IKEV2_AUTH_METHOD_RSA_SIG) { vec_add1 (p->auth.data, 0); - if (p->auth.key) - EVP_PKEY_free (p->auth.key); p->auth.key = ikev2_load_cert_file (p->auth.data); if (p->auth.key == NULL) return clib_error_return (0, "load cert '%s' failed", p->auth.data); diff --git a/src/plugins/ikev2/ikev2_crypto.c b/src/plugins/ikev2/ikev2_crypto.c index b1fdf890e08d..013857dee9be 100644 --- a/src/plugins/ikev2/ikev2_crypto.c +++ b/src/plugins/ikev2/ikev2_crypto.c @@ -828,6 +828,7 @@ ikev2_load_cert_file (u8 * file) } pkey = X509_get_pubkey (x509); + X509_free (x509); if (pkey == NULL) ikev2_log_error ("get pubkey %s failed", file); From c6f50a3e3eba16fcc77ca009d2eb7fe224c1912b Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 25 Sep 2020 16:55:03 +0000 Subject: [PATCH 058/129] ikev2: fix false positive NAT detection Type: fix Change-Id: Id7f865f537c55d00a784eec51624ba28e903a083 Signed-off-by: Filip Tehlar --- src/plugins/ikev2/ikev2.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index c69ac913c48e..96b8e7d9b234 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -687,11 +687,9 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, ikev2_notify_t *n = ikev2_parse_notify_payload (ikep); if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP) { - u8 *src_sha = - ikev2_compute_nat_sha1 (clib_net_to_host_u64 (ike->ispi), 0, - clib_net_to_host_u32 (sa-> - iaddr.as_u32), - udp->src_port); + u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, + sa->iaddr.as_u32, + udp->src_port); if (clib_memcmp (src_sha, n->data, vec_len (src_sha))) { sa->natt = 1; @@ -703,11 +701,9 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, else if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP) { - u8 *dst_sha = - ikev2_compute_nat_sha1 (clib_net_to_host_u64 (ike->ispi), 0, - clib_net_to_host_u32 (sa-> - raddr.as_u32), - udp->dst_port); + u8 *dst_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, + sa->raddr.as_u32, + udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { sa->natt = 1; @@ -797,8 +793,7 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, { u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, ike->rspi, - clib_net_to_host_u32 - (sa->raddr.as_u32), + sa->raddr.as_u32, udp->src_port); if (clib_memcmp (src_sha, n->data, vec_len (src_sha))) { @@ -2139,7 +2134,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), clib_host_to_net_u64 (sa->rspi), - clib_host_to_net_u32 (sa->raddr.as_u32), + sa->raddr.as_u32, udp->dst_port); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP, @@ -2694,7 +2689,7 @@ ikev2_node_fn (vlib_main_t * vm, { is_req = 1; ike0->exchange = IKEV2_EXCHANGE_IKE_AUTH; - uword *p = hash_get (km->sa_by_ispi, ike0->ispi); + uword *p = hash_get (km->sa_by_ispi, sa0->ispi); if (p) { ikev2_sa_t *sai = @@ -2771,7 +2766,7 @@ ikev2_node_fn (vlib_main_t * vm, if (sa0->is_initiator) { - ikev2_del_sa_init (ike0->ispi); + ikev2_del_sa_init (sa0->ispi); } else { @@ -3770,7 +3765,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), clib_host_to_net_u64 (sa.rspi), - clib_host_to_net_u32 (if_ip->as_u32), + if_ip->as_u32, clib_host_to_net_u16 (IKEV2_PORT)); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP, @@ -3779,7 +3774,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), clib_host_to_net_u64 (sa.rspi), - clib_host_to_net_u32 (p->responder.ip4.as_u32), + p->responder.ip4.as_u32, clib_host_to_net_u16 (sa.dst_port)); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP, @@ -3805,7 +3800,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) ike0->version = IKE_VERSION_2; ike0->flags = IKEV2_HDR_FLAG_INITIATOR; ike0->exchange = IKEV2_EXCHANGE_SA_INIT; - ike0->ispi = sa.ispi; + ike0->ispi = clib_host_to_net_u64 (sa.ispi); ike0->rspi = 0; ike0->msgid = 0; From 36e657032c4d77c2657cf5c14d3b5dfa3c13d48c Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Fri, 25 Sep 2020 15:36:19 +0200 Subject: [PATCH 059/129] virtio: fix the gro enable/disable on tx-vrings Type: fix Change-Id: I96c30baaf34fe7b0cd899966a507501e58cde934 Signed-off-by: Mohsin Kazmi (cherry picked from commit 1017a1d360cc1c38e2aee4b5f19ff1f2869a8cd9) --- src/vnet/devices/tap/cli.c | 2 +- src/vnet/devices/tap/tap.c | 2 -- src/vnet/devices/virtio/device.c | 28 +++++++++++++++++++++------- src/vnet/devices/virtio/virtio.c | 1 + src/vnet/gso/gro.h | 29 ++++++++++++++++------------- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/vnet/devices/tap/cli.c b/src/vnet/devices/tap/cli.c index 7580d9200616..89b2ff091b09 100644 --- a/src/vnet/devices/tap/cli.c +++ b/src/vnet/devices/tap/cli.c @@ -142,7 +142,7 @@ VLIB_CLI_COMMAND (tap_create_command, static) = { "[host-ip4-addr ] [host-ip6-addr ] " "[host-ip4-gw ] [host-ip6-gw ] " "[host-mac-addr ] [host-if-name ] " - "[host-mtu-size ] [no-gso|gso|csum-offload|gro-coalesce] " + "[host-mtu-size ] [no-gso|gso [gro-coalesce]|csum-offload] " "[persist] [attach] [tun] [packed] [in-order]", .function = tap_create_command_fn, }; diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c index c265aa201ec2..bc2bf56cab34 100644 --- a/src/vnet/devices/tap/tap.c +++ b/src/vnet/devices/tap/tap.c @@ -731,7 +731,6 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) if ((args->tap_flags & TAP_FLAG_GSO) && (args->tap_flags & TAP_FLAG_GRO_COALESCE)) { - vif->packet_coalesce = 1; virtio_set_packet_coalesce (vif); } vnet_hw_interface_set_input_node (vnm, vif->hw_if_index, @@ -900,7 +899,6 @@ tap_gso_enable_disable (vlib_main_t * vm, u32 sw_if_index, int enable_disable, } if (is_packet_coalesce) { - vif->packet_coalesce = 1; virtio_set_packet_coalesce (vif); } } diff --git a/src/vnet/devices/virtio/device.c b/src/vnet/devices/virtio/device.c index 56c0a98491e1..7fa4dde4ea32 100644 --- a/src/vnet/devices/virtio/device.c +++ b/src/vnet/devices/virtio/device.c @@ -719,24 +719,38 @@ virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid, virtio_main_t *mm = &virtio_main; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance); - virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid); + virtio_vring_t *rx_vring = vec_elt_at_index (vif->rxq_vrings, qid); + virtio_vring_t *tx_vring = 0; if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode)) { - vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + rx_vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; return clib_error_return (0, "interrupt mode is not supported"); } if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING) { - /* only enable packet coalesce in poll mode */ - gro_flow_table_set_is_enable (vring->flow_table, 1); - vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + vec_foreach (tx_vring, vif->txq_vrings) + { + /* only enable packet coalesce in poll mode */ + gro_flow_table_set_is_enable (tx_vring->flow_table, 1); + } + rx_vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; } else { - gro_flow_table_set_is_enable (vring->flow_table, 0); - vring->avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; + if (vif->packet_coalesce) + { + virtio_log_warning (vif, + "interface %U is in interrupt mode, disabling packet coalescing", + format_vnet_sw_if_index_name, vnet_get_main (), + vif->sw_if_index); + vec_foreach (tx_vring, vif->txq_vrings) + { + gro_flow_table_set_is_enable (tx_vring->flow_table, 0); + } + } + rx_vring->avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; } return 0; diff --git a/src/vnet/devices/virtio/virtio.c b/src/vnet/devices/virtio/virtio.c index ec22a0d45f4d..e74f3783756d 100644 --- a/src/vnet/devices/virtio/virtio.c +++ b/src/vnet/devices/virtio/virtio.c @@ -226,6 +226,7 @@ virtio_set_packet_coalesce (virtio_if_t * vif) vnet_main_t *vnm = vnet_get_main (); vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index); virtio_vring_t *vring; + vif->packet_coalesce = 1; vec_foreach (vring, vif->txq_vrings) { gro_flow_table_init (&vring->flow_table, diff --git a/src/vnet/gso/gro.h b/src/vnet/gso/gro.h index bfa592041e55..b2d6c2858885 100644 --- a/src/vnet/gso/gro.h +++ b/src/vnet/gso/gro.h @@ -164,16 +164,7 @@ static_always_inline void gro_flow_table_set_is_enable (gro_flow_table_t * flow_table, u8 is_enable) { if (flow_table) - { - if (is_enable) - { - flow_table->is_enable = 1; - } - else - { - flow_table->is_enable = 0; - } - } + flow_table->is_enable = is_enable; } static_always_inline void @@ -264,12 +255,24 @@ static_always_inline u8 * gro_flow_table_format (u8 * s, va_list * args) { gro_flow_table_t *flow_table = va_arg (*args, gro_flow_table_t *); + u32 indent; + + if (!flow_table) + return s; + + indent = format_get_indent (s); + if (flow_table->is_enable) + s = format (s, "packet-coalesce: enable\n"); + else + s = format (s, "packet-coalesce: disable\n"); + + indent += 2; s = format (s, - "flow-table: size %u gro-total-vectors %lu gro-n-vectors %u", - flow_table->flow_table_size, flow_table->total_vectors, - flow_table->n_vectors); + "%Uflow-table: size %u gro-total-vectors %lu gro-n-vectors %u", + format_white_space, indent, flow_table->flow_table_size, + flow_table->total_vectors, flow_table->n_vectors); if (flow_table->n_vectors) { double average_rate = From ddb070e8b1481cf9db77bc269d9d9754958a213b Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Fri, 18 Sep 2020 14:43:29 +0300 Subject: [PATCH 060/129] tap: do not use strlen on vector sanitizer complains about strlen on hi->name in tap_dump_ifs. hi->name is a vector which is not null-terminated, so use vec_len. Type: fix Signed-off-by: Vladimir Isaev Change-Id: Icdd5f65369bb51b0c4a9cd86c24899e6febd837c (cherry picked from commit 84f3d9fba4e1715237a41f0978430193363187c7) --- src/vnet/devices/tap/tap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c index bc2bf56cab34..040ec1f1ea57 100644 --- a/src/vnet/devices/tap/tap.c +++ b/src/vnet/devices/tap/tap.c @@ -944,8 +944,7 @@ tap_dump_ifs (tap_interface_details_t ** out_tapids) tapid->sw_if_index = vif->sw_if_index; hi = vnet_get_hw_interface (vnm, vif->hw_if_index); clib_memcpy(tapid->dev_name, hi->name, - MIN (ARRAY_LEN (tapid->dev_name) - 1, - strlen ((const char *) hi->name))); + MIN (ARRAY_LEN (tapid->dev_name) - 1, vec_len (hi->name))); vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS(0)); tapid->rx_ring_sz = vring->size; vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS(0)); From 47e0bd7303b1bcc81c3458ca9e26b43a39fcfe17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 15 Sep 2020 10:58:07 +0200 Subject: [PATCH 061/129] virtio: fix txq locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize txq lock only if some txq are shared and check if another worker is already operating on the txq before processing gro timeouts in input node. Type: fix Change-Id: I89dab6c0e6eb6a7aa621fa1548b0a2c76e6c7581 Signed-off-by: Benoît Ganne (cherry picked from commit b6b484d01adb8ab2ef5a50d5a3d6f3f097df2e0c) --- src/vnet/devices/virtio/node.c | 4 +++- src/vnet/devices/virtio/pci.c | 4 +++- src/vppinfra/lock.h | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/vnet/devices/virtio/node.c b/src/vnet/devices/virtio/node.c index 7fabe36401cf..1c9cfd0cc03f 100644 --- a/src/vnet/devices/virtio/node.c +++ b/src/vnet/devices/virtio/node.c @@ -279,10 +279,12 @@ virtio_device_input_gso_inline (vlib_main_t * vm, vlib_node_runtime_t * node, u16 last = vring->last_used_idx; u16 n_left = vring->used->idx - last; - if (vif->packet_coalesce) + if (vif->packet_coalesce + && clib_spinlock_trylock_if_init (&txq_vring->lockp)) { vnet_gro_flow_table_schedule_node_on_dispatcher (vm, txq_vring->flow_table); + clib_spinlock_unlock_if_init (&txq_vring->lockp); } if ((vring->used->flags & VRING_USED_F_NO_NOTIFY) == 0 && diff --git a/src/vnet/devices/virtio/pci.c b/src/vnet/devices/virtio/pci.c index 5ba9f36de81d..df8e2bdaf680 100644 --- a/src/vnet/devices/virtio/pci.c +++ b/src/vnet/devices/virtio/pci.c @@ -494,6 +494,7 @@ virtio_pci_control_vring_init (vlib_main_t * vm, virtio_if_t * vif, clib_error_t * virtio_pci_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 queue_num) { + vlib_thread_main_t *vtm = vlib_get_thread_main (); clib_error_t *error = 0; u16 queue_size = 0; virtio_vring_t *vring; @@ -519,7 +520,8 @@ virtio_pci_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 queue_num) vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num), CLIB_CACHE_LINE_BYTES); vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num)); - clib_spinlock_init (&vring->lockp); + if (vif->max_queue_pairs < vtm->n_vlib_mains) + clib_spinlock_init (&vring->lockp); } else { diff --git a/src/vppinfra/lock.h b/src/vppinfra/lock.h index 3cfe11cba176..470890b6ec76 100644 --- a/src/vppinfra/lock.h +++ b/src/vppinfra/lock.h @@ -91,6 +91,15 @@ clib_spinlock_lock (clib_spinlock_t * p) CLIB_LOCK_DBG (p); } +static_always_inline int +clib_spinlock_trylock (clib_spinlock_t * p) +{ + if (PREDICT_FALSE (CLIB_SPINLOCK_IS_LOCKED (p))) + return 0; + clib_spinlock_lock (p); + return 1; +} + static_always_inline void clib_spinlock_lock_if_init (clib_spinlock_t * p) { @@ -98,6 +107,14 @@ clib_spinlock_lock_if_init (clib_spinlock_t * p) clib_spinlock_lock (p); } +static_always_inline int +clib_spinlock_trylock_if_init (clib_spinlock_t * p) +{ + if (PREDICT_FALSE (*p != 0)) + return clib_spinlock_trylock (p); + return 1; +} + static_always_inline void clib_spinlock_unlock (clib_spinlock_t * p) { From 8eb1e6d1f092609d30496fae28c0e0d3f73bacbc Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Tue, 29 Sep 2020 10:01:25 +0000 Subject: [PATCH 062/129] virtio: fix modern device queue notify QUEUE_SELECT and QUEUE_NOTIFY_OFF registers are shared between all workers operating on the same device and operations are not atomic Type: fix Change-Id: Ie017b1bfc7e3b6b4e59029f45db78eeffd9f3aeb Signed-off-by: Mohsin Kazmi (cherry picked from commit 162a296756f3dbead55079e4670973d859df1ef9) --- src/vnet/devices/virtio/pci.c | 26 ++++++++++++++------- src/vnet/devices/virtio/pci.h | 5 +++- src/vnet/devices/virtio/virtio.h | 23 +++++++++++++----- src/vnet/devices/virtio/virtio_pci_legacy.c | 10 +++++++- src/vnet/devices/virtio/virtio_pci_modern.c | 11 ++++----- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/vnet/devices/virtio/pci.c b/src/vnet/devices/virtio/pci.c index df8e2bdaf680..7b7a12028333 100644 --- a/src/vnet/devices/virtio/pci.c +++ b/src/vnet/devices/virtio/pci.c @@ -486,7 +486,11 @@ virtio_pci_control_vring_init (vlib_main_t * vm, virtio_if_t * vif, virtio_log_debug (vif, "control-queue: number %u, size %u", queue_num, queue_size); vif->virtio_pci_func->setup_queue (vm, vif, queue_num, ptr); - vring->kick_fd = -1; + vring->queue_notify_offset = + vif->notify_off_multiplier * + vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num); + virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u", + queue_num, vring->queue_notify_offset); return error; } @@ -562,7 +566,11 @@ virtio_pci_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 queue_num) if (vif->virtio_pci_func->setup_queue (vm, vif, queue_num, ptr)) return clib_error_return (0, "error in queue address setup"); - vring->kick_fd = -1; + vring->queue_notify_offset = + vif->notify_off_multiplier * + vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num); + virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u", + queue_num, vring->queue_notify_offset); return error; } @@ -775,6 +783,7 @@ virtio_pci_read_caps (vlib_main_t * vm, virtio_if_t * vif, void **bar) if (common_cfg == 0 || notify == 0 || dev_cfg == 0 || isr == 0) { vif->virtio_pci_func = &virtio_pci_legacy_func; + vif->notify_off_multiplier = 0; virtio_log_debug (vif, "legacy virtio pci device found"); return error; } @@ -783,9 +792,14 @@ virtio_pci_read_caps (vlib_main_t * vm, virtio_if_t * vif, void **bar) vif->virtio_pci_func = &virtio_pci_modern_func; if (!pci_cfg) - virtio_log_debug (vif, "modern virtio pci device found"); + { + virtio_log_debug (vif, "modern virtio pci device found"); + } + else + { + virtio_log_debug (vif, "transitional virtio pci device found"); + } - virtio_log_debug (vif, "transitional virtio pci device found"); return error; } @@ -1231,8 +1245,6 @@ virtio_pci_delete_if (vlib_main_t * vm, virtio_if_t * vif) vec_foreach_index (i, vif->rxq_vrings) { virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, i); - if (vring->kick_fd != -1) - close (vring->kick_fd); if (vring->used) { virtio_free_rx_buffers (vm, vring); @@ -1244,8 +1256,6 @@ virtio_pci_delete_if (vlib_main_t * vm, virtio_if_t * vif) vec_foreach_index (i, vif->txq_vrings) { virtio_vring_t *vring = vec_elt_at_index (vif->txq_vrings, i); - if (vring->kick_fd != -1) - close (vring->kick_fd); if (vring->used) { virtio_free_used_desc (vm, vring); diff --git a/src/vnet/devices/virtio/pci.h b/src/vnet/devices/virtio/pci.h index ab5c6f15ec21..eeb0f9454bbb 100644 --- a/src/vnet/devices/virtio/pci.h +++ b/src/vnet/devices/virtio/pci.h @@ -195,7 +195,10 @@ typedef struct _virtio_pci_func u8 (*setup_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id, void *p); void (*del_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id); - void (*notify_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id); + u16 (*get_queue_notify_off) (vlib_main_t * vm, virtio_if_t * vif, + u16 queue_id); + void (*notify_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id, + u16 queue_notify_offset); u16 (*set_config_irq) (vlib_main_t * vm, virtio_if_t * vif, u16 vec); u16 (*set_queue_irq) (vlib_main_t * vm, virtio_if_t * vif, u16 vec, diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h index b00e1eceb858..309a2c37664f 100644 --- a/src/vnet/devices/virtio/virtio.h +++ b/src/vnet/devices/virtio/virtio.h @@ -65,8 +65,15 @@ typedef struct vring_avail_t *avail; u16 desc_in_use; u16 desc_next; - int kick_fd; - int call_fd; + union + { + struct + { + int kick_fd; + int call_fd; + }; + u16 queue_notify_offset; + }; u8 buffer_pool_index; u16 size; u16 queue_id; @@ -204,9 +211,11 @@ extern void virtio_show (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr, u32 type); extern void virtio_set_packet_coalesce (virtio_if_t * vif); extern void virtio_pci_legacy_notify_queue (vlib_main_t * vm, - virtio_if_t * vif, u16 queue_id); + virtio_if_t * vif, u16 queue_id, + u16 queue_notify_offset); extern void virtio_pci_modern_notify_queue (vlib_main_t * vm, - virtio_if_t * vif, u16 queue_id); + virtio_if_t * vif, u16 queue_id, + u16 queue_notify_offset); format_function_t format_virtio_device_name; format_function_t format_virtio_log_name; @@ -216,9 +225,11 @@ virtio_kick (vlib_main_t * vm, virtio_vring_t * vring, virtio_if_t * vif) if (vif->type == VIRTIO_IF_TYPE_PCI) { if (vif->is_modern) - virtio_pci_modern_notify_queue (vm, vif, vring->queue_id); + virtio_pci_modern_notify_queue (vm, vif, vring->queue_id, + vring->queue_notify_offset); else - virtio_pci_legacy_notify_queue (vm, vif, vring->queue_id); + virtio_pci_legacy_notify_queue (vm, vif, vring->queue_id, + vring->queue_notify_offset); } else { diff --git a/src/vnet/devices/virtio/virtio_pci_legacy.c b/src/vnet/devices/virtio/virtio_pci_legacy.c index cf1d84135aa3..1426a7035a21 100644 --- a/src/vnet/devices/virtio/virtio_pci_legacy.c +++ b/src/vnet/devices/virtio/virtio_pci_legacy.c @@ -203,9 +203,16 @@ virtio_pci_legacy_del_queue (vlib_main_t * vm, virtio_if_t * vif, vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN, &src); } +static u16 +virtio_pci_legacy_get_queue_notify_off (vlib_main_t * vm, virtio_if_t * vif, + u16 queue_id) +{ + return 0; +} + inline void virtio_pci_legacy_notify_queue (vlib_main_t * vm, virtio_if_t * vif, - u16 queue_id) + u16 queue_id, u16 queue_notify_off) { vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY, &queue_id); @@ -364,6 +371,7 @@ const virtio_pci_func_t virtio_pci_legacy_func = { .set_queue_size = virtio_pci_legacy_set_queue_num, .setup_queue = virtio_pci_legacy_setup_queue, .del_queue = virtio_pci_legacy_del_queue, + .get_queue_notify_off = virtio_pci_legacy_get_queue_notify_off, .notify_queue = virtio_pci_legacy_notify_queue, .set_config_irq = virtio_pci_legacy_set_config_irq, .set_queue_irq = virtio_pci_legacy_set_queue_irq, diff --git a/src/vnet/devices/virtio/virtio_pci_modern.c b/src/vnet/devices/virtio/virtio_pci_modern.c index 4eb0ff102aee..1934f98003d6 100644 --- a/src/vnet/devices/virtio/virtio_pci_modern.c +++ b/src/vnet/devices/virtio/virtio_pci_modern.c @@ -208,7 +208,8 @@ virtio_pci_modern_set_queue_enable (virtio_if_t * vif, u16 queue_id, } static u16 -virtio_pci_modern_get_queue_notify_off (virtio_if_t * vif, u16 queue_id) +virtio_pci_modern_get_queue_notify_off (vlib_main_t * vm, virtio_if_t * vif, + u16 queue_id) { u16 queue_notify_off = 0; virtio_pci_modern_set_queue_select (vif, queue_id); @@ -387,14 +388,11 @@ virtio_pci_modern_get_isr (vlib_main_t * vm, virtio_if_t * vif) inline void virtio_pci_modern_notify_queue (vlib_main_t * vm, virtio_if_t * vif, - u16 queue_id) + u16 queue_id, u16 queue_notify_off) { - u16 queue_notify_off = - virtio_pci_modern_get_queue_notify_off (vif, queue_id); virtio_pci_reg_write_u16 (vif, VIRTIO_NOTIFICATION_OFFSET (vif) + - vif->notify_off_multiplier * queue_notify_off, - queue_id); + queue_notify_off, queue_id); } static void @@ -418,6 +416,7 @@ const virtio_pci_func_t virtio_pci_modern_func = { .set_queue_size = virtio_pci_modern_set_queue_size, .setup_queue = virtio_pci_modern_setup_queue, .del_queue = virtio_pci_modern_del_queue, + .get_queue_notify_off = virtio_pci_modern_get_queue_notify_off, .notify_queue = virtio_pci_modern_notify_queue, .set_config_irq = virtio_pci_modern_set_msix_config, .set_queue_irq = virtio_pci_modern_set_queue_msix_vector, From 3c5414029bb432e51820e39e86f26fd6b39c6447 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Fri, 25 Sep 2020 14:06:34 +0000 Subject: [PATCH 063/129] misc: 20.09 Release Notes Type: docs Change-Id: I1b12f1d14a1a68504767c01ceac0eed115fb7ba6 Signed-off-by: Andrew Yourtchenko Signed-off-by: Ray Kinsella --- RELEASE.md | 656 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 655 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 45b3f1ad08e8..dd9d48bf1ff0 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -32,7 +32,661 @@ @page release_notes_2009 Release notes for VPP 20.09 -TBD +More than 458 commits since the previous release, including 266 fixes. + +## Release Highlights + +The FD.io VPP 20.09 release added a number of notable new features. In plugins, +the I/O layer added support for the Linux AF\_XDP interface with the AF\_XDP +plugin. New plugins where added supporting both the Wireguard security protocol +and CNAT destination based address translation, and the existing IKEv2 plugin +added support for NAT-T. In the cryptography layer, support was added for +synchronous software crypto engines, enabling users to allocate dedicated crypto +worker threads. The flow layer added support for steering IPSEC ESP/AH flows to +worker threads. GRO support was added to the packet coalescing library. + +This release introduces the new FD.io VPP API change policy to ensure +backwards-compatibility. The policy will ensure seamless upgrades to new +versions of FD.io VPP in future, provided no "in-progress" or deprecated APIs +are in use. Enabling the FD.io community to enjoy the benefits of new releases, +while minimizing the work involved in staying current. + +If you dive into the implementation, you will note that policy in action. A +number of modified API messages have had their original versions maintained to +ensure compatibility. + +Reflecting the new policy we added two new sections to the release notes +describing: +- Newly deprecated API messages: please note that if you are using a deprecated +message, they will soon be removed in a subsequent release. Collaborate with +the feature maintainer on the best approach to mitigate. +- In-progress API messages: They are work-in-progress, and are *not* subject to +the policy, and may change or even be removed at any time. Please collaborate +with the feature maintainer on plans to productize the message before using in +any product. In-progress APIs must eventually become stable or be removed. + +## Features + +- VNET + - Crypto Infra + - Add chacha20-poly1305 algo (61f49aa38) + - Asynchronous crypto engines (2284817ea) + - Add asynchronous crypto APIs (0c936b147) + - Added support for optimized cryptodev API (ef80ad6bf) + - FLOW + - Added ability to steer IPSec ESP/AH flows to worker threads (d4c3666b9) + - Added the vnet/flow API (d0236f725) + - GENEVE + - Support geneve interface acting as a bvi (7fc88cf3a) + - GSO + - Added software GRO support (f382b06fe) + - IPSec + - Dedicated IPSec interface type (dd4ccf262) + - Deprecate old interface API (e6df80de4) + - Interface Common + - Support configuring RSS steering queues (c4665093c) + - Native Virtio Drivers + - Add vhost sw\_if\_index filter for sw\_interface\_vhost\_user\_dump (a0e8d9669) + - Add modern device support (379aac395) + - Add virtio 1.1 api flags (518251bc8) + - TAP Drivers + - Add gro support (9e2a78564) + - Add virtio 1.1 API flag (50bd16559) + - TCP + - Track reorder with selective acknowledgments (cc4d6d022) +- Plugins + - AF\_XDP driver + - New plugin for Linux AF\_XDP input (4a76d6f6d) + - CNat + - New plugin for destination based NAT (29f3c7d2e) + - Wireguard + - New plugin, initial implementation of wireguard protocol (edca1325c) + - Crypto - OpenSSL + - Add chacha20-poly1305 support to crypto-openssl (1b6ed022e) + - DPDK + - Device\_id sorted order for cryptodev (5a849e3b3) + - Call the meson-based build instead of Makefiles (73903d7e8) + - Internet Key Exchange (IKEv2) Protocol + - Add support for NAT traversal (NAT-T) (4362baa33) + - Add profile dump API (6a9bd8188) + - Add support for AES-GCM cipher in IKE (a7b963df2) + - Add SA dump API (a340fe1ac) + - Network Delay Simulator + - Basic reorder support (e6c3e8f0e) +- VPP Comms Library + - Nest vcl\_mq\_epfd to support epoll\_wait without high CPU usage (4266d4d5f) + - Support connected udp listens (1e96617d9) + - Support inter worker rpc (40c07ce7a) + - Support multi-threads with session migration (a3a489691) +- Vector Library + - Add recursive macro expander to debug cli (961e3c842) +- Binary API Libraries + - Add new stream message convention (f5db3711b) + - Make VPP api handlers endian independent (e796a1873) +- Infrastructure Library + - Multiarch support for OCTEONTX2 SoC (e2f5236dc) + +## Known issues + +For the full list of issues please refer to fd.io [JIRA](https://jira.fd.io). + +## Fixed issues + +For the full list of fixed issues please refer to: +- fd.io [JIRA](https://jira.fd.io) +- git [commit log](https://git.fd.io/vpp/log/?h=stable/2009) + + +## API changes + +Description of results: + +* _Definition changed_: indicates that the API file was modified between releases. +* _Only in image_: indicates the API is new for this release. +* _Only in file_: indicates the API has been removed in this release. + +Message Name | Result +-------------------------------------------------------------|------------------ +adl_allowlist_enable_disable | only in image +adl_allowlist_enable_disable_reply | only in image +adl_interface_enable_disable | only in image +adl_interface_enable_disable_reply | only in image +bond_add_member | only in image +bond_add_member_reply | only in image +bond_create2 | only in image +bond_create2_reply | only in image +bond_detach_member | only in image +bond_detach_member_reply | only in image +cnat_add_del_snat_prefix | only in image +cnat_add_del_snat_prefix_reply | only in image +cnat_session_details | only in image +cnat_session_dump | only in image +cnat_session_purge | only in image +cnat_session_purge_reply | only in image +cnat_set_snat_addresses | only in image +cnat_set_snat_addresses_reply | only in image +cnat_translation_del | only in image +cnat_translation_del_reply | only in image +cnat_translation_details | only in image +cnat_translation_dump | only in image +cnat_translation_update | only in image +cnat_translation_update_reply | only in image +crypto_set_async_dispatch | only in image +crypto_set_async_dispatch_reply | only in image +crypto_set_handler | only in image +crypto_set_handler_reply | only in image +crypto_sw_scheduler_set_worker | only in image +crypto_sw_scheduler_set_worker_reply | only in image +det44_add_del_map | only in image +det44_add_del_map_reply | only in image +det44_close_session_in | only in image +det44_close_session_in_reply | only in image +det44_close_session_out | only in image +det44_close_session_out_reply | only in image +det44_forward | only in image +det44_forward_reply | only in image +det44_get_timeouts | only in image +det44_get_timeouts_reply | only in image +det44_interface_add_del_feature | only in image +det44_interface_add_del_feature_reply | only in image +det44_interface_details | only in image +det44_interface_dump | only in image +det44_map_details | only in image +det44_map_dump | only in image +det44_plugin_enable_disable | only in image +det44_plugin_enable_disable_reply | only in image +det44_reverse | only in image +det44_reverse_reply | only in image +det44_session_details | only in image +det44_session_dump | only in image +det44_set_timeouts | only in image +det44_set_timeouts_reply | only in image +flow_add | only in image +flow_add_reply | only in image +flow_del | only in image +flow_del_reply | only in image +flow_disable | only in image +flow_disable_reply | only in image +flow_enable | only in image +flow_enable_reply | only in image +geneve_add_del_tunnel2 | only in image +geneve_add_del_tunnel2_reply | only in image +gtpu_add_del_tunnel | definition changed +gtpu_tunnel_details | definition changed +gtpu_tunnel_update_tteid | only in image +gtpu_tunnel_update_tteid_reply | only in image +ikev2_child_sa_details | only in image +ikev2_child_sa_dump | only in image +ikev2_nonce_get | only in image +ikev2_nonce_get_reply | only in image +ikev2_profile_details | only in image +ikev2_profile_dump | only in image +ikev2_profile_set_ts | definition changed +ikev2_sa_details | only in image +ikev2_sa_dump | only in image +ikev2_set_esp_transforms | definition changed +ikev2_set_ike_transforms | definition changed +ikev2_set_responder | definition changed +ikev2_traffic_selector_details | only in image +ikev2_traffic_selector_dump | only in image +ipsec_itf_create | only in image +ipsec_itf_create_reply | only in image +ipsec_itf_delete | only in image +ipsec_itf_delete_reply | only in image +ipsec_itf_details | only in image +ipsec_itf_dump | only in image +ipsec_set_async_mode | only in image +ipsec_set_async_mode_reply | only in image +map_domains_get | only in image +map_domains_get_reply | only in image +nat44_add_del_static_mapping_v2 | only in image +nat44_add_del_static_mapping_v2_reply | only in image +nat_show_config_2 | only in image +nat_show_config_2_reply | only in image +nsim_configure2 | only in image +nsim_configure2_reply | only in image +pg_interface_enable_disable_coalesce | only in image +pg_interface_enable_disable_coalesce_reply | only in image +sr_policies_with_sl_index_details | only in image +sr_policies_with_sl_index_dump | only in image +sw_bond_interface_details | only in image +sw_bond_interface_dump | only in image +sw_member_interface_details | only in image +sw_member_interface_dump | only in image +trace_details | only in image +trace_dump | only in image +trace_dump_reply | only in image +virtio_pci_create_v2 | only in image +virtio_pci_create_v2_reply | only in image +wireguard_interface_create | only in image +wireguard_interface_create_reply | only in image +wireguard_interface_delete | only in image +wireguard_interface_delete_reply | only in image +wireguard_interface_details | only in image +wireguard_interface_dump | only in image +wireguard_peer_add | only in image +wireguard_peer_add_reply | only in image +wireguard_peer_remove | only in image +wireguard_peer_remove_reply | only in image +wireguard_peers_details | only in image +wireguard_peers_dump | only in image + +Found 123 api message signature differences + + +### Newly deprecated API messages + +These messages are still there in the API, but can and probably +will disappear in the next release. + +- bond_create +- bond_detach_slave +- bond_detach_slave_reply +- bond_enslave +- cop_interface_enable_disable +- cop_interface_enable_disable_reply +- cop_whitelist_enable_disable +- cop_whitelist_enable_disable_reply +- geneve_add_del_tunnel +- ipsec_tunnel_if_add_del +- ipsec_tunnel_if_set_sa +- ipsec_tunnel_if_set_sa_reply +- map_domain_dump +- nat_det_add_del_map +- nat_det_add_del_map_reply +- nat_det_close_session_in +- nat_det_close_session_in_reply +- nat_det_close_session_out +- nat_det_close_session_out_reply +- nat_det_forward +- nat_det_forward_reply +- nat_det_map_details +- nat_det_map_dump +- nat_det_reverse +- nat_det_reverse_reply +- nat_det_session_details +- nat_det_session_dump +- nat_show_config +- nsim_configure +- nsim_configure_reply +- sw_interface_bond_dump +- sw_interface_slave_dump +- virtio_pci_create +- virtio_pci_create_reply + +### In-progress API messages + +These messages are provided for testing and experimentation only. +They are *not* subject to any compatibility process, +and therefore can arbitrarily change or disappear at *any* moment. +Also they may have less than satisfactory testing, making +them unsuitable for other use than the technology preview. +If you are intending to use these messages in production projects, +please collaborate with the feature maintainer on their productization. + +- abf_itf_attach_add_del +- abf_itf_attach_add_del_reply +- abf_itf_attach_details +- abf_itf_attach_dump +- abf_plugin_get_version +- abf_plugin_get_version_reply +- abf_policy_add_del +- abf_policy_add_del_reply +- abf_policy_details +- abf_policy_dump +- adl_allowlist_enable_disable +- adl_allowlist_enable_disable_reply +- adl_interface_enable_disable +- adl_interface_enable_disable_reply +- af_xdp_create +- af_xdp_create_reply +- af_xdp_delete +- af_xdp_delete_reply +- cnat_add_del_snat_prefix +- cnat_add_del_snat_prefix_reply +- cnat_session_details +- cnat_session_dump +- cnat_session_purge +- cnat_session_purge_reply +- cnat_set_snat_addresses +- cnat_set_snat_addresses_reply +- cnat_translation_del +- cnat_translation_del_reply +- cnat_translation_details +- cnat_translation_dump +- cnat_translation_update +- cnat_translation_update_reply +- crypto_sw_scheduler_set_worker +- crypto_sw_scheduler_set_worker_reply +- det44_get_timeouts_reply +- det44_interface_add_del_feature +- det44_interface_add_del_feature_reply +- det44_interface_details +- det44_interface_dump +- det44_plugin_enable_disable +- det44_plugin_enable_disable_reply +- det44_set_timeouts +- det44_set_timeouts_reply +- flow_add +- flow_add_reply +- flow_del +- flow_del_reply +- flow_disable +- flow_disable_reply +- flow_enable +- flow_enable_reply +- gbp_bridge_domain_add +- gbp_bridge_domain_add_reply +- gbp_bridge_domain_del +- gbp_bridge_domain_del_reply +- gbp_bridge_domain_details +- gbp_bridge_domain_dump +- gbp_bridge_domain_dump_reply +- gbp_contract_add_del +- gbp_contract_add_del_reply +- gbp_contract_details +- gbp_contract_dump +- gbp_endpoint_add +- gbp_endpoint_add_reply +- gbp_endpoint_del +- gbp_endpoint_del_reply +- gbp_endpoint_details +- gbp_endpoint_dump +- gbp_endpoint_group_add +- gbp_endpoint_group_add_reply +- gbp_endpoint_group_del +- gbp_endpoint_group_del_reply +- gbp_endpoint_group_details +- gbp_endpoint_group_dump +- gbp_ext_itf_add_del +- gbp_ext_itf_add_del_reply +- gbp_ext_itf_details +- gbp_ext_itf_dump +- gbp_recirc_add_del +- gbp_recirc_add_del_reply +- gbp_recirc_details +- gbp_recirc_dump +- gbp_route_domain_add +- gbp_route_domain_add_reply +- gbp_route_domain_del +- gbp_route_domain_del_reply +- gbp_route_domain_details +- gbp_route_domain_dump +- gbp_route_domain_dump_reply +- gbp_subnet_add_del +- gbp_subnet_add_del_reply +- gbp_subnet_details +- gbp_subnet_dump +- gbp_vxlan_tunnel_add +- gbp_vxlan_tunnel_add_reply +- gbp_vxlan_tunnel_del +- gbp_vxlan_tunnel_del_reply +- gbp_vxlan_tunnel_details +- gbp_vxlan_tunnel_dump +- ikev2_child_sa_details +- ikev2_child_sa_dump +- ikev2_initiate_del_child_sa +- ikev2_initiate_del_child_sa_reply +- ikev2_initiate_del_ike_sa +- ikev2_initiate_del_ike_sa_reply +- ikev2_initiate_rekey_child_sa +- ikev2_initiate_rekey_child_sa_reply +- ikev2_initiate_sa_init +- ikev2_initiate_sa_init_reply +- ikev2_nonce_get +- ikev2_nonce_get_reply +- ikev2_profile_add_del +- ikev2_profile_add_del_reply +- ikev2_profile_details +- ikev2_profile_dump +- ikev2_profile_set_auth +- ikev2_profile_set_auth_reply +- ikev2_profile_set_id +- ikev2_profile_set_id_reply +- ikev2_profile_set_ipsec_udp_port +- ikev2_profile_set_ipsec_udp_port_reply +- ikev2_profile_set_liveness +- ikev2_profile_set_liveness_reply +- ikev2_profile_set_ts +- ikev2_profile_set_ts_reply +- ikev2_profile_set_udp_encap +- ikev2_profile_set_udp_encap_reply +- ikev2_sa_details +- ikev2_sa_dump +- ikev2_set_esp_transforms +- ikev2_set_esp_transforms_reply +- ikev2_set_ike_transforms +- ikev2_set_ike_transforms_reply +- ikev2_set_local_key +- ikev2_set_local_key_reply +- ikev2_set_responder +- ikev2_set_responder_reply +- ikev2_set_sa_lifetime +- ikev2_set_sa_lifetime_reply +- ikev2_set_tunnel_interface +- ikev2_set_tunnel_interface_reply +- ikev2_traffic_selector_details +- ikev2_traffic_selector_dump +- l2_emulation +- l2_emulation_reply +- mdata_enable_disable +- mdata_enable_disable_reply +- nat44_add_del_static_mapping_v2 +- nat44_add_del_static_mapping_v2_reply +- oddbuf_enable_disable +- oddbuf_enable_disable_reply +- pg_interface_enable_disable_coalesce +- pg_interface_enable_disable_coalesce_reply +- sample_macswap_enable_disable +- sample_macswap_enable_disable_reply +- sr_policies_with_sl_index_details +- sr_policies_with_sl_index_dump +- sw_interface_set_vxlan_gbp_bypass +- sw_interface_set_vxlan_gbp_bypass_reply +- trace_details +- trace_dump +- trace_dump_reply +- vxlan_gbp_tunnel_add_del +- vxlan_gbp_tunnel_add_del_reply +- vxlan_gbp_tunnel_details +- vxlan_gbp_tunnel_dump +- wireguard_interface_create +- wireguard_interface_create_reply +- wireguard_interface_delete +- wireguard_interface_delete_reply +- wireguard_interface_details +- wireguard_interface_dump +- wireguard_peer_add +- wireguard_peer_add_reply +- wireguard_peer_remove +- wireguard_peer_remove_reply +- wireguard_peers_details +- wireguard_peers_dump + +### Patches that changed API definitions + +| @c src/vpp/api/vpe.api || +| ------- | ------- | +| [d0236f725](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=d0236f725) | flow: add vnet/flow formal API | + +| @c src/vnet/crypto/crypto.api || +| ------- | ------- | +| [4035daffd](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4035daffd) | crypto: Crypto set handler API to support set all as CLI | +| [0c936b147](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=0c936b147) | crypto: Add async crypto APIs | + +| @c src/vnet/cop/cop.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [ac0326fc5](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=ac0326fc5) | adl: move allow/deny list function to plugin | + +| @c src/vnet/lisp-gpe/lisp_gpe.api || +| ------- | ------- | +| [4ab5190eb](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4ab5190eb) | lisp: API cleanup | + +| @c src/vnet/vxlan-gbp/vxlan_gbp.api || +| ------- | ------- | +| [f72b1aff7](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=f72b1aff7) | vxlan-gbp: Mark APIs as in-progress | + +| @c src/vnet/flow/flow_types.api || +| ------- | ------- | +| [34bfa50b6](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=34bfa50b6) | flow: code refactor | +| [d0236f725](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=d0236f725) | flow: add vnet/flow formal API | + +| @c src/vnet/flow/flow.api || +| ------- | ------- | +| [d0236f725](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=d0236f725) | flow: add vnet/flow formal API | + +| @c src/vnet/srv6/sr.api || +| ------- | ------- | +| [30fa97dc6](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=30fa97dc6) | sr: new messages created to return sl index for segment lists in a sr policy | + +| @c src/vnet/pg/pg.api || +| ------- | ------- | +| [f382b06fe](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=f382b06fe) | gso: packet coalesce library | +| [0cf528233](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=0cf528233) | gso: fix the udp checksum in test | + +| @c src/vnet/geneve/geneve.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [7fc88cf3a](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=7fc88cf3a) | geneve: support geneve interface acting as a bvi | + +| @c src/vnet/lisp-cp/one.api || +| ------- | ------- | +| [4ab5190eb](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4ab5190eb) | lisp: API cleanup | + +| @c src/vnet/lisp-cp/lisp.api || +| ------- | ------- | +| [4ab5190eb](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4ab5190eb) | lisp: API cleanup | + +| @c src/vnet/devices/tap/tapv2.api || +| ------- | ------- | +| [50bd16559](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=50bd16559) | tap: add virtio 1.1 API flag | + +| @c src/vnet/devices/virtio/vhost_user.api || +| ------- | ------- | +| [a0e8d9669](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=a0e8d9669) | virtio: add vhost sw_if_index filter for sw_interface_vhost_user_dump | + +| @c src/vnet/devices/virtio/virtio.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [518251bc8](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=518251bc8) | virtio: add virtio 1.1 api flags | + +| @c src/vnet/ipsec/ipsec.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [2e84d6655](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=2e84d6655) | ipsec: add ipsec set async mode api | +| [e6df80de4](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=e6df80de4) | ipsec: Deprecate old interface API | +| [dd4ccf262](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=dd4ccf262) | ipsec: Dedicated IPSec interface type | + +| @c src/vnet/bonding/bond.api || +| ------- | ------- | +| [ea7178631](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=ea7178631) | bonding: add bond_create2 API to include gso option | +| [4c4223edf](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4c4223edf) | bonding lacp: replace slave string with member | + +| @c src/vnet/ip/ip_types.api || +| ------- | ------- | +| [d0236f725](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=d0236f725) | flow: add vnet/flow formal API | + +| @c src/plugins/wireguard/wireguard.api || +| ------- | ------- | +| [edca1325c](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=edca1325c) | wireguard: initial implementation of wireguard protocol | + +| @c src/plugins/map/map.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [ac0326fc5](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=ac0326fc5) | adl: move allow/deny list function to plugin | +| [f5db3711b](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=f5db3711b) | api: add new stream message convention | + +| @c src/plugins/lacp/lacp.api || +| ------- | ------- | +| [4c4223edf](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4c4223edf) | bonding lacp: replace slave string with member | + +| @c src/plugins/l2e/l2e.api || +| ------- | ------- | +| [f733e7ade](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=f733e7ade) | l2e: mark API as in-progress | + +| @c src/plugins/ikev2/ikev2.api || +| ------- | ------- | +| [a340fe1ac](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=a340fe1ac) | ikev2: add SA dump API | +| [459d17bb7](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=459d17bb7) | ikev2: refactor and test profile dump API | +| [ac46e3b1d](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=ac46e3b1d) | ikev2: API downgrade due to lack of ikev2 tests | +| [6a9bd8188](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=6a9bd8188) | ikev2: add profile dump API | + +| @c src/plugins/ikev2/ikev2_types.api || +| ------- | ------- | +| [a340fe1ac](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=a340fe1ac) | ikev2: add SA dump API | +| [459d17bb7](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=459d17bb7) | ikev2: refactor and test profile dump API | +| [6a9bd8188](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=6a9bd8188) | ikev2: add profile dump API | + +| @c src/plugins/tracedump/tracedump.api || +| ------- | ------- | +| [65b65a469](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=65b65a469) | misc: add tracedump API plugin | + +| @c src/plugins/gtpu/gtpu.api || +| ------- | ------- | +| [9ebbb5c41](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=9ebbb5c41) | gtpu: support separate rx-decap and encap-tx teid values | + +| @c src/plugins/gbp/gbp.api || +| ------- | ------- | +| [d2f8fb9c7](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=d2f8fb9c7) | gbp: mark APIs as in-progress | + +| @c src/plugins/acl/acl.api || +| ------- | ------- | +| [24ee40a5c](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=24ee40a5c) | acl: correct acl vat help message | + +| @c src/plugins/nat/dslite/dslite.api || +| ------- | ------- | +| [603e75465](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=603e75465) | nat: move deterministic nat to det44 sub feature | + +| @c src/plugins/nat/det44/det44.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [603e75465](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=603e75465) | nat: move deterministic nat to det44 sub feature | + +| @c src/plugins/nat/nat_types.api || +| ------- | ------- | +| [96068d6b9](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=96068d6b9) | nat: nat66 to plugin | + +| @c src/plugins/nat/nat.api || +| ------- | ------- | +| [6484f4b9c](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=6484f4b9c) | nat: twice-nat static mapping pool address | +| [edc816355](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=edc816355) | nat: fix type in api message | +| [603e75465](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=603e75465) | nat: move deterministic nat to det44 sub feature | +| [96068d6b9](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=96068d6b9) | nat: nat66 to plugin | + +| @c src/plugins/nat/nat66/nat66.api || +| ------- | ------- | +| [96068d6b9](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=96068d6b9) | nat: nat66 to plugin | + +| @c src/plugins/cnat/cnat.api || +| ------- | ------- | +| [29f3c7d2e](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=29f3c7d2e) | cnat: Destination based NAT | + +| @c src/plugins/abf/abf.api || +| ------- | ------- | +| [df494dafa](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=df494dafa) | abf: mark API as in-progress | + +| @c src/plugins/adl/adl.api || +| ------- | ------- | +| [ac0326fc5](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=ac0326fc5) | adl: move allow/deny list function to plugin | + +| @c src/plugins/nsim/nsim.api || +| ------- | ------- | +| [00f21fb2f](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=00f21fb2f) | api: clean up use of deprecated flag | +| [e6c3e8f0e](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=e6c3e8f0e) | nsim: basic reorder support | + +| @c src/plugins/crypto_sw_scheduler/crypto_sw_scheduler.api || +| ------- | ------- | +| [0c936b147](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=0c936b147) | crypto: Add async crypto APIs | + +| @c src/plugins/dhcp/dhcp.api || +| ------- | ------- | +| [bad679291](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=bad679291) | api: register endian handlers for reply messages | + +| @c src/plugins/af_xdp/af_xdp.api || +| ------- | ------- | +| [4a76d6f6d](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4a76d6f6d) | af_xdp: AF_XDP input plugin | + @page release_notes_20051 Release notes for VPP 20.05.1 From 072def4738f149a6e3f2f3884fae55690d6ad3a1 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Wed, 30 Sep 2020 23:53:35 +0000 Subject: [PATCH 064/129] build: fix the version in 'show version' for RPM The RPM build ends up with "vXX.YY" to vstring, which is not what we'd expect - so fix it up. Change-Id: I0af68e69b1e40fc49ade759bb2f0ed9f47614217 Type: fix Signed-off-by: Andrew Yourtchenko --- src/scripts/version | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/scripts/version b/src/scripts/version index 455ab760352a..1c265bff68f9 100755 --- a/src/scripts/version +++ b/src/scripts/version @@ -30,6 +30,11 @@ TAG=$(echo ${vstring} | cut -d- -f1 | sed -e 's/^v//') ADD=$(echo ${vstring} | cut -s -d- -f2) POINT=$(echo ${TAG} | cut -d. -f3) +# during make pkg-rpm vstring ends up being vXX.YY, which is not what we expect. Fix it up. +if [ -z "${ADD}" ]; then + ADD="0" +fi + # if this is a "implicit zeroth" release (e.g. 19.08), check if we need to add ".0" # to fix the artifact versioning sorting if [ -z "${POINT}" ]; then From 93a786b4d7be2d3cdf517b974a5f215b0daaac8f Mon Sep 17 00:00:00 2001 From: Chuan Han Date: Fri, 25 Sep 2020 15:34:06 -0700 Subject: [PATCH 065/129] build: fix build for debian testing 1. add libelf-dev to default deb deps 2. Also use libffi7 instead of libffi6 for debian-testing Type: fix Signed-off-by: Chuan Han Change-Id: I9f13955812877422ecb8aac3dd34c5828b9c4607 --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5af0d5707e00..d4d39b381d75 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ DEB_DEPENDS += python3-venv # ensurepip DEB_DEPENDS += python3-dev # needed for python3 -m pip install psutil # python3.6 on 16.04 requires python36-dev -LIBFFI=libffi6 # works on all but 20.04 +LIBFFI=libffi6 # works on all but 20.04 and debian-testing ifeq ($(OS_VERSION_ID),18.04) DEB_DEPENDS += python-dev python-all python-pip python-virtualenv @@ -92,6 +92,8 @@ else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-10) DEB_DEPENDS += libelf-dev # for libbpf (af_xdp) else DEB_DEPENDS += libssl-dev + DEB_DEPENDS += libelf-dev # for libbpf (af_xdp) + LIBFFI=libffi7 endif DEB_DEPENDS += $(LIBFFI) From 94f5335efba1f396a2a96ecb3b7ac0636a01177b Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 30 Sep 2020 21:56:01 +0000 Subject: [PATCH 066/129] ikev2: fix issue when decrypting packet with no keys Type: fix Change-Id: I0e615d5089587992012a0f280ee902b2906f21c2 Signed-off-by: Filip Tehlar --- src/plugins/ikev2/ikev2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 96b8e7d9b234..bfad2adbd9e0 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -858,7 +858,7 @@ ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload, ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); int is_aead = tr_encr->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16; - if ((!sa->sk_ar || !sa->sk_ai) && !is_aead) + if (((!sa->sk_ar || !sa->sk_ai) && !is_aead) || (!sa->sk_ei || !sa->sk_er)) return 0; while (p < len && From 4a232f88d041b807ed8d3ad807a40809e86861eb Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 1 Oct 2020 03:08:52 +0000 Subject: [PATCH 067/129] ikev2: fix leaking pending INIT requests .. when associated profile is deleted. Type: fix Change-Id: Ib05831d79b3b58664ee0a930960513fd465373bf Signed-off-by: Filip Tehlar (cherry picked from commit 6614df53509030f1c3faf52512bcd8a9851dec5c) --- src/plugins/ikev2/ikev2.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index bfad2adbd9e0..7632a567fd4c 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -3334,6 +3334,22 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p) u32 *sai; u32 *del_sai = 0; + /* *INDENT-OFF* */ + pool_foreach(sa, km->sais, ({ + if (pi == sa->profile_index) + vec_add1 (del_sai, sa - km->sais); + })); + /* *INDENT-ON* */ + + vec_foreach (sai, del_sai) + { + sa = pool_elt_at_index (km->sais, sai[0]); + ikev2_sa_free_all_vec (sa); + hash_unset (km->sa_by_ispi, sa->ispi); + pool_put (km->sais, sa); + } + vec_reset_length (del_sai); + vec_foreach (tkm, km->per_thread_data) { /* *INDENT-OFF* */ From 53604e5c83b4066e31cd79adf145ba4c84fc492f Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Mon, 21 Sep 2020 13:07:29 -0400 Subject: [PATCH 068/129] build: add missing dnf-plugins-core package on centos-8 Type: fix Change-Id: I1a4d9a7a8089cbf488dcd6f09eec6b4e0d0d72fe Signed-off-by: Dave Wallace (cherry picked from commit 858856df162adc095b8ce3c5998c383b0b2f10ff) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d4d39b381d75..268c87f32354 100644 --- a/Makefile +++ b/Makefile @@ -285,7 +285,7 @@ ifeq ($(OS_ID),rhel) @sudo -E yum install $(CONFIRM) $(RPM_DEPENDS) @sudo -E debuginfo-install $(CONFIRM) glibc openssl-libs mbedtls-devel zlib else ifeq ($(OS_ID)-$(OS_VERSION_ID),centos-8) - @sudo -E dnf install $(CONFIRM) epel-release + @sudo -E dnf install $(CONFIRM) dnf-plugins-core epel-release @sudo -E dnf config-manager --set-enabled PowerTools @sudo -E dnf groupinstall $(CONFIRM) $(RPM_DEPENDS_GROUPS) @sudo -E dnf install $(CONFIRM) $(RPM_DEPENDS) From d5f8a9b0ad7a9658e99505c51574264e4f30745a Mon Sep 17 00:00:00 2001 From: Chuan Han Date: Thu, 15 Oct 2020 14:16:49 -0700 Subject: [PATCH 069/129] build: Add missing debian dependencies Otherwise, vpp install will fail. Type: improvement Signed-off-by: Chuan Han Change-Id: Ifb4d7b8f6fb7b333b8205ba6b424176f8554cfdc --- src/pkg/debian/control.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pkg/debian/control.in b/src/pkg/debian/control.in index 0b0c621e50c6..920baaec670a 100644 --- a/src/pkg/debian/control.in +++ b/src/pkg/debian/control.in @@ -51,6 +51,9 @@ Description: Vector Packet Processing--runtime libraries Package: vpp-plugin-core Architecture: any Depends: vpp (= ${source:Version}), + libmbedtls12, + libmbedx509-0, + libmbedcrypto3, ${shlibs:Depends} Description: Vector Packet Processing--runtime core plugins This package contains VPP core plugins @@ -76,6 +79,9 @@ Description: VPP Python API bindings Package: python3-vpp-api Architecture: any Depends: vpp (= ${source:Version}), + python3-cffi, + python3-ply, + python3-pycparser, ${python3:Depends}, ${misc:Depends} Description: VPP Python3 API bindings From 4b50a90aad8afe0844d4c3cb0ac3b799320b182f Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Thu, 15 Oct 2020 15:53:50 -0400 Subject: [PATCH 070/129] build: backport dpdk usertools support python3 only patch - On Centos-8, 'make install-ext-deps' fails due to the bpr-mangle-shebangs script failing the dpdk usertools python scripts containing '#!/usr/bin/env python'. Backport usertools section of the DPDK patch which fixes this issue: http://git.dpdk.org/dpdk/commit/?id=3f6f83626cf4967a99382a6518a614a1bf3d2c20 - Also fix README to reflect name change of dpdk master branch to 'main'. - On stable/2009, the dpdk build using make fails due to rpmbuild defaulting to using /usr/bin/python (version 2.7) which fails to build. The build on master uses meson which somehow resolves this issue. For this cherry-pick, fix the build by fixing the rpm vpp-ext-deps spec to force the use of python3. Type: fix Change-Id: I487b1ff2da786a4a3fd8fb0f859436b0e1885f1b Signed-off-by: Dave Wallace --- build/external/patches/README | 2 +- ...dpdk-usertools-support-python-3-only.patch | 212 ++++++++++++++++++ build/external/rpm/vpp-ext-deps.spec | 4 + 3 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch diff --git a/build/external/patches/README b/build/external/patches/README index 0bead2ef6292..b2c66d9bdc51 100644 --- a/build/external/patches/README +++ b/build/external/patches/README @@ -24,7 +24,7 @@ for release tag “v2.2.0” and will create a branch named “two_dot_two”. 5. Create the patch files with format-patch. This creates all the patch files for your branch (two_dot_two), with your latest commits as the last ones. - # git format-patch master..two_dot_two + # git format-patch main..two_dot_two 6. Copy, add and commit the new patches into the patches directory. diff --git a/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch b/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch new file mode 100644 index 000000000000..99ccc25dae1d --- /dev/null +++ b/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch @@ -0,0 +1,212 @@ +From 858b4575513fe72dce95370944b0da237b755204 Mon Sep 17 00:00:00 2001 +From: Dave Wallace +Date: Thu, 15 Oct 2020 15:22:22 -0400 +Subject: [PATCH] backport dpdk usertools support python 3 only + +Applicable usertools section of DPDK patch: +http://git.dpdk.org/dpdk/commit/?id=3f6f83626cf4967a99382a6518a614a1bf3d2c20 + +Required to avoid build failure of 'make install-ext-deps' on CentOS-8 due +to brp-mangle-shebangs failing on un-versioned python shebang (e.g. +'#! /usr/bin/env python'. + +Signed-off-by: Dave Wallace +--- + usertools/cpu_layout.py | 15 ++------------- + usertools/dpdk-devbind.py | 22 ++++------------------ + usertools/dpdk-pmdinfo.py | 7 +------ + usertools/dpdk-telemetry-client.py | 18 +++--------------- + usertools/dpdk-telemetry.py | 2 +- + 5 files changed, 11 insertions(+), 53 deletions(-) + +diff --git a/usertools/cpu_layout.py b/usertools/cpu_layout.py +index 5423c7965..cc3963821 100755 +--- a/usertools/cpu_layout.py ++++ b/usertools/cpu_layout.py +@@ -1,19 +1,8 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + # SPDX-License-Identifier: BSD-3-Clause + # Copyright(c) 2010-2014 Intel Corporation + # Copyright(c) 2017 Cavium, Inc. All rights reserved. + +-from __future__ import print_function +-import sys +-try: +- xrange # Python 2 +-except NameError: +- xrange = range # Python 3 +- +-if sys.version_info.major < 3: +- print("WARNING: Python 2 is deprecated for use in DPDK, and will not work in future releases.", file=sys.stderr) +- print("Please use Python 3 instead", file=sys.stderr) +- + sockets = [] + cores = [] + core_map = {} +@@ -21,7 +10,7 @@ + fd = open("{}/kernel_max".format(base_path)) + max_cpus = int(fd.read()) + fd.close() +-for cpu in xrange(max_cpus + 1): ++for cpu in range(max_cpus + 1): + try: + fd = open("{}/cpu{}/topology/core_id".format(base_path, cpu)) + except IOError: +diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py +index 094c2ffc8..8278a748d 100755 +--- a/usertools/dpdk-devbind.py ++++ b/usertools/dpdk-devbind.py +@@ -1,9 +1,8 @@ +-#! /usr/bin/env python ++#!/usr/bin/env python3 + # SPDX-License-Identifier: BSD-3-Clause + # Copyright(c) 2010-2014 Intel Corporation + # + +-from __future__ import print_function + import sys + import os + import getopt +@@ -12,10 +11,6 @@ + from os.path import exists, abspath, dirname, basename + from os.path import join as path_join + +-if sys.version_info.major < 3: +- print("WARNING: Python 2 is deprecated for use in DPDK, and will not work in future releases.", file=sys.stderr) +- print("Please use Python 3 instead", file=sys.stderr) +- + # The PCI base class for all devices + network_class = {'Class': '02', 'Vendor': None, 'Device': None, + 'SVendor': None, 'SDevice': None} +@@ -154,14 +149,6 @@ def usage(): + + """ % locals()) # replace items from local variables + +- +-# This is roughly compatible with check_output function in subprocess module +-# which is only available in python 2.7. +-def check_output(args, stderr=None): +- '''Run a command and capture its output''' +- return subprocess.Popen(args, stdout=subprocess.PIPE, +- stderr=stderr).communicate()[0] +- + # check if a specific kernel module is loaded + def module_is_loaded(module): + global loaded_modules +@@ -218,8 +205,7 @@ def get_pci_device_details(dev_id, probe_lspci): + device = {} + + if probe_lspci: +- extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() +- ++ extra_info = subprocess.check_output(["lspci", "-vmmks", dev_id]).splitlines() + # parse lspci details + for line in extra_info: + if len(line) == 0: +@@ -255,7 +241,7 @@ def get_device_details(devices_type): + # first loop through and read details for all devices + # request machine readable format, with numeric IDs and String + dev = {} +- dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines() ++ dev_lines = subprocess.check_output(["lspci", "-Dvmmnnk"]).splitlines() + for dev_line in dev_lines: + if len(dev_line) == 0: + if device_type_match(dev, devices_type): +@@ -283,7 +269,7 @@ def get_device_details(devices_type): + # check what is the interface if any for an ssh connection if + # any to this host, so we can mark it later. + ssh_if = [] +- route = check_output(["ip", "-o", "route"]) ++ route = subprocess.check_output(["ip", "-o", "route"]) + # filter out all lines for 169.254 routes + route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), + route.decode().splitlines())) +diff --git a/usertools/dpdk-pmdinfo.py b/usertools/dpdk-pmdinfo.py +index f9ed75517..166198279 100755 +--- a/usertools/dpdk-pmdinfo.py ++++ b/usertools/dpdk-pmdinfo.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + # SPDX-License-Identifier: BSD-3-Clause + # Copyright(c) 2016 Neil Horman + +@@ -7,8 +7,6 @@ + # Utility to dump PMD_INFO_STRING support from an object file + # + # ------------------------------------------------------------------------- +-from __future__ import print_function +-from __future__ import unicode_literals + import json + import io + import os +@@ -28,9 +26,6 @@ + pcidb = None + + # =========================================== +-if sys.version_info.major < 3: +- print("WARNING: Python 2 is deprecated for use in DPDK, and will not work in future releases.", file=sys.stderr) +- print("Please use Python 3 instead", file=sys.stderr) + + class Vendor: + """ +diff --git a/usertools/dpdk-telemetry-client.py b/usertools/dpdk-telemetry-client.py +index 98d28fa89..d8e439027 100755 +--- a/usertools/dpdk-telemetry-client.py ++++ b/usertools/dpdk-telemetry-client.py +@@ -1,10 +1,7 @@ +-#! /usr/bin/env python ++#! /usr/bin/env python3 + # SPDX-License-Identifier: BSD-3-Clause + # Copyright(c) 2018 Intel Corporation + +-from __future__ import print_function +-from __future__ import unicode_literals +- + import socket + import os + import sys +@@ -18,15 +15,6 @@ + GLOBAL_METRICS_REQ = "{\"action\":0,\"command\":\"global_stat_values\",\"data\":null}" + DEFAULT_FP = "/var/run/dpdk/default_client" + +-try: +- raw_input # Python 2 +-except NameError: +- raw_input = input # Python 3 +- +-if sys.version_info.major < 3: +- print("WARNING: Python 2 is deprecated for use in DPDK, and will not work in future releases.", file=sys.stderr) +- print("Please use Python 3 instead", file=sys.stderr) +- + class Socket: + + def __init__(self): +@@ -86,7 +74,7 @@ def requestMetrics(self): # Requests metrics for given client + + def repeatedlyRequestMetrics(self, sleep_time): # Recursively requests metrics for given client + print("\nPlease enter the number of times you'd like to continuously request Metrics:") +- n_requests = int(raw_input("\n:")) ++ n_requests = int(input("\n:")) + print("\033[F") #Removes the user input from screen, cleans it up + print("\033[K") + for i in range(n_requests): +@@ -107,7 +95,7 @@ def interactiveMenu(self, sleep_time): # Creates Interactive menu within the scr + print("[4] Unregister client") + + try: +- self.choice = int(raw_input("\n:")) ++ self.choice = int(input("\n:")) + print("\033[F") #Removes the user input for screen, cleans it up + print("\033[K") + if self.choice == 1: +diff --git a/usertools/dpdk-telemetry.py b/usertools/dpdk-telemetry.py +index 8e4039d57..181859658 100755 +--- a/usertools/dpdk-telemetry.py ++++ b/usertools/dpdk-telemetry.py +@@ -1,4 +1,4 @@ +-#! /usr/bin/python3 ++#! /usr/bin/env python3 + # SPDX-License-Identifier: BSD-3-Clause + # Copyright(c) 2020 Intel Corporation diff --git a/build/external/rpm/vpp-ext-deps.spec b/build/external/rpm/vpp-ext-deps.spec index e0980abe0721..956ea68d97bc 100644 --- a/build/external/rpm/vpp-ext-deps.spec +++ b/build/external/rpm/vpp-ext-deps.spec @@ -1,6 +1,10 @@ %define _install_dir /opt/vpp/external/%(uname -m) %define _make_args -C ../.. BUILD_DIR=%{_topdir}/tmp INSTALL_DIR=%{buildroot}%{_install_dir} +%{!?__python3: %global __python3 /usr/bin/python3} +%global __python %{__python3} +%global _pylib /usr/lib/python3.6/site-packages + Name: vpp-ext-deps Version: %{_version} Release: %{_release} From 9ef7eae6990f0eee02042d2596ab0195899f7aed Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Mon, 19 Oct 2020 14:57:55 -0400 Subject: [PATCH 071/129] build: fix broken debian dependencies on ubuntu-18.04 & debian-9 - Installation vpp-plugin-core from packagecloud.io/master & packagecloud.io/2009 breaks due to invalid dependencies on newer versions of libmbedtls & libmbedcrypto Type: fix Fixes: 641467406 Signed-off-by: Dave Wallace Change-Id: If736dabcc4a91a04b46515620dd87662b7b14260 Signed-off-by: Dave Wallace --- src/pkg/debian/control.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pkg/debian/control.in b/src/pkg/debian/control.in index 920baaec670a..ef66682f8a7d 100644 --- a/src/pkg/debian/control.in +++ b/src/pkg/debian/control.in @@ -51,9 +51,9 @@ Description: Vector Packet Processing--runtime libraries Package: vpp-plugin-core Architecture: any Depends: vpp (= ${source:Version}), - libmbedtls12, + libmbedtls12 | libmbedtls10, libmbedx509-0, - libmbedcrypto3, + libmbedcrypto3 | libmbedcrypto1 | libmbedcrypto0, ${shlibs:Depends} Description: Vector Packet Processing--runtime core plugins This package contains VPP core plugins From 312e441a8e4c1bd6c90d6f2570c2746139086be6 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Wed, 21 Oct 2020 19:27:05 -0400 Subject: [PATCH 072/129] build: fix external patch application to not create .orig files - Generation of patched original files (eg. dpdk-devbind.py.orig) causes build breakage of 'make install-ext-deps' on CentOS-8. Note: this only occurs on builds using 'make' for dpdk instead of 'meson'. Thus only applies to stable/2009. Type: fix Signed-off-by: Dave Wallace Change-Id: I3f1f70781b7a5564cd38e8876644d817e2eb4aad --- build/external/packages.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/external/packages.mk b/build/external/packages.mk index 005c2a958b2e..bcd1d38a3870 100644 --- a/build/external/packages.mk +++ b/build/external/packages.mk @@ -79,7 +79,7 @@ $(B)/.$1.patch.ok: $(B)/.$1.extract.ok ifneq ($$(wildcard $$($1_patch_dir)/*.patch),) @for f in $$($1_patch_dir)/*.patch ; do \ echo "Applying patch: $$$$(basename $$$$f)" ; \ - patch -p1 -d $$($1_src_dir) < $$$$f ; \ + patch -p1 -d $$($1_src_dir) --no-backup-if-mismatch < $$$$f ; \ done endif @touch $$@ From ee3ea114961610476bac544a979fdee8278d2b9e Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Fri, 23 Oct 2020 09:35:12 -0400 Subject: [PATCH 073/129] build: fix typo in dpdk-20.08 patch #0003 Type: fix Signed-off-by: Dave Wallace Change-Id: Id0b3264e723f1df161a606e4dbdcd70c36d448a4 --- .../0003-backport-dpdk-usertools-support-python-3-only.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch b/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch index 99ccc25dae1d..7cc718306aa1 100644 --- a/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch +++ b/build/external/patches/dpdk_20.08/0003-backport-dpdk-usertools-support-python-3-only.patch @@ -57,9 +57,9 @@ diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py index 094c2ffc8..8278a748d 100755 --- a/usertools/dpdk-devbind.py +++ b/usertools/dpdk-devbind.py -@@ -1,9 +1,8 @@ +@@ -1,4 +1,4 @@ -#! /usr/bin/env python -+#!/usr/bin/env python3 ++#! /usr/bin/env python3 # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2014 Intel Corporation # From 11166453a54511b1396faed46abb946a0d2eb393 Mon Sep 17 00:00:00 2001 From: Steven Luong Date: Mon, 12 Oct 2020 10:43:28 -0700 Subject: [PATCH 074/129] virtio: checksum error reported for ip6 traffic with GSO enable When GSO is enabled, vhost clears the checksum field prior to transmitting the packet. Some newer kernel version does not like that and complains about checksum error. This was seen with ip6 traffic. Type: fix Signed-off-by: Steven Luong Change-Id: I7c6f2a6148f4a30107bfa8b078f5990e64300cf1 (cherry picked from commit ac0f5363881fdce2721287bc5c756282166d9991) --- src/vnet/devices/virtio/vhost_user_input.c | 6 +----- src/vnet/devices/virtio/vhost_user_output.c | 6 ------ 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/vnet/devices/virtio/vhost_user_input.c b/src/vnet/devices/virtio/vhost_user_input.c index ea8e7d6f777c..1209e13d742a 100644 --- a/src/vnet/devices/virtio/vhost_user_input.c +++ b/src/vnet/devices/virtio/vhost_user_input.c @@ -292,15 +292,11 @@ vhost_user_handle_rx_offload (vlib_buffer_t * b0, u8 * b0_data, tcp_header_t *tcp = (tcp_header_t *) (b0_data + vnet_buffer (b0)->l4_hdr_offset); l4_hdr_sz = tcp_header_bytes (tcp); - tcp->checksum = 0; b0->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; } else if (l4_proto == IP_PROTOCOL_UDP) { - udp_header_t *udp = - (udp_header_t *) (b0_data + vnet_buffer (b0)->l4_hdr_offset); - l4_hdr_sz = sizeof (*udp); - udp->checksum = 0; + l4_hdr_sz = sizeof (udp_header_t); b0->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; } diff --git a/src/vnet/devices/virtio/vhost_user_output.c b/src/vnet/devices/virtio/vhost_user_output.c index 2d17ddfda047..54d478c7034c 100644 --- a/src/vnet/devices/virtio/vhost_user_output.c +++ b/src/vnet/devices/virtio/vhost_user_output.c @@ -256,18 +256,12 @@ vhost_user_handle_tx_offload (vhost_user_intf_t * vui, vlib_buffer_t * b, hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; hdr->csum_start = gho.l4_hdr_offset; hdr->csum_offset = offsetof (udp_header_t, checksum); - udp_header_t *udp = - (udp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset); - udp->checksum = 0; } else if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM) { hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; hdr->csum_start = gho.l4_hdr_offset; hdr->csum_offset = offsetof (tcp_header_t, checksum); - tcp_header_t *tcp = - (tcp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset); - tcp->checksum = 0; } /* GSO offload */ From 7ed6a731ad352d2cbd610481eed8f1ed5e2997c4 Mon Sep 17 00:00:00 2001 From: Mohammed Hawari Date: Wed, 21 Oct 2020 16:41:30 +0200 Subject: [PATCH 075/129] pci: set PCI memory enable before mapping PCI BAR This change mitigates software faults issued by some versions of the linux kernel vfio-pci driver when VF PCI BARs are used without setting the memory enable bit in the PCI configuration. This problem is mentionned in https://lkml.org/lkml/2020/6/25/628 Change-Id: Idc177be4a5adb6ee467b4dd8f055f133ff267fe1 Type: improvement Signed-off-by: Mohammed Hawari (cherry picked from commit 70fc36f26855fb4c7a56c5d1563d541b395f8f5d) --- src/vlib/linux/pci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/vlib/linux/pci.c b/src/vlib/linux/pci.c index 168acde72886..996c312b1704 100644 --- a/src/vlib/linux/pci.c +++ b/src/vlib/linux/pci.c @@ -1123,9 +1123,21 @@ vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h, clib_error_t *error; int flags = MAP_SHARED; u64 size = 0, offset = 0; + u16 command; pci_log_debug (vm, p, "map region %u to va %p", bar, addr); + if ((error = vlib_pci_read_config_u16 (vm, h, 4, &command))) + return error; + + if (!(command & PCI_COMMAND_MEMORY)) + { + pci_log_debug (vm, p, "setting memory enable bit"); + command |= PCI_COMMAND_MEMORY; + if ((error = vlib_pci_write_config_u16 (vm, h, 4, &command))) + return error; + } + if ((error = vlib_pci_region (vm, h, bar, &fd, &size, &offset))) return error; From 8cfcbaa726fd409ae5090380297c244690ce7c3b Mon Sep 17 00:00:00 2001 From: Mohammed Hawari Date: Mon, 2 Nov 2020 14:05:03 +0100 Subject: [PATCH 076/129] rdma: various fixes for chained buffers tx Type: fix Signed-off-by: Mohammed Hawari Change-Id: I428c87e581db335362fef30e274db8947a896416 (cherry picked from commit a210433d534fe0039ddc2a9aa9840895aef0405d) --- src/plugins/rdma/output.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/plugins/rdma/output.c b/src/plugins/rdma/output.c index 5b181485e49b..567fd7760a88 100644 --- a/src/plugins/rdma/output.c +++ b/src/plugins/rdma/output.c @@ -155,10 +155,11 @@ rdma_device_output_tx_mlx5_chained (vlib_main_t * vm, u32 sq_mask = pow2_mask (txq->dv_sq_log2sz); u32 mask = pow2_mask (txq->bufs_log2sz); u32 dseg_mask = RDMA_TXQ_DV_DSEG_SZ (txq) - 1; - const u32 lkey = wqe[0].dseg.lkey; + const u32 lkey = clib_host_to_net_u32 (rd->lkey); - vlib_buffer_copy_indices (txq->bufs + (txq->tail & mask), bi, - n_left_from - n); + vlib_buffer_copy_indices_to_ring (txq->bufs, bi, txq->tail & mask, + RDMA_TXQ_BUF_SZ (txq), n_left_from - n); + bi += n_left_from - n; while (n >= 1 && wqe_n >= 1) { @@ -264,10 +265,10 @@ rdma_device_output_tx_mlx5_chained (vlib_main_t * vm, n -= 1; } - if (n == n_left_from) - return 0; /* we fail to enqueue even a single packet */ + if (n != n_left_from) + rdma_device_output_tx_mlx5_doorbell (txq, last, tail, sq_mask); - rdma_device_output_tx_mlx5_doorbell (txq, last, tail, sq_mask); + txq->tail = tail; return n_left_from - n; } @@ -343,6 +344,9 @@ rdma_device_output_tx_mlx5 (vlib_main_t * vm, } rdma_device_output_tx_mlx5_doorbell (txq, &wqe[-1], tail, sq_mask); + vlib_buffer_copy_indices_to_ring (txq->bufs, bi, txq->tail & mask, + RDMA_TXQ_BUF_SZ (txq), n_left_from); + txq->tail = tail; return n_left_from; } @@ -389,6 +393,7 @@ rdma_device_output_tx_ibverb (vlib_main_t * vm, const rdma_device_t * rd, rdma_txq_t * txq, u32 n_left_from, u32 * bi, vlib_buffer_t ** b) { + const u32 mask = pow2_mask (txq->bufs_log2sz); struct ibv_send_wr wr[VLIB_FRAME_SIZE], *w = wr; struct ibv_sge sge[VLIB_FRAME_SIZE], *s = sge; u32 n = n_left_from; @@ -474,7 +479,9 @@ rdma_device_output_tx_ibverb (vlib_main_t * vm, n_left_from - (w - wr)); n_left_from = w - wr; } - + vlib_buffer_copy_indices_to_ring (txq->bufs, bi, txq->tail & mask, + RDMA_TXQ_BUF_SZ (txq), n_left_from); + txq->tail += n_left_from; return n_left_from; } @@ -498,7 +505,6 @@ rdma_device_output_tx_try (vlib_main_t * vm, const vlib_node_runtime_t * node, u32 n_left_from, u32 * bi, int is_mlx5dv) { vlib_buffer_t *b[VLIB_FRAME_SIZE]; - const u32 mask = pow2_mask (txq->bufs_log2sz); /* do not enqueue more packet than ring space */ n_left_from = clib_min (n_left_from, RDMA_TXQ_AVAIL_SZ (txq, txq->head, @@ -510,12 +516,11 @@ rdma_device_output_tx_try (vlib_main_t * vm, const vlib_node_runtime_t * node, vlib_get_buffers (vm, bi, b, n_left_from); n_left_from = is_mlx5dv ? - rdma_device_output_tx_mlx5 (vm, node, rd, txq, n_left_from, bi, b) : - rdma_device_output_tx_ibverb (vm, node, rd, txq, n_left_from, bi, b); - - vlib_buffer_copy_indices_to_ring (txq->bufs, bi, txq->tail & mask, - RDMA_TXQ_BUF_SZ (txq), n_left_from); - txq->tail += n_left_from; + rdma_device_output_tx_mlx5 (vm, node, rd, txq, n_left_from, bi, + b) : rdma_device_output_tx_ibverb (vm, node, + rd, txq, + n_left_from, + bi, b); return n_left_from; } From 071328283ef1210ccea8bef06b28be4f59c07d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 20 Oct 2020 14:31:55 +0200 Subject: [PATCH 077/129] svm: fix ASAN annotations for external chunks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chunks can be allocated from another process. We need to manually mark them as accessible for ASAN. Type: fix Change-Id: Ifbeef3346e9cee2c1231f80cbcf7f9673b5b54be Signed-off-by: Benoît Ganne (cherry picked from commit df601ae2d16ed127a9506a7a865484632ee1afe1) --- src/svm/fifo_segment.c | 1 + src/svm/svm_fifo.c | 3 +++ src/vlibmemory/socket_api.c | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/src/svm/fifo_segment.c b/src/svm/fifo_segment.c index 3fd7d9d6ede7..80a22b199787 100644 --- a/src/svm/fifo_segment.c +++ b/src/svm/fifo_segment.c @@ -784,6 +784,7 @@ fsh_slice_collect_chunks (fifo_segment_header_t * fsh, while (c) { + CLIB_MEM_UNPOISON (c, sizeof (*c)); next = c->next; fl_index = fs_freelist_for_size (c->length); c->next = fss->free_chunks[fl_index]; diff --git a/src/svm/svm_fifo.c b/src/svm/svm_fifo.c index fda9481e7216..22f92ba36d69 100644 --- a/src/svm/svm_fifo.c +++ b/src/svm/svm_fifo.c @@ -70,6 +70,8 @@ CLIB_MARCH_FN (svm_fifo_copy_from_chunk, void, svm_fifo_t * f, c = c->next; while ((to_copy -= n_chunk)) { + CLIB_MEM_UNPOISON (c, sizeof (*c)); + CLIB_MEM_UNPOISON (c->data, c->length); n_chunk = clib_min (c->length, to_copy); clib_memcpy_fast (dst + (len - to_copy), &c->data[0], n_chunk); c = c->length <= to_copy ? c->next : c; @@ -1054,6 +1056,7 @@ svm_fifo_peek (svm_fifo_t * f, u32 offset, u32 len, u8 * dst) len = clib_min (cursize - offset, len); head_idx = head + offset; + CLIB_MEM_UNPOISON (f->ooo_deq, sizeof (*f->ooo_deq)); if (!f->ooo_deq || !f_chunk_includes_pos (f->ooo_deq, head_idx)) f_update_ooo_deq (f, head_idx, head_idx + len); diff --git a/src/vlibmemory/socket_api.c b/src/vlibmemory/socket_api.c index a3a0c3b2eb9b..32434cf2b02f 100644 --- a/src/vlibmemory/socket_api.c +++ b/src/vlibmemory/socket_api.c @@ -645,6 +645,11 @@ vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp) if ((rv = ssvm_master_init_memfd (memfd))) goto reply; + /* delete the unused heap created in ssvm_server_init_memfd and mark it + * accessible again for ASAN */ + clib_mem_destroy_mspace (memfd->sh->heap); + CLIB_MEM_UNPOISON ((void *) memfd->sh->ssvm_va, memfd->ssvm_size); + /* Remember to close this fd when the socket connection goes away */ vec_add1 (regp->additional_fds_to_close, memfd->fd); From 019ce71c2d525758a46f4ea88e6722d61e7db1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 20 Oct 2020 14:36:55 +0200 Subject: [PATCH 078/129] ip: fix doxygen doc for address add/del command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: docs Change-Id: I96d5cdb41bd938f06d2d72f2625bf1b3d2c5b1b4 Signed-off-by: Benoît Ganne (cherry picked from commit 7bed48cb79ea13dc34ef263942b4a74030aeb11c) --- src/vnet/ip/ip46_cli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vnet/ip/ip46_cli.c b/src/vnet/ip/ip46_cli.c index ee797ab70682..f58be898d9bb 100644 --- a/src/vnet/ip/ip46_cli.c +++ b/src/vnet/ip/ip46_cli.c @@ -206,10 +206,10 @@ add_del_ip_address (vlib_main_t * vm, * @cliexcmd{set interface ip address GigabitEthernet2/0/0 @::a:1:1:0:7/126} * * To delete a specific interface ip address: - * @cliexcmd{set interface ip address GigabitEthernet2/0/0 172.16.2.12/24 del} + * @cliexcmd{set interface ip address del GigabitEthernet2/0/0 172.16.2.12/24} * * To delete all interfaces addresses (IPv4 and IPv6): - * @cliexcmd{set interface ip address GigabitEthernet2/0/0 del all} + * @cliexcmd{set interface ip address del GigabitEthernet2/0/0 all} * @endparblock ?*/ /* *INDENT-OFF* */ From 52bbd86836bbce0bf413aea46d05535f27ad614d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Fri, 6 Nov 2020 10:55:22 +0100 Subject: [PATCH 079/129] ipsec: fix outer table id lookup in ipsec tun script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: I195949b610dca1b860baca18a059d39949627961 Signed-off-by: Benoît Ganne (cherry picked from commit 27632cae3dbed6afbaaf12d8da7798d7ecaa2ddb) --- src/scripts/vnet/ipsec_tun_protect | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/vnet/ipsec_tun_protect b/src/scripts/vnet/ipsec_tun_protect index b30281fcf924..6dc4dd7b7808 100644 --- a/src/scripts/vnet/ipsec_tun_protect +++ b/src/scripts/vnet/ipsec_tun_protect @@ -22,7 +22,7 @@ ipsec sa add 20 spi 200 crypto-key 6541686776336961656264656f6f6579 crypto-alg a ipsec sa add 30 spi 300 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128 create ipip tunnel src 10.0.0.1 dst 10.0.0.2 -create ipip tunnel src 10.0.0.2 dst 10.0.0.1 +create ipip tunnel src 10.0.0.2 dst 10.0.0.1 outer-table-id 1 ipsec tunnel protect ipip0 sa-in 20 sa-out 30 ipsec tunnel protect ipip1 sa-in 30 sa-out 20 From dcb9fcfc64ab3b35f9ff6ca81cf40069a293d533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 15 Sep 2020 15:25:43 +0200 Subject: [PATCH 080/129] af_xdp: add option to claim all available rx queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: feature Change-Id: I97176c2c90ea664a68078b3a7b7d44eb237a7f13 Signed-off-by: Benoît Ganne (cherry picked from commit d4e109138279fcfbfce9d82384f0fa53b8f43ae1) --- src/plugins/af_xdp/af_xdp.api | 4 +-- src/plugins/af_xdp/af_xdp.h | 2 ++ src/plugins/af_xdp/af_xdp_doc.md | 36 ++++++++++++------------ src/plugins/af_xdp/cli.c | 2 +- src/plugins/af_xdp/device.c | 47 ++++++++++++++++++++------------ src/plugins/af_xdp/unformat.c | 2 ++ 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/plugins/af_xdp/af_xdp.api b/src/plugins/af_xdp/af_xdp.api index 765af6820e3d..14f51d87d6ab 100644 --- a/src/plugins/af_xdp/af_xdp.api +++ b/src/plugins/af_xdp/af_xdp.api @@ -31,7 +31,7 @@ enum af_xdp_mode @param context - sender context, to match reply w/ request @param host_if - Linux netdev interface name @param name - new af_xdp interface name (optional) - @param rxq_num - number of receive queues (optional) + @param rxq_num - number of receive queues. 65535 can be used as special value to request all available queues (optional) @param rxq_size - receive queue size (optional) @param txq_size - transmit queue size (optional) @param mode - operation mode (optional) @@ -50,7 +50,7 @@ define af_xdp_create u16 txq_size [default=0]; vl_api_af_xdp_mode_t mode [default=0]; string prog[256]; - option vat_help = " [name ifname] [rx-queue-size size] [tx-queue-size size] [num-rx-queues num] [prog pathname] [zero-copy|no-zero-copy]"; + option vat_help = " [name ifname] [rx-queue-size size] [tx-queue-size size] [num-rx-queues ] [prog pathname] [zero-copy|no-zero-copy]"; option status="in_progress"; }; diff --git a/src/plugins/af_xdp/af_xdp.h b/src/plugins/af_xdp/af_xdp.h index fd990ec3f90c..3bd53ad768d2 100644 --- a/src/plugins/af_xdp/af_xdp.h +++ b/src/plugins/af_xdp/af_xdp.h @@ -22,6 +22,8 @@ #include #include +#define AF_XDP_NUM_RX_QUEUES_ALL ((u16)-1) + #define af_xdp_log(lvl, dev, f, ...) \ vlib_log(lvl, af_xdp_main.log_class, "%v: " f, (dev)->name, ##__VA_ARGS__) diff --git a/src/plugins/af_xdp/af_xdp_doc.md b/src/plugins/af_xdp/af_xdp_doc.md index 40a3596be7ca..76d653fd251d 100644 --- a/src/plugins/af_xdp/af_xdp_doc.md +++ b/src/plugins/af_xdp/af_xdp_doc.md @@ -17,8 +17,13 @@ Because of AF_XDP restrictions, the MTU is limited to below PAGE_SIZE (4096-bytes on most systems) minus 256-bytes, and they are additional limitations depending upon specific Linux device drivers. As a rule of thumb, a MTU of 3000-bytes or less should be safe. -Furthermore, upon UMEM creation, the kernel allocates a physically-contiguous structure, whose size is proportional to the number of 4KB pages contained in the UMEM. That allocation might fail when the number of buffers allocated by VPP is too high. That number can be controlled with the `buffers { buffers-per-numa }` configuration option. -Finally, note that because of this limitation, this plugin is unlikely to be compatible with the use of 1GB hugepages. +Furthermore, upon UMEM creation, the kernel allocates a +physically-contiguous structure, whose size is proportional to the number +of 4KB pages contained in the UMEM. That allocation might fail when +the number of buffers allocated by VPP is too high. That number can be +controlled with the `buffers { buffers-per-numa }` configuration option. +Finally, note that because of this limitation, this plugin is unlikely +to be compatible with the use of 1GB hugepages. ## Requirements The Linux kernel interface must be up and have enough queues before @@ -31,9 +36,10 @@ AF_XDP interface, and only them. Depending on your configuration, there will usually be several RX queues (typically 1 per core) and packets are spread accross queues by RSS. In order to receive consistent traffic, you **must** program the NIC dispatching accordingly. The simplest way -to get all the packets is to reconfigure the Linux kernel driver to use -only `num_rx_queues` RX queues (ie all NIC queues will be associated -with the AF_XDP socket): +to get all the packets is to specify `num-rx-queues all` to grab all +available queues or to reconfigure the Linux kernel driver to use only +`num_rx_queues` RX queues (ie all NIC queues will be associated with +the AF_XDP socket): ``` ~# ethtool -L combined ``` @@ -57,25 +63,21 @@ kernel interface in promiscuous mode: ## Security considerations When creating an AF_XDP interface, it will receive all packets arriving -to the NIC RX queue #0. You need to configure the Linux kernel NIC -driver properly to ensure that only intented packets will arrive in -this queue. There is no way to filter the packets after-the-fact using -eg. netfilter or eBPF. +to the NIC RX queue [0, num_rx_queues[`. You need to configure the Linux +kernel NIC driver properly to ensure that only intented packets will +arrive in this queue. There is no way to filter the packets after-the-fact +using eg. netfilter or eBPF. ## Quickstart -1. Setup the Linux kernel interface (enp216s0f0 here) to use 4 queues: -``` -~# ethtool -L enp216s0f0 combined 4 -``` -2. Put the Linux kernel interface up and in promiscuous mode: +1. Put the Linux kernel interface up and in promiscuous mode: ``` ~# ip l set dev enp216s0f0 promisc on up ``` -3. Create the AF_XDP interface: +2. Create the AF_XDP interface: ``` -~# vppctl create int af_xdp host-if enp216s0f0 num-rx-queues 4 +~# vppctl create int af_xdp host-if enp216s0f0 num-rx-queues all ``` -4. Use the interface as usual, eg.: +3. Use the interface as usual, eg.: ``` ~# vppctl set int ip addr enp216s0f0/0 1.1.1.1/24 ~# vppctl set int st enp216s0f0/0 up diff --git a/src/plugins/af_xdp/cli.c b/src/plugins/af_xdp/cli.c index 5fe7c2ef399b..d5f21d4c3919 100644 --- a/src/plugins/af_xdp/cli.c +++ b/src/plugins/af_xdp/cli.c @@ -47,7 +47,7 @@ af_xdp_create_command_fn (vlib_main_t * vm, unformat_input_t * input, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (af_xdp_create_command, static) = { .path = "create interface af_xdp", - .short_help = "create interface af_xdp [name ifname] [rx-queue-size size] [tx-queue-size size] [num-rx-queues num] [prog pathname] [zero-copy|no-zero-copy]", + .short_help = "create interface af_xdp [name ifname] [rx-queue-size size] [tx-queue-size size] [num-rx-queues ] [prog pathname] [zero-copy|no-zero-copy]", .function = af_xdp_create_command_fn, }; /* *INDENT-ON* */ diff --git a/src/plugins/af_xdp/device.c b/src/plugins/af_xdp/device.c index 9bca41c962c1..35e39b79fbd7 100644 --- a/src/plugins/af_xdp/device.c +++ b/src/plugins/af_xdp/device.c @@ -171,14 +171,27 @@ static int af_xdp_create_queue (vlib_main_t * vm, af_xdp_create_if_args_t * args, af_xdp_device_t * ad, int qid, int rxq_num, int txq_num) { - struct xsk_umem **umem = vec_elt_at_index (ad->umem, qid); - struct xsk_socket **xsk = vec_elt_at_index (ad->xsk, qid); - af_xdp_rxq_t *rxq = vec_elt_at_index (ad->rxqs, qid); - af_xdp_txq_t *txq = vec_elt_at_index (ad->txqs, qid); + struct xsk_umem **umem; + struct xsk_socket **xsk; + af_xdp_rxq_t *rxq; + af_xdp_txq_t *txq; struct xsk_umem_config umem_config; struct xsk_socket_config sock_config; struct xdp_options opt; socklen_t optlen; + + vec_validate_aligned (ad->umem, qid, CLIB_CACHE_LINE_BYTES); + umem = vec_elt_at_index (ad->umem, qid); + + vec_validate_aligned (ad->xsk, qid, CLIB_CACHE_LINE_BYTES); + xsk = vec_elt_at_index (ad->xsk, qid); + + vec_validate_aligned (ad->rxqs, qid, CLIB_CACHE_LINE_BYTES); + rxq = vec_elt_at_index (ad->rxqs, qid); + + vec_validate_aligned (ad->txqs, qid, CLIB_CACHE_LINE_BYTES); + txq = vec_elt_at_index (ad->txqs, qid); + /* * fq and cq must always be allocated even if unused * whereas rx and tx indicates whether we want rxq, txq, or both @@ -335,10 +348,6 @@ af_xdp_create_if (vlib_main_t * vm, af_xdp_create_if_args_t * args) goto err1; q_num = clib_max (rxq_num, txq_num); - vec_validate_aligned (ad->rxqs, q_num - 1, CLIB_CACHE_LINE_BYTES); - vec_validate_aligned (ad->txqs, q_num - 1, CLIB_CACHE_LINE_BYTES); - vec_validate_aligned (ad->umem, q_num - 1, CLIB_CACHE_LINE_BYTES); - vec_validate_aligned (ad->xsk, q_num - 1, CLIB_CACHE_LINE_BYTES); ad->txq_num = txq_num; for (i = 0; i < q_num; i++) { @@ -347,10 +356,10 @@ af_xdp_create_if (vlib_main_t * vm, af_xdp_create_if_args_t * args) /* * queue creation failed * it is only a fatal error if we could not create the number of rx - * queues requested explicitely by the user + * queues requested explicitely by the user and the user did not + * requested 'max' * we might create less tx queues than workers but this is ok */ - af_xdp_txq_t *txq; /* fixup vectors length */ vec_set_len (ad->umem, i); @@ -358,15 +367,17 @@ af_xdp_create_if (vlib_main_t * vm, af_xdp_create_if_args_t * args) vec_set_len (ad->rxqs, i); vec_set_len (ad->txqs, i); - if (i < rxq_num) + if (i < rxq_num && AF_XDP_NUM_RX_QUEUES_ALL != rxq_num) goto err1; /* failed creating requested rxq: fatal error, bailing out */ - /* - * we created all rxq but failed some txq: not an error but - * initialize lock for shared txq - */ - ad->txq_num = i; - vec_foreach (txq, ad->txqs) clib_spinlock_init (&txq->lock); + if (i < txq_num) + { + /* we created less txq than threads not an error but initialize lock for shared txq */ + af_xdp_txq_t *txq; + ad->txq_num = i; + vec_foreach (txq, ad->txqs) clib_spinlock_init (&txq->lock); + } + args->rv = 0; clib_error_free (args->error); break; @@ -406,7 +417,7 @@ af_xdp_create_if (vlib_main_t * vm, af_xdp_create_if_args_t * args) vnet_hw_interface_set_input_node (vnm, ad->hw_if_index, af_xdp_input_node.index); - for (i = 0; i < rxq_num; i++) + for (i = 0; i < vec_len (ad->rxqs); i++) { af_xdp_rxq_t *rxq = vec_elt_at_index (ad->rxqs, i); clib_file_t f = { diff --git a/src/plugins/af_xdp/unformat.c b/src/plugins/af_xdp/unformat.c index 154d459900e4..b22924641121 100644 --- a/src/plugins/af_xdp/unformat.c +++ b/src/plugins/af_xdp/unformat.c @@ -40,6 +40,8 @@ unformat_af_xdp_create_if_args (unformat_input_t * input, va_list * vargs) ; else if (unformat (line_input, "tx-queue-size %u", &args->txq_size)) ; + else if (unformat (line_input, "num-rx-queues all")) + args->rxq_num = AF_XDP_NUM_RX_QUEUES_ALL; else if (unformat (line_input, "num-rx-queues %u", &args->rxq_num)) ; else if (unformat (line_input, "prog %s", &args->prog)) From 9c73329588d33a5e731d72b6eeae67201c7ce101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Thu, 8 Oct 2020 14:08:47 +0200 Subject: [PATCH 081/129] build: better detection of libbpf dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: Ib496e6eb0a76e6268aea09d5f4495f3ecd921ec2 Signed-off-by: Benoît Ganne (cherry picked from commit 24b5107edd21b191fac3d6f9f2ae58c6ede59a9e) --- build/external/packages/libbpf.mk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/build/external/packages/libbpf.mk b/build/external/packages/libbpf.mk index 90ff54b433c1..aa72832afe15 100644 --- a/build/external/packages/libbpf.mk +++ b/build/external/packages/libbpf.mk @@ -27,8 +27,10 @@ else LIBBPF_CFLAGS+= -O2 endif -IF_XDP:=$(shell echo "\#include " | $(CC) -E -xc - > /dev/null 2>&1) -IF_XDP:=$(.SHELLSTATUS) +# check for libelf, zlib and kernel if_xdp.h presence +LIBBPF_DEPS_CHECK:="\#include \\n\#include \\n\#include \\nint main(void){return 0;}" +LIBBPF_DEPS_CHECK:=$(shell echo -e $(LIBBPF_DEPS_CHECK) | $(CC) -xc -lelf -lz -o /dev/null - > /dev/null 2>&1) +LIBBPF_DEPS_CHECK:=$(.SHELLSTATUS) define libbpf_config_cmds @true @@ -46,8 +48,8 @@ define libbpf_install_cmds $(call libbpf_build_cmds__,install,$(libbpf_install_log)) endef -ifneq ($(IF_XDP),0) - $(warning "linux/if_xdp.h was not found on this system. libbpf will be skipped.") +ifneq ($(LIBBPF_DEPS_CHECK),0) + $(warning "Missing libbpf dependencies. libbpf will be skipped.") libbpf-install: @true else From 32c2b2ae602f9deaf36bddceaa6df9d931aa37b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Fri, 16 Oct 2020 17:12:41 +0200 Subject: [PATCH 082/129] rdma: add RSS support for IPv6 and TCP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: feature Change-Id: I8b0d918e6f13325954b29bf34e4ef224c1315c51 Signed-off-by: Benoît Ganne (cherry picked from commit 91603958d1d4fc3114739f9b264808940942e5c8) --- src/plugins/rdma/device.c | 81 +++++++++++++++++++++++++-------------- src/plugins/rdma/rdma.h | 9 +++-- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/plugins/rdma/device.c b/src/plugins/rdma/device.c index c91567445bf5..c2eb00062170 100644 --- a/src/plugins/rdma/device.c +++ b/src/plugins/rdma/device.c @@ -57,7 +57,7 @@ rdma_main_t rdma_main; static struct ibv_flow * rdma_rxq_init_flow (const rdma_device_t * rd, struct ibv_qp *qp, const mac_address_t * mac, const mac_address_t * mask, - u32 flags) + u16 ether_type, u32 flags) { struct ibv_flow *flow; struct raw_eth_flow_attr @@ -76,6 +76,12 @@ rdma_rxq_init_flow (const rdma_device_t * rd, struct ibv_qp *qp, memcpy (fa.spec_eth.val.dst_mac, mac, sizeof (fa.spec_eth.val.dst_mac)); memcpy (fa.spec_eth.mask.dst_mac, mask, sizeof (fa.spec_eth.mask.dst_mac)); + if (ether_type) + { + fa.spec_eth.val.ether_type = ether_type; + fa.spec_eth.mask.ether_type = 0xffff; + } + flow = ibv_create_flow (qp, &fa.attr); if (!flow) rdma_log (VLIB_LOG_LEVEL_ERR, rd, "ibv_create_flow() failed"); @@ -104,16 +110,17 @@ rdma_dev_set_promisc (rdma_device_t * rd) const mac_address_t all = {.bytes = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }; int err; - err = rdma_rxq_destroy_flow (rd, &rd->flow_mcast); - if (err) - return ~0; - - err = rdma_rxq_destroy_flow (rd, &rd->flow_ucast); + err = rdma_rxq_destroy_flow (rd, &rd->flow_mcast6); + err |= rdma_rxq_destroy_flow (rd, &rd->flow_ucast6); + err |= rdma_rxq_destroy_flow (rd, &rd->flow_mcast4); + err |= rdma_rxq_destroy_flow (rd, &rd->flow_ucast4); if (err) return ~0; - rd->flow_ucast = rdma_rxq_init_flow (rd, rd->rx_qp, &all, &all, 0); - if (!rd->flow_ucast) + rd->flow_ucast6 = + rdma_rxq_init_flow (rd, rd->rx_qp6, &all, &all, ntohs (ETH_P_IPV6), 0); + rd->flow_ucast4 = rdma_rxq_init_flow (rd, rd->rx_qp4, &all, &all, 0, 0); + if (!rd->flow_ucast6 || !rd->flow_ucast4) return ~0; rd->flags |= RDMA_DEVICE_F_PROMISC; @@ -128,25 +135,30 @@ rdma_dev_set_ucast (rdma_device_t * rd) const mac_address_t mcast = {.bytes = {0x1, 0x0, 0x0, 0x0, 0x0, 0x0} }; int err; - err = rdma_rxq_destroy_flow (rd, &rd->flow_mcast); - if (err) - return ~0; - - err = rdma_rxq_destroy_flow (rd, &rd->flow_ucast); + err = rdma_rxq_destroy_flow (rd, &rd->flow_mcast6); + err |= rdma_rxq_destroy_flow (rd, &rd->flow_ucast6); + err |= rdma_rxq_destroy_flow (rd, &rd->flow_mcast4); + err |= rdma_rxq_destroy_flow (rd, &rd->flow_ucast4); if (err) return ~0; - /* receive only packets with src = our MAC */ - rd->flow_ucast = rdma_rxq_init_flow (rd, rd->rx_qp, &rd->hwaddr, &ucast, 0); - if (!rd->flow_ucast) - return ~0; - - /* receive multicast packets */ - rd->flow_mcast = rdma_rxq_init_flow (rd, rd->rx_qp, &mcast, &mcast, - IBV_FLOW_ATTR_FLAGS_DONT_TRAP - /* let others receive mcast packet too (eg. Linux) */ + rd->flow_ucast6 = + rdma_rxq_init_flow (rd, rd->rx_qp6, &rd->hwaddr, &ucast, + ntohs (ETH_P_IPV6), 0); + rd->flow_mcast6 = + rdma_rxq_init_flow (rd, rd->rx_qp6, &mcast, &mcast, ntohs (ETH_P_IPV6), + IBV_FLOW_ATTR_FLAGS_DONT_TRAP + /* let others receive mcast packet too (eg. Linux) */ + ); + rd->flow_ucast4 = + rdma_rxq_init_flow (rd, rd->rx_qp4, &rd->hwaddr, &ucast, 0, 0); + rd->flow_mcast4 = + rdma_rxq_init_flow (rd, rd->rx_qp4, &mcast, &mcast, 0, + IBV_FLOW_ATTR_FLAGS_DONT_TRAP + /* let others receive mcast packet too (eg. Linux) */ ); - if (!rd->flow_mcast) + if (!rd->flow_ucast6 || !rd->flow_mcast6 || !rd->flow_ucast4 + || !rd->flow_mcast4) return ~0; rd->flags &= ~RDMA_DEVICE_F_PROMISC; @@ -375,8 +387,10 @@ rdma_dev_cleanup (rdma_device_t * rd) rdma_log (VLIB_LOG_LEVEL_DEBUG, rd, #fn "() failed (rv = %d)", rv); \ } - _(ibv_destroy_flow, rd->flow_mcast); - _(ibv_destroy_flow, rd->flow_ucast); + _(ibv_destroy_flow, rd->flow_mcast6); + _(ibv_destroy_flow, rd->flow_ucast6); + _(ibv_destroy_flow, rd->flow_mcast4); + _(ibv_destroy_flow, rd->flow_ucast4); _(ibv_dereg_mr, rd->mr); vec_foreach (txq, rd->txqs) { @@ -389,7 +403,8 @@ rdma_dev_cleanup (rdma_device_t * rd) _(ibv_destroy_cq, rxq->cq); } _(ibv_destroy_rwq_ind_table, rd->rx_rwq_ind_tbl); - _(ibv_destroy_qp, rd->rx_qp); + _(ibv_destroy_qp, rd->rx_qp6); + _(ibv_destroy_qp, rd->rx_qp4); _(ibv_dealloc_pd, rd->pd); _(ibv_close_device, rd->ctx); #undef _ @@ -523,10 +538,18 @@ rdma_rxq_finalize (vlib_main_t * vm, rdma_device_t * rd) qpia.rx_hash_conf.rx_hash_key_len = sizeof (rdma_rss_hash_key); qpia.rx_hash_conf.rx_hash_key = rdma_rss_hash_key; qpia.rx_hash_conf.rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ; + qpia.rx_hash_conf.rx_hash_fields_mask = - IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4; - if ((rd->rx_qp = ibv_create_qp_ex (rd->ctx, &qpia)) == 0) - return clib_error_return_unix (0, "Queue Pair create failed"); + IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4 | IBV_RX_HASH_SRC_PORT_TCP | + IBV_RX_HASH_DST_PORT_TCP; + if ((rd->rx_qp4 = ibv_create_qp_ex (rd->ctx, &qpia)) == 0) + return clib_error_return_unix (0, "IPv4 Queue Pair create failed"); + + qpia.rx_hash_conf.rx_hash_fields_mask = + IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6 | IBV_RX_HASH_SRC_PORT_TCP | + IBV_RX_HASH_DST_PORT_TCP; + if ((rd->rx_qp6 = ibv_create_qp_ex (rd->ctx, &qpia)) == 0) + return clib_error_return_unix (0, "IPv6 Queue Pair create failed"); if (rdma_dev_set_ucast (rd)) return clib_error_return_unix (0, "Set unicast mode failed"); diff --git a/src/plugins/rdma/rdma.h b/src/plugins/rdma/rdma.h index 016956ee0f20..19bfb8b11e56 100644 --- a/src/plugins/rdma/rdma.h +++ b/src/plugins/rdma/rdma.h @@ -172,10 +172,13 @@ typedef struct struct ibv_context *ctx; struct ibv_pd *pd; struct ibv_mr *mr; - struct ibv_qp *rx_qp; + struct ibv_qp *rx_qp4; + struct ibv_qp *rx_qp6; struct ibv_rwq_ind_table *rx_rwq_ind_tbl; - struct ibv_flow *flow_ucast; - struct ibv_flow *flow_mcast; + struct ibv_flow *flow_ucast4; + struct ibv_flow *flow_mcast4; + struct ibv_flow *flow_ucast6; + struct ibv_flow *flow_mcast6; clib_error_t *error; } rdma_device_t; From 19b477f977b73e67166ec0fc66cc9fb950e30799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 30 Sep 2020 18:35:27 +0200 Subject: [PATCH 083/129] ikev2: fix cli memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: Ibdd83fa336427ec0c66224ecebb1b6bd36d1d1ba Signed-off-by: Benoît Ganne (cherry picked from commit 1f6a6b8b2b4efd4d6735ffd6fa683a0190f232e2) --- src/plugins/ikev2/ikev2_cli.c | 70 ++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index 687e6f24d87b..151ee7b31fb4 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -175,6 +175,23 @@ VLIB_CLI_COMMAND (show_ikev2_sa_command, static) = { }; /* *INDENT-ON* */ +static uword +unformat_ikev2_token (unformat_input_t * input, va_list * va) +{ + u8 **string_return = va_arg (*va, u8 **); + const char *token_chars = "a-zA-Z0-9_"; + if (*string_return) + { + /* if string_return was already allocated (eg. because of a previous + * partial match with a successful unformat_token()), we must free it + * before reusing the pointer, otherwise we'll be leaking memory + */ + vec_free (*string_return); + *string_return = 0; + } + return unformat_user (input, unformat_token, token_chars, string_return); +} + static clib_error_t * ikev2_profile_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -197,27 +214,23 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, ikev2_transform_integ_type_t integ_alg; ikev2_transform_dh_type_t dh_type; - const char *valid_chars = "a-zA-Z0-9_"; - if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat (line_input, "add %U", unformat_token, valid_chars, &name)) + if (unformat (line_input, "add %U", unformat_ikev2_token, &name)) { r = ikev2_add_del_profile (vm, name, 1); goto done; } - else - if (unformat - (line_input, "del %U", unformat_token, valid_chars, &name)) + else if (unformat (line_input, "del %U", unformat_ikev2_token, &name)) { r = ikev2_add_del_profile (vm, name, 0); goto done; } else if (unformat (line_input, "set %U auth shared-key-mic string %v", - unformat_token, valid_chars, &name, &data)) + unformat_ikev2_token, &name, &data)) { r = ikev2_set_profile_auth (vm, name, @@ -226,7 +239,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U auth shared-key-mic hex %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_hex_string, &data)) { r = @@ -236,7 +249,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U auth rsa-sig cert-file %v", - unformat_token, valid_chars, &name, &data)) + unformat_ikev2_token, &name, &data)) { r = ikev2_set_profile_auth (vm, name, IKEV2_AUTH_METHOD_RSA_SIG, data, @@ -244,7 +257,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U id local %U %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, unformat_ip4_address, &ip4)) { @@ -255,7 +268,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U id local %U 0x%U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, unformat_hex_string, &data)) { @@ -264,7 +277,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U id local %U %v", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, &data)) { r = @@ -272,7 +285,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U id remote %U %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, unformat_ip4_address, &ip4)) { @@ -283,7 +296,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U id remote %U 0x%U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, unformat_hex_string, &data)) { @@ -292,7 +305,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U id remote %U %v", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, &data)) { r = ikev2_set_profile_id (vm, name, (u8) id_type, data, /*remote */ @@ -301,7 +314,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, } else if (unformat (line_input, "set %U traffic-selector local " "ip-range %U - %U port-range %u - %u protocol %u", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ip4_address, &ip4, unformat_ip4_address, &end_addr, &tmp1, &tmp2, &tmp3)) @@ -313,7 +326,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, } else if (unformat (line_input, "set %U traffic-selector remote " "ip-range %U - %U port-range %u - %u protocol %u", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ip4_address, &ip4, unformat_ip4_address, &end_addr, &tmp1, &tmp2, &tmp3)) @@ -324,7 +337,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U responder %U %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_vnet_sw_interface, vnm, &responder_sw_if_index, unformat_ip4_address, &responder_ip4)) @@ -335,7 +348,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U tunnel %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_vnet_sw_interface, vnm, &tun_sw_if_index)) { r = ikev2_set_profile_tunnel_interface (vm, name, tun_sw_if_index); @@ -345,7 +358,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, if (unformat (line_input, "set %U ike-crypto-alg %U %u ike-integ-alg %U ike-dh %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_transform_encr_type, &crypto_alg, &tmp1, unformat_ikev2_transform_integ_type, &integ_alg, unformat_ikev2_transform_dh_type, &dh_type)) @@ -359,7 +372,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, if (unformat (line_input, "set %U ike-crypto-alg %U %u ike-dh %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_transform_encr_type, &crypto_alg, &tmp1, unformat_ikev2_transform_dh_type, &dh_type)) { @@ -373,7 +386,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, if (unformat (line_input, "set %U esp-crypto-alg %U %u esp-integ-alg %U", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_transform_encr_type, &crypto_alg, &tmp1, unformat_ikev2_transform_integ_type, &integ_alg)) { @@ -385,7 +398,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "set %U esp-crypto-alg %U %u", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, unformat_ikev2_transform_encr_type, &crypto_alg, &tmp1)) { r = @@ -393,7 +406,7 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U sa-lifetime %lu %u %u %lu", - unformat_token, valid_chars, &name, + unformat_ikev2_token, &name, &tmp4, &tmp1, &tmp2, &tmp5)) { r = @@ -401,13 +414,13 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, goto done; } else if (unformat (line_input, "set %U udp-encap", - unformat_token, valid_chars, &name)) + unformat_ikev2_token, &name)) { r = ikev2_set_profile_udp_encap (vm, name); goto done; } else if (unformat (line_input, "set %U ipsec-over-udp port %u", - unformat_token, valid_chars, &name, &tmp1)) + unformat_ikev2_token, &name, &tmp1)) { int rv = ikev2_set_profile_ipsec_udp_port (vm, name, tmp1, 1); if (rv) @@ -651,15 +664,12 @@ ikev2_initiate_command_fn (vlib_main_t * vm, u32 tmp1; u64 tmp2; - const char *valid_chars = "a-zA-Z0-9_"; - if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat - (line_input, "sa-init %U", unformat_token, valid_chars, &name)) + if (unformat (line_input, "sa-init %U", unformat_ikev2_token, &name)) { r = ikev2_initiate_sa_init (vm, name); goto done; From b2a92ff3b97c6ae5f84b48e3a77400afaeb43d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 21 Oct 2020 11:13:24 +0200 Subject: [PATCH 084/129] svm: fix fifo unit test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fix fifo initialization overflowing chunk size - stick to the default base virtual address to initialize fifo. ASAN can be picky about address space Type: fix Change-Id: If9a29138d2c207859d72845e928290c808c4a982 Signed-off-by: Benoît Ganne (cherry picked from commit 07b94558087facbb16c0fa82a79fcbbd9b44c485) --- src/plugins/unittest/svm_fifo_test.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/unittest/svm_fifo_test.c b/src/plugins/unittest/svm_fifo_test.c index f5d4818bfe0b..a3f88d35b9cd 100644 --- a/src/plugins/unittest/svm_fifo_test.c +++ b/src/plugins/unittest/svm_fifo_test.c @@ -190,11 +190,13 @@ static svm_fifo_t * fifo_prepare (fifo_segment_t * fs, u32 fifo_size) { svm_fifo_t *f; + svm_fifo_chunk_t *c; f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO); - /* Paint fifo data vector with -1's */ - clib_memset (svm_fifo_head_chunk (f)->data, 0xFF, fifo_size); + /* Paint 1st fifo chunk with -1's */ + c = svm_fifo_head_chunk (f); + clib_memset (c->data, 0xFF, c->length); svm_fifo_init_ooo_lookup (f, 1 /* deq ooo */ ); return f; @@ -2726,8 +2728,8 @@ svm_fifo_test (vlib_main_t * vm, unformat_input_t * input, int res = 0; char *str; - clib_warning ("high mem %lu", HIGH_SEGMENT_BASEVA << 1); - fifo_segment_main_init (&segment_main, HIGH_SEGMENT_BASEVA << 1, 5); + clib_warning ("high mem %lu", HIGH_SEGMENT_BASEVA); + fifo_segment_main_init (&segment_main, HIGH_SEGMENT_BASEVA, 5); while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "fifo1")) From 020f02cf3df0538c4712aa94d68e2b42a0949d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Fri, 6 Nov 2020 10:51:47 +0100 Subject: [PATCH 085/129] ipsec: fix unformat types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ipsec_{crypto,integ}_alg_t are packed and smaller than u32. Callers are using those enums so unformat functions should too instead of u32 to not overflow the stack. Type: fix Change-Id: Ifc86366f1928ca6352f06f390a88ac64668289d5 Signed-off-by: Benoît Ganne (cherry picked from commit f6422ffbc82c55f50d06c8c7a2e230db7001ee35) --- src/vnet/ipsec/ipsec_format.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vnet/ipsec/ipsec_format.c b/src/vnet/ipsec/ipsec_format.c index e3c6f22bf00b..f365d0cd6204 100644 --- a/src/vnet/ipsec/ipsec_format.c +++ b/src/vnet/ipsec/ipsec_format.c @@ -95,7 +95,7 @@ format_ipsec_crypto_alg (u8 * s, va_list * args) uword unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args) { - u32 *r = va_arg (*args, u32 *); + ipsec_crypto_alg_t *r = va_arg (*args, ipsec_crypto_alg_t *); if (0); #define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_CRYPTO_ALG_##f; @@ -127,7 +127,7 @@ format_ipsec_integ_alg (u8 * s, va_list * args) uword unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args) { - u32 *r = va_arg (*args, u32 *); + ipsec_integ_alg_t *r = va_arg (*args, ipsec_integ_alg_t *); if (0); #define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_INTEG_ALG_##f; From 07aeedd242da8d46ca74c1ad47d4876daa150c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 15 Sep 2020 10:45:55 +0200 Subject: [PATCH 086/129] vpp: fix main heap init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NUMA node parsing with vlib_get_thread_core_numa() can failed on single socket systems. Use clib_get_current_numa_node() instead as we already pinned the main thread to the requested core. Type: fix Change-Id: I22339516d0305689a58584c92ded7c96eb53be39 Signed-off-by: Benoît Ganne (cherry picked from commit 33ce5e568f8b4fb1254bf5ee32865e9443c0185a) --- src/vpp/vnet/main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vpp/vnet/main.c b/src/vpp/vnet/main.c index 00cb4ad385ab..7d87d0cd3b10 100644 --- a/src/vpp/vnet/main.c +++ b/src/vpp/vnet/main.c @@ -282,11 +282,8 @@ main (int argc, char *argv[]) /* Allocate main heap */ if ((main_heap = clib_mem_init_thread_safe (0, main_heap_size))) { - vlib_worker_thread_t tmp; - /* Figure out which numa runs the main thread */ - vlib_get_thread_core_numa (&tmp, main_core); - __os_numa_index = tmp.numa_id; + __os_numa_index = clib_get_current_numa_node (); /* and use the main heap as that numa's numa heap */ clib_mem_set_per_numa_heap (main_heap); From 73a347660205b96693d50cbd754be8d838dd5ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 20 Oct 2020 14:12:20 +0200 Subject: [PATCH 087/129] wireguard: reset secret data before freeing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: I880bdd55ae5da0b9775a3fb548d44512348a7bc6 Signed-off-by: Benoît Ganne (cherry picked from commit 2531d50101991011fb1c7755d48f11b41f092628) --- src/plugins/wireguard/wireguard_noise.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/wireguard/wireguard_noise.c b/src/plugins/wireguard/wireguard_noise.c index 00b67109de48..850be2c86c8b 100755 --- a/src/plugins/wireguard/wireguard_noise.c +++ b/src/plugins/wireguard/wireguard_noise.c @@ -161,8 +161,8 @@ noise_create_initiation (vlib_main_t * vm, noise_remote_t * r, *s_idx = hs->hs_local_index; ret = true; error: - vnet_crypto_key_del (vm, key_idx); secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); + vnet_crypto_key_del (vm, key_idx); return ret; } @@ -244,8 +244,8 @@ noise_consume_initiation (vlib_main_t * vm, noise_local_t * l, ret = true; error: - vnet_crypto_key_del (vm, key_idx); secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); + vnet_crypto_key_del (vm, key_idx); secure_zero_memory (&hs, sizeof (hs)); return ret; } @@ -297,8 +297,8 @@ noise_create_response (vlib_main_t * vm, noise_remote_t * r, uint32_t * s_idx, *s_idx = hs->hs_local_index; ret = true; error: - vnet_crypto_key_del (vm, key_idx); secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); + vnet_crypto_key_del (vm, key_idx); secure_zero_memory (e, NOISE_PUBLIC_KEY_LEN); return ret; } @@ -358,9 +358,9 @@ noise_consume_response (vlib_main_t * vm, noise_remote_t * r, uint32_t s_idx, ret = true; } error: - vnet_crypto_key_del (vm, key_idx); secure_zero_memory (&hs, sizeof (hs)); secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); + vnet_crypto_key_del (vm, key_idx); return ret; } From 087d81dafad8ff52e3704357e1ee2d87b0aed694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Mon, 19 Oct 2020 09:49:09 +0200 Subject: [PATCH 088/129] af_xdp: fix NUMA node parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Non-NUMA systems might report -1 as NUMA node. Type: fix Change-Id: I092c817ea670009d6f530cc70ad13d45e15fd363 Signed-off-by: Benoît Ganne (cherry picked from commit 4317b8efb1c4a4163b2585b9abd71ec38cd0862c) --- src/plugins/af_xdp/device.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/plugins/af_xdp/device.c b/src/plugins/af_xdp/device.c index 35e39b79fbd7..5090d3a649a1 100644 --- a/src/plugins/af_xdp/device.c +++ b/src/plugins/af_xdp/device.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include "af_xdp.h" @@ -273,21 +274,18 @@ af_xdp_create_queue (vlib_main_t * vm, af_xdp_create_if_args_t * args, static int af_xdp_get_numa (const char *ifname) { - FILE *fptr; + char *path; + clib_error_t *err; int numa; - char *s; - s = (char *) format (0, "/sys/class/net/%s/device/numa_node%c", ifname, 0); - fptr = fopen (s, "rb"); - vec_free (s); - - if (!fptr) - return 0; - - if (fscanf (fptr, "%d\n", &numa) != 1) + path = + (char *) format (0, "/sys/class/net/%s/device/numa_node%c", ifname, 0); + err = clib_sysfs_read (path, "%d", &numa); + if (err || numa < 0) numa = 0; - fclose (fptr); + clib_error_free (err); + vec_free (path); return numa; } From e36b854a72e1740c2c267b3ca80bde28d26f876e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 4 Nov 2020 10:02:03 +0100 Subject: [PATCH 089/129] feature: reset interface feature arc on interface deletion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When removing an interface we must reset all per-interface per-feature arc data to ensure we do not get wrong feature arc config data when the sw_if_index is recycled. Type: fix Change-Id: I8c9d850d7c62b7b77193da4258ab5fb9bdda85a6 Signed-off-by: Benoît Ganne (cherry picked from commit 6178bdafa6a318d50cc8ad82f07c6c798c7024ef) --- src/vnet/arp/arp.c | 13 ++------ src/vnet/config.c | 8 +++++ src/vnet/config.h | 2 ++ src/vnet/feature/feature.c | 67 +++++++++++++++++++++++++++++--------- src/vnet/interface.h | 2 ++ 5 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/vnet/arp/arp.c b/src/vnet/arp/arp.c index 14a1ae97d1ee..b8104bdfbaef 100644 --- a/src/vnet/arp/arp.c +++ b/src/vnet/arp/arp.c @@ -852,17 +852,8 @@ static clib_error_t * vnet_arp_add_del_sw_interface (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) { ethernet_arp_main_t *am = ðernet_arp_main; - - if (!is_add && sw_if_index != ~0) - { - arp_disable (am, sw_if_index); - } - else if (is_add) - { - vnet_feature_enable_disable ("arp", "arp-disabled", - sw_if_index, 1, NULL, 0); - } - + if (is_add) + arp_disable (am, sw_if_index); return (NULL); } diff --git a/src/vnet/config.c b/src/vnet/config.c index 4e9fa36dfc30..c9d4909cdebe 100644 --- a/src/vnet/config.c +++ b/src/vnet/config.c @@ -241,6 +241,14 @@ vnet_get_config_heap (vnet_config_main_t * cm, u32 ci) return heap_elt_at_index (cm->config_string_heap, ci); } +void +vnet_config_del (vnet_config_main_t * cm, u32 config_id) +{ + u32 *p = vnet_get_config_heap (cm, config_id); + vnet_config_t *old = pool_elt_at_index (cm->config_pool, p[-1]); + remove_reference (cm, old); +} + u32 vnet_config_modify_end_node (vlib_main_t * vm, vnet_config_main_t * cm, diff --git a/src/vnet/config.h b/src/vnet/config.h index 7eb3cf0ae1f8..ccbbbf433e2a 100644 --- a/src/vnet/config.h +++ b/src/vnet/config.h @@ -147,6 +147,8 @@ void vnet_config_init (vlib_main_t * vm, int n_start_node_names, char *feature_node_names[], int n_feature_node_names); +void vnet_config_del (vnet_config_main_t * cm, u32 config_id); + /* Calls to add/delete features from configurations. */ u32 vnet_config_add_feature (vlib_main_t * vm, vnet_config_main_t * cm, diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c index 1bdd695e1de9..c93f586c349a 100644 --- a/src/vnet/feature/feature.c +++ b/src/vnet/feature/feature.c @@ -37,7 +37,7 @@ vnet_feature_register (vnet_feature_update_cb_t cb, void *data) } static void -vent_feature_reg_invoke (u32 sw_if_index, u8 arc_index, u8 is_enable) +vnet_feature_reg_invoke (u32 sw_if_index, u8 arc_index, u8 is_enable) { vnet_feature_upd_registration_t *reg; @@ -293,7 +293,7 @@ vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index, fm->sw_if_index_has_features[arc_index] = clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index, (feature_count > 0)); - vent_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0)); + vnet_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0)); fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count; return 0; @@ -515,9 +515,7 @@ vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index, int verbose) vlib_cli_output (vm, "\n%s:", areg->arc_name); areg = areg->next; - if (NULL == cm[feature_arc].config_index_by_sw_if_index || - vec_len (cm[feature_arc].config_index_by_sw_if_index) <= - sw_if_index) + if (!vnet_have_features (feature_arc, sw_if_index)) { vlib_cli_output (vm, " none configured"); continue; @@ -525,17 +523,8 @@ vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index, int verbose) current_config_index = vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index); - - if (current_config_index == ~0) - { - vlib_cli_output (vm, " none configured"); - continue; - } - - ASSERT (current_config_index - < vec_len (vcm->config_pool_index_by_user_index)); - - cfg_index = vcm->config_pool_index_by_user_index[current_config_index]; + cfg_index = + vec_elt (vcm->config_pool_index_by_user_index, current_config_index); cfg = pool_elt_at_index (vcm->config_pool, cfg_index); for (i = 0; i < vec_len (cfg->features); i++) @@ -662,6 +651,52 @@ VLIB_CLI_COMMAND (set_interface_feature_command, static) = { }; /* *INDENT-ON* */ +static clib_error_t * +vnet_feature_add_del_sw_interface (vnet_main_t * vnm, u32 sw_if_index, + u32 is_add) +{ + vnet_feature_main_t *fm = &feature_main; + const vnet_feature_arc_registration_t *far; + + if (is_add) + return 0; + + /* + * remove all enabled features from an interface on deletion + */ + for (far = fm->next_arc; far != 0; far = far->next) + { + const u8 arc_index = far->feature_arc_index; + vnet_feature_config_main_t *cm = + vec_elt_at_index (fm->feature_config_mains, arc_index); + const u32 ci = + vec_len (cm->config_index_by_sw_if_index) <= + sw_if_index ? ~0 : vec_elt (cm->config_index_by_sw_if_index, + sw_if_index); + + if (~0 == ci) + continue; + + fm->sw_if_index_has_features[arc_index] = + clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index, + 0); + + vnet_feature_reg_invoke (sw_if_index, arc_index, 0); + + if (vec_len (fm->feature_count_by_sw_if_index[arc_index]) > sw_if_index) + vec_elt (fm->feature_count_by_sw_if_index[arc_index], sw_if_index) = + 0; + + vec_elt (cm->config_index_by_sw_if_index, sw_if_index) = ~0; + vnet_config_del (&cm->config_main, ci); + } + + return 0; +} + +VNET_SW_INTERFACE_ADD_DEL_FUNCTION_PRIO (vnet_feature_add_del_sw_interface, + VNET_ITF_FUNC_PRIORITY_HIGH); + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/interface.h b/src/vnet/interface.h index 895ce2e92798..501ea7a6eb6e 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -179,6 +179,8 @@ static __clib_unused void * __clib_unused_##f = f; _VNET_INTERFACE_FUNCTION_DECL(f,sw_interface_mtu_change) #define VNET_SW_INTERFACE_ADD_DEL_FUNCTION(f) \ _VNET_INTERFACE_FUNCTION_DECL(f,sw_interface_add_del) +#define VNET_SW_INTERFACE_ADD_DEL_FUNCTION_PRIO(f,p) \ + _VNET_INTERFACE_FUNCTION_DECL_PRIO(f,sw_interface_add_del,p) #define VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(f) \ _VNET_INTERFACE_FUNCTION_DECL(f,sw_interface_admin_up_down) #define VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION_PRIO(f,p) \ From 1e0e3d55a85f5cec9ce00da267924c153d694600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Fri, 6 Nov 2020 14:14:23 +0100 Subject: [PATCH 090/129] ipsec: add support for tx-table-id in cli + example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: improvement Change-Id: I840741dfe040718b682935cdbcb0ba958d45a591 Signed-off-by: Benoît Ganne (cherry picked from commit 40aa27ef7cf63daa11974d0b06ea9ee1a102cb32) --- src/scripts/vnet/ipsec_spd_vrf | 72 ++++++++++++++++++++++++++++++++++ src/vnet/ipsec/ipsec_cli.c | 18 ++++++++- src/vnet/ipsec/ipsec_spd.c | 2 +- 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 src/scripts/vnet/ipsec_spd_vrf diff --git a/src/scripts/vnet/ipsec_spd_vrf b/src/scripts/vnet/ipsec_spd_vrf new file mode 100644 index 000000000000..faa891dc2c45 --- /dev/null +++ b/src/scripts/vnet/ipsec_spd_vrf @@ -0,0 +1,72 @@ + +create packet-generator interface pg0 +set int mac addr pg0 4.5.6 + +create sub-interfaces pg0 1 +create sub-interfaces pg0 2 +create sub-interfaces pg0 3 + +ip table add 1 +ip table add 2 +ip table add 3 + +set int ip table pg0.1 1 +set int ip table pg0.2 2 +set int ip table pg0.3 3 + +set int ip address pg0.1 192.168.0.1/24 +set int ip address pg0.2 192.168.0.1/24 +set int ip address pg0.3 192.168.0.1/24 + +set int state pg0 up +set int state pg0.1 up +set int state pg0.2 up +set int state pg0.3 up + +ipsec sa add 2 spi 2 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128 tunnel-src 192.168.0.1 tunnel-dst 192.168.0.2 tx-table-id 2 +ipsec sa add 3 spi 3 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128 tunnel-src 192.168.0.1 tunnel-dst 192.168.0.2 tx-table-id 3 + +ipsec spd add 1 +set interface ipsec spd pg0.1 1 +ipsec policy add spd 1 priority 100 outbound action bypass protocol 50 +ipsec policy add spd 1 priority 10 outbound action protect sa 2 local-ip-range 10.5.0.0 - 10.5.0.255 remote-ip-range 10.6.0.0 - 10.6.0.16 +ipsec policy add spd 1 priority 10 outbound action protect sa 3 local-ip-range 10.5.0.0 - 10.5.0.255 remote-ip-range 10.6.0.17 - 10.6.0.32 + +ip route table 1 add 10.6.0.0/16 via 192.168.0.2 pg0.1 +set ip neighbor pg0.1 192.168.0.2 00:11:22:33:44:55 +set ip neighbor pg0.2 192.168.0.2 00:11:22:33:44:55 +set ip neighbor pg0.3 192.168.0.2 00:11:22:33:44:55 + +trace add pg-input 100 + +packet-generator new { + name ipsec2 + limit 1 + rate 1e4 + node ethernet-input + interface pg0 + size 100-100 + data { + IP4: 1.2.3 -> 4.5.6 vlan 1 + UDP: 10.5.0.1 -> 10.6.0.1 + UDP: 4321 -> 1234 + length 72 + incrementing 100 + } +} + +packet-generator new { + name ipsec3 + limit 1 + rate 1e4 + node ethernet-input + interface pg0 + size 100-100 + data { + IP4: 1.2.3 -> 4.5.6 vlan 1 + UDP: 10.5.0.1 -> 10.6.0.22 + UDP: 4321 -> 1234 + length 72 + incrementing 100 + } +} diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c index 0d1ab033aec7..03727855b4f4 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -36,6 +36,7 @@ set_interface_spd_command_fn (vlib_main_t * vm, u32 spd_id; int is_add = 1; clib_error_t *error = NULL; + int err; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -53,7 +54,16 @@ set_interface_spd_command_fn (vlib_main_t * vm, goto done; } - ipsec_set_interface_spd (vm, sw_if_index, spd_id, is_add); + err = ipsec_set_interface_spd (vm, sw_if_index, spd_id, is_add); + switch (err) + { + case VNET_API_ERROR_SYSCALL_ERROR_1: + error = clib_error_return (0, "no such spd-id"); + break; + case VNET_API_ERROR_SYSCALL_ERROR_2: + error = clib_error_return (0, "spd already assigned"); + break; + } done: unformat_free (line_input); @@ -90,6 +100,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, u16 udp_src, udp_dst; int is_add, rv; u32 m_args = 0; + u32 tx_table_id; salt = 0; error = NULL; @@ -99,6 +110,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, integ_alg = IPSEC_INTEG_ALG_NONE; crypto_alg = IPSEC_CRYPTO_ALG_NONE; udp_src = udp_dst = IPSEC_UDP_PORT_NONE; + tx_table_id = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -144,6 +156,8 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "tunnel-dst %U", unformat_ip46_address, &tun_dst, IP46_TYPE_ANY)) ; + else if (unformat (line_input, "tx-table-id %d", &tx_table_id)) + ; else if (unformat (line_input, "inbound")) flags |= IPSEC_SA_FLAG_IS_INBOUND; else if (unformat (line_input, "use-anti-replay")) @@ -181,7 +195,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, } rv = ipsec_sa_add_and_lock (id, spi, proto, crypto_alg, &ck, integ_alg, &ik, flags, - 0, clib_host_to_net_u32 (salt), + tx_table_id, clib_host_to_net_u32 (salt), &tun_src, &tun_dst, &sai, udp_src, udp_dst); } else diff --git a/src/vnet/ipsec/ipsec_spd.c b/src/vnet/ipsec/ipsec_spd.c index ef41c2286c14..4e8017c35ff6 100644 --- a/src/vnet/ipsec/ipsec_spd.c +++ b/src/vnet/ipsec/ipsec_spd.c @@ -77,7 +77,7 @@ ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id, p = hash_get (im->spd_index_by_sw_if_index, sw_if_index); if (p && is_add) - return VNET_API_ERROR_SYSCALL_ERROR_1; /* spd already assigned */ + return VNET_API_ERROR_SYSCALL_ERROR_2; /* spd already assigned */ if (is_add) { From a6a5031e78f58684ad6d210a6acb9d46b990402b Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Fri, 13 Nov 2020 09:29:44 +0000 Subject: [PATCH 091/129] crypto-native: fix multi-arch variant initialization crypto_native/main.h is being built as default, and crypto_native_main is initialized with a size of 64 bytes. crypto_native/aes_gcm.c and crypto_native/aes_cbc.c are march variants, their ICL variants are expecting crypto_native_main to be 256 bytes. Type: fix Signed-off-by: Georgii Tkachuk Signed-off-by: Fan Zhang Signed-off-by: Ray Kinsella Change-Id: I4cddb75b712ea83c9cfca621887605d7bae104ec --- src/plugins/crypto_native/crypto_native.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/crypto_native/crypto_native.h b/src/plugins/crypto_native/crypto_native.h index 5b774b302dea..d5c33daa1a63 100644 --- a/src/plugins/crypto_native/crypto_native.h +++ b/src/plugins/crypto_native/crypto_native.h @@ -23,11 +23,7 @@ typedef void *(crypto_native_key_fn_t) (vnet_crypto_key_t * key); typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); -#if __VAES__ u8x16 cbc_iv[16]; -#else - u8x16 cbc_iv[4]; -#endif } crypto_native_per_thread_data_t; typedef struct From c646d54b46efbe1277adb440bba2b61c9d1c8c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 25 Nov 2020 13:53:21 +0100 Subject: [PATCH 092/129] dns: fix double-unlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dns cache should no longer be unlocked by caller. Type: fix Fixes: 84a563ae4050cc0389dcd438fbe9ea882f2b8404 Change-Id: I3708718ae8f00e4e4f4e04381caa0095c8494b82 Signed-off-by: Benoît Ganne (cherry picked from commit 2113c7f28b154df16af3637f67484971759a00a7) --- src/plugins/dns/dns.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/plugins/dns/dns.c b/src/plugins/dns/dns.c index bdf14961a783..66cc4f64f489 100644 --- a/src/plugins/dns/dns.c +++ b/src/plugins/dns/dns.c @@ -1471,12 +1471,6 @@ vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp) rmp->retval = clib_host_to_net_u32 (rv); })); /* *INDENT-ON* */ - - /* - * dns_resolve_name leaves the cache locked when it returns - * a cached result, so unlock it here. - */ - dns_cache_unlock (dm); } static void @@ -1551,12 +1545,6 @@ vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp) rmp->retval = clib_host_to_net_u32 (rv); })); /* *INDENT-ON* */ - - /* - * vnet_dns_resolve_name leaves the cache locked when it returns - * a cached result, so unlock it here. - */ - dns_cache_unlock (dm); } static clib_error_t * From 7946c61c55e461e1b4b5e77c8e62b06512c12e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 25 Nov 2020 13:51:33 +0100 Subject: [PATCH 093/129] syslog: use per-thread vlib_main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should not use main thread vlib_main in workers. Type: fix Change-Id: I58c0a8cadf2dc7f768b20ac90e7ec7921e2e8ca4 Signed-off-by: Benoît Ganne (cherry picked from commit 0a2fde105a5a0c996333d67d2901b4eaedf7cbe1) --- src/vnet/syslog/syslog.c | 6 ++---- src/vnet/syslog/syslog.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vnet/syslog/syslog.c b/src/vnet/syslog/syslog.c index f05ce8dc5ff2..20728b8a17a2 100644 --- a/src/vnet/syslog/syslog.c +++ b/src/vnet/syslog/syslog.c @@ -143,8 +143,7 @@ void syslog_msg_init (syslog_msg_t * syslog_msg, syslog_facility_t facility, syslog_severity_t severity, char *app_name, char *msgid) { - syslog_main_t *sm = &syslog_main; - vlib_main_t *vm = sm->vlib_main; + vlib_main_t *vm = vlib_get_main (); syslog_msg->header.facility = facility; syslog_msg->header.severity = severity; @@ -160,7 +159,7 @@ int syslog_msg_send (syslog_msg_t * syslog_msg) { syslog_main_t *sm = &syslog_main; - vlib_main_t *vm = sm->vlib_main; + vlib_main_t *vm = vlib_get_main (); u32 bi, msg_len, *to_next; u8 *tmp; vlib_buffer_t *b; @@ -611,7 +610,6 @@ syslog_init (vlib_main_t * vm) struct timeval timeval_0; vlib_node_t *ip4_lookup_node; - sm->vlib_main = vm; sm->vnet_main = vnet_get_main (); sm->procid = getpid (); diff --git a/src/vnet/syslog/syslog.h b/src/vnet/syslog/syslog.h index 4809af48e972..3ec1cb35f355 100644 --- a/src/vnet/syslog/syslog.h +++ b/src/vnet/syslog/syslog.h @@ -136,7 +136,6 @@ typedef struct u32 ip4_lookup_node_index; /** convenience variables */ - vlib_main_t *vlib_main; vnet_main_t *vnet_main; } syslog_main_t; From 7d304405ed3f19a8a3a4a25c3edf29248377cf21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 25 Nov 2020 16:43:13 +0100 Subject: [PATCH 094/129] dns: use correct per-thread vlib_main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using vlib_main of another thread is prohibited. Type: fix Change-Id: I7ae294dfaf2526738e91408c9b4865ef9f801b8a Signed-off-by: Benoît Ganne (cherry picked from commit 7483a7272d15354486371be7a20c4bf35ab2eb38) --- src/plugins/dns/dns.c | 64 +++++++++++++++--------------- src/plugins/dns/dns.h | 28 +++++++------ src/plugins/dns/request_node.c | 6 +-- src/plugins/dns/resolver_process.c | 25 ++++++------ 4 files changed, 63 insertions(+), 60 deletions(-) diff --git a/src/plugins/dns/dns.c b/src/plugins/dns/dns.c index 66cc4f64f489..bb60f748a41f 100644 --- a/src/plugins/dns/dns.c +++ b/src/plugins/dns/dns.c @@ -68,14 +68,13 @@ dns_cache_clear (dns_main_t * dm) } static int -dns_enable_disable (dns_main_t * dm, int is_enable) +dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable) { vlib_thread_main_t *tm = &vlib_thread_main; u32 n_vlib_mains = tm->n_vlib_mains; - vlib_main_t *vm = dm->vlib_main; /* Create the resolver process if not done already */ - vnet_dns_create_resolver_process (dm); + vnet_dns_create_resolver_process (vm, dm); if (is_enable) { @@ -122,10 +121,11 @@ static void vl_api_dns_enable_disable_t_handler (vl_api_dns_enable_disable_t * mp) { vl_api_dns_enable_disable_reply_t *rmp; + vlib_main_t *vm = vlib_get_main (); dns_main_t *dm = &dns_main; int rv; - rv = dns_enable_disable (dm, mp->enable); + rv = dns_enable_disable (vm, dm, mp->enable); REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY); } @@ -218,10 +218,9 @@ static void vl_api_dns_name_server_add_del_t_handler } void -vnet_dns_send_dns4_request (dns_main_t * dm, +vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm, dns_cache_entry_t * ep, ip4_address_t * server) { - vlib_main_t *vm = dm->vlib_main; f64 now = vlib_time_now (vm); u32 bi; vlib_buffer_t *b; @@ -288,7 +287,7 @@ vnet_dns_send_dns4_request (dns_main_t * dm, found_src_address: /* Go get a buffer */ - if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1) + if (vlib_buffer_alloc (vm, &bi, 1) != 1) return; b = vlib_get_buffer (vm, bi); @@ -337,10 +336,9 @@ vnet_dns_send_dns4_request (dns_main_t * dm, } void -vnet_dns_send_dns6_request (dns_main_t * dm, +vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm, dns_cache_entry_t * ep, ip6_address_t * server) { - vlib_main_t *vm = dm->vlib_main; f64 now = vlib_time_now (vm); u32 bi; vlib_buffer_t *b; @@ -397,7 +395,7 @@ vnet_dns_send_dns6_request (dns_main_t * dm, found_src_address: /* Go get a buffer */ - if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1) + if (vlib_buffer_alloc (vm, &bi, 1) != 1) return; b = vlib_get_buffer (vm, bi); @@ -536,7 +534,8 @@ vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here) } void -vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep) +vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm, + dns_cache_entry_t * ep) { dns_header_t *h; dns_query_t *qp; @@ -610,7 +609,7 @@ vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep) if (vec_len (dm->ip6_name_servers)) { vnet_dns_send_dns6_request - (dm, ep, dm->ip6_name_servers + ep->server_rotor); + (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor); goto out; } else @@ -619,7 +618,7 @@ vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep) if (vec_len (dm->ip4_name_servers)) { vnet_dns_send_dns4_request - (dm, ep, dm->ip4_name_servers + ep->server_rotor); + (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor); goto out; } } @@ -647,14 +646,14 @@ vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep) if (ep->server_af == 1 /* ip6 */ ) vnet_dns_send_dns6_request - (dm, ep, dm->ip6_name_servers + ep->server_rotor); + (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor); else vnet_dns_send_dns4_request - (dm, ep, dm->ip4_name_servers + ep->server_rotor); + (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor); out: - vlib_process_signal_event_mt (dm->vlib_main, + vlib_process_signal_event_mt (vm, dm->resolver_process_node_index, DNS_RESOLVER_EVENT_PENDING, 0); } @@ -808,8 +807,8 @@ dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data) } int -vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t, - dns_cache_entry_t ** retp) +vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name, + dns_pending_request_t * t, dns_cache_entry_t ** retp) { dns_cache_entry_t *ep; int rv; @@ -818,7 +817,7 @@ vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t, dns_pending_request_t *pr; int count; - now = vlib_time_now (dm->vlib_main); + now = vlib_time_now (vm); /* In case we can't actually answer the question right now... */ *retp = 0; @@ -950,7 +949,7 @@ vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t, clib_memcpy (pr->dst_address, t->dst_address, count); } - vnet_send_dns_request (dm, ep); + vnet_send_dns_request (vm, dm, ep); dns_cache_unlock (dm); return 0; } @@ -964,7 +963,8 @@ _(pending_requests) */ int -vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply) +vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm, + u32 ep_index, u8 * reply) { dns_header_t *h; dns_query_t *qp; @@ -1074,7 +1074,7 @@ vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply) found_last_request: - now = vlib_time_now (dm->vlib_main); + now = vlib_time_now (vm); cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2); /* Save the cname */ vec_add1 (cname, 0); @@ -1154,7 +1154,7 @@ vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply) */ vec_add1 (dm->unresolved_entries, next_ep - dm->entries); - vnet_send_dns_request (dm, next_ep); + vnet_send_dns_request (vm, dm, next_ep); return (1); } @@ -1438,6 +1438,7 @@ vnet_dns_response_to_name (u8 * response, static void vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp) { + vlib_main_t *vm = vlib_get_main (); dns_main_t *dm = &dns_main; vl_api_dns_resolve_name_reply_t *rmp; dns_cache_entry_t *ep; @@ -1451,7 +1452,7 @@ vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp) t0->client_index = mp->client_index; t0->client_context = mp->context; - rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep); + rv = vnet_dns_resolve_name (vm, dm, mp->name, t0, &ep); /* Error, e.g. not enabled? Tell the user */ if (rv < 0) @@ -1476,6 +1477,7 @@ vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp) static void vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp) { + vlib_main_t *vm = vlib_get_main (); dns_main_t *dm = &dns_main; vl_api_dns_resolve_ip_reply_t *rmp; dns_cache_entry_t *ep; @@ -1523,7 +1525,7 @@ vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp) t0->client_index = mp->client_index; t0->client_context = mp->context; - rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep); + rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep); vec_free (lookup_name); @@ -2716,18 +2718,19 @@ VLIB_CLI_COMMAND (test_dns_expire_command) = #endif void -vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr, - dns_cache_entry_t * ep, vlib_buffer_t * b0) +vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm, + dns_pending_request_t * pr, dns_cache_entry_t * ep, + vlib_buffer_t * b0) { clib_warning ("Unimplemented..."); } void -vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr, - dns_cache_entry_t * ep, vlib_buffer_t * b0) +vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm, + dns_pending_request_t * pr, dns_cache_entry_t * ep, + vlib_buffer_t * b0) { - vlib_main_t *vm = dm->vlib_main; u32 bi = 0; fib_prefix_t prefix; fib_node_index_t fei; @@ -3039,7 +3042,6 @@ dns_init (vlib_main_t * vm) { dns_main_t *dm = &dns_main; - dm->vlib_main = vm; dm->vnet_main = vnet_get_main (); dm->name_cache_size = 1000; dm->max_ttl_in_seconds = 86400; diff --git a/src/plugins/dns/dns.h b/src/plugins/dns/dns.h index 2351ab25f97c..e6ca440b48a5 100644 --- a/src/plugins/dns/dns.h +++ b/src/plugins/dns/dns.h @@ -123,7 +123,6 @@ typedef struct u16 msg_id_base; /* convenience */ - vlib_main_t *vlib_main; vnet_main_t *vnet_main; api_main_t *api_main; } dns_main_t; @@ -168,33 +167,36 @@ typedef enum DNS46_REPLY_N_ERROR, } dns46_reply_error_t; -void vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep); -int -vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply); +void vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm, + dns_cache_entry_t * ep); +int vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm, + u32 ep_index, u8 * reply); int vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index); int -vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t, - dns_cache_entry_t ** retp); +vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name, + dns_pending_request_t * t, dns_cache_entry_t ** retp); void -vnet_dns_send_dns6_request (dns_main_t * dm, +vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm, dns_cache_entry_t * ep, ip6_address_t * server); void -vnet_dns_send_dns4_request (dns_main_t * dm, +vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm, dns_cache_entry_t * ep, ip4_address_t * server); -void vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * t, - dns_cache_entry_t * ep, vlib_buffer_t * b0); +void vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm, + dns_pending_request_t * t, dns_cache_entry_t * ep, + vlib_buffer_t * b0); -void vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * t, - dns_cache_entry_t * ep, vlib_buffer_t * b0); +void vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm, + dns_pending_request_t * t, dns_cache_entry_t * ep, + vlib_buffer_t * b0); u8 *vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here); -void vnet_dns_create_resolver_process (dns_main_t * dm); +void vnet_dns_create_resolver_process (vlib_main_t * vm, dns_main_t * dm); format_function_t format_dns_reply; diff --git a/src/plugins/dns/request_node.c b/src/plugins/dns/request_node.c index d26e579cf472..a80876927e92 100644 --- a/src/plugins/dns/request_node.c +++ b/src/plugins/dns/request_node.c @@ -242,14 +242,14 @@ dns46_request_inline (vlib_main_t * vm, clib_memcpy_fast (t0->dst_address, ip40->src_address.as_u8, sizeof (ip4_address_t)); - vnet_dns_resolve_name (dm, name0, t0, &ep0); + vnet_dns_resolve_name (vm, dm, name0, t0, &ep0); if (ep0) { if (is_ip6) - vnet_send_dns6_reply (dm, t0, ep0, b0); + vnet_send_dns6_reply (vm, dm, t0, ep0, b0); else - vnet_send_dns4_reply (dm, t0, ep0, b0); + vnet_send_dns4_reply (vm, dm, t0, ep0, b0); next0 = DNS46_REQUEST_NEXT_IP_LOOKUP; } else diff --git a/src/plugins/dns/resolver_process.c b/src/plugins/dns/resolver_process.c index 71e5ba2ffabf..4aa101709c35 100644 --- a/src/plugins/dns/resolver_process.c +++ b/src/plugins/dns/resolver_process.c @@ -36,9 +36,8 @@ vnet_dns_response_to_name (u8 * response, u32 * min_ttlp); static void -resolve_event (dns_main_t * dm, f64 now, u8 * reply) +resolve_event (vlib_main_t * vm, dns_main_t * dm, f64 now, u8 * reply) { - vlib_main_t *vm = dm->vlib_main; dns_pending_request_t *pr; dns_header_t *d; u32 pool_index; @@ -76,7 +75,7 @@ resolve_event (dns_main_t * dm, f64 now, u8 * reply) vec_free (ep->dns_response); /* Handle [sic] recursion AKA CNAME indirection */ - rv = vnet_dns_cname_indirection_nolock (dm, pool_index, reply); + rv = vnet_dns_cname_indirection_nolock (vm, dm, pool_index, reply); /* CNAME found, further resolution pending, we're done here */ if (rv > 0) @@ -109,7 +108,7 @@ resolve_event (dns_main_t * dm, f64 now, u8 * reply) clib_warning ("Try server %U", format_ip6_address, dm->ip6_name_servers + ep->server_rotor); vnet_dns_send_dns6_request - (dm, ep, dm->ip6_name_servers + ep->server_rotor); + (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor); } else { @@ -132,7 +131,7 @@ resolve_event (dns_main_t * dm, f64 now, u8 * reply) clib_warning ("Try server %U", format_ip4_address, dm->ip4_name_servers + ep->server_rotor); vnet_dns_send_dns4_request - (dm, ep, dm->ip4_name_servers + ep->server_rotor); + (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor); } dns_cache_unlock (dm); return; @@ -222,9 +221,9 @@ resolve_event (dns_main_t * dm, f64 now, u8 * reply) case DNS_PEER_PENDING_IP_TO_NAME: case DNS_PEER_PENDING_NAME_TO_IP: if (pr->is_ip6) - vnet_send_dns6_reply (dm, pr, ep, 0 /* allocate a buffer */ ); + vnet_send_dns6_reply (vm, dm, pr, ep, 0 /* allocate a buffer */ ); else - vnet_send_dns4_reply (dm, pr, ep, 0 /* allocate a buffer */ ); + vnet_send_dns4_reply (vm, dm, pr, ep, 0 /* allocate a buffer */ ); break; default: clib_warning ("request type %d unknown", pr->request_type); @@ -286,7 +285,7 @@ resolve_event (dns_main_t * dm, f64 now, u8 * reply) } static void -retry_scan (dns_main_t * dm, f64 now) +retry_scan (vlib_main_t * vm, dns_main_t * dm, f64 now) { int i; dns_cache_entry_t *ep; @@ -297,7 +296,7 @@ retry_scan (dns_main_t * dm, f64 now) ep = pool_elt_at_index (dm->entries, dm->unresolved_entries[i]); ASSERT ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) == 0); - vnet_send_dns_request (dm, ep); + vnet_send_dns_request (vm, dm, ep); dns_cache_unlock (dm); } } @@ -330,11 +329,11 @@ dns_resolver_process (vlib_main_t * vm, case DNS_RESOLVER_EVENT_RESOLVED: for (i = 0; i < vec_len (event_data); i++) - resolve_event (dm, now, (u8 *) event_data[i]); + resolve_event (vm, dm, now, (u8 *) event_data[i]); break; case ~0: /* timeout */ - retry_scan (dm, now); + retry_scan (vm, dm, now); break; } vec_reset_length (event_data); @@ -347,7 +346,7 @@ dns_resolver_process (vlib_main_t * vm, } void -vnet_dns_create_resolver_process (dns_main_t * dm) +vnet_dns_create_resolver_process (vlib_main_t * vm, dns_main_t * dm) { /* Already created the resolver process? */ if (dm->resolver_process_node_index > 0) @@ -355,7 +354,7 @@ vnet_dns_create_resolver_process (dns_main_t * dm) /* No, create it now and make a note of the node index */ dm->resolver_process_node_index = vlib_process_create - (dm->vlib_main, "dns-resolver-process", + (vm, "dns-resolver-process", dns_resolver_process, 16 /* log2_n_stack_bytes */ ); } From 447f673e75247421c239d88f6ada45b3ff1a47fe Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Mon, 17 Aug 2020 10:59:23 +0000 Subject: [PATCH 095/129] ikev2: show IKE SA command improvements Ticket: VPP-1898 Type: improvement Change-Id: I1c56df331965c733a2d0eae63a12d5a4ee5a2e41 Signed-off-by: Filip Tehlar (cherry picked from commit 90690f1e8f39904990b4eeeb7851b248a9c908f3) --- src/plugins/ikev2/ikev2_cli.c | 264 ++++++++++++++++++++++------------ 1 file changed, 169 insertions(+), 95 deletions(-) diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index 151ee7b31fb4..727e34736277 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -46,131 +46,205 @@ format_ikev2_id_type_and_data (u8 * s, va_list * args) return s; } +static u8 * +format_ikev2_traffic_selector (u8 * s, va_list * va) +{ + ikev2_ts_t *ts = va_arg (*va, ikev2_ts_t *); + u32 index = va_arg (*va, u32); + + s = format (s, "%u type %u protocol_id %u addr " + "%U - %U port %u - %u\n", + index, ts->ts_type, ts->protocol_id, + format_ip4_address, &ts->start_addr, + format_ip4_address, &ts->end_addr, + clib_net_to_host_u16 (ts->start_port), + clib_net_to_host_u16 (ts->end_port)); + return s; +} -static clib_error_t * -show_ikev2_sa_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +static u8 * +format_ikev2_child_sa (u8 * s, va_list * va) { - ikev2_main_t *km = &ikev2_main; - ikev2_main_per_thread_data_t *tkm; - ikev2_sa_t *sa; + ikev2_child_sa_t *child = va_arg (*va, ikev2_child_sa_t *); + u32 index = va_arg (*va, u32); ikev2_ts_t *ts; - ikev2_child_sa_t *child; ikev2_sa_transform_t *tr; + u8 *c = 0; - vec_foreach (tkm, km->per_thread_data) - { - /* *INDENT-OFF* */ - pool_foreach (sa, tkm->sas, ({ - u8 * s = 0; - vlib_cli_output(vm, " iip %U ispi %lx rip %U rspi %lx", - format_ip4_address, &sa->iaddr, sa->ispi, - format_ip4_address, &sa->raddr, sa->rspi); + u32 indent = format_get_indent (s); + indent += 1; - tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); - s = format(s, "%U ", format_ikev2_sa_transform, tr); + s = format (s, "child sa %u:", index); - tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); - s = format(s, "%U ", format_ikev2_sa_transform, tr); + tr = ikev2_sa_get_td_for_type (child->r_proposals, + IKEV2_TRANSFORM_TYPE_ENCR); + c = format (c, "%U ", format_ikev2_sa_transform, tr); - tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); - s = format(s, "%U ", format_ikev2_sa_transform, tr); + tr = ikev2_sa_get_td_for_type (child->r_proposals, + IKEV2_TRANSFORM_TYPE_INTEG); + c = format (c, "%U ", format_ikev2_sa_transform, tr); - tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); - s = format(s, "%U ", format_ikev2_sa_transform, tr); + tr = ikev2_sa_get_td_for_type (child->r_proposals, + IKEV2_TRANSFORM_TYPE_ESN); + c = format (c, "%U ", format_ikev2_sa_transform, tr); - vlib_cli_output(vm, " %v", s); - vec_free(s); + s = format (s, "%v\n", c); + vec_free (c); - vlib_cli_output(vm, " nonce i:%U\n r:%U", - format_hex_bytes, sa->i_nonce, vec_len(sa->i_nonce), - format_hex_bytes, sa->r_nonce, vec_len(sa->r_nonce)); + s = format (s, "%Uspi(i) %lx spi(r) %lx\n", format_white_space, indent, + child->i_proposals ? child->i_proposals[0].spi : 0, + child->r_proposals ? child->r_proposals[0].spi : 0); - vlib_cli_output(vm, " SK_d %U", - format_hex_bytes, sa->sk_d, vec_len(sa->sk_d)); - if (sa->sk_ai) - { - vlib_cli_output(vm, " SK_a i:%U\n r:%U", - format_hex_bytes, sa->sk_ai, vec_len(sa->sk_ai), - format_hex_bytes, sa->sk_ar, vec_len(sa->sk_ar)); - } - vlib_cli_output(vm, " SK_e i:%U\n r:%U", - format_hex_bytes, sa->sk_ei, vec_len(sa->sk_ei), - format_hex_bytes, sa->sk_er, vec_len(sa->sk_er)); - vlib_cli_output(vm, " SK_p i:%U\n r:%U", - format_hex_bytes, sa->sk_pi, vec_len(sa->sk_pi), - format_hex_bytes, sa->sk_pr, vec_len(sa->sk_pr)); - - vlib_cli_output(vm, " identifier (i) %U", - format_ikev2_id_type_and_data, &sa->i_id); - vlib_cli_output(vm, " identifier (r) %U", - format_ikev2_id_type_and_data, &sa->r_id); - - vec_foreach(child, sa->childs) - { - vlib_cli_output(vm, " child sa %u:", child - sa->childs); + s = format (s, "%USK_e i:%U\n%Ur:%U\n", + format_white_space, indent, + format_hex_bytes, child->sk_ei, vec_len (child->sk_ei), + format_white_space, indent + 6, + format_hex_bytes, child->sk_er, vec_len (child->sk_er)); + if (child->sk_ai) + { + s = format (s, "%USK_a i:%U\n%Ur:%U\n", + format_white_space, indent, + format_hex_bytes, child->sk_ai, vec_len (child->sk_ai), + format_white_space, indent + 6, + format_hex_bytes, child->sk_ar, vec_len (child->sk_ar)); + } + s = format (s, "%Utraffic selectors (i):", format_white_space, indent); + vec_foreach (ts, child->tsi) + s = format (s, "%U", format_ikev2_traffic_selector, ts, ts - child->tsi); + s = format (s, "%Utraffic selectors (r):", format_white_space, indent); + vec_foreach (ts, child->tsr) + s = format (s, "%U", format_ikev2_traffic_selector, ts, ts - child->tsr); + return s; +} - tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); - s = format(s, "%U ", format_ikev2_sa_transform, tr); +static u8 * +format_ikev2_sa (u8 * s, va_list * va) +{ + ikev2_sa_t *sa = va_arg (*va, ikev2_sa_t *); + int details = va_arg (*va, int); + ikev2_sa_transform_t *tr; + ikev2_child_sa_t *child; + u32 indent = 1; - tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); - s = format(s, "%U ", format_ikev2_sa_transform, tr); + s = format (s, "iip %U ispi %lx rip %U rspi %lx", + format_ip4_address, &sa->iaddr, sa->ispi, + format_ip4_address, &sa->raddr, sa->rspi); + if (!details) + return s; - tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_ESN); - s = format(s, "%U ", format_ikev2_sa_transform, tr); + s = format (s, "\n%U", format_white_space, indent); - vlib_cli_output(vm, " %v", s); - vec_free(s); + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); + s = format (s, "%U ", format_ikev2_sa_transform, tr); - vlib_cli_output(vm, " spi(i) %lx spi(r) %lx", - child->i_proposals ? child->i_proposals[0].spi : 0, - child->r_proposals ? child->r_proposals[0].spi : 0); + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + s = format (s, "%U ", format_ikev2_sa_transform, tr); - vlib_cli_output(vm, " SK_e i:%U\n r:%U", - format_hex_bytes, child->sk_ei, vec_len(child->sk_ei), - format_hex_bytes, child->sk_er, vec_len(child->sk_er)); - if (child->sk_ai) - { - vlib_cli_output(vm, " SK_a i:%U\n r:%U", - format_hex_bytes, child->sk_ai, vec_len(child->sk_ai), - format_hex_bytes, child->sk_ar, vec_len(child->sk_ar)); - vlib_cli_output(vm, " traffic selectors (i):"); - } - vec_foreach(ts, child->tsi) - { - vlib_cli_output(vm, " %u type %u protocol_id %u addr " - "%U - %U port %u - %u", - ts - child->tsi, - ts->ts_type, ts->protocol_id, - format_ip4_address, &ts->start_addr, - format_ip4_address, &ts->end_addr, - clib_net_to_host_u16( ts->start_port), - clib_net_to_host_u16( ts->end_port)); - } - vlib_cli_output(vm, " traffic selectors (r):"); - vec_foreach(ts, child->tsr) + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); + s = format (s, "%U ", format_ikev2_sa_transform, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + s = format (s, "%U", format_ikev2_sa_transform, tr); + + s = format (s, "\n%U", format_white_space, indent); + + s = format (s, "nonce i:%U\n%Ur:%U\n", + format_hex_bytes, sa->i_nonce, vec_len (sa->i_nonce), + format_white_space, indent + 6, + format_hex_bytes, sa->r_nonce, vec_len (sa->r_nonce)); + + s = format (s, "%USK_d %U\n", format_white_space, indent, + format_hex_bytes, sa->sk_d, vec_len (sa->sk_d)); + if (sa->sk_ai) + { + s = format (s, "%USK_a i:%U\n%Ur:%U\n", + format_white_space, indent, + format_hex_bytes, sa->sk_ai, vec_len (sa->sk_ai), + format_white_space, indent + 6, + format_hex_bytes, sa->sk_ar, vec_len (sa->sk_ar)); + } + s = format (s, "%USK_e i:%U\n%Ur:%U\n", + format_white_space, indent, + format_hex_bytes, sa->sk_ei, vec_len (sa->sk_ei), + format_white_space, indent + 6, + format_hex_bytes, sa->sk_er, vec_len (sa->sk_er)); + s = format (s, "%USK_p i:%U\n%Ur:%U\n", + format_white_space, indent, + format_hex_bytes, sa->sk_pi, vec_len (sa->sk_pi), + format_white_space, indent + 6, + format_hex_bytes, sa->sk_pr, vec_len (sa->sk_pr)); + + s = format (s, "%Uidentifier (i) %U\n", + format_white_space, indent, + format_ikev2_id_type_and_data, &sa->i_id); + s = format (s, "%Uidentifier (r) %U\n", + format_white_space, indent, + format_ikev2_id_type_and_data, &sa->r_id); + + vec_foreach (child, sa->childs) + { + s = format (s, "%U%U", format_white_space, indent + 2, + format_ikev2_child_sa, child, child - sa->childs); + } + + return s; +} + +static clib_error_t * +show_ikev2_sa_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ikev2_main_t *km = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + ikev2_sa_t *sa; + u64 rspi; + u8 *s = 0; + int details = 0, show_one = 0; + + if (unformat_user (input, unformat_line_input, line_input)) + { + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "rspi %lx", &rspi)) + { + show_one = 1; + } + else if (unformat (line_input, "details")) + details = 1; + else + break; + } + unformat_free (line_input); + } + + vec_foreach (tkm, km->per_thread_data) + { + /* *INDENT-OFF* */ + pool_foreach (sa, tkm->sas, ({ + if (show_one) + { + if (sa->rspi == rspi) { - vlib_cli_output(vm, " %u type %u protocol_id %u addr " - "%U - %U port %u - %u", - ts - child->tsr, - ts->ts_type, ts->protocol_id, - format_ip4_address, &ts->start_addr, - format_ip4_address, &ts->end_addr, - clib_net_to_host_u16( ts->start_port), - clib_net_to_host_u16( ts->end_port)); + s = format (s, "%U\n", format_ikev2_sa, sa, 1); + break; } } - vlib_cli_output(vm, ""); + else + s = format (s, "%U\n", format_ikev2_sa, sa, details); })); /* *INDENT-ON* */ } + + vlib_cli_output (vm, "%v", s); + vec_free (s); return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_ikev2_sa_command, static) = { .path = "show ikev2 sa", - .short_help = "show ikev2 sa", + .short_help = "show ikev2 sa [rspi ] [details]", .function = show_ikev2_sa_command_fn, }; /* *INDENT-ON* */ From df61e60815b5bf0c2383dafa3c41ed1b60b8a900 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 16 Jul 2020 07:25:56 +0000 Subject: [PATCH 096/129] ikev2: better packet parsing functions Ticket: VPP-1918 Type: improvement Change-Id: I2bc3e30121697404dcd54f1c2127bd85ccc1029e Signed-off-by: Filip Tehlar (cherry picked from commit 558607dc3a96232191f413b9bc894524ff85f2a1) --- src/plugins/ikev2/ikev2.c | 542 ++++++++++++++++++--------- src/plugins/ikev2/ikev2.h | 15 +- src/plugins/ikev2/ikev2_crypto.c | 47 ++- src/plugins/ikev2/ikev2_payload.c | 76 +++- src/plugins/ikev2/ikev2_priv.h | 20 +- src/plugins/ikev2/test/test_ikev2.py | 162 +++++--- src/plugins/ikev2/test/vpp_ikev2.py | 8 +- test/patches/scapy-2.4.3/ikev2.patch | 24 ++ 8 files changed, 620 insertions(+), 274 deletions(-) create mode 100644 test/patches/scapy-2.4.3/ikev2.patch diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 7632a567fd4c..5c48e02685e2 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -71,7 +71,9 @@ _(IKE_SA_INIT_IGNORE, "IKE_SA_INIT ignore (IKE SA already auth)") \ _(IKE_REQ_RETRANSMIT, "IKE request retransmit") \ _(IKE_REQ_IGNORE, "IKE request ignore (old msgid)") \ _(NOT_IKEV2, "Non IKEv2 packets received") \ -_(BAD_LENGTH, "Bad packet length") +_(BAD_LENGTH, "Bad packet length") \ +_(MALFORMED_PACKET, "Malformed packet") \ +_(NO_BUFF_SPACE, "No buffer space") typedef enum { @@ -639,12 +641,54 @@ ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, u32 ip, u16 port) return res; } -static void -ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, - ike_header_t * ike, udp_header_t * udp, u32 len) +static int +ikev2_parse_ke_payload (const void *p, u32 rlen, ikev2_sa_t * sa, + u8 ** ke_data) +{ + const ike_ke_payload_header_t *ke = p; + u16 plen = clib_net_to_host_u16 (ke->length); + ASSERT (plen >= sizeof (*ke) && plen <= rlen); + if (sizeof (*ke) > rlen) + return 0; + + sa->dh_group = clib_net_to_host_u16 (ke->dh_group); + vec_reset_length (ke_data[0]); + vec_add (ke_data[0], ke->payload, plen - sizeof (*ke)); + return 1; +} + +static int +ikev2_parse_nonce_payload (const void *p, u32 rlen, u8 * nonce) +{ + const ike_payload_header_t *ikep = p; + u16 plen = clib_net_to_host_u16 (ikep->length); + ASSERT (plen >= sizeof (*ikep) && plen <= rlen); + clib_memcpy_fast (nonce, ikep->payload, plen - sizeof (*ikep)); + return 1; +} + +static int +ikev2_check_payload_length (const ike_payload_header_t * ikep, int rlen, + u16 * plen) +{ + if (sizeof (*ikep) > rlen) + return 0; + *plen = clib_net_to_host_u16 (ikep->length); + if (*plen < sizeof (*ikep) || *plen > rlen) + return 0; + return 1; +} + +static int +ikev2_process_sa_init_req (vlib_main_t * vm, + ikev2_sa_t * sa, ike_header_t * ike, + udp_header_t * udp, u32 len) { + u8 nonce[IKEV2_NONCE_SIZE]; int p = 0; u8 payload = ike->nextpayload; + ike_payload_header_t *ikep; + u16 plen; ikev2_elog_exchange ("ispi %lx rspi %lx IKE_INIT request received " "from %d.%d.%d.%d", @@ -657,34 +701,38 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, vec_reset_length (sa->last_sa_init_req_packet_data); vec_add (sa->last_sa_init_req_packet_data, ike, len); + if (len < sizeof (*ike)) + return 0; + + len -= sizeof (*ike); while (p < len && payload != IKEV2_PAYLOAD_NONE) { - ike_payload_header_t *ikep = (ike_payload_header_t *) & ike->payload[p]; - u32 plen = clib_net_to_host_u16 (ikep->length); - - if (plen < sizeof (ike_payload_header_t)) - return; + ikep = (ike_payload_header_t *) & ike->payload[p]; + int current_length = len - p; + if (!ikev2_check_payload_length (ikep, current_length, &plen)) + return 0; if (payload == IKEV2_PAYLOAD_SA) { ikev2_sa_free_proposal_vector (&sa->i_proposals); - sa->i_proposals = ikev2_parse_sa_payload (ikep); + sa->i_proposals = ikev2_parse_sa_payload (ikep, current_length); } else if (payload == IKEV2_PAYLOAD_KE) { - ike_ke_payload_header_t *ke = (ike_ke_payload_header_t *) ikep; - sa->dh_group = clib_net_to_host_u16 (ke->dh_group); - vec_free (sa->i_dh_data); - vec_add (sa->i_dh_data, ke->payload, plen - sizeof (*ke)); + if (!ikev2_parse_ke_payload (ikep, current_length, sa, + &sa->i_dh_data)) + return 0; } else if (payload == IKEV2_PAYLOAD_NONCE) { - vec_free (sa->i_nonce); - vec_add (sa->i_nonce, ikep->payload, plen - sizeof (*ikep)); + vec_reset_length (sa->i_nonce); + if (ikev2_parse_nonce_payload (ikep, current_length, nonce)) + vec_add (sa->i_nonce, nonce, plen - sizeof (*ikep)); } else if (payload == IKEV2_PAYLOAD_NOTIFY) { - ikev2_notify_t *n = ikev2_parse_notify_payload (ikep); + ikev2_notify_t *n = + ikev2_parse_notify_payload (ikep, current_length); if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP) { u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, @@ -726,7 +774,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, { ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE); sa->unsupported_cp = payload; - return; + return 0; } } @@ -735,14 +783,19 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa, } ikev2_set_state (sa, IKEV2_STATE_SA_INIT); + return 1; } static void -ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, - ike_header_t * ike, udp_header_t * udp, u32 len) +ikev2_process_sa_init_resp (vlib_main_t * vm, + ikev2_sa_t * sa, ike_header_t * ike, + udp_header_t * udp, u32 len) { + u8 nonce[IKEV2_NONCE_SIZE]; int p = 0; u8 payload = ike->nextpayload; + ike_payload_header_t *ikep; + u16 plen; sa->ispi = clib_net_to_host_u64 (ike->ispi); sa->rspi = clib_net_to_host_u64 (ike->rspi); @@ -755,18 +808,21 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, vec_reset_length (sa->last_sa_init_res_packet_data); vec_add (sa->last_sa_init_res_packet_data, ike, len); + if (sizeof (*ike) > len) + return; + + len -= sizeof (*ike); while (p < len && payload != IKEV2_PAYLOAD_NONE) { - ike_payload_header_t *ikep = (ike_payload_header_t *) & ike->payload[p]; - u32 plen = clib_net_to_host_u16 (ikep->length); - - if (plen < sizeof (ike_payload_header_t)) + int current_length = len - p; + ikep = (ike_payload_header_t *) & ike->payload[p]; + if (!ikev2_check_payload_length (ikep, current_length, &plen)) return; if (payload == IKEV2_PAYLOAD_SA) { ikev2_sa_free_proposal_vector (&sa->r_proposals); - sa->r_proposals = ikev2_parse_sa_payload (ikep); + sa->r_proposals = ikev2_parse_sa_payload (ikep, current_length); if (sa->r_proposals) { ikev2_set_state (sa, IKEV2_STATE_SA_INIT); @@ -776,19 +832,20 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, } else if (payload == IKEV2_PAYLOAD_KE) { - ike_ke_payload_header_t *ke = (ike_ke_payload_header_t *) ikep; - sa->dh_group = clib_net_to_host_u16 (ke->dh_group); - vec_free (sa->r_dh_data); - vec_add (sa->r_dh_data, ke->payload, plen - sizeof (*ke)); + if (!ikev2_parse_ke_payload (ikep, current_length, sa, + &sa->r_dh_data)) + return; } else if (payload == IKEV2_PAYLOAD_NONCE) { - vec_free (sa->r_nonce); - vec_add (sa->r_nonce, ikep->payload, plen - sizeof (*ikep)); + vec_reset_length (sa->r_nonce); + if (ikev2_parse_nonce_payload (ikep, current_length, nonce)) + vec_add (sa->r_nonce, nonce, plen - sizeof (*ikep)); } else if (payload == IKEV2_PAYLOAD_NOTIFY) { - ikev2_notify_t *n = ikev2_parse_notify_payload (ikep); + ikev2_notify_t *n = + ikev2_parse_notify_payload (ikep, current_length); if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP) { u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, @@ -841,15 +898,15 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, } static u8 * -ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload, - u32 len) +ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, + u8 * payload, u32 rlen, u32 * out_len) { ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); int p = 0; - u8 last_payload = 0, *plaintext = 0; - u8 *hmac = 0; + u8 last_payload = 0, *hmac = 0, *plaintext = 0; ike_payload_header_t *ikep = 0; - u32 plen = 0; + u16 plen = 0; + u32 dlen = 0; ikev2_sa_transform_t *tr_integ; ikev2_sa_transform_t *tr_encr; tr_integ = @@ -861,13 +918,16 @@ ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload, if (((!sa->sk_ar || !sa->sk_ai) && !is_aead) || (!sa->sk_ei || !sa->sk_er)) return 0; + if (rlen <= sizeof (*ike)) + return 0; + + int len = rlen - sizeof (*ike); while (p < len && *payload != IKEV2_PAYLOAD_NONE && last_payload != IKEV2_PAYLOAD_SK) { ikep = (ike_payload_header_t *) & ike->payload[p]; - plen = clib_net_to_host_u16 (ikep->length); - - if (plen < sizeof (*ikep)) + int current_length = len - p; + if (!ikev2_check_payload_length (ikep, current_length, &plen)) return 0; if (*payload == IKEV2_PAYLOAD_SK) @@ -905,24 +965,29 @@ ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload, u32 aad_len = ikep->payload - aad; u8 *tag = ikep->payload + plen; - plaintext = ikev2_decrypt_aead_data (ptd, sa, tr_encr, ikep->payload, - plen, aad, aad_len, tag); + int rc = ikev2_decrypt_aead_data (ptd, sa, tr_encr, ikep->payload, + plen, aad, aad_len, tag, &dlen); + if (rc) + { + *out_len = dlen; + plaintext = ikep->payload + IKEV2_GCM_IV_SIZE; + } } else { - if (len < tr_integ->key_trunc) + if (rlen < tr_integ->key_trunc) return 0; hmac = ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ar : sa->sk_ai, - (u8 *) ike, len - tr_integ->key_trunc); + (u8 *) ike, rlen - tr_integ->key_trunc); if (plen < sizeof (*ikep) + tr_integ->key_trunc) return 0; plen = plen - sizeof (*ikep) - tr_integ->key_trunc; - if (memcmp (hmac, &ikep->payload[plen], tr_integ->key_trunc)) + if (clib_memcmp (hmac, &ikep->payload[plen], tr_integ->key_trunc)) { ikev2_elog_error ("message integrity check failed"); vec_free (hmac); @@ -930,7 +995,13 @@ ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload, } vec_free (hmac); - plaintext = ikev2_decrypt_data (ptd, sa, tr_encr, ikep->payload, plen); + int rc = ikev2_decrypt_data (ptd, sa, tr_encr, ikep->payload, plen, + &dlen); + if (rc) + { + *out_len = dlen; + plaintext = ikep->payload + tr_encr->block_size; + } } return plaintext; @@ -945,7 +1016,7 @@ ikev2_is_id_equal (ikev2_id_t * i1, ikev2_id_t * i2) if (vec_len (i1->data) != vec_len (i2->data)) return 0; - if (memcmp (i1->data, i2->data, vec_len (i1->data))) + if (clib_memcmp (i1->data, i2->data, vec_len (i1->data))) return 0; return 1; @@ -989,16 +1060,44 @@ ikev2_initial_contact_cleanup (ikev2_sa_t * sa) sa->initial_contact = 0; } -static void -ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, - u32 len) +static int +ikev2_parse_id_payload (const void *p, u16 rlen, ikev2_id_t * sa_id) +{ + const ike_id_payload_header_t *id = p; + u16 plen = clib_net_to_host_u16 (id->length); + if (plen < sizeof (*id) || plen > rlen) + return 0; + + sa_id->type = id->id_type; + vec_reset_length (sa_id->data); + vec_add (sa_id->data, id->payload, plen - sizeof (*id)); + + return 1; +} + +static int +ikev2_parse_auth_payload (const void *p, u32 rlen, ikev2_auth_t * a) +{ + const ike_auth_payload_header_t *ah = p; + u16 plen = clib_net_to_host_u16 (ah->length); + + a->method = ah->auth_method; + vec_reset_length (a->data); + vec_add (a->data, ah->payload, plen - sizeof (*ah)); + return 1; +} + +static int +ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, + ike_header_t * ike, u32 len) { - ikev2_child_sa_t *first_child_sa; int p = 0; + ikev2_child_sa_t *first_child_sa; u8 payload = ike->nextpayload; u8 *plaintext = 0; ike_payload_header_t *ikep; - u32 plen; + u16 plen; + u32 dlen = 0; ikev2_elog_exchange ("ispi %lx rspi %lx EXCHANGE_IKE_AUTH received " "from %d.%d.%d.%d", clib_host_to_net_u64 (ike->ispi), @@ -1008,13 +1107,16 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, ikev2_calc_keys (sa); - plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len); + plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len, &dlen); if (!plaintext) { if (sa->unsupported_cp) - ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE); - goto cleanup_and_exit; + { + ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE); + return 0; + } + goto malformed; } /* select or create 1st child SA */ @@ -1030,64 +1132,57 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, /* process encrypted payload */ - p = 0; - while (p < vec_len (plaintext) && payload != IKEV2_PAYLOAD_NONE) + while (p < dlen && payload != IKEV2_PAYLOAD_NONE) { ikep = (ike_payload_header_t *) & plaintext[p]; - plen = clib_net_to_host_u16 (ikep->length); - - if (plen < sizeof (ike_payload_header_t)) - goto cleanup_and_exit; + int current_length = dlen - p; + if (!ikev2_check_payload_length (ikep, current_length, &plen)) + goto malformed; if (payload == IKEV2_PAYLOAD_SA) /* 33 */ { if (sa->is_initiator) { ikev2_sa_free_proposal_vector (&first_child_sa->r_proposals); - first_child_sa->r_proposals = ikev2_parse_sa_payload (ikep); + first_child_sa->r_proposals = ikev2_parse_sa_payload (ikep, + current_length); } else { ikev2_sa_free_proposal_vector (&first_child_sa->i_proposals); - first_child_sa->i_proposals = ikev2_parse_sa_payload (ikep); + first_child_sa->i_proposals = ikev2_parse_sa_payload (ikep, + current_length); } } else if (payload == IKEV2_PAYLOAD_IDI) /* 35 */ { - ike_id_payload_header_t *id = (ike_id_payload_header_t *) ikep; - - sa->i_id.type = id->id_type; - vec_free (sa->i_id.data); - vec_add (sa->i_id.data, id->payload, plen - sizeof (*id)); + if (!ikev2_parse_id_payload (ikep, current_length, &sa->i_id)) + goto malformed; } else if (payload == IKEV2_PAYLOAD_IDR) /* 36 */ { - ike_id_payload_header_t *id = (ike_id_payload_header_t *) ikep; - - sa->r_id.type = id->id_type; - vec_free (sa->r_id.data); - vec_add (sa->r_id.data, id->payload, plen - sizeof (*id)); + if (!ikev2_parse_id_payload (ikep, current_length, &sa->r_id)) + goto malformed; } else if (payload == IKEV2_PAYLOAD_AUTH) /* 39 */ { - ike_auth_payload_header_t *a = (ike_auth_payload_header_t *) ikep; - if (sa->is_initiator) { - sa->r_auth.method = a->auth_method; - vec_free (sa->r_auth.data); - vec_add (sa->r_auth.data, a->payload, plen - sizeof (*a)); + if (!ikev2_parse_auth_payload (ikep, current_length, + &sa->r_auth)) + goto malformed; } else { - sa->i_auth.method = a->auth_method; - vec_free (sa->i_auth.data); - vec_add (sa->i_auth.data, a->payload, plen - sizeof (*a)); + if (!ikev2_parse_auth_payload (ikep, current_length, + &sa->i_auth)) + goto malformed; } } else if (payload == IKEV2_PAYLOAD_NOTIFY) /* 41 */ { - ikev2_notify_t *n = ikev2_parse_notify_payload (ikep); + ikev2_notify_t *n = + ikev2_parse_notify_payload (ikep, current_length); if (n->msg_type == IKEV2_NOTIFY_MSG_INITIAL_CONTACT) { sa->initial_contact = 1; @@ -1101,12 +1196,12 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, else if (payload == IKEV2_PAYLOAD_TSI) /* 44 */ { vec_free (first_child_sa->tsi); - first_child_sa->tsi = ikev2_parse_ts_payload (ikep); + first_child_sa->tsi = ikev2_parse_ts_payload (ikep, current_length); } else if (payload == IKEV2_PAYLOAD_TSR) /* 45 */ { vec_free (first_child_sa->tsr); - first_child_sa->tsr = ikev2_parse_ts_payload (ikep); + first_child_sa->tsr = ikev2_parse_ts_payload (ikep, current_length); } else { @@ -1117,7 +1212,7 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, { ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE); sa->unsupported_cp = payload; - return; + return 0; } } @@ -1125,50 +1220,60 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, p += plen; } -cleanup_and_exit: - vec_free (plaintext); + return 1; + +malformed: + ikev2_set_state (sa, IKEV2_STATE_DELETED); + return 0; } -static void -ikev2_process_informational_req (vlib_main_t * vm, ikev2_sa_t * sa, - ike_header_t * ike, u32 len) +static int +ikev2_process_informational_req (vlib_main_t * vm, + ikev2_sa_t * sa, ike_header_t * ike, u32 len) { int p = 0; u8 payload = ike->nextpayload; u8 *plaintext = 0; ike_payload_header_t *ikep; - u32 plen; + u32 dlen = 0; + ikev2_notify_t *n = 0; sa->liveness_retries = 0; ikev2_elog_exchange ("ispi %lx rspi %lx INFORMATIONAL received " "from %d.%d.%d.%d", clib_host_to_net_u64 (ike->ispi), clib_host_to_net_u64 (ike->rspi), sa->iaddr.as_u32); - plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len); + plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len, &dlen); if (!plaintext) - goto cleanup_and_exit; + return 0; /* process encrypted payload */ p = 0; - while (p < vec_len (plaintext) && payload != IKEV2_PAYLOAD_NONE) + while (p < dlen && payload != IKEV2_PAYLOAD_NONE) { + u32 current_length = dlen - p; + if (p + sizeof (*ikep) > dlen) + return 0; + ikep = (ike_payload_header_t *) & plaintext[p]; - plen = clib_net_to_host_u16 (ikep->length); + u16 plen = clib_net_to_host_u16 (ikep->length); - if (plen < sizeof (ike_payload_header_t)) - goto cleanup_and_exit; + if (plen < sizeof (*ikep) || plen > current_length) + return 0; if (payload == IKEV2_PAYLOAD_NOTIFY) /* 41 */ { - ikev2_notify_t *n = ikev2_parse_notify_payload (ikep); + n = ikev2_parse_notify_payload (ikep, current_length); + if (!n) + return 0; if (n->msg_type == IKEV2_NOTIFY_MSG_AUTHENTICATION_FAILED) ikev2_set_state (sa, IKEV2_STATE_AUTH_FAILED); vec_free (n); } else if (payload == IKEV2_PAYLOAD_DELETE) /* 42 */ { - sa->del = ikev2_parse_delete_payload (ikep); + sa->del = ikev2_parse_delete_payload (ikep, current_length); } else if (payload == IKEV2_PAYLOAD_VENDOR) /* 43 */ { @@ -1181,21 +1286,19 @@ ikev2_process_informational_req (vlib_main_t * vm, ikev2_sa_t * sa, if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL) { sa->unsupported_cp = payload; - return; + return 0; } } - payload = ikep->nextpayload; p += plen; } - -cleanup_and_exit: - vec_free (plaintext); + return 1; } -static void -ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, - ike_header_t * ike, u32 len) +static int +ikev2_process_create_child_sa_req (vlib_main_t * vm, + ikev2_sa_t * sa, ike_header_t * ike, + u32 len) { int p = 0; u8 payload = ike->nextpayload; @@ -1204,39 +1307,39 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, u8 nonce[IKEV2_NONCE_SIZE]; ike_payload_header_t *ikep; - u32 plen; ikev2_notify_t *n = 0; ikev2_ts_t *tsi = 0; ikev2_ts_t *tsr = 0; ikev2_sa_proposal_t *proposal = 0; ikev2_child_sa_t *child_sa; + u32 dlen = 0; + u16 plen; ikev2_elog_exchange ("ispi %lx rspi %lx CREATE_CHILD_SA received " "from %d.%d.%d.%d", clib_host_to_net_u64 (ike->ispi), clib_host_to_net_u64 (ike->rspi), sa->raddr.as_u32); - plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len); + plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len, &dlen); if (!plaintext) goto cleanup_and_exit; /* process encrypted payload */ p = 0; - while (p < vec_len (plaintext) && payload != IKEV2_PAYLOAD_NONE) + while (payload != IKEV2_PAYLOAD_NONE) { ikep = (ike_payload_header_t *) & plaintext[p]; - plen = clib_net_to_host_u16 (ikep->length); - - if (plen < sizeof (ike_payload_header_t)) + int current_length = dlen - p; + if (!ikev2_check_payload_length (ikep, current_length, &plen)) goto cleanup_and_exit; - else if (payload == IKEV2_PAYLOAD_SA) + if (payload == IKEV2_PAYLOAD_SA) { - proposal = ikev2_parse_sa_payload (ikep); + proposal = ikev2_parse_sa_payload (ikep, current_length); } else if (payload == IKEV2_PAYLOAD_NOTIFY) { - n = ikev2_parse_notify_payload (ikep); + n = ikev2_parse_notify_payload (ikep, current_length); if (n->msg_type == IKEV2_NOTIFY_MSG_REKEY_SA) { rekeying = 1; @@ -1244,7 +1347,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, } else if (payload == IKEV2_PAYLOAD_DELETE) { - sa->del = ikev2_parse_delete_payload (ikep); + sa->del = ikev2_parse_delete_payload (ikep, current_length); } else if (payload == IKEV2_PAYLOAD_VENDOR) { @@ -1252,15 +1355,15 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, } else if (payload == IKEV2_PAYLOAD_NONCE) { - clib_memcpy_fast (nonce, ikep->payload, plen - sizeof (*ikep)); + ikev2_parse_nonce_payload (ikep, current_length, nonce); } else if (payload == IKEV2_PAYLOAD_TSI) { - tsi = ikev2_parse_ts_payload (ikep); + tsi = ikev2_parse_ts_payload (ikep, current_length); } else if (payload == IKEV2_PAYLOAD_TSR) { - tsr = ikev2_parse_ts_payload (ikep); + tsr = ikev2_parse_ts_payload (ikep, current_length); } else { @@ -1272,7 +1375,6 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, goto cleanup_and_exit; } } - payload = ikep->nextpayload; p += plen; } @@ -1288,7 +1390,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, rekey->tsi = tsi; rekey->tsr = tsr; /* update Nr */ - vec_free (sa->r_nonce); + vec_reset_length (sa->r_nonce); vec_add (sa->r_nonce, nonce, IKEV2_NONCE_SIZE); child_sa = ikev2_sa_get_child (sa, rekey->ispi, IKEV2_PROTOCOL_ESP, 1); if (child_sa) @@ -1318,14 +1420,15 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, vec_free (sa->i_nonce); vec_add (sa->i_nonce, nonce, IKEV2_NONCE_SIZE); /* generate new Nr */ - vec_free (sa->r_nonce); - sa->r_nonce = vec_new (u8, IKEV2_NONCE_SIZE); + vec_validate (sa->r_nonce, IKEV2_NONCE_SIZE - 1); RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE); + vec_free (n); } + return 1; cleanup_and_exit: - vec_free (plaintext); vec_free (n); + return 0; } static u8 * @@ -1511,7 +1614,7 @@ ikev2_sa_auth (ikev2_sa_t * sa) psk = ikev2_calc_prf(tr_prf, p->auth.data, key_pad); auth = ikev2_calc_prf(tr_prf, psk, authmsg); - if (!memcmp(auth, sa_auth->data, vec_len(sa_auth->data))) + if (!clib_memcmp(auth, sa_auth->data, vec_len(sa_auth->data))) { ikev2_set_state(sa, IKEV2_STATE_AUTHENTICATED); vec_free(auth); @@ -2069,9 +2172,11 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, } static u32 -ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, - udp_header_t * udp) +ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, + ike_header_t * ike, void *user, udp_header_t * udp) { + ikev2_main_t *km = &ikev2_main; + u16 buffer_data_size = vlib_buffer_get_default_data_size (km->vlib_main); v8 *integ = 0; ike_payload_header_t *ph; u16 plen; @@ -2328,6 +2433,13 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, tlen += vec_len (chain->data); ike->nextpayload = chain->first_payload_type; ike->length = clib_host_to_net_u32 (tlen); + + if (tlen + b->current_length + b->current_data > buffer_data_size) + { + tlen = ~0; + goto done; + } + clib_memcpy_fast (ike->payload, chain->data, vec_len (chain->data)); /* store whole IKE payload - needed for PSK auth */ @@ -2356,21 +2468,36 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, plen += IKEV2_GCM_ICV_SIZE; tlen += plen; + if (tlen + b->current_length + b->current_data > buffer_data_size) + { + tlen = ~0; + goto done; + } + /* payload and total length */ ph->length = clib_host_to_net_u16 (plen); ike->length = clib_host_to_net_u32 (tlen); if (is_aead) { - ikev2_encrypt_aead_data (ptd, sa, tr_encr, chain->data, - ph->payload, (u8 *) ike, - sizeof (*ike) + sizeof (*ph), - ph->payload + plen - sizeof (*ph) - - IKEV2_GCM_ICV_SIZE); + if (!ikev2_encrypt_aead_data (ptd, sa, tr_encr, chain->data, + ph->payload, (u8 *) ike, + sizeof (*ike) + sizeof (*ph), + ph->payload + plen - sizeof (*ph) - + IKEV2_GCM_ICV_SIZE)) + { + tlen = ~0; + goto done; + } } else { - ikev2_encrypt_data (ptd, sa, tr_encr, chain->data, ph->payload); + if (!ikev2_encrypt_data + (ptd, sa, tr_encr, chain->data, ph->payload)) + { + tlen = ~0; + goto done; + } integ = ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ai : sa->sk_ar, @@ -2391,8 +2518,8 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user, } static u32 -ikev2_retransmit_sa_init (ike_header_t * ike, - ip4_address_t iaddr, ip4_address_t raddr, u32 rlen) +ikev2_retransmit_sa_init (ike_header_t * ike, ip4_address_t iaddr, + ip4_address_t raddr, u32 rlen) { ikev2_main_t *km = &ikev2_main; ikev2_sa_t *sa; @@ -2409,14 +2536,17 @@ ikev2_retransmit_sa_init (ike_header_t * ike, while (p < rlen && payload!= IKEV2_PAYLOAD_NONE) { ike_payload_header_t * ikep = (ike_payload_header_t *) &ike->payload[p]; - u32 plen = clib_net_to_host_u16(ikep->length); + u32 plen = clib_net_to_host_u16 (ikep->length); + if (plen > p + sizeof (*ike)) + return ~0; if (plen < sizeof(ike_payload_header_t)) - return -1; + return ~0; if (payload == IKEV2_PAYLOAD_NONCE) { - if (!memcmp(sa->i_nonce, ikep->payload, plen - sizeof(*ikep))) + if (!clib_memcmp(sa->i_nonce, ikep->payload, + plen - sizeof(*ikep))) { /* req is retransmit */ if (sa->state == IKEV2_STATE_SA_INIT) @@ -2463,7 +2593,7 @@ ikev2_retransmit_sa_init (ike_header_t * ike, } static u32 -ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike, u32 rlen) +ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike) { u32 msg_id = clib_net_to_host_u32 (ike->msgid); @@ -2536,6 +2666,7 @@ ikev2_node_fn (vlib_main_t * vm, ikev2_next_t next_index; ikev2_main_t *km = &ikev2_main; u32 thread_index = vlib_get_thread_index (); + int res; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -2552,7 +2683,6 @@ ikev2_node_fn (vlib_main_t * vm, u32 bi0; vlib_buffer_t *b0; u32 next0 = IKEV2_NEXT_ERROR_DROP; - u32 sw_if_index0; ip4_header_t *ip40; udp_header_t *udp0; ike_header_t *ike0; @@ -2643,7 +2773,12 @@ ikev2_node_fn (vlib_main_t * vm, goto dispatch0; } - ikev2_process_sa_init_req (vm, sa0, ike0, udp0, rlen); + res = ikev2_process_sa_init_req (vm, sa0, + ike0, udp0, rlen); + if (!res) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, + 1); if (sa0->state == IKEV2_STATE_SA_INIT) { @@ -2657,7 +2792,12 @@ ikev2_node_fn (vlib_main_t * vm, if (sa0->state == IKEV2_STATE_SA_INIT || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE) { - slen = ikev2_generate_message (sa0, ike0, 0, udp0); + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); } if (sa0->state == IKEV2_STATE_SA_INIT) @@ -2702,7 +2842,13 @@ ikev2_node_fn (vlib_main_t * vm, ikev2_calc_keys (sa0); ikev2_sa_auth_init (sa0); slen = - ikev2_generate_message (sa0, ike0, 0, udp0); + ikev2_generate_message (b0, sa0, ike0, 0, + udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, + ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); } else { @@ -2738,7 +2884,7 @@ ikev2_node_fn (vlib_main_t * vm, pool_elt_at_index (km->per_thread_data[thread_index].sas, p[0]); - slen = ikev2_retransmit_resp (sa0, ike0, rlen); + slen = ikev2_retransmit_resp (sa0, ike0); if (slen) { vlib_node_increment_counter (vm, ikev2_node.index, @@ -2752,8 +2898,13 @@ ikev2_node_fn (vlib_main_t * vm, } sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); - ikev2_process_auth_req (vm, sa0, ike0, rlen); - ikev2_sa_auth (sa0); + res = ikev2_process_auth_req (vm, sa0, ike0, rlen); + if (res) + ikev2_sa_auth (sa0); + else + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, + 1); if (sa0->state == IKEV2_STATE_AUTHENTICATED) { ikev2_initial_contact_cleanup (sa0); @@ -2770,7 +2921,11 @@ ikev2_node_fn (vlib_main_t * vm, } else { - slen = ikev2_generate_message (sa0, ike0, 0, udp0); + slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); } } } @@ -2785,7 +2940,7 @@ ikev2_node_fn (vlib_main_t * vm, pool_elt_at_index (km->per_thread_data[thread_index].sas, p[0]); - slen = ikev2_retransmit_resp (sa0, ike0, rlen); + slen = ikev2_retransmit_resp (sa0, ike0); if (slen) { vlib_node_increment_counter (vm, ikev2_node.index, @@ -2798,7 +2953,16 @@ ikev2_node_fn (vlib_main_t * vm, goto dispatch0; } - ikev2_process_informational_req (vm, sa0, ike0, rlen); + res = ikev2_process_informational_req (vm, sa0, ike0, rlen); + if (!res) + { + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, + 1); + slen = ~0; + goto dispatch0; + } + if (sa0->del) { if (sa0->del[0].protocol_id != IKEV2_PROTOCOL_IKE) @@ -2833,7 +2997,11 @@ ikev2_node_fn (vlib_main_t * vm, if (!(ike0->flags & IKEV2_HDR_FLAG_RESPONSE)) { ike0->flags |= IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (sa0, ike0, 0, udp0); + slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); } } } @@ -2848,7 +3016,7 @@ ikev2_node_fn (vlib_main_t * vm, pool_elt_at_index (km->per_thread_data[thread_index].sas, p[0]); - slen = ikev2_retransmit_resp (sa0, ike0, rlen); + slen = ikev2_retransmit_resp (sa0, ike0); if (slen) { vlib_node_increment_counter (vm, ikev2_node.index, @@ -2861,7 +3029,17 @@ ikev2_node_fn (vlib_main_t * vm, goto dispatch0; } - ikev2_process_create_child_sa_req (vm, sa0, ike0, rlen); + res = ikev2_process_create_child_sa_req (vm, sa0, + ike0, rlen); + if (!res) + { + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, + 1); + slen = ~0; + goto dispatch0; + } + if (sa0->rekey) { if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE) @@ -2886,7 +3064,12 @@ ikev2_node_fn (vlib_main_t * vm, } else { - slen = ikev2_generate_message (sa0, ike0, 0, udp0); + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); } } } @@ -2957,13 +3140,12 @@ ikev2_node_fn (vlib_main_t * vm, ikev2_delete_sa (sa0); } - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { + ikev2_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; } @@ -3187,16 +3369,15 @@ ikev2_send_ike (vlib_main_t * vm, ip4_address_t * src, ip4_address_t * dst, } static u32 -ikev2_get_new_ike_header_buff (vlib_main_t * vm, ike_header_t ** ike) +ikev2_get_new_ike_header_buff (vlib_main_t * vm, vlib_buffer_t ** b) { u32 bi0; if (vlib_buffer_alloc (vm, &bi0, 1) != 1) { - *ike = 0; + *b = 0; return 0; } - vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0); - *ike = vlib_buffer_get_current (b0); + *b = vlib_get_buffer (vm, bi0); return bi0; } @@ -3273,19 +3454,21 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, { ikev2_main_t *km = &ikev2_main; ip4_address_t *src, *dst; + vlib_buffer_t *b0; /* Create the Initiator notification for IKE SA removal */ ike_header_t *ike0; u32 bi0 = 0; int len; - bi0 = ikev2_get_new_ike_header_buff (vm, &ike0); + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); if (!bi0) { ikev2_log_error ("buffer alloc failure"); return; } + ike0 = vlib_buffer_get_current (b0); ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); @@ -3294,7 +3477,9 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, sa->del->spi = sa->ispi; ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (sa, ike0, 0, 0); + len = ikev2_generate_message (b0, sa, ike0, 0, 0); + if (~0 == len) + return; if (sa->is_initiator) { @@ -3718,6 +3903,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) /* Create the Initiator Request */ { + vlib_buffer_t *b0; ike_header_t *ike0; u32 bi0 = 0; ip_lookup_main_t *lm = &im->lookup_main; @@ -3731,13 +3917,14 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) pool_elt_at_index (lm->if_address_pool, if_add_index0); ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add); - bi0 = ikev2_get_new_ike_header_buff (vm, &ike0); + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); if (!bi0) { char *errmsg = "buffer alloc failure"; ikev2_log_error (errmsg); return clib_error_return (0, errmsg); } + ike0 = vlib_buffer_get_current (b0); /* Prepare the SA and the IKE payload */ ikev2_sa_t sa; @@ -3865,15 +4052,17 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, ikev2_main_t *km = &ikev2_main; ike_header_t *ike0; u32 bi0 = 0; + vlib_buffer_t *b0; int len; - bi0 = ikev2_get_new_ike_header_buff (vm, &ike0); + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); if (!bi0) { ikev2_log_error ("buffer alloc failure"); return; } + ike0 = vlib_buffer_get_current (b0); ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); @@ -3882,7 +4071,10 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, sa->del->spi = csa->i_proposals->spi; ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (sa, ike0, 0, 0); + len = ikev2_generate_message (b0, sa, ike0, 0, 0); + if (~0 == len) + return; + if (sa->natt) len = ikev2_insert_non_esp_marker (ike0, len); ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len, @@ -3976,16 +4168,18 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, { /* Create the Initiator request for create child SA */ ike_header_t *ike0; + vlib_buffer_t *b0; u32 bi0 = 0; int len; - bi0 = ikev2_get_new_ike_header_buff (vm, &ike0); + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); if (!bi0) { ikev2_log_error ("buffer alloc failure"); return; } + ike0 = vlib_buffer_get_current (b0); ike0->version = IKE_VERSION_2; ike0->flags = IKEV2_HDR_FLAG_INITIATOR; ike0->exchange = IKEV2_EXCHANGE_CREATE_CHILD_SA; @@ -4002,7 +4196,10 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi)); rekey->spi = proposals[0].spi; rekey->ispi = csa->i_proposals->spi; - len = ikev2_generate_message (sa, ike0, proposals, 0); + len = ikev2_generate_message (b0, sa, ike0, proposals, 0); + if (~0 == len) + return; + if (sa->natt) len = ikev2_insert_non_esp_marker (ike0, len); ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len, @@ -4313,23 +4510,28 @@ ikev2_send_informational_request (ikev2_sa_t * sa) ikev2_main_t *km = &ikev2_main; ip4_address_t *src, *dst; ike_header_t *ike0; + vlib_buffer_t *b0; u32 bi0 = 0; u16 dp; int len; - bi0 = ikev2_get_new_ike_header_buff (km->vlib_main, &ike0); + bi0 = ikev2_get_new_ike_header_buff (km->vlib_main, &b0); if (!bi0) { ikev2_log_error ("buffer alloc failure"); return; } + ike0 = vlib_buffer_get_current (b0); ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (sa, ike0, 0, 0); + len = ikev2_generate_message (b0, sa, ike0, 0, 0); + if (~0 == len) + return; + if (sa->natt) len = ikev2_insert_non_esp_marker (ike0, len); diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h index d435179275aa..36ac85a39c52 100644 --- a/src/plugins/ikev2/ikev2.h +++ b/src/plugins/ikev2/ikev2.h @@ -45,13 +45,14 @@ typedef CLIB_PACKED (struct { /* *INDENT-ON* */ /* *INDENT-OFF* */ -typedef CLIB_PACKED (struct - { - u8 nextpayload; - u8 flags; - u16 length; - u16 dh_group; - u8 reserved[2]; u8 payload[0];}) ike_ke_payload_header_t; +typedef CLIB_PACKED (struct { + u8 nextpayload; + u8 flags; + u16 length; + u16 dh_group; + u8 reserved[2]; + u8 payload[0]; +}) ike_ke_payload_header_t; /* *INDENT-ON* */ /* *INDENT-OFF* */ diff --git a/src/plugins/ikev2/ikev2_crypto.c b/src/plugins/ikev2/ikev2_crypto.c index 013857dee9be..f5080ed819f6 100644 --- a/src/plugins/ikev2/ikev2_crypto.c +++ b/src/plugins/ikev2/ikev2_crypto.c @@ -349,10 +349,11 @@ ikev2_init_gcm_nonce (u8 * nonce, u8 * salt, u8 * iv) clib_memcpy (nonce + IKEV2_GCM_SALT_SIZE, iv, IKEV2_GCM_IV_SIZE); } -u8 * +int ikev2_decrypt_aead_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, ikev2_sa_transform_t * tr_encr, u8 * data, - int data_len, u8 * aad, u32 aad_len, u8 * tag) + int data_len, u8 * aad, u32 aad_len, u8 * tag, + u32 * out_len) { EVP_CIPHER_CTX *ctx = ptd->evp_ctx; int len = 0; @@ -369,34 +370,33 @@ ikev2_decrypt_aead_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, data += IKEV2_GCM_IV_SIZE; data_len -= IKEV2_GCM_IV_SIZE; - v8 *r = vec_new (u8, data_len); EVP_DecryptInit_ex (ctx, tr_encr->cipher, 0, 0, 0); EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_IVLEN, 12, 0); EVP_DecryptInit_ex (ctx, 0, 0, key, nonce); EVP_DecryptUpdate (ctx, 0, &len, aad, aad_len); - EVP_DecryptUpdate (ctx, r, &len, data, data_len); + EVP_DecryptUpdate (ctx, data, &len, data, data_len); EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, IKEV2_GCM_ICV_SIZE, tag); - if (EVP_DecryptFinal_ex (ctx, r + len, &len) > 0) + if (EVP_DecryptFinal_ex (ctx, data + len, &len) > 0) { - /* remove padding */ - _vec_len (r) -= r[vec_len (r) - 1] + 1; - return r; + *out_len = data_len - data[data_len - 1] - 1; + return 1; } - vec_free (r); return 0; } -v8 * +int ikev2_decrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, - ikev2_sa_transform_t * tr_encr, u8 * data, int len) + ikev2_sa_transform_t * tr_encr, u8 * data, int len, + u32 * out_len) { EVP_CIPHER_CTX *ctx = ptd->evp_ctx; - int out_len = 0, block_size; + int tmp_len = 0, block_size; u8 *key = sa->is_initiator ? sa->sk_er : sa->sk_ei; block_size = tr_encr->block_size; + u8 *iv = data; /* check if data is multiplier of cipher block size */ if (len % block_size) @@ -404,15 +404,20 @@ ikev2_decrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, ikev2_elog_error ("wrong data length"); return 0; } + data += block_size; + len -= block_size; - v8 *r = vec_new (u8, len - block_size); - EVP_DecryptInit_ex (ctx, tr_encr->cipher, NULL, key, data); - EVP_DecryptUpdate (ctx, r, &out_len, data + block_size, len - block_size); - EVP_DecryptFinal_ex (ctx, r + out_len, &out_len); - /* remove padding */ - _vec_len (r) -= r[vec_len (r) - 1] + 1; + EVP_DecryptInit_ex (ctx, tr_encr->cipher, NULL, key, iv); + EVP_CIPHER_CTX_set_padding (ctx, 0); + EVP_DecryptUpdate (ctx, data, &tmp_len, data, len); - return r; + if (EVP_DecryptFinal_ex (ctx, data + tmp_len, &tmp_len) > 0) + { + *out_len = len - data[len - 1] - 1; + return 1; + } + + return 0; } int @@ -424,6 +429,8 @@ ikev2_encrypt_aead_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, int out_len = 0, len = 0; u8 nonce[IKEV2_GCM_NONCE_SIZE]; u8 *key = sa->is_initiator ? sa->sk_ei : sa->sk_er; + if (!key) + return 0; /* generate IV; its length must be 8 octets for aes-gcm (rfc5282) */ RAND_bytes (dst, IKEV2_GCM_IV_SIZE); @@ -452,6 +459,8 @@ ikev2_encrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, int out_len = 0, len = 0; int bs = tr_encr->block_size; u8 *key = sa->is_initiator ? sa->sk_ei : sa->sk_er; + if (!key) + return 0; /* generate IV */ u8 *iv = dst; diff --git a/src/plugins/ikev2/ikev2_payload.c b/src/plugins/ikev2/ikev2_payload.c index 56bb652e9405..b7d7098605c1 100644 --- a/src/plugins/ikev2/ikev2_payload.c +++ b/src/plugins/ikev2/ikev2_payload.c @@ -327,22 +327,27 @@ ikev2_payload_chain_add_padding (ikev2_payload_chain_t * c, int bs) } ikev2_sa_proposal_t * -ikev2_parse_sa_payload (ike_payload_header_t * ikep) +ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen) { ikev2_sa_proposal_t *v = 0; ikev2_sa_proposal_t *proposal; ikev2_sa_transform_t *transform; u32 plen = clib_net_to_host_u16 (ikep->length); - ike_sa_proposal_data_t *sap; int proposal_ptr = 0; + if (sizeof (*ikep) > rlen) + return 0; + + rlen -= sizeof (*ikep); do { + if (proposal_ptr + sizeof (*sap) > rlen) + goto data_corrupted; + sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr]; - int i; - int transform_ptr; + int i, transform_ptr; /* IKE proposal should not have SPI */ if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0) @@ -353,6 +358,8 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep) goto data_corrupted; transform_ptr = proposal_ptr + sizeof (*sap) + sap->spi_size; + if (transform_ptr > rlen) + goto data_corrupted; vec_add2 (v, proposal, 1); proposal->proposal_num = sap->proposal_num; @@ -366,7 +373,9 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep) for (i = 0; i < sap->num_transforms; i++) { ike_sa_transform_data_t *tr = - (ike_sa_transform_data_t *) & ikep->payload[transform_ptr]; + (ike_sa_transform_data_t *) & ikep->payload[transform_ptr]; + if (transform_ptr + sizeof (*tr) > rlen) + goto data_corrupted; u16 tlen = clib_net_to_host_u16 (tr->transform_len); if (tlen < sizeof (*tr)) @@ -376,9 +385,11 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep) transform->type = tr->transform_type; transform->transform_id = clib_net_to_host_u16 (tr->transform_id); + if (transform_ptr + tlen > rlen) + goto data_corrupted; if (tlen > sizeof (*tr)) vec_add (transform->attrs, tr->attributes, tlen - sizeof (*tr)); - transform_ptr += tlen; + transform_ptr += tlen; } proposal_ptr += clib_net_to_host_u16 (sap->proposal_len); @@ -398,12 +409,18 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep) } ikev2_ts_t * -ikev2_parse_ts_payload (ike_payload_header_t * ikep) +ikev2_parse_ts_payload (ike_payload_header_t * ikep, u32 rlen) { ike_ts_payload_header_t *tsp = (ike_ts_payload_header_t *) ikep; ikev2_ts_t *r = 0, *ts; u8 i; + if (sizeof (*tsp) > rlen) + return 0; + + if (sizeof (*tsp) + tsp->num_ts * sizeof (ikev2_ts_payload_entry_t) > rlen) + return 0; + for (i = 0; i < tsp->num_ts; i++) { if (tsp->ts[i].ts_type != 7) /* TS_IPV4_ADDR_RANGE */ @@ -425,19 +442,25 @@ ikev2_parse_ts_payload (ike_payload_header_t * ikep) } ikev2_notify_t * -ikev2_parse_notify_payload (ike_payload_header_t * ikep) +ikev2_parse_notify_payload (ike_payload_header_t * ikep, u32 rlen) { ike_notify_payload_header_t *n = (ike_notify_payload_header_t *) ikep; - u32 plen = clib_net_to_host_u16 (ikep->length); + u32 plen = clib_net_to_host_u16 (n->length); ikev2_notify_t *r = 0; u32 spi; + if (sizeof (*n) > rlen) + return 0; + r = vec_new (ikev2_notify_t, 1); r->msg_type = clib_net_to_host_u16 (n->msg_type); r->protocol_id = n->protocol_id; if (n->spi_size == 4) { + if (sizeof (spi) + sizeof (*n) > rlen) + goto cleanup; + clib_memcpy (&spi, n->payload, n->spi_size); r->spi = clib_net_to_host_u32 (spi); } @@ -448,15 +471,22 @@ ikev2_parse_notify_payload (ike_payload_header_t * ikep) else { clib_warning ("invalid SPI Size %d", n->spi_size); + goto cleanup; } if (plen > (sizeof (*n) + n->spi_size)) { - vec_add (r->data, n->payload + n->spi_size, - plen - sizeof (*n) - n->spi_size); - } + if (plen <= sizeof (*n) + n->spi_size) + goto cleanup; + u32 data_len = plen - sizeof (*n) - n->spi_size; + vec_add (r->data, n->payload + n->spi_size, data_len); + } return r; + +cleanup: + vec_free (r); + return 0; } void @@ -467,13 +497,16 @@ ikev2_parse_vendor_payload (ike_payload_header_t * ikep) } ikev2_delete_t * -ikev2_parse_delete_payload (ike_payload_header_t * ikep) +ikev2_parse_delete_payload (ike_payload_header_t * ikep, u32 rlen) { - ike_delete_payload_header_t *d = (ike_delete_payload_header_t *) ikep; + ike_delete_payload_header_t * d = (ike_delete_payload_header_t *) ikep; ikev2_delete_t *r = 0, *del; - u16 num_of_spi = clib_net_to_host_u16 (d->num_of_spi); - u16 i = 0; + u16 i, num_of_spi; + + if (rlen < sizeof (*d)) + return 0; + num_of_spi = clib_net_to_host_u16 (d->num_of_spi); if (d->protocol_id == IKEV2_PROTOCOL_IKE) { r = vec_new (ikev2_delete_t, 1); @@ -481,11 +514,14 @@ ikev2_parse_delete_payload (ike_payload_header_t * ikep) } else { - r = vec_new (ikev2_delete_t, num_of_spi); - vec_foreach (del, r) + if (sizeof (*d) + num_of_spi * sizeof (u32) > rlen) + return 0; + + for (i = 0; i < num_of_spi; i++) { - del->protocol_id = d->protocol_id; - del->spi = clib_net_to_host_u32 (d->spi[i++]); + vec_add2 (r, del, 1); + del->protocol_id = d->protocol_id; + del->spi = clib_net_to_host_u32 (d->spi[i]); } } diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index f8b0458db9c8..f6f9989e4b2c 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -522,18 +522,19 @@ u8 *ikev2_calc_prfplus (ikev2_sa_transform_t * tr, u8 * key, u8 * seed, int len); v8 *ikev2_calc_integr (ikev2_sa_transform_t * tr, v8 * key, u8 * data, int len); -v8 *ikev2_decrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, - ikev2_sa_transform_t * tr_encr, u8 * data, int len); +int ikev2_decrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, + ikev2_sa_transform_t * tr_encr, u8 * data, int len, + u32 * out_len); int ikev2_encrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, ikev2_sa_transform_t * tr_encr, v8 * src, u8 * dst); int ikev2_encrypt_aead_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, ikev2_sa_transform_t * tr_encr, v8 * src, u8 * dst, u8 * aad, u32 aad_len, u8 * tag); -u8 *ikev2_decrypt_aead_data (ikev2_main_per_thread_data_t * ptd, +int ikev2_decrypt_aead_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa, ikev2_sa_transform_t * tr_encr, u8 * data, int data_len, u8 * aad, u32 aad_len, - u8 * tag); + u8 * tag, u32 * out_len); void ikev2_generate_dh (ikev2_sa_t * sa, ikev2_sa_transform_t * t); void ikev2_complete_dh (ikev2_sa_t * sa, ikev2_sa_transform_t * t); int ikev2_verify_sign (EVP_PKEY * pkey, u8 * sigbuf, u8 * data); @@ -573,10 +574,13 @@ void ikev2_payload_add_ts (ikev2_payload_chain_t * c, ikev2_ts_t * ts, void ikev2_payload_add_delete (ikev2_payload_chain_t * c, ikev2_delete_t * d); void ikev2_payload_chain_add_padding (ikev2_payload_chain_t * c, int bs); void ikev2_parse_vendor_payload (ike_payload_header_t * ikep); -ikev2_sa_proposal_t *ikev2_parse_sa_payload (ike_payload_header_t * ikep); -ikev2_ts_t *ikev2_parse_ts_payload (ike_payload_header_t * ikep); -ikev2_delete_t *ikev2_parse_delete_payload (ike_payload_header_t * ikep); -ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep); +ikev2_sa_proposal_t *ikev2_parse_sa_payload (ike_payload_header_t * ikep, + u32 rlen); +ikev2_ts_t *ikev2_parse_ts_payload (ike_payload_header_t * ikep, u32 rlen); +ikev2_delete_t *ikev2_parse_delete_payload (ike_payload_header_t * ikep, + u32 rlen); +ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep, + u32 rlen); int ikev2_set_log_level (ikev2_log_level_t log_level); static_always_inline ikev2_main_per_thread_data_t * diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 6116ebb29a73..0bdc417fb2dd 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -114,7 +114,7 @@ def decrypt(self, data, key, aad=None, icv=None): def pad(self, data): pad_len = (len(data) // self.bs + 1) * self.bs - len(data) data = data + b'\x00' * (pad_len - 1) - return data + bytes([pad_len]) + return data + bytes([pad_len - 1]) class AuthAlgo(object): @@ -167,6 +167,7 @@ def __init__(self, test, is_initiator=True, spi=b'\x04' * 8, else: self.sport = 500 self.dport = 500 + self.msg_id = 0 self.dh_params = None self.test = test self.priv_key = priv_key @@ -190,6 +191,10 @@ def __init__(self, test, is_initiator=True, spi=b'\x04' * 8, self.r_nonce = None self.child_sas = [IKEv2ChildSA(local_ts, remote_ts)] + def new_msg_id(self): + self.msg_id += 1 + return self.msg_id + def dh_pub_key(self): return self.i_dh_data @@ -502,10 +507,35 @@ def setUp(self): def tearDown(self): super(TemplateResponder, self).tearDown() + if self.sa.is_initiator: + self.initiate_del_sa() + r = self.vapi.ikev2_sa_dump() + self.assertEqual(len(r), 0) + self.p.remove_vpp_config() self.assertIsNone(self.p.query_vpp_config()) - def create_ike_msg(self, src_if, msg, sport=500, dport=500, natt=False): + def verify_del_sa(self, packet): + ih = self.get_ike_header(packet) + self.assertEqual(ih.id, self.sa.msg_id) + self.assertEqual(ih.exch_type, 37) # exchange informational + + def initiate_del_sa(self): + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + flags='Initiator', exch_type='INFORMATIONAL', + id=self.sa.new_msg_id()) + del_sa = ikev2.IKEv2_payload_Delete(proto='IKEv2') + ike_msg = self.encrypt_ike_msg(header, del_sa, 'Delete') + packet = self.create_packet(self.pg0, ike_msg, + self.sa.sport, self.sa.dport, + self.sa.natt) + self.pg0.add_stream(packet) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + self.verify_del_sa(capture[0]) + + def create_packet(self, src_if, msg, sport=500, dport=500, natt=False): res = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / IP(src=src_if.remote_ip4, dst=src_if.local_ip4) / UDP(sport=sport, dport=dport)) @@ -552,15 +582,49 @@ def send_sa_init(self, behind_nat=False): load=src_nat) self.sa.init_req_packet = self.sa.init_req_packet / nat_detection - ike_msg = self.create_ike_msg(self.pg0, self.sa.init_req_packet, - self.sa.sport, self.sa.dport, - self.sa.natt) + ike_msg = self.create_packet(self.pg0, self.sa.init_req_packet, + self.sa.sport, self.sa.dport, + self.sa.natt) self.pg0.add_stream(ike_msg) self.pg0.enable_capture() self.pg_start() capture = self.pg0.get_capture(1) self.verify_sa_init(capture[0]) + def encrypt_ike_msg(self, header, plain, first_payload): + if self.sa.ike_crypto == 'AES-GCM-16ICV': + data = self.sa.ike_crypto_alg.pad(raw(plain)) + plen = len(data) + GCM_IV_SIZE + GCM_ICV_SIZE +\ + len(ikev2.IKEv2_payload_Encrypted()) + tlen = plen + len(ikev2.IKEv2()) + + # prepare aad data + sk_p = ikev2.IKEv2_payload_Encrypted(next_payload=first_payload, + length=plen) + header.length = tlen + res = header / sk_p + encr = self.sa.encrypt(raw(plain), raw(res)) + sk_p = ikev2.IKEv2_payload_Encrypted(next_payload=first_payload, + length=plen, load=encr) + res = header / sk_p + else: + encr = self.sa.encrypt(raw(plain)) + trunc_len = self.sa.ike_integ_alg.trunc_len + plen = len(encr) + len(ikev2.IKEv2_payload_Encrypted()) + trunc_len + tlen = plen + len(ikev2.IKEv2()) + + sk_p = ikev2.IKEv2_payload_Encrypted(next_payload=first_payload, + length=plen, load=encr) + header.length = tlen + res = header / sk_p + + integ_data = raw(res) + hmac_data = self.sa.compute_hmac(self.sa.ike_integ_alg.mod(), + self.sa.my_authkey, integ_data) + res = res / Raw(hmac_data[:trunc_len]) + assert(len(res) == tlen) + return res + def send_sa_auth(self): tr_attr = self.sa.esp_crypto_attr() trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', @@ -595,48 +659,14 @@ def send_sa_auth(self): traffic_selector=tsr) / ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT')) - if self.sa.ike_crypto == 'AES-GCM-16ICV': - data = self.sa.ike_crypto_alg.pad(raw(plain)) - plen = len(data) + GCM_IV_SIZE + GCM_ICV_SIZE +\ - len(ikev2.IKEv2_payload_Encrypted()) - tlen = plen + len(ikev2.IKEv2()) - - # prepare aad data - sk_p = ikev2.IKEv2_payload_Encrypted(next_payload='IDi', - length=plen) - sa_auth = (ikev2.IKEv2(init_SPI=self.sa.ispi, - resp_SPI=self.sa.rspi, id=1, - length=tlen, flags='Initiator', exch_type='IKE_AUTH')) - sa_auth /= sk_p + header = ikev2.IKEv2( + init_SPI=self.sa.ispi, + resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), + flags='Initiator', exch_type='IKE_AUTH') - encr = self.sa.encrypt(raw(plain), raw(sa_auth)) - sk_p = ikev2.IKEv2_payload_Encrypted(next_payload='IDi', - length=plen, load=encr) - sa_auth = (ikev2.IKEv2(init_SPI=self.sa.ispi, - resp_SPI=self.sa.rspi, id=1, - length=tlen, flags='Initiator', exch_type='IKE_AUTH')) - sa_auth /= sk_p - else: - encr = self.sa.encrypt(raw(plain)) - trunc_len = self.sa.ike_integ_alg.trunc_len - plen = len(encr) + len(ikev2.IKEv2_payload_Encrypted()) + trunc_len - tlen = plen + len(ikev2.IKEv2()) - - sk_p = ikev2.IKEv2_payload_Encrypted(next_payload='IDi', - length=plen, load=encr) - sa_auth = (ikev2.IKEv2(init_SPI=self.sa.ispi, - resp_SPI=self.sa.rspi, id=1, - length=tlen, flags='Initiator', exch_type='IKE_AUTH')) - sa_auth /= sk_p - - integ_data = raw(sa_auth) - hmac_data = self.sa.compute_hmac(self.sa.ike_integ_alg.mod(), - self.sa.my_authkey, integ_data) - sa_auth = sa_auth / Raw(hmac_data[:trunc_len]) - - assert(len(sa_auth) == tlen) - packet = self.create_ike_msg(self.pg0, sa_auth, self.sa.sport, - self.sa.dport, self.sa.natt) + ike_msg = self.encrypt_ike_msg(header, plain, 'IDi') + packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, + self.sa.dport, self.sa.natt) self.pg0.add_stream(packet) self.pg0.enable_capture() self.pg_start() @@ -656,6 +686,7 @@ def get_ike_header(self, packet): def verify_sa_init(self, packet): ih = self.get_ike_header(packet) + self.assertEqual(ih.id, self.sa.msg_id) self.assertEqual(ih.exch_type, 34) self.assertTrue('Response' in ih.flags) self.assertEqual(ih.init_SPI, self.sa.ispi) @@ -691,6 +722,7 @@ def verify_sa_auth(self, packet): ike = self.get_ike_header(packet) udp = packet[UDP] self.verify_udp(udp) + self.assertEqual(ike.id, self.sa.msg_id) plain = self.sa.hmac_and_decrypt(ike) self.sa.calc_child_keys() @@ -1123,5 +1155,43 @@ def config_tc(self): 'ike-dh': '2048MODPgr'}) +class TestMalformedMessages(TemplateResponder, Ikev2Params): + """ malformed packet test """ + + def tearDown(self): + pass + + def config_tc(self): + self.config_params() + + def assert_counter(self, count, name): + node_name = '/err/ikev2/' + name + self.assertEqual(count, self.statistics.get_err_counter(node_name)) + + def create_ike_init_msg(self, length=None, payload=None): + msg = ikev2.IKEv2(length=length, init_SPI='\x11' * 8, + flags='Initiator', exch_type='IKE_SA_INIT') + if payload is not None: + msg /= payload + return self.create_packet(self.pg0, msg, self.sa.sport, + self.sa.dport) + + def verify_bad_packet_length(self): + ike_msg = self.create_ike_init_msg(length=0xdead) + self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count) + self.assert_counter(self.pkt_count, 'Bad packet length') + + def verify_bad_sa_payload_length(self): + p = ikev2.IKEv2_payload_SA(length=0xdead) + ike_msg = self.create_ike_init_msg(payload=p) + self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count) + self.assert_counter(self.pkt_count, 'Malformed packet') + + def test_responder(self): + self.pkt_count = 254 + self.verify_bad_packet_length() + self.verify_bad_sa_payload_length() + + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/src/plugins/ikev2/test/vpp_ikev2.py b/src/plugins/ikev2/test/vpp_ikev2.py index 5a2a51eb6074..b3339d0ea86e 100644 --- a/src/plugins/ikev2/test/vpp_ikev2.py +++ b/src/plugins/ikev2/test/vpp_ikev2.py @@ -115,19 +115,19 @@ def add_vpp_config(self): **self.remote_id) if hasattr(self, 'local_ts'): self.vapi.ikev2_profile_set_ts(name=self.profile_name, - ts={**self.local_ts}) + ts=self.local_ts) if hasattr(self, 'remote_ts'): self.vapi.ikev2_profile_set_ts(name=self.profile_name, - ts={**self.remote_ts}) + ts=self.remote_ts) if hasattr(self, 'responder'): self.vapi.ikev2_set_responder(name=self.profile_name, - responder={**self.responder}) + responder=self.responder) if hasattr(self, 'ike_transforms'): self.vapi.ikev2_set_ike_transforms(name=self.profile_name, - tr={**self.ike_transforms}) + tr=self.ike_transforms) if hasattr(self, 'esp_transforms'): self.vapi.ikev2_set_esp_transforms(name=self.profile_name, diff --git a/test/patches/scapy-2.4.3/ikev2.patch b/test/patches/scapy-2.4.3/ikev2.patch new file mode 100644 index 000000000000..be143e8b8c9d --- /dev/null +++ b/test/patches/scapy-2.4.3/ikev2.patch @@ -0,0 +1,24 @@ +diff --git a/scapy/contrib/ikev2.py b/scapy/contrib/ikev2.py +index 60b20480..a071ffc7 100644 +--- a/scapy/contrib/ikev2.py ++++ b/scapy/contrib/ikev2.py +@@ -608,13 +608,16 @@ class IKEv2_payload_TSr(IKEv2_class): + + + class IKEv2_payload_Delete(IKEv2_class): +- name = "IKEv2 Vendor ID" ++ name = "IKEv2 delete payload" + overload_fields = {IKEv2: {"next_payload": 42}} + fields_desc = [ + ByteEnumField("next_payload", None, IKEv2_payload_type), + ByteField("res", 0), +- FieldLenField("length", None, "vendorID", "H", adjust=lambda pkt, x:x + 4), # noqa: E501 +- StrLenField("vendorID", "", length_from=lambda x:x.length - 4), ++ FieldLenField("length", None, "SPIs", "H", adjust=lambda pkt, x:x + 8), # noqa: E501 ++ ByteEnumField("proto", 1, {1: "IKEv2", 2: "AH", 3: "ESP"}), ++ ByteField("SPIsize", 0), ++ ShortField("SPInum", 0), ++ StrLenField("SPIs", "", length_from=lambda x: x.length - 8), + ] + + From 0b685565c18b3d16bfebae2dcee33d551395d387 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Sat, 26 Sep 2020 16:47:13 +0000 Subject: [PATCH 097/129] ikev2: refactor ikev2 node Type: refactor Change-Id: I65acbd5d9724c500a24699de973df08016d9d8d6 Signed-off-by: Filip Tehlar (cherry picked from commit 3434cb8fe379791050a85617775bb518cdd0eb5d) --- src/plugins/ikev2/ikev2.c | 766 ++++++++++++++++++-------------------- 1 file changed, 359 insertions(+), 407 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 5c48e02685e2..bc37b7e00355 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1840,11 +1840,11 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) static int ikev2_create_tunnel_interface (vlib_main_t * vm, - u32 thread_index, ikev2_sa_t * sa, ikev2_child_sa_t * child, u32 sa_index, u32 child_index, u8 is_rekey) { + u32 thread_index = vlib_get_thread_index (); ikev2_main_t *km = &ikev2_main; ipsec_crypto_alg_t encr_type; ipsec_integ_alg_t integ_type; @@ -2662,264 +2662,117 @@ static uword ikev2_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - u32 n_left_from, *from, *to_next; - ikev2_next_t next_index; + u32 n_left = frame->n_vectors, *from; ikev2_main_t *km = &ikev2_main; - u32 thread_index = vlib_get_thread_index (); + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + u16 nexts[VLIB_FRAME_SIZE], *next = nexts; + ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); int res; from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) + vlib_get_buffers (vm, from, bufs, n_left); + b = bufs; + + while (n_left > 0) + { + vlib_buffer_t *b0 = b[0]; + next[0] = IKEV2_NEXT_ERROR_DROP; + ip4_header_t *ip40; + udp_header_t *udp0; + ike_header_t *ike0; + ikev2_sa_t *sa0 = 0; + ikev2_sa_t sa; /* temporary store for SA */ + u32 rlen, slen = 0; + int is_req = 0, has_non_esp_marker = 0; + + if (b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = IKEV2_NEXT_ERROR_DROP; - ip4_header_t *ip40; - udp_header_t *udp0; - ike_header_t *ike0; - ikev2_sa_t *sa0 = 0; - ikev2_sa_t sa; /* temporary store for SA */ - u32 rlen, slen = 0; - int is_req = 0, has_non_esp_marker = 0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - if (b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) - { - u8 *ptr = vlib_buffer_get_current (b0); - ip40 = (ip4_header_t *) ptr; - ptr += sizeof (*ip40); - udp0 = (udp_header_t *) ptr; - ptr += sizeof (*udp0); - ike0 = (ike_header_t *) ptr; - } - else - { - ike0 = vlib_buffer_get_current (b0); - vlib_buffer_advance (b0, -sizeof (*udp0)); - udp0 = vlib_buffer_get_current (b0); - vlib_buffer_advance (b0, -sizeof (*ip40)); - ip40 = vlib_buffer_get_current (b0); - } - - rlen = b0->current_length - sizeof (*ip40) - sizeof (*udp0); - - /* check for non-esp marker */ - if (*((u32 *) ike0) == 0) - { - ike0 = - (ike_header_t *) ((u8 *) ike0 + - sizeof (ikev2_non_esp_marker)); - rlen -= sizeof (ikev2_non_esp_marker); - has_non_esp_marker = 1; - } - - if (clib_net_to_host_u32 (ike0->length) != rlen) - { - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_BAD_LENGTH, 1); - goto dispatch0; - } - - if (ike0->version != IKE_VERSION_2) - { - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_NOT_IKEV2, 1); - goto dispatch0; - } - - if (ike0->exchange == IKEV2_EXCHANGE_SA_INIT) - { - sa0 = &sa; - clib_memset (sa0, 0, sizeof (*sa0)); - - if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR) - { - if (ike0->rspi == 0) - { - sa0->raddr.as_u32 = ip40->dst_address.as_u32; - sa0->iaddr.as_u32 = ip40->src_address.as_u32; - sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); - - slen = - ikev2_retransmit_sa_init (ike0, sa0->iaddr, - sa0->raddr, rlen); - if (slen) - { - vlib_node_increment_counter (vm, ikev2_node.index, - ~0 == - slen ? - IKEV2_ERROR_IKE_SA_INIT_IGNORE - : - IKEV2_ERROR_IKE_SA_INIT_RETRANSMIT, - 1); - goto dispatch0; - } + u8 *ptr = vlib_buffer_get_current (b0); + ip40 = (ip4_header_t *) ptr; + ptr += sizeof (*ip40); + udp0 = (udp_header_t *) ptr; + ptr += sizeof (*udp0); + ike0 = (ike_header_t *) ptr; + } + else + { + ike0 = vlib_buffer_get_current (b0); + vlib_buffer_advance (b0, -sizeof (*udp0)); + udp0 = vlib_buffer_get_current (b0); + vlib_buffer_advance (b0, -sizeof (*ip40)); + ip40 = vlib_buffer_get_current (b0); + } - res = ikev2_process_sa_init_req (vm, sa0, - ike0, udp0, rlen); - if (!res) - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_MALFORMED_PACKET, - 1); + rlen = b0->current_length - sizeof (*ip40) - sizeof (*udp0); - if (sa0->state == IKEV2_STATE_SA_INIT) - { - ikev2_sa_free_proposal_vector (&sa0->r_proposals); - sa0->r_proposals = - ikev2_select_proposal (sa0->i_proposals, - IKEV2_PROTOCOL_IKE); - ikev2_generate_sa_init_data (sa0); - } + /* check for non-esp marker */ + if (*((u32 *) ike0) == 0) + { + ike0 = + (ike_header_t *) ((u8 *) ike0 + sizeof (ikev2_non_esp_marker)); + rlen -= sizeof (ikev2_non_esp_marker); + has_non_esp_marker = 1; + } - if (sa0->state == IKEV2_STATE_SA_INIT - || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE) - { - slen = - ikev2_generate_message (b0, sa0, ike0, 0, udp0); - if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_NO_BUFF_SPACE, - 1); - } + if (clib_net_to_host_u32 (ike0->length) != rlen) + { + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_BAD_LENGTH, 1); + goto dispatch0; + } - if (sa0->state == IKEV2_STATE_SA_INIT) - { - /* add SA to the pool */ - pool_get (km->per_thread_data[thread_index].sas, - sa0); - clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); - ikev2_init_sa (vm, sa0); - hash_set (km-> - per_thread_data[thread_index].sa_by_rspi, - sa0->rspi, - sa0 - - km->per_thread_data[thread_index].sas); - } - else - { - ikev2_sa_free_all_vec (sa0); - } - } - } - else //received sa_init without initiator flag - { - sa0->raddr.as_u32 = ip40->src_address.as_u32; - sa0->iaddr.as_u32 = ip40->dst_address.as_u32; - ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen); + if (ike0->version != IKE_VERSION_2) + { + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NOT_IKEV2, 1); + goto dispatch0; + } - if (sa0->state == IKEV2_STATE_SA_INIT) - { - is_req = 1; - ike0->exchange = IKEV2_EXCHANGE_IKE_AUTH; - uword *p = hash_get (km->sa_by_ispi, sa0->ispi); - if (p) - { - ikev2_sa_t *sai = - pool_elt_at_index (km->sais, p[0]); - - if (clib_atomic_bool_cmp_and_swap - (&sai->init_response_received, 0, 1)) - { - ikev2_complete_sa_data (sa0, sai); - ikev2_calc_keys (sa0); - ikev2_sa_auth_init (sa0); - slen = - ikev2_generate_message (b0, sa0, ike0, 0, - udp0); - if (~0 == slen) - vlib_node_increment_counter (vm, - ikev2_node.index, - IKEV2_ERROR_NO_BUFF_SPACE, - 1); - } - else - { - /* we've already processed sa-init response */ - sa0->state = IKEV2_STATE_UNKNOWN; - } - } - } + if (ike0->exchange == IKEV2_EXCHANGE_SA_INIT) + { + sa0 = &sa; + clib_memset (sa0, 0, sizeof (*sa0)); - if (sa0->state == IKEV2_STATE_SA_INIT) - { - /* add SA to the pool */ - pool_get (km->per_thread_data[thread_index].sas, sa0); - clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); - hash_set (km->per_thread_data[thread_index].sa_by_rspi, - sa0->rspi, - sa0 - km->per_thread_data[thread_index].sas); - } - else - { - ikev2_sa_free_all_vec (sa0); - } - } - } - else if (ike0->exchange == IKEV2_EXCHANGE_IKE_AUTH) + if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR) { - uword *p; - p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, - clib_net_to_host_u64 (ike0->rspi)); - if (p) + if (ike0->rspi == 0) { - sa0 = - pool_elt_at_index (km->per_thread_data[thread_index].sas, - p[0]); + sa0->raddr.as_u32 = ip40->dst_address.as_u32; + sa0->iaddr.as_u32 = ip40->src_address.as_u32; + sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); - slen = ikev2_retransmit_resp (sa0, ike0); + slen = + ikev2_retransmit_sa_init (ike0, sa0->iaddr, + sa0->raddr, rlen); if (slen) { vlib_node_increment_counter (vm, ikev2_node.index, ~0 == slen ? - IKEV2_ERROR_IKE_REQ_IGNORE + IKEV2_ERROR_IKE_SA_INIT_IGNORE : - IKEV2_ERROR_IKE_REQ_RETRANSMIT, + IKEV2_ERROR_IKE_SA_INIT_RETRANSMIT, 1); goto dispatch0; } - sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); - res = ikev2_process_auth_req (vm, sa0, ike0, rlen); - if (res) - ikev2_sa_auth (sa0); - else + res = ikev2_process_sa_init_req (vm, sa0, ike0, udp0, rlen); + if (!res) vlib_node_increment_counter (vm, ikev2_node.index, IKEV2_ERROR_MALFORMED_PACKET, 1); - if (sa0->state == IKEV2_STATE_AUTHENTICATED) - { - ikev2_initial_contact_cleanup (sa0); - ikev2_sa_match_ts (sa0); - if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE) - ikev2_create_tunnel_interface (vm, thread_index, sa0, - &sa0->childs[0], - p[0], 0, 0); - } - if (sa0->is_initiator) + if (sa0->state == IKEV2_STATE_SA_INIT) { - ikev2_del_sa_init (sa0->ispi); + ikev2_sa_free_proposal_vector (&sa0->r_proposals); + sa0->r_proposals = + ikev2_select_proposal (sa0->i_proposals, + IKEV2_PROTOCOL_IKE); + ikev2_generate_sa_init_data (sa0); } - else + + if (sa0->state == IKEV2_STATE_SA_INIT + || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE) { slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) @@ -2927,237 +2780,336 @@ ikev2_node_fn (vlib_main_t * vm, IKEV2_ERROR_NO_BUFF_SPACE, 1); } - } - } - else if (ike0->exchange == IKEV2_EXCHANGE_INFORMATIONAL) - { - uword *p; - p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, - clib_net_to_host_u64 (ike0->rspi)); - if (p) - { - sa0 = - pool_elt_at_index (km->per_thread_data[thread_index].sas, - p[0]); - - slen = ikev2_retransmit_resp (sa0, ike0); - if (slen) - { - vlib_node_increment_counter (vm, ikev2_node.index, - ~0 == - slen ? - IKEV2_ERROR_IKE_REQ_IGNORE - : - IKEV2_ERROR_IKE_REQ_RETRANSMIT, - 1); - goto dispatch0; - } - res = ikev2_process_informational_req (vm, sa0, ike0, rlen); - if (!res) - { - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_MALFORMED_PACKET, - 1); - slen = ~0; - goto dispatch0; - } - - if (sa0->del) + if (sa0->state == IKEV2_STATE_SA_INIT) { - if (sa0->del[0].protocol_id != IKEV2_PROTOCOL_IKE) - { - ikev2_delete_t *d, *tmp, *resp = 0; - vec_foreach (d, sa0->del) - { - ikev2_child_sa_t *ch_sa; - ch_sa = ikev2_sa_get_child (sa0, d->spi, - d->protocol_id, - !sa0->is_initiator); - if (ch_sa) - { - ikev2_delete_tunnel_interface (km->vnet_main, - sa0, ch_sa); - if (!sa0->is_initiator) - { - vec_add2 (resp, tmp, 1); - tmp->protocol_id = d->protocol_id; - tmp->spi = ch_sa->r_proposals[0].spi; - } - ikev2_sa_del_child_sa (sa0, ch_sa); - } - } - if (!sa0->is_initiator) - { - vec_free (sa0->del); - sa0->del = resp; - } - } + /* add SA to the pool */ + pool_get (ptd->sas, sa0); + clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); + ikev2_init_sa (vm, sa0); + hash_set (ptd->sa_by_rspi, sa0->rspi, sa0 - ptd->sas); } - if (!(ike0->flags & IKEV2_HDR_FLAG_RESPONSE)) + else { - ike0->flags |= IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); - if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_NO_BUFF_SPACE, - 1); + ikev2_sa_free_all_vec (sa0); } } } - else if (ike0->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) + else //received sa_init without initiator flag { - uword *p; - p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, - clib_net_to_host_u64 (ike0->rspi)); - if (p) - { - sa0 = - pool_elt_at_index (km->per_thread_data[thread_index].sas, - p[0]); + sa0->raddr.as_u32 = ip40->src_address.as_u32; + sa0->iaddr.as_u32 = ip40->dst_address.as_u32; + ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen); - slen = ikev2_retransmit_resp (sa0, ike0); - if (slen) - { - vlib_node_increment_counter (vm, ikev2_node.index, - ~0 == - slen ? - IKEV2_ERROR_IKE_REQ_IGNORE - : - IKEV2_ERROR_IKE_REQ_RETRANSMIT, - 1); - goto dispatch0; - } - - res = ikev2_process_create_child_sa_req (vm, sa0, - ike0, rlen); - if (!res) + if (sa0->state == IKEV2_STATE_SA_INIT) + { + is_req = 1; + ike0->exchange = IKEV2_EXCHANGE_IKE_AUTH; + uword *p = hash_get (km->sa_by_ispi, sa0->ispi); + if (p) { - vlib_node_increment_counter (vm, ikev2_node.index, - IKEV2_ERROR_MALFORMED_PACKET, - 1); - slen = ~0; - goto dispatch0; - } + ikev2_sa_t *sai = pool_elt_at_index (km->sais, p[0]); - if (sa0->rekey) - { - if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE) - { - if (sa0->childs) - ikev2_sa_free_all_child_sa (&sa0->childs); - ikev2_child_sa_t *child; - vec_add2 (sa0->childs, child, 1); - clib_memset (child, 0, sizeof (*child)); - child->r_proposals = sa0->rekey[0].r_proposal; - child->i_proposals = sa0->rekey[0].i_proposal; - child->tsi = sa0->rekey[0].tsi; - child->tsr = sa0->rekey[0].tsr; - ikev2_create_tunnel_interface (vm, thread_index, - sa0, child, p[0], - child - sa0->childs, - 1); - } - if (sa0->is_initiator) - { - vec_free (sa0->rekey); - } - else + if (clib_atomic_bool_cmp_and_swap + (&sai->init_response_received, 0, 1)) { + ikev2_complete_sa_data (sa0, sai); + ikev2_calc_keys (sa0); + ikev2_sa_auth_init (sa0); slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, + ikev2_node.index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } + else + { + /* we've already processed sa-init response */ + sa0->state = IKEV2_STATE_UNKNOWN; + } } } + + if (sa0->state == IKEV2_STATE_SA_INIT) + { + /* add SA to the pool */ + pool_get (ptd->sas, sa0); + clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); + hash_set (ptd->sa_by_rspi, sa0->rspi, sa0 - ptd->sas); + } + else + { + ikev2_sa_free_all_vec (sa0); + } } - else + } + else if (ike0->exchange == IKEV2_EXCHANGE_IKE_AUTH) + { + uword *p; + p = hash_get (ptd->sa_by_rspi, clib_net_to_host_u64 (ike0->rspi)); + if (p) { - ikev2_elog_uint_peers (IKEV2_LOG_WARNING, "IKEv2 exchange %d " - "received from %d.%d.%d.%d to %d.%d.%d.%d", - ike0->exchange, - ip40->src_address.as_u32, - ip40->dst_address.as_u32); - } + sa0 = pool_elt_at_index (ptd->sas, p[0]); + slen = ikev2_retransmit_resp (sa0, ike0); + if (slen) + { + vlib_node_increment_counter (vm, ikev2_node.index, + ~0 == + slen ? + IKEV2_ERROR_IKE_REQ_IGNORE + : + IKEV2_ERROR_IKE_REQ_RETRANSMIT, + 1); + goto dispatch0; + } + + sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); + res = ikev2_process_auth_req (vm, sa0, ike0, rlen); + if (res) + ikev2_sa_auth (sa0); + else + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, 1); + if (sa0->state == IKEV2_STATE_AUTHENTICATED) + { + ikev2_initial_contact_cleanup (sa0); + ikev2_sa_match_ts (sa0); + if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE) + ikev2_create_tunnel_interface (vm, sa0, + &sa0->childs[0], + p[0], 0, 0); + } - dispatch0: - /* if we are sending packet back, rewrite headers */ - if (slen && ~0 != slen) - { - next0 = IKEV2_NEXT_IP4_LOOKUP; if (sa0->is_initiator) { - ip40->dst_address.as_u32 = sa0->raddr.as_u32; - ip40->src_address.as_u32 = sa0->iaddr.as_u32; + ikev2_del_sa_init (sa0->ispi); } else { - ip40->dst_address.as_u32 = sa0->iaddr.as_u32; - ip40->src_address.as_u32 = sa0->raddr.as_u32; + slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); + } + } + } + else if (ike0->exchange == IKEV2_EXCHANGE_INFORMATIONAL) + { + uword *p; + p = hash_get (ptd->sa_by_rspi, clib_net_to_host_u64 (ike0->rspi)); + if (p) + { + sa0 = pool_elt_at_index (ptd->sas, p[0]); + slen = ikev2_retransmit_resp (sa0, ike0); + if (slen) + { + vlib_node_increment_counter (vm, ikev2_node.index, + ~0 == + slen ? + IKEV2_ERROR_IKE_REQ_IGNORE + : + IKEV2_ERROR_IKE_REQ_RETRANSMIT, + 1); + goto dispatch0; } - if (is_req) + res = ikev2_process_informational_req (vm, sa0, ike0, rlen); + if (!res) { - udp0->dst_port = udp0->src_port = - clib_net_to_host_u16 (ikev2_get_port (sa0)); + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, + 1); + slen = ~0; + goto dispatch0; + } - if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT) - && sa0->natt) + if (sa0->del) + { + if (sa0->del[0].protocol_id != IKEV2_PROTOCOL_IKE) { - if (!has_non_esp_marker) - slen = ikev2_insert_non_esp_marker (ike0, slen); + ikev2_delete_t *d, *tmp, *resp = 0; + vec_foreach (d, sa0->del) + { + ikev2_child_sa_t *ch_sa; + ch_sa = ikev2_sa_get_child (sa0, d->spi, + d->protocol_id, + !sa0->is_initiator); + if (ch_sa) + { + ikev2_delete_tunnel_interface (km->vnet_main, + sa0, ch_sa); + if (!sa0->is_initiator) + { + vec_add2 (resp, tmp, 1); + tmp->protocol_id = d->protocol_id; + tmp->spi = ch_sa->r_proposals[0].spi; + } + ikev2_sa_del_child_sa (sa0, ch_sa); + } + } + if (!sa0->is_initiator) + { + vec_free (sa0->del); + sa0->del = resp; + } } } - else + if (!(ike0->flags & IKEV2_HDR_FLAG_RESPONSE)) { - if (has_non_esp_marker) - slen += sizeof (ikev2_non_esp_marker); + ike0->flags |= IKEV2_HDR_FLAG_RESPONSE; + slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); + } + } + } + else if (ike0->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) + { + uword *p; + p = hash_get (ptd->sa_by_rspi, clib_net_to_host_u64 (ike0->rspi)); + if (p) + { + sa0 = pool_elt_at_index (ptd->sas, p[0]); + slen = ikev2_retransmit_resp (sa0, ike0); + if (slen) + { + vlib_node_increment_counter (vm, ikev2_node.index, + ~0 == + slen ? + IKEV2_ERROR_IKE_REQ_IGNORE + : + IKEV2_ERROR_IKE_REQ_RETRANSMIT, + 1); + goto dispatch0; + } - u16 tp = udp0->dst_port; - udp0->dst_port = udp0->src_port; - udp0->src_port = tp; + res = ikev2_process_create_child_sa_req (vm, sa0, ike0, rlen); + if (!res) + { + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_MALFORMED_PACKET, + 1); + slen = ~0; + goto dispatch0; } - udp0->length = - clib_host_to_net_u16 (slen + sizeof (udp_header_t)); - udp0->checksum = 0; - b0->current_length = - slen + sizeof (ip4_header_t) + sizeof (udp_header_t); - ip40->length = clib_host_to_net_u16 (b0->current_length); - ip40->checksum = ip4_header_checksum (ip40); + if (sa0->rekey) + { + if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE) + { + if (sa0->childs) + ikev2_sa_free_all_child_sa (&sa0->childs); + ikev2_child_sa_t *child; + vec_add2 (sa0->childs, child, 1); + clib_memset (child, 0, sizeof (*child)); + child->r_proposals = sa0->rekey[0].r_proposal; + child->i_proposals = sa0->rekey[0].i_proposal; + child->tsi = sa0->rekey[0].tsi; + child->tsr = sa0->rekey[0].tsr; + ikev2_create_tunnel_interface (vm, sa0, child, p[0], + child - sa0->childs, 1); + } + if (sa0->is_initiator) + { + vec_free (sa0->rekey); + } + else + { + slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + if (~0 == slen) + vlib_node_increment_counter (vm, ikev2_node.index, + IKEV2_ERROR_NO_BUFF_SPACE, + 1); + } + } + } + } + else + { + ikev2_elog_uint_peers (IKEV2_LOG_WARNING, "IKEv2 exchange %d " + "received from %d.%d.%d.%d to %d.%d.%d.%d", + ike0->exchange, + ip40->src_address.as_u32, + ip40->dst_address.as_u32); + } + + dispatch0: + /* if we are sending packet back, rewrite headers */ + if (slen && ~0 != slen) + { + next[0] = IKEV2_NEXT_IP4_LOOKUP; + if (sa0->is_initiator) + { + ip40->dst_address.as_u32 = sa0->raddr.as_u32; + ip40->src_address.as_u32 = sa0->iaddr.as_u32; } - /* delete sa */ - if (sa0 && (sa0->state == IKEV2_STATE_DELETED || - sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)) + else { - ikev2_child_sa_t *c; + ip40->dst_address.as_u32 = sa0->iaddr.as_u32; + ip40->src_address.as_u32 = sa0->raddr.as_u32; + } - vec_foreach (c, sa0->childs) - ikev2_delete_tunnel_interface (km->vnet_main, sa0, c); + if (is_req) + { + udp0->dst_port = udp0->src_port = + clib_net_to_host_u16 (ikev2_get_port (sa0)); - ikev2_delete_sa (sa0); + if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT) + && sa0->natt) + { + if (!has_non_esp_marker) + slen = ikev2_insert_non_esp_marker (ike0, slen); + } } - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) + else { + if (has_non_esp_marker) + slen += sizeof (ikev2_non_esp_marker); - ikev2_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->next_index = next0; + u16 tp = udp0->dst_port; + udp0->dst_port = udp0->src_port; + udp0->src_port = tp; } - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); + udp0->length = clib_host_to_net_u16 (slen + sizeof (udp_header_t)); + udp0->checksum = 0; + b0->current_length = + slen + sizeof (ip4_header_t) + sizeof (udp_header_t); + ip40->length = clib_host_to_net_u16 (b0->current_length); + ip40->checksum = ip4_header_checksum (ip40); } + /* delete sa */ + if (sa0 && (sa0->state == IKEV2_STATE_DELETED || + sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)) + { + ikev2_child_sa_t *c; - vlib_put_next_frame (vm, node, next_index, n_left_to_next); + vec_foreach (c, sa0->childs) + ikev2_delete_tunnel_interface (km->vnet_main, sa0, c); + + ikev2_delete_sa (sa0); + } + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + + ikev2_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->next_index = next[0]; + } + n_left -= 1; + next += 1; + b += 1; } vlib_node_increment_counter (vm, ikev2_node.index, IKEV2_ERROR_PROCESSED, frame->n_vectors); + vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); return frame->n_vectors; } @@ -3176,7 +3128,7 @@ VLIB_REGISTER_NODE (ikev2_node,static) = { .next_nodes = { [IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup", - [IKEV2_NEXT_ERROR_DROP] = "error-drop", + [IKEV2_NEXT_ERROR_DROP] = "error-drop", }, }; /* *INDENT-ON* */ From 469181845b735f01f94e2c25e1868570bcd55f0c Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 8 Sep 2020 06:08:05 +0000 Subject: [PATCH 098/129] ikev2: support ipv6 traffic selectors & overlay Ticket: VPP-1917 Type: feature Change-Id: Ie9f22e7336aa7807b1967c48de9843df10fb575c Signed-off-by: Filip Tehlar (cherry picked from commit 84962d19ba76eafd5c7658aa86ec61c9b81f7702) --- src/plugins/ikev2/ikev2.api | 2 +- src/plugins/ikev2/ikev2.c | 528 ++++++++++++++++++--------- src/plugins/ikev2/ikev2.h | 12 +- src/plugins/ikev2/ikev2_api.c | 22 +- src/plugins/ikev2/ikev2_cli.c | 62 ++-- src/plugins/ikev2/ikev2_payload.c | 114 ++++-- src/plugins/ikev2/ikev2_priv.h | 50 +-- src/plugins/ikev2/ikev2_test.c | 78 ++-- src/plugins/ikev2/ikev2_types.api | 10 +- src/plugins/ikev2/test/test_ikev2.py | 184 +++++++--- src/plugins/ikev2/test/vpp_ikev2.py | 13 +- 11 files changed, 695 insertions(+), 380 deletions(-) diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api index 1e1dbf9589df..a7aeff1fa441 100644 --- a/src/plugins/ikev2/ikev2.api +++ b/src/plugins/ikev2/ikev2.api @@ -264,7 +264,7 @@ autoreply define ikev2_profile_set_ts string name[64]; vl_api_ikev2_ts_t ts; - option vat_help = "name protocol start_port end_port start_addr end_addr (local|remote)"; + option vat_help = "name protocol start_port end_port start_addr end_addr (local|remote)"; option status="in_progress"; }; diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index bc37b7e00355..a266853760fd 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -62,8 +62,6 @@ format_ikev2_trace (u8 * s, va_list * args) return s; } -static vlib_node_registration_t ikev2_node; - #define foreach_ikev2_error \ _(PROCESSED, "IKEv2 packets processed") \ _(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \ @@ -92,9 +90,16 @@ static char *ikev2_error_strings[] = { typedef enum { IKEV2_NEXT_IP4_LOOKUP, - IKEV2_NEXT_ERROR_DROP, - IKEV2_N_NEXT, -} ikev2_next_t; + IKEV2_NEXT_IP4_ERROR_DROP, + IKEV2_IP4_N_NEXT, +} ikev2_ip4_next_t; + +typedef enum +{ + IKEV2_NEXT_IP6_LOOKUP, + IKEV2_NEXT_IP6_ERROR_DROP, + IKEV2_IP6_N_NEXT, +} ikev2_ip6_next_t; typedef u32 ikev2_non_esp_marker; @@ -263,7 +268,7 @@ ikev2_sa_free_proposal_vector (ikev2_sa_proposal_t ** v) vec_free (p->transforms); } vec_free (*v); -}; +} static void ikev2_sa_free_child_sa (ikev2_child_sa_t * c) @@ -417,8 +422,8 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) sa->i_nonce = _(sai->i_nonce); sa->i_dh_data = _(sai->i_dh_data); sa->dh_private_key = _(sai->dh_private_key); - sa->iaddr.as_u32 = sai->iaddr.as_u32; - sa->raddr.as_u32 = sai->raddr.as_u32; + ip_address_copy (&sa->iaddr, &sai->iaddr); + ip_address_copy (&sa->raddr, &sai->raddr); sa->is_initiator = sai->is_initiator; sa->i_id.type = sai->i_id.type; sa->r_id.type = sai->r_id.type; @@ -627,16 +632,17 @@ ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) } static_always_inline u8 * -ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, u32 ip, u16 port) +ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t * ia, u16 port) { - /* ispi, rspi, ip, port */ - u8 buf[8 + 8 + 4 + 2]; + const u32 max_buf_size = + sizeof (ispi) + sizeof (rspi) + sizeof (ip6_address_t) + sizeof (u16); + u8 buf[max_buf_size]; u8 *res = vec_new (u8, 20); clib_memcpy_fast (&buf[0], &ispi, sizeof (ispi)); clib_memcpy_fast (&buf[8], &rspi, sizeof (rspi)); - clib_memcpy_fast (&buf[8 + 8], &ip, sizeof (ip)); - clib_memcpy_fast (&buf[8 + 8 + 4], &port, sizeof (port)); + clib_memcpy_fast (&buf[8 + 8], ip_addr_bytes (ia), ip_address_size (ia)); + clib_memcpy_fast (&buf[8 + 8 + ip_address_size (ia)], &port, sizeof (port)); SHA1 (buf, sizeof (buf), res); return res; } @@ -691,9 +697,10 @@ ikev2_process_sa_init_req (vlib_main_t * vm, u16 plen; ikev2_elog_exchange ("ispi %lx rspi %lx IKE_INIT request received " - "from %d.%d.%d.%d", - clib_net_to_host_u64 (ike->ispi), - clib_net_to_host_u64 (ike->rspi), sa->iaddr.as_u32); + "from ", clib_net_to_host_u64 (ike->ispi), + clib_net_to_host_u64 (ike->rspi), + ip_addr_v4 (&sa->iaddr).as_u32, + ip_addr_version (&sa->iaddr) == AF_IP4); sa->ispi = clib_net_to_host_u64 (ike->ispi); @@ -735,8 +742,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_parse_notify_payload (ikep, current_length); if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP) { - u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, - sa->iaddr.as_u32, + u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, &sa->iaddr, udp->src_port); if (clib_memcmp (src_sha, n->data, vec_len (src_sha))) { @@ -749,8 +755,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm, else if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP) { - u8 *dst_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, - sa->raddr.as_u32, + u8 *dst_sha = ikev2_compute_nat_sha1 (ike->ispi, 0, &sa->raddr, udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { @@ -801,8 +806,9 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, sa->rspi = clib_net_to_host_u64 (ike->rspi); ikev2_elog_exchange ("ispi %lx rspi %lx IKE_INIT response received " - "from %d.%d.%d.%d", sa->ispi, sa->rspi, - sa->raddr.as_u32); + "from ", sa->ispi, sa->rspi, + ip_addr_v4 (&sa->raddr).as_u32, + ip_addr_version (&sa->raddr) == AF_IP4); /* store whole IKE payload - needed for PSK auth */ vec_reset_length (sa->last_sa_init_res_packet_data); @@ -848,9 +854,8 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_parse_notify_payload (ikep, current_length); if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP) { - u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, - ike->rspi, - sa->raddr.as_u32, + u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, ike->rspi, + &sa->raddr, udp->src_port); if (clib_memcmp (src_sha, n->data, vec_len (src_sha))) { @@ -862,9 +867,8 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, else if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP) { - u8 *dst_sha = ikev2_compute_nat_sha1 (ike->ispi, - ike->rspi, - sa->iaddr.as_u32, + u8 *dst_sha = ikev2_compute_nat_sha1 (ike->ispi, ike->rspi, + &sa->iaddr, udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { @@ -1100,10 +1104,12 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, u32 dlen = 0; ikev2_elog_exchange ("ispi %lx rspi %lx EXCHANGE_IKE_AUTH received " - "from %d.%d.%d.%d", clib_host_to_net_u64 (ike->ispi), + "from ", clib_host_to_net_u64 (ike->ispi), clib_host_to_net_u64 (ike->rspi), - sa->is_initiator ? sa->raddr.as_u32 : sa-> - iaddr.as_u32); + sa->is_initiator ? + ip_addr_v4 (&sa->raddr).as_u32 : + ip_addr_v4 (&sa->iaddr).as_u32, + ip_addr_version (&sa->raddr) == AF_IP4); ikev2_calc_keys (sa); @@ -1240,8 +1246,10 @@ ikev2_process_informational_req (vlib_main_t * vm, sa->liveness_retries = 0; ikev2_elog_exchange ("ispi %lx rspi %lx INFORMATIONAL received " - "from %d.%d.%d.%d", clib_host_to_net_u64 (ike->ispi), - clib_host_to_net_u64 (ike->rspi), sa->iaddr.as_u32); + "from ", clib_host_to_net_u64 (ike->ispi), + clib_host_to_net_u64 (ike->rspi), + ip_addr_v4 (&sa->iaddr).as_u32, + ip_addr_version (&sa->iaddr) == AF_IP4); plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len, &dlen); @@ -1316,8 +1324,10 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, u16 plen; ikev2_elog_exchange ("ispi %lx rspi %lx CREATE_CHILD_SA received " - "from %d.%d.%d.%d", clib_host_to_net_u64 (ike->ispi), - clib_host_to_net_u64 (ike->rspi), sa->raddr.as_u32); + "from ", clib_host_to_net_u64 (ike->ispi), + clib_host_to_net_u64 (ike->rspi), + ip_addr_v4 (&sa->raddr).as_u32, + ip_addr_version (&sa->raddr) == AF_IP4); plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len, &dlen); @@ -1479,8 +1489,8 @@ ikev2_ts_cmp (ikev2_ts_t * ts1, ikev2_ts_t * ts2) { if (ts1->ts_type == ts2->ts_type && ts1->protocol_id == ts2->protocol_id && ts1->start_port == ts2->start_port && ts1->end_port == ts2->end_port && - ts1->start_addr.as_u32 == ts2->start_addr.as_u32 && - ts1->end_addr.as_u32 == ts2->end_addr.as_u32) + !ip_address_cmp (&ts1->start_addr, &ts2->start_addr) && + !ip_address_cmp (&ts1->end_addr, &ts2->end_addr)) return 1; return 0; @@ -1777,6 +1787,7 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) ikev2_main_t *km = &ikev2_main; u32 sw_if_index; int rv = 0; + ip46_address_t zero_addr = ip46_address_initializer; if (~0 == a->sw_if_index) { @@ -1802,9 +1813,9 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) if (rv) { - ikev2_elog_peers (IKEV2_LOG_ERROR, "installing ipip tunnel failed! " - "loc:%d.%d.%d.%d rem:%d.%d.%d.%d", - a->local_ip.ip4.as_u32, a->remote_ip.ip4.as_u32); + ikev2_elog_uint (IKEV2_LOG_ERROR, + "installing ipip tunnel failed! local spi: %x", + a->local_spi); return; } @@ -1825,14 +1836,14 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) a->local_spi, IPSEC_PROTOCOL_ESP, a->encr_type, &a->loc_ckey, a->integ_type, &a->loc_ikey, - a->flags, 0, a->salt_local, &a->local_ip, - &a->remote_ip, NULL, a->src_port, a->dst_port); + a->flags, 0, a->salt_local, &zero_addr, + &zero_addr, NULL, a->src_port, a->dst_port); rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi, IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey, a->integ_type, &a->rem_ikey, (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0, - a->salt_remote, &a->remote_ip, - &a->local_ip, NULL, a->ipsec_over_udp_port, + a->salt_remote, &zero_addr, + &zero_addr, NULL, a->ipsec_over_udp_port, a->ipsec_over_udp_port); rv |= ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in); @@ -1864,16 +1875,16 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, if (sa->is_initiator) { - ip46_address_set_ip4 (&a.local_ip, &sa->iaddr); - ip46_address_set_ip4 (&a.remote_ip, &sa->raddr); + ip_address_to_46 (&sa->iaddr, &a.local_ip); + ip_address_to_46 (&sa->raddr, &a.remote_ip); proposals = child->r_proposals; a.local_spi = child->r_proposals[0].spi; a.remote_spi = child->i_proposals[0].spi; } else { - ip46_address_set_ip4 (&a.local_ip, &sa->raddr); - ip46_address_set_ip4 (&a.remote_ip, &sa->iaddr); + ip_address_to_46 (&sa->raddr, &a.local_ip); + ip_address_to_46 (&sa->iaddr, &a.remote_ip); proposals = child->i_proposals; a.local_spi = child->i_proposals[0].spi; a.remote_spi = child->r_proposals[0].spi; @@ -2153,13 +2164,13 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, if (sa->is_initiator) { - ip46_address_set_ip4 (&a.local_ip, &sa->iaddr); - ip46_address_set_ip4 (&a.remote_ip, &sa->raddr); + ip_address_to_46 (&sa->iaddr, &a.local_ip); + ip_address_to_46 (&sa->raddr, &a.remote_ip); } else { - ip46_address_set_ip4 (&a.local_ip, &sa->raddr); - ip46_address_set_ip4 (&a.remote_ip, &sa->iaddr); + ip_address_to_46 (&sa->raddr, &a.local_ip); + ip_address_to_46 (&sa->iaddr, &a.remote_ip); } a.remote_sa_id = child->remote_sa_id; @@ -2239,8 +2250,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), clib_host_to_net_u64 (sa->rspi), - sa->raddr.as_u32, - udp->dst_port); + &sa->raddr, udp->dst_port); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP, nat_detection_sha1); @@ -2248,7 +2258,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), clib_host_to_net_u64 (sa->rspi), - sa->iaddr.as_u32, udp->src_port); + &sa->iaddr, udp->src_port); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP, nat_detection_sha1); @@ -2518,18 +2528,17 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, } static u32 -ikev2_retransmit_sa_init (ike_header_t * ike, ip4_address_t iaddr, - ip4_address_t raddr, u32 rlen) +ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr, + ip_address_t raddr, u32 rlen) { - ikev2_main_t *km = &ikev2_main; ikev2_sa_t *sa; - u32 thread_index = vlib_get_thread_index (); + ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); /* *INDENT-OFF* */ - pool_foreach (sa, km->per_thread_data[thread_index].sas, ({ + pool_foreach (sa, ptd->sas, ({ if (sa->ispi == clib_net_to_host_u64(ike->ispi) && - sa->iaddr.as_u32 == iaddr.as_u32 && - sa->raddr.as_u32 == raddr.as_u32) + !ip_address_cmp(&sa->iaddr, &iaddr) && + !ip_address_cmp(&sa->raddr, &raddr)) { int p = 0; u8 payload = ike->nextpayload; @@ -2566,7 +2575,8 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip4_address_t iaddr, "ispi %lx IKE_SA_INIT retransmit " "from %d.%d.%d.%d to %d.%d.%d.%d", ike->ispi, - raddr.as_u32, iaddr.as_u32); + ip_addr_v4(&raddr).as_u32, + ip_addr_v4 (&iaddr).as_u32); return slen; } /* else ignore req */ @@ -2576,7 +2586,8 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip4_address_t iaddr, "ispi %lx IKE_SA_INIT ignore " "from %d.%d.%d.%d to %d.%d.%d.%d", ike->ispi, - raddr.as_u32, iaddr.as_u32); + ip_addr_v4(&raddr).as_u32, + ip_addr_v4(&iaddr).as_u32); return ~0; } } @@ -2619,13 +2630,15 @@ ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike) ike->length = tmp->length; clib_memcpy_fast (ike->payload, tmp->payload, slen - sizeof (*ike)); ikev2_elog_uint_peers (IKEV2_LOG_DEBUG, "IKE retransmit msgid %d", - msg_id, sa->raddr.as_u32, sa->iaddr.as_u32); + msg_id, ip_addr_v4 (&sa->raddr).as_u32, + ip_addr_v4 (&sa->iaddr).as_u32); return slen; } /* old req ignore */ ikev2_elog_uint_peers (IKEV2_LOG_DEBUG, "IKE req ignore msgid %d", - msg_id, sa->raddr.as_u32, sa->iaddr.as_u32); + msg_id, ip_addr_v4 (&sa->raddr).as_u32, + ip_addr_v4 (&sa->iaddr).as_u32); return ~0; } @@ -2658,9 +2671,50 @@ ikev2_del_sa_init (u64 ispi) sizeof (ispi)); } -static uword -ikev2_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +static_always_inline void +ikev2_rewrite_v6_addrs (ikev2_sa_t * sa, ip6_header_t * ih) +{ + if (sa->is_initiator) + { + ip_address_copy_addr (&ih->dst_address, &sa->raddr); + ip_address_copy_addr (&ih->src_address, &sa->iaddr); + } + else + { + ip_address_copy_addr (&ih->dst_address, &sa->iaddr); + ip_address_copy_addr (&ih->src_address, &sa->raddr); + } +} + +static_always_inline void +ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih) +{ + if (sa->is_initiator) + { + ip_address_copy_addr (&ih->dst_address, &sa->raddr); + ip_address_copy_addr (&ih->src_address, &sa->iaddr); + } + else + { + ip_address_copy_addr (&ih->dst_address, &sa->iaddr); + ip_address_copy_addr (&ih->src_address, &sa->raddr); + } +} + +static_always_inline void +ikev2_set_ip_address (ikev2_sa_t * sa, const void *src, + const void *dst, const int af, const int is_initiator) +{ + const void *raddr = is_initiator ? src : dst; + const void *iaddr = is_initiator ? dst : src; + ip_address_set (&sa->raddr, raddr, af); + ip_address_set (&sa->iaddr, iaddr, af); +} + +static_always_inline uword +ikev2_node_internal (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + u8 is_ip4) { u32 n_left = frame->n_vectors, *from; ikev2_main_t *km = &ikev2_main; @@ -2676,13 +2730,16 @@ ikev2_node_fn (vlib_main_t * vm, while (n_left > 0) { vlib_buffer_t *b0 = b[0]; - next[0] = IKEV2_NEXT_ERROR_DROP; - ip4_header_t *ip40; + next[0] = is_ip4 ? IKEV2_NEXT_IP4_ERROR_DROP + : IKEV2_NEXT_IP6_ERROR_DROP; + ip4_header_t *ip40 = 0; + ip6_header_t *ip60 = 0; udp_header_t *udp0; ike_header_t *ike0; ikev2_sa_t *sa0 = 0; ikev2_sa_t sa; /* temporary store for SA */ u32 rlen, slen = 0; + int ip_hdr_sz = 0; int is_req = 0, has_non_esp_marker = 0; if (b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) @@ -2693,17 +2750,29 @@ ikev2_node_fn (vlib_main_t * vm, udp0 = (udp_header_t *) ptr; ptr += sizeof (*udp0); ike0 = (ike_header_t *) ptr; + ip_hdr_sz = sizeof (*ip40); } else { + u8 *ipx_hdr = b0->data + vnet_buffer (b0)->l3_hdr_offset; ike0 = vlib_buffer_get_current (b0); vlib_buffer_advance (b0, -sizeof (*udp0)); udp0 = vlib_buffer_get_current (b0); - vlib_buffer_advance (b0, -sizeof (*ip40)); - ip40 = vlib_buffer_get_current (b0); + + if (is_ip4) + { + ip40 = (ip4_header_t *) ipx_hdr; + ip_hdr_sz = sizeof (*ip40); + } + else + { + ip60 = (ip6_header_t *) ipx_hdr; + ip_hdr_sz = sizeof (*ip60); + } + vlib_buffer_advance (b0, -ip_hdr_sz); } - rlen = b0->current_length - sizeof (*ip40) - sizeof (*udp0); + rlen = b0->current_length - ip_hdr_sz - sizeof (*udp0); /* check for non-esp marker */ if (*((u32 *) ike0) == 0) @@ -2716,14 +2785,14 @@ ikev2_node_fn (vlib_main_t * vm, if (clib_net_to_host_u32 (ike0->length) != rlen) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_BAD_LENGTH, 1); goto dispatch0; } if (ike0->version != IKE_VERSION_2) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NOT_IKEV2, 1); goto dispatch0; } @@ -2733,12 +2802,20 @@ ikev2_node_fn (vlib_main_t * vm, sa0 = &sa; clib_memset (sa0, 0, sizeof (*sa0)); - if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR) + u8 is_initiator = ike0->flags & IKEV2_HDR_FLAG_INITIATOR; + if (is_initiator) { if (ike0->rspi == 0) { - sa0->raddr.as_u32 = ip40->dst_address.as_u32; - sa0->iaddr.as_u32 = ip40->src_address.as_u32; + if (is_ip4) + ikev2_set_ip_address (sa0, &ip40->dst_address, + &ip40->src_address, AF_IP4, + is_initiator); + else + ikev2_set_ip_address (sa0, &ip60->dst_address, + &ip60->src_address, AF_IP6, + is_initiator); + sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); slen = @@ -2746,7 +2823,7 @@ ikev2_node_fn (vlib_main_t * vm, sa0->raddr, rlen); if (slen) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, ~0 == slen ? IKEV2_ERROR_IKE_SA_INIT_IGNORE @@ -2758,7 +2835,7 @@ ikev2_node_fn (vlib_main_t * vm, res = ikev2_process_sa_init_req (vm, sa0, ike0, udp0, rlen); if (!res) - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, 1); @@ -2776,7 +2853,7 @@ ikev2_node_fn (vlib_main_t * vm, { slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } @@ -2797,8 +2874,15 @@ ikev2_node_fn (vlib_main_t * vm, } else //received sa_init without initiator flag { - sa0->raddr.as_u32 = ip40->src_address.as_u32; - sa0->iaddr.as_u32 = ip40->dst_address.as_u32; + if (is_ip4) + ikev2_set_ip_address (sa0, &ip40->src_address, + &ip40->dst_address, AF_IP4, + is_initiator); + else + ikev2_set_ip_address (sa0, &ip60->src_address, + &ip60->dst_address, AF_IP6, + is_initiator); + ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen); if (sa0->state == IKEV2_STATE_SA_INIT) @@ -2820,7 +2904,7 @@ ikev2_node_fn (vlib_main_t * vm, ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, - ikev2_node.index, + node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } @@ -2855,7 +2939,7 @@ ikev2_node_fn (vlib_main_t * vm, slen = ikev2_retransmit_resp (sa0, ike0); if (slen) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, ~0 == slen ? IKEV2_ERROR_IKE_REQ_IGNORE @@ -2870,7 +2954,7 @@ ikev2_node_fn (vlib_main_t * vm, if (res) ikev2_sa_auth (sa0); else - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, 1); if (sa0->state == IKEV2_STATE_AUTHENTICATED) { @@ -2890,7 +2974,7 @@ ikev2_node_fn (vlib_main_t * vm, { slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } @@ -2906,7 +2990,7 @@ ikev2_node_fn (vlib_main_t * vm, slen = ikev2_retransmit_resp (sa0, ike0); if (slen) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, ~0 == slen ? IKEV2_ERROR_IKE_REQ_IGNORE @@ -2919,7 +3003,7 @@ ikev2_node_fn (vlib_main_t * vm, res = ikev2_process_informational_req (vm, sa0, ike0, rlen); if (!res) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, 1); slen = ~0; @@ -2962,7 +3046,7 @@ ikev2_node_fn (vlib_main_t * vm, ike0->flags |= IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } @@ -2978,7 +3062,7 @@ ikev2_node_fn (vlib_main_t * vm, slen = ikev2_retransmit_resp (sa0, ike0); if (slen) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, ~0 == slen ? IKEV2_ERROR_IKE_REQ_IGNORE @@ -2991,7 +3075,7 @@ ikev2_node_fn (vlib_main_t * vm, res = ikev2_process_create_child_sa_req (vm, sa0, ike0, rlen); if (!res) { - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, 1); slen = ~0; @@ -3022,7 +3106,7 @@ ikev2_node_fn (vlib_main_t * vm, { slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } @@ -3042,16 +3126,15 @@ ikev2_node_fn (vlib_main_t * vm, /* if we are sending packet back, rewrite headers */ if (slen && ~0 != slen) { - next[0] = IKEV2_NEXT_IP4_LOOKUP; - if (sa0->is_initiator) + if (is_ip4) { - ip40->dst_address.as_u32 = sa0->raddr.as_u32; - ip40->src_address.as_u32 = sa0->iaddr.as_u32; + next[0] = IKEV2_NEXT_IP4_LOOKUP; + ikev2_rewrite_v4_addrs (sa0, ip40); } else { - ip40->dst_address.as_u32 = sa0->iaddr.as_u32; - ip40->src_address.as_u32 = sa0->raddr.as_u32; + next[0] = IKEV2_NEXT_IP6_LOOKUP; + ikev2_rewrite_v6_addrs (sa0, ip60); } if (is_req) @@ -3078,10 +3161,17 @@ ikev2_node_fn (vlib_main_t * vm, udp0->length = clib_host_to_net_u16 (slen + sizeof (udp_header_t)); udp0->checksum = 0; - b0->current_length = - slen + sizeof (ip4_header_t) + sizeof (udp_header_t); - ip40->length = clib_host_to_net_u16 (b0->current_length); - ip40->checksum = ip4_header_checksum (ip40); + b0->current_length = slen + ip_hdr_sz + sizeof (udp_header_t); + if (is_ip4) + { + ip40->length = clib_host_to_net_u16 (b0->current_length); + ip40->checksum = ip4_header_checksum (ip40); + } + else + { + ip60->payload_length = + clib_host_to_net_u16 (b0->current_length - sizeof (*ip60)); + } } /* delete sa */ if (sa0 && (sa0->state == IKEV2_STATE_DELETED || @@ -3107,16 +3197,28 @@ ikev2_node_fn (vlib_main_t * vm, b += 1; } - vlib_node_increment_counter (vm, ikev2_node.index, + vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_PROCESSED, frame->n_vectors); vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); return frame->n_vectors; } +static uword +ikev2_ip4 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */ ); +} + +static uword +ikev2_ip6 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return ikev2_node_internal (vm, node, frame, 0 /* is_ip4 */ ); +} + /* *INDENT-OFF* */ -VLIB_REGISTER_NODE (ikev2_node,static) = { - .function = ikev2_node_fn, - .name = "ikev2", +VLIB_REGISTER_NODE (ikev2_node_ip4,static) = { + .function = ikev2_ip4, + .name = "ikev2-ip4", .vector_size = sizeof (u32), .format_trace = format_ikev2_trace, .type = VLIB_NODE_TYPE_INTERNAL, @@ -3124,11 +3226,27 @@ VLIB_REGISTER_NODE (ikev2_node,static) = { .n_errors = ARRAY_LEN(ikev2_error_strings), .error_strings = ikev2_error_strings, - .n_next_nodes = IKEV2_N_NEXT, - + .n_next_nodes = IKEV2_IP4_N_NEXT, .next_nodes = { [IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup", - [IKEV2_NEXT_ERROR_DROP] = "error-drop", + [IKEV2_NEXT_IP4_ERROR_DROP] = "error-drop", + }, +}; + +VLIB_REGISTER_NODE (ikev2_node_ip6,static) = { + .function = ikev2_ip6, + .name = "ikev2-ip6", + .vector_size = sizeof (u32), + .format_trace = format_ikev2_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(ikev2_error_strings), + .error_strings = ikev2_error_strings, + + .n_next_nodes = IKEV2_IP6_N_NEXT, + .next_nodes = { + [IKEV2_NEXT_IP6_LOOKUP] = "ip6-lookup", + [IKEV2_NEXT_IP6_ERROR_DROP] = "error-drop", }, }; /* *INDENT-ON* */ @@ -3276,10 +3394,11 @@ ikev2_profile_index_by_name (u8 * name) static void -ikev2_send_ike (vlib_main_t * vm, ip4_address_t * src, ip4_address_t * dst, +ikev2_send_ike (vlib_main_t * vm, ip_address_t * src, ip_address_t * dst, u32 bi0, u32 len, u16 src_port, u16 dst_port, u32 sw_if_index) { ip4_header_t *ip40; + ip6_header_t *ip60; udp_header_t *udp0; vlib_buffer_t *b0; vlib_frame_t *f; @@ -3288,35 +3407,59 @@ ikev2_send_ike (vlib_main_t * vm, ip4_address_t * src, ip4_address_t * dst, b0 = vlib_get_buffer (vm, bi0); vlib_buffer_advance (b0, -sizeof (udp_header_t)); udp0 = vlib_buffer_get_current (b0); - vlib_buffer_advance (b0, -sizeof (ip4_header_t)); - ip40 = vlib_buffer_get_current (b0); - - - ip40->ip_version_and_header_length = 0x45; - ip40->tos = 0; - ip40->fragment_id = 0; - ip40->flags_and_fragment_offset = 0; - ip40->ttl = 0xff; - ip40->protocol = IP_PROTOCOL_UDP; - ip40->dst_address.as_u32 = dst->as_u32; - ip40->src_address.as_u32 = src->as_u32; udp0->dst_port = clib_host_to_net_u16 (dst_port); udp0->src_port = clib_host_to_net_u16 (src_port); udp0->length = clib_host_to_net_u16 (len + sizeof (udp_header_t)); udp0->checksum = 0; - b0->current_length = len + sizeof (ip4_header_t) + sizeof (udp_header_t); - ip40->length = clib_host_to_net_u16 (b0->current_length); - ip40->checksum = ip4_header_checksum (ip40); + if (ip_addr_version (dst) == AF_IP4) + { + vlib_buffer_advance (b0, -sizeof (ip4_header_t)); + ip40 = vlib_buffer_get_current (b0); + ip40->ip_version_and_header_length = 0x45; + ip40->tos = 0; + ip40->fragment_id = 0; + ip40->flags_and_fragment_offset = 0; + ip40->ttl = 0xff; + ip40->protocol = IP_PROTOCOL_UDP; + ip40->dst_address.as_u32 = ip_addr_v4 (dst).as_u32; + ip40->src_address.as_u32 = ip_addr_v4 (src).as_u32; + b0->current_length = + len + sizeof (ip4_header_t) + sizeof (udp_header_t); + ip40->length = clib_host_to_net_u16 (b0->current_length); + ip40->checksum = ip4_header_checksum (ip40); + } + else + { + vlib_buffer_advance (b0, -sizeof (ip6_header_t)); + ip60 = vlib_buffer_get_current (b0); + + b0->current_length = len + sizeof (*ip60) + sizeof (udp_header_t); + ip60->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (0x6 << 28); + ip60->payload_length = + clib_host_to_net_u16 (b0->current_length - sizeof (*ip60)); + ip60->protocol = IP_PROTOCOL_UDP; + ip60->hop_limit = 0xff; + clib_memcpy_fast (ip60->src_address.as_u8, ip_addr_v6 (src).as_u8, + sizeof (ip60->src_address)); + clib_memcpy_fast (ip60->dst_address.as_u8, ip_addr_v6 (dst).as_u8, + sizeof (ip60->src_address)); + } + + b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; vnet_buffer (b0)->sw_if_index[VLIB_RX] = sw_if_index; vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + u32 next_index = (ip_addr_version (dst) == AF_IP4) ? + ip4_lookup_node.index : ip6_lookup_node.index; + /* send the request */ - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); + f = vlib_get_frame_to_node (vm, next_index); to_next = vlib_frame_vector_args (f); to_next[0] = bi0; f->n_vectors = 1; - vlib_put_frame_to_node (vm, ip4_lookup_node.index, f); + vlib_put_frame_to_node (vm, next_index, f); } @@ -3405,7 +3548,7 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa) { ikev2_main_t *km = &ikev2_main; - ip4_address_t *src, *dst; + ip_address_t *src, *dst; vlib_buffer_t *b0; /* Create the Initiator notification for IKE SA removal */ @@ -3591,6 +3734,15 @@ ikev2_set_profile_auth (vlib_main_t * vm, u8 * name, u8 auth_method, return 0; } +static int +ikev2_is_id_supported (u8 id_type) +{ + return (id_type == IKEV2_ID_TYPE_ID_IPV4_ADDR || + id_type == IKEV2_ID_TYPE_ID_IPV6_ADDR || + id_type == IKEV2_ID_TYPE_ID_RFC822_ADDR || + id_type == IKEV2_ID_TYPE_ID_FQDN); +} + clib_error_t * ikev2_set_profile_id (vlib_main_t * vm, u8 * name, u8 id_type, u8 * data, int is_local) @@ -3598,8 +3750,7 @@ ikev2_set_profile_id (vlib_main_t * vm, u8 * name, u8 id_type, u8 * data, ikev2_profile_t *p; clib_error_t *r; - if (id_type > IKEV2_ID_TYPE_ID_RFC822_ADDR - && id_type < IKEV2_ID_TYPE_ID_KEY_ID) + if (!ikev2_is_id_supported (id_type)) { r = clib_error_return (0, "unsupported identity type %U", format_ikev2_id_type, id_type); @@ -3630,10 +3781,27 @@ ikev2_set_profile_id (vlib_main_t * vm, u8 * name, u8 id_type, u8 * data, return 0; } +static_always_inline void +ikev2_set_ts_type (ikev2_ts_t * ts, const ip_address_t * addr) +{ + if (ip_addr_version (addr) == AF_IP4) + ts->ts_type = TS_IPV4_ADDR_RANGE; + else + ts->ts_type = TS_IPV6_ADDR_RANGE; +} + +static_always_inline void +ikev2_set_ts_addrs (ikev2_ts_t * ts, const ip_address_t * start, + const ip_address_t * end) +{ + ip_address_copy (&ts->start_addr, start); + ip_address_copy (&ts->end_addr, end); +} + clib_error_t * ikev2_set_profile_ts (vlib_main_t * vm, u8 * name, u8 protocol_id, - u16 start_port, u16 end_port, ip4_address_t start_addr, - ip4_address_t end_addr, int is_local) + u16 start_port, u16 end_port, ip_address_t start_addr, + ip_address_t end_addr, int is_local) { ikev2_profile_t *p; clib_error_t *r; @@ -3646,23 +3814,24 @@ ikev2_set_profile_ts (vlib_main_t * vm, u8 * name, u8 protocol_id, return r; } + if (ip_addr_version (&start_addr) != ip_addr_version (&end_addr)) + return clib_error_return (0, "IP address version mismatch!"); + if (is_local) { - p->loc_ts.start_addr.as_u32 = start_addr.as_u32; - p->loc_ts.end_addr.as_u32 = end_addr.as_u32; + ikev2_set_ts_addrs (&p->loc_ts, &start_addr, &end_addr); p->loc_ts.start_port = start_port; p->loc_ts.end_port = end_port; p->loc_ts.protocol_id = protocol_id; - p->loc_ts.ts_type = 7; + ikev2_set_ts_type (&p->loc_ts, &start_addr); } else { - p->rem_ts.start_addr.as_u32 = start_addr.as_u32; - p->rem_ts.end_addr.as_u32 = end_addr.as_u32; + ikev2_set_ts_addrs (&p->rem_ts, &start_addr, &end_addr); p->rem_ts.start_port = start_port; p->rem_ts.end_port = end_port; p->rem_ts.protocol_id = protocol_id; - p->rem_ts.ts_type = 7; + ikev2_set_ts_type (&p->rem_ts, &start_addr); } return 0; @@ -3671,7 +3840,7 @@ ikev2_set_profile_ts (vlib_main_t * vm, u8 * name, u8 protocol_id, clib_error_t * ikev2_set_profile_responder (vlib_main_t * vm, u8 * name, - u32 sw_if_index, ip4_address_t ip4) + u32 sw_if_index, ip_address_t addr) { ikev2_profile_t *p; clib_error_t *r; @@ -3685,7 +3854,7 @@ ikev2_set_profile_responder (vlib_main_t * vm, u8 * name, } p->responder.sw_if_index = sw_if_index; - p->responder.ip4 = ip4; + ip_address_copy (&p->responder.addr, &addr); return 0; } @@ -3835,7 +4004,6 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) { ikev2_profile_t *p; clib_error_t *r; - ip4_main_t *im = &ip4_main; ikev2_main_t *km = &ikev2_main; p = ikev2_profile_index_by_name (name); @@ -3846,7 +4014,8 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) return r; } - if (p->responder.sw_if_index == ~0 || p->responder.ip4.data_u32 == 0) + if (p->responder.sw_if_index == ~0 + || ip_address_is_zero (&p->responder.addr)) { r = clib_error_return (0, "responder not set for profile %v", name); return r; @@ -3858,16 +4027,29 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) vlib_buffer_t *b0; ike_header_t *ike0; u32 bi0 = 0; - ip_lookup_main_t *lm = &im->lookup_main; - u32 if_add_index0; int len = sizeof (ike_header_t); + ip4_address_t *if_ip4; + ip6_address_t *if_ip6; + ip_address_t if_ip = IP_ADDRESS_V4_ALL_0S; - /* Get own iface IP */ - if_add_index0 = - lm->if_address_pool_index_by_sw_if_index[p->responder.sw_if_index]; - ip_interface_address_t *if_add = - pool_elt_at_index (lm->if_address_pool, if_add_index0); - ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add); + if (ip_addr_version (&p->responder.addr) == AF_IP4) + { + if_ip4 = ip4_interface_first_address (&ip4_main, + p->responder.sw_if_index, 0); + if (if_ip4) + { + ip_address_set (&if_ip, if_ip4, AF_IP4); + } + } + else + { + if_ip6 = ip6_interface_first_address (&ip6_main, + p->responder.sw_if_index); + if (if_ip6) + { + ip_address_set (&if_ip, if_ip6, AF_IP6); + } + } bi0 = ikev2_get_new_ike_header_buff (vm, &b0); if (!bi0) @@ -3920,8 +4102,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), clib_host_to_net_u64 (sa.rspi), - if_ip->as_u32, - clib_host_to_net_u16 (IKEV2_PORT)); + &if_ip, clib_host_to_net_u16 (IKEV2_PORT)); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP, nat_detection_sha1); @@ -3929,7 +4110,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) nat_detection_sha1 = ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), clib_host_to_net_u64 (sa.rspi), - p->responder.ip4.as_u32, + &p->responder.addr, clib_host_to_net_u16 (sa.dst_port)); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP, @@ -3964,8 +4145,8 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) vec_add (sa.last_sa_init_req_packet_data, ike0, len); /* add data to the SA then add it to the pool */ - sa.iaddr.as_u32 = if_ip->as_u32; - sa.raddr.as_u32 = p->responder.ip4.as_u32; + ip_address_copy (&sa.iaddr, &if_ip); + ip_address_copy (&sa.raddr, &p->responder.addr); sa.i_id.type = p->loc_id.type; sa.i_id.data = vec_dup (p->loc_id.data); sa.r_id.type = p->rem_id.type; @@ -3985,12 +4166,13 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); hash_set (km->sa_by_ispi, sa0->ispi, sa0 - km->sais); - ikev2_send_ike (vm, if_ip, &p->responder.ip4, bi0, len, + ikev2_send_ike (vm, &if_ip, &p->responder.addr, bi0, len, IKEV2_PORT, sa.dst_port, sa.sw_if_index); - ikev2_elog_exchange ("ispi %lx rspi %lx IKEV2_EXCHANGE_SA_INIT sent to " - "%d.%d.%d.%d", clib_host_to_net_u64 (sa0->ispi), 0, - p->responder.ip4.as_u32); + ikev2_elog_exchange ("ispi %lx rspi %lx IKEV2_EXCHANGE_SA_INIT sent to ", + clib_host_to_net_u64 (sa0->ispi), 0, + ip_addr_v4 (&p->responder.addr).as_u32, + ip_addr_version (&p->responder.addr) == AF_IP4); } return 0; @@ -4240,12 +4422,14 @@ ikev2_init (vlib_main_t * vm) km->sw_if_indices = hash_create (0, 0); km->udp_ports = hash_create (0, sizeof (uword)); - udp_register_dst_port (vm, IKEV2_PORT, ikev2_node.index, 1); - udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node.index, 1); + udp_register_dst_port (vm, IKEV2_PORT, ikev2_node_ip4.index, 1); + udp_register_dst_port (vm, IKEV2_PORT, ikev2_node_ip6.index, 0); + udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip4.index, 1); + udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip6.index, 0); - vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("ikev2"); + vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("ikev2-ip4"); vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0], - "ikev2"); + "ikev2-ip4"); ikev2_cli_reference (); km->log_level = IKEV2_LOG_ERROR; @@ -4316,13 +4500,17 @@ ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa, ip46_address_t remote_ip; if (sa->is_initiator) { - ip46_address_set_ip4 (&local_ip, &sa->iaddr); - ip46_address_set_ip4 (&remote_ip, &sa->raddr); + local_ip = to_ip46 (ip_addr_version (&sa->iaddr), + ip_addr_bytes (&sa->iaddr)); + remote_ip = to_ip46 (ip_addr_version (&sa->raddr), + ip_addr_bytes (&sa->raddr)); } else { - ip46_address_set_ip4 (&local_ip, &sa->raddr); - ip46_address_set_ip4 (&remote_ip, &sa->iaddr); + local_ip = to_ip46 (ip_addr_version (&sa->raddr), + ip_addr_bytes (&sa->raddr)); + remote_ip = to_ip46 (ip_addr_version (&sa->iaddr), + ip_addr_bytes (&sa->iaddr)); } /* *INDENT-OFF* */ @@ -4460,7 +4648,7 @@ static void ikev2_send_informational_request (ikev2_sa_t * sa) { ikev2_main_t *km = &ikev2_main; - ip4_address_t *src, *dst; + ip_address_t *src, *dst; ike_header_t *ike0; vlib_buffer_t *b0; u32 bi0 = 0; diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h index 36ac85a39c52..47c301f33a1f 100644 --- a/src/plugins/ikev2/ikev2.h +++ b/src/plugins/ikev2/ikev2.h @@ -369,6 +369,12 @@ typedef enum #undef _ } ikev2_id_type_t; +typedef enum +{ + TS_IPV4_ADDR_RANGE = 7, + TS_IPV6_ADDR_RANGE = 8, +} ikev2_traffic_selector_type_t; + clib_error_t *ikev2_init (vlib_main_t * vm); clib_error_t *ikev2_set_local_key (vlib_main_t * vm, u8 * file); clib_error_t *ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add); @@ -379,11 +385,11 @@ clib_error_t *ikev2_set_profile_id (vlib_main_t * vm, u8 * name, u8 id_type, u8 * data, int is_local); clib_error_t *ikev2_set_profile_ts (vlib_main_t * vm, u8 * name, u8 protocol_id, u16 start_port, - u16 end_port, ip4_address_t start_addr, - ip4_address_t end_addr, int is_local); + u16 end_port, ip_address_t start_addr, + ip_address_t end_addr, int is_local); clib_error_t *ikev2_set_profile_responder (vlib_main_t * vm, u8 * name, u32 sw_if_index, - ip4_address_t ip4); + ip_address_t addr); clib_error_t *ikev2_set_profile_ike_transforms (vlib_main_t * vm, u8 * name, ikev2_transform_encr_type_t crypto_alg, diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c index c73505b2421c..33ff0853832c 100644 --- a/src/plugins/ikev2/ikev2_api.c +++ b/src/plugins/ikev2/ikev2_api.c @@ -98,8 +98,8 @@ cp_ts (vl_api_ikev2_ts_t * vl_api_ts, ikev2_ts_t * ts, u8 is_local) vl_api_ts->protocol_id = ts->protocol_id; vl_api_ts->start_port = ts->start_port; vl_api_ts->end_port = ts->end_port; - ip4_address_encode (&ts->start_addr, vl_api_ts->start_addr); - ip4_address_encode (&ts->end_addr, vl_api_ts->end_addr); + ip_address_encode2 (&ts->start_addr, &vl_api_ts->start_addr); + ip_address_encode2 (&ts->end_addr, &vl_api_ts->end_addr); } static void @@ -116,7 +116,7 @@ cp_responder (vl_api_ikev2_responder_t * vl_api_responder, ikev2_responder_t * responder) { vl_api_responder->sw_if_index = responder->sw_if_index; - ip4_address_encode (&responder->ip4, vl_api_responder->ip4); + ip_address_encode2 (&responder->addr, &vl_api_responder->addr); } void @@ -208,8 +208,8 @@ send_sa (ikev2_sa_t * sa, vl_api_ikev2_sa_dump_t * mp, u32 api_sa_index) vl_api_ikev2_keys_t* k = &rsa->keys; rsa->profile_index = rsa->profile_index; rsa->sa_index = api_sa_index; - ip4_address_encode (&sa->iaddr, rsa->iaddr); - ip4_address_encode (&sa->raddr, rsa->raddr); + ip_address_encode2 (&sa->iaddr, &rsa->iaddr); + ip_address_encode2 (&sa->raddr, &rsa->raddr); rsa->ispi = sa->ispi; rsa->rspi = sa->rspi; cp_id(&rsa->i_id, &sa->i_id); @@ -593,9 +593,9 @@ vl_api_ikev2_profile_set_ts_t_handler (vl_api_ikev2_profile_set_ts_t * mp) vlib_main_t *vm = vlib_get_main (); clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); - ip4_address_t start_addr, end_addr; - ip4_address_decode (mp->ts.start_addr, &start_addr); - ip4_address_decode (mp->ts.end_addr, &end_addr); + ip_address_t start_addr, end_addr; + ip_address_decode2 (&mp->ts.start_addr, &start_addr); + ip_address_decode2 (&mp->ts.end_addr, &end_addr); error = ikev2_set_profile_ts (vm, tmp, mp->ts.protocol_id, clib_net_to_host_u16 (mp->ts.start_port), @@ -642,11 +642,11 @@ vl_api_ikev2_set_responder_t_handler (vl_api_ikev2_set_responder_t * mp) clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); - ip4_address_t ip4; - ip4_address_decode (mp->responder.ip4, &ip4); + ip_address_t ip; + ip_address_decode2 (&mp->responder.addr, &ip); u32 sw_if_index = clib_net_to_host_u32 (mp->responder.sw_if_index); - error = ikev2_set_profile_responder (vm, tmp, sw_if_index, ip4); + error = ikev2_set_profile_responder (vm, tmp, sw_if_index, ip); vec_free (tmp); if (error) rv = VNET_API_ERROR_UNSPECIFIED; diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index 727e34736277..c948578eb230 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -55,8 +55,8 @@ format_ikev2_traffic_selector (u8 * s, va_list * va) s = format (s, "%u type %u protocol_id %u addr " "%U - %U port %u - %u\n", index, ts->ts_type, ts->protocol_id, - format_ip4_address, &ts->start_addr, - format_ip4_address, &ts->end_addr, + format_ip_address, &ts->start_addr, + format_ip_address, &ts->end_addr, clib_net_to_host_u16 (ts->start_port), clib_net_to_host_u16 (ts->end_port)); return s; @@ -127,8 +127,8 @@ format_ikev2_sa (u8 * s, va_list * va) u32 indent = 1; s = format (s, "iip %U ispi %lx rip %U rspi %lx", - format_ip4_address, &sa->iaddr, sa->ispi, - format_ip4_address, &sa->raddr, sa->rspi); + format_ip_address, &sa->iaddr, sa->ispi, + format_ip_address, &sa->raddr, sa->rspi); if (!details) return s; @@ -279,11 +279,9 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, u8 *data = 0; u32 tmp1, tmp2, tmp3; u64 tmp4, tmp5; - ip4_address_t ip4; - ip4_address_t end_addr; + ip_address_t ip, end_addr; u32 responder_sw_if_index = (u32) ~ 0; u32 tun_sw_if_index = (u32) ~ 0; - ip4_address_t responder_ip4; ikev2_transform_encr_type_t crypto_alg; ikev2_transform_integ_type_t integ_alg; ikev2_transform_dh_type_t dh_type; @@ -333,10 +331,10 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "set %U id local %U %U", unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, - unformat_ip4_address, &ip4)) + unformat_ip_address, &ip)) { - data = vec_new (u8, 4); - clib_memcpy (data, ip4.as_u8, 4); + data = vec_new (u8, ip_address_size (&ip)); + clib_memcpy (data, ip_addr_bytes (&ip), ip_address_size (&ip)); r = ikev2_set_profile_id (vm, name, (u8) id_type, data, /*local */ 1); goto done; @@ -361,10 +359,10 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "set %U id remote %U %U", unformat_ikev2_token, &name, unformat_ikev2_id_type, &id_type, - unformat_ip4_address, &ip4)) + unformat_ip_address, &ip)) { - data = vec_new (u8, 4); - clib_memcpy (data, ip4.as_u8, 4); + data = vec_new (u8, ip_address_size (&ip)); + clib_memcpy (data, ip_addr_bytes (&ip), ip_address_size (&ip)); r = ikev2_set_profile_id (vm, name, (u8) id_type, data, /*remote */ 0); goto done; @@ -389,36 +387,32 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "set %U traffic-selector local " "ip-range %U - %U port-range %u - %u protocol %u", unformat_ikev2_token, &name, - unformat_ip4_address, &ip4, - unformat_ip4_address, &end_addr, - &tmp1, &tmp2, &tmp3)) + unformat_ip_address, &ip, + unformat_ip_address, &end_addr, &tmp1, &tmp2, &tmp3)) { r = ikev2_set_profile_ts (vm, name, (u8) tmp3, (u16) tmp1, (u16) tmp2, - ip4, end_addr, /*local */ 1); + ip, end_addr, /*local */ 1); goto done; } else if (unformat (line_input, "set %U traffic-selector remote " "ip-range %U - %U port-range %u - %u protocol %u", unformat_ikev2_token, &name, - unformat_ip4_address, &ip4, - unformat_ip4_address, &end_addr, - &tmp1, &tmp2, &tmp3)) + unformat_ip_address, &ip, + unformat_ip_address, &end_addr, &tmp1, &tmp2, &tmp3)) { r = ikev2_set_profile_ts (vm, name, (u8) tmp3, (u16) tmp1, (u16) tmp2, - ip4, end_addr, /*remote */ 0); + ip, end_addr, /*remote */ 0); goto done; } else if (unformat (line_input, "set %U responder %U %U", unformat_ikev2_token, &name, unformat_vnet_sw_interface, vnm, - &responder_sw_if_index, unformat_ip4_address, - &responder_ip4)) + &responder_sw_if_index, unformat_ip_address, &ip)) { r = - ikev2_set_profile_responder (vm, name, responder_sw_if_index, - responder_ip4); + ikev2_set_profile_responder (vm, name, responder_sw_if_index, ip); goto done; } else if (unformat (line_input, "set %U tunnel %U", @@ -565,7 +559,7 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, if (p->loc_id.type == IKEV2_ID_TYPE_ID_IPV4_ADDR) vlib_cli_output(vm, " local id-type %U data %U", format_ikev2_id_type, p->loc_id.type, - format_ip4_address, p->loc_id.data); + format_ip_address, p->loc_id.data); else if (p->loc_id.type == IKEV2_ID_TYPE_ID_KEY_ID) vlib_cli_output(vm, " local id-type %U data 0x%U", format_ikev2_id_type, p->loc_id.type, @@ -581,7 +575,7 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, if (p->rem_id.type == IKEV2_ID_TYPE_ID_IPV4_ADDR) vlib_cli_output(vm, " remote id-type %U data %U", format_ikev2_id_type, p->rem_id.type, - format_ip4_address, p->rem_id.data); + format_ip_address, p->rem_id.data); else if (p->rem_id.type == IKEV2_ID_TYPE_ID_KEY_ID) vlib_cli_output(vm, " remote id-type %U data 0x%U", format_ikev2_id_type, p->rem_id.type, @@ -592,19 +586,19 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, format_ikev2_id_type, p->rem_id.type, p->rem_id.data); } - if (p->loc_ts.end_addr.as_u32) + if (!ip_address_is_zero (&p->loc_ts.start_addr)) vlib_cli_output(vm, " local traffic-selector addr %U - %U port %u - %u" " protocol %u", - format_ip4_address, &p->loc_ts.start_addr, - format_ip4_address, &p->loc_ts.end_addr, + format_ip_address, &p->loc_ts.start_addr, + format_ip_address, &p->loc_ts.end_addr, p->loc_ts.start_port, p->loc_ts.end_port, p->loc_ts.protocol_id); - if (p->rem_ts.end_addr.as_u32) + if (!ip_address_is_zero (&p->rem_ts.start_addr)) vlib_cli_output(vm, " remote traffic-selector addr %U - %U port %u - %u" " protocol %u", - format_ip4_address, &p->rem_ts.start_addr, - format_ip4_address, &p->rem_ts.end_addr, + format_ip_address, &p->rem_ts.start_addr, + format_ip_address, &p->rem_ts.end_addr, p->rem_ts.start_port, p->rem_ts.end_port, p->rem_ts.protocol_id); if (~0 != p->tun_itf) @@ -613,7 +607,7 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, if (~0 != p->responder.sw_if_index) vlib_cli_output(vm, " responder %U %U", format_vnet_sw_if_index_name, vnet_get_main(), p->responder.sw_if_index, - format_ip4_address, &p->responder.ip4); + format_ip_address, &p->responder.addr); if (p->udp_encap) vlib_cli_output(vm, " udp-encap"); diff --git a/src/plugins/ikev2/ikev2_payload.c b/src/plugins/ikev2/ikev2_payload.c index b7d7098605c1..c03054aa9cd3 100644 --- a/src/plugins/ikev2/ikev2_payload.c +++ b/src/plugins/ikev2/ikev2_payload.c @@ -37,14 +37,23 @@ typedef CLIB_PACKED (struct { /* *INDENT-ON* */ /* *INDENT-OFF* */ +typedef CLIB_PACKED (struct { + ip4_address_t start_addr; + ip4_address_t end_addr; +}) ikev2_ip4_addr_pair_t; + +typedef CLIB_PACKED (struct { + ip6_address_t start_addr; + ip6_address_t end_addr; +}) ikev2_ip6_addr_pair_t; + typedef CLIB_PACKED (struct { u8 ts_type; u8 protocol_id; u16 selector_len; u16 start_port; u16 end_port; - ip4_address_t start_addr; - ip4_address_t end_addr; + u8 addr_pair[0]; }) ikev2_ts_payload_entry_t; /* *INDENT-OFF* */ @@ -286,12 +295,46 @@ ikev2_payload_add_auth (ikev2_payload_chain_t * c, ikev2_auth_t * auth) ikev2_payload_add_data (c, auth->data); } +static void +ikev2_payload_add_ts_entry (u8 ** data, ikev2_ts_t * ts) +{ + u8 * tmp; + ikev2_ts_payload_entry_t *entry; + int len = sizeof (*entry); + + if (ts->ts_type == TS_IPV4_ADDR_RANGE) + len += sizeof (ikev2_ip4_addr_pair_t); + else + len += sizeof (ikev2_ip6_addr_pair_t); + + vec_add2 (data[0], tmp, len); + entry = (ikev2_ts_payload_entry_t *) tmp; + entry->ts_type = ts->ts_type; + entry->protocol_id = ts->protocol_id; + entry->selector_len = clib_host_to_net_u16 (len); + entry->start_port = clib_host_to_net_u16 (ts->start_port); + entry->end_port = clib_host_to_net_u16 (ts->end_port); + + if (ts->ts_type == TS_IPV4_ADDR_RANGE) + { + ikev2_ip4_addr_pair_t *pair = (ikev2_ip4_addr_pair_t*) entry->addr_pair; + ip_address_copy_addr (&pair->start_addr, &ts->start_addr); + ip_address_copy_addr (&pair->end_addr, &ts->end_addr); + } + else + { + ikev2_ip6_addr_pair_t *pair = (ikev2_ip6_addr_pair_t*) entry->addr_pair; + ip_address_copy_addr (&pair->start_addr, &ts->start_addr); + ip_address_copy_addr (&pair->end_addr, &ts->end_addr); + } +} + void ikev2_payload_add_ts (ikev2_payload_chain_t * c, ikev2_ts_t * ts, u8 type) { ike_ts_payload_header_t *tsh; ikev2_ts_t *ts2; - u8 *data = 0, *tmp; + u8 *data = 0; tsh = (ike_ts_payload_header_t *) ikev2_payload_add_hdr (c, type, @@ -300,17 +343,9 @@ ikev2_payload_add_ts (ikev2_payload_chain_t * c, ikev2_ts_t * ts, u8 type) vec_foreach (ts2, ts) { - ASSERT (ts2->ts_type == 7); /*TS_IPV4_ADDR_RANGE */ - ikev2_ts_payload_entry_t *entry; - vec_add2 (data, tmp, sizeof (*entry)); - entry = (ikev2_ts_payload_entry_t *) tmp; - entry->ts_type = ts2->ts_type; - entry->protocol_id = ts2->protocol_id; - entry->selector_len = clib_host_to_net_u16 (16); - entry->start_port = clib_host_to_net_u16 (ts2->start_port); - entry->end_port = clib_host_to_net_u16 (ts2->end_port); - entry->start_addr.as_u32 = ts2->start_addr.as_u32; - entry->end_addr.as_u32 = ts2->end_addr.as_u32; + ASSERT (ts2->ts_type == TS_IPV4_ADDR_RANGE || + ts2->ts_type == TS_IPV6_ADDR_RANGE); + ikev2_payload_add_ts_entry (&data, ts2); } ikev2_payload_add_data (c, data); @@ -413,31 +448,56 @@ ikev2_parse_ts_payload (ike_payload_header_t * ikep, u32 rlen) { ike_ts_payload_header_t *tsp = (ike_ts_payload_header_t *) ikep; ikev2_ts_t *r = 0, *ts; - u8 i; + ikev2_ip4_addr_pair_t *pair4; + ikev2_ip6_addr_pair_t *pair6; + int p = 0, n_left; + ikev2_ts_payload_entry_t *pe; if (sizeof (*tsp) > rlen) return 0; - if (sizeof (*tsp) + tsp->num_ts * sizeof (ikev2_ts_payload_entry_t) > rlen) - return 0; + rlen -= sizeof (*tsp); + n_left = tsp->num_ts; - for (i = 0; i < tsp->num_ts; i++) + while (n_left && p + sizeof (*pe) < rlen) { - if (tsp->ts[i].ts_type != 7) /* TS_IPV4_ADDR_RANGE */ + pe = (ikev2_ts_payload_entry_t *) (((u8 *)tsp->ts) + p); + p += sizeof (*pe); + + if (pe->ts_type != TS_IPV4_ADDR_RANGE && + pe->ts_type != TS_IPV6_ADDR_RANGE) { ikev2_elog_uint (IKEV2_LOG_ERROR, - "unsupported TS type received (%u)", tsp->ts[i].ts_type); - continue; + "unsupported TS type received (%u)", pe->ts_type); + return 0; } vec_add2 (r, ts, 1); - ts->ts_type = tsp->ts[i].ts_type; - ts->protocol_id = tsp->ts[i].protocol_id; - ts->start_port = tsp->ts[i].start_port; - ts->end_port = tsp->ts[i].end_port; - ts->start_addr.as_u32 = tsp->ts[i].start_addr.as_u32; - ts->end_addr.as_u32 = tsp->ts[i].end_addr.as_u32; + ts->ts_type = pe->ts_type; + ts->protocol_id = pe->protocol_id; + ts->start_port = pe->start_port; + ts->end_port = pe->end_port; + + if (pe->ts_type == TS_IPV4_ADDR_RANGE) + { + pair4 = (ikev2_ip4_addr_pair_t*) pe->addr_pair; + ip_address_set (&ts->start_addr, &pair4->start_addr, AF_IP4); + ip_address_set (&ts->end_addr, &pair4->end_addr, AF_IP4); + p += sizeof (*pair4); + } + else + { + pair6 = (ikev2_ip6_addr_pair_t*) pe->addr_pair; + ip_address_set (&ts->start_addr, &pair6->start_addr, AF_IP6); + ip_address_set (&ts->end_addr, &pair6->end_addr, AF_IP6); + p += sizeof (*pair6); + } + n_left--; } + + if (n_left) + return 0; + return r; } diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index f6f9989e4b2c..68a546a0f489 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -81,7 +81,7 @@ do { \ } \ } while (0) \ -#define ikev2_elog_exchange(_format, _ispi, _rspi, _addr) \ +#define ikev2_elog_exchange_internal(_format, _ispi, _rspi, _addr) \ do { \ ikev2_main_t *km = &ikev2_main; \ if (PREDICT_FALSE (km->log_level >= IKEV2_LOG_DEBUG)) \ @@ -110,6 +110,17 @@ do { \ } \ } while (0) \ +#define IKE_ELOG_IP4_FMT "%d.%d.%d.%d" +#define IKE_ELOG_IP6_FMT "[v6]:%x%x:%x%x" + +#define ikev2_elog_exchange(_fmt, _ispi, _rspi, _addr, _v4) \ +do { \ + if (_v4) \ + ikev2_elog_exchange_internal (_fmt IKE_ELOG_IP4_FMT, _ispi, _rspi, _addr);\ + else \ + ikev2_elog_exchange_internal (_fmt IKE_ELOG_IP6_FMT, _ispi, _rspi, _addr);\ +} while (0) + #define ikev2_elog_uint(_level, _format, _val) \ do { \ ikev2_main_t *km = &ikev2_main; \ @@ -156,31 +167,6 @@ do { \ } \ } while (0) -#define ikev2_elog_peers(_level, _format, _ip1, _ip2) \ -do { \ - ikev2_main_t *km = &ikev2_main; \ - if (PREDICT_FALSE (km->log_level >= _level)) \ - { \ - ELOG_TYPE_DECLARE (e) = \ - { \ - .format = "ikev2: " _format, \ - .format_args = "i1i1i1i1i1i1i1i1", \ - }; \ - CLIB_PACKED(struct { \ - u8 i11; u8 i12; u8 i13; u8 i14; \ - u8 i21; u8 i22; u8 i23; u8 i24; }) *ed; \ - ed = ELOG_DATA (&vlib_global_main.elog_main, e); \ - ed->i14 = (_ip1) >> 24; \ - ed->i13 = (_ip1) >> 16; \ - ed->i12 = (_ip1) >> 8; \ - ed->i11 = (_ip1); \ - ed->i24 = (_ip2) >> 24; \ - ed->i23 = (_ip2) >> 16; \ - ed->i22 = (_ip2) >> 8; \ - ed->i21 = (_ip2); \ - } \ -} while (0) - #define ikev2_elog_error(_msg) \ _ikev2_elog(IKEV2_LOG_ERROR, "[error] " _msg) #define ikev2_elog_warning(_msg) \ @@ -258,19 +244,19 @@ typedef struct typedef struct { - u8 ts_type; + ikev2_traffic_selector_type_t ts_type; u8 protocol_id; u16 selector_len; u16 start_port; u16 end_port; - ip4_address_t start_addr; - ip4_address_t end_addr; + ip_address_t start_addr; + ip_address_t end_addr; } ikev2_ts_t; typedef struct { u32 sw_if_index; - ip4_address_t ip4; + ip_address_t addr; } ikev2_responder_t; typedef struct @@ -368,8 +354,8 @@ typedef struct ikev2_state_t state; u8 unsupported_cp; u8 initial_contact; - ip4_address_t iaddr; - ip4_address_t raddr; + ip_address_t iaddr; + ip_address_t raddr; u64 ispi; u64 rspi; u8 *i_nonce; diff --git a/src/plugins/ikev2/ikev2_test.c b/src/plugins/ikev2/ikev2_test.c index 222f01ad1239..81a222c0971b 100644 --- a/src/plugins/ikev2/ikev2_test.c +++ b/src/plugins/ikev2/ikev2_test.c @@ -135,7 +135,7 @@ MACRO_FORMAT (auth_method) s = format (s, " %s", id->data); break; case IKEV2_ID_TYPE_ID_IPV4_ADDR: - s = format (s, " %U", format_ip4_address, id->data); + s = format (s, " %U", format_ip_address, id->data); break; case IKEV2_ID_TYPE_ID_KEY_ID: s = format (s, " 0x%U", format_hex_bytes, id->data, id->data_len); @@ -225,7 +225,6 @@ static void vl_api_ikev2_profile_details_t_handler { vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_profile_t *p = &mp->profile; - ip4_address_t start_addr, end_addr; fformat (vam->ofp, "profile %s\n", p->name); @@ -256,21 +255,17 @@ static void vl_api_ikev2_profile_details_t_handler format_ikev2_id_type_and_data, &p->rem_id); } - ip4_address_decode (p->loc_ts.start_addr, &start_addr); - ip4_address_decode (p->loc_ts.end_addr, &end_addr); fformat (vam->ofp, " local traffic-selector addr %U - %U port %u - %u" " protocol %u\n", - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, + format_ip_address, &p->loc_ts.start_addr, + format_ip_address, &p->loc_ts.end_addr, clib_net_to_host_u16 (p->loc_ts.start_port), clib_net_to_host_u16 (p->loc_ts.end_port), p->loc_ts.protocol_id); - ip4_address_decode (p->rem_ts.start_addr, &start_addr); - ip4_address_decode (p->rem_ts.end_addr, &end_addr); fformat (vam->ofp, " remote traffic-selector addr %U - %U port %u - %u" " protocol %u\n", - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, + format_ip_address, &p->rem_ts.start_addr, + format_ip_address, &p->rem_ts.end_addr, clib_net_to_host_u16 (p->rem_ts.start_port), clib_net_to_host_u16 (p->rem_ts.end_port), p->rem_ts.protocol_id); u32 tun_itf = clib_net_to_host_u32 (p->tun_itf); @@ -280,7 +275,7 @@ static void vl_api_ikev2_profile_details_t_handler u32 sw_if_index = clib_net_to_host_u32 (p->responder.sw_if_index); if (~0 != sw_if_index) fformat (vam->ofp, " responder idx %d %U\n", - sw_if_index, format_ip4_address, &p->responder.ip4); + sw_if_index, format_ip_address, &p->responder.addr); if (p->udp_encap) fformat (vam->ofp, " udp-encap\n"); @@ -348,18 +343,18 @@ vl_api_ikev2_sa_details_t_handler (vl_api_ikev2_sa_details_t * mp) { vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_sa_t *sa = &mp->sa; - ip4_address_t iaddr; - ip4_address_t raddr; + ip_address_t iaddr; + ip_address_t raddr; vl_api_ikev2_keys_t *k = &sa->keys; vl_api_ikev2_sa_t_endian (sa); - ip4_address_decode (sa->iaddr, &iaddr); - ip4_address_decode (sa->raddr, &raddr); + ip_address_decode2 (&sa->iaddr, &iaddr); + ip_address_decode2 (&sa->raddr, &raddr); fformat (vam->ofp, "profile index %d sa index: %d\n", mp->sa.profile_index, mp->sa.sa_index); - fformat (vam->ofp, " iip %U ispi %lx rip %U rspi %lx\n", format_ip4_address, - &iaddr, sa->ispi, format_ip4_address, &raddr, sa->rspi); + fformat (vam->ofp, " iip %U ispi %lx rip %U rspi %lx\n", format_ip_address, + &iaddr, sa->ispi, format_ip_address, &raddr, sa->rspi); fformat (vam->ofp, " %U ", format_ikev2_sa_transform, &sa->encryption); fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->prf); fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->integrity); @@ -526,18 +521,17 @@ static void { vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_ts_t *ts = &mp->ts; - ip4_address_t start_addr; - ip4_address_t end_addr; + ip_address_t start_addr, end_addr; vl_api_ikev2_ts_t_endian (ts); - ip4_address_decode (ts->start_addr, &start_addr); - ip4_address_decode (ts->end_addr, &end_addr); + ip_address_decode2 (&ts->start_addr, &start_addr); + ip_address_decode2 (&ts->end_addr, &end_addr); fformat (vam->ofp, " %s protocol_id %u addr " "%U - %U port %u - %u\n", ts->is_local, ts->protocol_id, - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, ts->start_port, ts->end_port); + format_ip_address, &start_addr, + format_ip_address, &end_addr, ts->start_port, ts->end_port); vam->result_ready = 1; } @@ -797,7 +791,7 @@ api_ikev2_profile_set_id (vat_main_t * vam) u8 *data = 0; u8 is_local = 0; u32 id_type = 0; - ip4_address_t ip4; + ip_address_t ip; int ret; const char *valid_chars = "a-zA-Z0-9_"; @@ -808,10 +802,10 @@ api_ikev2_profile_set_id (vat_main_t * vam) vec_add1 (name, 0); else if (unformat (i, "id_type %U", unformat_ikev2_id_type, &id_type)) ; - else if (unformat (i, "id_data %U", unformat_ip4_address, &ip4)) + else if (unformat (i, "id_data %U", unformat_ip_address, &ip)) { - data = vec_new (u8, 4); - clib_memcpy (data, ip4.as_u8, 4); + data = vec_new (u8, ip_address_size (&ip)); + clib_memcpy (data, ip_addr_bytes (&ip), ip_address_size (&ip)); } else if (unformat (i, "id_data 0x%U", unformat_hex_string, &data)) ; @@ -875,14 +869,12 @@ api_ikev2_profile_set_ts (vat_main_t * vam) u8 *name = 0; u8 is_local = 0; u32 proto = 0, start_port = 0, end_port = (u32) ~ 0; - ip4_address_t start_addr, end_addr; + ip_address_t start_addr, end_addr; + u8 start_addr_set = 0, end_addr_set = 0; const char *valid_chars = "a-zA-Z0-9_"; int ret; - start_addr.as_u32 = 0; - end_addr.as_u32 = (u32) ~ 0; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "name %U", unformat_token, valid_chars, &name)) @@ -894,10 +886,10 @@ api_ikev2_profile_set_ts (vat_main_t * vam) else if (unformat (i, "end_port %d", &end_port)) ; else - if (unformat (i, "start_addr %U", unformat_ip4_address, &start_addr)) - ; - else if (unformat (i, "end_addr %U", unformat_ip4_address, &end_addr)) - ; + if (unformat (i, "start_addr %U", unformat_ip_address, &start_addr)) + start_addr_set = 1; + else if (unformat (i, "end_addr %U", unformat_ip_address, &end_addr)) + end_addr_set = 1; else if (unformat (i, "local")) is_local = 1; else if (unformat (i, "remote")) @@ -909,6 +901,12 @@ api_ikev2_profile_set_ts (vat_main_t * vam) } } + if (!start_addr_set || !end_addr_set) + { + errmsg ("missing start or end address"); + return -99; + } + if (!vec_len (name)) { errmsg ("profile name must be specified"); @@ -927,8 +925,8 @@ api_ikev2_profile_set_ts (vat_main_t * vam) mp->ts.protocol_id = (u8) proto; mp->ts.start_port = clib_host_to_net_u16 ((u16) start_port); mp->ts.end_port = clib_host_to_net_u16 ((u16) end_port); - ip4_address_encode (&start_addr, mp->ts.start_addr); - ip4_address_encode (&end_addr, mp->ts.end_addr); + ip_address_encode2 (&start_addr, &mp->ts.start_addr); + ip_address_encode2 (&end_addr, &mp->ts.end_addr); clib_memcpy (mp->name, name, vec_len (name)); vec_free (name); @@ -1035,7 +1033,7 @@ api_ikev2_set_responder (vat_main_t * vam) int ret; u8 *name = 0; u32 sw_if_index = ~0; - ip4_address_t address; + ip_address_t address; const char *valid_chars = "a-zA-Z0-9_"; @@ -1043,7 +1041,7 @@ api_ikev2_set_responder (vat_main_t * vam) { if (unformat (i, "%U interface %d address %U", unformat_token, valid_chars, - &name, &sw_if_index, unformat_ip4_address, &address)) + &name, &sw_if_index, unformat_ip_address, &address)) vec_add1 (name, 0); else { @@ -1070,7 +1068,7 @@ api_ikev2_set_responder (vat_main_t * vam) vec_free (name); mp->responder.sw_if_index = clib_host_to_net_u32 (sw_if_index); - ip4_address_encode (&address, mp->responder.ip4); + ip_address_encode2 (&address, &mp->responder.addr); S (mp); W (ret); diff --git a/src/plugins/ikev2/ikev2_types.api b/src/plugins/ikev2/ikev2_types.api index 58297c05e9ca..0f998b196c26 100644 --- a/src/plugins/ikev2/ikev2_types.api +++ b/src/plugins/ikev2/ikev2_types.api @@ -34,8 +34,8 @@ typedef ikev2_ts u8 protocol_id; u16 start_port; u16 end_port; - vl_api_ip4_address_t start_addr; - vl_api_ip4_address_t end_addr; + vl_api_address_t start_addr; + vl_api_address_t end_addr; }; typedef ikev2_auth @@ -49,7 +49,7 @@ typedef ikev2_auth typedef ikev2_responder { vl_api_interface_index_t sw_if_index; - vl_api_ip4_address_t ip4; + vl_api_address_t addr; }; typedef ikev2_ike_transforms @@ -134,8 +134,8 @@ typedef ikev2_sa u64 ispi; u64 rspi; - vl_api_ip4_address_t iaddr; - vl_api_ip4_address_t raddr; + vl_api_address_t iaddr; + vl_api_address_t raddr; vl_api_ikev2_keys_t keys; diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 0bdc417fb2dd..a47c59f578fd 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -9,15 +9,20 @@ algorithms, modes, ) -from ipaddress import IPv4Address +from ipaddress import IPv4Address, IPv6Address, ip_address from scapy.layers.ipsec import ESP from scapy.layers.inet import IP, UDP, Ether +from scapy.layers.inet6 import IPv6 from scapy.packet import raw, Raw from scapy.utils import long_converter from framework import VppTestCase, VppTestRunner from vpp_ikev2 import Profile, IDType, AuthMethod from vpp_papi import VppEnum +try: + text_type = unicode +except NameError: + text_type = str KEY_PAD = b"Key Pad for IKEv2" SALT_SIZE = 4 @@ -156,9 +161,9 @@ def __init__(self, local_ts, remote_ts, spi=None): class IKEv2SA(object): - def __init__(self, test, is_initiator=True, spi=b'\x04' * 8, - i_id=None, r_id=None, id_type='fqdn', nonce=None, - auth_data=None, local_ts=None, remote_ts=None, + def __init__(self, test, is_initiator=True, i_id=None, r_id=None, + spi=b'\x01\x02\x03\x04\x05\x06\x07\x08', id_type='fqdn', + nonce=None, auth_data=None, local_ts=None, remote_ts=None, auth_method='shared-key', priv_key=None, natt=False): self.natt = natt if natt: @@ -182,12 +187,12 @@ def __init__(self, test, is_initiator=True, spi=b'\x04' * 8, self.id_type = id_type self.auth_method = auth_method if self.is_initiator: - self.rspi = None + self.rspi = 8 * b'\x00' self.ispi = spi self.i_nonce = nonce else: self.rspi = spi - self.ispi = None + self.ispi = 8 * b'\x00' self.r_nonce = None self.child_sas = [IKEv2ChildSA(local_ts, remote_ts)] @@ -416,18 +421,25 @@ def hmac_and_decrypt(self, ike): ct = ep.load[:-integ_trunc] return self.decrypt(ct) - def generate_ts(self): + def build_ts_addr(self, ts, version): + return {'starting_address_v' + version: ts['start_addr'], + 'ending_address_v' + version: ts['end_addr']} + + def generate_ts(self, is_ip4): c = self.child_sas[0] - ts1 = ikev2.IPv4TrafficSelector( - IP_protocol_ID=0, - start_port=0, - end_port=0xffff, - starting_address_v4=c.local_ts['start_addr'], - ending_address_v4=c.local_ts['end_addr']) - ts2 = ikev2.IPv4TrafficSelector( - IP_protocol_ID=0, - starting_address_v4=c.remote_ts['start_addr'], - ending_address_v4=c.remote_ts['end_addr']) + ts_data = {'IP_protocol_ID': 0, + 'start_port': 0, + 'end_port': 0xffff} + if is_ip4: + ts_data.update(self.build_ts_addr(c.local_ts, '4')) + ts1 = ikev2.IPv4TrafficSelector(**ts_data) + ts_data.update(self.build_ts_addr(c.remote_ts, '4')) + ts2 = ikev2.IPv4TrafficSelector(**ts_data) + else: + ts_data.update(self.build_ts_addr(c.local_ts, '6')) + ts1 = ikev2.IPv6TrafficSelector(**ts_data) + ts_data.update(self.build_ts_addr(c.remote_ts, '6')) + ts2 = ikev2.IPv6TrafficSelector(**ts_data) return ([ts1], [ts2]) def set_ike_props(self, crypto, crypto_key_len, integ, prf, dh): @@ -474,7 +486,7 @@ def esp_crypto_attr(self): return self.crypto_attr(self.esp_crypto_key_len) def compute_nat_sha1(self, ip, port): - data = self.ispi + b'\x00' * 8 + ip + (port).to_bytes(2, 'big') + data = self.ispi + self.rspi + ip + (port).to_bytes(2, 'big') digest = hashes.Hash(hashes.SHA1(), backend=default_backend()) digest.update(data) return digest.finalize() @@ -493,6 +505,8 @@ def setUpClass(cls): i.admin_up() i.config_ip4() i.resolve_arp() + i.config_ip6() + i.resolve_ndp() @classmethod def tearDownClass(cls): @@ -504,6 +518,8 @@ def setUp(self): self.p.add_vpp_config() self.assertIsNotNone(self.p.query_vpp_config()) self.sa.generate_dh_data() + self.vapi.cli('ikev2 set logging level 4') + self.vapi.cli('event-lo clear') def tearDown(self): super(TemplateResponder, self).tearDown() @@ -528,16 +544,25 @@ def initiate_del_sa(self): ike_msg = self.encrypt_ike_msg(header, del_sa, 'Delete') packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, self.sa.dport, - self.sa.natt) + self.sa.natt, self.ip6) self.pg0.add_stream(packet) self.pg0.enable_capture() self.pg_start() capture = self.pg0.get_capture(1) self.verify_del_sa(capture[0]) - def create_packet(self, src_if, msg, sport=500, dport=500, natt=False): + def create_packet(self, src_if, msg, sport=500, dport=500, natt=False, + use_ip6=False): + if use_ip6: + src_ip = src_if.remote_ip6 + dst_ip = src_if.local_ip6 + ip_layer = IPv6 + else: + src_ip = src_if.remote_ip4 + dst_ip = src_if.local_ip4 + ip_layer = IP res = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - IP(src=src_if.remote_ip4, dst=src_if.local_ip4) / + ip_layer(src=src_ip, dst=dst_ip) / UDP(sport=sport, dport=dport)) if natt: # insert non ESP marker @@ -575,16 +600,24 @@ def send_sa_init(self, behind_nat=False): load=self.sa.i_nonce)) if behind_nat: - src_nat = self.sa.compute_nat_sha1(b'\x0a\x0a\x0a\x01', - self.sa.sport) - nat_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_SOURCE_IP', - load=src_nat) - self.sa.init_req_packet = self.sa.init_req_packet / nat_detection + src_address = b'\x0a\x0a\x0a\x01' + else: + src_address = bytes(self.pg0.local_ip4, 'ascii') + + src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) + dst_nat = self.sa.compute_nat_sha1(bytes(self.pg0.remote_ip4, 'ascii'), + self.sa.sport) + nat_src_detection = ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_SOURCE_IP', load=src_nat) + nat_dst_detection = ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) + self.sa.init_req_packet = (self.sa.init_req_packet / + nat_src_detection / + nat_dst_detection) ike_msg = self.create_packet(self.pg0, self.sa.init_req_packet, self.sa.sport, self.sa.dport, - self.sa.natt) + self.sa.natt, self.ip6) self.pg0.add_stream(ike_msg) self.pg0.enable_capture() self.pg_start() @@ -642,7 +675,7 @@ def send_sa_auth(self): props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) - tsi, tsr = self.sa.generate_ts() + tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) plain = (ikev2.IKEv2_payload_IDi(next_payload='IDr', IDtype=self.sa.id_type, load=self.sa.i_id) / ikev2.IKEv2_payload_IDr(next_payload='AUTH', @@ -666,7 +699,7 @@ def send_sa_auth(self): ike_msg = self.encrypt_ike_msg(header, plain, 'IDi') packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, - self.sa.dport, self.sa.natt) + self.sa.dport, self.sa.natt, self.ip6) self.pg0.add_stream(packet) self.pg0.enable_capture() self.pg_start() @@ -681,6 +714,8 @@ def get_ike_header(self, packet): # ipsec register for port 4500 esp = packet[ESP] ih = self.verify_and_remove_non_esp_marker(esp) + + self.assertEqual(ih.version, 0x20) return ih def verify_sa_init(self, packet): @@ -776,10 +811,14 @@ def verify_ike_sas(self): r = self.vapi.ikev2_sa_dump() self.assertEqual(len(r), 1) sa = r[0].sa - self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, 'little')) + self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, 'big')) self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, 'big')) - self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4)) - self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4)) + if self.ip6: + self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6)) + self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6)) + else: + self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4)) + self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4)) self.verify_keymat(sa.keys, self.sa, 'sk_d') self.verify_keymat(sa.keys, self.sa, 'sk_ai') self.verify_keymat(sa.keys, self.sa, 'sk_ar') @@ -806,7 +845,7 @@ def verify_ike_sas(self): self.verify_keymat(csa.keys, c, 'sk_ei') self.verify_keymat(csa.keys, c, 'sk_er') - tsi, tsr = self.sa.generate_ts() + tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) tsi = tsi[0] tsr = tsr[0] r = self.vapi.ikev2_traffic_selector_dump( @@ -838,10 +877,17 @@ def verify_ts(self, api_ts, ts, is_initiator): self.assertTrue(api_ts.is_local) else: self.assertFalse(api_ts.is_local) - self.assertEqual(api_ts.start_addr, - IPv4Address(ts.starting_address_v4)) - self.assertEqual(api_ts.end_addr, - IPv4Address(ts.ending_address_v4)) + + if self.p.ts_is_ip4: + self.assertEqual(api_ts.start_addr, + IPv4Address(ts.starting_address_v4)) + self.assertEqual(api_ts.end_addr, + IPv4Address(ts.ending_address_v4)) + else: + self.assertEqual(api_ts.start_addr, + IPv6Address(ts.starting_address_v6)) + self.assertEqual(api_ts.end_addr, + IPv6Address(ts.ending_address_v6)) self.assertEqual(api_ts.start_port, ts.start_port) self.assertEqual(api_ts.end_port, ts.end_port) self.assertEqual(api_ts.protocol_id, ts.IP_protocol_ID) @@ -872,6 +918,7 @@ def config_params(self, params={}): is_natt = 'natt' in params and params['natt'] or False self.p = Profile(self, 'pr1') + self.ip6 = False if 'ip6' not in params else params['ip6'] if 'auth' in params and params['auth'] == 'rsa-sig': auth_method = 'rsa-sig' @@ -897,8 +944,12 @@ def config_params(self, params={}): self.p.add_local_id(id_type='fqdn', data=b'vpp.home') self.p.add_remote_id(id_type='fqdn', data=b'roadwarrior.example.com') - self.p.add_local_ts(start_addr='10.10.10.0', end_addr='10.10.10.255') - self.p.add_remote_ts(start_addr='10.0.0.0', end_addr='10.0.0.255') + loc_ts = {'start_addr': '10.10.10.0', 'end_addr': '10.10.10.255'} if\ + 'loc_ts' not in params else params['loc_ts'] + rem_ts = {'start_addr': '10.0.0.0', 'end_addr': '10.0.0.255'} if\ + 'rem_ts' not in params else params['rem_ts'] + self.p.add_local_ts(**loc_ts) + self.p.add_remote_ts(**rem_ts) self.sa = IKEv2SA(self, i_id=self.p.remote_id['data'], r_id=self.p.local_id['data'], @@ -964,14 +1015,14 @@ def configure_profile(self, cfg): def test_profile_api(self): """ test profile dump API """ - loc_ts = { + loc_ts4 = { 'proto': 8, 'start_port': 1, 'end_port': 19, 'start_addr': '3.3.3.2', 'end_addr': '3.3.3.3', } - rem_ts = { + rem_ts4 = { 'proto': 9, 'start_port': 10, 'end_port': 119, @@ -979,14 +1030,29 @@ def test_profile_api(self): 'end_addr': '2.3.4.6', } + loc_ts6 = { + 'proto': 8, + 'start_port': 1, + 'end_port': 19, + 'start_addr': 'ab::1', + 'end_addr': 'ab::4', + } + rem_ts6 = { + 'proto': 9, + 'start_port': 10, + 'end_port': 119, + 'start_addr': 'cd::12', + 'end_addr': 'cd::13', + } + conf = { 'p1': { 'name': 'p1', 'loc_id': ('fqdn', b'vpp.home'), 'rem_id': ('fqdn', b'roadwarrior.example.com'), - 'loc_ts': loc_ts, - 'rem_ts': rem_ts, - 'responder': {'sw_if_index': 0, 'ip4': '5.6.7.8'}, + 'loc_ts': loc_ts4, + 'rem_ts': rem_ts4, + 'responder': {'sw_if_index': 0, 'addr': '5.6.7.8'}, 'ike_ts': { 'crypto_alg': 20, 'crypto_key_size': 32, @@ -1008,10 +1074,10 @@ def test_profile_api(self): 'p2': { 'name': 'p2', 'loc_id': ('ip4-addr', b'192.168.2.1'), - 'rem_id': ('ip4-addr', b'192.168.2.2'), - 'loc_ts': loc_ts, - 'rem_ts': rem_ts, - 'responder': {'sw_if_index': 4, 'ip4': '5.6.7.99'}, + 'rem_id': ('ip6-addr', b'abcd::1'), + 'loc_ts': loc_ts6, + 'rem_ts': rem_ts6, + 'responder': {'sw_if_index': 4, 'addr': 'def::10'}, 'ike_ts': { 'crypto_alg': 12, 'crypto_key_size': 16, @@ -1042,12 +1108,14 @@ def verify_ts(self, api_ts, cfg_ts): self.assertEqual(api_ts.protocol_id, cfg_ts['proto']) self.assertEqual(api_ts.start_port, cfg_ts['start_port']) self.assertEqual(api_ts.end_port, cfg_ts['end_port']) - self.assertEqual(api_ts.start_addr, IPv4Address(cfg_ts['start_addr'])) - self.assertEqual(api_ts.end_addr, IPv4Address(cfg_ts['end_addr'])) + self.assertEqual(api_ts.start_addr, + ip_address(text_type(cfg_ts['start_addr']))) + self.assertEqual(api_ts.end_addr, + ip_address(text_type(cfg_ts['end_addr']))) def verify_responder(self, api_r, cfg_r): self.assertEqual(api_r.sw_if_index, cfg_r['sw_if_index']) - self.assertEqual(api_r.ip4, IPv4Address(cfg_r['ip4'])) + self.assertEqual(api_r.addr, ip_address(cfg_r['addr'])) def verify_transforms(self, api_ts, cfg_ts): self.assertEqual(api_ts.crypto_alg, cfg_ts['crypto_alg']) @@ -1150,9 +1218,15 @@ class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params): """ def config_tc(self): self.config_params({ + 'ip6': True, + 'natt': True, 'ike-crypto': ('AES-GCM-16ICV', 32), 'ike-integ': 'NULL', - 'ike-dh': '2048MODPgr'}) + 'ike-dh': '2048MODPgr', + 'loc_ts': {'start_addr': 'ab:cd::0', + 'end_addr': 'ab:cd::10'}, + 'rem_ts': {'start_addr': '11::0', + 'end_addr': '11::100'}}) class TestMalformedMessages(TemplateResponder, Ikev2Params): @@ -1164,8 +1238,8 @@ def tearDown(self): def config_tc(self): self.config_params() - def assert_counter(self, count, name): - node_name = '/err/ikev2/' + name + def assert_counter(self, count, name, version='ip4'): + node_name = '/err/ikev2-%s/' % version + name self.assertEqual(count, self.statistics.get_err_counter(node_name)) def create_ike_init_msg(self, length=None, payload=None): diff --git a/src/plugins/ikev2/test/vpp_ikev2.py b/src/plugins/ikev2/test/vpp_ikev2.py index b3339d0ea86e..6ae30201450a 100644 --- a/src/plugins/ikev2/test/vpp_ikev2.py +++ b/src/plugins/ikev2/test/vpp_ikev2.py @@ -1,3 +1,4 @@ +from ipaddress import IPv4Address, AddressValueError from vpp_object import VppObject from vpp_papi import VppEnum @@ -12,7 +13,8 @@ def value(key): return AuthMethod.v[key] class IDType: v = {'ip4-addr': 1, - 'fqdn': 2} + 'fqdn': 2, + 'ip6-addr': 5} @staticmethod def value(key): return IDType.v[key] @@ -52,7 +54,8 @@ def add_remote_id(self, id_type, data): 'is_local': False} def add_local_ts(self, start_addr, end_addr, start_port=0, end_port=0xffff, - proto=0): + proto=0, is_ip4=True): + self.ts_is_ip4 = is_ip4 self.local_ts = {'is_local': True, 'protocol_id': proto, 'start_port': start_port, @@ -62,6 +65,12 @@ def add_local_ts(self, start_addr, end_addr, start_port=0, end_port=0xffff, def add_remote_ts(self, start_addr, end_addr, start_port=0, end_port=0xffff, proto=0): + try: + IPv4Address(start_addr) + is_ip4 = True + except AddressValueError: + is_ip4 = False + self.ts_is_ip4 = is_ip4 self.remote_ts = {'is_local': False, 'protocol_id': proto, 'start_port': start_port, From ae0d24f1be7fab03c5697996cb7da0fc6dd0bd12 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Mon, 5 Oct 2020 12:30:44 +0000 Subject: [PATCH 099/129] ikev2: fix memory leak in auth routine Type: fix Change-Id: I93529b069925fcef32cdb22e27975b802b4c3b97 Signed-off-by: Filip Tehlar (cherry picked from commit 623d87fd39c53e2f4d8718014e76836fe07c4245) --- src/plugins/ikev2/ikev2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index a266853760fd..cbffcba76ac8 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1672,11 +1672,13 @@ ikev2_sa_auth (ikev2_sa_t * sa) authmsg = ikev2_sa_generate_authmsg (sa, 1); if (sel_p->auth.method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC) { + vec_free (sa->r_auth.data); sa->r_auth.data = ikev2_calc_prf (tr_prf, psk, authmsg); sa->r_auth.method = IKEV2_AUTH_METHOD_SHARED_KEY_MIC; } else if (sel_p->auth.method == IKEV2_AUTH_METHOD_RSA_SIG) { + vec_free (sa->r_auth.data); sa->r_auth.data = ikev2_calc_sign (km->pkey, authmsg); sa->r_auth.method = IKEV2_AUTH_METHOD_RSA_SIG; } @@ -1733,11 +1735,13 @@ ikev2_sa_auth_init (ikev2_sa_t * sa) if (sa->i_auth.method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC) { + vec_free (sa->i_auth.data); sa->i_auth.data = ikev2_calc_prf (tr_prf, psk, authmsg); sa->i_auth.method = IKEV2_AUTH_METHOD_SHARED_KEY_MIC; } else if (sa->i_auth.method == IKEV2_AUTH_METHOD_RSA_SIG) { + vec_free (sa->i_auth.data); sa->i_auth.data = ikev2_calc_sign (km->pkey, authmsg); sa->i_auth.method = IKEV2_AUTH_METHOD_RSA_SIG; } From 3ff88076d3e5c1a172217f8e7070bfc7ef2f3d04 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 6 Oct 2020 08:04:10 +0000 Subject: [PATCH 100/129] ikev2: fix coverity warning Type: fix Change-Id: Iee96b3ea3e71ec248c3c3c98d153a08372b5faf0 Signed-off-by: Filip Tehlar (cherry picked from commit dc6378f71bc7c9835845a91dbbc1646ea46df51e) --- src/plugins/ikev2/ikev2.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index cbffcba76ac8..f45c2180093b 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -2715,6 +2715,26 @@ ikev2_set_ip_address (ikev2_sa_t * sa, const void *src, ip_address_set (&sa->iaddr, iaddr, af); } +static void +ikev2_elog_uint_peers_addr (u32 exchange, ip4_header_t * ip4, + ip6_header_t * ip6, u8 is_ip4) +{ + u32 src, dst; + if (is_ip4) + { + src = ip4->src_address.as_u32; + dst = ip4->dst_address.as_u32; + } + else + { + src = ip6->src_address.as_u32[3]; + dst = ip6->dst_address.as_u32[3]; + } + ikev2_elog_uint_peers (IKEV2_LOG_WARNING, "IKEv2 exchange %d " + "received from %d.%d.%d.%d to %d.%d.%d.%d", + exchange, src, dst); +} + static_always_inline uword ikev2_node_internal (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, @@ -3119,11 +3139,7 @@ ikev2_node_internal (vlib_main_t * vm, } else { - ikev2_elog_uint_peers (IKEV2_LOG_WARNING, "IKEv2 exchange %d " - "received from %d.%d.%d.%d to %d.%d.%d.%d", - ike0->exchange, - ip40->src_address.as_u32, - ip40->dst_address.as_u32); + ikev2_elog_uint_peers_addr (ike0->exchange, ip40, ip60, is_ip4); } dispatch0: From 8b69f7546e205470623d0ea1542e0488eb3f625f Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 23 Sep 2020 11:20:12 +0000 Subject: [PATCH 101/129] ikev2: fix initial contact cleanup When looking for existing SA connection to clean up search all per thread data, not only current one. Type: fix Change-Id: I59312e08a07ca1f474b6389999e59320c5128e7d Signed-off-by: Filip Tehlar (cherry picked from commit e7c8396982607634b4c747870499671ffa53868e) --- src/plugins/ikev2/ikev2.c | 210 +++++---- src/plugins/ikev2/test/test_ikev2.py | 658 ++++++++++++++++++--------- 2 files changed, 562 insertions(+), 306 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index f45c2180093b..49fb6b66f0a6 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -344,19 +344,17 @@ ikev2_sa_free_all_vec (ikev2_sa_t * sa) } static void -ikev2_delete_sa (ikev2_sa_t * sa) +ikev2_delete_sa (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa) { - ikev2_main_t *km = &ikev2_main; - u32 thread_index = vlib_get_thread_index (); uword *p; ikev2_sa_free_all_vec (sa); - p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, sa->rspi); + p = hash_get (ptd->sa_by_rspi, sa->rspi); if (p) { - hash_unset (km->per_thread_data[thread_index].sa_by_rspi, sa->rspi); - pool_put (km->per_thread_data[thread_index].sas, sa); + hash_unset (ptd->sa_by_rspi, sa->rspi); + pool_put (ptd->sas, sa); } } @@ -1027,43 +1025,61 @@ ikev2_is_id_equal (ikev2_id_t * i1, ikev2_id_t * i2) } static void -ikev2_initial_contact_cleanup (ikev2_sa_t * sa) +ikev2_initial_contact_cleanup_internal (ikev2_main_per_thread_data_t * ptd, + ikev2_sa_t * sa) { ikev2_main_t *km = &ikev2_main; ikev2_sa_t *tmp; u32 i, *delete = 0; ikev2_child_sa_t *c; - u32 thread_index = vlib_get_thread_index (); - - if (!sa->initial_contact) - return; /* find old IKE SAs with the same authenticated identity */ /* *INDENT-OFF* */ - pool_foreach (tmp, km->per_thread_data[thread_index].sas, ({ - if (!ikev2_is_id_equal (&tmp->i_id, &sa->i_id) - || !ikev2_is_id_equal(&tmp->r_id, &sa->r_id)) - continue; + pool_foreach (tmp, ptd->sas, ({ + if (!ikev2_is_id_equal (&tmp->i_id, &sa->i_id) + || !ikev2_is_id_equal(&tmp->r_id, &sa->r_id)) + continue; - if (sa->rspi != tmp->rspi) - vec_add1(delete, tmp - km->per_thread_data[thread_index].sas); + if (sa->rspi != tmp->rspi) + vec_add1(delete, tmp - ptd->sas); })); /* *INDENT-ON* */ for (i = 0; i < vec_len (delete); i++) { - tmp = - pool_elt_at_index (km->per_thread_data[thread_index].sas, delete[i]); - vec_foreach (c, - tmp->childs) ikev2_delete_tunnel_interface (km->vnet_main, - tmp, c); - ikev2_delete_sa (tmp); + tmp = pool_elt_at_index (ptd->sas, delete[i]); + vec_foreach (c, tmp->childs) + { + ikev2_delete_tunnel_interface (km->vnet_main, tmp, c); + } + ikev2_delete_sa (ptd, tmp); } vec_free (delete); sa->initial_contact = 0; } +static void +ikev2_initial_contact_cleanup (ikev2_main_per_thread_data_t * ptd, + ikev2_sa_t * sa) +{ + ikev2_main_t *km = &ikev2_main; + + if (!sa->initial_contact) + return; + + if (ptd) + { + ikev2_initial_contact_cleanup_internal (ptd, sa); + } + else + { + vec_foreach (ptd, km->per_thread_data) + ikev2_initial_contact_cleanup_internal (ptd, sa); + } + sa->initial_contact = 0; +} + static int ikev2_parse_id_payload (const void *p, u16 rlen, ikev2_id_t * sa_id) { @@ -2531,75 +2547,88 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, return tlen; } +static u32 +ikev2_retransmit_sa_init_one (ikev2_sa_t * sa, ike_header_t * ike, + ip_address_t iaddr, ip_address_t raddr, + u32 rlen) +{ + int p = 0; + ike_header_t *tmp; + u8 payload = ike->nextpayload; + + if (sa->ispi != clib_net_to_host_u64 (ike->ispi) || + ip_address_cmp (&sa->iaddr, &iaddr) || + ip_address_cmp (&sa->raddr, &raddr)) + { + return 0; + } + + while (p < rlen && payload != IKEV2_PAYLOAD_NONE) + { + ike_payload_header_t *ikep = (ike_payload_header_t *) & ike->payload[p]; + u32 plen = clib_net_to_host_u16 (ikep->length); + + if (plen < sizeof (ike_payload_header_t)) + return ~0; + + if (payload == IKEV2_PAYLOAD_NONCE && + !clib_memcmp (sa->i_nonce, ikep->payload, plen - sizeof (*ikep))) + { + /* req is retransmit */ + if (sa->state == IKEV2_STATE_SA_INIT) + { + tmp = (ike_header_t *) sa->last_sa_init_res_packet_data; + u32 slen = clib_net_to_host_u32 (tmp->length); + ike->ispi = tmp->ispi; + ike->rspi = tmp->rspi; + ike->nextpayload = tmp->nextpayload; + ike->version = tmp->version; + ike->exchange = tmp->exchange; + ike->flags = tmp->flags; + ike->msgid = tmp->msgid; + ike->length = tmp->length; + clib_memcpy_fast (ike->payload, tmp->payload, + slen - sizeof (*ike)); + ikev2_elog_uint_peers (IKEV2_LOG_DEBUG, + "ispi %lx IKE_SA_INIT retransmit " + "from %d.%d.%d.%d to %d.%d.%d.%d", + ike->ispi, + ip_addr_v4 (&raddr).as_u32, + ip_addr_v4 (&iaddr).as_u32); + return slen; + } + /* else ignore req */ + else + { + ikev2_elog_uint_peers (IKEV2_LOG_DEBUG, + "ispi %lx IKE_SA_INIT ignore " + "from %d.%d.%d.%d to %d.%d.%d.%d", + ike->ispi, + ip_addr_v4 (&raddr).as_u32, + ip_addr_v4 (&iaddr).as_u32); + return ~0; + } + } + payload = ikep->nextpayload; + p += plen; + } + + return 0; +} + static u32 ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr, ip_address_t raddr, u32 rlen) { ikev2_sa_t *sa; + u32 res; ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); /* *INDENT-OFF* */ pool_foreach (sa, ptd->sas, ({ - if (sa->ispi == clib_net_to_host_u64(ike->ispi) && - !ip_address_cmp(&sa->iaddr, &iaddr) && - !ip_address_cmp(&sa->raddr, &raddr)) - { - int p = 0; - u8 payload = ike->nextpayload; - - while (p < rlen && payload!= IKEV2_PAYLOAD_NONE) { - ike_payload_header_t * ikep = (ike_payload_header_t *) &ike->payload[p]; - u32 plen = clib_net_to_host_u16 (ikep->length); - if (plen > p + sizeof (*ike)) - return ~0; - - if (plen < sizeof(ike_payload_header_t)) - return ~0; - - if (payload == IKEV2_PAYLOAD_NONCE) - { - if (!clib_memcmp(sa->i_nonce, ikep->payload, - plen - sizeof(*ikep))) - { - /* req is retransmit */ - if (sa->state == IKEV2_STATE_SA_INIT) - { - ike_header_t * tmp = (ike_header_t*)sa->last_sa_init_res_packet_data; - u32 slen = clib_net_to_host_u32(tmp->length); - ike->ispi = tmp->ispi; - ike->rspi = tmp->rspi; - ike->nextpayload = tmp->nextpayload; - ike->version = tmp->version; - ike->exchange = tmp->exchange; - ike->flags = tmp->flags; - ike->msgid = tmp->msgid; - ike->length = tmp->length; - clib_memcpy_fast(ike->payload, tmp->payload, slen - sizeof(*ike)); - ikev2_elog_uint_peers (IKEV2_LOG_DEBUG, - "ispi %lx IKE_SA_INIT retransmit " - "from %d.%d.%d.%d to %d.%d.%d.%d", - ike->ispi, - ip_addr_v4(&raddr).as_u32, - ip_addr_v4 (&iaddr).as_u32); - return slen; - } - /* else ignore req */ - else - { - ikev2_elog_uint_peers (IKEV2_LOG_DEBUG, - "ispi %lx IKE_SA_INIT ignore " - "from %d.%d.%d.%d to %d.%d.%d.%d", - ike->ispi, - ip_addr_v4(&raddr).as_u32, - ip_addr_v4(&iaddr).as_u32); - return ~0; - } - } - } - payload = ikep->nextpayload; - p+=plen; - } - } + res = ikev2_retransmit_sa_init_one (sa, ike, iaddr, raddr, rlen); + if (res) + return res; })); /* *INDENT-ON* */ @@ -2982,7 +3011,7 @@ ikev2_node_internal (vlib_main_t * vm, IKEV2_ERROR_MALFORMED_PACKET, 1); if (sa0->state == IKEV2_STATE_AUTHENTICATED) { - ikev2_initial_contact_cleanup (sa0); + ikev2_initial_contact_cleanup (ptd, sa0); ikev2_sa_match_ts (sa0); if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE) ikev2_create_tunnel_interface (vm, sa0, @@ -3202,7 +3231,7 @@ ikev2_node_internal (vlib_main_t * vm, vec_foreach (c, sa0->childs) ikev2_delete_tunnel_interface (km->vnet_main, sa0, c); - ikev2_delete_sa (sa0); + ikev2_delete_sa (ptd, sa0); } if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) @@ -3596,6 +3625,9 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, if (~0 == len) return; + if (sa->natt) + len = ikev2_insert_non_esp_marker (ike0, len); + if (sa->is_initiator) { src = &sa->iaddr; @@ -4178,7 +4210,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) vec_add (sa.childs[0].tsi, &p->loc_ts, 1); vec_add (sa.childs[0].tsr, &p->rem_ts, 1); - ikev2_initial_contact_cleanup (&sa); + ikev2_initial_contact_cleanup (0, &sa); /* add SA to the pool */ ikev2_sa_t *sa0 = 0; @@ -4662,8 +4694,6 @@ ikev2_process_pending_sa_init (ikev2_main_t * km) /* *INDENT-ON* */ } -static vlib_node_registration_t ikev2_mngr_process_node; - static void ikev2_send_informational_request (ikev2_sa_t * sa) { @@ -4761,6 +4791,10 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, pool_foreach (sa, tkm->sas, ({ ikev2_child_sa_t *c; u8 del_old_ids = 0; + + if (sa->state != IKEV2_STATE_AUTHENTICATED) + continue; + if (sa->old_remote_id_present && 0 > sa->old_id_expiration) { sa->old_remote_id_present = 0; diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index a47c59f578fd..4f64b56d8532 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -193,38 +193,52 @@ def __init__(self, test, is_initiator=True, i_id=None, r_id=None, else: self.rspi = spi self.ispi = 8 * b'\x00' - self.r_nonce = None + self.r_nonce = nonce self.child_sas = [IKEv2ChildSA(local_ts, remote_ts)] def new_msg_id(self): self.msg_id += 1 return self.msg_id - def dh_pub_key(self): + @property + def my_dh_pub_key(self): + if self.is_initiator: + return self.i_dh_data + return self.r_dh_data + + @property + def peer_dh_pub_key(self): + if self.is_initiator: + return self.r_dh_data return self.i_dh_data def compute_secret(self): priv = self.dh_private_key - peer = self.r_dh_data + peer = self.peer_dh_pub_key p, g, l = self.ike_group return pow(int.from_bytes(peer, 'big'), int.from_bytes(priv, 'big'), p).to_bytes(l, 'big') def generate_dh_data(self): # generate DH keys + if self.ike_dh not in DH: + raise NotImplementedError('%s not in DH group' % self.ike_dh) + + if self.dh_params is None: + dhg = DH[self.ike_dh] + pn = dh.DHParameterNumbers(dhg[0], dhg[1]) + self.dh_params = pn.parameters(default_backend()) + + priv = self.dh_params.generate_private_key() + pub = priv.public_key() + x = priv.private_numbers().x + self.dh_private_key = x.to_bytes(priv.key_size // 8, 'big') + y = pub.public_numbers().y + if self.is_initiator: - if self.ike_dh not in DH: - raise NotImplementedError('%s not in DH group' % self.ike_dh) - if self.dh_params is None: - dhg = DH[self.ike_dh] - pn = dh.DHParameterNumbers(dhg[0], dhg[1]) - self.dh_params = pn.parameters(default_backend()) - priv = self.dh_params.generate_private_key() - pub = priv.public_key() - x = priv.private_numbers().x - self.dh_private_key = x.to_bytes(priv.key_size // 8, 'big') - y = pub.public_numbers().y self.i_dh_data = y.to_bytes(pub.key_size // 8, 'big') + else: + self.r_dh_data = y.to_bytes(pub.key_size // 8, 'big') def complete_dh_data(self): self.dh_shared_secret = self.compute_secret() @@ -335,13 +349,21 @@ def generate_authmsg(self, prf, packet): id = self.i_id nonce = self.r_nonce key = self.sk_pi + else: + id = self.r_id + nonce = self.i_nonce + key = self.sk_pr data = bytes([self.id_type, 0, 0, 0]) + id id_hash = self.calc_prf(prf, key, data) return packet + nonce + id_hash def auth_init(self): prf = self.ike_prf_alg.mod() - authmsg = self.generate_authmsg(prf, raw(self.init_req_packet)) + if self.is_initiator: + packet = self.init_req_packet + else: + packet = self.init_resp_packet + authmsg = self.generate_authmsg(prf, raw(packet)) if self.auth_method == 'shared-key': psk = self.calc_prf(prf, self.auth_data, KEY_PAD) self.auth_data = self.calc_prf(prf, psk, authmsg) @@ -440,7 +462,10 @@ def generate_ts(self, is_ip4): ts1 = ikev2.IPv6TrafficSelector(**ts_data) ts_data.update(self.build_ts_addr(c.remote_ts, '6')) ts2 = ikev2.IPv6TrafficSelector(**ts_data) - return ([ts1], [ts2]) + + if self.is_initiator: + return ([ts1], [ts2]) + return ([ts2], [ts1]) def set_ike_props(self, crypto, crypto_key_len, integ, prf, dh): if crypto not in CRYPTO_ALGOS: @@ -492,14 +517,14 @@ def compute_nat_sha1(self, ip, port): return digest.finalize() -class TemplateResponder(VppTestCase): - """ responder test template """ +class IkePeer(VppTestCase): + """ common class for initiator and responder """ @classmethod def setUpClass(cls): import scapy.contrib.ikev2 as _ikev2 globals()['ikev2'] = _ikev2 - super(TemplateResponder, cls).setUpClass() + super(IkePeer, cls).setUpClass() cls.create_pg_interfaces(range(2)) for i in cls.pg_interfaces: i.admin_up() @@ -510,10 +535,10 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - super(TemplateResponder, cls).tearDownClass() + super(IkePeer, cls).tearDownClass() def setUp(self): - super(TemplateResponder, self).setUp() + super(IkePeer, self).setUp() self.config_tc() self.p.add_vpp_config() self.assertIsNotNone(self.p.query_vpp_config()) @@ -521,36 +546,6 @@ def setUp(self): self.vapi.cli('ikev2 set logging level 4') self.vapi.cli('event-lo clear') - def tearDown(self): - super(TemplateResponder, self).tearDown() - if self.sa.is_initiator: - self.initiate_del_sa() - r = self.vapi.ikev2_sa_dump() - self.assertEqual(len(r), 0) - - self.p.remove_vpp_config() - self.assertIsNone(self.p.query_vpp_config()) - - def verify_del_sa(self, packet): - ih = self.get_ike_header(packet) - self.assertEqual(ih.id, self.sa.msg_id) - self.assertEqual(ih.exch_type, 37) # exchange informational - - def initiate_del_sa(self): - header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, - flags='Initiator', exch_type='INFORMATIONAL', - id=self.sa.new_msg_id()) - del_sa = ikev2.IKEv2_payload_Delete(proto='IKEv2') - ike_msg = self.encrypt_ike_msg(header, del_sa, 'Delete') - packet = self.create_packet(self.pg0, ike_msg, - self.sa.sport, self.sa.dport, - self.sa.natt, self.ip6) - self.pg0.add_stream(packet) - self.pg0.enable_capture() - self.pg_start() - capture = self.pg0.get_capture(1) - self.verify_del_sa(capture[0]) - def create_packet(self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False): if use_ip6: @@ -569,60 +564,30 @@ def create_packet(self, src_if, msg, sport=500, dport=500, natt=False, res = res / Raw(b'\x00' * 4) return res / msg - def send_sa_init(self, behind_nat=False): - tr_attr = self.sa.ike_crypto_attr() - trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', - transform_id=self.sa.ike_crypto, length=tr_attr[1], - key_length=tr_attr[0]) / - ikev2.IKEv2_payload_Transform(transform_type='Integrity', - transform_id=self.sa.ike_integ) / - ikev2.IKEv2_payload_Transform(transform_type='PRF', - transform_id=self.sa.ike_prf_alg.name) / - ikev2.IKEv2_payload_Transform(transform_type='GroupDesc', - transform_id=self.sa.ike_dh)) - - props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', - trans_nb=4, trans=trans)) - - if behind_nat: - next_payload = 'Notify' - else: - next_payload = None + def verify_udp(self, udp): + self.assertEqual(udp.sport, self.sa.sport) + self.assertEqual(udp.dport, self.sa.dport) - self.sa.init_req_packet = ( - ikev2.IKEv2(init_SPI=self.sa.ispi, - flags='Initiator', exch_type='IKE_SA_INIT') / - ikev2.IKEv2_payload_SA(next_payload='KE', prop=props) / - ikev2.IKEv2_payload_KE(next_payload='Nonce', - group=self.sa.ike_dh, - load=self.sa.dh_pub_key()) / - ikev2.IKEv2_payload_Nonce(next_payload=next_payload, - load=self.sa.i_nonce)) + def get_ike_header(self, packet): + try: + ih = packet[ikev2.IKEv2] + except IndexError as e: + # this is a workaround for getting IKEv2 layer as both ikev2 and + # ipsec register for port 4500 + esp = packet[ESP] + ih = self.verify_and_remove_non_esp_marker(esp) + self.assertEqual(ih.version, 0x20) + return ih - if behind_nat: - src_address = b'\x0a\x0a\x0a\x01' + def verify_and_remove_non_esp_marker(self, packet): + if self.sa.natt: + # if we are in nat traversal mode check for non esp marker + # and remove it + data = raw(packet) + self.assertEqual(data[:4], b'\x00' * 4) + return ikev2.IKEv2(data[4:]) else: - src_address = bytes(self.pg0.local_ip4, 'ascii') - - src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) - dst_nat = self.sa.compute_nat_sha1(bytes(self.pg0.remote_ip4, 'ascii'), - self.sa.sport) - nat_src_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_SOURCE_IP', load=src_nat) - nat_dst_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) - self.sa.init_req_packet = (self.sa.init_req_packet / - nat_src_detection / - nat_dst_detection) - - ike_msg = self.create_packet(self.pg0, self.sa.init_req_packet, - self.sa.sport, self.sa.dport, - self.sa.natt, self.ip6) - self.pg0.add_stream(ike_msg) - self.pg0.enable_capture() - self.pg_start() - capture = self.pg0.get_capture(1) - self.verify_sa_init(capture[0]) + return packet def encrypt_ike_msg(self, header, plain, first_payload): if self.sa.ike_crypto == 'AES-GCM-16ICV': @@ -658,114 +623,17 @@ def encrypt_ike_msg(self, header, plain, first_payload): assert(len(res) == tlen) return res - def send_sa_auth(self): - tr_attr = self.sa.esp_crypto_attr() - trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', - transform_id=self.sa.esp_crypto, length=tr_attr[1], - key_length=tr_attr[0]) / - ikev2.IKEv2_payload_Transform(transform_type='Integrity', - transform_id=self.sa.esp_integ) / - ikev2.IKEv2_payload_Transform( - transform_type='Extended Sequence Number', - transform_id='No ESN') / - ikev2.IKEv2_payload_Transform( - transform_type='Extended Sequence Number', - transform_id='ESN')) - - props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', - SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) - - tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) - plain = (ikev2.IKEv2_payload_IDi(next_payload='IDr', - IDtype=self.sa.id_type, load=self.sa.i_id) / - ikev2.IKEv2_payload_IDr(next_payload='AUTH', - IDtype=self.sa.id_type, load=self.sa.r_id) / - ikev2.IKEv2_payload_AUTH(next_payload='SA', - auth_type=AuthMethod.value(self.sa.auth_method), - load=self.sa.auth_data) / - ikev2.IKEv2_payload_SA(next_payload='TSi', prop=props) / - ikev2.IKEv2_payload_TSi(next_payload='TSr', - number_of_TSs=len(tsi), - traffic_selector=tsi) / - ikev2.IKEv2_payload_TSr(next_payload='Notify', - number_of_TSs=len(tsr), - traffic_selector=tsr) / - ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT')) - - header = ikev2.IKEv2( - init_SPI=self.sa.ispi, - resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), - flags='Initiator', exch_type='IKE_AUTH') - - ike_msg = self.encrypt_ike_msg(header, plain, 'IDi') - packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, - self.sa.dport, self.sa.natt, self.ip6) - self.pg0.add_stream(packet) - self.pg0.enable_capture() - self.pg_start() - capture = self.pg0.get_capture(1) - self.verify_sa_auth(capture[0]) - - def get_ike_header(self, packet): - try: - ih = packet[ikev2.IKEv2] - except IndexError as e: - # this is a workaround for getting IKEv2 layer as both ikev2 and - # ipsec register for port 4500 - esp = packet[ESP] - ih = self.verify_and_remove_non_esp_marker(esp) - - self.assertEqual(ih.version, 0x20) - return ih - - def verify_sa_init(self, packet): - ih = self.get_ike_header(packet) - - self.assertEqual(ih.id, self.sa.msg_id) - self.assertEqual(ih.exch_type, 34) - self.assertTrue('Response' in ih.flags) - self.assertEqual(ih.init_SPI, self.sa.ispi) - self.assertNotEqual(ih.resp_SPI, 0) - self.sa.rspi = ih.resp_SPI - try: - sa = ih[ikev2.IKEv2_payload_SA] - self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load - self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load - except IndexError as e: - self.logger.error("unexpected reply: SA/Nonce/KE payload found!") - self.logger.error(ih.show()) - raise - self.sa.complete_dh_data() - self.sa.calc_keys() - self.sa.auth_init() - - def verify_and_remove_non_esp_marker(self, packet): - if self.sa.natt: - # if we are in nat traversal mode check for non esp marker - # and remove it - data = raw(packet) - self.assertEqual(data[:4], b'\x00' * 4) - return ikev2.IKEv2(data[4:]) - else: - return packet - - def verify_udp(self, udp): - self.assertEqual(udp.sport, self.sa.sport) - self.assertEqual(udp.dport, self.sa.dport) - - def verify_sa_auth(self, packet): - ike = self.get_ike_header(packet) - udp = packet[UDP] - self.verify_udp(udp) - self.assertEqual(ike.id, self.sa.msg_id) - plain = self.sa.hmac_and_decrypt(ike) - self.sa.calc_child_keys() - def verify_ipsec_sas(self): sas = self.vapi.ipsec_sa_dump() self.assertEqual(len(sas), 2) - sa0 = sas[0].entry - sa1 = sas[1].entry + e = VppEnum.vl_api_ipsec_sad_flags_t + if self.sa.is_initiator: + sa0 = sas[0].entry + sa1 = sas[1].entry + else: + sa1 = sas[0].entry + sa0 = sas[1].entry + c = self.sa.child_sas[0] vpp_crypto_alg = self.vpp_enums[self.sa.vpp_esp_cypto_alg] @@ -814,11 +682,19 @@ def verify_ike_sas(self): self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, 'big')) self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, 'big')) if self.ip6: - self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6)) - self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6)) + if self.sa.is_initiator: + self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6)) + self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6)) + else: + self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6)) + self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6)) else: - self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4)) - self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4)) + if self.sa.is_initiator: + self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4)) + self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4)) + else: + self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4)) + self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4)) self.verify_keymat(sa.keys, self.sa, 'sk_d') self.verify_keymat(sa.keys, self.sa, 'sk_ai') self.verify_keymat(sa.keys, self.sa, 'sk_ar') @@ -892,8 +768,314 @@ def verify_ts(self, api_ts, ts, is_initiator): self.assertEqual(api_ts.end_port, ts.end_port) self.assertEqual(api_ts.protocol_id, ts.IP_protocol_ID) + +class TemplateInitiator(IkePeer): + """ initiator test template """ + + def tearDown(self): + super(TemplateInitiator, self).tearDown() + + def verify_sa_init_request(self, packet): + ih = packet[ikev2.IKEv2] + self.assertNotEqual(ih.init_SPI, 8 * b'\x00') + self.assertEqual(ih.exch_type, 34) # SA_INIT + self.sa.ispi = ih.init_SPI + self.assertEqual(ih.resp_SPI, 8 * b'\x00') + self.assertIn('Initiator', ih.flags) + self.assertNotIn('Response', ih.flags) + self.sa.i_nonce = ih[ikev2.IKEv2_payload_Nonce].load + self.sa.i_dh_data = ih[ikev2.IKEv2_payload_KE].load + + prop = packet[ikev2.IKEv2_payload_Proposal] + self.assertEqual(prop.proto, 1) # proto = ikev2 + self.assertEqual(prop.proposal, 1) + self.assertEqual(prop.trans[0].transform_type, 1) # encryption + self.assertEqual(prop.trans[0].transform_id, + self.p.ike_transforms['crypto_alg']) + self.assertEqual(prop.trans[1].transform_type, 2) # prf + self.assertEqual(prop.trans[1].transform_id, 5) # "hmac-sha2-256" + self.assertEqual(prop.trans[2].transform_type, 4) # dh + self.assertEqual(prop.trans[2].transform_id, + self.p.ike_transforms['dh_group']) + + self.sa.complete_dh_data() + self.sa.calc_keys() + + def verify_sa_auth_req(self, packet): + ih = self.get_ike_header(packet) + self.assertEqual(ih.resp_SPI, self.sa.rspi) + self.assertEqual(ih.init_SPI, self.sa.ispi) + self.assertEqual(ih.exch_type, 35) # IKE_AUTH + self.assertIn('Initiator', ih.flags) + self.assertNotIn('Response', ih.flags) + + udp = packet[UDP] + self.verify_udp(udp) + self.assertEqual(ih.id, self.sa.msg_id + 1) + self.sa.msg_id += 1 + plain = self.sa.hmac_and_decrypt(ih) + idi = ikev2.IKEv2_payload_IDi(plain) + idr = ikev2.IKEv2_payload_IDr(idi.payload) + self.assertEqual(idi.load, self.sa.i_id) + self.assertEqual(idr.load, self.sa.r_id) + + def send_init_response(self): + tr_attr = self.sa.ike_crypto_attr() + trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', + transform_id=self.sa.ike_crypto, length=tr_attr[1], + key_length=tr_attr[0]) / + ikev2.IKEv2_payload_Transform(transform_type='Integrity', + transform_id=self.sa.ike_integ) / + ikev2.IKEv2_payload_Transform(transform_type='PRF', + transform_id=self.sa.ike_prf_alg.name) / + ikev2.IKEv2_payload_Transform(transform_type='GroupDesc', + transform_id=self.sa.ike_dh)) + props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', + trans_nb=4, trans=trans)) + self.sa.init_resp_packet = ( + ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + exch_type='IKE_SA_INIT', flags='Response') / + ikev2.IKEv2_payload_SA(next_payload='KE', prop=props) / + ikev2.IKEv2_payload_KE(next_payload='Nonce', + group=self.sa.ike_dh, + load=self.sa.my_dh_pub_key) / + ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce)) + + ike_msg = self.create_packet(self.pg0, self.sa.init_resp_packet, + self.sa.sport, self.sa.dport, + self.sa.natt, self.ip6) + self.pg_send(self.pg0, ike_msg) + capture = self.pg0.get_capture(1) + self.verify_sa_auth_req(capture[0]) + + def initiate_sa_init(self): + self.pg0.enable_capture() + self.pg_start() + self.vapi.ikev2_initiate_sa_init(name=self.p.profile_name) + + capture = self.pg0.get_capture(1) + self.verify_sa_init_request(capture[0]) + self.send_init_response() + + def send_auth_response(self): + tr_attr = self.sa.esp_crypto_attr() + trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', + transform_id=self.sa.esp_crypto, length=tr_attr[1], + key_length=tr_attr[0]) / + ikev2.IKEv2_payload_Transform(transform_type='Integrity', + transform_id=self.sa.esp_integ) / + ikev2.IKEv2_payload_Transform( + transform_type='Extended Sequence Number', + transform_id='No ESN') / + ikev2.IKEv2_payload_Transform( + transform_type='Extended Sequence Number', + transform_id='ESN')) + + props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', + SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) + + tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) + plain = (ikev2.IKEv2_payload_IDi(next_payload='IDr', + IDtype=self.sa.id_type, load=self.sa.i_id) / + ikev2.IKEv2_payload_IDr(next_payload='AUTH', + IDtype=self.sa.id_type, load=self.sa.r_id) / + ikev2.IKEv2_payload_AUTH(next_payload='SA', + auth_type=AuthMethod.value(self.sa.auth_method), + load=self.sa.auth_data) / + ikev2.IKEv2_payload_SA(next_payload='TSi', prop=props) / + ikev2.IKEv2_payload_TSi(next_payload='TSr', + number_of_TSs=len(tsi), + traffic_selector=tsi) / + ikev2.IKEv2_payload_TSr(next_payload='Notify', + number_of_TSs=len(tsr), + traffic_selector=tsr) / + ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT')) + + header = ikev2.IKEv2( + init_SPI=self.sa.ispi, + resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), + flags='Response', exch_type='IKE_AUTH') + + ike_msg = self.encrypt_ike_msg(header, plain, 'IDi') + packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + self.pg_send(self.pg0, packet) + + def test_initiator(self): + self.initiate_sa_init() + self.sa.auth_init() + self.sa.calc_child_keys() + self.send_auth_response() + self.verify_ike_sas() + + +class TemplateResponder(IkePeer): + """ responder test template """ + + def tearDown(self): + super(TemplateResponder, self).tearDown() + if self.sa.is_initiator: + self.initiate_del_sa() + r = self.vapi.ikev2_sa_dump() + self.assertEqual(len(r), 0) + + self.p.remove_vpp_config() + self.assertIsNone(self.p.query_vpp_config()) + + def verify_del_sa(self, packet): + ih = self.get_ike_header(packet) + self.assertEqual(ih.id, self.sa.msg_id) + self.assertEqual(ih.exch_type, 37) # exchange informational + + def initiate_del_sa(self): + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + flags='Initiator', exch_type='INFORMATIONAL', + id=self.sa.new_msg_id()) + del_sa = ikev2.IKEv2_payload_Delete(proto='IKEv2') + ike_msg = self.encrypt_ike_msg(header, del_sa, 'Delete') + packet = self.create_packet(self.pg0, ike_msg, + self.sa.sport, self.sa.dport, + self.sa.natt, self.ip6) + self.pg0.add_stream(packet) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + self.verify_del_sa(capture[0]) + + def send_sa_init_req(self, behind_nat=False): + tr_attr = self.sa.ike_crypto_attr() + trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', + transform_id=self.sa.ike_crypto, length=tr_attr[1], + key_length=tr_attr[0]) / + ikev2.IKEv2_payload_Transform(transform_type='Integrity', + transform_id=self.sa.ike_integ) / + ikev2.IKEv2_payload_Transform(transform_type='PRF', + transform_id=self.sa.ike_prf_alg.name) / + ikev2.IKEv2_payload_Transform(transform_type='GroupDesc', + transform_id=self.sa.ike_dh)) + + props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', + trans_nb=4, trans=trans)) + + if behind_nat: + next_payload = 'Notify' + else: + next_payload = None + + self.sa.init_req_packet = ( + ikev2.IKEv2(init_SPI=self.sa.ispi, + flags='Initiator', exch_type='IKE_SA_INIT') / + ikev2.IKEv2_payload_SA(next_payload='KE', prop=props) / + ikev2.IKEv2_payload_KE(next_payload='Nonce', + group=self.sa.ike_dh, + load=self.sa.my_dh_pub_key) / + ikev2.IKEv2_payload_Nonce(next_payload=next_payload, + load=self.sa.i_nonce)) + + if behind_nat: + src_address = b'\x0a\x0a\x0a\x01' + else: + src_address = bytes(self.pg0.local_ip4, 'ascii') + + src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) + dst_nat = self.sa.compute_nat_sha1(bytes(self.pg0.remote_ip4, 'ascii'), + self.sa.sport) + nat_src_detection = ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_SOURCE_IP', load=src_nat) + nat_dst_detection = ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) + self.sa.init_req_packet = (self.sa.init_req_packet / + nat_src_detection / + nat_dst_detection) + + ike_msg = self.create_packet(self.pg0, self.sa.init_req_packet, + self.sa.sport, self.sa.dport, + self.sa.natt, self.ip6) + self.pg0.add_stream(ike_msg) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + self.verify_sa_init(capture[0]) + + def send_sa_auth(self): + tr_attr = self.sa.esp_crypto_attr() + trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', + transform_id=self.sa.esp_crypto, length=tr_attr[1], + key_length=tr_attr[0]) / + ikev2.IKEv2_payload_Transform(transform_type='Integrity', + transform_id=self.sa.esp_integ) / + ikev2.IKEv2_payload_Transform( + transform_type='Extended Sequence Number', + transform_id='No ESN') / + ikev2.IKEv2_payload_Transform( + transform_type='Extended Sequence Number', + transform_id='ESN')) + + props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', + SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) + + tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) + plain = (ikev2.IKEv2_payload_IDi(next_payload='IDr', + IDtype=self.sa.id_type, load=self.sa.i_id) / + ikev2.IKEv2_payload_IDr(next_payload='AUTH', + IDtype=self.sa.id_type, load=self.sa.r_id) / + ikev2.IKEv2_payload_AUTH(next_payload='SA', + auth_type=AuthMethod.value(self.sa.auth_method), + load=self.sa.auth_data) / + ikev2.IKEv2_payload_SA(next_payload='TSi', prop=props) / + ikev2.IKEv2_payload_TSi(next_payload='TSr', + number_of_TSs=len(tsi), + traffic_selector=tsi) / + ikev2.IKEv2_payload_TSr(next_payload='Notify', + number_of_TSs=len(tsr), + traffic_selector=tsr) / + ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT')) + + header = ikev2.IKEv2( + init_SPI=self.sa.ispi, + resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), + flags='Initiator', exch_type='IKE_AUTH') + + ike_msg = self.encrypt_ike_msg(header, plain, 'IDi') + packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + self.pg0.add_stream(packet) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + self.verify_sa_auth_resp(capture[0]) + + def verify_sa_init(self, packet): + ih = self.get_ike_header(packet) + + self.assertEqual(ih.id, self.sa.msg_id) + self.assertEqual(ih.exch_type, 34) + self.assertTrue('Response' in ih.flags) + self.assertEqual(ih.init_SPI, self.sa.ispi) + self.assertNotEqual(ih.resp_SPI, 0) + self.sa.rspi = ih.resp_SPI + try: + sa = ih[ikev2.IKEv2_payload_SA] + self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load + self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load + except IndexError as e: + self.logger.error("unexpected reply: SA/Nonce/KE payload found!") + self.logger.error(ih.show()) + raise + self.sa.complete_dh_data() + self.sa.calc_keys() + self.sa.auth_init() + + def verify_sa_auth_resp(self, packet): + ike = self.get_ike_header(packet) + udp = packet[UDP] + self.verify_udp(udp) + self.assertEqual(ike.id, self.sa.msg_id) + plain = self.sa.hmac_and_decrypt(ike) + self.sa.calc_child_keys() + def test_responder(self): - self.send_sa_init(self.sa.natt) + self.send_sa_init_req(self.sa.natt) self.send_sa_auth() self.verify_ipsec_sas() self.verify_ike_sas() @@ -942,17 +1124,33 @@ def config_params(self, params={}): auth_method = 'shared-key' client_priv = None - self.p.add_local_id(id_type='fqdn', data=b'vpp.home') - self.p.add_remote_id(id_type='fqdn', data=b'roadwarrior.example.com') + is_init = True if 'is_initiator' not in params else\ + params['is_initiator'] + + idr = {'id_type': 'fqdn', 'data': b'vpp.home'} + idi = {'id_type': 'fqdn', 'data': b'roadwarrior.example.com'} + if is_init: + self.p.add_local_id(**idr) + self.p.add_remote_id(**idi) + else: + self.p.add_local_id(**idi) + self.p.add_remote_id(**idr) + loc_ts = {'start_addr': '10.10.10.0', 'end_addr': '10.10.10.255'} if\ 'loc_ts' not in params else params['loc_ts'] rem_ts = {'start_addr': '10.0.0.0', 'end_addr': '10.0.0.255'} if\ 'rem_ts' not in params else params['rem_ts'] self.p.add_local_ts(**loc_ts) self.p.add_remote_ts(**rem_ts) - - self.sa = IKEv2SA(self, i_id=self.p.remote_id['data'], - r_id=self.p.local_id['data'], + if 'responder' in params: + self.p.add_responder(params['responder']) + if 'ike_transforms' in params: + self.p.add_ike_transforms(params['ike_transforms']) + if 'esp_transforms' in params: + self.p.add_esp_transforms(params['esp_transforms']) + + self.sa = IKEv2SA(self, i_id=idi['data'], r_id=idr['data'], + is_initiator=is_init, id_type=self.p.local_id['id_type'], natt=is_natt, priv_key=client_priv, auth_method=auth_method, auth_data=auth_data, @@ -962,7 +1160,8 @@ def config_params(self, params={}): params['ike-crypto'] ike_integ = 'HMAC-SHA1-96' if 'ike-integ' not in params else\ params['ike-integ'] - ike_dh = '2048MODPgr' if 'ike-dh' not in params else params['ike-dh'] + ike_dh = '2048MODPgr' if 'ike-dh' not in params else\ + params['ike-dh'] esp_crypto = ('AES-CBC', 32) if 'esp-crypto' not in params else\ params['esp-crypto'] @@ -1160,6 +1359,29 @@ def verify_profile(self, ap, cp): self.assertEqual(ap.tun_itf, 0xffffffff) +class TestInitiatorPsk(TemplateInitiator, Ikev2Params): + """ test ikev2 initiator - pre shared key auth """ + def config_tc(self): + self.config_params({ + 'is_initiator': False, # seen from test case perspective + # thus vpp is initiator + 'responder': {'sw_if_index': self.pg0.sw_if_index, + 'addr': self.pg0.remote_ip4}, + 'ike-crypto': ('AES-GCM-16ICV', 32), + 'ike-integ': 'NULL', + 'ike-dh': '3072MODPgr', + 'ike_transforms': { + 'crypto_alg': 20, # "aes-gcm-16" + 'crypto_key_size': 256, + 'dh_group': 15, # "modp-3072" + }, + 'esp_transforms': { + 'crypto_alg': 12, # "aes-cbc" + 'crypto_key_size': 256, + # "hmac-sha2-256-128" + 'integ_alg': 12}}) + + class TestResponderNATT(TemplateResponder, Ikev2Params): """ test ikev2 responder - nat traversal """ def config_tc(self): From 83c70b7a5afd230ab38544e55ec853646de4daf6 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 7 Oct 2020 19:17:00 +0000 Subject: [PATCH 102/129] ikev2: prevent crash after no IP address Type: fix Ticket: VPP-1900 This fixes a crash when initiating IKE connection using interface without any IP address. It also ensures that the IKE connection is automatically retried once the interface obtains an address. Signed-off-by: jan_cavojsky Signed-off-by: Filip Tehlar Change-Id: Ia1919c349e64b3a0a4198365e075e177e3ba3de5 (cherry picked from commit 6960da528443ea40b1cdab323c76f978f7b16a8b) --- src/plugins/ikev2/ikev2.c | 541 ++++++++++++++++++++++++-------------- 1 file changed, 345 insertions(+), 196 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 49fb6b66f0a6..b306d75b7b05 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -3594,56 +3594,62 @@ ikev2_unregister_udp_port (ikev2_profile_t * p) static void ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, ikev2_main_per_thread_data_t * tkm, - ikev2_sa_t * sa) + ikev2_sa_t * sa, u8 send_notification) { ikev2_main_t *km = &ikev2_main; ip_address_t *src, *dst; vlib_buffer_t *b0; + ikev2_child_sa_t *c; /* Create the Initiator notification for IKE SA removal */ ike_header_t *ike0; u32 bi0 = 0; int len; - bi0 = ikev2_get_new_ike_header_buff (vm, &b0); - if (!bi0) - { - ikev2_log_error ("buffer alloc failure"); - return; - } - - ike0 = vlib_buffer_get_current (b0); - ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; - ike0->ispi = clib_host_to_net_u64 (sa->ispi); - ike0->rspi = clib_host_to_net_u64 (sa->rspi); vec_resize (sa->del, 1); sa->del->protocol_id = IKEV2_PROTOCOL_IKE; sa->del->spi = sa->ispi; - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (b0, sa, ike0, 0, 0); - if (~0 == len) - return; - if (sa->natt) - len = ikev2_insert_non_esp_marker (ike0, len); - - if (sa->is_initiator) + if (send_notification) { - src = &sa->iaddr; - dst = &sa->raddr; - } - else - { - dst = &sa->iaddr; - src = &sa->raddr; - } + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); + if (!bi0) + { + ikev2_log_error ("buffer alloc failure"); + goto delete_sa; + } + + ike0 = vlib_buffer_get_current (b0); + ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; + ike0->ispi = clib_host_to_net_u64 (sa->ispi); + ike0->rspi = clib_host_to_net_u64 (sa->rspi); + + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); + sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + len = ikev2_generate_message (b0, sa, ike0, 0, 0); + if (~0 == len) + return; - ikev2_send_ike (vm, src, dst, bi0, len, - ikev2_get_port (sa), sa->dst_port, 0); + if (sa->natt) + len = ikev2_insert_non_esp_marker (ike0, len); + if (sa->is_initiator) + { + src = &sa->iaddr; + dst = &sa->raddr; + } + else + { + dst = &sa->iaddr; + src = &sa->raddr; + } + + ikev2_send_ike (vm, src, dst, bi0, len, + ikev2_get_port (sa), sa->dst_port, 0); + } + +delete_sa: /* delete local SA */ - ikev2_child_sa_t *c; vec_foreach (c, sa->childs) ikev2_delete_tunnel_interface (km->vnet_main, sa, c); @@ -3694,7 +3700,7 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p) vec_foreach (sai, del_sai) { sa = pool_elt_at_index (tkm->sas, sai[0]); - ikev2_initiate_delete_ike_sa_internal (km->vlib_main, tkm, sa); + ikev2_initiate_delete_ike_sa_internal (km->vlib_main, tkm, sa, 1); } vec_reset_length (del_sai); @@ -4051,12 +4057,45 @@ ikev2_set_profile_sa_lifetime (vlib_main_t * vm, u8 * name, return 0; } +static int +ikev2_get_if_address (u32 sw_if_index, ip_address_family_t af, + ip_address_t * out_addr) +{ + ip4_address_t *if_ip4; + ip6_address_t *if_ip6; + + if (af == AF_IP4) + { + if_ip4 = ip4_interface_first_address (&ip4_main, sw_if_index, 0); + if (if_ip4) + { + ip_address_set (out_addr, if_ip4, AF_IP4); + return 1; + } + } + else + { + if_ip6 = ip6_interface_first_address (&ip6_main, sw_if_index); + if (if_ip6) + { + ip_address_set (out_addr, if_ip6, AF_IP6); + return 1; + } + } + return 0; +} + clib_error_t * ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) { ikev2_profile_t *p; clib_error_t *r; ikev2_main_t *km = &ikev2_main; + vlib_buffer_t *b0; + ike_header_t *ike0; + u32 bi0 = 0; + int len = sizeof (ike_header_t), valid_ip = 0; + ip_address_t if_ip = { }; p = ikev2_profile_index_by_name (name); @@ -4073,159 +4112,145 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) return r; } + if (ikev2_get_if_address (p->responder.sw_if_index, + ip_addr_version (&p->responder.addr), &if_ip)) + { + valid_ip = 1; + } - /* Create the Initiator Request */ - { - vlib_buffer_t *b0; - ike_header_t *ike0; - u32 bi0 = 0; - int len = sizeof (ike_header_t); - ip4_address_t *if_ip4; - ip6_address_t *if_ip6; - ip_address_t if_ip = IP_ADDRESS_V4_ALL_0S; - - if (ip_addr_version (&p->responder.addr) == AF_IP4) - { - if_ip4 = ip4_interface_first_address (&ip4_main, - p->responder.sw_if_index, 0); - if (if_ip4) - { - ip_address_set (&if_ip, if_ip4, AF_IP4); - } - } - else - { - if_ip6 = ip6_interface_first_address (&ip6_main, - p->responder.sw_if_index); - if (if_ip6) - { - ip_address_set (&if_ip, if_ip6, AF_IP6); - } - } + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); + if (!bi0) + { + char *errmsg = "buffer alloc failure"; + ikev2_log_error (errmsg); + return clib_error_return (0, errmsg); + } + ike0 = vlib_buffer_get_current (b0); - bi0 = ikev2_get_new_ike_header_buff (vm, &b0); - if (!bi0) - { - char *errmsg = "buffer alloc failure"; - ikev2_log_error (errmsg); - return clib_error_return (0, errmsg); - } - ike0 = vlib_buffer_get_current (b0); - - /* Prepare the SA and the IKE payload */ - ikev2_sa_t sa; - clib_memset (&sa, 0, sizeof (ikev2_sa_t)); - ikev2_payload_chain_t *chain = 0; - ikev2_payload_new_chain (chain); - - /* Build the IKE proposal payload */ - ikev2_sa_proposal_t *proposals = 0; - ikev2_set_initiator_proposals (vm, &sa, &p->ike_ts, &proposals, 1); - proposals[0].proposal_num = 1; - proposals[0].protocol_id = IKEV2_PROTOCOL_IKE; - - /* Add and then cleanup proposal data */ - ikev2_payload_add_sa (chain, proposals); - ikev2_sa_free_proposal_vector (&proposals); - - sa.is_initiator = 1; - sa.profile_index = p - km->profiles; - sa.state = IKEV2_STATE_SA_INIT; - sa.tun_itf = p->tun_itf; - sa.udp_encap = p->udp_encap; - sa.ipsec_over_udp_port = p->ipsec_over_udp_port; - sa.is_tun_itf_set = 1; - sa.initial_contact = 1; - sa.dst_port = IKEV2_PORT; - ikev2_generate_sa_init_data (&sa); - ikev2_payload_add_ke (chain, sa.dh_group, sa.i_dh_data); - ikev2_payload_add_nonce (chain, sa.i_nonce); - - /* Build the child SA proposal */ - vec_resize (sa.childs, 1); - ikev2_set_initiator_proposals (vm, &sa, &p->esp_ts, - &sa.childs[0].i_proposals, 0); - sa.childs[0].i_proposals[0].proposal_num = 1; - sa.childs[0].i_proposals[0].protocol_id = IKEV2_PROTOCOL_ESP; - RAND_bytes ((u8 *) & sa.childs[0].i_proposals[0].spi, - sizeof (sa.childs[0].i_proposals[0].spi)); - - /* Add NAT detection notification messages (mandatory) */ - u8 *nat_detection_sha1 = - ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), - clib_host_to_net_u64 (sa.rspi), - &if_ip, clib_host_to_net_u16 (IKEV2_PORT)); - - ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP, - nat_detection_sha1); - vec_free (nat_detection_sha1); - nat_detection_sha1 = - ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), - clib_host_to_net_u64 (sa.rspi), - &p->responder.addr, - clib_host_to_net_u16 (sa.dst_port)); - ikev2_payload_add_notify (chain, - IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP, - nat_detection_sha1); - vec_free (nat_detection_sha1); - - u8 *sig_hash_algo = vec_new (u8, 8); - u64 tmpsig = clib_host_to_net_u64 (0x0001000200030004); - clib_memcpy_fast (sig_hash_algo, &tmpsig, sizeof (tmpsig)); - ikev2_payload_add_notify (chain, - IKEV2_NOTIFY_MSG_SIGNATURE_HASH_ALGORITHMS, - sig_hash_algo); - vec_free (sig_hash_algo); - - - /* Buffer update and boilerplate */ - len += vec_len (chain->data); - ike0->nextpayload = chain->first_payload_type; - ike0->length = clib_host_to_net_u32 (len); - clib_memcpy_fast (ike0->payload, chain->data, vec_len (chain->data)); - ikev2_payload_destroy_chain (chain); - - ike0->version = IKE_VERSION_2; - ike0->flags = IKEV2_HDR_FLAG_INITIATOR; - ike0->exchange = IKEV2_EXCHANGE_SA_INIT; - ike0->ispi = clib_host_to_net_u64 (sa.ispi); - ike0->rspi = 0; - ike0->msgid = 0; - - /* store whole IKE payload - needed for PSK auth */ - vec_reset_length (sa.last_sa_init_req_packet_data); - vec_add (sa.last_sa_init_req_packet_data, ike0, len); - - /* add data to the SA then add it to the pool */ - ip_address_copy (&sa.iaddr, &if_ip); - ip_address_copy (&sa.raddr, &p->responder.addr); - sa.i_id.type = p->loc_id.type; - sa.i_id.data = vec_dup (p->loc_id.data); - sa.r_id.type = p->rem_id.type; - sa.r_id.data = vec_dup (p->rem_id.data); - sa.i_auth.method = p->auth.method; - sa.i_auth.hex = p->auth.hex; - sa.i_auth.data = vec_dup (p->auth.data); - sa.sw_if_index = p->responder.sw_if_index; - vec_add (sa.childs[0].tsi, &p->loc_ts, 1); - vec_add (sa.childs[0].tsr, &p->rem_ts, 1); - - ikev2_initial_contact_cleanup (0, &sa); - - /* add SA to the pool */ - ikev2_sa_t *sa0 = 0; - pool_get (km->sais, sa0); - clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); - hash_set (km->sa_by_ispi, sa0->ispi, sa0 - km->sais); - - ikev2_send_ike (vm, &if_ip, &p->responder.addr, bi0, len, - IKEV2_PORT, sa.dst_port, sa.sw_if_index); - - ikev2_elog_exchange ("ispi %lx rspi %lx IKEV2_EXCHANGE_SA_INIT sent to ", - clib_host_to_net_u64 (sa0->ispi), 0, - ip_addr_v4 (&p->responder.addr).as_u32, - ip_addr_version (&p->responder.addr) == AF_IP4); - } + /* Prepare the SA and the IKE payload */ + ikev2_sa_t sa; + clib_memset (&sa, 0, sizeof (ikev2_sa_t)); + ikev2_payload_chain_t *chain = 0; + ikev2_payload_new_chain (chain); + + /* Build the IKE proposal payload */ + ikev2_sa_proposal_t *proposals = 0; + ikev2_set_initiator_proposals (vm, &sa, &p->ike_ts, &proposals, 1); + proposals[0].proposal_num = 1; + proposals[0].protocol_id = IKEV2_PROTOCOL_IKE; + + /* Add and then cleanup proposal data */ + ikev2_payload_add_sa (chain, proposals); + ikev2_sa_free_proposal_vector (&proposals); + + sa.is_initiator = 1; + sa.profile_index = p - km->profiles; + sa.state = IKEV2_STATE_SA_INIT; + sa.tun_itf = p->tun_itf; + sa.udp_encap = p->udp_encap; + sa.ipsec_over_udp_port = p->ipsec_over_udp_port; + sa.is_tun_itf_set = 1; + sa.initial_contact = 1; + sa.dst_port = IKEV2_PORT; + ikev2_generate_sa_init_data (&sa); + ikev2_payload_add_ke (chain, sa.dh_group, sa.i_dh_data); + ikev2_payload_add_nonce (chain, sa.i_nonce); + + /* Build the child SA proposal */ + vec_resize (sa.childs, 1); + ikev2_set_initiator_proposals (vm, &sa, &p->esp_ts, + &sa.childs[0].i_proposals, 0); + sa.childs[0].i_proposals[0].proposal_num = 1; + sa.childs[0].i_proposals[0].protocol_id = IKEV2_PROTOCOL_ESP; + RAND_bytes ((u8 *) & sa.childs[0].i_proposals[0].spi, + sizeof (sa.childs[0].i_proposals[0].spi)); + + /* Add NAT detection notification messages (mandatory) */ + u8 *nat_detection_sha1 = + ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), + clib_host_to_net_u64 (sa.rspi), + &if_ip, clib_host_to_net_u16 (IKEV2_PORT)); + + ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP, + nat_detection_sha1); + vec_free (nat_detection_sha1); + nat_detection_sha1 = + ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi), + clib_host_to_net_u64 (sa.rspi), + &p->responder.addr, + clib_host_to_net_u16 (sa.dst_port)); + ikev2_payload_add_notify (chain, + IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP, + nat_detection_sha1); + vec_free (nat_detection_sha1); + + u8 *sig_hash_algo = vec_new (u8, 8); + u64 tmpsig = clib_host_to_net_u64 (0x0001000200030004); + clib_memcpy_fast (sig_hash_algo, &tmpsig, sizeof (tmpsig)); + ikev2_payload_add_notify (chain, + IKEV2_NOTIFY_MSG_SIGNATURE_HASH_ALGORITHMS, + sig_hash_algo); + vec_free (sig_hash_algo); + + /* Buffer update and boilerplate */ + len += vec_len (chain->data); + ike0->nextpayload = chain->first_payload_type; + ike0->length = clib_host_to_net_u32 (len); + clib_memcpy_fast (ike0->payload, chain->data, vec_len (chain->data)); + ikev2_payload_destroy_chain (chain); + + ike0->version = IKE_VERSION_2; + ike0->flags = IKEV2_HDR_FLAG_INITIATOR; + ike0->exchange = IKEV2_EXCHANGE_SA_INIT; + ike0->ispi = clib_host_to_net_u64 (sa.ispi); + ike0->rspi = 0; + ike0->msgid = 0; + + /* store whole IKE payload - needed for PSK auth */ + vec_reset_length (sa.last_sa_init_req_packet_data); + vec_add (sa.last_sa_init_req_packet_data, ike0, len); + + /* add data to the SA then add it to the pool */ + ip_address_copy (&sa.iaddr, &if_ip); + ip_address_copy (&sa.raddr, &p->responder.addr); + sa.i_id.type = p->loc_id.type; + sa.i_id.data = vec_dup (p->loc_id.data); + sa.r_id.type = p->rem_id.type; + sa.r_id.data = vec_dup (p->rem_id.data); + sa.i_auth.method = p->auth.method; + sa.i_auth.hex = p->auth.hex; + sa.i_auth.data = vec_dup (p->auth.data); + sa.sw_if_index = p->responder.sw_if_index; + vec_add (sa.childs[0].tsi, &p->loc_ts, 1); + vec_add (sa.childs[0].tsr, &p->rem_ts, 1); + + ikev2_initial_contact_cleanup (0, &sa); + + /* add SA to the pool */ + ikev2_sa_t *sa0 = 0; + pool_get (km->sais, sa0); + clib_memcpy_fast (sa0, &sa, sizeof (*sa0)); + hash_set (km->sa_by_ispi, sa0->ispi, sa0 - km->sais); + + if (valid_ip) + { + ikev2_send_ike (vm, &if_ip, &p->responder.addr, bi0, len, + IKEV2_PORT, sa.dst_port, sa.sw_if_index); + + ikev2_elog_exchange + ("ispi %lx rspi %lx IKEV2_EXCHANGE_SA_INIT sent to ", + clib_host_to_net_u64 (sa0->ispi), 0, + ip_addr_v4 (&p->responder.addr).as_u32, + ip_addr_version (&p->responder.addr) == AF_IP4); + } + else + { + r = + clib_error_return (0, "interface %U does not have any IP address!", + format_vnet_sw_if_index_name, vnet_get_main (), + p->responder.sw_if_index); + return r; + } return 0; } @@ -4344,7 +4369,7 @@ ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi) return r; } - ikev2_initiate_delete_ike_sa_internal (vm, ftkm, fsa); + ikev2_initiate_delete_ike_sa_internal (vm, ftkm, fsa, 1); return 0; } @@ -4433,6 +4458,74 @@ ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi) return 0; } +static int +ikev2_sa_sw_if_match (ikev2_sa_t * sa, u32 sw_if_index) +{ + return (sa->sw_if_index == sw_if_index) && sa->is_initiator; +} + +static void +ikev2_sa_del (ikev2_profile_t * p, u32 sw_if_index) +{ + u64 *ispi, *ispi_vec = 0; + ikev2_sa_t *sa, **sap, **sa_vec = 0; + ikev2_main_t *km = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + p->responder.sw_if_index = ~0; + + vec_foreach (tkm, km->per_thread_data) + { + /* *INDENT-OFF* */ + pool_foreach (sa, tkm->sas, ({ + if (ikev2_sa_sw_if_match (sa, sw_if_index)) + vec_add1 (sa_vec, sa); + })); + /* *INDENT-ON* */ + + vec_foreach (sap, sa_vec) + { + ikev2_initiate_delete_ike_sa_internal (km->vlib_main, tkm, *sap, 0); + } + vec_reset_length (sa_vec); + } + vec_free (sa_vec); + + /* *INDENT-OFF* */ + pool_foreach (sa, km->sais, ({ + if (ikev2_sa_sw_if_match (sa, sw_if_index)) + vec_add1 (ispi_vec, sa->ispi); + })); + /* *INDENT-ON* */ + + vec_foreach (ispi, ispi_vec) + { + ikev2_del_sa_init_from_main (ispi); + } + + vec_free (ispi_vec); +} + +static clib_error_t * +ikev2_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) +{ + ikev2_main_t *km = &ikev2_main; + ikev2_profile_t *p; + + if (is_add) + return 0; + + /* *INDENT-OFF* */ + pool_foreach (p, km->profiles, ({ + if (p->responder.sw_if_index == sw_if_index) + ikev2_sa_del (p, sw_if_index); + })); + /* *INDENT-ON* */ + + return 0; +} + +VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ikev2_sw_interface_add_del); + clib_error_t * ikev2_init (vlib_main_t * vm) { @@ -4665,6 +4758,72 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) } } +static ike_payload_header_t * +ikev2_find_ike_payload (ike_header_t * ike, u32 payload_type) +{ + int p = 0; + ike_payload_header_t *ikep; + u32 payload = ike->nextpayload; + + while (payload != IKEV2_PAYLOAD_NONE) + { + ikep = (ike_payload_header_t *) & ike->payload[p]; + if (payload == payload_type) + return ikep; + + u16 plen = clib_net_to_host_u16 (ikep->length); + payload = ikep->nextpayload; + p += plen; + } + return 0; +} + +static void +ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) +{ + ikev2_profile_t *p; + u32 bi0; + u8 *nat_sha; + ike_payload_header_t *ph; + + if (ip_address_is_zero (&sa->iaddr)) + { + p = pool_elt_at_index (km->profiles, sa->profile_index); + if (!ikev2_get_if_address (p->responder.sw_if_index, + ip_addr_version (&p->responder.addr), + &sa->iaddr)) + return; + + /* update NAT detection payload */ + ph = + ikev2_find_ike_payload ((ike_header_t *) + sa->last_sa_init_req_packet_data, + IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); + if (!ph) + return; + + nat_sha = + ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), + clib_host_to_net_u64 (sa->rspi), + &sa->iaddr, + clib_host_to_net_u16 (IKEV2_PORT)); + clib_memcpy_fast (ph->payload, nat_sha, vec_len (nat_sha)); + vec_free (nat_sha); + } + + if (vlib_buffer_alloc (km->vlib_main, &bi0, 1) != 1) + return; + + vlib_buffer_t *b = vlib_get_buffer (km->vlib_main, bi0); + clib_memcpy_fast (vlib_buffer_get_current (b), + sa->last_sa_init_req_packet_data, + vec_len (sa->last_sa_init_req_packet_data)); + + ikev2_send_ike (km->vlib_main, &sa->iaddr, &sa->raddr, bi0, + vec_len (sa->last_sa_init_req_packet_data), + ikev2_get_port (sa), IKEV2_PORT, sa->sw_if_index); +} + static void ikev2_process_pending_sa_init (ikev2_main_t * km) { @@ -4679,17 +4838,7 @@ ikev2_process_pending_sa_init (ikev2_main_t * km) if (sa->init_response_received) continue; - u32 bi0; - if (vlib_buffer_alloc (km->vlib_main, &bi0, 1) != 1) - return; - - vlib_buffer_t * b = vlib_get_buffer (km->vlib_main, bi0); - clib_memcpy_fast (vlib_buffer_get_current (b), - sa->last_sa_init_req_packet_data, - vec_len (sa->last_sa_init_req_packet_data)); - ikev2_send_ike (km->vlib_main, &sa->iaddr, &sa->raddr, bi0, - vec_len (sa->last_sa_init_req_packet_data), - ikev2_get_port (sa), IKEV2_PORT, sa->sw_if_index); + ikev2_process_pending_sa_init_one (km, sa); })); /* *INDENT-ON* */ } From 233b12d11d6114e34f552f5b921dbfff1bca5205 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 7 Oct 2020 23:52:37 +0000 Subject: [PATCH 103/129] ikev2: fix setting responder/initiator addresses Type: fix Change-Id: Ic406aa914d92e802a5fb0f27c2ffa1b98db012b0 Signed-off-by: Filip Tehlar (cherry picked from commit ec112e5a9eb708c1ee85faf569fef6fa40178294) --- src/plugins/ikev2/ikev2.c | 82 +++++++++------------------- src/plugins/ikev2/ikev2_payload.c | 24 ++++++++ src/plugins/ikev2/ikev2_priv.h | 1 + src/plugins/ikev2/test/test_ikev2.py | 55 +++++++++++++++---- 4 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index b306d75b7b05..03e85d543f88 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -641,7 +641,7 @@ ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t * ia, u16 port) clib_memcpy_fast (&buf[8], &rspi, sizeof (rspi)); clib_memcpy_fast (&buf[8 + 8], ip_addr_bytes (ia), ip_address_size (ia)); clib_memcpy_fast (&buf[8 + 8 + ip_address_size (ia)], &port, sizeof (port)); - SHA1 (buf, sizeof (buf), res); + SHA1 (buf, 2 * sizeof (ispi) + sizeof (port) + ip_address_size (ia), res); return res; } @@ -2735,11 +2735,9 @@ ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih) } static_always_inline void -ikev2_set_ip_address (ikev2_sa_t * sa, const void *src, - const void *dst, const int af, const int is_initiator) +ikev2_set_ip_address (ikev2_sa_t * sa, const void *iaddr, + const void *raddr, const int af) { - const void *raddr = is_initiator ? src : dst; - const void *iaddr = is_initiator ? dst : src; ip_address_set (&sa->raddr, raddr, af); ip_address_set (&sa->iaddr, iaddr, af); } @@ -2855,19 +2853,16 @@ ikev2_node_internal (vlib_main_t * vm, sa0 = &sa; clib_memset (sa0, 0, sizeof (*sa0)); - u8 is_initiator = ike0->flags & IKEV2_HDR_FLAG_INITIATOR; - if (is_initiator) + if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR) { if (ike0->rspi == 0) { if (is_ip4) - ikev2_set_ip_address (sa0, &ip40->dst_address, - &ip40->src_address, AF_IP4, - is_initiator); + ikev2_set_ip_address (sa0, &ip40->src_address, + &ip40->dst_address, AF_IP4); else - ikev2_set_ip_address (sa0, &ip60->dst_address, - &ip60->src_address, AF_IP6, - is_initiator); + ikev2_set_ip_address (sa0, &ip60->src_address, + &ip60->dst_address, AF_IP6); sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); @@ -2928,13 +2923,11 @@ ikev2_node_internal (vlib_main_t * vm, else //received sa_init without initiator flag { if (is_ip4) - ikev2_set_ip_address (sa0, &ip40->src_address, - &ip40->dst_address, AF_IP4, - is_initiator); + ikev2_set_ip_address (sa0, &ip40->dst_address, + &ip40->src_address, AF_IP4); else - ikev2_set_ip_address (sa0, &ip60->src_address, - &ip60->dst_address, AF_IP6, - is_initiator); + ikev2_set_ip_address (sa0, &ip60->dst_address, + &ip60->src_address, AF_IP6); ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen); @@ -4758,33 +4751,12 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) } } -static ike_payload_header_t * -ikev2_find_ike_payload (ike_header_t * ike, u32 payload_type) -{ - int p = 0; - ike_payload_header_t *ikep; - u32 payload = ike->nextpayload; - - while (payload != IKEV2_PAYLOAD_NONE) - { - ikep = (ike_payload_header_t *) & ike->payload[p]; - if (payload == payload_type) - return ikep; - - u16 plen = clib_net_to_host_u16 (ikep->length); - payload = ikep->nextpayload; - p += plen; - } - return 0; -} - static void ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) { ikev2_profile_t *p; u32 bi0; - u8 *nat_sha; - ike_payload_header_t *ph; + u8 *nat_sha, *np; if (ip_address_is_zero (&sa->iaddr)) { @@ -4795,20 +4767,20 @@ ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) return; /* update NAT detection payload */ - ph = - ikev2_find_ike_payload ((ike_header_t *) - sa->last_sa_init_req_packet_data, - IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); - if (!ph) - return; - - nat_sha = - ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), - clib_host_to_net_u64 (sa->rspi), - &sa->iaddr, - clib_host_to_net_u16 (IKEV2_PORT)); - clib_memcpy_fast (ph->payload, nat_sha, vec_len (nat_sha)); - vec_free (nat_sha); + np = + ikev2_find_ike_notify_payload + ((ike_header_t *) sa->last_sa_init_req_packet_data, + IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); + if (np) + { + nat_sha = + ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), + clib_host_to_net_u64 (sa->rspi), + &sa->iaddr, + clib_host_to_net_u16 (IKEV2_PORT)); + clib_memcpy_fast (np, nat_sha, vec_len (nat_sha)); + vec_free (nat_sha); + } } if (vlib_buffer_alloc (km->vlib_main, &bi0, 1) != 1) diff --git a/src/plugins/ikev2/ikev2_payload.c b/src/plugins/ikev2/ikev2_payload.c index c03054aa9cd3..294864d8c439 100644 --- a/src/plugins/ikev2/ikev2_payload.c +++ b/src/plugins/ikev2/ikev2_payload.c @@ -588,6 +588,30 @@ ikev2_parse_delete_payload (ike_payload_header_t * ikep, u32 rlen) return r; } +u8 * +ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type) +{ + int p = 0; + ike_notify_payload_header_t *n; + ike_payload_header_t *ikep; + u32 payload = ike->nextpayload; + + while (payload != IKEV2_PAYLOAD_NONE) + { + ikep = (ike_payload_header_t *) & ike->payload[p]; + if (payload == IKEV2_PAYLOAD_NOTIFY) + { + n = (ike_notify_payload_header_t *)ikep; + if (n->msg_type == clib_net_to_host_u16 (msg_type)) + return n->payload; + } + u16 plen = clib_net_to_host_u16 (ikep->length); + payload = ikep->nextpayload; + p += plen; + } + return 0; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index 68a546a0f489..115a5b2a6b33 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -568,6 +568,7 @@ ikev2_delete_t *ikev2_parse_delete_payload (ike_payload_header_t * ikep, ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep, u32 rlen); int ikev2_set_log_level (ikev2_log_level_t log_level); +u8 *ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type); static_always_inline ikev2_main_per_thread_data_t * ikev2_get_per_thread_data () diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 4f64b56d8532..f75a517f8249 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -1,4 +1,5 @@ import os +from socket import inet_pton from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, hmac @@ -510,8 +511,10 @@ def ike_crypto_attr(self): def esp_crypto_attr(self): return self.crypto_attr(self.esp_crypto_key_len) - def compute_nat_sha1(self, ip, port): - data = self.ispi + self.rspi + ip + (port).to_bytes(2, 'big') + def compute_nat_sha1(self, ip, port, rspi=None): + if rspi is None: + rspi = self.rspi + data = self.ispi + rspi + ip + (port).to_bytes(2, 'big') digest = hashes.Hash(hashes.SHA1(), backend=default_backend()) digest.update(data) return digest.finalize() @@ -775,6 +778,36 @@ class TemplateInitiator(IkePeer): def tearDown(self): super(TemplateInitiator, self).tearDown() + @staticmethod + def find_notify_payload(packet, notify_type): + n = packet[ikev2.IKEv2_payload_Notify] + while n is not None: + if n.type == notify_type: + return n + n = n.payload + return None + + def verify_nat_detection(self, packet): + if self.ip6: + iph = packet[IPv6] + else: + iph = packet[IP] + udp = packet[UDP] + + # NAT_DETECTION_SOURCE_IP + s = self.find_notify_payload(packet, 16388) + self.assertIsNotNone(s) + src_sha = self.sa.compute_nat_sha1( + inet_pton(socket.AF_INET, iph.src), udp.sport, b'\x00' * 8) + self.assertEqual(s.load, src_sha) + + # NAT_DETECTION_DESTINATION_IP + s = self.find_notify_payload(packet, 16389) + self.assertIsNotNone(s) + dst_sha = self.sa.compute_nat_sha1( + inet_pton(socket.AF_INET, iph.dst), udp.dport, b'\x00' * 8) + self.assertEqual(s.load, dst_sha) + def verify_sa_init_request(self, packet): ih = packet[ikev2.IKEv2] self.assertNotEqual(ih.init_SPI, 8 * b'\x00') @@ -798,6 +831,7 @@ def verify_sa_init_request(self, packet): self.assertEqual(prop.trans[2].transform_id, self.p.ike_transforms['dh_group']) + self.verify_nat_detection(packet) self.sa.complete_dh_data() self.sa.calc_keys() @@ -957,11 +991,6 @@ def send_sa_init_req(self, behind_nat=False): props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', trans_nb=4, trans=trans)) - if behind_nat: - next_payload = 'Notify' - else: - next_payload = None - self.sa.init_req_packet = ( ikev2.IKEv2(init_SPI=self.sa.ispi, flags='Initiator', exch_type='IKE_SA_INIT') / @@ -969,19 +998,21 @@ def send_sa_init_req(self, behind_nat=False): ikev2.IKEv2_payload_KE(next_payload='Nonce', group=self.sa.ike_dh, load=self.sa.my_dh_pub_key) / - ikev2.IKEv2_payload_Nonce(next_payload=next_payload, + ikev2.IKEv2_payload_Nonce(next_payload='Notify', load=self.sa.i_nonce)) if behind_nat: src_address = b'\x0a\x0a\x0a\x01' else: - src_address = bytes(self.pg0.local_ip4, 'ascii') + src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4) src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) - dst_nat = self.sa.compute_nat_sha1(bytes(self.pg0.remote_ip4, 'ascii'), - self.sa.sport) + dst_nat = self.sa.compute_nat_sha1( + inet_pton(socket.AF_INET, self.pg0.local_ip4), + self.sa.dport) nat_src_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_SOURCE_IP', load=src_nat) + type='NAT_DETECTION_SOURCE_IP', load=src_nat, + next_payload='Notify') nat_dst_detection = ikev2.IKEv2_payload_Notify( type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) self.sa.init_req_packet = (self.sa.init_req_packet / From a81bcf3945c9a0128de2e5d32a71813e32b05bc4 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Sat, 10 Oct 2020 04:39:11 +0000 Subject: [PATCH 104/129] ikev2: support sending requests from responder Type: improvement Ticket: VPP-1894 Change-Id: I5a24a48416bca2ffbd346cdaa813fb25801e6c9b Signed-off-by: Filip Tehlar (cherry picked from commit edf2900ac633ae0d8575b04094b1bca40e1a221f) --- src/plugins/ikev2/ikev2.c | 28 +++--- src/plugins/ikev2/ikev2.h | 5 + src/plugins/ikev2/ikev2_priv.h | 2 + src/plugins/ikev2/test/test_ikev2.py | 140 +++++++++++++++++++++++---- 4 files changed, 146 insertions(+), 29 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 03e85d543f88..025b34ca32da 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -2353,7 +2353,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, { if (sa->del[0].protocol_id == IKEV2_PROTOCOL_IKE) { - if (sa->is_initiator) + if (ike_hdr_is_request (ike)) ikev2_payload_add_delete (chain, sa->del); /* The response to a request that deletes the IKE SA is an empty @@ -2447,16 +2447,14 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, ike->version = IKE_VERSION_2; ike->nextpayload = IKEV2_PAYLOAD_SK; tlen = sizeof (*ike); + if (sa->is_initiator) + ike->flags |= IKEV2_HDR_FLAG_INITIATOR; + + if (ike_hdr_is_request (ike)) { - ike->flags = IKEV2_HDR_FLAG_INITIATOR; sa->last_init_msg_id = clib_net_to_host_u32 (ike->msgid); } - else - { - ike->flags = IKEV2_HDR_FLAG_RESPONSE; - } - if (ike->exchange == IKEV2_EXCHANGE_SA_INIT) { @@ -2639,6 +2637,9 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr, static u32 ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike) { + if (ike_hdr_is_response (ike)) + return 0; + u32 msg_id = clib_net_to_host_u32 (ike->msgid); /* new req */ @@ -2853,7 +2854,7 @@ ikev2_node_internal (vlib_main_t * vm, sa0 = &sa; clib_memset (sa0, 0, sizeof (*sa0)); - if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR) + if (ike_hdr_is_initiator (ike0)) { if (ike0->rspi == 0) { @@ -2899,6 +2900,7 @@ ikev2_node_internal (vlib_main_t * vm, if (sa0->state == IKEV2_STATE_SA_INIT || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE) { + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -2946,6 +2948,7 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_complete_sa_data (sa0, sai); ikev2_calc_keys (sa0); ikev2_sa_auth_init (sa0); + ike0->flags = IKEV2_HDR_FLAG_INITIATOR; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) @@ -3087,9 +3090,9 @@ ikev2_node_internal (vlib_main_t * vm, } } } - if (!(ike0->flags & IKEV2_HDR_FLAG_RESPONSE)) + if (ike_hdr_is_request (ike0)) { - ike0->flags |= IKEV2_HDR_FLAG_RESPONSE; + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3150,6 +3153,7 @@ ikev2_node_internal (vlib_main_t * vm, } else { + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3616,7 +3620,7 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); - + ike0->flags = 0; ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); len = ikev2_generate_message (b0, sa, ike0, 0, 0); @@ -4270,6 +4274,7 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); + ike0->flags = 0; vec_resize (sa->del, 1); sa->del->protocol_id = IKEV2_PROTOCOL_ESP; sa->del->spi = csa->i_proposals->spi; @@ -4838,6 +4843,7 @@ ikev2_send_informational_request (ikev2_sa_t * sa) ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); + ike0->flags = 0; sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); len = ikev2_generate_message (b0, sa, ike0, 0, 0); if (~0 == len) diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h index 47c301f33a1f..893d9544aa82 100644 --- a/src/plugins/ikev2/ikev2.h +++ b/src/plugins/ikev2/ikev2.h @@ -44,6 +44,11 @@ typedef CLIB_PACKED (struct { }) ike_header_t; /* *INDENT-ON* */ +#define ike_hdr_is_response(_h) ((_h)->flags & IKEV2_HDR_FLAG_RESPONSE) +#define ike_hdr_is_request(_h) (!ike_hdr_is_response(_h)) +#define ike_hdr_is_initiator(_h) ((_h)->flags & IKEV2_HDR_FLAG_INITIATOR) +#define ike_hdr_is_responder(_h) (!(ike_hdr_is_initiator(_h))) + /* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index 115a5b2a6b33..2b89b66efa66 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -400,10 +400,12 @@ typedef struct u8 *last_sa_init_res_packet_data; /* retransmit */ + /* message id expected in the request from the other peer */ u32 last_msg_id; u8 *last_res_packet_data; u8 is_initiator; + /* last message id that was used for an initiated request */ u32 last_init_msg_id; u32 profile_index; u8 is_tun_itf_set; diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index f75a517f8249..ec68658f5641 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -113,9 +113,7 @@ def decrypt(self, data, key, aad=None, icv=None): self.mode(nonce, icv, len(icv)), default_backend()).decryptor() decryptor.authenticate_additional_data(aad) - pt = decryptor.update(ct) + decryptor.finalize() - pad_len = pt[-1] + 1 - return pt[:-pad_len] + return decryptor.update(ct) + decryptor.finalize() def pad(self, data): pad_len = (len(data) // self.bs + 1) * self.bs - len(data) @@ -435,14 +433,17 @@ def hmac_and_decrypt(self, ike): aad_len = len(ikev2.IKEv2_payload_Encrypted()) + len(ikev2.IKEv2()) ct = ep.load[:-GCM_ICV_SIZE] tag = ep.load[-GCM_ICV_SIZE:] - return self.decrypt(ct, raw(ike)[:aad_len], tag) + plain = self.decrypt(ct, raw(ike)[:aad_len], tag) else: self.verify_hmac(raw(ike)) integ_trunc = self.ike_integ_alg.trunc_len # remove ICV and decrypt payload ct = ep.load[:-integ_trunc] - return self.decrypt(ct) + plain = self.decrypt(ct) + # remove padding + pad_len = plain[-1] + return plain[:-pad_len - 1] def build_ts_addr(self, ts, version): return {'starting_address_v' + version: ts['start_addr'], @@ -540,6 +541,19 @@ def setUpClass(cls): def tearDownClass(cls): super(IkePeer, cls).tearDownClass() + def tearDown(self): + super(IkePeer, self).tearDown() + if self.del_sa_from_responder: + self.initiate_del_sa_from_responder() + else: + self.initiate_del_sa_from_initiator() + r = self.vapi.ikev2_sa_dump() + self.assertEqual(len(r), 0) + sas = self.vapi.ipsec_sa_dump() + self.assertEqual(len(sas), 0) + self.p.remove_vpp_config() + self.assertIsNone(self.p.query_vpp_config()) + def setUp(self): super(IkePeer, self).setUp() self.config_tc() @@ -580,6 +594,7 @@ def get_ike_header(self, packet): esp = packet[ESP] ih = self.verify_and_remove_non_esp_marker(esp) self.assertEqual(ih.version, 0x20) + self.assertNotIn('Version', ih.flags) return ih def verify_and_remove_non_esp_marker(self, packet): @@ -775,8 +790,49 @@ def verify_ts(self, api_ts, ts, is_initiator): class TemplateInitiator(IkePeer): """ initiator test template """ - def tearDown(self): - super(TemplateInitiator, self).tearDown() + def initiate_del_sa_from_initiator(self): + ispi = int.from_bytes(self.sa.ispi, 'little') + self.pg0.enable_capture() + self.pg_start() + self.vapi.ikev2_initiate_del_ike_sa(ispi=ispi) + capture = self.pg0.get_capture(1) + ih = self.get_ike_header(capture[0]) + self.assertNotIn('Response', ih.flags) + self.assertIn('Initiator', ih.flags) + self.assertEqual(ih.init_SPI, self.sa.ispi) + self.assertEqual(ih.resp_SPI, self.sa.rspi) + plain = self.sa.hmac_and_decrypt(ih) + d = ikev2.IKEv2_payload_Delete(plain) + self.assertEqual(d.proto, 1) # proto=IKEv2 + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + flags='Response', exch_type='INFORMATIONAL', + id=ih.id, next_payload='Encrypted') + resp = self.encrypt_ike_msg(header, b'', None) + self.send_and_assert_no_replies(self.pg0, resp) + + def verify_del_sa(self, packet): + ih = self.get_ike_header(packet) + self.assertEqual(ih.id, self.sa.msg_id) + self.assertEqual(ih.exch_type, 37) # exchange informational + self.assertIn('Response', ih.flags) + self.assertIn('Initiator', ih.flags) + plain = self.sa.hmac_and_decrypt(ih) + self.assertEqual(plain, b'') + + def initiate_del_sa_from_responder(self): + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + exch_type='INFORMATIONAL', + id=self.sa.new_msg_id()) + del_sa = ikev2.IKEv2_payload_Delete(proto='IKEv2') + ike_msg = self.encrypt_ike_msg(header, del_sa, 'Delete') + packet = self.create_packet(self.pg0, ike_msg, + self.sa.sport, self.sa.dport, + self.sa.natt, self.ip6) + self.pg0.add_stream(packet) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + self.verify_del_sa(capture[0]) @staticmethod def find_notify_payload(packet, notify_type): @@ -946,22 +1002,41 @@ def test_initiator(self): class TemplateResponder(IkePeer): """ responder test template """ - def tearDown(self): - super(TemplateResponder, self).tearDown() - if self.sa.is_initiator: - self.initiate_del_sa() - r = self.vapi.ikev2_sa_dump() - self.assertEqual(len(r), 0) - - self.p.remove_vpp_config() - self.assertIsNone(self.p.query_vpp_config()) + def initiate_del_sa_from_responder(self): + self.pg0.enable_capture() + self.pg_start() + self.vapi.ikev2_initiate_del_ike_sa( + ispi=int.from_bytes(self.sa.ispi, 'little')) + capture = self.pg0.get_capture(1) + ih = self.get_ike_header(capture[0]) + self.assertNotIn('Response', ih.flags) + self.assertNotIn('Initiator', ih.flags) + self.assertEqual(ih.exch_type, 37) # INFORMATIONAL + plain = self.sa.hmac_and_decrypt(ih) + d = ikev2.IKEv2_payload_Delete(plain) + self.assertEqual(d.proto, 1) # proto=IKEv2 + self.assertEqual(ih.init_SPI, self.sa.ispi) + self.assertEqual(ih.resp_SPI, self.sa.rspi) + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + flags='Initiator+Response', + exch_type='INFORMATIONAL', + id=ih.id, next_payload='Encrypted') + resp = self.encrypt_ike_msg(header, b'', None) + self.send_and_assert_no_replies(self.pg0, resp) def verify_del_sa(self, packet): ih = self.get_ike_header(packet) self.assertEqual(ih.id, self.sa.msg_id) self.assertEqual(ih.exch_type, 37) # exchange informational + self.assertIn('Response', ih.flags) + self.assertNotIn('Initiator', ih.flags) + self.assertEqual(ih.next_payload, 46) # Encrypted + self.assertEqual(ih.init_SPI, self.sa.ispi) + self.assertEqual(ih.resp_SPI, self.sa.rspi) + plain = self.sa.hmac_and_decrypt(ih) + self.assertEqual(plain, b'') - def initiate_del_sa(self): + def initiate_del_sa_from_initiator(self): header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, flags='Initiator', exch_type='INFORMATIONAL', id=self.sa.new_msg_id()) @@ -1081,7 +1156,7 @@ def verify_sa_init(self, packet): self.assertEqual(ih.id, self.sa.msg_id) self.assertEqual(ih.exch_type, 34) - self.assertTrue('Response' in ih.flags) + self.assertIn('Response', ih.flags) self.assertEqual(ih.init_SPI, self.sa.ispi) self.assertNotEqual(ih.resp_SPI, 0) self.sa.rspi = ih.resp_SPI @@ -1129,6 +1204,8 @@ def config_params(self, params={}): 'SHA2-384-192': ei.IPSEC_API_INTEG_ALG_SHA_384_192, 'SHA2-512-256': ei.IPSEC_API_INTEG_ALG_SHA_512_256} + self.del_sa_from_responder = False if 'del_sa_from_responder'\ + not in params else params['del_sa_from_responder'] is_natt = 'natt' in params and params['natt'] or False self.p = Profile(self, 'pr1') self.ip6 = False if 'ip6' not in params else params['ip6'] @@ -1392,8 +1469,34 @@ def verify_profile(self, ap, cp): class TestInitiatorPsk(TemplateInitiator, Ikev2Params): """ test ikev2 initiator - pre shared key auth """ + + def config_tc(self): + self.config_params({ + 'is_initiator': False, # seen from test case perspective + # thus vpp is initiator + 'responder': {'sw_if_index': self.pg0.sw_if_index, + 'addr': self.pg0.remote_ip4}, + 'ike-crypto': ('AES-GCM-16ICV', 32), + 'ike-integ': 'NULL', + 'ike-dh': '3072MODPgr', + 'ike_transforms': { + 'crypto_alg': 20, # "aes-gcm-16" + 'crypto_key_size': 256, + 'dh_group': 15, # "modp-3072" + }, + 'esp_transforms': { + 'crypto_alg': 12, # "aes-cbc" + 'crypto_key_size': 256, + # "hmac-sha2-256-128" + 'integ_alg': 12}}) + + +class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params): + """ test ikev2 initiator - delete IKE SA from responder """ + def config_tc(self): self.config_params({ + 'del_sa_from_responder': True, 'is_initiator': False, # seen from test case perspective # thus vpp is initiator 'responder': {'sw_if_index': self.pg0.sw_if_index, @@ -1471,6 +1574,7 @@ class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params): """ def config_tc(self): self.config_params({ + 'del_sa_from_responder': True, 'ip6': True, 'natt': True, 'ike-crypto': ('AES-GCM-16ICV', 32), From f7fd0e749b91aba981742ce704a993170ed1c34a Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 30 Oct 2020 05:00:18 +0000 Subject: [PATCH 105/129] ikev2: fix memory leak Type: fix Change-Id: I33c38c791cc9a28898de402ae831c4862073eb2d Signed-off-by: Filip Tehlar (cherry picked from commit b8bc2f1ef3332a795880f11f1c45a77b1b7851f6) --- src/plugins/ikev2/ikev2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 025b34ca32da..2281c91d44ff 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1443,17 +1443,22 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, rekey->tsi = tsi; rekey->tsr = tsr; /* update Ni */ - vec_free (sa->i_nonce); + vec_reset_length (sa->i_nonce); vec_add (sa->i_nonce, nonce, IKEV2_NONCE_SIZE); /* generate new Nr */ vec_validate (sa->r_nonce, IKEV2_NONCE_SIZE - 1); RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE); - vec_free (n); } + else + goto cleanup_and_exit; + vec_free (n); return 1; cleanup_and_exit: vec_free (n); + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); return 0; } From 56d712533bc4de75b184e523c89573a9616c7d67 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 30 Oct 2020 05:52:19 +0000 Subject: [PATCH 106/129] ikev2: cli for disabling dead peer detection Type: feature Change-Id: I0db0a9b2f872753fa64d27335838cb34645a9ee8 Signed-off-by: Filip Tehlar (cherry picked from commit af4a414eb74d1456121023e6b3aa76af6c16f89a) --- src/plugins/ikev2/ikev2.c | 9 ++++++++- src/plugins/ikev2/ikev2_cli.c | 19 ++++++++++++++++++- src/plugins/ikev2/ikev2_priv.h | 4 ++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 2281c91d44ff..feaae1e492a2 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -4873,6 +4873,13 @@ ikev2_send_informational_request (ikev2_sa_t * sa) sa->sw_if_index); } +void +ikev2_disable_dpd (void) +{ + ikev2_main_t *km = &ikev2_main; + km->dpd_disabled = 1; +} + static_always_inline int ikev2_mngr_process_responder_sas (ikev2_sa_t * sa) { @@ -4940,7 +4947,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, req_sent |= ikev2_mngr_process_child_sa(sa, c, del_old_ids); } - if (ikev2_mngr_process_responder_sas (sa)) + if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa)) vec_add1 (to_be_deleted, sa - tkm->sas); })); /* *INDENT-ON* */ diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index c948578eb230..676ca7b0c214 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -249,6 +249,23 @@ VLIB_CLI_COMMAND (show_ikev2_sa_command, static) = { }; /* *INDENT-ON* */ +static clib_error_t * +ikev2_disable_dpd_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ikev2_disable_dpd (); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (ikev2_cli_disable_dpd_command, static) = { + .path = "ikev2 dpd disable", + .short_help = "ikev2 dpd disable", + .function = ikev2_disable_dpd_command_fn, +}; +/* *INDENT-ON* */ + static uword unformat_ikev2_token (unformat_input_t * input, va_list * va) { @@ -777,7 +794,7 @@ VLIB_CLI_COMMAND (ikev2_initiate_command, static) = { "ikev2 initiate sa-init \n" "ikev2 initiate del-child-sa \n" "ikev2 initiate del-sa \n" - "ikev2 initiate rekey-child-sa \n", + "ikev2 initiate rekey-child-sa \n", .function = ikev2_initiate_command_fn, }; /* *INDENT-ON* */ diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index 2b89b66efa66..ae0c2a4bae35 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -496,6 +496,9 @@ typedef struct /* max number of retries before considering peer dead */ u32 liveness_max_retries; + + /* dead peer detection */ + u8 dpd_disabled; } ikev2_main_t; extern ikev2_main_t ikev2_main; @@ -571,6 +574,7 @@ ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep, u32 rlen); int ikev2_set_log_level (ikev2_log_level_t log_level); u8 *ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type); +void ikev2_disable_dpd (void); static_always_inline ikev2_main_per_thread_data_t * ikev2_get_per_thread_data () From 31b44a7a13770812cf0a4b777503c2549900348f Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 30 Oct 2020 05:59:55 +0000 Subject: [PATCH 107/129] ikev2: increase tick interval in process node This helps to resolve sporadic failures in unit tests. Type: fix Change-Id: I3abd77ed74310f9729a841e8569eafe6d7758dcb Signed-off-by: Filip Tehlar (cherry picked from commit 761f8f0eaaf43f38fdd9d160ba19ff833de7d210) --- src/plugins/ikev2/ikev2.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index feaae1e492a2..0e6b1c61f887 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -4915,8 +4915,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, while (1) { - u8 req_sent = 0; - vlib_process_wait_for_event_or_clock (vm, 1); + vlib_process_wait_for_event_or_clock (vm, 2); vlib_process_get_events (vm, NULL); /* process ike child sas */ @@ -4943,9 +4942,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, sa->old_id_expiration -= 1; vec_foreach (c, sa->childs) - { - req_sent |= ikev2_mngr_process_child_sa(sa, c, del_old_ids); - } + ikev2_mngr_process_child_sa(sa, c, del_old_ids); if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa)) vec_add1 (to_be_deleted, sa - tkm->sas); @@ -4986,14 +4983,6 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, /* *INDENT-ON* */ ikev2_process_pending_sa_init (km); - - if (req_sent) - { - vlib_process_wait_for_event_or_clock (vm, 5); - vlib_process_get_events (vm, NULL); - req_sent = 0; - } - } return 0; } From f6deabd4fc887b12d2335111e58354a87390813c Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 30 Oct 2020 05:28:11 +0000 Subject: [PATCH 108/129] ikev2: fix reply during rekey Type: fix Change-Id: If87f4b8ae92508215fe91178958fe2ddb91e5a35 Signed-off-by: Filip Tehlar (cherry picked from commit 68ad6258374201ba8f0dc052e6f44d6250555249) --- src/plugins/ikev2/ikev2.c | 2 +- src/plugins/ikev2/test/test_ikev2.py | 234 ++++++++++++++++++++++----- 2 files changed, 192 insertions(+), 44 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 0e6b1c61f887..206e1db0e2bf 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -3152,7 +3152,7 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_create_tunnel_interface (vm, sa0, child, p[0], child - sa0->childs, 1); } - if (sa0->is_initiator) + if (ike_hdr_is_response (ike0)) { vec_free (sa0->rekey); } diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index ec68658f5641..91cec8e9a62b 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -151,10 +151,28 @@ def __init__(self, name, mac, mod, key_len, trunc_len=None): hashes.SHA256, 32), } +CRYPTO_IDS = { + 12: 'AES-CBC', + 20: 'AES-GCM-16ICV', +} + +INTEG_IDS = { + 2: 'HMAC-SHA1-96', + 12: 'SHA2-256-128', + 13: 'SHA2-384-192', + 14: 'SHA2-512-256', +} + class IKEv2ChildSA(object): - def __init__(self, local_ts, remote_ts, spi=None): - self.spi = spi or os.urandom(4) + def __init__(self, local_ts, remote_ts, is_initiator): + spi = os.urandom(4) + if is_initiator: + self.ispi = spi + self.rspi = None + else: + self.rspi = spi + self.ispi = None self.local_ts = local_ts self.remote_ts = remote_ts @@ -193,7 +211,8 @@ def __init__(self, test, is_initiator=True, i_id=None, r_id=None, self.rspi = spi self.ispi = 8 * b'\x00' self.r_nonce = nonce - self.child_sas = [IKEv2ChildSA(local_ts, remote_ts)] + self.child_sas = [IKEv2ChildSA(local_ts, remote_ts, + self.is_initiator)] def new_msg_id(self): self.msg_id += 1 @@ -559,9 +578,11 @@ def setUp(self): self.config_tc() self.p.add_vpp_config() self.assertIsNotNone(self.p.query_vpp_config()) - self.sa.generate_dh_data() + if self.sa.is_initiator: + self.sa.generate_dh_data() self.vapi.cli('ikev2 set logging level 4') self.vapi.cli('event-lo clear') + self.vapi.cli('ikev2 dpd disable') def create_packet(self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False): @@ -641,16 +662,30 @@ def encrypt_ike_msg(self, header, plain, first_payload): assert(len(res) == tlen) return res - def verify_ipsec_sas(self): + def verify_ipsec_sas(self, is_rekey=False): sas = self.vapi.ipsec_sa_dump() - self.assertEqual(len(sas), 2) + if is_rekey: + # after rekey there is a short period of time in which old + # inbound SA is still present + sa_count = 3 + else: + sa_count = 2 + self.assertEqual(len(sas), sa_count) e = VppEnum.vl_api_ipsec_sad_flags_t if self.sa.is_initiator: - sa0 = sas[0].entry - sa1 = sas[1].entry + if is_rekey: + sa0 = sas[0].entry + sa1 = sas[2].entry + else: + sa0 = sas[0].entry + sa1 = sas[1].entry else: - sa1 = sas[0].entry - sa0 = sas[1].entry + if is_rekey: + sa0 = sas[2].entry + sa1 = sas[0].entry + else: + sa1 = sas[0].entry + sa0 = sas[1].entry c = self.sa.child_sas[0] @@ -738,6 +773,8 @@ def verify_ike_sas(self): self.verify_keymat(csa.keys, c, 'sk_ar') self.verify_keymat(csa.keys, c, 'sk_ei') self.verify_keymat(csa.keys, c, 'sk_er') + self.assertEqual(csa.i_spi.to_bytes(4, 'big'), c.ispi) + self.assertEqual(csa.r_spi.to_bytes(4, 'big'), c.rspi) tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) tsi = tsi[0] @@ -888,9 +925,23 @@ def verify_sa_init_request(self, packet): self.p.ike_transforms['dh_group']) self.verify_nat_detection(packet) + self.sa.set_ike_props( + crypto='AES-GCM-16ICV', crypto_key_len=32, + integ='NULL', prf='PRF_HMAC_SHA2_256', dh='3072MODPgr') + self.sa.set_esp_props(crypto='AES-CBC', crypto_key_len=32, + integ='SHA2-256-128') + self.sa.generate_dh_data() self.sa.complete_dh_data() self.sa.calc_keys() + def update_esp_transforms(self, trans, sa): + while trans: + if trans.transform_type == 1: # ecryption + sa.esp_crypto = CRYPTO_IDS[trans.transform_id] + elif trans.transform_type == 3: # integrity + sa.esp_integ = INTEG_IDS[trans.transform_id] + trans = trans.payload + def verify_sa_auth_req(self, packet): ih = self.get_ike_header(packet) self.assertEqual(ih.resp_SPI, self.sa.rspi) @@ -908,6 +959,11 @@ def verify_sa_auth_req(self, packet): idr = ikev2.IKEv2_payload_IDr(idi.payload) self.assertEqual(idi.load, self.sa.i_id) self.assertEqual(idr.load, self.sa.r_id) + prop = idi[ikev2.IKEv2_payload_Proposal] + c = self.sa.child_sas[0] + c.ispi = prop.SPI + self.update_esp_transforms( + prop[ikev2.IKEv2_payload_Transform], self.sa) def send_init_response(self): tr_attr = self.sa.ike_crypto_attr() @@ -961,8 +1017,9 @@ def send_auth_response(self): transform_type='Extended Sequence Number', transform_id='ESN')) + c = self.sa.child_sas[0] props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', - SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) + SPIsize=4, SPI=c.rspi, trans_nb=4, trans=trans)) tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) plain = (ikev2.IKEv2_payload_IDi(next_payload='IDr', @@ -1103,8 +1160,9 @@ def send_sa_init_req(self, behind_nat=False): capture = self.pg0.get_capture(1) self.verify_sa_init(capture[0]) - def send_sa_auth(self): + def generate_auth_payload(self, last_payload=None, is_rekey=False): tr_attr = self.sa.esp_crypto_attr() + last_payload = last_payload or 'Notify' trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', transform_id=self.sa.esp_crypto, length=tr_attr[1], key_length=tr_attr[0]) / @@ -1117,32 +1175,45 @@ def send_sa_auth(self): transform_type='Extended Sequence Number', transform_id='ESN')) + c = self.sa.child_sas[0] props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', - SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) + SPIsize=4, SPI=c.ispi, trans_nb=4, trans=trans)) tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4) - plain = (ikev2.IKEv2_payload_IDi(next_payload='IDr', - IDtype=self.sa.id_type, load=self.sa.i_id) / - ikev2.IKEv2_payload_IDr(next_payload='AUTH', - IDtype=self.sa.id_type, load=self.sa.r_id) / - ikev2.IKEv2_payload_AUTH(next_payload='SA', + plain = (ikev2.IKEv2_payload_AUTH(next_payload='SA', auth_type=AuthMethod.value(self.sa.auth_method), load=self.sa.auth_data) / ikev2.IKEv2_payload_SA(next_payload='TSi', prop=props) / ikev2.IKEv2_payload_TSi(next_payload='TSr', - number_of_TSs=len(tsi), - traffic_selector=tsi) / - ikev2.IKEv2_payload_TSr(next_payload='Notify', - number_of_TSs=len(tsr), - traffic_selector=tsr) / - ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT')) + number_of_TSs=len(tsi), traffic_selector=tsi) / + ikev2.IKEv2_payload_TSr(next_payload=last_payload, + number_of_TSs=len(tsr), traffic_selector=tsr)) + + if is_rekey: + first_payload = 'Nonce' + plain = (ikev2.IKEv2_payload_Nonce(load=self.sa.i_nonce, + next_payload='SA') / plain / + ikev2.IKEv2_payload_Notify(type='REKEY_SA', + proto='ESP', SPI=c.ispi)) + else: + first_payload = 'IDi' + ids = (ikev2.IKEv2_payload_IDi(next_payload='IDr', + IDtype=self.sa.id_type, load=self.sa.i_id) / + ikev2.IKEv2_payload_IDr(next_payload='AUTH', + IDtype=self.sa.id_type, load=self.sa.r_id)) + plain = ids / plain + return plain, first_payload + def send_sa_auth(self): + plain, first_payload = self.generate_auth_payload( + last_payload='Notify') + plain = plain / ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT') header = ikev2.IKEv2( init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), flags='Initiator', exch_type='IKE_AUTH') - ike_msg = self.encrypt_ike_msg(header, plain, 'IDi') + ike_msg = self.encrypt_ike_msg(header, plain, first_payload) packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6) self.pg0.add_stream(packet) @@ -1178,6 +1249,10 @@ def verify_sa_auth_resp(self, packet): self.verify_udp(udp) self.assertEqual(ike.id, self.sa.msg_id) plain = self.sa.hmac_and_decrypt(ike) + idr = ikev2.IKEv2_payload_IDr(plain) + prop = idr[ikev2.IKEv2_payload_Proposal] + self.assertEqual(prop.SPIsize, 4) + self.sa.child_sas[0].rspi = prop.SPI self.sa.calc_child_keys() def test_responder(self): @@ -1264,24 +1339,25 @@ def config_params(self, params={}): auth_data=auth_data, local_ts=self.p.remote_ts, remote_ts=self.p.local_ts) - ike_crypto = ('AES-CBC', 32) if 'ike-crypto' not in params else\ - params['ike-crypto'] - ike_integ = 'HMAC-SHA1-96' if 'ike-integ' not in params else\ - params['ike-integ'] - ike_dh = '2048MODPgr' if 'ike-dh' not in params else\ - params['ike-dh'] - - esp_crypto = ('AES-CBC', 32) if 'esp-crypto' not in params else\ - params['esp-crypto'] - esp_integ = 'HMAC-SHA1-96' if 'esp-integ' not in params else\ - params['esp-integ'] - - self.sa.set_ike_props( - crypto=ike_crypto[0], crypto_key_len=ike_crypto[1], - integ=ike_integ, prf='PRF_HMAC_SHA2_256', dh=ike_dh) - self.sa.set_esp_props( - crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], - integ=esp_integ) + if is_init: + ike_crypto = ('AES-CBC', 32) if 'ike-crypto' not in params else\ + params['ike-crypto'] + ike_integ = 'HMAC-SHA1-96' if 'ike-integ' not in params else\ + params['ike-integ'] + ike_dh = '2048MODPgr' if 'ike-dh' not in params else\ + params['ike-dh'] + + esp_crypto = ('AES-CBC', 32) if 'esp-crypto' not in params else\ + params['esp-crypto'] + esp_integ = 'HMAC-SHA1-96' if 'esp-integ' not in params else\ + params['esp-integ'] + + self.sa.set_ike_props( + crypto=ike_crypto[0], crypto_key_len=ike_crypto[1], + integ=ike_integ, prf='PRF_HMAC_SHA2_256', dh=ike_dh) + self.sa.set_esp_props( + crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], + integ=esp_integ) class TestApi(VppTestCase): @@ -1491,6 +1567,44 @@ def config_tc(self): 'integ_alg': 12}}) +class TestInitiatorRekey(TestInitiatorPsk): + """ test ikev2 initiator - rekey """ + + def rekey_from_initiator(self): + ispi = int.from_bytes(self.sa.child_sas[0].ispi, 'little') + self.pg0.enable_capture() + self.pg_start() + self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi) + capture = self.pg0.get_capture(1) + ih = self.get_ike_header(capture[0]) + self.assertEqual(ih.exch_type, 36) # CHILD_SA + self.assertNotIn('Response', ih.flags) + self.assertIn('Initiator', ih.flags) + plain = self.sa.hmac_and_decrypt(ih) + sa = ikev2.IKEv2_payload_SA(plain) + prop = sa[ikev2.IKEv2_payload_Proposal] + nonce = sa[ikev2.IKEv2_payload_Nonce] + self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load + self.sa.r_nonce = self.sa.i_nonce + # update new responder SPI + self.sa.child_sas[0].ispi = prop.SPI + self.sa.child_sas[0].rspi = prop.SPI + self.sa.calc_child_keys() + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + flags='Response', exch_type=36, + id=ih.id, next_payload='Encrypted') + resp = self.encrypt_ike_msg(header, sa, 'SA') + packet = self.create_packet(self.pg0, resp, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + self.send_and_assert_no_replies(self.pg0, packet) + + def test_initiator(self): + super(TestInitiatorRekey, self).test_initiator() + self.rekey_from_initiator() + self.verify_ike_sas() + self.verify_ipsec_sas(is_rekey=True) + + class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params): """ test ikev2 initiator - delete IKE SA from responder """ @@ -1529,6 +1643,40 @@ def config_tc(self): self.config_params() +class TestResponderRekey(TestResponderPsk): + """ test ikev2 responder - rekey """ + + def rekey_from_initiator(self): + sa, first_payload = self.generate_auth_payload(is_rekey=True) + header = ikev2.IKEv2( + init_SPI=self.sa.ispi, + resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), + flags='Initiator', exch_type='CREATE_CHILD_SA') + + ike_msg = self.encrypt_ike_msg(header, sa, first_payload) + packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + self.pg0.add_stream(packet) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + ih = self.get_ike_header(capture[0]) + plain = self.sa.hmac_and_decrypt(ih) + sa = ikev2.IKEv2_payload_SA(plain) + prop = sa[ikev2.IKEv2_payload_Proposal] + nonce = sa[ikev2.IKEv2_payload_Nonce] + self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load + # update new responder SPI + self.sa.child_sas[0].rspi = prop.SPI + + def test_responder(self): + super(TestResponderRekey, self).test_responder() + self.rekey_from_initiator() + self.sa.calc_child_keys() + self.verify_ike_sas() + self.verify_ipsec_sas(is_rekey=True) + + class TestResponderRsaSign(TemplateResponder, Ikev2Params): """ test ikev2 responder - cert based auth """ def config_tc(self): From 8035ffe8dc6c967414d0081c9b83ac7658006a3b Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 30 Oct 2020 04:47:44 +0000 Subject: [PATCH 109/129] ikev2: add option to disable NAT traversal Type: feature Ticket: VPP-1935 Change-Id: I705f84047b112279377590157a1c7b4a34f693d2 Signed-off-by: Filip Tehlar (cherry picked from commit d7fc12f07313f9147159f2562f6fcc928af7a963) --- src/plugins/ikev2/ikev2.api | 14 ++++++ src/plugins/ikev2/ikev2.c | 40 ++++++++++++----- src/plugins/ikev2/ikev2_api.c | 24 +++++++++- src/plugins/ikev2/ikev2_cli.c | 12 ++++- src/plugins/ikev2/ikev2_priv.h | 19 +++++++- src/plugins/ikev2/ikev2_test.c | 65 +++++++++++++++++++--------- src/plugins/ikev2/ikev2_types.api | 1 + src/plugins/ikev2/test/test_ikev2.py | 6 +++ src/plugins/ikev2/test/vpp_ikev2.py | 7 +++ 9 files changed, 154 insertions(+), 34 deletions(-) diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api index a7aeff1fa441..9f44cba1661a 100644 --- a/src/plugins/ikev2/ikev2.api +++ b/src/plugins/ikev2/ikev2.api @@ -251,6 +251,20 @@ autoreply define ikev2_profile_set_id option status="in_progress"; }; +/** \brief IKEv2: Disable NAT traversal + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param name - IKEv2 profile name +*/ +autoreply define ikev2_profile_disable_natt +{ + u32 client_index; + u32 context; + + string name[64]; + option status="in_progress"; +}; + /** \brief IKEv2: Set IKEv2 profile traffic selector parameters @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 206e1db0e2bf..09a7359d5c68 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -106,7 +106,7 @@ typedef u32 ikev2_non_esp_marker; static_always_inline u16 ikev2_get_port (ikev2_sa_t * sa) { - return sa->natt ? IKEV2_PORT_NATT : IKEV2_PORT; + return ikev2_natt_active (sa) ? IKEV2_PORT_NATT : IKEV2_PORT; } static_always_inline int @@ -428,6 +428,7 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) sa->profile_index = sai->profile_index; sa->tun_itf = sai->tun_itf; sa->is_tun_itf_set = sai->is_tun_itf_set; + sa->natt_state = sai->natt_state; sa->i_id.data = _(sai->i_id.data); sa->r_id.data = _(sai->r_id.data); sa->i_auth.method = sai->i_auth.method; @@ -744,7 +745,8 @@ ikev2_process_sa_init_req (vlib_main_t * vm, udp->src_port); if (clib_memcmp (src_sha, n->data, vec_len (src_sha))) { - sa->natt = 1; + if (sa->natt_state == IKEV2_NATT_ENABLED) + sa->natt_state = IKEV2_NATT_ACTIVE; ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx initiator" " behind NAT", sa->ispi); } @@ -757,7 +759,8 @@ ikev2_process_sa_init_req (vlib_main_t * vm, udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { - sa->natt = 1; + if (sa->natt_state == IKEV2_NATT_ENABLED) + sa->natt_state = IKEV2_NATT_ACTIVE; ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx responder" " (self) behind NAT", sa->ispi); } @@ -870,7 +873,8 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { - sa->natt = 1; + if (sa->natt_state == IKEV2_NATT_ENABLED) + sa->natt_state = IKEV2_NATT_ACTIVE; ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx initiator" " (self) behind NAT", sa->ispi); } @@ -1921,7 +1925,7 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, a.flags |= IPSEC_SA_FLAG_IS_TUNNEL; a.flags |= IPSEC_SA_FLAG_UDP_ENCAP; } - if (sa->natt) + if (ikev2_natt_active (sa)) a.flags |= IPSEC_SA_FLAG_UDP_ENCAP; a.is_rekey = is_rekey; @@ -2047,7 +2051,8 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, a.salt_remote = child->salt_ei; a.salt_local = child->salt_er; } - a.dst_port = sa->natt ? sa->dst_port : sa->ipsec_over_udp_port; + a.dst_port = + ikev2_natt_active (sa) ? sa->dst_port : sa->ipsec_over_udp_port; a.src_port = sa->ipsec_over_udp_port; } @@ -3194,7 +3199,7 @@ ikev2_node_internal (vlib_main_t * vm, clib_net_to_host_u16 (ikev2_get_port (sa0)); if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT) - && sa0->natt) + && ikev2_natt_active (sa0)) { if (!has_non_esp_marker) slen = ikev2_insert_non_esp_marker (ike0, slen); @@ -3632,7 +3637,7 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); if (sa->is_initiator) @@ -4150,6 +4155,8 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sa.state = IKEV2_STATE_SA_INIT; sa.tun_itf = p->tun_itf; sa.udp_encap = p->udp_encap; + if (p->natt_disabled) + sa.natt_state = IKEV2_NATT_DISABLED; sa.ipsec_over_udp_port = p->ipsec_over_udp_port; sa.is_tun_itf_set = 1; sa.initial_contact = 1; @@ -4289,7 +4296,7 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len, ikev2_get_port (sa), sa->dst_port, sa->sw_if_index); @@ -4414,7 +4421,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len, ikev2_get_port (sa), ikev2_get_port (sa), sa->sw_if_index); @@ -4717,6 +4724,17 @@ ikev2_set_liveness_params (u32 period, u32 max_retries) return 0; } +clib_error_t * +ikev2_profile_natt_disable (u8 * name) +{ + ikev2_profile_t *p = ikev2_profile_index_by_name (name); + if (!p) + return clib_error_return (0, "unknown profile %v", name); + + p->natt_disabled = 1; + return 0; +} + static void ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) { @@ -4854,7 +4872,7 @@ ikev2_send_informational_request (ikev2_sa_t * sa) if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); if (sa->is_initiator) diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c index 33ff0853832c..63d8760b0431 100644 --- a/src/plugins/ikev2/ikev2_api.c +++ b/src/plugins/ikev2/ikev2_api.c @@ -163,7 +163,7 @@ send_profile (ikev2_profile_t * profile, vl_api_registration_t * reg, rmp->profile.udp_encap = profile->udp_encap; rmp->profile.tun_itf = profile->tun_itf; - + rmp->profile.natt_disabled = profile->natt_disabled; rmp->profile.ipsec_over_udp_port = profile->ipsec_over_udp_port; rmp->profile.lifetime = profile->lifetime; @@ -857,6 +857,28 @@ static void REPLY_MACRO (VL_API_IKEV2_INITIATE_DEL_CHILD_SA_REPLY); } +static void + vl_api_ikev2_profile_disable_natt_t_handler + (vl_api_ikev2_profile_disable_natt_t * mp) +{ + vl_api_ikev2_profile_disable_natt_reply_t *rmp; + int rv = 0; + +#if WITH_LIBSSL > 0 + clib_error_t *error; + + u8 *tmp = format (0, "%s", mp->name); + error = ikev2_profile_natt_disable (tmp); + vec_free (tmp); + if (error) + rv = VNET_API_ERROR_UNSPECIFIED; +#else + rv = VNET_API_ERROR_UNIMPLEMENTED; +#endif + + REPLY_MACRO (VL_API_IKEV2_PROFILE_DISABLE_NATT_REPLY); +} + static void vl_api_ikev2_initiate_rekey_child_sa_t_handler (vl_api_ikev2_initiate_rekey_child_sa_t * mp) diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index 676ca7b0c214..3290b59ed68d 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -512,6 +512,12 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm, r = clib_error_return (0, "Error: %U", format_vnet_api_errno, rv); goto done; } + else if (unformat (line_input, "set %U disable natt", + unformat_ikev2_token, &name)) + { + r = ikev2_profile_natt_disable (name); + goto done; + } else break; } @@ -543,7 +549,8 @@ VLIB_CLI_COMMAND (ikev2_profile_add_del_command, static) = { "ikev2 profile set ike-crypto-alg ike-integ-alg ike-dh \n" "ikev2 profile set esp-crypto-alg " "[esp-integ-alg ]\n" - "ikev2 profile set sa-lifetime ", + "ikev2 profile set sa-lifetime " + "ikev2 profile set disable natt\n", .function = ikev2_profile_add_del_command_fn, }; /* *INDENT-ON* */ @@ -628,6 +635,9 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, if (p->udp_encap) vlib_cli_output(vm, " udp-encap"); + if (p->natt_disabled) + vlib_cli_output(vm, " NAT-T disabled"); + if (p->ipsec_over_udp_port != IPSEC_UDP_PORT_NONE) vlib_cli_output(vm, " ipsec-over-udp port %d", p->ipsec_over_udp_port); diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index ae0c2a4bae35..fa302dcf21a6 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -347,8 +347,24 @@ typedef struct u32 tun_itf; u8 udp_encap; + u8 natt_disabled; } ikev2_profile_t; +typedef enum +{ + /* SA will switch to port 4500 when NAT is detected. + * This is the default. */ + IKEV2_NATT_ENABLED, + + /* Do nothing when NAT is detected */ + IKEV2_NATT_DISABLED, + + /* NAT was detected and port switched to 4500 */ + IKEV2_NATT_ACTIVE, +} ikev2_natt_state_t; + +#define ikev2_natt_active(_sa) ((_sa)->natt_state == IKEV2_NATT_ACTIVE) + typedef struct { ikev2_state_t state; @@ -428,7 +444,7 @@ typedef struct u32 sw_if_index; /* is NAT traversal mode */ - u8 natt; + ikev2_natt_state_t natt_state; u8 keys_generated; } ikev2_sa_t; @@ -575,6 +591,7 @@ ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep, int ikev2_set_log_level (ikev2_log_level_t log_level); u8 *ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type); void ikev2_disable_dpd (void); +clib_error_t *ikev2_profile_natt_disable (u8 * name); static_always_inline ikev2_main_per_thread_data_t * ikev2_get_per_thread_data () diff --git a/src/plugins/ikev2/ikev2_test.c b/src/plugins/ikev2/ikev2_test.c index 81a222c0971b..d9f5e2256b6b 100644 --- a/src/plugins/ikev2/ikev2_test.c +++ b/src/plugins/ikev2/ikev2_test.c @@ -46,6 +46,7 @@ typedef struct vat_main_t *vat_main; } ikev2_test_main_t; +static const char *valid_chars = "a-zA-Z0-9_"; ikev2_test_main_t ikev2_test_main; uword @@ -191,6 +192,47 @@ format_ikev2_sa_transform (u8 * s, va_list * args) return s; } +static int +api_ikev2_profile_disable_natt (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_disable_natt_t *mp; + u8 *name = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + M (IKEV2_PROFILE_DISABLE_NATT, mp); + + clib_memcpy (mp->name, name, vec_len (name)); + vec_free (name); + + S (mp); + W (ret); + return ret; +} + static int api_ikev2_profile_dump (vat_main_t * vam) { @@ -280,6 +322,9 @@ static void vl_api_ikev2_profile_details_t_handler if (p->udp_encap) fformat (vam->ofp, " udp-encap\n"); + if (p->natt_disabled) + fformat (vam->ofp, " NAT-T disabled\n"); + u32 ipsec_over_udp_port = clib_net_to_host_u16 (p->ipsec_over_udp_port); if (ipsec_over_udp_port != IPSEC_UDP_PORT_NONE) fformat (vam->ofp, " ipsec-over-udp port %d\n", ipsec_over_udp_port); @@ -674,8 +719,6 @@ api_ikev2_profile_add_del (vat_main_t * vam) u8 *name = 0; int ret; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "del")) @@ -723,8 +766,6 @@ api_ikev2_profile_set_auth (vat_main_t * vam) u8 is_hex = 0; int ret; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "name %U", unformat_token, valid_chars, &name)) @@ -794,8 +835,6 @@ api_ikev2_profile_set_id (vat_main_t * vam) ip_address_t ip; int ret; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "name %U", unformat_token, valid_chars, &name)) @@ -871,8 +910,6 @@ api_ikev2_profile_set_ts (vat_main_t * vam) u32 proto = 0, start_port = 0, end_port = (u32) ~ 0; ip_address_t start_addr, end_addr; u8 start_addr_set = 0, end_addr_set = 0; - - const char *valid_chars = "a-zA-Z0-9_"; int ret; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) @@ -984,8 +1021,6 @@ api_ikev2_profile_set_udp_encap (vat_main_t * vam) int ret; u8 *name = 0; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "%U udp-encap", unformat_token, valid_chars, &name)) @@ -1035,8 +1070,6 @@ api_ikev2_set_responder (vat_main_t * vam) u32 sw_if_index = ~0; ip_address_t address; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat @@ -1084,8 +1117,6 @@ api_ikev2_set_ike_transforms (vat_main_t * vam) u8 *name = 0; u32 crypto_alg, crypto_key_size, integ_alg, dh_group; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "%U %d %d %d %d", unformat_token, valid_chars, &name, @@ -1134,8 +1165,6 @@ api_ikev2_set_esp_transforms (vat_main_t * vam) u8 *name = 0; u32 crypto_alg, crypto_key_size, integ_alg; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "%U %d %d %d", unformat_token, valid_chars, &name, @@ -1183,8 +1212,6 @@ api_ikev2_set_sa_lifetime (vat_main_t * vam) u64 lifetime, lifetime_maxdata; u32 lifetime_jitter, handover; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "%U %lu %u %u %lu", unformat_token, valid_chars, &name, @@ -1232,8 +1259,6 @@ api_ikev2_initiate_sa_init (vat_main_t * vam) int ret; u8 *name = 0; - const char *valid_chars = "a-zA-Z0-9_"; - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { if (unformat (i, "%U", unformat_token, valid_chars, &name)) diff --git a/src/plugins/ikev2/ikev2_types.api b/src/plugins/ikev2/ikev2_types.api index 0f998b196c26..d39cf88c8d4f 100644 --- a/src/plugins/ikev2/ikev2_types.api +++ b/src/plugins/ikev2/ikev2_types.api @@ -84,6 +84,7 @@ typedef ikev2_profile u16 ipsec_over_udp_port; u32 tun_itf; bool udp_encap; + bool natt_disabled; vl_api_ikev2_auth_t auth; }; diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 91cec8e9a62b..d065d46e8eb3 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -1393,6 +1393,8 @@ def configure_profile(self, cfg): p.set_lifetime_data(cfg['lifetime_data']) if 'tun_itf' in cfg: p.set_tunnel_interface(cfg['tun_itf']) + if 'natt_disabled' in cfg and cfg['natt_disabled']: + p.disable_natt() p.add_vpp_config() return p @@ -1431,6 +1433,7 @@ def test_profile_api(self): conf = { 'p1': { 'name': 'p1', + 'natt_disabled': True, 'loc_id': ('fqdn', b'vpp.home'), 'rem_id': ('fqdn', b'roadwarrior.example.com'), 'loc_ts': loc_ts4, @@ -1534,6 +1537,9 @@ def verify_profile(self, ap, cp): self.verify_ike_transforms(ap.ike_ts, cp['ike_ts']) self.verify_esp_transforms(ap.esp_ts, cp['esp_ts']) self.verify_auth(ap.auth, cp['auth']) + natt_dis = False if 'natt_disabled' not in cp else cp['natt_disabled'] + self.assertTrue(natt_dis == ap.natt_disabled) + if 'lifetime_data' in cp: self.verify_lifetime_data(ap, cp['lifetime_data']) self.assertEqual(ap.ipsec_over_udp_port, cp['ipsec_over_udp_port']) diff --git a/src/plugins/ikev2/test/vpp_ikev2.py b/src/plugins/ikev2/test/vpp_ikev2.py index 6ae30201450a..dd1c3fc986e6 100644 --- a/src/plugins/ikev2/test/vpp_ikev2.py +++ b/src/plugins/ikev2/test/vpp_ikev2.py @@ -27,6 +27,10 @@ def __init__(self, test, profile_name): self.vapi = test.vapi self.profile_name = profile_name self.udp_encap = False + self.natt = True + + def disable_natt(self): + self.natt = False def add_auth(self, method, data, is_hex=False): if isinstance(method, int): @@ -156,6 +160,9 @@ def add_vpp_config(self): self.vapi.ikev2_set_tunnel_interface(name=self.profile_name, sw_if_index=self.tun_itf) + if not self.natt: + self.vapi.ikev2_profile_disable_natt(name=self.profile_name) + def query_vpp_config(self): res = self.vapi.ikev2_profile_dump() for r in res: From cbc3dc0b3043512f3fc31763683a220c1bcc5de0 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 6 Nov 2020 11:00:42 +0000 Subject: [PATCH 110/129] ikev2: fix udp encap Type: fix Change-Id: I8c66f79f2d8cfff7c6d45e1fc5b529ffb3941491 Signed-off-by: Filip Tehlar (cherry picked from commit 67b8a7fa76d8ec2d73f1b2380e11bf8e2793448e) --- src/plugins/ikev2/ikev2.c | 9 ++++----- src/plugins/ikev2/test/test_ikev2.py | 23 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 09a7359d5c68..024cf326c166 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1816,7 +1816,6 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) ikev2_main_t *km = &ikev2_main; u32 sw_if_index; int rv = 0; - ip46_address_t zero_addr = ip46_address_initializer; if (~0 == a->sw_if_index) { @@ -1865,14 +1864,14 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) a->local_spi, IPSEC_PROTOCOL_ESP, a->encr_type, &a->loc_ckey, a->integ_type, &a->loc_ikey, - a->flags, 0, a->salt_local, &zero_addr, - &zero_addr, NULL, a->src_port, a->dst_port); + a->flags, 0, a->salt_local, &a->local_ip, + &a->remote_ip, NULL, a->src_port, a->dst_port); rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi, IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey, a->integ_type, &a->rem_ikey, (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0, - a->salt_remote, &zero_addr, - &zero_addr, NULL, a->ipsec_over_udp_port, + a->salt_remote, &a->remote_ip, + &a->local_ip, NULL, a->ipsec_over_udp_port, a->ipsec_over_udp_port); rv |= ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in); diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index d065d46e8eb3..61dd53e79889 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -181,7 +181,9 @@ class IKEv2SA(object): def __init__(self, test, is_initiator=True, i_id=None, r_id=None, spi=b'\x01\x02\x03\x04\x05\x06\x07\x08', id_type='fqdn', nonce=None, auth_data=None, local_ts=None, remote_ts=None, - auth_method='shared-key', priv_key=None, natt=False): + auth_method='shared-key', priv_key=None, natt=False, + udp_encap=False): + self.udp_encap = udp_encap self.natt = natt if natt: self.sport = 4500 @@ -662,6 +664,13 @@ def encrypt_ike_msg(self, header, plain, first_payload): assert(len(res) == tlen) return res + def verify_udp_encap(self, ipsec_sa): + e = VppEnum.vl_api_ipsec_sad_flags_t + if self.sa.udp_encap or self.sa.natt: + self.assertIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags) + else: + self.assertNotIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags) + def verify_ipsec_sas(self, is_rekey=False): sas = self.vapi.ipsec_sa_dump() if is_rekey: @@ -671,7 +680,6 @@ def verify_ipsec_sas(self, is_rekey=False): else: sa_count = 2 self.assertEqual(len(sas), sa_count) - e = VppEnum.vl_api_ipsec_sad_flags_t if self.sa.is_initiator: if is_rekey: sa0 = sas[0].entry @@ -689,6 +697,8 @@ def verify_ipsec_sas(self, is_rekey=False): c = self.sa.child_sas[0] + self.verify_udp_encap(sa0) + self.verify_udp_encap(sa1) vpp_crypto_alg = self.vpp_enums[self.sa.vpp_esp_cypto_alg] self.assertEqual(sa0.crypto_algorithm, vpp_crypto_alg) self.assertEqual(sa1.crypto_algorithm, vpp_crypto_alg) @@ -1332,13 +1342,17 @@ def config_params(self, params={}): if 'esp_transforms' in params: self.p.add_esp_transforms(params['esp_transforms']) + udp_encap = False if 'udp_encap' not in params else\ + params['udp_encap'] + if udp_encap: + self.p.set_udp_encap(True) + self.sa = IKEv2SA(self, i_id=idi['data'], r_id=idr['data'], is_initiator=is_init, id_type=self.p.local_id['id_type'], natt=is_natt, priv_key=client_priv, auth_method=auth_method, - auth_data=auth_data, + auth_data=auth_data, udp_encap=udp_encap, local_ts=self.p.remote_ts, remote_ts=self.p.local_ts) - if is_init: ike_crypto = ('AES-CBC', 32) if 'ike-crypto' not in params else\ params['ike-crypto'] @@ -1687,6 +1701,7 @@ class TestResponderRsaSign(TemplateResponder, Ikev2Params): """ test ikev2 responder - cert based auth """ def config_tc(self): self.config_params({ + 'udp_encap': True, 'auth': 'rsa-sig', 'server-key': 'server-key.pem', 'client-key': 'client-key.pem', From 6d878f3e61d7bace709a9d2285ab43f7502b38eb Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Sat, 31 Oct 2020 02:17:16 +0000 Subject: [PATCH 111/129] ikev2: fix msg IDs generation Type: fix Change-Id: Id922895c269f0d2450e55fcb6871b6857f443462 Signed-off-by: Filip Tehlar (cherry picked from commit f6b02e0d0bfd7e0f1d79e8ee426f48ca37ae5ff3) --- src/plugins/ikev2/ikev2.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 024cf326c166..30e2a48ee84d 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -436,6 +436,7 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) sa->i_auth.data = _(sai->i_auth.data); sa->i_auth.key = _(sai->i_auth.key); sa->last_sa_init_req_packet_data = _(sai->last_sa_init_req_packet_data); + sa->last_init_msg_id = sai->last_init_msg_id; sa->childs = _(sai->childs); sa->udp_encap = sai->udp_encap; sa->ipsec_over_udp_port = sai->ipsec_over_udp_port; @@ -1409,7 +1410,8 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, p += plen; } - if (sa->is_initiator && proposal->protocol_id == IKEV2_PROTOCOL_ESP) + if (sa->is_initiator && proposal + && proposal->protocol_id == IKEV2_PROTOCOL_ESP) { ikev2_rekey_t *rekey = &sa->rekey[0]; rekey->protocol_id = proposal->protocol_id; @@ -2460,11 +2462,6 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, if (sa->is_initiator) ike->flags |= IKEV2_HDR_FLAG_INITIATOR; - if (ike_hdr_is_request (ike)) - { - sa->last_init_msg_id = clib_net_to_host_u32 (ike->msgid); - } - if (ike->exchange == IKEV2_EXCHANGE_SA_INIT) { tlen += vec_len (chain->data); @@ -2958,6 +2955,9 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_calc_keys (sa0); ikev2_sa_auth_init (sa0); ike0->flags = IKEV2_HDR_FLAG_INITIATOR; + ike0->msgid = + clib_net_to_host_u32 (sai->last_init_msg_id); + sa0->last_init_msg_id = sai->last_init_msg_id + 1; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) @@ -3030,6 +3030,7 @@ ikev2_node_internal (vlib_main_t * vm, } else { + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3630,8 +3631,8 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); ike0->flags = 0; - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + sa->last_init_msg_id += 1; len = ikev2_generate_message (b0, sa, ike0, 0, 0); if (~0 == len) return; @@ -4213,6 +4214,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) ike0->ispi = clib_host_to_net_u64 (sa.ispi); ike0->rspi = 0; ike0->msgid = 0; + sa.last_init_msg_id += 1; /* store whole IKE payload - needed for PSK auth */ vec_reset_length (sa.last_sa_init_req_packet_data); @@ -4289,8 +4291,8 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, vec_resize (sa->del, 1); sa->del->protocol_id = IKEV2_PROTOCOL_ESP; sa->del->spi = csa->i_proposals->spi; - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + sa->last_init_msg_id += 1; len = ikev2_generate_message (b0, sa, ike0, 0, 0); if (~0 == len) return; @@ -4405,8 +4407,8 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, ike0->exchange = IKEV2_EXCHANGE_CREATE_CHILD_SA; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + sa->last_init_msg_id += 1; ikev2_rekey_t *rekey; vec_add2 (sa->rekey, rekey, 1); @@ -4864,9 +4866,9 @@ ikev2_send_informational_request (ikev2_sa_t * sa) ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); ike0->flags = 0; - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + sa->last_init_msg_id += 1; len = ikev2_generate_message (b0, sa, ike0, 0, 0); if (~0 == len) return; From 29ad98844bc90fb6780642cabe6fb074e6930628 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Mon, 9 Nov 2020 13:23:24 +0000 Subject: [PATCH 112/129] ikev2: add tests for DPD Type: test Change-Id: I9c1129a8596344551f3f8f2e029846d22511482e Signed-off-by: Filip Tehlar (cherry picked from commit 2008e314537500975acbd666e38d3fa6e7261bf5) --- src/plugins/ikev2/test/test_ikev2.py | 63 +++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 61dd53e79889..453a47e04c8c 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -1,4 +1,5 @@ import os +import time from socket import inet_pton from cryptography import x509 from cryptography.hazmat.backends import default_backend @@ -584,7 +585,6 @@ def setUp(self): self.sa.generate_dh_data() self.vapi.cli('ikev2 set logging level 4') self.vapi.cli('event-lo clear') - self.vapi.cli('ikev2 dpd disable') def create_packet(self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False): @@ -1289,6 +1289,10 @@ def config_params(self, params={}): 'SHA2-384-192': ei.IPSEC_API_INTEG_ALG_SHA_384_192, 'SHA2-512-256': ei.IPSEC_API_INTEG_ALG_SHA_512_256} + dpd_disabled = True if 'dpd_disabled' not in params else\ + params['dpd_disabled'] + if dpd_disabled: + self.vapi.cli('ikev2 dpd disable') self.del_sa_from_responder = False if 'del_sa_from_responder'\ not in params else params['del_sa_from_responder'] is_natt = 'natt' in params and params['natt'] or False @@ -1663,6 +1667,35 @@ def config_tc(self): self.config_params() +class TestResponderDpd(TestResponderPsk): + """ + Dead peer detection test + """ + def config_tc(self): + self.config_params({'dpd_disabled': False}) + + def tearDown(self): + pass + + def test_responder(self): + self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1) + super(TestResponderDpd, self).test_responder() + self.pg0.enable_capture() + self.pg_start() + # capture empty request but don't reply + capture = self.pg0.get_capture(expected_count=1, timeout=5) + ih = self.get_ike_header(capture[0]) + self.assertEqual(ih.exch_type, 37) # INFORMATIONAL + plain = self.sa.hmac_and_decrypt(ih) + self.assertEqual(plain, b'') + # wait for SA expiration + time.sleep(3) + ike_sas = self.vapi.ikev2_sa_dump() + self.assertEqual(len(ike_sas), 0) + ipsec_sas = self.vapi.ipsec_sa_dump() + self.assertEqual(len(ipsec_sas), 0) + + class TestResponderRekey(TestResponderPsk): """ test ikev2 responder - rekey """ @@ -1755,6 +1788,34 @@ def config_tc(self): 'end_addr': '11::100'}}) +class TestInitiatorKeepaliveMsg(TestInitiatorPsk): + """ + Test for keep alive messages + """ + + def send_empty_req_from_responder(self): + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + id=self.sa.new_msg_id(), flags='Initiator', + exch_type='INFORMATIONAL', + next_payload='Encrypted') + + msg = self.encrypt_ike_msg(header, b'', None) + packet = self.create_packet(self.pg0, msg, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + self.pg0.add_stream(packet) + self.pg0.enable_capture() + self.pg_start() + capture = self.pg0.get_capture(1) + ih = self.get_ike_header(capture[0]) + self.assertEqual(ih.id, self.sa.msg_id) + plain = self.sa.hmac_and_decrypt(ih) + self.assertEqual(plain, b'') + + def test_initiator(self): + super(TestInitiatorKeepaliveMsg, self).test_initiator() + self.send_empty_req_from_responder() + + class TestMalformedMessages(TemplateResponder, Ikev2Params): """ malformed packet test """ From 49de3282a3101dcc89e417d3c80a5af91d72a158 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 10 Nov 2020 09:32:13 +0000 Subject: [PATCH 113/129] ikev2: fix memleak when tunnel protect fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: fix Change-Id: I1d278fc2b03b948c054ff1686315635ac0278ae8 Signed-off-by: Filip Tehlar Signed-off-by: Benoît Ganne (cherry picked from commit 727082016f8822edcf40662d0059d3e8fab5e2ef) --- src/plugins/ikev2/ikev2.c | 51 +++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 30e2a48ee84d..d64ea6a88cdc 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1862,21 +1862,37 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) vec_add1 (sas_in, a->old_remote_sa_id); } - rv |= ipsec_sa_add_and_lock (a->local_sa_id, - a->local_spi, - IPSEC_PROTOCOL_ESP, a->encr_type, - &a->loc_ckey, a->integ_type, &a->loc_ikey, - a->flags, 0, a->salt_local, &a->local_ip, - &a->remote_ip, NULL, a->src_port, a->dst_port); - rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi, - IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey, - a->integ_type, &a->rem_ikey, - (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0, - a->salt_remote, &a->remote_ip, - &a->local_ip, NULL, a->ipsec_over_udp_port, - a->ipsec_over_udp_port); - - rv |= ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in); + rv = ipsec_sa_add_and_lock (a->local_sa_id, + a->local_spi, + IPSEC_PROTOCOL_ESP, a->encr_type, + &a->loc_ckey, a->integ_type, &a->loc_ikey, + a->flags, 0, a->salt_local, &a->local_ip, + &a->remote_ip, NULL, a->src_port, a->dst_port); + if (rv) + goto err0; + + rv = ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi, + IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey, + a->integ_type, &a->rem_ikey, + (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0, + a->salt_remote, &a->remote_ip, + &a->local_ip, NULL, a->ipsec_over_udp_port, + a->ipsec_over_udp_port); + if (rv) + goto err1; + + rv = ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in); + if (rv) + goto err2; + + return; + +err2: + ipsec_sa_unlock_id (a->remote_sa_id); +err1: + ipsec_sa_unlock_id (a->local_sa_id); +err0: + vec_free (sas_in); } static int @@ -4689,7 +4705,10 @@ ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa, u32 *sas_in = NULL; vec_add1 (sas_in, csa->remote_sa_id); vlib_worker_thread_barrier_sync (vm); - ipsec_tun_protect_update (sw_if_index, NULL, csa->local_sa_id, sas_in); + int rv = ipsec_tun_protect_update (sw_if_index, NULL, + csa->local_sa_id, sas_in); + if (rv) + vec_free (sas_in); ipsec_sa_unlock_id (ikev2_flip_alternate_sa_bit (csa->remote_sa_id)); vlib_worker_thread_barrier_release (vm); } From 186f018f68ad0b0e9026e1150b576e4fa7000987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Thu, 12 Nov 2020 10:29:23 +0100 Subject: [PATCH 114/129] ikev2: respect punting only for ipv4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IPSec punting to IKEv2 is valid only for NAT-T in IPv4. Fix coverity CID 214915. Type: fix Change-Id: I6f2db38abf179565316f50c5d47c78acce3a0d01 Signed-off-by: Benoît Ganne (cherry picked from commit d9ed0b67866fa6b8a5f449fdb8da8d6aacb5f225) --- src/plugins/ikev2/ikev2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index d64ea6a88cdc..a2640f03bdbd 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -2816,7 +2816,13 @@ ikev2_node_internal (vlib_main_t * vm, int ip_hdr_sz = 0; int is_req = 0, has_non_esp_marker = 0; - if (b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) + ASSERT (0 == b0->punt_reason + || (is_ip4 + && b0->punt_reason == + ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0])); + + if (is_ip4 + && b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) { u8 *ptr = vlib_buffer_get_current (b0); ip40 = (ip4_header_t *) ptr; From 6e13acc42ec519dcdaa8bd0acac0b264a686eaf2 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 19 Nov 2020 21:34:48 +0000 Subject: [PATCH 115/129] ikev2: fix issue when sending multiple requests at once Type: fix Change-Id: I8ed556de4370a03d10c56cce101cd5ea0d0aaf8b Signed-off-by: Filip Tehlar (cherry picked from commit 38340fa32c96e9c6cb1593f03117dd504efbd5f4) --- src/plugins/ikev2/ikev2.c | 5 +- src/plugins/ikev2/test/test_ikev2.py | 83 +++++++++++++++++++++------- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index a2640f03bdbd..2423bf2058d3 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1413,7 +1413,9 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, if (sa->is_initiator && proposal && proposal->protocol_id == IKEV2_PROTOCOL_ESP) { - ikev2_rekey_t *rekey = &sa->rekey[0]; + ikev2_rekey_t *rekey = sa->rekey; + if (vec_len (rekey) == 0) + goto cleanup_and_exit; rekey->protocol_id = proposal->protocol_id; rekey->i_proposal = ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); @@ -4433,6 +4435,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, sa->last_init_msg_id += 1; ikev2_rekey_t *rekey; + vec_reset_length (sa->rekey); vec_add2 (sa->rekey, rekey, 1); ikev2_sa_proposal_t *proposals = vec_dup (csa->i_proposals); diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 453a47e04c8c..eb2c5f988d4d 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -586,6 +586,27 @@ def setUp(self): self.vapi.cli('ikev2 set logging level 4') self.vapi.cli('event-lo clear') + def create_rekey_request(self): + sa, first_payload = self.generate_auth_payload(is_rekey=True) + header = ikev2.IKEv2( + init_SPI=self.sa.ispi, + resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), + flags='Initiator', exch_type='CREATE_CHILD_SA') + + ike_msg = self.encrypt_ike_msg(header, sa, first_payload) + return self.create_packet(self.pg0, ike_msg, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + + def create_empty_request(self): + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + id=self.sa.new_msg_id(), flags='Initiator', + exch_type='INFORMATIONAL', + next_payload='Encrypted') + + msg = self.encrypt_ike_msg(header, b'', None) + return self.create_packet(self.pg0, msg, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + def create_packet(self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False): if use_ip6: @@ -1591,6 +1612,47 @@ def config_tc(self): 'integ_alg': 12}}) +class TestInitiatorRequestWindowSize(TestInitiatorPsk): + """ test initiator - request window size (1) """ + + def rekey_respond(self, req, update_child_sa_data): + ih = self.get_ike_header(req) + plain = self.sa.hmac_and_decrypt(ih) + sa = ikev2.IKEv2_payload_SA(plain) + if update_child_sa_data: + prop = sa[ikev2.IKEv2_payload_Proposal] + self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load + self.sa.r_nonce = self.sa.i_nonce + self.sa.child_sas[0].ispi = prop.SPI + self.sa.child_sas[0].rspi = prop.SPI + self.sa.calc_child_keys() + + header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, + flags='Response', exch_type=36, + id=ih.id, next_payload='Encrypted') + resp = self.encrypt_ike_msg(header, sa, 'SA') + packet = self.create_packet(self.pg0, resp, self.sa.sport, + self.sa.dport, self.sa.natt, self.ip6) + self.send_and_assert_no_replies(self.pg0, packet) + + def test_initiator(self): + super(TestInitiatorRequestWindowSize, self).test_initiator() + self.pg0.enable_capture() + self.pg_start() + ispi = int.from_bytes(self.sa.child_sas[0].ispi, 'little') + self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi) + self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi) + capture = self.pg0.get_capture(2) + + # reply in reverse order + self.rekey_respond(capture[1], True) + self.rekey_respond(capture[0], False) + + # verify that only the second request was accepted + self.verify_ike_sas() + self.verify_ipsec_sas(is_rekey=True) + + class TestInitiatorRekey(TestInitiatorPsk): """ test ikev2 initiator - rekey """ @@ -1607,7 +1669,6 @@ def rekey_from_initiator(self): plain = self.sa.hmac_and_decrypt(ih) sa = ikev2.IKEv2_payload_SA(plain) prop = sa[ikev2.IKEv2_payload_Proposal] - nonce = sa[ikev2.IKEv2_payload_Nonce] self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load self.sa.r_nonce = self.sa.i_nonce # update new responder SPI @@ -1700,15 +1761,7 @@ class TestResponderRekey(TestResponderPsk): """ test ikev2 responder - rekey """ def rekey_from_initiator(self): - sa, first_payload = self.generate_auth_payload(is_rekey=True) - header = ikev2.IKEv2( - init_SPI=self.sa.ispi, - resp_SPI=self.sa.rspi, id=self.sa.new_msg_id(), - flags='Initiator', exch_type='CREATE_CHILD_SA') - - ike_msg = self.encrypt_ike_msg(header, sa, first_payload) - packet = self.create_packet(self.pg0, ike_msg, self.sa.sport, - self.sa.dport, self.sa.natt, self.ip6) + packet = self.create_rekey_request() self.pg0.add_stream(packet) self.pg0.enable_capture() self.pg_start() @@ -1717,7 +1770,6 @@ def rekey_from_initiator(self): plain = self.sa.hmac_and_decrypt(ih) sa = ikev2.IKEv2_payload_SA(plain) prop = sa[ikev2.IKEv2_payload_Proposal] - nonce = sa[ikev2.IKEv2_payload_Nonce] self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load # update new responder SPI self.sa.child_sas[0].rspi = prop.SPI @@ -1794,14 +1846,7 @@ class TestInitiatorKeepaliveMsg(TestInitiatorPsk): """ def send_empty_req_from_responder(self): - header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, - id=self.sa.new_msg_id(), flags='Initiator', - exch_type='INFORMATIONAL', - next_payload='Encrypted') - - msg = self.encrypt_ike_msg(header, b'', None) - packet = self.create_packet(self.pg0, msg, self.sa.sport, - self.sa.dport, self.sa.natt, self.ip6) + packet = self.create_empty_request() self.pg0.add_stream(packet) self.pg0.enable_capture() self.pg_start() From 0e68a7cb5bf7ed0c8b75c0aa10d418cc14e0bad1 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Sat, 21 Nov 2020 21:30:45 +0000 Subject: [PATCH 116/129] ikev2: better handling when no IKE DH configured Type: improvement Change-Id: I4289d20adaa3f2872889d5dbaafd9c025df8aca8 Signed-off-by: Filip Tehlar (cherry picked from commit e1ab06c14deaff5cc0870f7ec76f36613ffcc2d3) --- src/plugins/ikev2/ikev2.c | 93 +++++++++++++++++++++++++------ src/plugins/ikev2/ikev2_api.c | 102 ++++++++++++++++++++++++++++------ 2 files changed, 161 insertions(+), 34 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 2423bf2058d3..03b402145ade 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -62,6 +62,37 @@ format_ikev2_trace (u8 * s, va_list * args) return s; } +#define IKEV2_GENERATE_SA_INIT_OK_str "" +#define IKEV2_GENERATE_SA_INIT_OK_ERR_NO_DH_STR \ + "no DH group configured for IKE proposals!" +#define IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR \ + "DH group not supported!" + +typedef enum +{ + IKEV2_GENERATE_SA_INIT_OK, + IKEV2_GENERATE_SA_INIT_ERR_NO_DH, + IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH, +} ikev2_generate_sa_error_t; + +static u8 * +format_ikev2_gen_sa_error (u8 * s, va_list * args) +{ + ikev2_generate_sa_error_t e = va_arg (*args, ikev2_generate_sa_error_t); + switch (e) + { + case IKEV2_GENERATE_SA_INIT_OK: + break; + case IKEV2_GENERATE_SA_INIT_ERR_NO_DH: + s = format (s, IKEV2_GENERATE_SA_INIT_OK_ERR_NO_DH_STR); + break; + case IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH: + s = format (s, IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR); + break; + } + return s; +} + #define foreach_ikev2_error \ _(PROCESSED, "IKEv2 packets processed") \ _(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \ @@ -358,16 +389,14 @@ ikev2_delete_sa (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa) } } -static void +static ikev2_generate_sa_error_t ikev2_generate_sa_init_data (ikev2_sa_t * sa) { ikev2_sa_transform_t *t = 0, *t2; ikev2_main_t *km = &ikev2_main; if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE) - { - return; - } + return IKEV2_GENERATE_SA_INIT_ERR_NO_DH; /* check if received DH group is on our list of supported groups */ vec_foreach (t2, km->supported_transforms) @@ -382,7 +411,7 @@ ikev2_generate_sa_init_data (ikev2_sa_t * sa) if (!t) { sa->dh_group = IKEV2_TRANSFORM_DH_TYPE_NONE; - return; + return IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH; } if (sa->is_initiator) @@ -407,6 +436,7 @@ ikev2_generate_sa_init_data (ikev2_sa_t * sa) /* generate dh keys */ ikev2_generate_dh (sa, t); + return IKEV2_GENERATE_SA_INIT_OK; } static void @@ -2787,6 +2817,20 @@ ikev2_elog_uint_peers_addr (u32 exchange, ip4_header_t * ip4, exchange, src, dst); } +static void +ikev2_generate_sa_init_data_and_log (ikev2_sa_t * sa) +{ + ikev2_generate_sa_error_t rc = ikev2_generate_sa_init_data (sa); + + if (PREDICT_TRUE (rc == IKEV2_GENERATE_SA_INIT_OK)) + return; + + if (rc == IKEV2_GENERATE_SA_INIT_ERR_NO_DH) + ikev2_elog_error (IKEV2_GENERATE_SA_INIT_OK_ERR_NO_DH_STR); + else if (rc == IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH) + ikev2_elog_error (IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR); +} + static_always_inline uword ikev2_node_internal (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, @@ -2924,7 +2968,7 @@ ikev2_node_internal (vlib_main_t * vm, sa0->r_proposals = ikev2_select_proposal (sa0->i_proposals, IKEV2_PROTOCOL_IKE); - ikev2_generate_sa_init_data (sa0); + ikev2_generate_sa_init_data_and_log (sa0); } if (sa0->state == IKEV2_STATE_SA_INIT @@ -4149,15 +4193,6 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) valid_ip = 1; } - bi0 = ikev2_get_new_ike_header_buff (vm, &b0); - if (!bi0) - { - char *errmsg = "buffer alloc failure"; - ikev2_log_error (errmsg); - return clib_error_return (0, errmsg); - } - ike0 = vlib_buffer_get_current (b0); - /* Prepare the SA and the IKE payload */ ikev2_sa_t sa; clib_memset (&sa, 0, sizeof (ikev2_sa_t)); @@ -4185,7 +4220,15 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sa.is_tun_itf_set = 1; sa.initial_contact = 1; sa.dst_port = IKEV2_PORT; - ikev2_generate_sa_init_data (&sa); + + ikev2_generate_sa_error_t rc = ikev2_generate_sa_init_data (&sa); + if (rc != IKEV2_GENERATE_SA_INIT_OK) + { + ikev2_sa_free_all_vec (&sa); + ikev2_payload_destroy_chain (chain); + return clib_error_return (0, "%U", format_ikev2_gen_sa_error, rc); + } + ikev2_payload_add_ke (chain, sa.dh_group, sa.i_dh_data); ikev2_payload_add_nonce (chain, sa.i_nonce); @@ -4225,6 +4268,17 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sig_hash_algo); vec_free (sig_hash_algo); + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); + if (!bi0) + { + ikev2_sa_free_all_vec (&sa); + ikev2_payload_destroy_chain (chain); + char *errmsg = "buffer alloc failure"; + ikev2_log_error (errmsg); + return clib_error_return (0, errmsg); + } + ike0 = vlib_buffer_get_current (b0); + /* Buffer update and boilerplate */ len += vec_len (chain->data); ike0->nextpayload = chain->first_payload_type; @@ -5014,7 +5068,12 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, p = pool_elt_at_index (km->profiles, sa->profile_index); if (p) { - ikev2_initiate_sa_init (vm, p->name); + clib_error_t *e = ikev2_initiate_sa_init (vm, p->name); + if (e) + { + ikev2_log_error ("%U", format_clib_error, e); + clib_error_free (e); + } } } } diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c index 63d8760b0431..dd4c094c50e4 100644 --- a/src/plugins/ikev2/ikev2_api.c +++ b/src/plugins/ikev2/ikev2_api.c @@ -481,7 +481,11 @@ static void error = ikev2_set_liveness_params (clib_net_to_host_u32 (mp->period), clib_net_to_host_u32 (mp->max_retries)); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -502,7 +506,11 @@ vl_api_ikev2_profile_add_del_t_handler (vl_api_ikev2_profile_add_del_t * mp) error = ikev2_add_del_profile (vm, tmp, mp->is_add); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -528,7 +536,11 @@ static void vec_free (tmp); vec_free (data); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -553,7 +565,11 @@ vl_api_ikev2_profile_set_id_t_handler (vl_api_ikev2_profile_set_id_t * mp) vec_free (tmp); vec_free (data); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -575,7 +591,11 @@ static void error = ikev2_set_profile_udp_encap (vm, tmp); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -603,7 +623,11 @@ vl_api_ikev2_profile_set_ts_t_handler (vl_api_ikev2_profile_set_ts_t * mp) start_addr, end_addr, mp->ts.is_local); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -623,7 +647,11 @@ vl_api_ikev2_set_local_key_t_handler (vl_api_ikev2_set_local_key_t * mp) error = ikev2_set_local_key (vm, mp->key_file); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -649,7 +677,11 @@ vl_api_ikev2_set_responder_t_handler (vl_api_ikev2_set_responder_t * mp) error = ikev2_set_profile_responder (vm, tmp, sw_if_index, ip); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -677,7 +709,11 @@ vl_api_ikev2_set_ike_transforms_t_handler (vl_api_ikev2_set_ike_transforms_t * ntohl (mp->tr.crypto_key_size)); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -704,7 +740,11 @@ vl_api_ikev2_set_esp_transforms_t_handler (vl_api_ikev2_set_esp_transforms_t * ntohl (mp->tr.crypto_key_size)); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -733,7 +773,11 @@ vl_api_ikev2_set_sa_lifetime_t_handler (vl_api_ikev2_set_sa_lifetime_t * mp) (mp->lifetime_maxdata)); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -782,7 +826,11 @@ static void ntohl (mp->sw_if_index)); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } vec_free (tmp); #else rv = VNET_API_ERROR_UNIMPLEMENTED; @@ -807,7 +855,11 @@ vl_api_ikev2_initiate_sa_init_t_handler (vl_api_ikev2_initiate_sa_init_t * mp) error = ikev2_initiate_sa_init (vm, tmp); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -828,7 +880,11 @@ vl_api_ikev2_initiate_del_ike_sa_t_handler (vl_api_ikev2_initiate_del_ike_sa_t error = ikev2_initiate_delete_ike_sa (vm, mp->ispi); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -849,7 +905,11 @@ static void error = ikev2_initiate_delete_child_sa (vm, mp->ispi); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -871,7 +931,11 @@ static void error = ikev2_profile_natt_disable (tmp); vec_free (tmp); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -892,7 +956,11 @@ static void error = ikev2_initiate_rekey_child_sa (vm, mp->ispi); if (error) - rv = VNET_API_ERROR_UNSPECIFIED; + { + ikev2_log_error ("%U", format_clib_error, error); + clib_error_free (error); + rv = VNET_API_ERROR_UNSPECIFIED; + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif From b72fb31d69039a86a4ed69d510ce8298c0a4fb49 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 20 Nov 2020 13:05:59 +0000 Subject: [PATCH 117/129] ip-neighbor: Send API event when neighbor is removed Type: fix Signed-off-by: Neale Ranns Change-Id: I9952497a108bac26445af95c28d4eed46099c2fc --- src/vnet/ip-neighbor/ip_neighbor.api | 52 +++++++++++++++- src/vnet/ip-neighbor/ip_neighbor.c | 24 ++++---- src/vnet/ip-neighbor/ip_neighbor.h | 4 +- src/vnet/ip-neighbor/ip_neighbor_api.c | 76 ++++++++++++++++++++---- src/vnet/ip-neighbor/ip_neighbor_types.c | 15 +++++ src/vnet/ip-neighbor/ip_neighbor_types.h | 35 +++++------ src/vnet/ip-neighbor/ip_neighbor_watch.c | 17 ++++-- src/vnet/ip-neighbor/ip_neighbor_watch.h | 3 +- test/test_neighbor.py | 35 +++++++++++ 9 files changed, 210 insertions(+), 51 deletions(-) diff --git a/src/vnet/ip-neighbor/ip_neighbor.api b/src/vnet/ip-neighbor/ip_neighbor.api index fe344af5c820..62730e7c1e3c 100644 --- a/src/vnet/ip-neighbor/ip_neighbor.api +++ b/src/vnet/ip-neighbor/ip_neighbor.api @@ -179,8 +179,7 @@ autoreply define ip_neighbor_flush vl_api_interface_index_t sw_if_index [default=0xffffffff]; }; -/** \brief Register for IP4 ARP resolution event on receiving ARP reply or - MAC/IP info from ARP requests in L2 BDs +/** \brief Register for IP neighbour events creation @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param enable - 1 => register for events, 0 => cancel registration @@ -190,6 +189,7 @@ autoreply define ip_neighbor_flush */ autoreply define want_ip_neighbor_events { + option deprecated; u32 client_index; u32 context; bool enable; @@ -206,6 +206,7 @@ autoreply define want_ip_neighbor_events */ define ip_neighbor_event { + option deprecated; u32 client_index; u32 pid; vl_api_ip_neighbor_t neighbor; @@ -216,6 +217,53 @@ service { events ip_neighbor_event; }; + +/** \brief Register for IP neighbour events (creation or deletion) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param enable - 1 => register for events, 0 => cancel registration + @param pid - sender's pid + @param ip - exact IP address of interested neighbor resolution event + @param sw_if_index - interface on which the IP address is present. +*/ +autoreply define want_ip_neighbor_events_v2 +{ + u32 client_index; + u32 context; + bool enable; + u32 pid; + vl_api_address_t ip; + vl_api_interface_index_t sw_if_index [default=0xffffffff]; +}; + +enum ip_neighbor_event_flags +{ + /* The neighbor has been added/learned */ + IP_NEIGHBOR_API_EVENT_FLAG_ADDED = 0x1, + /* The neighbor has been removed/expired */ + IP_NEIGHBOR_API_EVENT_FLAG_REMOVED = 0x2, +}; + +/** \brief Tell client about an IP4 ARP resolution event or + MAC/IP info from ARP requests in L2 BDs + @param client_index - opaque cookie to identify the sender + @param pid - client pid registered to receive notification + @param flags - Flags + @param neighbor - neighbor +*/ +define ip_neighbor_event_v2 +{ + u32 client_index; + u32 pid; + vl_api_ip_neighbor_event_flags_t flags; + vl_api_ip_neighbor_t neighbor; +}; + +service { + rpc want_ip_neighbor_events_v2 returns want_ip_neighbor_events_v2_reply + events ip_neighbor_event_v2; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/ip-neighbor/ip_neighbor.c b/src/vnet/ip-neighbor/ip_neighbor.c index 4111b02d0d89..43d2ccf7f904 100644 --- a/src/vnet/ip-neighbor/ip_neighbor.c +++ b/src/vnet/ip-neighbor/ip_neighbor.c @@ -371,11 +371,14 @@ ip_neighbor_mk_incomplete_walk (adj_index_t ai, void *ctx) } static void -ip_neighbor_free (ip_neighbor_t * ipn) +ip_neighbor_destroy (ip_neighbor_t * ipn) { IP_NEIGHBOR_DBG ("free: %U", format_ip_neighbor, ip_neighbor_get_index (ipn)); + ip_neighbor_publish (ip_neighbor_get_index (ipn), + IP_NEIGHBOR_EVENT_REMOVED); + adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index, fib_proto_from_ip46 (ipn->ipn_key->ipnk_type), &ipn->ipn_key->ipnk_ip, @@ -409,7 +412,7 @@ ip_neighbor_force_reuse (ip46_type_t type) return (false); elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head); - ip_neighbor_free (ip_neighbor_get (elt->ipne_index)); + ip_neighbor_destroy (ip_neighbor_get (elt->ipne_index)); return (true); } @@ -540,7 +543,7 @@ ip_neighbor_add (const ip46_address_t * ip, check_customers: /* Customer(s) requesting event for this address? */ - ip_neighbor_publish (ip_neighbor_get_index (ipn)); + ip_neighbor_publish (ip_neighbor_get_index (ipn), IP_NEIGHBOR_EVENT_ADDED); if (stats_index) *stats_index = adj_nbr_find (fproto, @@ -573,7 +576,7 @@ ip_neighbor_del (const ip46_address_t * ip, ip46_type_t type, u32 sw_if_index) if (NULL == ipn) return (VNET_API_ERROR_NO_SUCH_ENTRY); - ip_neighbor_free (ipn); + ip_neighbor_destroy (ipn); return (0); } @@ -608,7 +611,8 @@ ip_neighbor_del_all (ip46_type_t type, u32 sw_if_index) ip_neighbor_walk (type, sw_if_index, ip_neighbor_del_all_walk_cb, &ctx); - vec_foreach (ipni, ctx.ipn_del) ip_neighbor_free (ip_neighbor_get (*ipni)); + vec_foreach (ipni, + ctx.ipn_del) ip_neighbor_destroy (ip_neighbor_get (*ipni)); vec_free (ctx.ipn_del); } @@ -1219,7 +1223,7 @@ ip_neighbor_flush (ip46_type_t type, u32 sw_if_index) })); /* *INDENT-ON* */ - vec_foreach (ipni, ipnis) ip_neighbor_free (ip_neighbor_get (*ipni)); + vec_foreach (ipni, ipnis) ip_neighbor_destroy (ip_neighbor_get (*ipni)); vec_free (ipnis); } @@ -1272,7 +1276,7 @@ ip_neighbor_sweep (ip46_type_t type) vec_foreach (ipni, ctx.ipnsc_stale) { - ip_neighbor_free (ip_neighbor_get (*ipni)); + ip_neighbor_destroy (ip_neighbor_get (*ipni)); } vec_free (ctx.ipnsc_stale); } @@ -1395,7 +1399,7 @@ ip_neighbor_add_del_interface_address_v4 (ip4_main_t * im, ip_neighbor_walk_covered, &ctx); vec_foreach (ipni, ctx.ipnis) - ip_neighbor_free (ip_neighbor_get (*ipni)); + ip_neighbor_destroy (ip_neighbor_get (*ipni)); vec_free (ctx.ipnis); } @@ -1434,7 +1438,7 @@ ip_neighbor_add_del_interface_address_v6 (ip6_main_t * im, ip_neighbor_walk_covered, &ctx); vec_foreach (ipni, ctx.ipnis) - ip_neighbor_free (ip_neighbor_get (*ipni)); + ip_neighbor_destroy (ip_neighbor_get (*ipni)); vec_free (ctx.ipnis); } @@ -1607,7 +1611,7 @@ ip_neighbor_age_loop (vlib_main_t * vm, else if (IP_NEIGHBOR_AGE_DEAD == res) { /* the oldest neighbor is dead, pop it, then restart the walk * again from the back */ - ip_neighbor_free (ip_neighbor_get(elt->ipne_index)); + ip_neighbor_destroy (ip_neighbor_get(elt->ipne_index)); goto restart; } diff --git a/src/vnet/ip-neighbor/ip_neighbor.h b/src/vnet/ip-neighbor/ip_neighbor.h index cdceadb08591..af3ac3e9e12d 100644 --- a/src/vnet/ip-neighbor/ip_neighbor.h +++ b/src/vnet/ip-neighbor/ip_neighbor.h @@ -22,8 +22,6 @@ #include -void ip_neighbor_scan_enable_disable (ip_neighbor_scan_arg_t * arg); - /***** * APIs external modules can invoke on the neighbor subsystem @@ -70,7 +68,7 @@ extern void ip_neighbor_sweep (ip46_type_t type); /** * From the watcher to the API to publish a new neighbor */ -extern void ip_neighbor_handle_event (const ip_neighbor_event_t * ipne); +extern void ip_neighbor_handle_event (ip_neighbor_event_t * ipne); /** * The set of function that vnet requires from the IP neighbour module. diff --git a/src/vnet/ip-neighbor/ip_neighbor_api.c b/src/vnet/ip-neighbor/ip_neighbor_api.c index 02952c7ba24f..eb535bc211ed 100644 --- a/src/vnet/ip-neighbor/ip_neighbor_api.c +++ b/src/vnet/ip-neighbor/ip_neighbor_api.c @@ -69,13 +69,12 @@ ip_neighbor_encode (vl_api_ip_neighbor_t * api, const ip_neighbor_t * ipn) } void -ip_neighbor_handle_event (const ip_neighbor_event_t * ipne) +ip_neighbor_handle_event (ip_neighbor_event_t * ipne) { - vl_api_ip_neighbor_event_t *mp; vl_api_registration_t *reg; - const ip_neighbor_t *ipn; + ip_neighbor_t *ipn; - ipn = ip_neighbor_get (ipne->ipne_index); + ipn = &ipne->ipne_nbr; if (NULL == ipn) /* Client can cancel, die, etc. */ @@ -88,15 +87,37 @@ ip_neighbor_handle_event (const ip_neighbor_event_t * ipne) if (vl_api_can_send_msg (reg)) { - mp = vl_msg_api_alloc (sizeof (*mp)); - clib_memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_EVENT + REPLY_MSG_ID_BASE); - mp->client_index = ipne->ipne_watch.ipw_client; - mp->pid = ipne->ipne_watch.ipw_pid; + if (1 == ipne->ipne_watch.ipw_api_version) + { + vl_api_ip_neighbor_event_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = + ntohs (VL_API_IP_NEIGHBOR_EVENT + REPLY_MSG_ID_BASE); + mp->client_index = ipne->ipne_watch.ipw_client; + mp->pid = ipne->ipne_watch.ipw_pid; - ip_neighbor_encode (&mp->neighbor, ipn); + ip_neighbor_encode (&mp->neighbor, ipn); - vl_api_send_msg (reg, (u8 *) mp); + vl_api_send_msg (reg, (u8 *) mp); + } + else if (2 == ipne->ipne_watch.ipw_api_version) + { + vl_api_ip_neighbor_event_v2_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = + ntohs (VL_API_IP_NEIGHBOR_EVENT_V2 + REPLY_MSG_ID_BASE); + mp->client_index = ipne->ipne_watch.ipw_client; + mp->pid = ipne->ipne_watch.ipw_pid; + mp->flags = clib_host_to_net_u32 (ipne->ipne_flags); + + ip_neighbor_encode (&mp->neighbor, ipn); + + vl_api_send_msg (reg, (u8 *) mp); + } } else { @@ -107,12 +128,14 @@ ip_neighbor_handle_event (const ip_neighbor_event_t * ipne) */ if (vlib_time_now (vlib_get_main ()) > last_time + 10.0) { - clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!", + clib_warning ("neighbor event for %U to pid %d: queue stuffed!", format_ip46_address, &ipn->ipn_key->ipnk_ip, IP46_TYPE_ANY, ipne->ipne_watch.ipw_pid); last_time = vlib_time_now (vlib_get_main ()); } } + + ip_neighbor_free (ipn); } typedef struct ip_neighbor_dump_ctx_t_ @@ -247,6 +270,7 @@ vl_api_want_ip_neighbor_events_t_handler (vl_api_want_ip_neighbor_events_t * ip_neighbor_watcher_t watch = { .ipw_client = mp->client_index, .ipw_pid = mp->pid, + .ipw_api_version = 1, }; if (mp->enable) @@ -258,6 +282,34 @@ vl_api_want_ip_neighbor_events_t_handler (vl_api_want_ip_neighbor_events_t * REPLY_MACRO (VL_API_WANT_IP_NEIGHBOR_EVENTS_REPLY); } +static void + vl_api_want_ip_neighbor_events_v2_t_handler + (vl_api_want_ip_neighbor_events_v2_t * mp) +{ + vl_api_want_ip_neighbor_events_reply_t *rmp; + ip46_address_t ip; + ip46_type_t itype; + int rv = 0; + + if (mp->sw_if_index != ~0) + VALIDATE_SW_IF_INDEX (mp); + itype = ip_address_decode (&mp->ip, &ip); + + ip_neighbor_watcher_t watch = { + .ipw_client = mp->client_index, + .ipw_pid = mp->pid, + .ipw_api_version = 2, + }; + + if (mp->enable) + ip_neighbor_watch (&ip, itype, ntohl (mp->sw_if_index), &watch); + else + ip_neighbor_unwatch (&ip, itype, ntohl (mp->sw_if_index), &watch); + + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_WANT_IP_NEIGHBOR_EVENTS_V2_REPLY); +} + static void vl_api_ip_neighbor_config_t_handler (vl_api_ip_neighbor_config_t * mp) { diff --git a/src/vnet/ip-neighbor/ip_neighbor_types.c b/src/vnet/ip-neighbor/ip_neighbor_types.c index 32c674d23924..b4b646bd4351 100644 --- a/src/vnet/ip-neighbor/ip_neighbor_types.c +++ b/src/vnet/ip-neighbor/ip_neighbor_types.c @@ -17,6 +17,21 @@ #include +void +ip_neighbor_clone (const ip_neighbor_t * ipn, ip_neighbor_t * clone) +{ + clib_memcpy (clone, ipn, sizeof (*ipn)); + + clone->ipn_key = clib_mem_alloc (sizeof (ip_neighbor_key_t)); + clib_memcpy (clone->ipn_key, ipn->ipn_key, sizeof (ip_neighbor_key_t)); +} + +void +ip_neighbor_free (ip_neighbor_t * ipn) +{ + clib_mem_free (ipn->ipn_key); +} + u8 * format_ip_neighbor_flags (u8 * s, va_list * args) { diff --git a/src/vnet/ip-neighbor/ip_neighbor_types.h b/src/vnet/ip-neighbor/ip_neighbor_types.h index 82c54177e802..de31705cf9e3 100644 --- a/src/vnet/ip-neighbor/ip_neighbor_types.h +++ b/src/vnet/ip-neighbor/ip_neighbor_types.h @@ -22,21 +22,6 @@ #include #include -#define IP_SCAN_DISABLED 0 -#define IP_SCAN_V4_NEIGHBORS (1 << 0) -#define IP_SCAN_V6_NEIGHBORS (1 << 1) -#define IP_SCAN_V46_NEIGHBORS (IP_SCAN_V4_NEIGHBORS | IP_SCAN_V6_NEIGHBORS) - -typedef struct -{ - u8 mode; /* 0: disable, 1: ip4, 2: ip6, 3: both */ - u8 scan_interval; /* neighbor scan interval in minutes */ - u8 max_proc_time; /* max processing time per run, in usecs */ - u8 max_update; /* max probe/delete operations per run */ - u8 scan_int_delay; /* delay in msecs, to resume scan on max */ - u8 stale_threshold; /* Threshold in minutes to delete nei entry */ -} ip_neighbor_scan_arg_t; - #define foreach_ip_neighbor_flag \ _(STATIC, 1 << 0, "static", "S") \ _(DYNAMIC, 1 << 1, "dynamic", "D") \ @@ -50,12 +35,13 @@ typedef enum ip_neighbor_flags_t_ #define _(a,b,c,d) IP_NEIGHBOR_FLAG_##a = b, foreach_ip_neighbor_flag #undef _ -} __attribute__ ((packed)) ip_neighbor_flags_t; +} __clib_packed ip_neighbor_flags_t; typedef struct ip_neighbor_watcher_t_ { u32 ipw_pid; u32 ipw_client; + int ipw_api_version; } ip_neighbor_watcher_t; extern u8 *format_ip_neighbor_watcher (u8 * s, va_list * args); @@ -116,12 +102,27 @@ typedef struct ip_neighbor_learn_t_ u32 sw_if_index; } ip_neighbor_learn_t; + +typedef enum ip_neighbor_event_flags_t_ +{ + IP_NEIGHBOR_EVENT_ADDED = (1 << 0), + IP_NEIGHBOR_EVENT_REMOVED = (1 << 1), +} ip_neighbor_event_flags_t; + typedef struct ip_neighbor_event_t_ { ip_neighbor_watcher_t ipne_watch; - index_t ipne_index; + ip_neighbor_event_flags_t ipne_flags; + ip_neighbor_t ipne_nbr; } ip_neighbor_event_t; +extern void ip_neighbor_clone (const ip_neighbor_t * ipn, + ip_neighbor_t * clone); + +extern void ip_neighbor_free (ip_neighbor_t * ipn); + + + #endif /* __INCLUDE_IP_NEIGHBOR_H__ */ /* diff --git a/src/vnet/ip-neighbor/ip_neighbor_watch.c b/src/vnet/ip-neighbor/ip_neighbor_watch.c index 7464ee62189f..875aa696cb97 100644 --- a/src/vnet/ip-neighbor/ip_neighbor_watch.c +++ b/src/vnet/ip-neighbor/ip_neighbor_watch.c @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -178,7 +179,9 @@ ip_neighbor_unwatch (const ip46_address_t * ip, } static void -ip_neighbor_signal (ip_neighbor_watcher_t *watchers, index_t ipni) +ip_neighbor_signal (ip_neighbor_watcher_t *watchers, + index_t ipni, + ip_neighbor_event_flags_t flags) { ip_neighbor_watcher_t *watcher; @@ -189,12 +192,14 @@ ip_neighbor_signal (ip_neighbor_watcher_t *watchers, index_t ipni) ip_neighbor_event_process_node.index, 0, 1, sizeof(*ipne)); ipne->ipne_watch = *watcher; - ipne->ipne_index = ipni; + ipne->ipne_flags = flags; + ip_neighbor_clone(ip_neighbor_get(ipni), &ipne->ipne_nbr); } } void -ip_neighbor_publish (index_t ipni) +ip_neighbor_publish (index_t ipni, + ip_neighbor_event_flags_t flags) { const ip_neighbor_t *ipn; ip_neighbor_key_t key; @@ -208,21 +213,21 @@ ip_neighbor_publish (index_t ipni) p = mhash_get (&ipnw_db.ipnwdb_hash, &key); if (p) { - ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni); + ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags); } ip46_address_reset (&key.ipnk_ip); p = mhash_get (&ipnw_db.ipnwdb_hash, &key); if (p) { - ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni); + ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags); } key.ipnk_sw_if_index = ~0; p = mhash_get (&ipnw_db.ipnwdb_hash, &key); if (p) { - ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni); + ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags); } } diff --git a/src/vnet/ip-neighbor/ip_neighbor_watch.h b/src/vnet/ip-neighbor/ip_neighbor_watch.h index 91d9f6fe12f5..294099fd3c86 100644 --- a/src/vnet/ip-neighbor/ip_neighbor_watch.h +++ b/src/vnet/ip-neighbor/ip_neighbor_watch.h @@ -29,7 +29,8 @@ extern void ip_neighbor_unwatch (const ip46_address_t * ip, u32 sw_if_index, const ip_neighbor_watcher_t * watch); -extern void ip_neighbor_publish (index_t ipni); +extern void ip_neighbor_publish (index_t ipni, + ip_neighbor_event_flags_t flags); #endif diff --git a/test/test_neighbor.py b/test/test_neighbor.py index 1045f4ba1e9b..c0af91013baf 100644 --- a/test/test_neighbor.py +++ b/test/test_neighbor.py @@ -1959,16 +1959,51 @@ def test_age(self): # # load up some neighbours again with 2s aging enabled # they should be removed after 10s (2s age + 4s for probes + gap) + # check for the add and remove events # + enum = VppEnum.vl_api_ip_neighbor_event_flags_t + + self.vapi.want_ip_neighbor_events_v2(enable=1) for ii in range(10): VppNeighbor(self, self.pg0.sw_if_index, self.pg0.remote_hosts[ii].mac, self.pg0.remote_hosts[ii].ip4).add_vpp_config() + + e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2") + self.assertEqual(e.flags, + enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED) + self.assertEqual(str(e.neighbor.ip_address), + self.pg0.remote_hosts[ii].ip4) + self.assertEqual(e.neighbor.mac_address, + self.pg0.remote_hosts[ii].mac) + self.sleep(10) self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff, af=vaf.ADDRESS_IP4)) + evs = [] + for ii in range(10): + e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2") + self.assertEqual(e.flags, + enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED) + evs.append(e) + + # check we got the correct mac/ip pairs - done separately + # because we don't care about the order the remove notifications + # arrive + for ii in range(10): + found = False + mac = self.pg0.remote_hosts[ii].mac + ip = self.pg0.remote_hosts[ii].ip4 + + for e in evs: + if (e.neighbor.mac_address == mac and + str(e.neighbor.ip_address) == ip): + found = True + break + self.assertTrue(found) + # # check if we can set age and recycle with empty neighbor list # From e7a1006e867029206535510576fb754398affede Mon Sep 17 00:00:00 2001 From: Mohammed Hawari Date: Tue, 24 Nov 2020 18:36:33 +0100 Subject: [PATCH 118/129] rdma: fixed UAR writing at tx Change-Id: Id81b4d27845c4e91cef90a4b8649662942d3cba1 Signed-off-by: Mohammed Hawari Type: fix (cherry picked from commit 3ef653aa886e6a07afba106b4f03c40e392e1307) --- src/plugins/rdma/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/rdma/output.c b/src/plugins/rdma/output.c index 567fd7760a88..8c267a6fb252 100644 --- a/src/plugins/rdma/output.c +++ b/src/plugins/rdma/output.c @@ -100,7 +100,7 @@ rdma_device_output_tx_mlx5_doorbell (rdma_txq_t * txq, rdma_mlx5_wqe_t * last, CLIB_MEMORY_STORE_BARRIER (); txq->dv_sq_dbrec[MLX5_SND_DBR] = htobe32 (tail); CLIB_COMPILER_BARRIER (); - txq->dv_sq_db[0] = *(u64 *) (txq->dv_sq_wqes + (txq->tail & sq_mask)); + txq->dv_sq_db[0] = *(u64 *) last; } static_always_inline void From 007bd2f1fe3a29a8600462af74cf3b1b077fdf30 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Wed, 21 Oct 2020 11:55:28 +0200 Subject: [PATCH 119/129] stats: missing dimension in stat_set_simple_counter A simple counter is a two dimensional array by threads and counter index. 28017 introduced an error missing the first dimension. If a vector is updated at the same time as a client reads, an invalid pointer my result. This will be caught by the optimistic locking after copying out the data, but if following a pointer outside of the stat segment then the stat client would crash. Add suitable boundary checks for access to stat memory segment. Fixes: 7d29e320fb2855a1ddb7a6af09078b8ed636de01 Type: fix Signed-off-by: Ole Troan Change-Id: I94f124ec71d98218c4eda5d124ac5594743d93d6 (cherry picked from commit 65c56c83ce4e58178b5ad90a8f325692c9904381) Signed-off-by: Elias Rudberg --- src/vpp-api/client/stat_client.c | 24 ++++++++++++++++++------ src/vpp-api/client/stat_client.h | 9 +++++++-- src/vpp/stats/stat_segment.c | 3 ++- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/vpp-api/client/stat_client.c b/src/vpp-api/client/stat_client.c index 56ff387d3431..018cce342284 100644 --- a/src/vpp-api/client/stat_client.c +++ b/src/vpp-api/client/stat_client.c @@ -192,6 +192,16 @@ stat_segment_heartbeat (void) return stat_segment_heartbeat_r (sm); } +#define stat_vec_dup(S,V) \ + ({ \ + __typeof__ ((V)[0]) * _v(v) = 0; \ + if (V && ((void *)V > (void *)S->shared_header) && \ + (((void*)V + vec_bytes(V)) < \ + ((void *)S->shared_header + S->memory_size))) \ + _v(v) = vec_dup(V); \ + _v(v); \ +}) + static stat_segment_data_t copy_data (stat_segment_directory_entry_t * ep, stat_client_main_t * sm) { @@ -213,21 +223,21 @@ copy_data (stat_segment_directory_entry_t * ep, stat_client_main_t * sm) case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE: simple_c = stat_segment_adjust (sm, ep->data); - result.simple_counter_vec = vec_dup (simple_c); + result.simple_counter_vec = stat_vec_dup (sm, simple_c); for (i = 0; i < vec_len (simple_c); i++) { counter_t *cb = stat_segment_adjust (sm, simple_c[i]); - result.simple_counter_vec[i] = vec_dup (cb); + result.simple_counter_vec[i] = stat_vec_dup (sm, cb); } break; case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED: combined_c = stat_segment_adjust (sm, ep->data); - result.combined_counter_vec = vec_dup (combined_c); + result.combined_counter_vec = stat_vec_dup (sm, combined_c); for (i = 0; i < vec_len (combined_c); i++) { vlib_counter_t *cb = stat_segment_adjust (sm, combined_c[i]); - result.combined_counter_vec[i] = vec_dup (cb); + result.combined_counter_vec[i] = stat_vec_dup (sm, cb); } break; @@ -246,11 +256,11 @@ copy_data (stat_segment_directory_entry_t * ep, stat_client_main_t * sm) case STAT_DIR_TYPE_NAME_VECTOR: { uint8_t **name_vector = stat_segment_adjust (sm, ep->data); - result.name_vector = vec_dup (name_vector); + result.name_vector = stat_vec_dup (sm, name_vector); for (i = 0; i < vec_len (name_vector); i++) { u8 *name = stat_segment_adjust (sm, name_vector[i]); - result.name_vector[i] = vec_dup (name); + result.name_vector[i] = stat_vec_dup (sm, name); } } break; @@ -290,6 +300,8 @@ stat_segment_data_free (stat_segment_data_t * res) case STAT_DIR_TYPE_ERROR_INDEX: vec_free (res[i].error_vector); break; + case STAT_DIR_TYPE_SCALAR_INDEX: + break; default: assert (0); } diff --git a/src/vpp-api/client/stat_client.h b/src/vpp-api/client/stat_client.h index c5fa55977585..b2457ad6e48b 100644 --- a/src/vpp-api/client/stat_client.h +++ b/src/vpp-api/client/stat_client.h @@ -101,8 +101,13 @@ _time_now_nsec (void) static inline void * stat_segment_adjust (stat_client_main_t * sm, void *data) { - return (void *) ((char *) sm->shared_header + - ((char *) data - (char *) sm->shared_header->base)); + void *p = (void *) ((char *) sm->shared_header + + ((char *) data - (char *) sm->shared_header->base)); + if ((char *) p > (char *) sm->shared_header && + (((char *) p + sizeof (p)) < + ((char *) sm->shared_header + sm->memory_size))) + return p; + return 0; } /* diff --git a/src/vpp/stats/stat_segment.c b/src/vpp/stats/stat_segment.c index 8255b16c0100..788d2fddb2cd 100644 --- a/src/vpp/stats/stat_segment.c +++ b/src/vpp/stats/stat_segment.c @@ -282,7 +282,8 @@ stat_set_simple_counter (stat_segment_directory_entry_t * ep, u32 thread_index, u32 index, u64 value) { ASSERT (ep->data); - counter_t *cb = ep->data; + counter_t **counters = ep->data; + counter_t *cb = counters[thread_index]; cb[index] = value; } From 7847f172a3e1f345dd9c2a91ab4caed1fa85dec7 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 1 Dec 2020 14:51:09 +0000 Subject: [PATCH 120/129] ikev2: fix nat traversal Type: fix Change-Id: Ie723cf680745ec2292a15e2df05c1821436dba19 Signed-off-by: Filip Tehlar (cherry picked from commit 18107c974c24a708e309542d1dbf4a52acc70b08) --- src/plugins/ikev2/ikev2.c | 3 +- src/plugins/ikev2/test/test_ikev2.py | 48 ++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 03b402145ade..4e1984927756 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -458,7 +458,8 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) sa->profile_index = sai->profile_index; sa->tun_itf = sai->tun_itf; sa->is_tun_itf_set = sai->is_tun_itf_set; - sa->natt_state = sai->natt_state; + if (sai->natt_state == IKEV2_NATT_DISABLED) + sa->natt_state = IKEV2_NATT_DISABLED; sa->i_id.data = _(sai->i_id.data); sa->r_id.data = _(sai->r_id.data); sa->i_auth.method = sai->i_auth.method; diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index eb2c5f988d4d..073799072ebc 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -632,6 +632,7 @@ def verify_udp(self, udp): def get_ike_header(self, packet): try: ih = packet[ikev2.IKEv2] + ih = self.verify_and_remove_non_esp_marker(ih) except IndexError as e: # this is a workaround for getting IKEv2 layer as both ikev2 and # ipsec register for port 4500 @@ -933,6 +934,8 @@ def verify_nat_detection(self, packet): self.assertEqual(s.load, dst_sha) def verify_sa_init_request(self, packet): + udp = packet[UDP] + self.sa.dport = udp.sport ih = packet[ikev2.IKEv2] self.assertNotEqual(ih.init_SPI, 8 * b'\x00') self.assertEqual(ih.exch_type, 34) # SA_INIT @@ -974,6 +977,8 @@ def update_esp_transforms(self, trans, sa): trans = trans.payload def verify_sa_auth_req(self, packet): + udp = packet[UDP] + self.sa.dport = udp.sport ih = self.get_ike_header(packet) self.assertEqual(ih.resp_SPI, self.sa.rspi) self.assertEqual(ih.init_SPI, self.sa.ispi) @@ -1009,6 +1014,15 @@ def send_init_response(self): transform_id=self.sa.ike_dh)) props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', trans_nb=4, trans=trans)) + + src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4) + if self.sa.natt: + dst_address = b'\x0a\x0a\x0a\x0a' + else: + dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4) + src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) + dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport) + self.sa.init_resp_packet = ( ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, exch_type='IKE_SA_INIT', flags='Response') / @@ -1016,11 +1030,16 @@ def send_init_response(self): ikev2.IKEv2_payload_KE(next_payload='Nonce', group=self.sa.ike_dh, load=self.sa.my_dh_pub_key) / - ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce)) + ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce, + next_payload='Notify') / + ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_SOURCE_IP', load=src_nat, + next_payload='Notify') / ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_DESTINATION_IP', load=dst_nat)) ike_msg = self.create_packet(self.pg0, self.sa.init_resp_packet, self.sa.sport, self.sa.dport, - self.sa.natt, self.ip6) + False, self.ip6) self.pg_send(self.pg0, ike_msg) capture = self.pg0.get_capture(1) self.verify_sa_auth_req(capture[0]) @@ -1588,6 +1607,31 @@ def verify_profile(self, ap, cp): self.assertEqual(ap.tun_itf, 0xffffffff) +class TestInitiatorNATT(TemplateInitiator, Ikev2Params): + """ test ikev2 initiator - NAT traversal (intitiator behind NAT) """ + + def config_tc(self): + self.config_params({ + 'natt': True, + 'is_initiator': False, # seen from test case perspective + # thus vpp is initiator + 'responder': {'sw_if_index': self.pg0.sw_if_index, + 'addr': self.pg0.remote_ip4}, + 'ike-crypto': ('AES-GCM-16ICV', 32), + 'ike-integ': 'NULL', + 'ike-dh': '3072MODPgr', + 'ike_transforms': { + 'crypto_alg': 20, # "aes-gcm-16" + 'crypto_key_size': 256, + 'dh_group': 15, # "modp-3072" + }, + 'esp_transforms': { + 'crypto_alg': 12, # "aes-cbc" + 'crypto_key_size': 256, + # "hmac-sha2-256-128" + 'integ_alg': 12}}) + + class TestInitiatorPsk(TemplateInitiator, Ikev2Params): """ test ikev2 initiator - pre shared key auth """ From a23dd5dbb5cde4cb12b3d7b0bed8156e2ff7e6b5 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Tue, 8 Dec 2020 10:50:08 -0500 Subject: [PATCH 121/129] build: fix centos-8 'make install-deps' enable PowerTools repo - The name of the powertools repo was changed [0] in centos-8 from 'PowerTools' to 'powertools'. Retrieve the correct name from 'dnf repolist all' instead of hard coding it. [0] https://git.centos.org/rpms/centos-repos/c/b759b17557b9577e8ea156740af0249ab1a22d70 Type: fix Signed-off-by: Dave Wallace Change-Id: Ic1402e671eb1d70dec429bab82ad18d8251f4eef (cherry picked from commit 1affb31ef528dcbc90b718bd70a9882a4225a385) --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 268c87f32354..6b5f50a7af46 100644 --- a/Makefile +++ b/Makefile @@ -286,7 +286,8 @@ ifeq ($(OS_ID),rhel) @sudo -E debuginfo-install $(CONFIRM) glibc openssl-libs mbedtls-devel zlib else ifeq ($(OS_ID)-$(OS_VERSION_ID),centos-8) @sudo -E dnf install $(CONFIRM) dnf-plugins-core epel-release - @sudo -E dnf config-manager --set-enabled PowerTools + @sudo -E dnf config-manager --set-enabled \ + $(shell dnf repolist all 2>/dev/null|grep -i powertools|cut -d' ' -f1) @sudo -E dnf groupinstall $(CONFIRM) $(RPM_DEPENDS_GROUPS) @sudo -E dnf install $(CONFIRM) $(RPM_DEPENDS) else ifeq ($(OS_ID),centos) From 3b82d3e39331c5c6cade1014444091ba31052551 Mon Sep 17 00:00:00 2001 From: Elias Rudberg Date: Tue, 8 Dec 2020 14:21:19 +0100 Subject: [PATCH 122/129] nat: avoid hairpinning infinite loop problem Fix in nat44 hairpinning code to check if anything was actually changed in the snat_hairpinning() routine, and return 0 if nothing changed. This helps avoid an infinite loop repeating the three nodes nat44-hairpinning-->ip4-lookup-->ip4-local in case there was no change. Also add a corresponding test case. This is essentially a cherry-pick of change 30284 but the automatic cherry-picking did not work because of some filename changes. Type: fix Signed-off-by: Elias Rudberg Change-Id: I21a59ae7423f40abeff9fc0411330da58b3011f0 --- src/plugins/nat/nat44_hairpinning.c | 12 ++++ src/plugins/nat/test/test_nat.py | 88 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/plugins/nat/nat44_hairpinning.c b/src/plugins/nat/nat44_hairpinning.c index 9eadcf308325..2859046ae05c 100644 --- a/src/plugins/nat/nat44_hairpinning.c +++ b/src/plugins/nat/nat44_hairpinning.c @@ -108,6 +108,7 @@ snat_hairpinning (vlib_main_t * vm, vlib_node_runtime_t * node, ip4_address_t sm0_addr; u16 sm0_port; u32 sm0_fib_index; + u32 old_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; /* Check if destination is static mappings */ if (!snat_static_mapping_match (sm, ip0->dst_address, udp0->dst_port, sm->outside_fib_index, proto0, @@ -159,6 +160,17 @@ snat_hairpinning (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; } + /* Check if anything has changed and if not, then return 0. This + helps avoid infinite loop, repeating the three nodes + nat44-hairpinning-->ip4-lookup-->ip4-local, in case nothing has + changed. */ + old_dst_addr0 = ip0->dst_address.as_u32; + old_dst_port0 = tcp0->dst; + if (new_dst_addr0 == old_dst_addr0 + && new_dst_port0 == old_dst_port0 + && vnet_buffer (b0)->sw_if_index[VLIB_TX] == old_sw_if_index) + return 0; + /* Destination is behind the same NAT, use internal address and port */ if (new_dst_addr0) { diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py index a305b7aa9f48..947182811932 100644 --- a/src/plugins/nat/test/test_nat.py +++ b/src/plugins/nat/test/test_nat.py @@ -2610,6 +2610,94 @@ def test_hairpinning2(self): self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise + def test_hairpinning_avoid_inf_loop(self): + """ NAT44 hairpinning - 1:1 NAPT avoid infinite loop """ + + host = self.pg0.remote_hosts[0] + server = self.pg0.remote_hosts[1] + host_in_port = 1234 + host_out_port = 0 + server_in_port = 5678 + server_out_port = 8765 + + self.nat44_add_address(self.nat_addr) + flags = self.config_flags.NAT_IS_INSIDE + self.vapi.nat44_interface_add_del_feature( + sw_if_index=self.pg0.sw_if_index, + flags=flags, is_add=1) + self.vapi.nat44_interface_add_del_feature( + sw_if_index=self.pg1.sw_if_index, + is_add=1) + + # add static mapping for server + self.nat44_add_static_mapping(server.ip4, self.nat_addr, + server_in_port, server_out_port, + proto=IP_PROTOS.tcp) + + # add another static mapping that maps pg0.local_ip4 address to itself + self.nat44_add_static_mapping(self.pg0.local_ip4, self.pg0.local_ip4) + + # send packet from host to VPP (the packet should get dropped) + p = (Ether(src=host.mac, dst=self.pg0.local_mac) / + IP(src=host.ip4, dst=self.pg0.local_ip4) / + TCP(sport=host_in_port, dport=server_out_port)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + # Here VPP used to crash due to an infinite loop + + cnt = self.statistics.get_counter('/nat44/hairpinning')[0] + # send packet from host to server + p = (Ether(src=host.mac, dst=self.pg0.local_mac) / + IP(src=host.ip4, dst=self.nat_addr) / + TCP(sport=host_in_port, dport=server_out_port)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + p = capture[0] + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.src, self.nat_addr) + self.assertEqual(ip.dst, server.ip4) + self.assertNotEqual(tcp.sport, host_in_port) + self.assertEqual(tcp.dport, server_in_port) + self.assert_packet_checksums_valid(p) + host_out_port = tcp.sport + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise + + after = self.statistics.get_counter('/nat44/hairpinning')[0] + if_idx = self.pg0.sw_if_index + self.assertEqual(after[if_idx] - cnt[if_idx], 1) + + # send reply from server to host + p = (Ether(src=server.mac, dst=self.pg0.local_mac) / + IP(src=server.ip4, dst=self.nat_addr) / + TCP(sport=server_in_port, dport=host_out_port)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + p = capture[0] + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.src, self.nat_addr) + self.assertEqual(ip.dst, host.ip4) + self.assertEqual(tcp.sport, server_out_port) + self.assertEqual(tcp.dport, host_in_port) + self.assert_packet_checksums_valid(p) + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise + + after = self.statistics.get_counter('/nat44/hairpinning')[0] + if_idx = self.pg0.sw_if_index + self.assertEqual(after[if_idx] - cnt[if_idx], 2) + def test_interface_addr(self): """ Acquire NAT44 addresses from interface """ self.vapi.nat44_add_del_interface_addr( From 1e44cf53b5611b46657f5742784ec85c35d36767 Mon Sep 17 00:00:00 2001 From: Paul Vinciguerra Date: Thu, 2 Apr 2020 23:50:25 -0400 Subject: [PATCH 123/129] docs: fix missing quotes in ubuntu install instructions type: docs Change-Id: Ifa09b63924f4b7bf2719bba6ada0e1122407641c Signed-off-by: Paul Vinciguerra (cherry picked from commit ac9a585c6207ac876025f924aeb96ddcac8c8805) --- docs/gettingstarted/installing/ubuntu.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/gettingstarted/installing/ubuntu.rst b/docs/gettingstarted/installing/ubuntu.rst index 98d73541c4e1..2521b6d27908 100644 --- a/docs/gettingstarted/installing/ubuntu.rst +++ b/docs/gettingstarted/installing/ubuntu.rst @@ -1,11 +1,11 @@ .. _ubuntu: .. toctree:: - -Ubuntu 18.04 - Setup the FD.io Repository -========================================== -Choose one of the following releases to install. +Ubuntu - Setup the FD.io Repository +=================================== + +Choose one of the following releases to install. Update the OS ----------------------- @@ -85,4 +85,4 @@ Uninstall the packages by running the following command: .. code-block:: console - sudo apt-get remove --purge vpp* + sudo apt-get remove --purge "vpp*" From d1598d4274f89b9e3ad87ddb4995fa0d7919503d Mon Sep 17 00:00:00 2001 From: Paul Vinciguerra Date: Tue, 24 Mar 2020 16:37:40 -0400 Subject: [PATCH 124/129] docs: update list of plugins The list of plugins is outdated. This change introduces a dynamically generated list of the plugins along with their descriptions, extracted directly from the sources. Type: docs Change-Id: Icb7b65e6b45289e257d71a1c18d10f62ced59cbe Signed-off-by: Paul Vinciguerra (cherry picked from commit 630ca994e0ff210a3de80d73bb395c931d2fd83f) --- .gitignore | 1 + docs/Makefile | 2 + docs/dynamic_includes/.gitkeep | 0 docs/gettingstarted/installing/packages.rst | 14 +--- docs/includes_renderer.py | 77 +++++++++++++++++++++ 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 docs/dynamic_includes/.gitkeep create mode 100644 docs/includes_renderer.py diff --git a/.gitignore b/.gitignore index ea3302415491..19378e8584aa 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ GTAGS /build-root/.doxygen-bootstrap.ok /build-root/.doxygen-siphon.dep /docs/_build +/docs/dynamic_includes /sphinx_venv !/docs/Makefile diff --git a/docs/Makefile b/docs/Makefile index 6c5960d18c48..49938640a349 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -27,6 +27,8 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile +# Generate dynamic content + @python3 ./includes_renderer.py @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) spell: diff --git a/docs/dynamic_includes/.gitkeep b/docs/dynamic_includes/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/gettingstarted/installing/packages.rst b/docs/gettingstarted/installing/packages.rst index 719fffb67f88..6c4fae18ee33 100644 --- a/docs/gettingstarted/installing/packages.rst +++ b/docs/gettingstarted/installing/packages.rst @@ -35,19 +35,7 @@ vpp-plugins Vector Packet Processing plugin modules. -* acl -* dpdk -* flowprobe -* gtpu -* ixge -* kubeproxy -* l2e -* lb -* memif -* nat -* pppoe -* sixrd -* stn +.. include:: ../../dynamic_includes/plugin_list.inc vpp-dbg ------- diff --git a/docs/includes_renderer.py b/docs/includes_renderer.py new file mode 100644 index 000000000000..d36752dd882d --- /dev/null +++ b/docs/includes_renderer.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020. Vinci Consulting Corp. All Rights Reserved. +# +# 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. + +import glob +import inspect +import os.path +import re + + +class ContentRenderer: + name = "" + curr_path = os.path.abspath(inspect.getsourcefile(lambda: 0)) + vpp_root = curr_path.rsplit("/", 2)[0] + output_dir = f"{vpp_root}/docs/dynamic_includes/" + + def render(self): + raise NotImplementedError + + +class PluginRenderer(ContentRenderer): + name = "plugin_list.inc" + + plugin_dir = f"{ContentRenderer.vpp_root}/src/plugins" + + pattern = r'VLIB_PLUGIN_REGISTER\s?\(\)\s*=\s*{.*\.description\s?=\s?"([^"]*)".*};' # noqa: 501 + regex = re.compile(pattern, re.MULTILINE | re.DOTALL) + + def render(self): + with open(f"{self.__class__.output_dir}{self.__class__.name}", + "w") as output: + with os.scandir(self.__class__.plugin_dir) as pdir: + for entry in sorted(pdir, key=lambda entry: entry.name): + if not entry.name.startswith('.') and entry.is_dir(): + description = "" + # we use glob because a plugin can (ioam for now) + # define the plugin definition in + # a further subdirectory. + for f in glob.iglob(f'{self.__class__.plugin_dir}/' + f'{entry.name}/**', + recursive=True): + if f.endswith('.c'): + with open(f, "r", encoding="utf-8") \ + as src: + for match in self.__class__.regex.finditer( + src.read()): + description = "%s" % (match.group(1)) + + output.write(f"* {entry.name} - {description}\n") + + +# if this list grows substantially, we can move the classes to +# a folder and import them. +renderers = [PluginRenderer, + ] + + +def main(): + print("rendering dynamic includes...") + for renderer in renderers: + renderer().render() + print("done.") + + +if __name__ == "__main__": + main() From 14bfb66d39ff50de24e8515268250ee9bdee2ef3 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Thu, 14 Jan 2021 16:46:49 -0500 Subject: [PATCH 125/129] build: add missing openssl-devel package for centos-8 vpp-ext-deps - In a new centos-8 installation, vpp-ext-deps fails on missing ssl.h header file after 'make install-deps'. Type: fix Signed-off-by: Dave Wallace Change-Id: I521d817dd1f1e21aff427d98b9832ea7c7b89339 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6b5f50a7af46..53218e2bbca5 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,7 @@ ifeq ($(OS_ID),fedora) RPM_DEPENDS_GROUPS = 'C Development Tools and Libraries' else ifeq ($(OS_ID)-$(OS_VERSION_ID),centos-8) RPM_DEPENDS += yum-utils - RPM_DEPENDS += compat-openssl10 + RPM_DEPENDS += compat-openssl10 openssl-devel RPM_DEPENDS += python2-devel python36-devel python3-ply RPM_DEPENDS += python3-virtualenv python3-jsonschema RPM_DEPENDS += cmake From 4f88004bc36c2382915b75990bb5f82f5c36a93c Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Wed, 20 Jan 2021 12:20:13 -0500 Subject: [PATCH 126/129] docs: vpp stateless traffic generator Add a use-case writeup. Type: docs Signed-off-by: Dave Barach Change-Id: Ib6e79e80455edbdeedcc96943dd98f16c57c559e (cherry picked from commit b8f6122b4f4c828dee103d1f3116d27e6e3e6f3a) --- docs/usecases/index.rst | 1 + docs/usecases/trafficgen.md | 105 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 docs/usecases/trafficgen.md diff --git a/docs/usecases/index.rst b/docs/usecases/index.rst index 062b225732b3..3b2ab23f827b 100644 --- a/docs/usecases/index.rst +++ b/docs/usecases/index.rst @@ -20,3 +20,4 @@ extensive list, but should give a sampling of the many features contained in FD. networksim webapp container_test + trafficgen diff --git a/docs/usecases/trafficgen.md b/docs/usecases/trafficgen.md new file mode 100644 index 000000000000..fe3d4c98904f --- /dev/null +++ b/docs/usecases/trafficgen.md @@ -0,0 +1,105 @@ +Vpp Stateless Traffic Generation +================================ + +It's simple to configure vpp as a high-performance stateless traffic +generator. A couple of vpp worker threads running on an older system +can easily generate 20 MPPS' worth of traffic. + +In the configurations shown below, we connect a vpp traffic generator +and a vpp UUT using two 40 gigabit ethernet ports on each system: + +``` + +-------------------+ +-------------------+ + | traffic generator | | UUT | + | port 0 | <=======> | port 0 | + | 192.168.40.2/24 | | 192.168.40.1/24 | + +-------------------+ +-------------------+ + + +-------------------+ +-------------------+ + | traffic generator | | UUT | + | port 1 | <=======> | port 1 | + | 192.168.41.2/24 | | 192.168.41.1/24 | + +-------------------+ +-------------------+ +``` + +Traffic Generator Setup Script +------------------------------ + +``` + set int ip address FortyGigabitEthernet2/0/0 192.168.40.2/24 + set int ip address FortyGigabitEthernet2/0/1 192.168.41.2/24 + set int state FortyGigabitEthernet2/0/0 up + set int state FortyGigabitEthernet2/0/1 up + + comment { send traffic to the VPP UUT } + + packet-generator new { + name worker0 + worker 0 + limit 0 + rate 1.2e7 + size 128-128 + tx-interface FortyGigabitEthernet2/0/0 + node FortyGigabitEthernet2/0/0-output + data { IP4: 1.2.40 -> 3cfd.fed0.b6c8 + UDP: 192.168.40.10 -> 192.168.50.10 + UDP: 1234 -> 2345 + incrementing 114 + } + } + + packet-generator new { + name worker1 + worker 1 + limit 0 + rate 1.2e7 + size 128-128 + tx-interface FortyGigabitEthernet2/0/1 + node FortyGigabitEthernet2/0/1-output + data { IP4: 1.2.4 -> 3cfd.fed0.b6c9 + UDP: 192.168.41.10 -> 192.168.51.10 + UDP: 1234 -> 2345 + incrementing 114 + } + } + + comment { delete return traffic on sight } + + ip route add 192.168.50.0/24 via drop + ip route add 192.168.51.0/24 via drop +``` + +Note 1: the destination MAC addresses shown in the configuration (e.g. +3cfd.fed0.b6c8 and 3cfd.fed0.b6c9) **must** match the vpp UUT port MAC +addresses. + +Note 2: this script assumes that /etc/vpp/startup.conf and/or the +command-line in use specifies (at least) two worker threads. Uncomment +"workers 2" in the cpu configuration section of /etc/vpp/startup.conf: + +``` + ## Specify a number of workers to be created + ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s) + ## and main thread's CPU core + workers 2 +``` + +Any plausible packet generator script - including one which replays +pcap captures - can be used. + + +UUT Setup Script +---------------- + +The vpp UUT uses a couple of static routes to forward traffic back to +the traffic generator: + +``` + set int ip address FortyGigabitEthernet2/0/0 192.168.40.1/24 + set int ip address FortyGigabitEthernet2/0/1 192.168.41.1/24 + set int state FortyGigabitEthernet2/0/0 up + set int state FortyGigabitEthernet2/0/1 up + + ip route add 192.168.50.10/32 via 192.168.41.2 + ip route add 192.168.51.10/32 via 192.168.40.2 +``` From 8b4bd27d60b1086727273cfd61c4fa8874530ac0 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 4 Dec 2020 17:38:11 +0000 Subject: [PATCH 127/129] ikev2: test responder behind NAT Type: test Ticket: VPP-1903 Change-Id: I7fab6931833d6e253b7b921172825387302d8f70 Signed-off-by: Filip Tehlar (cherry picked from commit 027d813a509be0f30e05b48b888007b0094e4faf) --- src/plugins/ikev2/test/test_ikev2.py | 78 +++++++++++++++++----------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 073799072ebc..e4471dd843a6 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -182,11 +182,12 @@ class IKEv2SA(object): def __init__(self, test, is_initiator=True, i_id=None, r_id=None, spi=b'\x01\x02\x03\x04\x05\x06\x07\x08', id_type='fqdn', nonce=None, auth_data=None, local_ts=None, remote_ts=None, - auth_method='shared-key', priv_key=None, natt=False, - udp_encap=False): + auth_method='shared-key', priv_key=None, i_natt=False, + r_natt=False, udp_encap=False): self.udp_encap = udp_encap - self.natt = natt - if natt: + self.i_natt = i_natt + self.r_natt = r_natt + if i_natt or r_natt: self.sport = 4500 self.dport = 4500 else: @@ -233,6 +234,10 @@ def peer_dh_pub_key(self): return self.r_dh_data return self.i_dh_data + @property + def natt(self): + return self.i_natt or self.r_natt + def compute_secret(self): priv = self.dh_private_key peer = self.peer_dh_pub_key @@ -1158,7 +1163,7 @@ def initiate_del_sa_from_initiator(self): capture = self.pg0.get_capture(1) self.verify_del_sa(capture[0]) - def send_sa_init_req(self, behind_nat=False): + def send_sa_init_req(self): tr_attr = self.sa.ike_crypto_attr() trans = (ikev2.IKEv2_payload_Transform(transform_type='Encryption', transform_id=self.sa.ike_crypto, length=tr_attr[1], @@ -1173,6 +1178,8 @@ def send_sa_init_req(self, behind_nat=False): props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', trans_nb=4, trans=trans)) + next_payload = None if self.ip6 else 'Notify' + self.sa.init_req_packet = ( ikev2.IKEv2(init_SPI=self.sa.ispi, flags='Initiator', exch_type='IKE_SA_INIT') / @@ -1180,26 +1187,30 @@ def send_sa_init_req(self, behind_nat=False): ikev2.IKEv2_payload_KE(next_payload='Nonce', group=self.sa.ike_dh, load=self.sa.my_dh_pub_key) / - ikev2.IKEv2_payload_Nonce(next_payload='Notify', + ikev2.IKEv2_payload_Nonce(next_payload=next_payload, load=self.sa.i_nonce)) - if behind_nat: - src_address = b'\x0a\x0a\x0a\x01' - else: - src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4) + if not self.ip6: + if self.sa.i_natt: + src_address = b'\x0a\x0a\x0a\x01' + else: + src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4) - src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) - dst_nat = self.sa.compute_nat_sha1( - inet_pton(socket.AF_INET, self.pg0.local_ip4), - self.sa.dport) - nat_src_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_SOURCE_IP', load=src_nat, - next_payload='Notify') - nat_dst_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) - self.sa.init_req_packet = (self.sa.init_req_packet / - nat_src_detection / - nat_dst_detection) + if self.sa.r_natt: + dst_address = b'\x0a\x0a\x0a\x0a' + else: + dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4) + + src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) + dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport) + nat_src_detection = ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_SOURCE_IP', load=src_nat, + next_payload='Notify') + nat_dst_detection = ikev2.IKEv2_payload_Notify( + type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) + self.sa.init_req_packet = (self.sa.init_req_packet / + nat_src_detection / + nat_dst_detection) ike_msg = self.create_packet(self.pg0, self.sa.init_req_packet, self.sa.sport, self.sa.dport, @@ -1306,7 +1317,7 @@ def verify_sa_auth_resp(self, packet): self.sa.calc_child_keys() def test_responder(self): - self.send_sa_init_req(self.sa.natt) + self.send_sa_init_req() self.send_sa_auth() self.verify_ipsec_sas() self.verify_ike_sas() @@ -1335,7 +1346,8 @@ def config_params(self, params={}): self.vapi.cli('ikev2 dpd disable') self.del_sa_from_responder = False if 'del_sa_from_responder'\ not in params else params['del_sa_from_responder'] - is_natt = 'natt' in params and params['natt'] or False + i_natt = False if 'i_natt' not in params else params['i_natt'] + r_natt = False if 'r_natt' not in params else params['r_natt'] self.p = Profile(self, 'pr1') self.ip6 = False if 'ip6' not in params else params['ip6'] @@ -1393,7 +1405,8 @@ def config_params(self, params={}): self.sa = IKEv2SA(self, i_id=idi['data'], r_id=idr['data'], is_initiator=is_init, - id_type=self.p.local_id['id_type'], natt=is_natt, + id_type=self.p.local_id['id_type'], + i_natt=i_natt, r_natt=r_natt, priv_key=client_priv, auth_method=auth_method, auth_data=auth_data, udp_encap=udp_encap, local_ts=self.p.remote_ts, remote_ts=self.p.local_ts) @@ -1607,12 +1620,19 @@ def verify_profile(self, ap, cp): self.assertEqual(ap.tun_itf, 0xffffffff) +class TestResponderBehindNAT(TemplateResponder, Ikev2Params): + """ test responder - responder behind NAT """ + + def config_tc(self): + self.config_params({'r_natt': True}) + + class TestInitiatorNATT(TemplateInitiator, Ikev2Params): """ test ikev2 initiator - NAT traversal (intitiator behind NAT) """ def config_tc(self): self.config_params({ - 'natt': True, + 'i_natt': True, 'is_initiator': False, # seen from test case perspective # thus vpp is initiator 'responder': {'sw_if_index': self.pg0.sw_if_index, @@ -1759,11 +1779,11 @@ def config_tc(self): 'integ_alg': 12}}) -class TestResponderNATT(TemplateResponder, Ikev2Params): - """ test ikev2 responder - nat traversal """ +class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params): + """ test ikev2 responder - initiator behind NAT """ def config_tc(self): self.config_params( - {'natt': True}) + {'i_natt': True}) class TestResponderPsk(TemplateResponder, Ikev2Params): From 4f7b92f0a0f37ea2875631d7f25d44834abe7af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20Linke=C5=A1?= Date: Thu, 27 May 2021 12:41:37 +0200 Subject: [PATCH 128/129] dpdk: disable i40evf in favor of iavf patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix an issue where multiple VPP instances with DPDK starting at the same time would not initialize VFs properly. This is done by using the iavf PMD (where the issue can't be reproduced) instead of the i40evf PMD. Type: fix Ticket: VPP-1943 Signed-off-by: Juraj Linkeš Change-Id: Idcc48088c7d66a76da2b4675c02c7c115706c8b3 --- .../0001-net-iavf-deprecate-i40evf-pmd.patch | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 build/external/patches/dpdk_20.08/0001-net-iavf-deprecate-i40evf-pmd.patch diff --git a/build/external/patches/dpdk_20.08/0001-net-iavf-deprecate-i40evf-pmd.patch b/build/external/patches/dpdk_20.08/0001-net-iavf-deprecate-i40evf-pmd.patch new file mode 100644 index 000000000000..aa660e701320 --- /dev/null +++ b/build/external/patches/dpdk_20.08/0001-net-iavf-deprecate-i40evf-pmd.patch @@ -0,0 +1,232 @@ +From bd048f56bc4b85fed31f34db676f1ad67c86bd16 Mon Sep 17 00:00:00 2001 +From: Robin Zhang +Date: Mon, 19 Apr 2021 03:05:39 +0000 +Subject: [PATCH] net/iavf: deprecate i40evf pmd + +The i40evf PMD will be deprecated, iavf will be the only VF driver for +Intel 700 serial (i40e) NIC family. To reach this, there will be 2 steps: + +Step 1: iavf will be the default VF driver, while i40evf still can be +selected by devarg: "driver=i40evf". +This is covered by this patch, which include: +1) add all 700 serial NIC VF device ID into iavf PMD +2) skip probe if devargs contain "driver=i40evf" in iavf +3) continue probe if devargs contain "driver=i40evf" in i40evf + +Step 2: i40evf and related devarg are removed, this will happen at DPDK +21.11 + +Between step 1 and step 2, no new feature will be added into i40evf except +bug fix. + +Signed-off-by: Robin Zhang +Acked-by: Qi Zhang +Acked-by: Ferruh Yigit +Acked-by: Beilei Xing +--- + doc/guides/nics/intel_vf.rst | 6 +++ + doc/guides/rel_notes/deprecation.rst | 8 ++++ + drivers/common/iavf/iavf_devids.h | 2 + + drivers/net/i40e/i40e_ethdev_vf.c | 45 ++++++++++++++++++++++ + drivers/net/iavf/iavf_ethdev.c | 57 +++++++++++++++++++++++++++- + 5 files changed, 116 insertions(+), 2 deletions(-) + +diff --git a/doc/guides/nics/intel_vf.rst b/doc/guides/nics/intel_vf.rst +index ade5152595..b95200698d 100644 +--- a/doc/guides/nics/intel_vf.rst ++++ b/doc/guides/nics/intel_vf.rst +@@ -88,6 +88,12 @@ For more detail on SR-IOV, please refer to the following documents: + assignment in hypervisor. Take qemu for example, the device assignment should carry the IAVF device id (0x1889) like + ``-device vfio-pci,x-pci-device-id=0x1889,host=03:0a.0``. + ++ Starting from DPDK 21.05, the default VF driver for Intel® 700 Series Ethernet Controller will be IAVF. No new feature ++ will be added into i40evf except bug fix until it's removed in DPDK 21.11. Between DPDK 21.05 and 21.11, by using the ++ ``devargs`` option ``driver=i40evf``, i40evf PMD still can be used on Intel® 700 Series Ethernet Controller, for example:: ++ ++ -a 81:02.0,driver=i40evf ++ + The PCIE host-interface of Intel Ethernet Switch FM10000 Series VF infrastructure + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst +index c2770feeae..25caf4e52d 100644 +--- a/doc/guides/rel_notes/deprecation.rst ++++ b/doc/guides/rel_notes/deprecation.rst +@@ -335,3 +335,11 @@ Deprecation Notices + ``make``. Given environments are too much variables for such a simple script, + it will be removed in DPDK 20.11. + Some useful parts may be converted into specific scripts. ++ ++* i40e: As there are both i40evf and iavf pmd, the functions of them are ++ duplicated. And now more and more advanced features are developed on iavf. ++ To keep consistent with kernel driver's name ++ (https://patchwork.ozlabs.org/patch/970154/), i40evf is no need to maintain. ++ Starting from 21.05, the default VF driver of i40e will be iavf, but i40evf ++ can still be used if users specify the devarg "driver=i40evf". I40evf will ++ be deleted in DPDK 21.11. +diff --git a/drivers/common/iavf/iavf_devids.h b/drivers/common/iavf/iavf_devids.h +index 2e63aac289..1c3acb586d 100644 +--- a/drivers/common/iavf/iavf_devids.h ++++ b/drivers/common/iavf/iavf_devids.h +@@ -13,5 +13,7 @@ + #define IAVF_DEV_ID_VF_HV 0x1571 + #define IAVF_DEV_ID_ADAPTIVE_VF 0x1889 + #define IAVF_DEV_ID_X722_VF 0x37CD ++#define IAVF_DEV_ID_X722_A0_VF 0x374D ++ + + #endif /* _IAVF_DEVIDS_H_ */ +diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c +index 69cab8e739..3d61c092d8 100644 +--- a/drivers/net/i40e/i40e_ethdev_vf.c ++++ b/drivers/net/i40e/i40e_ethdev_vf.c +@@ -1592,9 +1592,53 @@ i40evf_dev_uninit(struct rte_eth_dev *eth_dev) + return 0; + } + ++static int ++i40evf_check_driver_handler(__rte_unused const char *key, ++ const char *value, __rte_unused void *opaque) ++{ ++ if (strcmp(value, "i40evf")) ++ return -1; ++ ++ return 0; ++} ++ ++static int ++i40evf_driver_selected(struct rte_devargs *devargs) ++{ ++ struct rte_kvargs *kvlist; ++ const char *key = "driver"; ++ int ret = 0; ++ ++ if (devargs == NULL) ++ return 0; ++ ++ kvlist = rte_kvargs_parse(devargs->args, NULL); ++ if (kvlist == NULL) ++ return 0; ++ ++ if (!rte_kvargs_count(kvlist, key)) ++ goto exit; ++ ++ /* i40evf driver selected when there's a key-value pair: ++ * driver=i40evf ++ */ ++ if (rte_kvargs_process(kvlist, key, ++ i40evf_check_driver_handler, NULL) < 0) ++ goto exit; ++ ++ ret = 1; ++ ++exit: ++ rte_kvargs_free(kvlist); ++ return ret; ++} ++ + static int eth_i40evf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) + { ++ if (!i40evf_driver_selected(pci_dev->device.devargs)) ++ return 1; ++ + return rte_eth_dev_pci_generic_probe(pci_dev, + sizeof(struct i40e_adapter), i40evf_dev_init); + } +@@ -1617,6 +1661,7 @@ static struct rte_pci_driver rte_i40evf_pmd = { + RTE_PMD_REGISTER_PCI(net_i40e_vf, rte_i40evf_pmd); + RTE_PMD_REGISTER_PCI_TABLE(net_i40e_vf, pci_id_i40evf_map); + RTE_PMD_REGISTER_KMOD_DEP(net_i40e_vf, "* igb_uio | vfio-pci"); ++RTE_PMD_REGISTER_PARAM_STRING(net_i40e_vf, "driver=i40evf"); + + static int + i40evf_dev_configure(struct rte_eth_dev *dev) +diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c +index c3aa4cd725..f22c3ccdb9 100644 +--- a/drivers/net/iavf/iavf_ethdev.c ++++ b/drivers/net/iavf/iavf_ethdev.c +@@ -76,6 +76,10 @@ static int iavf_dev_filter_ctrl(struct rte_eth_dev *dev, + + static const struct rte_pci_id pci_id_iavf_map[] = { + { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) }, ++ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_VF) }, ++ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_VF_HV) }, ++ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_X722_VF) }, ++ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_X722_A0_VF) }, + { .vendor_id = 0, /* sentinel */ }, + }; + +@@ -1516,10 +1520,59 @@ iavf_dcf_cap_selected(struct rte_devargs *devargs) + return ret; + } + ++static int ++iavf_drv_i40evf_check_handler(__rte_unused const char *key, ++ const char *value, __rte_unused void *opaque) ++{ ++ if (strcmp(value, "i40evf")) ++ return -1; ++ ++ return 0; ++} ++ ++static int ++iavf_drv_i40evf_selected(struct rte_devargs *devargs, uint16_t device_id) ++{ ++ struct rte_kvargs *kvlist; ++ const char *key = "driver"; ++ int ret = 0; ++ ++ if (device_id != IAVF_DEV_ID_VF && ++ device_id != IAVF_DEV_ID_VF_HV && ++ device_id != IAVF_DEV_ID_X722_VF && ++ device_id != IAVF_DEV_ID_X722_A0_VF) ++ return 0; ++ ++ if (devargs == NULL) ++ return 0; ++ ++ kvlist = rte_kvargs_parse(devargs->args, NULL); ++ if (kvlist == NULL) ++ return 0; ++ ++ if (!rte_kvargs_count(kvlist, key)) ++ goto exit; ++ ++ /* i40evf driver selected when there's a key-value pair: ++ * driver=i40evf ++ */ ++ if (rte_kvargs_process(kvlist, key, ++ iavf_drv_i40evf_check_handler, NULL) < 0) ++ goto exit; ++ ++ ret = 1; ++ ++exit: ++ rte_kvargs_free(kvlist); ++ return ret; ++} ++ + static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) + { +- if (iavf_dcf_cap_selected(pci_dev->device.devargs)) ++ if (iavf_dcf_cap_selected(pci_dev->device.devargs) || ++ iavf_drv_i40evf_selected(pci_dev->device.devargs, ++ pci_dev->id.device_id)) + return 1; + + return rte_eth_dev_pci_generic_probe(pci_dev, +@@ -1542,7 +1595,7 @@ static struct rte_pci_driver rte_iavf_pmd = { + RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd); + RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map); + RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci"); +-RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf"); ++RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf driver=i40evf"); + RTE_LOG_REGISTER(iavf_logtype_init, pmd.net.iavf.init, NOTICE); + RTE_LOG_REGISTER(iavf_logtype_driver, pmd.net.iavf.driver, NOTICE); + #ifdef RTE_LIBRTE_IAVF_DEBUG_RX +-- +2.20.1 + From b6e090c49368bdd7692219a98aad1c997cb592d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Ganne?= Date: Tue, 18 Jan 2022 15:56:41 +0100 Subject: [PATCH 129/129] ipsec: fix AES CBC IV generation (CVE-2022-46397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For AES-CBC, the IV must be unpredictable (see NIST SP800-38a Appendix C). Chaining IVs like is done by ipsecmb and native backends for the VNET_CRYPTO_OP_FLAG_INIT_IV is fully predictable. Encrypt a counter as part of the message, making the (predictable) counter-generated IV unpredictable. Fixes: VPP-2037 Type: fix Change-Id: If4f192d62bf97dda553e7573331c75efa11822ae Signed-off-by: Benoît Ganne --- src/vnet/crypto/crypto.h | 4 +- src/vnet/ipsec/esp_encrypt.c | 88 ++++++++++++++++++++++++++++-------- src/vnet/ipsec/ipsec_sa.h | 2 +- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/vnet/crypto/crypto.h b/src/vnet/crypto/crypto.h index 07a73f14d043..20457074eb23 100644 --- a/src/vnet/crypto/crypto.h +++ b/src/vnet/crypto/crypto.h @@ -306,7 +306,7 @@ typedef struct i16 integ_start_offset; u32 crypto_total_length; /* adj total_length for integ, e.g.4 bytes for IPSec ESN */ - u16 integ_length_adj; + i16 integ_length_adj; u8 *iv; union { @@ -599,7 +599,7 @@ vnet_crypto_async_add_to_frame (vlib_main_t * vm, u32 key_index, u32 crypto_len, i16 integ_len_adj, i16 crypto_start_offset, - u16 integ_start_offset, + i16 integ_start_offset, u32 buffer_index, u16 next_node, u8 * iv, u8 * tag, u8 * aad, u8 flags) diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index c0773e2963f9..629df231601c 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -234,6 +234,24 @@ esp_get_ip6_hdr_len (ip6_header_t * ip6, ip6_ext_header_t ** ext_hdr) return len; } +/* IPsec IV generation: IVs requirements differ depending of the + * encryption mode: IVs must be unpredictable for AES-CBC whereas it can + * be predictable but should never be reused with the same key material + * for CTR and GCM. + * We use a packet counter as the IV for CTR and GCM, and to ensure the + * IV is unpredictable for CBC, it is then encrypted using the same key + * as the message. You can refer to NIST SP800-38a and NIST SP800-38d + * for more details. */ +static_always_inline void * +esp_generate_iv (ipsec_sa_t * sa, void *payload, int iv_sz) +{ + ASSERT (iv_sz >= sizeof (u64)); + u64 *iv = (u64 *) (payload - iv_sz); + clib_memset_u8 (iv, 0, iv_sz); + *iv = sa->iv_counter++; + return iv; +} + static_always_inline void esp_process_chained_ops (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_crypto_op_t * ops, vlib_buffer_t * b[], @@ -396,10 +414,16 @@ esp_prepare_sync_op (vlib_main_t * vm, ipsec_per_thread_data_t * ptd, vnet_crypto_op_t *op; vec_add2_aligned (crypto_ops[0], op, 1, CLIB_CACHE_LINE_BYTES); vnet_crypto_op_init (op, sa0->crypto_enc_op_id); + u8 *crypto_start = payload; + /* esp_add_footer_and_icv() in esp_encrypt_inline() makes sure we always + * have enough space for ESP header and footer which includes ICV */ + ASSERT (payload_len > icv_sz); + u16 crypto_len = payload_len - icv_sz; + + /* generate the IV in front of the payload */ + void *pkt_iv = esp_generate_iv (sa0, payload, iv_sz); - op->src = op->dst = payload; op->key_index = sa0->crypto_key_index; - op->len = payload_len - icv_sz; op->user_data = b - bufs; if (ipsec_sa_is_set_IS_AEAD (sa0)) @@ -411,18 +435,21 @@ esp_prepare_sync_op (vlib_main_t * vm, ipsec_per_thread_data_t * ptd, op->aad = payload - hdr_len - sizeof (esp_aead_t); op->aad_len = esp_aad_fill (op->aad, esp, sa0); - op->tag = payload + op->len; + op->tag = payload + crypto_len; op->tag_len = 16; - u64 *iv = (u64 *) (payload - iv_sz); nonce->salt = sa0->salt; - nonce->iv = *iv = clib_host_to_net_u64 (sa0->gcm_iv_counter++); + nonce->iv = *(u64 *) pkt_iv; op->iv = (u8 *) nonce; } else { - op->iv = payload - iv_sz; - op->flags = VNET_CRYPTO_OP_FLAG_INIT_IV; + /* construct zero iv in front of the IP header */ + op->iv = pkt_iv - hdr_len - iv_sz; + clib_memset_u8 (op->iv, 0, iv_sz); + /* include iv field in crypto */ + crypto_start -= iv_sz; + crypto_len += iv_sz; } if (lb != b[0]) @@ -431,8 +458,15 @@ esp_prepare_sync_op (vlib_main_t * vm, ipsec_per_thread_data_t * ptd, op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS; op->chunk_index = vec_len (ptd->chunks); op->tag = vlib_buffer_get_tail (lb) - icv_sz; - esp_encrypt_chain_crypto (vm, ptd, sa0, b[0], lb, icv_sz, payload, - payload_len, &op->n_chunks); + esp_encrypt_chain_crypto (vm, ptd, sa0, b[0], lb, icv_sz, + crypto_start, crypto_len + icv_sz, + &op->n_chunks); + } + else + { + /* not chained */ + op->src = op->dst = crypto_start; + op->len = crypto_len; } } @@ -482,17 +516,20 @@ esp_prepare_async_frame (vlib_main_t * vm, ipsec_per_thread_data_t * ptd, u8 *tag, *iv, *aad = 0; u8 flag = 0; u32 key_index; - i16 crypto_start_offset, integ_start_offset = 0; + i16 crypto_start_offset, integ_start_offset; u16 crypto_total_len, integ_total_len; post->next_index = next[0]; next[0] = ESP_ENCRYPT_NEXT_PENDING; /* crypto */ - crypto_start_offset = payload - b->data; + crypto_start_offset = integ_start_offset = payload - b->data; crypto_total_len = integ_total_len = payload_len - icv_sz; tag = payload + crypto_total_len; + /* generate the IV in front of the payload */ + void *pkt_iv = esp_generate_iv (sa, payload, iv_sz); + /* aead */ if (ipsec_sa_is_set_IS_AEAD (sa)) { @@ -503,7 +540,7 @@ esp_prepare_async_frame (vlib_main_t * vm, ipsec_per_thread_data_t * ptd, esp_aad_fill (aad, esp, sa); nonce = (esp_gcm_nonce_t *) (aad - sizeof (*nonce)); nonce->salt = sa->salt; - nonce->iv = *pkt_iv = clib_host_to_net_u64 (sa->gcm_iv_counter++); + nonce->iv = *(u64 *) pkt_iv; iv = (u8 *) nonce; key_index = sa->crypto_key_index; @@ -513,25 +550,38 @@ esp_prepare_async_frame (vlib_main_t * vm, ipsec_per_thread_data_t * ptd, flag |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS; tag = vlib_buffer_get_tail (lb) - icv_sz; crypto_total_len = esp_encrypt_chain_crypto (vm, ptd, sa, b, lb, - icv_sz, payload, - payload_len, 0); + icv_sz, + b->data + + crypto_start_offset, + crypto_total_len + + icv_sz, 0); } goto out; } + else + { + /* construct zero iv in front of the IP header */ + iv = pkt_iv - hdr_len - iv_sz; + clib_memset_u8 (iv, 0, iv_sz); + /* include iv field in crypto */ + crypto_start_offset -= iv_sz; + crypto_total_len += iv_sz; + } /* cipher then hash */ - iv = payload - iv_sz; - integ_start_offset = crypto_start_offset - iv_sz - sizeof (esp_header_t); + integ_start_offset -= iv_sz + sizeof (esp_header_t); integ_total_len += iv_sz + sizeof (esp_header_t); - flag |= VNET_CRYPTO_OP_FLAG_INIT_IV; key_index = sa->linked_key_index; if (b != lb) { flag |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS; crypto_total_len = esp_encrypt_chain_crypto (vm, ptd, sa, b, lb, - icv_sz, payload, - payload_len, 0); + icv_sz, + b->data + + crypto_start_offset, + crypto_total_len + icv_sz, + 0); tag = vlib_buffer_get_tail (lb) - icv_sz; integ_total_len = esp_encrypt_chain_integ (vm, ptd, sa, b, lb, icv_sz, payload - iv_sz - diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h index 5d65238b7369..24139a9dfbb8 100644 --- a/src/vnet/ipsec/ipsec_sa.h +++ b/src/vnet/ipsec/ipsec_sa.h @@ -182,7 +182,7 @@ typedef struct /* Salt used in GCM modes - stored in network byte order */ u32 salt; - u64 gcm_iv_counter; + u64 iv_counter; union {