1 /* Copyright (c) 2017 Facebook 2 * 3 * This program is free software; you can redistribute it and/or 4 * modify it under the terms of version 2 of the GNU General Public 5 * License as published by the Free Software Foundation. 6 * 7 * BPF program to set base_rtt to 80us when host is running TCP-NV and 8 * both hosts are in the same datacenter (as determined by IPv6 prefix). 9 * 10 * Use load_sock_ops to load this BPF program. 11 */ 12 13 #include <uapi/linux/bpf.h> 14 #include <uapi/linux/tcp.h> 15 #include <uapi/linux/if_ether.h> 16 #include <uapi/linux/if_packet.h> 17 #include <uapi/linux/ip.h> 18 #include <linux/socket.h> 19 #include "bpf_helpers.h" 20 #include "bpf_endian.h" 21 22 #define DEBUG 1 23 24 #define bpf_printk(fmt, ...) \ 25 ({ \ 26 char ____fmt[] = fmt; \ 27 bpf_trace_printk(____fmt, sizeof(____fmt), \ 28 ##__VA_ARGS__); \ 29 }) 30 31 SEC("sockops") 32 int bpf_basertt(struct bpf_sock_ops *skops) 33 { 34 char cong[20]; 35 char nv[] = "nv"; 36 int rv = 0, n; 37 int op; 38 39 op = (int) skops->op; 40 41 #ifdef DEBUG 42 bpf_printk("BPF command: %d\n", op); 43 #endif 44 45 /* Check if both hosts are in the same datacenter. For this 46 * example they are if the 1st 5.5 bytes in the IPv6 address 47 * are the same. 48 */ 49 if (skops->family == AF_INET6 && 50 skops->local_ip6[0] == skops->remote_ip6[0] && 51 (bpf_ntohl(skops->local_ip6[1]) & 0xfff00000) == 52 (bpf_ntohl(skops->remote_ip6[1]) & 0xfff00000)) { 53 switch (op) { 54 case BPF_SOCK_OPS_BASE_RTT: 55 n = bpf_getsockopt(skops, SOL_TCP, TCP_CONGESTION, 56 cong, sizeof(cong)); 57 if (!n && !__builtin_memcmp(cong, nv, sizeof(nv)+1)) { 58 /* Set base_rtt to 80us */ 59 rv = 80; 60 } else if (n) { 61 rv = n; 62 } else { 63 rv = -1; 64 } 65 break; 66 default: 67 rv = -1; 68 } 69 } else { 70 rv = -1; 71 } 72 #ifdef DEBUG 73 bpf_printk("Returning %d\n", rv); 74 #endif 75 skops->reply = rv; 76 return 1; 77 } 78 char _license[] SEC("license") = "GPL"; 79