* [dpdk-dev] [PATCH v1] lib/ipsec: add support for header construction @ 2019-05-17 16:03 Marko Kovacevic 2019-05-19 16:26 ` Ananyev, Konstantin 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction Fan Zhang 0 siblings, 2 replies; 27+ messages in thread From: Marko Kovacevic @ 2019-05-17 16:03 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, roy.fan.zhang, Marko Kovacevic Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> --- examples/ipsec-secgw/sa.c | 2 + lib/librte_ipsec/esp_inb.c | 14 ++++- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 119 +++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/rte_ipsec_sa.h | 25 ++++++++ lib/librte_ipsec/sa.c | 17 ++++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 8 +++ lib/librte_security/rte_security.h | 9 +++ 9 files changed, 191 insertions(+), 9 deletions(-) diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index b850e9839..4d85d09df 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (ss->flags == IP4_TUNNEL) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index 4e0e12a85..8a3cb8a15 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -377,9 +377,10 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], { uint32_t adj, i, k, tl; uint32_t hl[num]; + void *inner_h; + const void *outter_h; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; - const uint32_t tlen = sa->icv_len + sizeof(espt[0]); const uint32_t cofs = sa->ctp.cipher.offset; @@ -400,9 +401,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], ml[i], espt[i], adj, tl, sa->proto) == 0) { + outter_h = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, - tl, sqn + k); + inner_h = tun_process_step2(mb[i], ml[i], hl[i], adj, + tl, sqn + k); + + if ((sa->type & INB_TUN_HDR_MSK) != 0) + update_inb_tun_l3_hdr(sa, inner_h, outter_h); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index c798bc4c4..a71164e0c 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len, sa->hdr_l3_off, - sqn_low16(sqc)); + update_outb_tun_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, mb->pkt_len, + sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ esph = (struct esp_hdr *)(ph + sa->hdr_len); diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 58930cf18..f45db5d4a 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -11,6 +11,11 @@ * used internally by ipsec library. */ +#define IPV6_DSCP_MASK (DSCP_MASK << IPV6_HDR_TC_SHIFT) +#define IPV6_ECN_MASK (ECN_MASK << IPV6_HDR_TC_SHIFT) +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) +#define IPV6_ECN_CE IPV6_ECN_MASK + /* * Move preceding (L3) headers down to remove ESP header and IV. */ @@ -35,6 +40,26 @@ insert_esph(char *np, char *op, uint32_t hlen) np[i] = op[i]; } +static inline uint8_t +get_ipv6_tos(rte_be32_t vtc_flow) +{ + uint32_t v; + + v = rte_be_to_cpu_32(vtc_flow); + return v >> IPV6_HDR_TC_SHIFT; +} + +static inline rte_be32_t +set_ipv6_tos(rte_be32_t vtc_flow, uint32_t tos) +{ + uint32_t v; + + v = rte_cpu_to_be_32(tos << IPV6_HDR_TC_SHIFT); + vtc_flow &= ~rte_cpu_to_be_32(IPV6_TOS_MASK); + + return (v | vtc_flow); +} + /* update original ip header fields for transport case */ static inline int update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, @@ -64,20 +89,106 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_outb_tun_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct ipv4_hdr *v4h; struct ipv6_hdr *v6h; + uint32_t itp, otp; + const struct ipv4_hdr *v4in_h; + const struct ipv6_hdr *v6in_h; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); + + if (sa->proto == IPPROTO_IPIP) { + /* ipv4 inner header */ + v4in_h = inh; + + otp = v4h->type_of_service & ~sa->tos_mask; + itp = v4in_h->type_of_service & sa->tos_mask; + v4h->type_of_service = (otp | itp); + } else { + /* ipv6 inner header */ + v6in_h = inh; + + otp = v4h->type_of_service & ~sa->tos_mask; + itp = get_ipv6_tos(v6in_h->vtc_flow) & sa->tos_mask; + v4h->type_of_service = (otp | itp); + } } else { - v6h = p; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); + + if (sa->proto == IPPROTO_IPIP) { + /* ipv4 inner header */ + v4in_h = inh; + + otp = get_ipv6_tos(v6h->vtc_flow) & ~sa->tos_mask; + itp = v4in_h->type_of_service & sa->tos_mask; + v6h->vtc_flow = set_ipv6_tos(v6h->vtc_flow, otp | itp); + } else { + /* ipv6 inner header */ + v6in_h = inh; + + otp = get_ipv6_tos(v6h->vtc_flow) & ~sa->tos_mask; + itp = get_ipv6_tos(v6in_h->vtc_flow) & sa->tos_mask; + v6h->vtc_flow = set_ipv6_tos(v6h->vtc_flow, otp | itp); + } + } +} + +static inline void +update_inb_tun_l3_hdr(const struct rte_ipsec_sa *sa, void *ip_inner, + const void *ip_outter) +{ + struct ipv4_hdr *inner_v4h; + const struct ipv4_hdr *outter_v4h; + struct ipv6_hdr *inner_v6h; + const struct ipv6_hdr *outter_v6h; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + inner_v4h = ip_inner; + outter_v4h = ip_outter; + + inner_v6h = ip_inner; + outter_v6h = ip_outter; + + /* <update ecn bits in inner IP header> */ + if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { + + ecn_v4out = outter_v4h->type_of_service & ECN_MASK; + + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) { + ecn_v4in = inner_v4h->type_of_service & ECN_MASK; + if (ecn_v4out == ECN_CE && ecn_v4in != 0) + inner_v4h->type_of_service |= ECN_CE; + } else { + ecn_v6in = inner_v6h->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v4out == ECN_CE && ecn_v6in != 0) + inner_v6h->vtc_flow |= + rte_cpu_to_be_32(IPV6_ECN_CE); + } + } else { + ecn_v6out = outter_v6h->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV6) { + ecn_v6in = inner_v6h->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v6out == IPV6_ECN_CE && ecn_v6in != 0) + inner_v6h->vtc_flow |= + rte_cpu_to_be_32(IPV6_ECN_CE); + } else { + ecn_v4in = inner_v4h->type_of_service & ECN_MASK; + if (ecn_v6out == ECN_CE && ecn_v4in != 0) + inner_v4h->type_of_service |= ECN_CE; + } } } diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index fd9b3ed60..8f179ee9d 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,11 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, + RTE_SATP_LOG2_TTL, + RTE_SATP_LOG2_DF, + RTE_SATP_LOG2_FLABEL, RTE_SATP_LOG2_NUM }; @@ -123,6 +128,26 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + +#define RTE_IPSEC_SATP_TTL_MASK (1ULL << RTE_SATP_LOG2_TTL) +#define RTE_IPSEC_SATP_TTL_DISABLE (0ULL << RTE_SATP_LOG2_TTL) +#define RTE_IPSEC_SATP_TTL_ENABLE (1ULL << RTE_SATP_LOG2_TTL) + +#define RTE_IPSEC_SATP_DF_MASK (1ULL << RTE_SATP_LOG2_DF) +#define RTE_IPSEC_SATP_DF_DISABLE (0ULL << RTE_SATP_LOG2_DF) +#define RTE_IPSEC_SATP_DF_ENABLE (1ULL << RTE_SATP_LOG2_DF) + +#define RTE_IPSEC_SATP_FLABEL_MASK (1ULL << RTE_SATP_LOG2_FLABEL) +#define RTE_IPSEC_SATP_FLABEL_DISABLE (0ULL << RTE_SATP_LOG2_FLABEL) +#define RTE_IPSEC_SATP_FLABEL_ENABLE (1ULL << RTE_SATP_LOG2_FLABEL) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index 846e317fe..d48acd117 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -220,6 +220,17 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_SQN_RAW; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + *type = tp; return 0; } @@ -308,6 +319,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index ffb5fb4f8..41e0b78c9 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define INB_TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index f9b909090..6592637f7 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -47,6 +47,14 @@ struct ipv4_hdr { (((c) & 0xff) << 8) | \ ((d) & 0xff)) + +/** RFC 3168 */ +#define ECN_MASK (0x03) +#define ECN_CE ECN_MASK + +/** Packet Option Masks */ +#define DSCP_MASK (0xFC) + /** Maximal IPv4 packet length (including a header) */ #define IPV4_MAX_PKT_LEN 65535 diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index 76f54e0e0..577eff766 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * ECT(1) (ECN-Capable Transport(1)) + * * ECT(0) (ECN-Capable Transport(0)) + * * ECT(CE)(CE (Congestion Experienced)) + */ + + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.13.6 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v1] lib/ipsec: add support for header construction 2019-05-17 16:03 [dpdk-dev] [PATCH v1] lib/ipsec: add support for header construction Marko Kovacevic @ 2019-05-19 16:26 ` Ananyev, Konstantin 2019-06-20 12:27 ` Akhil Goyal 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction Fan Zhang 1 sibling, 1 reply; 27+ messages in thread From: Ananyev, Konstantin @ 2019-05-19 16:26 UTC (permalink / raw) To: Kovacevic, Marko, dev; +Cc: akhil.goyal, Zhang, Roy Fan Hi, > > Add support for RFC 4301(5.1.2) to update of > Type of service field and Traffic class field > bits inside ipv4/ipv6 packets for outbound cases > and inbound cases which deals with the update of > the DSCP/ENC bits inside each of the fields. > > Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> > --- > examples/ipsec-secgw/sa.c | 2 + > lib/librte_ipsec/esp_inb.c | 14 ++++- > lib/librte_ipsec/esp_outb.c | 4 +- > lib/librte_ipsec/iph.h | 119 +++++++++++++++++++++++++++++++++++-- > lib/librte_ipsec/rte_ipsec_sa.h | 25 ++++++++ > lib/librte_ipsec/sa.c | 17 ++++++ > lib/librte_ipsec/sa.h | 2 + > lib/librte_net/rte_ip.h | 8 +++ > lib/librte_security/rte_security.h | 9 +++ > 9 files changed, 191 insertions(+), 9 deletions(-) Looks good in general, some generic comments: - I think it is better to split the patch into few sub-pathces: One for rte_security, second for rte_net, third - rte_ipsec, forth - examples/ipsec-secgw - Would be good to add support for other options too (ttl, etc.) - Would be good to add new test-case for it into examples/ipsec-secgw/test/ Plus few nits in the code below. Konstantin > > diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c > index b850e9839..4d85d09df 100644 > --- a/examples/ipsec-secgw/sa.c > +++ b/examples/ipsec-secgw/sa.c > @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, > prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? > RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : > RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; > + prm->ipsec_xform.options.ecn = 1; > + prm->ipsec_xform.options.copy_dscp = 1; > > if (ss->flags == IP4_TUNNEL) { > prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; > diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c > index 4e0e12a85..8a3cb8a15 100644 > --- a/lib/librte_ipsec/esp_inb.c > +++ b/lib/librte_ipsec/esp_inb.c > @@ -377,9 +377,10 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], > { > uint32_t adj, i, k, tl; > uint32_t hl[num]; > + void *inner_h; > + const void *outter_h; > struct esp_tail espt[num]; > struct rte_mbuf *ml[num]; > - > const uint32_t tlen = sa->icv_len + sizeof(espt[0]); > const uint32_t cofs = sa->ctp.cipher.offset; > > @@ -400,9 +401,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], > if (tun_process_check(mb[i], ml[i], espt[i], adj, tl, > sa->proto) == 0) { > > + outter_h = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, > + mb[i]->l2_len); > + > /* modify packet's layout */ > - tun_process_step2(mb[i], ml[i], hl[i], adj, > - tl, sqn + k); > + inner_h = tun_process_step2(mb[i], ml[i], hl[i], adj, > + tl, sqn + k); > + > + if ((sa->type & INB_TUN_HDR_MSK) != 0) > + update_inb_tun_l3_hdr(sa, inner_h, outter_h); > + > /* update mbuf's metadata */ > tun_process_step3(mb[i], sa->tx_offload.msk, > sa->tx_offload.val); > diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c > index c798bc4c4..a71164e0c 100644 > --- a/lib/librte_ipsec/esp_outb.c > +++ b/lib/librte_ipsec/esp_outb.c > @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, > rte_memcpy(ph, sa->hdr, sa->hdr_len); > > /* update original and new ip header fields */ > - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len, sa->hdr_l3_off, > - sqn_low16(sqc)); > + update_outb_tun_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, mb->pkt_len, > + sa->hdr_l3_off, sqn_low16(sqc)); > > /* update spi, seqn and iv */ > esph = (struct esp_hdr *)(ph + sa->hdr_len); > diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h > index 58930cf18..f45db5d4a 100644 > --- a/lib/librte_ipsec/iph.h > +++ b/lib/librte_ipsec/iph.h > @@ -11,6 +11,11 @@ > * used internally by ipsec library. > */ > > +#define IPV6_DSCP_MASK (DSCP_MASK << IPV6_HDR_TC_SHIFT) > +#define IPV6_ECN_MASK (ECN_MASK << IPV6_HDR_TC_SHIFT) > +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) > +#define IPV6_ECN_CE IPV6_ECN_MASK > + > /* > * Move preceding (L3) headers down to remove ESP header and IV. > */ > @@ -35,6 +40,26 @@ insert_esph(char *np, char *op, uint32_t hlen) > np[i] = op[i]; > } > > +static inline uint8_t > +get_ipv6_tos(rte_be32_t vtc_flow) > +{ > + uint32_t v; > + > + v = rte_be_to_cpu_32(vtc_flow); > + return v >> IPV6_HDR_TC_SHIFT; > +} > + > +static inline rte_be32_t > +set_ipv6_tos(rte_be32_t vtc_flow, uint32_t tos) > +{ > + uint32_t v; > + > + v = rte_cpu_to_be_32(tos << IPV6_HDR_TC_SHIFT); > + vtc_flow &= ~rte_cpu_to_be_32(IPV6_TOS_MASK); > + > + return (v | vtc_flow); > +} > + > /* update original ip header fields for transport case */ > static inline int > update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > @@ -64,20 +89,106 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > > /* update original and new ip header fields for tunnel case */ > static inline void > -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > - uint32_t l2len, rte_be16_t pid) > +update_outb_tun_l3hdr(const struct rte_ipsec_sa *sa, void *outh, > + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) > { > struct ipv4_hdr *v4h; > struct ipv6_hdr *v6h; > + uint32_t itp, otp; > + const struct ipv4_hdr *v4in_h; > + const struct ipv6_hdr *v6in_h; > > if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { > - v4h = p; > + v4h = outh; > v4h->packet_id = pid; > v4h->total_length = rte_cpu_to_be_16(plen - l2len); I think it makes sense to invoke the code below, only when: ((sa->type & INB_TUN_HDR_MSK) != 0) Same as we doing for onbound. Also probably worth to put it into a separate inline function. > + > + if (sa->proto == IPPROTO_IPIP) { For consistency with the check above, seems a bit better: if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) > + /* ipv4 inner header */ > + v4in_h = inh; > + > + otp = v4h->type_of_service & ~sa->tos_mask; > + itp = v4in_h->type_of_service & sa->tos_mask; > + v4h->type_of_service = (otp | itp); > + } else { > + /* ipv6 inner header */ > + v6in_h = inh; > + > + otp = v4h->type_of_service & ~sa->tos_mask; > + itp = get_ipv6_tos(v6in_h->vtc_flow) & sa->tos_mask; > + v4h->type_of_service = (otp | itp); > + } > } else { > - v6h = p; > + v6h = outh; > v6h->payload_len = rte_cpu_to_be_16(plen - l2len - > sizeof(*v6h)); > + > + if (sa->proto == IPPROTO_IPIP) { Same comment as above here. > + /* ipv4 inner header */ > + v4in_h = inh; > + > + otp = get_ipv6_tos(v6h->vtc_flow) & ~sa->tos_mask; > + itp = v4in_h->type_of_service & sa->tos_mask; > + v6h->vtc_flow = set_ipv6_tos(v6h->vtc_flow, otp | itp); > + } else { > + /* ipv6 inner header */ > + v6in_h = inh; > + > + otp = get_ipv6_tos(v6h->vtc_flow) & ~sa->tos_mask; > + itp = get_ipv6_tos(v6in_h->vtc_flow) & sa->tos_mask; > + v6h->vtc_flow = set_ipv6_tos(v6h->vtc_flow, otp | itp); > + } > + } > +} > + > +static inline void > +update_inb_tun_l3_hdr(const struct rte_ipsec_sa *sa, void *ip_inner, > + const void *ip_outter) > +{ > + struct ipv4_hdr *inner_v4h; > + const struct ipv4_hdr *outter_v4h; > + struct ipv6_hdr *inner_v6h; > + const struct ipv6_hdr *outter_v6h; > + uint8_t ecn_v4out, ecn_v4in; > + uint32_t ecn_v6out, ecn_v6in; > + > + inner_v4h = ip_inner; > + outter_v4h = ip_outter; > + > + inner_v6h = ip_inner; > + outter_v6h = ip_outter; > + > + /* <update ecn bits in inner IP header> */ > + if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { > + > + ecn_v4out = outter_v4h->type_of_service & ECN_MASK; > + > + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) { > + ecn_v4in = inner_v4h->type_of_service & ECN_MASK; > + if (ecn_v4out == ECN_CE && ecn_v4in != 0) > + inner_v4h->type_of_service |= ECN_CE; > + } else { > + ecn_v6in = inner_v6h->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + if (ecn_v4out == ECN_CE && ecn_v6in != 0) > + inner_v6h->vtc_flow |= > + rte_cpu_to_be_32(IPV6_ECN_CE); > + } > + } else { > + ecn_v6out = outter_v6h->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + > + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV6) { > + ecn_v6in = inner_v6h->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + if (ecn_v6out == IPV6_ECN_CE && ecn_v6in != 0) > + inner_v6h->vtc_flow |= > + rte_cpu_to_be_32(IPV6_ECN_CE); > + } else { > + ecn_v4in = inner_v4h->type_of_service & ECN_MASK; > + if (ecn_v6out == ECN_CE && ecn_v4in != 0) > + inner_v4h->type_of_service |= ECN_CE; > + } > } > } > > diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h > index fd9b3ed60..8f179ee9d 100644 > --- a/lib/librte_ipsec/rte_ipsec_sa.h > +++ b/lib/librte_ipsec/rte_ipsec_sa.h > @@ -95,6 +95,11 @@ enum { > RTE_SATP_LOG2_MODE, > RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, > RTE_SATP_LOG2_ESN, > + RTE_SATP_LOG2_ECN, > + RTE_SATP_LOG2_DSCP, > + RTE_SATP_LOG2_TTL, > + RTE_SATP_LOG2_DF, > + RTE_SATP_LOG2_FLABEL, > RTE_SATP_LOG2_NUM > }; > > @@ -123,6 +128,26 @@ enum { > #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) > #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) > > +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) > +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) > +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) > + > +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) > +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) > +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) > + > +#define RTE_IPSEC_SATP_TTL_MASK (1ULL << RTE_SATP_LOG2_TTL) > +#define RTE_IPSEC_SATP_TTL_DISABLE (0ULL << RTE_SATP_LOG2_TTL) > +#define RTE_IPSEC_SATP_TTL_ENABLE (1ULL << RTE_SATP_LOG2_TTL) > + > +#define RTE_IPSEC_SATP_DF_MASK (1ULL << RTE_SATP_LOG2_DF) > +#define RTE_IPSEC_SATP_DF_DISABLE (0ULL << RTE_SATP_LOG2_DF) > +#define RTE_IPSEC_SATP_DF_ENABLE (1ULL << RTE_SATP_LOG2_DF) > + > +#define RTE_IPSEC_SATP_FLABEL_MASK (1ULL << RTE_SATP_LOG2_FLABEL) > +#define RTE_IPSEC_SATP_FLABEL_DISABLE (0ULL << RTE_SATP_LOG2_FLABEL) > +#define RTE_IPSEC_SATP_FLABEL_ENABLE (1ULL << RTE_SATP_LOG2_FLABEL) > + > /** > * get type of given SA > * @return > diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c > index 846e317fe..d48acd117 100644 > --- a/lib/librte_ipsec/sa.c > +++ b/lib/librte_ipsec/sa.c > @@ -220,6 +220,17 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) > else > tp |= RTE_IPSEC_SATP_SQN_RAW; > > + /* check for ECN flag */ > + if (prm->ipsec_xform.options.ecn == 0) > + tp |= RTE_IPSEC_SATP_ECN_DISABLE; > + else > + tp |= RTE_IPSEC_SATP_ECN_ENABLE; > + /* check for DSCP flag */ > + if (prm->ipsec_xform.options.copy_dscp == 0) > + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; > + else > + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; > + > *type = tp; > return 0; > } > @@ -308,6 +319,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, > static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | > RTE_IPSEC_SATP_MODE_MASK; > > + if (prm->ipsec_xform.options.ecn) > + sa->tos_mask |= ECN_MASK; > + > + if (prm->ipsec_xform.options.copy_dscp) > + sa->tos_mask |= DSCP_MASK; > + > if (cxf->aead != NULL) { > switch (cxf->aead->algo) { > case RTE_CRYPTO_AEAD_AES_GCM: > diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h > index ffb5fb4f8..41e0b78c9 100644 > --- a/lib/librte_ipsec/sa.h > +++ b/lib/librte_ipsec/sa.h > @@ -10,6 +10,7 @@ > #define IPSEC_MAX_HDR_SIZE 64 > #define IPSEC_MAX_IV_SIZE 16 > #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) > +#define INB_TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) > > /* padding alignment for different algorithms */ > enum { > @@ -103,6 +104,7 @@ struct rte_ipsec_sa { > uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ > uint8_t iv_len; > uint8_t pad_align; > + uint8_t tos_mask; > > /* template for tunnel header */ > uint8_t hdr[IPSEC_MAX_HDR_SIZE]; > diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h > index f9b909090..6592637f7 100644 > --- a/lib/librte_net/rte_ip.h > +++ b/lib/librte_net/rte_ip.h > @@ -47,6 +47,14 @@ struct ipv4_hdr { > (((c) & 0xff) << 8) | \ > ((d) & 0xff)) > > + > +/** RFC 3168 */ > +#define ECN_MASK (0x03) > +#define ECN_CE ECN_MASK > + > +/** Packet Option Masks */ > +#define DSCP_MASK (0xFC) Might be worth to add some prefix: IP_ECN_... Or even RTE_IP_ECN_... > + > /** Maximal IPv4 packet length (including a header) */ > #define IPV4_MAX_PKT_LEN 65535 > > diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h > index 76f54e0e0..577eff766 100644 > --- a/lib/librte_security/rte_security.h > +++ b/lib/librte_security/rte_security.h > @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { > * * 0: Inner packet is not modified. > */ > uint32_t dec_ttl : 1; > + > + /**< Explicit Congestion Notification (ECN) > + * > + * * ECT(1) (ECN-Capable Transport(1)) > + * * ECT(0) (ECN-Capable Transport(0)) > + * * ECT(CE)(CE (Congestion Experienced)) I think, that comment (possible ECN values) better move into rte_ip.h. And here explain briefly what would be behavior for ipsec implementation for 0/1 values. > + */ > + > + uint32_t ecn : 1; > }; > > /** IPSec security association direction */ > -- > 2.13.6 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v1] lib/ipsec: add support for header construction 2019-05-19 16:26 ` Ananyev, Konstantin @ 2019-06-20 12:27 ` Akhil Goyal 0 siblings, 0 replies; 27+ messages in thread From: Akhil Goyal @ 2019-06-20 12:27 UTC (permalink / raw) To: Ananyev, Konstantin, Kovacevic, Marko, dev; +Cc: Zhang, Roy Fan Hi Marko, Could you please address to the comments from Konstantin? We have an RC1 date coming. Thanks, Akhil > Hi, > > > > > Add support for RFC 4301(5.1.2) to update of > > Type of service field and Traffic class field > > bits inside ipv4/ipv6 packets for outbound cases > > and inbound cases which deals with the update of > > the DSCP/ENC bits inside each of the fields. > > > > Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> > > --- > > examples/ipsec-secgw/sa.c | 2 + > > lib/librte_ipsec/esp_inb.c | 14 ++++- > > lib/librte_ipsec/esp_outb.c | 4 +- > > lib/librte_ipsec/iph.h | 119 +++++++++++++++++++++++++++++++++++- > - > > lib/librte_ipsec/rte_ipsec_sa.h | 25 ++++++++ > > lib/librte_ipsec/sa.c | 17 ++++++ > > lib/librte_ipsec/sa.h | 2 + > > lib/librte_net/rte_ip.h | 8 +++ > > lib/librte_security/rte_security.h | 9 +++ > > 9 files changed, 191 insertions(+), 9 deletions(-) > > Looks good in general, some generic comments: > - I think it is better to split the patch into few sub-pathces: > One for rte_security, second for rte_net, third - rte_ipsec, forth - > examples/ipsec-secgw > - Would be good to add support for other options too (ttl, etc.) > - Would be good to add new test-case for it into examples/ipsec-secgw/test/ > > Plus few nits in the code below. > Konstantin > ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction. 2019-05-17 16:03 [dpdk-dev] [PATCH v1] lib/ipsec: add support for header construction Marko Kovacevic 2019-05-19 16:26 ` Ananyev, Konstantin @ 2019-06-25 13:43 ` Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 1/2] lib/ipsec: add support for header construction Fan Zhang ` (2 more replies) 1 sibling, 3 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-25 13:43 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patchset adds the ECN and DSCP tunnel mode header reconstruction support for rte_ipsec library. The ipsec-secgw sample application is updated with the feature's enabling and a python3 script for testing the correctness of the implementation. This patchset depends on the following patchset "[v2,0/4] IPv6 with options support for IPsec transport" (http://patchwork.dpdk.org/cover/55238/) v2: - Fixed a few bugs. - Updated according to Konstantin's comments. - Added python script for testing. Fan Zhang (1): examples/ipsec-secgw: support header reconstruction Marko Kovacevic (1): lib/ipsec: add support for header construction doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ lib/librte_ipsec/esp_inb.c | 14 +- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 134 +++++- lib/librte_ipsec/rte_ipsec_sa.h | 25 ++ lib/librte_ipsec/sa.c | 17 + lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 11 + lib/librte_security/rte_security.h | 9 + 12 files changed, 692 insertions(+), 12 deletions(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 1/2] lib/ipsec: add support for header construction 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction Fan Zhang @ 2019-06-25 13:43 ` Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang 2 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-25 13:43 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Marko Kovacevic, Fan Zhang From: Marko Kovacevic <marko.kovacevic@intel.com> Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- lib/librte_ipsec/esp_inb.c | 14 +++- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 134 +++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/rte_ipsec_sa.h | 25 +++++++ lib/librte_ipsec/sa.c | 17 +++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 11 +++ lib/librte_security/rte_security.h | 9 +++ 8 files changed, 205 insertions(+), 11 deletions(-) diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index 3e12ca103..8c68f8913 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -377,9 +377,10 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], { uint32_t adj, i, k, tl; uint32_t hl[num]; + void *inner_h; + const void *outter_h; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; - const uint32_t tlen = sa->icv_len + sizeof(espt[0]); const uint32_t cofs = sa->ctp.cipher.offset; @@ -400,9 +401,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], ml[i], espt[i], adj, tl, sa->proto) == 0) { + outter_h = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, - tl, sqn + k); + inner_h = tun_process_step2(mb[i], ml[i], hl[i], adj, + tl, sqn + k); + + if ((sa->type & INB_TUN_HDR_MSK) != 0) + update_inb_tun_l3_hdr(sa, inner_h, outter_h); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index 862a9982d..a0fa9e660 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len, sa->hdr_l3_off, - sqn_low16(sqc)); + update_outb_tun_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, mb->pkt_len, + sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ esph = (struct rte_esp_hdr *)(ph + sa->hdr_len); diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 62d78b7b1..a4e7070e3 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -5,14 +5,17 @@ #ifndef _IPH_H_ #define _IPH_H_ -#include <rte_ip.h> - /** * @file iph.h * Contains functions/structures/macros to manipulate IPv4/IPv6 headers * used internally by ipsec library. */ +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) +#define IPV6_ECN_CE IPV6_ECN_MASK + /* * Move preceding (L3) headers down to remove ESP header and IV. */ @@ -37,6 +40,26 @@ insert_esph(char *np, char *op, uint32_t hlen) np[i] = op[i]; } +static inline uint8_t +get_ipv6_tos(rte_be32_t vtc_flow) +{ + uint32_t v; + + v = rte_be_to_cpu_32(vtc_flow); + return v >> RTE_IPV6_HDR_TC_SHIFT; +} + +static inline rte_be32_t +set_ipv6_tos(rte_be32_t vtc_flow, uint32_t tos) +{ + uint32_t v; + + v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT); + vtc_flow &= ~rte_cpu_to_be_32(IPV6_TOS_MASK); + + return (v | vtc_flow); +} + /* update original ip header fields for transport case */ static inline int update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, @@ -103,21 +126,120 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_outb_tun_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct rte_ipv4_hdr *v4h; struct rte_ipv6_hdr *v6h; + uint32_t itp, otp; + const struct rte_ipv4_hdr *v4in_h; + const struct rte_ipv6_hdr *v6in_h; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); + + if ((sa->type & INB_TUN_HDR_MSK) == 0) + return; + + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4) { + /* ipv4 inner header */ + v4in_h = inh; + + otp = v4h->type_of_service & ~sa->tos_mask; + itp = v4in_h->type_of_service & sa->tos_mask; + v4h->type_of_service = (otp | itp); + } else { + /* ipv6 inner header */ + v6in_h = inh; + + otp = v4h->type_of_service & ~sa->tos_mask; + itp = get_ipv6_tos(v6in_h->vtc_flow) & sa->tos_mask; + v4h->type_of_service = (otp | itp); + } } else { - v6h = p; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); + + if ((sa->type & INB_TUN_HDR_MSK) == 0) + return; + + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4) { + /* ipv4 inner header */ + v4in_h = inh; + + otp = get_ipv6_tos(v6h->vtc_flow) & ~sa->tos_mask; + itp = v4in_h->type_of_service & sa->tos_mask; + v6h->vtc_flow = set_ipv6_tos(v6h->vtc_flow, otp | itp); + } else { + /* ipv6 inner header */ + v6in_h = inh; + + otp = get_ipv6_tos(v6h->vtc_flow) & ~sa->tos_mask; + itp = get_ipv6_tos(v6in_h->vtc_flow) & sa->tos_mask; + v6h->vtc_flow = set_ipv6_tos(v6h->vtc_flow, otp | itp); + } + } +} + +static inline void +update_inb_tun_l3_hdr(const struct rte_ipsec_sa *sa, void *ip_inner, + const void *ip_outter) +{ + struct rte_ipv4_hdr *inner_v4h; + const struct rte_ipv4_hdr *outter_v4h; + struct rte_ipv6_hdr *inner_v6h; + const struct rte_ipv6_hdr *outter_v6h; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + inner_v4h = ip_inner; + outter_v4h = ip_outter; + + inner_v6h = ip_inner; + outter_v6h = ip_outter; + + /* <update ecn bits in inner IP header> */ + if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { + + ecn_v4out = outter_v4h->type_of_service & RTE_IP_ECN_MASK; + + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4) { + ecn_v4in = inner_v4h->type_of_service & RTE_IP_ECN_MASK; + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) + inner_v4h->type_of_service |= RTE_IP_ECN_CE; + } else { + ecn_v6in = inner_v6h->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) + inner_v6h->vtc_flow |= + rte_cpu_to_be_32(IPV6_ECN_CE); + } + } else { + ecn_v6out = outter_v6h->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + + if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV6) { + ecn_v6in = inner_v6h->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v6in != 0)) + inner_v6h->vtc_flow |= + rte_cpu_to_be_32(IPV6_ECN_CE); + } else { + ecn_v4in = inner_v4h->type_of_service & RTE_IP_ECN_MASK; + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v4in != 0)) + inner_v4h->type_of_service |= RTE_IP_ECN_CE; + } } } #endif /* _IPH_H_ */ + diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index fd9b3ed60..8f179ee9d 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,11 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, + RTE_SATP_LOG2_TTL, + RTE_SATP_LOG2_DF, + RTE_SATP_LOG2_FLABEL, RTE_SATP_LOG2_NUM }; @@ -123,6 +128,26 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + +#define RTE_IPSEC_SATP_TTL_MASK (1ULL << RTE_SATP_LOG2_TTL) +#define RTE_IPSEC_SATP_TTL_DISABLE (0ULL << RTE_SATP_LOG2_TTL) +#define RTE_IPSEC_SATP_TTL_ENABLE (1ULL << RTE_SATP_LOG2_TTL) + +#define RTE_IPSEC_SATP_DF_MASK (1ULL << RTE_SATP_LOG2_DF) +#define RTE_IPSEC_SATP_DF_DISABLE (0ULL << RTE_SATP_LOG2_DF) +#define RTE_IPSEC_SATP_DF_ENABLE (1ULL << RTE_SATP_LOG2_DF) + +#define RTE_IPSEC_SATP_FLABEL_MASK (1ULL << RTE_SATP_LOG2_FLABEL) +#define RTE_IPSEC_SATP_FLABEL_DISABLE (0ULL << RTE_SATP_LOG2_FLABEL) +#define RTE_IPSEC_SATP_FLABEL_ENABLE (1ULL << RTE_SATP_LOG2_FLABEL) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index 1cb71caa1..952442785 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -220,6 +220,17 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_SQN_RAW; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + *type = tp; return 0; } @@ -310,6 +321,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= RTE_IP_ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= RTE_IP_DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index ffb5fb4f8..41e0b78c9 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define INB_TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index c2c67b85d..85c53e8d9 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -46,6 +46,17 @@ struct rte_ipv4_hdr { (((b) & 0xff) << 16) | \ (((c) & 0xff) << 8) | \ ((d) & 0xff)) +/** + * RFC 3168 Explicit Congestion Notification (ECN) + * * ECT(1) (ECN-Capable Transport(1)) + * * ECT(0) (ECN-Capable Transport(0)) + * * ECT(CE)(CE (Congestion Experienced)) + */ +#define RTE_IP_ECN_MASK (0x03) +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK + +/** Packet Option Masks */ +#define RTE_IP_DSCP_MASK (0xFC) /** Maximal IPv4 packet length (including a header) */ #define RTE_IPV4_MAX_PKT_LEN 65535 diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index 76f54e0e0..d0492928c 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * 1: In tunnel mode, enable outer header ECN Field copied from + * inner header in tunnel encapsulation, or inner header ECN + * field construction in decapsulation. + * * 0: Inner/outer header are not modified. + */ + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 2/2] examples/ipsec-secgw: support header reconstruction 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-06-25 13:43 ` Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang 2 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-25 13:43 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patch updates the ipsec-secgw application to support header reconstruction. In addition a series of tests have been added to prove the implementation's correctness. Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ 4 files changed, 487 insertions(+), 1 deletion(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py diff --git a/doc/guides/rel_notes/release_19_08.rst b/doc/guides/rel_notes/release_19_08.rst index 8c3932d06..393a69b68 100644 --- a/doc/guides/rel_notes/release_19_08.rst +++ b/doc/guides/rel_notes/release_19_08.rst @@ -88,6 +88,12 @@ New Features * Added multi-queue support to allow one af_xdp vdev with multiple netdev queues +* **Updated IPSec library Header Reconstruction.** + + Updated the IPSec library with ECN and DSCP field header reconstruction + feature followed by RFC4301. The IPSec-secgw sample application is also + updated to support this feature by default. + Removed Items ------------- diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index 7262ccee8..447f9dbb4 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (ss->flags == IP4_TUNNEL) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/examples/ipsec-secgw/test/run_test.sh b/examples/ipsec-secgw/test/run_test.sh index 4969effdb..3f73545c9 100755 --- a/examples/ipsec-secgw/test/run_test.sh +++ b/examples/ipsec-secgw/test/run_test.sh @@ -61,7 +61,8 @@ trs_3descbc_sha1_old \ trs_3descbc_sha1_esn \ trs_3descbc_sha1_esn_atom" -PKT_TESTS="trs_ipv6opts" +PKT_TESTS="trs_ipv6opts \ +tun_null_header_reconstruct" DIR=$(dirname $0) diff --git a/examples/ipsec-secgw/test/tun_null_header_reconstruct.py b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py new file mode 100755 index 000000000..f2653b351 --- /dev/null +++ b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 + +from scapy.all import * +import unittest +import pkttest + +#{ipv4{ipv4}} test +SRC_ADDR_IPV4_1 = "192.168.1.1" +DST_ADDR_IPV4_1 = "192.168.2.1" + +#{ipv6{ipv6}} test +SRC_ADDR_IPV6_1 = "1111:0000:0000:0000:0000:0000:0000:0001" +DST_ADDR_IPV6_1 = "2222:0000:0000:0000:0000:0000:0000:0001" + +#{ipv4{ipv6}} test +SRC_ADDR_IPV4_2 = "192.168.11.1" +DST_ADDR_IPV4_2 = "192.168.12.1" +SRC_ADDR_IPV6_2 = "1111:0000:0000:0000:0000:0000:0001:0001" +DST_ADDR_IPV6_2 = "2222:0000:0000:0000:0000:0000:0001:0001" + +#{ipv6{ipv4}} test +SRC_ADDR_IPV4_3 = "192.168.21.1" +DST_ADDR_IPV4_3 = "192.168.22.1" +SRC_ADDR_IPV6_3 = "1111:0000:0000:0000:0000:0001:0001:0001" +DST_ADDR_IPV6_3 = "2222:0000:0000:0000:0000:0001:0001:0001" + +def config(): + return """ +#outter-ipv4 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 5 pri 1 \\ +src {0}/32 \\ +dst {1}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 6 pri 1 \\ +src {1}/32 \\ +dst {0}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {0} dst {1} +sa in 6 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {1} dst {0} + +rt ipv4 dst {0}/32 port 1 +rt ipv4 dst {1}/32 port 0 + +#outter-ipv6 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 7 pri 1 \\ +src {2}/128 \\ +dst {3}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 8 pri 1 \\ +src {3}/128 \\ +dst {2}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 7 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {2} dst {3} +sa in 8 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {3} dst {2} + +rt ipv6 dst {2}/128 port 1 +rt ipv6 dst {3}/128 port 0 + +#outter-ipv4 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 9 pri 1 \\ +src {4}/128 \\ +dst {5}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 10 pri 1 \\ +src {5}/128 \\ +dst {4}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 9 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {6} dst {7} +sa in 10 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {7} dst {6} + +rt ipv6 dst {4}/128 port 1 +rt ipv4 dst {7}/32 port 0 + +#outter-ipv6 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 11 pri 1 \\ +src {8}/32 \\ +dst {9}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 12 pri 1 \\ +src {9}/32 \\ +dst {8}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 11 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {10} dst {11} +sa in 12 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {11} dst {10} + +rt ipv4 dst {8}/32 port 1 +rt ipv6 dst {11}/128 port 0 +""".format(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, SRC_ADDR_IPV4_2, DST_ADDR_IPV4_2, + SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, SRC_ADDR_IPV6_3, DST_ADDR_IPV6_3) + +ECN_ECT0 = 0x02 +ECN_ECT1 = 0x01 +ECN_CE = 0x03 +DSCP_1 = 0x04 +DSCP_3F = 0xFC + +class TestTunnelHeaderReconstruct(unittest.TestCase): + def setUp(self): + self.px = pkttest.PacketXfer() + th = IP(src=DST_ADDR_IPV4_1, dst=SRC_ADDR_IPV4_1) + self.sa_ipv4v4 = SecurityAssociation(ESP, spi=6, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_1, dst=SRC_ADDR_IPV6_1) + self.sa_ipv6v6 = SecurityAssociation(ESP, spi=8, tunnel_header = th) + + th = IP(src=DST_ADDR_IPV4_2, dst=SRC_ADDR_IPV4_2) + self.sa_ipv4v6 = SecurityAssociation(ESP, spi=10, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_3, dst=SRC_ADDR_IPV6_3) + self.sa_ipv6v4 = SecurityAssociation(ESP, spi=12, tunnel_header = th) + + def gen_pkt_plain_ipv4(self, src, dst, tos): + pkt = IP(src=src, dst=dst, tos=tos) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_plain_ipv6(self, src, dst, tc): + pkt = IPv6(src=src, dst=dst, tc=tc) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_tun_ipv4v4(self, tos_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_1, SRC_ADDR_IPV4_1, + tos_inner) + pkt = self.sa_ipv4v4.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 6) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v6(self, tc_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_1, SRC_ADDR_IPV6_1, + tc_inner) + pkt = self.sa_ipv6v6.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 8) + pkt[IPv6].tc = tc_outter + return pkt + + def gen_pkt_tun_ipv4v6(self, tos_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_2, SRC_ADDR_IPV6_2, + tc_inner) + pkt = self.sa_ipv4v6.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 10) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v4(self, tc_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_3, SRC_ADDR_IPV4_3, + tos_inner) + pkt = self.sa_ipv6v4.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 12) + pkt[IPv6].tc = tc_outter + return pkt + +#RFC4301 5.1.2.1 & 5.1.2.2, outbound packets shall be copied ECN field + def test_outb_ipv4v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_outb_ipv4v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + +#RFC4301 5.1.2.1 & 5.1.2.2, if outbound packets ECN is CE (0x3), inbound packets +#ECN is overwritten to CE, otherwise no change + +#Outter header not CE, Inner header should be no change + def test_inb_ipv4v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#Outter header CE, Inner header should be changed to CE + def test_inb_ipv4v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#RFC4301 5.1.2.1.5 Outer DS field should be copied from Inner DS field + def test_outb_ipv4v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_outb_ipv4v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + +#RFC4301 5.1.2.1.5 Inner DS field should not be affected by Outer DS field + def test_inb_ipv4v4_dscp(self): + pkt = self.gen_pkt_tun_ipv4v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_inb_ipv6v6_dscp(self): + pkt = self.gen_pkt_tun_ipv6v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv4v6_dscp(self): + pkt = self.gen_pkt_tun_ipv4v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv6v4_dscp(self): + pkt = self.gen_pkt_tun_ipv6v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + +pkttest.pkttest() -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP header reconstruction 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang @ 2019-06-26 15:05 ` Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction Fan Zhang ` (3 more replies) 2 siblings, 4 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-26 15:05 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patchset adds the ECN and DSCP tunnel mode header reconstruction support for rte_ipsec library. The ipsec-secgw sample application is updated with the feature's enabling and a python3 script for testing the correctness of the implementation. v3: - Rebased on top of latest dpdk-next-crypto. - Updated the library with individual header reconstruction function v2: - Fixed a few bugs. - Updated according to Konstantin's comments. - Added python script for testing. Fan Zhang (2): lib/ipsec: add support for header construction examples/ipsec-secgw: support header reconstruction doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ lib/librte_ipsec/esp_inb.c | 16 +- lib/librte_ipsec/esp_outb.c | 3 +- lib/librte_ipsec/iph.h | 148 ++++++- lib/librte_ipsec/rte_ipsec_sa.h | 25 ++ lib/librte_ipsec/sa.c | 17 + lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 11 + lib/librte_security/rte_security.h | 9 + 12 files changed, 708 insertions(+), 11 deletions(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang @ 2019-06-26 15:05 ` Fan Zhang 2019-06-26 22:15 ` Ananyev, Konstantin 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang ` (2 subsequent siblings) 3 siblings, 1 reply; 27+ messages in thread From: Fan Zhang @ 2019-06-26 15:05 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang, Marko Kovacevic Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- lib/librte_ipsec/esp_inb.c | 16 +++- lib/librte_ipsec/esp_outb.c | 3 +- lib/librte_ipsec/iph.h | 148 +++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/rte_ipsec_sa.h | 25 +++++++ lib/librte_ipsec/sa.c | 17 +++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 11 +++ lib/librte_security/rte_security.h | 9 +++ 8 files changed, 221 insertions(+), 10 deletions(-) diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index fb10b7085..3e1894e13 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -464,13 +464,15 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], uint32_t hl[num], to[num]; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; + const uint32_t cofs = sa->ctp.cipher.offset; + void *inner_h; + const void *outter_h; /* * remove icv, esp trailer and high-order * 32 bits of esn from packet length */ const uint32_t tlen = sa->icv_len + sizeof(espt[0]) + sqh_len; - const uint32_t cofs = sa->ctp.cipher.offset; /* * to minimize stalls due to load latency, @@ -489,9 +491,17 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl, sa->proto) == 0) { + outter_h = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, to[i], - tl, sqn + k); + + inner_h = tun_process_step2(mb[i], ml[i], hl[i], adj, + to[i], tl, sqn + k); + + if ((sa->type & TUN_HDR_MSK) != 0) + update_inb_tun_l3_hdr(sa, inner_h, outter_h); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index 8c6db3553..0c72a9d5f 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,7 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, + + update_outb_tun_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, mb->pkt_len, sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 62d78b7b1..1bde9daeb 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -5,14 +5,17 @@ #ifndef _IPH_H_ #define _IPH_H_ -#include <rte_ip.h> - /** * @file iph.h * Contains functions/structures/macros to manipulate IPv4/IPv6 headers * used internally by ipsec library. */ +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) +#define IPV6_ECN_CE IPV6_ECN_MASK + /* * Move preceding (L3) headers down to remove ESP header and IV. */ @@ -37,6 +40,26 @@ insert_esph(char *np, char *op, uint32_t hlen) np[i] = op[i]; } +static inline uint8_t +get_ipv6_tos(rte_be32_t vtc_flow) +{ + uint32_t v; + + v = rte_be_to_cpu_32(vtc_flow); + return v >> RTE_IPV6_HDR_TC_SHIFT; +} + +static inline rte_be32_t +set_ipv6_tos(rte_be32_t vtc_flow, uint32_t tos) +{ + uint32_t v; + + v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT); + vtc_flow &= ~rte_cpu_to_be_32(IPV6_TOS_MASK); + + return (v | vtc_flow); +} + /* update original ip header fields for transport case */ static inline int update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, @@ -101,23 +124,136 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, return rc; } +/** + * Update type-of-service/traffic-class field of inbound/outbound tunnel + * packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param tos_mask: type-of-service mask stored in sa. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + * @param is_inbound: 1 if it is a inbound packet, 0 if it is outbound. + */ +static inline void +update_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4, uint8_t is_inbound) +{ + uint8_t idx = ((is_inbound << 2) | (is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4out_h; + struct rte_ipv6_hdr *v6out_h; + struct rte_ipv4_hdr *v4in_h; + struct rte_ipv6_hdr *v6in_h; + uint32_t itp, otp; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + switch (idx) { + /* outbound */ + case 0: /*outh ipv6, inh ipv6 */ + v6out_h = update_h; + otp = get_ipv6_tos(v6out_h->vtc_flow) & ~tos_mask; + itp = get_ipv6_tos(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v6out_h->vtc_flow = set_ipv6_tos(v6out_h->vtc_flow, otp | itp); + break; + case 1: /*outh ipv6, inh ipv4 */ + v6out_h = update_h; + otp = get_ipv6_tos(v6out_h->vtc_flow) & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v6out_h->vtc_flow = set_ipv6_tos(v6out_h->vtc_flow, otp | itp); + break; + case 2: /*outh ipv4, inh ipv6 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = get_ipv6_tos(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + /* inbound */ + case 4: /* outh ipv6, inh ipv6 */ + v6in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v6in != 0)) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 5: /* outh ipv6, inh ipv4 */ + v4in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v4in != 0)) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + case 6: /* outh ipv4, inh ipv6 */ + v6in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 7: /* outh ipv4, inh ipv4 */ + v4in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + } +} + + /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_outb_tun_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct rte_ipv4_hdr *v4h; struct rte_ipv6_hdr *v6h; + uint8_t is_out_ipv4; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + is_out_ipv4 = 1; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); } else { - v6h = p; + is_out_ipv4 = 0; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); } + + if (sa->type & TUN_HDR_MSK) + update_tun_tos(inh, outh, sa->tos_mask, is_out_ipv4, + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4), 0); +} + +static inline void +update_inb_tun_l3_hdr(const struct rte_ipsec_sa *sa, void *ip_inner, + const void *ip_outter) +{ + update_tun_tos(ip_outter, ip_inner, sa->tos_mask, + ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0), + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4), + 1); } #endif /* _IPH_H_ */ diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index fd9b3ed60..8f179ee9d 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,11 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, + RTE_SATP_LOG2_TTL, + RTE_SATP_LOG2_DF, + RTE_SATP_LOG2_FLABEL, RTE_SATP_LOG2_NUM }; @@ -123,6 +128,26 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + +#define RTE_IPSEC_SATP_TTL_MASK (1ULL << RTE_SATP_LOG2_TTL) +#define RTE_IPSEC_SATP_TTL_DISABLE (0ULL << RTE_SATP_LOG2_TTL) +#define RTE_IPSEC_SATP_TTL_ENABLE (1ULL << RTE_SATP_LOG2_TTL) + +#define RTE_IPSEC_SATP_DF_MASK (1ULL << RTE_SATP_LOG2_DF) +#define RTE_IPSEC_SATP_DF_DISABLE (0ULL << RTE_SATP_LOG2_DF) +#define RTE_IPSEC_SATP_DF_ENABLE (1ULL << RTE_SATP_LOG2_DF) + +#define RTE_IPSEC_SATP_FLABEL_MASK (1ULL << RTE_SATP_LOG2_FLABEL) +#define RTE_IPSEC_SATP_FLABEL_DISABLE (0ULL << RTE_SATP_LOG2_FLABEL) +#define RTE_IPSEC_SATP_FLABEL_ENABLE (1ULL << RTE_SATP_LOG2_FLABEL) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index 087de958a..61d817dfc 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -220,6 +220,17 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_SQN_RAW; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + *type = tp; return 0; } @@ -310,6 +321,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= RTE_IP_ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= RTE_IP_DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index 20c0a65c0..51e69ad05 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index c2c67b85d..85c53e8d9 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -46,6 +46,17 @@ struct rte_ipv4_hdr { (((b) & 0xff) << 16) | \ (((c) & 0xff) << 8) | \ ((d) & 0xff)) +/** + * RFC 3168 Explicit Congestion Notification (ECN) + * * ECT(1) (ECN-Capable Transport(1)) + * * ECT(0) (ECN-Capable Transport(0)) + * * ECT(CE)(CE (Congestion Experienced)) + */ +#define RTE_IP_ECN_MASK (0x03) +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK + +/** Packet Option Masks */ +#define RTE_IP_DSCP_MASK (0xFC) /** Maximal IPv4 packet length (including a header) */ #define RTE_IPV4_MAX_PKT_LEN 65535 diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index 76f54e0e0..d0492928c 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * 1: In tunnel mode, enable outer header ECN Field copied from + * inner header in tunnel encapsulation, or inner header ECN + * field construction in decapsulation. + * * 0: Inner/outer header are not modified. + */ + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-06-26 22:15 ` Ananyev, Konstantin 0 siblings, 0 replies; 27+ messages in thread From: Ananyev, Konstantin @ 2019-06-26 22:15 UTC (permalink / raw) To: Zhang, Roy Fan, dev; +Cc: akhil.goyal, Kovacevic, Marko Hi Fan, > -----Original Message----- > From: Zhang, Roy Fan > Sent: Wednesday, June 26, 2019 4:05 PM > To: dev@dpdk.org > Cc: akhil.goyal@nxp.com; Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Roy Fan <roy.fan.zhang@intel.com>; Kovacevic, > Marko <marko.kovacevic@intel.com> > Subject: [PATCH v3 1/2] lib/ipsec: add support for header construction > > Add support for RFC 4301(5.1.2) to update of > Type of service field and Traffic class field > bits inside ipv4/ipv6 packets for outbound cases > and inbound cases which deals with the update of > the DSCP/ENC bits inside each of the fields. > This series cause all tunnel _esn_ testcases for non-AEAD algorithms (tun_aescbc_sha1_esn, tun_3descbc_sha1_esn, ...) to fail - ping can't go through. Both ipv4 and ipv6. Could you have a look? Thanks Konstantin > Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> > Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> > --- > lib/librte_ipsec/esp_inb.c | 16 +++- > lib/librte_ipsec/esp_outb.c | 3 +- > lib/librte_ipsec/iph.h | 148 +++++++++++++++++++++++++++++++++++-- > lib/librte_ipsec/rte_ipsec_sa.h | 25 +++++++ > lib/librte_ipsec/sa.c | 17 +++++ > lib/librte_ipsec/sa.h | 2 + > lib/librte_net/rte_ip.h | 11 +++ > lib/librte_security/rte_security.h | 9 +++ > 8 files changed, 221 insertions(+), 10 deletions(-) > > diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c > index fb10b7085..3e1894e13 100644 > --- a/lib/librte_ipsec/esp_inb.c > +++ b/lib/librte_ipsec/esp_inb.c > @@ -464,13 +464,15 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], > uint32_t hl[num], to[num]; > struct esp_tail espt[num]; > struct rte_mbuf *ml[num]; > + const uint32_t cofs = sa->ctp.cipher.offset; > + void *inner_h; > + const void *outter_h; > > /* > * remove icv, esp trailer and high-order > * 32 bits of esn from packet length > */ > const uint32_t tlen = sa->icv_len + sizeof(espt[0]) + sqh_len; > - const uint32_t cofs = sa->ctp.cipher.offset; > > /* > * to minimize stalls due to load latency, > @@ -489,9 +491,17 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], > if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl, > sa->proto) == 0) { > > + outter_h = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, > + mb[i]->l2_len); > + > /* modify packet's layout */ > - tun_process_step2(mb[i], ml[i], hl[i], adj, to[i], > - tl, sqn + k); > + > + inner_h = tun_process_step2(mb[i], ml[i], hl[i], adj, > + to[i], tl, sqn + k); > + > + if ((sa->type & TUN_HDR_MSK) != 0) > + update_inb_tun_l3_hdr(sa, inner_h, outter_h); > + > /* update mbuf's metadata */ > tun_process_step3(mb[i], sa->tx_offload.msk, > sa->tx_offload.val); > diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c > index 8c6db3553..0c72a9d5f 100644 > --- a/lib/librte_ipsec/esp_outb.c > +++ b/lib/librte_ipsec/esp_outb.c > @@ -152,7 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, > rte_memcpy(ph, sa->hdr, sa->hdr_len); > > /* update original and new ip header fields */ > - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, > + > + update_outb_tun_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, mb->pkt_len, > sa->hdr_l3_off, sqn_low16(sqc)); > > /* update spi, seqn and iv */ > diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h > index 62d78b7b1..1bde9daeb 100644 > --- a/lib/librte_ipsec/iph.h > +++ b/lib/librte_ipsec/iph.h > @@ -5,14 +5,17 @@ > #ifndef _IPH_H_ > #define _IPH_H_ > > -#include <rte_ip.h> > - > /** > * @file iph.h > * Contains functions/structures/macros to manipulate IPv4/IPv6 headers > * used internally by ipsec library. > */ > > +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) > +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) > +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) > +#define IPV6_ECN_CE IPV6_ECN_MASK > + > /* > * Move preceding (L3) headers down to remove ESP header and IV. > */ > @@ -37,6 +40,26 @@ insert_esph(char *np, char *op, uint32_t hlen) > np[i] = op[i]; > } > > +static inline uint8_t > +get_ipv6_tos(rte_be32_t vtc_flow) > +{ > + uint32_t v; > + > + v = rte_be_to_cpu_32(vtc_flow); > + return v >> RTE_IPV6_HDR_TC_SHIFT; > +} > + > +static inline rte_be32_t > +set_ipv6_tos(rte_be32_t vtc_flow, uint32_t tos) > +{ > + uint32_t v; > + > + v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT); > + vtc_flow &= ~rte_cpu_to_be_32(IPV6_TOS_MASK); > + > + return (v | vtc_flow); > +} > + > /* update original ip header fields for transport case */ > static inline int > update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > @@ -101,23 +124,136 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > return rc; > } > > +/** > + * Update type-of-service/traffic-class field of inbound/outbound tunnel > + * packet. > + * > + * @param ref_h: reference header, for outbound it is inner header, otherwise > + * outer header. > + * @param update_h: header to be updated tos/tc field, for outbound it is outer > + * header, otherwise inner header. > + * @param tos_mask: type-of-service mask stored in sa. > + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. > + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. > + * @param is_inbound: 1 if it is a inbound packet, 0 if it is outbound. > + */ > +static inline void > +update_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, > + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4, uint8_t is_inbound) > +{ > + uint8_t idx = ((is_inbound << 2) | (is_outh_ipv4 << 1) | is_inh_ipv4); > + struct rte_ipv4_hdr *v4out_h; > + struct rte_ipv6_hdr *v6out_h; > + struct rte_ipv4_hdr *v4in_h; > + struct rte_ipv6_hdr *v6in_h; > + uint32_t itp, otp; > + uint8_t ecn_v4out, ecn_v4in; > + uint32_t ecn_v6out, ecn_v6in; > + > + switch (idx) { > + /* outbound */ > + case 0: /*outh ipv6, inh ipv6 */ > + v6out_h = update_h; > + otp = get_ipv6_tos(v6out_h->vtc_flow) & ~tos_mask; > + itp = get_ipv6_tos(((const struct rte_ipv6_hdr *)ref_h)-> > + vtc_flow) & tos_mask; > + v6out_h->vtc_flow = set_ipv6_tos(v6out_h->vtc_flow, otp | itp); > + break; > + case 1: /*outh ipv6, inh ipv4 */ > + v6out_h = update_h; > + otp = get_ipv6_tos(v6out_h->vtc_flow) & ~tos_mask; > + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & > + tos_mask; > + v6out_h->vtc_flow = set_ipv6_tos(v6out_h->vtc_flow, otp | itp); > + break; > + case 2: /*outh ipv4, inh ipv6 */ > + v4out_h = update_h; > + otp = v4out_h->type_of_service & ~tos_mask; > + itp = get_ipv6_tos(((const struct rte_ipv6_hdr *)ref_h)-> > + vtc_flow) & tos_mask; > + v4out_h->type_of_service = (otp | itp); > + break; > + case 3: /* outh ipv4, inh ipv4 */ > + v4out_h = update_h; > + otp = v4out_h->type_of_service & ~tos_mask; > + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & > + tos_mask; > + v4out_h->type_of_service = (otp | itp); > + break; > + /* inbound */ > + case 4: /* outh ipv6, inh ipv6 */ > + v6in_h = update_h; > + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); > + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && > + (ecn_v6in != 0)) > + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); > + break; > + case 5: /* outh ipv6, inh ipv4 */ > + v4in_h = update_h; > + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; > + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && > + (ecn_v4in != 0)) > + v4in_h->type_of_service |= RTE_IP_ECN_CE; > + break; > + case 6: /* outh ipv4, inh ipv6 */ > + v6in_h = update_h; > + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> > + type_of_service & RTE_IP_ECN_MASK; > + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); > + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) > + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); > + break; > + case 7: /* outh ipv4, inh ipv4 */ > + v4in_h = update_h; > + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> > + type_of_service & RTE_IP_ECN_MASK; > + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; > + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) > + v4in_h->type_of_service |= RTE_IP_ECN_CE; > + break; > + } > +} > + > + > /* update original and new ip header fields for tunnel case */ > static inline void > -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > - uint32_t l2len, rte_be16_t pid) > +update_outb_tun_l3hdr(const struct rte_ipsec_sa *sa, void *outh, > + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) > { > struct rte_ipv4_hdr *v4h; > struct rte_ipv6_hdr *v6h; > + uint8_t is_out_ipv4; > > if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { > - v4h = p; > + is_out_ipv4 = 1; > + v4h = outh; > v4h->packet_id = pid; > v4h->total_length = rte_cpu_to_be_16(plen - l2len); > } else { > - v6h = p; > + is_out_ipv4 = 0; > + v6h = outh; > v6h->payload_len = rte_cpu_to_be_16(plen - l2len - > sizeof(*v6h)); > } > + > + if (sa->type & TUN_HDR_MSK) > + update_tun_tos(inh, outh, sa->tos_mask, is_out_ipv4, > + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == > + RTE_IPSEC_SATP_IPV4), 0); > +} > + > +static inline void > +update_inb_tun_l3_hdr(const struct rte_ipsec_sa *sa, void *ip_inner, > + const void *ip_outter) > +{ > + update_tun_tos(ip_outter, ip_inner, sa->tos_mask, > + ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0), > + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4), > + 1); > } > > #endif /* _IPH_H_ */ > diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h > index fd9b3ed60..8f179ee9d 100644 > --- a/lib/librte_ipsec/rte_ipsec_sa.h > +++ b/lib/librte_ipsec/rte_ipsec_sa.h > @@ -95,6 +95,11 @@ enum { > RTE_SATP_LOG2_MODE, > RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, > RTE_SATP_LOG2_ESN, > + RTE_SATP_LOG2_ECN, > + RTE_SATP_LOG2_DSCP, > + RTE_SATP_LOG2_TTL, > + RTE_SATP_LOG2_DF, > + RTE_SATP_LOG2_FLABEL, > RTE_SATP_LOG2_NUM > }; > > @@ -123,6 +128,26 @@ enum { > #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) > #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) > > +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) > +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) > +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) > + > +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) > +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) > +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) > + > +#define RTE_IPSEC_SATP_TTL_MASK (1ULL << RTE_SATP_LOG2_TTL) > +#define RTE_IPSEC_SATP_TTL_DISABLE (0ULL << RTE_SATP_LOG2_TTL) > +#define RTE_IPSEC_SATP_TTL_ENABLE (1ULL << RTE_SATP_LOG2_TTL) > + > +#define RTE_IPSEC_SATP_DF_MASK (1ULL << RTE_SATP_LOG2_DF) > +#define RTE_IPSEC_SATP_DF_DISABLE (0ULL << RTE_SATP_LOG2_DF) > +#define RTE_IPSEC_SATP_DF_ENABLE (1ULL << RTE_SATP_LOG2_DF) > + > +#define RTE_IPSEC_SATP_FLABEL_MASK (1ULL << RTE_SATP_LOG2_FLABEL) > +#define RTE_IPSEC_SATP_FLABEL_DISABLE (0ULL << RTE_SATP_LOG2_FLABEL) > +#define RTE_IPSEC_SATP_FLABEL_ENABLE (1ULL << RTE_SATP_LOG2_FLABEL) > + > /** > * get type of given SA > * @return > diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c > index 087de958a..61d817dfc 100644 > --- a/lib/librte_ipsec/sa.c > +++ b/lib/librte_ipsec/sa.c > @@ -220,6 +220,17 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) > else > tp |= RTE_IPSEC_SATP_SQN_RAW; > > + /* check for ECN flag */ > + if (prm->ipsec_xform.options.ecn == 0) > + tp |= RTE_IPSEC_SATP_ECN_DISABLE; > + else > + tp |= RTE_IPSEC_SATP_ECN_ENABLE; > + /* check for DSCP flag */ > + if (prm->ipsec_xform.options.copy_dscp == 0) > + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; > + else > + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; > + > *type = tp; > return 0; > } > @@ -310,6 +321,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, > static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | > RTE_IPSEC_SATP_MODE_MASK; > > + if (prm->ipsec_xform.options.ecn) > + sa->tos_mask |= RTE_IP_ECN_MASK; > + > + if (prm->ipsec_xform.options.copy_dscp) > + sa->tos_mask |= RTE_IP_DSCP_MASK; > + > if (cxf->aead != NULL) { > switch (cxf->aead->algo) { > case RTE_CRYPTO_AEAD_AES_GCM: > diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h > index 20c0a65c0..51e69ad05 100644 > --- a/lib/librte_ipsec/sa.h > +++ b/lib/librte_ipsec/sa.h > @@ -10,6 +10,7 @@ > #define IPSEC_MAX_HDR_SIZE 64 > #define IPSEC_MAX_IV_SIZE 16 > #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) > +#define TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) > > /* padding alignment for different algorithms */ > enum { > @@ -103,6 +104,7 @@ struct rte_ipsec_sa { > uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ > uint8_t iv_len; > uint8_t pad_align; > + uint8_t tos_mask; > > /* template for tunnel header */ > uint8_t hdr[IPSEC_MAX_HDR_SIZE]; > diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h > index c2c67b85d..85c53e8d9 100644 > --- a/lib/librte_net/rte_ip.h > +++ b/lib/librte_net/rte_ip.h > @@ -46,6 +46,17 @@ struct rte_ipv4_hdr { > (((b) & 0xff) << 16) | \ > (((c) & 0xff) << 8) | \ > ((d) & 0xff)) > +/** > + * RFC 3168 Explicit Congestion Notification (ECN) > + * * ECT(1) (ECN-Capable Transport(1)) > + * * ECT(0) (ECN-Capable Transport(0)) > + * * ECT(CE)(CE (Congestion Experienced)) > + */ > +#define RTE_IP_ECN_MASK (0x03) > +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK > + > +/** Packet Option Masks */ > +#define RTE_IP_DSCP_MASK (0xFC) > > /** Maximal IPv4 packet length (including a header) */ > #define RTE_IPV4_MAX_PKT_LEN 65535 > diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h > index 76f54e0e0..d0492928c 100644 > --- a/lib/librte_security/rte_security.h > +++ b/lib/librte_security/rte_security.h > @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { > * * 0: Inner packet is not modified. > */ > uint32_t dec_ttl : 1; > + > + /**< Explicit Congestion Notification (ECN) > + * > + * * 1: In tunnel mode, enable outer header ECN Field copied from > + * inner header in tunnel encapsulation, or inner header ECN > + * field construction in decapsulation. > + * * 0: Inner/outer header are not modified. > + */ > + uint32_t ecn : 1; > }; > > /** IPSec security association direction */ > -- > 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 2/2] examples/ipsec-secgw: support header reconstruction 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-06-26 15:05 ` Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang 3 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-26 15:05 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patch updates the ipsec-secgw application to support header reconstruction. In addition a series of tests have been added to prove the implementation's correctness. Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ 4 files changed, 487 insertions(+), 1 deletion(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py diff --git a/doc/guides/rel_notes/release_19_08.rst b/doc/guides/rel_notes/release_19_08.rst index 7c0435a43..d949dbcfb 100644 --- a/doc/guides/rel_notes/release_19_08.rst +++ b/doc/guides/rel_notes/release_19_08.rst @@ -99,6 +99,12 @@ New Features Updated ``librte_telemetry`` to fetch the global metrics from the ``librte_metrics`` library. +* **Updated IPSec library Header Reconstruction.** + + Updated the IPSec library with ECN and DSCP field header reconstruction + feature followed by RFC4301. The IPSec-secgw sample application is also + updated to support this feature by default. + Removed Items ------------- diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index 7262ccee8..447f9dbb4 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (ss->flags == IP4_TUNNEL) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/examples/ipsec-secgw/test/run_test.sh b/examples/ipsec-secgw/test/run_test.sh index 4969effdb..3f73545c9 100755 --- a/examples/ipsec-secgw/test/run_test.sh +++ b/examples/ipsec-secgw/test/run_test.sh @@ -61,7 +61,8 @@ trs_3descbc_sha1_old \ trs_3descbc_sha1_esn \ trs_3descbc_sha1_esn_atom" -PKT_TESTS="trs_ipv6opts" +PKT_TESTS="trs_ipv6opts \ +tun_null_header_reconstruct" DIR=$(dirname $0) diff --git a/examples/ipsec-secgw/test/tun_null_header_reconstruct.py b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py new file mode 100755 index 000000000..f2653b351 --- /dev/null +++ b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 + +from scapy.all import * +import unittest +import pkttest + +#{ipv4{ipv4}} test +SRC_ADDR_IPV4_1 = "192.168.1.1" +DST_ADDR_IPV4_1 = "192.168.2.1" + +#{ipv6{ipv6}} test +SRC_ADDR_IPV6_1 = "1111:0000:0000:0000:0000:0000:0000:0001" +DST_ADDR_IPV6_1 = "2222:0000:0000:0000:0000:0000:0000:0001" + +#{ipv4{ipv6}} test +SRC_ADDR_IPV4_2 = "192.168.11.1" +DST_ADDR_IPV4_2 = "192.168.12.1" +SRC_ADDR_IPV6_2 = "1111:0000:0000:0000:0000:0000:0001:0001" +DST_ADDR_IPV6_2 = "2222:0000:0000:0000:0000:0000:0001:0001" + +#{ipv6{ipv4}} test +SRC_ADDR_IPV4_3 = "192.168.21.1" +DST_ADDR_IPV4_3 = "192.168.22.1" +SRC_ADDR_IPV6_3 = "1111:0000:0000:0000:0000:0001:0001:0001" +DST_ADDR_IPV6_3 = "2222:0000:0000:0000:0000:0001:0001:0001" + +def config(): + return """ +#outter-ipv4 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 5 pri 1 \\ +src {0}/32 \\ +dst {1}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 6 pri 1 \\ +src {1}/32 \\ +dst {0}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {0} dst {1} +sa in 6 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {1} dst {0} + +rt ipv4 dst {0}/32 port 1 +rt ipv4 dst {1}/32 port 0 + +#outter-ipv6 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 7 pri 1 \\ +src {2}/128 \\ +dst {3}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 8 pri 1 \\ +src {3}/128 \\ +dst {2}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 7 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {2} dst {3} +sa in 8 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {3} dst {2} + +rt ipv6 dst {2}/128 port 1 +rt ipv6 dst {3}/128 port 0 + +#outter-ipv4 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 9 pri 1 \\ +src {4}/128 \\ +dst {5}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 10 pri 1 \\ +src {5}/128 \\ +dst {4}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 9 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {6} dst {7} +sa in 10 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {7} dst {6} + +rt ipv6 dst {4}/128 port 1 +rt ipv4 dst {7}/32 port 0 + +#outter-ipv6 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 11 pri 1 \\ +src {8}/32 \\ +dst {9}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 12 pri 1 \\ +src {9}/32 \\ +dst {8}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 11 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {10} dst {11} +sa in 12 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {11} dst {10} + +rt ipv4 dst {8}/32 port 1 +rt ipv6 dst {11}/128 port 0 +""".format(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, SRC_ADDR_IPV4_2, DST_ADDR_IPV4_2, + SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, SRC_ADDR_IPV6_3, DST_ADDR_IPV6_3) + +ECN_ECT0 = 0x02 +ECN_ECT1 = 0x01 +ECN_CE = 0x03 +DSCP_1 = 0x04 +DSCP_3F = 0xFC + +class TestTunnelHeaderReconstruct(unittest.TestCase): + def setUp(self): + self.px = pkttest.PacketXfer() + th = IP(src=DST_ADDR_IPV4_1, dst=SRC_ADDR_IPV4_1) + self.sa_ipv4v4 = SecurityAssociation(ESP, spi=6, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_1, dst=SRC_ADDR_IPV6_1) + self.sa_ipv6v6 = SecurityAssociation(ESP, spi=8, tunnel_header = th) + + th = IP(src=DST_ADDR_IPV4_2, dst=SRC_ADDR_IPV4_2) + self.sa_ipv4v6 = SecurityAssociation(ESP, spi=10, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_3, dst=SRC_ADDR_IPV6_3) + self.sa_ipv6v4 = SecurityAssociation(ESP, spi=12, tunnel_header = th) + + def gen_pkt_plain_ipv4(self, src, dst, tos): + pkt = IP(src=src, dst=dst, tos=tos) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_plain_ipv6(self, src, dst, tc): + pkt = IPv6(src=src, dst=dst, tc=tc) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_tun_ipv4v4(self, tos_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_1, SRC_ADDR_IPV4_1, + tos_inner) + pkt = self.sa_ipv4v4.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 6) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v6(self, tc_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_1, SRC_ADDR_IPV6_1, + tc_inner) + pkt = self.sa_ipv6v6.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 8) + pkt[IPv6].tc = tc_outter + return pkt + + def gen_pkt_tun_ipv4v6(self, tos_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_2, SRC_ADDR_IPV6_2, + tc_inner) + pkt = self.sa_ipv4v6.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 10) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v4(self, tc_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_3, SRC_ADDR_IPV4_3, + tos_inner) + pkt = self.sa_ipv6v4.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 12) + pkt[IPv6].tc = tc_outter + return pkt + +#RFC4301 5.1.2.1 & 5.1.2.2, outbound packets shall be copied ECN field + def test_outb_ipv4v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_outb_ipv4v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + +#RFC4301 5.1.2.1 & 5.1.2.2, if outbound packets ECN is CE (0x3), inbound packets +#ECN is overwritten to CE, otherwise no change + +#Outter header not CE, Inner header should be no change + def test_inb_ipv4v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#Outter header CE, Inner header should be changed to CE + def test_inb_ipv4v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#RFC4301 5.1.2.1.5 Outer DS field should be copied from Inner DS field + def test_outb_ipv4v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_outb_ipv4v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + +#RFC4301 5.1.2.1.5 Inner DS field should not be affected by Outer DS field + def test_inb_ipv4v4_dscp(self): + pkt = self.gen_pkt_tun_ipv4v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_inb_ipv6v6_dscp(self): + pkt = self.gen_pkt_tun_ipv6v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv4v6_dscp(self): + pkt = self.gen_pkt_tun_ipv4v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv6v4_dscp(self): + pkt = self.gen_pkt_tun_ipv6v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + +pkttest.pkttest() -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP header reconstruction 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang @ 2019-06-28 12:39 ` Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 1/2] lib/ipsec: add support for header construction Fan Zhang ` (2 more replies) 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang 3 siblings, 3 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-28 12:39 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patchset adds the ECN and DSCP tunnel mode header reconstruction support for rte_ipsec library. The ipsec-secgw sample application is updated with the feature's enabling and a python3 script for testing the correctness of the implementation. v4: - Fixed a bug. - Refrabricated the code a bit. v3: - Rebased on top of latest dpdk-next-crypto. - Updated the library with individual header reconstruction function. v2: - Fixed a few bugs. - Updated according to Konstantin's comments. - Added python script for testing. Fan Zhang (2): lib/ipsec: add support for header construction examples/ipsec-secgw: support header reconstruction doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ lib/librte_ipsec/esp_inb.c | 13 +- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 139 +++++- lib/librte_ipsec/rte_ipsec_sa.h | 10 + lib/librte_ipsec/sa.c | 18 + lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 12 + lib/librte_security/rte_security.h | 9 + 12 files changed, 686 insertions(+), 9 deletions(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v4 1/2] lib/ipsec: add support for header construction 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP " Fan Zhang @ 2019-06-28 12:39 ` Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 0/2] ipsec: ECN and DSCP " Fan Zhang 2 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-28 12:39 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang, Marko Kovacevic Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- lib/librte_ipsec/esp_inb.c | 13 +++- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 139 +++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/rte_ipsec_sa.h | 10 +++ lib/librte_ipsec/sa.c | 18 +++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 12 ++++ lib/librte_security/rte_security.h | 9 +++ 8 files changed, 199 insertions(+), 8 deletions(-) diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index fb10b7085..8e3ecbc64 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -464,6 +464,8 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], uint32_t hl[num], to[num]; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; + const void *outh; + void *inh; /* * remove icv, esp trailer and high-order @@ -489,9 +491,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl, sa->proto) == 0) { + outh = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, to[i], - tl, sqn + k); + inh = tun_process_step2(mb[i], ml[i], hl[i], adj, + to[i], tl, sqn + k); + + /* update inner ip header */ + update_tun_inb_l3hdr(sa, outh, inh); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index 8c6db3553..55799a867 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, - sa->hdr_l3_off, sqn_low16(sqc)); + update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, + mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ esph = (struct rte_esp_hdr *)(ph + sa->hdr_len); diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 62d78b7b1..e6a134ff8 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -101,23 +101,154 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, return rc; } +/* + * The masks for ipv6 header reconstruction (RFC4301) + */ +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) +#define IPV6_ECN_CE IPV6_ECN_MASK + +/* + * The macros to get and set traffic class (TC) for ipv6 packets + */ +#define GET_IPV6_TC(vtc_flow) \ + (uint32_t)((rte_be_to_cpu_32(vtc_flow)) >> RTE_IPV6_HDR_TC_SHIFT) + +#define SET_IPV6_TC(vtc_flow, tc) \ + vtc_flow = rte_cpu_to_be_32(tc << RTE_IPV6_HDR_TC_SHIFT) | \ + (vtc_flow & (~rte_cpu_to_be_32(IPV6_TOS_MASK))) \ + +/** + * Update type-of-service/traffic-class field of inbound/outbound tunnel + * packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param tos_mask: type-of-service mask stored in sa. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + * @param is_inbound: 1 if it is a inbound packet, 0 if it is outbound. + */ +static inline void +update_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4, uint8_t is_inbound) +{ + uint8_t idx = ((is_inbound << 2) | (is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4out_h; + struct rte_ipv6_hdr *v6out_h; + struct rte_ipv4_hdr *v4in_h; + struct rte_ipv6_hdr *v6in_h; + uint32_t itp, otp; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + switch (idx) { + /* outbound */ + case 0: /*outh ipv6, inh ipv6 */ + v6out_h = update_h; + otp = GET_IPV6_TC(v6out_h->vtc_flow) & ~tos_mask; + itp = GET_IPV6_TC(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + SET_IPV6_TC(v6out_h->vtc_flow, (otp | itp)); + break; + case 1: /*outh ipv6, inh ipv4 */ + v6out_h = update_h; + otp = GET_IPV6_TC(v6out_h->vtc_flow) & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + SET_IPV6_TC(v6out_h->vtc_flow, (otp | itp)); + break; + case 2: /*outh ipv4, inh ipv6 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = GET_IPV6_TC(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + /* inbound */ + case 4: /* outh ipv6, inh ipv6 */ + v6in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v6in != 0)) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 5: /* outh ipv6, inh ipv4 */ + v4in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v4in != 0)) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + case 6: /* outh ipv4, inh ipv6 */ + v6in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 7: /* outh ipv4, inh ipv4 */ + v4in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + } +} + /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_tun_outb_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct rte_ipv4_hdr *v4h; struct rte_ipv6_hdr *v6h; + uint8_t is_outh_ipv4; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + is_outh_ipv4 = 1; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); } else { - v6h = p; + is_outh_ipv4 = 0; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); } + + if (sa->type & TUN_HDR_MSK) + update_tun_tos(inh, outh, sa->tos_mask, is_outh_ipv4, + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4), 0); +} + +static inline void +update_tun_inb_l3hdr(const struct rte_ipsec_sa *sa, const void *outh, + void *inh) +{ + if (sa->type & TUN_HDR_MSK) + update_tun_tos(outh, inh, sa->tos_mask, + ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0), + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4), 1); } #endif /* _IPH_H_ */ diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index fd9b3ed60..a71b55f68 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,8 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, RTE_SATP_LOG2_NUM }; @@ -123,6 +125,14 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index 087de958a..4dec9c37d 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -214,6 +214,18 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_ESN_ENABLE; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + /* interpret flags */ if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM) tp |= RTE_IPSEC_SATP_SQN_ATOM; @@ -310,6 +322,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= RTE_IP_ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= RTE_IP_DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index 20c0a65c0..51e69ad05 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index c2c67b85d..2e5790691 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -70,6 +70,18 @@ struct rte_ipv4_hdr { #define RTE_IPV4_HDR_OFFSET_UNITS 8 +/** + * RFC 3168 Explicit Congestion Notification (ECN) + * * ECT(1) (ECN-Capable Transport(1)) + * * ECT(0) (ECN-Capable Transport(0)) + * * ECT(CE)(CE (Congestion Experienced)) + */ +#define RTE_IP_ECN_MASK (0x03) +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK + +/** Packet Option Masks */ +#define RTE_IP_DSCP_MASK (0xFC) + /* * IPv4 address types */ diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index 76f54e0e0..d0492928c 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * 1: In tunnel mode, enable outer header ECN Field copied from + * inner header in tunnel encapsulation, or inner header ECN + * field construction in decapsulation. + * * 0: Inner/outer header are not modified. + */ + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v4 2/2] examples/ipsec-secgw: support header reconstruction 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-06-28 12:39 ` Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 0/2] ipsec: ECN and DSCP " Fan Zhang 2 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-28 12:39 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patch updates the ipsec-secgw application to support header reconstruction. In addition a series of tests have been added to prove the implementation's correctness. Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ 4 files changed, 487 insertions(+), 1 deletion(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py diff --git a/doc/guides/rel_notes/release_19_08.rst b/doc/guides/rel_notes/release_19_08.rst index 7c0435a43..d949dbcfb 100644 --- a/doc/guides/rel_notes/release_19_08.rst +++ b/doc/guides/rel_notes/release_19_08.rst @@ -99,6 +99,12 @@ New Features Updated ``librte_telemetry`` to fetch the global metrics from the ``librte_metrics`` library. +* **Updated IPSec library Header Reconstruction.** + + Updated the IPSec library with ECN and DSCP field header reconstruction + feature followed by RFC4301. The IPSec-secgw sample application is also + updated to support this feature by default. + Removed Items ------------- diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index 7262ccee8..447f9dbb4 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (ss->flags == IP4_TUNNEL) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/examples/ipsec-secgw/test/run_test.sh b/examples/ipsec-secgw/test/run_test.sh index 4969effdb..3f73545c9 100755 --- a/examples/ipsec-secgw/test/run_test.sh +++ b/examples/ipsec-secgw/test/run_test.sh @@ -61,7 +61,8 @@ trs_3descbc_sha1_old \ trs_3descbc_sha1_esn \ trs_3descbc_sha1_esn_atom" -PKT_TESTS="trs_ipv6opts" +PKT_TESTS="trs_ipv6opts \ +tun_null_header_reconstruct" DIR=$(dirname $0) diff --git a/examples/ipsec-secgw/test/tun_null_header_reconstruct.py b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py new file mode 100755 index 000000000..f2653b351 --- /dev/null +++ b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 + +from scapy.all import * +import unittest +import pkttest + +#{ipv4{ipv4}} test +SRC_ADDR_IPV4_1 = "192.168.1.1" +DST_ADDR_IPV4_1 = "192.168.2.1" + +#{ipv6{ipv6}} test +SRC_ADDR_IPV6_1 = "1111:0000:0000:0000:0000:0000:0000:0001" +DST_ADDR_IPV6_1 = "2222:0000:0000:0000:0000:0000:0000:0001" + +#{ipv4{ipv6}} test +SRC_ADDR_IPV4_2 = "192.168.11.1" +DST_ADDR_IPV4_2 = "192.168.12.1" +SRC_ADDR_IPV6_2 = "1111:0000:0000:0000:0000:0000:0001:0001" +DST_ADDR_IPV6_2 = "2222:0000:0000:0000:0000:0000:0001:0001" + +#{ipv6{ipv4}} test +SRC_ADDR_IPV4_3 = "192.168.21.1" +DST_ADDR_IPV4_3 = "192.168.22.1" +SRC_ADDR_IPV6_3 = "1111:0000:0000:0000:0000:0001:0001:0001" +DST_ADDR_IPV6_3 = "2222:0000:0000:0000:0000:0001:0001:0001" + +def config(): + return """ +#outter-ipv4 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 5 pri 1 \\ +src {0}/32 \\ +dst {1}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 6 pri 1 \\ +src {1}/32 \\ +dst {0}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {0} dst {1} +sa in 6 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {1} dst {0} + +rt ipv4 dst {0}/32 port 1 +rt ipv4 dst {1}/32 port 0 + +#outter-ipv6 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 7 pri 1 \\ +src {2}/128 \\ +dst {3}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 8 pri 1 \\ +src {3}/128 \\ +dst {2}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 7 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {2} dst {3} +sa in 8 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {3} dst {2} + +rt ipv6 dst {2}/128 port 1 +rt ipv6 dst {3}/128 port 0 + +#outter-ipv4 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 9 pri 1 \\ +src {4}/128 \\ +dst {5}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 10 pri 1 \\ +src {5}/128 \\ +dst {4}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 9 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {6} dst {7} +sa in 10 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {7} dst {6} + +rt ipv6 dst {4}/128 port 1 +rt ipv4 dst {7}/32 port 0 + +#outter-ipv6 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 11 pri 1 \\ +src {8}/32 \\ +dst {9}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 12 pri 1 \\ +src {9}/32 \\ +dst {8}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 11 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {10} dst {11} +sa in 12 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {11} dst {10} + +rt ipv4 dst {8}/32 port 1 +rt ipv6 dst {11}/128 port 0 +""".format(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, SRC_ADDR_IPV4_2, DST_ADDR_IPV4_2, + SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, SRC_ADDR_IPV6_3, DST_ADDR_IPV6_3) + +ECN_ECT0 = 0x02 +ECN_ECT1 = 0x01 +ECN_CE = 0x03 +DSCP_1 = 0x04 +DSCP_3F = 0xFC + +class TestTunnelHeaderReconstruct(unittest.TestCase): + def setUp(self): + self.px = pkttest.PacketXfer() + th = IP(src=DST_ADDR_IPV4_1, dst=SRC_ADDR_IPV4_1) + self.sa_ipv4v4 = SecurityAssociation(ESP, spi=6, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_1, dst=SRC_ADDR_IPV6_1) + self.sa_ipv6v6 = SecurityAssociation(ESP, spi=8, tunnel_header = th) + + th = IP(src=DST_ADDR_IPV4_2, dst=SRC_ADDR_IPV4_2) + self.sa_ipv4v6 = SecurityAssociation(ESP, spi=10, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_3, dst=SRC_ADDR_IPV6_3) + self.sa_ipv6v4 = SecurityAssociation(ESP, spi=12, tunnel_header = th) + + def gen_pkt_plain_ipv4(self, src, dst, tos): + pkt = IP(src=src, dst=dst, tos=tos) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_plain_ipv6(self, src, dst, tc): + pkt = IPv6(src=src, dst=dst, tc=tc) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_tun_ipv4v4(self, tos_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_1, SRC_ADDR_IPV4_1, + tos_inner) + pkt = self.sa_ipv4v4.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 6) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v6(self, tc_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_1, SRC_ADDR_IPV6_1, + tc_inner) + pkt = self.sa_ipv6v6.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 8) + pkt[IPv6].tc = tc_outter + return pkt + + def gen_pkt_tun_ipv4v6(self, tos_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_2, SRC_ADDR_IPV6_2, + tc_inner) + pkt = self.sa_ipv4v6.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 10) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v4(self, tc_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_3, SRC_ADDR_IPV4_3, + tos_inner) + pkt = self.sa_ipv6v4.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 12) + pkt[IPv6].tc = tc_outter + return pkt + +#RFC4301 5.1.2.1 & 5.1.2.2, outbound packets shall be copied ECN field + def test_outb_ipv4v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_outb_ipv4v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + +#RFC4301 5.1.2.1 & 5.1.2.2, if outbound packets ECN is CE (0x3), inbound packets +#ECN is overwritten to CE, otherwise no change + +#Outter header not CE, Inner header should be no change + def test_inb_ipv4v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#Outter header CE, Inner header should be changed to CE + def test_inb_ipv4v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#RFC4301 5.1.2.1.5 Outer DS field should be copied from Inner DS field + def test_outb_ipv4v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_outb_ipv4v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + +#RFC4301 5.1.2.1.5 Inner DS field should not be affected by Outer DS field + def test_inb_ipv4v4_dscp(self): + pkt = self.gen_pkt_tun_ipv4v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_inb_ipv6v6_dscp(self): + pkt = self.gen_pkt_tun_ipv6v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv4v6_dscp(self): + pkt = self.gen_pkt_tun_ipv4v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv6v4_dscp(self): + pkt = self.gen_pkt_tun_ipv6v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + +pkttest.pkttest() -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v5 0/2] ipsec: ECN and DSCP header reconstruction 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang @ 2019-06-28 13:22 ` Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2 siblings, 2 replies; 27+ messages in thread From: Fan Zhang @ 2019-06-28 13:22 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patchset adds the ECN and DSCP tunnel mode header reconstruction support for rte_ipsec library. The ipsec-secgw sample application is updated with the feature's enabling and a python3 script for testing the correctness of the implementation. v5: - Fixed a checkpatch error. v4: - Fixed a bug. - Refrabricated the code a bit. v3: - Rebased on top of latest dpdk-next-crypto. - Updated the library with individual header reconstruction function. v2: - Fixed a few bugs. - Updated according to Konstantin's comments. - Added python script for testing. Fan Zhang (2): lib/ipsec: add support for header construction examples/ipsec-secgw: support header reconstruction doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ lib/librte_ipsec/esp_inb.c | 13 +- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 139 +++++- lib/librte_ipsec/rte_ipsec_sa.h | 10 + lib/librte_ipsec/sa.c | 18 + lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 12 + lib/librte_security/rte_security.h | 9 + 12 files changed, 686 insertions(+), 9 deletions(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v5 1/2] lib/ipsec: add support for header construction 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 0/2] ipsec: ECN and DSCP " Fan Zhang @ 2019-06-28 13:22 ` Fan Zhang 2019-07-01 10:40 ` Ananyev, Konstantin 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 1 sibling, 1 reply; 27+ messages in thread From: Fan Zhang @ 2019-06-28 13:22 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang, Marko Kovacevic Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- lib/librte_ipsec/esp_inb.c | 13 +++- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 139 +++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/rte_ipsec_sa.h | 10 +++ lib/librte_ipsec/sa.c | 18 +++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 12 ++++ lib/librte_security/rte_security.h | 9 +++ 8 files changed, 199 insertions(+), 8 deletions(-) diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index fb10b7085..8e3ecbc64 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -464,6 +464,8 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], uint32_t hl[num], to[num]; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; + const void *outh; + void *inh; /* * remove icv, esp trailer and high-order @@ -489,9 +491,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl, sa->proto) == 0) { + outh = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, to[i], - tl, sqn + k); + inh = tun_process_step2(mb[i], ml[i], hl[i], adj, + to[i], tl, sqn + k); + + /* update inner ip header */ + update_tun_inb_l3hdr(sa, outh, inh); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index 8c6db3553..55799a867 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, - sa->hdr_l3_off, sqn_low16(sqc)); + update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, + mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ esph = (struct rte_esp_hdr *)(ph + sa->hdr_len); diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 62d78b7b1..dcf26df1d 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -101,23 +101,154 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, return rc; } +/* + * The masks for ipv6 header reconstruction (RFC4301) + */ +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) +#define IPV6_ECN_CE IPV6_ECN_MASK + +/* + * The macros to get and set traffic class (TC) for ipv6 packets + */ +#define GET_IPV6_TC(vtc_flow) \ + (uint32_t)((rte_be_to_cpu_32(vtc_flow)) >> RTE_IPV6_HDR_TC_SHIFT) + +#define SET_IPV6_TC(vtc_flow, tc) \ + (vtc_flow = rte_cpu_to_be_32(tc << RTE_IPV6_HDR_TC_SHIFT) | \ + (vtc_flow & (~rte_cpu_to_be_32(IPV6_TOS_MASK)))) + +/** + * Update type-of-service/traffic-class field of inbound/outbound tunnel + * packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param tos_mask: type-of-service mask stored in sa. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + * @param is_inbound: 1 if it is a inbound packet, 0 if it is outbound. + */ +static inline void +update_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4, uint8_t is_inbound) +{ + uint8_t idx = ((is_inbound << 2) | (is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4out_h; + struct rte_ipv6_hdr *v6out_h; + struct rte_ipv4_hdr *v4in_h; + struct rte_ipv6_hdr *v6in_h; + uint32_t itp, otp; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + switch (idx) { + /* outbound */ + case 0: /*outh ipv6, inh ipv6 */ + v6out_h = update_h; + otp = GET_IPV6_TC(v6out_h->vtc_flow) & ~tos_mask; + itp = GET_IPV6_TC(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + SET_IPV6_TC(v6out_h->vtc_flow, (otp | itp)); + break; + case 1: /*outh ipv6, inh ipv4 */ + v6out_h = update_h; + otp = GET_IPV6_TC(v6out_h->vtc_flow) & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + SET_IPV6_TC(v6out_h->vtc_flow, (otp | itp)); + break; + case 2: /*outh ipv4, inh ipv6 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = GET_IPV6_TC(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + /* inbound */ + case 4: /* outh ipv6, inh ipv6 */ + v6in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v6in != 0)) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 5: /* outh ipv6, inh ipv4 */ + v4in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v4in != 0)) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + case 6: /* outh ipv4, inh ipv6 */ + v6in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 7: /* outh ipv4, inh ipv4 */ + v4in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + } +} + /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_tun_outb_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct rte_ipv4_hdr *v4h; struct rte_ipv6_hdr *v6h; + uint8_t is_outh_ipv4; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + is_outh_ipv4 = 1; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); } else { - v6h = p; + is_outh_ipv4 = 0; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); } + + if (sa->type & TUN_HDR_MSK) + update_tun_tos(inh, outh, sa->tos_mask, is_outh_ipv4, + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4), 0); +} + +static inline void +update_tun_inb_l3hdr(const struct rte_ipsec_sa *sa, const void *outh, + void *inh) +{ + if (sa->type & TUN_HDR_MSK) + update_tun_tos(outh, inh, sa->tos_mask, + ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0), + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4), 1); } #endif /* _IPH_H_ */ diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index fd9b3ed60..a71b55f68 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,8 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, RTE_SATP_LOG2_NUM }; @@ -123,6 +125,14 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index 087de958a..4dec9c37d 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -214,6 +214,18 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_ESN_ENABLE; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + /* interpret flags */ if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM) tp |= RTE_IPSEC_SATP_SQN_ATOM; @@ -310,6 +322,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= RTE_IP_ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= RTE_IP_DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index 20c0a65c0..51e69ad05 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index c2c67b85d..2e5790691 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -70,6 +70,18 @@ struct rte_ipv4_hdr { #define RTE_IPV4_HDR_OFFSET_UNITS 8 +/** + * RFC 3168 Explicit Congestion Notification (ECN) + * * ECT(1) (ECN-Capable Transport(1)) + * * ECT(0) (ECN-Capable Transport(0)) + * * ECT(CE)(CE (Congestion Experienced)) + */ +#define RTE_IP_ECN_MASK (0x03) +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK + +/** Packet Option Masks */ +#define RTE_IP_DSCP_MASK (0xFC) + /* * IPv4 address types */ diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index 76f54e0e0..d0492928c 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * 1: In tunnel mode, enable outer header ECN Field copied from + * inner header in tunnel encapsulation, or inner header ECN + * field construction in decapsulation. + * * 0: Inner/outer header are not modified. + */ + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v5 1/2] lib/ipsec: add support for header construction 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-07-01 10:40 ` Ananyev, Konstantin 0 siblings, 0 replies; 27+ messages in thread From: Ananyev, Konstantin @ 2019-07-01 10:40 UTC (permalink / raw) To: Zhang, Roy Fan, dev; +Cc: akhil.goyal, Kovacevic, Marko Hi Fan, > From: Zhang, Roy Fan > Sent: Friday, June 28, 2019 2:23 PM > To: dev@dpdk.org > Cc: akhil.goyal@nxp.com; Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Roy Fan <roy.fan.zhang@intel.com>; Kovacevic, > Marko <marko.kovacevic@intel.com> > Subject: [PATCH v5 1/2] lib/ipsec: add support for header construction > > Add support for RFC 4301(5.1.2) to update of > Type of service field and Traffic class field > bits inside ipv4/ipv6 packets for outbound cases > and inbound cases which deals with the update of > the DSCP/ENC bits inside each of the fields. Two minor nits below. Apart from that: Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> > > Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> > Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> > --- > diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h > index 62d78b7b1..dcf26df1d 100644 > --- a/lib/librte_ipsec/iph.h > +++ b/lib/librte_ipsec/iph.h > @@ -101,23 +101,154 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > return rc; > } > > +/* > + * The masks for ipv6 header reconstruction (RFC4301) > + */ > +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) > +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) > +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) > +#define IPV6_ECN_CE IPV6_ECN_MASK > + > +/* > + * The macros to get and set traffic class (TC) for ipv6 packets > + */ > +#define GET_IPV6_TC(vtc_flow) \ > + (uint32_t)((rte_be_to_cpu_32(vtc_flow)) >> RTE_IPV6_HDR_TC_SHIFT) > + > +#define SET_IPV6_TC(vtc_flow, tc) \ > + (vtc_flow = rte_cpu_to_be_32(tc << RTE_IPV6_HDR_TC_SHIFT) | \ > + (vtc_flow & (~rte_cpu_to_be_32(IPV6_TOS_MASK)))) > + For macros we need all its parameter references to be in (). i.e. (vtc_flow) = rte_cpu_to_be_32((tc) << ... Though I think inline function would suit better (as you have in previous patch version). > +/** > + * Update type-of-service/traffic-class field of inbound/outbound tunnel > + * packet. > + * > + * @param ref_h: reference header, for outbound it is inner header, otherwise > + * outer header. > + * @param update_h: header to be updated tos/tc field, for outbound it is outer > + * header, otherwise inner header. > + * @param tos_mask: type-of-service mask stored in sa. > + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. > + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. > + * @param is_inbound: 1 if it is a inbound packet, 0 if it is outbound. > + */ > +static inline void > +update_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, > + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4, uint8_t is_inbound) > +{ > + uint8_t idx = ((is_inbound << 2) | (is_outh_ipv4 << 1) | is_inh_ipv4); > + struct rte_ipv4_hdr *v4out_h; > + struct rte_ipv6_hdr *v6out_h; > + struct rte_ipv4_hdr *v4in_h; > + struct rte_ipv6_hdr *v6in_h; > + uint32_t itp, otp; > + uint8_t ecn_v4out, ecn_v4in; > + uint32_t ecn_v6out, ecn_v6in; > + > + switch (idx) { > + /* outbound */ > + case 0: /*outh ipv6, inh ipv6 */ > + v6out_h = update_h; > + otp = GET_IPV6_TC(v6out_h->vtc_flow) & ~tos_mask; > + itp = GET_IPV6_TC(((const struct rte_ipv6_hdr *)ref_h)-> > + vtc_flow) & tos_mask; > + SET_IPV6_TC(v6out_h->vtc_flow, (otp | itp)); > + break; > + case 1: /*outh ipv6, inh ipv4 */ > + v6out_h = update_h; > + otp = GET_IPV6_TC(v6out_h->vtc_flow) & ~tos_mask; > + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & > + tos_mask; > + SET_IPV6_TC(v6out_h->vtc_flow, (otp | itp)); > + break; > + case 2: /*outh ipv4, inh ipv6 */ > + v4out_h = update_h; > + otp = v4out_h->type_of_service & ~tos_mask; > + itp = GET_IPV6_TC(((const struct rte_ipv6_hdr *)ref_h)-> > + vtc_flow) & tos_mask; > + v4out_h->type_of_service = (otp | itp); > + break; > + case 3: /* outh ipv4, inh ipv4 */ > + v4out_h = update_h; > + otp = v4out_h->type_of_service & ~tos_mask; > + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & > + tos_mask; > + v4out_h->type_of_service = (otp | itp); > + break; Looking at the function - it might be better to split it into 2 separate functions: one for inbound, another for outbound. Then you'll have identical cases (0-3) for both, and that would probably be easier to follow. Again in that case you wouldn't need to: uint8_t idx = ((is_inbound << 2) |... > + /* inbound */ > + case 4: /* outh ipv6, inh ipv6 */ > + v6in_h = update_h; > + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); > + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && > + (ecn_v6in != 0)) > + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); > + break; > + case 5: /* outh ipv6, inh ipv4 */ > + v4in_h = update_h; > + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & > + rte_cpu_to_be_32(IPV6_ECN_MASK); > + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; > + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && > + (ecn_v4in != 0)) > + v4in_h->type_of_service |= RTE_IP_ECN_CE; > + break; > + case 6: /* outh ipv4, inh ipv6 */ > + v6in_h = update_h; > + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> > + type_of_service & RTE_IP_ECN_MASK; > + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); > + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) > + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); > + break; > + case 7: /* outh ipv4, inh ipv4 */ > + v4in_h = update_h; > + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> > + type_of_service & RTE_IP_ECN_MASK; > + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; > + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) > + v4in_h->type_of_service |= RTE_IP_ECN_CE; > + break; > + } > +} > + ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-06-28 13:22 ` Fan Zhang 2019-07-01 10:41 ` Ananyev, Konstantin 1 sibling, 1 reply; 27+ messages in thread From: Fan Zhang @ 2019-06-28 13:22 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patch updates the ipsec-secgw application to support header reconstruction. In addition a series of tests have been added to prove the implementation's correctness. Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> --- doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ 4 files changed, 487 insertions(+), 1 deletion(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py diff --git a/doc/guides/rel_notes/release_19_08.rst b/doc/guides/rel_notes/release_19_08.rst index 7c0435a43..d949dbcfb 100644 --- a/doc/guides/rel_notes/release_19_08.rst +++ b/doc/guides/rel_notes/release_19_08.rst @@ -99,6 +99,12 @@ New Features Updated ``librte_telemetry`` to fetch the global metrics from the ``librte_metrics`` library. +* **Updated IPSec library Header Reconstruction.** + + Updated the IPSec library with ECN and DSCP field header reconstruction + feature followed by RFC4301. The IPSec-secgw sample application is also + updated to support this feature by default. + Removed Items ------------- diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index 7262ccee8..447f9dbb4 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (ss->flags == IP4_TUNNEL) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/examples/ipsec-secgw/test/run_test.sh b/examples/ipsec-secgw/test/run_test.sh index 4969effdb..3f73545c9 100755 --- a/examples/ipsec-secgw/test/run_test.sh +++ b/examples/ipsec-secgw/test/run_test.sh @@ -61,7 +61,8 @@ trs_3descbc_sha1_old \ trs_3descbc_sha1_esn \ trs_3descbc_sha1_esn_atom" -PKT_TESTS="trs_ipv6opts" +PKT_TESTS="trs_ipv6opts \ +tun_null_header_reconstruct" DIR=$(dirname $0) diff --git a/examples/ipsec-secgw/test/tun_null_header_reconstruct.py b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py new file mode 100755 index 000000000..f2653b351 --- /dev/null +++ b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 + +from scapy.all import * +import unittest +import pkttest + +#{ipv4{ipv4}} test +SRC_ADDR_IPV4_1 = "192.168.1.1" +DST_ADDR_IPV4_1 = "192.168.2.1" + +#{ipv6{ipv6}} test +SRC_ADDR_IPV6_1 = "1111:0000:0000:0000:0000:0000:0000:0001" +DST_ADDR_IPV6_1 = "2222:0000:0000:0000:0000:0000:0000:0001" + +#{ipv4{ipv6}} test +SRC_ADDR_IPV4_2 = "192.168.11.1" +DST_ADDR_IPV4_2 = "192.168.12.1" +SRC_ADDR_IPV6_2 = "1111:0000:0000:0000:0000:0000:0001:0001" +DST_ADDR_IPV6_2 = "2222:0000:0000:0000:0000:0000:0001:0001" + +#{ipv6{ipv4}} test +SRC_ADDR_IPV4_3 = "192.168.21.1" +DST_ADDR_IPV4_3 = "192.168.22.1" +SRC_ADDR_IPV6_3 = "1111:0000:0000:0000:0000:0001:0001:0001" +DST_ADDR_IPV6_3 = "2222:0000:0000:0000:0000:0001:0001:0001" + +def config(): + return """ +#outter-ipv4 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 5 pri 1 \\ +src {0}/32 \\ +dst {1}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 6 pri 1 \\ +src {1}/32 \\ +dst {0}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {0} dst {1} +sa in 6 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {1} dst {0} + +rt ipv4 dst {0}/32 port 1 +rt ipv4 dst {1}/32 port 0 + +#outter-ipv6 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 7 pri 1 \\ +src {2}/128 \\ +dst {3}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 8 pri 1 \\ +src {3}/128 \\ +dst {2}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 7 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {2} dst {3} +sa in 8 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {3} dst {2} + +rt ipv6 dst {2}/128 port 1 +rt ipv6 dst {3}/128 port 0 + +#outter-ipv4 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 9 pri 1 \\ +src {4}/128 \\ +dst {5}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 10 pri 1 \\ +src {5}/128 \\ +dst {4}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 9 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {6} dst {7} +sa in 10 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {7} dst {6} + +rt ipv6 dst {4}/128 port 1 +rt ipv4 dst {7}/32 port 0 + +#outter-ipv6 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 11 pri 1 \\ +src {8}/32 \\ +dst {9}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 12 pri 1 \\ +src {9}/32 \\ +dst {8}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 11 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {10} dst {11} +sa in 12 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {11} dst {10} + +rt ipv4 dst {8}/32 port 1 +rt ipv6 dst {11}/128 port 0 +""".format(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, SRC_ADDR_IPV4_2, DST_ADDR_IPV4_2, + SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, SRC_ADDR_IPV6_3, DST_ADDR_IPV6_3) + +ECN_ECT0 = 0x02 +ECN_ECT1 = 0x01 +ECN_CE = 0x03 +DSCP_1 = 0x04 +DSCP_3F = 0xFC + +class TestTunnelHeaderReconstruct(unittest.TestCase): + def setUp(self): + self.px = pkttest.PacketXfer() + th = IP(src=DST_ADDR_IPV4_1, dst=SRC_ADDR_IPV4_1) + self.sa_ipv4v4 = SecurityAssociation(ESP, spi=6, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_1, dst=SRC_ADDR_IPV6_1) + self.sa_ipv6v6 = SecurityAssociation(ESP, spi=8, tunnel_header = th) + + th = IP(src=DST_ADDR_IPV4_2, dst=SRC_ADDR_IPV4_2) + self.sa_ipv4v6 = SecurityAssociation(ESP, spi=10, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_3, dst=SRC_ADDR_IPV6_3) + self.sa_ipv6v4 = SecurityAssociation(ESP, spi=12, tunnel_header = th) + + def gen_pkt_plain_ipv4(self, src, dst, tos): + pkt = IP(src=src, dst=dst, tos=tos) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_plain_ipv6(self, src, dst, tc): + pkt = IPv6(src=src, dst=dst, tc=tc) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_tun_ipv4v4(self, tos_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_1, SRC_ADDR_IPV4_1, + tos_inner) + pkt = self.sa_ipv4v4.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 6) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v6(self, tc_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_1, SRC_ADDR_IPV6_1, + tc_inner) + pkt = self.sa_ipv6v6.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 8) + pkt[IPv6].tc = tc_outter + return pkt + + def gen_pkt_tun_ipv4v6(self, tos_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_2, SRC_ADDR_IPV6_2, + tc_inner) + pkt = self.sa_ipv4v6.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 10) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v4(self, tc_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_3, SRC_ADDR_IPV4_3, + tos_inner) + pkt = self.sa_ipv6v4.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 12) + pkt[IPv6].tc = tc_outter + return pkt + +#RFC4301 5.1.2.1 & 5.1.2.2, outbound packets shall be copied ECN field + def test_outb_ipv4v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_outb_ipv4v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + +#RFC4301 5.1.2.1 & 5.1.2.2, if outbound packets ECN is CE (0x3), inbound packets +#ECN is overwritten to CE, otherwise no change + +#Outter header not CE, Inner header should be no change + def test_inb_ipv4v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#Outter header CE, Inner header should be changed to CE + def test_inb_ipv4v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#RFC4301 5.1.2.1.5 Outer DS field should be copied from Inner DS field + def test_outb_ipv4v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_outb_ipv4v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + +#RFC4301 5.1.2.1.5 Inner DS field should not be affected by Outer DS field + def test_inb_ipv4v4_dscp(self): + pkt = self.gen_pkt_tun_ipv4v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_inb_ipv6v6_dscp(self): + pkt = self.gen_pkt_tun_ipv6v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv4v6_dscp(self): + pkt = self.gen_pkt_tun_ipv4v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv6v4_dscp(self): + pkt = self.gen_pkt_tun_ipv6v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + +pkttest.pkttest() -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang @ 2019-07-01 10:41 ` Ananyev, Konstantin 0 siblings, 0 replies; 27+ messages in thread From: Ananyev, Konstantin @ 2019-07-01 10:41 UTC (permalink / raw) To: Zhang, Roy Fan, dev; +Cc: akhil.goyal > -----Original Message----- > From: Zhang, Roy Fan > Sent: Friday, June 28, 2019 2:23 PM > To: dev@dpdk.org > Cc: akhil.goyal@nxp.com; Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Roy Fan <roy.fan.zhang@intel.com> > Subject: [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction > > This patch updates the ipsec-secgw application to support > header reconstruction. In addition a series of tests have > been added to prove the implementation's correctness. > > Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> > --- Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> > 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP header reconstruction 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang ` (2 preceding siblings ...) 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP " Fan Zhang @ 2019-07-01 12:01 ` Fan Zhang 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction Fan Zhang ` (3 more replies) 3 siblings, 4 replies; 27+ messages in thread From: Fan Zhang @ 2019-07-01 12:01 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, pablo.de.lara.guarch, Fan Zhang This patchset adds the ECN and DSCP tunnel mode header reconstruction support for rte_ipsec library. The ipsec-secgw sample application is updated with the feature's enabling and a python3 script for testing the correctness of the implementation. v6: - update_tun_tos function split for inbound/outbound. - get/set ipv6 tc change from macro back to inline functions. v5: - Fixed a checkpatch error. v4: - Fixed a bug. - Refrabricated the code a bit. v3: - Rebased on top of latest dpdk-next-crypto. - Updated the library with individual header reconstruction function. v2: - Fixed a few bugs. - Updated according to Konstantin's comments. - Added python script for testing. Fan Zhang (2): lib/ipsec: add support for header construction examples/ipsec-secgw: support header reconstruction doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ lib/librte_ipsec/esp_inb.c | 13 +- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 168 +++++++- lib/librte_ipsec/rte_ipsec_sa.h | 10 + lib/librte_ipsec/sa.c | 18 + lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 12 + lib/librte_security/rte_security.h | 9 + 12 files changed, 715 insertions(+), 9 deletions(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang @ 2019-07-01 12:01 ` Fan Zhang 2019-07-01 13:11 ` Olivier Matz 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang ` (2 subsequent siblings) 3 siblings, 1 reply; 27+ messages in thread From: Fan Zhang @ 2019-07-01 12:01 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, pablo.de.lara.guarch, Fan Zhang, Marko Kovacevic Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> --- lib/librte_ipsec/esp_inb.c | 13 ++- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 168 ++++++++++++++++++++++++++++++++++++- lib/librte_ipsec/rte_ipsec_sa.h | 10 +++ lib/librte_ipsec/sa.c | 18 ++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 12 +++ lib/librte_security/rte_security.h | 9 ++ 8 files changed, 228 insertions(+), 8 deletions(-) diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index fb10b7085..8e3ecbc64 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -464,6 +464,8 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], uint32_t hl[num], to[num]; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; + const void *outh; + void *inh; /* * remove icv, esp trailer and high-order @@ -489,9 +491,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl, sa->proto) == 0) { + outh = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, to[i], - tl, sqn + k); + inh = tun_process_step2(mb[i], ml[i], hl[i], adj, + to[i], tl, sqn + k); + + /* update inner ip header */ + update_tun_inb_l3hdr(sa, outh, inh); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index 8c6db3553..55799a867 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, - sa->hdr_l3_off, sqn_low16(sqc)); + update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, + mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ esph = (struct rte_esp_hdr *)(ph + sa->hdr_len); diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 62d78b7b1..90faff6d5 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -101,23 +101,183 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, return rc; } +/* + * The masks for ipv6 header reconstruction (RFC4301) + */ +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) +#define IPV6_ECN_CE IPV6_ECN_MASK + +/* + * Inline functions to get and set ipv6 packet header traffic class (TC) field. + */ +static inline uint8_t +get_ipv6_tc(rte_be32_t vtc_flow) +{ + uint32_t v; + + v = rte_be_to_cpu_32(vtc_flow); + return v >> RTE_IPV6_HDR_TC_SHIFT; +} + +static inline rte_be32_t +set_ipv6_tc(rte_be32_t vtc_flow, uint32_t tos) +{ + uint32_t v; + + v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT); + vtc_flow &= ~rte_cpu_to_be_32(IPV6_TOS_MASK); + + return (v | vtc_flow); +} + +/** + * Update type-of-service/traffic-class field of outbound tunnel packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param tos_mask: type-of-service mask stored in sa. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + */ +static inline void +update_outb_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4) +{ + uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4out_h; + struct rte_ipv6_hdr *v6out_h; + uint32_t itp, otp; + + switch (idx) { + case 0: /*outh ipv6, inh ipv6 */ + v6out_h = update_h; + otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask; + itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp); + break; + case 1: /*outh ipv6, inh ipv4 */ + v6out_h = update_h; + otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp); + break; + case 2: /*outh ipv4, inh ipv6 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + } +} + +/** + * Update type-of-service/traffic-class field of inbound tunnel packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + */ +static inline void +update_inb_tun_tos(const void *ref_h, void *update_h, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4) +{ + uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4in_h; + struct rte_ipv6_hdr *v6in_h; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + switch (idx) { + case 0: /* outh ipv6, inh ipv6 */ + v6in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v6in != 0)) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 1: /* outh ipv6, inh ipv4 */ + v4in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(IPV6_ECN_MASK); + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if ((ecn_v6out == rte_cpu_to_be_32(IPV6_ECN_CE)) && + (ecn_v4in != 0)) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + case 2: /* outh ipv4, inh ipv6 */ + v6in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v6in = v6in_h->vtc_flow & rte_cpu_to_be_32(IPV6_ECN_MASK); + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v6in != 0) + v6in_h->vtc_flow |= rte_cpu_to_be_32(IPV6_ECN_CE); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IP_ECN_MASK; + ecn_v4in = v4in_h->type_of_service & RTE_IP_ECN_MASK; + if (ecn_v4out == RTE_IP_ECN_CE && ecn_v4in != 0) + v4in_h->type_of_service |= RTE_IP_ECN_CE; + break; + } +} + /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_tun_outb_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct rte_ipv4_hdr *v4h; struct rte_ipv6_hdr *v6h; + uint8_t is_outh_ipv4; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + is_outh_ipv4 = 1; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); } else { - v6h = p; + is_outh_ipv4 = 0; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); } + + if (sa->type & TUN_HDR_MSK) + update_outb_tun_tos(inh, outh, sa->tos_mask, is_outh_ipv4, + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4)); +} + +static inline void +update_tun_inb_l3hdr(const struct rte_ipsec_sa *sa, const void *outh, + void *inh) +{ + if (sa->type & TUN_HDR_MSK) + update_inb_tun_tos(outh, inh, + ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0), + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4)); } #endif /* _IPH_H_ */ diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index fd9b3ed60..a71b55f68 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,8 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, RTE_SATP_LOG2_NUM }; @@ -123,6 +125,14 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index 087de958a..4dec9c37d 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -214,6 +214,18 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_ESN_ENABLE; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + /* interpret flags */ if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM) tp |= RTE_IPSEC_SATP_SQN_ATOM; @@ -310,6 +322,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= RTE_IP_ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= RTE_IP_DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index 20c0a65c0..51e69ad05 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index c2c67b85d..2e5790691 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -70,6 +70,18 @@ struct rte_ipv4_hdr { #define RTE_IPV4_HDR_OFFSET_UNITS 8 +/** + * RFC 3168 Explicit Congestion Notification (ECN) + * * ECT(1) (ECN-Capable Transport(1)) + * * ECT(0) (ECN-Capable Transport(0)) + * * ECT(CE)(CE (Congestion Experienced)) + */ +#define RTE_IP_ECN_MASK (0x03) +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK + +/** Packet Option Masks */ +#define RTE_IP_DSCP_MASK (0xFC) + /* * IPv4 address types */ diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index 76f54e0e0..d0492928c 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * 1: In tunnel mode, enable outer header ECN Field copied from + * inner header in tunnel encapsulation, or inner header ECN + * field construction in decapsulation. + * * 0: Inner/outer header are not modified. + */ + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-07-01 13:11 ` Olivier Matz 0 siblings, 0 replies; 27+ messages in thread From: Olivier Matz @ 2019-07-01 13:11 UTC (permalink / raw) To: Fan Zhang; +Cc: dev, akhil.goyal, pablo.de.lara.guarch, Marko Kovacevic On Mon, Jul 01, 2019 at 01:01:23PM +0100, Fan Zhang wrote: > Add support for RFC 4301(5.1.2) to update of > Type of service field and Traffic class field > bits inside ipv4/ipv6 packets for outbound cases > and inbound cases which deals with the update of > the DSCP/ENC bits inside each of the fields. > > Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> > Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> > Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> > Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> > --- [...] > --- a/lib/librte_ipsec/esp_outb.c > +++ b/lib/librte_ipsec/esp_outb.c > @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, > rte_memcpy(ph, sa->hdr, sa->hdr_len); > > /* update original and new ip header fields */ > - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, > - sa->hdr_l3_off, sqn_low16(sqc)); > + update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, > + mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc)); > > /* update spi, seqn and iv */ > esph = (struct rte_esp_hdr *)(ph + sa->hdr_len); > diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h > index 62d78b7b1..90faff6d5 100644 > --- a/lib/librte_ipsec/iph.h > +++ b/lib/librte_ipsec/iph.h > @@ -101,23 +101,183 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, > return rc; > } > > +/* > + * The masks for ipv6 header reconstruction (RFC4301) > + */ > +#define IPV6_DSCP_MASK (RTE_IP_DSCP_MASK << RTE_IPV6_HDR_TC_SHIFT) > +#define IPV6_ECN_MASK (RTE_IP_ECN_MASK << RTE_IPV6_HDR_TC_SHIFT) > +#define IPV6_TOS_MASK (IPV6_ECN_MASK | IPV6_DSCP_MASK) > +#define IPV6_ECN_CE IPV6_ECN_MASK [...] > --- a/lib/librte_net/rte_ip.h > +++ b/lib/librte_net/rte_ip.h > @@ -70,6 +70,18 @@ struct rte_ipv4_hdr { > > #define RTE_IPV4_HDR_OFFSET_UNITS 8 > > +/** > + * RFC 3168 Explicit Congestion Notification (ECN) > + * * ECT(1) (ECN-Capable Transport(1)) > + * * ECT(0) (ECN-Capable Transport(0)) > + * * ECT(CE)(CE (Congestion Experienced)) > + */ > +#define RTE_IP_ECN_MASK (0x03) > +#define RTE_IP_ECN_CE RTE_IP_ECN_MASK > + > +/** Packet Option Masks */ > +#define RTE_IP_DSCP_MASK (0xFC) > + > /* > * IPv4 address types > */ Just a quick comment: these flags are also being added in librte_net by this patch: https://mails.dpdk.org/archives/dev/2019-June/135444.html Thanks, Olivier ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v6 2/2] examples/ipsec-secgw: support header reconstruction 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-07-01 12:01 ` Fan Zhang 2019-07-03 10:11 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Akhil Goyal 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 " Fan Zhang 3 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-07-01 12:01 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, pablo.de.lara.guarch, Fan Zhang This patch updates the ipsec-secgw application to support header reconstruction. In addition a series of tests have been added to prove the implementation's correctness. Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> --- doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ 4 files changed, 487 insertions(+), 1 deletion(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py diff --git a/doc/guides/rel_notes/release_19_08.rst b/doc/guides/rel_notes/release_19_08.rst index 7c0435a43..d949dbcfb 100644 --- a/doc/guides/rel_notes/release_19_08.rst +++ b/doc/guides/rel_notes/release_19_08.rst @@ -99,6 +99,12 @@ New Features Updated ``librte_telemetry`` to fetch the global metrics from the ``librte_metrics`` library. +* **Updated IPSec library Header Reconstruction.** + + Updated the IPSec library with ECN and DSCP field header reconstruction + feature followed by RFC4301. The IPSec-secgw sample application is also + updated to support this feature by default. + Removed Items ------------- diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index 7262ccee8..447f9dbb4 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -991,6 +991,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (ss->flags == TRANSPORT) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (ss->flags == IP4_TUNNEL) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/examples/ipsec-secgw/test/run_test.sh b/examples/ipsec-secgw/test/run_test.sh index 4969effdb..3f73545c9 100755 --- a/examples/ipsec-secgw/test/run_test.sh +++ b/examples/ipsec-secgw/test/run_test.sh @@ -61,7 +61,8 @@ trs_3descbc_sha1_old \ trs_3descbc_sha1_esn \ trs_3descbc_sha1_esn_atom" -PKT_TESTS="trs_ipv6opts" +PKT_TESTS="trs_ipv6opts \ +tun_null_header_reconstruct" DIR=$(dirname $0) diff --git a/examples/ipsec-secgw/test/tun_null_header_reconstruct.py b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py new file mode 100755 index 000000000..f2653b351 --- /dev/null +++ b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 + +from scapy.all import * +import unittest +import pkttest + +#{ipv4{ipv4}} test +SRC_ADDR_IPV4_1 = "192.168.1.1" +DST_ADDR_IPV4_1 = "192.168.2.1" + +#{ipv6{ipv6}} test +SRC_ADDR_IPV6_1 = "1111:0000:0000:0000:0000:0000:0000:0001" +DST_ADDR_IPV6_1 = "2222:0000:0000:0000:0000:0000:0000:0001" + +#{ipv4{ipv6}} test +SRC_ADDR_IPV4_2 = "192.168.11.1" +DST_ADDR_IPV4_2 = "192.168.12.1" +SRC_ADDR_IPV6_2 = "1111:0000:0000:0000:0000:0000:0001:0001" +DST_ADDR_IPV6_2 = "2222:0000:0000:0000:0000:0000:0001:0001" + +#{ipv6{ipv4}} test +SRC_ADDR_IPV4_3 = "192.168.21.1" +DST_ADDR_IPV4_3 = "192.168.22.1" +SRC_ADDR_IPV6_3 = "1111:0000:0000:0000:0000:0001:0001:0001" +DST_ADDR_IPV6_3 = "2222:0000:0000:0000:0000:0001:0001:0001" + +def config(): + return """ +#outter-ipv4 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 5 pri 1 \\ +src {0}/32 \\ +dst {1}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 6 pri 1 \\ +src {1}/32 \\ +dst {0}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {0} dst {1} +sa in 6 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {1} dst {0} + +rt ipv4 dst {0}/32 port 1 +rt ipv4 dst {1}/32 port 0 + +#outter-ipv6 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 7 pri 1 \\ +src {2}/128 \\ +dst {3}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 8 pri 1 \\ +src {3}/128 \\ +dst {2}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 7 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {2} dst {3} +sa in 8 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {3} dst {2} + +rt ipv6 dst {2}/128 port 1 +rt ipv6 dst {3}/128 port 0 + +#outter-ipv4 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 9 pri 1 \\ +src {4}/128 \\ +dst {5}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 10 pri 1 \\ +src {5}/128 \\ +dst {4}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 9 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {6} dst {7} +sa in 10 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {7} dst {6} + +rt ipv6 dst {4}/128 port 1 +rt ipv4 dst {7}/32 port 0 + +#outter-ipv6 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 11 pri 1 \\ +src {8}/32 \\ +dst {9}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 12 pri 1 \\ +src {9}/32 \\ +dst {8}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 11 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {10} dst {11} +sa in 12 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {11} dst {10} + +rt ipv4 dst {8}/32 port 1 +rt ipv6 dst {11}/128 port 0 +""".format(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, SRC_ADDR_IPV4_2, DST_ADDR_IPV4_2, + SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, SRC_ADDR_IPV6_3, DST_ADDR_IPV6_3) + +ECN_ECT0 = 0x02 +ECN_ECT1 = 0x01 +ECN_CE = 0x03 +DSCP_1 = 0x04 +DSCP_3F = 0xFC + +class TestTunnelHeaderReconstruct(unittest.TestCase): + def setUp(self): + self.px = pkttest.PacketXfer() + th = IP(src=DST_ADDR_IPV4_1, dst=SRC_ADDR_IPV4_1) + self.sa_ipv4v4 = SecurityAssociation(ESP, spi=6, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_1, dst=SRC_ADDR_IPV6_1) + self.sa_ipv6v6 = SecurityAssociation(ESP, spi=8, tunnel_header = th) + + th = IP(src=DST_ADDR_IPV4_2, dst=SRC_ADDR_IPV4_2) + self.sa_ipv4v6 = SecurityAssociation(ESP, spi=10, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_3, dst=SRC_ADDR_IPV6_3) + self.sa_ipv6v4 = SecurityAssociation(ESP, spi=12, tunnel_header = th) + + def gen_pkt_plain_ipv4(self, src, dst, tos): + pkt = IP(src=src, dst=dst, tos=tos) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_plain_ipv6(self, src, dst, tc): + pkt = IPv6(src=src, dst=dst, tc=tc) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_tun_ipv4v4(self, tos_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_1, SRC_ADDR_IPV4_1, + tos_inner) + pkt = self.sa_ipv4v4.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 6) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v6(self, tc_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_1, SRC_ADDR_IPV6_1, + tc_inner) + pkt = self.sa_ipv6v6.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 8) + pkt[IPv6].tc = tc_outter + return pkt + + def gen_pkt_tun_ipv4v6(self, tos_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_2, SRC_ADDR_IPV6_2, + tc_inner) + pkt = self.sa_ipv4v6.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 10) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v4(self, tc_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_3, SRC_ADDR_IPV4_3, + tos_inner) + pkt = self.sa_ipv6v4.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 12) + pkt[IPv6].tc = tc_outter + return pkt + +#RFC4301 5.1.2.1 & 5.1.2.2, outbound packets shall be copied ECN field + def test_outb_ipv4v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_outb_ipv4v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + +#RFC4301 5.1.2.1 & 5.1.2.2, if outbound packets ECN is CE (0x3), inbound packets +#ECN is overwritten to CE, otherwise no change + +#Outter header not CE, Inner header should be no change + def test_inb_ipv4v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#Outter header CE, Inner header should be changed to CE + def test_inb_ipv4v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#RFC4301 5.1.2.1.5 Outer DS field should be copied from Inner DS field + def test_outb_ipv4v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_outb_ipv4v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + +#RFC4301 5.1.2.1.5 Inner DS field should not be affected by Outer DS field + def test_inb_ipv4v4_dscp(self): + pkt = self.gen_pkt_tun_ipv4v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_inb_ipv6v6_dscp(self): + pkt = self.gen_pkt_tun_ipv6v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv4v6_dscp(self): + pkt = self.gen_pkt_tun_ipv4v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv6v4_dscp(self): + pkt = self.gen_pkt_tun_ipv6v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + +pkttest.pkttest() -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP header reconstruction 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang @ 2019-07-03 10:11 ` Akhil Goyal 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 " Fan Zhang 3 siblings, 0 replies; 27+ messages in thread From: Akhil Goyal @ 2019-07-03 10:11 UTC (permalink / raw) To: Fan Zhang, dev; +Cc: pablo.de.lara.guarch Hi Fan, This patchset need a rebase. As today we need to close the subtrees for RC1, this patchset will go in RC2. Thanks, Akhil > > This patchset adds the ECN and DSCP tunnel mode header reconstruction > support for rte_ipsec library. The ipsec-secgw sample application is > updated with the feature's enabling and a python3 script for testing > the correctness of the implementation. > > v6: > - update_tun_tos function split for inbound/outbound. > - get/set ipv6 tc change from macro back to inline functions. > > v5: > - Fixed a checkpatch error. > > v4: > - Fixed a bug. > - Refrabricated the code a bit. > > v3: > - Rebased on top of latest dpdk-next-crypto. > - Updated the library with individual header reconstruction function. > > v2: > - Fixed a few bugs. > - Updated according to Konstantin's comments. > - Added python script for testing. > > Fan Zhang (2): > lib/ipsec: add support for header construction > examples/ipsec-secgw: support header reconstruction > > doc/guides/rel_notes/release_19_08.rst | 6 + > examples/ipsec-secgw/sa.c | 2 + > examples/ipsec-secgw/test/run_test.sh | 3 +- > .../test/tun_null_header_reconstruct.py | 477 +++++++++++++++++++++ > lib/librte_ipsec/esp_inb.c | 13 +- > lib/librte_ipsec/esp_outb.c | 4 +- > lib/librte_ipsec/iph.h | 168 +++++++- > lib/librte_ipsec/rte_ipsec_sa.h | 10 + > lib/librte_ipsec/sa.c | 18 + > lib/librte_ipsec/sa.h | 2 + > lib/librte_net/rte_ip.h | 12 + > lib/librte_security/rte_security.h | 9 + > 12 files changed, 715 insertions(+), 9 deletions(-) > create mode 100755 examples/ipsec- > secgw/test/tun_null_header_reconstruct.py > > -- > 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v7 0/2] ipsec: ECN and DSCP header reconstruction 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang ` (2 preceding siblings ...) 2019-07-03 10:11 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Akhil Goyal @ 2019-07-04 10:42 ` Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 1/2] lib/ipsec: add support for header construction Fan Zhang ` (2 more replies) 3 siblings, 3 replies; 27+ messages in thread From: Fan Zhang @ 2019-07-04 10:42 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patchset adds the ECN and DSCP tunnel mode header reconstruction support for rte_ipsec library. The ipsec-secgw sample application is updated with the feature's enabling and a python3 script for testing the correctness of the implementation. v7: - rebased on top of latest dpdk-next-crypto. v6: - update_tun_tos function split for inbound/outbound. - get/set ipv6 tc change from macro back to inline functions. v5: - Fixed a checkpatch error. v4: - Fixed a bug. - Refrabricated the code a bit. v3: - Rebased on top of latest dpdk-next-crypto. - Updated the library with individual header reconstruction function. v2: - Fixed a few bugs. - Updated according to Konstantin's comments. - Added python script for testing. Fan Zhang (2): lib/ipsec: add support for header construction examples/ipsec-secgw: support header reconstruction doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 479 +++++++++++++++++++++ lib/librte_ipsec/esp_inb.c | 13 +- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 164 ++++++- lib/librte_ipsec/rte_ipsec_sa.h | 10 + lib/librte_ipsec/sa.c | 18 + lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 2 + lib/librte_security/rte_security.h | 9 + 12 files changed, 703 insertions(+), 9 deletions(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v7 1/2] lib/ipsec: add support for header construction 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 " Fan Zhang @ 2019-07-04 10:42 ` Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-07-05 10:12 ` [dpdk-dev] [PATCH v7 0/2] ipsec: ECN and DSCP " Akhil Goyal 2 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-07-04 10:42 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang, Marko Kovacevic Add support for RFC 4301(5.1.2) to update of Type of service field and Traffic class field bits inside ipv4/ipv6 packets for outbound cases and inbound cases which deals with the update of the DSCP/ENC bits inside each of the fields. Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> --- lib/librte_ipsec/esp_inb.c | 13 ++- lib/librte_ipsec/esp_outb.c | 4 +- lib/librte_ipsec/iph.h | 164 ++++++++++++++++++++++++++++++++++++- lib/librte_ipsec/rte_ipsec_sa.h | 10 +++ lib/librte_ipsec/sa.c | 18 ++++ lib/librte_ipsec/sa.h | 2 + lib/librte_net/rte_ip.h | 2 + lib/librte_security/rte_security.h | 9 ++ 8 files changed, 214 insertions(+), 8 deletions(-) diff --git a/lib/librte_ipsec/esp_inb.c b/lib/librte_ipsec/esp_inb.c index fb10b7085..8e3ecbc64 100644 --- a/lib/librte_ipsec/esp_inb.c +++ b/lib/librte_ipsec/esp_inb.c @@ -464,6 +464,8 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], uint32_t hl[num], to[num]; struct esp_tail espt[num]; struct rte_mbuf *ml[num]; + const void *outh; + void *inh; /* * remove icv, esp trailer and high-order @@ -489,9 +491,16 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[], if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl, sa->proto) == 0) { + outh = rte_pktmbuf_mtod_offset(mb[i], uint8_t *, + mb[i]->l2_len); + /* modify packet's layout */ - tun_process_step2(mb[i], ml[i], hl[i], adj, to[i], - tl, sqn + k); + inh = tun_process_step2(mb[i], ml[i], hl[i], adj, + to[i], tl, sqn + k); + + /* update inner ip header */ + update_tun_inb_l3hdr(sa, outh, inh); + /* update mbuf's metadata */ tun_process_step3(mb[i], sa->tx_offload.msk, sa->tx_offload.val); diff --git a/lib/librte_ipsec/esp_outb.c b/lib/librte_ipsec/esp_outb.c index 8c6db3553..55799a867 100644 --- a/lib/librte_ipsec/esp_outb.c +++ b/lib/librte_ipsec/esp_outb.c @@ -152,8 +152,8 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc, rte_memcpy(ph, sa->hdr, sa->hdr_len); /* update original and new ip header fields */ - update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len - sqh_len, - sa->hdr_l3_off, sqn_low16(sqc)); + update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen, + mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc)); /* update spi, seqn and iv */ esph = (struct rte_esp_hdr *)(ph + sa->hdr_len); diff --git a/lib/librte_ipsec/iph.h b/lib/librte_ipsec/iph.h index 62d78b7b1..861f16905 100644 --- a/lib/librte_ipsec/iph.h +++ b/lib/librte_ipsec/iph.h @@ -101,23 +101,179 @@ update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, return rc; } +/* + * Inline functions to get and set ipv6 packet header traffic class (TC) field. + */ +static inline uint8_t +get_ipv6_tc(rte_be32_t vtc_flow) +{ + uint32_t v; + + v = rte_be_to_cpu_32(vtc_flow); + return v >> RTE_IPV6_HDR_TC_SHIFT; +} + +static inline rte_be32_t +set_ipv6_tc(rte_be32_t vtc_flow, uint32_t tos) +{ + uint32_t v; + + v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT); + vtc_flow &= ~rte_cpu_to_be_32(RTE_IPV6_HDR_TC_MASK); + + return (v | vtc_flow); +} + +/** + * Update type-of-service/traffic-class field of outbound tunnel packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param tos_mask: type-of-service mask stored in sa. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + */ +static inline void +update_outb_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4) +{ + uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4out_h; + struct rte_ipv6_hdr *v6out_h; + uint32_t itp, otp; + + switch (idx) { + case 0: /*outh ipv6, inh ipv6 */ + v6out_h = update_h; + otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask; + itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp); + break; + case 1: /*outh ipv6, inh ipv4 */ + v6out_h = update_h; + otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp); + break; + case 2: /*outh ipv4, inh ipv6 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)-> + vtc_flow) & tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4out_h = update_h; + otp = v4out_h->type_of_service & ~tos_mask; + itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service & + tos_mask; + v4out_h->type_of_service = (otp | itp); + break; + } +} + +/** + * Update type-of-service/traffic-class field of inbound tunnel packet. + * + * @param ref_h: reference header, for outbound it is inner header, otherwise + * outer header. + * @param update_h: header to be updated tos/tc field, for outbound it is outer + * header, otherwise inner header. + * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6. + * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6. + */ +static inline void +update_inb_tun_tos(const void *ref_h, void *update_h, + uint8_t is_outh_ipv4, uint8_t is_inh_ipv4) +{ + uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4); + struct rte_ipv4_hdr *v4in_h; + struct rte_ipv6_hdr *v6in_h; + uint8_t ecn_v4out, ecn_v4in; + uint32_t ecn_v6out, ecn_v6in; + + switch (idx) { + case 0: /* outh ipv6, inh ipv6 */ + v6in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK); + ecn_v6in = v6in_h->vtc_flow & + rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK); + if ((ecn_v6out == rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE)) && + (ecn_v6in != 0)) + v6in_h->vtc_flow |= + rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE); + break; + case 1: /* outh ipv6, inh ipv4 */ + v4in_h = update_h; + ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow & + rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK); + ecn_v4in = v4in_h->type_of_service & RTE_IPV4_HDR_ECN_MASK; + if ((ecn_v6out == rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE)) && + (ecn_v4in != 0)) + v4in_h->type_of_service |= RTE_IPV4_HDR_ECN_CE; + break; + case 2: /* outh ipv4, inh ipv6 */ + v6in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IPV4_HDR_ECN_MASK; + ecn_v6in = v6in_h->vtc_flow & + rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK); + if (ecn_v4out == RTE_IPV4_HDR_ECN_CE && ecn_v6in != 0) + v6in_h->vtc_flow |= + rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE); + break; + case 3: /* outh ipv4, inh ipv4 */ + v4in_h = update_h; + ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)-> + type_of_service & RTE_IPV4_HDR_ECN_MASK; + ecn_v4in = v4in_h->type_of_service & RTE_IPV4_HDR_ECN_MASK; + if (ecn_v4out == RTE_IPV4_HDR_ECN_CE && ecn_v4in != 0) + v4in_h->type_of_service |= RTE_IPV4_HDR_ECN_CE; + break; + } +} + /* update original and new ip header fields for tunnel case */ static inline void -update_tun_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen, - uint32_t l2len, rte_be16_t pid) +update_tun_outb_l3hdr(const struct rte_ipsec_sa *sa, void *outh, + const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid) { struct rte_ipv4_hdr *v4h; struct rte_ipv6_hdr *v6h; + uint8_t is_outh_ipv4; if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { - v4h = p; + is_outh_ipv4 = 1; + v4h = outh; v4h->packet_id = pid; v4h->total_length = rte_cpu_to_be_16(plen - l2len); } else { - v6h = p; + is_outh_ipv4 = 0; + v6h = outh; v6h->payload_len = rte_cpu_to_be_16(plen - l2len - sizeof(*v6h)); } + + if (sa->type & TUN_HDR_MSK) + update_outb_tun_tos(inh, outh, sa->tos_mask, is_outh_ipv4, + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4)); +} + +static inline void +update_tun_inb_l3hdr(const struct rte_ipsec_sa *sa, const void *outh, + void *inh) +{ + if (sa->type & TUN_HDR_MSK) + update_inb_tun_tos(outh, inh, + ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0), + ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == + RTE_IPSEC_SATP_IPV4)); } #endif /* _IPH_H_ */ diff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h index b3f9b1080..47ce169d2 100644 --- a/lib/librte_ipsec/rte_ipsec_sa.h +++ b/lib/librte_ipsec/rte_ipsec_sa.h @@ -95,6 +95,8 @@ enum { RTE_SATP_LOG2_MODE, RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2, RTE_SATP_LOG2_ESN, + RTE_SATP_LOG2_ECN, + RTE_SATP_LOG2_DSCP, RTE_SATP_LOG2_NUM }; @@ -123,6 +125,14 @@ enum { #define RTE_IPSEC_SATP_ESN_DISABLE (0ULL << RTE_SATP_LOG2_ESN) #define RTE_IPSEC_SATP_ESN_ENABLE (1ULL << RTE_SATP_LOG2_ESN) +#define RTE_IPSEC_SATP_ECN_MASK (1ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_DISABLE (0ULL << RTE_SATP_LOG2_ECN) +#define RTE_IPSEC_SATP_ECN_ENABLE (1ULL << RTE_SATP_LOG2_ECN) + +#define RTE_IPSEC_SATP_DSCP_MASK (1ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_DISABLE (0ULL << RTE_SATP_LOG2_DSCP) +#define RTE_IPSEC_SATP_DSCP_ENABLE (1ULL << RTE_SATP_LOG2_DSCP) + /** * get type of given SA * @return diff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c index c117d8494..23d394b46 100644 --- a/lib/librte_ipsec/sa.c +++ b/lib/librte_ipsec/sa.c @@ -214,6 +214,18 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type) else tp |= RTE_IPSEC_SATP_ESN_ENABLE; + /* check for ECN flag */ + if (prm->ipsec_xform.options.ecn == 0) + tp |= RTE_IPSEC_SATP_ECN_DISABLE; + else + tp |= RTE_IPSEC_SATP_ECN_ENABLE; + + /* check for DSCP flag */ + if (prm->ipsec_xform.options.copy_dscp == 0) + tp |= RTE_IPSEC_SATP_DSCP_DISABLE; + else + tp |= RTE_IPSEC_SATP_DSCP_ENABLE; + /* interpret flags */ if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM) tp |= RTE_IPSEC_SATP_SQN_ATOM; @@ -310,6 +322,12 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm, static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK | RTE_IPSEC_SATP_MODE_MASK; + if (prm->ipsec_xform.options.ecn) + sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK; + + if (prm->ipsec_xform.options.copy_dscp) + sa->tos_mask |= RTE_IPV4_HDR_DSCP_MASK; + if (cxf->aead != NULL) { switch (cxf->aead->algo) { case RTE_CRYPTO_AEAD_AES_GCM: diff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h index 20c0a65c0..51e69ad05 100644 --- a/lib/librte_ipsec/sa.h +++ b/lib/librte_ipsec/sa.h @@ -10,6 +10,7 @@ #define IPSEC_MAX_HDR_SIZE 64 #define IPSEC_MAX_IV_SIZE 16 #define IPSEC_MAX_IV_QWORD (IPSEC_MAX_IV_SIZE / sizeof(uint64_t)) +#define TUN_HDR_MSK (RTE_IPSEC_SATP_ECN_MASK | RTE_IPSEC_SATP_DSCP_MASK) /* padding alignment for different algorithms */ enum { @@ -103,6 +104,7 @@ struct rte_ipsec_sa { uint8_t iv_ofs; /* offset for algo-specific IV inside crypto op */ uint8_t iv_len; uint8_t pad_align; + uint8_t tos_mask; /* template for tunnel header */ uint8_t hdr[IPSEC_MAX_HDR_SIZE]; diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index 4cd54f0d8..2cd050b5e 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -61,6 +61,7 @@ struct rte_ipv4_hdr { /* Type of Service fields */ #define RTE_IPV4_HDR_DSCP_MASK (0xfc) #define RTE_IPV4_HDR_ECN_MASK (0x03) +#define RTE_IPV4_HDR_ECN_CE RTE_IPV4_HDR_ECN_MASK /* Fragment Offset * Flags. */ #define RTE_IPV4_HDR_DF_SHIFT 14 @@ -362,6 +363,7 @@ struct rte_ipv6_hdr { #define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT) #define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT) #define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT) +#define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK /** * Process the pseudo-header checksum of an IPv6 header. diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index bbdf4b07b..96806e3a2 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -163,6 +163,15 @@ struct rte_security_ipsec_sa_options { * * 0: Inner packet is not modified. */ uint32_t dec_ttl : 1; + + /**< Explicit Congestion Notification (ECN) + * + * * 1: In tunnel mode, enable outer header ECN Field copied from + * inner header in tunnel encapsulation, or inner header ECN + * field construction in decapsulation. + * * 0: Inner/outer header are not modified. + */ + uint32_t ecn : 1; }; /** IPSec security association direction */ -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v7 2/2] examples/ipsec-secgw: support header reconstruction 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 " Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 1/2] lib/ipsec: add support for header construction Fan Zhang @ 2019-07-04 10:42 ` Fan Zhang 2019-07-05 10:12 ` [dpdk-dev] [PATCH v7 0/2] ipsec: ECN and DSCP " Akhil Goyal 2 siblings, 0 replies; 27+ messages in thread From: Fan Zhang @ 2019-07-04 10:42 UTC (permalink / raw) To: dev; +Cc: akhil.goyal, konstantin.ananyev, Fan Zhang This patch updates the ipsec-secgw application to support header reconstruction. In addition a series of tests have been added to prove the implementation's correctness. Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com> --- doc/guides/rel_notes/release_19_08.rst | 6 + examples/ipsec-secgw/sa.c | 2 + examples/ipsec-secgw/test/run_test.sh | 3 +- .../test/tun_null_header_reconstruct.py | 479 +++++++++++++++++++++ 4 files changed, 489 insertions(+), 1 deletion(-) create mode 100755 examples/ipsec-secgw/test/tun_null_header_reconstruct.py diff --git a/doc/guides/rel_notes/release_19_08.rst b/doc/guides/rel_notes/release_19_08.rst index 6da020db1..b02cfb4d3 100644 --- a/doc/guides/rel_notes/release_19_08.rst +++ b/doc/guides/rel_notes/release_19_08.rst @@ -128,6 +128,12 @@ New Features Added telemetry mode to l3fwd-power application to report application level busyness, empty and full polls of rte_eth_rx_burst(). +* **Updated IPSec library Header Reconstruction.** + + Updated the IPSec library with ECN and DSCP field header reconstruction + feature followed by RFC4301. The IPSec-secgw sample application is also + updated to support this feature by default. + Removed Items ------------- diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index c672b4a60..1083915f9 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -1063,6 +1063,8 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss, prm->ipsec_xform.mode = (IS_TRANSPORT(ss->flags)) ? RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; + prm->ipsec_xform.options.ecn = 1; + prm->ipsec_xform.options.copy_dscp = 1; if (IS_IP4_TUNNEL(ss->flags)) { prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; diff --git a/examples/ipsec-secgw/test/run_test.sh b/examples/ipsec-secgw/test/run_test.sh index b8c9fcda5..8055a4c04 100755 --- a/examples/ipsec-secgw/test/run_test.sh +++ b/examples/ipsec-secgw/test/run_test.sh @@ -64,7 +64,8 @@ trs_3descbc_sha1_old \ trs_3descbc_sha1_esn \ trs_3descbc_sha1_esn_atom" -PKT_TESTS="trs_ipv6opts" +PKT_TESTS="trs_ipv6opts \ +tun_null_header_reconstruct" DIR=$(dirname $0) diff --git a/examples/ipsec-secgw/test/tun_null_header_reconstruct.py b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py new file mode 100755 index 000000000..d4f42dfc0 --- /dev/null +++ b/examples/ipsec-secgw/test/tun_null_header_reconstruct.py @@ -0,0 +1,479 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Intel Corporation + +from scapy.all import * +import unittest +import pkttest + +#{ipv4{ipv4}} test +SRC_ADDR_IPV4_1 = "192.168.1.1" +DST_ADDR_IPV4_1 = "192.168.2.1" + +#{ipv6{ipv6}} test +SRC_ADDR_IPV6_1 = "1111:0000:0000:0000:0000:0000:0000:0001" +DST_ADDR_IPV6_1 = "2222:0000:0000:0000:0000:0000:0000:0001" + +#{ipv4{ipv6}} test +SRC_ADDR_IPV4_2 = "192.168.11.1" +DST_ADDR_IPV4_2 = "192.168.12.1" +SRC_ADDR_IPV6_2 = "1111:0000:0000:0000:0000:0000:0001:0001" +DST_ADDR_IPV6_2 = "2222:0000:0000:0000:0000:0000:0001:0001" + +#{ipv6{ipv4}} test +SRC_ADDR_IPV4_3 = "192.168.21.1" +DST_ADDR_IPV4_3 = "192.168.22.1" +SRC_ADDR_IPV6_3 = "1111:0000:0000:0000:0000:0001:0001:0001" +DST_ADDR_IPV6_3 = "2222:0000:0000:0000:0000:0001:0001:0001" + +def config(): + return """ +#outter-ipv4 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 5 pri 1 \\ +src {0}/32 \\ +dst {1}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 6 pri 1 \\ +src {1}/32 \\ +dst {0}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {0} dst {1} +sa in 6 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {1} dst {0} + +rt ipv4 dst {0}/32 port 1 +rt ipv4 dst {1}/32 port 0 + +#outter-ipv6 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 7 pri 1 \\ +src {2}/128 \\ +dst {3}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 8 pri 1 \\ +src {3}/128 \\ +dst {2}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 7 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {2} dst {3} +sa in 8 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {3} dst {2} + +rt ipv6 dst {2}/128 port 1 +rt ipv6 dst {3}/128 port 0 + +#outter-ipv4 inner-ipv6 tunnel mode test +sp ipv6 out esp protect 9 pri 1 \\ +src {4}/128 \\ +dst {5}/128 \\ +sport 0:65535 dport 0:65535 + +sp ipv6 in esp protect 10 pri 1 \\ +src {5}/128 \\ +dst {4}/128 \\ +sport 0:65535 dport 0:65535 + +sa out 9 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {6} dst {7} +sa in 10 cipher_algo null auth_algo null mode ipv4-tunnel \\ +src {7} dst {6} + +rt ipv6 dst {4}/128 port 1 +rt ipv4 dst {7}/32 port 0 + +#outter-ipv6 inner-ipv4 tunnel mode test +sp ipv4 out esp protect 11 pri 1 \\ +src {8}/32 \\ +dst {9}/32 \\ +sport 0:65535 dport 0:65535 + +sp ipv4 in esp protect 12 pri 1 \\ +src {9}/32 \\ +dst {8}/32 \\ +sport 0:65535 dport 0:65535 + +sa out 11 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {10} dst {11} +sa in 12 cipher_algo null auth_algo null mode ipv6-tunnel \\ +src {11} dst {10} + +rt ipv4 dst {8}/32 port 1 +rt ipv6 dst {11}/128 port 0 +""".format(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, SRC_ADDR_IPV4_2, DST_ADDR_IPV4_2, + SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, SRC_ADDR_IPV6_3, DST_ADDR_IPV6_3) + +ECN_ECT0 = 0x02 +ECN_ECT1 = 0x01 +ECN_CE = 0x03 +DSCP_1 = 0x04 +DSCP_3F = 0xFC + +class TestTunnelHeaderReconstruct(unittest.TestCase): + def setUp(self): + self.px = pkttest.PacketXfer() + th = IP(src=DST_ADDR_IPV4_1, dst=SRC_ADDR_IPV4_1) + self.sa_ipv4v4 = SecurityAssociation(ESP, spi=6, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_1, dst=SRC_ADDR_IPV6_1) + self.sa_ipv6v6 = SecurityAssociation(ESP, spi=8, tunnel_header = th) + + th = IP(src=DST_ADDR_IPV4_2, dst=SRC_ADDR_IPV4_2) + self.sa_ipv4v6 = SecurityAssociation(ESP, spi=10, tunnel_header = th) + + th = IPv6(src=DST_ADDR_IPV6_3, dst=SRC_ADDR_IPV6_3) + self.sa_ipv6v4 = SecurityAssociation(ESP, spi=12, tunnel_header = th) + + def gen_pkt_plain_ipv4(self, src, dst, tos): + pkt = IP(src=src, dst=dst, tos=tos) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_plain_ipv6(self, src, dst, tc): + pkt = IPv6(src=src, dst=dst, tc=tc) + pkt /= UDP(sport=123,dport=456)/Raw(load="abc") + return pkt + + def gen_pkt_tun_ipv4v4(self, tos_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_1, SRC_ADDR_IPV4_1, + tos_inner) + pkt = self.sa_ipv4v4.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 6) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v6(self, tc_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_1, SRC_ADDR_IPV6_1, + tc_inner) + pkt = self.sa_ipv6v6.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 8) + pkt[IPv6].tc = tc_outter + return pkt + + def gen_pkt_tun_ipv4v6(self, tos_outter, tc_inner): + pkt = self.gen_pkt_plain_ipv6(DST_ADDR_IPV6_2, SRC_ADDR_IPV6_2, + tc_inner) + pkt = self.sa_ipv4v6.encrypt(pkt) + self.assertEqual(pkt[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 10) + pkt[IP].tos = tos_outter + return pkt + + def gen_pkt_tun_ipv6v4(self, tc_outter, tos_inner): + pkt = self.gen_pkt_plain_ipv4(DST_ADDR_IPV4_3, SRC_ADDR_IPV4_3, + tos_inner) + pkt = self.sa_ipv6v4.encrypt(pkt) + self.assertEqual(pkt[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(pkt[ESP].spi, 12) + pkt[IPv6].tc = tc_outter + return pkt + +#RFC4301 5.1.2.1 & 5.1.2.2, outbound packets shall be copied ECN field + def test_outb_ipv4v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_outb_ipv4v6_ecn(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_outb_ipv6v4_ecn(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_ECT0) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + ECN_CE) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + +#RFC4301 5.1.2.1 & 5.1.2.2, if outbound packets ECN is CE (0x3), inbound packets +#ECN is overwritten to CE, otherwise no change + +#Outter header not CE, Inner header should be no change + def test_inb_ipv4v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_no_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT0) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT0, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_ECT1) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_ECT1, ECN_CE) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#Outter header CE, Inner header should be changed to CE + def test_inb_ipv4v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + def test_inb_ipv6v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv4v6_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + pkt = self.gen_pkt_tun_ipv4v6(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, ECN_CE) + + def test_inb_ipv6v4_ecn_inner_change(self): + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT0) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + + pkt = self.gen_pkt_tun_ipv6v4(ECN_CE, ECN_ECT1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, ECN_CE) + +#RFC4301 5.1.2.1.5 Outer DS field should be copied from Inner DS field + def test_outb_ipv4v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_1, DST_ADDR_IPV4_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 5) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_1, DST_ADDR_IPV6_1, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 7) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_outb_ipv4v6_dscp(self): + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_plain_ipv6(SRC_ADDR_IPV6_2, DST_ADDR_IPV6_2, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 9) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_outb_ipv6v4_dscp(self): + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_1) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_plain_ipv4(SRC_ADDR_IPV4_3, DST_ADDR_IPV4_3, + DSCP_3F) + resp = self.px.xfer_unprotected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_ESP) + self.assertEqual(resp[ESP].spi, 11) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + +#RFC4301 5.1.2.1.5 Inner DS field should not be affected by Outer DS field + def test_inb_ipv4v4_dscp(self): + pkt = self.gen_pkt_tun_ipv4v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + + def test_inb_ipv6v6_dscp(self): + pkt = self.gen_pkt_tun_ipv6v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv4v6_dscp(self): + pkt = self.gen_pkt_tun_ipv4v6(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_1) + + pkt = self.gen_pkt_tun_ipv4v6(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IPv6].nh, socket.IPPROTO_UDP) + self.assertEqual(resp[IPv6].tc, DSCP_3F) + + def test_inb_ipv6v4_dscp(self): + pkt = self.gen_pkt_tun_ipv6v4(DSCP_3F, DSCP_1) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_1) + + pkt = self.gen_pkt_tun_ipv6v4(DSCP_1, DSCP_3F) + resp = self.px.xfer_protected(pkt) + self.assertEqual(resp[IP].proto, socket.IPPROTO_UDP) + self.assertEqual(resp[IP].tos, DSCP_3F) + +pkttest.pkttest() -- 2.14.5 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v7 0/2] ipsec: ECN and DSCP header reconstruction 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 " Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang @ 2019-07-05 10:12 ` Akhil Goyal 2 siblings, 0 replies; 27+ messages in thread From: Akhil Goyal @ 2019-07-05 10:12 UTC (permalink / raw) To: Fan Zhang, dev; +Cc: konstantin.ananyev > > This patchset adds the ECN and DSCP tunnel mode header reconstruction > support for rte_ipsec library. The ipsec-secgw sample application is > updated with the feature's enabling and a python3 script for testing > the correctness of the implementation. > > v7: > - rebased on top of latest dpdk-next-crypto. > > v6: > - update_tun_tos function split for inbound/outbound. > - get/set ipv6 tc change from macro back to inline functions. > > v5: > - Fixed a checkpatch error. > > v4: > - Fixed a bug. > - Refrabricated the code a bit. > > v3: > - Rebased on top of latest dpdk-next-crypto. > - Updated the library with individual header reconstruction function. > > v2: > - Fixed a few bugs. > - Updated according to Konstantin's comments. > - Added python script for testing. > > Fan Zhang (2): > lib/ipsec: add support for header construction > examples/ipsec-secgw: support header reconstruction > > doc/guides/rel_notes/release_19_08.rst | 6 + > examples/ipsec-secgw/sa.c | 2 + > examples/ipsec-secgw/test/run_test.sh | 3 +- > .../test/tun_null_header_reconstruct.py | 479 +++++++++++++++++++++ > lib/librte_ipsec/esp_inb.c | 13 +- > lib/librte_ipsec/esp_outb.c | 4 +- > lib/librte_ipsec/iph.h | 164 ++++++- > lib/librte_ipsec/rte_ipsec_sa.h | 10 + > lib/librte_ipsec/sa.c | 18 + > lib/librte_ipsec/sa.h | 2 + > lib/librte_net/rte_ip.h | 2 + > lib/librte_security/rte_security.h | 9 + > 12 files changed, 703 insertions(+), 9 deletions(-) > create mode 100755 examples/ipsec- > secgw/test/tun_null_header_reconstruct.py > > -- > 2.14.5 Applied to dpdk-next-crypto Thanks. ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2019-07-05 10:12 UTC | newest] Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-05-17 16:03 [dpdk-dev] [PATCH v1] lib/ipsec: add support for header construction Marko Kovacevic 2019-05-19 16:26 ` Ananyev, Konstantin 2019-06-20 12:27 ` Akhil Goyal 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 0/2] ipsec: ECN and DSCP header reconstruction Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-25 13:43 ` [dpdk-dev] [PATCH v2 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-26 22:15 ` Ananyev, Konstantin 2019-06-26 15:05 ` [dpdk-dev] [PATCH v3 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-06-28 12:39 ` [dpdk-dev] [PATCH v4 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-07-01 10:40 ` Ananyev, Konstantin 2019-06-28 13:22 ` [dpdk-dev] [PATCH v5 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-07-01 10:41 ` Ananyev, Konstantin 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Fan Zhang 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-07-01 13:11 ` Olivier Matz 2019-07-01 12:01 ` [dpdk-dev] [PATCH v6 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-07-03 10:11 ` [dpdk-dev] [PATCH v6 0/2] ipsec: ECN and DSCP " Akhil Goyal 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 " Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 1/2] lib/ipsec: add support for header construction Fan Zhang 2019-07-04 10:42 ` [dpdk-dev] [PATCH v7 2/2] examples/ipsec-secgw: support header reconstruction Fan Zhang 2019-07-05 10:12 ` [dpdk-dev] [PATCH v7 0/2] ipsec: ECN and DSCP " Akhil Goyal
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).