├── .gitmodules ├── CoNext-replication.md ├── LICENSE ├── README.md ├── Thesis.pdf ├── libseg6 ├── bpf_seg6 │ ├── all.h │ ├── bpf.h │ ├── bpf.h-mainline │ ├── bpf.h.4-14 │ ├── bpf_api.h │ ├── bpf_elf.h │ └── proto.h └── libseg6.c ├── seg6-bpf-tests ├── Makefile ├── bpf_seg6 │ ├── all.h │ ├── bpf.h │ ├── bpf.h-mainline │ ├── bpf.h.4-14 │ ├── bpf_api.h │ ├── bpf_elf.h │ └── proto.h ├── libseg6.c ├── tests.seg ├── tests_bpf.c ├── tests_tlv.seg └── tlv_bpf.c └── use-cases ├── Links-aggreg ├── cpe_bpf │ ├── Makefile │ ├── bpf_seg6 │ │ ├── all.h │ │ ├── bpf.h │ │ ├── bpf.h.4-14 │ │ ├── bpf_api.h │ │ ├── bpf_elf.h │ │ └── proto.h │ ├── compile_openwrt.sh │ ├── end_otp_bpf.c │ ├── end_otp_usr.c │ ├── libseg6.c │ ├── perfs.sh │ ├── tests_otp.seg │ ├── tests_wrr.seg │ ├── uplink_wrr_bpf.c │ └── uplink_wrr_usr.c ├── dm_recv_bpf.c ├── libseg6.c ├── link_aggreg.py ├── link_aggreg_bpf.c ├── netns.py ├── proto.h ├── simulation.sh └── test.py ├── OAMP-segtrace ├── __init__.py ├── icmp.py ├── libseg6.c ├── oam_ecmp.py ├── oam_ecmp_bpf.c ├── proto.h ├── segtrace.py ├── simulation.sh └── tests.seg └── POWD-monitoring ├── Makefile ├── bpf_seg6 ├── all.h ├── bpf.h ├── bpf.h.4-14 ├── bpf_api.h ├── bpf_elf.h └── proto.h ├── dm_injector_bpf.c ├── dm_injector_usr ├── dm_injector_usr.c ├── end_otp.py ├── end_otp_bpf.c ├── libseg6.c ├── proto.h ├── tests.seg └── tests_injector.seg /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "segway"] 2 | path = segway 3 | url = https://github.com/Zashas/segway.git 4 | [submodule "linux-seg6-bpf"] 5 | path = linux-seg6-bpf 6 | url = https://github.com/Zashas/linux-seg6-bpf.git 7 | [submodule "openwrt-seg6"] 8 | path = openwrt-seg6 9 | url = https://github.com/Zashas/openwrt-seg6.git 10 | -------------------------------------------------------------------------------- /CoNext-replication.md: -------------------------------------------------------------------------------- 1 | # Instructions for replicating our results 2 | 3 | We hereby describe how to replicate the results described in the paper _"Leveraging eBPF for programmable network functions with IPv6 Segment Routing"_, presented at CoNext 2018. 4 | Whenever the installation of a BPF program is required, we suppose that our custom kernel [available here](https://github.com/Zashas/linux-seg6-bpf) (Linux 4.18 with minor modifications), iproute2 4.18, LLVM >= 6.0, [bcc](https://github.com/iovisor/bcc) and our fork of [pyroute2](https://github.com/Zashas/pyroute2) are installed on the machine hosting the program. 5 | 6 | The following [configuration script](https://raw.githubusercontent.com/target0/thesis-data/master/comp4-data/setup.sh) (adapted for each machine) was always executed prior to any measure, tweaking the parameters of our NICs and assigning a single core for packet forwarding. 7 | 8 | ## Performance evaluation of section 3.3 9 | 10 | 1. Setup a functional IPv6 network such as described in Figure 1, Setup 1. 11 | 1. Install on R using iproute2 on the SRv6 SID _R_BPF_ the following actions: 12 | 1. Static endpoints: End, End.T (`ip -6 route add SID6 encap seg6local action End/End.T`) 13 | 1. The BPF programs _pass_ (End BPF), _end\_t_ (End.T BPF), _inc\_tag_ (Tag++ BPF), _add\_8_ (Add TLV BPF) from [here](seg6-bpf-tests/tests_bpf.c) and [here](seg6-bpf-tests/tlv_bpf.c) (`ip -6 route add SID6 encap seg6local action End.BPF endpoint obj OBJECT_FILE.o sec FCT_NAME`). Compile the object files using `make`. 14 | 1. Enable/disable the BPF JIT using `# sysctl net.core.bpf_jit_enable=1/0` 15 | 1. Generate packets using trafgen from S1 with segments _[R_BPF, S2]_ and the parameters described in the article, measure the number of packets per second received on S2. 16 | 17 | ## Performance evaluation of section 4.1 18 | 19 | 1. Setup a functional IPv6 network such as described in Figure 1, Setup 1. 20 | 1. Download the files from [POWD-monitoring](use-cases/POWD-monitoring). 21 | 1. Measuring the performance of the encapsulation program: 22 | 1. Compile on R the _dm\_injector_ files using `make`. 23 | 1. Install on Rthe BPF program DM TLV injector using `ip -6 route add PREFIX encap bpf out obj dm_injector_bpf.o sec main headroom 112 dev IFOUT` with `PREFIX` the IPv6 prefix and `IFOUT` the interface towards S2. 24 | 1. Configure the encapsulation parameters: `./dm_injector_usr SID-OTP FREQUENCY CONTROLLER-IP6 CONTROLLER-DPORT`, with: `SID-OTP` the address of S2, `FREQUENCY` the probing ratio, and the IP:port tuple for the controller (irrelevant here). 25 | 1. Use pktgten to generate IPv6 packets from S1 towards S2, without SRH. The script used is available [here](https://raw.githubusercontent.com/target0/thesis-data/master/comp4-data/pktgen.sh). Measure the number of packets per second received on S2. 26 | 1. Measuring the performance of _End.DM_: 27 | 1. Craft a packet configuration for trafgen, IPv6 UDP 64 bits payload packets from S1 with segments _[R_DM, S2]_ and a valid DM TLV. 28 | 1. Install on R the _End.DM_ program on SID _R\_DM_ using `./end_otp.py R_DM IFOUT`, with `IFOUT` any physical interface. 29 | 1. Use trafgen to generate DM probes from S1. Measure the number of packets per second received on S2. 30 | 31 | ## Performance evaluation of section 4.2 32 | 33 | 1. Flash a Turris Omnia with our [OpenWRT `End.BPF` fork](https://github.com/Zashas/openwrt-seg6). 34 | 1. Setup a functional IPv6 network such as described in Figure 1, Setup 2. Enable native SRv6 support `sysctl net.ipv6.conf.all.seg6_enabled=1`, and on the used inbound interfaces: `sysctl net.ipv6.conf.IFACE.seg6_enabled=1`. 35 | 1. Download the files from [use-cases/Links-aggreg](Links-aggreg). Compile the source code in _cpe\_bpf_ using `make`. Configure the initial `tc netem` policies (such as in the [simulation script](use-cases/Links-aggreg/simulation.sh)). 36 | 1. On the Turris Omnia: 37 | 1. Install the two-way delay measurement function: `ip -6 route add SID-OTP-CPE encap seg6local action End.BPF endpoint obj cpe_bpf/end_otp_bpf.o section end_otp dev IFACE`, with `IFACE` any physical interface. 38 | 1. Install the WRR encapsulation `ip -6 route add default encap bpf in obj cpe_bpf/uplink_wrr_bpf.o section main dev IFACE`, with `IFACE` any physical interface. 39 | 1. Configure the BPF programs by running `cpe_bpf/end_otp_usr` and `cpe_bpf/uplink_wrr_usr IP6-AGG SEG-LINK1 WEIGHT-LINK1 SEG-LINK2 WEIGHT-LINK2`. `SEG-LINK1/2` are the intermediate segments forcing the usage of a specific link. 40 | 1. On the aggregator: start the aggregation daemon using `./link_aggreg.py PREFIX-CPE SID-CPE SID1-UP SID1-DOWN WEIGHT1 SID2-UP SID2-DOWN WEIGHT2 SID-OTP-CPE SID-OTP-AGG IFACE-DOWN1,IFACE-DOWN2,... IFACE-UP1,IFACE-UP2,...`, with `PREFIX-CPE` the prefix given to the CPE, `SID-CPE` an IPv6 loopback address on the CPE, `SID1-UP` a SID on the uplink path of WAN 1, `SID1-DOWN` a SID on the downlink path of WAN 1, `SID2-UP` a SID on the uplink path of WAN 2, `SID2-DOWN` a SID on the downlink path of WAN 2, `IFACE-DOWN*` the intefaces of the aggregator towards the WANs, and `IFACE-UP*` the bridges interfaces installed by the aggregator to deploy the uplink `tc netem` policies (tc cannot delay incoming traffic, only outgoing, hence the need for extra bridges). 41 | 1. Use nttcp to generate TCP connections between S1 and S2 and measure the aggregated bandwidth. 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Thesis-SRv6-BPF 2 | Code written for my master's thesis on End.BPF, an interface for programmable IPv6 Segment Routing network functions, and also featured in the paper _"Leveraging eBPF for programmable network functions with IPv6 Segment Routing"_, presented at CoNext 2018. The full thesis manuscript, including the architecture and performance evaluations of End.BPF and of the three use-cases released in this repository, is available in [Thesis.pdf](Thesis.pdf). 3 | 4 | The Linux patches adding the End.BPF hook and the four SRv6-related helpers can be retrieved from [net-next's patchwork website](https://patchwork.ozlabs.org/project/netdev/list/?series=&submitter=73189&state=3&q=&archive=&delegate=). These modifications are available in the upstream Linux kernel since Linux 4.18 (August 2018). 5 | 6 | Instructions for replicating the results presented in the CoNext 2018 paper are available [here](CoNext-replication.md). 7 | 8 | This repository contains: 9 | 10 | - segway: a unit testing framework for SRv6 11 | - libseg6: a library for handling IPv6 Segment Routing Headers in BPF 12 | - use-cases: the code, scripts and Makefiles of the use-cases developed in my master's thesis, that rely on SRv6 BPF 13 | - linux-seg6-bpf: linux kernel with the modifications required by the above use-cases 14 | - openwrt-seg6: fork of OpenWRT/LEDE with a SRv6 BPF support for Linux 4.14 15 | -------------------------------------------------------------------------------- /Thesis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zashas/Thesis-SRv6-BPF/e9f9624ade3f94eb22cbfaffa050506692eaad06/Thesis.pdf -------------------------------------------------------------------------------- /libseg6/bpf_seg6/all.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bpf_api.h" 6 | //#include "proto.h" 7 | 8 | /* Packet parsing state machine helpers. */ 9 | #define cursor_advance(_cursor, _len) \ 10 | ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) 11 | 12 | #define SR6_FLAG_PROTECTED (1 << 6) 13 | #define SR6_FLAG_OAM (1 << 5) 14 | #define SR6_FLAG_ALERT (1 << 4) 15 | #define SR6_FLAG_HMAC (1 << 3) 16 | -------------------------------------------------------------------------------- /libseg6/bpf_seg6/bpf_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_API__ 2 | #define __BPF_API__ 3 | 4 | /* Note: 5 | * 6 | * This file can be included into eBPF kernel programs. It contains 7 | * a couple of useful helper functions, map/section ABI (bpf_elf.h), 8 | * misc macros and some eBPF specific LLVM built-ins. 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | //#include 15 | #include "bpf.h" 16 | #include "proto.h" 17 | #include 18 | 19 | #include 20 | 21 | #include "bpf_elf.h" 22 | 23 | /** Misc macros. */ 24 | 25 | #ifndef __stringify 26 | # define __stringify(X) #X 27 | #endif 28 | 29 | #ifndef __maybe_unused 30 | # define __maybe_unused __attribute__((__unused__)) 31 | #endif 32 | 33 | #ifndef offsetof 34 | # define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) 35 | #endif 36 | 37 | #ifndef likely 38 | # define likely(X) __builtin_expect(!!(X), 1) 39 | #endif 40 | 41 | #ifndef unlikely 42 | # define unlikely(X) __builtin_expect(!!(X), 0) 43 | #endif 44 | 45 | #ifndef htons 46 | # define htons(X) __constant_htons((X)) 47 | #endif 48 | 49 | #ifndef ntohs 50 | # define ntohs(X) __constant_ntohs((X)) 51 | #endif 52 | 53 | #ifndef htonl 54 | # define htonl(X) __constant_htonl((X)) 55 | #endif 56 | 57 | #ifndef ntohl 58 | # define ntohl(X) __constant_ntohl((X)) 59 | #endif 60 | 61 | #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 62 | #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 63 | /* From https://stackoverflow.com/a/28592202 */ 64 | 65 | #ifndef __inline__ 66 | # define __inline__ __attribute__((always_inline)) 67 | #endif 68 | 69 | /** Section helper macros. */ 70 | 71 | #ifndef __section 72 | # define __section(NAME) \ 73 | __attribute__((section(NAME), used)) 74 | #endif 75 | 76 | #ifndef __section_tail 77 | # define __section_tail(ID, KEY) \ 78 | __section(__stringify(ID) "/" __stringify(KEY)) 79 | #endif 80 | 81 | #ifndef __section_xdp_entry 82 | # define __section_xdp_entry \ 83 | __section(ELF_SECTION_PROG) 84 | #endif 85 | 86 | #ifndef __section_cls_entry 87 | # define __section_cls_entry \ 88 | __section(ELF_SECTION_CLASSIFIER) 89 | #endif 90 | 91 | #ifndef __section_act_entry 92 | # define __section_act_entry \ 93 | __section(ELF_SECTION_ACTION) 94 | #endif 95 | 96 | #ifndef __section_lwt_entry 97 | # define __section_lwt_entry \ 98 | __section(ELF_SECTION_PROG) 99 | #endif 100 | 101 | #ifndef __section_license 102 | # define __section_license \ 103 | __section(ELF_SECTION_LICENSE) 104 | #endif 105 | 106 | #ifndef __section_maps 107 | # define __section_maps \ 108 | __section(ELF_SECTION_MAPS) 109 | #endif 110 | 111 | /** Declaration helper macros. */ 112 | 113 | #ifndef BPF_LICENSE 114 | # define BPF_LICENSE(NAME) \ 115 | char ____license[] __section_license = NAME 116 | #endif 117 | 118 | /** Classifier helper */ 119 | 120 | #ifndef BPF_H_DEFAULT 121 | # define BPF_H_DEFAULT -1 122 | #endif 123 | 124 | /** BPF helper functions for tc. Individual flags are in linux/bpf.h */ 125 | 126 | #ifndef __BPF_FUNC 127 | # define __BPF_FUNC(NAME, ...) \ 128 | (* NAME)(__VA_ARGS__) __maybe_unused 129 | #endif 130 | 131 | #ifndef BPF_FUNC 132 | # define BPF_FUNC(NAME, ...) \ 133 | __BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME 134 | #endif 135 | 136 | /* Map access/manipulation */ 137 | static void *BPF_FUNC(map_lookup_elem, void *map, const void *key); 138 | static int BPF_FUNC(map_update_elem, void *map, const void *key, 139 | const void *value, uint32_t flags); 140 | static int BPF_FUNC(map_delete_elem, void *map, const void *key); 141 | 142 | /* Time access */ 143 | static uint64_t BPF_FUNC(ktime_get_ns); 144 | 145 | /* Debugging */ 146 | 147 | /* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless 148 | * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved. 149 | * It would require ____fmt to be made const, which generates a reloc 150 | * entry (non-map). 151 | */ 152 | static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...); 153 | 154 | #ifndef printt 155 | # define printt(fmt, ...) \ 156 | ({ \ 157 | char ____fmt[] = fmt; \ 158 | trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ 159 | }) 160 | #endif 161 | 162 | /* Random numbers */ 163 | static uint32_t BPF_FUNC(get_prandom_u32); 164 | 165 | /* Tail calls */ 166 | static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map, 167 | uint32_t index); 168 | 169 | /* System helpers */ 170 | static uint32_t BPF_FUNC(get_smp_processor_id); 171 | static uint32_t BPF_FUNC(get_numa_node_id); 172 | 173 | /* Packet misc meta data */ 174 | static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb); 175 | static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index); 176 | 177 | static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb); 178 | static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb); 179 | static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb); 180 | 181 | /* Packet redirection */ 182 | static int BPF_FUNC(redirect, int ifindex, uint32_t flags); 183 | static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex, 184 | uint32_t flags); 185 | 186 | /* Packet manipulation */ 187 | static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off, 188 | void *to, uint32_t len); 189 | static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off, 190 | const void *from, uint32_t len, uint32_t flags); 191 | 192 | static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, 193 | uint32_t from, uint32_t to, uint32_t flags); 194 | static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, 195 | uint32_t from, uint32_t to, uint32_t flags); 196 | static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size, 197 | const void *to, uint32_t to_size, uint32_t seed); 198 | static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum); 199 | 200 | static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type); 201 | static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto, 202 | uint32_t flags); 203 | static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen, 204 | uint32_t flags); 205 | 206 | static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len); 207 | 208 | /* Event notification */ 209 | static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map, 210 | uint64_t index, const void *data, uint32_t size) = 211 | (void *) BPF_FUNC_perf_event_output; 212 | 213 | /* Packet vlan encap/decap */ 214 | static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, 215 | uint16_t vlan_tci); 216 | static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb); 217 | 218 | /* Packet tunnel encap/decap */ 219 | static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb, 220 | struct bpf_tunnel_key *to, uint32_t size, uint32_t flags); 221 | static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, 222 | const struct bpf_tunnel_key *from, uint32_t size, 223 | uint32_t flags); 224 | 225 | static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb, 226 | void *to, uint32_t size); 227 | static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb, 228 | const void *from, uint32_t size); 229 | 230 | /* OLD SEG6 helpers 231 | static int BPF_FUNC(skb_seg6_change_field, struct __sk_buff *skb, 232 | uint8_t field, uint32_t value); 233 | static int BPF_FUNC(skb_seg6_add_tlv, struct __sk_buff *skb, uint32_t tlv_offset, 234 | struct sr6_tlv *itlv); 235 | static int BPF_FUNC(skb_seg6_delete_tlv, struct __sk_buff *skb, struct sr6_tlv *tlv); 236 | static int BPF_FUNC(skb_seg6_action_end_x, struct __sk_buff *skb, struct ip6_addr *nhaddr); 237 | static int BPF_FUNC(skb_seg6_action_end_t, struct __sk_buff *skb, uint32_t tbl_id); 238 | static int BPF_FUNC(skb_seg6_action_end_b6, struct __sk_buff *skb, struct ip6_srh_t *srh); 239 | static int BPF_FUNC(skb_seg6_encap_push, struct __sk_buff *skb, struct ip6_srh_t *srh); 240 | */ 241 | 242 | 243 | static int BPF_FUNC(lwt_push_encap, struct __sk_buff *skb, uint32_t type, void *hdr, uint32_t len); 244 | static int BPF_FUNC(lwt_seg6_store_bytes, struct __sk_buff *skb, uint32_t offset, const void *from, uint32_t len); 245 | static int BPF_FUNC(lwt_seg6_action, struct __sk_buff *skb, uint32_t action, void *param, uint32_t param_len); 246 | static int BPF_FUNC(lwt_seg6_adjust_srh, struct __sk_buff *skb, uint32_t offset, int32_t len); 247 | 248 | /** LLVM built-ins, mem*() routines work for constant size */ 249 | 250 | #ifndef lock_xadd 251 | # define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) 252 | #endif 253 | 254 | #ifndef memset 255 | # define memset(s, c, n) __builtin_memset((s), (c), (n)) 256 | #endif 257 | 258 | #ifndef memcpy 259 | # define memcpy(d, s, n) __builtin_memcpy((d), (s), (n)) 260 | #endif 261 | 262 | #ifndef memmove 263 | # define memmove(d, s, n) __builtin_memmove((d), (s), (n)) 264 | #endif 265 | 266 | /* FIXME: __builtin_memcmp() is not yet fully useable unless llvm bug 267 | * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also 268 | * this one would generate a reloc entry (non-map), otherwise. 269 | */ 270 | #if 0 271 | #ifndef memcmp 272 | # define memcmp(a, b, n) __builtin_memcmp((a), (b), (n)) 273 | #endif 274 | #endif 275 | 276 | unsigned long long load_byte(void *skb, unsigned long long off) 277 | asm ("llvm.bpf.load.byte"); 278 | 279 | unsigned long long load_half(void *skb, unsigned long long off) 280 | asm ("llvm.bpf.load.half"); 281 | 282 | unsigned long long load_word(void *skb, unsigned long long off) 283 | asm ("llvm.bpf.load.word"); 284 | 285 | #endif /* __BPF_API__ */ 286 | -------------------------------------------------------------------------------- /libseg6/bpf_seg6/bpf_elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_ELF__ 2 | #define __BPF_ELF__ 3 | 4 | #include 5 | 6 | /* Note: 7 | * 8 | * Below ELF section names and bpf_elf_map structure definition 9 | * are not (!) kernel ABI. It's rather a "contract" between the 10 | * application and the BPF loader in tc. For compatibility, the 11 | * section names should stay as-is. Introduction of aliases, if 12 | * needed, are a possibility, though. 13 | */ 14 | 15 | /* ELF section names, etc */ 16 | #define ELF_SECTION_LICENSE "license" 17 | #define ELF_SECTION_MAPS "maps" 18 | #define ELF_SECTION_PROG "prog" 19 | #define ELF_SECTION_CLASSIFIER "classifier" 20 | #define ELF_SECTION_ACTION "action" 21 | 22 | #define ELF_MAX_MAPS 64 23 | #define ELF_MAX_LICENSE_LEN 128 24 | 25 | /* Object pinning settings */ 26 | #define PIN_NONE 0 27 | #define PIN_OBJECT_NS 1 28 | #define PIN_GLOBAL_NS 2 29 | 30 | /* ELF map definition */ 31 | struct bpf_elf_map { 32 | __u32 type; 33 | __u32 size_key; 34 | __u32 size_value; 35 | __u32 max_elem; 36 | __u32 flags; 37 | __u32 id; 38 | __u32 pinning; 39 | }; 40 | 41 | #endif /* __BPF_ELF__ */ 42 | -------------------------------------------------------------------------------- /libseg6/bpf_seg6/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /libseg6/libseg6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define bpf_skb_load_bytes skb_load_bytes 3 | #define bpf_lwt_seg6_adjust_srh lwt_seg6_adjust_srh 4 | #define bpf_lwt_seg6_store_bytes lwt_seg6_store_bytes 5 | 6 | #include "bpf_seg6/all.h" 7 | #define TLV_ITERATIONS 16 8 | 9 | __attribute__((always_inline)) 10 | struct ip6_srh_t *seg6_get_srh(struct __sk_buff *skb) 11 | { 12 | void *cursor, *data_end; 13 | struct ip6_srh_t *srh; 14 | struct ip6_t *ip; 15 | uint16_t opt_len; 16 | uint8_t *ipver; 17 | 18 | data_end = (void *)(long)skb->data_end; 19 | cursor = (void *)(long)skb->data; 20 | ipver = (uint8_t *)cursor; 21 | 22 | if ((void *)ipver + sizeof(*ipver) > data_end) 23 | return NULL; 24 | 25 | if ((*ipver >> 4) != 6) 26 | return NULL; 27 | 28 | ip = cursor_advance(cursor, sizeof(*ip)); 29 | if ((void *)ip + sizeof(*ip) > data_end) 30 | return NULL; 31 | 32 | if (ip->next_header != 43) 33 | return NULL; 34 | 35 | // skipping possible destination or hop-by-hop header 36 | if (ip->next_header == 0 || ip->next_header == 60) { 37 | if ((void *)cursor + 2 > data_end) 38 | return NULL; 39 | opt_len = (1 + (uint16_t) *((uint8_t *) cursor + 1)) << 3; 40 | if ((void *)cursor + opt_len > data_end) 41 | return NULL; 42 | cursor_advance(cursor, opt_len); 43 | } 44 | 45 | // possible destination header 46 | if (ip->next_header == 60) { 47 | if ((void *)cursor + 2 > data_end) 48 | return NULL; 49 | opt_len = (1 + (uint16_t) *((uint8_t *) cursor + 1)) << 3; 50 | if ((void *)cursor + opt_len > data_end) 51 | return NULL; 52 | cursor_advance(cursor, opt_len); 53 | } 54 | 55 | srh = cursor_advance(cursor, sizeof(*srh)); 56 | if ((void *)srh + sizeof(*srh) > data_end) 57 | return NULL; 58 | 59 | if (srh->type != 4) 60 | return NULL; 61 | 62 | return srh; 63 | } 64 | 65 | __attribute__((always_inline)) 66 | int __update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, 67 | uint32_t old_pad, uint32_t pad_off) 68 | { 69 | int err; 70 | 71 | if (new_pad != old_pad) { 72 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, 73 | (int) new_pad - (int) old_pad); 74 | if (err) 75 | return err; 76 | } 77 | 78 | if (new_pad > 0) { 79 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 0, 0}; 81 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; 82 | 83 | pad_tlv->type = SR6_TLV_PADDING; 84 | pad_tlv->len = new_pad - 2; 85 | 86 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, 87 | (void *)pad_tlv_buf, new_pad); 88 | if (err) 89 | return err; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | __attribute__((always_inline)) 96 | int __is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, 97 | uint32_t *tlv_off, uint32_t *pad_size, 98 | uint32_t *pad_off) 99 | { 100 | uint32_t srh_off, cur_off; 101 | int offset_valid = 0; 102 | int err; 103 | 104 | srh_off = (char *)srh - (char *)(long)skb->data; 105 | // cur_off = end of segments, start of possible TLVs 106 | cur_off = srh_off + sizeof(*srh) + 107 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); 108 | 109 | *pad_off = 0; 110 | 111 | // we can only go as far as ~10 TLVs due to the BPF max stack size 112 | #pragma clang loop unroll(full) 113 | for (int i = 0; i < TLV_ITERATIONS; i++) { 114 | struct sr6_tlv_t tlv; 115 | 116 | if (cur_off == *tlv_off) 117 | offset_valid = 1; 118 | 119 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) 120 | break; 121 | 122 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); 123 | if (err) 124 | return err; 125 | 126 | if (tlv.type == SR6_TLV_PADDING) { 127 | *pad_size = tlv.len + sizeof(tlv); 128 | *pad_off = cur_off; 129 | 130 | if (*tlv_off == srh_off) { 131 | *tlv_off = cur_off; 132 | offset_valid = 1; 133 | } 134 | break; 135 | 136 | } else if (tlv.type == SR6_TLV_HMAC) { 137 | break; 138 | } 139 | 140 | cur_off += sizeof(tlv) + tlv.len; 141 | } // we reached the padding or HMAC TLVs, or the end of the SRH 142 | 143 | if (*pad_off == 0) 144 | *pad_off = cur_off; 145 | 146 | if (*tlv_off == -1) 147 | *tlv_off = cur_off; 148 | else if (!offset_valid) 149 | return -EINVAL; 150 | 151 | return 0; 152 | } 153 | 154 | __attribute__((always_inline)) 155 | int seg6_add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, 156 | struct sr6_tlv_t *itlv, uint8_t tlv_size) 157 | { 158 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 159 | uint8_t len_remaining, new_pad; 160 | uint32_t pad_off = 0; 161 | uint32_t pad_size = 0; 162 | uint32_t partial_srh_len; 163 | int err; 164 | 165 | if (tlv_off != -1) 166 | tlv_off += srh_off; 167 | 168 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) 169 | return -EINVAL; 170 | 171 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 172 | if (err) 173 | return err; 174 | 175 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); 176 | if (err) 177 | return err; 178 | 179 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); 180 | if (err) 181 | return err; 182 | 183 | // the following can't be moved inside update_tlv_pad because the 184 | // bpf verifier has some issues with it 185 | pad_off += sizeof(*itlv) + itlv->len; 186 | partial_srh_len = pad_off - srh_off; 187 | len_remaining = partial_srh_len % 8; 188 | new_pad = 8 - len_remaining; 189 | 190 | if (new_pad == 1) // cannot pad for 1 byte only 191 | new_pad = 9; 192 | else if (new_pad == 8) 193 | new_pad = 0; 194 | 195 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 196 | } 197 | 198 | __attribute__((always_inline)) 199 | int seg6_delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, 200 | uint32_t tlv_off) 201 | { 202 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 203 | uint8_t len_remaining, new_pad; 204 | uint32_t partial_srh_len; 205 | uint32_t pad_off = 0; 206 | uint32_t pad_size = 0; 207 | struct sr6_tlv_t tlv; 208 | int err; 209 | 210 | tlv_off += srh_off; 211 | 212 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 213 | if (err) 214 | return err; 215 | 216 | err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); 217 | if (err) 218 | return err; 219 | 220 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); 221 | if (err) 222 | return err; 223 | 224 | pad_off -= sizeof(tlv) + tlv.len; 225 | partial_srh_len = pad_off - srh_off; 226 | len_remaining = partial_srh_len % 8; 227 | new_pad = 8 - len_remaining; 228 | if (new_pad == 1) // cannot pad for 1 byte only 229 | new_pad = 9; 230 | else if (new_pad == 8) 231 | new_pad = 0; 232 | 233 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 234 | } 235 | 236 | __attribute__((always_inline)) 237 | int seg6_find_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, unsigned char type, 238 | unsigned char len) 239 | { 240 | int srh_offset = (char *)srh - (char *)(long)skb->data; 241 | // initial cursor = end of segments, start of possible TLVs 242 | int cursor = srh_offset + sizeof(struct ip6_srh_t) + 243 | ((srh->first_segment + 1) << 4); 244 | 245 | #pragma clang loop unroll(full) 246 | for(int i=0; i < TLV_ITERATIONS; i++) { 247 | if (cursor >= srh_offset + ((srh->hdrlen + 1) << 3)) 248 | return -1; 249 | 250 | struct sr6_tlv_t tlv; 251 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(struct sr6_tlv_t))) 252 | return -1; 253 | //bpf_trace_printk("TLV type=%d len=%d found at offset %d\n", tlv.type, tlv.len, cursor); 254 | 255 | if (tlv.type == type && tlv.len + sizeof(struct sr6_tlv_t) == len) 256 | return cursor; 257 | 258 | cursor += sizeof(tlv) + tlv.len; 259 | } 260 | return -1; 261 | } 262 | -------------------------------------------------------------------------------- /seg6-bpf-tests/Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | LLC = llc 3 | 4 | SRCS = $(wildcard *.c) 5 | OBJS = $(patsubst %.c, %.o, $(SRCS)) 6 | 7 | .PHONY: bpf 8 | 9 | all: $(OBJS) 10 | 11 | clean: 12 | rm $(OBJS) 13 | 14 | %.o: %.c 15 | $(CC) -Wall -O2 -emit-llvm -g -c $< -o - | $(LLC) -march=bpf -filetype=obj -o $@ 16 | -------------------------------------------------------------------------------- /seg6-bpf-tests/bpf_seg6/all.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bpf_api.h" 6 | //#include "proto.h" 7 | 8 | /* Packet parsing state machine helpers. */ 9 | #define cursor_advance(_cursor, _len) \ 10 | ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) 11 | 12 | #define SR6_FLAG_PROTECTED (1 << 6) 13 | #define SR6_FLAG_OAM (1 << 5) 14 | #define SR6_FLAG_ALERT (1 << 4) 15 | #define SR6_FLAG_HMAC (1 << 3) 16 | -------------------------------------------------------------------------------- /seg6-bpf-tests/bpf_seg6/bpf_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_API__ 2 | #define __BPF_API__ 3 | 4 | /* Note: 5 | * 6 | * This file can be included into eBPF kernel programs. It contains 7 | * a couple of useful helper functions, map/section ABI (bpf_elf.h), 8 | * misc macros and some eBPF specific LLVM built-ins. 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | //#include 15 | #include "bpf.h" 16 | #include "proto.h" 17 | #include 18 | 19 | #include 20 | 21 | #include "bpf_elf.h" 22 | 23 | /** Misc macros. */ 24 | 25 | #ifndef __stringify 26 | # define __stringify(X) #X 27 | #endif 28 | 29 | #ifndef __maybe_unused 30 | # define __maybe_unused __attribute__((__unused__)) 31 | #endif 32 | 33 | #ifndef offsetof 34 | # define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) 35 | #endif 36 | 37 | #ifndef likely 38 | # define likely(X) __builtin_expect(!!(X), 1) 39 | #endif 40 | 41 | #ifndef unlikely 42 | # define unlikely(X) __builtin_expect(!!(X), 0) 43 | #endif 44 | 45 | #ifndef htons 46 | # define htons(X) __constant_htons((X)) 47 | #endif 48 | 49 | #ifndef ntohs 50 | # define ntohs(X) __constant_ntohs((X)) 51 | #endif 52 | 53 | #ifndef htonl 54 | # define htonl(X) __constant_htonl((X)) 55 | #endif 56 | 57 | #ifndef ntohl 58 | # define ntohl(X) __constant_ntohl((X)) 59 | #endif 60 | 61 | #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 62 | #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 63 | /* From https://stackoverflow.com/a/28592202 */ 64 | 65 | #ifndef __inline__ 66 | # define __inline__ __attribute__((always_inline)) 67 | #endif 68 | 69 | /** Section helper macros. */ 70 | 71 | #ifndef __section 72 | # define __section(NAME) \ 73 | __attribute__((section(NAME), used)) 74 | #endif 75 | 76 | #ifndef __section_tail 77 | # define __section_tail(ID, KEY) \ 78 | __section(__stringify(ID) "/" __stringify(KEY)) 79 | #endif 80 | 81 | #ifndef __section_xdp_entry 82 | # define __section_xdp_entry \ 83 | __section(ELF_SECTION_PROG) 84 | #endif 85 | 86 | #ifndef __section_cls_entry 87 | # define __section_cls_entry \ 88 | __section(ELF_SECTION_CLASSIFIER) 89 | #endif 90 | 91 | #ifndef __section_act_entry 92 | # define __section_act_entry \ 93 | __section(ELF_SECTION_ACTION) 94 | #endif 95 | 96 | #ifndef __section_lwt_entry 97 | # define __section_lwt_entry \ 98 | __section(ELF_SECTION_PROG) 99 | #endif 100 | 101 | #ifndef __section_license 102 | # define __section_license \ 103 | __section(ELF_SECTION_LICENSE) 104 | #endif 105 | 106 | #ifndef __section_maps 107 | # define __section_maps \ 108 | __section(ELF_SECTION_MAPS) 109 | #endif 110 | 111 | /** Declaration helper macros. */ 112 | 113 | #ifndef BPF_LICENSE 114 | # define BPF_LICENSE(NAME) \ 115 | char ____license[] __section_license = NAME 116 | #endif 117 | 118 | /** Classifier helper */ 119 | 120 | #ifndef BPF_H_DEFAULT 121 | # define BPF_H_DEFAULT -1 122 | #endif 123 | 124 | /** BPF helper functions for tc. Individual flags are in linux/bpf.h */ 125 | 126 | #ifndef __BPF_FUNC 127 | # define __BPF_FUNC(NAME, ...) \ 128 | (* NAME)(__VA_ARGS__) __maybe_unused 129 | #endif 130 | 131 | #ifndef BPF_FUNC 132 | # define BPF_FUNC(NAME, ...) \ 133 | __BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME 134 | #endif 135 | 136 | /* Map access/manipulation */ 137 | static void *BPF_FUNC(map_lookup_elem, void *map, const void *key); 138 | static int BPF_FUNC(map_update_elem, void *map, const void *key, 139 | const void *value, uint32_t flags); 140 | static int BPF_FUNC(map_delete_elem, void *map, const void *key); 141 | 142 | /* Time access */ 143 | static uint64_t BPF_FUNC(ktime_get_ns); 144 | 145 | /* Debugging */ 146 | 147 | /* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless 148 | * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved. 149 | * It would require ____fmt to be made const, which generates a reloc 150 | * entry (non-map). 151 | */ 152 | static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...); 153 | 154 | #ifndef printt 155 | # define printt(fmt, ...) \ 156 | ({ \ 157 | char ____fmt[] = fmt; \ 158 | trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ 159 | }) 160 | #endif 161 | 162 | /* Random numbers */ 163 | static uint32_t BPF_FUNC(get_prandom_u32); 164 | 165 | /* Tail calls */ 166 | static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map, 167 | uint32_t index); 168 | 169 | /* System helpers */ 170 | static uint32_t BPF_FUNC(get_smp_processor_id); 171 | static uint32_t BPF_FUNC(get_numa_node_id); 172 | 173 | /* Packet misc meta data */ 174 | static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb); 175 | static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index); 176 | 177 | static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb); 178 | static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb); 179 | static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb); 180 | 181 | /* Packet redirection */ 182 | static int BPF_FUNC(redirect, int ifindex, uint32_t flags); 183 | static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex, 184 | uint32_t flags); 185 | 186 | /* Packet manipulation */ 187 | static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off, 188 | void *to, uint32_t len); 189 | static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off, 190 | const void *from, uint32_t len, uint32_t flags); 191 | 192 | static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, 193 | uint32_t from, uint32_t to, uint32_t flags); 194 | static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, 195 | uint32_t from, uint32_t to, uint32_t flags); 196 | static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size, 197 | const void *to, uint32_t to_size, uint32_t seed); 198 | static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum); 199 | 200 | static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type); 201 | static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto, 202 | uint32_t flags); 203 | static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen, 204 | uint32_t flags); 205 | 206 | static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len); 207 | 208 | /* Event notification */ 209 | static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map, 210 | uint64_t index, const void *data, uint32_t size) = 211 | (void *) BPF_FUNC_perf_event_output; 212 | 213 | /* Packet vlan encap/decap */ 214 | static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, 215 | uint16_t vlan_tci); 216 | static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb); 217 | 218 | /* Packet tunnel encap/decap */ 219 | static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb, 220 | struct bpf_tunnel_key *to, uint32_t size, uint32_t flags); 221 | static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, 222 | const struct bpf_tunnel_key *from, uint32_t size, 223 | uint32_t flags); 224 | 225 | static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb, 226 | void *to, uint32_t size); 227 | static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb, 228 | const void *from, uint32_t size); 229 | 230 | /* OLD SEG6 helpers 231 | static int BPF_FUNC(skb_seg6_change_field, struct __sk_buff *skb, 232 | uint8_t field, uint32_t value); 233 | static int BPF_FUNC(skb_seg6_add_tlv, struct __sk_buff *skb, uint32_t tlv_offset, 234 | struct sr6_tlv *itlv); 235 | static int BPF_FUNC(skb_seg6_delete_tlv, struct __sk_buff *skb, struct sr6_tlv *tlv); 236 | static int BPF_FUNC(skb_seg6_action_end_x, struct __sk_buff *skb, struct ip6_addr *nhaddr); 237 | static int BPF_FUNC(skb_seg6_action_end_t, struct __sk_buff *skb, uint32_t tbl_id); 238 | static int BPF_FUNC(skb_seg6_action_end_b6, struct __sk_buff *skb, struct ip6_srh_t *srh); 239 | static int BPF_FUNC(skb_seg6_encap_push, struct __sk_buff *skb, struct ip6_srh_t *srh); 240 | */ 241 | 242 | 243 | static int BPF_FUNC(lwt_push_encap, struct __sk_buff *skb, uint32_t type, void *hdr, uint32_t len); 244 | static int BPF_FUNC(lwt_seg6_store_bytes, struct __sk_buff *skb, uint32_t offset, const void *from, uint32_t len); 245 | static int BPF_FUNC(lwt_seg6_action, struct __sk_buff *skb, uint32_t action, void *param, uint32_t param_len); 246 | static int BPF_FUNC(lwt_seg6_adjust_srh, struct __sk_buff *skb, uint32_t offset, int32_t len); 247 | 248 | /** LLVM built-ins, mem*() routines work for constant size */ 249 | 250 | #ifndef lock_xadd 251 | # define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) 252 | #endif 253 | 254 | #ifndef memset 255 | # define memset(s, c, n) __builtin_memset((s), (c), (n)) 256 | #endif 257 | 258 | #ifndef memcpy 259 | # define memcpy(d, s, n) __builtin_memcpy((d), (s), (n)) 260 | #endif 261 | 262 | #ifndef memmove 263 | # define memmove(d, s, n) __builtin_memmove((d), (s), (n)) 264 | #endif 265 | 266 | /* FIXME: __builtin_memcmp() is not yet fully useable unless llvm bug 267 | * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also 268 | * this one would generate a reloc entry (non-map), otherwise. 269 | */ 270 | #if 0 271 | #ifndef memcmp 272 | # define memcmp(a, b, n) __builtin_memcmp((a), (b), (n)) 273 | #endif 274 | #endif 275 | 276 | unsigned long long load_byte(void *skb, unsigned long long off) 277 | asm ("llvm.bpf.load.byte"); 278 | 279 | unsigned long long load_half(void *skb, unsigned long long off) 280 | asm ("llvm.bpf.load.half"); 281 | 282 | unsigned long long load_word(void *skb, unsigned long long off) 283 | asm ("llvm.bpf.load.word"); 284 | 285 | #endif /* __BPF_API__ */ 286 | -------------------------------------------------------------------------------- /seg6-bpf-tests/bpf_seg6/bpf_elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_ELF__ 2 | #define __BPF_ELF__ 3 | 4 | #include 5 | 6 | /* Note: 7 | * 8 | * Below ELF section names and bpf_elf_map structure definition 9 | * are not (!) kernel ABI. It's rather a "contract" between the 10 | * application and the BPF loader in tc. For compatibility, the 11 | * section names should stay as-is. Introduction of aliases, if 12 | * needed, are a possibility, though. 13 | */ 14 | 15 | /* ELF section names, etc */ 16 | #define ELF_SECTION_LICENSE "license" 17 | #define ELF_SECTION_MAPS "maps" 18 | #define ELF_SECTION_PROG "prog" 19 | #define ELF_SECTION_CLASSIFIER "classifier" 20 | #define ELF_SECTION_ACTION "action" 21 | 22 | #define ELF_MAX_MAPS 64 23 | #define ELF_MAX_LICENSE_LEN 128 24 | 25 | /* Object pinning settings */ 26 | #define PIN_NONE 0 27 | #define PIN_OBJECT_NS 1 28 | #define PIN_GLOBAL_NS 2 29 | 30 | /* ELF map definition */ 31 | struct bpf_elf_map { 32 | __u32 type; 33 | __u32 size_key; 34 | __u32 size_value; 35 | __u32 max_elem; 36 | __u32 flags; 37 | __u32 id; 38 | __u32 pinning; 39 | }; 40 | 41 | #endif /* __BPF_ELF__ */ 42 | -------------------------------------------------------------------------------- /seg6-bpf-tests/bpf_seg6/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /seg6-bpf-tests/libseg6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define bpf_skb_load_bytes skb_load_bytes 3 | #define bpf_lwt_seg6_adjust_srh lwt_seg6_adjust_srh 4 | #define bpf_lwt_seg6_store_bytes lwt_seg6_store_bytes 5 | 6 | #include "bpf_seg6/all.h" 7 | #define TLV_ITERATIONS 16 8 | 9 | __attribute__((always_inline)) 10 | struct ip6_srh_t *seg6_get_srh(struct __sk_buff *skb) 11 | { 12 | void *cursor, *data_end; 13 | struct ip6_srh_t *srh; 14 | struct ip6_t *ip; 15 | uint16_t opt_len; 16 | uint8_t *ipver; 17 | 18 | data_end = (void *)(long)skb->data_end; 19 | cursor = (void *)(long)skb->data; 20 | ipver = (uint8_t *)cursor; 21 | 22 | if ((void *)ipver + sizeof(*ipver) > data_end) 23 | return NULL; 24 | 25 | if ((*ipver >> 4) != 6) 26 | return NULL; 27 | 28 | ip = cursor_advance(cursor, sizeof(*ip)); 29 | if ((void *)ip + sizeof(*ip) > data_end) 30 | return NULL; 31 | 32 | if (ip->next_header != 43) 33 | return NULL; 34 | 35 | // skipping possible destination or hop-by-hop header 36 | if (ip->next_header == 0 || ip->next_header == 60) { 37 | if ((void *)cursor + 2 > data_end) 38 | return NULL; 39 | opt_len = (1 + (uint16_t) *((uint8_t *) cursor + 1)) << 3; 40 | if ((void *)cursor + opt_len > data_end) 41 | return NULL; 42 | cursor_advance(cursor, opt_len); 43 | } 44 | 45 | // possible destination header 46 | if (ip->next_header == 60) { 47 | if ((void *)cursor + 2 > data_end) 48 | return NULL; 49 | opt_len = (1 + (uint16_t) *((uint8_t *) cursor + 1)) << 3; 50 | if ((void *)cursor + opt_len > data_end) 51 | return NULL; 52 | cursor_advance(cursor, opt_len); 53 | } 54 | 55 | srh = cursor_advance(cursor, sizeof(*srh)); 56 | if ((void *)srh + sizeof(*srh) > data_end) 57 | return NULL; 58 | 59 | if (srh->type != 4) 60 | return NULL; 61 | 62 | return srh; 63 | } 64 | 65 | __attribute__((always_inline)) 66 | int __update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, 67 | uint32_t old_pad, uint32_t pad_off) 68 | { 69 | int err; 70 | 71 | if (new_pad != old_pad) { 72 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, 73 | (int) new_pad - (int) old_pad); 74 | if (err) 75 | return err; 76 | } 77 | 78 | if (new_pad > 0) { 79 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 0, 0}; 81 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; 82 | 83 | pad_tlv->type = SR6_TLV_PADDING; 84 | pad_tlv->len = new_pad - 2; 85 | 86 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, 87 | (void *)pad_tlv_buf, new_pad); 88 | if (err) 89 | return err; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | __attribute__((always_inline)) 96 | int __is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, 97 | uint32_t *tlv_off, uint32_t *pad_size, 98 | uint32_t *pad_off) 99 | { 100 | uint32_t srh_off, cur_off; 101 | int offset_valid = 0; 102 | int err; 103 | 104 | srh_off = (char *)srh - (char *)(long)skb->data; 105 | // cur_off = end of segments, start of possible TLVs 106 | cur_off = srh_off + sizeof(*srh) + 107 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); 108 | 109 | *pad_off = 0; 110 | 111 | // we can only go as far as ~10 TLVs due to the BPF max stack size 112 | #pragma clang loop unroll(full) 113 | for (int i = 0; i < TLV_ITERATIONS; i++) { 114 | struct sr6_tlv_t tlv; 115 | 116 | if (cur_off == *tlv_off) 117 | offset_valid = 1; 118 | 119 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) 120 | break; 121 | 122 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); 123 | if (err) 124 | return err; 125 | 126 | if (tlv.type == SR6_TLV_PADDING) { 127 | *pad_size = tlv.len + sizeof(tlv); 128 | *pad_off = cur_off; 129 | 130 | if (*tlv_off == srh_off) { 131 | *tlv_off = cur_off; 132 | offset_valid = 1; 133 | } 134 | break; 135 | 136 | } else if (tlv.type == SR6_TLV_HMAC) { 137 | break; 138 | } 139 | 140 | cur_off += sizeof(tlv) + tlv.len; 141 | } // we reached the padding or HMAC TLVs, or the end of the SRH 142 | 143 | if (*pad_off == 0) 144 | *pad_off = cur_off; 145 | 146 | if (*tlv_off == -1) 147 | *tlv_off = cur_off; 148 | else if (!offset_valid) 149 | return -EINVAL; 150 | 151 | return 0; 152 | } 153 | 154 | __attribute__((always_inline)) 155 | int seg6_add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, 156 | struct sr6_tlv_t *itlv, uint8_t tlv_size) 157 | { 158 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 159 | uint8_t len_remaining, new_pad; 160 | uint32_t pad_off = 0; 161 | uint32_t pad_size = 0; 162 | uint32_t partial_srh_len; 163 | int err; 164 | 165 | if (tlv_off != -1) 166 | tlv_off += srh_off; 167 | 168 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) 169 | return -EINVAL; 170 | 171 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 172 | if (err) 173 | return err; 174 | 175 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); 176 | if (err) 177 | return err; 178 | 179 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); 180 | if (err) 181 | return err; 182 | 183 | // the following can't be moved inside update_tlv_pad because the 184 | // bpf verifier has some issues with it 185 | pad_off += sizeof(*itlv) + itlv->len; 186 | partial_srh_len = pad_off - srh_off; 187 | len_remaining = partial_srh_len % 8; 188 | new_pad = 8 - len_remaining; 189 | 190 | if (new_pad == 1) // cannot pad for 1 byte only 191 | new_pad = 9; 192 | else if (new_pad == 8) 193 | new_pad = 0; 194 | 195 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 196 | } 197 | 198 | __attribute__((always_inline)) 199 | int seg6_delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, 200 | uint32_t tlv_off) 201 | { 202 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 203 | uint8_t len_remaining, new_pad; 204 | uint32_t partial_srh_len; 205 | uint32_t pad_off = 0; 206 | uint32_t pad_size = 0; 207 | struct sr6_tlv_t tlv; 208 | int err; 209 | 210 | tlv_off += srh_off; 211 | 212 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 213 | if (err) 214 | return err; 215 | 216 | err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); 217 | if (err) 218 | return err; 219 | 220 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); 221 | if (err) 222 | return err; 223 | 224 | pad_off -= sizeof(tlv) + tlv.len; 225 | partial_srh_len = pad_off - srh_off; 226 | len_remaining = partial_srh_len % 8; 227 | new_pad = 8 - len_remaining; 228 | if (new_pad == 1) // cannot pad for 1 byte only 229 | new_pad = 9; 230 | else if (new_pad == 8) 231 | new_pad = 0; 232 | 233 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 234 | } 235 | 236 | __attribute__((always_inline)) 237 | int seg6_find_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, unsigned char type, 238 | unsigned char len) 239 | { 240 | int srh_offset = (char *)srh - (char *)(long)skb->data; 241 | // initial cursor = end of segments, start of possible TLVs 242 | int cursor = srh_offset + sizeof(struct ip6_srh_t) + 243 | ((srh->first_segment + 1) << 4); 244 | 245 | #pragma clang loop unroll(full) 246 | for(int i=0; i < TLV_ITERATIONS; i++) { 247 | if (cursor >= srh_offset + ((srh->hdrlen + 1) << 3)) 248 | return -1; 249 | 250 | struct sr6_tlv_t tlv; 251 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(struct sr6_tlv_t))) 252 | return -1; 253 | //bpf_trace_printk("TLV type=%d len=%d found at offset %d\n", tlv.type, tlv.len, cursor); 254 | 255 | if (tlv.type == type && tlv.len + sizeof(struct sr6_tlv_t) == len) 256 | return cursor; 257 | 258 | cursor += sizeof(tlv) + tlv.len; 259 | } 260 | return -1; 261 | } 262 | -------------------------------------------------------------------------------- /seg6-bpf-tests/tests.seg: -------------------------------------------------------------------------------- 1 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::1 encap seg6local action End.BPF obj tests_bpf.o section pass dev dum0` 2 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::2 encap seg6local action End.BPF obj tests_bpf.o section drop dev dum0` 3 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::3 encap seg6local action End.BPF obj tests_bpf.o section inc_tag dev dum0` 4 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::4 encap seg6local action End.BPF obj tests_bpf.o section alert dev dum0` 5 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::5 encap seg6local action End.BPF obj tests_bpf.o section end_x dev dum0` 6 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::6 encap seg6local action End.BPF obj tests_bpf.o section end_b6 dev dum0` 7 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::7 encap seg6local action End.BPF obj tests_bpf.o section end_t dev dum0` 8 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::8 encap seg6local action End.BPF obj tests_bpf.o section b6_encap_wrong dev dum0` 9 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::9 encap seg6local action End.BPF obj tests_bpf.o section b6_encap dev dum0` 10 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::10 encap seg6local action End.BPF obj tests_bpf.o section long_b6_encap dev dum0` 11 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::12 encap seg6local action End.BPF obj tests_bpf.o section long_b6 dev dum0` 12 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::17 encap seg6local action End.BPF obj tests_bpf.o section wrong_stores dev dum0` 13 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::18 encap seg6local action End.BPF obj tests_bpf.o section wrong_adjusts dev dum0` 14 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::19 encap seg6local action End.BPF obj tests_bpf.o section invalid_hdrlen dev dum0` 15 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::21 encap seg6local action End.BPF obj tests_bpf.o section end_dt6 dev dum0` 16 | 17 | if add dum1 18 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::11 encap bpf in obj tests_bpf.o section push_encap dev dum1` 19 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::13 encap bpf in obj tests_bpf.o section long_encap_inline dev dum1` 20 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::14 encap bpf in obj tests_bpf.o section encap_inline_3seg dev dum1` 21 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::15 encap bpf in obj tests_bpf.o section long_encap_push dev dum1` 22 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::16 encap bpf in obj tests_bpf.o section push_encap_wrong dev dum1` 23 | #`/home/math/shared/iproute2/ip/ip -6 route add fd00::20 encap bpf xmit obj tests_bpf.o section push_encap_udp dev dum1` 24 | 25 | # Regular IP packets without SRH should be dropped by the seg6local encap 26 | > fc00::1 -> fd00::1 27 | < none 28 | 29 | # return BPF_OK 30 | > fc00::2 -> fd00::1 / [fc00::14,+fd00::1] 31 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::1] 32 | 33 | # return BPF_DROP 34 | > fc00::2 -> fd00::2 / [fc00::14,+fd00::2] 35 | < none 36 | 37 | # Incrementing the tag 38 | > fc00::2 -> fd00::3 / [fc00::14,+fd00::3] 39 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::3] 40 | 41 | > fc00::2 -> fd00::3 / [fc00::14,+fd00::3] 42 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::3] 43 | 44 | > fc00::2 -> fd00::3 / [fc00::14,+fd00::3] 45 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::3] 46 | 47 | # Adding the Alert flag to all passing by SRv6 packets 48 | > fc00::2 -> fd00::4 / [fc00::14,+fd00::4] 49 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::4] 50 | 51 | # Dropping if an incorrect store has taken place 52 | > fc00::2 -> fd00::17 / [fc00::14,+fd00::17] 53 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::17] 54 | 55 | # Dropping if an incorrect adjust has taken place 56 | > fc00::2 -> fd00::18 / [fc00::14,+fd00::18] {Ingr: fc00::2} {Egr: fc00::dead} 57 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::18] {Ingr: fc00::2} {Egr: fc00::dead} 58 | 59 | 60 | `ip -6 route add fc42::1 dev dum1` 61 | 62 | # Dynamic End.X action 63 | > fc00::2 -> fd00::5 / [fc00::14,+fd00::5] 64 | < (dum1) fc00::2 -> fc00::14 / [+fc00::14,fd00::5] 65 | 66 | `ip -6 route add dead::1 dev dum0` 67 | `ip -6 route add table 42 dead::1 dev dum1` 68 | 69 | # Dynamic End.T action 70 | > fc00::2 -> fd00::7 / [fc00::89, dead::1,+fd00::7] 71 | < (dum1) fc00::2 -> dead::1 / [fc00::89, +dead::1, fd00::7] 72 | 73 | > fc00::2 -> fd00::1 / [fc00::89, dead::1,+fd00::1] 74 | < (dum0) fc00::2 -> dead::1 / [fc00::89, +dead::1, fd00::1] 75 | 76 | # Dynamic End.B6 action 77 | > fc00::21 -> fd00::6 / [fc00::14,+fd00::6] 78 | < fc00::21 -> fc00::2 / [fc00::14,+fc00::2] / [+fc00::14,fd00::6] 79 | 80 | # Dynamic End.B6 action 81 | > fc00::21 -> fd00::8 / [fc00::14,+fd00::8] 82 | < none 83 | 84 | # Dynamic SRH encapsulation 85 | `ip sr tunsrc set fd00::41` 86 | > fc00::21 -> fd00::9 / [fc00::14,+fd00::9] 87 | < fd00::41 -> fc00::2 / [fc00::1,+fc00::2] / fc00::21 -> fc00::14 / [+fc00::14,fd00::9] 88 | 89 | # This time using the LWT in bpf hook 90 | > fc00::21 -> fd00::20 / TCP(42,42) 91 | < (dum1) fc00::21 -> fd00::20 / TCP(42,42) 92 | 93 | # This time using the LWT xmit bpf hook 94 | > fc00::21 -> fd00::20 / UDP(10, 10) 95 | < (dum0) fd00::41 -> fc00::2 / [fc00::1,+fc00::2] / fc00::21 -> fd00::20 / UDP(10, 10) 96 | 97 | # Dynamic long SRH encapsulation 98 | > fc00::21 -> fd00::10 / [fc00::14,+fd00::10] / TCP(42, 42) / "a not too short payload ..." 99 | < fd00::41 -> fc00::5 / [fc00::1,fc00::2,fc00::3,fc00::4,+fc00::5] / fc00::21 -> fc00::14 / [+fc00::14,fd00::10] / TCP(42, 42) / "a not too short payload ..." 100 | 101 | # Dynamic long End.B6 action 102 | > fc00::21 -> fd00::12 / [fc00::14,+fd00::12] / TCP(42, 42) / "a not too short payload ..." 103 | < fc00::21 -> fc00::5 / [fc00::14,fc00::2,fc00::3,fc00::4,+fc00::5] / [+fc00::14, fd00::12] / TCP(42, 42) / "a not too short payload ..." 104 | 105 | # in the LWT bpf hook now 106 | > fc00::21 -> fd00::13 / [fc00::14,+fd00::13] / TCP(42, 42) / "a not too short payload ..." 107 | < fc00::21 -> fc00::5 / [fd00::13,fc00::2,fc00::3,fc00::4,+fc00::5] / [fc00::14, +fd00::13] / TCP(42, 42) / "a not too short payload ..." 108 | 109 | > fc00::21 -> fd00::14 / TCP(42, 42) / "This is a HTTPS payload" 110 | < fc00::21 -> fc00::3 / [fd00::14,fc00::2,+fc00::3] / TCP(42, 42) / "This is a HTTPS payload" 111 | 112 | > fc00::21 -> fd00::15 113 | < fd00::41 -> fc00::5 / [fc00::1,fc00::2,fc00::3,fc00::4,+fc00::5] / fc00::21 -> fd00::15 114 | 115 | > fc00::21 -> fd00::16 116 | < none 117 | 118 | > fc00::2 -> fd00::19 / [fc00::14,+fd00::19] 119 | < none 120 | 121 | > fc00::2 -> fd00::21 / [+fd00::21, fd00::1] / fab1::2 -> fc00::1 122 | < fab1::2 -> fc00::1 123 | -------------------------------------------------------------------------------- /seg6-bpf-tests/tests_tlv.seg: -------------------------------------------------------------------------------- 1 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::2 encap seg6local action End.BPF obj tlv_bpf.o section add_ingr dev dum0` 2 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::3 encap seg6local action End.BPF obj tlv_bpf.o section add_8 dev dum0` 3 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::4 encap seg6local action End.BPF obj tlv_bpf.o section add_opaq_begin dev dum0` 4 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::5 encap seg6local action End.BPF obj tlv_bpf.o section add_ingr_no_offset dev dum0` 5 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::6 encap seg6local action End.BPF obj tlv_bpf.o section add_wrong_offset dev dum0` 6 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::7 encap seg6local action End.BPF obj tlv_bpf.o section add_6 dev dum0` 7 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::8 encap seg6local action End.BPF obj tlv_bpf.o section add_ingr_mid dev dum0` 8 | 9 | # Adding a Ingress TLV 10 | > fc00::2 -> fd00::2 / [fc00::14,+fd00::2] / UDP 11 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::2] {Ingr: fc00::1} {Pad: 2} / UDP 12 | 13 | > fc00::2 -> fd00::2 / [dead::beef,fc00::14,+fd00::2] / UDP 14 | < fc00::2 -> fc00::14 / [dead::beef, +fc00::14,fd00::2] {Ingr: fc00::1} {Pad: 2} / UDP 15 | 16 | # Adding a Ingress TLV with no offset 17 | > fc00::2 -> fd00::5 / [fc00::14,+fd00::5] / UDP 18 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::5] {Ingr: fc00::1} {Pad: 2} / UDP 19 | 20 | # Adding a Ingress TLV with a wrong offset 21 | > fc00::2 -> fd00::6 / [fc00::14,+fd00::6] / UDP 22 | < none 23 | 24 | # Adding a Ingress TLV after a 20 bytes TLV 25 | > fc00::2 -> fd00::8 / [fc00::14,+fd00::8] {Opaq: 00000000000000000000000000000042} {Egr: fc00::dead} / UDP 26 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::8] {Opaq: 00000000000000000000000000000042} {Ingr:fc00::beef} {Egr: fc00::dead} {Pad: 2} / UDP 27 | 28 | 29 | # Adding a NSH TLV on 8 bytes (no pad) 30 | > fc00::2 -> fd00::3 / [fc00::14,+fd00::3] / UDP 31 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::3] {NSH: 0102030405} / UDP 32 | 33 | # Adding a NSH TLV on 6 bytes (pad 2+0) 34 | > fc00::2 -> fd00::7 / [fc00::14,+fd00::7] / UDP 35 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::7] {NSH: 010203} {Pad: 1} / UDP 36 | 37 | # Add an Opaq TLV as first TLV 38 | > fc00::2 -> fd00::4 / [fc00::14,+fd00::4] / UDP 39 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::4] {Opaq: 00000000000000000000000000000042} {Pad: 2} / UDP 40 | 41 | > fc00::2 -> fd00::4 / [fc00::14,+fd00::4] {Egr: fc00::dead} {Pad: 2} / UDP 42 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::4] {Opaq: 00000000000000000000000000000042} {Egr: fc00::dead} / UDP 43 | 44 | > fc00::2 -> fd00::4 / [fc00::14,+fd00::4] {Opaq: 00000000000000000000000000000042} {Egr: fc00::dead} / UDP 45 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::4] {Opaq: 00000000000000000000000000000042} {Opaq: 00000000000000000000000000000042} {Egr: fc00::dead} {Pad: 2} / UDP 46 | 47 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::10 encap seg6local action End.BPF obj tlv_bpf.o section del_first dev dum0` 48 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::11 encap seg6local action End.BPF obj tlv_bpf.o section del_20 dev dum0` 49 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::12 encap seg6local action End.BPF obj tlv_bpf.o section del_24 dev dum0` 50 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::13 encap seg6local action End.BPF obj tlv_bpf.o section del_24_hmac dev dum0` 51 | > fc00::2 -> fd00::10 / [fc00::14,+fd00::10] {Ingr: fc00::2} {Pad: 2} / UDP 52 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::10] / UDP 53 | 54 | > fc00::2 -> fd00::10 / [fc00::14,+fd00::10] {Ingr: fc00::2} {Egr: fc00::dead} / UDP 55 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::10] {Egr: fc00::dead} {Pad: 2} / UDP 56 | 57 | > fc00::2 -> fd00::10 / [fc00::14,+fd00::10] {NSH: 0102030405} / UDP 58 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::10] / UDP 59 | 60 | > fc00::2 -> fd00::10 / [fc00::14,+fd00::10] {NSH: 0102} {Pad: 1} / UDP 61 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::10] / UDP 62 | 63 | > fc00::2 -> fd00::11 / [fc00::14,+fd00::11] {Ingr: fc00::2} {Egr: fc00::dead} / UDP 64 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::11] {Ingr: fc00::2} {Pad: 2} / UDP 65 | 66 | > fc00::2 -> fd00::11 / [fc00::14,+fd00::11] {Ingr: fc00::2} {Egr: fc00::dead} {Opaq: 00000000000000000000000000000042} {Pad: 2} / UDP 67 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::11] {Ingr: fc00::2} {Opaq: 00000000000000000000000000000042} / UDP 68 | 69 | > fc00::2 -> fd00::11 / [fc00::14,+fd00::11] {Ingr: fc00::2} {NSH: 01020304050607} {NSH: 08090A0B0C0D0E} {Opaq: 00000000000000000000000000000042} {Pad: 2} / UDP 70 | < fc00::2 -> fc00::14 / [+fc00::14,fd00::11] {Ingr: fc00::2} {NSH: 08090A0B0C0D0E} {Opaq: 00000000000000000000000000000042} {Pad: 4} / UDP 71 | -------------------------------------------------------------------------------- /seg6-bpf-tests/tlv_bpf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bpf_seg6/all.h" 3 | #include "libseg6.c" 4 | 5 | struct sr6_tlv_nsh { 6 | unsigned char type; 7 | unsigned char len; 8 | unsigned char flags; 9 | unsigned char value[5]; 10 | } BPF_PACKET_HEADER; 11 | 12 | __section("add_8") 13 | int do_add_8(struct __sk_buff *skb) { 14 | struct ip6_srh_t *srh = seg6_get_srh(skb); 15 | if (srh == NULL) 16 | return BPF_DROP; 17 | 18 | struct sr6_tlv_nsh tlv; 19 | tlv.type = 6; // NSH 20 | tlv.len = 6; 21 | tlv.flags = 0; 22 | tlv.value[0] = 1; 23 | tlv.value[1] = 2; 24 | tlv.value[2] = 3; 25 | tlv.value[3] = 4; 26 | tlv.value[4] = 5; 27 | int err = seg6_add_tlv(skb,srh, (srh->hdrlen+1) << 3, (struct sr6_tlv_t *)&tlv, 8); 28 | 29 | return (err) ? BPF_DROP : BPF_OK; 30 | } 31 | 32 | __section("add_6") 33 | int do_add_6(struct __sk_buff *skb) { 34 | struct ip6_srh_t *srh = seg6_get_srh(skb); 35 | if (srh == NULL) 36 | return BPF_DROP; 37 | 38 | struct sr6_tlv_nsh tlv; 39 | tlv.type = 6; // NSH 40 | tlv.len = 4; 41 | tlv.flags = 0; 42 | tlv.value[0] = 1; 43 | tlv.value[1] = 2; 44 | tlv.value[2] = 3; 45 | int err = seg6_add_tlv(skb,srh, (srh->hdrlen+1) << 3, (struct sr6_tlv_t *)&tlv, 6); 46 | 47 | return (err) ? BPF_DROP : BPF_OK; 48 | } 49 | 50 | 51 | __section("add_ingr") 52 | int do_add_ingr(struct __sk_buff *skb) { 53 | struct ip6_srh_t *srh = seg6_get_srh(skb); 54 | if (srh == NULL) 55 | return BPF_DROP; 56 | 57 | struct sr6_tlv_128 tlv; 58 | tlv.type = 1; 59 | tlv.len = 18; 60 | tlv.flags = 0; 61 | tlv.reserved = 0; 62 | memset(tlv.value, 0, 16); 63 | tlv.value[15] = 1; 64 | tlv.value[0] = 0xfc; 65 | int err = seg6_add_tlv(skb,srh, (srh->hdrlen+1) << 3, (struct sr6_tlv_t *)&tlv, 20); 66 | 67 | return (err) ? BPF_DROP : BPF_OK; 68 | } 69 | 70 | __section("add_ingr_no_offset") 71 | int do_add_ingr_no_offset(struct __sk_buff *skb) { 72 | struct ip6_srh_t *srh = seg6_get_srh(skb); 73 | if (srh == NULL) 74 | return BPF_DROP; 75 | 76 | struct sr6_tlv_128 tlv; 77 | tlv.type = 1; 78 | tlv.len = 18; 79 | tlv.flags = 0; 80 | tlv.reserved = 0; 81 | memset(tlv.value, 0, 16); 82 | tlv.value[15] = 1; 83 | tlv.value[0] = 0xfc; 84 | int err = seg6_add_tlv(skb,srh, -1, (struct sr6_tlv_t *)&tlv, 20); 85 | 86 | return (err) ? BPF_DROP : BPF_OK; 87 | } 88 | 89 | __section("add_ingr_mid") 90 | int do_add_ingr_mid(struct __sk_buff *skb) { 91 | struct ip6_srh_t *srh = seg6_get_srh(skb); 92 | if (srh == NULL) 93 | return BPF_DROP; 94 | 95 | struct sr6_tlv_128 tlv; 96 | tlv.type = 1; 97 | tlv.len = 18; 98 | tlv.flags = 0; 99 | tlv.reserved = 0; 100 | memset(tlv.value, 0, 16); 101 | tlv.value[15] = 0xef; 102 | tlv.value[14] = 0xbe; 103 | tlv.value[0] = 0xfc; 104 | int err = seg6_add_tlv(skb,srh, 8 + (srh->first_segment+1)*16 + 20, (struct sr6_tlv_t *)&tlv, 20); 105 | 106 | return (err) ? BPF_DROP : BPF_OK; 107 | } 108 | 109 | 110 | 111 | __section("add_wrong_offset") 112 | int do_add_ingr_wrong_offset(struct __sk_buff *skb) { 113 | struct ip6_srh_t *srh = seg6_get_srh(skb); 114 | if (srh == NULL) 115 | return BPF_DROP; 116 | 117 | struct sr6_tlv_128 tlv; 118 | tlv.type = 1; 119 | tlv.len = 18; 120 | tlv.flags = 0; 121 | tlv.reserved = 0; 122 | memset(tlv.value, 0, 16); 123 | tlv.value[15] = 1; 124 | tlv.value[0] = 0xfc; 125 | int err = seg6_add_tlv(skb,srh, 11, (struct sr6_tlv_t *)&tlv, 20); 126 | 127 | return (err) ? BPF_DROP : BPF_OK; 128 | } 129 | 130 | __section("add_opaq_begin") 131 | int do_add_opaq_begin(struct __sk_buff *skb) { 132 | struct ip6_srh_t *srh = seg6_get_srh(skb); 133 | if (srh == NULL) 134 | return BPF_DROP; 135 | 136 | struct sr6_tlv_128 tlv; 137 | tlv.type = 3; 138 | tlv.len = 18; 139 | tlv.flags = 0; 140 | tlv.reserved = 0; 141 | memset(tlv.value, 0, 16); 142 | tlv.value[15] = 0x42; 143 | int err = seg6_add_tlv(skb,srh, 8+(srh->first_segment+1)*16, (struct sr6_tlv_t *)&tlv, 20); 144 | 145 | return (err) ? BPF_DROP : BPF_OK; 146 | } 147 | 148 | __section("del_first") 149 | int do_del_first(struct __sk_buff *skb) { 150 | struct ip6_srh_t *srh = seg6_get_srh(skb); 151 | if (srh == NULL) 152 | return BPF_DROP; 153 | 154 | /* 155 | struct sr6_tlv_t *tlv = (struct sr6_tlv_t *)((char *)srh+8+(srh->first_segment+1)*16); 156 | if ((void *)tlv > data_end) // Check needed otherwise filter not accepted by the kernel 157 | return BPF_OK;*/ 158 | 159 | int err = seg6_delete_tlv(skb, srh, 8+(srh->first_segment+1)*16); 160 | return (err) ? BPF_DROP : BPF_OK; 161 | } 162 | 163 | __section("del_20") 164 | int do_del_20(struct __sk_buff *skb) { 165 | struct ip6_srh_t *srh = seg6_get_srh(skb); 166 | if (srh == NULL) 167 | return BPF_DROP; 168 | 169 | int err = seg6_delete_tlv(skb, srh, 8+(srh->first_segment+1)*16+20); 170 | return (err) ? BPF_DROP : BPF_OK; 171 | } 172 | 173 | __section("del_24") 174 | int do_del_24(struct __sk_buff *skb) { 175 | struct ip6_srh_t *srh = seg6_get_srh(skb); 176 | if (srh == NULL) 177 | return BPF_DROP; 178 | 179 | int err = seg6_delete_tlv(skb, srh, 8+(srh->first_segment+1)*16+24); 180 | return (err) ? BPF_DROP : BPF_OK; 181 | } 182 | 183 | __section("del_24_hmac") 184 | int do_del_24_hmac(struct __sk_buff *skb) { 185 | struct ip6_srh_t *srh = seg6_get_srh(skb); 186 | int offset = (char *)srh - (char *)(long)skb->data; 187 | if (srh == NULL) 188 | return BPF_DROP; 189 | 190 | uint8_t flags = srh->flags & (~SR6_FLAG_HMAC); 191 | 192 | int err = seg6_delete_tlv(skb, srh, 8+(srh->first_segment+1)*16+24); 193 | if (err) 194 | return BPF_DROP; 195 | 196 | lwt_seg6_store_bytes(skb, offset + offsetof(struct ip6_srh_t, flags), (void *) &flags, sizeof(flags)); 197 | return BPF_OK; 198 | } 199 | 200 | 201 | char __license[] __section("license") = "GPL"; 202 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | LLC = llc 3 | 4 | all: bpf tools 5 | 6 | tools: 7 | clang end_otp_usr.c -o end_otp_usr 8 | clang uplink_wrr_usr.c -o uplink_wrr_usr 9 | 10 | 11 | bpf: 12 | $(CC) -O2 -emit-llvm -g -c end_otp_bpf.c -o - | $(LLC) -march=bpf -filetype=obj -o end_otp_bpf.o 13 | $(CC) -O2 -emit-llvm -g -c uplink_wrr_bpf.c -o - | $(LLC) -march=bpf -filetype=obj -o uplink_wrr_bpf.o 14 | 15 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/bpf_seg6/all.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bpf_api.h" 6 | //#include "proto.h" 7 | 8 | /* Packet parsing state machine helpers. */ 9 | #define cursor_advance(_cursor, _len) \ 10 | ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) 11 | 12 | #define SR6_FLAG_PROTECTED (1 << 6) 13 | #define SR6_FLAG_OAM (1 << 5) 14 | #define SR6_FLAG_ALERT (1 << 4) 15 | #define SR6_FLAG_HMAC (1 << 3) 16 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/bpf_seg6/bpf_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_API__ 2 | #define __BPF_API__ 3 | 4 | /* Note: 5 | * 6 | * This file can be included into eBPF kernel programs. It contains 7 | * a couple of useful helper functions, map/section ABI (bpf_elf.h), 8 | * misc macros and some eBPF specific LLVM built-ins. 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | //#include 15 | #include "bpf.h" 16 | #include "proto.h" 17 | #include 18 | 19 | #include 20 | 21 | #include "bpf_elf.h" 22 | 23 | /** Misc macros. */ 24 | 25 | #ifndef __stringify 26 | # define __stringify(X) #X 27 | #endif 28 | 29 | #ifndef __maybe_unused 30 | # define __maybe_unused __attribute__((__unused__)) 31 | #endif 32 | 33 | #ifndef offsetof 34 | # define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) 35 | #endif 36 | 37 | #ifndef likely 38 | # define likely(X) __builtin_expect(!!(X), 1) 39 | #endif 40 | 41 | #ifndef unlikely 42 | # define unlikely(X) __builtin_expect(!!(X), 0) 43 | #endif 44 | 45 | #ifndef htons 46 | # define htons(X) __constant_htons((X)) 47 | #endif 48 | 49 | #ifndef ntohs 50 | # define ntohs(X) __constant_ntohs((X)) 51 | #endif 52 | 53 | #ifndef htonl 54 | # define htonl(X) __constant_htonl((X)) 55 | #endif 56 | 57 | #ifndef ntohl 58 | # define ntohl(X) __constant_ntohl((X)) 59 | #endif 60 | 61 | #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 62 | #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 63 | /* From https://stackoverflow.com/a/28592202 */ 64 | 65 | #ifndef __inline__ 66 | # define __inline__ __attribute__((always_inline)) 67 | #endif 68 | 69 | /** Section helper macros. */ 70 | 71 | #ifndef __section 72 | # define __section(NAME) \ 73 | __attribute__((section(NAME), used)) 74 | #endif 75 | 76 | #ifndef __section_tail 77 | # define __section_tail(ID, KEY) \ 78 | __section(__stringify(ID) "/" __stringify(KEY)) 79 | #endif 80 | 81 | #ifndef __section_xdp_entry 82 | # define __section_xdp_entry \ 83 | __section(ELF_SECTION_PROG) 84 | #endif 85 | 86 | #ifndef __section_cls_entry 87 | # define __section_cls_entry \ 88 | __section(ELF_SECTION_CLASSIFIER) 89 | #endif 90 | 91 | #ifndef __section_act_entry 92 | # define __section_act_entry \ 93 | __section(ELF_SECTION_ACTION) 94 | #endif 95 | 96 | #ifndef __section_lwt_entry 97 | # define __section_lwt_entry \ 98 | __section(ELF_SECTION_PROG) 99 | #endif 100 | 101 | #ifndef __section_license 102 | # define __section_license \ 103 | __section(ELF_SECTION_LICENSE) 104 | #endif 105 | 106 | #ifndef __section_maps 107 | # define __section_maps \ 108 | __section(ELF_SECTION_MAPS) 109 | #endif 110 | 111 | /** Declaration helper macros. */ 112 | 113 | #ifndef BPF_LICENSE 114 | # define BPF_LICENSE(NAME) \ 115 | char ____license[] __section_license = NAME 116 | #endif 117 | 118 | /** Classifier helper */ 119 | 120 | #ifndef BPF_H_DEFAULT 121 | # define BPF_H_DEFAULT -1 122 | #endif 123 | 124 | /** BPF helper functions for tc. Individual flags are in linux/bpf.h */ 125 | 126 | #ifndef __BPF_FUNC 127 | # define __BPF_FUNC(NAME, ...) \ 128 | (* NAME)(__VA_ARGS__) __maybe_unused 129 | #endif 130 | 131 | #ifndef BPF_FUNC 132 | # define BPF_FUNC(NAME, ...) \ 133 | __BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME 134 | #endif 135 | 136 | /* Map access/manipulation */ 137 | static void *BPF_FUNC(map_lookup_elem, void *map, const void *key); 138 | static int BPF_FUNC(map_update_elem, void *map, const void *key, 139 | const void *value, uint32_t flags); 140 | static int BPF_FUNC(map_delete_elem, void *map, const void *key); 141 | 142 | /* Time access */ 143 | static uint64_t BPF_FUNC(ktime_get_ns); 144 | 145 | /* Debugging */ 146 | 147 | /* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless 148 | * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved. 149 | * It would require ____fmt to be made const, which generates a reloc 150 | * entry (non-map). 151 | */ 152 | static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...); 153 | 154 | #ifndef printt 155 | # define printt(fmt, ...) \ 156 | ({ \ 157 | char ____fmt[] = fmt; \ 158 | trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ 159 | }) 160 | #endif 161 | 162 | /* Random numbers */ 163 | static uint32_t BPF_FUNC(get_prandom_u32); 164 | 165 | /* Tail calls */ 166 | static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map, 167 | uint32_t index); 168 | 169 | /* System helpers */ 170 | static uint32_t BPF_FUNC(get_smp_processor_id); 171 | static uint32_t BPF_FUNC(get_numa_node_id); 172 | 173 | /* Packet misc meta data */ 174 | static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb); 175 | static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index); 176 | 177 | static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb); 178 | static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb); 179 | static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb); 180 | 181 | /* Packet redirection */ 182 | static int BPF_FUNC(redirect, int ifindex, uint32_t flags); 183 | static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex, 184 | uint32_t flags); 185 | 186 | /* Packet manipulation */ 187 | static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off, 188 | void *to, uint32_t len); 189 | static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off, 190 | const void *from, uint32_t len, uint32_t flags); 191 | 192 | static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, 193 | uint32_t from, uint32_t to, uint32_t flags); 194 | static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, 195 | uint32_t from, uint32_t to, uint32_t flags); 196 | static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size, 197 | const void *to, uint32_t to_size, uint32_t seed); 198 | static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum); 199 | 200 | static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type); 201 | static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto, 202 | uint32_t flags); 203 | static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen, 204 | uint32_t flags); 205 | 206 | static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len); 207 | 208 | /* Event notification */ 209 | static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map, 210 | uint64_t index, const void *data, uint32_t size) = 211 | (void *) BPF_FUNC_perf_event_output; 212 | 213 | /* Packet vlan encap/decap */ 214 | static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, 215 | uint16_t vlan_tci); 216 | static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb); 217 | 218 | /* Packet tunnel encap/decap */ 219 | static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb, 220 | struct bpf_tunnel_key *to, uint32_t size, uint32_t flags); 221 | static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, 222 | const struct bpf_tunnel_key *from, uint32_t size, 223 | uint32_t flags); 224 | 225 | static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb, 226 | void *to, uint32_t size); 227 | static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb, 228 | const void *from, uint32_t size); 229 | 230 | /* OLD SEG6 helpers 231 | static int BPF_FUNC(skb_seg6_change_field, struct __sk_buff *skb, 232 | uint8_t field, uint32_t value); 233 | static int BPF_FUNC(skb_seg6_add_tlv, struct __sk_buff *skb, uint32_t tlv_offset, 234 | struct sr6_tlv *itlv); 235 | static int BPF_FUNC(skb_seg6_delete_tlv, struct __sk_buff *skb, struct sr6_tlv *tlv); 236 | static int BPF_FUNC(skb_seg6_action_end_x, struct __sk_buff *skb, struct ip6_addr *nhaddr); 237 | static int BPF_FUNC(skb_seg6_action_end_t, struct __sk_buff *skb, uint32_t tbl_id); 238 | static int BPF_FUNC(skb_seg6_action_end_b6, struct __sk_buff *skb, struct ip6_srh_t *srh); 239 | static int BPF_FUNC(skb_seg6_encap_push, struct __sk_buff *skb, struct ip6_srh_t *srh); 240 | */ 241 | 242 | 243 | static int BPF_FUNC(lwt_push_encap, struct __sk_buff *skb, uint32_t type, void *hdr, uint32_t len); 244 | static int BPF_FUNC(lwt_seg6_store_bytes, struct __sk_buff *skb, uint32_t offset, const void *from, uint32_t len); 245 | static int BPF_FUNC(lwt_seg6_action, struct __sk_buff *skb, uint32_t action, void *param, uint32_t param_len); 246 | static int BPF_FUNC(lwt_seg6_adjust_srh, struct __sk_buff *skb, uint32_t offset, int32_t len); 247 | 248 | /** LLVM built-ins, mem*() routines work for constant size */ 249 | 250 | #ifndef lock_xadd 251 | # define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) 252 | #endif 253 | 254 | #ifndef memset 255 | # define memset(s, c, n) __builtin_memset((s), (c), (n)) 256 | #endif 257 | 258 | #ifndef memcpy 259 | # define memcpy(d, s, n) __builtin_memcpy((d), (s), (n)) 260 | #endif 261 | 262 | #ifndef memmove 263 | # define memmove(d, s, n) __builtin_memmove((d), (s), (n)) 264 | #endif 265 | 266 | /* FIXME: __builtin_memcmp() is not yet fully useable unless llvm bug 267 | * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also 268 | * this one would generate a reloc entry (non-map), otherwise. 269 | */ 270 | #if 0 271 | #ifndef memcmp 272 | # define memcmp(a, b, n) __builtin_memcmp((a), (b), (n)) 273 | #endif 274 | #endif 275 | 276 | unsigned long long load_byte(void *skb, unsigned long long off) 277 | asm ("llvm.bpf.load.byte"); 278 | 279 | unsigned long long load_half(void *skb, unsigned long long off) 280 | asm ("llvm.bpf.load.half"); 281 | 282 | unsigned long long load_word(void *skb, unsigned long long off) 283 | asm ("llvm.bpf.load.word"); 284 | 285 | #endif /* __BPF_API__ */ 286 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/bpf_seg6/bpf_elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_ELF__ 2 | #define __BPF_ELF__ 3 | 4 | #include 5 | 6 | /* Note: 7 | * 8 | * Below ELF section names and bpf_elf_map structure definition 9 | * are not (!) kernel ABI. It's rather a "contract" between the 10 | * application and the BPF loader in tc. For compatibility, the 11 | * section names should stay as-is. Introduction of aliases, if 12 | * needed, are a possibility, though. 13 | */ 14 | 15 | /* ELF section names, etc */ 16 | #define ELF_SECTION_LICENSE "license" 17 | #define ELF_SECTION_MAPS "maps" 18 | #define ELF_SECTION_PROG "prog" 19 | #define ELF_SECTION_CLASSIFIER "classifier" 20 | #define ELF_SECTION_ACTION "action" 21 | 22 | #define ELF_MAX_MAPS 64 23 | #define ELF_MAX_LICENSE_LEN 128 24 | 25 | /* Object pinning settings */ 26 | #define PIN_NONE 0 27 | #define PIN_OBJECT_NS 1 28 | #define PIN_GLOBAL_NS 2 29 | 30 | /* ELF map definition */ 31 | struct bpf_elf_map { 32 | __u32 type; 33 | __u32 size_key; 34 | __u32 size_value; 35 | __u32 max_elem; 36 | __u32 flags; 37 | __u32 id; 38 | __u32 pinning; 39 | }; 40 | 41 | #endif /* __BPF_ELF__ */ 42 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/bpf_seg6/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/compile_openwrt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export STAGING_DIR=/mnt/turris/openwrt-seg6/staging_dir/ 4 | 5 | /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/bin/arm-openwrt-linux-muslgnueabi-gcc \ 6 | -isystem /mnt/turris/openwrt-seg6/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/include \ 7 | -isystem /mnt/turris/openwrt-seg6/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/include \ 8 | -isystem /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/usr/include \ 9 | -isystem /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/include/fortify \ 10 | -isystem /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/include \ 11 | -Os -pipe -mcpu=cortex-a9 -mfpu=vfpv3-d16 \ 12 | -Wno-error=unused-but-set-variable -Wno-error=unused-result -mfloat-abi=hard \ 13 | -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 \ 14 | -Werror-implicit-function-declaration -Wno-system-headers \ 15 | end_otp_usr.c -o end_otp_usr 16 | 17 | /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/bin/arm-openwrt-linux-muslgnueabi-gcc \ 18 | -isystem /mnt/turris/openwrt-seg6/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/include \ 19 | -isystem /mnt/turris/openwrt-seg6/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/include \ 20 | -isystem /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/usr/include \ 21 | -isystem /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/include/fortify \ 22 | -isystem /mnt/turris/openwrt-seg6/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/include \ 23 | -fvisibility=hidden -Os -pipe -mcpu=cortex-a9 -mfpu=vfpv3-d16 -fno-caller-saves -fno-plt -fhonour-copts \ 24 | -Wno-error=unused-but-set-variable -Wno-error=unused-result -mfloat-abi=hard \ 25 | -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -ffunction-sections \ 26 | -Werror-implicit-function-declaration -Wno-system-headers -fpic -fPIC -DPIC \ 27 | uplink_wrr_usr.c -o uplink_wrr_usr 28 | 29 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/end_otp_bpf.c: -------------------------------------------------------------------------------- 1 | #include "bpf_seg6/all.h" 2 | #include "libseg6.c" 3 | 4 | #define SR6_TLV_DM 7 5 | #define SR6_TLV_URO 131 6 | 7 | struct bpf_elf_map __section_maps end_otp_delta = { 8 | .type = BPF_MAP_TYPE_ARRAY, 9 | .id = 43, 10 | .size_key = sizeof(uint32_t), 11 | .size_value = sizeof(uint32_t), 12 | .max_elem = 4, 13 | .pinning = PIN_GLOBAL_NS, 14 | }; 15 | 16 | 17 | struct timestamp_ieee1588_v2 { 18 | uint32_t tv_sec; 19 | uint32_t tv_nsec; 20 | }; 21 | 22 | struct sr6_tlv_dm_t { 23 | unsigned char type; // value TBA by IANA, use NSH+1 24 | unsigned char len; 25 | unsigned short reserved; 26 | unsigned char version:4; // 1 27 | unsigned char flags:4; // R|T|0|0, R: Query(0),Response(1), T: if tc class, set to 1 28 | unsigned char cc; 29 | /* For a Query: 0x0 in-band response, 0x1 out of band, 0x2: no response 30 | * For a response: 0x1 success, 0x10-0xFF: errors */ 31 | unsigned short reserved2; 32 | unsigned char qtf:4; /* timestamp formats */ 33 | unsigned char rtf:4; 34 | unsigned char rtpf:4; 35 | unsigned int reserved3:20; 36 | unsigned int session_id:24; /* set by the querier */ 37 | unsigned char tc; 38 | struct timestamp_ieee1588_v2 timestamps[4]; 39 | unsigned char sub_tlv[0]; // possible UDP Return Object (URO) 40 | } BPF_PACKET_HEADER; 41 | 42 | __section("end_otp") 43 | int End_OTP(struct __sk_buff *skb) { 44 | // first thing, fetch the monotonic timestamp, since we do not want the 45 | // following operations to be included in the delay measurement 46 | uint64_t timestamp = ktime_get_ns(); 47 | 48 | struct ip6_srh_t *srh = seg6_get_srh(skb); 49 | if (!srh) 50 | return BPF_DROP; 51 | 52 | 53 | struct sr6_tlv_dm_t tlv; 54 | int cursor = seg6_find_tlv(skb, srh, SR6_TLV_DM, sizeof(tlv)); 55 | if (cursor < 0) 56 | return BPF_DROP; 57 | 58 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(tlv)) < 0) 59 | return BPF_DROP; 60 | 61 | unsigned char query_cc = tlv.cc; 62 | if (tlv.version != 1) { 63 | tlv.cc = 0x11; 64 | goto send; 65 | } else if (tlv.cc != 0x00) { // we are only capable of handling in-band replies 66 | tlv.cc = 0x12; 67 | goto send; 68 | } else if (tlv.flags & 8) { 69 | tlv.cc = 0x11; 70 | goto send; 71 | } else if (tlv.rtf != 0 && tlv.rtf != 3) { // Unsupported already set RTF type 72 | tlv.cc = 0x10; // Generic error 73 | goto send; 74 | } 75 | 76 | tlv.flags |= 8; // DM TLV becomes a response 77 | tlv.rtf = 3; 78 | 79 | int id = 0; 80 | uint32_t *clk_diff_sec = map_lookup_elem(&end_otp_delta, &id); 81 | id++; 82 | uint32_t *clk_diff_ns = map_lookup_elem(&end_otp_delta, &id); 83 | if (!clk_diff_sec || !clk_diff_ns) { 84 | tlv.cc = 0x1C; 85 | goto send; 86 | } 87 | 88 | uint32_t ts_sec = (uint32_t) (timestamp / 1000000000); 89 | uint32_t ts_ns = (uint32_t) (timestamp % 1000000000); 90 | ts_ns += *clk_diff_ns; 91 | if (ts_ns > 1000000000) { 92 | ts_sec += 1; 93 | ts_ns = ts_ns - 1000000000; 94 | } 95 | ts_sec += *clk_diff_sec; 96 | tlv.timestamps[1].tv_sec = htonl(ts_sec); 97 | tlv.timestamps[1].tv_nsec = htonl(ts_ns); 98 | 99 | // this is a BPF limitation, we can not obtain two different HW timestamps 100 | tlv.timestamps[2].tv_sec = tlv.timestamps[1].tv_sec; 101 | tlv.timestamps[2].tv_nsec = tlv.timestamps[1].tv_nsec; 102 | 103 | send: 104 | if (query_cc == 0x00) { // in-band 105 | if (bpf_lwt_seg6_store_bytes(skb, cursor, &tlv, sizeof(tlv)) < 0) 106 | return BPF_DROP; 107 | 108 | return BPF_OK; 109 | } else { 110 | return BPF_DROP; 111 | } 112 | } 113 | 114 | char __license[] __section("license") = "GPL"; 115 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/end_otp_usr.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 | uint32_t mono_real_diff_ns() 14 | { 15 | struct timespec mono, real; 16 | clock_gettime(CLOCK_MONOTONIC, &mono); 17 | clock_gettime(CLOCK_REALTIME, &real); 18 | if (mono.tv_nsec > real.tv_nsec) 19 | return (uint32_t) (1000000000 - mono.tv_nsec + real.tv_nsec); 20 | 21 | return (uint32_t) (real.tv_nsec - mono.tv_nsec); 22 | } 23 | 24 | uint32_t mono_real_diff_sec() 25 | { 26 | struct timespec mono, real; 27 | clock_gettime(CLOCK_MONOTONIC, &mono); 28 | clock_gettime(CLOCK_REALTIME, &real); 29 | 30 | if (mono.tv_nsec > real.tv_nsec) 31 | return (uint32_t) (real.tv_sec - mono.tv_sec - 1); 32 | 33 | return (uint32_t) (real.tv_sec - mono.tv_sec); 34 | } 35 | 36 | int bpf(int cmd, union bpf_attr *attr, unsigned int size) 37 | { 38 | #ifdef __NR_bpf 39 | return syscall(__NR_bpf, cmd, attr, size); 40 | #else 41 | fprintf(stderr, "No bpf syscall, kernel headers too old?\n"); 42 | errno = ENOSYS; 43 | return -1; 44 | #endif 45 | } 46 | 47 | __u64 bpf_ptr_to_u64(const void *ptr) 48 | { 49 | return (__u64) (unsigned long) ptr; 50 | } 51 | 52 | int bpf_update_elem(int fd, void *key, void *value, uint64_t flags) 53 | { 54 | union bpf_attr attr = {}; 55 | attr.map_fd = fd; 56 | attr.key = bpf_ptr_to_u64(key); 57 | attr.value = bpf_ptr_to_u64(value);; 58 | attr.flags = flags; 59 | 60 | static int nb = 0; 61 | nb++; 62 | int ret = bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); 63 | if (ret < 0) { 64 | fprintf(stderr, "Map update #%d failed: %s\n", nb, strerror(errno)); 65 | } 66 | 67 | return ret; 68 | } 69 | 70 | /* Main function */ 71 | 72 | int main (int argc, char *argv[]) 73 | { 74 | union bpf_attr attr_obj = {}; 75 | int map_fd[1]; 76 | 77 | char *map_paths[] = {"/sys/fs/bpf/ip/globals/end_otp_delta"}; 78 | 79 | for(int i=0; i < sizeof(map_fd)/sizeof(int); i++) { 80 | attr_obj.map_fd = 0; 81 | attr_obj.pathname = bpf_ptr_to_u64(map_paths[i]); 82 | map_fd[i] = bpf(BPF_OBJ_GET, &attr_obj, sizeof(attr_obj)); 83 | if (map_fd[i] <= 0) { 84 | fprintf(stderr, "Fetching map failed: %s\n", strerror(errno)); 85 | return -1; 86 | } 87 | } 88 | 89 | uint32_t key = 0; 90 | uint32_t delta_s = mono_real_diff_sec(); 91 | bpf_update_elem(map_fd[0], &key, &delta_s, BPF_ANY); 92 | 93 | uint32_t delta_ns = mono_real_diff_ns(); 94 | key++; 95 | bpf_update_elem(map_fd[0], &key, &delta_ns, BPF_ANY); 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/libseg6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define bpf_skb_load_bytes skb_load_bytes 3 | #define bpf_lwt_seg6_adjust_srh lwt_seg6_adjust_srh 4 | #define bpf_lwt_seg6_store_bytes lwt_seg6_store_bytes 5 | 6 | #include "bpf_seg6/all.h" 7 | #define TLV_ITERATIONS 16 8 | 9 | __attribute__((always_inline)) 10 | struct ip6_srh_t *seg6_get_srh(struct __sk_buff *skb) 11 | { 12 | void *cursor, *data_end; 13 | struct ip6_srh_t *srh; 14 | struct ip6_t *ip; 15 | uint16_t opt_len; 16 | uint8_t *ipver; 17 | 18 | data_end = (void *)(long)skb->data_end; 19 | cursor = (void *)(long)skb->data; 20 | ipver = (uint8_t *)cursor; 21 | 22 | if ((void *)ipver + sizeof(*ipver) > data_end) 23 | return NULL; 24 | 25 | if ((*ipver >> 4) != 6) 26 | return NULL; 27 | 28 | ip = cursor_advance(cursor, sizeof(*ip)); 29 | if ((void *)ip + sizeof(*ip) > data_end) 30 | return NULL; 31 | 32 | if (ip->next_header != 43) 33 | return NULL; 34 | 35 | // skipping possible destination or hop-by-hop header 36 | if (ip->next_header == 0 || ip->next_header == 60) { 37 | if ((void *)cursor + 2 > data_end) 38 | return NULL; 39 | opt_len = (1 + (uint16_t) *((uint8_t *) cursor + 1)) << 3; 40 | if ((void *)cursor + opt_len > data_end) 41 | return NULL; 42 | cursor_advance(cursor, opt_len); 43 | } 44 | 45 | // possible destination header 46 | if (ip->next_header == 60) { 47 | if ((void *)cursor + 2 > data_end) 48 | return NULL; 49 | opt_len = (1 + (uint16_t) *((uint8_t *) cursor + 1)) << 3; 50 | if ((void *)cursor + opt_len > data_end) 51 | return NULL; 52 | cursor_advance(cursor, opt_len); 53 | } 54 | 55 | srh = cursor_advance(cursor, sizeof(*srh)); 56 | if ((void *)srh + sizeof(*srh) > data_end) 57 | return NULL; 58 | 59 | if (srh->type != 4) 60 | return NULL; 61 | 62 | return srh; 63 | } 64 | 65 | __attribute__((always_inline)) 66 | int __update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, 67 | uint32_t old_pad, uint32_t pad_off) 68 | { 69 | int err; 70 | 71 | if (new_pad != old_pad) { 72 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, 73 | (int) new_pad - (int) old_pad); 74 | if (err) 75 | return err; 76 | } 77 | 78 | if (new_pad > 0) { 79 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 0, 0}; 81 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; 82 | 83 | pad_tlv->type = SR6_TLV_PADDING; 84 | pad_tlv->len = new_pad - 2; 85 | 86 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, 87 | (void *)pad_tlv_buf, new_pad); 88 | if (err) 89 | return err; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | __attribute__((always_inline)) 96 | int __is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, 97 | uint32_t *tlv_off, uint32_t *pad_size, 98 | uint32_t *pad_off) 99 | { 100 | uint32_t srh_off, cur_off; 101 | int offset_valid = 0; 102 | int err; 103 | 104 | srh_off = (char *)srh - (char *)(long)skb->data; 105 | // cur_off = end of segments, start of possible TLVs 106 | cur_off = srh_off + sizeof(*srh) + 107 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); 108 | 109 | *pad_off = 0; 110 | 111 | // we can only go as far as ~10 TLVs due to the BPF max stack size 112 | #pragma clang loop unroll(full) 113 | for (int i = 0; i < TLV_ITERATIONS; i++) { 114 | struct sr6_tlv_t tlv; 115 | 116 | if (cur_off == *tlv_off) 117 | offset_valid = 1; 118 | 119 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) 120 | break; 121 | 122 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); 123 | if (err) 124 | return err; 125 | 126 | if (tlv.type == SR6_TLV_PADDING) { 127 | *pad_size = tlv.len + sizeof(tlv); 128 | *pad_off = cur_off; 129 | 130 | if (*tlv_off == srh_off) { 131 | *tlv_off = cur_off; 132 | offset_valid = 1; 133 | } 134 | break; 135 | 136 | } else if (tlv.type == SR6_TLV_HMAC) { 137 | break; 138 | } 139 | 140 | cur_off += sizeof(tlv) + tlv.len; 141 | } // we reached the padding or HMAC TLVs, or the end of the SRH 142 | 143 | if (*pad_off == 0) 144 | *pad_off = cur_off; 145 | 146 | if (*tlv_off == -1) 147 | *tlv_off = cur_off; 148 | else if (!offset_valid) 149 | return -EINVAL; 150 | 151 | return 0; 152 | } 153 | 154 | __attribute__((always_inline)) 155 | int seg6_add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, 156 | struct sr6_tlv_t *itlv, uint8_t tlv_size) 157 | { 158 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 159 | uint8_t len_remaining, new_pad; 160 | uint32_t pad_off = 0; 161 | uint32_t pad_size = 0; 162 | uint32_t partial_srh_len; 163 | int err; 164 | 165 | if (tlv_off != -1) 166 | tlv_off += srh_off; 167 | 168 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) 169 | return -EINVAL; 170 | 171 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 172 | if (err) 173 | return err; 174 | 175 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); 176 | if (err) 177 | return err; 178 | 179 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); 180 | if (err) 181 | return err; 182 | 183 | // the following can't be moved inside update_tlv_pad because the 184 | // bpf verifier has some issues with it 185 | pad_off += sizeof(*itlv) + itlv->len; 186 | partial_srh_len = pad_off - srh_off; 187 | len_remaining = partial_srh_len % 8; 188 | new_pad = 8 - len_remaining; 189 | 190 | if (new_pad == 1) // cannot pad for 1 byte only 191 | new_pad = 9; 192 | else if (new_pad == 8) 193 | new_pad = 0; 194 | 195 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 196 | } 197 | 198 | __attribute__((always_inline)) 199 | int seg6_delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, 200 | uint32_t tlv_off) 201 | { 202 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 203 | uint8_t len_remaining, new_pad; 204 | uint32_t partial_srh_len; 205 | uint32_t pad_off = 0; 206 | uint32_t pad_size = 0; 207 | struct sr6_tlv_t tlv; 208 | int err; 209 | 210 | tlv_off += srh_off; 211 | 212 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 213 | if (err) 214 | return err; 215 | 216 | err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); 217 | if (err) 218 | return err; 219 | 220 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); 221 | if (err) 222 | return err; 223 | 224 | pad_off -= sizeof(tlv) + tlv.len; 225 | partial_srh_len = pad_off - srh_off; 226 | len_remaining = partial_srh_len % 8; 227 | new_pad = 8 - len_remaining; 228 | if (new_pad == 1) // cannot pad for 1 byte only 229 | new_pad = 9; 230 | else if (new_pad == 8) 231 | new_pad = 0; 232 | 233 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 234 | } 235 | 236 | __attribute__((always_inline)) 237 | int seg6_find_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, unsigned char type, 238 | unsigned char len) 239 | { 240 | int srh_offset = (char *)srh - (char *)(long)skb->data; 241 | // initial cursor = end of segments, start of possible TLVs 242 | int cursor = srh_offset + sizeof(struct ip6_srh_t) + 243 | ((srh->first_segment + 1) << 4); 244 | 245 | #pragma clang loop unroll(full) 246 | for(int i=0; i < TLV_ITERATIONS; i++) { 247 | if (cursor >= srh_offset + ((srh->hdrlen + 1) << 3)) 248 | return -1; 249 | 250 | struct sr6_tlv_t tlv; 251 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(struct sr6_tlv_t))) 252 | return -1; 253 | //bpf_trace_printk("TLV type=%d len=%d found at offset %d\n", tlv.type, tlv.len, cursor); 254 | 255 | if (tlv.type == type && tlv.len + sizeof(struct sr6_tlv_t) == len) 256 | return cursor; 257 | 258 | cursor += sizeof(tlv) + tlv.len; 259 | } 260 | return -1; 261 | } 262 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/perfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cleanup() 4 | { 5 | if [ "$?" = "0" ]; then 6 | echo "End.OTP perfs [PASS]"; 7 | else 8 | echo "End.OTP perfs [FAILED]"; 9 | fi 10 | 11 | set +e 12 | #rm inject_dm 13 | ip netns del ns1 2> /dev/null 14 | ip netns del ns2 2> /dev/null 15 | pkill -F /tmp/end_otp_fb00::3-128.pid 16 | } 17 | 18 | set -e 19 | trap cleanup 0 2 3 6 9 20 | 21 | #gcc measures/inject_dm.c -o inject_dm 22 | 23 | ip netns add ns1 24 | ip netns add ns2 25 | 26 | ip link add veth1 type veth peer name veth2 27 | 28 | ip link set veth1 netns ns1 29 | ip link set veth2 netns ns2 30 | 31 | ip netns exec ns1 ip link set dev veth1 up 32 | ip netns exec ns2 ip link set dev veth2 up 33 | ip netns exec ns1 ip link set dev lo up 34 | ip netns exec ns2 ip link set dev lo up 35 | 36 | # All link scope addresses and routes required between veths 37 | ip netns exec ns1 ip -6 addr add fb00::12/16 dev veth1 38 | ip netns exec ns1 ip -6 route add fb00::21 dev veth1 39 | ip netns exec ns2 ip -6 addr add fb00::21/16 dev veth2 40 | ip netns exec ns2 ip -6 route add fb00::12/16 dev veth2 41 | 42 | ip netns exec ns1 ip -6 addr add fb00::1 dev lo 43 | ip netns exec ns2 ip -6 addr add fb00::2 dev lo 44 | 45 | ip netns exec ns1 tc qdisc add dev veth1 root netem delay 1ms 46 | 47 | ip netns exec ns2 ./end_otp.py fb00::3/128 veth2 48 | ip netns exec ns1 ip -6 route add fb00::3 via fb00::21 dev veth1 49 | ip netns exec ns1 ip -6 route add fb00::2 via fb00::21 dev veth1 50 | ip netns exec ns2 ip -6 route add fb00::1 via fb00::12 dev veth2 51 | 52 | # needed so fb00::1 and fb00::2 both have the other MAC address in cache 53 | # otherwise the first measurement is flawed 54 | ip netns exec ns1 ping -I fb00::1 fb00::2 -c 1 > /dev/null 55 | 56 | read -p "Press enter to start measuring" 57 | ip netns exec ns1 bash -c "measures/recv.py &" 58 | sleep 1 59 | for i in {0..4} 60 | do 61 | delay="$((10 ** $i))" 62 | delay="$(($delay / 10))" 63 | ip netns exec ns1 tc qdisc change dev veth1 root netem delay ${delay}ms 64 | echo "delay: $delay" 65 | for j in {1..20} 66 | do 67 | ip netns exec ns1 ./inject_dm fb00::1 fb00::2 9000 fb00::3 68 | sleep 1 69 | done 70 | done 71 | 72 | exit 0 73 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/tests_otp.seg: -------------------------------------------------------------------------------- 1 | `rm /sys/fs/bpf/ip/globals/end_otp_delta` 2 | 3 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::10 encap seg6local action End.BPF obj end_otp_bpf.o section end_otp dev dum0` 4 | `echo "userspace"` 5 | `./end_otp_usr` 6 | 7 | `sleep 1` 8 | 9 | > fc00::42 -> fd00::10 / [baba::1, fc00::1337, +fd00::10, fab1::49] {Type:7 Value: 00000100000003000000420000003713000000000000000000000000000000000000000000000000000000000000} 10 | < fc00::42 -> fc00::1337 / [baba::1, +fc00::1337, fd00::10, fab1::49] 11 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/tests_wrr.seg: -------------------------------------------------------------------------------- 1 | `rm /sys/fs/bpf/ip/globals/uplink_wrr_sids` 2 | `rm /sys/fs/bpf/ip/globals/uplink_wrr_weights` 3 | `rm /sys/fs/bpf/ip/globals/uplink_wrr_state` 4 | 5 | `/home/math/shared/iproute2/ip/ip -6 route add fd00::10 encap bpf in obj uplink_wrr_bpf.o section main dev dum0` 6 | `./uplink_wrr_usr fc00::0 fc00::a 3 fc00::b 2` 7 | 8 | `sleep 1` 9 | 10 | > fc00::42 -> fd00::10 11 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 12 | 13 | > fc00::42 -> fd00::10 14 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 15 | 16 | > fc00::42 -> fd00::10 17 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 18 | 19 | > fc00::42 -> fd00::10 20 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 21 | 22 | > fc00::42 -> fd00::10 23 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 24 | 25 | > fc00::42 -> fd00::10 26 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 27 | 28 | > fc00::42 -> fd00::10 29 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 30 | 31 | > fc00::42 -> fd00::10 32 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 33 | 34 | > fc00::42 -> fd00::10 35 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 36 | 37 | > fc00::42 -> fd00::10 38 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 39 | 40 | > fc00::42 -> fd00::10 41 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 42 | 43 | > fc00::42 -> fd00::10 44 | < fd00::42 -> fc00::a / [fc00::a, ::] / fc00::42 -> fd00::10 45 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/uplink_wrr_bpf.c: -------------------------------------------------------------------------------- 1 | #include "bpf_seg6/all.h" 2 | 3 | struct bpf_elf_map __section_maps uplink_wrr_sids = { 4 | .type = BPF_MAP_TYPE_ARRAY, 5 | .id = 0, 6 | .size_key = sizeof(uint32_t), 7 | .size_value = sizeof(struct ip6_addr_t), 8 | .max_elem = 3, 9 | .pinning = PIN_GLOBAL_NS, 10 | }; 11 | 12 | struct bpf_elf_map __section_maps uplink_wrr_weights = { 13 | .type = BPF_MAP_TYPE_ARRAY, 14 | .id = 1, 15 | .size_key = sizeof(uint32_t), 16 | .size_value = sizeof(uint32_t), 17 | .max_elem = 2, 18 | .pinning = PIN_GLOBAL_NS, 19 | }; 20 | 21 | struct bpf_elf_map __section_maps uplink_wrr_state = { 22 | .type = BPF_MAP_TYPE_ARRAY, 23 | .id = 1, 24 | .size_key = sizeof(uint32_t), 25 | .size_value = sizeof(uint32_t), 26 | .max_elem = 3, 27 | .pinning = PIN_GLOBAL_NS, 28 | }; 29 | 30 | static __attribute__((always_inline)) 31 | void build_SRH(char *srh_buf, struct ip6_addr_t *intermediate, struct ip6_addr_t *dst) 32 | { 33 | struct ip6_srh_t *srh = (struct ip6_srh_t *)srh_buf; 34 | srh->nexthdr = 0; 35 | srh->type = 4; 36 | srh->flags = 0; 37 | srh->tag = 0; 38 | srh->hdrlen = 4; 39 | srh->segments_left = 1; 40 | srh->first_segment = 1; 41 | 42 | struct ip6_addr_t *seg0 = (struct ip6_addr_t *)((char*) srh + sizeof(*srh)); 43 | seg0->hi = dst->hi; 44 | seg0->lo = dst->lo; 45 | 46 | struct ip6_addr_t *seg1 = (struct ip6_addr_t *)((char*) seg0 + sizeof(struct ip6_addr_t)); 47 | seg1->hi = intermediate->hi; 48 | seg1->lo = intermediate->lo; 49 | } 50 | 51 | static __attribute__((always_inline)) 52 | struct ip6_addr_t *WRR() 53 | { 54 | struct ip6_addr_t *sid1, *sid2; 55 | int *w1, *w2; 56 | int *last_sid, *prev_cw, *gcd; 57 | 58 | int k=0; 59 | sid1 = map_lookup_elem(&uplink_wrr_sids, &k); 60 | w1 = map_lookup_elem(&uplink_wrr_weights, &k); 61 | last_sid = map_lookup_elem(&uplink_wrr_state, &k); 62 | 63 | k++; 64 | sid2 = map_lookup_elem(&uplink_wrr_sids, &k); 65 | w2 = map_lookup_elem(&uplink_wrr_weights, &k); 66 | prev_cw = map_lookup_elem(&uplink_wrr_state, &k); 67 | 68 | k++; 69 | gcd = map_lookup_elem(&uplink_wrr_state, &k); 70 | 71 | if (!w1) return NULL; 72 | if (!w2) return NULL; 73 | if (!sid1) return NULL; 74 | if (!sid2) return NULL; 75 | if (!last_sid) return NULL; 76 | if (!prev_cw) return NULL; 77 | if (!gcd) return NULL; 78 | 79 | struct ip6_addr_t *ret = NULL; 80 | int i = *last_sid; 81 | int cw = *prev_cw; 82 | 83 | i = (i+1) % 2; 84 | if (i == 0) { 85 | cw = cw - *gcd; 86 | if (cw <= 0) 87 | cw = *w1 >= *w2 ? *w1 : *w2; 88 | } 89 | if (i == 0 && *w1 >= cw) { 90 | ret = sid1; 91 | } else if (i == 1 && *w2 >= cw) { 92 | ret = sid2; 93 | } else { 94 | i = (i+1) % 2; 95 | if (i == 0) { 96 | cw = cw - *gcd; 97 | if (cw <= 0) 98 | cw = *w1 >= *w2 ? *w1 : *w2; 99 | } 100 | if (i == 0 && *w1 >= cw) 101 | ret = sid1; 102 | else if (i == 1 && *w2 >= cw) 103 | ret = sid2; 104 | else 105 | ret = NULL; // should never happen 106 | } 107 | 108 | k=0; 109 | map_update_elem(&uplink_wrr_state, &k, &i ,BPF_ANY); 110 | k++; 111 | map_update_elem(&uplink_wrr_state, &k, &cw ,BPF_ANY); 112 | 113 | return ret; 114 | } 115 | 116 | __section("main") 117 | int LB(struct __sk_buff *skb) 118 | { 119 | void *data_end = (void *)(long)skb->data_end; 120 | void *cursor = (void *)(long)skb->data; 121 | 122 | struct ip6_t *ip; 123 | ip = cursor_advance(cursor, sizeof(struct ip6_t)); 124 | if ((void *)ip + sizeof(*ip) > data_end) 125 | return BPF_DROP; 126 | 127 | struct ip6_addr_t *hop = WRR(); 128 | if (hop == NULL) 129 | return BPF_DROP; 130 | 131 | struct ip6_addr_t *sid_dst; 132 | int k = 2; 133 | sid_dst = map_lookup_elem(&uplink_wrr_sids, &k); 134 | if (sid_dst == NULL) 135 | return BPF_DROP; 136 | 137 | char srh_buf[40]; 138 | build_SRH(srh_buf, hop, sid_dst); 139 | lwt_push_encap(skb, BPF_LWT_ENCAP_SEG6, (void *)srh_buf, 40); 140 | return BPF_OK; 141 | } 142 | 143 | char __license[] __section("license") = "GPL"; 144 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/cpe_bpf/uplink_wrr_usr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int get_gcd(int a, int b) 13 | { 14 | int c; 15 | while (a != 0) { 16 | c = a; 17 | a = b%a; 18 | b = c; 19 | } 20 | return b; 21 | } 22 | 23 | int bpf(int cmd, union bpf_attr *attr, unsigned int size) 24 | { 25 | #ifdef __NR_bpf 26 | return syscall(__NR_bpf, cmd, attr, size); 27 | #else 28 | fprintf(stderr, "No bpf syscall, kernel headers too old?\n"); 29 | errno = ENOSYS; 30 | return -1; 31 | #endif 32 | } 33 | 34 | __u64 bpf_ptr_to_u64(const void *ptr) 35 | { 36 | return (__u64) (unsigned long) ptr; 37 | } 38 | 39 | int bpf_update_elem(int fd, void *key, void *value, uint64_t flags) 40 | { 41 | union bpf_attr attr = {}; 42 | attr.map_fd = fd; 43 | attr.key = bpf_ptr_to_u64(key); 44 | attr.value = bpf_ptr_to_u64(value);; 45 | attr.flags = flags; 46 | 47 | static int nb = 0; 48 | nb++; 49 | int ret = bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); 50 | if (ret < 0) { 51 | fprintf(stderr, "Map update #%d failed: %s\n", nb, strerror(errno)); 52 | } 53 | 54 | return ret; 55 | } 56 | 57 | /* Main function */ 58 | 59 | int main (int argc, char *argv[]) 60 | { 61 | struct in6_addr sid1, sid2, sid_agg; 62 | int w1, w2, gcd; 63 | int cw = 0; 64 | int last_sid = -1; 65 | 66 | if (argc != 6) { 67 | printf("Error, needed parameters: ./uplink_wrr_usr SID-AGG SID1 W1 SID2 W2"); 68 | return -1; 69 | } 70 | 71 | if (!inet_pton(AF_INET6, argv[2], &sid1) || !inet_pton(AF_INET6, argv[4], &sid2) || !inet_pton(AF_INET6, argv[1], &sid_agg)) { 72 | printf("Error: SIDs must be valid IPv6 addresses."); 73 | printf("./uplink_wrr_usr SID1 W1 SID2 W2"); 74 | return -1; 75 | } 76 | 77 | w1 = atoi(argv[3]); 78 | w2 = atoi(argv[5]); 79 | if (w1 <= 0 || w2 <= 0) { 80 | printf("Error: weights must be positive numbers."); 81 | printf("./uplink_wrr_usr SID1 W1 SID2 W2"); 82 | return -1; 83 | } 84 | gcd = get_gcd(w1, w2); 85 | 86 | union bpf_attr attr_obj = {}; 87 | int map_fd[3]; 88 | 89 | char *map_paths[] = { 90 | "/sys/fs/bpf/ip/globals/uplink_wrr_sids", 91 | "/sys/fs/bpf/ip/globals/uplink_wrr_weights", 92 | "/sys/fs/bpf/ip/globals/uplink_wrr_state" 93 | }; 94 | 95 | for(int i=0; i < sizeof(map_fd)/sizeof(int); i++) { 96 | attr_obj.map_fd = 0; 97 | attr_obj.pathname = bpf_ptr_to_u64(map_paths[i]); 98 | map_fd[i] = bpf(BPF_OBJ_GET, &attr_obj, sizeof(attr_obj)); 99 | if (map_fd[i] <= 0) { 100 | fprintf(stderr, "Fetching map failed: %s\n", strerror(errno)); 101 | return -1; 102 | } 103 | } 104 | 105 | uint32_t key = 0; 106 | bpf_update_elem(map_fd[0], &key, &sid1, BPF_ANY); 107 | bpf_update_elem(map_fd[1], &key, &w1, BPF_ANY); 108 | bpf_update_elem(map_fd[2], &key, &last_sid, BPF_ANY); 109 | 110 | key++; 111 | bpf_update_elem(map_fd[0], &key, &sid2, BPF_ANY); 112 | bpf_update_elem(map_fd[1], &key, &w2, BPF_ANY); 113 | bpf_update_elem(map_fd[2], &key, &cw, BPF_ANY); 114 | 115 | key++; 116 | bpf_update_elem(map_fd[0], &key, &sid_agg, BPF_ANY); 117 | bpf_update_elem(map_fd[2], &key, &gcd, BPF_ANY); 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/dm_recv_bpf.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | #include "libseg6.c" 3 | 4 | #define SR6_TLV_DM 7 5 | 6 | BPF_PERF_OUTPUT(dm_messages); 7 | 8 | struct timestamp_ieee1588_v2 { 9 | uint32_t tv_sec; 10 | uint32_t tv_nsec; 11 | }; 12 | 13 | struct sr6_tlv_dm_t { 14 | unsigned char type; // value TBA by IANA, use NSH+1 15 | unsigned char len; 16 | unsigned short reserved; 17 | unsigned char version:4; // 1 18 | unsigned char flags:4; // R|T|0|0, R: Query(0),Response(1), T: if tc class, set to 1 19 | unsigned char cc; 20 | /* For a Query: 0x0 in-band response, 0x1 out of band, 0x2: no response 21 | * For a response: 0x1 success, 0x10-0xFF: errors */ 22 | unsigned short reserved2; 23 | unsigned char qtf:4; /* timestamp formats */ 24 | unsigned char rtf:4; 25 | unsigned char rtpf:4; 26 | unsigned int reserved3:20; 27 | unsigned int session_id:24; /* set by the querier */ 28 | unsigned char tc; 29 | struct timestamp_ieee1588_v2 timestamps[4]; 30 | unsigned char sub_tlv[0]; // possible UDP Return Object (URO) 31 | } BPF_PACKET_HEADER; 32 | 33 | 34 | int DM_recv(struct __sk_buff *skb) { 35 | struct ip6_srh_t *srh = seg6_get_srh(skb); 36 | if (!srh) 37 | return BPF_DROP; 38 | 39 | struct sr6_tlv_dm_t tlv; 40 | int cursor = seg6_find_tlv(skb, srh, SR6_TLV_DM, sizeof(tlv)); 41 | if (cursor < 0) 42 | return BPF_DROP; 43 | 44 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(tlv)) < 0) 45 | return BPF_DROP; 46 | 47 | unsigned char query_cc = tlv.cc; 48 | 49 | // only handle version 1, in-band messages, replies and rtf type 3 50 | if (tlv.version != 1 || tlv.cc != 0x00 || (tlv.flags & 8) == 0 || tlv.rtf != 3) 51 | return BPF_DROP; 52 | 53 | dm_messages.perf_submit_skb(skb, skb->len, &tlv, sizeof(tlv)); 54 | return BPF_DROP; 55 | } 56 | 57 | char __license[] __section("license") = "GPL"; 58 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/libseg6.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | 3 | __attribute__((always_inline)) 4 | struct ip6_srh_t *seg6_get_srh(struct __sk_buff *skb) 5 | { 6 | void *cursor, *data_end; 7 | struct ip6_srh_t *srh; 8 | struct ip6_t *ip; 9 | uint8_t *ipver; 10 | 11 | data_end = (void *)(long)skb->data_end; 12 | cursor = (void *)(long)skb->data; 13 | ipver = (uint8_t *)cursor; 14 | 15 | if ((void *)ipver + sizeof(*ipver) > data_end) 16 | return NULL; 17 | 18 | if ((*ipver >> 4) != 6) 19 | return NULL; 20 | 21 | ip = cursor_advance(cursor, sizeof(*ip)); 22 | if ((void *)ip + sizeof(*ip) > data_end) 23 | return NULL; 24 | 25 | if (ip->next_header != 43) 26 | return NULL; 27 | 28 | srh = cursor_advance(cursor, sizeof(*srh)); 29 | if ((void *)srh + sizeof(*srh) > data_end) 30 | return NULL; 31 | 32 | if (srh->type != 4) 33 | return NULL; 34 | 35 | return srh; 36 | } 37 | 38 | __attribute__((always_inline)) 39 | int __update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, 40 | uint32_t old_pad, uint32_t pad_off) 41 | { 42 | int err; 43 | 44 | if (new_pad != old_pad) { 45 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, 46 | (int) new_pad - (int) old_pad); 47 | if (err) 48 | return err; 49 | } 50 | 51 | if (new_pad > 0) { 52 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0}; 54 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; 55 | 56 | pad_tlv->type = SR6_TLV_PADDING; 57 | pad_tlv->len = new_pad - 2; 58 | 59 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, 60 | (void *)pad_tlv_buf, new_pad); 61 | if (err) 62 | return err; 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | __attribute__((always_inline)) 69 | int __is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, 70 | uint32_t *tlv_off, uint32_t *pad_size, 71 | uint32_t *pad_off) 72 | { 73 | uint32_t srh_off, cur_off; 74 | int offset_valid = 0; 75 | int err; 76 | 77 | srh_off = (char *)srh - (char *)(long)skb->data; 78 | // cur_off = end of segments, start of possible TLVs 79 | cur_off = srh_off + sizeof(*srh) + 80 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); 81 | 82 | *pad_off = 0; 83 | 84 | // we can only go as far as ~10 TLVs due to the BPF max stack size 85 | #pragma clang loop unroll(full) 86 | for (int i = 0; i < 10; i++) { 87 | struct sr6_tlv_t tlv; 88 | 89 | if (cur_off == *tlv_off) 90 | offset_valid = 1; 91 | 92 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) 93 | break; 94 | 95 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); 96 | if (err) 97 | return err; 98 | 99 | if (tlv.type == SR6_TLV_PADDING) { 100 | *pad_size = tlv.len + sizeof(tlv); 101 | *pad_off = cur_off; 102 | 103 | if (*tlv_off == srh_off) { 104 | *tlv_off = cur_off; 105 | offset_valid = 1; 106 | } 107 | break; 108 | 109 | } else if (tlv.type == SR6_TLV_HMAC) { 110 | break; 111 | } 112 | 113 | cur_off += sizeof(tlv) + tlv.len; 114 | } // we reached the padding or HMAC TLVs, or the end of the SRH 115 | 116 | if (*pad_off == 0) 117 | *pad_off = cur_off; 118 | 119 | if (*tlv_off == -1) 120 | *tlv_off = cur_off; 121 | else if (!offset_valid) 122 | return -EINVAL; 123 | 124 | return 0; 125 | } 126 | 127 | __attribute__((always_inline)) 128 | int seg6_add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, 129 | struct sr6_tlv_t *itlv, uint8_t tlv_size) 130 | { 131 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 132 | uint8_t len_remaining, new_pad; 133 | uint32_t pad_off = 0; 134 | uint32_t pad_size = 0; 135 | uint32_t partial_srh_len; 136 | int err; 137 | 138 | if (tlv_off != -1) 139 | tlv_off += srh_off; 140 | 141 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) 142 | return -EINVAL; 143 | 144 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 145 | if (err) 146 | return err; 147 | 148 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); 149 | if (err) 150 | return err; 151 | 152 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); 153 | if (err) 154 | return err; 155 | 156 | // the following can't be moved inside update_tlv_pad because the 157 | // bpf verifier has some issues with it 158 | pad_off += sizeof(*itlv) + itlv->len; 159 | partial_srh_len = pad_off - srh_off; 160 | len_remaining = partial_srh_len % 8; 161 | new_pad = 8 - len_remaining; 162 | 163 | if (new_pad == 1) // cannot pad for 1 byte only 164 | new_pad = 9; 165 | else if (new_pad == 8) 166 | new_pad = 0; 167 | 168 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 169 | } 170 | 171 | __attribute__((always_inline)) 172 | int seg6_delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, 173 | uint32_t tlv_off) 174 | { 175 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 176 | uint8_t len_remaining, new_pad; 177 | uint32_t partial_srh_len; 178 | uint32_t pad_off = 0; 179 | uint32_t pad_size = 0; 180 | struct sr6_tlv_t tlv; 181 | int err; 182 | 183 | tlv_off += srh_off; 184 | 185 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 186 | if (err) 187 | return err; 188 | 189 | err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); 190 | if (err) 191 | return err; 192 | 193 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); 194 | if (err) 195 | return err; 196 | 197 | pad_off -= sizeof(tlv) + tlv.len; 198 | partial_srh_len = pad_off - srh_off; 199 | len_remaining = partial_srh_len % 8; 200 | new_pad = 8 - len_remaining; 201 | if (new_pad == 1) // cannot pad for 1 byte only 202 | new_pad = 9; 203 | else if (new_pad == 8) 204 | new_pad = 0; 205 | 206 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 207 | } 208 | 209 | __attribute__((always_inline)) 210 | int seg6_find_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, unsigned char type, 211 | unsigned char len) 212 | { 213 | int srh_offset = (char *)srh - (char *)(long)skb->data; 214 | // initial cursor = end of segments, start of possible TLVs 215 | int cursor = srh_offset + sizeof(struct ip6_srh_t) + 216 | ((srh->first_segment + 1) << 4); 217 | 218 | #pragma clang loop unroll(full) 219 | for(int i=0; i < 10; i++) { // TODO limitation 220 | if (cursor >= srh_offset + ((srh->hdrlen + 1) << 3)) 221 | return -1; 222 | 223 | struct sr6_tlv_t tlv; 224 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(struct sr6_tlv_t))) 225 | return -1; 226 | 227 | if (tlv.type == type && tlv.len + sizeof(struct sr6_tlv_t) == len) 228 | return cursor; 229 | 230 | cursor += sizeof(tlv) + tlv.len; 231 | } 232 | return -1; 233 | } 234 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/link_aggreg_bpf.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | 3 | BPF_ARRAY(sids, struct ip6_addr_t, 3); 4 | BPF_ARRAY(weights, int, 2); 5 | BPF_ARRAY(wrr, int, 3); 6 | 7 | static __attribute__((always_inline)) 8 | void build_SRH(char *srh_buf, struct ip6_addr_t *intermediate, struct ip6_addr_t *dst) 9 | { 10 | struct ip6_srh_t *srh = (struct ip6_srh_t *)srh_buf; 11 | srh->nexthdr = 0; 12 | srh->type = 4; 13 | srh->flags = 0; 14 | srh->tag = 0; 15 | srh->hdrlen = 4; 16 | srh->segments_left = 1; 17 | srh->first_segment = 1; 18 | 19 | struct ip6_addr_t *seg0 = (struct ip6_addr_t *)((char*) srh + sizeof(*srh)); 20 | seg0->hi = dst->hi; 21 | seg0->lo = dst->lo; 22 | 23 | struct ip6_addr_t *seg1 = (struct ip6_addr_t *)((char*) seg0 + sizeof(struct ip6_addr_t)); 24 | seg1->hi = intermediate->hi; 25 | seg1->lo = intermediate->lo; 26 | } 27 | 28 | static __attribute__((always_inline)) 29 | struct ip6_addr_t *WRR() 30 | { 31 | struct ip6_addr_t *sid1, *sid2; 32 | int *w1, *w2; 33 | int *last_sid, *prev_cw, *gcd; 34 | int k=0; 35 | w1 = weights.lookup(&k); 36 | sid1 = sids.lookup(&k); 37 | last_sid = wrr.lookup(&k); 38 | k++; 39 | w2 = weights.lookup(&k); 40 | sid2 = sids.lookup(&k); 41 | prev_cw = wrr.lookup(&k); 42 | k++; 43 | gcd = wrr.lookup(&k); 44 | 45 | if (!w1) return NULL; 46 | if (!w2) return NULL; 47 | if (!sid1) return NULL; 48 | if (!sid2) return NULL; 49 | if (!last_sid) return NULL; 50 | if (!prev_cw) return NULL; 51 | if (!gcd) return NULL; 52 | 53 | struct ip6_addr_t *ret = NULL; 54 | int i = *last_sid; 55 | int cw = *prev_cw; 56 | 57 | i = (i+1) % 2; 58 | if (i == 0) { 59 | cw = cw - *gcd; 60 | if (cw <= 0) 61 | cw = max(*w1, *w2); 62 | } 63 | if (i == 0 && *w1 >= cw) { 64 | ret = sid1; 65 | } else if (i == 1 && *w2 >= cw) { 66 | ret = sid2; 67 | } else { 68 | i = (i+1) % 2; 69 | if (i == 0) { 70 | cw = cw - *gcd; 71 | if (cw <= 0) 72 | cw = max(*w1, *w2); 73 | } 74 | if (i == 0 && *w1 >= cw) 75 | ret = sid1; 76 | else if (i == 1 && *w2 >= cw) 77 | ret = sid2; 78 | else 79 | ret = NULL; // should never happen 80 | } 81 | 82 | k=0; 83 | wrr.update(&k, &i); 84 | k++; 85 | wrr.update(&k, &cw); 86 | 87 | return ret; 88 | } 89 | 90 | int LB(struct __sk_buff *skb) 91 | { 92 | void *data_end = (void *)(long)skb->data_end; 93 | void *cursor = (void *)(long)skb->data; 94 | 95 | struct ip6_t *ip; 96 | ip = cursor_advance(cursor, sizeof(struct ip6_t)); 97 | if ((void *)ip + sizeof(*ip) > data_end) 98 | return BPF_DROP; 99 | 100 | struct ip6_addr_t *hop = WRR(); 101 | if (hop == NULL) 102 | return BPF_DROP; 103 | 104 | struct ip6_addr_t *sid_dst; 105 | int k = 2; 106 | sid_dst = sids.lookup(&k); 107 | if (sid_dst == NULL) 108 | return BPF_DROP; 109 | 110 | char srh_buf[40]; 111 | build_SRH(srh_buf, hop, sid_dst); 112 | bpf_lwt_push_encap(skb, BPF_LWT_ENCAP_SEG6, (void *)srh_buf, 40); 113 | return BPF_OK; 114 | } 115 | 116 | char __license[] __section("license") = "GPL"; 117 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/netns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | #coding: utf-8 3 | 4 | from pyroute2 import netns 5 | import subprocess, shlex, sys 6 | 7 | def exec_ns(ns_name, cmd): 8 | netns.setns(ns_name) 9 | subprocess.Popen(cmd) 10 | 11 | if __name__ == '__main__': 12 | if len(sys.argv) < 3: 13 | print("Format: netns.py NS cmd") 14 | sys.exit(1) 15 | 16 | exec_ns(sys.argv[1], sys.argv[2:]) 17 | 18 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /use-cases/Links-aggreg/test.py: -------------------------------------------------------------------------------- 1 | import sys, logging, signal, socket, os, socket, math, struct 2 | import ctypes as ct 3 | from functools import reduce 4 | 5 | class DM_TLV(ct.Structure): 6 | _pack_ = 1 7 | _fields_ = [ ("type", ct.c_uint8), 8 | ("len", ct.c_uint8), 9 | ("reserved", ct.c_ushort), 10 | 11 | ("version", ct.c_uint8, 4), 12 | ("flags", ct.c_uint8, 4), 13 | ("cc", ct.c_uint8), 14 | ("reserved2", ct.c_ushort), 15 | 16 | ("qtf", ct.c_uint8, 4), 17 | ("rtf", ct.c_uint8, 4), 18 | ("rtpf", ct.c_uint32, 4), 19 | ("reserved3", ct.c_uint32, 20), 20 | 21 | ("session_id", ct.c_uint32, 24), 22 | ("tc", ct.c_uint32, 8), 23 | 24 | ("timestamp1", ct.c_uint64), 25 | ("timestamp2", ct.c_ulonglong), 26 | ("timestamp3", ct.c_ulonglong), 27 | ("timestamp4", ct.c_ulonglong) ] 28 | 29 | class Node: 30 | sid, sid_bytes = "", b"" 31 | otp_sid, otp_sid_bytes = "", b"" 32 | weight = 0 33 | delay_down, delay_up = 0, 0 34 | 35 | def __init__(self, sid, otp_sid, weight): 36 | self.sid, self.otp_sid = sid, otp_sid 37 | self.otp_sid_bytes = socket.inet_pton(socket.AF_INET6, otp_sid) 38 | self.sid_bytes = socket.inet_pton(socket.AF_INET6, sid) 39 | self.weight = int(weight) 40 | 41 | def update_delays(self, delay_down, delay_up): 42 | self.delay_down, self.delay_up = delay_down, delay_up 43 | 44 | def send_delay_probe(node): 45 | src = "fc00::2" 46 | src = "::1" 47 | src_rcv = "fc00::2a" 48 | 49 | segments = (bytes(16), node.otp_sid_bytes, node.sid_bytes) 50 | 51 | dm = DM_TLV() 52 | dm.type = 7 53 | dm.len = 46 54 | dm.version = 1 55 | dm.cc = 0 56 | dm.qtf = 3 57 | dm.timestamp1 = 42 58 | dm.session_id = 10 59 | 60 | hdrlen = (len(bytes(dm)) + len(segments) * 16) >> 3 61 | srh_base = struct.pack("!BBBBBBH", 0, hdrlen, 4, len(segments) - 1, len(segments) - 1, 0, 0) 62 | srh = srh_base + reduce(lambda x,y: x+y, segments) + bytes(dm) 63 | 64 | sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 65 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RTHDR, srh) 66 | 67 | sock.bind((src, 53)) 68 | sock.sendto(b"", (src_rcv, 53)) # Port number is irrelevant for ICMP 69 | 70 | n = Node("fc00::3a", "fc00::3c", 1) 71 | send_delay_probe(n) 72 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zashas/Thesis-SRv6-BPF/e9f9624ade3f94eb22cbfaffa050506692eaad06/use-cases/OAMP-segtrace/__init__.py -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/icmp.py: -------------------------------------------------------------------------------- 1 | import socket, struct, sys 2 | 3 | def calculate_checksum(source_string): 4 | #Copyright (c) Matthew Dixon Cowles, . 5 | #Distributable under the terms of the GNU General Public License 6 | #version 2. Provided with no warranties of any sort. 7 | 8 | """ 9 | A port of the functionality of in_cksum() from ping.c 10 | Ideally this would act on the string as a series of 16-bit ints (host 11 | packed), but this works. 12 | Network data is big-endian, hosts are typically little-endian 13 | """ 14 | countTo = (int(len(source_string) / 2)) * 2 15 | sum = 0 16 | count = 0 17 | 18 | # Handle bytes in pairs (decoding as short ints) 19 | loByte = 0 20 | hiByte = 0 21 | while count < countTo: 22 | if (sys.byteorder == "little"): 23 | loByte = source_string[count] 24 | hiByte = source_string[count + 1] 25 | else: 26 | loByte = source_string[count + 1] 27 | hiByte = source_string[count] 28 | 29 | sum = sum + (hiByte * 256 + loByte) 30 | count += 2 31 | 32 | # Handle last byte if applicable (odd-number of bytes) 33 | # Endianness should be irrelevant in this case 34 | if countTo < len(source_string): # Check for odd length 35 | loByte = source_string[len(source_string) - 1] 36 | sum += loByte 37 | 38 | sum &= 0xffffffff # Truncate sum to 32 bits (a variance from ping.c, which 39 | # uses signed ints, but overflow is unlikely in ping) 40 | 41 | sum = (sum >> 16) + (sum & 0xffff) # Add high 16 bits to low 16 bits 42 | sum += (sum >> 16) # Add carry from above (if any) 43 | answer = ~sum & 0xffff # Invert and truncate to 16 bits 44 | answer = socket.htons(answer) 45 | 46 | return answer 47 | 48 | def send(src, dst, type, code, data, hops=64, srh=None): 49 | sock = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) 50 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_UNICAST_HOPS, hops) 51 | if srh: 52 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RTHDR, srh) 53 | 54 | sock.bind((src, 1)) 55 | 56 | # Compute ICMPv6 pseudo header 57 | pseudo_header = socket.inet_pton(socket.AF_INET6, src) 58 | pseudo_header += socket.inet_pton(socket.AF_INET6, dst) 59 | pseudo_header += struct.pack("!IBBBBBBH", len(data)+4, 0, 0, 0, 58, type, code, 0) 60 | checksum = calculate_checksum(pseudo_header + data) 61 | 62 | header = struct.pack("!BBH", type, code, checksum) 63 | packet = header + data 64 | sock.sendto(packet, (dst, 0)) # Port number is irrelevant for ICMP 65 | 66 | 67 | if __name__ == '__main__': 68 | data = "075c0001" 69 | data = bytearray.fromhex(data) 70 | send("2a02:a03f:4258:3200:7ce:57d4:ce01:d90f", "2a00:1450:400e:802::200e", 128, 0, data) 71 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/libseg6.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | 3 | __attribute__((always_inline)) 4 | struct ip6_srh_t *seg6_get_srh(struct __sk_buff *skb) 5 | { 6 | void *cursor, *data_end; 7 | struct ip6_srh_t *srh; 8 | struct ip6_t *ip; 9 | uint8_t *ipver; 10 | 11 | data_end = (void *)(long)skb->data_end; 12 | cursor = (void *)(long)skb->data; 13 | ipver = (uint8_t *)cursor; 14 | 15 | if ((void *)ipver + sizeof(*ipver) > data_end) 16 | return NULL; 17 | 18 | if ((*ipver >> 4) != 6) 19 | return NULL; 20 | 21 | ip = cursor_advance(cursor, sizeof(*ip)); 22 | if ((void *)ip + sizeof(*ip) > data_end) 23 | return NULL; 24 | 25 | if (ip->next_header != 43) 26 | return NULL; 27 | 28 | srh = cursor_advance(cursor, sizeof(*srh)); 29 | if ((void *)srh + sizeof(*srh) > data_end) 30 | return NULL; 31 | 32 | if (srh->type != 4) 33 | return NULL; 34 | 35 | return srh; 36 | } 37 | 38 | __attribute__((always_inline)) 39 | int __update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, 40 | uint32_t old_pad, uint32_t pad_off) 41 | { 42 | int err; 43 | 44 | if (new_pad != old_pad) { 45 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, 46 | (int) new_pad - (int) old_pad); 47 | if (err) 48 | return err; 49 | } 50 | 51 | if (new_pad > 0) { 52 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0}; 54 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; 55 | 56 | pad_tlv->type = SR6_TLV_PADDING; 57 | pad_tlv->len = new_pad - 2; 58 | 59 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, 60 | (void *)pad_tlv_buf, new_pad); 61 | if (err) 62 | return err; 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | __attribute__((always_inline)) 69 | int __is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, 70 | uint32_t *tlv_off, uint32_t *pad_size, 71 | uint32_t *pad_off) 72 | { 73 | uint32_t srh_off, cur_off; 74 | int offset_valid = 0; 75 | int err; 76 | 77 | srh_off = (char *)srh - (char *)(long)skb->data; 78 | // cur_off = end of segments, start of possible TLVs 79 | cur_off = srh_off + sizeof(*srh) + 80 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); 81 | 82 | *pad_off = 0; 83 | 84 | // we can only go as far as ~10 TLVs due to the BPF max stack size 85 | #pragma clang loop unroll(full) 86 | for (int i = 0; i < 10; i++) { 87 | struct sr6_tlv_t tlv; 88 | 89 | if (cur_off == *tlv_off) 90 | offset_valid = 1; 91 | 92 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) 93 | break; 94 | 95 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); 96 | if (err) 97 | return err; 98 | 99 | if (tlv.type == SR6_TLV_PADDING) { 100 | *pad_size = tlv.len + sizeof(tlv); 101 | *pad_off = cur_off; 102 | 103 | if (*tlv_off == srh_off) { 104 | *tlv_off = cur_off; 105 | offset_valid = 1; 106 | } 107 | break; 108 | 109 | } else if (tlv.type == SR6_TLV_HMAC) { 110 | break; 111 | } 112 | 113 | cur_off += sizeof(tlv) + tlv.len; 114 | } // we reached the padding or HMAC TLVs, or the end of the SRH 115 | 116 | if (*pad_off == 0) 117 | *pad_off = cur_off; 118 | 119 | if (*tlv_off == -1) 120 | *tlv_off = cur_off; 121 | else if (!offset_valid) 122 | return -EINVAL; 123 | 124 | return 0; 125 | } 126 | 127 | __attribute__((always_inline)) 128 | int seg6_add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, 129 | struct sr6_tlv_t *itlv, uint8_t tlv_size) 130 | { 131 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 132 | uint8_t len_remaining, new_pad; 133 | uint32_t pad_off = 0; 134 | uint32_t pad_size = 0; 135 | uint32_t partial_srh_len; 136 | int err; 137 | 138 | if (tlv_off != -1) 139 | tlv_off += srh_off; 140 | 141 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) 142 | return -EINVAL; 143 | 144 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 145 | if (err) 146 | return err; 147 | 148 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); 149 | if (err) 150 | return err; 151 | 152 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, sizeof(*itlv) + itlv->len); 153 | if (err) 154 | return err; 155 | 156 | // the following can't be moved inside update_tlv_pad because the 157 | // bpf verifier has some issues with it 158 | pad_off += sizeof(*itlv) + itlv->len; 159 | partial_srh_len = pad_off - srh_off; 160 | len_remaining = partial_srh_len % 8; 161 | new_pad = 8 - len_remaining; 162 | 163 | if (new_pad == 1) // cannot pad for 1 byte only 164 | new_pad = 9; 165 | else if (new_pad == 8) 166 | new_pad = 0; 167 | 168 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 169 | } 170 | 171 | __attribute__((always_inline)) 172 | int seg6_delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, 173 | uint32_t tlv_off) 174 | { 175 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 176 | uint8_t len_remaining, new_pad; 177 | uint32_t partial_srh_len; 178 | uint32_t pad_off = 0; 179 | uint32_t pad_size = 0; 180 | struct sr6_tlv_t tlv; 181 | int err; 182 | 183 | tlv_off += srh_off; 184 | 185 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 186 | if (err) 187 | return err; 188 | 189 | err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); 190 | if (err) 191 | return err; 192 | 193 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); 194 | if (err) 195 | return err; 196 | 197 | pad_off -= sizeof(tlv) + tlv.len; 198 | partial_srh_len = pad_off - srh_off; 199 | len_remaining = partial_srh_len % 8; 200 | new_pad = 8 - len_remaining; 201 | if (new_pad == 1) // cannot pad for 1 byte only 202 | new_pad = 9; 203 | else if (new_pad == 8) 204 | new_pad = 0; 205 | 206 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 207 | } 208 | 209 | __attribute__((always_inline)) 210 | int seg6_find_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, unsigned char type, 211 | unsigned char len) 212 | { 213 | int srh_offset = (char *)srh - (char *)(long)skb->data; 214 | // initial cursor = end of segments, start of possible TLVs 215 | int cursor = srh_offset + sizeof(struct ip6_srh_t) + 216 | ((srh->first_segment + 1) << 4); 217 | 218 | #pragma clang loop unroll(full) 219 | for(int i=0; i < 10; i++) { // TODO limitation 220 | if (cursor >= srh_offset + ((srh->hdrlen + 1) << 3)) 221 | return -1; 222 | 223 | struct sr6_tlv_t tlv; 224 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(struct sr6_tlv_t))) 225 | return -1; 226 | //bpf_trace_printk("TLV type=%d len=%d found at offset %d\n", tlv.type, tlv.len, cursor); 227 | 228 | if (tlv.type == type && tlv.len + sizeof(struct sr6_tlv_t) == len) 229 | return cursor; 230 | 231 | cursor += sizeof(tlv) + tlv.len; 232 | } 233 | return -1; 234 | } 235 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/oam_ecmp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from bcc import BPF 4 | from pyroute2 import IPRoute 5 | import sys, logging, signal, socket, icmp, struct, pickle 6 | from daemonize import Daemonize 7 | import ctypes as ct 8 | from time import sleep 9 | 10 | import traceback 11 | 12 | # Needed for the simulation in our virtualized network (validation.sh). 13 | # In a real use-case, the routing daemon would fill the eBPF map with the global addresses 14 | LOCAL_GLOBAL_MAP = { 15 | 'fe80::23b':'fc00::3:0', 16 | 'fe80::24b':'fc00::4:0', 17 | 'fe80::35b':'fc00::5:0', 18 | 'fe80::36b':'fc00::6:0', 19 | } 20 | 21 | PID = "/tmp/seg6_oam_{}.pid" 22 | sid, iface = None, None 23 | 24 | def ip_str_to_ct(s): 25 | return (ct.c_ubyte * 16).from_buffer_copy(socket.inet_pton(socket.AF_INET6, s)) 26 | 27 | def install_rt(bpf_file): 28 | b = BPF(src_file=bpf_file) 29 | fn = b.load_func("SEG6_OAM", 19) # TODO 30 | 31 | fds = [] 32 | fds.append(b["link_local_table"].map_fd) 33 | 34 | ipr = IPRoute() 35 | idx = ipr.link_lookup(ifname=iface)[0] 36 | 37 | encap = {'type':'seg6local', 'action':'bpf', 'bpf':{'fd':fn.fd, 'name':fn.name}} 38 | ipr.route("add", dst=sid, oif=idx, encap=encap) 39 | 40 | return b, fds 41 | 42 | def remove_rt(sig, fr): 43 | ipr = IPRoute() 44 | idx = ipr.link_lookup(ifname=iface)[0] 45 | ipr.route("del", dst=sid, oif=idx) 46 | sys.exit(0) 47 | 48 | def run_daemon(bpf): 49 | signal.signal(signal.SIGTERM, remove_rt) 50 | signal.signal(signal.SIGINT, remove_rt) 51 | 52 | for laddr, gaddr in LOCAL_GLOBAL_MAP.items(): 53 | _ = lambda x: socket.inet_pton(socket.AF_INET6, x) 54 | logger.info("{}:{}".format(laddr, gaddr)) 55 | bpf["link_local_table"][ip_str_to_ct(laddr)] = ip_str_to_ct(gaddr) 56 | 57 | while 1: 58 | bpf.kprobe_poll() 59 | sleep(0.01) # tune polling frequency here 60 | 61 | if len(sys.argv) < 3: 62 | print("Format: ./oam_ecmp.py SID DEV [ll-db]") 63 | sys.exit(1) 64 | 65 | sid,iface = sys.argv[1:3] 66 | bpf, fds = install_rt('oam_ecmp_bpf.c') 67 | rt_name = sid.replace('/','-') 68 | 69 | if len(sys.argv) >= 4: 70 | f = open(sys.argv[3], 'rb') 71 | LOCAL_GLOBAL_MAP = pickle.load(f) 72 | 73 | logger = logging.getLogger(__name__) 74 | logger.setLevel(logging.DEBUG) 75 | logger.propagate = False 76 | fh = logging.FileHandler("/tmp/seg6_oam_{}.log".format(rt_name), "a") 77 | fh.setLevel(logging.DEBUG) 78 | logger.addHandler(fh) 79 | fds.append(fh.stream.fileno()) 80 | formatter = logging.Formatter("%(asctime)s: [%(levelname)s] %(message)s", "%b %e %H:%M:%S") 81 | fh.setFormatter(formatter) 82 | 83 | logger.info(repr(LOCAL_GLOBAL_MAP)) 84 | 85 | daemon = Daemonize(app="seg6-oam", pid=PID.format(rt_name), action=lambda: run_daemon(bpf), 86 | keep_fds=fds, logger=logger) 87 | print("SRv6 OAM daemon forked to background.") 88 | 89 | daemon.start() 90 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/oam_ecmp_bpf.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | #include "libseg6.c" 3 | 4 | #define SR6_TLV_OAM_NH_REQ 100 5 | #define SR6_TLV_OAM_NH_REPLY 101 6 | #define MAX_NH 16 7 | 8 | BPF_HASH(link_local_table, struct ip6_addr_t, struct ip6_addr_t); 9 | 10 | struct oam_nh_request_t { 11 | uint8_t tlv_type; 12 | uint8_t len; 13 | uint16_t session_id; 14 | struct ip6_addr_t dst; 15 | } BPF_PACKET_HEADER; 16 | 17 | struct oam_nh_reply_t { 18 | uint8_t tlv_type; 19 | uint8_t len; 20 | uint8_t nb_nh; 21 | uint8_t reserved; 22 | struct ip6_addr_t nexthops[MAX_NH]; 23 | } BPF_PACKET_HEADER; 24 | 25 | int SEG6_OAM(struct __sk_buff *skb) { 26 | struct oam_nh_request_t tlv_req; 27 | struct oam_nh_reply_t tlv_reply; 28 | int ret; 29 | 30 | struct ip6_srh_t *srh = seg6_get_srh(skb); 31 | if (!srh) 32 | return BPF_DROP; 33 | 34 | struct ip6_t *ip = (void *)(long)skb->data; 35 | if ((void *)ip + sizeof(*ip) > (void *)(long)skb->data_end) 36 | return BPF_DROP; 37 | 38 | int cursor = seg6_find_tlv(skb, srh, SR6_TLV_OAM_NH_REQ, sizeof(tlv_req)); 39 | if (cursor < 0) // no OAM TLV found, nevermind 40 | return BPF_OK; 41 | if (bpf_skb_load_bytes(skb, cursor, &tlv_req, sizeof(tlv_req)) < 0) 42 | return BPF_DROP; // error 43 | 44 | memset(&tlv_reply.nexthops, 0, MAX_NH << 4); 45 | ret = bpf_ipv6_fib_multipath_nh(skb, &tlv_req.dst, 16, &tlv_reply.nexthops, MAX_NH << 4); 46 | if (ret < 0) 47 | return BPF_DROP; 48 | 49 | tlv_reply.nb_nh = ret; 50 | tlv_reply.reserved = 0; 51 | tlv_reply.tlv_type = SR6_TLV_OAM_NH_REPLY; 52 | tlv_reply.len = (tlv_reply.nb_nh << 4) + 2 * sizeof(uint8_t); 53 | 54 | // Convert potential link local addresses to global ones 55 | #pragma clang loop unroll(full) 56 | for (int i=0; i < MAX_NH; i++) { 57 | if (i >= tlv_reply.nb_nh) 58 | break; 59 | 60 | struct ip6_addr_t *addr = &tlv_reply.nexthops[i]; 61 | // check if addr is in fe80::/10 62 | /*if ((bpf_htonll(addr->hi) >> 56) == 0xfe && 63 | !((((bpf_htonll(addr->hi) >> 54) & 3) ^ 2))) {*/ 64 | struct ip6_addr_t *gaddr = link_local_table.lookup(addr); 65 | if (gaddr != NULL) 66 | *addr = *gaddr; 67 | //} 68 | } 69 | 70 | ret = seg6_add_tlv(skb, srh, -1, (struct sr6_tlv_t *)&tlv_reply, tlv_reply.len + 2); 71 | if (ret) 72 | return BPF_DROP; 73 | return BPF_OK; 74 | } 75 | 76 | char __license[] __section("license") = "GPL"; 77 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | 202 | static __attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb); 203 | #endif 204 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/segtrace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import socket, struct, queue, enum, random, sys, icmp 3 | import ctypes as ct 4 | 5 | ICMP_ECHO_REQ = 128 6 | ICMP_OAM_REQ = 100 7 | TRACERT_PORT = 33434 8 | RTHDR_TYPE = 4 9 | SR6_TLV_OAM_NH_REQ = 100 10 | SR6_TLV_OAM_NH_REPLY = 101 11 | SR6_TLV_PADDING = 4 12 | SRH_FLAG_OAM = 32 13 | TLV_OAM_RD = 1 14 | TRIES_PER_PROBE = 3 15 | 16 | # Build the GNU timeval struct (seconds, microseconds) 17 | TIMEOUT = struct.pack("ll", 1, 0) 18 | MAX_HOPS = 8 19 | 20 | nb_sends = 0 21 | 22 | class NodeType(enum.Enum): 23 | UNKNOWN = 0 24 | IPV6 = 1 # Regular IPv6 node 25 | SEG6 = 2 # SRv6 + OAM ECMP 26 | 27 | def __str__(self): 28 | if self.value == 1: 29 | return 'IP' 30 | elif self.value == 2: 31 | return 'SR' 32 | 33 | return 'UNKNOWN' 34 | 35 | class Node: 36 | type = NodeType.UNKNOWN 37 | addr = '' 38 | name = None 39 | error = False 40 | 41 | def __init__(self, type, addr=addr): 42 | self.type = type 43 | self.addr = addr 44 | 45 | try: 46 | self.name = socket.gethostbyaddr(addr)[0] 47 | except socket.error as e: 48 | self.name = None 49 | 50 | def __eq__(self, other): 51 | _ = lambda x: socket.inet_pton(socket.AF_INET6, x) 52 | if isinstance(other, str): 53 | if self.type == NodeType.UNKNOWN: 54 | return False 55 | return (_(self.addr) == _(other)) 56 | 57 | if self.type != other.type: 58 | return False 59 | 60 | return (_(self.addr) == _(other.addr)) 61 | 62 | def __str__(self): 63 | if self.type == NodeType.UNKNOWN: 64 | return "*" 65 | 66 | if self.name: 67 | return "{} ({} / {})".format(self.name, self.addr, str(self.type)) 68 | else: 69 | return "{} ({})".format(self.addr, str(self.type)) 70 | 71 | def __repr__(self): 72 | return "".format(self.__str__()) 73 | 74 | def build_srh(dst, segments): 75 | segments = [dst] + segments[::-1] 76 | ct_segments = ct.c_ubyte * 16 * len(segments) 77 | 78 | class SRH(ct.Structure): 79 | _fields_ = [ ("nh", ct.c_uint8), 80 | ("hdr_len", ct.c_uint8), 81 | ("type", ct.c_uint8), 82 | ("segleft", ct.c_uint8), 83 | ("lastentry", ct.c_uint8), 84 | ("flags", ct.c_ubyte), 85 | ("tag", ct.c_ushort), 86 | ("segments", ct_segments) ] 87 | 88 | srh = SRH(type=RTHDR_TYPE, segleft=len(segments)-1, lastentry=len(segments)-1) 89 | srh.hdr_len = (len(bytes(srh)) >> 3) - 1 90 | srh.segments = ct_segments.from_buffer_copy(b''.join([socket.inet_pton(socket.AF_INET6, s) for s in segments])) 91 | return srh 92 | 93 | 94 | def send_oam_probe(src, dst, target): 95 | oam_dst = socket.inet_pton(socket.AF_INET6, dst) # for the replier, regular SID -> OAM SID 96 | oam_dst = oam_dst[:-2] + b'\x00\x08' 97 | oam_dst = socket.inet_ntop(socket.AF_INET6, oam_dst) 98 | segments = [src, oam_dst] 99 | ct_segments = ct.c_ubyte * 16 * 2 100 | 101 | class SRH_OAM_REQ(ct.Structure): 102 | _fields_ = [ ("nh", ct.c_uint8), 103 | ("hdr_len", ct.c_uint8), 104 | ("type", ct.c_uint8), 105 | ("segleft", ct.c_uint8), 106 | ("lastentry", ct.c_uint8), 107 | ("flags", ct.c_ubyte), 108 | ("tag", ct.c_ushort), 109 | ("segments", ct_segments), 110 | ("tlv_oam_type", ct.c_uint8), 111 | ("tlv_oam_len", ct.c_uint8), 112 | ("tlv_oam_sessid", ct.c_ushort), 113 | ("tlv_oam_target", ct.c_ubyte * 16), 114 | ("tlv_pad_type", ct.c_uint8), 115 | ("tlv_pad_len", ct.c_uint8), 116 | ("tlv_pad", ct.c_ushort), 117 | ] 118 | 119 | srh = SRH_OAM_REQ(type=RTHDR_TYPE, segleft=len(segments)-1, lastentry=len(segments)-1, flags=SRH_FLAG_OAM, 120 | tlv_oam_type=SR6_TLV_OAM_NH_REQ, tlv_oam_len=18, 121 | tlv_pad_type=SR6_TLV_PADDING, tlv_pad_len=2, tlv_pad=0) 122 | srh.hdr_len = (len(bytes(srh)) >> 3) - 1 123 | srh.segments = ct_segments.from_buffer_copy(b''.join([socket.inet_pton(socket.AF_INET6, s) for s in segments])) 124 | #srh.segment2 = (ct.c_ubyte * 16).from_buffer_copy(socket.inet_pton(socket.AF_INET6, oam_dst)) 125 | srh.tlv_oam_target = (ct.c_ubyte * 16).from_buffer_copy(socket.inet_pton(socket.AF_INET6, target)) 126 | sessid = random.randrange(0, 65535) 127 | srh.tlv_oam_sessid = sessid 128 | 129 | sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 130 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, TIMEOUT) 131 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RTHDR, bytes(srh)) 132 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RECVRTHDR, 1) 133 | sock.bind((src, 4242)) 134 | 135 | global nb_sends 136 | try: 137 | sock.sendto(b"foobar", (src, 4242)) 138 | nb_sends += 1 139 | except OSError: 140 | return None 141 | 142 | tries = TRIES_PER_PROBE 143 | while tries > 0: 144 | try: 145 | msg, ancdata, flags, addr = sock.recvmsg(100, 512) 146 | for cmsg_level, cmsg_type, cmsg_data in ancdata: 147 | if cmsg_level == socket.IPPROTO_IPV6 and cmsg_type == socket.IPV6_RTHDR: 148 | try: 149 | return parse_oam_reply(cmsg_data, sessid) 150 | except ValueError: 151 | pass 152 | except socket.error as e: 153 | pass 154 | 155 | tries -= 1 156 | sock.close() 157 | 158 | #payload = struct.pack('!HBB', sessid, 0, 0) 159 | #icmp.send(src, segments[0], ICMP_OAM_REQ, 0, payload, srh=bytes(srh)) 160 | return None 161 | 162 | def parse_oam_reply(bare_reply, req_sessid): 163 | class SRH_OAM_Reply(ct.Structure): 164 | _fields_ = [ ("nh", ct.c_uint8), 165 | ("hdr_len", ct.c_uint8), 166 | ("type", ct.c_uint8), 167 | ("segleft", ct.c_uint8), 168 | ("lastentry", ct.c_uint8), 169 | ("flags", ct.c_ubyte), 170 | ("tag", ct.c_ushort), 171 | ("segments", ct.c_ubyte * 16 * 2), 172 | ("tlv_oam_type", ct.c_uint8), 173 | ("tlv_oam_len", ct.c_uint8), 174 | ("tlv_oam_sessid", ct.c_ushort), 175 | ("tlv_oam_target", ct.c_ubyte * 16), 176 | ("tlv_oam2_type", ct.c_uint8), 177 | ("tlv_oam2_len", ct.c_uint8), 178 | ("tlv_oam2_nh", ct.c_uint8), 179 | ("tlv_oam2_reserved", ct.c_uint8), 180 | # nexthops here ... 181 | ] 182 | 183 | if len(bare_reply) <= ct.sizeof(SRH_OAM_Reply): 184 | raise ValueError 185 | 186 | reply = SRH_OAM_Reply.from_buffer_copy(bare_reply) 187 | if reply.tlv_oam_sessid != req_sessid: 188 | raise ValueError 189 | 190 | if reply.tlv_oam2_type != SR6_TLV_OAM_NH_REPLY: 191 | raise ValueError 192 | 193 | if len(bare_reply) < ct.sizeof(SRH_OAM_Reply) + 16 * reply.tlv_oam2_nh: 194 | raise ValueError 195 | 196 | if reply.tlv_oam2_nh == 0: 197 | return [] 198 | 199 | hops = bare_reply[ct.sizeof(SRH_OAM_Reply):ct.sizeof(SRH_OAM_Reply) + 16 * reply.tlv_oam2_nh] 200 | hops = [hops[x:x+16] for x in range(0, len(hops), 16)] 201 | hops = list(map(lambda x: Node(NodeType.IPV6, socket.inet_ntop(socket.AF_INET6, x)), hops)) 202 | return hops 203 | 204 | def new_recv_icmp_sock(allowed=None): 205 | rcv_icmp = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) 206 | rcv_icmp.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, TIMEOUT) 207 | 208 | if allowed: 209 | # icmp6_filter is a bitmap, ICMP packets of type 1 are passing if the first bit is set to 0, etc.. 210 | icmp6_filter = [255]*32 # by default, block all 211 | for type in allowed: 212 | icmp6_filter[type >> 3] &= ~(1 << ((type) & 7)) 213 | 214 | # socket.ICMPV6_FILTER is not defined, but its value is 1 as of Linux 4.16 215 | rcv_icmp.setsockopt(socket.IPPROTO_ICMPV6, 1, bytes(icmp6_filter)) 216 | 217 | return rcv_icmp 218 | 219 | def send_udp_probe(src, dst, hops, srh, sport): 220 | sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 221 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_UNICAST_HOPS, hops) 222 | if srh: 223 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RTHDR, srh) 224 | 225 | sock.bind((src, sport)) 226 | sock.sendto(b"foo", (dst, 33434)) 227 | global nb_sends 228 | nb_sends += 1 229 | sock.close() 230 | 231 | def segtrace(src, target): 232 | paths = queue.Queue() 233 | paths.put([]) 234 | final_paths = [] 235 | 236 | while not paths.empty(): # unfinished paths 237 | path = paths.get() 238 | nexthops = [] 239 | segments = [n.addr for n in path if n.type != NodeType.UNKNOWN] 240 | 241 | # Sending SRv6 OAM probes 242 | if len(path) > 0 and path[-1].type != NodeType.UNKNOWN: 243 | ecmp_hops = send_oam_probe(src, path[-1].addr, target) 244 | if ecmp_hops != None: 245 | path[-1].type = NodeType.SEG6 246 | nexthops = ecmp_hops 247 | 248 | # If the next hops are still not discovered, sending UDP probes 249 | if not nexthops: 250 | tries = TRIES_PER_PROBE 251 | else: 252 | tries = 0 253 | 254 | sock_recv= new_recv_icmp_sock(allowed=(1,3,129)) 255 | while tries > 0: 256 | send_udp_probe(src, target, len(path) + 1, \ 257 | build_srh(target, segments) if segments else None, 33434 + TRIES_PER_PROBE - tries) 258 | #icmp.send(src, target, ICMP_ECHO_REQ, 0, b"\x42\x42\x00\x01", hops=len(path) + 1, \ 259 | # srh=build_srh(target, segments) if segments else None) 260 | try: 261 | reply, replier = sock_recv.recvfrom(512) 262 | new_nh = Node(NodeType.IPV6, replier[0]) 263 | if new_nh not in nexthops: 264 | nexthops.append(new_nh) 265 | except socket.error as e: 266 | pass 267 | 268 | tries -= 1 269 | sock_recv.close() 270 | 271 | if not nexthops: # if still no data, we put it as unknown and keep going 272 | nexthops = [Node(NodeType.UNKNOWN)] 273 | 274 | for node in nexthops: 275 | new_path = path + [node] 276 | if node == target or len(new_path) >= MAX_HOPS: 277 | final_paths.append(new_path) 278 | else: 279 | paths.put(new_path) 280 | 281 | l = None 282 | for p in final_paths: 283 | if l != None and l != len(p): 284 | print("FAIL !") 285 | l = len(p) 286 | # print("\n -> ".join(map(str, p))) 287 | # print("") 288 | print("{},{},{},{},{}".format(_src,_dst,len(final_paths),nb_sends,l)) 289 | 290 | if __name__ == "__main__": 291 | src,dst = None, None 292 | if len(sys.argv) >= 3: 293 | _src, _dst = sys.argv[1:3] 294 | try: 295 | socket.inet_pton(socket.AF_INET6, _src) 296 | socket.inet_pton(socket.AF_INET6, _dst) 297 | src, dst = _src, _dst 298 | except: 299 | pass 300 | 301 | if not src or not dst: 302 | print("Usage: segtrace.py bindaddr target") 303 | sys.exit(1) 304 | 305 | segtrace(src, dst) 306 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/simulation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NB_NODES=10 3 | NB_LINKS=11 4 | 5 | cleanup() 6 | { 7 | if [ "$?" = "0" ]; then 8 | echo "segtrace [PASS]"; 9 | else 10 | echo "segtrace [FAILED]"; 11 | fi 12 | 13 | set +e 14 | pkill -F /tmp/seg6_oam_fc00::2:0008-128.pid 15 | pkill -F /tmp/seg6_oam_fc00::3:0008-128.pid 16 | for i in {1..11} 17 | do 18 | ip netns del ns${i} 2> /dev/null 19 | done 20 | } 21 | 22 | 23 | # set_link(link, node1, node2) 24 | set_link() 25 | { 26 | ip link set veth${1}a netns ns${2} 27 | ip link set veth${1}b netns ns${3} 28 | ip netns exec ns${2} ip link set dev veth${1}a up 29 | ip netns exec ns${3} ip link set dev veth${1}b up 30 | 31 | ip netns exec ns${2} ip -6 addr add fe80::${2}${3}a/16 scope link dev veth${1}a 32 | ip netns exec ns${2} ip -6 route add fe80::${2}${3}b scope link dev veth${1}a 33 | 34 | ip netns exec ns${3} ip -6 addr add fe80::${2}${3}b/16 scope link dev veth${1}b 35 | ip netns exec ns${3} ip -6 route add fe80::${2}${3}a scope link dev veth${1}b 36 | echo "Link #$1 created between nodes $2 and $3" 37 | } 38 | 39 | set -e 40 | trap cleanup 0 2 3 6 9 41 | 42 | for i in {1..10} 43 | do 44 | ip netns add ns${i} 45 | ip netns exec ns${i} ip link set dev lo up 46 | ip netns exec ns${i} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 47 | ip netns exec ns${i} sysctl net.ipv6.conf.all.seg6_enabled=1 > /dev/null 48 | ip netns exec ns${i} sysctl net.ipv6.conf.default.seg6_enabled=1 > /dev/null 49 | ip netns exec ns${i} sysctl net.ipv6.conf.lo.seg6_enabled=1 > /dev/null 50 | echo "NS #$i created" 51 | done 52 | 53 | for i in {1..11} 54 | do 55 | ip link add veth${i}a type veth peer name veth${i}b 56 | done 57 | 58 | set_link 1 1 2 59 | set_link 2 2 4 60 | set_link 3 4 7 61 | set_link 4 7 9 62 | set_link 5 9 10 63 | set_link 6 2 3 64 | set_link 7 3 5 65 | set_link 8 3 6 66 | set_link 9 5 8 67 | set_link 10 6 8 68 | set_link 11 8 10 69 | 70 | 71 | ip netns exec ns1 ip -6 addr add fc00::1:0000/16 dev veth1a 72 | ip netns exec ns2 ip -6 addr add fc00::2:0000/16 dev veth1b 73 | #ip netns exec ns2 ip -6 addr add fc00::2:0008/16 dev veth1b 74 | ip netns exec ns3 ip -6 addr add fc00::3:0000/16 dev veth6b 75 | ip netns exec ns4 ip -6 addr add fc00::4:0000/16 dev veth2b 76 | ip netns exec ns5 ip -6 addr add fc00::5:0000/16 dev veth7b 77 | ip netns exec ns6 ip -6 addr add fc00::6:0000/16 dev veth8b 78 | ip netns exec ns7 ip -6 addr add fc00::7:0000/16 dev veth3b 79 | ip netns exec ns8 ip -6 addr add fc00::8:0000/16 dev veth9b 80 | ip netns exec ns9 ip -6 addr add fc00::9:0000/16 dev veth4b 81 | ip netns exec ns10 ip -6 addr add fc00::10:0000/16 dev veth5b 82 | 83 | # Poor's man OSPF ... 84 | 85 | ip netns exec ns1 ip -6 route add fc00:0000::/32 dev veth1a via fe80::12b 86 | ip netns exec ns2 ip -6 route add fc00::10:0000 dev veth2a via fe80::24b 87 | ip netns exec ns4 ip -6 route add fc00:0000::/32 dev veth3a via fe80::47b 88 | ip netns exec ns7 ip -6 route add fc00:0000::/32 dev veth4a via fe80::79b 89 | ip netns exec ns9 ip -6 route add fc00:0000::/32 dev veth5a via fe80::910b 90 | 91 | ip netns exec ns2 ip -6 route add fc00::4:0000 dev veth2a via fe80::24b 92 | ip netns exec ns2 ip -6 route add fc00::7:0000 dev veth2a via fe80::24b 93 | ip netns exec ns2 ip -6 route add fc00::9:0000 dev veth2a via fe80::24b 94 | 95 | ip netns exec ns10 ip -6 route add fc00::1:0000 dev veth5b via fe80::910a 96 | ip netns exec ns9 ip -6 route add fc00::1:0000 dev veth4b via fe80::79a 97 | ip netns exec ns7 ip -6 route add fc00::1:0000 dev veth3b via fe80::47a 98 | ip netns exec ns4 ip -6 route add fc00::1:0000 dev veth2b via fe80::24a 99 | ip netns exec ns2 ip -6 route add fc00::1:0000 dev veth1b via fe80::12a 100 | 101 | 102 | # ECMP routes 103 | ip netns exec ns2 ip -6 route add fc00:0000::/32 dev veth6a via fe80::23b 104 | ip netns exec ns2 ip -6 route append fc00::10:0000 dev veth6a via fe80::23b 105 | ip netns exec ns3 ip -6 route add fc00::5:0000 dev veth7a via fe80::35b 106 | ip netns exec ns3 ip -6 route add fc00::6:0000 dev veth8a via fe80::36b 107 | ip netns exec ns3 ip -6 route add fc00:0000::/32 dev veth7a via fe80::35b 108 | ip netns exec ns3 ip -6 route add fc00::10:0000 dev veth7a via fe80::35b 109 | ip netns exec ns3 ip -6 route append fc00::10:0000 dev veth8a via fe80::36b 110 | 111 | ip netns exec ns5 ip -6 route add fc00::10:0000 dev veth9a via fe80::58b 112 | ip netns exec ns5 ip -6 route add fc00::8:0000/112 dev veth9a via fe80::58b 113 | ip netns exec ns6 ip -6 route add fc00::8:0000 dev veth10a via fe80::68b 114 | ip netns exec ns6 ip -6 route add fc00::10:0000 dev veth10a via fe80::68b 115 | ip netns exec ns8 ip -6 route add fc00::10:0000 dev veth11a via fe80::810b 116 | 117 | ip netns exec ns3 ip -6 route add fc00::1:0000 dev veth6b via fe80::23a 118 | ip netns exec ns5 ip -6 route add fc00::1:0000 dev veth7b via fe80::35a 119 | ip netns exec ns6 ip -6 route add fc00::1:0000 dev veth8b via fe80::36a 120 | ip netns exec ns8 ip -6 route add fc00::1:0000 dev veth9b via fe80::58a 121 | 122 | ip netns exec ns2 ip -6 route 123 | 124 | #ip netns exec ns1 sysctl net.ipv6.conf.lo.seg6_enabled=1 > /dev/null 125 | #ip netns exec ns1 sysctl net.ipv6.conf.veth1a.seg6_enabled=1 > /dev/null 126 | 127 | sleep 2 128 | 129 | # "unit tests": making sure fc00::1:0000 can communicate with all other nodes 130 | for i in {2..10} 131 | do 132 | echo "ip netns exec ns1 ping -I fc00::1:0000 fc00::${i}:0000 -c 1 > /dev/null" 133 | #ip netns exec ns1 ping -6 -I fc00::1:0000 fc00::${i}:0000 -c 1 134 | done 135 | echo "Network launched!" 136 | 137 | #ip netns exec ns1 traceroute -6 -q 10 -s fc00::1:0000 fc00::10:0000 138 | #ip netns exec ns1 ping -I fc00::1:0000 fc00::2:0008 -c 1 139 | ip netns exec ns1 traceroute -6 -s fc00::1:0000 fc00::10:0000 140 | 141 | ip netns exec ns1 tcpdump -i veth1a -w segtrace.pcap & 142 | #ip netns exec ns2 ./oam_ecmp.py fc00::2:0008/128 veth1b 143 | #ip netns exec ns3 ./oam_ecmp.py fc00::3:0008/128 veth6b 144 | 145 | ip netns exec ns1 ./segtrace.py fc00::1:0000 fc00::10:0000 146 | 147 | exit 0 148 | -------------------------------------------------------------------------------- /use-cases/OAMP-segtrace/tests.seg: -------------------------------------------------------------------------------- 1 | `./oam_ecmp.py fd00::beef/128 dum0` 2 | 3 | `ip -6 route add dead:beef::8 nexthop via fc00::7 dev dum0` 4 | `ip -6 route add dead:beef::42 nexthop via fc00::0 dev dum0 nexthop via fe80::23b dev dum0 nexthop via fc00::2 dev dum0` 5 | `ip -6 route` 6 | `sleep 1` 7 | 8 | # TLV (2 bytes) | OAM req type (1 byte) | OAM special parameters (1 byte) | IPv6 addr (16 bytes) 9 | # URO 20 bytes 10 | 11 | > fc00::49 -> fd00::beef / [baba::1, fc00::1337, +fd00::beef, fc00::49] {Type:100 Value: 2a2adeadbeef000000000000000000000008} 12 | < fc00::49 -> fc00::1337 / [baba::1, +fc00::1337, fd00::beef, fc00::49] {Type:100 Value: 2a2adeadbeef000000000000000000000008} 13 | 14 | > fc00::49 -> fd00::beef / [baba::1, fc00::1337, +fd00::beef, fc00::49] {Type:100 Value: 2a2adeadbeef000000000000000000000042} 15 | < fc00::49 -> fc00::1337 / [baba::1, +fc00::1337, fd00::beef, fc00::49] {Type:100 Value: 2a2adeadbeef000000000000000000000042} 16 | 17 | # not in routing table 18 | > fc00::49 -> fd00::beef / [baba::1, fc00::1337, +fd00::beef, fc00::49] {Type:100 Value: 2a2adeadbeef000000000000000000000004} 19 | < fc00::49 -> fc00::1337 / [baba::1, +fc00::1337, fd00::beef, fc00::49] {Type:100 Value: 2a2adeadbeef000000000000000000000004} 20 | 21 | 22 | `sleep 1` 23 | `pkill -F /tmp/seg6_oam_fd00::beef-128.pid` 24 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | LLC = llc 3 | 4 | all: bpf tools 5 | 6 | tools: 7 | clang dm_injector_usr.c -o dm_injector_usr 8 | 9 | bpf: 10 | $(CC) -O2 -emit-llvm -c dm_injector_bpf.c -o - | $(LLC) -march=bpf -filetype=obj -o dm_injector_bpf.o 11 | 12 | .PHONY: tools 13 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/bpf_seg6/all.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bpf_api.h" 6 | //#include "proto.h" 7 | 8 | /* Packet parsing state machine helpers. */ 9 | #define cursor_advance(_cursor, _len) \ 10 | ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) 11 | 12 | #define SR6_FLAG_PROTECTED (1 << 6) 13 | #define SR6_FLAG_OAM (1 << 5) 14 | #define SR6_FLAG_ALERT (1 << 4) 15 | #define SR6_FLAG_HMAC (1 << 3) 16 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/bpf_seg6/bpf_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_API__ 2 | #define __BPF_API__ 3 | 4 | /* Note: 5 | * 6 | * This file can be included into eBPF kernel programs. It contains 7 | * a couple of useful helper functions, map/section ABI (bpf_elf.h), 8 | * misc macros and some eBPF specific LLVM built-ins. 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | //#include 15 | #include "bpf.h" 16 | #include "proto.h" 17 | #include 18 | 19 | #include 20 | 21 | #include "bpf_elf.h" 22 | 23 | /** Misc macros. */ 24 | 25 | #ifndef __stringify 26 | # define __stringify(X) #X 27 | #endif 28 | 29 | #ifndef __maybe_unused 30 | # define __maybe_unused __attribute__((__unused__)) 31 | #endif 32 | 33 | #ifndef offsetof 34 | # define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) 35 | #endif 36 | 37 | #ifndef likely 38 | # define likely(X) __builtin_expect(!!(X), 1) 39 | #endif 40 | 41 | #ifndef unlikely 42 | # define unlikely(X) __builtin_expect(!!(X), 0) 43 | #endif 44 | 45 | #ifndef htons 46 | # define htons(X) __constant_htons((X)) 47 | #endif 48 | 49 | #ifndef ntohs 50 | # define ntohs(X) __constant_ntohs((X)) 51 | #endif 52 | 53 | #ifndef htonl 54 | # define htonl(X) __constant_htonl((X)) 55 | #endif 56 | 57 | #ifndef ntohl 58 | # define ntohl(X) __constant_ntohl((X)) 59 | #endif 60 | 61 | #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 62 | #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 63 | /* From https://stackoverflow.com/a/28592202 */ 64 | 65 | #ifndef __inline__ 66 | # define __inline__ __attribute__((always_inline)) 67 | #endif 68 | 69 | /** Section helper macros. */ 70 | 71 | #ifndef __section 72 | # define __section(NAME) \ 73 | __attribute__((section(NAME), used)) 74 | #endif 75 | 76 | #ifndef __section_tail 77 | # define __section_tail(ID, KEY) \ 78 | __section(__stringify(ID) "/" __stringify(KEY)) 79 | #endif 80 | 81 | #ifndef __section_xdp_entry 82 | # define __section_xdp_entry \ 83 | __section(ELF_SECTION_PROG) 84 | #endif 85 | 86 | #ifndef __section_cls_entry 87 | # define __section_cls_entry \ 88 | __section(ELF_SECTION_CLASSIFIER) 89 | #endif 90 | 91 | #ifndef __section_act_entry 92 | # define __section_act_entry \ 93 | __section(ELF_SECTION_ACTION) 94 | #endif 95 | 96 | #ifndef __section_lwt_entry 97 | # define __section_lwt_entry \ 98 | __section(ELF_SECTION_PROG) 99 | #endif 100 | 101 | #ifndef __section_license 102 | # define __section_license \ 103 | __section(ELF_SECTION_LICENSE) 104 | #endif 105 | 106 | #ifndef __section_maps 107 | # define __section_maps \ 108 | __section(ELF_SECTION_MAPS) 109 | #endif 110 | 111 | /** Declaration helper macros. */ 112 | 113 | #ifndef BPF_LICENSE 114 | # define BPF_LICENSE(NAME) \ 115 | char ____license[] __section_license = NAME 116 | #endif 117 | 118 | /** Classifier helper */ 119 | 120 | #ifndef BPF_H_DEFAULT 121 | # define BPF_H_DEFAULT -1 122 | #endif 123 | 124 | /** BPF helper functions for tc. Individual flags are in linux/bpf.h */ 125 | 126 | #ifndef __BPF_FUNC 127 | # define __BPF_FUNC(NAME, ...) \ 128 | (* NAME)(__VA_ARGS__) __maybe_unused 129 | #endif 130 | 131 | #ifndef BPF_FUNC 132 | # define BPF_FUNC(NAME, ...) \ 133 | __BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME 134 | #endif 135 | 136 | /* Map access/manipulation */ 137 | static void *BPF_FUNC(map_lookup_elem, void *map, const void *key); 138 | static int BPF_FUNC(map_update_elem, void *map, const void *key, 139 | const void *value, uint32_t flags); 140 | static int BPF_FUNC(map_delete_elem, void *map, const void *key); 141 | 142 | /* Time access */ 143 | static uint64_t BPF_FUNC(ktime_get_ns); 144 | 145 | /* Debugging */ 146 | 147 | /* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless 148 | * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved. 149 | * It would require ____fmt to be made const, which generates a reloc 150 | * entry (non-map). 151 | */ 152 | static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...); 153 | 154 | #ifndef printt 155 | # define printt(fmt, ...) \ 156 | ({ \ 157 | char ____fmt[] = fmt; \ 158 | trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ 159 | }) 160 | #endif 161 | 162 | /* Random numbers */ 163 | static uint32_t BPF_FUNC(get_prandom_u32); 164 | 165 | /* Tail calls */ 166 | static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map, 167 | uint32_t index); 168 | 169 | /* System helpers */ 170 | static uint32_t BPF_FUNC(get_smp_processor_id); 171 | static uint32_t BPF_FUNC(get_numa_node_id); 172 | 173 | /* Packet misc meta data */ 174 | static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb); 175 | static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index); 176 | 177 | static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb); 178 | static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb); 179 | static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb); 180 | 181 | /* Packet redirection */ 182 | static int BPF_FUNC(redirect, int ifindex, uint32_t flags); 183 | static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex, 184 | uint32_t flags); 185 | 186 | /* Packet manipulation */ 187 | static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off, 188 | void *to, uint32_t len); 189 | static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off, 190 | const void *from, uint32_t len, uint32_t flags); 191 | 192 | static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, 193 | uint32_t from, uint32_t to, uint32_t flags); 194 | static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, 195 | uint32_t from, uint32_t to, uint32_t flags); 196 | static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size, 197 | const void *to, uint32_t to_size, uint32_t seed); 198 | static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum); 199 | 200 | static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type); 201 | static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto, 202 | uint32_t flags); 203 | static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen, 204 | uint32_t flags); 205 | 206 | static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len); 207 | 208 | /* Event notification */ 209 | static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map, 210 | uint64_t index, const void *data, uint32_t size) = 211 | (void *) BPF_FUNC_perf_event_output; 212 | 213 | /* Packet vlan encap/decap */ 214 | static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, 215 | uint16_t vlan_tci); 216 | static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb); 217 | 218 | /* Packet tunnel encap/decap */ 219 | static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb, 220 | struct bpf_tunnel_key *to, uint32_t size, uint32_t flags); 221 | static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, 222 | const struct bpf_tunnel_key *from, uint32_t size, 223 | uint32_t flags); 224 | 225 | static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb, 226 | void *to, uint32_t size); 227 | static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb, 228 | const void *from, uint32_t size); 229 | 230 | static int BPF_FUNC(lwt_push_encap, struct __sk_buff *skb, uint32_t type, void *hdr, uint32_t len); 231 | static int BPF_FUNC(lwt_seg6_store_bytes, struct __sk_buff *skb, uint32_t offset, const void *from, uint32_t len); 232 | static int BPF_FUNC(lwt_seg6_action, struct __sk_buff *skb, uint32_t action, void *param, uint32_t param_len); 233 | static int BPF_FUNC(lwt_seg6_adjust_srh, struct __sk_buff *skb, uint32_t offset, int32_t len); 234 | static uint64_t BPF_FUNC(ktime_get_real_ns); 235 | 236 | /** LLVM built-ins, mem*() routines work for constant size */ 237 | 238 | #ifndef lock_xadd 239 | # define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) 240 | #endif 241 | 242 | #ifndef memset 243 | # define memset(s, c, n) __builtin_memset((s), (c), (n)) 244 | #endif 245 | 246 | #ifndef memcpy 247 | # define memcpy(d, s, n) __builtin_memcpy((d), (s), (n)) 248 | #endif 249 | 250 | #ifndef memmove 251 | # define memmove(d, s, n) __builtin_memmove((d), (s), (n)) 252 | #endif 253 | 254 | /* FIXME: __builtin_memcmp() is not yet fully useable unless llvm bug 255 | * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also 256 | * this one would generate a reloc entry (non-map), otherwise. 257 | */ 258 | #if 0 259 | #ifndef memcmp 260 | # define memcmp(a, b, n) __builtin_memcmp((a), (b), (n)) 261 | #endif 262 | #endif 263 | 264 | unsigned long long load_byte(void *skb, unsigned long long off) 265 | asm ("llvm.bpf.load.byte"); 266 | 267 | unsigned long long load_half(void *skb, unsigned long long off) 268 | asm ("llvm.bpf.load.half"); 269 | 270 | unsigned long long load_word(void *skb, unsigned long long off) 271 | asm ("llvm.bpf.load.word"); 272 | 273 | #endif /* __BPF_API__ */ 274 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/bpf_seg6/bpf_elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_ELF__ 2 | #define __BPF_ELF__ 3 | 4 | #include 5 | 6 | /* Note: 7 | * 8 | * Below ELF section names and bpf_elf_map structure definition 9 | * are not (!) kernel ABI. It's rather a "contract" between the 10 | * application and the BPF loader in tc. For compatibility, the 11 | * section names should stay as-is. Introduction of aliases, if 12 | * needed, are a possibility, though. 13 | */ 14 | 15 | /* ELF section names, etc */ 16 | #define ELF_SECTION_LICENSE "license" 17 | #define ELF_SECTION_MAPS "maps" 18 | #define ELF_SECTION_PROG "prog" 19 | #define ELF_SECTION_CLASSIFIER "classifier" 20 | #define ELF_SECTION_ACTION "action" 21 | 22 | #define ELF_MAX_MAPS 64 23 | #define ELF_MAX_LICENSE_LEN 128 24 | 25 | /* Object pinning settings */ 26 | #define PIN_NONE 0 27 | #define PIN_OBJECT_NS 1 28 | #define PIN_GLOBAL_NS 2 29 | 30 | /* ELF map definition */ 31 | struct bpf_elf_map { 32 | __u32 type; 33 | __u32 size_key; 34 | __u32 size_value; 35 | __u32 max_elem; 36 | __u32 flags; 37 | __u32 id; 38 | __u32 pinning; 39 | }; 40 | 41 | #endif /* __BPF_ELF__ */ 42 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/bpf_seg6/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/dm_injector_bpf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bpf_seg6/all.h" 3 | 4 | struct bpf_elf_map __section_maps powd_inj_sids = { 5 | .type = BPF_MAP_TYPE_ARRAY, 6 | .id = 0, 7 | .size_key = sizeof(uint32_t), 8 | .size_value = sizeof(struct ip6_addr_t), 9 | .max_elem = 2, 10 | .pinning = PIN_GLOBAL_NS, 11 | }; 12 | 13 | struct bpf_elf_map __section_maps powd_inj_freq_dport = { 14 | .type = BPF_MAP_TYPE_ARRAY, 15 | .id = 1, 16 | .size_key = sizeof(uint32_t), 17 | .size_value = sizeof(uint64_t), 18 | .max_elem = 2, 19 | .pinning = PIN_GLOBAL_NS, 20 | }; 21 | 22 | struct bpf_elf_map __section_maps powd_inj_cnt = { 23 | .type = BPF_MAP_TYPE_ARRAY, 24 | .id = 0, 25 | .size_key = sizeof(uint32_t), 26 | .size_value = sizeof(uint64_t), 27 | .max_elem = 1, 28 | .pinning = PIN_OBJECT_NS, 29 | }; 30 | 31 | struct timestamp_ieee1588_v2 { 32 | uint32_t tv_sec; 33 | uint32_t tv_nsec; 34 | }; 35 | 36 | struct sr6_tlv_dm_t { 37 | unsigned char type; // value TBA by IANA, use NSH+1 38 | unsigned char len; 39 | unsigned short reserved; 40 | unsigned char version:4; // 1 41 | unsigned char flags:4; // R|T|0|0, R: Query(0),Response(1), T: if tc class, set to 1 42 | unsigned char cc; 43 | /* For a Query: 0x0 in-band response, 0x1 out of band, 0x2: no response 44 | * For a response: 0x1 success, 0x10-0xFF: errors */ 45 | unsigned short reserved2; 46 | unsigned char qtf:4; /* timestamp formats */ 47 | unsigned char rtf:4; 48 | unsigned char rtpf:4; 49 | unsigned int reserved3:20; 50 | unsigned int session_id:24; /* set by the querier */ 51 | unsigned char tc; 52 | struct timestamp_ieee1588_v2 timestamps[4]; 53 | unsigned char sub_tlv[0]; // possible UDP Return Object (URO) 54 | } BPF_PACKET_HEADER; 55 | 56 | struct uro_v6 { 57 | unsigned char type; // URO = 131 58 | unsigned char len; // = 18 59 | unsigned short dport; 60 | struct ip6_addr_t daddr; 61 | } BPF_PACKET_HEADER; 62 | 63 | 64 | static __attribute__((always_inline)) 65 | int encap_srh_dm_tlv(struct __sk_buff *skb) 66 | { 67 | int k = 0; 68 | struct ip6_addr_t *sid_otp = map_lookup_elem(&powd_inj_sids, &k); 69 | k++; 70 | struct ip6_addr_t *sid_uro = map_lookup_elem(&powd_inj_sids, &k); 71 | uint16_t *uro_dport = (uint16_t *)map_lookup_elem(&powd_inj_freq_dport, &k); 72 | if (!sid_otp || !sid_uro || !uro_dport) 73 | return -EFAULT; 74 | 75 | char srh_buf[96]; 76 | memset(srh_buf, 0, sizeof(srh_buf)); 77 | struct ip6_srh_t *srh = (struct ip6_srh_t *)srh_buf; 78 | srh->type = 4; 79 | srh->hdrlen = 11; 80 | srh->segments_left = 0; 81 | srh->first_segment = 0; 82 | 83 | struct ip6_addr_t *seg0 = (struct ip6_addr_t *)((char*) srh + sizeof(*srh)); 84 | seg0->hi = sid_otp->hi; 85 | seg0->lo = sid_otp->lo; 86 | 87 | struct sr6_tlv_dm_t *dm = (struct sr6_tlv_dm_t *)((char*) seg0 + sizeof(struct ip6_addr_t)); 88 | dm->type = 7; 89 | dm->len = sizeof(*dm) - 2; 90 | dm->version = 1; 91 | dm->qtf = 3; 92 | dm->cc = 1; 93 | 94 | uint64_t tx_tstamp = ktime_get_real_ns(); 95 | dm->timestamps[0].tv_sec = htonl((uint32_t) (tx_tstamp / 1000000000)); 96 | dm->timestamps[0].tv_nsec = htonl((uint32_t) (tx_tstamp % 1000000000)); 97 | 98 | struct uro_v6 *uro = (struct uro_v6 *) ((char *)dm + sizeof(*dm)); 99 | uro->type = 131; 100 | uro->dport = *uro_dport; 101 | uro->len = sizeof(*uro) - 2; 102 | uro->daddr.hi = sid_uro->hi; 103 | uro->daddr.lo = sid_uro->lo; 104 | 105 | struct sr6_tlv *tlv_pad = (struct sr6_tlv *) ((char *)uro + sizeof(*uro)); 106 | tlv_pad->type = 4; 107 | tlv_pad->len = 2; 108 | 109 | return lwt_push_encap(skb, BPF_LWT_ENCAP_SEG6, (void *)srh_buf, sizeof(srh_buf)); 110 | } 111 | 112 | __section("main") 113 | int injector(struct __sk_buff *skb) 114 | { 115 | int k = 0; 116 | uint64_t *counter = map_lookup_elem(&powd_inj_cnt, &k); 117 | uint64_t *freq = map_lookup_elem(&powd_inj_freq_dport, &k); 118 | 119 | if (!counter || !freq) 120 | return BPF_OK; 121 | 122 | __sync_fetch_and_add(counter, 1); // atomic increment 123 | if (*counter >= *freq) { 124 | uint64_t zero = 0; 125 | map_update_elem(&powd_inj_cnt, &k, &zero, BPF_ANY); 126 | if (encap_srh_dm_tlv(skb)) { 127 | printt("drop\n"); 128 | return BPF_DROP; 129 | } 130 | 131 | return BPF_OK; 132 | } 133 | 134 | return BPF_OK; 135 | } 136 | 137 | char __license[] __section("license") = "GPL"; 138 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/dm_injector_usr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zashas/Thesis-SRv6-BPF/e9f9624ade3f94eb22cbfaffa050506692eaad06/use-cases/POWD-monitoring/dm_injector_usr -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/dm_injector_usr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int bpf(int cmd, union bpf_attr *attr, unsigned int size) 13 | { 14 | #ifdef __NR_bpf 15 | return syscall(__NR_bpf, cmd, attr, size); 16 | #else 17 | fprintf(stderr, "No bpf syscall, kernel headers too old?\n"); 18 | errno = ENOSYS; 19 | return -1; 20 | #endif 21 | } 22 | 23 | __u64 bpf_ptr_to_u64(const void *ptr) 24 | { 25 | return (__u64) (unsigned long) ptr; 26 | } 27 | 28 | int bpf_update_elem(int fd, void *key, void *value, uint64_t flags) 29 | { 30 | union bpf_attr attr = {}; 31 | attr.map_fd = fd; 32 | attr.key = bpf_ptr_to_u64(key); 33 | attr.value = bpf_ptr_to_u64(value);; 34 | attr.flags = flags; 35 | 36 | static int nb = 0; 37 | nb++; 38 | int ret = bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); 39 | if (ret < 0) { 40 | fprintf(stderr, "Map update #%d failed: %s\n", nb, strerror(errno)); 41 | } 42 | 43 | return ret; 44 | } 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | struct in6_addr sid_otp, sid_uro; 49 | uint64_t frequency, dport; 50 | 51 | if (argc != 5) { 52 | printf("Expected: %s SID-OTP FREQUENCY CONTROLLER-IP6 CONTROLLER-DPORT\n", argv[0]); 53 | return -1; 54 | } 55 | 56 | if (!inet_pton(AF_INET6, argv[1], &sid_otp) || !inet_pton(AF_INET6, argv[3], &sid_uro)) { 57 | printf("Error: SIDs and CONTROLLER-IP6 must be valid IPv6 addresses.\n"); 58 | printf("Expected: %s SID-OTP FREQUENCY CONTROLLER-IP6 CONTROLLER-DPORT\n", argv[0]); 59 | return -1; 60 | } 61 | 62 | frequency = strtoll(argv[2], NULL, 10); 63 | dport = strtoll(argv[4], NULL, 10); 64 | dport = htons((uint16_t) dport & 65535); 65 | if (frequency <= 0) { 66 | printf("Error: frequency must be a strictly positive number.\n"); 67 | printf("Expected: %s SID-OTP FREQUENCY CONTROLLER-IP6 CONTROLLER-DPORT\n", argv[0]); 68 | return -1; 69 | } 70 | 71 | if (dport <= 0 || dport >= 65536) { 72 | printf("Error: CONTROLLER-DPORT must be a number between 1 and 65535.\n"); 73 | printf("Expected: %s SID-OTP FREQUENCY CONTROLLER-IP6 CONTROLLER-DPORT\n", argv[0]); 74 | return -1; 75 | } 76 | 77 | union bpf_attr attr_obj = {}; 78 | int map_fd[2]; 79 | 80 | char *map_paths[] = { 81 | "/sys/fs/bpf/ip/globals/powd_inj_freq_dport", 82 | "/sys/fs/bpf/ip/globals/powd_inj_sids" 83 | }; 84 | 85 | for(int i=0; i < sizeof(map_fd)/sizeof(int); i++) { 86 | attr_obj.map_fd = 0; 87 | attr_obj.pathname = bpf_ptr_to_u64(map_paths[i]); 88 | map_fd[i] = bpf(BPF_OBJ_GET, &attr_obj, sizeof(attr_obj)); 89 | if (map_fd[i] <= 0) { 90 | fprintf(stderr, "Fetching map failed: %s\n", strerror(errno)); 91 | return -1; 92 | } 93 | } 94 | 95 | uint32_t key = 0; 96 | bpf_update_elem(map_fd[0], &key, &frequency, BPF_ANY); 97 | bpf_update_elem(map_fd[1], &key, &sid_otp, BPF_ANY); 98 | key++; 99 | bpf_update_elem(map_fd[0], &key, &dport, BPF_ANY); 100 | bpf_update_elem(map_fd[1], &key, &sid_uro, BPF_ANY); 101 | 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/end_otp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from bcc import BPF 4 | from pyroute2 import IPRoute 5 | import sys, logging, signal, socket, os, struct 6 | from daemonize import Daemonize 7 | import ctypes as ct 8 | from time import sleep 9 | 10 | socket.SO_TIMESTAMPING = 37 11 | socket.SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3) 12 | socket.SOF_TIMESTAMPING_SOFTWARE = (1<<4) 13 | 14 | dir_path = os.path.dirname(os.path.realpath(__file__)) 15 | PID = "/tmp/end_otp_{}.pid" 16 | sid, iface = None, None 17 | 18 | # For RX software timestamping to be done in kernel, at least on socket with 19 | # SOF_TIMESTAMPING_RX_SOFTWARE must be created (even without a bind or connect). 20 | def open_rx_tstamp_sock(): 21 | sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 22 | flags = socket.SOF_TIMESTAMPING_SOFTWARE | socket.SOF_TIMESTAMPING_RX_SOFTWARE 23 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_TIMESTAMPING, struct.pack('I', 24)) 24 | 25 | return sock 26 | 27 | def handle_oob_request(cpu, data, size): 28 | class OOBRequest(ct.Structure): 29 | _fields_ = [ ("tlv_dm", ct.c_ubyte * 48), 30 | ("uro_type", ct.c_ubyte), 31 | ("uro_len", ct.c_ubyte), 32 | ("uro_dport", ct.c_ushort), 33 | ("uro_daddr", ct.c_ubyte * 16), 34 | ("skb", ct.c_ubyte * (size - ct.sizeof(ct.c_ubyte * 68))) ] 35 | 36 | logger.info("got req"); 37 | req = ct.cast(data, ct.POINTER(OOBRequest)).contents 38 | uro_port = socket.ntohs(req.uro_dport) 39 | uro_ip = socket.inet_ntop(socket.AF_INET6, bytes(req.uro_daddr)) 40 | 41 | sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 42 | try: 43 | sock.connect((uro_ip, uro_port)) 44 | sock.send(bytes(req.tlv_dm)) 45 | sock.close() 46 | except Exception as e: 47 | logger.error("Could not sent out-of-band DM reply to ({}, {}): {}".format(uro_ip, uro_port, e)) 48 | 49 | def install_rt(bpf_file): 50 | b = BPF(src_file=bpf_file) 51 | fn = b.load_func("End_OTP", 19) # TODO 52 | 53 | fds = [] 54 | fds.append(b["oob_dm_requests"].map_fd) 55 | 56 | ipr = IPRoute() 57 | idx = ipr.link_lookup(ifname=iface)[0] 58 | 59 | encap = {'type':'seg6local', 'action':'bpf', 'bpf':{'fd':fn.fd, 'name':fn.name}} 60 | ipr.route("add", dst=sid, oif=idx, encap=encap) 61 | 62 | return b, fds 63 | 64 | def remove_rt(sig, fr): 65 | ipr = IPRoute() 66 | idx = ipr.link_lookup(ifname=iface)[0] 67 | ipr.route("del", dst=sid, oif=idx) 68 | sys.exit(0) 69 | 70 | def run_daemon(bpf): 71 | signal.signal(signal.SIGTERM, remove_rt) 72 | signal.signal(signal.SIGINT, remove_rt) 73 | sock = open_rx_tstamp_sock() # keep a local variable here, otherwise Python's GC will close the sock 74 | 75 | bpf["oob_dm_requests"].open_perf_buffer(handle_oob_request) 76 | 77 | while 1: 78 | bpf.kprobe_poll() 79 | sleep(0.01) # tune polling frequency here 80 | 81 | if len(sys.argv) < 3: 82 | print("Format: ./end_otp.py SID DEV") 83 | sys.exit(1) 84 | 85 | sid,iface = sys.argv[1:3] 86 | bpf, fds = install_rt(os.path.join(dir_path, 'end_otp_bpf.c')) 87 | rt_name = sid.replace('/','-') 88 | 89 | logger = logging.getLogger(__name__) 90 | logger.setLevel(logging.DEBUG) 91 | logger.propagate = False 92 | fh = logging.FileHandler("/tmp/end_otp_{}.log".format(rt_name), "a") 93 | fh.setLevel(logging.DEBUG) 94 | logger.addHandler(fh) 95 | fds.append(fh.stream.fileno()) 96 | formatter = logging.Formatter("%(asctime)s: %(message)s", 97 | "%b %e %H:%M:%S") 98 | fh.setFormatter(formatter) 99 | 100 | daemon = Daemonize(app="end_otp", pid=PID.format(rt_name), action=lambda: run_daemon(bpf), 101 | keep_fds=fds, logger=logger) 102 | 103 | print("End.OTP daemon forked to background.") 104 | daemon.start() 105 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/end_otp_bpf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libseg6.c" 3 | 4 | #define SR6_TLV_DM 7 5 | #define SR6_TLV_URO 131 6 | 7 | BPF_PERF_OUTPUT(oob_dm_requests); 8 | 9 | struct timestamp_ieee1588_v2 { 10 | uint32_t tv_sec; 11 | uint32_t tv_nsec; 12 | }; 13 | 14 | struct sr6_tlv_dm_t { 15 | unsigned char type; // value TBA by IANA, use NSH+1 16 | unsigned char len; 17 | unsigned short reserved; 18 | unsigned char version:4; // 1 19 | unsigned char flags:4; // R|T|0|0, R: Query(0),Response(1), T: if tc class, set to 1 20 | unsigned char cc; 21 | /* For a Query: 0x0 in-band response, 0x1 out of band, 0x2: no response 22 | * For a response: 0x1 success, 0x10-0xFF: errors */ 23 | unsigned short reserved2; 24 | unsigned char qtf:4; /* timestamp formats */ 25 | unsigned char rtf:4; 26 | unsigned char rtpf:4; 27 | unsigned int reserved3:20; 28 | unsigned int session_id:24; /* set by the querier */ 29 | unsigned char tc; 30 | struct timestamp_ieee1588_v2 timestamps[4]; 31 | unsigned char sub_tlv[0]; // possible UDP Return Object (URO) 32 | } BPF_PACKET_HEADER; 33 | 34 | struct uro_v6 { 35 | unsigned char type; // URO = 131 36 | unsigned char len; // = 18 37 | unsigned short dport; 38 | struct ip6_addr_t daddr; 39 | } BPF_PACKET_HEADER; 40 | 41 | struct oob_request { 42 | struct sr6_tlv_dm_t response; 43 | struct uro_v6 uro; 44 | }; 45 | 46 | int End_OTP(struct __sk_buff *skb) { 47 | struct ip6_srh_t *srh = seg6_get_srh(skb); 48 | if (!srh) 49 | return BPF_DROP; 50 | 51 | struct sr6_tlv_dm_t tlv; 52 | int cursor = seg6_find_tlv(skb, srh, SR6_TLV_DM, sizeof(tlv)); 53 | if (cursor < 0) 54 | return BPF_DROP; 55 | 56 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(tlv)) < 0) 57 | return BPF_DROP; 58 | 59 | unsigned char query_cc = tlv.cc; 60 | if (tlv.version != 1) { 61 | tlv.cc = 0x11; 62 | goto send; 63 | } else if (tlv.cc > 0x02) { 64 | tlv.cc = 0x12; 65 | goto send; 66 | } else if (tlv.flags & 8) { 67 | tlv.cc = 0x11; 68 | goto send; 69 | } else if (tlv.rtf != 0 && tlv.rtf != 3) { // Unsupported already set RTF type 70 | tlv.cc = 0x10; // Generic error 71 | goto send; 72 | } 73 | 74 | tlv.flags |= 8; // DM TLV becomes a response 75 | tlv.rtf = 3; 76 | 77 | uint64_t rx_tstamp = bpf_skb_get_tstamp(skb); 78 | tlv.timestamps[1].tv_sec = bpf_htonl((uint32_t) (rx_tstamp / 1000000000)); 79 | tlv.timestamps[1].tv_nsec = bpf_htonl((uint32_t) (rx_tstamp % 1000000000)); 80 | 81 | if (query_cc == 0x00) { // in case of a two-way delay measurement 82 | uint64_t tx_tstamp = bpf_ktime_get_real_ns(); 83 | tlv.timestamps[2].tv_sec = bpf_htonl((uint32_t) (tx_tstamp / 1000000000)); 84 | tlv.timestamps[2].tv_nsec = bpf_htonl((uint32_t) (tx_tstamp % 1000000000)); 85 | } 86 | 87 | send: 88 | if (query_cc == 0x00) { // in-band 89 | if (bpf_lwt_seg6_store_bytes(skb, cursor, &tlv, sizeof(tlv)) < 0) 90 | return BPF_DROP; 91 | 92 | return BPF_OK; 93 | } else if (query_cc == 0x01) { // out-of-band, sending to userspace daemon 94 | struct oob_request req; 95 | memcpy(&req.response, &tlv, sizeof(tlv)); 96 | 97 | cursor = seg6_find_tlv(skb, srh, SR6_TLV_URO, sizeof(req.uro)); 98 | if (cursor < 0) 99 | return BPF_DROP; 100 | 101 | if (bpf_skb_load_bytes(skb, cursor, &req.uro, sizeof(req.uro)) < 0) 102 | return BPF_DROP; 103 | 104 | oob_dm_requests.perf_submit_skb(skb, skb->len, &req, sizeof(req)); 105 | 106 | int table = 254; 107 | int err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_DT6, (void *)&table, sizeof(table)); 108 | if (err) 109 | return BPF_DROP; 110 | 111 | return BPF_REDIRECT; 112 | } else { 113 | return BPF_DROP; 114 | } 115 | } 116 | 117 | char __license[] __section("license") = "GPL"; 118 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/libseg6.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | 3 | __attribute__((always_inline)) 4 | struct ip6_srh_t *seg6_get_srh(struct __sk_buff *skb) 5 | { 6 | void *cursor, *data_end; 7 | struct ip6_srh_t *srh; 8 | struct ip6_t *ip; 9 | uint8_t *ipver; 10 | 11 | data_end = (void *)(long)skb->data_end; 12 | cursor = (void *)(long)skb->data; 13 | ipver = (uint8_t *)cursor; 14 | 15 | if ((void *)ipver + sizeof(*ipver) > data_end) 16 | return NULL; 17 | 18 | if ((*ipver >> 4) != 6) 19 | return NULL; 20 | 21 | ip = cursor_advance(cursor, sizeof(*ip)); 22 | if ((void *)ip + sizeof(*ip) > data_end) 23 | return NULL; 24 | 25 | if (ip->next_header != 43) 26 | return NULL; 27 | 28 | srh = cursor_advance(cursor, sizeof(*srh)); 29 | if ((void *)srh + sizeof(*srh) > data_end) 30 | return NULL; 31 | 32 | if (srh->type != 4) 33 | return NULL; 34 | 35 | return srh; 36 | } 37 | 38 | __attribute__((always_inline)) 39 | int __update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, 40 | uint32_t old_pad, uint32_t pad_off) 41 | { 42 | int err; 43 | 44 | if (new_pad != old_pad) { 45 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, 46 | (int) new_pad - (int) old_pad); 47 | if (err) 48 | return err; 49 | } 50 | 51 | if (new_pad > 0) { 52 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0}; 54 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; 55 | 56 | pad_tlv->type = SR6_TLV_PADDING; 57 | pad_tlv->len = new_pad - 2; 58 | 59 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, 60 | (void *)pad_tlv_buf, new_pad); 61 | if (err) 62 | return err; 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | __attribute__((always_inline)) 69 | int __is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, 70 | uint32_t *tlv_off, uint32_t *pad_size, 71 | uint32_t *pad_off) 72 | { 73 | uint32_t srh_off, cur_off; 74 | int offset_valid = 0; 75 | int err; 76 | 77 | srh_off = (char *)srh - (char *)(long)skb->data; 78 | // cur_off = end of segments, start of possible TLVs 79 | cur_off = srh_off + sizeof(*srh) + 80 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); 81 | 82 | *pad_off = 0; 83 | 84 | // we can only go as far as ~10 TLVs due to the BPF max stack size 85 | #pragma clang loop unroll(full) 86 | for (int i = 0; i < 10; i++) { 87 | struct sr6_tlv_t tlv; 88 | 89 | if (cur_off == *tlv_off) 90 | offset_valid = 1; 91 | 92 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) 93 | break; 94 | 95 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); 96 | if (err) 97 | return err; 98 | 99 | if (tlv.type == SR6_TLV_PADDING) { 100 | *pad_size = tlv.len + sizeof(tlv); 101 | *pad_off = cur_off; 102 | 103 | if (*tlv_off == srh_off) { 104 | *tlv_off = cur_off; 105 | offset_valid = 1; 106 | } 107 | break; 108 | 109 | } else if (tlv.type == SR6_TLV_HMAC) { 110 | break; 111 | } 112 | 113 | cur_off += sizeof(tlv) + tlv.len; 114 | } // we reached the padding or HMAC TLVs, or the end of the SRH 115 | 116 | if (*pad_off == 0) 117 | *pad_off = cur_off; 118 | 119 | if (*tlv_off == -1) 120 | *tlv_off = cur_off; 121 | else if (!offset_valid) 122 | return -EINVAL; 123 | 124 | return 0; 125 | } 126 | 127 | __attribute__((always_inline)) 128 | int seg6_add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, 129 | struct sr6_tlv_t *itlv, uint8_t tlv_size) 130 | { 131 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 132 | uint8_t len_remaining, new_pad; 133 | uint32_t pad_off = 0; 134 | uint32_t pad_size = 0; 135 | uint32_t partial_srh_len; 136 | int err; 137 | 138 | if (tlv_off != -1) 139 | tlv_off += srh_off; 140 | 141 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) 142 | return -EINVAL; 143 | 144 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 145 | if (err) 146 | return err; 147 | 148 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); 149 | if (err) 150 | return err; 151 | 152 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); 153 | if (err) 154 | return err; 155 | 156 | // the following can't be moved inside update_tlv_pad because the 157 | // bpf verifier has some issues with it 158 | pad_off += sizeof(*itlv) + itlv->len; 159 | partial_srh_len = pad_off - srh_off; 160 | len_remaining = partial_srh_len % 8; 161 | new_pad = 8 - len_remaining; 162 | 163 | if (new_pad == 1) // cannot pad for 1 byte only 164 | new_pad = 9; 165 | else if (new_pad == 8) 166 | new_pad = 0; 167 | 168 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 169 | } 170 | 171 | __attribute__((always_inline)) 172 | int seg6_delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, 173 | uint32_t tlv_off) 174 | { 175 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; 176 | uint8_t len_remaining, new_pad; 177 | uint32_t partial_srh_len; 178 | uint32_t pad_off = 0; 179 | uint32_t pad_size = 0; 180 | struct sr6_tlv_t tlv; 181 | int err; 182 | 183 | tlv_off += srh_off; 184 | 185 | err = __is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); 186 | if (err) 187 | return err; 188 | 189 | err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); 190 | if (err) 191 | return err; 192 | 193 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); 194 | if (err) 195 | return err; 196 | 197 | pad_off -= sizeof(tlv) + tlv.len; 198 | partial_srh_len = pad_off - srh_off; 199 | len_remaining = partial_srh_len % 8; 200 | new_pad = 8 - len_remaining; 201 | if (new_pad == 1) // cannot pad for 1 byte only 202 | new_pad = 9; 203 | else if (new_pad == 8) 204 | new_pad = 0; 205 | 206 | return __update_tlv_pad(skb, new_pad, pad_size, pad_off); 207 | } 208 | 209 | __attribute__((always_inline)) 210 | int seg6_find_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, unsigned char type, 211 | unsigned char len) 212 | { 213 | int srh_offset = (char *)srh - (char *)(long)skb->data; 214 | // initial cursor = end of segments, start of possible TLVs 215 | int cursor = srh_offset + sizeof(struct ip6_srh_t) + 216 | ((srh->first_segment + 1) << 4); 217 | 218 | #pragma clang loop unroll(full) 219 | for(int i=0; i < 10; i++) { // TODO limitation 220 | if (cursor >= srh_offset + ((srh->hdrlen + 1) << 3)) 221 | return -1; 222 | 223 | struct sr6_tlv_t tlv; 224 | if (bpf_skb_load_bytes(skb, cursor, &tlv, sizeof(struct sr6_tlv_t))) 225 | return -1; 226 | //bpf_trace_printk("TLV type=%d len=%d found at offset %d\n", tlv.type, tlv.len, cursor); 227 | 228 | if (tlv.type == type && tlv.len + sizeof(struct sr6_tlv_t) == len) 229 | return cursor; 230 | 231 | cursor += sizeof(tlv) + tlv.len; 232 | } 233 | return -1; 234 | } 235 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BCC_PROTO_H 18 | #define __BCC_PROTO_H 19 | 20 | //#include 21 | #include 22 | 23 | #define BPF_PACKET_HEADER __attribute__((packed)) //__attribute__((deprecated("packet"))) 24 | 25 | struct ethernet_t { 26 | unsigned long long dst:48; 27 | unsigned long long src:48; 28 | unsigned int type:16; 29 | } BPF_PACKET_HEADER; 30 | 31 | struct dot1q_t { 32 | unsigned short pri:3; 33 | unsigned short cfi:1; 34 | unsigned short vlanid:12; 35 | unsigned short type; 36 | } BPF_PACKET_HEADER; 37 | 38 | struct arp_t { 39 | unsigned short htype; 40 | unsigned short ptype; 41 | unsigned char hlen; 42 | unsigned char plen; 43 | unsigned short oper; 44 | unsigned long long sha:48; 45 | unsigned long long spa:32; 46 | unsigned long long tha:48; 47 | unsigned int tpa; 48 | } BPF_PACKET_HEADER; 49 | 50 | struct ip_t { 51 | unsigned char ver:4; // byte 0 52 | unsigned char hlen:4; 53 | unsigned char tos; 54 | unsigned short tlen; 55 | unsigned short identification; // byte 4 56 | unsigned short ffo_unused:1; 57 | unsigned short df:1; 58 | unsigned short mf:1; 59 | unsigned short foffset:13; 60 | unsigned char ttl; // byte 8 61 | unsigned char nextp; 62 | unsigned short hchecksum; 63 | unsigned int src; // byte 12 64 | unsigned int dst; // byte 16 65 | } BPF_PACKET_HEADER; 66 | 67 | struct icmp_t { 68 | unsigned char type; 69 | unsigned char code; 70 | unsigned short checksum; 71 | } BPF_PACKET_HEADER; 72 | 73 | struct ip6_t { 74 | unsigned int ver:4; 75 | unsigned int priority:8; 76 | unsigned int flow_label:20; 77 | unsigned short payload_len; 78 | unsigned char next_header; 79 | unsigned char hop_limit; 80 | unsigned long long src_hi; 81 | unsigned long long src_lo; 82 | unsigned long long dst_hi; 83 | unsigned long long dst_lo; 84 | } BPF_PACKET_HEADER; 85 | 86 | struct ip6_addr_t { 87 | unsigned long long hi; 88 | unsigned long long lo; 89 | } BPF_PACKET_HEADER; 90 | 91 | struct ip6_opt_t { 92 | unsigned char next_header; 93 | unsigned char ext_len; 94 | unsigned char pad[6]; 95 | } BPF_PACKET_HEADER; 96 | 97 | struct icmp6_t { 98 | unsigned char type; 99 | unsigned char code; 100 | unsigned short checksum; 101 | } BPF_PACKET_HEADER; 102 | 103 | struct udp_t { 104 | unsigned short sport; 105 | unsigned short dport; 106 | unsigned short length; 107 | unsigned short crc; 108 | } BPF_PACKET_HEADER; 109 | 110 | struct tcp_t { 111 | unsigned short src_port; // byte 0 112 | unsigned short dst_port; 113 | unsigned int seq_num; // byte 4 114 | unsigned int ack_num; // byte 8 115 | unsigned char offset:4; // byte 12 116 | unsigned char reserved:4; 117 | unsigned char flag_cwr:1; 118 | unsigned char flag_ece:1; 119 | unsigned char flag_urg:1; 120 | unsigned char flag_ack:1; 121 | unsigned char flag_psh:1; 122 | unsigned char flag_rst:1; 123 | unsigned char flag_syn:1; 124 | unsigned char flag_fin:1; 125 | unsigned short rcv_wnd; 126 | unsigned short cksum; // byte 16 127 | unsigned short urg_ptr; 128 | } BPF_PACKET_HEADER; 129 | 130 | struct vxlan_t { 131 | unsigned int rsv1:4; 132 | unsigned int iflag:1; 133 | unsigned int rsv2:3; 134 | unsigned int rsv3:24; 135 | unsigned int key:24; 136 | unsigned int rsv4:8; 137 | } BPF_PACKET_HEADER; 138 | 139 | struct vxlan_gbp_t { 140 | unsigned int gflag:1; 141 | unsigned int rsv1:3; 142 | unsigned int iflag:1; 143 | unsigned int rsv2:3; 144 | unsigned int rsv3:1; 145 | unsigned int dflag:1; 146 | unsigned int rsv4:1; 147 | unsigned int aflag:1; 148 | unsigned int rsv5:3; 149 | unsigned int tag:16; 150 | unsigned int key:24; 151 | unsigned int rsv6:8; 152 | } BPF_PACKET_HEADER; 153 | 154 | struct ip6_srh_t { 155 | unsigned char nexthdr; 156 | unsigned char hdrlen; 157 | unsigned char type; 158 | unsigned char segments_left; 159 | unsigned char first_segment; 160 | unsigned char flags; 161 | unsigned short tag; 162 | 163 | struct ip6_addr_t segments[0]; 164 | } BPF_PACKET_HEADER; 165 | 166 | 167 | struct sr6_tlv_t { 168 | unsigned char type; 169 | unsigned char len; 170 | unsigned char value[0]; 171 | } BPF_PACKET_HEADER; 172 | 173 | struct sr6_tlv_128 { 174 | unsigned char type; 175 | unsigned char len; 176 | unsigned char reserved; 177 | unsigned char flags; 178 | unsigned char value[16]; 179 | } BPF_PACKET_HEADER; 180 | 181 | struct sr6_tlv_hmac { 182 | unsigned char type; 183 | unsigned char len; 184 | unsigned short reserved; 185 | unsigned int keyid; 186 | unsigned char hmac[32]; 187 | } BPF_PACKET_HEADER; 188 | 189 | #define SR6_FLAG_PROTECTED (1 << 6) 190 | #define SR6_FLAG_OAM (1 << 5) 191 | #define SR6_FLAG_ALERT (1 << 4) 192 | #define SR6_FLAG_HMAC (1 << 3) 193 | 194 | #define SR6_TLV_INGRESS 1 195 | #define SR6_TLV_EGRESS 2 196 | #define SR6_TLV_OPAQ 3 197 | #define SR6_TLV_PADDING 4 198 | #define SR6_TLV_HMAC 5 199 | #define SR6_TLV_NSH 6 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/tests.seg: -------------------------------------------------------------------------------- 1 | `./end_otp.py fd00::10/128 dum0` 2 | 3 | `sleep 1` 4 | 5 | > fc00::42 -> fd00::10 / [baba::1, fc00::1337, +fd00::10, fab1::49] {Type:7 Value: 00000100000003000000420000003713000000000000000000000000000000000000000000000000000000000000} 6 | < fc00::42 -> fc00::1337 / [baba::1, +fc00::1337, fd00::10, fab1::49] 7 | 8 | > fc00::42 -> fd00::10 / [baba::1, fc00::1337, +fd00::10, fab1::49] {Type:7 Value: 00000101000003000000420000003713000000000000000000000000000000000000000000000000000000000000} {Type:131 Value:2a2abeef000000000000000000000000c100} 9 | < none 10 | 11 | 12 | `sleep 1` 13 | `pkill -F /tmp/end_otp_fd00::10-128.pid` 14 | -------------------------------------------------------------------------------- /use-cases/POWD-monitoring/tests_injector.seg: -------------------------------------------------------------------------------- 1 | `rm /sys/fs/bpf/ip/globals/powd_inj_freq_dport` 2 | `rm /sys/fs/bpf/ip/globals/powd_inj_sids` 3 | 4 | if add dum1 5 | `ip -6 route add fc00::42 encap bpf out obj dm_injector_bpf.o sec main headroom 112 dev dum1` 6 | `ip -6 route` 7 | 8 | > fc00::21 -> fc00::42 9 | < fc00::21 -> fc00::42 10 | 11 | `./dm_injector_usr fc00::20:a fc00::20:b 1 fc00::beef 4242` 12 | 13 | > fc00::22 -> fc00::42 14 | < fc00::22 -> fc00::42 15 | 16 | > fc00::23 -> fc00::42 17 | < fc00::23 -> fc00::42 18 | --------------------------------------------------------------------------------