Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <config.h>
18 : :
19 : : #include "dpif-netlink.h"
20 : :
21 : : #include <ctype.h>
22 : : #include <errno.h>
23 : : #include <fcntl.h>
24 : : #include <inttypes.h>
25 : : #include <net/if.h>
26 : : #include <linux/types.h>
27 : : #include <linux/pkt_sched.h>
28 : : #include <poll.h>
29 : : #include <stdlib.h>
30 : : #include <strings.h>
31 : : #include <sys/epoll.h>
32 : : #include <sys/stat.h>
33 : : #include <unistd.h>
34 : :
35 : : #include "bitmap.h"
36 : : #include "dpif-provider.h"
37 : : #include "openvswitch/dynamic-string.h"
38 : : #include "flow.h"
39 : : #include "fat-rwlock.h"
40 : : #include "netdev.h"
41 : : #include "netdev-linux.h"
42 : : #include "netdev-vport.h"
43 : : #include "netlink-conntrack.h"
44 : : #include "netlink-notifier.h"
45 : : #include "netlink-socket.h"
46 : : #include "netlink.h"
47 : : #include "odp-util.h"
48 : : #include "openvswitch/ofpbuf.h"
49 : : #include "packets.h"
50 : : #include "poll-loop.h"
51 : : #include "random.h"
52 : : #include "openvswitch/shash.h"
53 : : #include "sset.h"
54 : : #include "timeval.h"
55 : : #include "unaligned.h"
56 : : #include "util.h"
57 : : #include "openvswitch/vlog.h"
58 : :
59 : 20190 : VLOG_DEFINE_THIS_MODULE(dpif_netlink);
60 : : #ifdef _WIN32
61 : : enum { WINDOWS = 1 };
62 : : #else
63 : : enum { WINDOWS = 0 };
64 : : #endif
65 : : enum { MAX_PORTS = USHRT_MAX };
66 : :
67 : : /* This ethtool flag was introduced in Linux 2.6.24, so it might be
68 : : * missing if we have old headers. */
69 : : #define ETH_FLAG_LRO (1 << 15) /* LRO is enabled */
70 : :
71 : : struct dpif_netlink_dp {
72 : : /* Generic Netlink header. */
73 : : uint8_t cmd;
74 : :
75 : : /* struct ovs_header. */
76 : : int dp_ifindex;
77 : :
78 : : /* Attributes. */
79 : : const char *name; /* OVS_DP_ATTR_NAME. */
80 : : const uint32_t *upcall_pid; /* OVS_DP_ATTR_UPCALL_PID. */
81 : : uint32_t user_features; /* OVS_DP_ATTR_USER_FEATURES */
82 : : const struct ovs_dp_stats *stats; /* OVS_DP_ATTR_STATS. */
83 : : const struct ovs_dp_megaflow_stats *megaflow_stats;
84 : : /* OVS_DP_ATTR_MEGAFLOW_STATS.*/
85 : : };
86 : :
87 : : static void dpif_netlink_dp_init(struct dpif_netlink_dp *);
88 : : static int dpif_netlink_dp_from_ofpbuf(struct dpif_netlink_dp *,
89 : : const struct ofpbuf *);
90 : : static void dpif_netlink_dp_dump_start(struct nl_dump *);
91 : : static int dpif_netlink_dp_transact(const struct dpif_netlink_dp *request,
92 : : struct dpif_netlink_dp *reply,
93 : : struct ofpbuf **bufp);
94 : : static int dpif_netlink_dp_get(const struct dpif *,
95 : : struct dpif_netlink_dp *reply,
96 : : struct ofpbuf **bufp);
97 : :
98 : : struct dpif_netlink_flow {
99 : : /* Generic Netlink header. */
100 : : uint8_t cmd;
101 : :
102 : : /* struct ovs_header. */
103 : : unsigned int nlmsg_flags;
104 : : int dp_ifindex;
105 : :
106 : : /* Attributes.
107 : : *
108 : : * The 'stats' member points to 64-bit data that might only be aligned on
109 : : * 32-bit boundaries, so get_unaligned_u64() should be used to access its
110 : : * values.
111 : : *
112 : : * If 'actions' is nonnull then OVS_FLOW_ATTR_ACTIONS will be included in
113 : : * the Netlink version of the command, even if actions_len is zero. */
114 : : const struct nlattr *key; /* OVS_FLOW_ATTR_KEY. */
115 : : size_t key_len;
116 : : const struct nlattr *mask; /* OVS_FLOW_ATTR_MASK. */
117 : : size_t mask_len;
118 : : const struct nlattr *actions; /* OVS_FLOW_ATTR_ACTIONS. */
119 : : size_t actions_len;
120 : : ovs_u128 ufid; /* OVS_FLOW_ATTR_FLOW_ID. */
121 : : bool ufid_present; /* Is there a UFID? */
122 : : bool ufid_terse; /* Skip serializing key/mask/acts? */
123 : : const struct ovs_flow_stats *stats; /* OVS_FLOW_ATTR_STATS. */
124 : : const uint8_t *tcp_flags; /* OVS_FLOW_ATTR_TCP_FLAGS. */
125 : : const ovs_32aligned_u64 *used; /* OVS_FLOW_ATTR_USED. */
126 : : bool clear; /* OVS_FLOW_ATTR_CLEAR. */
127 : : bool probe; /* OVS_FLOW_ATTR_PROBE. */
128 : : };
129 : :
130 : : static void dpif_netlink_flow_init(struct dpif_netlink_flow *);
131 : : static int dpif_netlink_flow_from_ofpbuf(struct dpif_netlink_flow *,
132 : : const struct ofpbuf *);
133 : : static void dpif_netlink_flow_to_ofpbuf(const struct dpif_netlink_flow *,
134 : : struct ofpbuf *);
135 : : static int dpif_netlink_flow_transact(struct dpif_netlink_flow *request,
136 : : struct dpif_netlink_flow *reply,
137 : : struct ofpbuf **bufp);
138 : : static void dpif_netlink_flow_get_stats(const struct dpif_netlink_flow *,
139 : : struct dpif_flow_stats *);
140 : : static void dpif_netlink_flow_to_dpif_flow(struct dpif *, struct dpif_flow *,
141 : : const struct dpif_netlink_flow *);
142 : :
143 : : /* One of the dpif channels between the kernel and userspace. */
144 : : struct dpif_channel {
145 : : struct nl_sock *sock; /* Netlink socket. */
146 : : long long int last_poll; /* Last time this channel was polled. */
147 : : };
148 : :
149 : : #ifdef _WIN32
150 : : #define VPORT_SOCK_POOL_SIZE 1
151 : : /* On Windows, there is no native support for epoll. There are equivalent
152 : : * interfaces though, that are not used currently. For simpicity, a pool of
153 : : * netlink sockets is used. Each socket is represented by 'struct
154 : : * dpif_windows_vport_sock'. Since it is a pool, multiple OVS ports may be
155 : : * sharing the same socket. In the future, we can add a reference count and
156 : : * such fields. */
157 : : struct dpif_windows_vport_sock {
158 : : struct nl_sock *nl_sock; /* netlink socket. */
159 : : };
160 : : #endif
161 : :
162 : : struct dpif_handler {
163 : : struct dpif_channel *channels;/* Array of channels for each handler. */
164 : : struct epoll_event *epoll_events;
165 : : int epoll_fd; /* epoll fd that includes channel socks. */
166 : : int n_events; /* Num events returned by epoll_wait(). */
167 : : int event_offset; /* Offset into 'epoll_events'. */
168 : :
169 : : #ifdef _WIN32
170 : : /* Pool of sockets. */
171 : : struct dpif_windows_vport_sock *vport_sock_pool;
172 : : size_t last_used_pool_idx; /* Index to aid in allocating a
173 : : socket in the pool to a port. */
174 : : #endif
175 : : };
176 : :
177 : : /* Datapath interface for the openvswitch Linux kernel module. */
178 : : struct dpif_netlink {
179 : : struct dpif dpif;
180 : : int dp_ifindex;
181 : :
182 : : /* Upcall messages. */
183 : : struct fat_rwlock upcall_lock;
184 : : struct dpif_handler *handlers;
185 : : uint32_t n_handlers; /* Num of upcall handlers. */
186 : : int uc_array_size; /* Size of 'handler->channels' and */
187 : : /* 'handler->epoll_events'. */
188 : :
189 : : /* Change notification. */
190 : : struct nl_sock *port_notifier; /* vport multicast group subscriber. */
191 : : bool refresh_channels;
192 : : };
193 : :
194 : : static void report_loss(struct dpif_netlink *, struct dpif_channel *,
195 : : uint32_t ch_idx, uint32_t handler_id);
196 : :
197 : : static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
198 : :
199 : : /* Generic Netlink family numbers for OVS.
200 : : *
201 : : * Initialized by dpif_netlink_init(). */
202 : : static int ovs_datapath_family;
203 : : static int ovs_vport_family;
204 : : static int ovs_flow_family;
205 : : static int ovs_packet_family;
206 : :
207 : : /* Generic Netlink multicast groups for OVS.
208 : : *
209 : : * Initialized by dpif_netlink_init(). */
210 : : static unsigned int ovs_vport_mcgroup;
211 : :
212 : : static int dpif_netlink_init(void);
213 : : static int open_dpif(const struct dpif_netlink_dp *, struct dpif **);
214 : : static uint32_t dpif_netlink_port_get_pid(const struct dpif *,
215 : : odp_port_t port_no, uint32_t hash);
216 : : static void dpif_netlink_handler_uninit(struct dpif_handler *handler);
217 : : static int dpif_netlink_refresh_channels(struct dpif_netlink *,
218 : : uint32_t n_handlers);
219 : : static void dpif_netlink_vport_to_ofpbuf(const struct dpif_netlink_vport *,
220 : : struct ofpbuf *);
221 : : static int dpif_netlink_vport_from_ofpbuf(struct dpif_netlink_vport *,
222 : : const struct ofpbuf *);
223 : :
224 : : static struct dpif_netlink *
225 : 39865 : dpif_netlink_cast(const struct dpif *dpif)
226 : : {
227 : 39865 : dpif_assert_class(dpif, &dpif_netlink_class);
228 : 39864 : return CONTAINER_OF(dpif, struct dpif_netlink, dpif);
229 : : }
230 : :
231 : : static int
232 : 122 : dpif_netlink_enumerate(struct sset *all_dps,
233 : : const struct dpif_class *dpif_class OVS_UNUSED)
234 : : {
235 : : struct nl_dump dump;
236 : : uint64_t reply_stub[NL_DUMP_BUFSIZE / 8];
237 : : struct ofpbuf msg, buf;
238 : : int error;
239 : :
240 : 122 : error = dpif_netlink_init();
241 [ - + ]: 122 : if (error) {
242 : 0 : return error;
243 : : }
244 : :
245 : 122 : ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub);
246 : 122 : dpif_netlink_dp_dump_start(&dump);
247 [ + + ]: 181 : while (nl_dump_next(&dump, &msg, &buf)) {
248 : : struct dpif_netlink_dp dp;
249 : :
250 [ + - ]: 59 : if (!dpif_netlink_dp_from_ofpbuf(&dp, &msg)) {
251 : 59 : sset_add(all_dps, dp.name);
252 : : }
253 : : }
254 : 122 : ofpbuf_uninit(&buf);
255 : 122 : return nl_dump_done(&dump);
256 : : }
257 : :
258 : : static int
259 : 186 : dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
260 : : bool create, struct dpif **dpifp)
261 : : {
262 : : struct dpif_netlink_dp dp_request, dp;
263 : : struct ofpbuf *buf;
264 : : uint32_t upcall_pid;
265 : : int error;
266 : :
267 : 186 : error = dpif_netlink_init();
268 [ - + ]: 186 : if (error) {
269 : 0 : return error;
270 : : }
271 : :
272 : : /* Create or look up datapath. */
273 : 186 : dpif_netlink_dp_init(&dp_request);
274 [ + + ]: 186 : if (create) {
275 : 63 : dp_request.cmd = OVS_DP_CMD_NEW;
276 : 63 : upcall_pid = 0;
277 : 63 : dp_request.upcall_pid = &upcall_pid;
278 : : } else {
279 : : /* Use OVS_DP_CMD_SET to report user features */
280 : 123 : dp_request.cmd = OVS_DP_CMD_SET;
281 : : }
282 : 186 : dp_request.name = name;
283 : 186 : dp_request.user_features |= OVS_DP_F_UNALIGNED;
284 : 186 : dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
285 : 186 : error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
286 [ - + ]: 186 : if (error) {
287 : 0 : return error;
288 : : }
289 : :
290 : 186 : error = open_dpif(&dp, dpifp);
291 : 186 : ofpbuf_delete(buf);
292 : 186 : return error;
293 : : }
294 : :
295 : : static int
296 : 186 : open_dpif(const struct dpif_netlink_dp *dp, struct dpif **dpifp)
297 : : {
298 : : struct dpif_netlink *dpif;
299 : :
300 : 186 : dpif = xzalloc(sizeof *dpif);
301 : 186 : dpif->port_notifier = NULL;
302 : 186 : fat_rwlock_init(&dpif->upcall_lock);
303 : :
304 : 186 : dpif_init(&dpif->dpif, &dpif_netlink_class, dp->name,
305 : 372 : dp->dp_ifindex, dp->dp_ifindex);
306 : :
307 : 186 : dpif->dp_ifindex = dp->dp_ifindex;
308 : 186 : *dpifp = &dpif->dpif;
309 : :
310 : 186 : return 0;
311 : : }
312 : :
313 : : /* Destroys the netlink sockets pointed by the elements in 'socksp'
314 : : * and frees the 'socksp'. */
315 : : static void
316 : 0 : vport_del_socksp__(struct nl_sock **socksp, uint32_t n_socks)
317 : : {
318 : : size_t i;
319 : :
320 [ # # ]: 0 : for (i = 0; i < n_socks; i++) {
321 : 0 : nl_sock_destroy(socksp[i]);
322 : : }
323 : :
324 : 0 : free(socksp);
325 : 0 : }
326 : :
327 : : /* Creates an array of netlink sockets. Returns an array of the
328 : : * corresponding pointers. Records the error in 'error'. */
329 : : static struct nl_sock **
330 : 295 : vport_create_socksp__(uint32_t n_socks, int *error)
331 : : {
332 : 295 : struct nl_sock **socksp = xzalloc(n_socks * sizeof *socksp);
333 : : size_t i;
334 : :
335 [ + + ]: 590 : for (i = 0; i < n_socks; i++) {
336 : 295 : *error = nl_sock_create(NETLINK_GENERIC, &socksp[i]);
337 [ - + ]: 295 : if (*error) {
338 : 0 : goto error;
339 : : }
340 : : }
341 : :
342 : 295 : return socksp;
343 : :
344 : : error:
345 : 0 : vport_del_socksp__(socksp, n_socks);
346 : :
347 : 0 : return NULL;
348 : : }
349 : :
350 : : #ifdef _WIN32
351 : : static void
352 : : vport_delete_sock_pool(struct dpif_handler *handler)
353 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
354 : : {
355 : : if (handler->vport_sock_pool) {
356 : : uint32_t i;
357 : : struct dpif_windows_vport_sock *sock_pool =
358 : : handler->vport_sock_pool;
359 : :
360 : : for (i = 0; i < VPORT_SOCK_POOL_SIZE; i++) {
361 : : if (sock_pool[i].nl_sock) {
362 : : nl_sock_unsubscribe_packets(sock_pool[i].nl_sock);
363 : : nl_sock_destroy(sock_pool[i].nl_sock);
364 : : sock_pool[i].nl_sock = NULL;
365 : : }
366 : : }
367 : :
368 : : free(handler->vport_sock_pool);
369 : : handler->vport_sock_pool = NULL;
370 : : }
371 : : }
372 : :
373 : : static int
374 : : vport_create_sock_pool(struct dpif_handler *handler)
375 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
376 : : {
377 : : struct dpif_windows_vport_sock *sock_pool;
378 : : size_t i;
379 : : int error = 0;
380 : :
381 : : sock_pool = xzalloc(VPORT_SOCK_POOL_SIZE * sizeof *sock_pool);
382 : : for (i = 0; i < VPORT_SOCK_POOL_SIZE; i++) {
383 : : error = nl_sock_create(NETLINK_GENERIC, &sock_pool[i].nl_sock);
384 : : if (error) {
385 : : goto error;
386 : : }
387 : :
388 : : /* Enable the netlink socket to receive packets. This is equivalent to
389 : : * calling nl_sock_join_mcgroup() to receive events. */
390 : : error = nl_sock_subscribe_packets(sock_pool[i].nl_sock);
391 : : if (error) {
392 : : goto error;
393 : : }
394 : : }
395 : :
396 : : handler->vport_sock_pool = sock_pool;
397 : : handler->last_used_pool_idx = 0;
398 : : return 0;
399 : :
400 : : error:
401 : : vport_delete_sock_pool(handler);
402 : : return error;
403 : : }
404 : :
405 : : /* Returns an array pointers to netlink sockets. The sockets are picked from a
406 : : * pool. Records the error in 'error'. */
407 : : static struct nl_sock **
408 : : vport_create_socksp_windows(struct dpif_netlink *dpif, int *error)
409 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
410 : : {
411 : : uint32_t n_socks = dpif->n_handlers;
412 : : struct nl_sock **socksp;
413 : : size_t i;
414 : :
415 : : ovs_assert(n_socks <= 1);
416 : : socksp = xzalloc(n_socks * sizeof *socksp);
417 : :
418 : : /* Pick netlink sockets to use in a round-robin fashion from each
419 : : * handler's pool of sockets. */
420 : : for (i = 0; i < n_socks; i++) {
421 : : struct dpif_handler *handler = &dpif->handlers[i];
422 : : struct dpif_windows_vport_sock *sock_pool = handler->vport_sock_pool;
423 : : size_t index = handler->last_used_pool_idx;
424 : :
425 : : /* A pool of sockets is allocated when the handler is initialized. */
426 : : if (sock_pool == NULL) {
427 : : free(socksp);
428 : : *error = EINVAL;
429 : : return NULL;
430 : : }
431 : :
432 : : ovs_assert(index < VPORT_SOCK_POOL_SIZE);
433 : : socksp[i] = sock_pool[index].nl_sock;
434 : : socksp[i] = sock_pool[index].nl_sock;
435 : : ovs_assert(socksp[i]);
436 : : index = (index == VPORT_SOCK_POOL_SIZE - 1) ? 0 : index + 1;
437 : : handler->last_used_pool_idx = index;
438 : : }
439 : :
440 : : return socksp;
441 : : }
442 : :
443 : : static void
444 : : vport_del_socksp_windows(struct dpif_netlink *dpif, struct nl_sock **socksp)
445 : : {
446 : : free(socksp);
447 : : }
448 : : #endif /* _WIN32 */
449 : :
450 : : static struct nl_sock **
451 : 295 : vport_create_socksp(struct dpif_netlink *dpif, int *error)
452 : : {
453 : : #ifdef _WIN32
454 : : return vport_create_socksp_windows(dpif, error);
455 : : #else
456 : 295 : return vport_create_socksp__(dpif->n_handlers, error);
457 : : #endif
458 : : }
459 : :
460 : : static void
461 : 0 : vport_del_socksp(struct dpif_netlink *dpif, struct nl_sock **socksp)
462 : : {
463 : : #ifdef _WIN32
464 : : vport_del_socksp_windows(dpif, socksp);
465 : : #else
466 : 0 : vport_del_socksp__(socksp, dpif->n_handlers);
467 : : #endif
468 : 0 : }
469 : :
470 : : /* Given the array of pointers to netlink sockets 'socksp', returns
471 : : * the array of corresponding pids. If the 'socksp' is NULL, returns
472 : : * a single-element array of value 0. */
473 : : static uint32_t *
474 : 295 : vport_socksp_to_pids(struct nl_sock **socksp, uint32_t n_socks)
475 : : {
476 : : uint32_t *pids;
477 : :
478 [ - + ]: 295 : if (!socksp) {
479 : 0 : pids = xzalloc(sizeof *pids);
480 : : } else {
481 : : size_t i;
482 : :
483 : 295 : pids = xzalloc(n_socks * sizeof *pids);
484 [ + + ]: 590 : for (i = 0; i < n_socks; i++) {
485 : 295 : pids[i] = nl_sock_pid(socksp[i]);
486 : : }
487 : : }
488 : :
489 : 295 : return pids;
490 : : }
491 : :
492 : : /* Given the port number 'port_idx', extracts the pids of netlink sockets
493 : : * associated to the port and assigns it to 'upcall_pids'. */
494 : : static bool
495 : 63 : vport_get_pids(struct dpif_netlink *dpif, uint32_t port_idx,
496 : : uint32_t **upcall_pids)
497 : : {
498 : : uint32_t *pids;
499 : : size_t i;
500 : :
501 : : /* Since the nl_sock can only be assigned in either all
502 : : * or none "dpif->handlers" channels, the following check
503 : : * would suffice. */
504 [ - + ]: 63 : if (!dpif->handlers[0].channels[port_idx].sock) {
505 : 0 : return false;
506 : : }
507 : : ovs_assert(!WINDOWS || dpif->n_handlers <= 1);
508 : :
509 : 63 : pids = xzalloc(dpif->n_handlers * sizeof *pids);
510 : :
511 [ + + ]: 126 : for (i = 0; i < dpif->n_handlers; i++) {
512 : 63 : pids[i] = nl_sock_pid(dpif->handlers[i].channels[port_idx].sock);
513 : : }
514 : :
515 : 63 : *upcall_pids = pids;
516 : :
517 : 63 : return true;
518 : : }
519 : :
520 : : static int
521 : 295 : vport_add_channels(struct dpif_netlink *dpif, odp_port_t port_no,
522 : : struct nl_sock **socksp)
523 : : {
524 : : struct epoll_event event;
525 : 295 : uint32_t port_idx = odp_to_u32(port_no);
526 : : size_t i, j;
527 : : int error;
528 : :
529 [ - + ]: 295 : if (dpif->handlers == NULL) {
530 : 0 : return 0;
531 : : }
532 : :
533 : : /* We assume that the datapath densely chooses port numbers, which can
534 : : * therefore be used as an index into 'channels' and 'epoll_events' of
535 : : * 'dpif->handler'. */
536 [ + - ]: 295 : if (port_idx >= dpif->uc_array_size) {
537 : 295 : uint32_t new_size = port_idx + 1;
538 : :
539 [ - + ]: 295 : if (new_size > MAX_PORTS) {
540 [ # # ]: 0 : VLOG_WARN_RL(&error_rl, "%s: datapath port %"PRIu32" too big",
541 : : dpif_name(&dpif->dpif), port_no);
542 : 0 : return EFBIG;
543 : : }
544 : :
545 [ + + ]: 590 : for (i = 0; i < dpif->n_handlers; i++) {
546 : 295 : struct dpif_handler *handler = &dpif->handlers[i];
547 : :
548 : 295 : handler->channels = xrealloc(handler->channels,
549 : : new_size * sizeof *handler->channels);
550 : :
551 [ + + ]: 590 : for (j = dpif->uc_array_size; j < new_size; j++) {
552 : 295 : handler->channels[j].sock = NULL;
553 : : }
554 : :
555 : 295 : handler->epoll_events = xrealloc(handler->epoll_events,
556 : : new_size * sizeof *handler->epoll_events);
557 : :
558 : : }
559 : 295 : dpif->uc_array_size = new_size;
560 : : }
561 : :
562 : 295 : memset(&event, 0, sizeof event);
563 : 295 : event.events = EPOLLIN;
564 : 295 : event.data.u32 = port_idx;
565 : :
566 [ + + ]: 590 : for (i = 0; i < dpif->n_handlers; i++) {
567 : 295 : struct dpif_handler *handler = &dpif->handlers[i];
568 : :
569 : : #ifndef _WIN32
570 [ - + ]: 295 : if (epoll_ctl(handler->epoll_fd, EPOLL_CTL_ADD, nl_sock_fd(socksp[i]),
571 : : &event) < 0) {
572 : 0 : error = errno;
573 : 0 : goto error;
574 : : }
575 : : #endif
576 : 295 : dpif->handlers[i].channels[port_idx].sock = socksp[i];
577 : 295 : dpif->handlers[i].channels[port_idx].last_poll = LLONG_MIN;
578 : : }
579 : :
580 : 295 : return 0;
581 : :
582 : : error:
583 [ # # ]: 0 : for (j = 0; j < i; j++) {
584 : : #ifndef _WIN32
585 : 0 : epoll_ctl(dpif->handlers[j].epoll_fd, EPOLL_CTL_DEL,
586 : 0 : nl_sock_fd(socksp[j]), NULL);
587 : : #endif
588 : 0 : dpif->handlers[j].channels[port_idx].sock = NULL;
589 : : }
590 : :
591 : 295 : return error;
592 : : }
593 : :
594 : : static void
595 : 295 : vport_del_channels(struct dpif_netlink *dpif, odp_port_t port_no)
596 : : {
597 : 295 : uint32_t port_idx = odp_to_u32(port_no);
598 : : size_t i;
599 : :
600 [ + - ][ - + ]: 295 : if (!dpif->handlers || port_idx >= dpif->uc_array_size) {
601 : 0 : return;
602 : : }
603 : :
604 : : /* Since the sock can only be assigned in either all or none
605 : : * of "dpif->handlers" channels, the following check would
606 : : * suffice. */
607 [ - + ]: 295 : if (!dpif->handlers[0].channels[port_idx].sock) {
608 : 0 : return;
609 : : }
610 : :
611 [ + + ]: 590 : for (i = 0; i < dpif->n_handlers; i++) {
612 : 295 : struct dpif_handler *handler = &dpif->handlers[i];
613 : : #ifndef _WIN32
614 : 295 : epoll_ctl(handler->epoll_fd, EPOLL_CTL_DEL,
615 : 295 : nl_sock_fd(handler->channels[port_idx].sock), NULL);
616 : 295 : nl_sock_destroy(handler->channels[port_idx].sock);
617 : : #endif
618 : 295 : handler->channels[port_idx].sock = NULL;
619 : 295 : handler->event_offset = handler->n_events = 0;
620 : : }
621 : : }
622 : :
623 : : static void
624 : 249 : destroy_all_channels(struct dpif_netlink *dpif)
625 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
626 : : {
627 : : unsigned int i;
628 : :
629 [ + + ]: 249 : if (!dpif->handlers) {
630 : 186 : return;
631 : : }
632 : :
633 [ + + ]: 358 : for (i = 0; i < dpif->uc_array_size; i++ ) {
634 : : struct dpif_netlink_vport vport_request;
635 : 295 : uint32_t upcall_pids = 0;
636 : :
637 : : /* Since the sock can only be assigned in either all or none
638 : : * of "dpif->handlers" channels, the following check would
639 : : * suffice. */
640 [ - + ]: 295 : if (!dpif->handlers[0].channels[i].sock) {
641 : 0 : continue;
642 : : }
643 : :
644 : : /* Turn off upcalls. */
645 : 295 : dpif_netlink_vport_init(&vport_request);
646 : 295 : vport_request.cmd = OVS_VPORT_CMD_SET;
647 : 295 : vport_request.dp_ifindex = dpif->dp_ifindex;
648 : 295 : vport_request.port_no = u32_to_odp(i);
649 : 295 : vport_request.n_upcall_pids = 1;
650 : 295 : vport_request.upcall_pids = &upcall_pids;
651 : 295 : dpif_netlink_vport_transact(&vport_request, NULL, NULL);
652 : :
653 : 295 : vport_del_channels(dpif, u32_to_odp(i));
654 : : }
655 : :
656 [ + + ]: 126 : for (i = 0; i < dpif->n_handlers; i++) {
657 : 63 : struct dpif_handler *handler = &dpif->handlers[i];
658 : :
659 : 63 : dpif_netlink_handler_uninit(handler);
660 : 63 : free(handler->epoll_events);
661 : 63 : free(handler->channels);
662 : : }
663 : :
664 : 63 : free(dpif->handlers);
665 : 63 : dpif->handlers = NULL;
666 : 63 : dpif->n_handlers = 0;
667 : 63 : dpif->uc_array_size = 0;
668 : : }
669 : :
670 : : static void
671 : 186 : dpif_netlink_close(struct dpif *dpif_)
672 : : {
673 : 186 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
674 : :
675 : 186 : nl_sock_destroy(dpif->port_notifier);
676 : :
677 : 186 : fat_rwlock_wrlock(&dpif->upcall_lock);
678 : 186 : destroy_all_channels(dpif);
679 : 186 : fat_rwlock_unlock(&dpif->upcall_lock);
680 : :
681 : 186 : fat_rwlock_destroy(&dpif->upcall_lock);
682 : 186 : free(dpif);
683 : 186 : }
684 : :
685 : : static int
686 : 64 : dpif_netlink_destroy(struct dpif *dpif_)
687 : : {
688 : 64 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
689 : : struct dpif_netlink_dp dp;
690 : :
691 : 64 : dpif_netlink_dp_init(&dp);
692 : 64 : dp.cmd = OVS_DP_CMD_DEL;
693 : 64 : dp.dp_ifindex = dpif->dp_ifindex;
694 : 64 : return dpif_netlink_dp_transact(&dp, NULL, NULL);
695 : : }
696 : :
697 : : static bool
698 : 5991 : dpif_netlink_run(struct dpif *dpif_)
699 : : {
700 : 5991 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
701 : :
702 [ - + ]: 5991 : if (dpif->refresh_channels) {
703 : 0 : dpif->refresh_channels = false;
704 : 0 : fat_rwlock_wrlock(&dpif->upcall_lock);
705 : 0 : dpif_netlink_refresh_channels(dpif, dpif->n_handlers);
706 : 0 : fat_rwlock_unlock(&dpif->upcall_lock);
707 : : }
708 : 5991 : return false;
709 : : }
710 : :
711 : : static int
712 : 1060 : dpif_netlink_get_stats(const struct dpif *dpif_, struct dpif_dp_stats *stats)
713 : : {
714 : : struct dpif_netlink_dp dp;
715 : : struct ofpbuf *buf;
716 : : int error;
717 : :
718 : 1060 : error = dpif_netlink_dp_get(dpif_, &dp, &buf);
719 [ + - ]: 1060 : if (!error) {
720 : 1060 : memset(stats, 0, sizeof *stats);
721 : :
722 [ + - ]: 1060 : if (dp.stats) {
723 : 1060 : stats->n_hit = get_32aligned_u64(&dp.stats->n_hit);
724 : 1060 : stats->n_missed = get_32aligned_u64(&dp.stats->n_missed);
725 : 1060 : stats->n_lost = get_32aligned_u64(&dp.stats->n_lost);
726 : 1060 : stats->n_flows = get_32aligned_u64(&dp.stats->n_flows);
727 : : }
728 : :
729 [ + - ]: 1060 : if (dp.megaflow_stats) {
730 : 1060 : stats->n_masks = dp.megaflow_stats->n_masks;
731 : 1060 : stats->n_mask_hit = get_32aligned_u64(
732 : 1060 : &dp.megaflow_stats->n_mask_hit);
733 : : } else {
734 : 0 : stats->n_masks = UINT32_MAX;
735 : 0 : stats->n_mask_hit = UINT64_MAX;
736 : : }
737 : 1060 : ofpbuf_delete(buf);
738 : : }
739 : 1060 : return error;
740 : : }
741 : :
742 : : static const char *
743 : 4054 : get_vport_type(const struct dpif_netlink_vport *vport)
744 : : {
745 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
746 : :
747 [ + + - + : 4054 : switch (vport->type) {
+ - - -
- ]
748 : : case OVS_VPORT_TYPE_NETDEV: {
749 : 2160 : const char *type = netdev_get_type_from_name(vport->name);
750 : :
751 [ + - ]: 2160 : return type ? type : "system";
752 : : }
753 : :
754 : : case OVS_VPORT_TYPE_INTERNAL:
755 : 1889 : return "internal";
756 : :
757 : : case OVS_VPORT_TYPE_GENEVE:
758 : 0 : return "geneve";
759 : :
760 : : case OVS_VPORT_TYPE_GRE:
761 : 2 : return "gre";
762 : :
763 : : case OVS_VPORT_TYPE_VXLAN:
764 : 3 : return "vxlan";
765 : :
766 : : case OVS_VPORT_TYPE_LISP:
767 : 0 : return "lisp";
768 : :
769 : : case OVS_VPORT_TYPE_STT:
770 : 0 : return "stt";
771 : :
772 : : case OVS_VPORT_TYPE_UNSPEC:
773 : : case __OVS_VPORT_TYPE_MAX:
774 : 0 : break;
775 : : }
776 : :
777 [ # # ]: 0 : VLOG_WARN_RL(&rl, "dp%d: port `%s' has unsupported type %u",
778 : : vport->dp_ifindex, vport->name, (unsigned int) vport->type);
779 : 0 : return "unknown";
780 : : }
781 : :
782 : : static enum ovs_vport_type
783 : 232 : netdev_to_ovs_vport_type(const struct netdev *netdev)
784 : : {
785 : 232 : const char *type = netdev_get_type(netdev);
786 : :
787 [ + - ][ + + ]: 232 : if (!strcmp(type, "tap") || !strcmp(type, "system")) {
788 : 151 : return OVS_VPORT_TYPE_NETDEV;
789 [ + + ]: 81 : } else if (!strcmp(type, "internal")) {
790 : 76 : return OVS_VPORT_TYPE_INTERNAL;
791 [ - + ]: 5 : } else if (strstr(type, "stt")) {
792 : 0 : return OVS_VPORT_TYPE_STT;
793 [ - + ]: 5 : } else if (!strcmp(type, "geneve")) {
794 : 0 : return OVS_VPORT_TYPE_GENEVE;
795 [ + + ]: 5 : } else if (strstr(type, "gre")) {
796 : 2 : return OVS_VPORT_TYPE_GRE;
797 [ + - ]: 3 : } else if (!strcmp(type, "vxlan")) {
798 : 3 : return OVS_VPORT_TYPE_VXLAN;
799 [ # # ]: 0 : } else if (!strcmp(type, "lisp")) {
800 : 0 : return OVS_VPORT_TYPE_LISP;
801 : : } else {
802 : 0 : return OVS_VPORT_TYPE_UNSPEC;
803 : : }
804 : : }
805 : :
806 : : static int
807 : 232 : dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
808 : : odp_port_t *port_nop)
809 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
810 : : {
811 : : const struct netdev_tunnel_config *tnl_cfg;
812 : : char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
813 : 232 : const char *name = netdev_vport_get_dpif_port(netdev,
814 : : namebuf, sizeof namebuf);
815 : 232 : const char *type = netdev_get_type(netdev);
816 : : struct dpif_netlink_vport request, reply;
817 : : struct ofpbuf *buf;
818 : : uint64_t options_stub[64 / 8];
819 : : struct ofpbuf options;
820 : 232 : struct nl_sock **socksp = NULL;
821 : : uint32_t *upcall_pids;
822 : 232 : int error = 0;
823 : :
824 [ + - ]: 232 : if (dpif->handlers) {
825 : 232 : socksp = vport_create_socksp(dpif, &error);
826 [ - + ]: 232 : if (!socksp) {
827 : 0 : return error;
828 : : }
829 : : }
830 : :
831 : 232 : dpif_netlink_vport_init(&request);
832 : 232 : request.cmd = OVS_VPORT_CMD_NEW;
833 : 232 : request.dp_ifindex = dpif->dp_ifindex;
834 : 232 : request.type = netdev_to_ovs_vport_type(netdev);
835 [ - + ]: 232 : if (request.type == OVS_VPORT_TYPE_UNSPEC) {
836 [ # # ]: 0 : VLOG_WARN_RL(&error_rl, "%s: cannot create port `%s' because it has "
837 : : "unsupported type `%s'",
838 : : dpif_name(&dpif->dpif), name, type);
839 : 0 : vport_del_socksp(dpif, socksp);
840 : 0 : return EINVAL;
841 : : }
842 : 232 : request.name = name;
843 : :
844 [ + + ]: 232 : if (request.type == OVS_VPORT_TYPE_NETDEV) {
845 : : #ifdef _WIN32
846 : : /* XXX : Map appropiate Windows handle */
847 : : #else
848 : 151 : netdev_linux_ethtool_set_flag(netdev, ETH_FLAG_LRO, "LRO", false);
849 : : #endif
850 : : }
851 : :
852 : 232 : tnl_cfg = netdev_get_tunnel_config(netdev);
853 [ + + ][ + + ]: 232 : if (tnl_cfg && (tnl_cfg->dst_port != 0 || tnl_cfg->exts)) {
[ - + ]
854 : 3 : ofpbuf_use_stack(&options, options_stub, sizeof options_stub);
855 [ + - ]: 3 : if (tnl_cfg->dst_port) {
856 : 3 : nl_msg_put_u16(&options, OVS_TUNNEL_ATTR_DST_PORT,
857 : 3 : ntohs(tnl_cfg->dst_port));
858 : : }
859 [ - + ]: 3 : if (tnl_cfg->exts) {
860 : : size_t ext_ofs;
861 : : int i;
862 : :
863 : 0 : ext_ofs = nl_msg_start_nested(&options, OVS_TUNNEL_ATTR_EXTENSION);
864 [ # # ]: 0 : for (i = 0; i < 32; i++) {
865 [ # # ]: 0 : if (tnl_cfg->exts & (1 << i)) {
866 : 0 : nl_msg_put_flag(&options, i);
867 : : }
868 : : }
869 : 0 : nl_msg_end_nested(&options, ext_ofs);
870 : : }
871 : 3 : request.options = options.data;
872 : 3 : request.options_len = options.size;
873 : : }
874 : :
875 : 232 : request.port_no = *port_nop;
876 : 232 : upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
877 [ + - ]: 232 : request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
878 : 232 : request.upcall_pids = upcall_pids;
879 : :
880 : 232 : error = dpif_netlink_vport_transact(&request, &reply, &buf);
881 [ + - ]: 232 : if (!error) {
882 : 232 : *port_nop = reply.port_no;
883 : : } else {
884 [ # # ][ # # ]: 0 : if (error == EBUSY && *port_nop != ODPP_NONE) {
885 [ # # ]: 0 : VLOG_INFO("%s: requested port %"PRIu32" is in use",
886 : : dpif_name(&dpif->dpif), *port_nop);
887 : : }
888 : :
889 : 0 : vport_del_socksp(dpif, socksp);
890 : 0 : goto exit;
891 : : }
892 : :
893 [ + - ]: 232 : if (socksp) {
894 : 232 : error = vport_add_channels(dpif, *port_nop, socksp);
895 [ - + ]: 232 : if (error) {
896 [ # # ]: 0 : VLOG_INFO("%s: could not add channel for port %s",
897 : : dpif_name(&dpif->dpif), name);
898 : :
899 : : /* Delete the port. */
900 : 0 : dpif_netlink_vport_init(&request);
901 : 0 : request.cmd = OVS_VPORT_CMD_DEL;
902 : 0 : request.dp_ifindex = dpif->dp_ifindex;
903 : 0 : request.port_no = *port_nop;
904 : 0 : dpif_netlink_vport_transact(&request, NULL, NULL);
905 : 0 : vport_del_socksp(dpif, socksp);
906 : 0 : goto exit;
907 : : }
908 : : }
909 : 232 : free(socksp);
910 : :
911 : : exit:
912 : 232 : ofpbuf_delete(buf);
913 : 232 : free(upcall_pids);
914 : :
915 : 232 : return error;
916 : : }
917 : :
918 : : static int
919 : 232 : dpif_netlink_port_add(struct dpif *dpif_, struct netdev *netdev,
920 : : odp_port_t *port_nop)
921 : : {
922 : 232 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
923 : : int error;
924 : :
925 : 232 : fat_rwlock_wrlock(&dpif->upcall_lock);
926 : 232 : error = dpif_netlink_port_add__(dpif, netdev, port_nop);
927 : 232 : fat_rwlock_unlock(&dpif->upcall_lock);
928 : :
929 : 232 : return error;
930 : : }
931 : :
932 : : static int
933 : 0 : dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
934 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
935 : : {
936 : : struct dpif_netlink_vport vport;
937 : : int error;
938 : :
939 : 0 : dpif_netlink_vport_init(&vport);
940 : 0 : vport.cmd = OVS_VPORT_CMD_DEL;
941 : 0 : vport.dp_ifindex = dpif->dp_ifindex;
942 : 0 : vport.port_no = port_no;
943 : 0 : error = dpif_netlink_vport_transact(&vport, NULL, NULL);
944 : :
945 : 0 : vport_del_channels(dpif, port_no);
946 : :
947 : 0 : return error;
948 : : }
949 : :
950 : : static int
951 : 0 : dpif_netlink_port_del(struct dpif *dpif_, odp_port_t port_no)
952 : : {
953 : 0 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
954 : : int error;
955 : :
956 : 0 : fat_rwlock_wrlock(&dpif->upcall_lock);
957 : 0 : error = dpif_netlink_port_del__(dpif, port_no);
958 : 0 : fat_rwlock_unlock(&dpif->upcall_lock);
959 : :
960 : 0 : return error;
961 : : }
962 : :
963 : : static int
964 : 4097 : dpif_netlink_port_query__(const struct dpif_netlink *dpif, odp_port_t port_no,
965 : : const char *port_name, struct dpif_port *dpif_port)
966 : : {
967 : : struct dpif_netlink_vport request;
968 : : struct dpif_netlink_vport reply;
969 : : struct ofpbuf *buf;
970 : : int error;
971 : :
972 : 4097 : dpif_netlink_vport_init(&request);
973 : 4097 : request.cmd = OVS_VPORT_CMD_GET;
974 : 4097 : request.dp_ifindex = dpif->dp_ifindex;
975 : 4097 : request.port_no = port_no;
976 : 4097 : request.name = port_name;
977 : :
978 : 4097 : error = dpif_netlink_vport_transact(&request, &reply, &buf);
979 [ + + ]: 4097 : if (!error) {
980 [ - + ]: 3851 : if (reply.dp_ifindex != request.dp_ifindex) {
981 : : /* A query by name reported that 'port_name' is in some datapath
982 : : * other than 'dpif', but the caller wants to know about 'dpif'. */
983 : 0 : error = ENODEV;
984 [ + - ]: 3851 : } else if (dpif_port) {
985 : 3851 : dpif_port->name = xstrdup(reply.name);
986 : 3851 : dpif_port->type = xstrdup(get_vport_type(&reply));
987 : 3851 : dpif_port->port_no = reply.port_no;
988 : : }
989 : 3851 : ofpbuf_delete(buf);
990 : : }
991 : 4097 : return error;
992 : : }
993 : :
994 : : static int
995 : 0 : dpif_netlink_port_query_by_number(const struct dpif *dpif_, odp_port_t port_no,
996 : : struct dpif_port *dpif_port)
997 : : {
998 : 0 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
999 : :
1000 : 0 : return dpif_netlink_port_query__(dpif, port_no, NULL, dpif_port);
1001 : : }
1002 : :
1003 : : static int
1004 : 4097 : dpif_netlink_port_query_by_name(const struct dpif *dpif_, const char *devname,
1005 : : struct dpif_port *dpif_port)
1006 : : {
1007 : 4097 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1008 : :
1009 : 4097 : return dpif_netlink_port_query__(dpif, 0, devname, dpif_port);
1010 : : }
1011 : :
1012 : : static uint32_t
1013 : 242 : dpif_netlink_port_get_pid__(const struct dpif_netlink *dpif,
1014 : : odp_port_t port_no, uint32_t hash)
1015 : : OVS_REQ_RDLOCK(dpif->upcall_lock)
1016 : : {
1017 : 242 : uint32_t port_idx = odp_to_u32(port_no);
1018 : 242 : uint32_t pid = 0;
1019 : :
1020 [ + - ][ + - ]: 242 : if (dpif->handlers && dpif->uc_array_size > 0) {
1021 : : /* The ODPP_NONE "reserved" port number uses the "ovs-system"'s
1022 : : * channel, since it is not heavily loaded. */
1023 [ + + ]: 242 : uint32_t idx = port_idx >= dpif->uc_array_size ? 0 : port_idx;
1024 : 242 : struct dpif_handler *h = &dpif->handlers[hash % dpif->n_handlers];
1025 : :
1026 : : /* Needs to check in case the socket pointer is changed in between
1027 : : * the holding of upcall_lock. A known case happens when the main
1028 : : * thread deletes the vport while the handler thread is handling
1029 : : * the upcall from that port. */
1030 [ + - ]: 242 : if (h->channels[idx].sock) {
1031 : 242 : pid = nl_sock_pid(h->channels[idx].sock);
1032 : : }
1033 : : }
1034 : :
1035 : 242 : return pid;
1036 : : }
1037 : :
1038 : : static uint32_t
1039 : 242 : dpif_netlink_port_get_pid(const struct dpif *dpif_, odp_port_t port_no,
1040 : : uint32_t hash)
1041 : : {
1042 : 242 : const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1043 : : uint32_t ret;
1044 : :
1045 : 242 : fat_rwlock_rdlock(&dpif->upcall_lock);
1046 : 242 : ret = dpif_netlink_port_get_pid__(dpif, port_no, hash);
1047 : 242 : fat_rwlock_unlock(&dpif->upcall_lock);
1048 : :
1049 : 242 : return ret;
1050 : : }
1051 : :
1052 : : static int
1053 : 137 : dpif_netlink_flow_flush(struct dpif *dpif_)
1054 : : {
1055 : 137 : const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1056 : : struct dpif_netlink_flow flow;
1057 : :
1058 : 137 : dpif_netlink_flow_init(&flow);
1059 : 137 : flow.cmd = OVS_FLOW_CMD_DEL;
1060 : 137 : flow.dp_ifindex = dpif->dp_ifindex;
1061 : 137 : return dpif_netlink_flow_transact(&flow, NULL, NULL);
1062 : : }
1063 : :
1064 : : struct dpif_netlink_port_state {
1065 : : struct nl_dump dump;
1066 : : struct ofpbuf buf;
1067 : : };
1068 : :
1069 : : static void
1070 : 254 : dpif_netlink_port_dump_start__(const struct dpif_netlink *dpif,
1071 : : struct nl_dump *dump)
1072 : : {
1073 : : struct dpif_netlink_vport request;
1074 : : struct ofpbuf *buf;
1075 : :
1076 : 254 : dpif_netlink_vport_init(&request);
1077 : 254 : request.cmd = OVS_VPORT_CMD_GET;
1078 : 254 : request.dp_ifindex = dpif->dp_ifindex;
1079 : :
1080 : 254 : buf = ofpbuf_new(1024);
1081 : 254 : dpif_netlink_vport_to_ofpbuf(&request, buf);
1082 : 254 : nl_dump_start(dump, NETLINK_GENERIC, buf);
1083 : 254 : ofpbuf_delete(buf);
1084 : 254 : }
1085 : :
1086 : : static int
1087 : 128 : dpif_netlink_port_dump_start(const struct dpif *dpif_, void **statep)
1088 : : {
1089 : 128 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1090 : : struct dpif_netlink_port_state *state;
1091 : :
1092 : 128 : *statep = state = xmalloc(sizeof *state);
1093 : 128 : dpif_netlink_port_dump_start__(dpif, &state->dump);
1094 : :
1095 : 128 : ofpbuf_init(&state->buf, NL_DUMP_BUFSIZE);
1096 : 128 : return 0;
1097 : : }
1098 : :
1099 : : static int
1100 : 583 : dpif_netlink_port_dump_next__(const struct dpif_netlink *dpif,
1101 : : struct nl_dump *dump,
1102 : : struct dpif_netlink_vport *vport,
1103 : : struct ofpbuf *buffer)
1104 : : {
1105 : : struct ofpbuf buf;
1106 : : int error;
1107 : :
1108 [ + + ]: 583 : if (!nl_dump_next(dump, &buf, buffer)) {
1109 : 254 : return EOF;
1110 : : }
1111 : :
1112 : 329 : error = dpif_netlink_vport_from_ofpbuf(vport, &buf);
1113 [ - + ]: 329 : if (error) {
1114 [ # # ]: 0 : VLOG_WARN_RL(&error_rl, "%s: failed to parse vport record (%s)",
1115 : : dpif_name(&dpif->dpif), ovs_strerror(error));
1116 : : }
1117 : 583 : return error;
1118 : : }
1119 : :
1120 : : static int
1121 : 331 : dpif_netlink_port_dump_next(const struct dpif *dpif_, void *state_,
1122 : : struct dpif_port *dpif_port)
1123 : : {
1124 : 331 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1125 : 331 : struct dpif_netlink_port_state *state = state_;
1126 : : struct dpif_netlink_vport vport;
1127 : : int error;
1128 : :
1129 : 331 : error = dpif_netlink_port_dump_next__(dpif, &state->dump, &vport,
1130 : : &state->buf);
1131 [ + + ]: 331 : if (error) {
1132 : 128 : return error;
1133 : : }
1134 : 203 : dpif_port->name = CONST_CAST(char *, vport.name);
1135 : 203 : dpif_port->type = CONST_CAST(char *, get_vport_type(&vport));
1136 : 203 : dpif_port->port_no = vport.port_no;
1137 : 331 : return 0;
1138 : : }
1139 : :
1140 : : static int
1141 : 128 : dpif_netlink_port_dump_done(const struct dpif *dpif_ OVS_UNUSED, void *state_)
1142 : : {
1143 : 128 : struct dpif_netlink_port_state *state = state_;
1144 : 128 : int error = nl_dump_done(&state->dump);
1145 : :
1146 : 128 : ofpbuf_uninit(&state->buf);
1147 : 128 : free(state);
1148 : 128 : return error;
1149 : : }
1150 : :
1151 : : static int
1152 : 6222 : dpif_netlink_port_poll(const struct dpif *dpif_, char **devnamep)
1153 : : {
1154 : 6222 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1155 : :
1156 : : /* Lazily create the Netlink socket to listen for notifications. */
1157 [ + + ]: 6222 : if (!dpif->port_notifier) {
1158 : : struct nl_sock *sock;
1159 : : int error;
1160 : :
1161 : 63 : error = nl_sock_create(NETLINK_GENERIC, &sock);
1162 [ - + ]: 63 : if (error) {
1163 : 0 : return error;
1164 : : }
1165 : :
1166 : 63 : error = nl_sock_join_mcgroup(sock, ovs_vport_mcgroup);
1167 [ - + ]: 63 : if (error) {
1168 : 0 : nl_sock_destroy(sock);
1169 : 0 : return error;
1170 : : }
1171 : 63 : dpif->port_notifier = sock;
1172 : :
1173 : : /* We have no idea of the current state so report that everything
1174 : : * changed. */
1175 : 63 : return ENOBUFS;
1176 : : }
1177 : :
1178 : : for (;;) {
1179 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
1180 : : uint64_t buf_stub[4096 / 8];
1181 : : struct ofpbuf buf;
1182 : : int error;
1183 : :
1184 : 6159 : ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
1185 : 6159 : error = nl_sock_recv(dpif->port_notifier, &buf, false);
1186 [ + + ]: 6159 : if (!error) {
1187 : : struct dpif_netlink_vport vport;
1188 : :
1189 : 168 : error = dpif_netlink_vport_from_ofpbuf(&vport, &buf);
1190 [ + - ]: 168 : if (!error) {
1191 [ + - ]: 168 : if (vport.dp_ifindex == dpif->dp_ifindex
1192 [ - + ]: 168 : && (vport.cmd == OVS_VPORT_CMD_NEW
1193 [ # # ]: 0 : || vport.cmd == OVS_VPORT_CMD_DEL
1194 [ # # ]: 0 : || vport.cmd == OVS_VPORT_CMD_SET)) {
1195 [ - + ]: 168 : VLOG_DBG("port_changed: dpif:%s vport:%s cmd:%"PRIu8,
1196 : : dpif->dpif.full_name, vport.name, vport.cmd);
1197 [ - + ][ # # ]: 168 : if (vport.cmd == OVS_VPORT_CMD_DEL && dpif->handlers) {
1198 : 0 : dpif->refresh_channels = true;
1199 : : }
1200 : 168 : *devnamep = xstrdup(vport.name);
1201 : 168 : ofpbuf_uninit(&buf);
1202 : 168 : return 0;
1203 : : }
1204 : : }
1205 [ - + ]: 5991 : } else if (error != EAGAIN) {
1206 [ # # ]: 0 : VLOG_WARN_RL(&rl, "error reading or parsing netlink (%s)",
1207 : : ovs_strerror(error));
1208 : 0 : nl_sock_drain(dpif->port_notifier);
1209 : 0 : error = ENOBUFS;
1210 : : }
1211 : :
1212 : 5991 : ofpbuf_uninit(&buf);
1213 [ + - ]: 5991 : if (error) {
1214 : 5991 : return error;
1215 : : }
1216 : 6159 : }
1217 : : }
1218 : :
1219 : : static void
1220 : 6356 : dpif_netlink_port_poll_wait(const struct dpif *dpif_)
1221 : : {
1222 : 6356 : const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1223 : :
1224 [ + - ]: 6356 : if (dpif->port_notifier) {
1225 : 6356 : nl_sock_wait(dpif->port_notifier, POLLIN);
1226 : : } else {
1227 : 0 : poll_immediate_wake();
1228 : : }
1229 : 6356 : }
1230 : :
1231 : : static void
1232 : 4371 : dpif_netlink_flow_init_ufid(struct dpif_netlink_flow *request,
1233 : : const ovs_u128 *ufid, bool terse)
1234 : : {
1235 [ + + ]: 4371 : if (ufid) {
1236 : 2985 : request->ufid = *ufid;
1237 : 2985 : request->ufid_present = true;
1238 : : } else {
1239 : 1386 : request->ufid_present = false;
1240 : : }
1241 : 4371 : request->ufid_terse = terse;
1242 : 4371 : }
1243 : :
1244 : : static void
1245 : 567 : dpif_netlink_init_flow_get__(const struct dpif_netlink *dpif,
1246 : : const struct nlattr *key, size_t key_len,
1247 : : const ovs_u128 *ufid, bool terse,
1248 : : struct dpif_netlink_flow *request)
1249 : : {
1250 : 567 : dpif_netlink_flow_init(request);
1251 : 567 : request->cmd = OVS_FLOW_CMD_GET;
1252 : 567 : request->dp_ifindex = dpif->dp_ifindex;
1253 : 567 : request->key = key;
1254 : 567 : request->key_len = key_len;
1255 : 567 : dpif_netlink_flow_init_ufid(request, ufid, terse);
1256 : 567 : }
1257 : :
1258 : : static void
1259 : 567 : dpif_netlink_init_flow_get(const struct dpif_netlink *dpif,
1260 : : const struct dpif_flow_get *get,
1261 : : struct dpif_netlink_flow *request)
1262 : : {
1263 : 567 : dpif_netlink_init_flow_get__(dpif, get->key, get->key_len, get->ufid,
1264 : : false, request);
1265 : 567 : }
1266 : :
1267 : : static int
1268 : 0 : dpif_netlink_flow_get__(const struct dpif_netlink *dpif,
1269 : : const struct nlattr *key, size_t key_len,
1270 : : const ovs_u128 *ufid, bool terse,
1271 : : struct dpif_netlink_flow *reply, struct ofpbuf **bufp)
1272 : : {
1273 : : struct dpif_netlink_flow request;
1274 : :
1275 : 0 : dpif_netlink_init_flow_get__(dpif, key, key_len, ufid, terse, &request);
1276 : 0 : return dpif_netlink_flow_transact(&request, reply, bufp);
1277 : : }
1278 : :
1279 : : static int
1280 : 0 : dpif_netlink_flow_get(const struct dpif_netlink *dpif,
1281 : : const struct dpif_netlink_flow *flow,
1282 : : struct dpif_netlink_flow *reply, struct ofpbuf **bufp)
1283 : : {
1284 [ # # ]: 0 : return dpif_netlink_flow_get__(dpif, flow->key, flow->key_len,
1285 : 0 : flow->ufid_present ? &flow->ufid : NULL,
1286 : : false, reply, bufp);
1287 : : }
1288 : :
1289 : : static void
1290 : 1981 : dpif_netlink_init_flow_put(struct dpif_netlink *dpif,
1291 : : const struct dpif_flow_put *put,
1292 : : struct dpif_netlink_flow *request)
1293 : : {
1294 : : static const struct nlattr dummy_action;
1295 : :
1296 : 1981 : dpif_netlink_flow_init(request);
1297 [ + + ]: 1981 : request->cmd = (put->flags & DPIF_FP_CREATE
1298 : : ? OVS_FLOW_CMD_NEW : OVS_FLOW_CMD_SET);
1299 : 1981 : request->dp_ifindex = dpif->dp_ifindex;
1300 : 1981 : request->key = put->key;
1301 : 1981 : request->key_len = put->key_len;
1302 : 1981 : request->mask = put->mask;
1303 : 1981 : request->mask_len = put->mask_len;
1304 : 1981 : dpif_netlink_flow_init_ufid(request, put->ufid, false);
1305 : :
1306 : : /* Ensure that OVS_FLOW_ATTR_ACTIONS will always be included. */
1307 : 3962 : request->actions = (put->actions
1308 : : ? put->actions
1309 [ + + ]: 1981 : : CONST_CAST(struct nlattr *, &dummy_action));
1310 : 1981 : request->actions_len = put->actions_len;
1311 [ - + ]: 1981 : if (put->flags & DPIF_FP_ZERO_STATS) {
1312 : 0 : request->clear = true;
1313 : : }
1314 [ + + ]: 1981 : if (put->flags & DPIF_FP_PROBE) {
1315 : 567 : request->probe = true;
1316 : : }
1317 [ + + ]: 1981 : request->nlmsg_flags = put->flags & DPIF_FP_MODIFY ? 0 : NLM_F_CREATE;
1318 : 1981 : }
1319 : :
1320 : : static void
1321 : 1823 : dpif_netlink_init_flow_del__(struct dpif_netlink *dpif,
1322 : : const struct nlattr *key, size_t key_len,
1323 : : const ovs_u128 *ufid, bool terse,
1324 : : struct dpif_netlink_flow *request)
1325 : : {
1326 : 1823 : dpif_netlink_flow_init(request);
1327 : 1823 : request->cmd = OVS_FLOW_CMD_DEL;
1328 : 1823 : request->dp_ifindex = dpif->dp_ifindex;
1329 : 1823 : request->key = key;
1330 : 1823 : request->key_len = key_len;
1331 : 1823 : dpif_netlink_flow_init_ufid(request, ufid, terse);
1332 : 1823 : }
1333 : :
1334 : : static void
1335 : 1823 : dpif_netlink_init_flow_del(struct dpif_netlink *dpif,
1336 : : const struct dpif_flow_del *del,
1337 : : struct dpif_netlink_flow *request)
1338 : : {
1339 : 1823 : dpif_netlink_init_flow_del__(dpif, del->key, del->key_len,
1340 : 1823 : del->ufid, del->terse, request);
1341 : 1823 : }
1342 : :
1343 : : struct dpif_netlink_flow_dump {
1344 : : struct dpif_flow_dump up;
1345 : : struct nl_dump nl_dump;
1346 : : atomic_int status;
1347 : : };
1348 : :
1349 : : static struct dpif_netlink_flow_dump *
1350 : 4410 : dpif_netlink_flow_dump_cast(struct dpif_flow_dump *dump)
1351 : : {
1352 : 4410 : return CONTAINER_OF(dump, struct dpif_netlink_flow_dump, up);
1353 : : }
1354 : :
1355 : : static struct dpif_flow_dump *
1356 : 2205 : dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse)
1357 : : {
1358 : 2205 : const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1359 : : struct dpif_netlink_flow_dump *dump;
1360 : : struct dpif_netlink_flow request;
1361 : : struct ofpbuf *buf;
1362 : :
1363 : 2205 : dump = xmalloc(sizeof *dump);
1364 : 2205 : dpif_flow_dump_init(&dump->up, dpif_);
1365 : :
1366 : 2205 : dpif_netlink_flow_init(&request);
1367 : 2205 : request.cmd = OVS_FLOW_CMD_GET;
1368 : 2205 : request.dp_ifindex = dpif->dp_ifindex;
1369 : 2205 : request.ufid_present = false;
1370 : 2205 : request.ufid_terse = terse;
1371 : :
1372 : 2205 : buf = ofpbuf_new(1024);
1373 : 2205 : dpif_netlink_flow_to_ofpbuf(&request, buf);
1374 : 2205 : nl_dump_start(&dump->nl_dump, NETLINK_GENERIC, buf);
1375 : 2205 : ofpbuf_delete(buf);
1376 : 2205 : atomic_init(&dump->status, 0);
1377 : 2205 : dump->up.terse = terse;
1378 : :
1379 : 2205 : return &dump->up;
1380 : : }
1381 : :
1382 : : static int
1383 : 2205 : dpif_netlink_flow_dump_destroy(struct dpif_flow_dump *dump_)
1384 : : {
1385 : 2205 : struct dpif_netlink_flow_dump *dump = dpif_netlink_flow_dump_cast(dump_);
1386 : 2205 : unsigned int nl_status = nl_dump_done(&dump->nl_dump);
1387 : : int dump_status;
1388 : :
1389 : : /* No other thread has access to 'dump' at this point. */
1390 : 2205 : atomic_read_relaxed(&dump->status, &dump_status);
1391 : 2205 : free(dump);
1392 [ - + ]: 2205 : return dump_status ? dump_status : nl_status;
1393 : : }
1394 : :
1395 : : struct dpif_netlink_flow_dump_thread {
1396 : : struct dpif_flow_dump_thread up;
1397 : : struct dpif_netlink_flow_dump *dump;
1398 : : struct dpif_netlink_flow flow;
1399 : : struct dpif_flow_stats stats;
1400 : : struct ofpbuf nl_flows; /* Always used to store flows. */
1401 : : struct ofpbuf *nl_actions; /* Used if kernel does not supply actions. */
1402 : : };
1403 : :
1404 : : static struct dpif_netlink_flow_dump_thread *
1405 : 5973 : dpif_netlink_flow_dump_thread_cast(struct dpif_flow_dump_thread *thread)
1406 : : {
1407 : 5973 : return CONTAINER_OF(thread, struct dpif_netlink_flow_dump_thread, up);
1408 : : }
1409 : :
1410 : : static struct dpif_flow_dump_thread *
1411 : 2205 : dpif_netlink_flow_dump_thread_create(struct dpif_flow_dump *dump_)
1412 : : {
1413 : 2205 : struct dpif_netlink_flow_dump *dump = dpif_netlink_flow_dump_cast(dump_);
1414 : : struct dpif_netlink_flow_dump_thread *thread;
1415 : :
1416 : 2205 : thread = xmalloc(sizeof *thread);
1417 : 2205 : dpif_flow_dump_thread_init(&thread->up, &dump->up);
1418 : 2205 : thread->dump = dump;
1419 : 2205 : ofpbuf_init(&thread->nl_flows, NL_DUMP_BUFSIZE);
1420 : 2205 : thread->nl_actions = NULL;
1421 : :
1422 : 2205 : return &thread->up;
1423 : : }
1424 : :
1425 : : static void
1426 : 2205 : dpif_netlink_flow_dump_thread_destroy(struct dpif_flow_dump_thread *thread_)
1427 : : {
1428 : 2205 : struct dpif_netlink_flow_dump_thread *thread
1429 : : = dpif_netlink_flow_dump_thread_cast(thread_);
1430 : :
1431 : 2205 : ofpbuf_uninit(&thread->nl_flows);
1432 : 2205 : ofpbuf_delete(thread->nl_actions);
1433 : 2205 : free(thread);
1434 : 2205 : }
1435 : :
1436 : : static void
1437 : 8422 : dpif_netlink_flow_to_dpif_flow(struct dpif *dpif, struct dpif_flow *dpif_flow,
1438 : : const struct dpif_netlink_flow *datapath_flow)
1439 : : {
1440 : 8422 : dpif_flow->key = datapath_flow->key;
1441 : 8422 : dpif_flow->key_len = datapath_flow->key_len;
1442 : 8422 : dpif_flow->mask = datapath_flow->mask;
1443 : 8422 : dpif_flow->mask_len = datapath_flow->mask_len;
1444 : 8422 : dpif_flow->actions = datapath_flow->actions;
1445 : 8422 : dpif_flow->actions_len = datapath_flow->actions_len;
1446 : 8422 : dpif_flow->ufid_present = datapath_flow->ufid_present;
1447 : 8422 : dpif_flow->pmd_id = PMD_ID_NULL;
1448 [ + + ]: 8422 : if (datapath_flow->ufid_present) {
1449 : 7981 : dpif_flow->ufid = datapath_flow->ufid;
1450 : : } else {
1451 [ + - ][ - + ]: 441 : ovs_assert(datapath_flow->key && datapath_flow->key_len);
1452 : 441 : dpif_flow_hash(dpif, datapath_flow->key, datapath_flow->key_len,
1453 : : &dpif_flow->ufid);
1454 : : }
1455 : 8422 : dpif_netlink_flow_get_stats(datapath_flow, &dpif_flow->stats);
1456 : 8422 : }
1457 : :
1458 : : static int
1459 : 3768 : dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
1460 : : struct dpif_flow *flows, int max_flows)
1461 : : {
1462 : 3768 : struct dpif_netlink_flow_dump_thread *thread
1463 : : = dpif_netlink_flow_dump_thread_cast(thread_);
1464 : 3768 : struct dpif_netlink_flow_dump *dump = thread->dump;
1465 : 3768 : struct dpif_netlink *dpif = dpif_netlink_cast(thread->up.dpif);
1466 : : int n_flows;
1467 : :
1468 : 3768 : ofpbuf_delete(thread->nl_actions);
1469 : 3768 : thread->nl_actions = NULL;
1470 : :
1471 : 3768 : n_flows = 0;
1472 [ + + ]: 11623 : while (!n_flows
1473 [ + + ][ + + ]: 7855 : || (n_flows < max_flows && thread->nl_flows.size)) {
1474 : : struct dpif_netlink_flow datapath_flow;
1475 : : struct ofpbuf nl_flow;
1476 : : int error;
1477 : :
1478 : : /* Try to grab another flow. */
1479 [ + + ]: 10060 : if (!nl_dump_next(&dump->nl_dump, &nl_flow, &thread->nl_flows)) {
1480 : 2205 : break;
1481 : : }
1482 : :
1483 : : /* Convert the flow to our output format. */
1484 : 7855 : error = dpif_netlink_flow_from_ofpbuf(&datapath_flow, &nl_flow);
1485 [ - + ]: 7855 : if (error) {
1486 : 0 : atomic_store_relaxed(&dump->status, error);
1487 : 0 : break;
1488 : : }
1489 : :
1490 [ + + ][ + - ]: 7855 : if (dump->up.terse || datapath_flow.actions) {
1491 : : /* Common case: we don't want actions, or the flow includes
1492 : : * actions. */
1493 : 7855 : dpif_netlink_flow_to_dpif_flow(&dpif->dpif, &flows[n_flows++],
1494 : : &datapath_flow);
1495 : : } else {
1496 : : /* Rare case: the flow does not include actions. Retrieve this
1497 : : * individual flow again to get the actions. */
1498 : 0 : error = dpif_netlink_flow_get(dpif, &datapath_flow,
1499 : : &datapath_flow, &thread->nl_actions);
1500 [ # # ]: 0 : if (error == ENOENT) {
1501 [ # # ]: 0 : VLOG_DBG("dumped flow disappeared on get");
1502 : 0 : continue;
1503 [ # # ]: 0 : } else if (error) {
1504 [ # # ]: 0 : VLOG_WARN("error fetching dumped flow: %s",
1505 : : ovs_strerror(error));
1506 : 0 : atomic_store_relaxed(&dump->status, error);
1507 : 0 : break;
1508 : : }
1509 : :
1510 : : /* Save this flow. Then exit, because we only have one buffer to
1511 : : * handle this case. */
1512 : 0 : dpif_netlink_flow_to_dpif_flow(&dpif->dpif, &flows[n_flows++],
1513 : : &datapath_flow);
1514 : 0 : break;
1515 : : }
1516 : : }
1517 : 3768 : return n_flows;
1518 : : }
1519 : :
1520 : : static void
1521 : 1217 : dpif_netlink_encode_execute(int dp_ifindex, const struct dpif_execute *d_exec,
1522 : : struct ofpbuf *buf)
1523 : : {
1524 : : struct ovs_header *k_exec;
1525 : : size_t key_ofs;
1526 : :
1527 : 1217 : ofpbuf_prealloc_tailroom(buf, (64
1528 : 1217 : + dp_packet_size(d_exec->packet)
1529 : 1217 : + ODP_KEY_METADATA_SIZE
1530 : 1217 : + d_exec->actions_len));
1531 : :
1532 : 1217 : nl_msg_put_genlmsghdr(buf, 0, ovs_packet_family, NLM_F_REQUEST,
1533 : : OVS_PACKET_CMD_EXECUTE, OVS_PACKET_VERSION);
1534 : :
1535 : 1217 : k_exec = ofpbuf_put_uninit(buf, sizeof *k_exec);
1536 : 1217 : k_exec->dp_ifindex = dp_ifindex;
1537 : :
1538 : 1217 : nl_msg_put_unspec(buf, OVS_PACKET_ATTR_PACKET,
1539 : 1217 : dp_packet_data(d_exec->packet),
1540 : 1217 : dp_packet_size(d_exec->packet));
1541 : :
1542 : 1217 : key_ofs = nl_msg_start_nested(buf, OVS_PACKET_ATTR_KEY);
1543 : 1217 : odp_key_from_pkt_metadata(buf, &d_exec->packet->md);
1544 : 1217 : nl_msg_end_nested(buf, key_ofs);
1545 : :
1546 : 1217 : nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS,
1547 : 1217 : d_exec->actions, d_exec->actions_len);
1548 [ + + ]: 1217 : if (d_exec->probe) {
1549 : 189 : nl_msg_put_flag(buf, OVS_PACKET_ATTR_PROBE);
1550 : : }
1551 [ + + ]: 1217 : if (d_exec->mtu) {
1552 : 6 : nl_msg_put_u16(buf, OVS_PACKET_ATTR_MRU, d_exec->mtu);
1553 : : }
1554 : 1217 : }
1555 : :
1556 : : /* Executes, against 'dpif', up to the first 'n_ops' operations in 'ops'.
1557 : : * Returns the number actually executed (at least 1, if 'n_ops' is
1558 : : * positive). */
1559 : : static size_t
1560 : 4386 : dpif_netlink_operate__(struct dpif_netlink *dpif,
1561 : : struct dpif_op **ops, size_t n_ops)
1562 : : {
1563 : : enum { MAX_OPS = 50 };
1564 : :
1565 : : struct op_auxdata {
1566 : : struct nl_transaction txn;
1567 : :
1568 : : struct ofpbuf request;
1569 : : uint64_t request_stub[1024 / 8];
1570 : :
1571 : : struct ofpbuf reply;
1572 : : uint64_t reply_stub[1024 / 8];
1573 : : } auxes[MAX_OPS];
1574 : :
1575 : : struct nl_transaction *txnsp[MAX_OPS];
1576 : : size_t i;
1577 : :
1578 : 4386 : n_ops = MIN(n_ops, MAX_OPS);
1579 [ + + ]: 9974 : for (i = 0; i < n_ops; i++) {
1580 : 5588 : struct op_auxdata *aux = &auxes[i];
1581 : 5588 : struct dpif_op *op = ops[i];
1582 : : struct dpif_flow_put *put;
1583 : : struct dpif_flow_del *del;
1584 : : struct dpif_flow_get *get;
1585 : : struct dpif_netlink_flow flow;
1586 : :
1587 : 5588 : ofpbuf_use_stub(&aux->request,
1588 : 5588 : aux->request_stub, sizeof aux->request_stub);
1589 : 5588 : aux->txn.request = &aux->request;
1590 : :
1591 : 5588 : ofpbuf_use_stub(&aux->reply, aux->reply_stub, sizeof aux->reply_stub);
1592 : 5588 : aux->txn.reply = NULL;
1593 : :
1594 [ + + + + : 5588 : switch (op->type) {
- ]
1595 : : case DPIF_OP_FLOW_PUT:
1596 : 1981 : put = &op->u.flow_put;
1597 : 1981 : dpif_netlink_init_flow_put(dpif, put, &flow);
1598 [ - + ]: 1981 : if (put->stats) {
1599 : 0 : flow.nlmsg_flags |= NLM_F_ECHO;
1600 : 0 : aux->txn.reply = &aux->reply;
1601 : : }
1602 : 1981 : dpif_netlink_flow_to_ofpbuf(&flow, &aux->request);
1603 : 1981 : break;
1604 : :
1605 : : case DPIF_OP_FLOW_DEL:
1606 : 1823 : del = &op->u.flow_del;
1607 : 1823 : dpif_netlink_init_flow_del(dpif, del, &flow);
1608 [ + + ]: 1823 : if (del->stats) {
1609 : 1319 : flow.nlmsg_flags |= NLM_F_ECHO;
1610 : 1319 : aux->txn.reply = &aux->reply;
1611 : : }
1612 : 1823 : dpif_netlink_flow_to_ofpbuf(&flow, &aux->request);
1613 : 1823 : break;
1614 : :
1615 : : case DPIF_OP_EXECUTE:
1616 : : /* Can't execute a packet that won't fit in a Netlink attribute. */
1617 [ - + ]: 1217 : if (OVS_UNLIKELY(nl_attr_oversized(
1618 : : dp_packet_size(op->u.execute.packet)))) {
1619 : : /* Report an error immediately if this is the first operation.
1620 : : * Otherwise the easiest thing to do is to postpone to the next
1621 : : * call (when this will be the first operation). */
1622 [ # # ]: 0 : if (i == 0) {
1623 [ # # ]: 0 : VLOG_ERR_RL(&error_rl,
1624 : : "dropping oversized %"PRIu32"-byte packet",
1625 : : dp_packet_size(op->u.execute.packet));
1626 : 0 : op->error = ENOBUFS;
1627 : 0 : return 1;
1628 : : }
1629 : 0 : n_ops = i;
1630 : : } else {
1631 : 1217 : dpif_netlink_encode_execute(dpif->dp_ifindex, &op->u.execute,
1632 : : &aux->request);
1633 : : }
1634 : 1217 : break;
1635 : :
1636 : : case DPIF_OP_FLOW_GET:
1637 : 567 : get = &op->u.flow_get;
1638 : 567 : dpif_netlink_init_flow_get(dpif, get, &flow);
1639 : 567 : aux->txn.reply = get->buffer;
1640 : 567 : dpif_netlink_flow_to_ofpbuf(&flow, &aux->request);
1641 : 567 : break;
1642 : :
1643 : : default:
1644 : 0 : OVS_NOT_REACHED();
1645 : : }
1646 : : }
1647 : :
1648 [ + + ]: 9974 : for (i = 0; i < n_ops; i++) {
1649 : 5588 : txnsp[i] = &auxes[i].txn;
1650 : : }
1651 : 4386 : nl_transact_multiple(NETLINK_GENERIC, txnsp, n_ops);
1652 : :
1653 [ + + ]: 9974 : for (i = 0; i < n_ops; i++) {
1654 : 5588 : struct op_auxdata *aux = &auxes[i];
1655 : 5588 : struct nl_transaction *txn = &auxes[i].txn;
1656 : 5588 : struct dpif_op *op = ops[i];
1657 : : struct dpif_flow_put *put;
1658 : : struct dpif_flow_del *del;
1659 : : struct dpif_flow_get *get;
1660 : :
1661 : 5588 : op->error = txn->error;
1662 : :
1663 [ + + + + : 5588 : switch (op->type) {
- ]
1664 : : case DPIF_OP_FLOW_PUT:
1665 : 1981 : put = &op->u.flow_put;
1666 [ - + ]: 1981 : if (put->stats) {
1667 [ # # ]: 0 : if (!op->error) {
1668 : : struct dpif_netlink_flow reply;
1669 : :
1670 : 0 : op->error = dpif_netlink_flow_from_ofpbuf(&reply,
1671 : 0 : txn->reply);
1672 [ # # ]: 0 : if (!op->error) {
1673 : 0 : dpif_netlink_flow_get_stats(&reply, put->stats);
1674 : : }
1675 : : }
1676 : : }
1677 : 1981 : break;
1678 : :
1679 : : case DPIF_OP_FLOW_DEL:
1680 : 1823 : del = &op->u.flow_del;
1681 [ + + ]: 1823 : if (del->stats) {
1682 [ + - ]: 1319 : if (!op->error) {
1683 : : struct dpif_netlink_flow reply;
1684 : :
1685 : 1319 : op->error = dpif_netlink_flow_from_ofpbuf(&reply,
1686 : 1319 : txn->reply);
1687 [ + - ]: 1319 : if (!op->error) {
1688 : 1319 : dpif_netlink_flow_get_stats(&reply, del->stats);
1689 : : }
1690 : : }
1691 : : }
1692 : 1823 : break;
1693 : :
1694 : : case DPIF_OP_EXECUTE:
1695 : 1217 : break;
1696 : :
1697 : : case DPIF_OP_FLOW_GET:
1698 : 567 : get = &op->u.flow_get;
1699 [ + - ]: 567 : if (!op->error) {
1700 : : struct dpif_netlink_flow reply;
1701 : :
1702 : 567 : op->error = dpif_netlink_flow_from_ofpbuf(&reply, txn->reply);
1703 [ + - ]: 567 : if (!op->error) {
1704 : 567 : dpif_netlink_flow_to_dpif_flow(&dpif->dpif, get->flow,
1705 : : &reply);
1706 : : }
1707 : : }
1708 : 567 : break;
1709 : :
1710 : : default:
1711 : 0 : OVS_NOT_REACHED();
1712 : : }
1713 : :
1714 : 5588 : ofpbuf_uninit(&aux->request);
1715 : 5588 : ofpbuf_uninit(&aux->reply);
1716 : : }
1717 : :
1718 : 4386 : return n_ops;
1719 : : }
1720 : :
1721 : : static void
1722 : 4386 : dpif_netlink_operate(struct dpif *dpif_, struct dpif_op **ops, size_t n_ops)
1723 : : {
1724 : 4386 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1725 : :
1726 [ + + ]: 8772 : while (n_ops > 0) {
1727 : 4386 : size_t chunk = dpif_netlink_operate__(dpif, ops, n_ops);
1728 : 4386 : ops += chunk;
1729 : 4386 : n_ops -= chunk;
1730 : : }
1731 : 4386 : }
1732 : :
1733 : : #if _WIN32
1734 : : static void
1735 : : dpif_netlink_handler_uninit(struct dpif_handler *handler)
1736 : : {
1737 : : vport_delete_sock_pool(handler);
1738 : : }
1739 : :
1740 : : static int
1741 : : dpif_netlink_handler_init(struct dpif_handler *handler)
1742 : : {
1743 : : return vport_create_sock_pool(handler);
1744 : : }
1745 : : #else
1746 : :
1747 : : static int
1748 : 63 : dpif_netlink_handler_init(struct dpif_handler *handler)
1749 : : {
1750 : 63 : handler->epoll_fd = epoll_create(10);
1751 [ - + ]: 63 : return handler->epoll_fd < 0 ? errno : 0;
1752 : : }
1753 : :
1754 : : static void
1755 : 63 : dpif_netlink_handler_uninit(struct dpif_handler *handler)
1756 : : {
1757 : 63 : close(handler->epoll_fd);
1758 : 63 : }
1759 : : #endif
1760 : :
1761 : : /* Synchronizes 'channels' in 'dpif->handlers' with the set of vports
1762 : : * currently in 'dpif' in the kernel, by adding a new set of channels for
1763 : : * any kernel vport that lacks one and deleting any channels that have no
1764 : : * backing kernel vports. */
1765 : : static int
1766 : 126 : dpif_netlink_refresh_channels(struct dpif_netlink *dpif, uint32_t n_handlers)
1767 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
1768 : : {
1769 : : unsigned long int *keep_channels;
1770 : : struct dpif_netlink_vport vport;
1771 : : size_t keep_channels_nbits;
1772 : : struct nl_dump dump;
1773 : : uint64_t reply_stub[NL_DUMP_BUFSIZE / 8];
1774 : : struct ofpbuf buf;
1775 : 126 : int retval = 0;
1776 : : size_t i;
1777 : :
1778 : : ovs_assert(!WINDOWS || n_handlers <= 1);
1779 : : ovs_assert(!WINDOWS || dpif->n_handlers <= 1);
1780 : :
1781 [ + + ]: 126 : if (dpif->n_handlers != n_handlers) {
1782 : 63 : destroy_all_channels(dpif);
1783 : 63 : dpif->handlers = xzalloc(n_handlers * sizeof *dpif->handlers);
1784 [ + + ]: 126 : for (i = 0; i < n_handlers; i++) {
1785 : : int error;
1786 : 63 : struct dpif_handler *handler = &dpif->handlers[i];
1787 : :
1788 : 63 : error = dpif_netlink_handler_init(handler);
1789 [ - + ]: 63 : if (error) {
1790 : : size_t j;
1791 : 0 : struct dpif_handler *tmp = &dpif->handlers[i];
1792 : :
1793 : :
1794 [ # # ]: 0 : for (j = 0; j < i; j++) {
1795 : 0 : dpif_netlink_handler_uninit(tmp);
1796 : : }
1797 : 0 : free(dpif->handlers);
1798 : 0 : dpif->handlers = NULL;
1799 : :
1800 : 0 : return error;
1801 : : }
1802 : : }
1803 : 63 : dpif->n_handlers = n_handlers;
1804 : : }
1805 : :
1806 [ + + ]: 252 : for (i = 0; i < n_handlers; i++) {
1807 : 126 : struct dpif_handler *handler = &dpif->handlers[i];
1808 : :
1809 : 126 : handler->event_offset = handler->n_events = 0;
1810 : : }
1811 : :
1812 : 126 : keep_channels_nbits = dpif->uc_array_size;
1813 : 126 : keep_channels = bitmap_allocate(keep_channels_nbits);
1814 : :
1815 : 126 : ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub);
1816 : 126 : dpif_netlink_port_dump_start__(dpif, &dump);
1817 [ + + ]: 252 : while (!dpif_netlink_port_dump_next__(dpif, &dump, &vport, &buf)) {
1818 : 126 : uint32_t port_no = odp_to_u32(vport.port_no);
1819 : 126 : uint32_t *upcall_pids = NULL;
1820 : : int error;
1821 : :
1822 [ + + ]: 126 : if (port_no >= dpif->uc_array_size
1823 [ - + ]: 63 : || !vport_get_pids(dpif, port_no, &upcall_pids)) {
1824 : 63 : struct nl_sock **socksp = vport_create_socksp(dpif, &error);
1825 : :
1826 [ - + ]: 63 : if (!socksp) {
1827 : 0 : goto error;
1828 : : }
1829 : :
1830 : 63 : error = vport_add_channels(dpif, vport.port_no, socksp);
1831 [ - + ]: 63 : if (error) {
1832 [ # # ]: 0 : VLOG_INFO("%s: could not add channels for port %s",
1833 : : dpif_name(&dpif->dpif), vport.name);
1834 : 0 : vport_del_socksp(dpif, socksp);
1835 : 0 : retval = error;
1836 : 0 : goto error;
1837 : : }
1838 : 63 : upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
1839 : 63 : free(socksp);
1840 : : }
1841 : :
1842 : : /* Configure the vport to deliver misses to 'sock'. */
1843 [ + + ]: 126 : if (vport.upcall_pids[0] == 0
1844 [ + - ]: 63 : || vport.n_upcall_pids != dpif->n_handlers
1845 [ - + ]: 63 : || memcmp(upcall_pids, vport.upcall_pids, n_handlers * sizeof
1846 : : *upcall_pids)) {
1847 : : struct dpif_netlink_vport vport_request;
1848 : :
1849 : 63 : dpif_netlink_vport_init(&vport_request);
1850 : 63 : vport_request.cmd = OVS_VPORT_CMD_SET;
1851 : 63 : vport_request.dp_ifindex = dpif->dp_ifindex;
1852 : 63 : vport_request.port_no = vport.port_no;
1853 : 63 : vport_request.n_upcall_pids = dpif->n_handlers;
1854 : 63 : vport_request.upcall_pids = upcall_pids;
1855 : 63 : error = dpif_netlink_vport_transact(&vport_request, NULL, NULL);
1856 [ - + ]: 63 : if (error) {
1857 [ # # ]: 0 : VLOG_WARN_RL(&error_rl,
1858 : : "%s: failed to set upcall pid on port: %s",
1859 : : dpif_name(&dpif->dpif), ovs_strerror(error));
1860 : :
1861 [ # # ][ # # ]: 0 : if (error != ENODEV && error != ENOENT) {
1862 : 0 : retval = error;
1863 : : } else {
1864 : : /* The vport isn't really there, even though the dump says
1865 : : * it is. Probably we just hit a race after a port
1866 : : * disappeared. */
1867 : : }
1868 : 63 : goto error;
1869 : : }
1870 : : }
1871 : :
1872 [ + + ]: 126 : if (port_no < keep_channels_nbits) {
1873 : 63 : bitmap_set1(keep_channels, port_no);
1874 : : }
1875 : 126 : free(upcall_pids);
1876 : 126 : continue;
1877 : :
1878 : : error:
1879 : 0 : free(upcall_pids);
1880 : 0 : vport_del_channels(dpif, vport.port_no);
1881 : : }
1882 : 126 : nl_dump_done(&dump);
1883 : 126 : ofpbuf_uninit(&buf);
1884 : :
1885 : : /* Discard any saved channels that we didn't reuse. */
1886 [ + + ]: 189 : for (i = 0; i < keep_channels_nbits; i++) {
1887 [ - + ]: 63 : if (!bitmap_is_set(keep_channels, i)) {
1888 : 0 : vport_del_channels(dpif, u32_to_odp(i));
1889 : : }
1890 : : }
1891 : 126 : free(keep_channels);
1892 : :
1893 : 126 : return retval;
1894 : : }
1895 : :
1896 : : static int
1897 : 63 : dpif_netlink_recv_set__(struct dpif_netlink *dpif, bool enable)
1898 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
1899 : : {
1900 [ - + ]: 63 : if ((dpif->handlers != NULL) == enable) {
1901 : 0 : return 0;
1902 [ - + ]: 63 : } else if (!enable) {
1903 : 0 : destroy_all_channels(dpif);
1904 : 0 : return 0;
1905 : : } else {
1906 : 63 : return dpif_netlink_refresh_channels(dpif, 1);
1907 : : }
1908 : : }
1909 : :
1910 : : static int
1911 : 63 : dpif_netlink_recv_set(struct dpif *dpif_, bool enable)
1912 : : {
1913 : 63 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1914 : : int error;
1915 : :
1916 : 63 : fat_rwlock_wrlock(&dpif->upcall_lock);
1917 : 63 : error = dpif_netlink_recv_set__(dpif, enable);
1918 : 63 : fat_rwlock_unlock(&dpif->upcall_lock);
1919 : :
1920 : 63 : return error;
1921 : : }
1922 : :
1923 : : static int
1924 : 63 : dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
1925 : : {
1926 : 63 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
1927 : 63 : int error = 0;
1928 : :
1929 : : #ifdef _WIN32
1930 : : /* Multiple upcall handlers will be supported once kernel datapath supports
1931 : : * it. */
1932 : : if (n_handlers > 1) {
1933 : : return error;
1934 : : }
1935 : : #endif
1936 : :
1937 : 63 : fat_rwlock_wrlock(&dpif->upcall_lock);
1938 [ + - ]: 63 : if (dpif->handlers) {
1939 : 63 : error = dpif_netlink_refresh_channels(dpif, n_handlers);
1940 : : }
1941 : 63 : fat_rwlock_unlock(&dpif->upcall_lock);
1942 : :
1943 : 63 : return error;
1944 : : }
1945 : :
1946 : : static int
1947 : 0 : dpif_netlink_queue_to_priority(const struct dpif *dpif OVS_UNUSED,
1948 : : uint32_t queue_id, uint32_t *priority)
1949 : : {
1950 [ # # ]: 0 : if (queue_id < 0xf000) {
1951 : 0 : *priority = TC_H_MAKE(1 << 16, queue_id + 1);
1952 : 0 : return 0;
1953 : : } else {
1954 : 0 : return EINVAL;
1955 : : }
1956 : : }
1957 : :
1958 : : static int
1959 : 1374 : parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
1960 : : struct dpif_upcall *upcall, int *dp_ifindex)
1961 : : {
1962 : : static const struct nl_policy ovs_packet_policy[] = {
1963 : : /* Always present. */
1964 : : [OVS_PACKET_ATTR_PACKET] = { .type = NL_A_UNSPEC,
1965 : : .min_len = ETH_HEADER_LEN },
1966 : : [OVS_PACKET_ATTR_KEY] = { .type = NL_A_NESTED },
1967 : :
1968 : : /* OVS_PACKET_CMD_ACTION only. */
1969 : : [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
1970 : : [OVS_PACKET_ATTR_EGRESS_TUN_KEY] = { .type = NL_A_NESTED, .optional = true },
1971 : : [OVS_PACKET_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true },
1972 : : [OVS_PACKET_ATTR_MRU] = { .type = NL_A_U16, .optional = true }
1973 : : };
1974 : :
1975 : 1374 : struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
1976 : 1374 : struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
1977 : 1374 : struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
1978 : 1374 : struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
1979 : :
1980 : : struct nlattr *a[ARRAY_SIZE(ovs_packet_policy)];
1981 [ + - ][ + - ]: 1374 : if (!nlmsg || !genl || !ovs_header
[ + - ]
1982 [ + - ]: 1374 : || nlmsg->nlmsg_type != ovs_packet_family
1983 [ - + ]: 1374 : || !nl_policy_parse(&b, 0, ovs_packet_policy, a,
1984 : : ARRAY_SIZE(ovs_packet_policy))) {
1985 : 0 : return EINVAL;
1986 : : }
1987 : :
1988 : 2748 : int type = (genl->cmd == OVS_PACKET_CMD_MISS ? DPIF_UC_MISS
1989 [ + + ]: 1439 : : genl->cmd == OVS_PACKET_CMD_ACTION ? DPIF_UC_ACTION
1990 [ + - ]: 65 : : -1);
1991 [ - + ]: 1374 : if (type < 0) {
1992 : 0 : return EINVAL;
1993 : : }
1994 : :
1995 : : /* (Re)set ALL fields of '*upcall' on successful return. */
1996 : 1374 : upcall->type = type;
1997 : 1374 : upcall->key = CONST_CAST(struct nlattr *,
1998 : : nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
1999 : 1374 : upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
2000 : 1374 : dpif_flow_hash(&dpif->dpif, upcall->key, upcall->key_len, &upcall->ufid);
2001 : 1374 : upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
2002 : 1374 : upcall->out_tun_key = a[OVS_PACKET_ATTR_EGRESS_TUN_KEY];
2003 : 1374 : upcall->actions = a[OVS_PACKET_ATTR_ACTIONS];
2004 : 1374 : upcall->mru = a[OVS_PACKET_ATTR_MRU];
2005 : :
2006 : : /* Allow overwriting the netlink attribute header without reallocating. */
2007 : 1374 : dp_packet_use_stub(&upcall->packet,
2008 : 1374 : CONST_CAST(struct nlattr *,
2009 : : nl_attr_get(a[OVS_PACKET_ATTR_PACKET])) - 1,
2010 : 1374 : nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]) +
2011 : : sizeof(struct nlattr));
2012 : 1374 : dp_packet_set_data(&upcall->packet,
2013 : 1374 : (char *)dp_packet_data(&upcall->packet) + sizeof(struct nlattr));
2014 : 1374 : dp_packet_set_size(&upcall->packet, nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]));
2015 : :
2016 : 1374 : *dp_ifindex = ovs_header->dp_ifindex;
2017 : :
2018 : 1374 : return 0;
2019 : : }
2020 : :
2021 : : #ifdef _WIN32
2022 : : #define PACKET_RECV_BATCH_SIZE 50
2023 : : static int
2024 : : dpif_netlink_recv_windows(struct dpif_netlink *dpif, uint32_t handler_id,
2025 : : struct dpif_upcall *upcall, struct ofpbuf *buf)
2026 : : OVS_REQ_RDLOCK(dpif->upcall_lock)
2027 : : {
2028 : : struct dpif_handler *handler;
2029 : : int read_tries = 0;
2030 : : struct dpif_windows_vport_sock *sock_pool;
2031 : : uint32_t i;
2032 : :
2033 : : if (!dpif->handlers) {
2034 : : return EAGAIN;
2035 : : }
2036 : :
2037 : : /* Only one handler is supported currently. */
2038 : : if (handler_id >= 1) {
2039 : : return EAGAIN;
2040 : : }
2041 : :
2042 : : if (handler_id >= dpif->n_handlers) {
2043 : : return EAGAIN;
2044 : : }
2045 : :
2046 : : handler = &dpif->handlers[handler_id];
2047 : : sock_pool = handler->vport_sock_pool;
2048 : :
2049 : : for (i = 0; i < VPORT_SOCK_POOL_SIZE; i++) {
2050 : : for (;;) {
2051 : : int dp_ifindex;
2052 : : int error;
2053 : :
2054 : : if (++read_tries > PACKET_RECV_BATCH_SIZE) {
2055 : : return EAGAIN;
2056 : : }
2057 : :
2058 : : error = nl_sock_recv(sock_pool[i].nl_sock, buf, false);
2059 : : if (error == ENOBUFS) {
2060 : : /* ENOBUFS typically means that we've received so many
2061 : : * packets that the buffer overflowed. Try again
2062 : : * immediately because there's almost certainly a packet
2063 : : * waiting for us. */
2064 : : /* XXX: report_loss(dpif, ch, idx, handler_id); */
2065 : : continue;
2066 : : }
2067 : :
2068 : : /* XXX: ch->last_poll = time_msec(); */
2069 : : if (error) {
2070 : : if (error == EAGAIN) {
2071 : : break;
2072 : : }
2073 : : return error;
2074 : : }
2075 : :
2076 : : error = parse_odp_packet(dpif, buf, upcall, &dp_ifindex);
2077 : : if (!error && dp_ifindex == dpif->dp_ifindex) {
2078 : : return 0;
2079 : : } else if (error) {
2080 : : return error;
2081 : : }
2082 : : }
2083 : : }
2084 : :
2085 : : return EAGAIN;
2086 : : }
2087 : : #else
2088 : : static int
2089 : 3449 : dpif_netlink_recv__(struct dpif_netlink *dpif, uint32_t handler_id,
2090 : : struct dpif_upcall *upcall, struct ofpbuf *buf)
2091 : : OVS_REQ_RDLOCK(dpif->upcall_lock)
2092 : : {
2093 : : struct dpif_handler *handler;
2094 : 3449 : int read_tries = 0;
2095 : :
2096 [ + - ][ - + ]: 3449 : if (!dpif->handlers || handler_id >= dpif->n_handlers) {
2097 : 0 : return EAGAIN;
2098 : : }
2099 : :
2100 : 3449 : handler = &dpif->handlers[handler_id];
2101 [ + + ]: 3449 : if (handler->event_offset >= handler->n_events) {
2102 : : int retval;
2103 : :
2104 : 3438 : handler->event_offset = handler->n_events = 0;
2105 : :
2106 : : do {
2107 : 3438 : retval = epoll_wait(handler->epoll_fd, handler->epoll_events,
2108 : : dpif->uc_array_size, 0);
2109 [ - + ][ # # ]: 3438 : } while (retval < 0 && errno == EINTR);
2110 : :
2111 [ - + ]: 3438 : if (retval < 0) {
2112 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
2113 [ # # ]: 0 : VLOG_WARN_RL(&rl, "epoll_wait failed (%s)", ovs_strerror(errno));
2114 [ + + ]: 3438 : } else if (retval > 0) {
2115 : 1363 : handler->n_events = retval;
2116 : : }
2117 : : }
2118 : :
2119 [ + + ]: 3449 : while (handler->event_offset < handler->n_events) {
2120 : 1374 : int idx = handler->epoll_events[handler->event_offset].data.u32;
2121 : 1374 : struct dpif_channel *ch = &dpif->handlers[handler_id].channels[idx];
2122 : :
2123 : 1374 : handler->event_offset++;
2124 : :
2125 : : for (;;) {
2126 : : int dp_ifindex;
2127 : : int error;
2128 : :
2129 [ - + ]: 1374 : if (++read_tries > 50) {
2130 : 1374 : return EAGAIN;
2131 : : }
2132 : :
2133 : 1374 : error = nl_sock_recv(ch->sock, buf, false);
2134 [ - + ]: 1374 : if (error == ENOBUFS) {
2135 : : /* ENOBUFS typically means that we've received so many
2136 : : * packets that the buffer overflowed. Try again
2137 : : * immediately because there's almost certainly a packet
2138 : : * waiting for us. */
2139 : 0 : report_loss(dpif, ch, idx, handler_id);
2140 : 0 : continue;
2141 : : }
2142 : :
2143 : 1374 : ch->last_poll = time_msec();
2144 [ - + ]: 1374 : if (error) {
2145 [ # # ]: 0 : if (error == EAGAIN) {
2146 : 0 : break;
2147 : : }
2148 : 0 : return error;
2149 : : }
2150 : :
2151 : 1374 : error = parse_odp_packet(dpif, buf, upcall, &dp_ifindex);
2152 [ + - ][ + - ]: 1374 : if (!error && dp_ifindex == dpif->dp_ifindex) {
2153 : 1374 : return 0;
2154 [ # # ]: 0 : } else if (error) {
2155 : 0 : return error;
2156 : : }
2157 : 0 : }
2158 : : }
2159 : :
2160 : 2075 : return EAGAIN;
2161 : : }
2162 : : #endif
2163 : :
2164 : : static int
2165 : 3449 : dpif_netlink_recv(struct dpif *dpif_, uint32_t handler_id,
2166 : : struct dpif_upcall *upcall, struct ofpbuf *buf)
2167 : : {
2168 : 3449 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
2169 : : int error;
2170 : :
2171 : 3449 : fat_rwlock_rdlock(&dpif->upcall_lock);
2172 : : #ifdef _WIN32
2173 : : error = dpif_netlink_recv_windows(dpif, handler_id, upcall, buf);
2174 : : #else
2175 : 3449 : error = dpif_netlink_recv__(dpif, handler_id, upcall, buf);
2176 : : #endif
2177 : 3449 : fat_rwlock_unlock(&dpif->upcall_lock);
2178 : :
2179 : 3449 : return error;
2180 : : }
2181 : :
2182 : : static void
2183 : 885 : dpif_netlink_recv_wait__(struct dpif_netlink *dpif, uint32_t handler_id)
2184 : : OVS_REQ_RDLOCK(dpif->upcall_lock)
2185 : : {
2186 : : #ifdef _WIN32
2187 : : uint32_t i;
2188 : : struct dpif_windows_vport_sock *sock_pool =
2189 : : dpif->handlers[handler_id].vport_sock_pool;
2190 : :
2191 : : /* Only one handler is supported currently. */
2192 : : if (handler_id >= 1) {
2193 : : return;
2194 : : }
2195 : :
2196 : : for (i = 0; i < VPORT_SOCK_POOL_SIZE; i++) {
2197 : : nl_sock_wait(sock_pool[i].nl_sock, POLLIN);
2198 : : }
2199 : : #else
2200 [ + - ][ + - ]: 885 : if (dpif->handlers && handler_id < dpif->n_handlers) {
2201 : 885 : struct dpif_handler *handler = &dpif->handlers[handler_id];
2202 : :
2203 : 885 : poll_fd_wait(handler->epoll_fd, POLLIN);
2204 : : }
2205 : : #endif
2206 : 885 : }
2207 : :
2208 : : static void
2209 : 885 : dpif_netlink_recv_wait(struct dpif *dpif_, uint32_t handler_id)
2210 : : {
2211 : 885 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
2212 : :
2213 : 885 : fat_rwlock_rdlock(&dpif->upcall_lock);
2214 : 885 : dpif_netlink_recv_wait__(dpif, handler_id);
2215 : 885 : fat_rwlock_unlock(&dpif->upcall_lock);
2216 : 885 : }
2217 : :
2218 : : static void
2219 : 0 : dpif_netlink_recv_purge__(struct dpif_netlink *dpif)
2220 : : OVS_REQ_WRLOCK(dpif->upcall_lock)
2221 : : {
2222 [ # # ]: 0 : if (dpif->handlers) {
2223 : : size_t i, j;
2224 : :
2225 [ # # ]: 0 : for (i = 0; i < dpif->uc_array_size; i++ ) {
2226 [ # # ]: 0 : if (!dpif->handlers[0].channels[i].sock) {
2227 : 0 : continue;
2228 : : }
2229 : :
2230 [ # # ]: 0 : for (j = 0; j < dpif->n_handlers; j++) {
2231 : 0 : nl_sock_drain(dpif->handlers[j].channels[i].sock);
2232 : : }
2233 : : }
2234 : : }
2235 : 0 : }
2236 : :
2237 : : static void
2238 : 0 : dpif_netlink_recv_purge(struct dpif *dpif_)
2239 : : {
2240 : 0 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
2241 : :
2242 : 0 : fat_rwlock_wrlock(&dpif->upcall_lock);
2243 : 0 : dpif_netlink_recv_purge__(dpif);
2244 : 0 : fat_rwlock_unlock(&dpif->upcall_lock);
2245 : 0 : }
2246 : :
2247 : : static char *
2248 : 63 : dpif_netlink_get_datapath_version(void)
2249 : : {
2250 : 63 : char *version_str = NULL;
2251 : :
2252 : : #ifdef __linux__
2253 : :
2254 : : #define MAX_VERSION_STR_SIZE 80
2255 : : #define LINUX_DATAPATH_VERSION_FILE "/sys/module/openvswitch/version"
2256 : : FILE *f;
2257 : :
2258 : 63 : f = fopen(LINUX_DATAPATH_VERSION_FILE, "r");
2259 [ + - ]: 63 : if (f) {
2260 : : char *newline;
2261 : : char version[MAX_VERSION_STR_SIZE];
2262 : :
2263 [ + - ]: 63 : if (fgets(version, MAX_VERSION_STR_SIZE, f)) {
2264 : 63 : newline = strchr(version, '\n');
2265 [ + - ]: 63 : if (newline) {
2266 : 63 : *newline = '\0';
2267 : : }
2268 : 63 : version_str = xstrdup(version);
2269 : : }
2270 : 63 : fclose(f);
2271 : : }
2272 : : #endif
2273 : :
2274 : 63 : return version_str;
2275 : : }
2276 : :
2277 : : struct dpif_netlink_ct_dump_state {
2278 : : struct ct_dpif_dump_state up;
2279 : : struct nl_ct_dump_state *nl_ct_dump;
2280 : : };
2281 : :
2282 : : static int
2283 : 53 : dpif_netlink_ct_dump_start(struct dpif *dpif OVS_UNUSED,
2284 : : struct ct_dpif_dump_state **dump_,
2285 : : const uint16_t *zone)
2286 : : {
2287 : : struct dpif_netlink_ct_dump_state *dump;
2288 : : int err;
2289 : :
2290 : 53 : dump = xzalloc(sizeof *dump);
2291 : 53 : err = nl_ct_dump_start(&dump->nl_ct_dump, zone);
2292 [ - + ]: 53 : if (err) {
2293 : 0 : free(dump);
2294 : 0 : return err;
2295 : : }
2296 : :
2297 : 53 : *dump_ = &dump->up;
2298 : :
2299 : 53 : return 0;
2300 : : }
2301 : :
2302 : : static int
2303 : 439 : dpif_netlink_ct_dump_next(struct dpif *dpif OVS_UNUSED,
2304 : : struct ct_dpif_dump_state *dump_,
2305 : : struct ct_dpif_entry *entry)
2306 : : {
2307 : : struct dpif_netlink_ct_dump_state *dump;
2308 : :
2309 : 439 : INIT_CONTAINER(dump, dump_, up);
2310 : :
2311 : 439 : return nl_ct_dump_next(dump->nl_ct_dump, entry);
2312 : : }
2313 : :
2314 : : static int
2315 : 53 : dpif_netlink_ct_dump_done(struct dpif *dpif OVS_UNUSED,
2316 : : struct ct_dpif_dump_state *dump_)
2317 : : {
2318 : : struct dpif_netlink_ct_dump_state *dump;
2319 : : int err;
2320 : :
2321 : 53 : INIT_CONTAINER(dump, dump_, up);
2322 : :
2323 : 53 : err = nl_ct_dump_done(dump->nl_ct_dump);
2324 : 53 : free(dump);
2325 : 53 : return err;
2326 : : }
2327 : :
2328 : : static int
2329 : 6 : dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone)
2330 : : {
2331 [ - + ]: 6 : if (zone) {
2332 : 0 : return nl_ct_flush_zone(*zone);
2333 : : } else {
2334 : 6 : return nl_ct_flush();
2335 : : }
2336 : : }
2337 : :
2338 : : const struct dpif_class dpif_netlink_class = {
2339 : : "system",
2340 : : NULL, /* init */
2341 : : dpif_netlink_enumerate,
2342 : : NULL,
2343 : : dpif_netlink_open,
2344 : : dpif_netlink_close,
2345 : : dpif_netlink_destroy,
2346 : : dpif_netlink_run,
2347 : : NULL, /* wait */
2348 : : dpif_netlink_get_stats,
2349 : : dpif_netlink_port_add,
2350 : : dpif_netlink_port_del,
2351 : : NULL, /* port_set_config */
2352 : : dpif_netlink_port_query_by_number,
2353 : : dpif_netlink_port_query_by_name,
2354 : : dpif_netlink_port_get_pid,
2355 : : dpif_netlink_port_dump_start,
2356 : : dpif_netlink_port_dump_next,
2357 : : dpif_netlink_port_dump_done,
2358 : : dpif_netlink_port_poll,
2359 : : dpif_netlink_port_poll_wait,
2360 : : dpif_netlink_flow_flush,
2361 : : dpif_netlink_flow_dump_create,
2362 : : dpif_netlink_flow_dump_destroy,
2363 : : dpif_netlink_flow_dump_thread_create,
2364 : : dpif_netlink_flow_dump_thread_destroy,
2365 : : dpif_netlink_flow_dump_next,
2366 : : dpif_netlink_operate,
2367 : : dpif_netlink_recv_set,
2368 : : dpif_netlink_handlers_set,
2369 : : NULL, /* poll_thread_set */
2370 : : dpif_netlink_queue_to_priority,
2371 : : dpif_netlink_recv,
2372 : : dpif_netlink_recv_wait,
2373 : : dpif_netlink_recv_purge,
2374 : : NULL, /* register_dp_purge_cb */
2375 : : NULL, /* register_upcall_cb */
2376 : : NULL, /* enable_upcall */
2377 : : NULL, /* disable_upcall */
2378 : : dpif_netlink_get_datapath_version, /* get_datapath_version */
2379 : : dpif_netlink_ct_dump_start,
2380 : : dpif_netlink_ct_dump_next,
2381 : : dpif_netlink_ct_dump_done,
2382 : : dpif_netlink_ct_flush
2383 : : };
2384 : :
2385 : : static int
2386 : 5496 : dpif_netlink_init(void)
2387 : : {
2388 : : static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
2389 : : static int error;
2390 : :
2391 [ + + ]: 5496 : if (ovsthread_once_start(&once)) {
2392 : 158 : error = nl_lookup_genl_family(OVS_DATAPATH_FAMILY,
2393 : : &ovs_datapath_family);
2394 [ + + ]: 158 : if (error) {
2395 [ + - ]: 31 : VLOG_WARN("Generic Netlink family '%s' does not exist. "
2396 : : "The Open vSwitch kernel module is probably not loaded.",
2397 : : OVS_DATAPATH_FAMILY);
2398 : : }
2399 [ + + ]: 158 : if (!error) {
2400 : 127 : error = nl_lookup_genl_family(OVS_VPORT_FAMILY, &ovs_vport_family);
2401 : : }
2402 [ + + ]: 158 : if (!error) {
2403 : 127 : error = nl_lookup_genl_family(OVS_FLOW_FAMILY, &ovs_flow_family);
2404 : : }
2405 [ + + ]: 158 : if (!error) {
2406 : 127 : error = nl_lookup_genl_family(OVS_PACKET_FAMILY,
2407 : : &ovs_packet_family);
2408 : : }
2409 [ + + ]: 158 : if (!error) {
2410 : 127 : error = nl_lookup_genl_mcgroup(OVS_VPORT_FAMILY, OVS_VPORT_MCGROUP,
2411 : : &ovs_vport_mcgroup);
2412 : : }
2413 : :
2414 : 158 : ovsthread_once_done(&once);
2415 : : }
2416 : :
2417 : 5496 : return error;
2418 : : }
2419 : :
2420 : : bool
2421 : 0 : dpif_netlink_is_internal_device(const char *name)
2422 : : {
2423 : : struct dpif_netlink_vport reply;
2424 : : struct ofpbuf *buf;
2425 : : int error;
2426 : :
2427 : 0 : error = dpif_netlink_vport_get(name, &reply, &buf);
2428 [ # # ]: 0 : if (!error) {
2429 : 0 : ofpbuf_delete(buf);
2430 [ # # ][ # # ]: 0 : } else if (error != ENODEV && error != ENOENT) {
2431 [ # # ]: 0 : VLOG_WARN_RL(&error_rl, "%s: vport query failed (%s)",
2432 : : name, ovs_strerror(error));
2433 : : }
2434 : :
2435 : 0 : return reply.type == OVS_VPORT_TYPE_INTERNAL;
2436 : : }
2437 : :
2438 : : /* Parses the contents of 'buf', which contains a "struct ovs_header" followed
2439 : : * by Netlink attributes, into 'vport'. Returns 0 if successful, otherwise a
2440 : : * positive errno value.
2441 : : *
2442 : : * 'vport' will contain pointers into 'buf', so the caller should not free
2443 : : * 'buf' while 'vport' is still in use. */
2444 : : static int
2445 : 4915 : dpif_netlink_vport_from_ofpbuf(struct dpif_netlink_vport *vport,
2446 : : const struct ofpbuf *buf)
2447 : : {
2448 : : static const struct nl_policy ovs_vport_policy[] = {
2449 : : [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32 },
2450 : : [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32 },
2451 : : [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
2452 : : [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC },
2453 : : [OVS_VPORT_ATTR_STATS] = { NL_POLICY_FOR(struct ovs_vport_stats),
2454 : : .optional = true },
2455 : : [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = true },
2456 : : };
2457 : :
2458 : 4915 : dpif_netlink_vport_init(vport);
2459 : :
2460 : 4915 : struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
2461 : 4915 : struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
2462 : 4915 : struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
2463 : 4915 : struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
2464 : :
2465 : : struct nlattr *a[ARRAY_SIZE(ovs_vport_policy)];
2466 [ + - ][ + - ]: 4915 : if (!nlmsg || !genl || !ovs_header
[ + - ]
2467 [ + - ]: 4915 : || nlmsg->nlmsg_type != ovs_vport_family
2468 [ - + ]: 4915 : || !nl_policy_parse(&b, 0, ovs_vport_policy, a,
2469 : : ARRAY_SIZE(ovs_vport_policy))) {
2470 : 0 : return EINVAL;
2471 : : }
2472 : :
2473 : 4915 : vport->cmd = genl->cmd;
2474 : 4915 : vport->dp_ifindex = ovs_header->dp_ifindex;
2475 : 4915 : vport->port_no = nl_attr_get_odp_port(a[OVS_VPORT_ATTR_PORT_NO]);
2476 : 4915 : vport->type = nl_attr_get_u32(a[OVS_VPORT_ATTR_TYPE]);
2477 : 4915 : vport->name = nl_attr_get_string(a[OVS_VPORT_ATTR_NAME]);
2478 [ + - ]: 4915 : if (a[OVS_VPORT_ATTR_UPCALL_PID]) {
2479 : 4915 : vport->n_upcall_pids = nl_attr_get_size(a[OVS_VPORT_ATTR_UPCALL_PID])
2480 : 4915 : / (sizeof *vport->upcall_pids);
2481 : 4915 : vport->upcall_pids = nl_attr_get(a[OVS_VPORT_ATTR_UPCALL_PID]);
2482 : :
2483 : : }
2484 [ + - ]: 4915 : if (a[OVS_VPORT_ATTR_STATS]) {
2485 : 4915 : vport->stats = nl_attr_get(a[OVS_VPORT_ATTR_STATS]);
2486 : : }
2487 [ + + ]: 4915 : if (a[OVS_VPORT_ATTR_OPTIONS]) {
2488 : 9 : vport->options = nl_attr_get(a[OVS_VPORT_ATTR_OPTIONS]);
2489 : 9 : vport->options_len = nl_attr_get_size(a[OVS_VPORT_ATTR_OPTIONS]);
2490 : : }
2491 : 4915 : return 0;
2492 : : }
2493 : :
2494 : : /* Appends to 'buf' (which must initially be empty) a "struct ovs_header"
2495 : : * followed by Netlink attributes corresponding to 'vport'. */
2496 : : static void
2497 : 5276 : dpif_netlink_vport_to_ofpbuf(const struct dpif_netlink_vport *vport,
2498 : : struct ofpbuf *buf)
2499 : : {
2500 : : struct ovs_header *ovs_header;
2501 : :
2502 : 5276 : nl_msg_put_genlmsghdr(buf, 0, ovs_vport_family, NLM_F_REQUEST | NLM_F_ECHO,
2503 : 5276 : vport->cmd, OVS_VPORT_VERSION);
2504 : :
2505 : 5276 : ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
2506 : 5276 : ovs_header->dp_ifindex = vport->dp_ifindex;
2507 : :
2508 [ + + ]: 5276 : if (vport->port_no != ODPP_NONE) {
2509 : 4455 : nl_msg_put_odp_port(buf, OVS_VPORT_ATTR_PORT_NO, vport->port_no);
2510 : : }
2511 : :
2512 [ + + ]: 5276 : if (vport->type != OVS_VPORT_TYPE_UNSPEC) {
2513 : 232 : nl_msg_put_u32(buf, OVS_VPORT_ATTR_TYPE, vport->type);
2514 : : }
2515 : :
2516 [ + + ]: 5276 : if (vport->name) {
2517 : 4664 : nl_msg_put_string(buf, OVS_VPORT_ATTR_NAME, vport->name);
2518 : : }
2519 : :
2520 [ + + ]: 5276 : if (vport->upcall_pids) {
2521 : 590 : nl_msg_put_unspec(buf, OVS_VPORT_ATTR_UPCALL_PID,
2522 : 590 : vport->upcall_pids,
2523 : 590 : vport->n_upcall_pids * sizeof *vport->upcall_pids);
2524 : : }
2525 : :
2526 [ - + ]: 5276 : if (vport->stats) {
2527 : 0 : nl_msg_put_unspec(buf, OVS_VPORT_ATTR_STATS,
2528 : 0 : vport->stats, sizeof *vport->stats);
2529 : : }
2530 : :
2531 [ + + ]: 5276 : if (vport->options) {
2532 : 3 : nl_msg_put_nested(buf, OVS_VPORT_ATTR_OPTIONS,
2533 : 3 : vport->options, vport->options_len);
2534 : : }
2535 : 5276 : }
2536 : :
2537 : : /* Clears 'vport' to "empty" values. */
2538 : : void
2539 : 10769 : dpif_netlink_vport_init(struct dpif_netlink_vport *vport)
2540 : : {
2541 : 10769 : memset(vport, 0, sizeof *vport);
2542 : 10769 : vport->port_no = ODPP_NONE;
2543 : 10769 : }
2544 : :
2545 : : /* Executes 'request' in the kernel datapath. If the command fails, returns a
2546 : : * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0
2547 : : * without doing anything else. If 'reply' and 'bufp' are nonnull, then the
2548 : : * result of the command is expected to be an ovs_vport also, which is decoded
2549 : : * and stored in '*reply' and '*bufp'. The caller must free '*bufp' when the
2550 : : * reply is no longer needed ('reply' will contain pointers into '*bufp'). */
2551 : : int
2552 : 5188 : dpif_netlink_vport_transact(const struct dpif_netlink_vport *request,
2553 : : struct dpif_netlink_vport *reply,
2554 : : struct ofpbuf **bufp)
2555 : : {
2556 : : struct ofpbuf *request_buf;
2557 : : int error;
2558 : :
2559 [ - + ]: 5188 : ovs_assert((reply != NULL) == (bufp != NULL));
2560 : :
2561 : 5188 : error = dpif_netlink_init();
2562 [ + + ]: 5188 : if (error) {
2563 [ + - ]: 166 : if (reply) {
2564 : 166 : *bufp = NULL;
2565 : 166 : dpif_netlink_vport_init(reply);
2566 : : }
2567 : 166 : return error;
2568 : : }
2569 : :
2570 : 5022 : request_buf = ofpbuf_new(1024);
2571 : 5022 : dpif_netlink_vport_to_ofpbuf(request, request_buf);
2572 : 5022 : error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
2573 : 5022 : ofpbuf_delete(request_buf);
2574 : :
2575 [ + + ]: 5022 : if (reply) {
2576 [ + + ]: 4664 : if (!error) {
2577 : 4418 : error = dpif_netlink_vport_from_ofpbuf(reply, *bufp);
2578 : : }
2579 [ + + ]: 4664 : if (error) {
2580 : 246 : dpif_netlink_vport_init(reply);
2581 : 246 : ofpbuf_delete(*bufp);
2582 : 246 : *bufp = NULL;
2583 : : }
2584 : : }
2585 : 5022 : return error;
2586 : : }
2587 : :
2588 : : /* Obtains information about the kernel vport named 'name' and stores it into
2589 : : * '*reply' and '*bufp'. The caller must free '*bufp' when the reply is no
2590 : : * longer needed ('reply' will contain pointers into '*bufp'). */
2591 : : int
2592 : 501 : dpif_netlink_vport_get(const char *name, struct dpif_netlink_vport *reply,
2593 : : struct ofpbuf **bufp)
2594 : : {
2595 : : struct dpif_netlink_vport request;
2596 : :
2597 : 501 : dpif_netlink_vport_init(&request);
2598 : 501 : request.cmd = OVS_VPORT_CMD_GET;
2599 : 501 : request.name = name;
2600 : :
2601 : 501 : return dpif_netlink_vport_transact(&request, reply, bufp);
2602 : : }
2603 : :
2604 : : /* Parses the contents of 'buf', which contains a "struct ovs_header" followed
2605 : : * by Netlink attributes, into 'dp'. Returns 0 if successful, otherwise a
2606 : : * positive errno value.
2607 : : *
2608 : : * 'dp' will contain pointers into 'buf', so the caller should not free 'buf'
2609 : : * while 'dp' is still in use. */
2610 : : static int
2611 : 1305 : dpif_netlink_dp_from_ofpbuf(struct dpif_netlink_dp *dp, const struct ofpbuf *buf)
2612 : : {
2613 : : static const struct nl_policy ovs_datapath_policy[] = {
2614 : : [OVS_DP_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
2615 : : [OVS_DP_ATTR_STATS] = { NL_POLICY_FOR(struct ovs_dp_stats),
2616 : : .optional = true },
2617 : : [OVS_DP_ATTR_MEGAFLOW_STATS] = {
2618 : : NL_POLICY_FOR(struct ovs_dp_megaflow_stats),
2619 : : .optional = true },
2620 : : };
2621 : :
2622 : 1305 : dpif_netlink_dp_init(dp);
2623 : :
2624 : 1305 : struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
2625 : 1305 : struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
2626 : 1305 : struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
2627 : 1305 : struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
2628 : :
2629 : : struct nlattr *a[ARRAY_SIZE(ovs_datapath_policy)];
2630 [ + - ][ + - ]: 1305 : if (!nlmsg || !genl || !ovs_header
[ + - ]
2631 [ + - ]: 1305 : || nlmsg->nlmsg_type != ovs_datapath_family
2632 [ - + ]: 1305 : || !nl_policy_parse(&b, 0, ovs_datapath_policy, a,
2633 : : ARRAY_SIZE(ovs_datapath_policy))) {
2634 : 0 : return EINVAL;
2635 : : }
2636 : :
2637 : 1305 : dp->cmd = genl->cmd;
2638 : 1305 : dp->dp_ifindex = ovs_header->dp_ifindex;
2639 : 1305 : dp->name = nl_attr_get_string(a[OVS_DP_ATTR_NAME]);
2640 [ + - ]: 1305 : if (a[OVS_DP_ATTR_STATS]) {
2641 : 1305 : dp->stats = nl_attr_get(a[OVS_DP_ATTR_STATS]);
2642 : : }
2643 : :
2644 [ + - ]: 1305 : if (a[OVS_DP_ATTR_MEGAFLOW_STATS]) {
2645 : 1305 : dp->megaflow_stats = nl_attr_get(a[OVS_DP_ATTR_MEGAFLOW_STATS]);
2646 : : }
2647 : :
2648 : 1305 : return 0;
2649 : : }
2650 : :
2651 : : /* Appends to 'buf' the Generic Netlink message described by 'dp'. */
2652 : : static void
2653 : 1432 : dpif_netlink_dp_to_ofpbuf(const struct dpif_netlink_dp *dp, struct ofpbuf *buf)
2654 : : {
2655 : : struct ovs_header *ovs_header;
2656 : :
2657 : 1432 : nl_msg_put_genlmsghdr(buf, 0, ovs_datapath_family,
2658 : 1432 : NLM_F_REQUEST | NLM_F_ECHO, dp->cmd,
2659 : : OVS_DATAPATH_VERSION);
2660 : :
2661 : 1432 : ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
2662 : 1432 : ovs_header->dp_ifindex = dp->dp_ifindex;
2663 : :
2664 [ + + ]: 1432 : if (dp->name) {
2665 : 186 : nl_msg_put_string(buf, OVS_DP_ATTR_NAME, dp->name);
2666 : : }
2667 : :
2668 [ + + ]: 1432 : if (dp->upcall_pid) {
2669 : 63 : nl_msg_put_u32(buf, OVS_DP_ATTR_UPCALL_PID, *dp->upcall_pid);
2670 : : }
2671 : :
2672 [ + + ]: 1432 : if (dp->user_features) {
2673 : 186 : nl_msg_put_u32(buf, OVS_DP_ATTR_USER_FEATURES, dp->user_features);
2674 : : }
2675 : :
2676 : : /* Skip OVS_DP_ATTR_STATS since we never have a reason to serialize it. */
2677 : 1432 : }
2678 : :
2679 : : /* Clears 'dp' to "empty" values. */
2680 : : static void
2681 : 3983 : dpif_netlink_dp_init(struct dpif_netlink_dp *dp)
2682 : : {
2683 : 3983 : memset(dp, 0, sizeof *dp);
2684 : 3983 : }
2685 : :
2686 : : static void
2687 : 122 : dpif_netlink_dp_dump_start(struct nl_dump *dump)
2688 : : {
2689 : : struct dpif_netlink_dp request;
2690 : : struct ofpbuf *buf;
2691 : :
2692 : 122 : dpif_netlink_dp_init(&request);
2693 : 122 : request.cmd = OVS_DP_CMD_GET;
2694 : :
2695 : 122 : buf = ofpbuf_new(1024);
2696 : 122 : dpif_netlink_dp_to_ofpbuf(&request, buf);
2697 : 122 : nl_dump_start(dump, NETLINK_GENERIC, buf);
2698 : 122 : ofpbuf_delete(buf);
2699 : 122 : }
2700 : :
2701 : : /* Executes 'request' in the kernel datapath. If the command fails, returns a
2702 : : * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0
2703 : : * without doing anything else. If 'reply' and 'bufp' are nonnull, then the
2704 : : * result of the command is expected to be of the same form, which is decoded
2705 : : * and stored in '*reply' and '*bufp'. The caller must free '*bufp' when the
2706 : : * reply is no longer needed ('reply' will contain pointers into '*bufp'). */
2707 : : static int
2708 : 1310 : dpif_netlink_dp_transact(const struct dpif_netlink_dp *request,
2709 : : struct dpif_netlink_dp *reply, struct ofpbuf **bufp)
2710 : : {
2711 : : struct ofpbuf *request_buf;
2712 : : int error;
2713 : :
2714 [ - + ]: 1310 : ovs_assert((reply != NULL) == (bufp != NULL));
2715 : :
2716 : 1310 : request_buf = ofpbuf_new(1024);
2717 : 1310 : dpif_netlink_dp_to_ofpbuf(request, request_buf);
2718 : 1310 : error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
2719 : 1310 : ofpbuf_delete(request_buf);
2720 : :
2721 [ + + ]: 1310 : if (reply) {
2722 : 1246 : dpif_netlink_dp_init(reply);
2723 [ + - ]: 1246 : if (!error) {
2724 : 1246 : error = dpif_netlink_dp_from_ofpbuf(reply, *bufp);
2725 : : }
2726 [ - + ]: 1246 : if (error) {
2727 : 0 : ofpbuf_delete(*bufp);
2728 : 0 : *bufp = NULL;
2729 : : }
2730 : : }
2731 : 1310 : return error;
2732 : : }
2733 : :
2734 : : /* Obtains information about 'dpif_' and stores it into '*reply' and '*bufp'.
2735 : : * The caller must free '*bufp' when the reply is no longer needed ('reply'
2736 : : * will contain pointers into '*bufp'). */
2737 : : static int
2738 : 1060 : dpif_netlink_dp_get(const struct dpif *dpif_, struct dpif_netlink_dp *reply,
2739 : : struct ofpbuf **bufp)
2740 : : {
2741 : 1060 : struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
2742 : : struct dpif_netlink_dp request;
2743 : :
2744 : 1060 : dpif_netlink_dp_init(&request);
2745 : 1060 : request.cmd = OVS_DP_CMD_GET;
2746 : 1060 : request.dp_ifindex = dpif->dp_ifindex;
2747 : :
2748 : 1060 : return dpif_netlink_dp_transact(&request, reply, bufp);
2749 : : }
2750 : :
2751 : : /* Parses the contents of 'buf', which contains a "struct ovs_header" followed
2752 : : * by Netlink attributes, into 'flow'. Returns 0 if successful, otherwise a
2753 : : * positive errno value.
2754 : : *
2755 : : * 'flow' will contain pointers into 'buf', so the caller should not free 'buf'
2756 : : * while 'flow' is still in use. */
2757 : : static int
2758 : 9741 : dpif_netlink_flow_from_ofpbuf(struct dpif_netlink_flow *flow,
2759 : : const struct ofpbuf *buf)
2760 : : {
2761 : : static const struct nl_policy ovs_flow_policy[__OVS_FLOW_ATTR_MAX] = {
2762 : : [OVS_FLOW_ATTR_KEY] = { .type = NL_A_NESTED, .optional = true },
2763 : : [OVS_FLOW_ATTR_MASK] = { .type = NL_A_NESTED, .optional = true },
2764 : : [OVS_FLOW_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true },
2765 : : [OVS_FLOW_ATTR_STATS] = { NL_POLICY_FOR(struct ovs_flow_stats),
2766 : : .optional = true },
2767 : : [OVS_FLOW_ATTR_TCP_FLAGS] = { .type = NL_A_U8, .optional = true },
2768 : : [OVS_FLOW_ATTR_USED] = { .type = NL_A_U64, .optional = true },
2769 : : [OVS_FLOW_ATTR_UFID] = { .type = NL_A_UNSPEC, .optional = true,
2770 : : .min_len = sizeof(ovs_u128) },
2771 : : /* The kernel never uses OVS_FLOW_ATTR_CLEAR. */
2772 : : /* The kernel never uses OVS_FLOW_ATTR_PROBE. */
2773 : : /* The kernel never uses OVS_FLOW_ATTR_UFID_FLAGS. */
2774 : : };
2775 : :
2776 : 9741 : dpif_netlink_flow_init(flow);
2777 : :
2778 : 9741 : struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
2779 : 9741 : struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
2780 : 9741 : struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
2781 : 9741 : struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
2782 : :
2783 : : struct nlattr *a[ARRAY_SIZE(ovs_flow_policy)];
2784 [ + - ][ + - ]: 9741 : if (!nlmsg || !genl || !ovs_header
[ + - ]
2785 [ + - ]: 9741 : || nlmsg->nlmsg_type != ovs_flow_family
2786 [ - + ]: 9741 : || !nl_policy_parse(&b, 0, ovs_flow_policy, a,
2787 : : ARRAY_SIZE(ovs_flow_policy))) {
2788 : 0 : return EINVAL;
2789 : : }
2790 [ + + ][ - + ]: 9741 : if (!a[OVS_FLOW_ATTR_KEY] && !a[OVS_FLOW_ATTR_UFID]) {
2791 : 0 : return EINVAL;
2792 : : }
2793 : :
2794 : 9741 : flow->nlmsg_flags = nlmsg->nlmsg_flags;
2795 : 9741 : flow->dp_ifindex = ovs_header->dp_ifindex;
2796 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_KEY]) {
2797 : 652 : flow->key = nl_attr_get(a[OVS_FLOW_ATTR_KEY]);
2798 : 652 : flow->key_len = nl_attr_get_size(a[OVS_FLOW_ATTR_KEY]);
2799 : : }
2800 : :
2801 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_UFID]) {
2802 : : const ovs_u128 *ufid;
2803 : :
2804 : 9300 : ufid = nl_attr_get_unspec(a[OVS_FLOW_ATTR_UFID],
2805 : 9300 : nl_attr_get_size(a[OVS_FLOW_ATTR_UFID]));
2806 : 9300 : flow->ufid = *ufid;
2807 : 9300 : flow->ufid_present = true;
2808 : : }
2809 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_MASK]) {
2810 : 652 : flow->mask = nl_attr_get(a[OVS_FLOW_ATTR_MASK]);
2811 : 652 : flow->mask_len = nl_attr_get_size(a[OVS_FLOW_ATTR_MASK]);
2812 : : }
2813 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_ACTIONS]) {
2814 : 652 : flow->actions = nl_attr_get(a[OVS_FLOW_ATTR_ACTIONS]);
2815 : 652 : flow->actions_len = nl_attr_get_size(a[OVS_FLOW_ATTR_ACTIONS]);
2816 : : }
2817 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_STATS]) {
2818 : 4228 : flow->stats = nl_attr_get(a[OVS_FLOW_ATTR_STATS]);
2819 : : }
2820 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_TCP_FLAGS]) {
2821 : 1523 : flow->tcp_flags = nl_attr_get(a[OVS_FLOW_ATTR_TCP_FLAGS]);
2822 : : }
2823 [ + + ]: 9741 : if (a[OVS_FLOW_ATTR_USED]) {
2824 : 4228 : flow->used = nl_attr_get(a[OVS_FLOW_ATTR_USED]);
2825 : : }
2826 : 9741 : return 0;
2827 : : }
2828 : :
2829 : : /* Appends to 'buf' (which must initially be empty) a "struct ovs_header"
2830 : : * followed by Netlink attributes corresponding to 'flow'. */
2831 : : static void
2832 : 6713 : dpif_netlink_flow_to_ofpbuf(const struct dpif_netlink_flow *flow,
2833 : : struct ofpbuf *buf)
2834 : : {
2835 : : struct ovs_header *ovs_header;
2836 : :
2837 : 6713 : nl_msg_put_genlmsghdr(buf, 0, ovs_flow_family,
2838 : 6713 : NLM_F_REQUEST | flow->nlmsg_flags,
2839 : 6713 : flow->cmd, OVS_FLOW_VERSION);
2840 : :
2841 : 6713 : ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
2842 : 6713 : ovs_header->dp_ifindex = flow->dp_ifindex;
2843 : :
2844 [ + + ]: 6713 : if (flow->ufid_present) {
2845 : 2985 : nl_msg_put_unspec(buf, OVS_FLOW_ATTR_UFID, &flow->ufid,
2846 : : sizeof flow->ufid);
2847 : : }
2848 [ + + ]: 6713 : if (flow->ufid_terse) {
2849 : 3522 : nl_msg_put_u32(buf, OVS_FLOW_ATTR_UFID_FLAGS,
2850 : : OVS_UFID_F_OMIT_KEY | OVS_UFID_F_OMIT_MASK
2851 : : | OVS_UFID_F_OMIT_ACTIONS);
2852 : : }
2853 [ + + ][ + + ]: 6713 : if (!flow->ufid_terse || !flow->ufid_present) {
2854 [ + + ]: 5394 : if (flow->key_len) {
2855 : 2989 : nl_msg_put_unspec(buf, OVS_FLOW_ATTR_KEY,
2856 : 2989 : flow->key, flow->key_len);
2857 : : }
2858 : :
2859 [ + + ]: 5394 : if (flow->mask_len) {
2860 : 1351 : nl_msg_put_unspec(buf, OVS_FLOW_ATTR_MASK,
2861 : 1351 : flow->mask, flow->mask_len);
2862 : : }
2863 [ + + ][ - + ]: 5394 : if (flow->actions || flow->actions_len) {
2864 : 1981 : nl_msg_put_unspec(buf, OVS_FLOW_ATTR_ACTIONS,
2865 : 1981 : flow->actions, flow->actions_len);
2866 : : }
2867 : : }
2868 : :
2869 : : /* We never need to send these to the kernel. */
2870 [ - + ]: 6713 : ovs_assert(!flow->stats);
2871 [ - + ]: 6713 : ovs_assert(!flow->tcp_flags);
2872 [ - + ]: 6713 : ovs_assert(!flow->used);
2873 : :
2874 [ - + ]: 6713 : if (flow->clear) {
2875 : 0 : nl_msg_put_flag(buf, OVS_FLOW_ATTR_CLEAR);
2876 : : }
2877 [ + + ]: 6713 : if (flow->probe) {
2878 : 567 : nl_msg_put_flag(buf, OVS_FLOW_ATTR_PROBE);
2879 : : }
2880 : 6713 : }
2881 : :
2882 : : /* Clears 'flow' to "empty" values. */
2883 : : static void
2884 : 16454 : dpif_netlink_flow_init(struct dpif_netlink_flow *flow)
2885 : : {
2886 : 16454 : memset(flow, 0, sizeof *flow);
2887 : 16454 : }
2888 : :
2889 : : /* Executes 'request' in the kernel datapath. If the command fails, returns a
2890 : : * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0
2891 : : * without doing anything else. If 'reply' and 'bufp' are nonnull, then the
2892 : : * result of the command is expected to be a flow also, which is decoded and
2893 : : * stored in '*reply' and '*bufp'. The caller must free '*bufp' when the reply
2894 : : * is no longer needed ('reply' will contain pointers into '*bufp'). */
2895 : : static int
2896 : 137 : dpif_netlink_flow_transact(struct dpif_netlink_flow *request,
2897 : : struct dpif_netlink_flow *reply,
2898 : : struct ofpbuf **bufp)
2899 : : {
2900 : : struct ofpbuf *request_buf;
2901 : : int error;
2902 : :
2903 [ - + ]: 137 : ovs_assert((reply != NULL) == (bufp != NULL));
2904 : :
2905 [ - + ]: 137 : if (reply) {
2906 : 0 : request->nlmsg_flags |= NLM_F_ECHO;
2907 : : }
2908 : :
2909 : 137 : request_buf = ofpbuf_new(1024);
2910 : 137 : dpif_netlink_flow_to_ofpbuf(request, request_buf);
2911 : 137 : error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
2912 : 137 : ofpbuf_delete(request_buf);
2913 : :
2914 [ - + ]: 137 : if (reply) {
2915 [ # # ]: 0 : if (!error) {
2916 : 0 : error = dpif_netlink_flow_from_ofpbuf(reply, *bufp);
2917 : : }
2918 [ # # ]: 0 : if (error) {
2919 : 0 : dpif_netlink_flow_init(reply);
2920 : 0 : ofpbuf_delete(*bufp);
2921 : 0 : *bufp = NULL;
2922 : : }
2923 : : }
2924 : 137 : return error;
2925 : : }
2926 : :
2927 : : static void
2928 : 9741 : dpif_netlink_flow_get_stats(const struct dpif_netlink_flow *flow,
2929 : : struct dpif_flow_stats *stats)
2930 : : {
2931 [ + + ]: 9741 : if (flow->stats) {
2932 : 4228 : stats->n_packets = get_32aligned_u64(&flow->stats->n_packets);
2933 : 4228 : stats->n_bytes = get_32aligned_u64(&flow->stats->n_bytes);
2934 : : } else {
2935 : 5513 : stats->n_packets = 0;
2936 : 5513 : stats->n_bytes = 0;
2937 : : }
2938 [ + + ]: 9741 : stats->used = flow->used ? get_32aligned_u64(flow->used) : 0;
2939 [ + + ]: 9741 : stats->tcp_flags = flow->tcp_flags ? *flow->tcp_flags : 0;
2940 : 9741 : }
2941 : :
2942 : : /* Logs information about a packet that was recently lost in 'ch' (in
2943 : : * 'dpif_'). */
2944 : : static void
2945 : 0 : report_loss(struct dpif_netlink *dpif, struct dpif_channel *ch, uint32_t ch_idx,
2946 : : uint32_t handler_id)
2947 : : {
2948 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
2949 : : struct ds s;
2950 : :
2951 [ # # ]: 0 : if (VLOG_DROP_WARN(&rl)) {
2952 : 0 : return;
2953 : : }
2954 : :
2955 : 0 : ds_init(&s);
2956 [ # # ]: 0 : if (ch->last_poll != LLONG_MIN) {
2957 : 0 : ds_put_format(&s, " (last polled %lld ms ago)",
2958 : 0 : time_msec() - ch->last_poll);
2959 : : }
2960 : :
2961 [ # # ]: 0 : VLOG_WARN("%s: lost packet on port channel %u of handler %u",
2962 : : dpif_name(&dpif->dpif), ch_idx, handler_id);
2963 : 0 : ds_destroy(&s);
2964 : : }
|