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