Line data Source code
1 : /*
2 : * vr_dpdk_netlink.c -- message handling from agent
3 : *
4 : * Copyright (c) 2014, Juniper Networks Private Inc.,
5 : * Copyright Contributors to the OpenSDN project
6 : * All rights reserved
7 : */
8 :
9 : #include <stdint.h>
10 : #include <sys/stat.h>
11 : #include <sys/un.h>
12 : #include <linux/genetlink.h>
13 :
14 : #include <rte_errno.h>
15 : #include "nl_util.h"
16 : #include "vr_dpdk.h"
17 : #include "vr_dpdk_usocket.h"
18 : #include "vr_message.h"
19 : #include "vr_genetlink.h"
20 : #include "vr_uvhost.h"
21 : #include "vr_uvhost_msg.h"
22 :
23 : #define HDR_LEN (NLMSG_HDRLEN + GENL_HDRLEN + sizeof(struct nlattr))
24 :
25 : struct nlmsghdr *dpdk_nl_message_hdr(struct vr_message *);
26 : unsigned int dpdk_nl_message_len(struct vr_message *);
27 :
28 : int vr_usocket_message_write(struct vr_usocket *, struct vr_message *);
29 : int vr_nl_uvh_sock;
30 :
31 : void
32 53 : vr_dpdk_netlink_wakeup(void)
33 : {
34 53 : if (likely(vr_dpdk.netlink_event_sock != NULL)) {
35 53 : if (vr_usocket_eventfd_write(vr_dpdk.netlink_event_sock) < 0) {
36 0 : vr_usocket_close(vr_dpdk.netlink_event_sock);
37 0 : vr_dpdk.netlink_event_sock = NULL;
38 : }
39 : }
40 53 : }
41 :
42 : static void
43 2862 : dpdk_nl_process_response(void *usockp, struct nlmsghdr *nlh)
44 : {
45 : __u32 seq;
46 2862 : unsigned int multi_flag = 0;
47 2862 : bool write = true;
48 :
49 : struct vr_message *resp;
50 :
51 : struct nlmsghdr *resp_nlh;
52 : struct genlmsghdr *genlh, *resp_genlh;
53 : struct nlattr *resp_nla;
54 :
55 2862 : seq = nlh->nlmsg_seq;
56 2862 : genlh = (struct genlmsghdr *)((unsigned char *)nlh + NLMSG_HDRLEN);
57 :
58 : /* Process responses */
59 5725 : while ((resp = (struct vr_message *)vr_message_dequeue_response())) {
60 2863 : if (!write) {
61 0 : vr_message_free(resp);
62 0 : continue;
63 : }
64 :
65 2863 : if (!vr_response_queue_empty()) {
66 1 : multi_flag = NLM_F_MULTI;
67 : } else {
68 2862 : multi_flag = 0;
69 : }
70 :
71 : /* Update Netlink headers */
72 2863 : resp_nlh = dpdk_nl_message_hdr(resp);
73 2863 : resp_nlh->nlmsg_len = dpdk_nl_message_len(resp);
74 2863 : resp_nlh->nlmsg_type = nlh->nlmsg_type;
75 2863 : resp_nlh->nlmsg_flags = multi_flag;
76 2863 : resp_nlh->nlmsg_seq = seq;
77 2863 : resp_nlh->nlmsg_pid = 0;
78 :
79 2863 : resp_genlh = (struct genlmsghdr *)((unsigned char *)resp_nlh +
80 : NLMSG_HDRLEN);
81 2863 : memcpy(resp_genlh, genlh, sizeof(*genlh));
82 :
83 2863 : resp_nla = (struct nlattr *)((unsigned char *)resp_genlh + GENL_HDRLEN);
84 2863 : resp_nla->nla_len = resp->vr_message_len;
85 2863 : resp_nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL;
86 :
87 2863 : if (vr_usocket_message_write(usockp, resp) < 0) {
88 0 : write = false;
89 0 : vr_usocket_close(usockp);
90 : }
91 : }
92 :
93 2862 : return;
94 : }
95 :
96 : int
97 2862 : dpdk_netlink_receive(void *usockp, char *nl_buf,
98 : unsigned int nl_len)
99 : {
100 : int ret;
101 : struct vr_message request;
102 :
103 2862 : memset(&request, 0, sizeof(request));
104 2862 : request.vr_message_buf = nl_buf + HDR_LEN;
105 2862 : request.vr_message_len = nl_len - HDR_LEN;
106 :
107 2862 : ret = vr_message_request(&request);
108 2862 : if (ret < 0)
109 0 : vr_send_response(ret);
110 :
111 2862 : dpdk_nl_process_response(usockp, (struct nlmsghdr *)nl_buf);
112 :
113 2862 : return 0;
114 : }
115 :
116 : unsigned int
117 5726 : dpdk_nl_message_len(struct vr_message *message)
118 : {
119 5726 : return message->vr_message_len + HDR_LEN;
120 : }
121 :
122 : struct nlmsghdr *
123 5726 : dpdk_nl_message_hdr(struct vr_message *message)
124 : {
125 5726 : return (struct nlmsghdr *)(message->vr_message_buf - HDR_LEN);
126 : }
127 :
128 : static void
129 2863 : dpdk_nl_trans_free(char *buf)
130 : {
131 2863 : buf -= HDR_LEN;
132 2863 : vr_free(buf, VR_MESSAGE_OBJECT);
133 :
134 2863 : return;
135 : }
136 :
137 : static char *
138 2863 : dpdk_nl_trans_alloc(unsigned int size)
139 : {
140 : char *buf;
141 :
142 2863 : buf = vr_malloc(size + HDR_LEN, VR_MESSAGE_OBJECT);
143 2863 : if (!buf)
144 0 : return NULL;
145 :
146 2863 : return buf + HDR_LEN;
147 : }
148 :
149 : static struct vr_mtransport dpdk_nl_transport = {
150 : .mtrans_alloc = dpdk_nl_trans_alloc,
151 : .mtrans_free = dpdk_nl_trans_free,
152 : };
153 :
154 : /*
155 : * vr_netlink_uvhost_vif_del - sends a message to the user space vhost
156 : * thread when a vif is deleted. vif_idx is the index of the vif.
157 : *
158 : * Returns 0 on success, -1 otherwise.
159 : */
160 : int
161 166 : vr_netlink_uvhost_vif_del(unsigned int vif_idx)
162 : {
163 : vrnu_msg_t msg;
164 :
165 166 : memset(&msg, 0, sizeof(msg));
166 166 : msg.vrnum_type = VRNU_MSG_VIF_DEL;
167 166 : msg.vrnum_vif_del.vrnu_vif_idx = vif_idx;
168 :
169 : /*
170 : * This is a blocking send.
171 : */
172 166 : if (send(vr_nl_uvh_sock, (void *) &msg, sizeof(msg), 0) !=
173 : sizeof(msg)) {
174 0 : RTE_LOG(ERR, VROUTER, " error deleting vif %u from user space vhost:"
175 : " %s (%d)\n", vif_idx, rte_strerror(errno), errno);
176 0 : return -1;
177 : }
178 :
179 166 : return 0;
180 : }
181 :
182 : /*
183 : * vr_netlink_uvhost_vif_add - sends a message to the user space vhost
184 : * thread when a new vif is created. The name os the vif is specified in
185 : * the vif_name argument.
186 : *
187 : * Returns 0 on success, -1 otherwise.
188 : */
189 : int
190 332 : vr_netlink_uvhost_vif_add(char *vif_name, uint32_t vif_idx,
191 : uint32_t vif_gen, uint32_t vif_nrxqs,
192 : uint32_t vif_ntxqs,
193 : unsigned char vif_vhostuser_mode)
194 : {
195 : vrnu_msg_t msg;
196 :
197 332 : memset(&msg, 0, sizeof(msg));
198 332 : msg.vrnum_type = VRNU_MSG_VIF_ADD;
199 332 : strncpy(msg.vrnum_vif_add.vrnu_vif_name, vif_name,
200 : sizeof(msg.vrnum_vif_add.vrnu_vif_name) - 1);
201 332 : msg.vrnum_vif_add.vrnu_vif_idx = vif_idx;
202 332 : msg.vrnum_vif_add.vrnu_vif_nrxqs = vif_nrxqs;
203 332 : msg.vrnum_vif_add.vrnu_vif_ntxqs = vif_ntxqs;
204 332 : msg.vrnum_vif_add.vrnu_vif_gen = vif_gen;
205 332 : msg.vrnum_vif_add.vrnu_vif_vhostuser_mode = vif_vhostuser_mode;
206 :
207 : /*
208 : * This is a blocking send.
209 : */
210 332 : if (send(vr_nl_uvh_sock, (void *) &msg, sizeof(msg), 0) !=
211 : sizeof(msg)) {
212 0 : RTE_LOG(ERR, VROUTER, " error adding vif %u to user space vhost:"
213 : " %s (%d)\n", vif_idx, rte_strerror(errno), errno);
214 0 : return -1;
215 : }
216 :
217 332 : return 0;
218 : }
219 :
220 : void
221 53 : dpdk_netlink_exit(void)
222 : {
223 53 : vr_message_transport_unregister(&dpdk_nl_transport);
224 53 : vr_usocket_close(vr_dpdk.netlink_sock);
225 53 : vr_dpdk.netlink_sock = NULL;
226 53 : vr_dpdk.netlink_event_sock = NULL;
227 :
228 53 : return;
229 : }
230 :
231 : /*
232 : * vr_nl_uvhost_connect - connect to the user space vhost server on a UNIX
233 : * domain socket.
234 : *
235 : * Returns 0 on success, error otherwise.
236 : */
237 : static int
238 53 : vr_nl_uvhost_connect(void)
239 : {
240 53 : int s = 0, ret = -1, err;
241 : struct sockaddr_un nl_sun, uvh_sun;
242 :
243 53 : s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
244 53 : if (s == -1) {
245 0 : RTE_LOG(ERR, VROUTER, " error creating uvhost socket: %s (%d)\n",
246 : rte_strerror(errno), errno);
247 0 : goto error;
248 : }
249 53 : RTE_LOG(INFO, VROUTER, " uvhost Unix socket FD is %d\n", s);
250 :
251 53 : memset(&nl_sun, 0, sizeof(nl_sun));
252 53 : nl_sun.sun_family = AF_UNIX;
253 53 : strncpy(nl_sun.sun_path, vr_socket_dir, sizeof(nl_sun.sun_path) - 1);
254 53 : strncat(nl_sun.sun_path, "/"VR_NL_UVH_SOCK_NAME, sizeof(nl_sun.sun_path)
255 53 : - strlen(nl_sun.sun_path) - 1);
256 :
257 53 : mkdir(vr_socket_dir, VR_DEF_SOCKET_DIR_MODE);
258 53 : unlink(nl_sun.sun_path);
259 53 : ret = bind(s, (struct sockaddr *) &nl_sun, sizeof(nl_sun));
260 53 : if (ret == -1) {
261 0 : RTE_LOG(ERR, VROUTER, " error binding uvhost FD %d to %s: %s (%d)\n",
262 : s, nl_sun.sun_path, rte_strerror(errno), errno);
263 0 : goto error;
264 : }
265 :
266 : /*
267 : * This will block until the user space vhost thread listens on the
268 : * socket.
269 : */
270 53 : memset(&uvh_sun, 0, sizeof(uvh_sun));
271 53 : uvh_sun.sun_family = AF_UNIX;
272 53 : strncpy(uvh_sun.sun_path, vr_socket_dir, sizeof(uvh_sun.sun_path) - 1);
273 53 : strncat(uvh_sun.sun_path, "/"VR_UVH_NL_SOCK_NAME, sizeof(uvh_sun.sun_path)
274 53 : - strlen(uvh_sun.sun_path) - 1);
275 :
276 53 : ret = vr_dpdk_retry_connect(s, (struct sockaddr *) &uvh_sun, sizeof(uvh_sun));
277 53 : if (ret == -1) {
278 0 : RTE_LOG(ERR, VROUTER, " error connecting uvhost socket FD %d to %s:"
279 : " %s (%d)\n", s, uvh_sun.sun_path, rte_strerror(errno), errno);
280 0 : goto error;
281 : }
282 :
283 53 : vr_nl_uvh_sock = s;
284 :
285 53 : return 0;
286 :
287 0 : error:
288 :
289 0 : err = errno;
290 0 : if (s > 0) {
291 0 : close(s);
292 : }
293 0 : errno = err;
294 :
295 0 : return ret;
296 : }
297 :
298 : /* Init NetLink and UVHost sockets */
299 : int
300 53 : vr_dpdk_netlink_init(void)
301 : {
302 53 : void *event_sock = NULL;
303 : int ret;
304 :
305 53 : RTE_LOG(INFO, VROUTER, "Starting NetLink...\n");
306 53 : ret = vr_message_transport_register(&dpdk_nl_transport);
307 53 : if (ret)
308 0 : return ret;
309 :
310 : #ifdef AGENT_VROUTER_TCP
311 : vr_dpdk.netlink_sock = vr_usocket(NETLINK, TCP);
312 : #else
313 53 : vr_dpdk.netlink_sock = vr_usocket(NETLINK, UNIX);
314 : #endif
315 53 : if (!vr_dpdk.netlink_sock) {
316 0 : RTE_LOG(ERR, VROUTER, " error creating NetLink server socket:"
317 : " %s (%d)\n", rte_strerror(errno), errno);
318 0 : goto error;
319 : }
320 53 : RTE_LOG(INFO, VROUTER, " NetLink TCP socket FD is %d\n",
321 : ((struct vr_usocket *)vr_dpdk.netlink_sock)->usock_fd);
322 :
323 53 : ret = vr_nl_uvhost_connect();
324 53 : if (ret != 0) {
325 0 : RTE_LOG(ERR, VROUTER, " error creating uvhost connection\n");
326 0 : goto error;
327 : }
328 :
329 : /* create and bind event usock to wake up the NetLink lcore */
330 53 : event_sock = (void *)vr_usocket(EVENT, RAW);
331 53 : if (!event_sock) {
332 0 : RTE_LOG(ERR, VROUTER, " error creating NetLink event\n");
333 0 : goto error;
334 : }
335 :
336 53 : if (vr_usocket_bind_usockets(vr_dpdk.netlink_sock,
337 : event_sock)) {
338 0 : RTE_LOG(ERR, VROUTER, " error binding NetLink event\n");
339 0 : goto error;
340 : }
341 53 : vr_dpdk.netlink_event_sock = event_sock;
342 :
343 53 : return 0;
344 :
345 0 : error:
346 0 : vr_message_transport_unregister(&dpdk_nl_transport);
347 0 : vr_usocket_close(vr_dpdk.netlink_sock);
348 :
349 0 : return -1;
350 : }
|