dpif-linux: Don't allow arbitrary internal ports to identify a datapath.
[openvswitch] / 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 *minorp)
457 {
458     struct ethtool_drvinfo drvinfo;
459     int minor, port_no;
460     struct ifreq ifr;
461     int error;
462     int sock;
463
464     sock = socket(AF_INET, SOCK_DGRAM, 0);
465     if (sock < 0) {
466         VLOG_WARN("socket(AF_INET) failed: %s", strerror(errno));
467         error = errno;
468         goto error;
469     }
470
471     memset(&ifr, 0, sizeof ifr);
472     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
473     ifr.ifr_data = (caddr_t) &drvinfo;
474
475     memset(&drvinfo, 0, sizeof drvinfo);
476     drvinfo.cmd = ETHTOOL_GDRVINFO;
477     if (ioctl(sock, SIOCETHTOOL, &ifr)) {
478         VLOG_WARN("ioctl(SIOCETHTOOL) failed: %s", strerror(errno));
479         error = errno;
480         goto error_close_sock;
481     }
482
483     if (strcmp(drvinfo.driver, "openvswitch")) {
484         VLOG_WARN("%s is not an openvswitch device", name);
485         error = EOPNOTSUPP;
486         goto error_close_sock;
487     }
488
489     if (sscanf(drvinfo.bus_info, "%d.%d", &minor, &port_no) != 2) {
490         VLOG_WARN("%s ethtool bus_info has unexpected format", name);
491         error = EPROTOTYPE;
492         goto error_close_sock;
493     } else if (port_no != ODPP_LOCAL) {
494         /* This is an Open vSwitch device but not the local port.  We
495          * intentionally support only using the name of the local port as the
496          * name of a datapath; otherwise, it would be too difficult to
497          * enumerate all the names of a datapath. */
498         error = EOPNOTSUPP;
499         goto error_close_sock;
500     }
501
502     *minorp = minor;
503     close(sock);
504     return 0;
505
506 error_close_sock:
507     close(sock);
508 error:
509     return error;
510 }
511
512 static int
513 make_openvswitch_device(int minor, char **fnp)
514 {
515     dev_t dev = makedev(get_openvswitch_major(), minor);
516     const char dirname[] = "/dev/net";
517     struct stat s;
518     char fn[128];
519
520     *fnp = NULL;
521     sprintf(fn, "%s/dp%d", dirname, minor);
522     if (!stat(fn, &s)) {
523         if (!S_ISCHR(s.st_mode)) {
524             VLOG_WARN_RL(&error_rl, "%s is not a character device, fixing",
525                          fn);
526         } else if (s.st_rdev != dev) {
527             VLOG_WARN_RL(&error_rl,
528                          "%s is device %u:%u instead of %u:%u, fixing",
529                          fn, major(s.st_rdev), minor(s.st_rdev),
530                          major(dev), minor(dev));
531         } else {
532             goto success;
533         }
534         if (unlink(fn)) {
535             VLOG_WARN_RL(&error_rl, "%s: unlink failed (%s)",
536                          fn, strerror(errno));
537             return errno;
538         }
539     } else if (errno == ENOENT) {
540         if (stat(dirname, &s)) {
541             if (errno == ENOENT) {
542                 if (mkdir(dirname, 0755)) {
543                     VLOG_WARN_RL(&error_rl, "%s: mkdir failed (%s)",
544                                  dirname, strerror(errno));
545                     return errno;
546                 }
547             } else {
548                 VLOG_WARN_RL(&error_rl, "%s: stat failed (%s)",
549                              dirname, strerror(errno));
550                 return errno;
551             }
552         }
553     } else {
554         VLOG_WARN_RL(&error_rl, "%s: stat failed (%s)", fn, strerror(errno));
555         return errno;
556     }
557
558     /* The device needs to be created. */
559     if (mknod(fn, S_IFCHR | 0700, dev)) {
560         VLOG_WARN_RL(&error_rl,
561                      "%s: creating character device %u:%u failed (%s)",
562                      fn, major(dev), minor(dev), strerror(errno));
563         return errno;
564     }
565
566 success:
567     *fnp = xstrdup(fn);
568     return 0;
569 }
570
571
572 static int
573 get_openvswitch_major(void)
574 {
575     static unsigned int openvswitch_major;
576     if (!openvswitch_major) {
577         enum { DEFAULT_MAJOR = 248 };
578         openvswitch_major = get_major("openvswitch", DEFAULT_MAJOR);
579     }
580     return openvswitch_major;
581 }
582
583 static int
584 get_major(const char *target, int default_major)
585 {
586     const char fn[] = "/proc/devices";
587     char line[128];
588     FILE *file;
589     int ln;
590
591     file = fopen(fn, "r");
592     if (!file) {
593         VLOG_ERR("opening %s failed (%s)", fn, strerror(errno));
594         goto error;
595     }
596
597     for (ln = 1; fgets(line, sizeof line, file); ln++) {
598         char name[64];
599         int major;
600
601         if (!strncmp(line, "Character", 9) || line[0] == '\0') {
602             /* Nothing to do. */
603         } else if (!strncmp(line, "Block", 5)) {
604             /* We only want character devices, so skip the rest of the file. */
605             break;
606         } else if (sscanf(line, "%d %63s", &major, name)) {
607             if (!strcmp(name, target)) {
608                 fclose(file);
609                 return major;
610             }
611         } else {
612             static bool warned;
613             if (!warned) {
614                 VLOG_WARN("%s:%d: syntax error", fn, ln);
615             }
616             warned = true;
617         }
618     }
619
620     VLOG_ERR("%s: %s major not found (is the module loaded?), using "
621              "default major %d", fn, target, default_major);
622 error:
623     VLOG_INFO("using default major %d for %s", default_major, target);
624     return default_major;
625 }
626
627 static int
628 finish_open(struct dpif *dpif_, const char *local_ifname)
629 {
630     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
631     dpif->local_ifindex = if_nametoindex(local_ifname);
632     if (!dpif->local_ifindex) {
633         int error = errno;
634         dpif_close(dpif_);
635         VLOG_WARN("could not get ifindex of %s device: %s",
636                   local_ifname, strerror(errno));
637         return error;
638     }
639     return 0;
640 }
641
642 static int
643 create_minor(const char *name, int minor, struct dpif **dpifp)
644 {
645     int error = open_minor(minor, dpifp);
646     if (!error) {
647         error = do_ioctl(*dpifp, ODP_DP_CREATE, name);
648         if (!error) {
649             error = finish_open(*dpifp, name);
650         } else {
651             dpif_close(*dpifp);
652         }
653     }
654     return error;
655 }
656
657 static int
658 open_minor(int minor, struct dpif **dpifp)
659 {
660     int error;
661     char *fn;
662     int fd;
663
664     error = make_openvswitch_device(minor, &fn);
665     if (error) {
666         return error;
667     }
668
669     fd = open(fn, O_RDONLY | O_NONBLOCK);
670     if (fd >= 0) {
671         struct dpif_linux *dpif = xmalloc(sizeof *dpif);
672         error = linux_netdev_notifier_register(&dpif->port_notifier,
673                                                dpif_linux_port_changed, dpif);
674         if (!error) {
675             char *name;
676
677             name = xasprintf("dp%d", minor);
678             dpif_init(&dpif->dpif, &dpif_linux_class, name, minor, minor);
679             free(name);
680
681             dpif->fd = fd;
682             dpif->local_ifindex = 0;
683             svec_init(&dpif->changed_ports);
684             *dpifp = &dpif->dpif;
685         } else {
686             free(dpif);
687         }
688     } else {
689         error = errno;
690         VLOG_WARN("%s: open failed (%s)", fn, strerror(error));
691     }
692     free(fn);
693
694     return error;
695 }
696
697 static void
698 dpif_linux_port_changed(const struct linux_netdev_change *change, void *dpif_)
699 {
700     struct dpif_linux *dpif = dpif_;
701
702     if (change->master_ifindex == dpif->local_ifindex
703         && (change->nlmsg_type == RTM_NEWLINK
704             || change->nlmsg_type == RTM_DELLINK))
705     {
706         /* Our datapath changed, either adding a new port or deleting an
707          * existing one. */
708         if (!svec_contains(&dpif->changed_ports, change->ifname)) {
709             svec_add(&dpif->changed_ports, change->ifname);
710             svec_sort(&dpif->changed_ports);
711         }
712     }
713 }