#include "dynamic-string.h"
#include "flow.h"
#include "netlink.h"
+#include "odp-util.h"
#include "ofp-print.h"
#include "ofpbuf.h"
#include "packets.h"
static int lookup_minor(const char *name, unsigned int *minor);
static int open_by_minor(unsigned int minor, struct dpif *);
static int make_openflow_device(unsigned int minor, char **fnp);
-static char *odp_actions_to_string(const union odp_action actions[],
- size_t n_actions);
static void check_rw_odp_flow(struct odp_flow *);
int
}
}
-#define IOCTL(DPIF, CMD, ARG) do_ioctl(DPIF, CMD, #CMD, ARG)
-
static int
do_ioctl(const struct dpif *dpif, int cmd, const char *cmd_name,
const void *arg)
{
- if (ioctl(dpif->fd, cmd, arg)) {
- VLOG_WARN_RL(&error_rl, "dp%u: ioctl(%s) failed (%s)",
- dpif->minor, cmd_name, strerror(errno));
- return errno;
- } else {
- VLOG_DBG_RL(&dpmsg_rl, "dp%u: ioctl(%s): success",
- dpif->minor, cmd_name);
- return 0;
+ 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(errno));
+ } else {
+ VLOG_DBG_RL(&dpmsg_rl, "dp%u: ioctl(%s): success",
+ dpif->minor, cmd_name);
+ }
}
+ return error;
}
int
int
dpif_delete(struct dpif *dpif)
{
- return IOCTL(dpif, ODP_DP_DESTROY, NULL);
+ return do_ioctl(dpif, ODP_DP_DESTROY, "ODP_DP_DESTROY", NULL);
}
int
dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
{
memset(stats, 0, sizeof *stats);
- return IOCTL(dpif, ODP_DP_STATS, stats);
+ return do_ioctl(dpif, ODP_DP_STATS, "ODP_DP_STATS", stats);
}
int
dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
{
int tmp;
- int error = IOCTL(dpif, ODP_GET_DROP_FRAGS, &tmp);
+ int error = do_ioctl(dpif, ODP_GET_DROP_FRAGS, "ODP_GET_DROP_FRAGS", &tmp);
*drop_frags = error ? tmp & 1 : false;
return error;
}
dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
{
int tmp = drop_frags;
- return IOCTL(dpif, ODP_SET_DROP_FRAGS, &tmp);
+ return do_ioctl(dpif, ODP_SET_DROP_FRAGS, "ODP_SET_DROP_FRAGS", &tmp);
}
int
dpif_get_listen_mask(const struct dpif *dpif, int *listen_mask)
{
- int error = IOCTL(dpif, ODP_GET_LISTEN_MASK, listen_mask);
+ int error = do_ioctl(dpif, ODP_GET_LISTEN_MASK, "ODP_GET_LISTEN_MASK",
+ listen_mask);
if (error) {
*listen_mask = 0;
}
int
dpif_set_listen_mask(struct dpif *dpif, int listen_mask)
{
- return IOCTL(dpif, ODP_SET_LISTEN_MASK, &listen_mask);
+ return do_ioctl(dpif, ODP_SET_LISTEN_MASK, "ODP_SET_LISTEN_MASK",
+ &listen_mask);
}
int
dpif_port_del(struct dpif *dpif, uint16_t port_no)
{
int tmp = port_no;
- return IOCTL(dpif, ODP_PORT_DEL, &tmp);
+ return do_ioctl(dpif, ODP_PORT_DEL, "ODP_PORT_DEL", &tmp);
}
int
*ports = xcalloc(1, stats.n_ports * sizeof **ports);
pv.ports = *ports;
pv.n_ports = stats.n_ports;
- error = IOCTL(dpif, ODP_PORT_LIST, &pv);
+ error = do_ioctl(dpif, ODP_PORT_LIST, "ODP_PORT_LIST", &pv);
if (error) {
free(*ports);
goto error;
pg.group = group;
pg.ports = (uint16_t *) ports;
pg.n_ports = n_ports;
- return IOCTL(dpif, ODP_PORT_GROUP_SET, &pg);
+ 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
pg.group = group;
pg.ports = ports;
pg.n_ports = n_ports;
- error = IOCTL(dpif, ODP_PORT_GROUP_GET, &pg);
+ error = do_ioctl(dpif, ODP_PORT_GROUP_GET, "ODP_PORT_GROUP_GET", &pg);
*n_out = error ? 0 : pg.n_ports;
return error;
}
int
dpif_flow_flush(struct dpif *dpif)
{
- return IOCTL(dpif, ODP_FLOW_FLUSH, NULL);
+ return do_ioctl(dpif, ODP_FLOW_FLUSH, "ODP_FLOW_FLUSH", NULL);
+}
+
+static void
+log_flow_message(const struct dpif *dpif, enum vlog_level level, int error,
+ const char *operation,
+ const flow_t *flow, const struct odp_flow_stats *stats,
+ const union odp_action *actions, size_t n_actions)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ ds_put_format(&ds, "dp%u: ", dpif->minor);
+ if (error) {
+ ds_put_cstr(&ds, "failed to ");
+ }
+ ds_put_format(&ds, "%s ", operation);
+ if (error) {
+ ds_put_format(&ds, "(%s) ", strerror(error));
+ }
+ flow_format(&ds, flow);
+ if (stats) {
+ ds_put_cstr(&ds, ", ");
+ format_odp_flow_stats(&ds, stats);
+ }
+ if (actions || n_actions) {
+ ds_put_cstr(&ds, ", actions:");
+ format_odp_actions(&ds, actions, n_actions);
+ }
+ vlog(THIS_MODULE, level, "%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+}
+
+static int
+do_flow_ioctl(const struct dpif *dpif, int cmd, struct odp_flow *flow,
+ const char *operation, bool show_stats)
+{
+ int error = do_ioctl(dpif, cmd, NULL, flow);
+ if (error && show_stats) {
+ flow->n_actions = 0;
+ }
+ if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))) {
+ log_flow_message(dpif, error ? VLL_WARN : VLL_DBG, error, operation,
+ &flow->key,
+ show_stats && !error ? &flow->stats : NULL,
+ flow->actions, flow->n_actions);
+ }
+ return error;
}
int
dpif_flow_add(struct dpif *dpif, struct odp_flow *flow)
{
- if (VLOG_IS_DBG_ENABLED()) {
- char *actions_string = odp_actions_to_string(flow->actions,
- flow->n_actions);
- char *flow_string = flow_to_string(&flow->key);
- VLOG_DBG("adding flow %s with actions %s",
- flow_string, actions_string);
- free(flow_string);
- free(actions_string);
- }
- return IOCTL(dpif, ODP_FLOW_ADD, flow);
+ return do_flow_ioctl(dpif, ODP_FLOW_ADD, flow, "add flow", false);
}
int
flow.key = *key;
flow.actions = (union odp_action *) actions;
flow.n_actions = n_actions;
- return IOCTL(dpif, ODP_FLOW_SET_ACTS, &flow);
+ return do_flow_ioctl(dpif, ODP_FLOW_SET_ACTS, &flow, "set flow actions",
+ false);
}
int
dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
{
check_rw_odp_flow(flow);
- return IOCTL(dpif, ODP_FLOW_DEL, flow);
+ return do_flow_ioctl(dpif, ODP_FLOW_DEL, flow, "delete flow", true);
}
int
dpif_flow_query(const struct dpif *dpif, struct odp_flow *flow)
{
check_rw_odp_flow(flow);
- return IOCTL(dpif, ODP_FLOW_QUERY, flow);
+ return do_flow_ioctl(dpif, ODP_FLOW_QUERY, flow, "query flow", true);
}
int
for (i = 0; i < n; i++) {
check_rw_odp_flow(&flows[i]);
}
- return IOCTL(dpif, ODP_FLOW_QUERY_MULTIPLE, &fv);
+ return do_ioctl(dpif, ODP_FLOW_QUERY_MULTIPLE, "ODP_FLOW_QUERY_MULTIPLE",
+ &fv);
}
int
flows[i].n_actions = 0;
}
}
- error = IOCTL(dpif, ODP_FLOW_LIST, &fv);
+ error = do_ioctl(dpif, ODP_FLOW_LIST, "ODP_FLOW_LIST", &fv);
*n_out = error ? 0 : fv.n_flows;
return error;
}
execute.n_actions = n_actions;
execute.data = buf->data;
execute.length = buf->size;
+#if 0
if (VLOG_IS_DBG_ENABLED()) {
char *actions_string = odp_actions_to_string(actions, n_actions);
char *packet_string = ofp_packet_to_string(buf->data, buf->size,
free(actions_string);
free(packet_string);
}
- return IOCTL(dpif, ODP_EXECUTE, &execute);
+#endif
+ return do_ioctl(dpif, ODP_EXECUTE, "ODP_EXECUTE", &execute);
}
int
dpif_snat_add_port(struct dpif *dpif, const struct odp_snat_config *osc)
{
- return IOCTL(dpif, ODP_SNAT_ADD_PORT, osc);
+ return do_ioctl(dpif, ODP_SNAT_ADD_PORT, "ODP_SNAT_ADD_PORT", osc);
}
int
dpif_snat_del_port(struct dpif *dpif, uint16_t port)
{
int tmp = port;
- return IOCTL(dpif, ODP_SNAT_DEL_PORT, &tmp);
+ return do_ioctl(dpif, ODP_SNAT_DEL_PORT, "ODP_SNAT_DEL_PORT", &tmp);
}
int
return 0;
}
\f
-static char *
-odp_actions_to_string(const union odp_action actions[], size_t n_actions)
-{
- struct ds ds = DS_EMPTY_INITIALIZER;
- if (!n_actions) {
- ds_put_cstr(&ds, "<no actions>");
- } else {
- const union odp_action *a;
- for (a = actions; a < &actions[n_actions]; a++) {
- if (a != actions) {
- ds_put_char(&ds, ',');
- }
- switch (a->type) {
- case ODPAT_OUTPUT:
- ds_put_format(&ds, "out:%"PRIu16, a->output.port);
- break;
- case ODPAT_OUTPUT_GROUP:
- ds_put_format(&ds, "group:%"PRIu16, a->output_group.group);
- break;
- case ODPAT_CONTROLLER:
- ds_put_format(&ds, "controller(arg:%"PRIu32")",
- a->controller.arg);
- break;
- case ODPAT_SET_VLAN_VID:
- ds_put_format(&ds, "vid:%"PRIu16, ntohs(a->vlan_vid.vlan_vid));
- break;
- case ODPAT_SET_VLAN_PCP:
- ds_put_format(&ds, "pri:%"PRIu8, a->vlan_pcp.vlan_pcp);
- break;
- case ODPAT_STRIP_VLAN:
- ds_put_cstr(&ds, "strip-vlan");
- break;
- case ODPAT_SET_DL_SRC:
- ds_put_format(&ds, "dl-src:"ETH_ADDR_FMT,
- ETH_ADDR_ARGS(a->dl_addr.dl_addr));
- break;
- case ODPAT_SET_DL_DST:
- ds_put_format(&ds, "dl-dst:"ETH_ADDR_FMT,
- ETH_ADDR_ARGS(a->dl_addr.dl_addr));
- break;
- case ODPAT_SET_NW_SRC:
- ds_put_format(&ds, "nw-src:"IP_FMT,
- IP_ARGS(&a->nw_addr.nw_addr));
- break;
- case ODPAT_SET_NW_DST:
- ds_put_format(&ds, "nw-dst:"IP_FMT,
- IP_ARGS(&a->nw_addr.nw_addr));
- break;
- case ODPAT_SET_TP_SRC:
- ds_put_format(&ds, "tp-src:%"PRIu16,
- ntohs(a->tp_port.tp_port));
- break;
- case ODPAT_SET_TP_DST:
- ds_put_format(&ds, "tp-dst:%"PRIu16,
- ntohs(a->tp_port.tp_port));
- break;
- case ODPAT_SNAT:
- ds_put_format(&ds, "snat:%"PRIu16, a->snat.port);
- break;
- default:
- ds_put_format(&ds, "unknown(%"PRIu16")", a->type);
- break;
- }
- }
-
- }
- return ds_cstr(&ds);
-}
-
/* There is a tendency to construct odp_flow objects on the stack and to
* forget to properly initialize their "actions" and "n_actions" members.
* When this happens, we get memory corruption because the kernel
#include <config.h>
#include "odp-util.h"
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
+#include "dynamic-string.h"
+#include "flow.h"
+#include "packets.h"
+#include "timeval.h"
#include "util.h"
void
return a;
}
+void
+format_odp_action(struct ds *ds, const union odp_action *a)
+{
+ switch (a->type) {
+ case ODPAT_OUTPUT:
+ ds_put_format(ds, "%"PRIu16, a->output.port);
+ break;
+ case ODPAT_OUTPUT_GROUP:
+ ds_put_format(ds, "g%"PRIu16, a->output_group.group);
+ break;
+ case ODPAT_CONTROLLER:
+ ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
+ break;
+ case ODPAT_SET_VLAN_VID:
+ ds_put_format(ds, "set_vlan(%"PRIu16")", ntohs(a->vlan_vid.vlan_vid));
+ break;
+ case ODPAT_SET_VLAN_PCP:
+ ds_put_format(ds, "set_vlan_pcp(%"PRIu8")", a->vlan_pcp.vlan_pcp);
+ break;
+ case ODPAT_STRIP_VLAN:
+ ds_put_format(ds, "strip_vlan");
+ break;
+ case ODPAT_SET_DL_SRC:
+ ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")",
+ ETH_ADDR_ARGS(a->dl_addr.dl_addr));
+ break;
+ case ODPAT_SET_DL_DST:
+ ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")",
+ ETH_ADDR_ARGS(a->dl_addr.dl_addr));
+ break;
+ case ODPAT_SET_NW_SRC:
+ ds_put_format(ds, "set_nw_src("IP_FMT")",
+ IP_ARGS(&a->nw_addr.nw_addr));
+ break;
+ case ODPAT_SET_NW_DST:
+ ds_put_format(ds, "set_nw_dst("IP_FMT")",
+ IP_ARGS(&a->nw_addr.nw_addr));
+ break;
+ case ODPAT_SET_TP_SRC:
+ ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(a->tp_port.tp_port));
+ break;
+ case ODPAT_SET_TP_DST:
+ ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(a->tp_port.tp_port));
+ break;
+ case ODPAT_SNAT:
+ ds_put_format(ds, "snat(%"PRIu16")", a->snat.port);
+ break;
+ default:
+ ds_put_format(ds, "***bad action %"PRIu16"***", a->type);
+ break;
+ }
+}
+
+void
+format_odp_actions(struct ds *ds, const union odp_action *actions,
+ size_t n_actions)
+{
+ size_t i;
+ for (i = 0; i < n_actions; i++) {
+ if (i) {
+ ds_put_char(ds, ',');
+ }
+ format_odp_action(ds, &actions[i]);
+ }
+ if (!n_actions) {
+ ds_put_cstr(ds, "drop");
+ }
+}
+
+void
+format_odp_flow_stats(struct ds *ds, const struct odp_flow_stats *s)
+{
+ ds_put_format(ds, "packets:%"PRIu64", bytes:%"PRIu64", used:",
+ s->n_packets, s->n_bytes);
+ if (s->used_sec) {
+ long long int used = s->used_sec * 1000 + s->used_nsec / 1000000;
+ ds_put_format(ds, "%.3fs", (time_msec() - used) / 1000.0);
+ } else {
+ ds_put_format(ds, "never");
+ }
+}
+
+void
+format_odp_flow(struct ds *ds, const struct odp_flow *f)
+{
+ flow_format(ds, &f->key);
+ ds_put_cstr(ds, ", ");
+ format_odp_flow_stats(ds, &f->stats);
+ ds_put_cstr(ds, ", actions:");
+ format_odp_actions(ds, f->actions, f->n_actions);
+}
+