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