Skip to content

Instantly share code, notes, and snippets.

@ljjjustin
Last active May 30, 2022 15:42
Show Gist options
  • Save ljjjustin/c4e3977a32ddd0aeb044fd4ac616f52a to your computer and use it in GitHub Desktop.
Save ljjjustin/c4e3977a32ddd0aeb044fd4ac616f52a to your computer and use it in GitHub Desktop.
trace_net_drop.stp
https://cloud.tencent.com/developer/article/1631874
#!/usr/bin/stap --all-modules
%{
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/textsearch.h>
#include <net/checksum.h>
#include <linux/dma-mapping.h>
#include <linux/netdev_features.h>
#include <linux/skbuff.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/udp.h>
#include <uapi/linux/tcp.h>
%}
############################################################
# trace_net_drop.stp
# An example script to mimic the behavior of the dropwatch utility
# Need install kernel-debuginfo and kernel-debuginfo-common before running this script
# Default reports every 5 seconds with timestamp
# Usage example: //-g for guru mode
#stap -g -v --all-modules trace_net_drop.stp tcp daddr=10.0.0.14 dport=22 //dump all stack when skb dest addr/port 10.0.0.14/22
#stap -g -v --all-modules trace_net_drop.stp tcp saddr=1.1.1.1 sport=1000 daddr=2.2.2.2 dport=22 match=nf_hook_slow //just dump stack when kfree_skb is called by function "nf_hook_slow"
#stap -g -v --all-modules trace_net_drop.stp tcp daddr=10.0.0.14 dport=22 filter=tcp_rcv_state_process //dump any backtrace except function kfree_skb is called by "tcp_rcv_state_process"
#stap -g -v --all-modules -B CONFIG_MODVERSIONS=y trace_net_drop.stp tcp daddr=10.0.0.14 dport=22 filter=tcp_rcv_state_process //add '-B CONFIG_MODVERSIONS=y' if kernel config enable Module versioning support
############################################################
function get_skb_saddr:string(skb:long)
%{
int ret=-1;
unsigned int src_port = 0;
struct udphdr *udp_header;
struct tcphdr *tcp_header;
struct sk_buff *skb= (struct sk_buff *)STAP_ARG_skb;
struct iphdr *ip_header;
unsigned int src_ip=0;
if(!skb)
{
goto EXIT_F;
}
ip_header = (struct iphdr *)skb_network_header(skb);
if(!ip_header)
{
goto EXIT_F;
}
src_ip = (unsigned int)ip_header->saddr;
// printk(KERN_DEBUG "IP addres = %pI4 DEST = %pI4\n", &src_ip, &dest_ip);
EXIT_F:
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%d.%d.%d.%d",(unsigned int)((unsigned char *)&src_ip)[0],
(unsigned int)((unsigned char *)&src_ip)[1],(unsigned int)((unsigned char *)&src_ip)[2],(unsigned int)((unsigned char *)&src_ip)[3]);
%}
function get_skb_daddr:string(skb:long)
%{
int ret=-1;
struct udphdr *udp_header;
struct tcphdr *tcp_header;
struct sk_buff *skb= (struct sk_buff *)STAP_ARG_skb;
struct iphdr *ip_header;
unsigned int dst_ip=0;
if(!skb)
{
goto EXIT_F;
}
ip_header = (struct iphdr *)skb_network_header(skb);
if(!ip_header)
{
goto EXIT_F;
}
dst_ip = (unsigned int)ip_header->daddr;
EXIT_F:
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%d.%d.%d.%d",(unsigned int)((unsigned char *)&dst_ip)[0],
(unsigned int)((unsigned char *)&dst_ip)[1],(unsigned int)((unsigned char *)&dst_ip)[2],(unsigned int)((unsigned char *)&dst_ip)[3]);
%}
function get_skb_sport:string(skb:long)
%{
int ret=-1;
unsigned int src_port = 0;
struct udphdr *udp_header;
struct tcphdr *tcp_header;
struct sk_buff *skb= (struct sk_buff *)STAP_ARG_skb;
struct iphdr *ip_header;
if(!skb)
{
goto EXIT_F;
}
ip_header = (struct iphdr *)skb_network_header(skb);
if(!ip_header)
{
goto EXIT_F;
}
if (ip_header->protocol==17) {
udp_header = (struct udphdr *)skb_transport_header(skb);
src_port = (unsigned int)ntohs(udp_header->source);
} else if (ip_header->protocol == 6) {
tcp_header = (struct tcphdr *)skb_transport_header(skb);
src_port = (unsigned int)ntohs(tcp_header->source);
}
// printk("src_port=%d\r\n",src_port);
EXIT_F:
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%d",src_port);
%}
function get_skb_dport:string(skb:long)
%{
int ret=-1;
unsigned int dst_port = 0;
struct udphdr *udp_header;
struct tcphdr *tcp_header;
struct sk_buff *skb= (struct sk_buff *)STAP_ARG_skb;
struct iphdr *ip_header;
if(!skb)
{
goto EXIT_F;
}
ip_header = (struct iphdr *)skb_network_header(skb);
if(!ip_header)
{
goto EXIT_F;
}
if (ip_header->protocol==17) {
udp_header = (struct udphdr *)skb_transport_header(skb);
dst_port = (unsigned int)ntohs(udp_header->dest);
} else if (ip_header->protocol == 6) {
tcp_header = (struct tcphdr *)skb_transport_header(skb);
dst_port = (unsigned int)ntohs(tcp_header->dest);
}
EXIT_F:
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%d",dst_port);
%}
function get_skb_ipproto:string(skb:long)
%{
char *ipproto = "NONE";
struct sk_buff *skb= (struct sk_buff *)STAP_ARG_skb;
struct iphdr *ip_header;
if(!skb)
{
goto EXIT_F;
}
ip_header = (struct iphdr *)skb_network_header(skb);
if(!ip_header)
{
goto EXIT_F;
}
if (ip_header->protocol == 6) {
ipproto="TCP";
}
else if (ip_header->protocol == 17) {
ipproto="UDP";
}
else if (ip_header->protocol == 1) {
ipproto="ICMP";//IPPROTO_ICMP
}
EXIT_F:
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%s",ipproto);
%}
global addr = "all"
global port = "all"
global saddr = "all"
global sport = "all"
global daddr = "all"
global dport = "all"
global match = "all"
global filter = "none"
global WatchIpproto = "ALL"
global kfree_skb_stack
global kfree_skb_location
global interval=5 # default interval between output
global timeout=0
global BackTrace = 0
/*function get_param_val:string (mystr:string) %{
char *ptr;
int ch = '=';
char *strargs = STAP_ARG_mystr;
ptr=strchr(strargs , ch);
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%s",ptr + 1);
%}*/
function usage (msg:string)
{
printf("%s:\n\n",msg);
printf("\tall|tcp|udp|icmp: trace proto\n")
printf("\taddr=ip address:ip address\n")
printf("\tsaddr=ip source address:ip source address\n")
printf("\tdaddr=ip dest address:ip destination address\n")
printf("\tport=port: ip port\n")
printf("\tsport=source port:source port\n")
printf("\tdport=dest port:dest port\n")
printf("\tmatch=<all|kernel function name>:match a specific function or any function\n")
printf("\tfilter=<all|kernel function name>:filter a specific function or any function\n")
printf("\tbt: print call trace\n")
printf("\tinterval=second:Dump trace every 'interval' second\n")
printf("\texample:\n")
printf("\ttrace_net_drop.stp tcp saddr=1.1.1.1 sport=5000 daddr=2.2.2.2 dport=80\n\n");
exit();
}
function print_header (msg:string)
{
printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s\n","IP PROTO","SRC or DST ADDRESS","SRC or DST PORT","Source Address",
"Dest Address","Source Port","Dest Port","match function","filter function","INTERVAL(sec)")
printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20d\n",WatchIpproto,addr,port,saddr,daddr,sport,dport,match,filter,interval)
}
function process_cmdline:long ()
{
for (i=1; i <= argc; i++) {
argument = tokenize(argv[i], "=")
if (argument == "help") {
usage("Usage");
exit();
}
else if (argument == "all") {
WatchIpproto = "ALL";
continue;
}
else if (argument == "tcp") {
WatchIpproto = "TCP";
continue;
}
else if (argument == "udp") {
WatchIpproto = "UDP";
continue;
}
else if (argument == "icmp") {
WatchIpproto = "ICMP";
continue;
}
else if (argument == "addr") {
argv[i]="";
addr = tokenize(argv[i], "=");
continue;
}
else if (argument == "port") {
argv[i]="";
port=tokenize(argv[i], "=");
continue;
}
else if (argument == "saddr") {
argv[i]="";
saddr=tokenize(argv[i], "=");
continue;
}
else if (argument == "daddr") {
argv[i]="";
daddr=tokenize(argv[i], "=");
continue;
}
else if (argument == "sport") {
argv[i]="";
sport=tokenize(argv[i], "=");
continue;
}
else if (argument == "dport") {
argv[i]="";
dport=tokenize(argv[i], "=");
continue;
}
else if (argument == "match") {
argv[i]="";
match=tokenize(argv[i], "=");
continue;
}
else if (argument == "filter") {
argv[i]="";
filter=tokenize(argv[i], "=");
continue;
}
else if (argument == "interval") {
argv[i]="";
interval=strtol(tokenize(argv[i], "="),10);
continue;
}
else if (argument == "bt") {
BackTrace=1;
}
else
usage("process cmdline fail")
}
print_header("");
}
probe begin
{
// printf("param num:%s,%d\r\n",@#,argc)
if (@1 == "all" || @1 == "tcp" || @1 =="udp" || @1 == "icmp" || @1 =="help") {
process_cmdline();
}
else {
usage("error cmdline");
}
printf("Monitoring for dropped packets\n")
}
probe end
{
printf("Stopping dropped packet monitor\n")
}
# increment a drop counter for every location we drop at
probe kernel.trace("kfree_skb") {
if(WatchIpproto != "ALL")
{
skb_ip_proto=get_skb_ipproto($skb)
if(skb_ip_proto != WatchIpproto)
next
}
if(addr != "all")
{
skb_src_ip=get_skb_saddr($skb)
skb_dst_ip=get_skb_daddr($skb)
if(addr != skb_src_ip && addr != skb_dst_ip)
next
}
if(port != "all")
{
skb_src_port=get_skb_sport($skb)
skb_dst_port=get_skb_dport($skb)
if(port != skb_src_port && port != skb_dst_port)
next
}
if(saddr != "all")
{
skb_src_ip=get_skb_saddr($skb)
if(saddr != skb_src_ip)
next
}
if(daddr != "all")
{
skb_dst_ip=get_skb_daddr($skb)
if(daddr != skb_dst_ip)
next
}
if(sport != "all")
{
skb_src_port=get_skb_sport($skb)
if(sport != skb_src_port)
next
}
if(dport != "all")
{
skb_dst_port=get_skb_dport($skb)
if(dport != skb_dst_port)
next
}
// locations[$location] <<< 1 //systemtap Statistical aggregate
if(match == "all" && filter== "none")
{
if(BackTrace)
kfree_skb_stack[backtrace()] <<< 1
else
kfree_skb_location[$location] <<< 1
}
else if(symname($location)==match)
{
if(BackTrace)
kfree_skb_stack[backtrace()] <<< 1
else
kfree_skb_location[$location] <<< 1
}
else if(symname($location)!=filter && filter!="none")
{
if(BackTrace)
kfree_skb_stack[backtrace()] <<< 1
else
kfree_skb_location[$location] <<< 1
}
}
#Default every 5 seconds report our drop locations
probe timer.sec(1)
{
if(++timeout != interval)
next
timeout=0
printf("\n====== %s ======\n", ctime(gettimeofday_s()))
if(BackTrace)
{
// add a single plus (+) or minus (-) operator after the VAR or the ARRAY
//identifier, the iteration order will be sorted by the ascending or descending
//index or value.
foreach (bt in kfree_skb_stack-) {
printf("%d packets dropped at stack:\n",@count(kfree_skb_stack[bt]))
print_syms(bt)
}
delete kfree_skb_stack
}
else
{
foreach (lt in kfree_skb_location-) {
printf("%d packets dropped at %s\n",@count(kfree_skb_location[lt]), symname(lt))
}
delete kfree_skb_location
}
}
### trace_net_drop.stp ends ###
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment