1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
12 * Contains functions/structures/macros to manipulate IPv4/IPv6 headers
13 * used internally by ipsec library.
17 * Move preceding (L3) headers down to remove ESP header and IV.
20 remove_esph(char *np, char *op, uint32_t hlen)
24 for (i = hlen; i-- != 0; np[i] = op[i])
29 * Move preceding (L3) headers up to free space for ESP header and IV.
32 insert_esph(char *np, char *op, uint32_t hlen)
36 for (i = 0; i != hlen; i++)
40 /* update original ip header fields for transport case */
42 update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen,
43 uint32_t l2len, uint32_t l3len, uint8_t proto)
48 if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) {
49 struct rte_ipv4_hdr *v4h;
52 rc = v4h->next_proto_id;
53 v4h->next_proto_id = proto;
54 v4h->total_length = rte_cpu_to_be_16(plen - l2len);
57 struct rte_ipv6_hdr *v6h;
62 /* basic IPv6 header with no extensions */
63 if (l3len == sizeof(struct rte_ipv6_hdr))
66 /* IPv6 with extensions */
72 /* locate last extension within l3len bytes */
75 ext_len = sizeof(struct rte_ipv6_hdr);
77 while (pd + ext_len < plimit) {
79 nh = rte_ipv6_get_next_ext(pd, nh, &ext_len);
84 /* invalid l3len - extension exceeds header length */
85 if (unlikely(pd + ext_len != plimit))
88 /* save last extension offset */
92 /* update header type; return original value */
96 /* fix packet length */
97 v6h->payload_len = rte_cpu_to_be_16(plen - l2len -
105 * Inline functions to get and set ipv6 packet header traffic class (TC) field.
107 static inline uint8_t
108 get_ipv6_tc(rte_be32_t vtc_flow)
112 v = rte_be_to_cpu_32(vtc_flow);
113 return v >> RTE_IPV6_HDR_TC_SHIFT;
116 static inline rte_be32_t
117 set_ipv6_tc(rte_be32_t vtc_flow, uint32_t tos)
121 v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT);
122 vtc_flow &= ~rte_cpu_to_be_32(RTE_IPV6_HDR_TC_MASK);
124 return (v | vtc_flow);
128 * Update type-of-service/traffic-class field of outbound tunnel packet.
130 * @param ref_h: reference header, for outbound it is inner header, otherwise
132 * @param update_h: header to be updated tos/tc field, for outbound it is outer
133 * header, otherwise inner header.
134 * @param tos_mask: type-of-service mask stored in sa.
135 * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6.
136 * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6.
139 update_outb_tun_tos(const void *ref_h, void *update_h, uint32_t tos_mask,
140 uint8_t is_outh_ipv4, uint8_t is_inh_ipv4)
142 uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4);
143 struct rte_ipv4_hdr *v4out_h;
144 struct rte_ipv6_hdr *v6out_h;
148 case 0: /*outh ipv6, inh ipv6 */
150 otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask;
151 itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)->
152 vtc_flow) & tos_mask;
153 v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp);
155 case 1: /*outh ipv6, inh ipv4 */
157 otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask;
158 itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service &
160 v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp);
162 case 2: /*outh ipv4, inh ipv6 */
164 otp = v4out_h->type_of_service & ~tos_mask;
165 itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)->
166 vtc_flow) & tos_mask;
167 v4out_h->type_of_service = (otp | itp);
169 case 3: /* outh ipv4, inh ipv4 */
171 otp = v4out_h->type_of_service & ~tos_mask;
172 itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service &
174 v4out_h->type_of_service = (otp | itp);
180 * Update type-of-service/traffic-class field of inbound tunnel packet.
182 * @param ref_h: reference header, for outbound it is inner header, otherwise
184 * @param update_h: header to be updated tos/tc field, for outbound it is outer
185 * header, otherwise inner header.
186 * @param is_outh_ipv4: 1 if outer header is ipv4, 0 if it is ipv6.
187 * @param is_inner_ipv4: 1 if inner header is ipv4, 0 if it is ipv6.
190 update_inb_tun_tos(const void *ref_h, void *update_h,
191 uint8_t is_outh_ipv4, uint8_t is_inh_ipv4)
193 uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4);
194 struct rte_ipv4_hdr *v4in_h;
195 struct rte_ipv6_hdr *v6in_h;
196 uint8_t ecn_v4out, ecn_v4in;
197 uint32_t ecn_v6out, ecn_v6in;
200 case 0: /* outh ipv6, inh ipv6 */
202 ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow &
203 rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
204 ecn_v6in = v6in_h->vtc_flow &
205 rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
206 if ((ecn_v6out == rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE)) &&
209 rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE);
211 case 1: /* outh ipv6, inh ipv4 */
213 ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow &
214 rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
215 ecn_v4in = v4in_h->type_of_service & RTE_IPV4_HDR_ECN_MASK;
216 if ((ecn_v6out == rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE)) &&
218 v4in_h->type_of_service |= RTE_IPV4_HDR_ECN_CE;
220 case 2: /* outh ipv4, inh ipv6 */
222 ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)->
223 type_of_service & RTE_IPV4_HDR_ECN_MASK;
224 ecn_v6in = v6in_h->vtc_flow &
225 rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
226 if (ecn_v4out == RTE_IPV4_HDR_ECN_CE && ecn_v6in != 0)
228 rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE);
230 case 3: /* outh ipv4, inh ipv4 */
232 ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)->
233 type_of_service & RTE_IPV4_HDR_ECN_MASK;
234 ecn_v4in = v4in_h->type_of_service & RTE_IPV4_HDR_ECN_MASK;
235 if (ecn_v4out == RTE_IPV4_HDR_ECN_CE && ecn_v4in != 0)
236 v4in_h->type_of_service |= RTE_IPV4_HDR_ECN_CE;
241 /* update original and new ip header fields for tunnel case */
243 update_tun_outb_l3hdr(const struct rte_ipsec_sa *sa, void *outh,
244 const void *inh, uint32_t plen, uint32_t l2len, rte_be16_t pid)
246 struct rte_ipv4_hdr *v4h;
247 struct rte_ipv6_hdr *v6h;
248 uint8_t is_outh_ipv4;
250 if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) {
253 v4h->packet_id = pid;
254 v4h->total_length = rte_cpu_to_be_16(plen - l2len);
258 v6h->payload_len = rte_cpu_to_be_16(plen - l2len -
262 if (sa->type & TUN_HDR_MSK)
263 update_outb_tun_tos(inh, outh, sa->tos_mask, is_outh_ipv4,
264 ((sa->type & RTE_IPSEC_SATP_IPV_MASK) ==
265 RTE_IPSEC_SATP_IPV4));
269 update_tun_inb_l3hdr(const struct rte_ipsec_sa *sa, const void *outh,
272 if (sa->type & TUN_HDR_MSK)
273 update_inb_tun_tos(outh, inh,
274 ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0),
275 ((sa->type & RTE_IPSEC_SATP_IPV_MASK) ==
276 RTE_IPSEC_SATP_IPV4));