X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fdpif.c;h=72184c8408512f82d3373b485fcf7b646bbb3eba;hb=40a8ca3292a78639919e32ddd1558ce02ad938eb;hp=4159dbd0f7f07373a1568289dcd7de693fc4a639;hpb=96fba48f52254c0cef942dcce130e33d290297da;p=sliver-openvswitch.git diff --git a/lib/dpif.c b/lib/dpif.c index 4159dbd0f..72184c840 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -33,14 +33,16 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "svec.h" #include "util.h" #include "valgrind.h" #include "vlog.h" #define THIS_MODULE VLM_dpif -static struct dpif_class *dpif_classes[] = { +static const struct dpif_class *dpif_classes[] = { &dpif_linux_class, + &dpif_netdev_class, }; enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) }; @@ -61,6 +63,66 @@ static void log_flow_put(struct dpif *, int error, static bool should_log_flow_message(int error); static void check_rw_odp_flow(struct odp_flow *); +/* Performs periodic work needed by all the various kinds of dpifs. + * + * If your program opens any dpifs, it must call both this function and + * netdev_run() within its main poll loop. */ +void +dp_run(void) +{ + int i; + for (i = 0; i < N_DPIF_CLASSES; i++) { + const struct dpif_class *class = dpif_classes[i]; + if (class->run) { + class->run(); + } + } +} + +/* Arranges for poll_block() to wake up when dp_run() needs to be called. + * + * If your program opens any dpifs, it must call both this function and + * netdev_wait() within its main poll loop. */ +void +dp_wait(void) +{ + int i; + for (i = 0; i < N_DPIF_CLASSES; i++) { + const struct dpif_class *class = dpif_classes[i]; + if (class->wait) { + class->wait(); + } + } +} + +/* Clears 'all_dps' and enumerates the names of all known created datapaths, + * where possible, into it. The caller must first initialize 'all_dps'. + * Returns 0 if successful, otherwise a positive errno value. + * + * Some kinds of datapaths might not be practically enumerable. This is not + * considered an error. */ +int +dp_enumerate(struct svec *all_dps) +{ + int error; + int i; + + svec_clear(all_dps); + error = 0; + for (i = 0; i < N_DPIF_CLASSES; i++) { + const struct dpif_class *class = dpif_classes[i]; + int retval = class->enumerate ? class->enumerate(all_dps) : 0; + if (retval) { + VLOG_WARN("failed to enumerate %s datapaths: %s", + class->name, strerror(retval)); + if (!error) { + error = retval; + } + } + } + return error; +} + static int do_open(const char *name_, bool create, struct dpif **dpifp) { @@ -107,13 +169,35 @@ dpif_open(const char *name, struct dpif **dpifp) /* Tries to create and open a new datapath with the given 'name'. Will fail if * a datapath named 'name' already exists. Returns 0 if successful, otherwise * a positive errno value. On success stores a pointer to the datapath in - * '*dpifp', otherwise a null pointer.*/ + * '*dpifp', otherwise a null pointer. */ int dpif_create(const char *name, struct dpif **dpifp) { return do_open(name, true, dpifp); } +/* Tries to open a datapath with the given 'name', creating it if it does not + * exist. Returns 0 if successful, otherwise a positive errno value. On + * success stores a pointer to the datapath in '*dpifp', otherwise a null + * pointer. */ +int +dpif_create_and_open(const char *name, struct dpif **dpifp) +{ + int error; + + error = dpif_create(name, dpifp); + if (error == EEXIST || error == EBUSY) { + error = dpif_open(name, dpifp); + if (error) { + VLOG_WARN("datapath %s already exists but cannot be opened: %s", + name, strerror(error)); + } + } else if (error) { + VLOG_WARN("failed to create datapath %s: %s", name, strerror(error)); + } + return error; +} + /* Closes and frees the connection to 'dpif'. Does not destroy the datapath * itself; call dpif_delete() first, instead, if that is desirable. */ void @@ -121,7 +205,7 @@ dpif_close(struct dpif *dpif) { if (dpif) { char *name = dpif->name; - dpif->class->close(dpif); + dpif->dpif_class->close(dpif); free(name); } } @@ -133,6 +217,32 @@ dpif_name(const struct dpif *dpif) return dpif->name; } +/* Enumerates all names that may be used to open 'dpif' into 'all_names'. The + * Linux datapath, for example, supports opening a datapath both by number, + * e.g. "dp0", and by the name of the datapath's local port. For some + * datapaths, this might be an infinite set (e.g. in a file name, slashes may + * be duplicated any number of times), in which case only the names most likely + * to be used will be enumerated. + * + * The caller must already have initialized 'all_names'. Any existing names in + * 'all_names' will not be disturbed. */ +int +dpif_get_all_names(const struct dpif *dpif, struct svec *all_names) +{ + if (dpif->dpif_class->get_all_names) { + int error = dpif->dpif_class->get_all_names(dpif, all_names); + if (error) { + VLOG_WARN_RL(&error_rl, + "failed to retrieve names for datpath %s: %s", + dpif_name(dpif), strerror(error)); + } + return error; + } else { + svec_add(all_names, dpif_name(dpif)); + return 0; + } +} + /* Destroys the datapath that 'dpif' is connected to, first removing all of its * ports. After calling this function, it does not make sense to pass 'dpif' * to any functions other than dpif_name() or dpif_close(). */ @@ -143,7 +253,7 @@ dpif_delete(struct dpif *dpif) COVERAGE_INC(dpif_destroy); - error = dpif->class->delete(dpif); + error = dpif->dpif_class->destroy(dpif); log_operation(dpif, "delete", error); return error; } @@ -153,7 +263,7 @@ dpif_delete(struct dpif *dpif) int dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats) { - int error = dpif->class->get_stats(dpif, stats); + int error = dpif->dpif_class->get_stats(dpif, stats); if (error) { memset(stats, 0, sizeof *stats); } @@ -169,7 +279,7 @@ dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats) int dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags) { - int error = dpif->class->get_drop_frags(dpif, drop_frags); + int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags); if (error) { *drop_frags = false; } @@ -183,7 +293,7 @@ dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags) int dpif_set_drop_frags(struct dpif *dpif, bool drop_frags) { - int error = dpif->class->set_drop_frags(dpif, drop_frags); + int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags); log_operation(dpif, "set_drop_frags", error); return error; } @@ -202,7 +312,7 @@ dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags, COVERAGE_INC(dpif_port_add); - error = dpif->class->port_add(dpif, devname, flags, &port_no); + error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no); if (!error) { VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16, dpif_name(dpif), devname, port_no); @@ -226,7 +336,7 @@ dpif_port_del(struct dpif *dpif, uint16_t port_no) COVERAGE_INC(dpif_port_del); - error = dpif->class->port_del(dpif, port_no); + error = dpif->dpif_class->port_del(dpif, port_no); log_operation(dpif, "port_del", error); return error; } @@ -238,7 +348,7 @@ int dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no, struct odp_port *port) { - int error = dpif->class->port_query_by_number(dpif, port_no, port); + int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port); if (!error) { VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s", dpif_name(dpif), port_no, port->devname); @@ -257,7 +367,7 @@ int dpif_port_query_by_name(const struct dpif *dpif, const char *devname, struct odp_port *port) { - int error = dpif->class->port_query_by_name(dpif, devname, port); + int error = dpif->dpif_class->port_query_by_name(dpif, devname, port); if (!error) { VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16, dpif_name(dpif), devname, port->port); @@ -309,7 +419,7 @@ dpif_port_list(const struct dpif *dpif, struct odp_port **portsp, size_t *n_portsp) { struct odp_port *ports; - size_t n_ports; + size_t n_ports = 0; int error; for (;;) { @@ -322,7 +432,7 @@ dpif_port_list(const struct dpif *dpif, } ports = xcalloc(stats.n_ports, sizeof *ports); - retval = dpif->class->port_list(dpif, ports, stats.n_ports); + retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports); if (retval < 0) { /* Hard error. */ error = -retval; @@ -351,6 +461,40 @@ exit: return error; } +/* Polls for changes in the set of ports in 'dpif'. If the set of ports in + * 'dpif' has changed, this function does one of the following: + * + * - Stores the name of the device that was added to or deleted from 'dpif' in + * '*devnamep' and returns 0. The caller is responsible for freeing + * '*devnamep' (with free()) when it no longer needs it. + * + * - Returns ENOBUFS and sets '*devnamep' to NULL. + * + * This function may also return 'false positives', where it returns 0 and + * '*devnamep' names a device that was not actually added or deleted or it + * returns ENOBUFS without any change. + * + * Returns EAGAIN if the set of ports in 'dpif' has not changed. May also + * return other positive errno values to indicate that something has gone + * wrong. */ +int +dpif_port_poll(const struct dpif *dpif, char **devnamep) +{ + int error = dpif->dpif_class->port_poll(dpif, devnamep); + if (error) { + *devnamep = NULL; + } + return error; +} + +/* Arranges for the poll loop to wake up when port_poll(dpif) will return a + * value other than EAGAIN. */ +void +dpif_port_poll_wait(const struct dpif *dpif) +{ + dpif->dpif_class->port_poll_wait(dpif); +} + /* Retrieves a list of the port numbers in port group 'group' in 'dpif'. * * On success, returns 0 and points '*ports' to a newly allocated array of @@ -369,8 +513,8 @@ dpif_port_group_get(const struct dpif *dpif, uint16_t group, *ports = NULL; *n_ports = 0; for (;;) { - int retval = dpif->class->port_group_get(dpif, group, - *ports, *n_ports); + int retval = dpif->dpif_class->port_group_get(dpif, group, + *ports, *n_ports); if (retval < 0) { /* Hard error. */ error = -retval; @@ -408,7 +552,7 @@ dpif_port_group_set(struct dpif *dpif, uint16_t group, COVERAGE_INC(dpif_port_group_set); - error = dpif->class->port_group_set(dpif, group, ports, n_ports); + error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports); log_operation(dpif, "port_group_set", error); return error; } @@ -422,7 +566,7 @@ dpif_flow_flush(struct dpif *dpif) COVERAGE_INC(dpif_flow_flush); - error = dpif->class->flow_flush(dpif); + error = dpif->dpif_class->flow_flush(dpif); log_operation(dpif, "flow_flush", error); return error; } @@ -448,7 +592,7 @@ dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow) COVERAGE_INC(dpif_flow_get); check_rw_odp_flow(flow); - error = dpif->class->flow_get(dpif, flow, 1); + error = dpif->dpif_class->flow_get(dpif, flow, 1); if (!error) { error = flow->stats.error; } @@ -498,7 +642,7 @@ dpif_flow_get_multiple(const struct dpif *dpif, check_rw_odp_flow(&flows[i]); } - error = dpif->class->flow_get(dpif, flows, n); + error = dpif->dpif_class->flow_get(dpif, flows, n); log_operation(dpif, "flow_get_multiple", error); return error; } @@ -526,7 +670,7 @@ dpif_flow_put(struct dpif *dpif, struct odp_flow_put *put) COVERAGE_INC(dpif_flow_put); - error = dpif->class->flow_put(dpif, put); + error = dpif->dpif_class->flow_put(dpif, put); if (should_log_flow_message(error)) { log_flow_put(dpif, error, put); } @@ -548,7 +692,7 @@ dpif_flow_del(struct dpif *dpif, struct odp_flow *flow) check_rw_odp_flow(flow); memset(&flow->stats, 0, sizeof flow->stats); - error = dpif->class->flow_del(dpif, flow); + error = dpif->dpif_class->flow_del(dpif, flow); if (should_log_flow_message(error)) { log_flow_operation(dpif, "delete flow", error, flow); } @@ -577,7 +721,7 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n, flows[i].n_actions = 0; } } - retval = dpif->class->flow_list(dpif, flows, n); + retval = dpif->dpif_class->flow_list(dpif, flows, n); if (retval < 0) { *n_out = 0; VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)", @@ -654,7 +798,8 @@ dpif_execute(struct dpif *dpif, uint16_t in_port, COVERAGE_INC(dpif_execute); if (n_actions > 0) { - error = dpif->class->execute(dpif, in_port, actions, n_actions, buf); + error = dpif->dpif_class->execute(dpif, in_port, actions, + n_actions, buf); } else { error = 0; } @@ -681,7 +826,7 @@ dpif_execute(struct dpif *dpif, uint16_t in_port, int dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask) { - int error = dpif->class->recv_get_mask(dpif, listen_mask); + int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask); if (error) { *listen_mask = 0; } @@ -695,7 +840,7 @@ dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask) int dpif_recv_set_mask(struct dpif *dpif, int listen_mask) { - int error = dpif->class->recv_set_mask(dpif, listen_mask); + int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask); log_operation(dpif, "recv_set_mask", error); return error; } @@ -711,7 +856,7 @@ dpif_recv_set_mask(struct dpif *dpif, int listen_mask) int dpif_recv(struct dpif *dpif, struct ofpbuf **packetp) { - int error = dpif->class->recv(dpif, packetp); + int error = dpif->dpif_class->recv(dpif, packetp); if (!error) { if (VLOG_IS_DBG_ENABLED()) { struct ofpbuf *buf = *packetp; @@ -765,7 +910,7 @@ dpif_recv_purge(struct dpif *dpif) void dpif_recv_wait(struct dpif *dpif) { - dpif->class->recv_wait(dpif); + dpif->dpif_class->recv_wait(dpif); } /* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type' @@ -779,10 +924,11 @@ dpif_get_netflow_ids(const struct dpif *dpif, } void -dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name, +dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class, + const char *name, uint8_t netflow_engine_type, uint8_t netflow_engine_id) { - dpif->class = class; + dpif->dpif_class = dpif_class; dpif->name = xstrdup(name); dpif->netflow_engine_type = netflow_engine_type; dpif->netflow_engine_id = netflow_engine_id; @@ -900,145 +1046,3 @@ check_rw_odp_flow(struct odp_flow *flow) memset(&flow->actions[0], 0xcc, sizeof flow->actions[0]); } } - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct dpifmon { - struct dpif *dpif; - struct nl_sock *sock; - int local_ifindex; -}; - -int -dpifmon_create(const char *datapath_name, struct dpifmon **monp) -{ - struct dpifmon *mon; - char local_name[IFNAMSIZ]; - int error; - - mon = *monp = xmalloc(sizeof *mon); - - error = dpif_open(datapath_name, &mon->dpif); - if (error) { - goto error; - } - error = dpif_port_get_name(mon->dpif, ODPP_LOCAL, - local_name, sizeof local_name); - if (error) { - goto error_close_dpif; - } - - mon->local_ifindex = if_nametoindex(local_name); - if (!mon->local_ifindex) { - error = errno; - VLOG_WARN("could not get ifindex of %s device: %s", - local_name, strerror(errno)); - goto error_close_dpif; - } - - error = nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, &mon->sock); - if (error) { - VLOG_WARN("could not create rtnetlink socket: %s", strerror(error)); - goto error_close_dpif; - } - - return 0; - -error_close_dpif: - dpif_close(mon->dpif); -error: - free(mon); - *monp = NULL; - return error; -} - -void -dpifmon_destroy(struct dpifmon *mon) -{ - if (mon) { - dpif_close(mon->dpif); - nl_sock_destroy(mon->sock); - } -} - -int -dpifmon_poll(struct dpifmon *mon, char **devnamep) -{ - static struct vlog_rate_limit slow_rl = VLOG_RATE_LIMIT_INIT(1, 5); - static const struct nl_policy rtnlgrp_link_policy[] = { - [IFLA_IFNAME] = { .type = NL_A_STRING }, - [IFLA_MASTER] = { .type = NL_A_U32, .optional = true }, - }; - struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)]; - struct ofpbuf *buf; - int error; - - *devnamep = NULL; -again: - error = nl_sock_recv(mon->sock, &buf, false); - switch (error) { - case 0: - if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg), - rtnlgrp_link_policy, - attrs, ARRAY_SIZE(rtnlgrp_link_policy))) { - VLOG_WARN_RL(&slow_rl, "received bad rtnl message"); - error = ENOBUFS; - } else { - const char *devname = nl_attr_get_string(attrs[IFLA_IFNAME]); - bool for_us; - - if (attrs[IFLA_MASTER]) { - 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. */ - struct odp_port port; - for_us = !dpif_port_query_by_name(mon->dpif, devname, &port); - } - - if (!for_us) { - /* Not for us, try again. */ - ofpbuf_delete(buf); - COVERAGE_INC(dpifmon_poll_false_wakeup); - goto again; - } - COVERAGE_INC(dpifmon_poll_changed); - *devnamep = xstrdup(devname); - } - ofpbuf_delete(buf); - break; - - case EAGAIN: - /* Nothing to do. */ - break; - - case ENOBUFS: - VLOG_WARN_RL(&slow_rl, "dpifmon socket overflowed"); - break; - - default: - VLOG_WARN_RL(&slow_rl, "error on dpifmon socket: %s", strerror(error)); - break; - } - return error; -} - -void -dpifmon_run(struct dpifmon *mon UNUSED) -{ - /* Nothing to do in this implementation. */ -} - -void -dpifmon_wait(struct dpifmon *mon) -{ - nl_sock_wait(mon->sock, POLLIN); -}