Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #ifndef _IPH_H_
6 : : #define _IPH_H_
7 : :
8 : : #include <rte_ip.h>
9 : :
10 : : /**
11 : : * @file iph.h
12 : : * Contains functions/structures/macros to manipulate IPv4/IPv6 headers
13 : : * used internally by ipsec library.
14 : : */
15 : :
16 : : /*
17 : : * Move preceding (L3) headers down to remove ESP header and IV.
18 : : */
19 : : static inline void
20 : : remove_esph(char *np, char *op, uint32_t hlen)
21 : : {
22 : : uint32_t i;
23 : :
24 [ # # ]: 0 : for (i = hlen; i-- != 0; np[i] = op[i])
25 : : ;
26 : : }
27 : :
28 : : /*
29 : : * Move preceding (L3) headers up to free space for ESP header and IV.
30 : : */
31 : : static inline void
32 : : insert_esph(char *np, char *op, uint32_t hlen)
33 : : {
34 : : uint32_t i;
35 : :
36 [ # # ]: 0 : for (i = 0; i != hlen; i++)
37 : 0 : np[i] = op[i];
38 : : }
39 : :
40 : : /* update original ip header fields for transport case */
41 : : static inline int
42 : 0 : update_trs_l3hdr(const struct rte_ipsec_sa *sa, void *p, uint32_t plen,
43 : : uint32_t l2len, uint32_t l3len, uint8_t proto)
44 : : {
45 : : int32_t rc;
46 : :
47 : : /* IPv4 */
48 [ # # ]: 0 : if ((sa->type & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) {
49 : : struct rte_ipv4_hdr *v4h;
50 : :
51 : : v4h = p;
52 : 0 : rc = v4h->next_proto_id;
53 : 0 : v4h->next_proto_id = proto;
54 [ # # ]: 0 : v4h->total_length = rte_cpu_to_be_16(plen - l2len);
55 : : /* IPv6 */
56 : : } else {
57 : : struct rte_ipv6_hdr *v6h;
58 : : uint8_t *p_nh;
59 : :
60 : : v6h = p;
61 : :
62 : : /* basic IPv6 header with no extensions */
63 [ # # ]: 0 : if (l3len == sizeof(struct rte_ipv6_hdr))
64 : 0 : p_nh = &v6h->proto;
65 : :
66 : : /* IPv6 with extensions */
67 : : else {
68 : : size_t ext_len;
69 : : int nh;
70 : : uint8_t *pd, *plimit;
71 : :
72 : : /* locate last extension within l3len bytes */
73 : : pd = (uint8_t *)p;
74 : 0 : plimit = pd + l3len;
75 : 0 : ext_len = sizeof(struct rte_ipv6_hdr);
76 : 0 : nh = v6h->proto;
77 [ # # ]: 0 : while (pd + ext_len < plimit) {
78 : : pd += ext_len;
79 : 0 : nh = rte_ipv6_get_next_ext(pd, nh, &ext_len);
80 [ # # ]: 0 : if (unlikely(nh < 0))
81 : 0 : return -EINVAL;
82 : : }
83 : :
84 : : /* invalid l3len - extension exceeds header length */
85 [ # # ]: 0 : if (unlikely(pd + ext_len != plimit))
86 : : return -EINVAL;
87 : :
88 : : /* save last extension offset */
89 : : p_nh = pd;
90 : : }
91 : :
92 : : /* update header type; return original value */
93 : 0 : rc = *p_nh;
94 : 0 : *p_nh = proto;
95 : :
96 : : /* fix packet length */
97 [ # # ]: 0 : v6h->payload_len = rte_cpu_to_be_16(plen - l2len -
98 : : sizeof(*v6h));
99 : : }
100 : :
101 : : return rc;
102 : : }
103 : :
104 : : /*
105 : : * Inline functions to get and set ipv6 packet header traffic class (TC) field.
106 : : */
107 : : static inline uint8_t
108 : : get_ipv6_tc(rte_be32_t vtc_flow)
109 : : {
110 : : uint32_t v;
111 : :
112 : 0 : v = rte_be_to_cpu_32(vtc_flow);
113 : 0 : return v >> RTE_IPV6_HDR_TC_SHIFT;
114 : : }
115 : :
116 : : static inline rte_be32_t
117 : : set_ipv6_tc(rte_be32_t vtc_flow, uint32_t tos)
118 : : {
119 : : uint32_t v;
120 : :
121 : 0 : v = rte_cpu_to_be_32(tos << RTE_IPV6_HDR_TC_SHIFT);
122 : 0 : vtc_flow &= ~rte_cpu_to_be_32(RTE_IPV6_HDR_TC_MASK);
123 : :
124 : 0 : return (v | vtc_flow);
125 : : }
126 : :
127 : : /**
128 : : * Update type-of-service/traffic-class field of outbound tunnel packet.
129 : : *
130 : : * @param ref_h: reference header, for outbound it is inner header, otherwise
131 : : * outer header.
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.
137 : : */
138 : : static inline void
139 : 0 : 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)
141 : : {
142 : 0 : uint8_t idx = ((is_outh_ipv4 << 1) | is_inh_ipv4);
143 : : struct rte_ipv4_hdr *v4out_h;
144 : : struct rte_ipv6_hdr *v6out_h;
145 : : uint32_t itp, otp;
146 : :
147 [ # # # # : 0 : switch (idx) {
# ]
148 : 0 : case 0: /*outh ipv6, inh ipv6 */
149 : : v6out_h = update_h;
150 [ # # ]: 0 : otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask;
151 [ # # ]: 0 : itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)->
152 : : vtc_flow) & tos_mask;
153 [ # # ]: 0 : v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp);
154 : 0 : break;
155 : 0 : case 1: /*outh ipv6, inh ipv4 */
156 : : v6out_h = update_h;
157 [ # # ]: 0 : otp = get_ipv6_tc(v6out_h->vtc_flow) & ~tos_mask;
158 : 0 : itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service &
159 : : tos_mask;
160 [ # # ]: 0 : v6out_h->vtc_flow = set_ipv6_tc(v6out_h->vtc_flow, otp | itp);
161 : 0 : break;
162 : 0 : case 2: /*outh ipv4, inh ipv6 */
163 : : v4out_h = update_h;
164 : 0 : otp = v4out_h->type_of_service & ~tos_mask;
165 [ # # ]: 0 : itp = get_ipv6_tc(((const struct rte_ipv6_hdr *)ref_h)->
166 : : vtc_flow) & tos_mask;
167 : 0 : v4out_h->type_of_service = (otp | itp);
168 : 0 : break;
169 : 0 : case 3: /* outh ipv4, inh ipv4 */
170 : : v4out_h = update_h;
171 : 0 : otp = v4out_h->type_of_service & ~tos_mask;
172 : 0 : itp = ((const struct rte_ipv4_hdr *)ref_h)->type_of_service &
173 : : tos_mask;
174 : 0 : v4out_h->type_of_service = (otp | itp);
175 : 0 : break;
176 : : }
177 : 0 : }
178 : :
179 : : /**
180 : : * Update type-of-service/traffic-class field of inbound tunnel packet.
181 : : *
182 : : * @param ref_h: reference header, for outbound it is inner header, otherwise
183 : : * outer header.
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.
188 : : */
189 : : static inline void
190 : 0 : update_inb_tun_tos(const void *ref_h, void *update_h,
191 : : uint8_t is_outh_ipv4, uint8_t is_inh_ipv4)
192 : : {
193 : 0 : 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;
198 : :
199 [ # # # # : 0 : switch (idx) {
# ]
200 : 0 : case 0: /* outh ipv6, inh ipv6 */
201 : : v6in_h = update_h;
202 : 0 : ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow &
203 : : rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
204 : 0 : ecn_v6in = v6in_h->vtc_flow &
205 : : rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
206 [ # # # # ]: 0 : if ((ecn_v6out == rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE)) &&
207 : : (ecn_v6in != 0))
208 : 0 : v6in_h->vtc_flow |=
209 : : rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE);
210 : : break;
211 : 0 : case 1: /* outh ipv6, inh ipv4 */
212 : : v4in_h = update_h;
213 : 0 : ecn_v6out = ((const struct rte_ipv6_hdr *)ref_h)->vtc_flow &
214 : : rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
215 : 0 : ecn_v4in = v4in_h->type_of_service & RTE_IPV4_HDR_ECN_MASK;
216 [ # # # # ]: 0 : if ((ecn_v6out == rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE)) &&
217 : : (ecn_v4in != 0))
218 : 0 : v4in_h->type_of_service |= RTE_IPV4_HDR_ECN_CE;
219 : : break;
220 : 0 : case 2: /* outh ipv4, inh ipv6 */
221 : : v6in_h = update_h;
222 : 0 : ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)->
223 : : type_of_service & RTE_IPV4_HDR_ECN_MASK;
224 : 0 : ecn_v6in = v6in_h->vtc_flow &
225 : : rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_MASK);
226 [ # # ]: 0 : if (ecn_v4out == RTE_IPV4_HDR_ECN_CE && ecn_v6in != 0)
227 : 0 : v6in_h->vtc_flow |=
228 : : rte_cpu_to_be_32(RTE_IPV6_HDR_ECN_CE);
229 : : break;
230 : 0 : case 3: /* outh ipv4, inh ipv4 */
231 : : v4in_h = update_h;
232 : 0 : ecn_v4out = ((const struct rte_ipv4_hdr *)ref_h)->
233 : : type_of_service & RTE_IPV4_HDR_ECN_MASK;
234 : 0 : ecn_v4in = v4in_h->type_of_service & RTE_IPV4_HDR_ECN_MASK;
235 [ # # ]: 0 : if (ecn_v4out == RTE_IPV4_HDR_ECN_CE && ecn_v4in != 0)
236 : 0 : v4in_h->type_of_service |= RTE_IPV4_HDR_ECN_CE;
237 : : break;
238 : : }
239 : 0 : }
240 : :
241 : : /* update original and new ip header fields for tunnel case */
242 : : static inline void
243 : 0 : 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)
245 : : {
246 : : struct rte_ipv4_hdr *v4h;
247 : : struct rte_ipv6_hdr *v6h;
248 : : uint8_t is_outh_ipv4;
249 : :
250 [ # # ]: 0 : if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) {
251 : : is_outh_ipv4 = 1;
252 : : v4h = outh;
253 : 0 : v4h->packet_id = pid;
254 [ # # ]: 0 : v4h->total_length = rte_cpu_to_be_16(plen - l2len);
255 : : } else {
256 : : is_outh_ipv4 = 0;
257 : : v6h = outh;
258 [ # # ]: 0 : v6h->payload_len = rte_cpu_to_be_16(plen - l2len -
259 : : sizeof(*v6h));
260 : : }
261 : :
262 [ # # ]: 0 : if (sa->type & TUN_HDR_MSK)
263 : 0 : update_outb_tun_tos(inh, outh, sa->tos_mask, is_outh_ipv4,
264 : 0 : ((sa->type & RTE_IPSEC_SATP_IPV_MASK) ==
265 : : RTE_IPSEC_SATP_IPV4));
266 : 0 : }
267 : :
268 : : static inline void
269 : 0 : update_tun_inb_l3hdr(const struct rte_ipsec_sa *sa, const void *outh,
270 : : void *inh)
271 : : {
272 [ # # ]: 0 : if (sa->type & TUN_HDR_MSK)
273 : 0 : update_inb_tun_tos(outh, inh,
274 : 0 : ((sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) != 0),
275 : 0 : ((sa->type & RTE_IPSEC_SATP_IPV_MASK) ==
276 : : RTE_IPSEC_SATP_IPV4));
277 : 0 : }
278 : :
279 : : #endif /* _IPH_H_ */
|