X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fdpif-linux.c;h=25715f489ce5186ea3465cc2440957c2fe6507d2;hb=5521e08eb7a233129208a1c04ee11a0599f25879;hp=3935eff646b293b485366028a96d6a58f6d0aa2e;hpb=e4516b2071faac9d1e39301b3079bf2362df42c1;p=sliver-openvswitch.git diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 3935eff64..25715f489 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -46,7 +46,6 @@ #include "netlink.h" #include "odp-util.h" #include "ofpbuf.h" -#include "openvswitch/datapath-compat.h" #include "packets.h" #include "poll-loop.h" #include "random.h" @@ -73,8 +72,10 @@ struct dpif_linux_dp { /* Attributes. */ const char *name; /* OVS_DP_ATTR_NAME. */ - const uint32_t *upcall_pid; /* OVS_DP_UPCALL_PID. */ + const uint32_t *upcall_pid; /* OVS_DP_ATTR_UPCALL_PID. */ struct ovs_dp_stats stats; /* OVS_DP_ATTR_STATS. */ + struct ovs_dp_megaflow_stats megaflow_stats; + /* OVS_DP_ATTR_MEGAFLOW_STATS.*/ }; static void dpif_linux_dp_init(struct dpif_linux_dp *); @@ -140,6 +141,7 @@ struct dpif_linux { int dp_ifindex; /* Upcall messages. */ + struct ovs_mutex upcall_lock; int uc_array_size; /* Size of 'channels' and 'epoll_events'. */ struct dpif_channel *channels; struct epoll_event *epoll_events; @@ -247,6 +249,7 @@ open_dpif(const struct dpif_linux_dp *dp, struct dpif **dpifp) dpif = xzalloc(sizeof *dpif); dpif->port_notifier = NULL; + ovs_mutex_init(&dpif->upcall_lock); dpif->epoll_fd = -1; dpif_init(&dpif->dpif, &dpif_linux_class, dp->name, @@ -276,6 +279,8 @@ destroy_channels(struct dpif_linux *dpif) continue; } + epoll_ctl(dpif->epoll_fd, EPOLL_CTL_DEL, nl_sock_fd(ch->sock), NULL); + /* Turn off upcalls. */ dpif_linux_vport_init(&vport_request); vport_request.cmd = OVS_VPORT_CMD_SET; @@ -295,8 +300,8 @@ destroy_channels(struct dpif_linux *dpif) dpif->epoll_events = NULL; dpif->n_events = dpif->event_offset = 0; - close(dpif->epoll_fd); - dpif->epoll_fd = -1; + /* Don't close dpif->epoll_fd since that would cause other threads that + * call dpif_recv_wait(dpif) to wait on an arbitrary fd or a closed fd. */ } static int @@ -376,6 +381,10 @@ dpif_linux_close(struct dpif *dpif_) nl_sock_destroy(dpif->port_notifier); destroy_channels(dpif); + if (dpif->epoll_fd >= 0) { + close(dpif->epoll_fd); + } + ovs_mutex_destroy(&dpif->upcall_lock); free(dpif); } @@ -404,6 +413,8 @@ dpif_linux_get_stats(const struct dpif *dpif_, struct dpif_dp_stats *stats) stats->n_missed = dp.stats.n_missed; stats->n_lost = dp.stats.n_lost; stats->n_flows = dp.stats.n_flows; + stats->n_masks = dp.megaflow_stats.n_masks; + stats->n_mask_hit = dp.megaflow_stats.n_mask_hit; ofpbuf_delete(buf); } return error; @@ -466,8 +477,8 @@ netdev_to_ovs_vport_type(const struct netdev *netdev) } static int -dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev, - odp_port_t *port_nop) +dpif_linux_port_add__(struct dpif *dpif_, struct netdev *netdev, + odp_port_t *port_nop) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); const struct netdev_tunnel_config *tnl_cfg; @@ -558,7 +569,21 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev, } static int -dpif_linux_port_del(struct dpif *dpif_, odp_port_t port_no) +dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev, + odp_port_t *port_nop) +{ + struct dpif_linux *dpif = dpif_linux_cast(dpif_); + int error; + + ovs_mutex_lock(&dpif->upcall_lock); + error = dpif_linux_port_add__(dpif_, netdev, port_nop); + ovs_mutex_unlock(&dpif->upcall_lock); + + return error; +} + +static int +dpif_linux_port_del__(struct dpif *dpif_, odp_port_t port_no) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); struct dpif_linux_vport vport; @@ -575,6 +600,19 @@ dpif_linux_port_del(struct dpif *dpif_, odp_port_t port_no) return error; } +static int +dpif_linux_port_del(struct dpif *dpif_, odp_port_t port_no) +{ + struct dpif_linux *dpif = dpif_linux_cast(dpif_); + int error; + + ovs_mutex_lock(&dpif->upcall_lock); + error = dpif_linux_port_del__(dpif_, port_no); + ovs_mutex_unlock(&dpif->upcall_lock); + + return error; +} + static int dpif_linux_port_query__(const struct dpif *dpif, odp_port_t port_no, const char *port_name, struct dpif_port *dpif_port) @@ -620,26 +658,29 @@ dpif_linux_port_query_by_name(const struct dpif *dpif, const char *devname, return dpif_linux_port_query__(dpif, 0, devname, dpif_port); } -static odp_port_t +static uint32_t dpif_linux_get_max_ports(const struct dpif *dpif OVS_UNUSED) { - return u32_to_odp(MAX_PORTS); + return MAX_PORTS; } static uint32_t dpif_linux_port_get_pid(const struct dpif *dpif_, odp_port_t port_no) { - const struct dpif_linux *dpif = dpif_linux_cast(dpif_); + struct dpif_linux *dpif = dpif_linux_cast(dpif_); uint32_t port_idx = odp_to_u32(port_no); + uint32_t pid = 0; - if (dpif->epoll_fd < 0) { - return 0; - } else { + ovs_mutex_lock(&dpif->upcall_lock); + if (dpif->epoll_fd >= 0) { /* The ODPP_NONE "reserved" port number uses the "ovs-system"'s * channel, since it is not heavily loaded. */ uint32_t idx = port_idx >= dpif->uc_array_size ? 0 : port_idx; - return nl_sock_pid(dpif->channels[idx].sock); + pid = nl_sock_pid(dpif->channels[idx].sock); } + ovs_mutex_unlock(&dpif->upcall_lock); + + return pid; } static int @@ -669,7 +710,7 @@ dpif_linux_port_dump_start(const struct dpif *dpif_, void **statep) *statep = state = xmalloc(sizeof *state); dpif_linux_vport_init(&request); - request.cmd = OVS_DP_CMD_GET; + request.cmd = OVS_VPORT_CMD_GET; request.dp_ifindex = dpif->dp_ifindex; buf = ofpbuf_new(1024); @@ -761,19 +802,21 @@ dpif_linux_port_poll(const struct dpif *dpif_, char **devnamep) VLOG_DBG("port_changed: dpif:%s vport:%s cmd:%"PRIu8, dpif->dpif.full_name, vport.name, vport.cmd); *devnamep = xstrdup(vport.name); + ofpbuf_uninit(&buf); return 0; - } else { - continue; } } - } else if (error == EAGAIN) { - return EAGAIN; + } else if (error != EAGAIN) { + VLOG_WARN_RL(&rl, "error reading or parsing netlink (%s)", + ovs_strerror(error)); + nl_sock_drain(dpif->port_notifier); + error = ENOBUFS; } - VLOG_WARN_RL(&rl, "error reading or parsing netlink (%s)", - ovs_strerror(error)); - nl_sock_drain(dpif->port_notifier); - return ENOBUFS; + ofpbuf_uninit(&buf); + if (error) { + return error; + } } } @@ -924,7 +967,7 @@ dpif_linux_flow_dump_start(const struct dpif *dpif_, void **statep) *statep = state = xmalloc(sizeof *state); dpif_linux_flow_init(&request); - request.cmd = OVS_DP_CMD_GET; + request.cmd = OVS_FLOW_CMD_GET; request.dp_ifindex = dpif->dp_ifindex; buf = ofpbuf_new(1024); @@ -1195,7 +1238,7 @@ dpif_linux_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops) } static int -dpif_linux_recv_set(struct dpif *dpif_, bool enable) +dpif_linux_recv_set__(struct dpif *dpif_, bool enable) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); @@ -1209,9 +1252,11 @@ dpif_linux_recv_set(struct dpif *dpif_, bool enable) struct dpif_port_dump port_dump; struct dpif_port port; - dpif->epoll_fd = epoll_create(10); if (dpif->epoll_fd < 0) { - return errno; + dpif->epoll_fd = epoll_create(10); + if (dpif->epoll_fd < 0) { + return errno; + } } DPIF_PORT_FOR_EACH (&port, &port_dump, &dpif->dpif) { @@ -1264,6 +1309,19 @@ dpif_linux_recv_set(struct dpif *dpif_, bool enable) return 0; } +static int +dpif_linux_recv_set(struct dpif *dpif_, bool enable) +{ + struct dpif_linux *dpif = dpif_linux_cast(dpif_); + int error; + + ovs_mutex_lock(&dpif->upcall_lock); + error = dpif_linux_recv_set__(dpif_, enable); + ovs_mutex_unlock(&dpif->upcall_lock); + + return error; +} + static int dpif_linux_queue_to_priority(const struct dpif *dpif OVS_UNUSED, uint32_t queue_id, uint32_t *priority) @@ -1332,8 +1390,8 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall, } static int -dpif_linux_recv(struct dpif *dpif_, struct dpif_upcall *upcall, - struct ofpbuf *buf) +dpif_linux_recv__(struct dpif *dpif_, struct dpif_upcall *upcall, + struct ofpbuf *buf) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); int read_tries = 0; @@ -1403,33 +1461,49 @@ dpif_linux_recv(struct dpif *dpif_, struct dpif_upcall *upcall, return EAGAIN; } +static int +dpif_linux_recv(struct dpif *dpif_, struct dpif_upcall *upcall, + struct ofpbuf *buf) +{ + struct dpif_linux *dpif = dpif_linux_cast(dpif_); + int error; + + ovs_mutex_lock(&dpif->upcall_lock); + error = dpif_linux_recv__(dpif_, upcall, buf); + ovs_mutex_unlock(&dpif->upcall_lock); + + return error; +} + static void dpif_linux_recv_wait(struct dpif *dpif_) { - const struct dpif_linux *dpif = dpif_linux_cast(dpif_); + struct dpif_linux *dpif = dpif_linux_cast(dpif_); - if (dpif->epoll_fd < 0) { - return; + ovs_mutex_lock(&dpif->upcall_lock); + if (dpif->epoll_fd >= 0) { + poll_fd_wait(dpif->epoll_fd, POLLIN); } - - poll_fd_wait(dpif->epoll_fd, POLLIN); + ovs_mutex_unlock(&dpif->upcall_lock); } static void dpif_linux_recv_purge(struct dpif *dpif_) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); - struct dpif_channel *ch; - if (dpif->epoll_fd < 0) { - return; - } + ovs_mutex_lock(&dpif->upcall_lock); + if (dpif->epoll_fd >= 0) { + struct dpif_channel *ch; - for (ch = dpif->channels; ch < &dpif->channels[dpif->uc_array_size]; ch++) { - if (ch->sock) { - nl_sock_drain(ch->sock); + for (ch = dpif->channels; ch < &dpif->channels[dpif->uc_array_size]; + ch++) { + if (ch->sock) { + nl_sock_drain(ch->sock); + } } } + ovs_mutex_unlock(&dpif->upcall_lock); } const struct dpif_class dpif_linux_class = { @@ -1495,8 +1569,7 @@ dpif_linux_init(void) } if (!error) { error = nl_lookup_genl_mcgroup(OVS_VPORT_FAMILY, OVS_VPORT_MCGROUP, - &ovs_vport_mcgroup, - OVS_VPORT_MCGROUP_FALLBACK_ID); + &ovs_vport_mcgroup); } ovsthread_once_done(&once); @@ -1701,6 +1774,9 @@ dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, const struct ofpbuf *buf) [OVS_DP_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ }, [OVS_DP_ATTR_STATS] = { NL_POLICY_FOR(struct ovs_dp_stats), .optional = true }, + [OVS_DP_ATTR_MEGAFLOW_STATS] = { + NL_POLICY_FOR(struct ovs_dp_megaflow_stats), + .optional = true }, }; struct nlattr *a[ARRAY_SIZE(ovs_datapath_policy)]; @@ -1732,6 +1808,13 @@ dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, const struct ofpbuf *buf) sizeof dp->stats); } + if (a[OVS_DP_ATTR_MEGAFLOW_STATS]) { + /* Can't use structure assignment because Netlink doesn't ensure + * sufficient alignment for 64-bit members. */ + memcpy(&dp->megaflow_stats, nl_attr_get(a[OVS_DP_ATTR_MEGAFLOW_STATS]), + sizeof dp->megaflow_stats); + } + return 0; } @@ -1764,6 +1847,8 @@ static void dpif_linux_dp_init(struct dpif_linux_dp *dp) { memset(dp, 0, sizeof *dp); + dp->megaflow_stats.n_masks = UINT32_MAX; + dp->megaflow_stats.n_mask_hit = UINT64_MAX; } static void @@ -1802,11 +1887,11 @@ dpif_linux_dp_transact(const struct dpif_linux_dp *request, ofpbuf_delete(request_buf); if (reply) { + dpif_linux_dp_init(reply); if (!error) { error = dpif_linux_dp_from_ofpbuf(reply, *bufp); } if (error) { - dpif_linux_dp_init(reply); ofpbuf_delete(*bufp); *bufp = NULL; } @@ -2012,7 +2097,7 @@ report_loss(struct dpif *dpif_, struct dpif_channel *ch) time_msec() - ch->last_poll); } - VLOG_WARN("%s: lost packet on channel %td%s", + VLOG_WARN("%s: lost packet on channel %"PRIdPTR"%s", dpif_name(dpif_), ch - dpif->channels, ds_cstr(&s)); ds_destroy(&s); }