netdev-dummy: Limit receive queue length to 100 packets.
[sliver-openvswitch.git] / lib / netdev-dummy.c
1 /*
2  * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "dummy.h"
20
21 #include <errno.h>
22
23 #include "flow.h"
24 #include "list.h"
25 #include "netdev-provider.h"
26 #include "netdev-vport.h"
27 #include "odp-util.h"
28 #include "ofp-print.h"
29 #include "ofpbuf.h"
30 #include "packets.h"
31 #include "poll-loop.h"
32 #include "shash.h"
33 #include "sset.h"
34 #include "unixctl.h"
35 #include "vlog.h"
36
37 VLOG_DEFINE_THIS_MODULE(netdev_dummy);
38
39 struct netdev_dummy {
40     struct netdev up;
41     uint8_t hwaddr[ETH_ADDR_LEN];
42     int mtu;
43     struct netdev_stats stats;
44     enum netdev_flags flags;
45     unsigned int change_seq;
46     int ifindex;
47
48     struct list rxes;           /* List of child "netdev_rx_dummy"s. */
49 };
50
51 /* Max 'recv_queue_len' in struct netdev_dummy. */
52 #define NETDEV_DUMMY_MAX_QUEUE 100
53
54 struct netdev_rx_dummy {
55     struct netdev_rx up;
56     struct list node;           /* In netdev_dummy's "rxes" list. */
57     struct list recv_queue;
58     int recv_queue_len;         /* list_size(&recv_queue). */
59     bool listening;
60 };
61
62 static struct shash dummy_netdevs = SHASH_INITIALIZER(&dummy_netdevs);
63
64 static const struct netdev_rx_class netdev_rx_dummy_class;
65
66 static unixctl_cb_func netdev_dummy_set_admin_state;
67 static int netdev_dummy_create(const struct netdev_class *, const char *,
68                                struct netdev **);
69 static void netdev_dummy_poll_notify(struct netdev_dummy *);
70
71 static bool
72 is_dummy_class(const struct netdev_class *class)
73 {
74     return class->create == netdev_dummy_create;
75 }
76
77 static struct netdev_dummy *
78 netdev_dummy_cast(const struct netdev *netdev)
79 {
80     ovs_assert(is_dummy_class(netdev_get_class(netdev)));
81     return CONTAINER_OF(netdev, struct netdev_dummy, up);
82 }
83
84 static struct netdev_rx_dummy *
85 netdev_rx_dummy_cast(const struct netdev_rx *rx)
86 {
87     netdev_rx_assert_class(rx, &netdev_rx_dummy_class);
88     return CONTAINER_OF(rx, struct netdev_rx_dummy, up);
89 }
90
91 static int
92 netdev_dummy_create(const struct netdev_class *class, const char *name,
93                     struct netdev **netdevp)
94 {
95     static unsigned int n = 0xaa550000;
96     struct netdev_dummy *netdev;
97
98     netdev = xzalloc(sizeof *netdev);
99     netdev_init(&netdev->up, name, class);
100     netdev->hwaddr[0] = 0xaa;
101     netdev->hwaddr[1] = 0x55;
102     netdev->hwaddr[2] = n >> 24;
103     netdev->hwaddr[3] = n >> 16;
104     netdev->hwaddr[4] = n >> 8;
105     netdev->hwaddr[5] = n;
106     netdev->mtu = 1500;
107     netdev->flags = 0;
108     netdev->change_seq = 1;
109     netdev->ifindex = -EOPNOTSUPP;
110     list_init(&netdev->rxes);
111
112     shash_add(&dummy_netdevs, name, netdev);
113
114     n++;
115
116     *netdevp = &netdev->up;
117
118     return 0;
119 }
120
121 static void
122 netdev_dummy_destroy(struct netdev *netdev_)
123 {
124     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
125
126     shash_find_and_delete(&dummy_netdevs,
127                           netdev_get_name(netdev_));
128     free(netdev);
129 }
130
131 static int
132 netdev_dummy_get_config(const struct netdev *netdev_, struct smap *args)
133 {
134     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
135
136     if (netdev->ifindex >= 0) {
137         smap_add_format(args, "ifindex", "%d", netdev->ifindex);
138     }
139     return 0;
140 }
141
142 static int
143 netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
144 {
145     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
146
147     netdev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP);
148     return 0;
149 }
150
151 static int
152 netdev_dummy_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
153 {
154     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
155     struct netdev_rx_dummy *rx;
156
157     rx = xmalloc(sizeof *rx);
158     netdev_rx_init(&rx->up, &netdev->up, &netdev_rx_dummy_class);
159     list_push_back(&netdev->rxes, &rx->node);
160     list_init(&rx->recv_queue);
161     rx->recv_queue_len = 0;
162
163     *rxp = &rx->up;
164     return 0;
165 }
166
167 static int
168 netdev_rx_dummy_recv(struct netdev_rx *rx_, void *buffer, size_t size)
169 {
170     struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
171     struct ofpbuf *packet;
172     size_t packet_size;
173
174     if (list_is_empty(&rx->recv_queue)) {
175         return -EAGAIN;
176     }
177
178     packet = ofpbuf_from_list(list_pop_front(&rx->recv_queue));
179     rx->recv_queue_len--;
180     if (packet->size > size) {
181         return -EMSGSIZE;
182     }
183     packet_size = packet->size;
184
185     memcpy(buffer, packet->data, packet->size);
186     ofpbuf_delete(packet);
187
188     return packet_size;
189 }
190
191 static void
192 netdev_rx_dummy_destroy(struct netdev_rx *rx_)
193 {
194     struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
195     list_remove(&rx->node);
196     ofpbuf_list_delete(&rx->recv_queue);
197     free(rx);
198 }
199
200 static void
201 netdev_rx_dummy_wait(struct netdev_rx *rx_)
202 {
203     struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
204     if (!list_is_empty(&rx->recv_queue)) {
205         poll_immediate_wake();
206     }
207 }
208
209 static int
210 netdev_rx_dummy_drain(struct netdev_rx *rx_)
211 {
212     struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
213     ofpbuf_list_delete(&rx->recv_queue);
214     rx->recv_queue_len = 0;
215     return 0;
216 }
217
218 static int
219 netdev_dummy_send(struct netdev *netdev, const void *buffer OVS_UNUSED,
220                   size_t size)
221 {
222     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
223
224     dev->stats.tx_packets++;
225     dev->stats.tx_bytes += size;
226
227     return 0;
228 }
229
230 static int
231 netdev_dummy_set_etheraddr(struct netdev *netdev,
232                            const uint8_t mac[ETH_ADDR_LEN])
233 {
234     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
235
236     if (!eth_addr_equals(dev->hwaddr, mac)) {
237         memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
238         netdev_dummy_poll_notify(dev);
239     }
240
241     return 0;
242 }
243
244 static int
245 netdev_dummy_get_etheraddr(const struct netdev *netdev,
246                            uint8_t mac[ETH_ADDR_LEN])
247 {
248     const struct netdev_dummy *dev = netdev_dummy_cast(netdev);
249
250     memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
251     return 0;
252 }
253
254 static int
255 netdev_dummy_get_mtu(const struct netdev *netdev, int *mtup)
256 {
257     const struct netdev_dummy *dev = netdev_dummy_cast(netdev);
258
259     *mtup = dev->mtu;
260     return 0;
261 }
262
263 static int
264 netdev_dummy_set_mtu(const struct netdev *netdev, int mtu)
265 {
266     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
267
268     dev->mtu = mtu;
269     return 0;
270 }
271
272 static int
273 netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
274 {
275     const struct netdev_dummy *dev = netdev_dummy_cast(netdev);
276
277     *stats = dev->stats;
278     return 0;
279 }
280
281 static int
282 netdev_dummy_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
283 {
284     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
285
286     dev->stats = *stats;
287     return 0;
288 }
289
290 static int
291 netdev_dummy_get_ifindex(const struct netdev *netdev)
292 {
293     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
294
295     return dev->ifindex;
296 }
297
298 static int
299 netdev_dummy_update_flags(struct netdev *netdev_,
300                           enum netdev_flags off, enum netdev_flags on,
301                           enum netdev_flags *old_flagsp)
302 {
303     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
304
305     if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
306         return EINVAL;
307     }
308
309     *old_flagsp = netdev->flags;
310     netdev->flags |= on;
311     netdev->flags &= ~off;
312     if (*old_flagsp != netdev->flags) {
313         netdev_dummy_poll_notify(netdev);
314     }
315     return 0;
316 }
317
318 static unsigned int
319 netdev_dummy_change_seq(const struct netdev *netdev)
320 {
321     return netdev_dummy_cast(netdev)->change_seq;
322 }
323 \f
324 /* Helper functions. */
325
326 static void
327 netdev_dummy_poll_notify(struct netdev_dummy *dev)
328 {
329     dev->change_seq++;
330     if (!dev->change_seq) {
331         dev->change_seq++;
332     }
333 }
334
335 static const struct netdev_class dummy_class = {
336     "dummy",
337     NULL,                       /* init */
338     NULL,                       /* run */
339     NULL,                       /* wait */
340
341     netdev_dummy_create,
342     netdev_dummy_destroy,
343     netdev_dummy_get_config,
344     netdev_dummy_set_config,
345     NULL,                       /* get_tunnel_config */
346
347     netdev_dummy_rx_open,
348
349     netdev_dummy_send,          /* send */
350     NULL,                       /* send_wait */
351
352     netdev_dummy_set_etheraddr,
353     netdev_dummy_get_etheraddr,
354     netdev_dummy_get_mtu,
355     netdev_dummy_set_mtu,
356     netdev_dummy_get_ifindex,
357     NULL,                       /* get_carrier */
358     NULL,                       /* get_carrier_resets */
359     NULL,                       /* get_miimon */
360     netdev_dummy_get_stats,
361     netdev_dummy_set_stats,
362
363     NULL,                       /* get_features */
364     NULL,                       /* set_advertisements */
365
366     NULL,                       /* set_policing */
367     NULL,                       /* get_qos_types */
368     NULL,                       /* get_qos_capabilities */
369     NULL,                       /* get_qos */
370     NULL,                       /* set_qos */
371     NULL,                       /* get_queue */
372     NULL,                       /* set_queue */
373     NULL,                       /* delete_queue */
374     NULL,                       /* get_queue_stats */
375     NULL,                       /* dump_queues */
376     NULL,                       /* dump_queue_stats */
377
378     NULL,                       /* get_in4 */
379     NULL,                       /* set_in4 */
380     NULL,                       /* get_in6 */
381     NULL,                       /* add_router */
382     NULL,                       /* get_next_hop */
383     NULL,                       /* get_status */
384     NULL,                       /* arp_lookup */
385
386     netdev_dummy_update_flags,
387
388     netdev_dummy_change_seq
389 };
390
391 static const struct netdev_rx_class netdev_rx_dummy_class = {
392     netdev_rx_dummy_destroy,
393     netdev_rx_dummy_recv,
394     netdev_rx_dummy_wait,
395     netdev_rx_dummy_drain,
396 };
397
398 static struct ofpbuf *
399 eth_from_packet_or_flow(const char *s)
400 {
401     enum odp_key_fitness fitness;
402     struct ofpbuf *packet;
403     struct ofpbuf odp_key;
404     struct flow flow;
405     int error;
406
407     if (!eth_from_hex(s, &packet)) {
408         return packet;
409     }
410
411     /* Convert string to datapath key.
412      *
413      * It would actually be nicer to parse an OpenFlow-like flow key here, but
414      * the code for that currently calls exit() on parse error.  We have to
415      * settle for parsing a datapath key for now.
416      */
417     ofpbuf_init(&odp_key, 0);
418     error = odp_flow_key_from_string(s, NULL, &odp_key);
419     if (error) {
420         ofpbuf_uninit(&odp_key);
421         return NULL;
422     }
423
424     /* Convert odp_key to flow. */
425     fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
426     if (fitness == ODP_FIT_ERROR) {
427         ofpbuf_uninit(&odp_key);
428         return NULL;
429     }
430
431     packet = ofpbuf_new(0);
432     flow_compose(packet, &flow);
433
434     ofpbuf_uninit(&odp_key);
435     return packet;
436 }
437
438 static void
439 netdev_dummy_receive(struct unixctl_conn *conn,
440                      int argc, const char *argv[], void *aux OVS_UNUSED)
441 {
442     struct netdev_dummy *dummy_dev;
443     int n_listeners;
444     int i;
445
446     dummy_dev = shash_find_data(&dummy_netdevs, argv[1]);
447     if (!dummy_dev) {
448         unixctl_command_reply_error(conn, "no such dummy netdev");
449         return;
450     }
451
452     n_listeners = 0;
453     for (i = 2; i < argc; i++) {
454         struct netdev_rx_dummy *rx;
455         struct ofpbuf *packet;
456
457         packet = eth_from_packet_or_flow(argv[i]);
458         if (!packet) {
459             unixctl_command_reply_error(conn, "bad packet syntax");
460             return;
461         }
462
463         dummy_dev->stats.rx_packets++;
464         dummy_dev->stats.rx_bytes += packet->size;
465
466         n_listeners = 0;
467         LIST_FOR_EACH (rx, node, &dummy_dev->rxes) {
468             if (rx->recv_queue_len < NETDEV_DUMMY_MAX_QUEUE) {
469                 struct ofpbuf *copy = ofpbuf_clone(packet);
470                 list_push_back(&rx->recv_queue, &copy->list_node);
471                 rx->recv_queue_len++;
472             }
473             n_listeners++;
474         }
475         ofpbuf_delete(packet);
476     }
477
478     if (!n_listeners) {
479         unixctl_command_reply(conn, "packets queued but nobody listened");
480     } else {
481         unixctl_command_reply(conn, "success");
482     }
483 }
484
485 static void
486 netdev_dummy_set_admin_state__(struct netdev_dummy *dev, bool admin_state)
487 {
488     enum netdev_flags old_flags;
489
490     if (admin_state) {
491         netdev_dummy_update_flags(&dev->up, 0, NETDEV_UP, &old_flags);
492     } else {
493         netdev_dummy_update_flags(&dev->up, NETDEV_UP, 0, &old_flags);
494     }
495 }
496
497 static void
498 netdev_dummy_set_admin_state(struct unixctl_conn *conn, int argc,
499                              const char *argv[], void *aux OVS_UNUSED)
500 {
501     bool up;
502
503     if (!strcasecmp(argv[argc - 1], "up")) {
504         up = true;
505     } else if ( !strcasecmp(argv[argc - 1], "down")) {
506         up = false;
507     } else {
508         unixctl_command_reply_error(conn, "Invalid Admin State");
509         return;
510     }
511
512     if (argc > 2) {
513         struct netdev_dummy *dummy_dev;
514
515         dummy_dev = shash_find_data(&dummy_netdevs, argv[1]);
516         if (dummy_dev) {
517             netdev_dummy_set_admin_state__(dummy_dev, up);
518         } else {
519             unixctl_command_reply_error(conn, "Unknown Dummy Interface");
520             return;
521         }
522     } else {
523         struct shash_node *node;
524
525         SHASH_FOR_EACH (node, &dummy_netdevs) {
526             netdev_dummy_set_admin_state__(node->data, up);
527         }
528     }
529     unixctl_command_reply(conn, "OK");
530 }
531
532 void
533 netdev_dummy_register(bool override)
534 {
535     unixctl_command_register("netdev-dummy/receive", "NAME PACKET|FLOW...",
536                              2, INT_MAX, netdev_dummy_receive, NULL);
537     unixctl_command_register("netdev-dummy/set-admin-state",
538                              "[netdev] up|down", 1, 2,
539                              netdev_dummy_set_admin_state, NULL);
540
541     if (override) {
542         struct sset types;
543         const char *type;
544
545         sset_init(&types);
546         netdev_enumerate_types(&types);
547         SSET_FOR_EACH (type, &types) {
548             if (!netdev_unregister_provider(type)) {
549                 struct netdev_class *class;
550
551                 class = xmalloc(sizeof *class);
552                 *class = dummy_class;
553                 class->type = xstrdup(type);
554                 netdev_register_provider(class);
555             }
556         }
557         sset_destroy(&types);
558     }
559     netdev_register_provider(&dummy_class);
560
561     netdev_vport_tunnel_register();
562 }