Files
xdp-project-bpf-examples/pping/pping_helpers.h
Simon Sundberg 670df84bd9 pping: Add IPv6 support
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>
2021-02-08 20:28:46 +01:00

80 lines
2.0 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef PPING_HELPERS_H
#define PPING_HELPERS_H
#include <linux/in6.h>
#include <linux/tcp.h>
#include <string.h>
#include "pping.h"
#define MAX_TCP_OPTIONS 10
/*
* Maps and IPv4 address into an IPv6 address according to RFC 4291 sec 2.5.5.2
*/
static __always_inline void map_ipv4_to_ipv6(__be32 ipv4, struct in6_addr *ipv6)
{
/* __u16 ipv4_prefix[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0xffff}; */
/* memcpy(&(ipv6->in6_u.u6_addr8), ipv4_prefix, sizeof(ipv4_prefix)); */
memset(&(ipv6->in6_u.u6_addr8[0]), 0x00, 10);
memset(&(ipv6->in6_u.u6_addr8[10]), 0xff, 2);
#if __UAPI_DEF_IN6_ADDR_ALT
ipv6->in6_u.u6_addr32[3] = ipv4;
#else
memcpy(&(ipv6->in6_u.u6_addr8[12]), &ipv4, sizeof(ipv4));
#endif
}
/*
* Parses the TSval and TSecr values from the TCP options field. If sucessful
* the TSval and TSecr values will be stored at tsval and tsecr (in network
* byte order).
* Returns 0 if sucessful and -1 on failure
*/
static __always_inline int parse_tcp_ts(struct tcphdr *tcph, void *data_end,
__u32 *tsval, __u32 *tsecr)
{
int len = tcph->doff << 2;
void *opt_end = (void *)tcph + len;
__u8 *pos = (__u8 *)(tcph + 1); //Current pos in TCP options
__u8 i, opt, opt_size;
if (tcph + 1 > data_end || len <= sizeof(struct tcphdr))
return -1;
for (i = 0; i < MAX_TCP_OPTIONS; i++) {
if (pos + 1 > opt_end || pos + 1 > data_end)
return -1;
opt = *pos;
if (opt == 0) // Reached end of TCP options
return -1;
if (opt == 1) { // TCP NOP option - advance one byte
pos++;
continue;
}
// Option > 1, should have option size
if (pos + 2 > opt_end || pos + 2 > data_end)
return -1;
opt_size = *(pos + 1);
// Option-kind is TCP timestap (yey!)
if (opt == 8 && opt_size == 10) {
if (pos + opt_size > opt_end ||
pos + opt_size > data_end)
return -1;
*tsval = *(__u32 *)(pos + 2);
*tsecr = *(__u32 *)(pos + 6);
return 0;
}
// Some other TCP option - advance option-length bytes
pos += opt_size;
}
return -1;
}
#endif