]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-dummy.c
netdev-dummy: Fix synchronization error in netdev_dummy_get_config().
[mirror_ovs.git] / lib / netdev-dummy.c
CommitLineData
614c4892 1/*
275707c3 2 * Copyright (c) 2010, 2011, 2012, 2013 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>
22
fbac791a 23#include "flow.h"
614c4892
BP
24#include "list.h"
25#include "netdev-provider.h"
c060c4cf 26#include "netdev-vport.h"
fbac791a
BP
27#include "odp-util.h"
28#include "ofp-print.h"
29#include "ofpbuf.h"
614c4892 30#include "packets.h"
fbac791a 31#include "poll-loop.h"
614c4892 32#include "shash.h"
0cbfe35d 33#include "sset.h"
eab5611a
BP
34#include "stream.h"
35#include "unaligned.h"
fbac791a 36#include "unixctl.h"
614c4892
BP
37#include "vlog.h"
38
39VLOG_DEFINE_THIS_MODULE(netdev_dummy);
40
eab5611a
BP
41struct dummy_stream {
42 struct stream *stream;
43 struct ofpbuf rxbuf;
44 struct list txq;
45};
46
5e1de67f
BP
47/* Protects 'dummy_list'. */
48static struct ovs_mutex dummy_list_mutex = OVS_MUTEX_INITIALIZER;
49
50/* Contains all 'struct dummy_dev's. */
51static struct list dummy_list OVS_GUARDED_BY(dummy_list_mutex)
52 = LIST_INITIALIZER(&dummy_list);
53
b5d57fc8
BP
54struct netdev_dummy {
55 struct netdev up;
86383816 56
5e1de67f
BP
57 /* In dummy_list. */
58 struct list list_node OVS_GUARDED_BY(dummy_list_mutex);
59
86383816 60 /* Protects all members below. */
5e1de67f 61 struct ovs_mutex mutex OVS_ACQ_AFTER(dummy_list_mutex);
86383816 62
614c4892
BP
63 uint8_t hwaddr[ETH_ADDR_LEN];
64 int mtu;
65 struct netdev_stats stats;
66 enum netdev_flags flags;
ac4d3bcb 67 unsigned int change_seq;
8073dd31 68 int ifindex;
796223f5 69
eab5611a
BP
70 struct pstream *pstream;
71 struct dummy_stream *streams;
72 size_t n_streams;
73
796223f5 74 struct list rxes; /* List of child "netdev_rx_dummy"s. */
614c4892
BP
75};
76
e34cfdd9
BP
77/* Max 'recv_queue_len' in struct netdev_dummy. */
78#define NETDEV_DUMMY_MAX_QUEUE 100
79
796223f5
BP
80struct netdev_rx_dummy {
81 struct netdev_rx up;
b5d57fc8 82 struct list node; /* In netdev_dummy's "rxes" list. */
fbac791a 83 struct list recv_queue;
e34cfdd9
BP
84 int recv_queue_len; /* list_size(&recv_queue). */
85 bool listening;
614c4892
BP
86};
87
95d4ec33 88static unixctl_cb_func netdev_dummy_set_admin_state;
9dc63482 89static int netdev_dummy_construct(struct netdev *);
86383816
BP
90static void netdev_dummy_poll_notify(struct netdev_dummy *netdev)
91 OVS_REQUIRES(netdev->mutex);
eab5611a
BP
92static void netdev_dummy_queue_packet(struct netdev_dummy *, struct ofpbuf *);
93
94static void dummy_stream_close(struct dummy_stream *);
614c4892
BP
95
96static bool
97is_dummy_class(const struct netdev_class *class)
98{
9dc63482 99 return class->construct == netdev_dummy_construct;
614c4892
BP
100}
101
614c4892
BP
102static struct netdev_dummy *
103netdev_dummy_cast(const struct netdev *netdev)
104{
b5d57fc8 105 ovs_assert(is_dummy_class(netdev_get_class(netdev)));
180c6d0b 106 return CONTAINER_OF(netdev, struct netdev_dummy, up);
614c4892
BP
107}
108
796223f5
BP
109static struct netdev_rx_dummy *
110netdev_rx_dummy_cast(const struct netdev_rx *rx)
111{
9dc63482 112 ovs_assert(is_dummy_class(netdev_get_class(rx->netdev)));
796223f5
BP
113 return CONTAINER_OF(rx, struct netdev_rx_dummy, up);
114}
115
eab5611a
BP
116static void
117netdev_dummy_run(void)
118{
5e1de67f 119 struct netdev_dummy *dev;
eab5611a 120
5e1de67f
BP
121 ovs_mutex_lock(&dummy_list_mutex);
122 LIST_FOR_EACH (dev, list_node, &dummy_list) {
eab5611a
BP
123 size_t i;
124
86383816
BP
125 ovs_mutex_lock(&dev->mutex);
126
eab5611a
BP
127 if (dev->pstream) {
128 struct stream *new_stream;
129 int error;
130
131 error = pstream_accept(dev->pstream, &new_stream);
132 if (!error) {
133 struct dummy_stream *s;
134
135 dev->streams = xrealloc(dev->streams,
136 ((dev->n_streams + 1)
137 * sizeof *dev->streams));
138 s = &dev->streams[dev->n_streams++];
139 s->stream = new_stream;
140 ofpbuf_init(&s->rxbuf, 2048);
141 list_init(&s->txq);
142 } else if (error != EAGAIN) {
143 VLOG_WARN("%s: accept failed (%s)",
10a89ef0 144 pstream_get_name(dev->pstream), ovs_strerror(error));
eab5611a
BP
145 pstream_close(dev->pstream);
146 dev->pstream = NULL;
147 }
148 }
149
150 for (i = 0; i < dev->n_streams; i++) {
151 struct dummy_stream *s = &dev->streams[i];
152 int error = 0;
153 size_t n;
154
155 stream_run(s->stream);
156
157 if (!list_is_empty(&s->txq)) {
158 struct ofpbuf *txbuf;
159 int retval;
160
161 txbuf = ofpbuf_from_list(list_front(&s->txq));
162 retval = stream_send(s->stream, txbuf->data, txbuf->size);
163 if (retval > 0) {
164 ofpbuf_pull(txbuf, retval);
165 if (!txbuf->size) {
166 list_remove(&txbuf->list_node);
167 ofpbuf_delete(txbuf);
168 }
169 } else if (retval != -EAGAIN) {
170 error = -retval;
171 }
172 }
173
174 if (!error) {
175 if (s->rxbuf.size < 2) {
176 n = 2 - s->rxbuf.size;
177 } else {
178 uint16_t frame_len;
179
180 frame_len = ntohs(get_unaligned_be16(s->rxbuf.data));
181 if (frame_len < ETH_HEADER_LEN) {
182 error = EPROTO;
183 n = 0;
184 } else {
185 n = (2 + frame_len) - s->rxbuf.size;
186 }
187 }
188 }
189 if (!error) {
190 int retval;
191
192 ofpbuf_prealloc_tailroom(&s->rxbuf, n);
193 retval = stream_recv(s->stream, ofpbuf_tail(&s->rxbuf), n);
194 if (retval > 0) {
195 s->rxbuf.size += retval;
196 if (retval == n && s->rxbuf.size > 2) {
197 ofpbuf_pull(&s->rxbuf, 2);
198 netdev_dummy_queue_packet(dev,
199 ofpbuf_clone(&s->rxbuf));
200 ofpbuf_clear(&s->rxbuf);
201 }
202 } else if (retval != -EAGAIN) {
203 error = (retval < 0 ? -retval
204 : s->rxbuf.size ? EPROTO
205 : EOF);
206 }
207 }
208
209 if (error) {
210 VLOG_DBG("%s: closing connection (%s)",
211 stream_get_name(s->stream),
212 ovs_retval_to_string(error));
213 dummy_stream_close(&dev->streams[i]);
214 dev->streams[i] = dev->streams[--dev->n_streams];
215 }
216 }
86f1d032 217
86383816 218 ovs_mutex_unlock(&dev->mutex);
eab5611a 219 }
5e1de67f 220 ovs_mutex_unlock(&dummy_list_mutex);
eab5611a
BP
221}
222
223static void
224dummy_stream_close(struct dummy_stream *s)
225{
226 stream_close(s->stream);
227 ofpbuf_uninit(&s->rxbuf);
228 ofpbuf_list_delete(&s->txq);
229}
230
231static void
232netdev_dummy_wait(void)
233{
5e1de67f 234 struct netdev_dummy *dev;
eab5611a 235
5e1de67f
BP
236 ovs_mutex_lock(&dummy_list_mutex);
237 LIST_FOR_EACH (dev, list_node, &dummy_list) {
eab5611a
BP
238 size_t i;
239
86383816 240 ovs_mutex_lock(&dev->mutex);
eab5611a
BP
241 if (dev->pstream) {
242 pstream_wait(dev->pstream);
243 }
244 for (i = 0; i < dev->n_streams; i++) {
245 struct dummy_stream *s = &dev->streams[i];
246
247 stream_run_wait(s->stream);
248 if (!list_is_empty(&s->txq)) {
249 stream_send_wait(s->stream);
250 }
251 stream_recv_wait(s->stream);
252 }
86383816 253 ovs_mutex_unlock(&dev->mutex);
eab5611a 254 }
5e1de67f 255 ovs_mutex_unlock(&dummy_list_mutex);
eab5611a
BP
256}
257
9dc63482
BP
258static struct netdev *
259netdev_dummy_alloc(void)
260{
261 struct netdev_dummy *netdev = xzalloc(sizeof *netdev);
262 return &netdev->up;
263}
264
614c4892 265static int
9dc63482 266netdev_dummy_construct(struct netdev *netdev_)
614c4892 267{
97be1538 268 static atomic_uint next_n = ATOMIC_VAR_INIT(0xaa550000);
9dc63482 269 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
01cdb3a1
BP
270 unsigned int n;
271
97be1538 272 atomic_add(&next_n, 1, &n);
86383816
BP
273
274 ovs_mutex_init(&netdev->mutex, PTHREAD_MUTEX_NORMAL);
b5d57fc8
BP
275 netdev->hwaddr[0] = 0xaa;
276 netdev->hwaddr[1] = 0x55;
277 netdev->hwaddr[2] = n >> 24;
278 netdev->hwaddr[3] = n >> 16;
279 netdev->hwaddr[4] = n >> 8;
280 netdev->hwaddr[5] = n;
281 netdev->mtu = 1500;
282 netdev->flags = 0;
283 netdev->change_seq = 1;
284 netdev->ifindex = -EOPNOTSUPP;
eab5611a
BP
285
286 netdev->pstream = NULL;
287 netdev->streams = NULL;
288 netdev->n_streams = 0;
289
b5d57fc8
BP
290 list_init(&netdev->rxes);
291
5e1de67f
BP
292 ovs_mutex_lock(&dummy_list_mutex);
293 list_push_back(&dummy_list, &netdev->list_node);
294 ovs_mutex_unlock(&dummy_list_mutex);
295
614c4892
BP
296 return 0;
297}
298
299static void
9dc63482 300netdev_dummy_destruct(struct netdev *netdev_)
614c4892 301{
b5d57fc8 302 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
eab5611a 303 size_t i;
614c4892 304
5e1de67f
BP
305 ovs_mutex_lock(&dummy_list_mutex);
306 list_remove(&netdev->list_node);
307 ovs_mutex_unlock(&dummy_list_mutex);
308
eab5611a
BP
309 pstream_close(netdev->pstream);
310 for (i = 0; i < netdev->n_streams; i++) {
311 dummy_stream_close(&netdev->streams[i]);
312 }
313 free(netdev->streams);
86383816 314 ovs_mutex_destroy(&netdev->mutex);
9dc63482
BP
315}
316
317static void
318netdev_dummy_dealloc(struct netdev *netdev_)
319{
320 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
321
b5d57fc8 322 free(netdev);
614c4892
BP
323}
324
8073dd31 325static int
b5d57fc8 326netdev_dummy_get_config(const struct netdev *netdev_, struct smap *args)
8073dd31 327{
b5d57fc8 328 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
8073dd31 329
5a9bf514 330 ovs_mutex_lock(&netdev->mutex);
b5d57fc8
BP
331 if (netdev->ifindex >= 0) {
332 smap_add_format(args, "ifindex", "%d", netdev->ifindex);
8073dd31 333 }
eab5611a
BP
334 if (netdev->pstream) {
335 smap_add(args, "pstream", pstream_get_name(netdev->pstream));
336 }
5a9bf514
BP
337 ovs_mutex_unlock(&netdev->mutex);
338
8073dd31
NM
339 return 0;
340}
341
342static int
b5d57fc8 343netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
614c4892 344{
b5d57fc8 345 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
eab5611a 346 const char *pstream;
614c4892 347
86383816 348 ovs_mutex_lock(&netdev->mutex);
b5d57fc8 349 netdev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP);
eab5611a
BP
350
351 pstream = smap_get(args, "pstream");
352 if (!pstream
353 || !netdev->pstream
354 || strcmp(pstream_get_name(netdev->pstream), pstream)) {
355 pstream_close(netdev->pstream);
356 netdev->pstream = NULL;
357
358 if (pstream) {
359 int error;
360
361 error = pstream_open(pstream, &netdev->pstream, DSCP_DEFAULT);
362 if (error) {
10a89ef0
BP
363 VLOG_WARN("%s: open failed (%s)",
364 pstream, ovs_strerror(error));
eab5611a
BP
365 }
366 }
367 }
86383816
BP
368 ovs_mutex_unlock(&netdev->mutex);
369
614c4892
BP
370 return 0;
371}
372
9dc63482
BP
373static struct netdev_rx *
374netdev_dummy_rx_alloc(void)
375{
376 struct netdev_rx_dummy *rx = xzalloc(sizeof *rx);
377 return &rx->up;
378}
379
7b6b0ef4 380static int
9dc63482 381netdev_dummy_rx_construct(struct netdev_rx *rx_)
7b6b0ef4 382{
9dc63482
BP
383 struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
384 struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
796223f5 385
86383816 386 ovs_mutex_lock(&netdev->mutex);
b5d57fc8 387 list_push_back(&netdev->rxes, &rx->node);
796223f5 388 list_init(&rx->recv_queue);
e34cfdd9 389 rx->recv_queue_len = 0;
86383816 390 ovs_mutex_unlock(&netdev->mutex);
796223f5 391
7b6b0ef4
BP
392 return 0;
393}
394
9dc63482
BP
395static void
396netdev_dummy_rx_destruct(struct netdev_rx *rx_)
397{
398 struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
86383816 399 struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
9dc63482 400
86383816 401 ovs_mutex_lock(&netdev->mutex);
9dc63482
BP
402 list_remove(&rx->node);
403 ofpbuf_list_delete(&rx->recv_queue);
86383816 404 ovs_mutex_unlock(&netdev->mutex);
9dc63482
BP
405}
406
407static void
408netdev_dummy_rx_dealloc(struct netdev_rx *rx_)
409{
410 struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
411
412 free(rx);
413}
414
7b6b0ef4 415static int
9dc63482 416netdev_dummy_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
fbac791a 417{
796223f5 418 struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
86383816 419 struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
fbac791a 420 struct ofpbuf *packet;
7d6ce2d1 421 int retval;
fbac791a 422
86383816
BP
423 ovs_mutex_lock(&netdev->mutex);
424 if (!list_is_empty(&rx->recv_queue)) {
425 packet = ofpbuf_from_list(list_pop_front(&rx->recv_queue));
426 rx->recv_queue_len--;
427 } else {
428 packet = NULL;
429 }
430 ovs_mutex_unlock(&netdev->mutex);
431
432 if (!packet) {
fbac791a
BP
433 return -EAGAIN;
434 }
435
7d6ce2d1
BP
436 if (packet->size <= size) {
437 memcpy(buffer, packet->data, packet->size);
438 retval = packet->size;
439 } else {
440 retval = -EMSGSIZE;
fbac791a 441 }
fbac791a
BP
442 ofpbuf_delete(packet);
443
7d6ce2d1 444 return retval;
fbac791a
BP
445}
446
447static void
9dc63482 448netdev_dummy_rx_wait(struct netdev_rx *rx_)
796223f5
BP
449{
450 struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
86383816
BP
451 struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
452
453 ovs_mutex_lock(&netdev->mutex);
796223f5 454 if (!list_is_empty(&rx->recv_queue)) {
fbac791a
BP
455 poll_immediate_wake();
456 }
86383816 457 ovs_mutex_unlock(&netdev->mutex);
fbac791a
BP
458}
459
460static int
9dc63482 461netdev_dummy_rx_drain(struct netdev_rx *rx_)
fbac791a 462{
796223f5 463 struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
86383816
BP
464 struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
465
466 ovs_mutex_lock(&netdev->mutex);
796223f5 467 ofpbuf_list_delete(&rx->recv_queue);
e34cfdd9 468 rx->recv_queue_len = 0;
86383816
BP
469 ovs_mutex_unlock(&netdev->mutex);
470
fbac791a 471 return 0;
7b6b0ef4
BP
472}
473
02d5bfe3 474static int
eab5611a 475netdev_dummy_send(struct netdev *netdev, const void *buffer, size_t size)
02d5bfe3 476{
b5d57fc8 477 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
eab5611a
BP
478 size_t i;
479
480 if (size < ETH_HEADER_LEN) {
481 return EMSGSIZE;
482 } else {
483 const struct eth_header *eth = buffer;
484 int max_size;
485
486 max_size = dev->mtu + ETH_HEADER_LEN;
487 if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
488 max_size += VLAN_HEADER_LEN;
489 }
490 if (size > max_size) {
491 return EMSGSIZE;
492 }
493 }
02d5bfe3 494
86383816 495 ovs_mutex_lock(&dev->mutex);
02d5bfe3
BP
496 dev->stats.tx_packets++;
497 dev->stats.tx_bytes += size;
498
eab5611a
BP
499 for (i = 0; i < dev->n_streams; i++) {
500 struct dummy_stream *s = &dev->streams[i];
501
502 if (list_size(&s->txq) < NETDEV_DUMMY_MAX_QUEUE) {
503 struct ofpbuf *b;
504
505 b = ofpbuf_clone_data_with_headroom(buffer, size, 2);
506 put_unaligned_be16(ofpbuf_push_uninit(b, 2), htons(size));
507 list_push_back(&s->txq, &b->list_node);
508 }
509 }
86383816 510 ovs_mutex_unlock(&dev->mutex);
eab5611a 511
02d5bfe3
BP
512 return 0;
513}
514
614c4892
BP
515static int
516netdev_dummy_set_etheraddr(struct netdev *netdev,
517 const uint8_t mac[ETH_ADDR_LEN])
518{
b5d57fc8 519 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
614c4892 520
86383816 521 ovs_mutex_lock(&dev->mutex);
614c4892
BP
522 if (!eth_addr_equals(dev->hwaddr, mac)) {
523 memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
b5d57fc8 524 netdev_dummy_poll_notify(dev);
614c4892 525 }
86383816 526 ovs_mutex_unlock(&dev->mutex);
614c4892
BP
527
528 return 0;
529}
530
531static int
532netdev_dummy_get_etheraddr(const struct netdev *netdev,
533 uint8_t mac[ETH_ADDR_LEN])
534{
86383816 535 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
614c4892 536
86383816 537 ovs_mutex_lock(&dev->mutex);
614c4892 538 memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
86383816
BP
539 ovs_mutex_unlock(&dev->mutex);
540
614c4892
BP
541 return 0;
542}
543
544static int
545netdev_dummy_get_mtu(const struct netdev *netdev, int *mtup)
546{
86383816 547 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
614c4892 548
86383816 549 ovs_mutex_lock(&dev->mutex);
614c4892 550 *mtup = dev->mtu;
86383816
BP
551 ovs_mutex_unlock(&dev->mutex);
552
614c4892
BP
553 return 0;
554}
555
9b020780
PS
556static int
557netdev_dummy_set_mtu(const struct netdev *netdev, int mtu)
558{
b5d57fc8 559 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
9b020780 560
86383816 561 ovs_mutex_lock(&dev->mutex);
9b020780 562 dev->mtu = mtu;
86383816
BP
563 ovs_mutex_unlock(&dev->mutex);
564
9b020780
PS
565 return 0;
566}
567
614c4892
BP
568static int
569netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
570{
86383816 571 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
614c4892 572
86383816 573 ovs_mutex_lock(&dev->mutex);
614c4892 574 *stats = dev->stats;
86383816
BP
575 ovs_mutex_unlock(&dev->mutex);
576
614c4892
BP
577 return 0;
578}
579
580static int
581netdev_dummy_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
582{
b5d57fc8 583 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
614c4892 584
86383816 585 ovs_mutex_lock(&dev->mutex);
614c4892 586 dev->stats = *stats;
86383816
BP
587 ovs_mutex_unlock(&dev->mutex);
588
614c4892
BP
589 return 0;
590}
591
8073dd31
NM
592static int
593netdev_dummy_get_ifindex(const struct netdev *netdev)
594{
b5d57fc8 595 struct netdev_dummy *dev = netdev_dummy_cast(netdev);
86383816
BP
596 int ifindex;
597
598 ovs_mutex_lock(&dev->mutex);
599 ifindex = dev->ifindex;
600 ovs_mutex_unlock(&dev->mutex);
8073dd31 601
86383816 602 return ifindex;
8073dd31
NM
603}
604
614c4892 605static int
86383816
BP
606netdev_dummy_update_flags__(struct netdev_dummy *netdev,
607 enum netdev_flags off, enum netdev_flags on,
608 enum netdev_flags *old_flagsp)
609 OVS_REQUIRES(netdev->mutex)
614c4892 610{
614c4892
BP
611 if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
612 return EINVAL;
613 }
614
b5d57fc8
BP
615 *old_flagsp = netdev->flags;
616 netdev->flags |= on;
617 netdev->flags &= ~off;
618 if (*old_flagsp != netdev->flags) {
619 netdev_dummy_poll_notify(netdev);
614c4892 620 }
86383816 621
614c4892
BP
622 return 0;
623}
624
86383816
BP
625static int
626netdev_dummy_update_flags(struct netdev *netdev_,
627 enum netdev_flags off, enum netdev_flags on,
628 enum netdev_flags *old_flagsp)
629{
630 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
631 int error;
632
633 ovs_mutex_lock(&netdev->mutex);
634 error = netdev_dummy_update_flags__(netdev, off, on, old_flagsp);
635 ovs_mutex_unlock(&netdev->mutex);
636
637 return error;
638}
639
ac4d3bcb 640static unsigned int
86383816 641netdev_dummy_change_seq(const struct netdev *netdev_)
ac4d3bcb 642{
86383816
BP
643 struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
644 unsigned int change_seq;
645
646 ovs_mutex_lock(&netdev->mutex);
647 change_seq = netdev->change_seq;
648 ovs_mutex_unlock(&netdev->mutex);
649
650 return change_seq;
ac4d3bcb 651}
614c4892
BP
652\f
653/* Helper functions. */
654
655static void
b5d57fc8 656netdev_dummy_poll_notify(struct netdev_dummy *dev)
614c4892 657{
ac4d3bcb
EJ
658 dev->change_seq++;
659 if (!dev->change_seq) {
660 dev->change_seq++;
661 }
614c4892
BP
662}
663
664static const struct netdev_class dummy_class = {
665 "dummy",
666 NULL, /* init */
eab5611a
BP
667 netdev_dummy_run,
668 netdev_dummy_wait,
614c4892 669
9dc63482
BP
670 netdev_dummy_alloc,
671 netdev_dummy_construct,
672 netdev_dummy_destruct,
673 netdev_dummy_dealloc,
8073dd31
NM
674 netdev_dummy_get_config,
675 netdev_dummy_set_config,
f431bf7d 676 NULL, /* get_tunnel_config */
614c4892 677
02d5bfe3 678 netdev_dummy_send, /* send */
614c4892
BP
679 NULL, /* send_wait */
680
681 netdev_dummy_set_etheraddr,
682 netdev_dummy_get_etheraddr,
683 netdev_dummy_get_mtu,
9b020780 684 netdev_dummy_set_mtu,
8073dd31 685 netdev_dummy_get_ifindex,
614c4892 686 NULL, /* get_carrier */
65c3058c 687 NULL, /* get_carrier_resets */
63331829 688 NULL, /* get_miimon */
614c4892
BP
689 netdev_dummy_get_stats,
690 netdev_dummy_set_stats,
691
692 NULL, /* get_features */
693 NULL, /* set_advertisements */
614c4892
BP
694
695 NULL, /* set_policing */
696 NULL, /* get_qos_types */
697 NULL, /* get_qos_capabilities */
698 NULL, /* get_qos */
699 NULL, /* set_qos */
700 NULL, /* get_queue */
701 NULL, /* set_queue */
702 NULL, /* delete_queue */
703 NULL, /* get_queue_stats */
704 NULL, /* dump_queues */
705 NULL, /* dump_queue_stats */
706
707 NULL, /* get_in4 */
708 NULL, /* set_in4 */
709 NULL, /* get_in6 */
710 NULL, /* add_router */
711 NULL, /* get_next_hop */
275707c3 712 NULL, /* get_status */
614c4892
BP
713 NULL, /* arp_lookup */
714
715 netdev_dummy_update_flags,
716
9dc63482 717 netdev_dummy_change_seq,
614c4892 718
9dc63482
BP
719 netdev_dummy_rx_alloc,
720 netdev_dummy_rx_construct,
721 netdev_dummy_rx_destruct,
722 netdev_dummy_rx_dealloc,
723 netdev_dummy_rx_recv,
724 netdev_dummy_rx_wait,
725 netdev_dummy_rx_drain,
796223f5
BP
726};
727
fbac791a
BP
728static struct ofpbuf *
729eth_from_packet_or_flow(const char *s)
730{
731 enum odp_key_fitness fitness;
732 struct ofpbuf *packet;
733 struct ofpbuf odp_key;
734 struct flow flow;
735 int error;
736
737 if (!eth_from_hex(s, &packet)) {
738 return packet;
739 }
740
741 /* Convert string to datapath key.
742 *
743 * It would actually be nicer to parse an OpenFlow-like flow key here, but
744 * the code for that currently calls exit() on parse error. We have to
745 * settle for parsing a datapath key for now.
746 */
747 ofpbuf_init(&odp_key, 0);
e6cc0bab 748 error = odp_flow_from_string(s, NULL, &odp_key, NULL);
fbac791a
BP
749 if (error) {
750 ofpbuf_uninit(&odp_key);
751 return NULL;
752 }
753
754 /* Convert odp_key to flow. */
755 fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
756 if (fitness == ODP_FIT_ERROR) {
757 ofpbuf_uninit(&odp_key);
758 return NULL;
759 }
760
761 packet = ofpbuf_new(0);
762 flow_compose(packet, &flow);
763
764 ofpbuf_uninit(&odp_key);
765 return packet;
766}
767
323cc924 768static void
eab5611a 769netdev_dummy_queue_packet__(struct netdev_rx_dummy *rx, struct ofpbuf *packet)
2273ea5a 770{
eab5611a
BP
771 list_push_back(&rx->recv_queue, &packet->list_node);
772 rx->recv_queue_len++;
773}
2273ea5a 774
eab5611a
BP
775static void
776netdev_dummy_queue_packet(struct netdev_dummy *dummy, struct ofpbuf *packet)
777{
778 struct netdev_rx_dummy *rx, *prev;
779
780 prev = NULL;
2273ea5a
BP
781 LIST_FOR_EACH (rx, node, &dummy->rxes) {
782 if (rx->recv_queue_len < NETDEV_DUMMY_MAX_QUEUE) {
eab5611a
BP
783 if (prev) {
784 netdev_dummy_queue_packet__(prev, ofpbuf_clone(packet));
785 }
786 prev = rx;
2273ea5a
BP
787 }
788 }
eab5611a
BP
789 if (prev) {
790 netdev_dummy_queue_packet__(prev, packet);
791 } else {
792 ofpbuf_delete(packet);
793 }
2273ea5a
BP
794}
795
fbac791a
BP
796static void
797netdev_dummy_receive(struct unixctl_conn *conn,
798 int argc, const char *argv[], void *aux OVS_UNUSED)
799{
b5d57fc8 800 struct netdev_dummy *dummy_dev;
86f1d032 801 struct netdev *netdev;
fbac791a
BP
802 int i;
803
86f1d032
BP
804 netdev = netdev_from_name(argv[1]);
805 if (!netdev || !is_dummy_class(netdev->netdev_class)) {
bde9f75d 806 unixctl_command_reply_error(conn, "no such dummy netdev");
86f1d032 807 goto exit;
fbac791a 808 }
86f1d032 809 dummy_dev = netdev_dummy_cast(netdev);
fbac791a 810
fbac791a 811 for (i = 2; i < argc; i++) {
fbac791a
BP
812 struct ofpbuf *packet;
813
814 packet = eth_from_packet_or_flow(argv[i]);
815 if (!packet) {
bde9f75d 816 unixctl_command_reply_error(conn, "bad packet syntax");
86f1d032 817 goto exit;
fbac791a
BP
818 }
819
86383816 820 ovs_mutex_lock(&dummy_dev->mutex);
02d5bfe3
BP
821 dummy_dev->stats.rx_packets++;
822 dummy_dev->stats.rx_bytes += packet->size;
eab5611a 823 netdev_dummy_queue_packet(dummy_dev, packet);
86383816 824 ovs_mutex_unlock(&dummy_dev->mutex);
fbac791a
BP
825 }
826
323cc924 827 unixctl_command_reply(conn, NULL);
86f1d032
BP
828
829exit:
830 netdev_close(netdev);
fbac791a
BP
831}
832
95d4ec33 833static void
b5d57fc8 834netdev_dummy_set_admin_state__(struct netdev_dummy *dev, bool admin_state)
86383816 835 OVS_REQUIRES(dev->mutex)
95d4ec33
EJ
836{
837 enum netdev_flags old_flags;
838
839 if (admin_state) {
86383816 840 netdev_dummy_update_flags__(dev, 0, NETDEV_UP, &old_flags);
95d4ec33 841 } else {
86383816 842 netdev_dummy_update_flags__(dev, NETDEV_UP, 0, &old_flags);
95d4ec33
EJ
843 }
844}
845
846static void
847netdev_dummy_set_admin_state(struct unixctl_conn *conn, int argc,
848 const char *argv[], void *aux OVS_UNUSED)
849{
850 bool up;
851
852 if (!strcasecmp(argv[argc - 1], "up")) {
853 up = true;
854 } else if ( !strcasecmp(argv[argc - 1], "down")) {
855 up = false;
856 } else {
857 unixctl_command_reply_error(conn, "Invalid Admin State");
858 return;
859 }
860
861 if (argc > 2) {
86f1d032
BP
862 struct netdev *netdev = netdev_from_name(argv[1]);
863 if (netdev && is_dummy_class(netdev->netdev_class)) {
864 struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
95d4ec33 865
86383816 866 ovs_mutex_lock(&dummy_dev->mutex);
b5d57fc8 867 netdev_dummy_set_admin_state__(dummy_dev, up);
86383816
BP
868 ovs_mutex_unlock(&dummy_dev->mutex);
869
86f1d032 870 netdev_close(netdev);
95d4ec33
EJ
871 } else {
872 unixctl_command_reply_error(conn, "Unknown Dummy Interface");
86f1d032 873 netdev_close(netdev);
95d4ec33
EJ
874 return;
875 }
876 } else {
5e1de67f 877 struct netdev_dummy *netdev;
86383816 878
5e1de67f
BP
879 ovs_mutex_lock(&dummy_list_mutex);
880 LIST_FOR_EACH (netdev, list_node, &dummy_list) {
86383816
BP
881 ovs_mutex_lock(&netdev->mutex);
882 netdev_dummy_set_admin_state__(netdev, up);
883 ovs_mutex_unlock(&netdev->mutex);
95d4ec33 884 }
5e1de67f 885 ovs_mutex_unlock(&dummy_list_mutex);
95d4ec33
EJ
886 }
887 unixctl_command_reply(conn, "OK");
888}
889
614c4892 890void
0cbfe35d 891netdev_dummy_register(bool override)
614c4892 892{
fbac791a
BP
893 unixctl_command_register("netdev-dummy/receive", "NAME PACKET|FLOW...",
894 2, INT_MAX, netdev_dummy_receive, NULL);
95d4ec33
EJ
895 unixctl_command_register("netdev-dummy/set-admin-state",
896 "[netdev] up|down", 1, 2,
897 netdev_dummy_set_admin_state, NULL);
0cbfe35d
BP
898
899 if (override) {
900 struct sset types;
901 const char *type;
902
903 sset_init(&types);
904 netdev_enumerate_types(&types);
905 SSET_FOR_EACH (type, &types) {
906 if (!netdev_unregister_provider(type)) {
907 struct netdev_class *class;
86383816 908 int error;
0cbfe35d 909
86383816 910 class = xmemdup(&dummy_class, sizeof dummy_class);
0cbfe35d 911 class->type = xstrdup(type);
86383816
BP
912 error = netdev_register_provider(class);
913 if (error) {
914 VLOG_ERR("%s: failed to register netdev provider (%s)",
915 type, ovs_strerror(error));
916 free(CONST_CAST(char *, class->type));
917 free(class);
918 }
0cbfe35d
BP
919 }
920 }
921 sset_destroy(&types);
922 }
923 netdev_register_provider(&dummy_class);
c060c4cf 924
7c54c27f 925 netdev_vport_tunnel_register();
614c4892 926}