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