1#!/usr/bin/env python 2# 3# tc_perf_event.py Output skb and meta data through perf event 4# 5# Copyright (c) 2016-present, Facebook, Inc. 6# Licensed under the Apache License, Version 2.0 (the "License") 7 8from bcc import BPF 9import ctypes as ct 10import pyroute2 11import socket 12 13bpf_txt = """ 14#include <uapi/linux/if_ether.h> 15#include <uapi/linux/in6.h> 16#include <uapi/linux/ipv6.h> 17#include <uapi/linux/pkt_cls.h> 18#include <uapi/linux/bpf.h> 19 20BPF_PERF_OUTPUT(skb_events); 21 22struct eth_hdr { 23 unsigned char h_dest[ETH_ALEN]; 24 unsigned char h_source[ETH_ALEN]; 25 unsigned short h_proto; 26}; 27 28int handle_egress(struct __sk_buff *skb) 29{ 30 void *data = (void *)(long)skb->data; 31 void *data_end = (void *)(long)skb->data_end; 32 struct eth_hdr *eth = data; 33 struct ipv6hdr *ip6h = data + sizeof(*eth); 34 u32 magic = 0xfaceb00c; 35 36 /* single length check */ 37 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) 38 return TC_ACT_OK; 39 40 if (eth->h_proto == htons(ETH_P_IPV6) && 41 ip6h->nexthdr == IPPROTO_ICMPV6) 42 skb_events.perf_submit_skb(skb, skb->len, &magic, sizeof(magic)); 43 44 return TC_ACT_OK; 45}""" 46 47def print_skb_event(cpu, data, size): 48 class SkbEvent(ct.Structure): 49 _fields_ = [ ("magic", ct.c_uint32), 50 ("raw", ct.c_ubyte * (size - ct.sizeof(ct.c_uint32))) ] 51 52 skb_event = ct.cast(data, ct.POINTER(SkbEvent)).contents 53 icmp_type = int(skb_event.raw[54]) 54 55 # Only print for echo request 56 if icmp_type == 128: 57 src_ip = bytes(bytearray(skb_event.raw[22:38])) 58 dst_ip = bytes(bytearray(skb_event.raw[38:54])) 59 print("%-3s %-32s %-12s 0x%08x" % 60 (cpu, socket.inet_ntop(socket.AF_INET6, src_ip), 61 socket.inet_ntop(socket.AF_INET6, dst_ip), 62 skb_event.magic)) 63 64try: 65 b = BPF(text=bpf_txt) 66 fn = b.load_func("handle_egress", BPF.SCHED_CLS) 67 68 ipr = pyroute2.IPRoute() 69 ipr.link("add", ifname="me", kind="veth", peer="you") 70 me = ipr.link_lookup(ifname="me")[0] 71 you = ipr.link_lookup(ifname="you")[0] 72 for idx in (me, you): 73 ipr.link('set', index=idx, state='up') 74 75 ipr.tc("add", "clsact", me) 76 ipr.tc("add-filter", "bpf", me, ":1", fd=fn.fd, name=fn.name, 77 parent="ffff:fff3", classid=1, direct_action=True) 78 79 b["skb_events"].open_perf_buffer(print_skb_event) 80 print('Try: "ping6 ff02::1%me"\n') 81 print("%-3s %-32s %-12s %-10s" % ("CPU", "SRC IP", "DST IP", "Magic")) 82 while True: 83 b.perf_buffer_poll() 84finally: 85 if "me" in locals(): ipr.link("del", index=me) 86