X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto-sflow.c;h=208ad8c765762831108ba8fbfbec1aa1ce768201;hb=e53df2065c0fe1cd8e913102913cc8c939994984;hp=608abe905f163920b88d2e87d0d043f37c3631d6;hpb=72b0630028e94a24d92a7c14cd7bce96a252a3f5;p=openvswitch diff --git a/ofproto/ofproto-sflow.c b/ofproto/ofproto-sflow.c index 608abe90..208ad8c7 100644 --- a/ofproto/ofproto-sflow.c +++ b/ofproto/ofproto-sflow.c @@ -54,6 +54,12 @@ struct ofproto_sflow { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); +static bool +nullable_string_is_equal(const char *a, const char *b) +{ + return a ? b && !strcmp(a, b) : !b; +} + static bool ofproto_sflow_options_equal(const struct ofproto_sflow_options *a, const struct ofproto_sflow_options *b) @@ -63,14 +69,15 @@ ofproto_sflow_options_equal(const struct ofproto_sflow_options *a, && a->polling_interval == b->polling_interval && a->header_len == b->header_len && a->sub_id == b->sub_id - && !strcmp(a->agent_device, b->agent_device) - && !strcmp(a->control_ip, b->control_ip)); + && nullable_string_is_equal(a->agent_device, b->agent_device) + && nullable_string_is_equal(a->control_ip, b->control_ip)); } static struct ofproto_sflow_options * ofproto_sflow_options_clone(const struct ofproto_sflow_options *old) { struct ofproto_sflow_options *new = xmemdup(old, sizeof *old); + svec_clone(&new->targets, &old->targets); new->agent_device = old->agent_device ? xstrdup(old->agent_device) : NULL; new->control_ip = old->control_ip ? xstrdup(old->control_ip) : NULL; return new; @@ -80,6 +87,7 @@ static void ofproto_sflow_options_destroy(struct ofproto_sflow_options *options) { if (options) { + svec_destroy(&options->targets); free(options->agent_device); free(options->control_ip); free(options); @@ -140,12 +148,14 @@ sflow_agent_get_counters(void *os_, SFLPoller *poller, counters->ifIndex = SFL_DS_INDEX(poller->dsi); counters->ifType = 6; if (!netdev_get_features(osp->netdev, ¤t, NULL, NULL, NULL)) { + /* The values of ifDirection come from MAU MIB (RFC 2668): 0 = unknown, + 1 = full-duplex, 2 = half-duplex, 3 = in, 4=out */ counters->ifSpeed = netdev_features_to_bps(current); counters->ifDirection = (netdev_features_is_full_duplex(current) ? 1 : 2); } else { counters->ifSpeed = 100000000; - counters->ifDirection = 1; + counters->ifDirection = 0; } if (!netdev_get_flags(osp->netdev, &flags) && flags & NETDEV_UP) { bool carrier; @@ -349,6 +359,13 @@ ofproto_sflow_set_options(struct ofproto_sflow *os, time_t now; int error; + if (!options->targets.n || !options->sampling_rate) { + /* No point in doing any work if there are no targets or nothing to + * sample. */ + ofproto_sflow_clear(os); + return; + } + options_changed = (!os->options || !ofproto_sflow_options_equal(options, os->options)); @@ -361,7 +378,8 @@ ofproto_sflow_set_options(struct ofproto_sflow *os, error = collectors_create(&options->targets, SFL_DEFAULT_COLLECTOR_PORT, &os->collectors); if (os->collectors == NULL) { - VLOG_WARN_RL(&rl, "no configured collectors, sFlow disabled"); + VLOG_WARN_RL(&rl, "no collectors could be initialized, " + "sFlow disabled"); ofproto_sflow_clear(os); return; } @@ -400,10 +418,10 @@ ofproto_sflow_set_options(struct ofproto_sflow *os, sflow_agent_send_packet_cb); receiver = sfl_agent_addReceiver(os->sflow_agent); - sfl_receiver_set_sFlowRcvrOwner(receiver, "OpenVSwitch sFlow"); + sfl_receiver_set_sFlowRcvrOwner(receiver, "Open vSwitch sFlow"); sfl_receiver_set_sFlowRcvrTimeout(receiver, 0xffffffff); - /* Add a single sampler to represent the whole switch (special :0 + /* Add a single sampler to represent the datapath (special :0 * datasource). The alternative is to model a physical switch more closely * and instantiate a separate sampler object for each interface, but then * unicasts would have to be offered to two samplers, and @@ -427,6 +445,14 @@ ofproto_sflow_set_options(struct ofproto_sflow *os, } } +static int +ofproto_sflow_odp_port_to_ifindex(const struct ofproto_sflow *os, + uint16_t odp_port) +{ + struct ofproto_sflow_port *osp = port_array_get(&os->ports, odp_port); + return osp ? SFL_DS_INDEX(osp->dsi) : 0; +} + void ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg) { @@ -475,7 +501,7 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg) /* Build a flow sample */ memset(&fs, 0, sizeof fs); - fs.input = msg->port == ODPP_LOCAL ? 0x3fffffff : msg->port; + fs.input = ofproto_sflow_odp_port_to_ifindex(os, msg->port); fs.output = 0; /* Filled in correctly below. */ fs.sample_pool = hdr->sample_pool; @@ -505,7 +531,7 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg) switch (a->type) { case ODPAT_OUTPUT: - fs.output = a->output.port; + fs.output = ofproto_sflow_odp_port_to_ifindex(os, a->output.port); n_outputs++; break; @@ -527,7 +553,14 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg) break; } } - if (n_outputs > 1 || !fs.output) { + + /* Set output port, as defined by http://www.sflow.org/sflow_version_5.txt + (search for "Input/output port information"). */ + if (!n_outputs) { + /* This value indicates that the packet was dropped for an unknown + * reason. */ + fs.output = 0x40000000 | 256; + } else if (n_outputs > 1 || !fs.output) { /* Setting the high bit means "multiple output ports". */ fs.output = 0x80000000 | n_outputs; }