├── .gitmodules ├── Makefile ├── README.md ├── build └── .gitignore ├── other └── IPIPDirect.service └── src ├── IPIPDirect_kern.c ├── IPIPDirect_loader.c └── include ├── bpf_helpers.h └── common.h /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/include/libbpf"] 2 | path = src/include/libbpf 3 | url = https://github.com/libbpf/libbpf.git 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | 3 | BUILD_DIR = build 4 | SRC_DIR = src 5 | 6 | LIBBPF_DIR = $(SRC_DIR)/include/libbpf 7 | LIBBPF_STATIC_DIR = $(LIBBPF_DIR)/src/staticobjs 8 | 9 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/bpf_prog_linfo.o $(LIBBPF_STATIC_DIR)/bpf.o $(LIBBPF_STATIC_DIR)/btf_dump.o 10 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/btf_iter.o $(LIBBPF_STATIC_DIR)/btf_relocate.o $(LIBBPF_STATIC_DIR)/btf.o 11 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/elf.o $(LIBBPF_STATIC_DIR)/features.o $(LIBBPF_STATIC_DIR)/gen_loader.o 12 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/hashmap.o $(LIBBPF_STATIC_DIR)/libbpf_errno.o $(LIBBPF_STATIC_DIR)/libbpf_probes.o 13 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/libbpf.o $(LIBBPF_STATIC_DIR)/linker.o $(LIBBPF_STATIC_DIR)/netlink.o 14 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/nlattr.o $(LIBBPF_STATIC_DIR)/relo_core.o $(LIBBPF_STATIC_DIR)/ringbuf.o 15 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/str_error.o $(LIBBPF_STATIC_DIR)/strset.o $(LIBBPF_STATIC_DIR)/usdt.o 16 | LIBBPF_STATIC_OBJS += $(LIBBPF_STATIC_DIR)/zip.o 17 | 18 | CFLAGS += -I$(LIBBPF_DIR)/src -g -O2 19 | 20 | all: loader kern 21 | kern: 22 | $(CC) -I $(LIBBPF_DIR)/src -O2 --target=bpf -g -c $(SRC_DIR)/IPIPDirect_kern.c -o $(BUILD_DIR)/IPIPDirect_filter.o 23 | loader: libbpf 24 | $(CC) -lelf -lz -o $(BUILD_DIR)/IPIPDirect_loader $(LIBBPF_STATIC_OBJS) $(SRC_DIR)/IPIPDirect_loader.c 25 | clean: 26 | $(MAKE) -C $(LIBBPF_DIR)/src clean 27 | rm -f $(BUILD_DIR)/*.o 28 | rm -f $(BUILD_DIR)/*.bc 29 | rm -f $(BUILD_DIR)/IPIPDirect_loader 30 | libbpf: 31 | $(MAKE) -C $(LIBBPF_DIR)/src 32 | install: 33 | mkdir -p /etc/IPIPDirect/ 34 | cp $(BUILD_DIR)/IPIPDirect_filter.o /etc/IPIPDirect/IPIPDirect_filter.o 35 | cp $(BUILD_DIR)/IPIPDirect_loader /usr/bin/IPIPDirect_loader 36 | cp -n other/IPIPDirect.service /etc/systemd/system/IPIPDirect.service 37 | .PHONY: libbpf all 38 | .DEFAULT: all -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IPIP Direct (TC) 2 | 3 | ## Description 4 | A program made to attach to the TC hook using the egress filter. This program makes it so any outgoing IPIP packets are sent directly back to the client instead of back through the IPIP tunnel. In cases where you don't need the end-application replies to go back through the forwarding server/IPIP tunnel, this is very useful and will result in less load on the forwarding server. With that said, in other cases it can result in less latency and more. 5 | 6 | ## Usage 7 | Usage is as follows: 8 | 9 | ``` 10 | ./IPIPDirect_Loader 11 | ``` 12 | 13 | Example: 14 | 15 | ``` 16 | ./IPIPDirect_Loader ens18 17 | ``` 18 | 19 | ## Installation 20 | Use the MAKE file to install the program. These commands should do: 21 | 22 | ``` 23 | make 24 | make install 25 | ``` 26 | 27 | You may also clean the installation by executing: 28 | 29 | ``` 30 | make clean 31 | ``` 32 | 33 | ## Systemd File 34 | A `systemd` file is located in the other/ directory and is installed via `make install`. You will need to edit the system file if you are using an interface other than `ens18`. 35 | 36 | You may enable the service by executing so it'll start on bootup: 37 | 38 | ``` 39 | systemctl enable IPIPDirect 40 | ``` 41 | 42 | You may start/stop/restart the service by executing: 43 | 44 | ``` 45 | systemctl restart IPIPDirect # Restart service. 46 | systemctl stop IPIPDirect # Stop service. 47 | systemctl start IPIPDirect # Start service. 48 | ``` 49 | 50 | ## Kernel Requirements 51 | Kernel >= 5.3 is required for this. Newer kernels add the `BPF_ADJ_ROOM_MAC` mode to the `bpf_skb_adjust_room()` function which is needed for this program to work correctly. 52 | 53 | ## Notes 54 | When compiling, you may need to copy `/usr/src/linux-headers-xxx/include/uapi/linux/bpf.h` to `/usr/include/linux/bpf.h`. For some reason, newer kernels don't have an up-to-date `/usr/include/linux/bpf.h` file. I'm unsure if this is intentional or a bug. However, I got the program to compile properly by copying that file. 55 | 56 | **Update** - Apparently this is only a bug on Ubuntu. 57 | 58 | ## Credits 59 | * [Christian Deacon](https://www.linkedin.com/in/christian-deacon-902042186/) - Creator -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /other/IPIPDirect.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=IPIP Direct TC program. 3 | After=network-online.target 4 | Requires=network-online.target 5 | 6 | [Service] 7 | ExecStart=/usr/bin/IPIPDirect_loader ens18 8 | Restart=always 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /src/IPIPDirect_kern.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "include/common.h" 14 | #include "include/bpf_helpers.h" 15 | 16 | // Uncomment this line if you want to exempt A2S_INFO responses from being sent directly. https://developer.valvesoftware.com/wiki/Server_queries#A2S_INFO 17 | //#define EXCLUDE_A2S_INFO 18 | 19 | // Debug 20 | //#define DEBUG 21 | 22 | #define ETH_LEN sizeof(struct ethhdr) 23 | 24 | #define ETH_DEST_OFF (offsetof(struct ethhdr, h_dest)) 25 | #define IP_CHECK_OFF (ETH_LEN + offsetof(struct iphdr, check)) 26 | #define IP_SADDR_OFF (ETH_LEN + offsetof(struct iphdr, saddr)) 27 | 28 | // MAC map for gateway interface's MAC address. The program only worked for me if I had the Ethernet header's destination MAC address set to the gateway. 29 | struct 30 | { 31 | __uint(type, BPF_MAP_TYPE_ARRAY); 32 | __uint(max_entries, 1); 33 | __type(key, uint32_t); 34 | __type(value, uint64_t); 35 | } mac_map SEC(".maps"); 36 | 37 | SEC("tc/egress") 38 | int tc_egress(struct __sk_buff *skb) 39 | { 40 | // Initialize packet data. 41 | void *data_end = (void *)(long)skb->data_end; 42 | void *data = (void *)(long)skb->data; 43 | 44 | // Initialize Ethernet header. 45 | struct ethhdr *ethhdr = data; 46 | 47 | // Check Ethernet header's length. 48 | if (ethhdr + 1 > (struct ethhdr *)data_end) 49 | { 50 | return TC_ACT_OK; 51 | } 52 | 53 | // Check Ethernet protocol and ensure it's IP. 54 | if (likely(ethhdr->h_proto == htons(ETH_P_IP))) 55 | { 56 | // Initialize outer IP header. 57 | struct iphdr *iphdr = data + sizeof(struct ethhdr); 58 | 59 | // Check outer IP header's length. 60 | if (unlikely(iphdr + 1 > (struct iphdr *)data_end)) 61 | { 62 | return TC_ACT_SHOT; 63 | } 64 | 65 | // Check for IPIP protocol. 66 | if (iphdr->protocol == IPPROTO_IPIP) 67 | { 68 | // Initialize inner IP header. 69 | struct iphdr *inner_ip = data + sizeof(struct ethhdr) + sizeof(struct iphdr); 70 | 71 | // Check inner IP header length. 72 | if (unlikely(inner_ip + 1 > (struct iphdr *)data_end)) 73 | { 74 | return TC_ACT_SHOT; 75 | } 76 | 77 | #ifdef EXCLUDE_A2S_INFO 78 | // Before we move ahead, let's check for A2S_INFO response and exempt that from modification. 79 | if (inner_ip->protocol == IPPROTO_UDP) 80 | { 81 | // Initialize UDP header. 82 | struct udphdr *udphdr = data + sizeof(struct ethhdr) + sizeof(struct iphdr) + (inner_ip->ihl * 4); 83 | 84 | // Check UDP header length. 85 | if (unlikely(udphdr + 1 > (struct udphdr *)data_end)) 86 | { 87 | return TC_ACT_SHOT; 88 | } 89 | 90 | // Initialize UDP data. 91 | uint8_t *pcktData = data + sizeof(struct ethhdr) + sizeof(struct iphdr) + (inner_ip->ihl * 4) + sizeof(struct udphdr); 92 | 93 | // Check UDP data length. 94 | if (!(pcktData + 5 > (uint8_t *)data_end)) 95 | { 96 | // Check first byte of data and see if it matches A2S_INFO response header. If it does, pass to upper layers and ignore packet modification. 97 | if ((*pcktData++) == 0xFF && (*pcktData++) == 0xFF && (*pcktData++) == 0xFF && (*pcktData++) == 0xFF && (*pcktData) == 0x49) 98 | { 99 | return TC_ACT_OK; 100 | } 101 | } 102 | } 103 | #endif 104 | 105 | // Save inner IP source address for checksum calculation later on.. 106 | uint32_t oldAddr; 107 | oldAddr = inner_ip->saddr; 108 | 109 | // Save forwarding address. 110 | uint32_t forwardAddr = iphdr->daddr; 111 | 112 | // Remove outer IP header and check if it was successful. 113 | if (bpf_skb_adjust_room(skb, -(int)sizeof(struct iphdr), BPF_ADJ_ROOM_MAC, 0) != 0) 114 | { 115 | return TC_ACT_SHOT; 116 | } 117 | 118 | // Reinitialize values. 119 | data_end = (void *)(long)skb->data_end; 120 | data = (void *)(long)skb->data; 121 | iphdr = data + sizeof(struct ethhdr); 122 | 123 | // Check IP header length. 124 | if (iphdr + 1 > (struct iphdr *)data_end) 125 | { 126 | return TC_ACT_OK; 127 | } 128 | 129 | // Recalculate layer three checksum (IP header). 130 | bpf_l3_csum_replace(skb, IP_CHECK_OFF, oldAddr, forwardAddr, sizeof(forwardAddr)); 131 | 132 | // Reinitialize values. 133 | data_end = (void *)(long)skb->data_end; 134 | data = (void *)(long)skb->data; 135 | iphdr = data + sizeof(struct ethhdr); 136 | 137 | // Check IP header length. 138 | if (iphdr + 1 > (struct iphdr *)data_end) 139 | { 140 | return TC_ACT_OK; 141 | } 142 | 143 | // Change source address to forwarding address. 144 | bpf_skb_store_bytes(skb, IP_SADDR_OFF, &forwardAddr, sizeof(forwardAddr), 0); 145 | 146 | // Reinitialize values. 147 | data_end = (void *)(long)skb->data_end; 148 | data = (void *)(long)skb->data; 149 | iphdr = data + sizeof(struct ethhdr); 150 | 151 | // Check IP header length. 152 | if (iphdr + 1 > (struct iphdr *)data_end) 153 | { 154 | return TC_ACT_OK; 155 | } 156 | 157 | // Check for gateway address from BPF map. 158 | uint64_t *val; 159 | uint32_t key = 0; 160 | 161 | val = bpf_map_lookup_elem(&mac_map, &key); 162 | 163 | if (!val) 164 | { 165 | #ifdef DEBUG 166 | // Print debug message. This can be found by performing 'cat /sys/kernel/debug/tracing/trace_pipe'. 167 | //printk("MAC map bad value.\n"); 168 | #endif 169 | 170 | return TC_ACT_OK; 171 | } 172 | 173 | uint8_t dstMAC[ETH_ALEN]; 174 | 175 | int2mac(*val, dstMAC); 176 | 177 | // Replace destination MAC. 178 | bpf_skb_store_bytes(skb, ETH_DEST_OFF, &dstMAC, ETH_ALEN, 0); 179 | 180 | // Reinitialize values. 181 | data_end = (void *)(long)skb->data_end; 182 | data = (void *)(long)skb->data; 183 | iphdr = data + sizeof(struct ethhdr); 184 | 185 | // Check IP header length. 186 | if (iphdr + 1 > (struct iphdr *)data_end) 187 | { 188 | return TC_ACT_OK; 189 | } 190 | 191 | // Recalculate transport protocol header. 192 | switch (iphdr->protocol) 193 | { 194 | case IPPROTO_UDP: 195 | { 196 | // Initialize UDP header. 197 | struct udphdr *udphdr = data + sizeof(struct ethhdr) + (iphdr->ihl * 4); 198 | 199 | // Check UDP header length. 200 | if (udphdr + 1 > (struct udphdr *)data_end) 201 | { 202 | return TC_ACT_SHOT; 203 | } 204 | 205 | uint32_t offset = sizeof(struct ethhdr) + (iphdr->ihl * 4) + offsetof(struct udphdr, check); 206 | 207 | // Recalculate layer four checksum (UDP checksum). 208 | bpf_l4_csum_replace(skb, offset, oldAddr, iphdr->saddr, 0x10 | sizeof(iphdr->saddr)); 209 | 210 | break; 211 | } 212 | 213 | case IPPROTO_TCP: 214 | { 215 | // Initialize TCP header. 216 | struct tcphdr *tcphdr = data + sizeof(struct ethhdr) + (iphdr->ihl * 4); 217 | 218 | // Check TCP header length. 219 | if (tcphdr + 1 > (struct tcphdr *)data_end) 220 | { 221 | return TC_ACT_SHOT; 222 | } 223 | 224 | // Get TCP header checksum's offset. 225 | uint32_t offset = sizeof(struct ethhdr) + (iphdr->ihl * 4) + offsetof(struct tcphdr, check); 226 | 227 | // Recalculate layer four checksum (TCP checksum). 228 | bpf_l4_csum_replace(skb, offset, oldAddr, iphdr->saddr, 0x10 | sizeof(iphdr->saddr)); 229 | 230 | break; 231 | } 232 | } 233 | } 234 | } 235 | 236 | // Pass packet to upper layers. 237 | return TC_ACT_OK; 238 | } 239 | 240 | // License. 241 | char __license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/IPIPDirect_loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "include/libbpf/src/bpf.h" 17 | #include "include/libbpf/src/libbpf.h" 18 | #include "include/common.h" 19 | 20 | // TC CMD sizes. 21 | #define CMD_MAX 2048 22 | #define CMD_MAX_TC 256 23 | 24 | // Initialize static variables. 25 | static uint8_t cont = 1; 26 | static int mac_map_fd; 27 | static uint8_t gwMAC[ETH_ALEN]; 28 | 29 | // TC program file name. 30 | const char TCFile[] = "/etc/IPIPDirect/IPIPDirect_filter.o"; 31 | 32 | // Maps. 33 | const char *map_mac = BASEDIR_MAPS "/mac_map"; 34 | 35 | // Extern error number. 36 | extern int errno; 37 | 38 | // Signal function. 39 | void signHdl(int tmp) 40 | { 41 | // Set cont to 0 which will stop the while loop and the program. 42 | cont = 0; 43 | } 44 | 45 | // Get gateway MAC address. 46 | void GetGatewayMAC() 47 | { 48 | // Command to run. 49 | char cmd[] = "ip neigh | grep \"$(ip -4 route list 0/0 | cut -d' ' -f3) \" | cut -d' ' -f5 | tr '[a-f]' '[A-F]'"; 50 | 51 | // Execute command. 52 | FILE *fp = popen(cmd, "r"); 53 | 54 | // Check if command is valid. 55 | if (fp != NULL) 56 | { 57 | // Initialize line char. 58 | char line[18]; 59 | 60 | // Get output from command. 61 | if (fgets(line, sizeof(line), fp) != NULL) 62 | { 63 | // Parse output and put it into gwMAC. 64 | sscanf(line, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &gwMAC[0], &gwMAC[1], &gwMAC[2], &gwMAC[3], &gwMAC[4], &gwMAC[5]); 65 | } 66 | 67 | // Close command. 68 | pclose(fp); 69 | } 70 | } 71 | 72 | int open_map(const char *name) 73 | { 74 | // Initialize FD. 75 | int fd; 76 | 77 | // Get map objective. 78 | fd = bpf_obj_get(name); 79 | 80 | // Check map FD. 81 | if (fd < 0) 82 | { 83 | fprintf(stderr, "Error getting map. Map name => %s\n", name); 84 | 85 | return fd; 86 | } 87 | 88 | // Return FD. 89 | return fd; 90 | } 91 | 92 | void bpf_close_and_exit(struct bpf_object *obj, int ret) 93 | { 94 | bpf_object__close(obj); 95 | 96 | exit(ret); 97 | } 98 | 99 | void tc_egress_attach_bpf(int ifidx, const char *obj_path, const char *prog_name, struct bpf_object **obj, struct bpf_program **prog) 100 | { 101 | int ret; 102 | 103 | *obj = bpf_object__open_file(obj_path, NULL); 104 | 105 | if (!(*obj)) 106 | { 107 | fprintf(stderr, "Error opening BPF object (%s). Error => %d (%s).\n", obj_path, errno, strerror(errno)); 108 | 109 | exit(errno); 110 | } 111 | 112 | if (bpf_object__load(*obj) != 0) 113 | { 114 | fprintf(stderr, "Error loading BPF object into kernel. Error => %d (%s).\n", errno, strerror(errno)); 115 | 116 | bpf_close_and_exit(*obj, errno); 117 | } 118 | 119 | // Try unpinning maps first. 120 | bpf_object__unpin_maps(*obj, BASEDIR_MAPS); 121 | 122 | // Pin maps. 123 | bpf_object__pin_maps(*obj, BASEDIR_MAPS); 124 | 125 | *prog = bpf_object__find_program_by_name(*obj, prog_name); 126 | 127 | if (!(*prog)) 128 | { 129 | fprintf(stderr, "Error loading BPF program with name 'tc_egress'. Error => %d (%s).\n", errno, strerror(errno)); 130 | 131 | bpf_close_and_exit(*obj, errno); 132 | } 133 | 134 | int fd = bpf_program__fd(*prog); 135 | 136 | if (fd < 0) 137 | { 138 | fprintf(stderr, "BPF program FD is below 0! FD => %d.\n", fd); 139 | 140 | bpf_close_and_exit(*obj, 1); 141 | } 142 | 143 | DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, 144 | .ifindex = ifidx, 145 | .attach_point = BPF_TC_EGRESS 146 | ); 147 | 148 | if ((ret = bpf_tc_hook_destroy(&hook)) < 0) 149 | { 150 | fprintf(stderr, "Warning! Failed to destroy TC hook. Return code => %d.\n", ret); 151 | } 152 | 153 | if ((ret = bpf_tc_hook_create(&hook)) < 0) 154 | { 155 | if (ret != -17) 156 | { 157 | fprintf(stderr, "Failed to create TC hook. Return code => %d.\n", ret); 158 | 159 | bpf_close_and_exit(*obj, ret); 160 | } 161 | } 162 | 163 | DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts, .prog_fd = fd); 164 | 165 | if ((ret = bpf_tc_attach(&hook, &opts)) < 0) 166 | { 167 | fprintf(stderr, "Failed to attach TC program. Return code => %d.\n", ret); 168 | 169 | bpf_close_and_exit(*obj, errno); 170 | } 171 | } 172 | 173 | int tc_remove_egress_filter(int ifidx, struct bpf_object **obj) 174 | { 175 | int ret; 176 | 177 | DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, 178 | .ifindex = ifidx, 179 | .attach_point = BPF_TC_EGRESS 180 | ); 181 | 182 | if ((ret = bpf_tc_hook_destroy(&hook)) < 0) 183 | { 184 | fprintf(stderr, "Failed to detach TC program. Return code => %d.\n", ret); 185 | } 186 | 187 | bpf_object__close(*obj); 188 | 189 | return ret; 190 | } 191 | 192 | int main(int argc, char *argv[]) 193 | { 194 | // Check argument count. 195 | if (argc < 2) 196 | { 197 | fprintf(stderr, "Usage: %s \n", argv[0]); 198 | 199 | exit(1); 200 | } 201 | 202 | // Initialize variables. 203 | int err, ifindex; 204 | 205 | // Get interface index. 206 | ifindex = if_nametoindex(argv[1]); 207 | 208 | // Check if interface is valid. 209 | if (ifindex <= 0) 210 | { 211 | fprintf(stderr, "Error loading interface (%s).\n", argv[1]); 212 | 213 | exit(1); 214 | } 215 | 216 | struct bpf_object *obj = NULL; 217 | struct bpf_program *prog = NULL; 218 | 219 | // Attempt to attach to egress filter. 220 | tc_egress_attach_bpf(ifindex, TCFile, "tc_egress", &obj, &prog); 221 | 222 | // Get MAC map. 223 | mac_map_fd = open_map(map_mac); 224 | 225 | if (mac_map_fd < 0) 226 | { 227 | // Attempt to remove TC filter since map failed. 228 | err = tc_remove_egress_filter(ifindex, &obj); 229 | 230 | exit(err); 231 | } 232 | 233 | // Get gateway MAC address and store it in gwMAC. 234 | GetGatewayMAC(); 235 | 236 | // Add gateway MAC address to the "mac_map" BPF map. 237 | uint64_t val; 238 | val = mac2int(gwMAC); 239 | 240 | uint32_t key2 = 0; 241 | 242 | bpf_map_update_elem(mac_map_fd, &key2, &val, BPF_ANY); 243 | 244 | // Signal calls so we can shutdown program. 245 | signal(SIGINT, signHdl); 246 | signal(SIGTERM, signHdl); 247 | signal(SIGKILL, signHdl); 248 | 249 | // Debug. 250 | fprintf(stdout, "Starting IPIP Direct TC egress program.\n"); 251 | 252 | // Loop! 253 | while (cont) 254 | { 255 | // We sleep every second. 256 | sleep(1); 257 | } 258 | 259 | // Debug. 260 | fprintf(stdout, "Cleaning up...\n"); 261 | 262 | // Remove TC egress filter. 263 | err = tc_remove_egress_filter(ifindex, &obj); 264 | 265 | exit(err); 266 | } -------------------------------------------------------------------------------- /src/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define likely(x) __builtin_expect(!!(x), 1) 7 | #define unlikely(x) __builtin_expect(!!(x), 0) 8 | 9 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 10 | #define htons(x) ((__be16)___constant_swab16((x))) 11 | #define ntohs(x) ((__be16)___constant_swab16((x))) 12 | #define htonl(x) ((__be32)___constant_swab32((x))) 13 | #define ntohl(x) ((__be32)___constant_swab32((x))) 14 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 15 | #define htons(x) (x) 16 | #define ntohs(X) (x) 17 | #define htonl(x) (x) 18 | #define ntohl(x) (x) 19 | #endif -------------------------------------------------------------------------------- /src/include/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define BASEDIR_MAPS "/sys/fs/bpf/tc/globals" 5 | 6 | __always_inline uint64_t mac2int(const uint8_t hwaddr[]) 7 | { 8 | int8_t i; 9 | uint64_t ret = 0; 10 | const uint8_t *p = hwaddr; 11 | 12 | for (i = 5; i >= 0; i--) 13 | { 14 | ret |= (uint64_t) *p++ << (CHAR_BIT * i); 15 | } 16 | 17 | return ret; 18 | } 19 | 20 | __always_inline void int2mac(const uint64_t mac, uint8_t *hwaddr) 21 | { 22 | int8_t i; 23 | uint8_t *p = hwaddr; 24 | 25 | for (i = 5; i >= 0; i--) 26 | { 27 | *p++ = mac >> (CHAR_BIT * i); 28 | } 29 | } --------------------------------------------------------------------------------