mirror of
https://github.com/xdp-project/bpf-examples.git
synced 2024-05-06 15:54:53 +00:00
pping: Refactor TC and XDP programs
Refactor TC and XDP programs to reuse common logic for parsing packets. Add functions for parsing packets for an identifier to pping_helpers.h which both TC and XDP parts use. Also make it easier to extend pping with support for new protocols, as only new parsing functions have to be added and inserted into a single place. Also add reserved members to end of structs in pping.h to indicate padding. Signed-off-by: Simon Sundberg <simon.sundberg@kau.se>
This commit is contained in:
@@ -2,9 +2,16 @@
|
||||
#ifndef PPING_HELPERS_H
|
||||
#define PPING_HELPERS_H
|
||||
|
||||
#include <linux/bpf.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 <stdbool.h>
|
||||
#include "pping.h"
|
||||
|
||||
#define AF_INET 2
|
||||
@@ -14,12 +21,12 @@
|
||||
/*
|
||||
* 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)
|
||||
static void map_ipv4_to_ipv6(__be32 ipv4, struct in6_addr *ipv6)
|
||||
{
|
||||
/* __u16 ipv4_prefix[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0xffff}; */
|
||||
/* memcpy(ipv6, ipv4_prefix, sizeof(ipv4_prefix)); // Won't load on TC */
|
||||
memset(&ipv6->in6_u.u6_addr8[0], 0x00, 10);
|
||||
memset(&ipv6->in6_u.u6_addr8[10], 0xff, 2);
|
||||
/* __builtin_memcpy(ipv6, ipv4_prefix, sizeof(ipv4_prefix)); */
|
||||
__builtin_memset(&ipv6->in6_u.u6_addr8[0], 0x00, 10);
|
||||
__builtin_memset(&ipv6->in6_u.u6_addr8[10], 0xff, 2);
|
||||
ipv6->in6_u.u6_addr32[3] = ipv4;
|
||||
}
|
||||
|
||||
@@ -29,8 +36,8 @@ static __always_inline void map_ipv4_to_ipv6(__be32 ipv4, struct in6_addr *ipv6)
|
||||
* 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)
|
||||
static 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;
|
||||
@@ -73,5 +80,80 @@ static __always_inline int parse_tcp_ts(struct tcphdr *tcph, void *data_end,
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Attempts to fetch an identifier for TCP packets, based on the TCP timestamp
|
||||
* option. If sucessful, identifier will be set to TSval if is_ingress, TSecr
|
||||
* otherwise, the port-members of saddr and daddr will be set the the TCP source
|
||||
* and dest, respectively, and 0 will be returned. On failure, -1 will be
|
||||
* returned.
|
||||
*/
|
||||
static int parse_tcp_identifier(struct hdr_cursor *nh, void *data_end,
|
||||
bool is_egress, struct flow_address *saddr,
|
||||
struct flow_address *daddr, __u32 *identifier)
|
||||
{
|
||||
__u32 tsval, tsecr;
|
||||
struct tcphdr *tcph;
|
||||
|
||||
if (parse_tcphdr(nh, data_end, &tcph) < 0)
|
||||
return -1;
|
||||
if (parse_tcp_ts(tcph, data_end, &tsval, &tsecr) < 0)
|
||||
return -1; //Possible TODO, fall back on seq/ack instead
|
||||
|
||||
saddr->port = tcph->source;
|
||||
daddr->port = tcph->dest;
|
||||
*identifier = is_egress ? tsval : tsecr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to parse the packet limited by the data and data_end pointers,
|
||||
* to retrieve a protocol dependent packet identifier. If sucessful, the
|
||||
* ipv and identifier of p_id will be set, saddr and daddr (which may be part
|
||||
* of p_id) will be filled with the source and destionation addresses of the
|
||||
* packet, and 0 will be returned. On failure, -1 will be returned.
|
||||
*/
|
||||
static int parse_packet_identifier(void *data, void *data_end, bool is_egress,
|
||||
struct packet_id *p_id,
|
||||
struct flow_address *saddr,
|
||||
struct flow_address *daddr)
|
||||
{
|
||||
struct hdr_cursor nh = { .pos = data };
|
||||
struct ethhdr *eth;
|
||||
struct iphdr *iph;
|
||||
struct ipv6hdr *ip6h;
|
||||
int proto, err;
|
||||
|
||||
proto = parse_ethhdr(&nh, data_end, ð);
|
||||
|
||||
// Parse IPv4/6 header
|
||||
if (proto == bpf_htons(ETH_P_IP)) {
|
||||
p_id->flow.ipv = AF_INET;
|
||||
proto = parse_iphdr(&nh, data_end, &iph);
|
||||
} else if (proto == bpf_htons(ETH_P_IPV6)) {
|
||||
p_id->flow.ipv = AF_INET6;
|
||||
proto = parse_ip6hdr(&nh, data_end, &ip6h);
|
||||
} else
|
||||
return -1;
|
||||
|
||||
// Add new protocols here
|
||||
if (proto == IPPROTO_TCP)
|
||||
err = parse_tcp_identifier(&nh, data_end, is_egress, saddr,
|
||||
daddr, &p_id->identifier);
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
// Sucessfully parsed packet identifier - fill in IP-addresses and return
|
||||
if (p_id->flow.ipv == AF_INET) {
|
||||
map_ipv4_to_ipv6(iph->saddr, &saddr->ip);
|
||||
map_ipv4_to_ipv6(iph->daddr, &daddr->ip);
|
||||
} else { // IPv6
|
||||
saddr->ip = ip6h->saddr;
|
||||
daddr->ip = ip6h->daddr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user