1#!/usr/bin/python 2# @lint-avoid-python-3-compatibility-imports 3# 4# rdmaucma: Trace RDMA Userspace Connection Manager Access Event. 5# For Linux, uses BCC, eBPF. 6# 7# USAGE: rdmaucma [-h] 8# 9# Copyright (c) 2023 zhenwei pi 10# Licensed under the Apache License, Version 2.0 (the "License") 11# 12# 29-MAY-2023 zhenwei pi Created this. 13 14from __future__ import print_function 15from bcc import BPF 16from socket import inet_ntop, AF_INET, AF_INET6 17import socket, struct 18import argparse 19import ctypes 20from time import strftime 21 22# arguments 23examples = """examples: 24 ./rdmaucma # Trace all RDMA Userspace Connection Manager Access Event 25""" 26parser = argparse.ArgumentParser( 27 description="Trace RDMA Userspace Connection Manager Access Event", 28 formatter_class=argparse.RawDescriptionHelpFormatter, 29 epilog=examples) 30parser.add_argument("-D", "--debug", action="store_true", 31 help="print BPF program before starting (for debugging purposes)") 32parser.add_argument("--ebpf", action="store_true", 33 help=argparse.SUPPRESS) 34args = parser.parse_args() 35 36# define BPF program 37bpf_text = """ 38#include <linux/bpf.h> 39#include <uapi/linux/ptrace.h> 40#include <rdma/rdma_cm.h> 41 42struct ipv4_data_t { 43 u32 saddr; 44 u32 daddr; 45 u16 sport; 46 u16 dport; 47 int event; 48}; 49 50BPF_PERF_OUTPUT(ipv4_events); 51 52struct ipv6_data_t { 53 unsigned __int128 saddr; 54 unsigned __int128 daddr; 55 u16 sport; 56 u16 dport; 57 int event; 58}; 59 60BPF_PERF_OUTPUT(ipv6_events); 61 62int trace_ucma_event_handler(struct pt_regs *ctx, 63 struct rdma_cm_id *cm_id, 64 struct rdma_cm_event *event) 65{ 66 struct sockaddr_storage *ss = &cm_id->route.addr.src_addr; 67 68 if (ss->ss_family == AF_INET) { 69 struct ipv4_data_t ipv4_data = { 0 }; 70 struct sockaddr_in *addr4 = (struct sockaddr_in *)ss; 71 ipv4_data.sport = addr4->sin_port; 72 ipv4_data.saddr = addr4->sin_addr.s_addr; 73 74 addr4 = (struct sockaddr_in *)&cm_id->route.addr.dst_addr; 75 ipv4_data.dport = addr4->sin_port; 76 ipv4_data.daddr = addr4->sin_addr.s_addr; 77 78 ipv4_data.event = event->event; 79 ipv4_events.perf_submit(ctx, &ipv4_data, sizeof(ipv4_data)); 80 } else if (ss->ss_family == AF_INET6) { 81 struct ipv6_data_t ipv6_data = { 0 }; 82 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)ss; 83 ipv6_data.sport = addr6->sin6_port; 84 bpf_probe_read_kernel(&ipv6_data.saddr, sizeof(ipv6_data.saddr), addr6->sin6_addr.in6_u.u6_addr32); 85 86 addr6 = (struct sockaddr_in6 *)&cm_id->route.addr.dst_addr; 87 ipv6_data.dport = addr6->sin6_port; 88 bpf_probe_read_kernel(&ipv6_data.daddr, sizeof(ipv6_data.daddr), addr6->sin6_addr.in6_u.u6_addr32); 89 90 ipv6_data.event = event->event; 91 ipv6_events.perf_submit(ctx, &ipv6_data, sizeof(ipv6_data)); 92 } else { 93 return -EPROTONOSUPPORT; 94 } 95 96 return 0; 97} 98""" 99 100# debug/dump ebpf enable or not 101if args.debug or args.ebpf: 102 print(bpf_text) 103 if args.ebpf: 104 exit() 105 106# load BPF program 107b = BPF(text=bpf_text) 108b.attach_kprobe(event="ucma_event_handler", fn_name="trace_ucma_event_handler") 109 110# see linux/include/rdma/rdma_cm.h 111rdma_cm_event = [ 112 "address resolved", 113 "address error", 114 "route resolved ", 115 "route error", 116 "connect request", 117 "connect response", 118 "connect error", 119 "unreachable", 120 "rejected", 121 "established", 122 "disconnected", 123 "device removal", 124 "multicast join", 125 "multicast error", 126 "address change", 127 "timewait exit" ] 128 129def print_ipv4_event(cpu, data, size): 130 event = b["ipv4_events"].event(data) 131 132 cm_event = "unknown event" 133 if event.event < len(rdma_cm_event): 134 cm_event = rdma_cm_event[event.event] 135 136 print("%-9s %-16s %-6s %-45s %-45s" % (strftime("%H:%M:%S").encode('ascii'), 137 cm_event, "IPv4", 138 inet_ntop(AF_INET, struct.pack("I", event.saddr)) + ":" + str(socket.ntohs(event.sport)), 139 inet_ntop(AF_INET, struct.pack("I", event.daddr)) + ":" + str(socket.ntohs(event.dport)))) 140 141def print_ipv6_event(cpu, data, size): 142 event = b["ipv6_events"].event(data) 143 144 cm_event = "unknown event" 145 if event.event < len(rdma_cm_event): 146 cm_event = rdma_cm_event[event.event] 147 148 print("%-9s %-16s %-6s %-45s %-45s" % (strftime("%H:%M:%S").encode('ascii'), 149 cm_event, "IPv6", 150 inet_ntop(AF_INET6, event.saddr) + ":" + str(socket.ntohs(event.sport)), 151 inet_ntop(AF_INET6, event.daddr) + ":" + str(socket.ntohs(event.dport)))) 152 153 154b["ipv4_events"].open_perf_buffer(print_ipv4_event) 155b["ipv6_events"].open_perf_buffer(print_ipv6_event) 156 157# output 158print("Tracing RDMA Userspace Connection Manager Access event... Hit Ctrl-C to end.") 159 160# address length 39 = max("2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b", "255.255.255.255") 161print("%-9s %-16s %-4s %-45s %-45s" % ("Timestamp", "Event", "Family", "Local", "Remote")) 162 163while (1): 164 try: 165 b.perf_buffer_poll() 166 except KeyboardInterrupt: 167 exit() 168