mirror of
https://github.com/xdp-project/bpf-examples.git
synced 2024-05-06 15:54:53 +00:00
Several changes to add IPv6 support: - Change structs in pping.h - replace ipv4_flow with network_tuple - rename ts_key to packet_id - rename ts_timestamp to packet_timestamp - Add map_ipv4_to_ipv4 in pping_helpers.h - Also remove obsolete fill_ipv4_flow - Rewrite pping_kern* - parse either IPv4 or IPv6 header (depending on proto) - Use map_ipv4_to_ipv6 to store IPv4 address in network_tuple Support printout of IPv6 addresses in pping.c - Add function format_ip_address as wrapper over inet_ntop - Change handle_rtt_event to first format IP-address strings in local buffers, then perform single printout While some steps have been taken to be more general towards different types of packet identifiers (not just the currently supported TCP timestamps), significant refactorization of pping_kern* will still be required. Also, pping_kern_xdp and pping_kern_tc also have large sections of very similar code that can be refactored into functions. Signed-off-by: Simon Sundberg <simon.sundberg@kau.se>
97 lines
2.4 KiB
C
97 lines
2.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#include <linux/bpf.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
#include <iproute2/bpf_elf.h>
|
|
#include <xdp/parsing_helpers.h>
|
|
|
|
#include <linux/in.h>
|
|
#include <linux/in6.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/ipv6.h>
|
|
#include <linux/tcp.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "pping.h"
|
|
#include "pping_helpers.h"
|
|
|
|
char _license[] SEC("license") = "GPL";
|
|
|
|
#ifdef HAVE_TC_LIBBPF /* detected by configure script in config.mk */
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__uint(key_size, sizeof(struct packet_id));
|
|
__uint(value_size, sizeof(struct packet_timestamp));
|
|
__uint(max_entries, 16384);
|
|
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
|
} ts_start SEC(".maps");
|
|
|
|
#else
|
|
struct bpf_elf_map SEC("maps") ts_start = {
|
|
.type = BPF_MAP_TYPE_HASH,
|
|
.size_key = sizeof(struct packet_id),
|
|
.size_value = sizeof(struct packet_timestamp),
|
|
.max_elem = 16384,
|
|
.pinning = PIN_GLOBAL_NS,
|
|
};
|
|
#endif
|
|
|
|
// TC-BFP for parsing TSVAL from egress traffic and add to map
|
|
SEC(TCBPF_PROG_SEC)
|
|
int tc_bpf_prog_egress(struct __sk_buff *skb)
|
|
{
|
|
void *data = (void *)(long)skb->data;
|
|
void *data_end = (void *)(long)skb->data_end;
|
|
|
|
int proto = -1;
|
|
__u32 tsval, tsecr;
|
|
|
|
struct hdr_cursor nh = { .pos = data };
|
|
struct ethhdr *eth;
|
|
struct iphdr *iph;
|
|
struct ipv6hdr *ip6h;
|
|
struct tcphdr *tcph;
|
|
|
|
struct packet_id p_id = { 0 };
|
|
struct packet_timestamp p_ts = { 0 };
|
|
|
|
proto = bpf_ntohs(parse_ethhdr(&nh, data_end, ð));
|
|
|
|
// Parse IPv4/6 header
|
|
if (proto == ETH_P_IP) {
|
|
p_id.flow.ipv = AF_INET;
|
|
proto = parse_iphdr(&nh, data_end, &iph);
|
|
} else if (proto == ETH_P_IPV6) {
|
|
p_id.flow.ipv = AF_INET6;
|
|
proto = parse_ip6hdr(&nh, data_end, &ip6h);
|
|
} else
|
|
goto end;
|
|
|
|
// Parse TCP timestamp
|
|
if (proto != IPPROTO_TCP)
|
|
goto end;
|
|
if (parse_tcphdr(&nh, data_end, &tcph) < 0)
|
|
goto end;
|
|
if (parse_tcp_ts(tcph, data_end, &tsval, &tsecr) < 0)
|
|
goto end;
|
|
|
|
// We have a TCP timestamp, try adding it to the map
|
|
p_id.identifier = tsval;
|
|
if (p_id.flow.ipv == AF_INET) {
|
|
map_ipv4_to_ipv6(iph->saddr, &(p_id.flow.saddr));
|
|
map_ipv4_to_ipv6(iph->daddr, &(p_id.flow.daddr));
|
|
} else { // IPv6
|
|
p_id.flow.saddr = ip6h->saddr;
|
|
p_id.flow.daddr = ip6h->daddr;
|
|
}
|
|
p_id.flow.sport = tcph->source;
|
|
p_id.flow.dport = tcph->dest;
|
|
|
|
p_ts.timestamp = bpf_ktime_get_ns(); // or bpf_ktime_get_boot_ns
|
|
bpf_map_update_elem(&ts_start, &p_id, &p_ts, BPF_NOEXIST);
|
|
|
|
end:
|
|
return BPF_OK;
|
|
}
|