ip Provider
The ip provider provides probes for tracing both IPv4 and IPv6 protocols.
This provider became available in Solaris Nevada build 93; It is not available in Solaris 10.
Probes
The ip probes are described in the table below.
ip Probes
Probe | Description |
---|---|
send | Probe that fires whenever the kernel network stack sends an ip packet. |
receive | Probe that fires whenever the kernel network stack receives an ip packet. |
These probes trace packets on physical interfaces and also packets on loopback interfaces that are processed by ip. An IP packet must have a full IP header to be visible by these probes.
Note: loopback tcp packets on Solaris may be processed by tcp fusion, a performance feature that by-passes the ip layer. These fused packets will not be visible using the ip:::send and ip:::receive probes. They are typically all loopback tcp packets after the tcp handshake.
Arguments
The argument types for the ip probes are listed in the table below. The arguments are described in the following section.
ip Probe Arguments
Probe | args[0] | args[1] | args[2] | args[3] | args[4] | args[5] |
---|---|---|---|---|---|---|
send | pktinfo_t * | csinfo_t * | ipinfo_t * | ifinfo_t * | ipv4info_t * | ipv6info_t * |
receive | pktinfo_t * | csinfo_t * | ipinfo_t * | ifinfo_t * | ipv4info_t * | ipv6info_t * |
args[0] - pktinfo_t structure
The pktinfo_t structure is where packet ID info can be made available for deeper analysis if packet IDs become supported by the kernel in the future.
The pkt_addr member is currently always NULL.
typedef struct pktinfo { uintptr_t pkt_addr; /* currently always NULL */ } pktinfo_t;
args[1] - csinfo_t structure
The csinfo_t structure is where connection state info can be made available if connection IDs become supported by the kernel in the future.
The cs_addr member is currently always NULL.
typedef struct csinfo { uintptr_t cs_addr; /* currently always NULL */ } csinfo_t;
args[2] - ipinfo_t structure
The ipinfo_t structure contains common IP info for both IPv4 and IPv6.
typedef struct ipinfo { uint8_t ip_ver; /* IP version (4, 6) */ uint16_t ip_plength; /* payload length */ string ip_saddr; /* source address */ string ip_daddr; /* destination address */ } ipinfo_t;
ipinfo_t Members
ip_ver | IP version number. Currently either 4 or 6. |
ip_plength | Payload length in bytes. This is the length of the packet at the time of tracing, excluding the IP header. |
ip_saddr | Source IP address, as a string. For IPv4 this is a dotted decimal quad, IPv6 follows RFC-1884 convention 2 with lower case hexadecimal digits. |
ip_daddr | Destination IP address, as a string. For IPv4 this is a dotted decimal quad, IPv6 follows RFC-1884 convention 2 with lower case hexadecimal digits. |
args[3] - ifinfo_t structure
The ifinfo_t structure contains network interface info.
typedef struct ifinfo { string if_name; /* interface name */ int8_t if_local; /* is delivered locally */ netstackid_t if_ipstack; /* ipstack ID */ uintptr_t if_addr; /* pointer to raw ill_t */ } ifinfo_t;
ifinfo_t Members
if_name | Interface name as a string. For example, "eri0", "lo0", "ip.tun0", "<unknown>". |
if_local | Is-local status. 1: is a local interface, 0: is not a local interface, -1: is unknown. |
if_ipstack | ipstack ID, for associating ip stack instances, or NULL. |
if_addr | Pointer to raw kernel structure for advanced debugging only. |
The ifinfo_t details are provided for debugging convenience in the ip layer, if that information is available. There may be some types of traffic where some or all of that information is not available during the ip layer, for which the members may be: "<null>", -1, NULL, NULL.
args[4] - ipv4info_t structure
The ipv4info_t structure is a DTrace translated version of the IPv4 header.
typedef struct ipv4info { uint8_t ipv4_ver; /* IP version (4) */ uint8_t ipv4_ihl; /* header length, bytes */ uint8_t ipv4_tos; /* type of service field */ uint16_t ipv4_length; /* length (header + payload) */ uint16_t ipv4_ident; /* identification */ uint8_t ipv4_flags; /* IP flags */ uint16_t ipv4_offset; /* fragment offset */ uint8_t ipv4_ttl; /* time to live */ uint8_t ipv4_protocol; /* next level protocol */ string ipv4_protostr; /* next level protocol, as a string */ uint16_t ipv4_checksum; /* header checksum */ ipaddr_t ipv4_src; /* source address */ ipaddr_t ipv4_dst; /* destination address */ string ipv4_saddr; /* source address, string */ string ipv4_daddr; /* destination address, string */ ipha_t *ipv4_hdr; /* pointer to raw header */ } ipv4info_t;
ipv4info_t Members
ipv4_ver | IP version (4). |
ipv4_ihl | IPv4 header length, in bytes. |
ipv4_tos | Contents of IPv4 type of service field. |
ipv4_length | IPv4 packet length (header + payload) at time of tracing, in bytes. |
ipv4_ident | IPv4 identification field. |
ipv4_flags | IPv4 flags. See the ipv4_flags table below for bitwise values. |
ipv4_offset | IPv4 fragment offset, in bytes. |
ipv4_ttl | IPv4 time to live. |
ipv4_protocol | IPv4 encapsulated protocol number. See /usr/include/netinet/in.h for the protocol list (IPPROTO_*). |
ipv4_protostr | IPv4 encapsulated protocol, as a string. Eg, "TCP". |
ipv4_checksum | IPv4 header checksum, if available at time of tracing. |
ipv4_src | IPv4 source address, as an ipaddr_t. |
ipv4_dst | IPv4 destination address, as an ipaddr_t. |
ipv4_saddr | IPv4 source address, as a dotted decimal quad string. |
ipv4_daddr | IPv4 destination address, as a dotted decimal quad string. |
ipv4_hdr | Pointer to raw IPv4 header at the time of tracing. |
See RFC-791 for a detailed explanation for these IPv4 header fields. If the packet is IPv6, these members are either "<null>", 0, or NULL depending on type.
ipv4_flags Values
IPH_DF | Don't fragment |
IPH_MF | More fragments |
args[5] - ipv6info_t structure
The ipv6info_t structure is a DTrace translated version of the IPv6 header.
typedef struct ipv6info { uint8_t ipv6_ver; /* IP version (6) */ uint8_t ipv6_tclass; /* traffic class */ uint32_t ipv6_flow; /* flow label */ uint16_t ipv6_plen; /* payload length */ uint8_t ipv6_nexthdr; /* next header protocol */ string ipv6_nextstr; /* next header protocol, as a string*/ uint8_t ipv6_hlim; /* hop limit */ in6_addr_t *ipv6_src; /* source address */ in6_addr_t *ipv6_dst; /* destination address */ string ipv6_saddr; /* source address, string */ string ipv6_daddr; /* destination address, string */ ip6_t *ipv6_hdr; /* pointer to raw header */ } ipv6info_t;
ipv6info_t Members
ipv6_ver | IP version (6). |
ipv6_tclass | IPv6 traffic class. |
ipv6_flow | IPv6 flow label. |
ipv6_plen | IPv6 payload length at time of tracing, in bytes. |
ipv6_nexthdr | IPv6 next header protocol number. See /usr/include/netinet/in.h for the protocol list (IPPROTO_*). |
ipv6_nextstr | IPv6 next header protocol, as a string. Eg, "TCP". |
ipv6_hlim | IPv6 hop limit. |
ipv6_src | IPv6 source address, as an in6_addr_t. |
ipv6_dst | IPv6 destination address, as an in6_addr_t. |
ipv6_saddr | IPv6 source address, as an RFC-1884 convention 2 string with lower case hexadecimal digits. |
ipv6_daddr | IPv6 destination address, as an RFC-1884 convention 2 string with lower case hexadecimal digits. |
ipv6_hdr | Pointer to raw IPv6 header at the time of tracing. |
See RFC-2460 for a detailed explanation for these IPv6 header fields. If the packet is IPv4, these members are either "<null>", 0, or NULL depending on type.
Examples
Some simple examples of ip provider usage follow.
Packets by host address
This DTrace one-liner counts received packets by host address:
# dtrace -n 'ip:::receive { @[args[2]->ip_saddr] = count(); }' dtrace: description 'ip:::receive ' matched 4 probes ^C 192.168.1.5 1 192.168.1.185 4 fe80::214:4fff:fe3b:76c8 9 127.0.0.1 14 192.168.1.109 28
The output above shows that 28 IP packets were recieved from 192.168.1.109, 14 IP packets from 127.0.0.1, and so on.
Sent size distribution
This DTrace one-liner prints distribution plots of sent payload size by destination:
# dtrace -n 'ip:::send { @[args[2]->ip_daddr] = quantize(args[2]->ip_plength); }' dtrace: description 'ip:::send ' matched 11 probes ^C 192.168.2.27 value ------------- Distribution ------------- count 8 | 0 16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7 32 |@@@@ 1 64 |@@@@ 1 128 | 0 192.168.1.109 value ------------- Distribution ------------- count 8 | 0 16 |@@@@@ 5 32 |@@@ 3 64 |@@@@@@@@@@@@@@@@@@@@@@@@@@ 24 128 |@ 1 256 |@ 1 512 |@@ 2 1024 |@ 1 2048 | 0
ipio.d
The following DTrace script traces IP packets and prints various details:
#!/usr/sbin/dtrace -s #pragma D option quiet #pragma D option switchrate=10hz dtrace:::BEGIN { printf(" %3s %10s %15s %15s %8s %6s\n", "CPU", "DELTA(us)", "SOURCE", "DEST", "INT", "BYTES"); last = timestamp; } ip:::send { this->elapsed = (timestamp - last) / 1000; printf(" %3d %10d %15s -> %15s %8s %6d\n", cpu, this->elapsed, args[2]->ip_saddr, args[2]->ip_daddr, args[3]->if_name, args[2]->ip_plength); last = timestamp; } ip:::receive { this->elapsed = (timestamp - last) / 1000; printf(" %3d %10d %15s <- %15s %8s %6d\n", cpu, this->elapsed, args[2]->ip_daddr, args[2]->ip_saddr, args[3]->if_name, args[2]->ip_plength); last = timestamp; }
This example output shows tracing packets as they pass in and out of tunnels:
# ./ipio.d CPU DELTA(us) SOURCE DEST INT BYTES 1 598913 10.1.100.123 -> 192.168.10.75 ip.tun0 68 1 73 192.168.1.108 -> 192.168.5.1 nge0 140 1 18325 192.168.1.108 <- 192.168.5.1 nge0 140 1 69 10.1.100.123 <- 192.168.10.75 ip.tun0 68 0 102921 10.1.100.123 -> 192.168.10.75 ip.tun0 20 0 79 192.168.1.108 -> 192.168.5.1 nge0 92
The fields printed are:
field | description |
---|---|
CPU | CPU id that event occurred on |
DELTA(us) | elapsed time since previous event |
SOURCE | source IP address |
DEST | destination IP address |
INT | interface name |
BYTES | payload bytes |
Note: The output may be shuffled slightly on multi-CPU servers due to DTrace per-CPU buffering; keep an eye on changes in the CPU column, or add a timestamp column and post sort.
ipproto.d
This DTrace script provides a neat summary for both send and receive IP traffic, including the next level protocol:
#!/usr/sbin/dtrace -s #pragma D option quiet dtrace:::BEGIN { printf("Tracing... Hit Ctrl-C to end.\n"); } ip:::send, ip:::receive { this->protostr = args[2]->ip_ver == 4 ? args[4]->ipv4_protostr : args[5]->ipv6_nextstr; @num[args[2]->ip_saddr, args[2]->ip_daddr, this->protostr] = count(); } dtrace:::END { printf(" %-28s %-28s %6s %8s\n", "SADDR", "DADDR", "PROTO", "COUNT"); printa(" %-28s %-28s %6s %@8d\n", @num); }
This script was run on a system with both IPv4 and IPv6 interfaces for several seconds:
# ./ipproto.d Tracing... Hit Ctrl-C to end. ^C SADDR DADDR PROTO COUNT 192.168.1.108 192.168.155.32 UDP 1 192.168.1.108 192.168.17.55 UDP 1 192.168.1.108 192.168.228.54 UDP 1 192.168.1.108 192.168.1.5 UDP 1 192.168.1.108 192.168.2.27 ICMP 1 192.168.1.200 192.168.3.255 UDP 1 192.168.1.5 192.168.1.108 UDP 1 192.168.2.27 192.168.1.108 ICMP 1 fe80::214:4fff:fe3b:76c8 ff02::1 ICMPV6 1 fe80::2e0:81ff:fe5e:8308 fe80::214:4fff:fe3b:76c8 ICMPV6 1 fe80::2e0:81ff:fe5e:8308 ff02::1:2 UDP 1 192.168.1.185 192.168.1.255 UDP 2 192.168.1.211 192.168.1.255 UDP 3 192.168.1.109 192.168.1.108 TCP 428 192.168.1.108 192.168.1.109 TCP 789
The fields printed are:
field | description |
---|---|
SADDR | source IP address |
DADDR | destination IP address |
PROTO | IP next level protocol |
COUNT | number of packets |
The example output above provides a quick summary of network activity with host address details; we can see that both 192.168.1.109 and 192.168.1.108 are swapping many packets via TCP.
Stability
The ip provider uses DTrace's stability mechanism to describe its stabilities, as shown in the following table. For more information about the stability mechanism, see Chapter 39, Stability.
Element | Name stability | Data stability | Dependency class |
---|---|---|---|
Provider | Evolving | Evolving | ISA |
Module | Private | Private | Unknown |
Function | Private | Private | Unknown |
Name | Evolving | Evolving | ISA |
Arguments | Evolving | Evolving | ISA |