Query Ethtool via Netlink Kernel Interface
Besides old ioctl
interface of ethtool, the linux kernel also provides
netlink interface for controlling ethtool.
The existing documents does not serve me well on getting my work done, so I hope this blog could help others by demonstrate on querying ethtool PAUSE informations via netlink.
The libnl has already provided many helper functions regarding communicating through generic netlink interface. But I think the understanding of every bits in netlink message is essential skill set of a good network developer.
Package structure
The ethtool is using NETLINK_GENERIC
family of netlink with below
data structure on each request and reply:
+-------------------------------------------------------------------+
| |
| Netlink Header(struct nlmsghdr) |
| |
+-------------------------------------------------------------------+
| |
| Generic Netlink Header(struct genlmsghdr) |
| |
+-------------------------------------------------------------------+
| |
| Ethtool Attributes |
| |
+-------------------------------------------------------------------+
.
.
.
Netlink Header
The netlink header struct nlmsghdr
is holding nlmsg_type
to differentiate
which kernel module is responsible for processing this netlink request(the
wifi nl80211 is also using NETLINK_GENERIC
).
In libnl and kernel code of generic netlink, this nlmsg_type
is also called
as Family ID.
The ethtool netlink kernel module is required to register itself to get a family id/message type dynamically allocated.
The user space program need to use the reserved GENL_ID_CTRL
netlink message
type/family id to find out the family ID they are interested. I will explain
that in follow up sections.
The netlink header also holds flags
which is useful for ethtool netlink
communication. The most commonly used flags for querying are:
NLM_F_REQUEST
– Mandatory for all request sending from user to kernel.NLM_F_DUMP
– Dump the information for all interfaces.
Generic Netlink Header
The generic netlink header struct genlmsghdr
is holding cmd
to
differentiate which function is responsible for processing this netlink
request.
For example, the CTRL_CMD_GETFAMILY
is used to retrieve the netlink message
type/family ID.
Ethtool Attributes
The contents of ethtool netlink package after the generic netlink header
is wrapped into nested(NLA_F_NESTED
) netlink attribute(struct nlattr
)
including both the ethtool headers and contents.
There could be multiple ethtool header included in single netlink
request/reply. They are using these nla_type
:
ETHTOOL_A_HEADER_DEV_INDEX
– For interface indexETHTOOL_A_HEADER_DEV_NAME
– For interface nameETHTOOL_A_HEADER_FLAGS
– For flags
For example, if you would like to request the ethtool PAUSE information of
sim0
. You need to include this netlink attribute after the generic netlink
header:
- type:
ETHTOOL_A_HEADER_DEV_NAME
- payload:
sim0\0
Even when you are dumping(NLM_F_DUMP
) the information, you still
need to include a empty netlink attribute:
- type:
ETHTOOL_A_PAUSE_HEADER | NLA_F_NESTED
- payload:
NULL
Workflow
Let me walk you through the whole ethool netlink interface by querying sim0’s ethtool PAUSE option by a userspace program:
- Query the family ID of ethtool.
- Assemble the netlink message for querying PAUSE option.
- Send request to netlink socket.
- Parse the netlink reply message.
Using netdevsim kernel module, you may simulate a network interface with ethtool PAUSE support via this script:
|
|
Query the Family ID of Ethtool
To query the family ID of ethtool, you need:
- netlink header flag:
NLM_F_REQUEST
- netlink header message type:
GENL_ID_CTRL
- generic netlink header cmd:
CTRL_CMD_GETFAMILY
- generic netlink header version:
CTRL_CMD_GETFAMILY_VERSION
- netlink attribute type:
CTRL_ATTR_FAMILY_NAME
- netlink attribute payload:
sim0\0
The message on wire send from userspace to kernel will be:
# Netlink Header
0x28 0x00 0x00 0x00 # totol netlink message length
0x10 0x00 0x01 0x00 # 0x10 0x00: `GENL_ID_CTRL`
# 0x01 0x00: flags: NLM_F_REQUEST
0x00 0x00 0x00 0x00 # Sequence number
0x00 0x00 0x00 0x00 # Sending process port ID
# Generic Netlink Header
0x03 0x01 0x00 0x00 # 0x03: CTRL_CMD_GETFAMILY
# 0x01: CTRL_CMD_GETFAMILY_VERSION
# 0x00 0x00: reserved
# Netlink attribute - CTRL_ATTR_FAMILY_NAME
0x14 0x00 0x02 0x00 # 0x14 0x00: lenth of this attribute
# 0x02 0x00: CTRL_ATTR_FAMILY_NAME
0x65 0x74 0x68 0x74 # C chars: e t h t
0x6f 0x6f 0x6c 0x00 # C chars: o o l NULL
0x00 0x00 0x00 0x00 # padding
0x00 0x00 0x00 0x00 # padding
The kernel will reply with a lot netlink attributes, one of them is:
- netlink attribute type:
CTRL_ATTR_FAMILY_NAME
- netlink attribute payload: 21(just example, might be different in your OS)
The message on wire send from kernel to userspace is to large to explain in this blog. You may parse it like above.
Assemble the Netlink Message for Querying PAUSE Option
To query ethtool PAUSE options, you need:
- netlink header flag:
NLM_F_REQUEST
- netlink header message type: 21 (the number you get in previous step)
- generic netlink header cmd:
ETHTOOL_MSG_PAUSE_GET
- generic netlink header version:
ETHTOOL_GENL_VERSION
- netlink attribute type:
ETHTOOL_A_PAUSE_HEADER | NLA_F_NESTED
- netlink attribute payload: is another netlink attribute
- netlink attribute type:
ETHTOOL_A_HEADER_DEV_NAME
- netlink attribute payload:
sim0\0
- netlink attribute type:
The message on wire send from userspace to kernel will be:
# Netlink header
0x24 0x00 0x00 0x00 # length of netlink message
0x15 0x00 0x01 0x00 # 0x15 0x00: family ID 21
# 0x01 0x00: flags: NLM_F_REQUEST
0x00 0x00 0x00 0x00 # Sequence number
0x00 0x00 0x00 0x00 # Sending process port ID
# Generic Netlink Header
0x15 0x01 0x00 0x00 # 0x15: `ETHTOOL_MSG_PAUSE_GET`
# 0x01: `ETHTOOL_GENL_VERSION`
# 0x00 0x00: reserved
# Netlink attribute - ethtool header ETHTOOL_A_PAUSE_HEADER
0x10 0x00 0x01 0x80 # 0x10 0x00: length 16
# 0x01 0x80: `ETHTOOL_A_PAUSE_HEADER | NLA_F_NESTED`
# Netlink attribute - ethtool header ETHTOOL_A_HEADER_DEV_NAME
0x09 0x00 0x02 0x00 # 0x09 0x00: length 9 (without padding)
# 0x02 0x00: `ETHTOOL_A_HEADER_DEV_NAME`
0x73 0x69 0x6d 0x30 # c char: s i m 0
0x00 0x00 0x00 0x00 # NULL and padding.
Send Request to Netlink Socket.
You should:
Bind to
AF_NETLINK
socket with family ID 21(the number you retrieved in previous call).Send above netlink message to:
|
|
Parse the Netlink Reply message.
The message on wire reply from kernel to use space will be:
# Netlink Header
0x44 0x00 0x00 0x00 # length of this message
0x15 0x00 0x00 0x00 # 0x15 0x00: Family ID 21
# flags: 0
0x01 0x00 0x00 0x00 # sequence number, you may ignore it
0x3c 0x05 0x88 0xb2 # Sending process port ID, you may ignore it
# Generic Netlink Header
0x16 0x01 0x00 0x00 # 0x16: `ETHTOOL_MSG_PAUSE_GET_REPLY`
# 0x01: `ETHTOOL_GENL_VERSION`
# 0x00 0x00: reserved
# Netlink Attributes -- ethtool header
0x18 0x00 0x01 0x80 # 0x18 0x00: lenth 24
# 0x01 0x80: `ETHTOOL_A_PAUSE_HEADER | NLA_F_NESTED`
# Netlink Attributes -- ethtool header ETHTOOL_A_HEADER_DEV_INDEX
0x08 0x00 0x01 0x00 # 0x08 0x00: length 8
# 0x01 0x00: `ETHTOOL_A_HEADER_DEV_INDEX`
0x0b 0x00 0x00 0x00 # 0x0b 0x00, 0x00, 0x00: interface index 11
# Netlink Attributes -- ethtool header ETHTOOL_A_HEADER_DEV_NAME
0x09 0x00 0x02 0x00 # 0x09 0x00: length 9(without padding)
# 0x02 0x00: `ETHTOOL_A_HEADER_DEV_NAME`
0x73 0x69 0x6d 0x30 # c char: sim0
0x00 0x00 0x00 0x00 # NULL and padding. nested header ends at 24 length
# Netlink Attributes -- ethtool header ETHTOOL_A_PAUSE_AUTONEG
0x05 0x00 0x02 0x00 # 0x05 0x00: lenth 5(without padding)
# 0x02 0x00: ETHTOOL_A_PAUSE_AUTONEG
# Netlink Attributes -- ethtool header ETHTOOL_A_PAUSE_RX
0x00 0x00 0x00 0x00 # u8 payload: FALSE and padding
0x05 0x00 0x03 0x00 # 0x05 0x00: lenth 5(without padding)
# 0x03 0x00: ETHTOOL_A_PAUSE_RX
0x01 0x00 0x00 0x00 # u8 payload: TRUE and padding
# Netlink Attributes -- ethtool header ETHTOOL_A_PAUSE_TX
0x05 0x00 0x04 0x00 # 0x05 0x00: lenth 5(without padding)
# 0x04 0x00: ETHTOOL_A_PAUSE_TX
0x01 0x00 0x00 0x00 # u8 payload: TRUE and padding.