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 /* Max 'recv_queue_len' in struct netdev_dummy. */
64 #define NETDEV_DUMMY_MAX_QUEUE 100
66 struct netdev_rx_dummy
{
68 struct list node
; /* In netdev_dummy's "rxes" list. */
69 struct list recv_queue
;
70 int recv_queue_len
; /* list_size(&recv_queue). */
74 static struct shash dummy_netdevs
= SHASH_INITIALIZER(&dummy_netdevs
);
76 static const struct netdev_rx_class netdev_rx_dummy_class
;
78 static unixctl_cb_func netdev_dummy_set_admin_state
;
79 static int netdev_dummy_create(const struct netdev_class
*, const char *,
81 static void netdev_dummy_poll_notify(struct netdev_dummy
*);
82 static void netdev_dummy_queue_packet(struct netdev_dummy
*, struct ofpbuf
*);
84 static void dummy_stream_close(struct dummy_stream
*);
87 is_dummy_class(const struct netdev_class
*class)
89 return class->create
== netdev_dummy_create
;
92 static struct netdev_dummy
*
93 netdev_dummy_cast(const struct netdev
*netdev
)
95 ovs_assert(is_dummy_class(netdev_get_class(netdev
)));
96 return CONTAINER_OF(netdev
, struct netdev_dummy
, up
);
99 static struct netdev_rx_dummy
*
100 netdev_rx_dummy_cast(const struct netdev_rx
*rx
)
102 netdev_rx_assert_class(rx
, &netdev_rx_dummy_class
);
103 return CONTAINER_OF(rx
, struct netdev_rx_dummy
, up
);
107 netdev_dummy_run(void)
109 struct shash_node
*node
;
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
];
209 dummy_stream_close(struct dummy_stream
*s
)
211 stream_close(s
->stream
);
212 ofpbuf_uninit(&s
->rxbuf
);
213 ofpbuf_list_delete(&s
->txq
);
217 netdev_dummy_wait(void)
219 struct shash_node
*node
;
221 SHASH_FOR_EACH (node
, &dummy_netdevs
) {
222 struct netdev_dummy
*dev
= node
->data
;
226 pstream_wait(dev
->pstream
);
228 for (i
= 0; i
< dev
->n_streams
; i
++) {
229 struct dummy_stream
*s
= &dev
->streams
[i
];
231 stream_run_wait(s
->stream
);
232 if (!list_is_empty(&s
->txq
)) {
233 stream_send_wait(s
->stream
);
235 stream_recv_wait(s
->stream
);
241 netdev_dummy_create(const struct netdev_class
*class, const char *name
,
242 struct netdev
**netdevp
)
244 static atomic_uint next_n
= ATOMIC_VAR_INIT(0xaa550000);
245 struct netdev_dummy
*netdev
;
248 atomic_add(&next_n
, 1, &n
);
249 netdev
= xzalloc(sizeof *netdev
);
250 netdev_init(&netdev
->up
, name
, class);
251 netdev
->hwaddr
[0] = 0xaa;
252 netdev
->hwaddr
[1] = 0x55;
253 netdev
->hwaddr
[2] = n
>> 24;
254 netdev
->hwaddr
[3] = n
>> 16;
255 netdev
->hwaddr
[4] = n
>> 8;
256 netdev
->hwaddr
[5] = n
;
259 netdev
->change_seq
= 1;
260 netdev
->ifindex
= -EOPNOTSUPP
;
262 netdev
->pstream
= NULL
;
263 netdev
->streams
= NULL
;
264 netdev
->n_streams
= 0;
266 list_init(&netdev
->rxes
);
268 shash_add(&dummy_netdevs
, name
, netdev
);
270 *netdevp
= &netdev
->up
;
276 netdev_dummy_destroy(struct netdev
*netdev_
)
278 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
281 shash_find_and_delete(&dummy_netdevs
,
282 netdev_get_name(netdev_
));
283 pstream_close(netdev
->pstream
);
284 for (i
= 0; i
< netdev
->n_streams
; i
++) {
285 dummy_stream_close(&netdev
->streams
[i
]);
287 free(netdev
->streams
);
292 netdev_dummy_get_config(const struct netdev
*netdev_
, struct smap
*args
)
294 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
296 if (netdev
->ifindex
>= 0) {
297 smap_add_format(args
, "ifindex", "%d", netdev
->ifindex
);
299 if (netdev
->pstream
) {
300 smap_add(args
, "pstream", pstream_get_name(netdev
->pstream
));
306 netdev_dummy_set_config(struct netdev
*netdev_
, const struct smap
*args
)
308 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
311 netdev
->ifindex
= smap_get_int(args
, "ifindex", -EOPNOTSUPP
);
313 pstream
= smap_get(args
, "pstream");
316 || strcmp(pstream_get_name(netdev
->pstream
), pstream
)) {
317 pstream_close(netdev
->pstream
);
318 netdev
->pstream
= NULL
;
323 error
= pstream_open(pstream
, &netdev
->pstream
, DSCP_DEFAULT
);
325 VLOG_WARN("%s: open failed (%s)",
326 pstream
, ovs_strerror(error
));
334 netdev_dummy_rx_open(struct netdev
*netdev_
, struct netdev_rx
**rxp
)
336 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
337 struct netdev_rx_dummy
*rx
;
339 rx
= xmalloc(sizeof *rx
);
340 netdev_rx_init(&rx
->up
, &netdev
->up
, &netdev_rx_dummy_class
);
341 list_push_back(&netdev
->rxes
, &rx
->node
);
342 list_init(&rx
->recv_queue
);
343 rx
->recv_queue_len
= 0;
350 netdev_rx_dummy_recv(struct netdev_rx
*rx_
, void *buffer
, size_t size
)
352 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
353 struct ofpbuf
*packet
;
356 if (list_is_empty(&rx
->recv_queue
)) {
360 packet
= ofpbuf_from_list(list_pop_front(&rx
->recv_queue
));
361 rx
->recv_queue_len
--;
362 if (packet
->size
<= size
) {
363 memcpy(buffer
, packet
->data
, packet
->size
);
364 retval
= packet
->size
;
368 ofpbuf_delete(packet
);
374 netdev_rx_dummy_destroy(struct netdev_rx
*rx_
)
376 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
377 list_remove(&rx
->node
);
378 ofpbuf_list_delete(&rx
->recv_queue
);
383 netdev_rx_dummy_wait(struct netdev_rx
*rx_
)
385 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
386 if (!list_is_empty(&rx
->recv_queue
)) {
387 poll_immediate_wake();
392 netdev_rx_dummy_drain(struct netdev_rx
*rx_
)
394 struct netdev_rx_dummy
*rx
= netdev_rx_dummy_cast(rx_
);
395 ofpbuf_list_delete(&rx
->recv_queue
);
396 rx
->recv_queue_len
= 0;
401 netdev_dummy_send(struct netdev
*netdev
, const void *buffer
, size_t size
)
403 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
406 if (size
< ETH_HEADER_LEN
) {
409 const struct eth_header
*eth
= buffer
;
412 max_size
= dev
->mtu
+ ETH_HEADER_LEN
;
413 if (eth
->eth_type
== htons(ETH_TYPE_VLAN
)) {
414 max_size
+= VLAN_HEADER_LEN
;
416 if (size
> max_size
) {
421 dev
->stats
.tx_packets
++;
422 dev
->stats
.tx_bytes
+= size
;
424 for (i
= 0; i
< dev
->n_streams
; i
++) {
425 struct dummy_stream
*s
= &dev
->streams
[i
];
427 if (list_size(&s
->txq
) < NETDEV_DUMMY_MAX_QUEUE
) {
430 b
= ofpbuf_clone_data_with_headroom(buffer
, size
, 2);
431 put_unaligned_be16(ofpbuf_push_uninit(b
, 2), htons(size
));
432 list_push_back(&s
->txq
, &b
->list_node
);
440 netdev_dummy_set_etheraddr(struct netdev
*netdev
,
441 const uint8_t mac
[ETH_ADDR_LEN
])
443 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
445 if (!eth_addr_equals(dev
->hwaddr
, mac
)) {
446 memcpy(dev
->hwaddr
, mac
, ETH_ADDR_LEN
);
447 netdev_dummy_poll_notify(dev
);
454 netdev_dummy_get_etheraddr(const struct netdev
*netdev
,
455 uint8_t mac
[ETH_ADDR_LEN
])
457 const struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
459 memcpy(mac
, dev
->hwaddr
, ETH_ADDR_LEN
);
464 netdev_dummy_get_mtu(const struct netdev
*netdev
, int *mtup
)
466 const struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
473 netdev_dummy_set_mtu(const struct netdev
*netdev
, int mtu
)
475 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
482 netdev_dummy_get_stats(const struct netdev
*netdev
, struct netdev_stats
*stats
)
484 const struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
491 netdev_dummy_set_stats(struct netdev
*netdev
, const struct netdev_stats
*stats
)
493 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
500 netdev_dummy_get_ifindex(const struct netdev
*netdev
)
502 struct netdev_dummy
*dev
= netdev_dummy_cast(netdev
);
508 netdev_dummy_update_flags(struct netdev
*netdev_
,
509 enum netdev_flags off
, enum netdev_flags on
,
510 enum netdev_flags
*old_flagsp
)
512 struct netdev_dummy
*netdev
= netdev_dummy_cast(netdev_
);
514 if ((off
| on
) & ~(NETDEV_UP
| NETDEV_PROMISC
)) {
518 *old_flagsp
= netdev
->flags
;
520 netdev
->flags
&= ~off
;
521 if (*old_flagsp
!= netdev
->flags
) {
522 netdev_dummy_poll_notify(netdev
);
528 netdev_dummy_change_seq(const struct netdev
*netdev
)
530 return netdev_dummy_cast(netdev
)->change_seq
;
533 /* Helper functions. */
536 netdev_dummy_poll_notify(struct netdev_dummy
*dev
)
539 if (!dev
->change_seq
) {
544 static const struct netdev_class dummy_class
= {
551 netdev_dummy_destroy
,
552 netdev_dummy_get_config
,
553 netdev_dummy_set_config
,
554 NULL
, /* get_tunnel_config */
556 netdev_dummy_rx_open
,
558 netdev_dummy_send
, /* send */
559 NULL
, /* send_wait */
561 netdev_dummy_set_etheraddr
,
562 netdev_dummy_get_etheraddr
,
563 netdev_dummy_get_mtu
,
564 netdev_dummy_set_mtu
,
565 netdev_dummy_get_ifindex
,
566 NULL
, /* get_carrier */
567 NULL
, /* get_carrier_resets */
568 NULL
, /* get_miimon */
569 netdev_dummy_get_stats
,
570 netdev_dummy_set_stats
,
572 NULL
, /* get_features */
573 NULL
, /* set_advertisements */
575 NULL
, /* set_policing */
576 NULL
, /* get_qos_types */
577 NULL
, /* get_qos_capabilities */
580 NULL
, /* get_queue */
581 NULL
, /* set_queue */
582 NULL
, /* delete_queue */
583 NULL
, /* get_queue_stats */
584 NULL
, /* dump_queues */
585 NULL
, /* dump_queue_stats */
590 NULL
, /* add_router */
591 NULL
, /* get_next_hop */
592 NULL
, /* get_status */
593 NULL
, /* arp_lookup */
595 netdev_dummy_update_flags
,
597 netdev_dummy_change_seq
600 static const struct netdev_rx_class netdev_rx_dummy_class
= {
601 netdev_rx_dummy_destroy
,
602 netdev_rx_dummy_recv
,
603 netdev_rx_dummy_wait
,
604 netdev_rx_dummy_drain
,
607 static struct ofpbuf
*
608 eth_from_packet_or_flow(const char *s
)
610 enum odp_key_fitness fitness
;
611 struct ofpbuf
*packet
;
612 struct ofpbuf odp_key
;
616 if (!eth_from_hex(s
, &packet
)) {
620 /* Convert string to datapath key.
622 * It would actually be nicer to parse an OpenFlow-like flow key here, but
623 * the code for that currently calls exit() on parse error. We have to
624 * settle for parsing a datapath key for now.
626 ofpbuf_init(&odp_key
, 0);
627 error
= odp_flow_from_string(s
, NULL
, &odp_key
, NULL
);
629 ofpbuf_uninit(&odp_key
);
633 /* Convert odp_key to flow. */
634 fitness
= odp_flow_key_to_flow(odp_key
.data
, odp_key
.size
, &flow
);
635 if (fitness
== ODP_FIT_ERROR
) {
636 ofpbuf_uninit(&odp_key
);
640 packet
= ofpbuf_new(0);
641 flow_compose(packet
, &flow
);
643 ofpbuf_uninit(&odp_key
);
648 netdev_dummy_queue_packet__(struct netdev_rx_dummy
*rx
, struct ofpbuf
*packet
)
650 list_push_back(&rx
->recv_queue
, &packet
->list_node
);
651 rx
->recv_queue_len
++;
655 netdev_dummy_queue_packet(struct netdev_dummy
*dummy
, struct ofpbuf
*packet
)
657 struct netdev_rx_dummy
*rx
, *prev
;
660 LIST_FOR_EACH (rx
, node
, &dummy
->rxes
) {
661 if (rx
->recv_queue_len
< NETDEV_DUMMY_MAX_QUEUE
) {
663 netdev_dummy_queue_packet__(prev
, ofpbuf_clone(packet
));
669 netdev_dummy_queue_packet__(prev
, packet
);
671 ofpbuf_delete(packet
);
676 netdev_dummy_receive(struct unixctl_conn
*conn
,
677 int argc
, const char *argv
[], void *aux OVS_UNUSED
)
679 struct netdev_dummy
*dummy_dev
;
682 dummy_dev
= shash_find_data(&dummy_netdevs
, argv
[1]);
684 unixctl_command_reply_error(conn
, "no such dummy netdev");
688 for (i
= 2; i
< argc
; i
++) {
689 struct ofpbuf
*packet
;
691 packet
= eth_from_packet_or_flow(argv
[i
]);
693 unixctl_command_reply_error(conn
, "bad packet syntax");
697 dummy_dev
->stats
.rx_packets
++;
698 dummy_dev
->stats
.rx_bytes
+= packet
->size
;
700 netdev_dummy_queue_packet(dummy_dev
, packet
);
703 unixctl_command_reply(conn
, NULL
);
707 netdev_dummy_set_admin_state__(struct netdev_dummy
*dev
, bool admin_state
)
709 enum netdev_flags old_flags
;
712 netdev_dummy_update_flags(&dev
->up
, 0, NETDEV_UP
, &old_flags
);
714 netdev_dummy_update_flags(&dev
->up
, NETDEV_UP
, 0, &old_flags
);
719 netdev_dummy_set_admin_state(struct unixctl_conn
*conn
, int argc
,
720 const char *argv
[], void *aux OVS_UNUSED
)
724 if (!strcasecmp(argv
[argc
- 1], "up")) {
726 } else if ( !strcasecmp(argv
[argc
- 1], "down")) {
729 unixctl_command_reply_error(conn
, "Invalid Admin State");
734 struct netdev_dummy
*dummy_dev
;
736 dummy_dev
= shash_find_data(&dummy_netdevs
, argv
[1]);
738 netdev_dummy_set_admin_state__(dummy_dev
, up
);
740 unixctl_command_reply_error(conn
, "Unknown Dummy Interface");
744 struct shash_node
*node
;
746 SHASH_FOR_EACH (node
, &dummy_netdevs
) {
747 netdev_dummy_set_admin_state__(node
->data
, up
);
750 unixctl_command_reply(conn
, "OK");
754 netdev_dummy_register(bool override
)
756 unixctl_command_register("netdev-dummy/receive", "NAME PACKET|FLOW...",
757 2, INT_MAX
, netdev_dummy_receive
, NULL
);
758 unixctl_command_register("netdev-dummy/set-admin-state",
759 "[netdev] up|down", 1, 2,
760 netdev_dummy_set_admin_state
, NULL
);
767 netdev_enumerate_types(&types
);
768 SSET_FOR_EACH (type
, &types
) {
769 if (!netdev_unregister_provider(type
)) {
770 struct netdev_class
*class;
772 class = xmalloc(sizeof *class);
773 *class = dummy_class
;
774 class->type
= xstrdup(type
);
775 netdev_register_provider(class);
778 sset_destroy(&types
);
780 netdev_register_provider(&dummy_class
);
782 netdev_vport_tunnel_register();