1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016 Intel Corporation 3 */ 4 5 #ifndef __IPIP_H__ 6 #define __IPIP_H__ 7 8 #include <stdint.h> 9 #include <netinet/in.h> 10 #include <netinet/ip.h> 11 #include <netinet/ip6.h> 12 13 #include <rte_mbuf.h> 14 15 static inline void * 16 ipip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t is_ipv6, 17 struct ip_addr *src, struct ip_addr *dst) 18 { 19 struct ip *inip4, *outip4; 20 struct ip6_hdr *inip6, *outip6; 21 uint8_t ds_ecn; 22 23 inip4 = rte_pktmbuf_mtod(m, struct ip *); 24 25 RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION); 26 27 if (inip4->ip_v == IPVERSION) { 28 /* XXX This should be done by the forwarding engine instead */ 29 inip4->ip_ttl -= 1; 30 if (inip4->ip_sum >= rte_cpu_to_be_16(0xffff - 0x100)) 31 inip4->ip_sum += rte_cpu_to_be_16(0x100) + 1; 32 else 33 inip4->ip_sum += rte_cpu_to_be_16(0x100); 34 ds_ecn = inip4->ip_tos; 35 } else { 36 inip6 = (struct ip6_hdr *)inip4; 37 /* XXX This should be done by the forwarding engine instead */ 38 inip6->ip6_hops -= 1; 39 ds_ecn = ntohl(inip6->ip6_flow) >> 20; 40 } 41 42 if (is_ipv6) { 43 offset += sizeof(struct ip6_hdr); 44 outip6 = (struct ip6_hdr *)rte_pktmbuf_prepend(m, offset); 45 46 RTE_ASSERT(outip6 != NULL); 47 48 /* Per RFC4301 5.1.2.1 */ 49 outip6->ip6_flow = htonl(IP6_VERSION << 28 | ds_ecn << 20); 50 outip6->ip6_plen = htons(rte_pktmbuf_data_len(m) - 51 sizeof(struct ip6_hdr)); 52 53 outip6->ip6_nxt = IPPROTO_ESP; 54 outip6->ip6_hops = IPDEFTTL; 55 56 memcpy(&outip6->ip6_src.s6_addr, src, 16); 57 memcpy(&outip6->ip6_dst.s6_addr, dst, 16); 58 59 return outip6; 60 } 61 62 offset += sizeof(struct ip); 63 outip4 = (struct ip *)rte_pktmbuf_prepend(m, offset); 64 65 RTE_ASSERT(outip4 != NULL); 66 67 /* Per RFC4301 5.1.2.1 */ 68 outip4->ip_v = IPVERSION; 69 outip4->ip_hl = 5; 70 outip4->ip_tos = ds_ecn; 71 outip4->ip_len = htons(rte_pktmbuf_data_len(m)); 72 73 outip4->ip_id = 0; 74 outip4->ip_off = 0; 75 76 outip4->ip_ttl = IPDEFTTL; 77 outip4->ip_p = IPPROTO_ESP; 78 79 outip4->ip_src.s_addr = src->ip.ip4; 80 outip4->ip_dst.s_addr = dst->ip.ip4; 81 m->packet_type &= ~RTE_PTYPE_L4_MASK; 82 return outip4; 83 } 84 85 static inline struct ip * 86 ip4ip_outbound(struct rte_mbuf *m, uint32_t offset, 87 struct ip_addr *src, struct ip_addr *dst) 88 { 89 return ipip_outbound(m, offset, 0, src, dst); 90 } 91 92 static inline struct ip6_hdr * 93 ip6ip_outbound(struct rte_mbuf *m, uint32_t offset, 94 struct ip_addr *src, struct ip_addr *dst) 95 { 96 return ipip_outbound(m, offset, 1, src, dst); 97 } 98 99 static inline void 100 ip4_ecn_setup(struct ip *ip4) 101 { 102 if (ip4->ip_tos & IPTOS_ECN_MASK) { 103 unsigned long sum; 104 uint8_t old; 105 106 old = ip4->ip_tos; 107 ip4->ip_tos |= IPTOS_ECN_CE; 108 sum = old + (~(*(uint8_t *)&ip4->ip_tos) & 0xff); 109 sum += rte_be_to_cpu_16(ip4->ip_sum); 110 sum = (sum & 0xffff) + (sum >> 16); 111 ip4->ip_sum = rte_cpu_to_be_16(sum + (sum >> 16)); 112 } 113 } 114 115 static inline void 116 ip6_ecn_setup(struct ip6_hdr *ip6) 117 { 118 if ((ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK) 119 ip6->ip6_flow = htonl(ntohl(ip6->ip6_flow) | 120 (IPTOS_ECN_CE << 20)); 121 } 122 123 static inline void 124 ipip_inbound(struct rte_mbuf *m, uint32_t offset) 125 { 126 struct ip *inip4, *outip4; 127 struct ip6_hdr *inip6, *outip6; 128 uint32_t ip_len, set_ecn; 129 130 outip4 = rte_pktmbuf_mtod(m, struct ip*); 131 132 RTE_ASSERT(outip4->ip_v == IPVERSION || outip4->ip_v == IP6_VERSION); 133 134 if (outip4->ip_v == IPVERSION) { 135 ip_len = sizeof(struct ip); 136 set_ecn = ((outip4->ip_tos & IPTOS_ECN_CE) == IPTOS_ECN_CE); 137 } else { 138 outip6 = (struct ip6_hdr *)outip4; 139 ip_len = sizeof(struct ip6_hdr); 140 set_ecn = ntohl(outip6->ip6_flow) >> 20; 141 set_ecn = ((set_ecn & IPTOS_ECN_CE) == IPTOS_ECN_CE); 142 } 143 144 inip4 = (struct ip *)rte_pktmbuf_adj(m, offset + ip_len); 145 RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION); 146 147 /* Check packet is still bigger than IP header (inner) */ 148 RTE_ASSERT(rte_pktmbuf_pkt_len(m) > ip_len); 149 150 /* RFC4301 5.1.2.1 Note 6 */ 151 if (inip4->ip_v == IPVERSION) { 152 if (set_ecn) 153 ip4_ecn_setup(inip4); 154 /* XXX This should be done by the forwarding engine instead */ 155 inip4->ip_ttl -= 1; 156 if (inip4->ip_sum >= rte_cpu_to_be_16(0xffff - 0x100)) 157 inip4->ip_sum += rte_cpu_to_be_16(0x100) + 1; 158 else 159 inip4->ip_sum += rte_cpu_to_be_16(0x100); 160 m->packet_type &= ~RTE_PTYPE_L4_MASK; 161 if (inip4->ip_p == IPPROTO_UDP) 162 m->packet_type |= RTE_PTYPE_L4_UDP; 163 else if (inip4->ip_p == IPPROTO_TCP) 164 m->packet_type |= RTE_PTYPE_L4_TCP; 165 } else { 166 inip6 = (struct ip6_hdr *)inip4; 167 if (set_ecn) 168 ip6_ecn_setup(inip6); 169 /* XXX This should be done by the forwarding engine instead */ 170 inip6->ip6_hops -= 1; 171 } 172 } 173 174 #endif /* __IPIP_H__ */ 175