// networking tapset
// Copyright (C) 2005, 2006 IBM Corp.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
//
// This family of probe points is used to probe the activities of the network device.
//
// ===================================================================
//
// BZ1546179 fix notes.
//
// The following kernel commit changed the sk_buff structure:
//
// commit bffa72cf7f9df842f0016ba03586039296b4caaf
// Author: Eric Dumazet
// Date: Tue Sep 19 05:14:24 2017 -0700
//
// net: sk_buff rbnode reorg
//
// skb->rbnode shares space with skb->next, skb->prev and skb->tstamp
//
// The sk_buff structure now looks like this:
//
// ====
// struct sk_buff {
// union {
// struct {
// /* These two members must be first. */
// struct sk_buff *next;
// struct sk_buff *prev;
//
// union {
// struct net_device *dev;
// /* Some protocols might use this space to store information,
// * while device pointer would be NULL.
// * UDP receive path is one user.
// */
// unsigned long dev_scratch;
// };
// };
// struct rb_node rbnode; /* used in netem & tcp stack */
// };
// ... stuff deleted ...
// };
// ====
//
// There doesn't seem to be a way by looking at the sk_buf structure
// to know which of those union values are valid. If a probe does
// something like "dev_name = kernel_string($skb->dev->name)", that
// could fail in a variety of ways (since it is difficult to know if
// $skb->dev is supposed to be valid). To avoid a probe user getting a
// read error (with no way to trap that error), accesses to sk_buff
// structs have been surrounded with "try { .. } catch { }" in probes.
//
// Note that this is done only in probes, not in functions. A user
// doing his own probing might want to try to catch an error in a
// function himself.
//
// Also note that statements accessing the same sk_buff structure
// field are grouped in a single try/catch statement. Statements
// accessing different sk_buff structure fields each have their own
// try/catch statement.
//
// ===================================================================
/* A function that returns the device name given the net_device struct */
function get_netdev_name:string (addr:long) {
return kernel_string(@cast(addr, "net_device")->name)
}
/**
* probe netdev.receive - Data received from network device.
* @dev_name: The name of the device. e.g: eth0, ath1.
* @length: The length of the receiving buffer.
* @protocol: Protocol of received packet.
*
*/
/// protocol
/// The possible values of protocol could be:
/// Protocol Values
///
///
///
///
/// Value(Hex)Protocol
///
///
/// 0001802.3
/// 0002AX.25
/// 0004802.2
/// 0005SNAP
/// 0009Localtalk
/// 0800IP
/// 0805X.25
/// 0806ARP
/// 8035RARP
/// 8100802.1Q VLAN
/// 8137IPX
/// 86DDIPv6
///
///
///
///
///
///
/// truesize
///
/// The size of the received data.
///
///
///
///
///
// Main device receive routine, be called when packet arrives on network device
probe netdev.receive
= kernel.function("netif_receive_skb_internal") !,
kernel.function("netif_receive_skb")
{
try { dev_name = get_netdev_name($skb->dev) } catch { }
try { length = $skb->len } catch { }
try { protocol = $skb->protocol } catch { }
try { truesize = $skb->truesize } catch { }
}
/**
* probe netdev.transmit - Network device transmitting buffer
* @dev_name: The name of the device. e.g: eth0, ath1.
* @length: The length of the transmit buffer.
* @protocol: The protocol of this packet(defined in include/linux/if_ether.h).
* @truesize: The size of the data to be transmitted.
*
*/
// Queue a buffer for transmission to a network device
probe netdev.transmit
= kernel.function("__dev_queue_xmit") !,
kernel.function("dev_queue_xmit")
{
try { dev_name = get_netdev_name($skb->dev) } catch { }
try { length = $skb->len } catch { }
try { protocol = $skb->protocol } catch { }
try { truesize = $skb->truesize } catch { }
}
/**
* probe netdev.change_mtu - Called when the netdev MTU is changed
* @dev_name: The device that will have the MTU changed
* @old_mtu: The current MTU
* @new_mtu: The new MTU
*/
probe netdev.change_mtu
= kernel.function("dev_set_mtu")
{
old_mtu = $dev->mtu
new_mtu = $new_mtu
dev_name = get_netdev_name($dev)
}
/**
* probe netdev.open - Called when the device is opened
* @dev_name: The device that is going to be opened
*/
probe netdev.open
= kernel.function("dev_open")
{
dev_name = get_netdev_name($dev)
}
/**
* probe netdev.close - Called when the device is closed
* @dev_name: The device that is going to be closed
*/
probe netdev.close
= kernel.function("dev_close")
{
dev_name = get_netdev_name($dev)
}
/**
* probe netdev.hard_transmit - Called when the devices is going to TX (hard)
* @dev_name: The device scheduled to transmit
* @protocol: The protocol used in the transmission
* @length: The length of the transmit buffer.
* @truesize: The size of the data to be transmitted.
*/
probe netdev.hard_transmit
= kernel.function("dev_hard_start_xmit") ?
{
dev_name = get_netdev_name($dev)
try { protocol = @choose_defined($first, $skb)->protocol } catch { }
try { length = @choose_defined($first, $skb)->len } catch { }
try { truesize = @choose_defined($first, $skb)->truesize } catch { }
}
/**
* probe netdev.rx - Called when the device is going to receive a packet
* @dev_name: The device received the packet
* @protocol: The packet protocol
*/
probe netdev.rx
= kernel.function("netif_rx")
{
try {
netdev = $skb->dev
dev_name = get_netdev_name(netdev)
} catch { }
try { protocol = $skb->protocol } catch { }
}
/**
* probe netdev.change_rx_flag - Called when the device RX flag will be changed
* @dev_name: The device that will be changed
* @flags: The new flags
*/
probe netdev.change_rx_flag
= kernel.function("dev_change_rx_flags") ?
{
dev_name = (@defined($dev) ? get_netdev_name($dev) : "unknown")
flags = @choose_defined($flags, 0)
}
/**
* probe netdev.set_promiscuity - Called when the device enters/leaves promiscuity
* @dev_name: The device that is entering/leaving promiscuity mode
* @enable: If the device is entering promiscuity mode
* @disable: If the device is leaving promiscuity mode
* @inc: Count the number of promiscuity openers
*/
probe netdev.set_promiscuity
= kernel.function("dev_set_promiscuity")
{
dev_name = get_netdev_name($dev)
if ($inc){
enable = 1
} else {
disable = 1
}
inc = $inc
}
/**
* probe netdev.ioctl - Called when the device suffers an IOCTL
* @cmd: The IOCTL request
* @arg: The IOCTL argument (usually the netdev interface)
*/
probe netdev.ioctl
= kernel.function("dev_ioctl")
{
cmd = $cmd
arg = user_string_quoted(@choose_defined($ifr, $arg))
}
/**
* probe netdev.register - Called when the device is registered
* @dev_name: The device that is going to be registered
*/
probe netdev.register
= kernel.function("register_netdevice"),
kernel.function("register_netdev")
{
dev_name = get_netdev_name($dev)
}
/**
* probe netdev.unregister - Called when the device is being unregistered
* @dev_name: The device that is going to be unregistered
*/
probe netdev.unregister
= kernel.function("unregister_netdev")
{
dev_name = get_netdev_name($dev)
}
/**
* probe netdev.get_stats - Called when someone asks the device statistics
* @dev_name: The device that is going to provide the statistics
*/
probe netdev.get_stats
= kernel.function("dev_get_stats") ?
{
dev_name = get_netdev_name($dev)
}
/**
* probe netdev.change_mac - Called when the netdev_name has the MAC changed
* @dev_name: The device that will have the MAC changed
* @mac_len: The MAC length
* @old_mac: The current MAC address
* @new_mac: The new MAC address
*/
probe netdev.change_mac
= kernel.function("dev_set_mac_address") ?
{
dev_name = get_netdev_name($dev)
mac_len = $dev->addr_len
// Old MAC Address
old_mac = sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
$dev->dev_addr[0], $dev->dev_addr[1],
$dev->dev_addr[2], $dev->dev_addr[3],
$dev->dev_addr[4], $dev->dev_addr[5])
// New MAC Address
new_mac = sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
$sa->sa_data[0], $sa->sa_data[1],
$sa->sa_data[2], $sa->sa_data[3],
$sa->sa_data[4], $sa->sa_data[5])
}