netdev: New Function netdev_change_seq().
[sliver-openvswitch.git] / lib / netdev-dummy.c
1 /*
2  * Copyright (c) 2010 Nicira Networks.
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 "list.h"
24 #include "netdev-provider.h"
25 #include "packets.h"
26 #include "shash.h"
27 #include "vlog.h"
28
29 VLOG_DEFINE_THIS_MODULE(netdev_dummy);
30
31 struct netdev_dummy_notifier {
32     struct netdev_notifier notifier;
33     struct list list_node;
34     struct shash_node *shash_node;
35 };
36
37 struct netdev_dev_dummy {
38     struct netdev_dev netdev_dev;
39     uint8_t hwaddr[ETH_ADDR_LEN];
40     int mtu;
41     struct netdev_stats stats;
42     enum netdev_flags flags;
43     unsigned int change_seq;
44 };
45
46 struct netdev_dummy {
47     struct netdev netdev;
48 };
49
50 static struct shash netdev_dummy_notifiers =
51     SHASH_INITIALIZER(&netdev_dummy_notifiers);
52
53 static int netdev_dummy_create(const struct netdev_class *, const char *,
54                                const struct shash *, struct netdev_dev **);
55 static void netdev_dummy_poll_notify(const struct netdev *);
56
57 static bool
58 is_dummy_class(const struct netdev_class *class)
59 {
60     return class->create == netdev_dummy_create;
61 }
62
63 static struct netdev_dev_dummy *
64 netdev_dev_dummy_cast(const struct netdev_dev *netdev_dev)
65 {
66     assert(is_dummy_class(netdev_dev_get_class(netdev_dev)));
67     return CONTAINER_OF(netdev_dev, struct netdev_dev_dummy, netdev_dev);
68 }
69
70 static struct netdev_dummy *
71 netdev_dummy_cast(const struct netdev *netdev)
72 {
73     struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
74     assert(is_dummy_class(netdev_dev_get_class(netdev_dev)));
75     return CONTAINER_OF(netdev, struct netdev_dummy, netdev);
76 }
77
78 static int
79 netdev_dummy_create(const struct netdev_class *class, const char *name,
80                     const struct shash *args,
81                     struct netdev_dev **netdev_devp)
82 {
83     static unsigned int n = 0xaa550000;
84     struct netdev_dev_dummy *netdev_dev;
85
86     netdev_dev = xzalloc(sizeof *netdev_dev);
87     netdev_dev_init(&netdev_dev->netdev_dev, name, args, class);
88     netdev_dev->hwaddr[0] = 0xaa;
89     netdev_dev->hwaddr[1] = 0x55;
90     netdev_dev->hwaddr[2] = n >> 24;
91     netdev_dev->hwaddr[3] = n >> 16;
92     netdev_dev->hwaddr[4] = n >> 8;
93     netdev_dev->hwaddr[5] = n;
94     netdev_dev->mtu = 1500;
95     netdev_dev->flags = 0;
96     netdev_dev->change_seq = 1;
97
98     n++;
99
100     *netdev_devp = &netdev_dev->netdev_dev;
101
102     return 0;
103 }
104
105 static void
106 netdev_dummy_destroy(struct netdev_dev *netdev_dev_)
107 {
108     struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_);
109
110     free(netdev_dev);
111 }
112
113 static int
114 netdev_dummy_open(struct netdev_dev *netdev_dev_, int ethertype OVS_UNUSED,
115                   struct netdev **netdevp)
116 {
117     struct netdev_dummy *netdev;
118
119     netdev = xmalloc(sizeof *netdev);
120     netdev_init(&netdev->netdev, netdev_dev_);
121
122     *netdevp = &netdev->netdev;
123     return 0;
124 }
125
126 static void
127 netdev_dummy_close(struct netdev *netdev_)
128 {
129     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
130     free(netdev);
131 }
132
133 static int
134 netdev_dummy_set_etheraddr(struct netdev *netdev,
135                            const uint8_t mac[ETH_ADDR_LEN])
136 {
137     struct netdev_dev_dummy *dev =
138         netdev_dev_dummy_cast(netdev_get_dev(netdev));
139
140     if (!eth_addr_equals(dev->hwaddr, mac)) {
141         memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
142         netdev_dummy_poll_notify(netdev);
143     }
144
145     return 0;
146 }
147
148 static int
149 netdev_dummy_get_etheraddr(const struct netdev *netdev,
150                            uint8_t mac[ETH_ADDR_LEN])
151 {
152     const struct netdev_dev_dummy *dev =
153         netdev_dev_dummy_cast(netdev_get_dev(netdev));
154
155     memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
156     return 0;
157 }
158
159 static int
160 netdev_dummy_get_mtu(const struct netdev *netdev, int *mtup)
161 {
162     const struct netdev_dev_dummy *dev =
163         netdev_dev_dummy_cast(netdev_get_dev(netdev));
164
165     *mtup = dev->mtu;
166     return 0;
167 }
168
169 static int
170 netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
171 {
172     const struct netdev_dev_dummy *dev =
173         netdev_dev_dummy_cast(netdev_get_dev(netdev));
174
175     *stats = dev->stats;
176     return 0;
177 }
178
179 static int
180 netdev_dummy_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
181 {
182     struct netdev_dev_dummy *dev =
183         netdev_dev_dummy_cast(netdev_get_dev(netdev));
184
185     dev->stats = *stats;
186     return 0;
187 }
188
189 static int
190 netdev_dummy_update_flags(struct netdev *netdev,
191                           enum netdev_flags off, enum netdev_flags on,
192                           enum netdev_flags *old_flagsp)
193 {
194     struct netdev_dev_dummy *dev =
195         netdev_dev_dummy_cast(netdev_get_dev(netdev));
196
197     if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
198         return EINVAL;
199     }
200
201     *old_flagsp = dev->flags;
202     dev->flags |= on;
203     dev->flags &= ~off;
204     if (*old_flagsp != dev->flags) {
205         netdev_dummy_poll_notify(netdev);
206     }
207     return 0;
208 }
209
210 static int
211 netdev_dummy_poll_add(struct netdev *netdev,
212                       void (*cb)(struct netdev_notifier *), void *aux,
213                       struct netdev_notifier **notifierp)
214 {
215     const char *name = netdev_get_name(netdev);
216     struct netdev_dummy_notifier *notifier;
217     struct list *list;
218     struct shash_node *shash_node;
219
220     shash_node = shash_find_data(&netdev_dummy_notifiers, name);
221     if (!shash_node) {
222         list = xmalloc(sizeof *list);
223         list_init(list);
224         shash_node = shash_add(&netdev_dummy_notifiers, name, list);
225     } else {
226         list = shash_node->data;
227     }
228
229     notifier = xmalloc(sizeof *notifier);
230     netdev_notifier_init(&notifier->notifier, netdev, cb, aux);
231     list_push_back(list, &notifier->list_node);
232     notifier->shash_node = shash_node;
233
234     *notifierp = &notifier->notifier;
235
236     return 0;
237 }
238
239 static void
240 netdev_dummy_poll_remove(struct netdev_notifier *notifier_)
241 {
242     struct netdev_dummy_notifier *notifier =
243         CONTAINER_OF(notifier_, struct netdev_dummy_notifier, notifier);
244
245     struct list *list;
246
247     list = list_remove(&notifier->list_node);
248     if (list_is_empty(list)) {
249         shash_delete(&netdev_dummy_notifiers, notifier->shash_node);
250         free(list);
251     }
252
253     free(notifier);
254 }
255
256 static unsigned int
257 netdev_dummy_change_seq(const struct netdev *netdev)
258 {
259     return netdev_dev_dummy_cast(netdev_get_dev(netdev))->change_seq;
260 }
261 \f
262 /* Helper functions. */
263
264 static void
265 netdev_dummy_poll_notify(const struct netdev *netdev)
266 {
267     const char *name = netdev_get_name(netdev);
268     struct list *list = shash_find_data(&netdev_dummy_notifiers, name);
269     struct netdev_dev_dummy *dev =
270         netdev_dev_dummy_cast(netdev_get_dev(netdev));
271
272     if (list) {
273         struct netdev_dummy_notifier *notifier;
274
275         LIST_FOR_EACH (notifier, list_node, list) {
276             struct netdev_notifier *n = &notifier->notifier;
277             n->cb(n);
278         }
279     }
280
281     dev->change_seq++;
282     if (!dev->change_seq) {
283         dev->change_seq++;
284     }
285 }
286
287 static const struct netdev_class dummy_class = {
288     "dummy",
289     NULL,                       /* init */
290     NULL,                       /* run */
291     NULL,                       /* wait */
292
293     netdev_dummy_create,
294     netdev_dummy_destroy,
295     NULL,
296
297     netdev_dummy_open,
298     netdev_dummy_close,
299
300     NULL,                       /* enumerate */
301
302     NULL,                       /* recv */
303     NULL,                       /* recv_wait */
304     NULL,                       /* drain */
305
306     NULL,                       /* send */
307     NULL,                       /* send_wait */
308
309     netdev_dummy_set_etheraddr,
310     netdev_dummy_get_etheraddr,
311     netdev_dummy_get_mtu,
312     NULL,                       /* get_ifindex */
313     NULL,                       /* get_carrier */
314     NULL,                       /* get_miimon */
315     netdev_dummy_get_stats,
316     netdev_dummy_set_stats,
317
318     NULL,                       /* get_features */
319     NULL,                       /* set_advertisements */
320     NULL,                       /* get_vlan_vid */
321
322     NULL,                       /* set_policing */
323     NULL,                       /* get_qos_types */
324     NULL,                       /* get_qos_capabilities */
325     NULL,                       /* get_qos */
326     NULL,                       /* set_qos */
327     NULL,                       /* get_queue */
328     NULL,                       /* set_queue */
329     NULL,                       /* delete_queue */
330     NULL,                       /* get_queue_stats */
331     NULL,                       /* dump_queues */
332     NULL,                       /* dump_queue_stats */
333
334     NULL,                       /* get_in4 */
335     NULL,                       /* set_in4 */
336     NULL,                       /* get_in6 */
337     NULL,                       /* add_router */
338     NULL,                       /* get_next_hop */
339     NULL,                       /* get_status */
340     NULL,                       /* arp_lookup */
341
342     netdev_dummy_update_flags,
343
344     netdev_dummy_poll_add,
345     netdev_dummy_poll_remove,
346     netdev_dummy_change_seq
347 };
348
349 void
350 netdev_dummy_register(void)
351 {
352     netdev_register_provider(&dummy_class);
353 }