github.com/datadog/cilium@v1.6.12/bpf/lib/ipv6.h (about) 1 /* 2 * Copyright (C) 2016-2017 Authors of Cilium 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 #ifndef __LIB_IPV6__ 19 #define __LIB_IPV6__ 20 21 #include <linux/ipv6.h> 22 23 #include "dbg.h" 24 #define IPV6_FLOWINFO_MASK bpf_htonl(0x0FFFFFFF) 25 #define IPV6_FLOWLABEL_MASK bpf_htonl(0x000FFFFF) 26 #define IPV6_FLOWLABEL_STATELESS_FLAG bpf_htonl(0x00080000) 27 28 #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) 29 #define IPV6_TCLASS_SHIFT 20 30 31 /* Number of extension headers that can be skipped */ 32 #define IPV6_MAX_HEADERS 4 33 34 #define NEXTHDR_HOP 0 /* Hop-by-hop option header. */ 35 #define NEXTHDR_TCP 6 /* TCP segment. */ 36 #define NEXTHDR_UDP 17 /* UDP message. */ 37 #define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */ 38 #define NEXTHDR_ROUTING 43 /* Routing header. */ 39 #define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */ 40 #define NEXTHDR_GRE 47 /* GRE header. */ 41 #define NEXTHDR_ESP 50 /* Encapsulating security payload. */ 42 #define NEXTHDR_AUTH 51 /* Authentication header. */ 43 #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */ 44 #define NEXTHDR_NONE 59 /* No next header */ 45 #define NEXTHDR_DEST 60 /* Destination options header. */ 46 #define NEXTHDR_SCTP 132 /* SCTP message. */ 47 #define NEXTHDR_MOBILITY 135 /* Mobility header. */ 48 49 #define NEXTHDR_MAX 255 50 51 static inline int ipv6_optlen(struct ipv6_opt_hdr *opthdr) 52 { 53 return (opthdr->hdrlen + 1) << 3; 54 } 55 56 static inline int ipv6_authlen(struct ipv6_opt_hdr *opthdr) 57 { 58 return (opthdr->hdrlen + 2) << 2; 59 } 60 61 static inline int __inline__ ipv6_hdrlen(struct __sk_buff *skb, int l3_off, __u8 *nexthdr) 62 { 63 int i, len = sizeof(struct ipv6hdr); 64 struct ipv6_opt_hdr opthdr; 65 __u8 nh = *nexthdr; 66 67 #pragma unroll 68 for (i = 0; i < IPV6_MAX_HEADERS; i++) { 69 switch (nh) { 70 case NEXTHDR_NONE: 71 return DROP_INVALID_EXTHDR; 72 73 case NEXTHDR_FRAGMENT: 74 return DROP_FRAG_NOSUPPORT; 75 76 case NEXTHDR_HOP: 77 case NEXTHDR_ROUTING: 78 case NEXTHDR_AUTH: 79 case NEXTHDR_DEST: 80 if (skb_load_bytes(skb, l3_off + len, &opthdr, sizeof(opthdr)) < 0) 81 return DROP_INVALID; 82 83 nh = opthdr.nexthdr; 84 if (nh == NEXTHDR_AUTH) 85 len += ipv6_authlen(&opthdr); 86 else 87 len += ipv6_optlen(&opthdr); 88 break; 89 90 default: 91 *nexthdr = nh; 92 return len; 93 } 94 } 95 96 /* Reached limit of supported extension headers */ 97 return DROP_INVALID_EXTHDR; 98 } 99 100 static inline void ipv6_addr_copy(union v6addr *dst, union v6addr *src) 101 { 102 dst->d1 = src->d1; 103 dst->d2 = src->d2; 104 } 105 106 static inline __u64 ipv6_addrcmp(union v6addr *a, union v6addr *b) 107 { 108 __u64 tmp; 109 110 tmp = a->d1 - b->d1; 111 if (!tmp) 112 tmp = a->d2 - b->d2; 113 return tmp; 114 } 115 116 // Only works with contiguous masks. 117 static inline int ipv6_addr_in_net(union v6addr *addr, union v6addr *net, union v6addr *mask) 118 { 119 return ((addr->p1 & mask->p1) == net->p1) 120 && (!mask->p2 121 || (((addr->p2 & mask->p2) == net->p2) 122 && (!mask->p3 123 || (((addr->p3 & mask->p3) == net->p3) 124 && (!mask->p4 || ((addr->p4 & mask->p4) == net->p4)))))); 125 } 126 127 #define GET_PREFIX(PREFIX) \ 128 bpf_htonl(prefix <= 0 ? 0 : prefix < 32 ? ((1<<prefix) - 1) << (32-prefix) \ 129 : 0xFFFFFFFF) 130 131 static inline void ipv6_addr_clear_suffix(union v6addr *addr, int prefix) 132 { 133 addr->p1 &= GET_PREFIX(prefix); 134 prefix -= 32; 135 addr->p2 &= GET_PREFIX(prefix); 136 prefix -= 32; 137 addr->p3 &= GET_PREFIX(prefix); 138 prefix -= 32; 139 addr->p4 &= GET_PREFIX(prefix); 140 prefix -= 32; 141 } 142 143 static inline int ipv6_match_prefix_64(const union v6addr *addr, const union v6addr *prefix) 144 { 145 int tmp; 146 147 tmp = addr->p1 - prefix->p1; 148 if (!tmp) 149 tmp = addr->p2 - prefix->p2; 150 151 return !tmp; 152 } 153 154 static inline int ipv6_dec_hoplimit(struct __sk_buff *skb, int off) 155 { 156 __u8 hl; 157 158 skb_load_bytes(skb, off + offsetof(struct ipv6hdr, hop_limit), 159 &hl, sizeof(hl)); 160 if (hl <= 1) 161 return 1; 162 hl--; 163 if (skb_store_bytes(skb, off + offsetof(struct ipv6hdr, hop_limit), 164 &hl, sizeof(hl), BPF_F_RECOMPUTE_CSUM) < 0) 165 return DROP_WRITE_ERROR; 166 return 0; 167 } 168 169 static inline int ipv6_load_saddr(struct __sk_buff *skb, int off, union v6addr *dst) 170 { 171 return skb_load_bytes(skb, off + offsetof(struct ipv6hdr, saddr), dst->addr, 172 sizeof(((struct ipv6hdr *)NULL)->saddr)); 173 } 174 175 /* Assumes that caller fixes checksum csum_diff() and l4_csum_replace() */ 176 static inline int ipv6_store_saddr(struct __sk_buff *skb, __u8 *addr, int off) 177 { 178 return skb_store_bytes(skb, off + offsetof(struct ipv6hdr, saddr), addr, 16, 0); 179 } 180 181 static inline int ipv6_load_daddr(struct __sk_buff *skb, int off, union v6addr *dst) 182 { 183 return skb_load_bytes(skb, off + offsetof(struct ipv6hdr, daddr), dst->addr, 184 sizeof(((struct ipv6hdr *)NULL)->daddr)); 185 } 186 187 /* Assumes that caller fixes checksum csum_diff() and l4_csum_replace() */ 188 static inline int ipv6_store_daddr(struct __sk_buff *skb, __u8 *addr, int off) 189 { 190 return skb_store_bytes(skb, off + offsetof(struct ipv6hdr, daddr), addr, 16, 0); 191 } 192 193 static inline int ipv6_load_nexthdr(struct __sk_buff *skb, int off, __u8 *nexthdr) 194 { 195 return skb_load_bytes(skb, off + offsetof(struct ipv6hdr, nexthdr), nexthdr, 196 sizeof(__u8)); 197 } 198 199 /* Assumes that caller fixes checksum csum_diff() and l4_csum_replace() */ 200 static inline int ipv6_store_nexthdr(struct __sk_buff *skb, __u8 *nexthdr, int off) 201 { 202 return skb_store_bytes(skb, off + offsetof(struct ipv6hdr, nexthdr), nexthdr, 203 sizeof(__u8), 0); 204 } 205 206 static inline int ipv6_load_paylen(struct __sk_buff *skb, int off, __be16 *len) 207 { 208 return skb_load_bytes(skb, off + offsetof(struct ipv6hdr, payload_len), 209 len, sizeof(*len)); 210 } 211 212 /* Assumes that caller fixes checksum csum_diff() and l4_csum_replace() */ 213 static inline int ipv6_store_paylen(struct __sk_buff *skb, int off, __be16 *len) 214 { 215 return skb_store_bytes(skb, off + offsetof(struct ipv6hdr, payload_len), 216 len, sizeof(*len), 0); 217 } 218 219 static inline int ipv6_store_flowlabel(struct __sk_buff *skb, int off, __be32 label) 220 { 221 __be32 old; 222 223 /* use traffic class from packet */ 224 if (skb_load_bytes(skb, off, &old, 4) < 0) 225 return DROP_INVALID; 226 227 old &= IPV6_TCLASS_MASK; 228 old = bpf_htonl(0x60000000) | label | old; 229 230 if (skb_store_bytes(skb, off, &old, 4, BPF_F_RECOMPUTE_CSUM) < 0) 231 return DROP_WRITE_ERROR; 232 233 return 0; 234 } 235 236 static inline __be32 ipv6_pseudohdr_checksum(struct ipv6hdr *hdr, 237 __u8 next_hdr, 238 __u16 payload_len, __be32 sum) 239 { 240 __be32 len = bpf_htonl((__u32)payload_len); 241 __be32 nexthdr = bpf_htonl((__u32)next_hdr); 242 sum = csum_diff(NULL, 0, &hdr->saddr, sizeof(struct in6_addr), sum); 243 sum = csum_diff(NULL, 0, &hdr->daddr, sizeof(struct in6_addr), sum); 244 sum = csum_diff(NULL, 0, &len, sizeof(len), sum); 245 sum = csum_diff(NULL, 0, &nexthdr, sizeof(nexthdr), sum); 246 247 return sum; 248 } 249 250 /* 251 * Ipv4 mapped address - 0:0:0:0:0:FFFF::/96 252 */ 253 static inline int ipv6_addr_is_mapped(union v6addr *addr) 254 { 255 return addr->p1 == 0 && addr->p2 == 0 && addr->p3 == 0xFFFF0000; 256 } 257 #endif /* __LIB_IPV6__ */