Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2010, 2011, 2012, 2013, 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 "dummy.h"
20 : :
21 : : #include <errno.h>
22 : : #include <unistd.h>
23 : :
24 : : #include "dp-packet.h"
25 : : #include "dpif-netdev.h"
26 : : #include "flow.h"
27 : : #include "netdev-provider.h"
28 : : #include "netdev-vport.h"
29 : : #include "odp-util.h"
30 : : #include "openvswitch/dynamic-string.h"
31 : : #include "openvswitch/list.h"
32 : : #include "openvswitch/ofp-print.h"
33 : : #include "openvswitch/ofpbuf.h"
34 : : #include "openvswitch/vlog.h"
35 : : #include "ovs-atomic.h"
36 : : #include "packets.h"
37 : : #include "pcap-file.h"
38 : : #include "poll-loop.h"
39 : : #include "openvswitch/shash.h"
40 : : #include "sset.h"
41 : : #include "stream.h"
42 : : #include "unaligned.h"
43 : : #include "timeval.h"
44 : : #include "unixctl.h"
45 : : #include "reconnect.h"
46 : :
47 : 1288 : VLOG_DEFINE_THIS_MODULE(netdev_dummy);
48 : :
49 : : struct reconnect;
50 : :
51 : : struct dummy_packet_stream {
52 : : struct stream *stream;
53 : : struct dp_packet rxbuf;
54 : : struct ovs_list txq;
55 : : };
56 : :
57 : : enum dummy_packet_conn_type {
58 : : NONE, /* No connection is configured. */
59 : : PASSIVE, /* Listener. */
60 : : ACTIVE /* Connect to listener. */
61 : : };
62 : :
63 : : enum dummy_netdev_conn_state {
64 : : CONN_STATE_CONNECTED, /* Listener connected. */
65 : : CONN_STATE_NOT_CONNECTED, /* Listener not connected. */
66 : : CONN_STATE_UNKNOWN, /* No relavent information. */
67 : : };
68 : :
69 : : struct dummy_packet_pconn {
70 : : struct pstream *pstream;
71 : : struct dummy_packet_stream **streams;
72 : : size_t n_streams;
73 : : };
74 : :
75 : : struct dummy_packet_rconn {
76 : : struct dummy_packet_stream *rstream;
77 : : struct reconnect *reconnect;
78 : : };
79 : :
80 : : struct dummy_packet_conn {
81 : : enum dummy_packet_conn_type type;
82 : : union {
83 : : struct dummy_packet_pconn pconn;
84 : : struct dummy_packet_rconn rconn;
85 : : } u;
86 : : };
87 : :
88 : : struct pkt_list_node {
89 : : struct dp_packet *pkt;
90 : : struct ovs_list list_node;
91 : : };
92 : :
93 : : /* Protects 'dummy_list'. */
94 : : static struct ovs_mutex dummy_list_mutex = OVS_MUTEX_INITIALIZER;
95 : :
96 : : /* Contains all 'struct dummy_dev's. */
97 : : static struct ovs_list dummy_list OVS_GUARDED_BY(dummy_list_mutex)
98 : : = OVS_LIST_INITIALIZER(&dummy_list);
99 : :
100 : : struct netdev_dummy {
101 : : struct netdev up;
102 : :
103 : : /* In dummy_list. */
104 : : struct ovs_list list_node OVS_GUARDED_BY(dummy_list_mutex);
105 : :
106 : : /* Protects all members below. */
107 : : struct ovs_mutex mutex OVS_ACQ_AFTER(dummy_list_mutex);
108 : :
109 : : struct eth_addr hwaddr OVS_GUARDED;
110 : : int mtu OVS_GUARDED;
111 : : struct netdev_stats stats OVS_GUARDED;
112 : : enum netdev_flags flags OVS_GUARDED;
113 : : int ifindex OVS_GUARDED;
114 : : int numa_id OVS_GUARDED;
115 : :
116 : : struct dummy_packet_conn conn OVS_GUARDED;
117 : :
118 : : FILE *tx_pcap, *rxq_pcap OVS_GUARDED;
119 : :
120 : : struct in_addr address, netmask;
121 : : struct in6_addr ipv6, ipv6_mask;
122 : : struct ovs_list rxes OVS_GUARDED; /* List of child "netdev_rxq_dummy"s. */
123 : :
124 : : /* The following properties are for dummy-pmd and they cannot be changed
125 : : * when a device is running, so we remember the request and update them
126 : : * next time netdev_dummy_reconfigure() is called. */
127 : : int requested_n_txq OVS_GUARDED;
128 : : int requested_n_rxq OVS_GUARDED;
129 : : int requested_numa_id OVS_GUARDED;
130 : : };
131 : :
132 : : /* Max 'recv_queue_len' in struct netdev_dummy. */
133 : : #define NETDEV_DUMMY_MAX_QUEUE 100
134 : :
135 : : struct netdev_rxq_dummy {
136 : : struct netdev_rxq up;
137 : : struct ovs_list node; /* In netdev_dummy's "rxes" list. */
138 : : struct ovs_list recv_queue;
139 : : int recv_queue_len; /* ovs_list_size(&recv_queue). */
140 : : struct seq *seq; /* Reports newly queued packets. */
141 : : };
142 : :
143 : : static unixctl_cb_func netdev_dummy_set_admin_state;
144 : : static int netdev_dummy_construct(struct netdev *);
145 : : static void netdev_dummy_queue_packet(struct netdev_dummy *,
146 : : struct dp_packet *, int);
147 : :
148 : : static void dummy_packet_stream_close(struct dummy_packet_stream *);
149 : :
150 : : static void pkt_list_delete(struct ovs_list *);
151 : :
152 : : static bool
153 : 53752933 : is_dummy_class(const struct netdev_class *class)
154 : : {
155 : 53752933 : return class->construct == netdev_dummy_construct;
156 : : }
157 : :
158 : : static struct netdev_dummy *
159 : 26959168 : netdev_dummy_cast(const struct netdev *netdev)
160 : : {
161 [ - + ]: 26959168 : ovs_assert(is_dummy_class(netdev_get_class(netdev)));
162 : 26959196 : return CONTAINER_OF(netdev, struct netdev_dummy, up);
163 : : }
164 : :
165 : : static struct netdev_rxq_dummy *
166 : 26828802 : netdev_rxq_dummy_cast(const struct netdev_rxq *rx)
167 : : {
168 [ - + ]: 26828802 : ovs_assert(is_dummy_class(netdev_get_class(rx->netdev)));
169 : 20357388 : return CONTAINER_OF(rx, struct netdev_rxq_dummy, up);
170 : : }
171 : :
172 : : static void
173 : 120 : dummy_packet_stream_init(struct dummy_packet_stream *s, struct stream *stream)
174 : : {
175 [ + - ]: 120 : int rxbuf_size = stream ? 2048 : 0;
176 : 120 : s->stream = stream;
177 : 120 : dp_packet_init(&s->rxbuf, rxbuf_size);
178 : 120 : ovs_list_init(&s->txq);
179 : 120 : }
180 : :
181 : : static struct dummy_packet_stream *
182 : 60 : dummy_packet_stream_create(struct stream *stream)
183 : : {
184 : : struct dummy_packet_stream *s;
185 : :
186 : 60 : s = xzalloc(sizeof *s);
187 : 60 : dummy_packet_stream_init(s, stream);
188 : :
189 : 60 : return s;
190 : : }
191 : :
192 : : static void
193 : 62358 : dummy_packet_stream_wait(struct dummy_packet_stream *s)
194 : : {
195 : 62358 : stream_run_wait(s->stream);
196 [ + + ]: 62358 : if (!ovs_list_is_empty(&s->txq)) {
197 : 2622 : stream_send_wait(s->stream);
198 : : }
199 : 62358 : stream_recv_wait(s->stream);
200 : 62358 : }
201 : :
202 : : static void
203 : 4722 : dummy_packet_stream_send(struct dummy_packet_stream *s, const void *buffer, size_t size)
204 : : {
205 [ + - ]: 4722 : if (ovs_list_size(&s->txq) < NETDEV_DUMMY_MAX_QUEUE) {
206 : : struct dp_packet *b;
207 : : struct pkt_list_node *node;
208 : :
209 : 4722 : b = dp_packet_clone_data_with_headroom(buffer, size, 2);
210 : 4722 : put_unaligned_be16(dp_packet_push_uninit(b, 2), htons(size));
211 : :
212 : 4722 : node = xmalloc(sizeof *node);
213 : 4722 : node->pkt = b;
214 : 4722 : ovs_list_push_back(&s->txq, &node->list_node);
215 : : }
216 : 4722 : }
217 : :
218 : : static int
219 : 60283 : dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
220 : : {
221 : 60283 : int error = 0;
222 : : size_t n;
223 : :
224 : 60283 : stream_run(s->stream);
225 : :
226 [ + + ]: 60283 : if (!ovs_list_is_empty(&s->txq)) {
227 : : struct pkt_list_node *txbuf_node;
228 : : struct dp_packet *txbuf;
229 : : int retval;
230 : :
231 : 4722 : ASSIGN_CONTAINER(txbuf_node, ovs_list_front(&s->txq), list_node);
232 : 4722 : txbuf = txbuf_node->pkt;
233 : 4722 : retval = stream_send(s->stream, dp_packet_data(txbuf), dp_packet_size(txbuf));
234 : :
235 [ + - ]: 4722 : if (retval > 0) {
236 : 4722 : dp_packet_pull(txbuf, retval);
237 [ + - ]: 4722 : if (!dp_packet_size(txbuf)) {
238 : 4722 : ovs_list_remove(&txbuf_node->list_node);
239 : 4722 : free(txbuf_node);
240 : 4722 : dp_packet_delete(txbuf);
241 : : }
242 [ # # ]: 0 : } else if (retval != -EAGAIN) {
243 : 0 : error = -retval;
244 : : }
245 : : }
246 : :
247 [ + - ]: 60283 : if (!error) {
248 [ + + ]: 60283 : if (dp_packet_size(&s->rxbuf) < 2) {
249 : 55561 : n = 2 - dp_packet_size(&s->rxbuf);
250 : : } else {
251 : : uint16_t frame_len;
252 : :
253 : 4722 : frame_len = ntohs(get_unaligned_be16(dp_packet_data(&s->rxbuf)));
254 [ - + ]: 4722 : if (frame_len < ETH_HEADER_LEN) {
255 : 0 : error = EPROTO;
256 : 0 : n = 0;
257 : : } else {
258 : 4722 : n = (2 + frame_len) - dp_packet_size(&s->rxbuf);
259 : : }
260 : : }
261 : : }
262 [ + - ]: 60283 : if (!error) {
263 : : int retval;
264 : :
265 : 60283 : dp_packet_prealloc_tailroom(&s->rxbuf, n);
266 : 60283 : retval = stream_recv(s->stream, dp_packet_tail(&s->rxbuf), n);
267 : :
268 [ + + ]: 60283 : if (retval > 0) {
269 : 9444 : dp_packet_set_size(&s->rxbuf, dp_packet_size(&s->rxbuf) + retval);
270 [ + - ][ + + ]: 9444 : if (retval == n && dp_packet_size(&s->rxbuf) > 2) {
271 : 4722 : dp_packet_pull(&s->rxbuf, 2);
272 : 4722 : netdev_dummy_queue_packet(dev,
273 : 4722 : dp_packet_clone(&s->rxbuf), 0);
274 : 9444 : dp_packet_clear(&s->rxbuf);
275 : : }
276 [ + + ]: 50839 : } else if (retval != -EAGAIN) {
277 : 45 : error = (retval < 0 ? -retval
278 [ - + ]: 90 : : dp_packet_size(&s->rxbuf) ? EPROTO
279 [ - + ]: 45 : : EOF);
280 : : }
281 : : }
282 : :
283 : 60283 : return error;
284 : : }
285 : :
286 : : static void
287 : 45 : dummy_packet_stream_close(struct dummy_packet_stream *s)
288 : : {
289 : 45 : stream_close(s->stream);
290 : 45 : dp_packet_uninit(&s->rxbuf);
291 : 45 : pkt_list_delete(&s->txq);
292 : 45 : }
293 : :
294 : : static void
295 : 2963 : dummy_packet_conn_init(struct dummy_packet_conn *conn)
296 : : {
297 : 2963 : memset(conn, 0, sizeof *conn);
298 : 2963 : conn->type = NONE;
299 : 2963 : }
300 : :
301 : : static void
302 : 80 : dummy_packet_conn_get_config(struct dummy_packet_conn *conn, struct smap *args)
303 : : {
304 : :
305 [ - - + ]: 80 : switch (conn->type) {
306 : : case PASSIVE:
307 : 0 : smap_add(args, "pstream", pstream_get_name(conn->u.pconn.pstream));
308 : 0 : break;
309 : :
310 : : case ACTIVE:
311 : 0 : smap_add(args, "stream", stream_get_name(conn->u.rconn.rstream->stream));
312 : 0 : break;
313 : :
314 : : case NONE:
315 : : default:
316 : 80 : break;
317 : : }
318 : 80 : }
319 : :
320 : : static void
321 : 1038 : dummy_packet_conn_close(struct dummy_packet_conn *conn)
322 : : {
323 : : int i;
324 : 1038 : struct dummy_packet_pconn *pconn = &conn->u.pconn;
325 : 1038 : struct dummy_packet_rconn *rconn = &conn->u.rconn;
326 : :
327 [ + + + ]: 1038 : switch (conn->type) {
328 : : case PASSIVE:
329 : 1 : pstream_close(pconn->pstream);
330 [ - + ]: 1 : for (i = 0; i < pconn->n_streams; i++) {
331 : 0 : dummy_packet_stream_close(pconn->streams[i]);
332 : 0 : free(pconn->streams[i]);
333 : : }
334 : 1 : free(pconn->streams);
335 : 1 : pconn->pstream = NULL;
336 : 1 : pconn->streams = NULL;
337 : 1 : break;
338 : :
339 : : case ACTIVE:
340 : 1 : dummy_packet_stream_close(rconn->rstream);
341 : 1 : free(rconn->rstream);
342 : 1 : rconn->rstream = NULL;
343 : 1 : reconnect_destroy(rconn->reconnect);
344 : 1 : rconn->reconnect = NULL;
345 : 1 : break;
346 : :
347 : : case NONE:
348 : : default:
349 : 1036 : break;
350 : : }
351 : :
352 : 1038 : conn->type = NONE;
353 : 1038 : memset(conn, 0, sizeof *conn);
354 : 1038 : }
355 : :
356 : : static void
357 : 5296 : dummy_packet_conn_set_config(struct dummy_packet_conn *conn,
358 : : const struct smap *args)
359 : : {
360 : 5296 : const char *pstream = smap_get(args, "pstream");
361 : 5296 : const char *stream = smap_get(args, "stream");
362 : :
363 [ + + ][ - + ]: 5296 : if (pstream && stream) {
364 [ # # ]: 0 : VLOG_WARN("Open failed: both %s and %s are configured",
365 : : pstream, stream);
366 : 0 : return;
367 : : }
368 : :
369 [ + + + ]: 5296 : switch (conn->type) {
370 : : case PASSIVE:
371 [ + - + - ]: 76 : if (pstream &&
372 : 38 : !strcmp(pstream_get_name(conn->u.pconn.pstream), pstream)) {
373 : 38 : return;
374 : : }
375 : 0 : dummy_packet_conn_close(conn);
376 : 0 : break;
377 : : case ACTIVE:
378 [ + - + - ]: 676 : if (stream &&
379 : 338 : !strcmp(stream_get_name(conn->u.rconn.rstream->stream), stream)) {
380 : 338 : return;
381 : : }
382 : 0 : dummy_packet_conn_close(conn);
383 : 0 : break;
384 : : case NONE:
385 : : default:
386 : 4920 : break;
387 : : }
388 : :
389 [ + + ]: 4920 : if (pstream) {
390 : : int error;
391 : :
392 : 62 : error = pstream_open(pstream, &conn->u.pconn.pstream, DSCP_DEFAULT);
393 [ - + ]: 62 : if (error) {
394 [ # # ]: 0 : VLOG_WARN("%s: open failed (%s)", pstream, ovs_strerror(error));
395 : : } else {
396 : 62 : conn->type = PASSIVE;
397 : : }
398 : : }
399 : :
400 [ + + ]: 4920 : if (stream) {
401 : : int error;
402 : : struct stream *active_stream;
403 : : struct reconnect *reconnect;
404 : :
405 : 60 : reconnect = reconnect_create(time_msec());
406 : 60 : reconnect_set_name(reconnect, stream);
407 : 60 : reconnect_set_passive(reconnect, false, time_msec());
408 : 60 : reconnect_enable(reconnect, time_msec());
409 : 60 : reconnect_set_backoff(reconnect, 100, INT_MAX);
410 : 60 : reconnect_set_probe_interval(reconnect, 0);
411 : 60 : conn->u.rconn.reconnect = reconnect;
412 : 60 : conn->type = ACTIVE;
413 : :
414 : 60 : error = stream_open(stream, &active_stream, DSCP_DEFAULT);
415 : 60 : conn->u.rconn.rstream = dummy_packet_stream_create(active_stream);
416 : :
417 [ + - - ]: 60 : switch (error) {
418 : : case 0:
419 : 60 : reconnect_connected(reconnect, time_msec());
420 : 60 : break;
421 : :
422 : : case EAGAIN:
423 : 0 : reconnect_connecting(reconnect, time_msec());
424 : 0 : break;
425 : :
426 : : default:
427 : 0 : reconnect_connect_failed(reconnect, time_msec(), error);
428 : 0 : stream_close(active_stream);
429 : 0 : conn->u.rconn.rstream->stream = NULL;
430 : 60 : break;
431 : : }
432 : : }
433 : : }
434 : :
435 : : static void
436 : 26703 : dummy_pconn_run(struct netdev_dummy *dev)
437 : : OVS_REQUIRES(dev->mutex)
438 : : {
439 : : struct stream *new_stream;
440 : 26703 : struct dummy_packet_pconn *pconn = &dev->conn.u.pconn;
441 : : int error;
442 : : size_t i;
443 : :
444 : 26703 : error = pstream_accept(pconn->pstream, &new_stream);
445 [ + + ]: 26703 : if (!error) {
446 : : struct dummy_packet_stream *s;
447 : :
448 : 60 : pconn->streams = xrealloc(pconn->streams,
449 : 60 : ((pconn->n_streams + 1)
450 : : * sizeof s));
451 : 60 : s = xmalloc(sizeof *s);
452 : 60 : pconn->streams[pconn->n_streams++] = s;
453 : 60 : dummy_packet_stream_init(s, new_stream);
454 [ - + ]: 26643 : } else if (error != EAGAIN) {
455 [ # # ]: 0 : VLOG_WARN("%s: accept failed (%s)",
456 : : pstream_get_name(pconn->pstream), ovs_strerror(error));
457 : 0 : pstream_close(pconn->pstream);
458 : 0 : pconn->pstream = NULL;
459 : 0 : dev->conn.type = NONE;
460 : : }
461 : :
462 [ + + ]: 52975 : for (i = 0; i < pconn->n_streams; ) {
463 : 26272 : struct dummy_packet_stream *s = pconn->streams[i];
464 : :
465 : 26272 : error = dummy_packet_stream_run(dev, s);
466 [ + + ]: 26272 : if (error) {
467 [ - + ]: 44 : VLOG_DBG("%s: closing connection (%s)",
468 : : stream_get_name(s->stream),
469 : : ovs_retval_to_string(error));
470 : 44 : dummy_packet_stream_close(s);
471 : 44 : free(s);
472 : 44 : pconn->streams[i] = pconn->streams[--pconn->n_streams];
473 : : } else {
474 : 26228 : i++;
475 : : }
476 : : }
477 : 26703 : }
478 : :
479 : : static void
480 : 34014 : dummy_rconn_run(struct netdev_dummy *dev)
481 : : OVS_REQUIRES(dev->mutex)
482 : : {
483 : 34014 : struct dummy_packet_rconn *rconn = &dev->conn.u.rconn;
484 : :
485 [ - + ]: 34014 : switch (reconnect_run(rconn->reconnect, time_msec())) {
486 : : case RECONNECT_CONNECT:
487 : : {
488 : : int error;
489 : :
490 [ # # ]: 0 : if (rconn->rstream->stream) {
491 : 0 : error = stream_connect(rconn->rstream->stream);
492 : : } else {
493 : 0 : error = stream_open(reconnect_get_name(rconn->reconnect),
494 : 0 : &rconn->rstream->stream, DSCP_DEFAULT);
495 : : }
496 : :
497 [ # # # ]: 0 : switch (error) {
498 : : case 0:
499 : 0 : reconnect_connected(rconn->reconnect, time_msec());
500 : 0 : break;
501 : :
502 : : case EAGAIN:
503 : 0 : reconnect_connecting(rconn->reconnect, time_msec());
504 : 0 : break;
505 : :
506 : : default:
507 : 0 : reconnect_connect_failed(rconn->reconnect, time_msec(), error);
508 : 0 : stream_close(rconn->rstream->stream);
509 : 0 : rconn->rstream->stream = NULL;
510 : 0 : break;
511 : : }
512 : : }
513 : 0 : break;
514 : :
515 : : case RECONNECT_DISCONNECT:
516 : : case RECONNECT_PROBE:
517 : : default:
518 : 34014 : break;
519 : : }
520 : :
521 [ + + ]: 34014 : if (reconnect_is_connected(rconn->reconnect)) {
522 : : int err;
523 : :
524 : 34011 : err = dummy_packet_stream_run(dev, rconn->rstream);
525 : :
526 [ + + ]: 34011 : if (err) {
527 : 1 : reconnect_disconnected(rconn->reconnect, time_msec(), err);
528 : 1 : stream_close(rconn->rstream->stream);
529 : 1 : rconn->rstream->stream = NULL;
530 : : }
531 : : }
532 : 34014 : }
533 : :
534 : : static void
535 : 511610 : dummy_packet_conn_run(struct netdev_dummy *dev)
536 : : OVS_REQUIRES(dev->mutex)
537 : : {
538 [ + + + ]: 511610 : switch (dev->conn.type) {
539 : : case PASSIVE:
540 : 26703 : dummy_pconn_run(dev);
541 : 26703 : break;
542 : :
543 : : case ACTIVE:
544 : 34014 : dummy_rconn_run(dev);
545 : 34014 : break;
546 : :
547 : : case NONE:
548 : : default:
549 : 450893 : break;
550 : : }
551 : 511610 : }
552 : :
553 : : static void
554 : 511610 : dummy_packet_conn_wait(struct dummy_packet_conn *conn)
555 : : {
556 : : int i;
557 [ + + + ]: 511610 : switch (conn->type) {
558 : : case PASSIVE:
559 : 26703 : pstream_wait(conn->u.pconn.pstream);
560 [ + + ]: 52931 : for (i = 0; i < conn->u.pconn.n_streams; i++) {
561 : 26228 : struct dummy_packet_stream *s = conn->u.pconn.streams[i];
562 : 26228 : dummy_packet_stream_wait(s);
563 : : }
564 : 26703 : break;
565 : : case ACTIVE:
566 [ + + ]: 34014 : if (reconnect_is_connected(conn->u.rconn.reconnect)) {
567 : 34010 : dummy_packet_stream_wait(conn->u.rconn.rstream);
568 : : }
569 : 34014 : break;
570 : :
571 : : case NONE:
572 : : default:
573 : 450893 : break;
574 : : }
575 : 511610 : }
576 : :
577 : : static void
578 : 13397 : dummy_packet_conn_send(struct dummy_packet_conn *conn,
579 : : const void *buffer, size_t size)
580 : : {
581 : : int i;
582 : :
583 [ + + + ]: 13397 : switch (conn->type) {
584 : : case PASSIVE:
585 [ + + ]: 5209 : for (i = 0; i < conn->u.pconn.n_streams; i++) {
586 : 2602 : struct dummy_packet_stream *s = conn->u.pconn.streams[i];
587 : :
588 : 2602 : dummy_packet_stream_send(s, buffer, size);
589 : 2602 : pstream_wait(conn->u.pconn.pstream);
590 : : }
591 : 2607 : break;
592 : :
593 : : case ACTIVE:
594 [ + - ]: 2120 : if (reconnect_is_connected(conn->u.rconn.reconnect)) {
595 : 2120 : dummy_packet_stream_send(conn->u.rconn.rstream, buffer, size);
596 : 2120 : dummy_packet_stream_wait(conn->u.rconn.rstream);
597 : : }
598 : 2120 : break;
599 : :
600 : : case NONE:
601 : : default:
602 : 8670 : break;
603 : : }
604 : 13397 : }
605 : :
606 : : static enum dummy_netdev_conn_state
607 : 5 : dummy_netdev_get_conn_state(struct dummy_packet_conn *conn)
608 : : {
609 : : enum dummy_netdev_conn_state state;
610 : :
611 [ + - ]: 5 : if (conn->type == ACTIVE) {
612 [ + - ]: 5 : if (reconnect_is_connected(conn->u.rconn.reconnect)) {
613 : 5 : state = CONN_STATE_CONNECTED;
614 : : } else {
615 : 5 : state = CONN_STATE_NOT_CONNECTED;
616 : : }
617 : : } else {
618 : 0 : state = CONN_STATE_UNKNOWN;
619 : : }
620 : :
621 : 5 : return state;
622 : : }
623 : :
624 : : static void
625 : 321880 : netdev_dummy_run(const struct netdev_class *netdev_class)
626 : : {
627 : : struct netdev_dummy *dev;
628 : :
629 : 321880 : ovs_mutex_lock(&dummy_list_mutex);
630 [ + + ]: 2159424 : LIST_FOR_EACH (dev, list_node, &dummy_list) {
631 [ + + ]: 1837544 : if (netdev_get_class(&dev->up) != netdev_class) {
632 : 1325934 : continue;
633 : : }
634 : 511610 : ovs_mutex_lock(&dev->mutex);
635 : 511610 : dummy_packet_conn_run(dev);
636 : 511610 : ovs_mutex_unlock(&dev->mutex);
637 : : }
638 : 321880 : ovs_mutex_unlock(&dummy_list_mutex);
639 : 321880 : }
640 : :
641 : : static void
642 : 321880 : netdev_dummy_wait(const struct netdev_class *netdev_class)
643 : : {
644 : : struct netdev_dummy *dev;
645 : :
646 : 321880 : ovs_mutex_lock(&dummy_list_mutex);
647 [ + + ]: 2159424 : LIST_FOR_EACH (dev, list_node, &dummy_list) {
648 [ + + ]: 1837544 : if (netdev_get_class(&dev->up) != netdev_class) {
649 : 1325934 : continue;
650 : : }
651 : 511610 : ovs_mutex_lock(&dev->mutex);
652 : 511610 : dummy_packet_conn_wait(&dev->conn);
653 : 511610 : ovs_mutex_unlock(&dev->mutex);
654 : : }
655 : 321880 : ovs_mutex_unlock(&dummy_list_mutex);
656 : 321880 : }
657 : :
658 : : static struct netdev *
659 : 2963 : netdev_dummy_alloc(void)
660 : : {
661 : 2963 : struct netdev_dummy *netdev = xzalloc(sizeof *netdev);
662 : 2963 : return &netdev->up;
663 : : }
664 : :
665 : : static int
666 : 2963 : netdev_dummy_construct(struct netdev *netdev_)
667 : : {
668 : : static atomic_count next_n = ATOMIC_COUNT_INIT(0xaa550000);
669 : 2963 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
670 : : unsigned int n;
671 : :
672 : 2963 : n = atomic_count_inc(&next_n);
673 : :
674 : 2963 : ovs_mutex_init(&netdev->mutex);
675 : 2963 : ovs_mutex_lock(&netdev->mutex);
676 : 2963 : netdev->hwaddr.ea[0] = 0xaa;
677 : 2963 : netdev->hwaddr.ea[1] = 0x55;
678 : 2963 : netdev->hwaddr.ea[2] = n >> 24;
679 : 2963 : netdev->hwaddr.ea[3] = n >> 16;
680 : 2963 : netdev->hwaddr.ea[4] = n >> 8;
681 : 2963 : netdev->hwaddr.ea[5] = n;
682 : 2963 : netdev->mtu = 1500;
683 : 2963 : netdev->flags = 0;
684 : 2963 : netdev->ifindex = -EOPNOTSUPP;
685 : 2963 : netdev->requested_n_rxq = netdev_->n_rxq;
686 : 2963 : netdev->requested_n_txq = netdev_->n_txq;
687 : 2963 : netdev->numa_id = 0;
688 : :
689 : 2963 : dummy_packet_conn_init(&netdev->conn);
690 : :
691 : 2963 : ovs_list_init(&netdev->rxes);
692 : 2963 : ovs_mutex_unlock(&netdev->mutex);
693 : :
694 : 2963 : ovs_mutex_lock(&dummy_list_mutex);
695 : 2963 : ovs_list_push_back(&dummy_list, &netdev->list_node);
696 : 2963 : ovs_mutex_unlock(&dummy_list_mutex);
697 : :
698 : 2963 : return 0;
699 : : }
700 : :
701 : : static void
702 : 1038 : netdev_dummy_destruct(struct netdev *netdev_)
703 : : {
704 : 1038 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
705 : :
706 : 1038 : ovs_mutex_lock(&dummy_list_mutex);
707 : 1038 : ovs_list_remove(&netdev->list_node);
708 : 1038 : ovs_mutex_unlock(&dummy_list_mutex);
709 : :
710 : 1038 : ovs_mutex_lock(&netdev->mutex);
711 : 1038 : dummy_packet_conn_close(&netdev->conn);
712 : 1038 : netdev->conn.type = NONE;
713 : :
714 : 1038 : ovs_mutex_unlock(&netdev->mutex);
715 : 1038 : ovs_mutex_destroy(&netdev->mutex);
716 : 1038 : }
717 : :
718 : : static void
719 : 1038 : netdev_dummy_dealloc(struct netdev *netdev_)
720 : : {
721 : 1038 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
722 : :
723 : 1038 : free(netdev);
724 : 1038 : }
725 : :
726 : : static int
727 : 80 : netdev_dummy_get_config(const struct netdev *dev, struct smap *args)
728 : : {
729 : 80 : struct netdev_dummy *netdev = netdev_dummy_cast(dev);
730 : :
731 : 80 : ovs_mutex_lock(&netdev->mutex);
732 : :
733 [ + + ]: 80 : if (netdev->ifindex >= 0) {
734 : 2 : smap_add_format(args, "ifindex", "%d", netdev->ifindex);
735 : : }
736 : :
737 : 80 : dummy_packet_conn_get_config(&netdev->conn, args);
738 : :
739 : : /* 'dummy-pmd' specific config. */
740 [ + + ]: 80 : if (!netdev_is_pmd(dev)) {
741 : 74 : goto exit;
742 : : }
743 : 6 : smap_add_format(args, "requested_rx_queues", "%d", netdev->requested_n_rxq);
744 : 6 : smap_add_format(args, "configured_rx_queues", "%d", dev->n_rxq);
745 : 6 : smap_add_format(args, "requested_tx_queues", "%d", netdev->requested_n_txq);
746 : 6 : smap_add_format(args, "configured_tx_queues", "%d", dev->n_txq);
747 : :
748 : : exit:
749 : 80 : ovs_mutex_unlock(&netdev->mutex);
750 : 80 : return 0;
751 : : }
752 : :
753 : : static int
754 : 1138 : netdev_dummy_get_addr_list(const struct netdev *netdev_, struct in6_addr **paddr,
755 : : struct in6_addr **pmask, int *n_addr)
756 : : {
757 : 1138 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
758 : 1138 : int cnt = 0, i = 0, err = 0;
759 : : struct in6_addr *addr, *mask;
760 : :
761 : 1138 : ovs_mutex_lock(&netdev->mutex);
762 [ + + ]: 1138 : if (netdev->address.s_addr != INADDR_ANY) {
763 : 400 : cnt++;
764 : : }
765 : :
766 [ + + ]: 1138 : if (ipv6_addr_is_set(&netdev->ipv6)) {
767 : 6 : cnt++;
768 : : }
769 [ + + ]: 1138 : if (!cnt) {
770 : 738 : err = EADDRNOTAVAIL;
771 : 738 : goto out;
772 : : }
773 : 400 : addr = xmalloc(sizeof *addr * cnt);
774 : 400 : mask = xmalloc(sizeof *mask * cnt);
775 [ + - ]: 400 : if (netdev->address.s_addr != INADDR_ANY) {
776 : 400 : in6_addr_set_mapped_ipv4(&addr[i], netdev->address.s_addr);
777 : 400 : in6_addr_set_mapped_ipv4(&mask[i], netdev->netmask.s_addr);
778 : 400 : i++;
779 : : }
780 : :
781 [ + + ]: 400 : if (ipv6_addr_is_set(&netdev->ipv6)) {
782 : 6 : memcpy(&addr[i], &netdev->ipv6, sizeof *addr);
783 : 6 : memcpy(&mask[i], &netdev->ipv6_mask, sizeof *mask);
784 : 6 : i++;
785 : : }
786 [ + - ]: 400 : if (paddr) {
787 : 400 : *paddr = addr;
788 : 400 : *pmask = mask;
789 : 400 : *n_addr = cnt;
790 : : } else {
791 : 0 : free(addr);
792 : 0 : free(mask);
793 : : }
794 : : out:
795 : 1138 : ovs_mutex_unlock(&netdev->mutex);
796 : :
797 : 1138 : return err;
798 : : }
799 : :
800 : : static int
801 : 45 : netdev_dummy_set_in4(struct netdev *netdev_, struct in_addr address,
802 : : struct in_addr netmask)
803 : : {
804 : 45 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
805 : :
806 : 45 : ovs_mutex_lock(&netdev->mutex);
807 : 45 : netdev->address = address;
808 : 45 : netdev->netmask = netmask;
809 : 45 : netdev_change_seq_changed(netdev_);
810 : 45 : ovs_mutex_unlock(&netdev->mutex);
811 : :
812 : 45 : return 0;
813 : : }
814 : :
815 : : static int
816 : 2 : netdev_dummy_set_in6(struct netdev *netdev_, struct in6_addr *in6,
817 : : struct in6_addr *mask)
818 : : {
819 : 2 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
820 : :
821 : 2 : ovs_mutex_lock(&netdev->mutex);
822 : 2 : netdev->ipv6 = *in6;
823 : 2 : netdev->ipv6_mask = *mask;
824 : 2 : netdev_change_seq_changed(netdev_);
825 : 2 : ovs_mutex_unlock(&netdev->mutex);
826 : :
827 : 2 : return 0;
828 : : }
829 : :
830 : : static int
831 : 5296 : netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
832 : : {
833 : 5296 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
834 : : const char *pcap;
835 : : int new_n_rxq, new_n_txq, new_numa_id;
836 : :
837 : 5296 : ovs_mutex_lock(&netdev->mutex);
838 : 5296 : netdev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP);
839 : :
840 : 5296 : dummy_packet_conn_set_config(&netdev->conn, args);
841 : :
842 [ + + ]: 5296 : if (netdev->rxq_pcap) {
843 : 1182 : fclose(netdev->rxq_pcap);
844 : : }
845 [ + + ][ + + ]: 5296 : if (netdev->tx_pcap && netdev->tx_pcap != netdev->rxq_pcap) {
846 : 1179 : fclose(netdev->tx_pcap);
847 : : }
848 : 5296 : netdev->rxq_pcap = netdev->tx_pcap = NULL;
849 : 5296 : pcap = smap_get(args, "pcap");
850 [ + + ]: 5296 : if (pcap) {
851 : 8 : netdev->rxq_pcap = netdev->tx_pcap = ovs_pcap_open(pcap, "ab");
852 : : } else {
853 : 5288 : const char *rxq_pcap = smap_get(args, "rxq_pcap");
854 : 5288 : const char *tx_pcap = smap_get(args, "tx_pcap");
855 : :
856 [ + + ]: 5288 : if (rxq_pcap) {
857 : 1457 : netdev->rxq_pcap = ovs_pcap_open(rxq_pcap, "ab");
858 : : }
859 [ + + ]: 5288 : if (tx_pcap) {
860 : 1460 : netdev->tx_pcap = ovs_pcap_open(tx_pcap, "ab");
861 : : }
862 : : }
863 : :
864 : 5296 : netdev_change_seq_changed(netdev_);
865 : :
866 : : /* 'dummy-pmd' specific config. */
867 [ + + ]: 5296 : if (!netdev_->netdev_class->is_pmd) {
868 : 5251 : goto exit;
869 : : }
870 : :
871 [ + + ]: 45 : new_n_rxq = MAX(smap_get_int(args, "n_rxq", netdev->requested_n_rxq), 1);
872 [ - + ]: 45 : new_n_txq = MAX(smap_get_int(args, "n_txq", netdev->requested_n_txq), 1);
873 : 45 : new_numa_id = smap_get_int(args, "numa_id", 0);
874 [ + + ]: 45 : if (new_n_rxq != netdev->requested_n_rxq
875 [ + - ]: 36 : || new_n_txq != netdev->requested_n_txq
876 [ + + ]: 36 : || new_numa_id != netdev->requested_numa_id) {
877 : 10 : netdev->requested_n_rxq = new_n_rxq;
878 : 10 : netdev->requested_n_txq = new_n_txq;
879 : 10 : netdev->requested_numa_id = new_numa_id;
880 : 10 : netdev_request_reconfigure(netdev_);
881 : : }
882 : :
883 : : exit:
884 : 5296 : ovs_mutex_unlock(&netdev->mutex);
885 : 5296 : return 0;
886 : : }
887 : :
888 : : static int
889 : 2368 : netdev_dummy_get_numa_id(const struct netdev *netdev_)
890 : : {
891 : 2368 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
892 : :
893 : 2368 : ovs_mutex_lock(&netdev->mutex);
894 : 2368 : int numa_id = netdev->numa_id;
895 : 2368 : ovs_mutex_unlock(&netdev->mutex);
896 : :
897 : 2368 : return numa_id;
898 : : }
899 : :
900 : : /* Sets the number of tx queues and rx queues for the dummy PMD interface. */
901 : : static int
902 : 10 : netdev_dummy_reconfigure(struct netdev *netdev_)
903 : : {
904 : 10 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
905 : :
906 : 10 : ovs_mutex_lock(&netdev->mutex);
907 : :
908 : 10 : netdev_->n_txq = netdev->requested_n_txq;
909 : 10 : netdev_->n_rxq = netdev->requested_n_rxq;
910 : 10 : netdev->numa_id = netdev->requested_numa_id;
911 : :
912 : 10 : ovs_mutex_unlock(&netdev->mutex);
913 : 10 : return 0;
914 : : }
915 : :
916 : : static struct netdev_rxq *
917 : 2258 : netdev_dummy_rxq_alloc(void)
918 : : {
919 : 2258 : struct netdev_rxq_dummy *rx = xzalloc(sizeof *rx);
920 : 2258 : return &rx->up;
921 : : }
922 : :
923 : : static int
924 : 2258 : netdev_dummy_rxq_construct(struct netdev_rxq *rxq_)
925 : : {
926 : 2258 : struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
927 : 2258 : struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
928 : :
929 : 2258 : ovs_mutex_lock(&netdev->mutex);
930 : 2258 : ovs_list_push_back(&netdev->rxes, &rx->node);
931 : 2258 : ovs_list_init(&rx->recv_queue);
932 : 2258 : rx->recv_queue_len = 0;
933 : 2258 : rx->seq = seq_create();
934 : 2258 : ovs_mutex_unlock(&netdev->mutex);
935 : :
936 : 2258 : return 0;
937 : : }
938 : :
939 : : static void
940 : 307 : netdev_dummy_rxq_destruct(struct netdev_rxq *rxq_)
941 : : {
942 : 307 : struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
943 : 307 : struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
944 : :
945 : 307 : ovs_mutex_lock(&netdev->mutex);
946 : 307 : ovs_list_remove(&rx->node);
947 : 307 : pkt_list_delete(&rx->recv_queue);
948 : 307 : ovs_mutex_unlock(&netdev->mutex);
949 : 307 : seq_destroy(rx->seq);
950 : 307 : }
951 : :
952 : : static void
953 : 307 : netdev_dummy_rxq_dealloc(struct netdev_rxq *rxq_)
954 : : {
955 : 307 : struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
956 : :
957 : 307 : free(rx);
958 : 307 : }
959 : :
960 : : static int
961 : 26314786 : netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet_batch *batch)
962 : : {
963 : 26314786 : struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
964 : 26314638 : struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
965 : : struct dp_packet *packet;
966 : :
967 : 26313556 : ovs_mutex_lock(&netdev->mutex);
968 [ + + ]: 26322084 : if (!ovs_list_is_empty(&rx->recv_queue)) {
969 : : struct pkt_list_node *pkt_node;
970 : :
971 : 8619 : ASSIGN_CONTAINER(pkt_node, ovs_list_pop_front(&rx->recv_queue), list_node);
972 : 8619 : packet = pkt_node->pkt;
973 : 8619 : free(pkt_node);
974 : 8619 : rx->recv_queue_len--;
975 : : } else {
976 : 26313241 : packet = NULL;
977 : : }
978 : 26321860 : ovs_mutex_unlock(&netdev->mutex);
979 : :
980 [ + + ]: 26322579 : if (!packet) {
981 [ + + ]: 26313960 : if (netdev_is_pmd(&netdev->up)) {
982 : : /* If 'netdev' is a PMD device, this is called as part of the PMD
983 : : * thread busy loop. We yield here (without quiescing) for two
984 : : * reasons:
985 : : *
986 : : * - To reduce the CPU utilization during the testsuite
987 : : * - To give valgrind a chance to switch thread. According
988 : : * to the valgrind documentation, there's a big lock that
989 : : * prevents multiple thread from being executed at the same
990 : : * time. On my system, without this sleep, the pmd threads
991 : : * testcases fail under valgrind, because ovs-vswitchd becomes
992 : : * unresponsive. */
993 : 25806141 : sched_yield();
994 : : }
995 : 26320169 : return EAGAIN;
996 : : }
997 : 8619 : ovs_mutex_lock(&netdev->mutex);
998 : 8619 : netdev->stats.rx_packets++;
999 : 8619 : netdev->stats.rx_bytes += dp_packet_size(packet);
1000 : 8619 : ovs_mutex_unlock(&netdev->mutex);
1001 : :
1002 : 8619 : batch->packets[0] = packet;
1003 : 8619 : batch->count = 1;
1004 : 8619 : return 0;
1005 : : }
1006 : :
1007 : : static void
1008 : 510552 : netdev_dummy_rxq_wait(struct netdev_rxq *rxq_)
1009 : : {
1010 : 510552 : struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
1011 : 510552 : struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
1012 : 510552 : uint64_t seq = seq_read(rx->seq);
1013 : :
1014 : 510552 : ovs_mutex_lock(&netdev->mutex);
1015 [ + + ]: 510552 : if (!ovs_list_is_empty(&rx->recv_queue)) {
1016 : 8565 : poll_immediate_wake();
1017 : : } else {
1018 : 501987 : seq_wait(rx->seq, seq);
1019 : : }
1020 : 510552 : ovs_mutex_unlock(&netdev->mutex);
1021 : 510552 : }
1022 : :
1023 : : static int
1024 : 0 : netdev_dummy_rxq_drain(struct netdev_rxq *rxq_)
1025 : : {
1026 : 0 : struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
1027 : 0 : struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
1028 : :
1029 : 0 : ovs_mutex_lock(&netdev->mutex);
1030 : 0 : pkt_list_delete(&rx->recv_queue);
1031 : 0 : rx->recv_queue_len = 0;
1032 : 0 : ovs_mutex_unlock(&netdev->mutex);
1033 : :
1034 : 0 : seq_change(rx->seq);
1035 : :
1036 : 0 : return 0;
1037 : : }
1038 : :
1039 : : static int
1040 : 13397 : netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
1041 : : struct dp_packet_batch *batch, bool may_steal,
1042 : : bool concurrent_txq OVS_UNUSED)
1043 : : {
1044 : 13397 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1045 : 13397 : int error = 0;
1046 : : int i;
1047 : :
1048 [ + + ]: 26794 : for (i = 0; i < batch->count; i++) {
1049 : 13397 : const void *buffer = dp_packet_data(batch->packets[i]);
1050 : 13397 : size_t size = dp_packet_size(batch->packets[i]);
1051 : :
1052 : 13397 : size -= dp_packet_get_cutlen(batch->packets[i]);
1053 : :
1054 [ - + ]: 13397 : if (size < ETH_HEADER_LEN) {
1055 : 0 : error = EMSGSIZE;
1056 : 0 : break;
1057 : : } else {
1058 : 13397 : const struct eth_header *eth = buffer;
1059 : : int max_size;
1060 : :
1061 : 13397 : ovs_mutex_lock(&dev->mutex);
1062 : 13397 : max_size = dev->mtu + ETH_HEADER_LEN;
1063 : 13397 : ovs_mutex_unlock(&dev->mutex);
1064 : :
1065 [ + + ]: 13397 : if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
1066 : 38 : max_size += VLAN_HEADER_LEN;
1067 : : }
1068 [ - + ]: 13397 : if (size > max_size) {
1069 : 0 : error = EMSGSIZE;
1070 : 0 : break;
1071 : : }
1072 : : }
1073 : :
1074 : 13397 : ovs_mutex_lock(&dev->mutex);
1075 : 13397 : dev->stats.tx_packets++;
1076 : 13397 : dev->stats.tx_bytes += size;
1077 : :
1078 : 13397 : dummy_packet_conn_send(&dev->conn, buffer, size);
1079 : :
1080 : : /* Reply to ARP requests for 'dev''s assigned IP address. */
1081 [ + + ]: 13397 : if (dev->address.s_addr) {
1082 : : struct dp_packet packet;
1083 : : struct flow flow;
1084 : :
1085 : 336 : dp_packet_use_const(&packet, buffer, size);
1086 : 336 : flow_extract(&packet, &flow);
1087 [ + + ]: 336 : if (flow.dl_type == htons(ETH_TYPE_ARP)
1088 [ - + ]: 1 : && flow.nw_proto == ARP_OP_REQUEST
1089 [ # # ]: 0 : && flow.nw_dst == dev->address.s_addr) {
1090 : 0 : struct dp_packet *reply = dp_packet_new(0);
1091 : 0 : compose_arp(reply, ARP_OP_REPLY, dev->hwaddr, flow.dl_src,
1092 : : false, flow.nw_dst, flow.nw_src);
1093 : 336 : netdev_dummy_queue_packet(dev, reply, 0);
1094 : : }
1095 : : }
1096 : :
1097 [ + + ]: 13397 : if (dev->tx_pcap) {
1098 : : struct dp_packet packet;
1099 : :
1100 : 10282 : dp_packet_use_const(&packet, buffer, size);
1101 : 10282 : ovs_pcap_write(dev->tx_pcap, &packet);
1102 : 10282 : fflush(dev->tx_pcap);
1103 : : }
1104 : :
1105 : 13397 : ovs_mutex_unlock(&dev->mutex);
1106 : : }
1107 : :
1108 : 13397 : dp_packet_delete_batch(batch, may_steal);
1109 : :
1110 : 13397 : return error;
1111 : : }
1112 : :
1113 : : static int
1114 : 2629 : netdev_dummy_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
1115 : : {
1116 : 2629 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1117 : :
1118 : 2629 : ovs_mutex_lock(&dev->mutex);
1119 [ + + ]: 2629 : if (!eth_addr_equals(dev->hwaddr, mac)) {
1120 : 641 : dev->hwaddr = mac;
1121 : 641 : netdev_change_seq_changed(netdev);
1122 : : }
1123 : 2629 : ovs_mutex_unlock(&dev->mutex);
1124 : :
1125 : 2629 : return 0;
1126 : : }
1127 : :
1128 : : static int
1129 : 17009 : netdev_dummy_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
1130 : : {
1131 : 17009 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1132 : :
1133 : 17009 : ovs_mutex_lock(&dev->mutex);
1134 : 17009 : *mac = dev->hwaddr;
1135 : 17009 : ovs_mutex_unlock(&dev->mutex);
1136 : :
1137 : 17009 : return 0;
1138 : : }
1139 : :
1140 : : static int
1141 : 20278 : netdev_dummy_get_mtu(const struct netdev *netdev, int *mtup)
1142 : : {
1143 : 20278 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1144 : :
1145 : 20278 : ovs_mutex_lock(&dev->mutex);
1146 : 20278 : *mtup = dev->mtu;
1147 : 20278 : ovs_mutex_unlock(&dev->mutex);
1148 : :
1149 : 20278 : return 0;
1150 : : }
1151 : :
1152 : : static int
1153 : 330 : netdev_dummy_set_mtu(struct netdev *netdev, int mtu)
1154 : : {
1155 : 330 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1156 : :
1157 : 330 : ovs_mutex_lock(&dev->mutex);
1158 [ + + ]: 330 : if (dev->mtu != mtu) {
1159 : 8 : dev->mtu = mtu;
1160 : 8 : netdev_change_seq_changed(netdev);
1161 : : }
1162 : 330 : ovs_mutex_unlock(&dev->mutex);
1163 : :
1164 : 330 : return 0;
1165 : : }
1166 : :
1167 : : static int
1168 : 4220 : netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
1169 : : {
1170 : 4220 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1171 : :
1172 : 4220 : ovs_mutex_lock(&dev->mutex);
1173 : : /* Passing only collected counters */
1174 : 4220 : stats->tx_packets = dev->stats.tx_packets;
1175 : 4220 : stats->tx_bytes = dev->stats.tx_bytes;
1176 : 4220 : stats->rx_packets = dev->stats.rx_packets;
1177 : 4220 : stats->rx_bytes = dev->stats.rx_bytes;
1178 : 4220 : ovs_mutex_unlock(&dev->mutex);
1179 : :
1180 : 4220 : return 0;
1181 : : }
1182 : :
1183 : : static int
1184 : 1 : netdev_dummy_get_queue(const struct netdev *netdev OVS_UNUSED,
1185 : : unsigned int queue_id, struct smap *details OVS_UNUSED)
1186 : : {
1187 [ - + ]: 1 : if (queue_id == 0) {
1188 : 0 : return 0;
1189 : : } else {
1190 : 1 : return EINVAL;
1191 : : }
1192 : : }
1193 : :
1194 : : static void
1195 : 20 : netdev_dummy_init_queue_stats(struct netdev_queue_stats *stats)
1196 : : {
1197 : 20 : *stats = (struct netdev_queue_stats) {
1198 : : .tx_bytes = UINT64_MAX,
1199 : : .tx_packets = UINT64_MAX,
1200 : : .tx_errors = UINT64_MAX,
1201 : : .created = LLONG_MIN,
1202 : : };
1203 : 20 : }
1204 : :
1205 : : static int
1206 : 20 : netdev_dummy_get_queue_stats(const struct netdev *netdev OVS_UNUSED,
1207 : : unsigned int queue_id,
1208 : : struct netdev_queue_stats *stats)
1209 : : {
1210 [ + + ]: 20 : if (queue_id == 0) {
1211 : 10 : netdev_dummy_init_queue_stats(stats);
1212 : 10 : return 0;
1213 : : } else {
1214 : 10 : return EINVAL;
1215 : : }
1216 : : }
1217 : :
1218 : : struct netdev_dummy_queue_state {
1219 : : unsigned int next_queue;
1220 : : };
1221 : :
1222 : : static int
1223 : 13 : netdev_dummy_queue_dump_start(const struct netdev *netdev OVS_UNUSED,
1224 : : void **statep)
1225 : : {
1226 : 13 : struct netdev_dummy_queue_state *state = xmalloc(sizeof *state);
1227 : 13 : state->next_queue = 0;
1228 : 13 : *statep = state;
1229 : 13 : return 0;
1230 : : }
1231 : :
1232 : : static int
1233 : 26 : netdev_dummy_queue_dump_next(const struct netdev *netdev OVS_UNUSED,
1234 : : void *state_,
1235 : : unsigned int *queue_id,
1236 : : struct smap *details OVS_UNUSED)
1237 : : {
1238 : 26 : struct netdev_dummy_queue_state *state = state_;
1239 [ + + ]: 26 : if (state->next_queue == 0) {
1240 : 13 : *queue_id = 0;
1241 : 13 : state->next_queue++;
1242 : 13 : return 0;
1243 : : } else {
1244 : 13 : return EOF;
1245 : : }
1246 : : }
1247 : :
1248 : : static int
1249 : 13 : netdev_dummy_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
1250 : : void *state)
1251 : : {
1252 : 13 : free(state);
1253 : 13 : return 0;
1254 : : }
1255 : :
1256 : : static int
1257 : 10 : netdev_dummy_dump_queue_stats(const struct netdev *netdev OVS_UNUSED,
1258 : : void (*cb)(unsigned int queue_id,
1259 : : struct netdev_queue_stats *,
1260 : : void *aux),
1261 : : void *aux)
1262 : : {
1263 : : struct netdev_queue_stats stats;
1264 : 10 : netdev_dummy_init_queue_stats(&stats);
1265 : 10 : cb(0, &stats, aux);
1266 : 10 : return 0;
1267 : : }
1268 : :
1269 : : static int
1270 : 6966 : netdev_dummy_get_ifindex(const struct netdev *netdev)
1271 : : {
1272 : 6966 : struct netdev_dummy *dev = netdev_dummy_cast(netdev);
1273 : : int ifindex;
1274 : :
1275 : 6966 : ovs_mutex_lock(&dev->mutex);
1276 : 6966 : ifindex = dev->ifindex;
1277 : 6966 : ovs_mutex_unlock(&dev->mutex);
1278 : :
1279 : 6966 : return ifindex;
1280 : : }
1281 : :
1282 : : static int
1283 : 49844 : netdev_dummy_update_flags__(struct netdev_dummy *netdev,
1284 : : enum netdev_flags off, enum netdev_flags on,
1285 : : enum netdev_flags *old_flagsp)
1286 : : OVS_REQUIRES(netdev->mutex)
1287 : : {
1288 [ - + ]: 49844 : if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
1289 : 0 : return EINVAL;
1290 : : }
1291 : :
1292 : 49844 : *old_flagsp = netdev->flags;
1293 : 49844 : netdev->flags |= on;
1294 : 49844 : netdev->flags &= ~off;
1295 [ + + ]: 49844 : if (*old_flagsp != netdev->flags) {
1296 : 3129 : netdev_change_seq_changed(&netdev->up);
1297 : : }
1298 : :
1299 : 49844 : return 0;
1300 : : }
1301 : :
1302 : : static int
1303 : 49778 : netdev_dummy_update_flags(struct netdev *netdev_,
1304 : : enum netdev_flags off, enum netdev_flags on,
1305 : : enum netdev_flags *old_flagsp)
1306 : : {
1307 : 49778 : struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
1308 : : int error;
1309 : :
1310 : 49778 : ovs_mutex_lock(&netdev->mutex);
1311 : 49778 : error = netdev_dummy_update_flags__(netdev, off, on, old_flagsp);
1312 : 49778 : ovs_mutex_unlock(&netdev->mutex);
1313 : :
1314 : 49778 : return error;
1315 : : }
1316 : :
1317 : : /* Helper functions. */
1318 : :
1319 : : #define NETDEV_DUMMY_CLASS(NAME, PMD, RECOFIGURE) \
1320 : : { \
1321 : : NAME, \
1322 : : PMD, /* is_pmd */ \
1323 : : NULL, /* init */ \
1324 : : netdev_dummy_run, \
1325 : : netdev_dummy_wait, \
1326 : : \
1327 : : netdev_dummy_alloc, \
1328 : : netdev_dummy_construct, \
1329 : : netdev_dummy_destruct, \
1330 : : netdev_dummy_dealloc, \
1331 : : netdev_dummy_get_config, \
1332 : : netdev_dummy_set_config, \
1333 : : NULL, /* get_tunnel_config */ \
1334 : : NULL, /* build header */ \
1335 : : NULL, /* push header */ \
1336 : : NULL, /* pop header */ \
1337 : : netdev_dummy_get_numa_id, \
1338 : : NULL, /* set_tx_multiq */ \
1339 : : \
1340 : : netdev_dummy_send, /* send */ \
1341 : : NULL, /* send_wait */ \
1342 : : \
1343 : : netdev_dummy_set_etheraddr, \
1344 : : netdev_dummy_get_etheraddr, \
1345 : : netdev_dummy_get_mtu, \
1346 : : netdev_dummy_set_mtu, \
1347 : : netdev_dummy_get_ifindex, \
1348 : : NULL, /* get_carrier */ \
1349 : : NULL, /* get_carrier_resets */ \
1350 : : NULL, /* get_miimon */ \
1351 : : netdev_dummy_get_stats, \
1352 : : \
1353 : : NULL, /* get_features */ \
1354 : : NULL, /* set_advertisements */ \
1355 : : \
1356 : : NULL, /* set_policing */ \
1357 : : NULL, /* get_qos_types */ \
1358 : : NULL, /* get_qos_capabilities */ \
1359 : : NULL, /* get_qos */ \
1360 : : NULL, /* set_qos */ \
1361 : : netdev_dummy_get_queue, \
1362 : : NULL, /* set_queue */ \
1363 : : NULL, /* delete_queue */ \
1364 : : netdev_dummy_get_queue_stats, \
1365 : : netdev_dummy_queue_dump_start, \
1366 : : netdev_dummy_queue_dump_next, \
1367 : : netdev_dummy_queue_dump_done, \
1368 : : netdev_dummy_dump_queue_stats, \
1369 : : \
1370 : : NULL, /* set_in4 */ \
1371 : : netdev_dummy_get_addr_list, \
1372 : : NULL, /* add_router */ \
1373 : : NULL, /* get_next_hop */ \
1374 : : NULL, /* get_status */ \
1375 : : NULL, /* arp_lookup */ \
1376 : : \
1377 : : netdev_dummy_update_flags, \
1378 : : RECOFIGURE, \
1379 : : \
1380 : : netdev_dummy_rxq_alloc, \
1381 : : netdev_dummy_rxq_construct, \
1382 : : netdev_dummy_rxq_destruct, \
1383 : : netdev_dummy_rxq_dealloc, \
1384 : : netdev_dummy_rxq_recv, \
1385 : : netdev_dummy_rxq_wait, \
1386 : : netdev_dummy_rxq_drain, \
1387 : : }
1388 : :
1389 : : static const struct netdev_class dummy_class =
1390 : : NETDEV_DUMMY_CLASS("dummy", false, NULL);
1391 : :
1392 : : static const struct netdev_class dummy_internal_class =
1393 : : NETDEV_DUMMY_CLASS("dummy-internal", false, NULL);
1394 : :
1395 : : static const struct netdev_class dummy_pmd_class =
1396 : : NETDEV_DUMMY_CLASS("dummy-pmd", true,
1397 : : netdev_dummy_reconfigure);
1398 : :
1399 : : static void
1400 : 352 : pkt_list_delete(struct ovs_list *l)
1401 : : {
1402 : : struct pkt_list_node *pkt;
1403 : :
1404 [ - + ]: 352 : LIST_FOR_EACH_POP(pkt, list_node, l) {
1405 : 0 : dp_packet_delete(pkt->pkt);
1406 : 0 : free(pkt);
1407 : : }
1408 : 352 : }
1409 : :
1410 : : static struct dp_packet *
1411 : 3903 : eth_from_packet_or_flow(const char *s)
1412 : : {
1413 : : enum odp_key_fitness fitness;
1414 : : struct dp_packet *packet;
1415 : : struct ofpbuf odp_key;
1416 : : struct flow flow;
1417 : : int error;
1418 : :
1419 [ + + ]: 3903 : if (!eth_from_hex(s, &packet)) {
1420 : 2723 : return packet;
1421 : : }
1422 : :
1423 : : /* Convert string to datapath key.
1424 : : *
1425 : : * It would actually be nicer to parse an OpenFlow-like flow key here, but
1426 : : * the code for that currently calls exit() on parse error. We have to
1427 : : * settle for parsing a datapath key for now.
1428 : : */
1429 : 1180 : ofpbuf_init(&odp_key, 0);
1430 : 1180 : error = odp_flow_from_string(s, NULL, &odp_key, NULL);
1431 [ + + ]: 1180 : if (error) {
1432 : 6 : ofpbuf_uninit(&odp_key);
1433 : 6 : return NULL;
1434 : : }
1435 : :
1436 : : /* Convert odp_key to flow. */
1437 : 1174 : fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
1438 [ - + ]: 1174 : if (fitness == ODP_FIT_ERROR) {
1439 : 0 : ofpbuf_uninit(&odp_key);
1440 : 0 : return NULL;
1441 : : }
1442 : :
1443 : 1174 : packet = dp_packet_new(0);
1444 : 1174 : flow_compose(packet, &flow);
1445 : :
1446 : 1174 : ofpbuf_uninit(&odp_key);
1447 : 3903 : return packet;
1448 : : }
1449 : :
1450 : : static void
1451 : 8619 : netdev_dummy_queue_packet__(struct netdev_rxq_dummy *rx, struct dp_packet *packet)
1452 : : {
1453 : 8619 : struct pkt_list_node *pkt_node = xmalloc(sizeof *pkt_node);
1454 : :
1455 : 8619 : pkt_node->pkt = packet;
1456 : 8619 : ovs_list_push_back(&rx->recv_queue, &pkt_node->list_node);
1457 : 8619 : rx->recv_queue_len++;
1458 : 8619 : seq_change(rx->seq);
1459 : 8619 : }
1460 : :
1461 : : static void
1462 : 8619 : netdev_dummy_queue_packet(struct netdev_dummy *dummy, struct dp_packet *packet,
1463 : : int queue_id)
1464 : : OVS_REQUIRES(dummy->mutex)
1465 : : {
1466 : : struct netdev_rxq_dummy *rx, *prev;
1467 : :
1468 [ + + ]: 8619 : if (dummy->rxq_pcap) {
1469 : 6738 : ovs_pcap_write(dummy->rxq_pcap, packet);
1470 : 6738 : fflush(dummy->rxq_pcap);
1471 : : }
1472 : 8619 : prev = NULL;
1473 [ + + ]: 17308 : LIST_FOR_EACH (rx, node, &dummy->rxes) {
1474 [ + + ][ + - ]: 8689 : if (rx->up.queue_id == queue_id &&
1475 : 8619 : rx->recv_queue_len < NETDEV_DUMMY_MAX_QUEUE) {
1476 [ - + ]: 8619 : if (prev) {
1477 : 0 : netdev_dummy_queue_packet__(prev, dp_packet_clone(packet));
1478 : : }
1479 : 8619 : prev = rx;
1480 : : }
1481 : : }
1482 [ + - ]: 8619 : if (prev) {
1483 : 8619 : netdev_dummy_queue_packet__(prev, packet);
1484 : : } else {
1485 : 0 : dp_packet_delete(packet);
1486 : : }
1487 : 8619 : }
1488 : :
1489 : : static void
1490 : 3903 : netdev_dummy_receive(struct unixctl_conn *conn,
1491 : : int argc, const char *argv[], void *aux OVS_UNUSED)
1492 : : {
1493 : : struct netdev_dummy *dummy_dev;
1494 : : struct netdev *netdev;
1495 : 3903 : int i, k = 1, rx_qid = 0;
1496 : :
1497 : 3903 : netdev = netdev_from_name(argv[k++]);
1498 [ + - ][ - + ]: 3903 : if (!netdev || !is_dummy_class(netdev->netdev_class)) {
1499 : 0 : unixctl_command_reply_error(conn, "no such dummy netdev");
1500 : 0 : goto exit_netdev;
1501 : : }
1502 : 3903 : dummy_dev = netdev_dummy_cast(netdev);
1503 : :
1504 : 3903 : ovs_mutex_lock(&dummy_dev->mutex);
1505 : :
1506 [ + + ][ + - ]: 3903 : if (argc > k + 1 && !strcmp(argv[k], "--qid")) {
1507 : 14 : rx_qid = strtol(argv[k + 1], NULL, 10);
1508 [ + - ][ - + ]: 14 : if (rx_qid < 0 || rx_qid >= netdev->n_rxq) {
1509 : 0 : unixctl_command_reply_error(conn, "bad rx queue id.");
1510 : 0 : goto exit;
1511 : : }
1512 : 14 : k += 2;
1513 : : }
1514 : :
1515 [ + + ]: 7800 : for (i = k; i < argc; i++) {
1516 : : struct dp_packet *packet;
1517 : :
1518 : 3903 : packet = eth_from_packet_or_flow(argv[i]);
1519 [ + + ]: 3903 : if (!packet) {
1520 : 6 : unixctl_command_reply_error(conn, "bad packet syntax");
1521 : 6 : goto exit;
1522 : : }
1523 : :
1524 : 3897 : netdev_dummy_queue_packet(dummy_dev, packet, rx_qid);
1525 : : }
1526 : :
1527 : 3897 : unixctl_command_reply(conn, NULL);
1528 : :
1529 : : exit:
1530 : 3903 : ovs_mutex_unlock(&dummy_dev->mutex);
1531 : : exit_netdev:
1532 : 3903 : netdev_close(netdev);
1533 : 3903 : }
1534 : :
1535 : : static void
1536 : 66 : netdev_dummy_set_admin_state__(struct netdev_dummy *dev, bool admin_state)
1537 : : OVS_REQUIRES(dev->mutex)
1538 : : {
1539 : : enum netdev_flags old_flags;
1540 : :
1541 [ + + ]: 66 : if (admin_state) {
1542 : 64 : netdev_dummy_update_flags__(dev, 0, NETDEV_UP, &old_flags);
1543 : : } else {
1544 : 2 : netdev_dummy_update_flags__(dev, NETDEV_UP, 0, &old_flags);
1545 : : }
1546 : 66 : }
1547 : :
1548 : : static void
1549 : 14 : netdev_dummy_set_admin_state(struct unixctl_conn *conn, int argc,
1550 : : const char *argv[], void *aux OVS_UNUSED)
1551 : : {
1552 : : bool up;
1553 : :
1554 [ + + ]: 14 : if (!strcasecmp(argv[argc - 1], "up")) {
1555 : 12 : up = true;
1556 [ + - ]: 2 : } else if ( !strcasecmp(argv[argc - 1], "down")) {
1557 : 2 : up = false;
1558 : : } else {
1559 : 0 : unixctl_command_reply_error(conn, "Invalid Admin State");
1560 : 0 : return;
1561 : : }
1562 : :
1563 [ + + ]: 14 : if (argc > 2) {
1564 : 5 : struct netdev *netdev = netdev_from_name(argv[1]);
1565 [ + - ][ + - ]: 10 : if (netdev && is_dummy_class(netdev->netdev_class)) {
1566 : 5 : struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
1567 : :
1568 : 5 : ovs_mutex_lock(&dummy_dev->mutex);
1569 : 5 : netdev_dummy_set_admin_state__(dummy_dev, up);
1570 : 5 : ovs_mutex_unlock(&dummy_dev->mutex);
1571 : :
1572 : 5 : netdev_close(netdev);
1573 : : } else {
1574 : 0 : unixctl_command_reply_error(conn, "Unknown Dummy Interface");
1575 : 0 : netdev_close(netdev);
1576 : 0 : return;
1577 : : }
1578 : : } else {
1579 : : struct netdev_dummy *netdev;
1580 : :
1581 : 9 : ovs_mutex_lock(&dummy_list_mutex);
1582 [ + + ]: 70 : LIST_FOR_EACH (netdev, list_node, &dummy_list) {
1583 : 61 : ovs_mutex_lock(&netdev->mutex);
1584 : 61 : netdev_dummy_set_admin_state__(netdev, up);
1585 : 61 : ovs_mutex_unlock(&netdev->mutex);
1586 : : }
1587 : 9 : ovs_mutex_unlock(&dummy_list_mutex);
1588 : : }
1589 : 14 : unixctl_command_reply(conn, "OK");
1590 : : }
1591 : :
1592 : : static void
1593 : 5 : display_conn_state__(struct ds *s, const char *name,
1594 : : enum dummy_netdev_conn_state state)
1595 : : {
1596 : 5 : ds_put_format(s, "%s: ", name);
1597 : :
1598 [ + - - ]: 5 : switch (state) {
1599 : : case CONN_STATE_CONNECTED:
1600 : 5 : ds_put_cstr(s, "connected\n");
1601 : 5 : break;
1602 : :
1603 : : case CONN_STATE_NOT_CONNECTED:
1604 : 0 : ds_put_cstr(s, "disconnected\n");
1605 : 0 : break;
1606 : :
1607 : : case CONN_STATE_UNKNOWN:
1608 : : default:
1609 : 0 : ds_put_cstr(s, "unknown\n");
1610 : 0 : break;
1611 : : };
1612 : 5 : }
1613 : :
1614 : : static void
1615 : 5 : netdev_dummy_conn_state(struct unixctl_conn *conn, int argc,
1616 : : const char *argv[], void *aux OVS_UNUSED)
1617 : : {
1618 : 5 : enum dummy_netdev_conn_state state = CONN_STATE_UNKNOWN;
1619 : : struct ds s;
1620 : :
1621 : 5 : ds_init(&s);
1622 : :
1623 [ + - ]: 5 : if (argc > 1) {
1624 : 5 : const char *dev_name = argv[1];
1625 : 5 : struct netdev *netdev = netdev_from_name(dev_name);
1626 : :
1627 [ + - ][ + - ]: 5 : if (netdev && is_dummy_class(netdev->netdev_class)) {
1628 : 5 : struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
1629 : :
1630 : 5 : ovs_mutex_lock(&dummy_dev->mutex);
1631 : 5 : state = dummy_netdev_get_conn_state(&dummy_dev->conn);
1632 : 5 : ovs_mutex_unlock(&dummy_dev->mutex);
1633 : :
1634 : 5 : netdev_close(netdev);
1635 : : }
1636 : 5 : display_conn_state__(&s, dev_name, state);
1637 : : } else {
1638 : : struct netdev_dummy *netdev;
1639 : :
1640 : 0 : ovs_mutex_lock(&dummy_list_mutex);
1641 [ # # ]: 0 : LIST_FOR_EACH (netdev, list_node, &dummy_list) {
1642 : 0 : ovs_mutex_lock(&netdev->mutex);
1643 : 0 : state = dummy_netdev_get_conn_state(&netdev->conn);
1644 : 0 : ovs_mutex_unlock(&netdev->mutex);
1645 [ # # ]: 0 : if (state != CONN_STATE_UNKNOWN) {
1646 : 0 : display_conn_state__(&s, netdev->up.name, state);
1647 : : }
1648 : : }
1649 : 0 : ovs_mutex_unlock(&dummy_list_mutex);
1650 : : }
1651 : :
1652 : 5 : unixctl_command_reply(conn, ds_cstr(&s));
1653 : 5 : ds_destroy(&s);
1654 : 5 : }
1655 : :
1656 : : static void
1657 : 45 : netdev_dummy_ip4addr(struct unixctl_conn *conn, int argc OVS_UNUSED,
1658 : : const char *argv[], void *aux OVS_UNUSED)
1659 : : {
1660 : 45 : struct netdev *netdev = netdev_from_name(argv[1]);
1661 : :
1662 [ + - ][ + - ]: 90 : if (netdev && is_dummy_class(netdev->netdev_class)) {
1663 : : struct in_addr ip, mask;
1664 : : char *error;
1665 : :
1666 : 45 : error = ip_parse_masked(argv[2], &ip.s_addr, &mask.s_addr);
1667 [ + - ]: 45 : if (!error) {
1668 : 45 : netdev_dummy_set_in4(netdev, ip, mask);
1669 : 45 : unixctl_command_reply(conn, "OK");
1670 : : } else {
1671 : 0 : unixctl_command_reply_error(conn, error);
1672 : 0 : free(error);
1673 : : }
1674 : : } else {
1675 : 0 : unixctl_command_reply_error(conn, "Unknown Dummy Interface");
1676 : : }
1677 : :
1678 : 45 : netdev_close(netdev);
1679 : 45 : }
1680 : :
1681 : : static void
1682 : 2 : netdev_dummy_ip6addr(struct unixctl_conn *conn, int argc OVS_UNUSED,
1683 : : const char *argv[], void *aux OVS_UNUSED)
1684 : : {
1685 : 2 : struct netdev *netdev = netdev_from_name(argv[1]);
1686 : :
1687 [ + - ][ + - ]: 4 : if (netdev && is_dummy_class(netdev->netdev_class)) {
1688 : : struct in6_addr ip6;
1689 : : char *error;
1690 : : uint32_t plen;
1691 : :
1692 : 2 : error = ipv6_parse_cidr(argv[2], &ip6, &plen);
1693 [ + - ]: 2 : if (!error) {
1694 : : struct in6_addr mask;
1695 : :
1696 : 2 : mask = ipv6_create_mask(plen);
1697 : 2 : netdev_dummy_set_in6(netdev, &ip6, &mask);
1698 : 2 : unixctl_command_reply(conn, "OK");
1699 : : } else {
1700 : 0 : unixctl_command_reply_error(conn, error);
1701 : 0 : free(error);
1702 : : }
1703 : 2 : netdev_close(netdev);
1704 : : } else {
1705 : 0 : unixctl_command_reply_error(conn, "Unknown Dummy Interface");
1706 : : }
1707 : :
1708 : 2 : netdev_close(netdev);
1709 : 2 : }
1710 : :
1711 : :
1712 : : static void
1713 : 90 : netdev_dummy_override(const char *type)
1714 : : {
1715 [ + - ]: 90 : if (!netdev_unregister_provider(type)) {
1716 : : struct netdev_class *class;
1717 : : int error;
1718 : :
1719 : 90 : class = xmemdup(&dummy_class, sizeof dummy_class);
1720 : 90 : class->type = xstrdup(type);
1721 : 90 : error = netdev_register_provider(class);
1722 [ - + ]: 90 : if (error) {
1723 [ # # ]: 0 : VLOG_ERR("%s: failed to register netdev provider (%s)",
1724 : : type, ovs_strerror(error));
1725 : 0 : free(CONST_CAST(char *, class->type));
1726 : 0 : free(class);
1727 : : }
1728 : : }
1729 : 90 : }
1730 : :
1731 : : void
1732 : 543 : netdev_dummy_register(enum dummy_level level)
1733 : : {
1734 : 543 : unixctl_command_register("netdev-dummy/receive",
1735 : : "name [--qid queue_id] packet|flow...",
1736 : : 2, INT_MAX, netdev_dummy_receive, NULL);
1737 : 543 : unixctl_command_register("netdev-dummy/set-admin-state",
1738 : : "[netdev] up|down", 1, 2,
1739 : : netdev_dummy_set_admin_state, NULL);
1740 : 543 : unixctl_command_register("netdev-dummy/conn-state",
1741 : : "[netdev]", 0, 1,
1742 : : netdev_dummy_conn_state, NULL);
1743 : 543 : unixctl_command_register("netdev-dummy/ip4addr",
1744 : : "[netdev] ipaddr/mask-prefix-len", 2, 2,
1745 : : netdev_dummy_ip4addr, NULL);
1746 : 543 : unixctl_command_register("netdev-dummy/ip6addr",
1747 : : "[netdev] ip6addr", 2, 2,
1748 : : netdev_dummy_ip6addr, NULL);
1749 : :
1750 [ + + ]: 543 : if (level == DUMMY_OVERRIDE_ALL) {
1751 : : struct sset types;
1752 : : const char *type;
1753 : :
1754 : 1 : sset_init(&types);
1755 : 1 : netdev_enumerate_types(&types);
1756 [ + - ][ + + ]: 11 : SSET_FOR_EACH (type, &types) {
[ + + ]
1757 [ + + ]: 10 : if (strcmp(type, "patch")) {
1758 : 9 : netdev_dummy_override(type);
1759 : : }
1760 : : }
1761 : 1 : sset_destroy(&types);
1762 [ + + ]: 542 : } else if (level == DUMMY_OVERRIDE_SYSTEM) {
1763 : 81 : netdev_dummy_override("system");
1764 : : }
1765 : 543 : netdev_register_provider(&dummy_class);
1766 : 543 : netdev_register_provider(&dummy_internal_class);
1767 : 543 : netdev_register_provider(&dummy_pmd_class);
1768 : :
1769 : 543 : netdev_vport_tunnel_register();
1770 : 543 : }
|