~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/test_tc_tunnel.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 /* In-place tunneling */
  4 
  5 #include <stdbool.h>
  6 #include <string.h>
  7 
  8 #include <linux/stddef.h>
  9 #include <linux/bpf.h>
 10 #include <linux/if_ether.h>
 11 #include <linux/in.h>
 12 #include <linux/ip.h>
 13 #include <linux/ipv6.h>
 14 #include <linux/mpls.h>
 15 #include <linux/tcp.h>
 16 #include <linux/udp.h>
 17 #include <linux/pkt_cls.h>
 18 #include <linux/types.h>
 19 
 20 #include <bpf/bpf_endian.h>
 21 #include <bpf/bpf_helpers.h>
 22 #include "bpf_compiler.h"
 23 
 24 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
 25 
 26 static const int cfg_port = 8000;
 27 
 28 static const int cfg_udp_src = 20000;
 29 
 30 #define L2_PAD_SZ       (sizeof(struct vxlanhdr) + ETH_HLEN)
 31 
 32 #define UDP_PORT                5555
 33 #define MPLS_OVER_UDP_PORT      6635
 34 #define ETH_OVER_UDP_PORT       7777
 35 #define VXLAN_UDP_PORT          8472
 36 
 37 #define EXTPROTO_VXLAN  0x1
 38 
 39 #define VXLAN_N_VID     (1u << 24)
 40 #define VXLAN_VNI_MASK  bpf_htonl((VXLAN_N_VID - 1) << 8)
 41 #define VXLAN_FLAGS     0x8
 42 #define VXLAN_VNI       1
 43 
 44 #ifndef NEXTHDR_DEST
 45 #define NEXTHDR_DEST    60
 46 #endif
 47 
 48 /* MPLS label 1000 with S bit (last label) set and ttl of 255. */
 49 static const __u32 mpls_label = __bpf_constant_htonl(1000 << 12 |
 50                                                      MPLS_LS_S_MASK | 0xff);
 51 
 52 struct vxlanhdr {
 53         __be32 vx_flags;
 54         __be32 vx_vni;
 55 } __attribute__((packed));
 56 
 57 struct gre_hdr {
 58         __be16 flags;
 59         __be16 protocol;
 60 } __attribute__((packed));
 61 
 62 union l4hdr {
 63         struct udphdr udp;
 64         struct gre_hdr gre;
 65 };
 66 
 67 struct v4hdr {
 68         struct iphdr ip;
 69         union l4hdr l4hdr;
 70         __u8 pad[L2_PAD_SZ];            /* space for L2 header / vxlan header ... */
 71 } __attribute__((packed));
 72 
 73 struct v6hdr {
 74         struct ipv6hdr ip;
 75         union l4hdr l4hdr;
 76         __u8 pad[L2_PAD_SZ];            /* space for L2 header / vxlan header ... */
 77 } __attribute__((packed));
 78 
 79 static __always_inline void set_ipv4_csum(struct iphdr *iph)
 80 {
 81         __u16 *iph16 = (__u16 *)iph;
 82         __u32 csum;
 83         int i;
 84 
 85         iph->check = 0;
 86 
 87         __pragma_loop_unroll_full
 88         for (i = 0, csum = 0; i < sizeof(*iph) >> 1; i++)
 89                 csum += *iph16++;
 90 
 91         iph->check = ~((csum & 0xffff) + (csum >> 16));
 92 }
 93 
 94 static __always_inline int __encap_ipv4(struct __sk_buff *skb, __u8 encap_proto,
 95                                         __u16 l2_proto, __u16 ext_proto)
 96 {
 97         __u16 udp_dst = UDP_PORT;
 98         struct iphdr iph_inner;
 99         struct v4hdr h_outer;
100         struct tcphdr tcph;
101         int olen, l2_len;
102         __u8 *l2_hdr = NULL;
103         int tcp_off;
104         __u64 flags;
105 
106         /* Most tests encapsulate a packet into a tunnel with the same
107          * network protocol, and derive the outer header fields from
108          * the inner header.
109          *
110          * The 6in4 case tests different inner and outer protocols. As
111          * the inner is ipv6, but the outer expects an ipv4 header as
112          * input, manually build a struct iphdr based on the ipv6hdr.
113          */
114         if (encap_proto == IPPROTO_IPV6) {
115                 const __u32 saddr = (192 << 24) | (168 << 16) | (1 << 8) | 1;
116                 const __u32 daddr = (192 << 24) | (168 << 16) | (1 << 8) | 2;
117                 struct ipv6hdr iph6_inner;
118 
119                 /* Read the IPv6 header */
120                 if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph6_inner,
121                                        sizeof(iph6_inner)) < 0)
122                         return TC_ACT_OK;
123 
124                 /* Derive the IPv4 header fields from the IPv6 header */
125                 memset(&iph_inner, 0, sizeof(iph_inner));
126                 iph_inner.version = 4;
127                 iph_inner.ihl = 5;
128                 iph_inner.tot_len = bpf_htons(sizeof(iph6_inner) +
129                                     bpf_ntohs(iph6_inner.payload_len));
130                 iph_inner.ttl = iph6_inner.hop_limit - 1;
131                 iph_inner.protocol = iph6_inner.nexthdr;
132                 iph_inner.saddr = __bpf_constant_htonl(saddr);
133                 iph_inner.daddr = __bpf_constant_htonl(daddr);
134 
135                 tcp_off = sizeof(iph6_inner);
136         } else {
137                 if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
138                                        sizeof(iph_inner)) < 0)
139                         return TC_ACT_OK;
140 
141                 tcp_off = sizeof(iph_inner);
142         }
143 
144         /* filter only packets we want */
145         if (iph_inner.ihl != 5 || iph_inner.protocol != IPPROTO_TCP)
146                 return TC_ACT_OK;
147 
148         if (bpf_skb_load_bytes(skb, ETH_HLEN + tcp_off,
149                                &tcph, sizeof(tcph)) < 0)
150                 return TC_ACT_OK;
151 
152         if (tcph.dest != __bpf_constant_htons(cfg_port))
153                 return TC_ACT_OK;
154 
155         olen = sizeof(h_outer.ip);
156         l2_len = 0;
157 
158         flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV4;
159 
160         switch (l2_proto) {
161         case ETH_P_MPLS_UC:
162                 l2_len = sizeof(mpls_label);
163                 udp_dst = MPLS_OVER_UDP_PORT;
164                 break;
165         case ETH_P_TEB:
166                 l2_len = ETH_HLEN;
167                 if (ext_proto & EXTPROTO_VXLAN) {
168                         udp_dst = VXLAN_UDP_PORT;
169                         l2_len += sizeof(struct vxlanhdr);
170                 } else
171                         udp_dst = ETH_OVER_UDP_PORT;
172                 break;
173         }
174         flags |= BPF_F_ADJ_ROOM_ENCAP_L2(l2_len);
175 
176         switch (encap_proto) {
177         case IPPROTO_GRE:
178                 flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
179                 olen += sizeof(h_outer.l4hdr.gre);
180                 h_outer.l4hdr.gre.protocol = bpf_htons(l2_proto);
181                 h_outer.l4hdr.gre.flags = 0;
182                 break;
183         case IPPROTO_UDP:
184                 flags |= BPF_F_ADJ_ROOM_ENCAP_L4_UDP;
185                 olen += sizeof(h_outer.l4hdr.udp);
186                 h_outer.l4hdr.udp.source = __bpf_constant_htons(cfg_udp_src);
187                 h_outer.l4hdr.udp.dest = bpf_htons(udp_dst);
188                 h_outer.l4hdr.udp.check = 0;
189                 h_outer.l4hdr.udp.len = bpf_htons(bpf_ntohs(iph_inner.tot_len) +
190                                                   sizeof(h_outer.l4hdr.udp) +
191                                                   l2_len);
192                 break;
193         case IPPROTO_IPIP:
194         case IPPROTO_IPV6:
195                 break;
196         default:
197                 return TC_ACT_OK;
198         }
199 
200         /* add L2 encap (if specified) */
201         l2_hdr = (__u8 *)&h_outer + olen;
202         switch (l2_proto) {
203         case ETH_P_MPLS_UC:
204                 *(__u32 *)l2_hdr = mpls_label;
205                 break;
206         case ETH_P_TEB:
207                 flags |= BPF_F_ADJ_ROOM_ENCAP_L2_ETH;
208 
209                 if (ext_proto & EXTPROTO_VXLAN) {
210                         struct vxlanhdr *vxlan_hdr = (struct vxlanhdr *)l2_hdr;
211 
212                         vxlan_hdr->vx_flags = VXLAN_FLAGS;
213                         vxlan_hdr->vx_vni = bpf_htonl((VXLAN_VNI & VXLAN_VNI_MASK) << 8);
214 
215                         l2_hdr += sizeof(struct vxlanhdr);
216                 }
217 
218                 if (bpf_skb_load_bytes(skb, 0, l2_hdr, ETH_HLEN))
219                         return TC_ACT_SHOT;
220 
221                 break;
222         }
223         olen += l2_len;
224 
225         /* add room between mac and network header */
226         if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
227                 return TC_ACT_SHOT;
228 
229         /* prepare new outer network header */
230         h_outer.ip = iph_inner;
231         h_outer.ip.tot_len = bpf_htons(olen +
232                                        bpf_ntohs(h_outer.ip.tot_len));
233         h_outer.ip.protocol = encap_proto;
234 
235         set_ipv4_csum((void *)&h_outer.ip);
236 
237         /* store new outer network header */
238         if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
239                                 BPF_F_INVALIDATE_HASH) < 0)
240                 return TC_ACT_SHOT;
241 
242         /* if changing outer proto type, update eth->h_proto */
243         if (encap_proto == IPPROTO_IPV6) {
244                 struct ethhdr eth;
245 
246                 if (bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth)) < 0)
247                         return TC_ACT_SHOT;
248                 eth.h_proto = bpf_htons(ETH_P_IP);
249                 if (bpf_skb_store_bytes(skb, 0, &eth, sizeof(eth), 0) < 0)
250                         return TC_ACT_SHOT;
251         }
252 
253         return TC_ACT_OK;
254 }
255 
256 static __always_inline int encap_ipv4(struct __sk_buff *skb, __u8 encap_proto,
257                                       __u16 l2_proto)
258 {
259         return __encap_ipv4(skb, encap_proto, l2_proto, 0);
260 }
261 
262 static __always_inline int __encap_ipv6(struct __sk_buff *skb, __u8 encap_proto,
263                                         __u16 l2_proto, __u16 ext_proto)
264 {
265         __u16 udp_dst = UDP_PORT;
266         struct ipv6hdr iph_inner;
267         struct v6hdr h_outer;
268         struct tcphdr tcph;
269         int olen, l2_len;
270         __u8 *l2_hdr = NULL;
271         __u16 tot_len;
272         __u64 flags;
273 
274         if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
275                                sizeof(iph_inner)) < 0)
276                 return TC_ACT_OK;
277 
278         /* filter only packets we want */
279         if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(iph_inner),
280                                &tcph, sizeof(tcph)) < 0)
281                 return TC_ACT_OK;
282 
283         if (tcph.dest != __bpf_constant_htons(cfg_port))
284                 return TC_ACT_OK;
285 
286         olen = sizeof(h_outer.ip);
287         l2_len = 0;
288 
289         flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV6;
290 
291         switch (l2_proto) {
292         case ETH_P_MPLS_UC:
293                 l2_len = sizeof(mpls_label);
294                 udp_dst = MPLS_OVER_UDP_PORT;
295                 break;
296         case ETH_P_TEB:
297                 l2_len = ETH_HLEN;
298                 if (ext_proto & EXTPROTO_VXLAN) {
299                         udp_dst = VXLAN_UDP_PORT;
300                         l2_len += sizeof(struct vxlanhdr);
301                 } else
302                         udp_dst = ETH_OVER_UDP_PORT;
303                 break;
304         }
305         flags |= BPF_F_ADJ_ROOM_ENCAP_L2(l2_len);
306 
307         switch (encap_proto) {
308         case IPPROTO_GRE:
309                 flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
310                 olen += sizeof(h_outer.l4hdr.gre);
311                 h_outer.l4hdr.gre.protocol = bpf_htons(l2_proto);
312                 h_outer.l4hdr.gre.flags = 0;
313                 break;
314         case IPPROTO_UDP:
315                 flags |= BPF_F_ADJ_ROOM_ENCAP_L4_UDP;
316                 olen += sizeof(h_outer.l4hdr.udp);
317                 h_outer.l4hdr.udp.source = __bpf_constant_htons(cfg_udp_src);
318                 h_outer.l4hdr.udp.dest = bpf_htons(udp_dst);
319                 tot_len = bpf_ntohs(iph_inner.payload_len) + sizeof(iph_inner) +
320                           sizeof(h_outer.l4hdr.udp) + l2_len;
321                 h_outer.l4hdr.udp.check = 0;
322                 h_outer.l4hdr.udp.len = bpf_htons(tot_len);
323                 break;
324         case IPPROTO_IPV6:
325                 break;
326         default:
327                 return TC_ACT_OK;
328         }
329 
330         /* add L2 encap (if specified) */
331         l2_hdr = (__u8 *)&h_outer + olen;
332         switch (l2_proto) {
333         case ETH_P_MPLS_UC:
334                 *(__u32 *)l2_hdr = mpls_label;
335                 break;
336         case ETH_P_TEB:
337                 flags |= BPF_F_ADJ_ROOM_ENCAP_L2_ETH;
338 
339                 if (ext_proto & EXTPROTO_VXLAN) {
340                         struct vxlanhdr *vxlan_hdr = (struct vxlanhdr *)l2_hdr;
341 
342                         vxlan_hdr->vx_flags = VXLAN_FLAGS;
343                         vxlan_hdr->vx_vni = bpf_htonl((VXLAN_VNI & VXLAN_VNI_MASK) << 8);
344 
345                         l2_hdr += sizeof(struct vxlanhdr);
346                 }
347 
348                 if (bpf_skb_load_bytes(skb, 0, l2_hdr, ETH_HLEN))
349                         return TC_ACT_SHOT;
350                 break;
351         }
352         olen += l2_len;
353 
354         /* add room between mac and network header */
355         if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
356                 return TC_ACT_SHOT;
357 
358         /* prepare new outer network header */
359         h_outer.ip = iph_inner;
360         h_outer.ip.payload_len = bpf_htons(olen +
361                                            bpf_ntohs(h_outer.ip.payload_len));
362 
363         h_outer.ip.nexthdr = encap_proto;
364 
365         /* store new outer network header */
366         if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
367                                 BPF_F_INVALIDATE_HASH) < 0)
368                 return TC_ACT_SHOT;
369 
370         return TC_ACT_OK;
371 }
372 
373 static int encap_ipv6_ipip6(struct __sk_buff *skb)
374 {
375         struct iphdr iph_inner;
376         struct v6hdr h_outer;
377         struct tcphdr tcph;
378         struct ethhdr eth;
379         __u64 flags;
380         int olen;
381 
382         if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
383                                sizeof(iph_inner)) < 0)
384                 return TC_ACT_OK;
385 
386         /* filter only packets we want */
387         if (bpf_skb_load_bytes(skb, ETH_HLEN + (iph_inner.ihl << 2),
388                                &tcph, sizeof(tcph)) < 0)
389                 return TC_ACT_OK;
390 
391         if (tcph.dest != __bpf_constant_htons(cfg_port))
392                 return TC_ACT_OK;
393 
394         olen = sizeof(h_outer.ip);
395 
396         flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV6;
397 
398         /* add room between mac and network header */
399         if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
400                 return TC_ACT_SHOT;
401 
402         /* prepare new outer network header */
403         memset(&h_outer.ip, 0, sizeof(h_outer.ip));
404         h_outer.ip.version = 6;
405         h_outer.ip.hop_limit = iph_inner.ttl;
406         h_outer.ip.saddr.s6_addr[1] = 0xfd;
407         h_outer.ip.saddr.s6_addr[15] = 1;
408         h_outer.ip.daddr.s6_addr[1] = 0xfd;
409         h_outer.ip.daddr.s6_addr[15] = 2;
410         h_outer.ip.payload_len = iph_inner.tot_len;
411         h_outer.ip.nexthdr = IPPROTO_IPIP;
412 
413         /* store new outer network header */
414         if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
415                                 BPF_F_INVALIDATE_HASH) < 0)
416                 return TC_ACT_SHOT;
417 
418         /* update eth->h_proto */
419         if (bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth)) < 0)
420                 return TC_ACT_SHOT;
421         eth.h_proto = bpf_htons(ETH_P_IPV6);
422         if (bpf_skb_store_bytes(skb, 0, &eth, sizeof(eth), 0) < 0)
423                 return TC_ACT_SHOT;
424 
425         return TC_ACT_OK;
426 }
427 
428 static __always_inline int encap_ipv6(struct __sk_buff *skb, __u8 encap_proto,
429                                       __u16 l2_proto)
430 {
431         return __encap_ipv6(skb, encap_proto, l2_proto, 0);
432 }
433 
434 SEC("encap_ipip_none")
435 int __encap_ipip_none(struct __sk_buff *skb)
436 {
437         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
438                 return encap_ipv4(skb, IPPROTO_IPIP, ETH_P_IP);
439         else
440                 return TC_ACT_OK;
441 }
442 
443 SEC("encap_gre_none")
444 int __encap_gre_none(struct __sk_buff *skb)
445 {
446         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
447                 return encap_ipv4(skb, IPPROTO_GRE, ETH_P_IP);
448         else
449                 return TC_ACT_OK;
450 }
451 
452 SEC("encap_gre_mpls")
453 int __encap_gre_mpls(struct __sk_buff *skb)
454 {
455         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
456                 return encap_ipv4(skb, IPPROTO_GRE, ETH_P_MPLS_UC);
457         else
458                 return TC_ACT_OK;
459 }
460 
461 SEC("encap_gre_eth")
462 int __encap_gre_eth(struct __sk_buff *skb)
463 {
464         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
465                 return encap_ipv4(skb, IPPROTO_GRE, ETH_P_TEB);
466         else
467                 return TC_ACT_OK;
468 }
469 
470 SEC("encap_udp_none")
471 int __encap_udp_none(struct __sk_buff *skb)
472 {
473         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
474                 return encap_ipv4(skb, IPPROTO_UDP, ETH_P_IP);
475         else
476                 return TC_ACT_OK;
477 }
478 
479 SEC("encap_udp_mpls")
480 int __encap_udp_mpls(struct __sk_buff *skb)
481 {
482         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
483                 return encap_ipv4(skb, IPPROTO_UDP, ETH_P_MPLS_UC);
484         else
485                 return TC_ACT_OK;
486 }
487 
488 SEC("encap_udp_eth")
489 int __encap_udp_eth(struct __sk_buff *skb)
490 {
491         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
492                 return encap_ipv4(skb, IPPROTO_UDP, ETH_P_TEB);
493         else
494                 return TC_ACT_OK;
495 }
496 
497 SEC("encap_vxlan_eth")
498 int __encap_vxlan_eth(struct __sk_buff *skb)
499 {
500         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
501                 return __encap_ipv4(skb, IPPROTO_UDP,
502                                     ETH_P_TEB,
503                                     EXTPROTO_VXLAN);
504         else
505                 return TC_ACT_OK;
506 }
507 
508 SEC("encap_sit_none")
509 int __encap_sit_none(struct __sk_buff *skb)
510 {
511         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
512                 return encap_ipv4(skb, IPPROTO_IPV6, ETH_P_IP);
513         else
514                 return TC_ACT_OK;
515 }
516 
517 SEC("encap_ip6tnl_none")
518 int __encap_ip6tnl_none(struct __sk_buff *skb)
519 {
520         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
521                 return encap_ipv6(skb, IPPROTO_IPV6, ETH_P_IPV6);
522         else
523                 return TC_ACT_OK;
524 }
525 
526 SEC("encap_ipip6_none")
527 int __encap_ipip6_none(struct __sk_buff *skb)
528 {
529         if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
530                 return encap_ipv6_ipip6(skb);
531         else
532                 return TC_ACT_OK;
533 }
534 
535 SEC("encap_ip6gre_none")
536 int __encap_ip6gre_none(struct __sk_buff *skb)
537 {
538         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
539                 return encap_ipv6(skb, IPPROTO_GRE, ETH_P_IPV6);
540         else
541                 return TC_ACT_OK;
542 }
543 
544 SEC("encap_ip6gre_mpls")
545 int __encap_ip6gre_mpls(struct __sk_buff *skb)
546 {
547         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
548                 return encap_ipv6(skb, IPPROTO_GRE, ETH_P_MPLS_UC);
549         else
550                 return TC_ACT_OK;
551 }
552 
553 SEC("encap_ip6gre_eth")
554 int __encap_ip6gre_eth(struct __sk_buff *skb)
555 {
556         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
557                 return encap_ipv6(skb, IPPROTO_GRE, ETH_P_TEB);
558         else
559                 return TC_ACT_OK;
560 }
561 
562 SEC("encap_ip6udp_none")
563 int __encap_ip6udp_none(struct __sk_buff *skb)
564 {
565         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
566                 return encap_ipv6(skb, IPPROTO_UDP, ETH_P_IPV6);
567         else
568                 return TC_ACT_OK;
569 }
570 
571 SEC("encap_ip6udp_mpls")
572 int __encap_ip6udp_mpls(struct __sk_buff *skb)
573 {
574         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
575                 return encap_ipv6(skb, IPPROTO_UDP, ETH_P_MPLS_UC);
576         else
577                 return TC_ACT_OK;
578 }
579 
580 SEC("encap_ip6udp_eth")
581 int __encap_ip6udp_eth(struct __sk_buff *skb)
582 {
583         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
584                 return encap_ipv6(skb, IPPROTO_UDP, ETH_P_TEB);
585         else
586                 return TC_ACT_OK;
587 }
588 
589 SEC("encap_ip6vxlan_eth")
590 int __encap_ip6vxlan_eth(struct __sk_buff *skb)
591 {
592         if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
593                 return __encap_ipv6(skb, IPPROTO_UDP,
594                                     ETH_P_TEB,
595                                     EXTPROTO_VXLAN);
596         else
597                 return TC_ACT_OK;
598 }
599 
600 static int decap_internal(struct __sk_buff *skb, int off, int len, char proto)
601 {
602         __u64 flags = BPF_F_ADJ_ROOM_FIXED_GSO;
603         struct ipv6_opt_hdr ip6_opt_hdr;
604         struct gre_hdr greh;
605         struct udphdr udph;
606         int olen = len;
607 
608         switch (proto) {
609         case IPPROTO_IPIP:
610                 flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV4;
611                 break;
612         case IPPROTO_IPV6:
613                 flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV6;
614                 break;
615         case NEXTHDR_DEST:
616                 if (bpf_skb_load_bytes(skb, off + len, &ip6_opt_hdr,
617                                        sizeof(ip6_opt_hdr)) < 0)
618                         return TC_ACT_OK;
619                 switch (ip6_opt_hdr.nexthdr) {
620                 case IPPROTO_IPIP:
621                         flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV4;
622                         break;
623                 case IPPROTO_IPV6:
624                         flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV6;
625                         break;
626                 default:
627                         return TC_ACT_OK;
628                 }
629                 break;
630         case IPPROTO_GRE:
631                 olen += sizeof(struct gre_hdr);
632                 if (bpf_skb_load_bytes(skb, off + len, &greh, sizeof(greh)) < 0)
633                         return TC_ACT_OK;
634                 switch (bpf_ntohs(greh.protocol)) {
635                 case ETH_P_MPLS_UC:
636                         olen += sizeof(mpls_label);
637                         break;
638                 case ETH_P_TEB:
639                         olen += ETH_HLEN;
640                         break;
641                 }
642                 break;
643         case IPPROTO_UDP:
644                 olen += sizeof(struct udphdr);
645                 if (bpf_skb_load_bytes(skb, off + len, &udph, sizeof(udph)) < 0)
646                         return TC_ACT_OK;
647                 switch (bpf_ntohs(udph.dest)) {
648                 case MPLS_OVER_UDP_PORT:
649                         olen += sizeof(mpls_label);
650                         break;
651                 case ETH_OVER_UDP_PORT:
652                         olen += ETH_HLEN;
653                         break;
654                 case VXLAN_UDP_PORT:
655                         olen += ETH_HLEN + sizeof(struct vxlanhdr);
656                         break;
657                 }
658                 break;
659         default:
660                 return TC_ACT_OK;
661         }
662 
663         if (bpf_skb_adjust_room(skb, -olen, BPF_ADJ_ROOM_MAC, flags))
664                 return TC_ACT_SHOT;
665 
666         return TC_ACT_OK;
667 }
668 
669 static int decap_ipv4(struct __sk_buff *skb)
670 {
671         struct iphdr iph_outer;
672 
673         if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer,
674                                sizeof(iph_outer)) < 0)
675                 return TC_ACT_OK;
676 
677         if (iph_outer.ihl != 5)
678                 return TC_ACT_OK;
679 
680         return decap_internal(skb, ETH_HLEN, sizeof(iph_outer),
681                               iph_outer.protocol);
682 }
683 
684 static int decap_ipv6(struct __sk_buff *skb)
685 {
686         struct ipv6hdr iph_outer;
687 
688         if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer,
689                                sizeof(iph_outer)) < 0)
690                 return TC_ACT_OK;
691 
692         return decap_internal(skb, ETH_HLEN, sizeof(iph_outer),
693                               iph_outer.nexthdr);
694 }
695 
696 SEC("decap")
697 int decap_f(struct __sk_buff *skb)
698 {
699         switch (skb->protocol) {
700         case __bpf_constant_htons(ETH_P_IP):
701                 return decap_ipv4(skb);
702         case __bpf_constant_htons(ETH_P_IPV6):
703                 return decap_ipv6(skb);
704         default:
705                 /* does not match, ignore */
706                 return TC_ACT_OK;
707         }
708 }
709 
710 char __license[] SEC("license") = "GPL";
711 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php