1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2017 6WIND S.A.
3 * Copyright 2017 Mellanox Technologies, Ltd
7 #include <linux/netlink.h>
12 #include <tap_tcmsgs.h>
25 struct qdisc_custom_arg {
32 * Initialize a netlink message with a TC header.
35 * The netlink message to fill.
37 * The netdevice ifindex where the rule will be applied.
39 * The type of TC message to create (RTM_NEWTFILTER, RTM_NEWQDISC, etc.).
41 * Overrides the default netlink flags for this msg with those specified.
44 tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type, uint16_t flags)
46 struct nlmsghdr *n = &msg->nh;
48 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
51 n->nlmsg_flags = flags;
53 n->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
54 msg->t.tcm_family = AF_UNSPEC;
55 msg->t.tcm_ifindex = ifindex;
59 * Delete a specific QDISC identified by its iface, and it's handle and parent.
62 * The netlink socket file descriptor used for communication.
64 * The netdevice ifindex on whom the deletion will happen.
66 * Additional info to identify the QDISC (handle and parent).
69 * 0 on success, -1 otherwise with errno set.
72 qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
77 tc_init_msg(&msg, ifindex, RTM_DELQDISC, 0);
78 msg.t.tcm_handle = qinfo->handle;
79 msg.t.tcm_parent = qinfo->parent;
80 /* if no netlink socket is provided, create one */
85 "Could not delete QDISC: null netlink socket\n");
91 if (tap_nl_send(fd, &msg.nh) < 0)
93 if (tap_nl_recv_ack(fd) < 0)
96 return tap_nl_final(fd);
105 * Add the multiqueue QDISC with MULTIQ_MAJOR_HANDLE handle.
108 * The netlink socket file descriptor used for communication.
110 * The netdevice ifindex where to add the multiqueue QDISC.
113 * 0 on success, -1 otherwise with errno set.
116 qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
118 struct tc_multiq_qopt opt;
121 tc_init_msg(&msg, ifindex, RTM_NEWQDISC,
122 NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
123 msg.t.tcm_handle = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
124 msg.t.tcm_parent = TC_H_ROOT;
125 tap_nlattr_add(&msg.nh, TCA_KIND, sizeof("multiq"), "multiq");
126 tap_nlattr_add(&msg.nh, TCA_OPTIONS, sizeof(opt), &opt);
127 if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
129 if (tap_nl_recv_ack(nlsk_fd) < 0)
135 * Add the ingress QDISC with default ffff: handle.
138 * The netlink socket file descriptor used for communication.
140 * The netdevice ifindex where the QDISC will be added.
143 * 0 on success, -1 otherwise with errno set.
146 qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
150 tc_init_msg(&msg, ifindex, RTM_NEWQDISC,
151 NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
152 msg.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
153 msg.t.tcm_parent = TC_H_INGRESS;
154 tap_nlattr_add(&msg.nh, TCA_KIND, sizeof("ingress"), "ingress");
155 if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
157 if (tap_nl_recv_ack(nlsk_fd) < 0)
163 * Callback function to delete a QDISC.
166 * The netlink message to parse, received from the kernel.
168 * Custom arguments for the callback.
171 * 0 on success, -1 otherwise with errno set.
174 qdisc_del_cb(struct nlmsghdr *nh, void *arg)
176 struct tcmsg *t = NLMSG_DATA(nh);
177 struct list_args *args = arg;
179 struct qdisc qinfo = {
180 .handle = t->tcm_handle,
181 .parent = t->tcm_parent,
184 /* filter out other ifaces' qdiscs */
185 if (args->ifindex != (unsigned int)t->tcm_ifindex)
188 * Use another nlsk_fd (0) to avoid tampering with the current list
191 return qdisc_del(0, args->ifindex, &qinfo);
195 * Iterate over all QDISC, and call the callback() function for each.
198 * The netlink socket file descriptor used for communication.
200 * The netdevice ifindex where to find QDISCs.
201 * @param[in] callback
202 * The function to call for each QDISC.
203 * @param[in, out] arg
204 * The arguments to provide the callback function with.
207 * 0 on success, -1 otherwise with errno set.
210 qdisc_iterate(int nlsk_fd, uint16_t ifindex,
211 int (*callback)(struct nlmsghdr *, void *), void *arg)
214 struct list_args args = {
220 tc_init_msg(&msg, ifindex, RTM_GETQDISC, NLM_F_REQUEST | NLM_F_DUMP);
221 if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
223 if (tap_nl_recv(nlsk_fd, callback, &args) < 0)
229 * Delete all QDISCs for a given netdevice.
232 * The netlink socket file descriptor used for communication.
234 * The netdevice ifindex where to find QDISCs.
237 * 0 on success, -1 otherwise with errno set.
240 qdisc_flush(int nlsk_fd, uint16_t ifindex)
242 return qdisc_iterate(nlsk_fd, ifindex, qdisc_del_cb, NULL);
246 * Create the multiqueue QDISC, only if it does not exist already.
249 * The netlink socket file descriptor used for communication.
251 * The netdevice ifindex where to add the multiqueue QDISC.
254 * 0 if the qdisc exists or if has been successfully added.
255 * Return -1 otherwise.
258 qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
262 err = qdisc_add_multiq(nlsk_fd, ifindex);
263 if (err < 0 && errno != -EEXIST) {
264 RTE_LOG(ERR, PMD, "Could not add multiq qdisc (%d): %s\n",
265 errno, strerror(errno));
272 * Create the ingress QDISC, only if it does not exist already.
275 * The netlink socket file descriptor used for communication.
277 * The netdevice ifindex where to add the ingress QDISC.
280 * 0 if the qdisc exists or if has been successfully added.
281 * Return -1 otherwise.
284 qdisc_create_ingress(int nlsk_fd, uint16_t ifindex)
288 err = qdisc_add_ingress(nlsk_fd, ifindex);
289 if (err < 0 && errno != -EEXIST) {
290 RTE_LOG(ERR, PMD, "Could not add ingress qdisc (%d): %s\n",
291 errno, strerror(errno));