X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif.c;h=85d05bb714ce61df9078aa8654f71a183c02dab7;hb=f4ba4c4f954f565facc204c2f42947a37704eb1e;hp=21f1173fa8fe132479e1e03255aad9db7a20d0d9;hpb=a14bc59fb8f27db193d74662dc9c5cb8237177ef;p=openvswitch diff --git a/lib/dpif.c b/lib/dpif.c index 21f1173f..85d05bb7 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -49,6 +49,13 @@ #include "vlog.h" #define THIS_MODULE VLM_dpif +/* A datapath interface. */ +struct dpif { + char *name; + unsigned int minor; + int fd; +}; + /* Rate limit for individual messages going to or from the datapath, output at * DBG level. This is very high because, if these are enabled, it is because * we really need to see them. */ @@ -60,24 +67,26 @@ static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5); static int get_minor_from_name(const char *name, unsigned int *minor); static int name_to_minor(const char *name, unsigned int *minor); static int lookup_minor(const char *name, unsigned int *minor); -static int open_by_minor(unsigned int minor, struct dpif *); +static int open_by_minor(unsigned int minor, struct dpif **dpifp); static int make_openvswitch_device(unsigned int minor, char **fnp); static void check_rw_odp_flow(struct odp_flow *); int -dpif_open(const char *name, struct dpif *dpif) +dpif_open(const char *name, struct dpif **dpifp) { + struct dpif *dpif; + unsigned int minor; int listen_mask; int error; - dpif->fd = -1; + *dpifp = NULL; - error = name_to_minor(name, &dpif->minor); + error = name_to_minor(name, &minor); if (error) { return error; } - error = open_by_minor(dpif->minor, dpif); + error = open_by_minor(minor, &dpif); if (error) { return error; } @@ -89,12 +98,13 @@ dpif_open(const char *name, struct dpif *dpif) if (ioctl(dpif->fd, ODP_GET_LISTEN_MASK, &listen_mask)) { error = errno; if (error != ENODEV) { - VLOG_WARN("dp%u: probe returned unexpected error: %s", - dpif->minor, strerror(error)); + VLOG_WARN("%s: probe returned unexpected error: %s", + dpif_name(dpif), strerror(error)); } dpif_close(dpif); return error; } + *dpifp = dpif; return 0; } @@ -102,8 +112,9 @@ void dpif_close(struct dpif *dpif) { if (dpif) { + free(dpif->name); close(dpif->fd); - dpif->fd = -1; + free(dpif); } } @@ -114,49 +125,51 @@ do_ioctl(const struct dpif *dpif, int cmd, const char *cmd_name, int error = ioctl(dpif->fd, cmd, arg) ? errno : 0; if (cmd_name) { if (error) { - VLOG_WARN_RL(&error_rl, "dp%u: ioctl(%s) failed (%s)", - dpif->minor, cmd_name, strerror(error)); + VLOG_WARN_RL(&error_rl, "%s: ioctl(%s) failed (%s)", + dpif_name(dpif), cmd_name, strerror(error)); } else { - VLOG_DBG_RL(&dpmsg_rl, "dp%u: ioctl(%s): success", - dpif->minor, cmd_name); + VLOG_DBG_RL(&dpmsg_rl, "%s: ioctl(%s): success", + dpif_name(dpif), cmd_name); } } return error; } int -dpif_create(const char *name, struct dpif *dpif) +dpif_create(const char *name, struct dpif **dpifp) { unsigned int minor; int error; + *dpifp = NULL; if (!get_minor_from_name(name, &minor)) { /* Minor was specified in 'name', go ahead and create it. */ - error = open_by_minor(minor, dpif); + struct dpif *dpif; + + error = open_by_minor(minor, &dpif); if (error) { return error; } - if (!strncmp(name, "nl:", 3)) { - char devname[128]; - sprintf(devname, "of%u", minor); - error = ioctl(dpif->fd, ODP_DP_CREATE, devname) < 0 ? errno : 0; + error = ioctl(dpif->fd, ODP_DP_CREATE, name) < 0 ? errno : 0; + if (!error) { + *dpifp = dpif; } else { - error = ioctl(dpif->fd, ODP_DP_CREATE, name) < 0 ? errno : 0; - } - if (error) { dpif_close(dpif); } return error; } else { for (minor = 0; minor < ODP_MAX; minor++) { - error = open_by_minor(minor, dpif); + struct dpif *dpif; + + error = open_by_minor(minor, &dpif); if (error) { return error; } error = ioctl(dpif->fd, ODP_DP_CREATE, name) < 0 ? errno : 0; if (!error) { + *dpifp = dpif; return 0; } dpif_close(dpif); @@ -168,20 +181,10 @@ dpif_create(const char *name, struct dpif *dpif) } } -int -dpif_get_name(struct dpif *dpif, char *name, size_t name_size) +const char * +dpif_name(const struct dpif *dpif) { - struct odp_port port; - int error; - - assert(name_size > 0); - *name = '\0'; - - error = dpif_port_query_by_number(dpif, ODPP_LOCAL, &port); - if (!error) { - ovs_strlcpy(name, port.devname, name_size); - } - return error; + return dpif->name; } int @@ -215,25 +218,7 @@ dpif_set_drop_frags(struct dpif *dpif, bool drop_frags) } int -dpif_get_listen_mask(const struct dpif *dpif, int *listen_mask) -{ - int error = do_ioctl(dpif, ODP_GET_LISTEN_MASK, "ODP_GET_LISTEN_MASK", - listen_mask); - if (error) { - *listen_mask = 0; - } - return error; -} - -int -dpif_set_listen_mask(struct dpif *dpif, int listen_mask) -{ - return do_ioctl(dpif, ODP_SET_LISTEN_MASK, "ODP_SET_LISTEN_MASK", - &listen_mask); -} - -int -dpif_purge(struct dpif *dpif) +dpif_recv_purge(struct dpif *dpif) { struct odp_stats stats; unsigned int i; @@ -258,26 +243,33 @@ dpif_purge(struct dpif *dpif) } int -dpif_port_add(struct dpif *dpif, const char *devname, uint16_t port_no, - uint16_t flags) +dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags, + uint16_t *port_nop) { struct odp_port port; + uint16_t port_no; + int error; COVERAGE_INC(dpif_port_add); + memset(&port, 0, sizeof port); strncpy(port.devname, devname, sizeof port.devname); - port.port = port_no; port.flags = flags; - if (!ioctl(dpif->fd, ODP_PORT_ADD, &port)) { - VLOG_DBG_RL(&dpmsg_rl, "dp%u: added %s as port %"PRIu16, - dpif->minor, devname, port_no); - return 0; + + error = do_ioctl(dpif, ODP_PORT_ADD, NULL, &port); + if (!error) { + port_no = port.port; + VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16, + dpif_name(dpif), devname, port_no); } else { - VLOG_WARN_RL(&error_rl, "dp%u: failed to add %s as port " - "%"PRIu16": %s", dpif->minor, devname, port_no, - strerror(errno)); - return errno; + port_no = UINT16_MAX; + VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", + dpif_name(dpif), devname, strerror(errno)); } + if (port_nop) { + *port_nop = port_no; + } + return error; } int @@ -295,12 +287,12 @@ dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no, memset(port, 0, sizeof *port); port->port = port_no; if (!ioctl(dpif->fd, ODP_PORT_QUERY, port)) { - VLOG_DBG_RL(&dpmsg_rl, "dp%u: port %"PRIu16" is device %s", - dpif->minor, port_no, port->devname); + VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s", + dpif_name(dpif), port_no, port->devname); return 0; } else { - VLOG_WARN_RL(&error_rl, "dp%u: failed to query port %"PRIu16": %s", - dpif->minor, port_no, strerror(errno)); + VLOG_WARN_RL(&error_rl, "%s: failed to query port %"PRIu16": %s", + dpif_name(dpif), port_no, strerror(errno)); return errno; } } @@ -312,45 +304,81 @@ dpif_port_query_by_name(const struct dpif *dpif, const char *devname, memset(port, 0, sizeof *port); strncpy(port->devname, devname, sizeof port->devname); if (!ioctl(dpif->fd, ODP_PORT_QUERY, port)) { - VLOG_DBG_RL(&dpmsg_rl, "dp%u: device %s is on port %"PRIu16, - dpif->minor, devname, port->port); + VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16, + dpif_name(dpif), devname, port->port); return 0; } else { - VLOG_WARN_RL(&error_rl, "dp%u: failed to query port %s: %s", - dpif->minor, devname, strerror(errno)); + /* Log level is DBG here because all the current callers are interested + * in whether 'dpif' actually has a port 'devname', so that it's not an + * issue worth logging if it doesn't. */ + VLOG_DBG_RL(&error_rl, "%s: failed to query port %s: %s", + dpif_name(dpif), devname, strerror(errno)); return errno; } } +int +dpif_port_get_name(struct dpif *dpif, uint16_t port_no, + char *name, size_t name_size) +{ + struct odp_port port; + int error; + + assert(name_size > 0); + + error = dpif_port_query_by_number(dpif, port_no, &port); + if (!error) { + ovs_strlcpy(name, port.devname, name_size); + } else { + *name = '\0'; + } + return error; +} + int dpif_port_list(const struct dpif *dpif, - struct odp_port **ports, size_t *n_ports) + struct odp_port **portsp, size_t *n_portsp) { - struct odp_portvec pv; - struct odp_stats stats; + struct odp_port *ports; + size_t n_ports; int error; - do { + for (;;) { + struct odp_stats stats; + struct odp_portvec pv; + error = dpif_get_dp_stats(dpif, &stats); if (error) { - goto error; + goto exit; } - *ports = xcalloc(1, stats.n_ports * sizeof **ports); - pv.ports = *ports; + ports = xcalloc(stats.n_ports, sizeof *ports); + pv.ports = ports; pv.n_ports = stats.n_ports; error = do_ioctl(dpif, ODP_PORT_LIST, "ODP_PORT_LIST", &pv); if (error) { - free(*ports); - goto error; + /* Hard error. */ + free(ports); + goto exit; + } else if (pv.n_ports <= stats.n_ports) { + /* Success. */ + error = 0; + n_ports = pv.n_ports; + goto exit; + } else { + /* Soft error: port count increased behind our back. Try again. */ + free(ports); } - } while (pv.n_ports != stats.n_ports); - *n_ports = pv.n_ports; - return 0; + } -error: - *ports = NULL; - *n_ports = 0; +exit: + if (error) { + *portsp = NULL; + *n_portsp = 0; + } else { + *portsp = ports; + *n_portsp = n_ports; + } return error; } @@ -368,21 +396,39 @@ dpif_port_group_set(struct dpif *dpif, uint16_t group, return do_ioctl(dpif, ODP_PORT_GROUP_SET, "ODP_PORT_GROUP_SET", &pg); } -/* Careful: '*n_out' can be greater than 'n_ports' on return, if 'n_ports' is - * less than the number of ports in 'group'. */ int dpif_port_group_get(const struct dpif *dpif, uint16_t group, - uint16_t ports[], size_t n_ports, size_t *n_out) + uint16_t **ports, size_t *n_ports) { - struct odp_port_group pg; int error; - assert(n_ports <= UINT16_MAX); - pg.group = group; - pg.ports = ports; - pg.n_ports = n_ports; - error = do_ioctl(dpif, ODP_PORT_GROUP_GET, "ODP_PORT_GROUP_GET", &pg); - *n_out = error ? 0 : pg.n_ports; + *ports = NULL; + *n_ports = 0; + for (;;) { + struct odp_port_group pg; + pg.group = group; + pg.ports = *ports; + pg.n_ports = *n_ports; + + error = do_ioctl(dpif, ODP_PORT_GROUP_GET, "ODP_PORT_GROUP_GET", &pg); + if (error) { + /* Hard error. */ + free(*ports); + *ports = NULL; + *n_ports = 0; + break; + } else if (pg.n_ports <= *n_ports) { + /* Success. */ + *n_ports = pg.n_ports; + break; + } else { + /* Soft error: there were more ports than we expected in the + * group. Try again. */ + free(*ports); + *ports = xcalloc(pg.n_ports, sizeof **ports); + *n_ports = pg.n_ports; + } + } return error; } @@ -413,7 +459,7 @@ log_flow_message(const struct dpif *dpif, int error, const union odp_action *actions, size_t n_actions) { struct ds ds = DS_EMPTY_INITIALIZER; - ds_put_format(&ds, "dp%u: ", dpif->minor); + ds_put_format(&ds, "%s: ", dpif_name(dpif)); if (error) { ds_put_cstr(&ds, "failed to "); } @@ -491,10 +537,23 @@ dpif_flow_del(struct dpif *dpif, struct odp_flow *flow) int dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow) { - COVERAGE_INC(dpif_flow_query); + struct odp_flowvec fv; + int error; + + COVERAGE_INC(dpif_flow_get); + check_rw_odp_flow(flow); - memset(&flow->stats, 0, sizeof flow->stats); - return do_flow_ioctl(dpif, ODP_FLOW_GET, flow, "get flow", true); + fv.flows = flow; + fv.n_flows = 1; + error = do_ioctl(dpif, ODP_FLOW_GET, "ODP_FLOW_GET", &fv); + if (!error) { + error = flow->stats.error; + if (error) { + VLOG_WARN_RL(&error_rl, "%s: ioctl(ODP_FLOW_GET) failed (%s)", + dpif_name(dpif), strerror(error)); + } + } + return error; } int @@ -510,7 +569,7 @@ dpif_flow_get_multiple(const struct dpif *dpif, for (i = 0; i < n; i++) { check_rw_odp_flow(&flows[i]); } - return do_ioctl(dpif, ODP_FLOW_GET_MULTIPLE, "ODP_FLOW_GET_MULTIPLE", + return do_ioctl(dpif, ODP_FLOW_GET, "ODP_FLOW_GET", &fv); } @@ -536,12 +595,13 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n, error = do_ioctl(dpif, ODP_FLOW_LIST, NULL, &fv); if (error) { *n_out = 0; - VLOG_WARN_RL(&error_rl, "dp%u: flow list failed (%s)", - dpif->minor, strerror(error)); + VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)", + dpif_name(dpif), strerror(error)); } else { COVERAGE_ADD(dpif_flow_query_list_n, fv.n_flows); *n_out = fv.n_flows; - VLOG_DBG_RL(&dpmsg_rl, "dp%u: listed %zu flows", dpif->minor, *n_out); + VLOG_DBG_RL(&dpmsg_rl, "%s: listed %zu flows", + dpif_name(dpif), *n_out); } return error; } @@ -571,9 +631,9 @@ dpif_flow_list_all(const struct dpif *dpif, } if (stats.n_flows != n_flows) { - VLOG_WARN_RL(&error_rl, "dp%u: datapath stats reported %"PRIu32" " + VLOG_WARN_RL(&error_rl, "%s: datapath stats reported %"PRIu32" " "flows but flow listing reported %zu", - dpif->minor, stats.n_flows, n_flows); + dpif_name(dpif), stats.n_flows, n_flows); } *flowsp = flows; *np = n_flows; @@ -604,7 +664,7 @@ dpif_execute(struct dpif *dpif, uint16_t in_port, if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))) { struct ds ds = DS_EMPTY_INITIALIZER; char *packet = ofp_packet_to_string(buf->data, buf->size, buf->size); - ds_put_format(&ds, "dp%u: execute ", dpif->minor); + ds_put_format(&ds, "%s: execute ", dpif_name(dpif)); format_odp_actions(&ds, actions, n_actions); if (error) { ds_put_format(&ds, " failed (%s)", strerror(error)); @@ -617,6 +677,24 @@ dpif_execute(struct dpif *dpif, uint16_t in_port, return error; } +int +dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask) +{ + int error = do_ioctl(dpif, ODP_GET_LISTEN_MASK, "ODP_GET_LISTEN_MASK", + listen_mask); + if (error) { + *listen_mask = 0; + } + return error; +} + +int +dpif_recv_set_mask(struct dpif *dpif, int listen_mask) +{ + return do_ioctl(dpif, ODP_SET_LISTEN_MASK, "ODP_SET_LISTEN_MASK", + &listen_mask); +} + int dpif_recv(struct dpif *dpif, struct ofpbuf **bufp) { @@ -629,8 +707,8 @@ dpif_recv(struct dpif *dpif, struct ofpbuf **bufp) if (retval < 0) { error = errno; if (error != EAGAIN) { - VLOG_WARN_RL(&error_rl, "dp%u: read failed: %s", - dpif->minor, strerror(error)); + VLOG_WARN_RL(&error_rl, "%s: read failed: %s", + dpif_name(dpif), strerror(error)); } } else if (retval >= sizeof(struct odp_msg)) { struct odp_msg *msg = buf->data; @@ -640,8 +718,8 @@ dpif_recv(struct dpif *dpif, struct ofpbuf **bufp) void *payload = msg + 1; size_t length = buf->size - sizeof *msg; char *s = ofp_packet_to_string(payload, length, length); - VLOG_DBG_RL(&dpmsg_rl, "dp%u: received %s message of length " - "%zu on port %"PRIu16": %s", dpif->minor, + VLOG_DBG_RL(&dpmsg_rl, "%s: received %s message of length " + "%zu on port %"PRIu16": %s", dpif_name(dpif), (msg->type == _ODPL_MISS_NR ? "miss" : msg->type == _ODPL_ACTION_NR ? "action" : ""), @@ -653,18 +731,18 @@ dpif_recv(struct dpif *dpif, struct ofpbuf **bufp) COVERAGE_INC(dpif_recv); return 0; } else { - VLOG_WARN_RL(&error_rl, "dp%u: discarding message truncated " + VLOG_WARN_RL(&error_rl, "%s: discarding message truncated " "from %zu bytes to %d", - dpif->minor, msg->length, retval); + dpif_name(dpif), msg->length, retval); error = ERANGE; } } else if (!retval) { - VLOG_WARN_RL(&error_rl, "dp%u: unexpected end of file", dpif->minor); + VLOG_WARN_RL(&error_rl, "%s: unexpected end of file", dpif_name(dpif)); error = EPROTO; } else { VLOG_WARN_RL(&error_rl, - "dp%u: discarding too-short message (%d bytes)", - dpif->minor, retval); + "%s: discarding too-short message (%d bytes)", + dpif_name(dpif), retval); error = ERANGE; } @@ -678,9 +756,16 @@ dpif_recv_wait(struct dpif *dpif) { poll_fd_wait(dpif->fd, POLLIN); } + +void +dpif_get_netflow_ids(const struct dpif *dpif, + uint8_t *engine_type, uint8_t *engine_id) +{ + *engine_type = *engine_id = dpif->minor; +} struct dpifmon { - struct dpif dpif; + struct dpif *dpif; struct nl_sock *sock; int local_ifindex; }; @@ -698,7 +783,8 @@ dpifmon_create(const char *datapath_name, struct dpifmon **monp) if (error) { goto error; } - error = dpif_get_name(&mon->dpif, local_name, sizeof local_name); + error = dpif_port_get_name(mon->dpif, ODPP_LOCAL, + local_name, sizeof local_name); if (error) { goto error_close_dpif; } @@ -720,7 +806,7 @@ dpifmon_create(const char *datapath_name, struct dpifmon **monp) return 0; error_close_dpif: - dpif_close(&mon->dpif); + dpif_close(mon->dpif); error: free(mon); *monp = NULL; @@ -731,7 +817,7 @@ void dpifmon_destroy(struct dpifmon *mon) { if (mon) { - dpif_close(&mon->dpif); + dpif_close(mon->dpif); nl_sock_destroy(mon->sock); } } @@ -766,13 +852,9 @@ again: uint32_t master_ifindex = nl_attr_get_u32(attrs[IFLA_MASTER]); for_us = master_ifindex == mon->local_ifindex; } else { - /* It's for us if that device is one of our ports. This is - * open-coded instead of using dpif_port_query_by_name() to - * avoid logging a warning on failure. */ + /* It's for us if that device is one of our ports. */ struct odp_port port; - memset(&port, 0, sizeof port); - strncpy(port.devname, devname, sizeof port.devname); - for_us = !ioctl(mon->dpif.fd, ODP_PORT_QUERY, &port); + for_us = !dpif_port_query_by_name(mon->dpif, devname, &port); } if (!for_us) { @@ -998,24 +1080,20 @@ get_minor_from_name(const char *name, unsigned int *minor) if (!strncmp(name, "dp", 2) && isdigit(name[2])) { *minor = atoi(name + 2); return 0; - } else if (!strncmp(name, "nl:", 3) && isdigit(name[3])) { - /* This is for compatibility only and will be dropped. */ - *minor = atoi(name + 3); - return 0; } else { return EINVAL; } } static int -open_by_minor(unsigned int minor, struct dpif *dpif) +open_by_minor(unsigned int minor, struct dpif **dpifp) { + struct dpif *dpif; int error; char *fn; int fd; - dpif->minor = -1; - dpif->fd = -1; + *dpifp = NULL; error = make_openvswitch_device(minor, &fn); if (error) { return error; @@ -1028,10 +1106,13 @@ open_by_minor(unsigned int minor, struct dpif *dpif) free(fn); return error; } - free(fn); + + dpif = xmalloc(sizeof *dpif); + dpif->name = xasprintf("dp%u", dpif->minor); dpif->minor = minor; dpif->fd = fd; + *dpifp = dpif; return 0; }