]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/drivers/net/tap/tap_tcmsgs.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / tap / tap_tcmsgs.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2017 6WIND S.A.
3 * Copyright 2017 Mellanox Technologies, Ltd
4 */
5
6 #include <inttypes.h>
7 #include <linux/netlink.h>
8 #include <net/if.h>
9 #include <string.h>
10
11 #include <rte_log.h>
12 #include <tap_tcmsgs.h>
13 #include "tap_log.h"
14
15 struct qdisc {
16 uint32_t handle;
17 uint32_t parent;
18 };
19
20 struct list_args {
21 int nlsk_fd;
22 uint16_t ifindex;
23 void *custom_arg;
24 };
25
26 struct qdisc_custom_arg {
27 uint32_t handle;
28 uint32_t parent;
29 uint8_t exists;
30 };
31
32 /**
33 * Initialize a netlink message with a TC header.
34 *
35 * @param[in, out] msg
36 * The netlink message to fill.
37 * @param[in] ifindex
38 * The netdevice ifindex where the rule will be applied.
39 * @param[in] type
40 * The type of TC message to create (RTM_NEWTFILTER, RTM_NEWQDISC, etc.).
41 * @param[in] flags
42 * Overrides the default netlink flags for this msg with those specified.
43 */
44 void
45 tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type, uint16_t flags)
46 {
47 struct nlmsghdr *n = &msg->nh;
48
49 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
50 n->nlmsg_type = type;
51 if (flags)
52 n->nlmsg_flags = flags;
53 else
54 n->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
55 msg->t.tcm_family = AF_UNSPEC;
56 msg->t.tcm_ifindex = ifindex;
57 }
58
59 /**
60 * Delete a specific QDISC identified by its iface, and it's handle and parent.
61 *
62 * @param[in] nlsk_fd
63 * The netlink socket file descriptor used for communication.
64 * @param[in] ifindex
65 * The netdevice ifindex on whom the deletion will happen.
66 * @param[in] qinfo
67 * Additional info to identify the QDISC (handle and parent).
68 *
69 * @return
70 * 0 on success, -1 otherwise with errno set.
71 */
72 static int
73 qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
74 {
75 struct nlmsg msg;
76 int fd = 0;
77
78 tc_init_msg(&msg, ifindex, RTM_DELQDISC, 0);
79 msg.t.tcm_handle = qinfo->handle;
80 msg.t.tcm_parent = qinfo->parent;
81 /* if no netlink socket is provided, create one */
82 if (!nlsk_fd) {
83 fd = tap_nl_init(0);
84 if (fd < 0) {
85 TAP_LOG(ERR,
86 "Could not delete QDISC: null netlink socket");
87 return -1;
88 }
89 } else {
90 fd = nlsk_fd;
91 }
92 if (tap_nl_send(fd, &msg.nh) < 0)
93 goto error;
94 if (tap_nl_recv_ack(fd) < 0)
95 goto error;
96 if (!nlsk_fd)
97 return tap_nl_final(fd);
98 return 0;
99 error:
100 if (!nlsk_fd)
101 tap_nl_final(fd);
102 return -1;
103 }
104
105 /**
106 * Add the multiqueue QDISC with MULTIQ_MAJOR_HANDLE handle.
107 *
108 * @param[in] nlsk_fd
109 * The netlink socket file descriptor used for communication.
110 * @param[in] ifindex
111 * The netdevice ifindex where to add the multiqueue QDISC.
112 *
113 * @return
114 * 0 on success, -1 otherwise with errno set.
115 */
116 int
117 qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
118 {
119 struct tc_multiq_qopt opt = {0};
120 struct nlmsg msg;
121
122 tc_init_msg(&msg, ifindex, RTM_NEWQDISC,
123 NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
124 msg.t.tcm_handle = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
125 msg.t.tcm_parent = TC_H_ROOT;
126 tap_nlattr_add(&msg.nh, TCA_KIND, sizeof("multiq"), "multiq");
127 tap_nlattr_add(&msg.nh, TCA_OPTIONS, sizeof(opt), &opt);
128 if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
129 return -1;
130 if (tap_nl_recv_ack(nlsk_fd) < 0)
131 return -1;
132 return 0;
133 }
134
135 /**
136 * Add the ingress QDISC with default ffff: handle.
137 *
138 * @param[in] nlsk_fd
139 * The netlink socket file descriptor used for communication.
140 * @param[in] ifindex
141 * The netdevice ifindex where the QDISC will be added.
142 *
143 * @return
144 * 0 on success, -1 otherwise with errno set.
145 */
146 int
147 qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
148 {
149 struct nlmsg msg;
150
151 tc_init_msg(&msg, ifindex, RTM_NEWQDISC,
152 NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
153 msg.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
154 msg.t.tcm_parent = TC_H_INGRESS;
155 tap_nlattr_add(&msg.nh, TCA_KIND, sizeof("ingress"), "ingress");
156 if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
157 return -1;
158 if (tap_nl_recv_ack(nlsk_fd) < 0)
159 return -1;
160 return 0;
161 }
162
163 /**
164 * Callback function to delete a QDISC.
165 *
166 * @param[in] nh
167 * The netlink message to parse, received from the kernel.
168 * @param[in] arg
169 * Custom arguments for the callback.
170 *
171 * @return
172 * 0 on success, -1 otherwise with errno set.
173 */
174 static int
175 qdisc_del_cb(struct nlmsghdr *nh, void *arg)
176 {
177 struct tcmsg *t = NLMSG_DATA(nh);
178 struct list_args *args = arg;
179
180 struct qdisc qinfo = {
181 .handle = t->tcm_handle,
182 .parent = t->tcm_parent,
183 };
184
185 /* filter out other ifaces' qdiscs */
186 if (args->ifindex != (unsigned int)t->tcm_ifindex)
187 return 0;
188 /*
189 * Use another nlsk_fd (0) to avoid tampering with the current list
190 * iteration.
191 */
192 return qdisc_del(0, args->ifindex, &qinfo);
193 }
194
195 /**
196 * Iterate over all QDISC, and call the callback() function for each.
197 *
198 * @param[in] nlsk_fd
199 * The netlink socket file descriptor used for communication.
200 * @param[in] ifindex
201 * The netdevice ifindex where to find QDISCs.
202 * @param[in] callback
203 * The function to call for each QDISC.
204 * @param[in, out] arg
205 * The arguments to provide the callback function with.
206 *
207 * @return
208 * 0 on success, -1 otherwise with errno set.
209 */
210 static int
211 qdisc_iterate(int nlsk_fd, uint16_t ifindex,
212 int (*callback)(struct nlmsghdr *, void *), void *arg)
213 {
214 struct nlmsg msg;
215 struct list_args args = {
216 .nlsk_fd = nlsk_fd,
217 .ifindex = ifindex,
218 .custom_arg = arg,
219 };
220
221 tc_init_msg(&msg, ifindex, RTM_GETQDISC, NLM_F_REQUEST | NLM_F_DUMP);
222 if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
223 return -1;
224 if (tap_nl_recv(nlsk_fd, callback, &args) < 0)
225 return -1;
226 return 0;
227 }
228
229 /**
230 * Delete all QDISCs for a given netdevice.
231 *
232 * @param[in] nlsk_fd
233 * The netlink socket file descriptor used for communication.
234 * @param[in] ifindex
235 * The netdevice ifindex where to find QDISCs.
236 *
237 * @return
238 * 0 on success, -1 otherwise with errno set.
239 */
240 int
241 qdisc_flush(int nlsk_fd, uint16_t ifindex)
242 {
243 return qdisc_iterate(nlsk_fd, ifindex, qdisc_del_cb, NULL);
244 }
245
246 /**
247 * Create the multiqueue QDISC, only if it does not exist already.
248 *
249 * @param[in] nlsk_fd
250 * The netlink socket file descriptor used for communication.
251 * @param[in] ifindex
252 * The netdevice ifindex where to add the multiqueue QDISC.
253 *
254 * @return
255 * 0 if the qdisc exists or if has been successfully added.
256 * Return -1 otherwise.
257 */
258 int
259 qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
260 {
261 int err = 0;
262
263 err = qdisc_add_multiq(nlsk_fd, ifindex);
264 if (err < 0 && errno != -EEXIST) {
265 TAP_LOG(ERR, "Could not add multiq qdisc (%d): %s",
266 errno, strerror(errno));
267 return -1;
268 }
269 return 0;
270 }
271
272 /**
273 * Create the ingress QDISC, only if it does not exist already.
274 *
275 * @param[in] nlsk_fd
276 * The netlink socket file descriptor used for communication.
277 * @param[in] ifindex
278 * The netdevice ifindex where to add the ingress QDISC.
279 *
280 * @return
281 * 0 if the qdisc exists or if has been successfully added.
282 * Return -1 otherwise.
283 */
284 int
285 qdisc_create_ingress(int nlsk_fd, uint16_t ifindex)
286 {
287 int err = 0;
288
289 err = qdisc_add_ingress(nlsk_fd, ifindex);
290 if (err < 0 && errno != -EEXIST) {
291 TAP_LOG(ERR, "Could not add ingress qdisc (%d): %s",
292 errno, strerror(errno));
293 return -1;
294 }
295 return 0;
296 }