2 * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "netdev-provider.h"
26 #include "netdev-vport.h"
28 #include "ofp-print.h"
31 #include "poll-loop.h"
35 #include "unaligned.h"
39 VLOG_DEFINE_THIS_MODULE(netdev_dummy
);
42 struct stream
*stream
;
49 uint8_t hwaddr
[ETH_ADDR_LEN
];
51 struct netdev_stats stats
;
52 enum netdev_flags flags
;
53 unsigned int change_seq
;
56 struct pstream
*pstream
;
57 struct dummy_stream
*streams
;
60 struct list rxes
; /* List of child "netdev_rx_dummy"s. */
63 static const struct netdev_class dummy_class
;
65 /* Max 'recv_queue_len' in struct netdev_dummy. */
66 #define NETDEV_DUMMY_MAX_QUEUE 100
68 struct netdev_rx_dummy
{
70 struct list node
; /* In netdev_dummy's "rxes" list. */
71 struct list recv_queue
;
72 int recv_queue_len
; /* list_size(&recv_queue). */
76 static unixctl_cb_func netdev_dummy_set_admin_state
;
77 static int netdev_dummy_construct(struct netdev
*);
78 static void netdev_dummy_poll_notify(struct netdev_dummy
*);
79 static void netdev_dummy_queue_packet(struct netdev_dummy
*, struct ofpbuf
*);
81 static void dummy_stream_close(struct dummy_stream
*);
84 is_dummy_class(const struct netdev_class
*class)
86 return class->construct
== netdev_dummy_construct
;
89 static struct netdev_dummy
*
90 netdev_dummy_cast(const struct netdev
*netdev
)
92 ovs_assert(is_dummy_class(netdev_get_class(netdev
)));
93 return CONTAINER_OF(netdev
, struct netdev_dummy
, up
);
96 static struct netdev_rx_dummy
*
97 netdev_rx_dummy_cast(const struct netdev_rx
*rx
)
99 ovs_assert(is_dummy_class(netdev_get_class(rx
->netdev
)));
100 return CONTAINER_OF(rx
, struct netdev_rx_dummy
, up
);
104 netdev_dummy_run(void)
106 struct shash dummy_netdevs
;
107 struct shash_node
*node
;
109 shash_init(&dummy_netdevs
);
110 netdev_get_devices(&dummy_class
, &dummy_netdevs
);
111 SHASH_FOR_EACH (node
, &dummy_netdevs
) {
112 struct netdev_dummy
*dev
= node
->data
;
116 struct stream
*new_stream
;
119 error
= pstream_accept(dev
->pstream
, &new_stream
);
121 struct dummy_stream
*s
;
123 dev
->streams
= xrealloc(dev
->streams
,
124 ((dev
->n_streams
+ 1)
125 * sizeof *dev
->streams
));
126 s
= &dev
->streams
[dev
->n_streams
++];
127 s
->stream
= new_stream
;
128 ofpbuf_init(&s
->rxbuf
, 2048);
130 } else if (error
!= EAGAIN
) {
131 VLOG_WARN("%s: accept failed (%s)",
132 pstream_get_name(dev
->pstream
), ovs_strerror(error
));
133 pstream_close(dev
->pstream
);
138 for (i
= 0; i
< dev
->n_streams
; i
++) {
139 struct dummy_stream
*s
= &dev
->streams
[i
];
143 stream_run(s
->stream
);
145 if (!list_is_empty(&s
->txq
)) {
146 struct ofpbuf
*txbuf
;
149 txbuf
= ofpbuf_from_list(list_front(&s
->txq
));
150 retval
= stream_send(s
->stream
, txbuf
->data
, txbuf
->size
);
152 ofpbuf_pull(txbuf
, retval
);
154 list_remove(&txbuf
->list_node
);
155 ofpbuf_delete(txbuf
);
157 } else if (retval
!= -EAGAIN
) {
163 if (s
->rxbuf
.size
< 2) {
164 n
= 2 - s
->rxbuf
.size
;
168 frame_len
= ntohs(get_unaligned_be16(s
->rxbuf
.data
));
169 if (frame_len
< ETH_HEADER_LEN
) {
173 n
= (2 + frame_len
) - s
->rxbuf
.size
;
180 ofpbuf_prealloc_tailroom(&s
->rxbuf
, n
);
181 retval
= stream_recv(s
->stream
, ofpbuf_tail(&s
->rxbuf
), n
);
183 s
->rxbuf
.size
+= retval
;
184 if (retval
== n
&& s
->rxbuf
.size
> 2) {
185 ofpbuf_pull(&s
->rxbuf
, 2);
186 netdev_dummy_queue_packet(dev
,
187 ofpbuf_clone(&s
->rxbuf
));
188 ofpbuf_clear(&s
->rxbuf
);
190 } else if (retval
!= -EAGAIN
) {
191 error
= (retval
< 0 ? -retval
192 : s
->rxbuf
.size
? EPROTO
198 VLOG_DBG("%s: closing connection (%s)",
199 stream_get_name(s
->stream
),
200 ovs_retval_to_string(error
));
201 dummy_stream_close(&dev
->streams
[i
]);
202 dev
->streams
[i
] = dev
->streams
[--dev
->n_streams
];
206 netdev_close(&dev
->up
);
208 shash_destroy(&dummy_netdevs
);
212 dummy_stream_close(struct dummy_stream
*s
)
214 stream_close(s
->stream
);
215 ofpbuf_uninit(&s
->rxbuf
);
216 ofpbuf_list_delete(&s
->txq
);
220 netdev_dummy_wait(void)
222 struct shash dummy_netdevs
;
223 struct shash_node
*node
;
225 shash_init(&dummy_netdevs
);
226 netdev_get_devices(&dummy_class
, &dummy_netdevs
);
227 SHASH_FOR_EACH (node
, &dummy_netdevs
) {
228 struct netdev_dummy
*dev
= node
->data
;
232 pstream_wait(dev
->pstream
);
234 for (i
= 0; i
< dev
->n_streams
; i
++) {
235 struct dummy_stream
*s
= &dev
->streams
[i
];
237 stream_run_wait(s
->stream
);
238 if (!list_is_empty(&s
->txq
)) {
239 stream_send_wait(s
->stream
);
241 stream_recv_wait(s
->stream
);
243 netdev_close(&dev
->up
);
245 shash_destroy(&dummy_netdevs
);
248 static struct netdev
*
249 netdev_dummy_alloc(void)
251 struct netdev_dummy
*netdev
= xzalloc(sizeof *netdev
);
256 netdev_dummy_construct(struct netdev
*netdev_
)
258 static atomic_uint next_n
= ATOMIC_VAR_INIT(0xaa550000);
259 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
262 atomic_add(&next_n
, 1, &n
);
263 netdev
->hwaddr
[0] = 0xaa;
264 netdev
->hwaddr
[1] = 0x55;
265 netdev
->hwaddr
[2] = n
>> 24;
266 netdev
->hwaddr
[3] = n
>> 16;
267 netdev
->hwaddr
[4] = n
>> 8;
268 netdev
->hwaddr
[5] = n
;
271 netdev
->change_seq
= 1;
272 netdev
->ifindex
= -EOPNOTSUPP
;
274 netdev
->pstream
= NULL
;
275 netdev
->streams
= NULL
;
276 netdev
->n_streams
= 0;
278 list_init(&netdev
->rxes
);
284 netdev_dummy_destruct(struct netdev
*netdev_
)
286 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
289 pstream_close(netdev
->pstream
);
290 for (i
= 0; i
< netdev
->n_streams
; i
++) {
291 dummy_stream_close(&netdev
->streams
[i
]);
293 free(netdev
->streams
);
297 netdev_dummy_dealloc(struct netdev
*netdev_
)
299 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
305 netdev_dummy_get_config(const struct netdev
*netdev_
, struct smap
*args
)
307 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
309 if (netdev
->ifindex
>= 0) {
310 smap_add_format(args
, "ifindex", "%d", netdev
->ifindex
);
312 if (netdev
->pstream
) {
313 smap_add(args
, "pstream", pstream_get_name(netdev
->pstream
));
319 netdev_dummy_set_config(struct netdev
*netdev_
, const struct smap
*args
)
321 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
324 netdev
->ifindex
= smap_get_int(args
, "ifindex", -EOPNOTSUPP
);
326 pstream
= smap_get(args
, "pstream");
329 || strcmp(pstream_get_name(netdev
->pstream
), pstream
)) {
330 pstream_close(netdev
->pstream
);
331 netdev
->pstream
= NULL
;
336 error
= pstream_open(pstream
, &netdev
->pstream
, DSCP_DEFAULT
);
338 VLOG_WARN("%s: open failed (%s)",
339 pstream
, ovs_strerror(error
));
346 static struct netdev_rx
*
347 netdev_dummy_rx_alloc(void)
349 struct netdev_rx_dummy
*rx
= xzalloc(sizeof *rx
);
354 netdev_dummy_rx_construct(struct netdev_rx
*rx_
)
356 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
357 struct netdev_dummy
*netdev
= netdev_dummy_cast(rx
->up
.netdev
);
359 list_push_back(&netdev
->rxes
, &rx
->node
);
360 list_init(&rx
->recv_queue
);
361 rx
->recv_queue_len
= 0;
367 netdev_dummy_rx_destruct(struct netdev_rx
*rx_
)
369 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
371 list_remove(&rx
->node
);
372 ofpbuf_list_delete(&rx
->recv_queue
);
376 netdev_dummy_rx_dealloc(struct netdev_rx
*rx_
)
378 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
384 netdev_dummy_rx_recv(struct netdev_rx
*rx_
, void *buffer
, size_t size
)
386 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
387 struct ofpbuf
*packet
;
390 if (list_is_empty(&rx
->recv_queue
)) {
394 packet
= ofpbuf_from_list(list_pop_front(&rx
->recv_queue
));
395 rx
->recv_queue_len
--;
396 if (packet
->size
<= size
) {
397 memcpy(buffer
, packet
->data
, packet
->size
);
398 retval
= packet
->size
;
402 ofpbuf_delete(packet
);
408 netdev_dummy_rx_wait(struct netdev_rx
*rx_
)
410 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
411 if (!list_is_empty(&rx
->recv_queue
)) {
412 poll_immediate_wake();
417 netdev_dummy_rx_drain(struct netdev_rx
*rx_
)
419 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
420 ofpbuf_list_delete(&rx
->recv_queue
);
421 rx
->recv_queue_len
= 0;
426 netdev_dummy_send(struct netdev
*netdev
, const void *buffer
, size_t size
)
428 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
431 if (size
< ETH_HEADER_LEN
) {
434 const struct eth_header
*eth
= buffer
;
437 max_size
= dev
->mtu
+ ETH_HEADER_LEN
;
438 if (eth
->eth_type
== htons(ETH_TYPE_VLAN
)) {
439 max_size
+= VLAN_HEADER_LEN
;
441 if (size
> max_size
) {
446 dev
->stats
.tx_packets
++;
447 dev
->stats
.tx_bytes
+= size
;
449 for (i
= 0; i
< dev
->n_streams
; i
++) {
450 struct dummy_stream
*s
= &dev
->streams
[i
];
452 if (list_size(&s
->txq
) < NETDEV_DUMMY_MAX_QUEUE
) {
455 b
= ofpbuf_clone_data_with_headroom(buffer
, size
, 2);
456 put_unaligned_be16(ofpbuf_push_uninit(b
, 2), htons(size
));
457 list_push_back(&s
->txq
, &b
->list_node
);
465 netdev_dummy_set_etheraddr(struct netdev
*netdev
,
466 const uint8_t mac
[ETH_ADDR_LEN
])
468 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
470 if (!eth_addr_equals(dev
->hwaddr
, mac
)) {
471 memcpy(dev
->hwaddr
, mac
, ETH_ADDR_LEN
);
472 netdev_dummy_poll_notify(dev
);
479 netdev_dummy_get_etheraddr(const struct netdev
*netdev
,
480 uint8_t mac
[ETH_ADDR_LEN
])
482 const struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
484 memcpy(mac
, dev
->hwaddr
, ETH_ADDR_LEN
);
489 netdev_dummy_get_mtu(const struct netdev
*netdev
, int *mtup
)
491 const struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
498 netdev_dummy_set_mtu(const struct netdev
*netdev
, int mtu
)
500 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
507 netdev_dummy_get_stats(const struct netdev
*netdev
, struct netdev_stats
*stats
)
509 const struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
516 netdev_dummy_set_stats(struct netdev
*netdev
, const struct netdev_stats
*stats
)
518 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
525 netdev_dummy_get_ifindex(const struct netdev
*netdev
)
527 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
533 netdev_dummy_update_flags(struct netdev
*netdev_
,
534 enum netdev_flags off
, enum netdev_flags on
,
535 enum netdev_flags
*old_flagsp
)
537 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
539 if ((off
| on
) & ~(NETDEV_UP
| NETDEV_PROMISC
)) {
543 *old_flagsp
= netdev
->flags
;
545 netdev
->flags
&= ~off
;
546 if (*old_flagsp
!= netdev
->flags
) {
547 netdev_dummy_poll_notify(netdev
);
553 netdev_dummy_change_seq(const struct netdev
*netdev
)
555 return netdev_dummy_cast(netdev
)->change_seq
;
558 /* Helper functions. */
561 netdev_dummy_poll_notify(struct netdev_dummy
*dev
)
564 if (!dev
->change_seq
) {
569 static const struct netdev_class dummy_class
= {
576 netdev_dummy_construct
,
577 netdev_dummy_destruct
,
578 netdev_dummy_dealloc
,
579 netdev_dummy_get_config
,
580 netdev_dummy_set_config
,
581 NULL
, /* get_tunnel_config */
583 netdev_dummy_send
, /* send */
584 NULL
, /* send_wait */
586 netdev_dummy_set_etheraddr
,
587 netdev_dummy_get_etheraddr
,
588 netdev_dummy_get_mtu
,
589 netdev_dummy_set_mtu
,
590 netdev_dummy_get_ifindex
,
591 NULL
, /* get_carrier */
592 NULL
, /* get_carrier_resets */
593 NULL
, /* get_miimon */
594 netdev_dummy_get_stats
,
595 netdev_dummy_set_stats
,
597 NULL
, /* get_features */
598 NULL
, /* set_advertisements */
600 NULL
, /* set_policing */
601 NULL
, /* get_qos_types */
602 NULL
, /* get_qos_capabilities */
605 NULL
, /* get_queue */
606 NULL
, /* set_queue */
607 NULL
, /* delete_queue */
608 NULL
, /* get_queue_stats */
609 NULL
, /* dump_queues */
610 NULL
, /* dump_queue_stats */
615 NULL
, /* add_router */
616 NULL
, /* get_next_hop */
617 NULL
, /* get_status */
618 NULL
, /* arp_lookup */
620 netdev_dummy_update_flags
,
622 netdev_dummy_change_seq
,
624 netdev_dummy_rx_alloc
,
625 netdev_dummy_rx_construct
,
626 netdev_dummy_rx_destruct
,
627 netdev_dummy_rx_dealloc
,
628 netdev_dummy_rx_recv
,
629 netdev_dummy_rx_wait
,
630 netdev_dummy_rx_drain
,
633 static struct ofpbuf
*
634 eth_from_packet_or_flow(const char *s
)
636 enum odp_key_fitness fitness
;
637 struct ofpbuf
*packet
;
638 struct ofpbuf odp_key
;
642 if (!eth_from_hex(s
, &packet
)) {
646 /* Convert string to datapath key.
648 * It would actually be nicer to parse an OpenFlow-like flow key here, but
649 * the code for that currently calls exit() on parse error. We have to
650 * settle for parsing a datapath key for now.
652 ofpbuf_init(&odp_key
, 0);
653 error
= odp_flow_from_string(s
, NULL
, &odp_key
, NULL
);
655 ofpbuf_uninit(&odp_key
);
659 /* Convert odp_key to flow. */
660 fitness
= odp_flow_key_to_flow(odp_key
.data
, odp_key
.size
, &flow
);
661 if (fitness
== ODP_FIT_ERROR
) {
662 ofpbuf_uninit(&odp_key
);
666 packet
= ofpbuf_new(0);
667 flow_compose(packet
, &flow
);
669 ofpbuf_uninit(&odp_key
);
674 netdev_dummy_queue_packet__(struct netdev_rx_dummy
*rx
, struct ofpbuf
*packet
)
676 list_push_back(&rx
->recv_queue
, &packet
->list_node
);
677 rx
->recv_queue_len
++;
681 netdev_dummy_queue_packet(struct netdev_dummy
*dummy
, struct ofpbuf
*packet
)
683 struct netdev_rx_dummy
*rx
, *prev
;
686 LIST_FOR_EACH (rx
, node
, &dummy
->rxes
) {
687 if (rx
->recv_queue_len
< NETDEV_DUMMY_MAX_QUEUE
) {
689 netdev_dummy_queue_packet__(prev
, ofpbuf_clone(packet
));
695 netdev_dummy_queue_packet__(prev
, packet
);
697 ofpbuf_delete(packet
);
702 netdev_dummy_receive(struct unixctl_conn
*conn
,
703 int argc
, const char *argv
[], void *aux OVS_UNUSED
)
705 struct netdev_dummy
*dummy_dev
;
706 struct netdev
*netdev
;
709 netdev
= netdev_from_name(argv
[1]);
710 if (!netdev
|| !is_dummy_class(netdev
->netdev_class
)) {
711 unixctl_command_reply_error(conn
, "no such dummy netdev");
714 dummy_dev
= netdev_dummy_cast(netdev
);
716 for (i
= 2; i
< argc
; i
++) {
717 struct ofpbuf
*packet
;
719 packet
= eth_from_packet_or_flow(argv
[i
]);
721 unixctl_command_reply_error(conn
, "bad packet syntax");
725 dummy_dev
->stats
.rx_packets
++;
726 dummy_dev
->stats
.rx_bytes
+= packet
->size
;
728 netdev_dummy_queue_packet(dummy_dev
, packet
);
731 unixctl_command_reply(conn
, NULL
);
734 netdev_close(netdev
);
738 netdev_dummy_set_admin_state__(struct netdev_dummy
*dev
, bool admin_state
)
740 enum netdev_flags old_flags
;
743 netdev_dummy_update_flags(&dev
->up
, 0, NETDEV_UP
, &old_flags
);
745 netdev_dummy_update_flags(&dev
->up
, NETDEV_UP
, 0, &old_flags
);
750 netdev_dummy_set_admin_state(struct unixctl_conn
*conn
, int argc
,
751 const char *argv
[], void *aux OVS_UNUSED
)
755 if (!strcasecmp(argv
[argc
- 1], "up")) {
757 } else if ( !strcasecmp(argv
[argc
- 1], "down")) {
760 unixctl_command_reply_error(conn
, "Invalid Admin State");
765 struct netdev
*netdev
= netdev_from_name(argv
[1]);
766 if (netdev
&& is_dummy_class(netdev
->netdev_class
)) {
767 struct netdev_dummy
*dummy_dev
= netdev_dummy_cast(netdev
);
769 netdev_dummy_set_admin_state__(dummy_dev
, up
);
770 netdev_close(netdev
);
772 unixctl_command_reply_error(conn
, "Unknown Dummy Interface");
773 netdev_close(netdev
);
777 struct shash dummy_netdevs
;
778 struct shash_node
*node
;
780 shash_init(&dummy_netdevs
);
781 netdev_get_devices(&dummy_class
, &dummy_netdevs
);
782 SHASH_FOR_EACH (node
, &dummy_netdevs
) {
783 struct netdev
*netdev
= node
->data
;
784 netdev_dummy_set_admin_state__(netdev_dummy_cast(netdev
), up
);
785 netdev_close(netdev
);
787 shash_destroy(&dummy_netdevs
);
789 unixctl_command_reply(conn
, "OK");
793 netdev_dummy_register(bool override
)
795 unixctl_command_register("netdev-dummy/receive", "NAME PACKET|FLOW...",
796 2, INT_MAX
, netdev_dummy_receive
, NULL
);
797 unixctl_command_register("netdev-dummy/set-admin-state",
798 "[netdev] up|down", 1, 2,
799 netdev_dummy_set_admin_state
, NULL
);
806 netdev_enumerate_types(&types
);
807 SSET_FOR_EACH (type
, &types
) {
808 if (!netdev_unregister_provider(type
)) {
809 struct netdev_class
*class;
811 class = xmalloc(sizeof *class);
812 *class = dummy_class
;
813 class->type
= xstrdup(type
);
814 netdev_register_provider(class);
817 sset_destroy(&types
);
819 netdev_register_provider(&dummy_class
);
821 netdev_vport_tunnel_register();