X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif-linux.c;h=af6eee4161c9abc73b3429854cf230b73ec88a9b;hb=87103e1fccd88e0fc8a64d774ddb620deeb90678;hp=4c34325651fdd6efef0594b876ebb9699324d5c9;hpb=c69ee87c10818267f991236201150b1fa51ae519;p=openvswitch diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 4c343256..af6eee41 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -23,17 +23,21 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include "dpif-provider.h" +#include "netdev.h" #include "ofpbuf.h" #include "poll-loop.h" #include "rtnetlink.h" +#include "shash.h" #include "svec.h" #include "util.h" @@ -51,7 +55,7 @@ struct dpif_linux { /* Change notification. */ int local_ifindex; /* Ifindex of local port. */ - struct svec changed_ports; /* Ports that have changed. */ + struct shash changed_ports; /* Ports that have changed. */ struct rtnetlink_notifier port_notifier; bool change_error; }; @@ -171,7 +175,7 @@ dpif_linux_close(struct dpif *dpif_) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); rtnetlink_notifier_unregister(&dpif->port_notifier); - svec_destroy(&dpif->changed_ports); + shash_destroy(&dpif->changed_ports); free(dpif->local_ifname); close(dpif->fd); free(dpif); @@ -190,6 +194,28 @@ dpif_linux_get_all_names(const struct dpif *dpif_, struct svec *all_names) static int dpif_linux_destroy(struct dpif *dpif_) { + struct odp_port *ports; + size_t n_ports; + int err; + int i; + + err = dpif_port_list(dpif_, &ports, &n_ports); + if (err) { + return err; + } + + for (i = 0; i < n_ports; i++) { + if (ports[i].port != ODPP_LOCAL) { + err = do_ioctl(dpif_, ODP_VPORT_DEL, ports[i].devname); + if (err) { + VLOG_WARN_RL(&error_rl, "%s: error deleting port %s (%s)", + dpif_name(dpif_), ports[i].devname, strerror(err)); + } + } + } + + free(ports); + return do_ioctl(dpif_, ODP_DP_DESTROY, NULL); } @@ -230,7 +256,7 @@ dpif_linux_port_add(struct dpif *dpif_, const char *devname, uint16_t flags, memset(&port, 0, sizeof port); strncpy(port.devname, devname, sizeof port.devname); port.flags = flags; - error = do_ioctl(dpif_, ODP_PORT_ADD, &port); + error = do_ioctl(dpif_, ODP_PORT_ATTACH, &port); if (!error) { *port_no = port.port; } @@ -241,7 +267,27 @@ static int dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no) { int tmp = port_no; - return do_ioctl(dpif_, ODP_PORT_DEL, &tmp); + int err; + struct odp_port port; + + err = dpif_port_query_by_number(dpif_, port_no, &port); + if (err) { + return err; + } + + err = do_ioctl(dpif_, ODP_PORT_DETACH, &tmp); + if (err) { + return err; + } + + if (!netdev_is_open(port.devname)) { + /* Try deleting the port if no one has it open. This shouldn't + * actually be necessary unless the config changed while we weren't + * running but it won't hurt anything if the port is already gone. */ + do_ioctl(dpif_, ODP_VPORT_DEL, port.devname); + } + + return 0; } static int @@ -287,10 +333,12 @@ dpif_linux_port_poll(const struct dpif *dpif_, char **devnamep) if (dpif->change_error) { dpif->change_error = false; - svec_clear(&dpif->changed_ports); + shash_clear(&dpif->changed_ports); return ENOBUFS; - } else if (dpif->changed_ports.n) { - *devnamep = dpif->changed_ports.names[--dpif->changed_ports.n]; + } else if (!shash_is_empty(&dpif->changed_ports)) { + struct shash_node *node = shash_first(&dpif->changed_ports); + *devnamep = xstrdup(node->name); + shash_delete(&dpif->changed_ports, node); return 0; } else { return EAGAIN; @@ -301,7 +349,7 @@ static void dpif_linux_port_poll_wait(const struct dpif *dpif_) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); - if (dpif->changed_ports.n || dpif->change_error) { + if (!shash_is_empty(&dpif->changed_ports) || dpif->change_error) { poll_immediate_wake(); } else { rtnetlink_notifier_wait(); @@ -417,7 +465,8 @@ dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp) int retval; int error; - buf = ofpbuf_new(65536); + buf = ofpbuf_new(65536 + DPIF_RECV_MSG_PADDING); + ofpbuf_reserve(buf, DPIF_RECV_MSG_PADDING); retval = read(dpif->fd, ofpbuf_tail(buf), ofpbuf_tailroom(buf)); if (retval < 0) { error = errno; @@ -677,6 +726,8 @@ get_major(const char *target) } } + fclose(file); + VLOG_ERR("%s: %s major not found (is the module loaded?)", fn, target); return -ENODEV; } @@ -740,7 +791,7 @@ open_minor(int minor, struct dpif **dpifp) dpif->local_ifname = NULL; dpif->minor = minor; dpif->local_ifindex = 0; - svec_init(&dpif->changed_ports); + shash_init(&dpif->changed_ports); dpif->change_error = false; *dpifp = &dpif->dpif; } else { @@ -767,10 +818,7 @@ dpif_linux_port_changed(const struct rtnetlink_change *change, void *dpif_) { /* Our datapath changed, either adding a new port or deleting an * existing one. */ - if (!svec_contains(&dpif->changed_ports, change->ifname)) { - svec_add(&dpif->changed_ports, change->ifname); - svec_sort(&dpif->changed_ports); - } + shash_add_once(&dpif->changed_ports, change->ifname, NULL); } } else { dpif->change_error = true;