next up previous
Next: Usage - tc Up: QoS Support in Linux Previous: Dump

Interface between the kernel and user space

The interface between the kernel and the user space is achieved using netlink sockets. Netlink sockets are described in more detail in later sections. For now, let us look at the sequence of steps involved in executing a command given in the user space.

The interfaces between the kernel traffic elements and the user space programs are defined in include/linux/pkt_cls.h and include/linux/pkt_sched.h. The pkt_sched.h file will specify the parameters that are of significance in each type of queue. rtnetlink is used to exchange traffic control objects between the user level and the kernel level. This is specified in the net/core/rtnetlink.c and linux/include/rtnetlink.h. rtnetlink is based on netlink. The netlink socket uses the sockaddr_nl address structure. This is the structure that is used by the user level code to communicate with the kernel. The code for the netlink is in net/netlink/.

struct sockaddr_nl
        sa_family_t     nl_family;      /* AF_NETLINK   */
        unsigned short  nl_pad;         /* zero         */
        __u32           nl_pid;         /* process pid  */
        __u32           nl_groups;      /* multicast groups mask */

struct nlmsghdr
        __u32           nlmsg_len;      /* Length of message including header
        __u16           nlmsg_type;     /* Message content */
        __u16           nlmsg_flags;    /* Additional flags */
        __u32           nlmsg_seq;      /* Sequence number */
        __u32           nlmsg_pid;      /* Sending process PID */

The message format used to transmit traffic control messages to the kernel is shown in Figure 8. The messages are stored at byte boundaries. The length of the message includes the message header as well.

Figure 8: tc to kernel - Message formats

If traffic control is enabled in the linux kernel, at boot time, the __initfunc function in net/core/dev.c is called. This in turn invokes the pktsched_init function in net/sched/sch_api.c. This function initiates various declarations and bindings. One of the most important initializations that is done here is shown below:

struct rtnetlink_link *link_p;

if (link_p) {
 link_p[RTM_NEWQDISC-RTM_BASE].doit = tc_ctl_qdisc;
 link_p[RTM_DELQDISC-RTM_BASE].doit = tc_ctl_qdisc;
 link_p[RTM_GETQDISC-RTM_BASE].doit = tc_ctl_qdisc;
 link_p[RTM_GETQDISC-RTM_BASE].dumpit = tc_dump_qdisc;
 link_p[RTM_NEWTCLASS-RTM_BASE].doit = tc_ctl_tclass;
 link_p[RTM_DELTCLASS-RTM_BASE].doit = tc_ctl_tclass;
 link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;
 link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;
This fills in the pointers to the various functions that need to be called based on actions (i.e., add, delete, change etc) and entities (i.e., queuing disciplines, classes and filters) specified at the user level. This function also registers the various queuing disciplines that are supported during the kernel configuration.

A netlink socket is created from the user level application to the kernel, in order to send configuration messages, which will be interpreted and executed by the kernel. When the user issues a specific action on a specific entity, a sendto is done on the netlink socket. This results in the netlink_sendmsg function in net/netlink/af_netlink.c being invoked. The rtnetlink_rcv_msg function in net/core/rtnetlink.c receives the messages sent from the user space. In this function, the message header is examined (nlmsghdr) to determine the type of the message. The message type could be RTM_NEWQDISC, RTM_DELQDISC etc. Based on the message type, the corresponding function in rtnetlink_link is invoked (either doit or dumpit, which point to appropriate function). These are the steps involved in executing a command that is specified at the user level.

next up previous
Next: Usage - tc Up: QoS Support in Linux Previous: Dump
Saravanan Radhakrishnan