Update fake bond devices' statistics with the sum of bond slaves' stats.
[sliver-openvswitch.git] / lib / netdev-gre.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 #include <errno.h>
19 #include <fcntl.h>
20 #include <net/if.h>
21 #include <sys/ioctl.h>
22
23 #include "list.h"
24 #include "netdev-provider.h"
25 #include "openflow/openflow.h"
26 #include "openvswitch/datapath-protocol.h"
27 #include "openvswitch/gre.h"
28 #include "packets.h"
29 #include "shash.h"
30 #include "socket-util.h"
31
32 #define THIS_MODULE VLM_netdev_gre
33 #include "vlog.h"
34
35 struct netdev_dev_gre {
36     struct netdev_dev netdev_dev;
37 };
38
39 struct netdev_gre {
40     struct netdev netdev;
41 };
42
43 struct netdev_gre_notifier {
44     struct netdev_notifier notifier;
45     struct list node;
46 };
47
48 static int ioctl_fd = -1;
49 static struct shash netdev_gre_notifiers =
50                                     SHASH_INITIALIZER(&netdev_gre_notifiers);
51
52 static void poll_notify(const struct netdev_gre *netdev);
53
54 static struct netdev_dev_gre *
55 netdev_dev_gre_cast(const struct netdev_dev *netdev_dev)
56 {
57     netdev_dev_assert_class(netdev_dev, &netdev_gre_class);
58     return CONTAINER_OF(netdev_dev, struct netdev_dev_gre, netdev_dev);
59 }
60
61 static struct netdev_gre *
62 netdev_gre_cast(const struct netdev *netdev)
63 {
64     netdev_assert_class(netdev, &netdev_gre_class);
65     return CONTAINER_OF(netdev, struct netdev_gre, netdev);
66 }
67
68 static int
69 netdev_gre_init(void)
70 {
71     static int status = -1;
72     if (status < 0) {
73         ioctl_fd = open("/dev/net/dp0", O_RDONLY | O_NONBLOCK);
74         status = ioctl_fd >= 0 ? 0 : errno;
75         if (status) {
76             VLOG_ERR("failed to open ioctl fd: %s", strerror(status));
77         }
78     }
79     return status;
80 }
81
82 static int
83 do_ioctl(int cmd, void *arg)
84 {
85     return ioctl(ioctl_fd, cmd, arg) ? errno : 0;
86 }
87
88 static int
89 parse_config(const char *name, const struct shash *args,
90              struct gre_port_config *config)
91 {
92     struct shash_node *node;
93
94     memset(config, 0, sizeof *config);
95
96     config->flags |= GRE_F_IN_CSUM;
97     config->flags |= GRE_F_OUT_CSUM;
98     config->flags |= GRE_F_PMTUD;
99
100     SHASH_FOR_EACH (node, args) {
101         if (!strcmp(node->name, "remote_ip")) {
102             struct in_addr in_addr;
103             if (lookup_ip(node->data, &in_addr)) {
104                 VLOG_WARN("%s: bad gre 'remote_ip'", name);
105             } else {
106                 config->daddr = in_addr.s_addr;
107             }
108         } else if (!strcmp(node->name, "local_ip")) {
109             struct in_addr in_addr;
110             if (lookup_ip(node->data, &in_addr)) {
111                 VLOG_WARN("%s: bad gre 'local_ip'", name);
112             } else {
113                 config->saddr = in_addr.s_addr;
114             }
115         } else if (!strcmp(node->name, "key")) {
116             if (!strcmp(node->data, "flow")) {
117                 config->flags |= GRE_F_IN_KEY_MATCH;
118                 config->flags |= GRE_F_OUT_KEY_ACTION;
119             } else {
120                 config->out_key = config->in_key = htonl(atoi(node->data));
121             }
122         } else if (!strcmp(node->name, "in_key")) {
123             if (!strcmp(node->data, "flow")) {
124                 config->flags |= GRE_F_IN_KEY_MATCH;
125             } else {
126                 config->in_key = htonl(atoi(node->data));
127             }
128         } else if (!strcmp(node->name, "out_key")) {
129             if (!strcmp(node->data, "flow")) {
130                 config->flags |= GRE_F_OUT_KEY_ACTION;
131             } else {
132                 config->out_key = htonl(atoi(node->data));
133             }
134         } else if (!strcmp(node->name, "tos")) {
135             if (!strcmp(node->data, "inherit")) {
136                 config->flags |= GRE_F_TOS_INHERIT;
137             } else {
138                 config->tos = atoi(node->data);
139             }
140         } else if (!strcmp(node->name, "ttl")) {
141             if (!strcmp(node->data, "inherit")) {
142                 config->flags |= GRE_F_TTL_INHERIT;
143             } else {
144                 config->ttl = atoi(node->data);
145             }
146         } else if (!strcmp(node->name, "csum")) {
147             if (!strcmp(node->data, "false")) {
148                 config->flags &= ~GRE_F_IN_CSUM;
149                 config->flags &= ~GRE_F_OUT_CSUM;
150             }
151         } else if (!strcmp(node->name, "pmtud")) {
152             if (!strcmp(node->data, "false")) {
153                 config->flags &= ~GRE_F_PMTUD;
154             }
155         } else {
156             VLOG_WARN("%s: unknown gre argument '%s'", name, node->name);
157         }
158     }
159
160     if (!config->daddr) {
161         VLOG_WARN("%s: gre type requires valid 'remote_ip' argument", name);
162         return EINVAL;
163     }
164
165     return 0;
166 }
167
168 static int
169 netdev_gre_create(const char *name, const char *type OVS_UNUSED,
170                   const struct shash *args, struct netdev_dev **netdev_devp)
171 {
172     int err;
173     struct odp_vport_add ova;
174     struct gre_port_config port_config;
175     struct netdev_dev_gre *netdev_dev;
176
177     ovs_strlcpy(ova.port_type, "gre", sizeof ova.port_type);
178     ovs_strlcpy(ova.devname, name, sizeof ova.devname);
179     ova.config = &port_config;
180
181     err = parse_config(name, args, &port_config);
182     if (err) {
183         return err;
184     }
185
186     err = do_ioctl(ODP_VPORT_ADD, &ova);
187     if (err == EEXIST) {
188         VLOG_WARN("%s: destroying existing device", name);
189
190         err = do_ioctl(ODP_VPORT_DEL, ova.devname);
191         if (err) {
192             return err;
193         }
194
195         err = do_ioctl(ODP_VPORT_ADD, &ova);
196     }
197
198     if (err) {
199         return err;
200     }
201
202     netdev_dev = xmalloc(sizeof *netdev_dev);
203     netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_gre_class);
204
205     *netdev_devp = &netdev_dev->netdev_dev;
206     return 0;
207 }
208
209 static int
210 netdev_gre_reconfigure(struct netdev_dev *netdev_dev_, const struct shash *args)
211 {
212     const char *name = netdev_dev_get_name(netdev_dev_);
213     struct odp_vport_mod ovm;
214     struct gre_port_config port_config;
215     int err;
216
217     ovs_strlcpy(ovm.devname, name, sizeof ovm.devname);
218     ovm.config = &port_config;
219
220     err = parse_config(name, args, &port_config);
221     if (err) {
222         return err;
223     }
224
225     return do_ioctl(ODP_VPORT_MOD, &ovm);
226 }
227
228 static void
229 netdev_gre_destroy(struct netdev_dev *netdev_dev_)
230 {
231     struct netdev_dev_gre *netdev_dev = netdev_dev_gre_cast(netdev_dev_);
232
233     do_ioctl(ODP_VPORT_DEL, (char *)netdev_dev_get_name(netdev_dev_));
234     free(netdev_dev);
235 }
236
237 static int
238 netdev_gre_open(struct netdev_dev *netdev_dev_, int ethertype OVS_UNUSED,
239                 struct netdev **netdevp)
240 {
241     struct netdev_gre *netdev;
242
243     netdev = xmalloc(sizeof *netdev);
244     netdev_init(&netdev->netdev, netdev_dev_);
245
246     *netdevp = &netdev->netdev;
247     return 0;
248 }
249
250 static void
251 netdev_gre_close(struct netdev *netdev_)
252 {
253     struct netdev_gre *netdev = netdev_gre_cast(netdev_);
254     free(netdev);
255 }
256
257 static int
258 netdev_gre_set_etheraddr(struct netdev *netdev_,
259                          const uint8_t mac[ETH_ADDR_LEN])
260 {
261     struct netdev_gre *netdev = netdev_gre_cast(netdev_);
262     struct odp_vport_ether vport_ether;
263     int err;
264
265     ovs_strlcpy(vport_ether.devname, netdev_get_name(netdev_),
266                 sizeof vport_ether.devname);
267
268     memcpy(vport_ether.ether_addr, mac, ETH_ADDR_LEN);
269
270     err = ioctl(ioctl_fd, ODP_VPORT_ETHER_SET, &vport_ether);
271     if (err) {
272         return err;
273     }
274
275     poll_notify(netdev);
276     return 0;
277 }
278
279 static int
280 netdev_gre_get_etheraddr(const struct netdev *netdev_,
281                          uint8_t mac[ETH_ADDR_LEN])
282 {
283     struct odp_vport_ether vport_ether;
284     int err;
285
286     ovs_strlcpy(vport_ether.devname, netdev_get_name(netdev_),
287                 sizeof vport_ether.devname);
288
289     err = ioctl(ioctl_fd, ODP_VPORT_ETHER_GET, &vport_ether);
290     if (err) {
291         return err;
292     }
293
294     memcpy(mac, vport_ether.ether_addr, ETH_ADDR_LEN);
295     return 0;
296 }
297
298 static int
299 netdev_gre_get_mtu(const struct netdev *netdev_, int *mtup)
300 {
301     struct odp_vport_mtu vport_mtu;
302     int err;
303
304     ovs_strlcpy(vport_mtu.devname, netdev_get_name(netdev_),
305                 sizeof vport_mtu.devname);
306
307     err = ioctl(ioctl_fd, ODP_VPORT_MTU_GET, &vport_mtu);
308     if (err) {
309         return err;
310     }
311
312     *mtup = vport_mtu.mtu;
313     return 0;
314 }
315
316 static int
317 netdev_gre_get_carrier(const struct netdev *netdev OVS_UNUSED, bool *carrier)
318 {
319     *carrier = true;
320     return 0;
321 }
322
323 static int
324 netdev_gre_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
325 {
326     const char *name = netdev_get_name(netdev_);
327     struct odp_vport_stats_req ovsr;
328     int err;
329
330     ovs_strlcpy(ovsr.devname, name, sizeof ovsr.devname);
331     err = do_ioctl(ODP_VPORT_STATS_GET, &ovsr);
332     if (err) {
333         return err;
334     }
335
336     stats->rx_packets = ovsr.stats.rx_packets;
337     stats->tx_packets = ovsr.stats.tx_packets;
338     stats->rx_bytes = ovsr.stats.rx_bytes;
339     stats->tx_bytes = ovsr.stats.tx_bytes;
340     stats->rx_errors = ovsr.stats.rx_errors;
341     stats->tx_errors = ovsr.stats.tx_errors;
342     stats->rx_dropped = ovsr.stats.rx_dropped;
343     stats->tx_dropped = ovsr.stats.tx_dropped;
344     stats->multicast = UINT64_MAX;
345     stats->collisions = ovsr.stats.collisions;
346     stats->rx_length_errors = UINT64_MAX;
347     stats->rx_over_errors = ovsr.stats.rx_over_err;
348     stats->rx_crc_errors = ovsr.stats.rx_crc_err;
349     stats->rx_frame_errors = ovsr.stats.rx_frame_err;
350     stats->rx_fifo_errors = UINT64_MAX;
351     stats->rx_missed_errors = UINT64_MAX;
352     stats->tx_aborted_errors = UINT64_MAX;
353     stats->tx_carrier_errors = UINT64_MAX;
354     stats->tx_fifo_errors = UINT64_MAX;
355     stats->tx_heartbeat_errors = UINT64_MAX;
356     stats->tx_window_errors = UINT64_MAX;
357
358     return 0;
359 }
360
361 static int
362 netdev_gre_update_flags(struct netdev *netdev OVS_UNUSED,
363                         enum netdev_flags off, enum netdev_flags on OVS_UNUSED,
364                         enum netdev_flags *old_flagsp)
365 {
366     if (off & (NETDEV_UP | NETDEV_PROMISC)) {
367         return EOPNOTSUPP;
368     }
369
370     *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
371     return 0;
372 }
373
374 static int
375 netdev_gre_poll_add(struct netdev *netdev, void (*cb)(struct netdev_notifier *),
376                     void *aux, struct netdev_notifier **notifierp)
377 {
378     const char *netdev_name = netdev_get_name(netdev);
379     struct netdev_gre_notifier *notifier;
380     struct list *list;
381
382     list = shash_find_data(&netdev_gre_notifiers, netdev_name);
383     if (!list) {
384         list = xmalloc(sizeof *list);
385         list_init(list);
386         shash_add(&netdev_gre_notifiers, netdev_name, list);
387     }
388
389     notifier = xmalloc(sizeof *notifier);
390     netdev_notifier_init(&notifier->notifier, netdev, cb, aux);
391     list_push_back(list, &notifier->node);
392
393     *notifierp = &notifier->notifier;
394     return 0;
395 }
396
397 static void
398 netdev_gre_poll_remove(struct netdev_notifier *notifier_)
399 {
400     struct netdev_gre_notifier *notifier =
401                 CONTAINER_OF(notifier_, struct netdev_gre_notifier, notifier);
402     struct list *list;
403
404     list = list_remove(&notifier->node);
405     if (list_is_empty(list)) {
406         const char *netdev_name = netdev_get_name(notifier_->netdev);
407         shash_delete(&netdev_gre_notifiers,
408                      shash_find(&netdev_gre_notifiers, netdev_name));
409         free(list);
410     }
411     free(notifier);
412 }
413
414 static void
415 poll_notify(const struct netdev_gre *netdev)
416 {
417     struct list *list = shash_find_data(&netdev_gre_notifiers,
418                                         netdev_get_name(&netdev->netdev));
419
420     if (list) {
421         struct netdev_gre_notifier *notifier;
422
423         LIST_FOR_EACH (notifier, struct netdev_gre_notifier, node, list) {
424             struct netdev_notifier *n = &notifier->notifier;
425             n->cb(n);
426         }
427     }
428 }
429
430 const struct netdev_class netdev_gre_class = {
431     "gre",
432
433     netdev_gre_init,
434     NULL,                       /* run */
435     NULL,                       /* wait */
436
437     netdev_gre_create,
438     netdev_gre_destroy,
439     netdev_gre_reconfigure,
440
441     netdev_gre_open,
442     netdev_gre_close,
443
444     NULL,                       /* enumerate */
445
446     NULL,                       /* recv */
447     NULL,                       /* recv_wait */
448     NULL,                       /* drain */
449
450     NULL,                       /* send */
451     NULL,                       /* send_wait */
452
453     netdev_gre_set_etheraddr,
454     netdev_gre_get_etheraddr,
455     netdev_gre_get_mtu,
456     NULL,                       /* get_ifindex */
457     netdev_gre_get_carrier,
458     netdev_gre_get_stats,
459     NULL,                       /* set_stats */
460
461     NULL,                       /* get_features */
462     NULL,                       /* set_advertisements */
463     NULL,                       /* get_vlan_vid */
464     NULL,                       /* set_policing */
465
466     NULL,                       /* get_in4 */
467     NULL,                       /* set_in4 */
468     NULL,                       /* get_in6 */
469     NULL,                       /* add_router */
470     NULL,                       /* get_next_hop */
471     NULL,                       /* arp_lookup */
472
473     netdev_gre_update_flags,
474
475     netdev_gre_poll_add,
476     netdev_gre_poll_remove,
477 };