From 2c1887fad07538ec05e557c21a2d9f6468e21c37 Mon Sep 17 00:00:00 2001 From: Marcin Smoczynski Date: Mon, 24 Jun 2019 15:39:58 +0200 Subject: [PATCH] ipsec: fix transport mode for IPv6 with extensions Reconstructing IPv6 header after encryption or decryption requires updating 'next header' value in the preceding protocol header, which is determined by parsing IPv6 header and iteratively looking for next IPv6 header extension. It is required that 'l3_len' in the mbuf metadata contains a total length of the IPv6 header with header extensions up to ESP header. Fixes: 4d7ea3e1459b ("ipsec: implement SA data-path API") Cc: stable@dpdk.org Signed-off-by: Marcin Smoczynski Acked-by: Konstantin Ananyev Acked-by: Akhil Goyal Tested-by: Konstantin Ananyev --- lib/Makefile | 3 ++- lib/librte_ipsec/iph.h | 55 ++++++++++++++++++++++++++++++++++++------ lib/meson.build | 2 +- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 791e0d9911..3ad579f682 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -108,7 +108,8 @@ DEPDIRS-librte_gso += librte_mempool DIRS-$(CONFIG_RTE_LIBRTE_BPF) += librte_bpf DEPDIRS-librte_bpf := librte_eal librte_mempool librte_mbuf librte_ethdev DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) += librte_ipsec -DEPDIRS-librte_ipsec := librte_eal librte_mbuf librte_cryptodev librte_security +DEPDIRS-librte_ipsec := librte_eal librte_mbuf librte_cryptodev librte_security \ + librte_net DIRS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += librte_telemetry DEPDIRS-librte_telemetry := librte_eal librte_metrics librte_ethdev DIRS-$(CONFIG_RTE_LIBRTE_RCU) += librte_rcu diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index a0ca41d51b..62d78b7b17 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -5,6 +5,8 @@ #ifndef _IPH_H_ #define _IPH_H_ +#include + /** * @file iph.h * Contains functions/structures/macros to manipulate IPv4/IPv6 headers @@ -40,24 +42,61 @@ static inline int update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, uint32_t l2len, uint32_t l3len, uint8_t proto) { - struct rte_ipv4_hdr *v4h; - struct rte_ipv6_hdr *v6h; int32_t rc; + /* IPv4 */ if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) { + struct rte_ipv4_hdr *v4h; + v4h = p; rc = v4h->next_proto_id; v4h->next_proto_id = proto; v4h->total_length = rte_cpu_to_be_16(plen - l2len); - } else if (l3len == sizeof(*v6h)) { + /* IPv6 */ + } else { + struct rte_ipv6_hdr *v6h; + uint8_t *p_nh; + v6h = p; - rc = v6h->proto; - v6h->proto = proto; + + /* basic IPv6 header with no extensions */ + if (l3len == sizeof(struct rte_ipv6_hdr)) + p_nh = &v6h->proto; + + /* IPv6 with extensions */ + else { + size_t ext_len; + int nh; + uint8_t *pd, *plimit; + + /* locate last extension within l3len bytes */ + pd = (uint8_t *)p; + plimit = pd + l3len; + ext_len = sizeof(struct rte_ipv6_hdr); + nh = v6h->proto; + while (pd + ext_len < plimit) { + pd += ext_len; + nh = rte_ipv6_get_next_ext(pd, nh, &ext_len); + if (unlikely(nh < 0)) + return -EINVAL; + } + + /* invalid l3len - extension exceeds header length */ + if (unlikely(pd + ext_len != plimit)) + return -EINVAL; + + /* save last extension offset */ + p_nh = pd; + } + + /* update header type; return original value */ + rc = *p_nh; + *p_nh = proto; + + /* fix packet length */ v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); - /* need to add support for IPv6 with options */ - } else - rc = -ENOTSUP; + } return rc; } diff --git a/lib/meson.build b/lib/meson.build index 5ddf1ca116..3d77b1f901 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -23,7 +23,7 @@ libraries = [ 'kni', 'latencystats', 'lpm', 'member', 'power', 'pdump', 'rawdev', 'rcu', 'reorder', 'sched', 'security', 'stack', 'vhost', - #ipsec lib depends on crypto and security + # ipsec lib depends on net, crypto and security 'ipsec', # add pkt framework libs which use other libs from above 'port', 'table', 'pipeline', -- 2.20.1