FILE
tc_l2_redirect_kern.c
File preview with syntax highlighting.
linux-6.19.14/samples/bpf/tc_l2_redirect_kern.c
1/* Copyright (c) 2016 Facebook 2 * 3 * This program is free software; you can redistribute it and/or 4 * modify it under the terms of version 2 of the GNU General Public 5 * License as published by the Free Software Foundation. 6 */ 7#define KBUILD_MODNAME "foo" 8#include <uapi/linux/bpf.h> 9#include <uapi/linux/if_ether.h> 10#include <uapi/linux/if_packet.h> 11#include <uapi/linux/ip.h> 12#include <uapi/linux/ipv6.h> 13#include <uapi/linux/in.h> 14#include <uapi/linux/tcp.h> 15#include <uapi/linux/filter.h> 16#include <uapi/linux/pkt_cls.h> 17#include <net/ipv6.h> 18#include <bpf/bpf_helpers.h> 19 20#define _htonl __builtin_bswap32 21 22#define PIN_GLOBAL_NS 2 23struct bpf_elf_map { 24 __u32 type; 25 __u32 size_key; 26 __u32 size_value; 27 __u32 max_elem; 28 __u32 flags; 29 __u32 id; 30 __u32 pinning; 31}; 32 33/* copy of 'struct ethhdr' without __packed */ 34struct eth_hdr { 35 unsigned char h_dest[ETH_ALEN]; 36 unsigned char h_source[ETH_ALEN]; 37 unsigned short h_proto; 38}; 39 40struct bpf_elf_map SEC("maps") tun_iface = { 41 .type = BPF_MAP_TYPE_ARRAY, 42 .size_key = sizeof(int), 43 .size_value = sizeof(int), 44 .pinning = PIN_GLOBAL_NS, 45 .max_elem = 1, 46}; 47 48static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr) 49{ 50 if (eth_proto == htons(ETH_P_IP)) 51 return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100); 52 else if (eth_proto == htons(ETH_P_IPV6)) 53 return (daddr == _htonl(0x2401face)); 54 55 return false; 56} 57 58SEC("l2_to_iptun_ingress_forward") 59int _l2_to_iptun_ingress_forward(struct __sk_buff *skb) 60{ 61 void *data = (void *)(long)skb->data; 62 struct eth_hdr *eth = data; 63 void *data_end = (void *)(long)skb->data_end; 64 int key = 0, *ifindex; 65 66 if (data + sizeof(*eth) > data_end) 67 return TC_ACT_OK; 68 69 ifindex = bpf_map_lookup_elem(&tun_iface, &key); 70 if (!ifindex) 71 return TC_ACT_OK; 72 73 if (eth->h_proto == htons(ETH_P_IP)) { 74 char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n"; 75 struct iphdr *iph = data + sizeof(*eth); 76 77 if (data + sizeof(*eth) + sizeof(*iph) > data_end) 78 return TC_ACT_OK; 79 80 if (iph->protocol != IPPROTO_IPIP) 81 return TC_ACT_OK; 82 83 bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex, 84 _htonl(iph->daddr)); 85 return bpf_redirect(*ifindex, BPF_F_INGRESS); 86 } else if (eth->h_proto == htons(ETH_P_IPV6)) { 87 char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n"; 88 struct ipv6hdr *ip6h = data + sizeof(*eth); 89 90 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) 91 return TC_ACT_OK; 92 93 if (ip6h->nexthdr != IPPROTO_IPIP && 94 ip6h->nexthdr != IPPROTO_IPV6) 95 return TC_ACT_OK; 96 97 bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex, 98 _htonl(ip6h->daddr.s6_addr32[0]), 99 _htonl(ip6h->daddr.s6_addr32[3])); 100 return bpf_redirect(*ifindex, BPF_F_INGRESS); 101 } 102 103 return TC_ACT_OK; 104} 105 106SEC("l2_to_iptun_ingress_redirect") 107int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb) 108{ 109 struct bpf_tunnel_key tkey = {}; 110 void *data = (void *)(long)skb->data; 111 struct eth_hdr *eth = data; 112 void *data_end = (void *)(long)skb->data_end; 113 int key = 0, *ifindex; 114 115 if (data + sizeof(*eth) > data_end) 116 return TC_ACT_OK; 117 118 ifindex = bpf_map_lookup_elem(&tun_iface, &key); 119 if (!ifindex) 120 return TC_ACT_OK; 121 122 if (eth->h_proto == htons(ETH_P_IP)) { 123 char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n"; 124 struct iphdr *iph = data + sizeof(*eth); 125 __be32 daddr = iph->daddr; 126 127 if (data + sizeof(*eth) + sizeof(*iph) > data_end) 128 return TC_ACT_OK; 129 130 if (!is_vip_addr(eth->h_proto, daddr)) 131 return TC_ACT_OK; 132 133 bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex); 134 } else { 135 return TC_ACT_OK; 136 } 137 138 tkey.tunnel_id = 10000; 139 tkey.tunnel_ttl = 64; 140 tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */ 141 bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0); 142 return bpf_redirect(*ifindex, 0); 143} 144 145SEC("l2_to_ip6tun_ingress_redirect") 146int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb) 147{ 148 struct bpf_tunnel_key tkey = {}; 149 void *data = (void *)(long)skb->data; 150 struct eth_hdr *eth = data; 151 void *data_end = (void *)(long)skb->data_end; 152 int key = 0, *ifindex; 153 154 if (data + sizeof(*eth) > data_end) 155 return TC_ACT_OK; 156 157 ifindex = bpf_map_lookup_elem(&tun_iface, &key); 158 if (!ifindex) 159 return TC_ACT_OK; 160 161 if (eth->h_proto == htons(ETH_P_IP)) { 162 char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n"; 163 struct iphdr *iph = data + sizeof(*eth); 164 165 if (data + sizeof(*eth) + sizeof(*iph) > data_end) 166 return TC_ACT_OK; 167 168 if (!is_vip_addr(eth->h_proto, iph->daddr)) 169 return TC_ACT_OK; 170 171 bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr), 172 *ifindex); 173 } else if (eth->h_proto == htons(ETH_P_IPV6)) { 174 char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n"; 175 struct ipv6hdr *ip6h = data + sizeof(*eth); 176 177 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) 178 return TC_ACT_OK; 179 180 if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0])) 181 return TC_ACT_OK; 182 183 bpf_trace_printk(fmt6, sizeof(fmt6), 184 _htonl(ip6h->daddr.s6_addr32[0]), *ifindex); 185 } else { 186 return TC_ACT_OK; 187 } 188 189 tkey.tunnel_id = 10000; 190 tkey.tunnel_ttl = 64; 191 /* 2401:db02:0:0:0:0:0:66 */ 192 tkey.remote_ipv6[0] = _htonl(0x2401db02); 193 tkey.remote_ipv6[1] = 0; 194 tkey.remote_ipv6[2] = 0; 195 tkey.remote_ipv6[3] = _htonl(0x00000066); 196 bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6); 197 return bpf_redirect(*ifindex, 0); 198} 199 200SEC("drop_non_tun_vip") 201int _drop_non_tun_vip(struct __sk_buff *skb) 202{ 203 void *data = (void *)(long)skb->data; 204 struct eth_hdr *eth = data; 205 void *data_end = (void *)(long)skb->data_end; 206 207 if (data + sizeof(*eth) > data_end) 208 return TC_ACT_OK; 209 210 if (eth->h_proto == htons(ETH_P_IP)) { 211 struct iphdr *iph = data + sizeof(*eth); 212 213 if (data + sizeof(*eth) + sizeof(*iph) > data_end) 214 return TC_ACT_OK; 215 216 if (is_vip_addr(eth->h_proto, iph->daddr)) 217 return TC_ACT_SHOT; 218 } else if (eth->h_proto == htons(ETH_P_IPV6)) { 219 struct ipv6hdr *ip6h = data + sizeof(*eth); 220 221 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) 222 return TC_ACT_OK; 223 224 if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0])) 225 return TC_ACT_SHOT; 226 } 227 228 return TC_ACT_OK; 229} 230 231char _license[] SEC("license") = "GPL";
~/
Read-only file preview.