417349d8d768dfac6c44bcefcb93594d0d904bbe
[sliver-openvswitch.git] / lib / dpif-linux.c
1 /*
2  * Copyright (c) 2008, 2009 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 "dpif.h"
19
20 #include <assert.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <net/if.h>
26 #include <linux/ethtool.h>
27 #include <linux/rtnetlink.h>
28 #include <linux/sockios.h>
29 #include <stdlib.h>
30 #include <sys/ioctl.h>
31 #include <unistd.h>
32
33 #include "dpif-provider.h"
34 #include "netdev-linux.h"
35 #include "ofpbuf.h"
36 #include "poll-loop.h"
37 #include "svec.h"
38 #include "util.h"
39
40 #include "vlog.h"
41 #define THIS_MODULE VLM_dpif_linux
42
43 /* Datapath interface for the openvswitch Linux kernel module. */
44 struct dpif_linux {
45     struct dpif dpif;
46     int fd;
47
48     /* Change notification. */
49     int local_ifindex;          /* Ifindex of local port. */
50     struct svec changed_ports;  /* Ports that have changed. */
51     struct linux_netdev_notifier port_notifier;
52 };
53
54 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
55
56 static int do_ioctl(const struct dpif *, int cmd, const void *arg);
57 static int lookup_minor(const char *name, int *minor);
58 static int finish_open(struct dpif *, const char *local_ifname);
59 static int create_minor(const char *name, int minor, struct dpif **dpifp);
60 static int open_minor(int minor, struct dpif **dpifp);
61 static int make_openvswitch_device(int minor, char **fnp);
62 static void dpif_linux_port_changed(const struct linux_netdev_change *,
63                                     void *dpif);
64
65 static struct dpif_linux *
66 dpif_linux_cast(const struct dpif *dpif)
67 {
68     dpif_assert_class(dpif, &dpif_linux_class);
69     return CONTAINER_OF(dpif, struct dpif_linux, dpif);
70 }
71
72 static void
73 dpif_linux_run(void)
74 {
75     linux_netdev_notifier_run();
76 }
77
78 static void
79 dpif_linux_wait(void)
80 {
81     linux_netdev_notifier_wait();
82 }
83
84 static int
85 dpif_linux_open(const char *name UNUSED, char *suffix, bool create,
86                 struct dpif **dpifp)
87 {
88     int minor;
89
90     minor = !strncmp(name, "dp", 2) && isdigit(name[2]) ? atoi(name + 2) : -1;
91     if (create) {
92         if (minor >= 0) {
93             return create_minor(suffix, minor, dpifp);
94         } else {
95             /* Scan for unused minor number. */
96             for (minor = 0; minor < ODP_MAX; minor++) {
97                 int error = create_minor(suffix, minor, dpifp);
98                 if (error != EBUSY) {
99                     return error;
100                 }
101             }
102
103             /* All datapath numbers in use. */
104             return ENOBUFS;
105         }
106     } else {
107         struct dpif_linux *dpif;
108         struct odp_port port;
109         int error;
110
111         if (minor < 0) {
112             error = lookup_minor(suffix, &minor);
113             if (error) {
114                 return error;
115             }
116         }
117
118         error = open_minor(minor, dpifp);
119         if (error) {
120             return error;
121         }
122         dpif = dpif_linux_cast(*dpifp);
123
124         /* We need the local port's ifindex for the poll function.  Start by
125          * getting the local port's name. */
126         memset(&port, 0, sizeof port);
127         port.port = ODPP_LOCAL;
128         if (ioctl(dpif->fd, ODP_PORT_QUERY, &port)) {
129             error = errno;
130             if (error != ENODEV) {
131                 VLOG_WARN("%s: probe returned unexpected error: %s",
132                           dpif_name(*dpifp), strerror(error));
133             }
134             dpif_close(*dpifp);
135             return error;
136         }
137
138         /* Then use that to finish up opening. */
139         return finish_open(&dpif->dpif, port.devname);
140     }
141 }
142
143 static void
144 dpif_linux_close(struct dpif *dpif_)
145 {
146     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
147     linux_netdev_notifier_unregister(&dpif->port_notifier);
148     svec_destroy(&dpif->changed_ports);
149     close(dpif->fd);
150     free(dpif);
151 }
152
153 static int
154 dpif_linux_delete(struct dpif *dpif_)
155 {
156     return do_ioctl(dpif_, ODP_DP_DESTROY, NULL);
157 }
158
159 static int
160 dpif_linux_get_stats(const struct dpif *dpif_, struct odp_stats *stats)
161 {
162     return do_ioctl(dpif_, ODP_DP_STATS, stats);
163 }
164
165 static int
166 dpif_linux_get_drop_frags(const struct dpif *dpif_, bool *drop_fragsp)
167 {
168     int drop_frags;
169     int error;
170
171     error = do_ioctl(dpif_, ODP_GET_DROP_FRAGS, &drop_frags);
172     if (!error) {
173         *drop_fragsp = drop_frags & 1;
174     }
175     return error;
176 }
177
178 static int
179 dpif_linux_set_drop_frags(struct dpif *dpif_, bool drop_frags)
180 {
181     int drop_frags_int = drop_frags;
182     return do_ioctl(dpif_, ODP_SET_DROP_FRAGS, &drop_frags_int);
183 }
184
185 static int
186 dpif_linux_port_add(struct dpif *dpif_, const char *devname, uint16_t flags,
187                     uint16_t *port_no)
188 {
189     struct odp_port port;
190     int error;
191
192     memset(&port, 0, sizeof port);
193     strncpy(port.devname, devname, sizeof port.devname);
194     port.flags = flags;
195     error = do_ioctl(dpif_, ODP_PORT_ADD, &port);
196     if (!error) {
197         *port_no = port.port;
198     }
199     return error;
200 }
201
202 static int
203 dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no)
204 {
205     int tmp = port_no;
206     return do_ioctl(dpif_, ODP_PORT_DEL, &tmp);
207 }
208
209 static int
210 dpif_linux_port_query_by_number(const struct dpif *dpif_, uint16_t port_no,
211                           struct odp_port *port)
212 {
213     memset(port, 0, sizeof *port);
214     port->port = port_no;
215     return do_ioctl(dpif_, ODP_PORT_QUERY, port);
216 }
217
218 static int
219 dpif_linux_port_query_by_name(const struct dpif *dpif_, const char *devname,
220                               struct odp_port *port)
221 {
222     memset(port, 0, sizeof *port);
223     strncpy(port->devname, devname, sizeof port->devname);
224     return do_ioctl(dpif_, ODP_PORT_QUERY, port);
225 }
226
227 static int
228 dpif_linux_flow_flush(struct dpif *dpif_)
229 {
230     return do_ioctl(dpif_, ODP_FLOW_FLUSH, NULL);
231 }
232
233 static int
234 dpif_linux_port_list(const struct dpif *dpif_, struct odp_port *ports, int n)
235 {
236     struct odp_portvec pv;
237     int error;
238
239     pv.ports = ports;
240     pv.n_ports = n;
241     error = do_ioctl(dpif_, ODP_PORT_LIST, &pv);
242     return error ? -error : pv.n_ports;
243 }
244
245 static int
246 dpif_linux_port_poll(const struct dpif *dpif_, char **devnamep)
247 {
248     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
249     int error;
250
251     error = linux_netdev_notifier_get_error(&dpif->port_notifier);
252     if (!error) {
253         if (!dpif->changed_ports.n) {
254             return EAGAIN;
255         }
256         *devnamep = dpif->changed_ports.names[--dpif->changed_ports.n];
257     } else {
258         svec_clear(&dpif->changed_ports);
259     }
260     return error;
261 }
262
263 static void
264 dpif_linux_port_poll_wait(const struct dpif *dpif_)
265 {
266     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
267     if (dpif->changed_ports.n
268         || linux_netdev_notifier_peek_error(&dpif->port_notifier)) {
269         poll_immediate_wake();
270     } else {
271         linux_netdev_notifier_wait();
272     }
273 }
274
275 static int
276 dpif_linux_port_group_get(const struct dpif *dpif_, int group,
277                           uint16_t ports[], int n)
278 {
279     struct odp_port_group pg;
280     int error;
281
282     assert(n <= UINT16_MAX);
283     pg.group = group;
284     pg.ports = ports;
285     pg.n_ports = n;
286     error = do_ioctl(dpif_, ODP_PORT_GROUP_GET, &pg);
287     return error ? -error : pg.n_ports;
288 }
289
290 static int
291 dpif_linux_port_group_set(struct dpif *dpif_, int group,
292                           const uint16_t ports[], int n)
293 {
294     struct odp_port_group pg;
295
296     assert(n <= UINT16_MAX);
297     pg.group = group;
298     pg.ports = (uint16_t *) ports;
299     pg.n_ports = n;
300     return do_ioctl(dpif_, ODP_PORT_GROUP_SET, &pg);
301 }
302
303 static int
304 dpif_linux_flow_get(const struct dpif *dpif_, struct odp_flow flows[], int n)
305 {
306     struct odp_flowvec fv;
307     fv.flows = flows;
308     fv.n_flows = n;
309     return do_ioctl(dpif_, ODP_FLOW_GET, &fv);
310 }
311
312 static int
313 dpif_linux_flow_put(struct dpif *dpif_, struct odp_flow_put *put)
314 {
315     return do_ioctl(dpif_, ODP_FLOW_PUT, put);
316 }
317
318 static int
319 dpif_linux_flow_del(struct dpif *dpif_, struct odp_flow *flow)
320 {
321     return do_ioctl(dpif_, ODP_FLOW_DEL, flow);
322 }
323
324 static int
325 dpif_linux_flow_list(const struct dpif *dpif_, struct odp_flow flows[], int n)
326 {
327     struct odp_flowvec fv;
328     int error;
329
330     fv.flows = flows;
331     fv.n_flows = n;
332     error = do_ioctl(dpif_, ODP_FLOW_LIST, &fv);
333     return error ? -error : fv.n_flows;
334 }
335
336 static int
337 dpif_linux_execute(struct dpif *dpif_, uint16_t in_port,
338                    const union odp_action actions[], int n_actions,
339                    const struct ofpbuf *buf)
340 {
341     struct odp_execute execute;
342     memset(&execute, 0, sizeof execute);
343     execute.in_port = in_port;
344     execute.actions = (union odp_action *) actions;
345     execute.n_actions = n_actions;
346     execute.data = buf->data;
347     execute.length = buf->size;
348     return do_ioctl(dpif_, ODP_EXECUTE, &execute);
349 }
350
351 static int
352 dpif_linux_recv_get_mask(const struct dpif *dpif_, int *listen_mask)
353 {
354     return do_ioctl(dpif_, ODP_GET_LISTEN_MASK, listen_mask);
355 }
356
357 static int
358 dpif_linux_recv_set_mask(struct dpif *dpif_, int listen_mask)
359 {
360     return do_ioctl(dpif_, ODP_SET_LISTEN_MASK, &listen_mask);
361 }
362
363 static int
364 dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp)
365 {
366     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
367     struct ofpbuf *buf;
368     int retval;
369     int error;
370
371     buf = ofpbuf_new(65536);
372     retval = read(dpif->fd, ofpbuf_tail(buf), ofpbuf_tailroom(buf));
373     if (retval < 0) {
374         error = errno;
375         if (error != EAGAIN) {
376             VLOG_WARN_RL(&error_rl, "%s: read failed: %s",
377                          dpif_name(dpif_), strerror(error));
378         }
379     } else if (retval >= sizeof(struct odp_msg)) {
380         struct odp_msg *msg = buf->data;
381         if (msg->length <= retval) {
382             buf->size += retval;
383             *bufp = buf;
384             return 0;
385         } else {
386             VLOG_WARN_RL(&error_rl, "%s: discarding message truncated "
387                          "from %zu bytes to %d",
388                          dpif_name(dpif_), msg->length, retval);
389             error = ERANGE;
390         }
391     } else if (!retval) {
392         VLOG_WARN_RL(&error_rl, "%s: unexpected end of file", dpif_name(dpif_));
393         error = EPROTO;
394     } else {
395         VLOG_WARN_RL(&error_rl,
396                      "%s: discarding too-short message (%d bytes)",
397                      dpif_name(dpif_), retval);
398         error = ERANGE;
399     }
400
401     *bufp = NULL;
402     ofpbuf_delete(buf);
403     return error;
404 }
405
406 static void
407 dpif_linux_recv_wait(struct dpif *dpif_)
408 {
409     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
410     poll_fd_wait(dpif->fd, POLLIN);
411 }
412
413 const struct dpif_class dpif_linux_class = {
414     "",                         /* This is the default class. */
415     "linux",
416     dpif_linux_run,
417     dpif_linux_wait,
418     dpif_linux_open,
419     dpif_linux_close,
420     dpif_linux_delete,
421     dpif_linux_get_stats,
422     dpif_linux_get_drop_frags,
423     dpif_linux_set_drop_frags,
424     dpif_linux_port_add,
425     dpif_linux_port_del,
426     dpif_linux_port_query_by_number,
427     dpif_linux_port_query_by_name,
428     dpif_linux_port_list,
429     dpif_linux_port_poll,
430     dpif_linux_port_poll_wait,
431     dpif_linux_port_group_get,
432     dpif_linux_port_group_set,
433     dpif_linux_flow_get,
434     dpif_linux_flow_put,
435     dpif_linux_flow_del,
436     dpif_linux_flow_flush,
437     dpif_linux_flow_list,
438     dpif_linux_execute,
439     dpif_linux_recv_get_mask,
440     dpif_linux_recv_set_mask,
441     dpif_linux_recv,
442     dpif_linux_recv_wait,
443 };
444 \f
445 static int get_openvswitch_major(void);
446 static int get_major(const char *target, int default_major);
447
448 static int
449 do_ioctl(const struct dpif *dpif_, int cmd, const void *arg)
450 {
451     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
452     return ioctl(dpif->fd, cmd, arg) ? errno : 0;
453 }
454
455 static int
456 lookup_minor(const char *name, int *minor)
457 {
458     struct ethtool_drvinfo drvinfo;
459     struct ifreq ifr;
460     int error;
461     int sock;
462
463     sock = socket(AF_INET, SOCK_DGRAM, 0);
464     if (sock < 0) {
465         VLOG_WARN("socket(AF_INET) failed: %s", strerror(errno));
466         error = errno;
467         goto error;
468     }
469
470     memset(&ifr, 0, sizeof ifr);
471     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
472     ifr.ifr_data = (caddr_t) &drvinfo;
473
474     memset(&drvinfo, 0, sizeof drvinfo);
475     drvinfo.cmd = ETHTOOL_GDRVINFO;
476     if (ioctl(sock, SIOCETHTOOL, &ifr)) {
477         VLOG_WARN("ioctl(SIOCETHTOOL) failed: %s", strerror(errno));
478         error = errno;
479         goto error_close_sock;
480     }
481
482     if (strcmp(drvinfo.driver, "openvswitch")) {
483         VLOG_WARN("%s is not an openvswitch device", name);
484         error = EOPNOTSUPP;
485         goto error_close_sock;
486     }
487
488     if (!isdigit(drvinfo.bus_info[0])) {
489         VLOG_WARN("%s ethtool info does not contain an openvswitch minor",
490                   name);
491         error = EPROTOTYPE;
492         goto error_close_sock;
493     }
494
495     *minor = atoi(drvinfo.bus_info);
496     close(sock);
497     return 0;
498
499 error_close_sock:
500     close(sock);
501 error:
502     return error;
503 }
504
505 static int
506 make_openvswitch_device(int minor, char **fnp)
507 {
508     dev_t dev = makedev(get_openvswitch_major(), minor);
509     const char dirname[] = "/dev/net";
510     struct stat s;
511     char fn[128];
512
513     *fnp = NULL;
514     sprintf(fn, "%s/dp%d", dirname, minor);
515     if (!stat(fn, &s)) {
516         if (!S_ISCHR(s.st_mode)) {
517             VLOG_WARN_RL(&error_rl, "%s is not a character device, fixing",
518                          fn);
519         } else if (s.st_rdev != dev) {
520             VLOG_WARN_RL(&error_rl,
521                          "%s is device %u:%u instead of %u:%u, fixing",
522                          fn, major(s.st_rdev), minor(s.st_rdev),
523                          major(dev), minor(dev));
524         } else {
525             goto success;
526         }
527         if (unlink(fn)) {
528             VLOG_WARN_RL(&error_rl, "%s: unlink failed (%s)",
529                          fn, strerror(errno));
530             return errno;
531         }
532     } else if (errno == ENOENT) {
533         if (stat(dirname, &s)) {
534             if (errno == ENOENT) {
535                 if (mkdir(dirname, 0755)) {
536                     VLOG_WARN_RL(&error_rl, "%s: mkdir failed (%s)",
537                                  dirname, strerror(errno));
538                     return errno;
539                 }
540             } else {
541                 VLOG_WARN_RL(&error_rl, "%s: stat failed (%s)",
542                              dirname, strerror(errno));
543                 return errno;
544             }
545         }
546     } else {
547         VLOG_WARN_RL(&error_rl, "%s: stat failed (%s)", fn, strerror(errno));
548         return errno;
549     }
550
551     /* The device needs to be created. */
552     if (mknod(fn, S_IFCHR | 0700, dev)) {
553         VLOG_WARN_RL(&error_rl,
554                      "%s: creating character device %u:%u failed (%s)",
555                      fn, major(dev), minor(dev), strerror(errno));
556         return errno;
557     }
558
559 success:
560     *fnp = xstrdup(fn);
561     return 0;
562 }
563
564
565 static int
566 get_openvswitch_major(void)
567 {
568     static unsigned int openvswitch_major;
569     if (!openvswitch_major) {
570         enum { DEFAULT_MAJOR = 248 };
571         openvswitch_major = get_major("openvswitch", DEFAULT_MAJOR);
572     }
573     return openvswitch_major;
574 }
575
576 static int
577 get_major(const char *target, int default_major)
578 {
579     const char fn[] = "/proc/devices";
580     char line[128];
581     FILE *file;
582     int ln;
583
584     file = fopen(fn, "r");
585     if (!file) {
586         VLOG_ERR("opening %s failed (%s)", fn, strerror(errno));
587         goto error;
588     }
589
590     for (ln = 1; fgets(line, sizeof line, file); ln++) {
591         char name[64];
592         int major;
593
594         if (!strncmp(line, "Character", 9) || line[0] == '\0') {
595             /* Nothing to do. */
596         } else if (!strncmp(line, "Block", 5)) {
597             /* We only want character devices, so skip the rest of the file. */
598             break;
599         } else if (sscanf(line, "%d %63s", &major, name)) {
600             if (!strcmp(name, target)) {
601                 fclose(file);
602                 return major;
603             }
604         } else {
605             static bool warned;
606             if (!warned) {
607                 VLOG_WARN("%s:%d: syntax error", fn, ln);
608             }
609             warned = true;
610         }
611     }
612
613     VLOG_ERR("%s: %s major not found (is the module loaded?), using "
614              "default major %d", fn, target, default_major);
615 error:
616     VLOG_INFO("using default major %d for %s", default_major, target);
617     return default_major;
618 }
619
620 static int
621 finish_open(struct dpif *dpif_, const char *local_ifname)
622 {
623     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
624     dpif->local_ifindex = if_nametoindex(local_ifname);
625     if (!dpif->local_ifindex) {
626         int error = errno;
627         dpif_close(dpif_);
628         VLOG_WARN("could not get ifindex of %s device: %s",
629                   local_ifname, strerror(errno));
630         return error;
631     }
632     return 0;
633 }
634
635 static int
636 create_minor(const char *name, int minor, struct dpif **dpifp)
637 {
638     int error = open_minor(minor, dpifp);
639     if (!error) {
640         error = do_ioctl(*dpifp, ODP_DP_CREATE, name);
641         if (!error) {
642             error = finish_open(*dpifp, name);
643         } else {
644             dpif_close(*dpifp);
645         }
646     }
647     return error;
648 }
649
650 static int
651 open_minor(int minor, struct dpif **dpifp)
652 {
653     int error;
654     char *fn;
655     int fd;
656
657     error = make_openvswitch_device(minor, &fn);
658     if (error) {
659         return error;
660     }
661
662     fd = open(fn, O_RDONLY | O_NONBLOCK);
663     if (fd >= 0) {
664         struct dpif_linux *dpif = xmalloc(sizeof *dpif);
665         error = linux_netdev_notifier_register(&dpif->port_notifier,
666                                                dpif_linux_port_changed, dpif);
667         if (!error) {
668             char *name;
669
670             name = xasprintf("dp%d", minor);
671             dpif_init(&dpif->dpif, &dpif_linux_class, name, minor, minor);
672             free(name);
673
674             dpif->fd = fd;
675             dpif->local_ifindex = 0;
676             svec_init(&dpif->changed_ports);
677             *dpifp = &dpif->dpif;
678         } else {
679             free(dpif);
680         }
681     } else {
682         error = errno;
683         VLOG_WARN("%s: open failed (%s)", fn, strerror(error));
684     }
685     free(fn);
686
687     return error;
688 }
689
690 static void
691 dpif_linux_port_changed(const struct linux_netdev_change *change, void *dpif_)
692 {
693     struct dpif_linux *dpif = dpif_;
694
695     if (change->master_ifindex == dpif->local_ifindex
696         && (change->nlmsg_type == RTM_NEWLINK
697             || change->nlmsg_type == RTM_DELLINK))
698     {
699         /* Our datapath changed, either adding a new port or deleting an
700          * existing one. */
701         if (!svec_contains(&dpif->changed_ports, change->ifname)) {
702             svec_add(&dpif->changed_ports, change->ifname);
703             svec_sort(&dpif->changed_ports);
704         }
705     }
706 }