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