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