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