X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif-linux.c;h=509174c869d1ce18b5ad9fd759374450742677f1;hb=e868fb3d322f5c46385f1fc6db5bb1ab33f90305;hp=c35ad62e6c2f8afef5732667f38364dac3adf542;hpb=f9ef1c31cfcd2d9ded66588a11c59e29e5aaa2ca;p=openvswitch diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index c35ad62e..509174c8 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -89,7 +89,10 @@ struct dpif_linux_flow { * * The 'stats' and 'used' members point to 64-bit data that might only be * aligned on 32-bit boundaries, so get_unaligned_u64() should be used to - * access their values. */ + * access their values. + * + * If 'actions' is nonnull then ODP_FLOW_ATTR_ACTIONS will be included in + * the Netlink version of the command, even if actions_len is zero. */ const struct nlattr *key; /* ODP_FLOW_ATTR_KEY. */ size_t key_len; const struct nlattr *actions; /* ODP_FLOW_ATTR_ACTIONS. */ @@ -503,21 +506,31 @@ dpif_linux_port_poll_wait(const struct dpif *dpif_) } static int -dpif_linux_flow_get(const struct dpif *dpif_, - const struct nlattr *key, size_t key_len, - struct ofpbuf **actionsp, struct dpif_flow_stats *stats) +dpif_linux_flow_get__(const struct dpif *dpif_, + const struct nlattr *key, size_t key_len, + struct dpif_linux_flow *reply, struct ofpbuf **bufp) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); - struct dpif_linux_flow request, reply; - struct ofpbuf *buf; - int error; + struct dpif_linux_flow request; dpif_linux_flow_init(&request); request.cmd = ODP_FLOW_CMD_GET; request.dp_ifindex = dpif->dp_ifindex; request.key = key; request.key_len = key_len; - error = dpif_linux_flow_transact(&request, &reply, &buf); + return dpif_linux_flow_transact(&request, reply, bufp); +} + +static int +dpif_linux_flow_get(const struct dpif *dpif_, + const struct nlattr *key, size_t key_len, + struct ofpbuf **actionsp, struct dpif_flow_stats *stats) +{ + struct dpif_linux_flow reply; + struct ofpbuf *buf; + int error; + + error = dpif_linux_flow_get__(dpif_, key, key_len, &reply, &buf); if (!error) { if (stats) { dpif_linux_flow_get_stats(&reply, stats); @@ -541,6 +554,7 @@ dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags, { struct dpif_linux *dpif = dpif_linux_cast(dpif_); struct dpif_linux_flow request, reply; + struct nlattr dummy_action; struct ofpbuf *buf; int error; @@ -549,7 +563,8 @@ dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags, request.dp_ifindex = dpif->dp_ifindex; request.key = key; request.key_len = key_len; - request.actions = actions; + /* Ensure that ODP_FLOW_ATTR_ACTIONS will always be included. */ + request.actions = actions ? actions : &dummy_action; request.actions_len = actions_len; if (flags & DPIF_FP_ZERO_STATS) { request.clear = true; @@ -594,6 +609,7 @@ struct dpif_linux_flow_state { struct nl_dump dump; struct dpif_linux_flow flow; struct dpif_flow_stats stats; + struct ofpbuf *buf; }; static int @@ -615,6 +631,8 @@ dpif_linux_flow_dump_start(const struct dpif *dpif_, void **statep) nl_dump_start(&state->dump, genl_sock, buf); ofpbuf_delete(buf); + state->buf = NULL; + return 0; } @@ -628,24 +646,42 @@ dpif_linux_flow_dump_next(const struct dpif *dpif_ OVS_UNUSED, void *state_, struct ofpbuf buf; int error; - if (!nl_dump_next(&state->dump, &buf)) { - return EOF; - } + do { + ofpbuf_delete(state->buf); + state->buf = NULL; - error = dpif_linux_flow_from_ofpbuf(&state->flow, &buf); - if (!error) { - if (key) { - *key = state->flow.key; - *key_len = state->flow.key_len; + if (!nl_dump_next(&state->dump, &buf)) { + return EOF; } - if (actions) { - *actions = state->flow.actions; - *actions_len = state->flow.actions_len; + + error = dpif_linux_flow_from_ofpbuf(&state->flow, &buf); + if (error) { + return error; } - if (stats) { - dpif_linux_flow_get_stats(&state->flow, &state->stats); - *stats = &state->stats; + + if (actions && !state->flow.actions) { + error = dpif_linux_flow_get__(dpif_, state->flow.key, + state->flow.key_len, + &state->flow, &state->buf); + if (error == ENOENT) { + VLOG_DBG("dumped flow disappeared on get"); + } else if (error) { + VLOG_WARN("error fetching dumped flow: %s", strerror(error)); + } } + } while (error); + + if (actions) { + *actions = state->flow.actions; + *actions_len = state->flow.actions_len; + } + if (key) { + *key = state->flow.key; + *key_len = state->flow.key_len; + } + if (stats) { + dpif_linux_flow_get_stats(&state->flow, &state->stats); + *stats = &state->stats; } return error; } @@ -655,6 +691,7 @@ dpif_linux_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) { struct dpif_linux_flow_state *state = state_; int error = nl_dump_done(&state->dump); + ofpbuf_delete(state->buf); free(state); return error; } @@ -1071,6 +1108,8 @@ dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport *vport, } if (a[ODP_VPORT_ATTR_MTU]) { vport->mtu = nl_attr_get_u32(a[ODP_VPORT_ATTR_MTU]); + } else { + vport->mtu = INT_MAX; } if (a[ODP_VPORT_ATTR_OPTIONS]) { vport->options = nl_attr_get(a[ODP_VPORT_ATTR_OPTIONS]); @@ -1121,7 +1160,7 @@ dpif_linux_vport_to_ofpbuf(const struct dpif_linux_vport *vport, vport->address, ETH_ADDR_LEN); } - if (vport->mtu) { + if (vport->mtu && vport->mtu != INT_MAX) { nl_msg_put_u32(buf, ODP_VPORT_ATTR_MTU, vport->mtu); } @@ -1437,6 +1476,9 @@ dpif_linux_flow_from_ofpbuf(struct dpif_linux_flow *flow, if (a[ODP_FLOW_ATTR_TCP_FLAGS]) { flow->tcp_flags = nl_attr_get(a[ODP_FLOW_ATTR_TCP_FLAGS]); } + if (a[ODP_FLOW_ATTR_USED]) { + flow->used = nl_attr_get(a[ODP_FLOW_ATTR_USED]); + } return 0; } @@ -1459,7 +1501,7 @@ dpif_linux_flow_to_ofpbuf(const struct dpif_linux_flow *flow, nl_msg_put_unspec(buf, ODP_FLOW_ATTR_KEY, flow->key, flow->key_len); } - if (flow->actions_len) { + if (flow->actions || flow->actions_len) { nl_msg_put_unspec(buf, ODP_FLOW_ATTR_ACTIONS, flow->actions, flow->actions_len); }