[ovs-dev] [PATCH] sFlow export: include standard tunnel structures (for GRE, VXLAN etc.)
Romain Lenglet
rlenglet at vmware.com
Wed Oct 9 17:30:17 UTC 2013
Hi Neil,
Thanks for your patch.
I concur with Jesse that making this feature optional is essential.
Tunnel header information is not always desirable.
On Oct 8, 2013, at 10:09 PM, Neil Mckee <neil.mckee at inmon.com> wrote:
>
> On Oct 7, 2013, at 2:57 PM, Ben Pfaff <blp at nicira.com> wrote:
>
>> On Sun, Oct 06, 2013 at 10:11:11PM -0700, Neil Mckee wrote:
>>> Please comment on this proposed patch. It adds the standard
>>> sFlow-TUNNEL structures to the sFlow export, which will be helpful
>>> for tracing tunneled traffic through a network fabric in real-time.
>>>
>>> As part of doing that, it switches over from using odp_port to ofp_port
>>> as the port reference used in dpif-sflow, which allows some only-for-sflow
>>> code to be removed elsewhere. It also completely removes the private
>>> port-lookup hash table that dpif-sflow was maintaining and replaces
>>> it with a simple callback to the parent dpif - presenting the parent with
>>> a structure to fill in with just the necessary details about the port.
>>> This makes it easier for the parent dpif to control what port state is
>>> exposed to the sFlow module during the processing of a packet-sample.
>>>
>>> (This same mechanism can now be extended to expose some
>>> bundle/LAG information, so the standard sFlow-LAG structures can
>>> be exported too, but that can be in another patch).
>>>
>>> This patch also cleans up the way sFlow is treated in ofproto-xlate.c, so
>>> that the upcall cookie just contains the essential details and the
>>> sFlow-specific encoding is migrated into ofproto-dpif-sflow.c.
>>>
>>> Finally a new test for sFlow tunnel structures was added that exercises
>>> the new code. So 'make check TESTSUITEFLAGS="-k sflow"' now runs
>>> two separate tests.
>>>
>>> One very specific question is asked in an XXX comment in ofproto-dpif.c,
>>> regarding which lock should be acquired during the new callback. A little
>>> guidance there would be most appreciated.
>>
>> This commit increases the size of the sflow userdata (the 'sflow'
>> member in struct user_action_cookie) from 8 bytes to 12. If the size
>> increase can be avoided, then it is desirable to avoid it, because
>> only recent versions of the Open vSwitch kernel module support
>> userdata longer than 8 bytes.
>>
>> I'd like to see a full discussion of Jesse's comments.
>>
>> I see various other minor issues but nothing that will be much trouble.
>
> It seemed like the easiest way to reduce the cookie to 8 bytes was to have
> two sFlow cookie types:
>
> USER_ACTION_COOKIE_SFLOW_SINGLEPORT
> USER_ACTION_COOKIE_SFLOW_MULTIPORT
>
> That way there will still be room in case ofp_port_t goes from 16 to 32 bits.
>
> If cookie->type were uint8_t you would recover 8 more bits, if ever needed.
>
> The revised patch is inlined below for your comments. It now also has the
> LAG export (and a test for it). It goes out with the periodic counter-push
> -- not with every packet-sample. This LAG information can be important for
> synthesizing network-wide traffic matrices accurately, and for detecting
> instability promptly:
> http://sflow.org/sflow_lag.txt
>
> Unresolved questions are marked with XXX comments.
>
> Neil
>
>
> Add sFlow Tunnel and LAG structures.
> Signed-off-by: Neil McKee<neil.mckee at inmon.com>
>
> ---
> lib/lacp.c | 64 +++++++++
> lib/lacp.h | 23 +++
> lib/odp-util.c | 51 +++++--
> lib/odp-util.h | 19 ++-
> lib/sflow.h | 38 ++++-
> lib/sflow_agent.c | 15 ++
> lib/sflow_api.h | 1 +
> lib/sflow_receiver.c | 19 +++
> manpages.mk | 8 +-
> ofproto/ofproto-dpif-sflow.c | 326 ++++++++++++++++++++++++++----------------
> ofproto/ofproto-dpif-sflow.h | 25 +++-
> ofproto/ofproto-dpif-upcall.c | 3 +-
> ofproto/ofproto-dpif-xlate.c | 61 ++++----
> ofproto/ofproto-dpif.c | 42 ++++--
> tests/odp.at | 2 +-
> tests/ofproto-dpif.at | 138 ++++++++++++++++++
> tests/test-sflow.c | 82 +++++++++++
> 17 files changed, 714 insertions(+), 203 deletions(-)
>
> diff --git a/lib/lacp.c b/lib/lacp.c
> index 5421e2a..ff83850 100644
> --- a/lib/lacp.c
> +++ b/lib/lacp.c
> @@ -122,6 +122,11 @@ struct slave {
> struct lacp_info ntt_actor; /* Used to decide if we Need To Transmit. */
> struct timer tx; /* Next message transmission timer. */
> struct timer rx; /* Expected message receive timer. */
> + struct {
> + uint32_t rx_pdus; /* dot3adAggPortStatsLACPDUsRx */
> + uint32_t rx_pdus_bad; /* dot3adAggPortStatsIllegalRx */
> + uint32_t tx_pdus; /* dot3adAggPortStatsLACPDUsTx */
> + } counters;
> };
>
> static struct ovs_mutex mutex;
> @@ -316,9 +321,11 @@ lacp_process_packet(struct lacp *lacp, const void *slave_,
> if (!slave) {
> goto out;
> }
> + slave->counters.rx_pdus++;
>
> pdu = parse_lacp_packet(packet);
> if (!pdu) {
> + slave->counters.rx_pdus_bad++;
> VLOG_WARN_RL(&rl, "%s: received an unparsable LACP PDU.", lacp->name);
> goto out;
> }
> @@ -529,6 +536,7 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
> slave->ntt_actor = actor;
> compose_lacp_pdu(&actor, &slave->partner, &pdu);
> send_pdu(slave->aux, &pdu, sizeof pdu);
> + slave->counters.tx_pdus++;
>
> duration = (slave->partner.state & LACP_STATE_TIME
> ? LACP_FAST_TIME_TX
> @@ -954,3 +962,59 @@ lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
> out:
> ovs_mutex_unlock(&mutex);
> }
> +
> +/* Extract a snapshot of the current state and counters for a slave port.
> + Return false if the slave is not active. */
> +bool
> +lacp_get_slave_stats(const struct lacp *lacp, const void *slave_, struct lacp_slave_stats *stats)
> + OVS_EXCLUDED(mutex)
> +{
> + struct slave *slave;
> + struct lacp_info actor;
> + bool ret;
> +
> + ovs_mutex_lock(&mutex);
> +
> + slave = slave_lookup(lacp, slave_);
> + if(slave) {
> + ret = true;
> + slave_get_actor(slave, &actor);
> + memcpy(&stats->dot3adAggPortActorSystemID,
> + actor.sys_id,
> + ETH_ADDR_LEN);
> + memcpy(&stats->dot3adAggPortPartnerOperSystemID,
> + slave->partner.sys_id,
> + ETH_ADDR_LEN);
> + stats->dot3adAggPortAttachedAggID = (lacp->key_slave->key ?
> + lacp->key_slave->key :
> + lacp->key_slave->port_id);
> +
> + /* Construct my admin-state. Assume aggregation is configured on. */
> + stats->dot3adAggPortActorAdminState = LACP_STATE_AGG;
> + if(lacp->active) {
> + stats->dot3adAggPortActorAdminState |= LACP_STATE_ACT;
> + }
> + if(lacp->fast) {
> + stats->dot3adAggPortActorAdminState |= LACP_STATE_TIME;
> + }
> + /* XXX Not sure how to know the partner admin state. It
> + * might have to be captured and remembered during the
> + * negotiation phase.
> + */
> + stats->dot3adAggPortPartnerAdminState = 0;
> +
> + stats->dot3adAggPortActorOperState = actor.state;
> + stats->dot3adAggPortPartnerOperState = slave->partner.state;
> +
> + /* Read out the latest counters */
> + stats->dot3adAggPortStatsLACPDUsRx = slave->counters.rx_pdus;
> + stats->dot3adAggPortStatsIllegalRx = slave->counters.rx_pdus_bad;
> + stats->dot3adAggPortStatsLACPDUsTx = slave->counters.tx_pdus;
> + }
> + else {
> + ret = false;
> + }
> + ovs_mutex_unlock(&mutex);
> + return ret;
> +
> +}
> diff --git a/lib/lacp.h b/lib/lacp.h
> index 89b0e0a..f5fcc96 100644
> --- a/lib/lacp.h
> +++ b/lib/lacp.h
> @@ -69,4 +69,27 @@ typedef void lacp_send_pdu(void *slave, const void *pdu, size_t pdu_size);
> void lacp_run(struct lacp *, lacp_send_pdu *);
> void lacp_wait(struct lacp *);
>
> +struct lacp_slave_stats {
> + /* id */
> + uint8_t dot3adAggPortActorSystemID[ETH_ADDR_LEN];
> + uint8_t dot3adAggPortPartnerOperSystemID[ETH_ADDR_LEN];
> + uint32_t dot3adAggPortAttachedAggID;
> + /* state */
> + uint8_t dot3adAggPortActorAdminState;
> + uint8_t dot3adAggPortActorOperState;
> + uint8_t dot3adAggPortPartnerAdminState;
> + uint8_t dot3adAggPortPartnerOperState;
> + /* counters */
> + uint32_t dot3adAggPortStatsLACPDUsRx;
> + /* uint32_t dot3adAggPortStatsMarkerPDUsRx; */
> + /* uint32_t dot3adAggPortStatsMarkerResponsePDUsRx; */
> + /* uint32_t dot3adAggPortStatsUnknownRx; */
> + uint32_t dot3adAggPortStatsIllegalRx;
> + uint32_t dot3adAggPortStatsLACPDUsTx;
> + /* uint32_t dot3adAggPortStatsMarkerPDUsTx; */
> + /* uint32_t dot3adAggPortStatsMarkerResponsePDUsTx; */
> +};
> +
> +bool lacp_get_slave_stats(const struct lacp *, const void *slave_, struct lacp_slave_stats *);
> +
> #endif /* lacp.h */
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index 5ca8baf..de66ed5 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -294,12 +294,21 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
> userdata_unspec = false;
>
> if (userdata_len == sizeof cookie.sflow
> - && cookie.type == USER_ACTION_COOKIE_SFLOW) {
> + && cookie.type == USER_ACTION_COOKIE_SFLOW_SINGLEPORT) {
> ds_put_format(ds, ",sFlow("
> - "vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")",
> - vlan_tci_to_vid(cookie.sflow.vlan_tci),
> - vlan_tci_to_pcp(cookie.sflow.vlan_tci),
> - cookie.sflow.output);
> + "vid=%"PRIu16",pcp=%"PRIu8
> + ",n_outputs=1,output_port=%"PRIu32")",
> + vlan_tci_to_vid(cookie.sflow.single.vlan_tci),
> + vlan_tci_to_pcp(cookie.sflow.single.vlan_tci),
> + cookie.sflow.single.output_port);
> + } else if (userdata_len == sizeof cookie.sflow
> + && cookie.type == USER_ACTION_COOKIE_SFLOW_MULTIPORT) {
> + ds_put_format(ds, ",sFlow("
> + "vid=%"PRIu16",pcp=%"PRIu8
> + ",n_outputs=%"PRIu32",output_port=0)",
> + vlan_tci_to_vid(cookie.sflow.multi.vlan_tci),
> + vlan_tci_to_pcp(cookie.sflow.multi.vlan_tci),
> + cookie.sflow.multi.n_outputs);
> } else if (userdata_len == sizeof cookie.slow_path
> && cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
> const char *reason;
> @@ -325,8 +334,8 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
> }
>
> if (userdata_unspec) {
> - size_t i;
> - ds_put_format(ds, ",userdata(");
> + size_t i;
> + ds_put_format(ds, ",userdata(");
> for (i = 0; i < userdata_len; i++) {
> ds_put_format(ds, "%02x", userdata[i]);
> }
> @@ -507,7 +516,8 @@ parse_odp_action(const char *s, const struct simap *port_names,
>
> {
> unsigned long long int pid;
> - unsigned long long int output;
> + unsigned long long int n_outputs;
> + unsigned long long int output_port;
> unsigned long long int probability;
> unsigned long long int collector_set_id;
> unsigned long long int obs_domain_id;
> @@ -519,8 +529,8 @@ parse_odp_action(const char *s, const struct simap *port_names,
> odp_put_userspace_action(pid, NULL, 0, actions);
> return n;
> } else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i,"
> - "pcp=%i,output=%lli))%n",
> - &pid, &vid, &pcp, &output, &n) > 0 && n > 0) {
> + "pcp=%i,n_outputs=%lli,output_port=%lli))%n",
> + &pid, &vid, &pcp, &n_outputs, &output_port, &n) > 0 && n > 0) {
> union user_action_cookie cookie;
> uint16_t tci;
>
> @@ -529,11 +539,22 @@ parse_odp_action(const char *s, const struct simap *port_names,
> tci |= VLAN_CFI;
> }
>
> - cookie.type = USER_ACTION_COOKIE_SFLOW;
> - cookie.sflow.vlan_tci = htons(tci);
> - cookie.sflow.output = output;
> - odp_put_userspace_action(pid, &cookie, sizeof cookie.sflow,
> - actions);
> + if(n_outputs == 1) {
> + cookie.type = USER_ACTION_COOKIE_SFLOW_SINGLEPORT;
> + cookie.sflow.single.vlan_tci = htons(tci);
> + cookie.sflow.single.output_port = output_port;
> + odp_put_userspace_action(pid, &cookie,
> + sizeof cookie.sflow.single,
> + actions);
> + }
> + else {
> + cookie.type = USER_ACTION_COOKIE_SFLOW_MULTIPORT;
> + cookie.sflow.multi.vlan_tci = htons(tci);
> + cookie.sflow.multi.n_outputs = n_outputs;
> + odp_put_userspace_action(pid, &cookie,
> + sizeof cookie.sflow.multi,
> + actions);
> + }
> return n;
> } else if (sscanf(s, "userspace(pid=%lli,slow_path(%n", &pid, &n) > 0
> && n > 0) {
> diff --git a/lib/odp-util.h b/lib/odp-util.h
> index 192cfa0..9dc63bb 100644
> --- a/lib/odp-util.h
> +++ b/lib/odp-util.h
> @@ -142,7 +142,8 @@ void commit_odp_actions(const struct flow *, struct flow *base,
>
> enum user_action_cookie_type {
> USER_ACTION_COOKIE_UNSPEC,
> - USER_ACTION_COOKIE_SFLOW, /* Packet for per-bridge sFlow sampling. */
> + USER_ACTION_COOKIE_SFLOW_SINGLEPORT, /* sFlow sample (1 output port). */
> + USER_ACTION_COOKIE_SFLOW_MULTIPORT, /* sFlow sample (N output ports). */
> USER_ACTION_COOKIE_SLOW_PATH, /* Userspace must process this flow. */
> USER_ACTION_COOKIE_FLOW_SAMPLE, /* Packet for per-flow sampling. */
> USER_ACTION_COOKIE_IPFIX, /* Packet for per-bridge IPFIX sampling. */
> @@ -153,10 +154,18 @@ enum user_action_cookie_type {
> union user_action_cookie {
> uint16_t type; /* enum user_action_cookie_type. */
>
> - struct {
> - uint16_t type; /* USER_ACTION_COOKIE_SFLOW. */
> - ovs_be16 vlan_tci; /* Destination VLAN TCI. */
> - uint32_t output; /* SFL_FLOW_SAMPLE_TYPE 'output' value. */
> + union {
> + struct {
> + uint16_t type; /* USER_ACTION_COOKIE_SFLOW_SINGLEPORT. */
> + ovs_be16 vlan_tci; /* Destination VLAN TCI. */
> + ofp_port_t output_port; /* Output port */
> + /* XXX do we need to pad to 8 bytes -- while sizeof(ofp_port_t) is still 2 ?*/
> + } single;
> + struct {
> + uint16_t type; /* USER_ACTION_COOKIE_SFLOW_MULTIPORT. */
> + ovs_be16 vlan_tci; /* Destination VLAN TCI. */
> + uint32_t n_outputs; /* Number of output ports. */
> + } multi;
> } sflow;
>
> struct {
> diff --git a/lib/sflow.h b/lib/sflow.h
> index 0d1f2b9..0038c27 100644
> --- a/lib/sflow.h
> +++ b/lib/sflow.h
> @@ -285,6 +285,8 @@ enum SFLFlow_type_tag {
> SFLFLOW_EX_MPLS_FTN = 1010,
> SFLFLOW_EX_MPLS_LDP_FEC = 1011,
> SFLFLOW_EX_VLAN_TUNNEL = 1012, /* VLAN stack */
> + SFLFLOW_EX_IPV4_TUNNEL_EGRESS = 1023, /* http://sflow.org/sflow_tunnels.txt */
> + SFLFLOW_EX_IPV4_TUNNEL_INGRESS = 1024,
> };
>
> typedef union _SFLFlow_type {
> @@ -382,6 +384,9 @@ typedef struct _SFLFlow_sample_expanded {
>
> /* Counter types */
>
> +#define SFL_UNDEF_COUNTER(c) c=(typeof(c))-1
> +#define SFL_UNDEF_GAUGE(c) c=0
> +
> /* Generic interface counters - see RFC 1573, 2233 */
>
> typedef struct _SFLIf_counters {
> @@ -478,6 +483,35 @@ typedef struct _SFLVlan_counters {
> u_int32_t discards;
> } SFLVlan_counters;
>
> +
> +/* LAG Port Statistics - see http://sflow.org/sflow_lag.txt */
> +/* opaque = counter_data; enterprise = 0; format = 7 */
> +
> +typedef union _SFLLACP_portState {
> + uint32_t all;
> + struct {
> + uint8_t actorAdmin;
> + uint8_t actorOper;
> + uint8_t partnerAdmin;
> + uint8_t partnerOper;
> + } v;
> +} SFLLACP_portState;
> +
> +typedef struct _SFLLACP_counters {
> + uint8_t actorSystemID[8]; /* 6 bytes + 2 pad */
> + uint8_t partnerSystemID[8]; /* 6 bytes + 2 pad */
> + uint32_t attachedAggID;
> + SFLLACP_portState portState;
> + uint32_t LACPDUsRx;
> + uint32_t markerPDUsRx;
> + uint32_t markerResponsePDUsRx;
> + uint32_t unknownRx;
> + uint32_t illegalRx;
> + uint32_t LACPDUsTx;
> + uint32_t markerPDUsTx;
> + uint32_t markerResponsePDUsTx;
> +} SFLLACP_counters;
> +
> /* Counters data */
>
> enum SFLCounters_type_tag {
> @@ -486,7 +520,8 @@ enum SFLCounters_type_tag {
> SFLCOUNTERS_ETHERNET = 2,
> SFLCOUNTERS_TOKENRING = 3,
> SFLCOUNTERS_VG = 4,
> - SFLCOUNTERS_VLAN = 5
> + SFLCOUNTERS_VLAN = 5,
> + SFLCOUNTERS_LACP = 7
> };
>
> typedef union _SFLCounters_type {
> @@ -495,6 +530,7 @@ typedef union _SFLCounters_type {
> SFLTokenring_counters tokenring;
> SFLVg_counters vg;
> SFLVlan_counters vlan;
> + SFLLACP_counters lacp;
> } SFLCounters_type;
>
> typedef struct _SFLCounters_sample_element {
> diff --git a/lib/sflow_agent.c b/lib/sflow_agent.c
> index 817420d..9c2e028 100644
> --- a/lib/sflow_agent.c
> +++ b/lib/sflow_agent.c
> @@ -363,6 +363,21 @@ SFLPoller *sfl_agent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
> return NULL;
> }
>
> +/*_________________-----------------------------------__________________
> + _________________ sfl_agent_getPollerByBridgePort __________________
> + -----------------___________________________________------------------
> +*/
> +
> +SFLPoller *sfl_agent_getPollerByBridgePort(SFLAgent *agent, uint32_t port_no)
> +{
> + /* find it and return it */
> + SFLPoller *pl = agent->pollers;
> + for(; pl != NULL; pl = pl->nxt)
> + if(pl->bridgePort == port_no) return pl;
> + /* not found */
> + return NULL;
> +}
> +
> /*_________________---------------------------__________________
> _________________ sfl_agent_getReceiver __________________
> -----------------___________________________------------------
> diff --git a/lib/sflow_api.h b/lib/sflow_api.h
> index 3cc060b..2730a4c 100644
> --- a/lib/sflow_api.h
> +++ b/lib/sflow_api.h
> @@ -281,6 +281,7 @@ void sfl_agent_set_agentSubId(SFLAgent *agent, u_int32_t subId);
> to get counters if it is not the same as the global ifIndex */
> void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t port_no);
> u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller);
> +SFLPoller *sfl_agent_getPollerByBridgePort(SFLAgent *agent, u_int32_t port_no);
>
> /* call this to indicate a discontinuity with a counter like samplePool so that the
> sflow collector will ignore the next delta */
> diff --git a/lib/sflow_receiver.c b/lib/sflow_receiver.c
> index 3e5a67a..8b3ffad 100644
> --- a/lib/sflow_receiver.c
> +++ b/lib/sflow_receiver.c
> @@ -460,6 +460,8 @@ static int computeFlowSampleSize(SFLReceiver *receiver, SFL_FLOW_SAMPLE_TYPE *fs
> case SFLFLOW_EX_MPLS_FTN: elemSiz = mplsFtnEncodingLength(&elem->flowType.mpls_ftn); break;
> case SFLFLOW_EX_MPLS_LDP_FEC: elemSiz = mplsLdpFecEncodingLength(&elem->flowType.mpls_ldp_fec); break;
> case SFLFLOW_EX_VLAN_TUNNEL: elemSiz = vlanTunnelEncodingLength(&elem->flowType.vlan_tunnel); break;
> + case SFLFLOW_EX_IPV4_TUNNEL_EGRESS: elemSiz = sizeof(SFLSampled_ipv4); break;
> + case SFLFLOW_EX_IPV4_TUNNEL_INGRESS: elemSiz = sizeof(SFLSampled_ipv4); break;
> default:
> sflError(receiver, "unexpected packet_data_tag");
> return -1;
> @@ -556,6 +558,8 @@ int sfl_receiver_writeFlowSample(SFLReceiver *receiver, SFL_FLOW_SAMPLE_TYPE *fs
> putNet32(receiver, elem->flowType.ethernet.eth_type);
> break;
> case SFLFLOW_IPV4:
> + case SFLFLOW_EX_IPV4_TUNNEL_EGRESS:
> + case SFLFLOW_EX_IPV4_TUNNEL_INGRESS:
> putNet32(receiver, elem->flowType.ipv4.length);
> putNet32(receiver, elem->flowType.ipv4.protocol);
> put32(receiver, elem->flowType.ipv4.src_ip.addr);
> @@ -630,6 +634,7 @@ static int computeCountersSampleSize(SFLReceiver *receiver, SFL_COUNTERS_SAMPLE_
> case SFLCOUNTERS_TOKENRING: elemSiz = sizeof(elem->counterBlock.tokenring); break;
> case SFLCOUNTERS_VG: elemSiz = sizeof(elem->counterBlock.vg); break;
> case SFLCOUNTERS_VLAN: elemSiz = sizeof(elem->counterBlock.vlan); break;
> + case SFLCOUNTERS_LACP: elemSiz = sizeof(elem->counterBlock.lacp); break;
> default:
> sflError(receiver, "unexpected counters_tag");
> return -1;
> @@ -731,6 +736,20 @@ int sfl_receiver_writeCountersSample(SFLReceiver *receiver, SFL_COUNTERS_SAMPLE_
> putNet32(receiver, elem->counterBlock.vlan.broadcastPkts);
> putNet32(receiver, elem->counterBlock.vlan.discards);
> break;
> + case SFLCOUNTERS_LACP:
> + putMACAddress(receiver, elem->counterBlock.lacp.actorSystemID);
> + putMACAddress(receiver, elem->counterBlock.lacp.partnerSystemID);
> + putNet32(receiver, elem->counterBlock.lacp.attachedAggID);
> + put32(receiver, elem->counterBlock.lacp.portState.all);
> + putNet32(receiver, elem->counterBlock.lacp.LACPDUsRx);
> + putNet32(receiver, elem->counterBlock.lacp.markerPDUsRx);
> + putNet32(receiver, elem->counterBlock.lacp.markerResponsePDUsRx);
> + putNet32(receiver, elem->counterBlock.lacp.unknownRx);
> + putNet32(receiver, elem->counterBlock.lacp.illegalRx);
> + putNet32(receiver, elem->counterBlock.lacp.LACPDUsTx);
> + putNet32(receiver, elem->counterBlock.lacp.markerPDUsTx);
> + putNet32(receiver, elem->counterBlock.lacp.markerResponsePDUsTx);
> + break;
> default:
> sflError(receiver, "unexpected counters_tag");
> return -1;
> diff --git a/manpages.mk b/manpages.mk
> index 811d2f9..2a34f04 100644
> --- a/manpages.mk
> +++ b/manpages.mk
> @@ -116,6 +116,10 @@ lib/vconn-active.man:
> lib/vconn-passive.man:
> lib/vlog.man:
>
> +utilities/ovs-dpctl-top.8: \
> + utilities/ovs-dpctl-top.8.in
> +utilities/ovs-dpctl-top.8.in:
> +
> utilities/ovs-dpctl.8: \
> utilities/ovs-dpctl.8.in \
> lib/common.man \
> @@ -124,10 +128,6 @@ utilities/ovs-dpctl.8.in:
> lib/common.man:
> lib/vlog.man:
>
> -utilities/ovs-dpctl-top.8: \
> - utilities/ovs-dpctl-top.8.in
> -utilities/ovs-dpctl-top.8.in:
> -
> utilities/ovs-l3ping.8: \
> utilities/ovs-l3ping.8.in \
> lib/common-syn.man \
> diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
> index 158887f..1e90a29 100644
> --- a/ofproto/ofproto-dpif-sflow.c
> +++ b/ofproto/ofproto-dpif-sflow.c
> @@ -24,8 +24,6 @@
> #include "collectors.h"
> #include "compiler.h"
> #include "dpif.h"
> -#include "hash.h"
> -#include "hmap.h"
> #include "netdev.h"
> #include "netlink.h"
> #include "ofpbuf.h"
> @@ -39,32 +37,24 @@
> #include "vlog.h"
> #include "lib/odp-util.h"
> #include "ofproto-provider.h"
> +#include "lacp.h"
>
> VLOG_DEFINE_THIS_MODULE(sflow);
>
> static struct ovs_mutex mutex;
>
> -struct dpif_sflow_port {
> - struct hmap_node hmap_node; /* In struct dpif_sflow's "ports" hmap. */
> - SFLDataSource_instance dsi; /* sFlow library's notion of port number. */
> - struct ofport *ofport; /* To retrive port stats. */
> - odp_port_t odp_port;
> -};
> -
> struct dpif_sflow {
> struct collectors *collectors;
> SFLAgent *sflow_agent;
> struct ofproto_sflow_options *options;
> time_t next_tick;
> size_t n_flood, n_all;
> - struct hmap ports; /* Contains "struct dpif_sflow_port"s. */
> uint32_t probability;
> atomic_int ref_cnt;
> + dpif_sflow_callback port_callback;
> + void *port_callback_magic;
> };
>
> -static void dpif_sflow_del_port__(struct dpif_sflow *,
> - struct dpif_sflow_port *);
> -
> #define RECEIVER_INDEX 1
>
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> @@ -144,21 +134,6 @@ sflow_agent_send_packet_cb(void *ds_, SFLAgent *agent OVS_UNUSED,
> collectors_send(ds->collectors, pkt, pktLen);
> }
>
> -static struct dpif_sflow_port *
> -dpif_sflow_find_port(const struct dpif_sflow *ds, odp_port_t odp_port)
> - OVS_REQUIRES(mutex)
> -{
> - struct dpif_sflow_port *dsp;
> -
> - HMAP_FOR_EACH_IN_BUCKET (dsp, hmap_node, hash_odp_port(odp_port),
> - &ds->ports) {
> - if (dsp->odp_port == odp_port) {
> - return dsp;
> - }
> - }
> - return NULL;
> -}
> -
> static void
> sflow_agent_get_counters(void *ds_, SFLPoller *poller,
> SFL_COUNTERS_SAMPLE_TYPE *cs)
> @@ -167,21 +142,27 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
> struct dpif_sflow *ds = ds_;
> SFLCounters_sample_element elem;
> enum netdev_features current;
> - struct dpif_sflow_port *dsp;
> SFLIf_counters *counters;
> struct netdev_stats stats;
> enum netdev_flags flags;
> -
> - dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
> - if (!dsp) {
> - return;
> + struct dpif_sflow_port_lookup port_lookup;
> + SFLCounters_sample_element lacpElem;
> + struct lacp_slave_stats lacp_stats;
> + SFLLACP_counters *lacp;
> +
> + memset(&port_lookup, 0, sizeof port_lookup);
> + if(!(*ds->port_callback)(ds->port_callback_magic,
> + (ofp_port_t)(poller->bridgePort),
> + &port_lookup)) {
> + return;
> }
> -
> +
> + memset(&elem, 0, sizeof elem);
> elem.tag = SFLCOUNTERS_GENERIC;
> counters = &elem.counterBlock.generic;
> counters->ifIndex = SFL_DS_INDEX(poller->dsi);
> counters->ifType = 6;
> - if (!netdev_get_features(dsp->ofport->netdev, ¤t, NULL, NULL, NULL)) {
> + if (!netdev_get_features(port_lookup.ofport->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, 0);
> @@ -191,9 +172,9 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
> counters->ifSpeed = 100000000;
> counters->ifDirection = 0;
> }
> - if (!netdev_get_flags(dsp->ofport->netdev, &flags) && flags & NETDEV_UP) {
> + if (!netdev_get_flags(port_lookup.ofport->netdev, &flags) && flags & NETDEV_UP) {
> counters->ifStatus = 1; /* ifAdminStatus up. */
> - if (netdev_get_carrier(dsp->ofport->netdev)) {
> + if (netdev_get_carrier(port_lookup.ofport->netdev)) {
> counters->ifStatus |= 2; /* ifOperStatus us. */
> }
> } else {
> @@ -205,23 +186,57 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
> 2. Does the multicast counter include broadcasts?
> 3. Does the rx_packets counter include multicasts/broadcasts?
> */
> - ofproto_port_get_stats(dsp->ofport, &stats);
> + ofproto_port_get_stats(port_lookup.ofport, &stats);
> counters->ifInOctets = stats.rx_bytes;
> counters->ifInUcastPkts = stats.rx_packets;
> counters->ifInMulticastPkts = stats.multicast;
> - counters->ifInBroadcastPkts = -1;
> + SFL_UNDEF_COUNTER(counters->ifInBroadcastPkts);
> counters->ifInDiscards = stats.rx_dropped;
> counters->ifInErrors = stats.rx_errors;
> - counters->ifInUnknownProtos = -1;
> + SFL_UNDEF_COUNTER(counters->ifInUnknownProtos);
> counters->ifOutOctets = stats.tx_bytes;
> counters->ifOutUcastPkts = stats.tx_packets;
> - counters->ifOutMulticastPkts = -1;
> - counters->ifOutBroadcastPkts = -1;
> + SFL_UNDEF_COUNTER(counters->ifOutMulticastPkts);
> + SFL_UNDEF_COUNTER(counters->ifOutBroadcastPkts);
> counters->ifOutDiscards = stats.tx_dropped;
> counters->ifOutErrors = stats.tx_errors;
> counters->ifPromiscuousMode = 0;
>
> SFLADD_ELEMENT(cs, &elem);
> +
> + if(port_lookup.lacp) {
> + memset(&lacp_stats, 0, sizeof lacp_stats);
> + /* Implements sFlow standard: http://sflow.org/sflow_lag.txt */
> + if(lacp_get_slave_stats(port_lookup.lacp,
> + port_lookup.lacp_slave,
> + &lacp_stats)) {
> + memset(&lacpElem, 0, sizeof lacpElem);
> + lacpElem.tag = SFLCOUNTERS_LACP;
> + lacp = &lacpElem.counterBlock.lacp;
> + memcpy(lacp->actorSystemID,
> + lacp_stats.dot3adAggPortActorSystemID,
> + ETH_ADDR_LEN);
> + memcpy(lacp->partnerSystemID,
> + lacp_stats.dot3adAggPortPartnerOperSystemID,
> + ETH_ADDR_LEN);
> + lacp->attachedAggID = lacp_stats.dot3adAggPortAttachedAggID;
> + lacp->portState.v.actorAdmin = lacp_stats.dot3adAggPortActorAdminState;
> + lacp->portState.v.actorOper = lacp_stats.dot3adAggPortActorOperState;
> + lacp->portState.v.partnerAdmin = lacp_stats.dot3adAggPortPartnerAdminState;
> + lacp->portState.v.partnerOper = lacp_stats.dot3adAggPortPartnerOperState;
> + lacp->LACPDUsRx = lacp_stats.dot3adAggPortStatsLACPDUsRx;
> + SFL_UNDEF_COUNTER(lacp->markerPDUsRx);
> + SFL_UNDEF_COUNTER(lacp->markerResponsePDUsRx);
> + SFL_UNDEF_COUNTER(lacp->unknownRx);
> + lacp->illegalRx = lacp_stats.dot3adAggPortStatsIllegalRx;
> + lacp->LACPDUsTx = lacp_stats.dot3adAggPortStatsLACPDUsTx;
> + SFL_UNDEF_COUNTER(lacp->markerPDUsTx);
> + SFL_UNDEF_COUNTER(lacp->markerResponsePDUsTx);
> +
> + SFLADD_ELEMENT(cs, &lacpElem);
> + }
> + }
> +
> sfl_poller_writeCountersSample(poller, cs);
> }
>
> @@ -324,7 +339,6 @@ dpif_sflow_create(void)
>
> ds = xcalloc(1, sizeof *ds);
> ds->next_tick = time_now() + 1;
> - hmap_init(&ds->ports);
> ds->probability = 0;
> route_table_register();
> atomic_init(&ds->ref_cnt, 1);
> @@ -369,84 +383,54 @@ dpif_sflow_unref(struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
> atomic_sub(&ds->ref_cnt, 1, &orig);
> ovs_assert(orig > 0);
> if (orig == 1) {
> - struct dpif_sflow_port *dsp, *next;
> -
> route_table_unregister();
> dpif_sflow_clear(ds);
> - HMAP_FOR_EACH_SAFE (dsp, next, hmap_node, &ds->ports) {
> - dpif_sflow_del_port__(ds, dsp);
> - }
> - hmap_destroy(&ds->ports);
> free(ds);
> }
> }
>
> static void
> -dpif_sflow_add_poller(struct dpif_sflow *ds, struct dpif_sflow_port *dsp)
> +dpif_sflow_add_poller(struct dpif_sflow *ds, uint32_t ifindex, ofp_port_t ofp_port)
> OVS_REQUIRES(mutex)
> {
> - SFLPoller *poller = sfl_agent_addPoller(ds->sflow_agent, &dsp->dsi, ds,
> - sflow_agent_get_counters);
> - sfl_poller_set_sFlowCpInterval(poller, ds->options->polling_interval);
> - sfl_poller_set_sFlowCpReceiver(poller, RECEIVER_INDEX);
> - sfl_poller_set_bridgePort(poller, odp_to_u32(dsp->odp_port));
> + SFLDataSource_instance dsi;
> + SFLPoller *poller;
> + if(ds->sflow_agent) {
> + SFL_DS_SET(dsi, SFL_DSCLASS_IFINDEX, ifindex, 0);
> + poller = sfl_agent_addPoller(ds->sflow_agent, &dsi, ds,
> + sflow_agent_get_counters);
> + sfl_poller_set_sFlowCpInterval(poller, ds->options->polling_interval);
> + sfl_poller_set_sFlowCpReceiver(poller, RECEIVER_INDEX);
> + sfl_poller_set_bridgePort(poller, (uint32_t)ofp_port);
> + }
> }
>
> void
> -dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport,
> - odp_port_t odp_port) OVS_EXCLUDED(mutex)
> +dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport) OVS_EXCLUDED(mutex)
> {
> - struct dpif_sflow_port *dsp;
> int ifindex;
>
> ovs_mutex_lock(&mutex);
> - dpif_sflow_del_port(ds, odp_port);
> -
> + dpif_sflow_del_port(ds, ofport->ofp_port);
> ifindex = netdev_get_ifindex(ofport->netdev);
> -
> - if (ifindex <= 0) {
> - /* Not an ifindex port, so do not add a cross-reference to it here */
> - goto out;
> + if (ifindex > 0) {
> + /* ifindex port, so add a poller for it here */
> + dpif_sflow_add_poller(ds, ifindex, ofport->ofp_port);
> }
> -
> - /* Add to table of ports. */
> - dsp = xmalloc(sizeof *dsp);
> - dsp->ofport = ofport;
> - dsp->odp_port = odp_port;
> - SFL_DS_SET(dsp->dsi, SFL_DSCLASS_IFINDEX, ifindex, 0);
> - hmap_insert(&ds->ports, &dsp->hmap_node, hash_odp_port(odp_port));
> -
> - /* Add poller. */
> - if (ds->sflow_agent) {
> - dpif_sflow_add_poller(ds, dsp);
> - }
> -
> -out:
> ovs_mutex_unlock(&mutex);
> }
>
> -static void
> -dpif_sflow_del_port__(struct dpif_sflow *ds, struct dpif_sflow_port *dsp)
> - OVS_REQUIRES(mutex)
> -{
> - if (ds->sflow_agent) {
> - sfl_agent_removePoller(ds->sflow_agent, &dsp->dsi);
> - sfl_agent_removeSampler(ds->sflow_agent, &dsp->dsi);
> - }
> - hmap_remove(&ds->ports, &dsp->hmap_node);
> - free(dsp);
> -}
> -
> void
> -dpif_sflow_del_port(struct dpif_sflow *ds, odp_port_t odp_port)
> +dpif_sflow_del_port(struct dpif_sflow *ds, ofp_port_t ofp_port)
> OVS_EXCLUDED(mutex)
> {
> - struct dpif_sflow_port *dsp;
> -
> + SFLPoller *poller;
> ovs_mutex_lock(&mutex);
> - dsp = dpif_sflow_find_port(ds, odp_port);
> - if (dsp) {
> - dpif_sflow_del_port__(ds, dsp);
> + if(ds->sflow_agent) {
> + poller = sfl_agent_getPollerByBridgePort(ds->sflow_agent, (uint32_t)ofp_port);
> + if(poller) {
> + sfl_agent_removePoller(ds->sflow_agent, &poller->dsi);
> + }
> }
> ovs_mutex_unlock(&mutex);
> }
> @@ -456,7 +440,6 @@ dpif_sflow_set_options(struct dpif_sflow *ds,
> const struct ofproto_sflow_options *options)
> OVS_EXCLUDED(mutex)
> {
> - struct dpif_sflow_port *dsp;
> bool options_changed;
> SFLReceiver *receiver;
> SFLAddress agentIP;
> @@ -543,33 +526,65 @@ dpif_sflow_set_options(struct dpif_sflow *ds,
> sfl_sampler_set_sFlowFsMaximumHeaderSize(sampler, ds->options->header_len);
> sfl_sampler_set_sFlowFsReceiver(sampler, RECEIVER_INDEX);
>
> - /* Add pollers for the currently known ifindex-ports */
> - HMAP_FOR_EACH (dsp, hmap_node, &ds->ports) {
> - dpif_sflow_add_poller(ds, dsp);
> - }
> -
> -
> out:
> ovs_mutex_unlock(&mutex);
> }
>
> -int
> -dpif_sflow_odp_port_to_ifindex(const struct dpif_sflow *ds,
> - odp_port_t odp_port) OVS_EXCLUDED(mutex)
> +void
> +dpif_sflow_set_port_lookup_callback(struct dpif_sflow *ds,
> + dpif_sflow_callback callback,
> + void *magic)
> + OVS_EXCLUDED(mutex)
> {
> - struct dpif_sflow_port *dsp;
> - int ret;
> -
> ovs_mutex_lock(&mutex);
> - dsp = dpif_sflow_find_port(ds, odp_port);
> - ret = dsp ? SFL_DS_INDEX(dsp->dsi) : 0;
> + ds->port_callback = callback;
> + ds->port_callback_magic = magic;
> ovs_mutex_unlock(&mutex);
> - return ret;
> +}
> +
> +/* Implements sFlow standard: http://sflow.org/sflow_tunnels.txt */
> +static bool
> +dpif_sflow_ipv4_tunnel_encode(SFLSampled_ipv4 *tunnel4,
> + struct dpif_sflow_port_lookup *port_lookup)
> +{
> + const char *netdev_type;
> + const struct netdev_tunnel_config *tunnel_config;
> +
> + /* XXX will need the struct flow here too - for those tunnels that
> + get their config dynamically from the flow. */
> +
> + tunnel_config = netdev_get_tunnel_config(port_lookup->ofport->netdev);
> + if(tunnel_config == NULL) {
> + return false;
> + }
> + netdev_type = netdev_get_type(port_lookup->ofport->netdev);
> + tunnel4->src_ip.addr = tunnel_config->ip_src;
> + tunnel4->dst_ip.addr = tunnel_config->ip_dst;
> + /* Indicate 0==unknown for the src_port. It may be set to a random
> + number on a flow-by-flow basis to increase entropy for ECMP fabrics.
> + The assumption being made here is that it is not so important to
> + report this. At least not important enough to justify the effort
> + of making it accessible here. */
Exporting the source UDP source port is essential.
You also have to export the tunnel key: GRE key (32- or 64-bit), VNI (24-bit), etc.
I don't see how this feature could be useful without the UDP source port and tunnel key.
> + tunnel4->src_port = 0;
> + tunnel4->dst_port = tunnel_config->dst_port;
> + tunnel4->tos = tunnel_config->tos;
> + /* Use the netdev_type to determine the IP protocol
> + that was (or will be) seen on the wire. */
> + if(!strncmp(netdev_type, "gre", strlen("gre"))) {
> + tunnel4->protocol = IPPROTO_GRE;
> + }
> + else if(!strncmp(netdev_type, "vxlan", strlen("vxlan"))) {
> + tunnel4->protocol = IPPROTO_UDP;
> + }
> + else if(!strncmp(netdev_type, "ipsec", strlen("ipsec"))) {
> + tunnel4->protocol = IPPROTO_ESP;
> + }
This list is missing LISP.
And when IPsec is used, please report the encapsulated tunnel header type.
More generally, please accurately report all tunnel types supported by OVS, cf. vswitchd/vswitch.xml's documentation of supported port types: gre, ipsec_gre, gre64, ipsec_gre64, vxlan, and lisp.
> + return true;
> }
>
> void
> dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,
> - const struct flow *flow, odp_port_t odp_in_port,
> + const struct flow *flow,
> const union user_action_cookie *cookie)
> OVS_EXCLUDED(mutex)
> {
> @@ -578,10 +593,13 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,
> SFLSampled_header *header;
> SFLFlow_sample_element switchElem;
> SFLSampler *sampler;
> - struct dpif_sflow_port *in_dsp;
> ovs_be16 vlan_tci;
> + struct dpif_sflow_port_lookup in_lookup, out_lookup;
> + SFLFlow_sample_element in_tunnelElem, out_tunnelElem;
> + int in_ifindex, out_ifindex;
>
> ovs_mutex_lock(&mutex);
> +
> sampler = ds->sflow_agent->samplers;
> if (!sampler) {
> goto out;
> @@ -590,11 +608,26 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,
> /* Build a flow sample. */
> memset(&fs, 0, sizeof fs);
>
> - /* Look up the input ifIndex if this port has one. Otherwise just
> - * leave it as 0 (meaning 'unknown') and continue. */
> - in_dsp = dpif_sflow_find_port(ds, odp_in_port);
> - if (in_dsp) {
> - fs.input = SFL_DS_INDEX(in_dsp->dsi);
> + memset(&in_lookup, 0, sizeof in_lookup);
> + if((*ds->port_callback)(ds->port_callback_magic,
> + flow->in_port.ofp_port,
> + &in_lookup)) {
> + if(in_lookup.ofport->netdev) {
> + /* Look up the input ifIndex if this port has one. Otherwise just
> + * leave it as 0 (meaning 'unknown') and continue. */
> + in_ifindex = netdev_get_ifindex(in_lookup.ofport->netdev);
> + if(in_ifindex > 0) {
> + fs.input = in_ifindex;
> + }
> + }
> + if(in_lookup.is_tunnel) {
> + memset(&in_tunnelElem, 0, sizeof in_tunnelElem);
> + in_tunnelElem.tag = SFLFLOW_EX_IPV4_TUNNEL_INGRESS;
> + if(dpif_sflow_ipv4_tunnel_encode(&in_tunnelElem.flowType.ipv4,
> + &in_lookup)) {
> + SFLADD_ELEMENT(&fs, &in_tunnelElem);
> + }
> + }
> }
>
> /* Make the assumption that the random number generator in the datapath converges
> @@ -623,15 +656,62 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,
> switchElem.flowType.sw.src_priority = vlan_tci_to_pcp(flow->vlan_tci);
>
> /* Retrieve data from user_action_cookie. */
> - vlan_tci = cookie->sflow.vlan_tci;
> - switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(vlan_tci);
> - switchElem.flowType.sw.dst_priority = vlan_tci_to_pcp(vlan_tci);
> + if(cookie->type == USER_ACTION_COOKIE_SFLOW_MULTIPORT) {
> + VLOG_INFO("sFlow cookie multiport");
> + vlan_tci = cookie->sflow.multi.vlan_tci;
> + switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(vlan_tci);
> + switchElem.flowType.sw.dst_priority = vlan_tci_to_pcp(vlan_tci);
> + /* See http://www.sflow.org/sflow_version_5.txt (search for "Input/output
> + * port information") */
> + if(cookie->sflow.multi.n_outputs == 0) {
> + /* 0x40000000 | 256 means "packet dropped for unknown reason". */
> + fs.output = 0x40000000 | 256;
> + }
> + else {
> + /* 0x80000000 means "multiple output ports. */
> + fs.output = 0x80000000 | cookie->sflow.multi.n_outputs;
> + }
> + }
> + else if(cookie->type == USER_ACTION_COOKIE_SFLOW_SINGLEPORT) {
> + VLOG_INFO("sFlow cookie singleport");
> + vlan_tci = cookie->sflow.single.vlan_tci;
> + switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(vlan_tci);
> + switchElem.flowType.sw.dst_priority = vlan_tci_to_pcp(vlan_tci);
> +
> + if(cookie->sflow.single.output_port) {
> + memset(&out_lookup, 0, sizeof out_lookup);
> + if((*ds->port_callback)(ds->port_callback_magic,
> + cookie->sflow.single.output_port,
> + &out_lookup)) {
> + if(out_lookup.ofport->netdev) {
> + /* Look up the output ifIndex if this port has one. Otherwise just
> + * leave it as 0 (meaning 'unknown') and continue. */
> + out_ifindex = netdev_get_ifindex(out_lookup.ofport->netdev);
> + if(out_ifindex > 0) {
> + fs.output = out_ifindex;
> + }
> + }
> + if(out_lookup.is_tunnel) {
> + memset(&out_tunnelElem, 0, sizeof out_tunnelElem);
> + out_tunnelElem.tag = SFLFLOW_EX_IPV4_TUNNEL_EGRESS;
> + if(dpif_sflow_ipv4_tunnel_encode(&out_tunnelElem.flowType.ipv4,
> + &out_lookup)) {
> + VLOG_INFO("sFlow add tunnel element");
> + SFLADD_ELEMENT(&fs, &out_tunnelElem);
> + }
> + }
> + }
> + }
> + }
> + else {
> + VLOG_WARN("unknown upcall cookie type: %"PRIu16, cookie->type);
> + }
>
> - fs.output = cookie->sflow.output;
>
> /* Submit the flow sample to be encoded into the next datagram. */
> SFLADD_ELEMENT(&fs, &hdrElem);
> SFLADD_ELEMENT(&fs, &switchElem);
> + VLOG_INFO("sFlow writeFlowSample");
> sfl_sampler_writeFlowSample(sampler, &fs);
>
> out:
> diff --git a/ofproto/ofproto-dpif-sflow.h b/ofproto/ofproto-dpif-sflow.h
> index d53c95c..736256a 100644
> --- a/ofproto/ofproto-dpif-sflow.h
> +++ b/ofproto/ofproto-dpif-sflow.h
> @@ -21,6 +21,7 @@
> #include <stdint.h>
> #include "svec.h"
> #include "lib/odp-util.h"
> +#include "lacp.h"
>
> struct dpif;
> struct dpif_upcall;
> @@ -34,14 +35,28 @@ void dpif_sflow_unref(struct dpif_sflow *);
>
> uint32_t dpif_sflow_get_probability(const struct dpif_sflow *);
>
> +struct dpif_sflow_port_lookup {
> + struct ofport *ofport;
> + /* indicate tunnel */
> + bool is_tunnel;
> + /* LAG/bundle details */
> + struct lacp *lacp;
> + void *lacp_slave;
> +};
> +
> +typedef bool (*dpif_sflow_callback)(void *, ofp_port_t, struct dpif_sflow_port_lookup *);
> +
> +void dpif_sflow_set_port_lookup_callback(struct dpif_sflow *, dpif_sflow_callback, void *);
> +
> void dpif_sflow_set_options(struct dpif_sflow *,
> const struct ofproto_sflow_options *);
> +
> void dpif_sflow_clear(struct dpif_sflow *);
> bool dpif_sflow_is_enabled(const struct dpif_sflow *);
>
> -void dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport,
> - odp_port_t odp_port);
> -void dpif_sflow_del_port(struct dpif_sflow *, odp_port_t odp_port);
> +void dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport);
> +
> +void dpif_sflow_del_port(struct dpif_sflow *, ofp_port_t ofp_port);
>
> void dpif_sflow_run(struct dpif_sflow *);
> void dpif_sflow_wait(struct dpif_sflow *);
> @@ -49,10 +64,6 @@ void dpif_sflow_wait(struct dpif_sflow *);
> void dpif_sflow_received(struct dpif_sflow *,
> struct ofpbuf *,
> const struct flow *,
> - odp_port_t odp_port,
> const union user_action_cookie *);
>
> -int dpif_sflow_odp_port_to_ifindex(const struct dpif_sflow *,
> - odp_port_t odp_port);
> -
> #endif /* ofproto/ofproto-dpif-sflow.h */
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index d75c61b..668d5f9 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -456,7 +456,8 @@ classify_upcall(const struct upcall *upcall)
> memset(&cookie, 0, sizeof cookie);
> memcpy(&cookie, nl_attr_get(dpif_upcall->userdata), userdata_len);
> if (userdata_len == sizeof cookie.sflow
> - && cookie.type == USER_ACTION_COOKIE_SFLOW) {
> + && (cookie.type == USER_ACTION_COOKIE_SFLOW_SINGLEPORT
> + || cookie.type == USER_ACTION_COOKIE_SFLOW_MULTIPORT)) {
> return SFLOW_UPCALL;
> } else if (userdata_len == sizeof cookie.slow_path
> && cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index a5b6814..b3898e4 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -162,7 +162,7 @@ struct xlate_ctx {
> uint32_t orig_skb_priority; /* Priority when packet arrived. */
> uint8_t table_id; /* OpenFlow table ID where flow was found. */
> uint32_t sflow_n_outputs; /* Number of output ports. */
> - odp_port_t sflow_odp_port; /* Output port for composing sFlow action. */
> + odp_port_t sflow_ofp_port; /* Output port for composing sFlow action. */
> uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
> bool exit; /* No further actions should be processed. */
> };
> @@ -1350,34 +1350,19 @@ compose_sample_action(const struct xbridge *xbridge,
> }
>
> static void
> -compose_sflow_cookie(const struct xbridge *xbridge, ovs_be16 vlan_tci,
> - odp_port_t odp_port, unsigned int n_outputs,
> +compose_sflow_cookie(ovs_be16 vlan_tci,
> + ofp_port_t ofp_port, unsigned int n_outputs,
> union user_action_cookie *cookie)
> {
> - int ifindex;
> -
> - cookie->type = USER_ACTION_COOKIE_SFLOW;
> - cookie->sflow.vlan_tci = vlan_tci;
> -
> - /* See http://www.sflow.org/sflow_version_5.txt (search for "Input/output
> - * port information") for the interpretation of cookie->output. */
> - switch (n_outputs) {
> - case 0:
> - /* 0x40000000 | 256 means "packet dropped for unknown reason". */
> - cookie->sflow.output = 0x40000000 | 256;
> - break;
> -
> - case 1:
> - ifindex = dpif_sflow_odp_port_to_ifindex(xbridge->sflow, odp_port);
> - if (ifindex) {
> - cookie->sflow.output = ifindex;
> - break;
> - }
> - /* Fall through. */
> - default:
> - /* 0x80000000 means "multiple output ports. */
> - cookie->sflow.output = 0x80000000 | n_outputs;
> - break;
> + if(n_outputs == 1) {
> + cookie->type = USER_ACTION_COOKIE_SFLOW_SINGLEPORT;
> + cookie->sflow.single.vlan_tci = vlan_tci;
> + cookie->sflow.single.output_port = ofp_port;
> + }
> + else {
> + cookie->type = USER_ACTION_COOKIE_SFLOW_MULTIPORT;
> + cookie->sflow.multi.vlan_tci = vlan_tci;
> + cookie->sflow.multi.n_outputs = (uint32_t)n_outputs;
> }
> }
>
> @@ -1386,7 +1371,7 @@ static size_t
> compose_sflow_action(const struct xbridge *xbridge,
> struct ofpbuf *odp_actions,
> const struct flow *flow,
> - odp_port_t odp_port)
> + ofp_port_t ofp_port)
> {
> uint32_t probability;
> union user_action_cookie cookie;
> @@ -1396,8 +1381,11 @@ compose_sflow_action(const struct xbridge *xbridge,
> }
>
> probability = dpif_sflow_get_probability(xbridge->sflow);
> - compose_sflow_cookie(xbridge, htons(0), odp_port,
> - odp_port == ODPP_NONE ? 0 : 1, &cookie);
> + // maybe we should be putting something like flow->out_port.ofp_port in here?
> + // -- and flow->in_port.ofp_port too if that's the easiest way to get the tunnel
> + // ids to the sFlow module?
> + compose_sflow_cookie(htons(0), ofp_port,
> + ofp_port == OFPP_NONE ? 0 : 1, &cookie);
>
> return compose_sample_action(xbridge, odp_actions, flow, probability,
> &cookie, sizeof cookie.sflow);
> @@ -1449,8 +1437,8 @@ add_sflow_action(struct xlate_ctx *ctx)
> {
> ctx->user_cookie_offset = compose_sflow_action(ctx->xbridge,
> &ctx->xout->odp_actions,
> - &ctx->xin->flow, ODPP_NONE);
> - ctx->sflow_odp_port = 0;
> + &ctx->xin->flow, OFPP_NONE);
> + ctx->sflow_ofp_port = 0;
> ctx->sflow_n_outputs = 0;
> }
>
> @@ -1478,10 +1466,11 @@ fix_sflow_action(struct xlate_ctx *ctx)
>
> cookie = ofpbuf_at(&ctx->xout->odp_actions, ctx->user_cookie_offset,
> sizeof cookie->sflow);
> - ovs_assert(cookie->type == USER_ACTION_COOKIE_SFLOW);
> + ovs_assert(cookie->type == USER_ACTION_COOKIE_SFLOW_SINGLEPORT
> + || cookie->type == USER_ACTION_COOKIE_SFLOW_MULTIPORT);
>
> - compose_sflow_cookie(ctx->xbridge, base->vlan_tci,
> - ctx->sflow_odp_port, ctx->sflow_n_outputs, cookie);
> + compose_sflow_cookie(base->vlan_tci,
> + ctx->sflow_ofp_port, ctx->sflow_n_outputs, cookie);
> }
>
> static enum slow_path_reason
> @@ -1649,7 +1638,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
> nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT,
> out_port);
>
> - ctx->sflow_odp_port = odp_port;
> + ctx->sflow_ofp_port = ofp_port;
> ctx->sflow_n_outputs++;
> ctx->xout->nf_output_iface = ofp_port;
> }
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 80874b8..3bacd56 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -1763,7 +1763,7 @@ port_construct(struct ofport *port_)
> dpif_port_destroy(&dpif_port);
>
> if (ofproto->sflow) {
> - dpif_sflow_add_port(ofproto->sflow, port_, port->odp_port);
> + dpif_sflow_add_port(ofproto->sflow, port_);
> }
>
> return 0;
> @@ -1863,24 +1863,47 @@ port_reconfigured(struct ofport *port_, enum ofputil_port_config old_config)
> }
> }
>
> +static bool
> +dpif_sflow_port_lookup_callback(void *magic, ofp_port_t ofp_port, struct dpif_sflow_port_lookup *port_lookup)
> +{
> + /* XXX do we need to acquire ofproto_mutex here? Or should it be acquired in handle_sflow_upcall() below,
> + * so that it will not be released until after the sFlow-module has followed the pointers we are giving
> + * it here and the sflow sample has been fully processed? */
> +
> + struct ofproto_dpif *ofproto = (struct ofproto_dpif *)magic;
> + struct ofport_dpif *port = get_ofp_port(ofproto, ofp_port);
> + if(port) {
> + port_lookup->ofport = &port->up;
> + port_lookup->is_tunnel = port->is_tunnel;
> + if(port->bundle
> + && port->bundle->lacp) {
> + port_lookup->lacp = port->bundle->lacp;
> + port_lookup->lacp_slave = port;
> + }
> + return true;
> + }
> + return false;
> +}
> +
> +
> static int
> set_sflow(struct ofproto *ofproto_,
> const struct ofproto_sflow_options *sflow_options)
> {
> struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
> struct dpif_sflow *ds = ofproto->sflow;
> + struct ofport_dpif *ofport;
>
> if (sflow_options) {
> if (!ds) {
> - struct ofport_dpif *ofport;
> -
> - ds = ofproto->sflow = dpif_sflow_create();
> - HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
> - dpif_sflow_add_port(ds, &ofport->up, ofport->odp_port);
> - }
> - ofproto->backer->need_revalidate = REV_RECONFIGURE;
> + ds = ofproto->sflow = dpif_sflow_create();
> + ofproto->backer->need_revalidate = REV_RECONFIGURE;
> }
> + dpif_sflow_set_port_lookup_callback(ds, dpif_sflow_port_lookup_callback, (void *)ofproto);
> dpif_sflow_set_options(ds, sflow_options);
> + HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
> + dpif_sflow_add_port(ds, &ofport->up);
> + }
> } else {
> if (ds) {
> dpif_sflow_unref(ds);
> @@ -3444,8 +3467,7 @@ handle_sflow_upcall(struct dpif_backer *backer,
>
> memset(&cookie, 0, sizeof cookie);
> memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof cookie.sflow);
> - dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
> - odp_in_port, &cookie);
> + dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, &cookie);
> }
>
> static void
> diff --git a/tests/odp.at b/tests/odp.at
> index 469e120..7b5fef1 100644
> --- a/tests/odp.at
> +++ b/tests/odp.at
> @@ -155,7 +155,7 @@ AT_SETUP([OVS datapath actions parsing and formatting - valid forms])
> AT_DATA([actions.txt], [dnl
> 1,2,3
> userspace(pid=555666777)
> -userspace(pid=6633,sFlow(vid=9,pcp=7,output=10))
> +userspace(pid=6633,sFlow(vid=9,pcp=7,n_outputs=1,output_port=10))
> userspace(pid=9765,slow_path())
> userspace(pid=9765,slow_path(cfm))
> userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f))
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index f67c3ab..77bd6b7 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -1831,6 +1831,144 @@ IFCOUNTERS
> AT_CLEANUP
>
>
> +dnl Test sFlow tunnel structures.
> +AT_SETUP([ofproto-dpif - sFlow tunnel structures])
> +OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=gre \
> + options:remote_ip=1.1.1.1 options:local_ip=2.2.2.2 \
> + options:key=5 ofport_request=1\
> + -- add-port br0 p2 -- set Interface p2 type=dummy \
> + options:ifindex=1002 ofport_request=2])
> +AT_DATA([flows.txt], [dnl
> +actions=output:1
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +AT_CHECK([ovs-appctl dpif/show | tail -n +5], [0], [dnl
> + br0 65534/100: (dummy)
> + p1 1/1: (gre: key=5, local_ip=2.2.2.2, remote_ip=1.1.1.1)
> + p2 2/2: (dummy: ifindex=1002)
> +])
> +
> +dnl set up sFlow logging
> +dnl ON_EXIT([kill `cat test-sflow.pid`])
> +AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
> +AT_CAPTURE_FILE([sflow.log])
> +SFLOW_PORT=`parse_listening_port < test-sflow.log`
> +ovs-appctl time/stop
> +ovs-vsctl \
> + set Bridge br0 sflow=@sf -- \
> + --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
> + header=128 sampling=1 polling=0
> +
> +dnl use ofproto/trace to check the actions
> +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=4,ttl=128,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> + [Datapath actions: sample(sample=100.0%,actions(userspace(pid=0,sFlow(vid=0,pcp=0,n_outputs=1,output_port=1)))),set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,tos=0x0,ttl=64,flags(df,key))),1
> +])
> +
> +dnl use netdev-dummy/receive to send a packet that will be sampled
> +AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=4,ttl=128,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
> +
> +dnl sleep long enough to get the sFlow datagram flushed out (may be delayed for up to 1 second)
> +for i in `seq 1 30`; do
> + ovs-appctl time/warp 100
> +done
> +OVS_VSWITCHD_STOP
> +ovs-appctl -t test-sflow exit
> +
> +AT_CHECK([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
> + /g']], [0], [dnl
> +HEADER
> + dgramSeqNo=1
> + ds=127.0.0.1>2:1000
> + fsSeqNo=1
> + tunnel4_out_length=0
> + tunnel4_out_protocol=47
> + tunnel4_out_src=2.2.2.2
> + tunnel4_out_dst=1.1.1.1
> + tunnel4_out_src_port=0
> + tunnel4_out_dst_port=0
> + tunnel4_out_tcp_flags=0
> + tunnel4_out_tos=0
> + in_vlan=0
> + in_priority=0
> + out_vlan=0
> + out_priority=0
> + meanSkip=1
> + samplePool=1
> + dropEvents=0
> + in_ifindex=1002
> + in_format=0
> + out_ifindex=0
> + out_format=0
> + hdr_prot=1
> + pkt_len=64
> + stripped=4
> + hdr_len=60
> + hdr=50-54-00-00-00-07-50-54-00-00-00-05-08-00-45-04-00-28-00-00-00-00-80-06-B9-78-C0-A8-00-01-C0-A8-00-02-00-08-00-09-00-00-00-00-00-00-00-00-50-00-00-00-00-00-00-00-00-00-00-00-00-00
> +])
> +AT_CLEANUP
> +
> +dnl Test sFlow LAG structures
> +AT_SETUP([ofproto-dpif - sFlow LACP structures])
> +
> +OVS_VSWITCHD_START([dnl
> + add-bond br0 bond p1 p2 --\
> + set Port bond lacp=active bond-mode=active-backup \
> + other_config:lacp-time="fast" \
> + other_config:lacp-system-id=11:22:33:44:55:66 \
> + other_config:lacp-system-priority=54321 --\
> + set Interface p1 type=dummy \
> + other_config:lacp-port-id=11 \
> + other_config:lacp-port-priority=111 \
> + other_config:lacp-aggregation-key=3333 --\
> + set Interface p2 type=dummy \
> + other_config:lacp-port-id=22 \
> + other_config:lacp-port-priority=222 \
> + other_config:lacp-aggregation-key=3333 ])
> +
> +ON_EXIT([kill `cat test-sflow.pid`])
> +AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
> +AT_CAPTURE_FILE([sflow.log])
> +SFLOW_PORT=`parse_listening_port < test-sflow.log`
> +
> +ovs-appctl time/stop
> +
> +ovs-vsctl \
> + set Interface p1 options:ifindex=1003 -- \
> + set Bridge br0 sflow=@sf -- \
> + --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
> + header=128 sampling=1 polling=1
> +
> +dnl sleep long enough to get the sFlow datagram flushed out (may be delayed for up to 1 second)
> +for i in `seq 1 30`; do
> + ovs-appctl time/warp 100
> +done
> +OVS_VSWITCHD_STOP
> +ovs-appctl -t test-sflow exit
> +
> +AT_CHECK([[sort sflow.log | $EGREP 'LACPCOUNTERS|ERROR' | head -n 1 | sed 's/ /\
> + /g']], [0], [dnl
> +LACPCOUNTERS
> + sysID=11:22:33:44:55:66
> + partnerID=00:00:00:00:00:00
> + aggID=3333
> + actorAdmin=0x7
> + actorOper=0xbf
> + partnerAdmin=0x0
> + partnerOper=0x2
> + LACPUDsRx=0
> + markerPDUsRx=4294967295
> + markerRespPDUsRx=4294967295
> + unknownRx=4294967295
> + illegalRx=0
> + LACPUDsTx=1
> + markerPDUsTx=4294967295
> + markerRespPDUsTx=4294967295
> +])
> +
> +AT_CLEANUP
>
> dnl Test that basic NetFlow reports flow statistics correctly:
> dnl - The initial packet of a flow are correctly accounted.
> diff --git a/tests/test-sflow.c b/tests/test-sflow.c
> index cba01b9..c53e5ab 100644
> --- a/tests/test-sflow.c
> +++ b/tests/test-sflow.c
> @@ -54,8 +54,11 @@ static unixctl_cb_func test_sflow_exit;
>
> /* Structure element tag numbers. */
> #define SFLOW_TAG_CTR_IFCOUNTERS 1
> +#define SFLOW_TAG_CTR_LACPCOUNTERS 7
> #define SFLOW_TAG_PKT_HEADER 1
> #define SFLOW_TAG_PKT_SWITCH 1001
> +#define SFLOW_TAG_PKT_TUNNEL4_OUT 1023
> +#define SFLOW_TAG_PKT_TUNNEL4_IN 1024
>
> struct sflow_addr {
> enum {
> @@ -99,7 +102,10 @@ struct sflow_xdr {
> struct {
> uint32_t HEADER;
> uint32_t SWITCH;
> + uint32_t TUNNEL4_OUT;
> + uint32_t TUNNEL4_IN;
> uint32_t IFCOUNTERS;
> + uint32_t LACPCOUNTERS;
> } offset;
>
> /* Flow sample fields. */
> @@ -221,6 +227,42 @@ process_counter_sample(struct sflow_xdr *x)
> printf(" promiscuous=%"PRIu32, sflowxdr_next(x));
> printf("\n");
> }
> + if(x->offset.LACPCOUNTERS) {
> + uint8_t *mac;
> + union {
> + uint32_t all;
> + struct {
> + uint8_t actorAdmin;
> + uint8_t actorOper;
> + uint8_t partnerAdmin;
> + uint8_t partnerOper;
> + } v;
> + } state;
> +
> + sflowxdr_setc(x, x->offset.LACPCOUNTERS);
> + printf("LACPCOUNTERS");
> + mac = (uint8_t *)sflowxdr_str(x);
> + printf(" sysID="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
> + sflowxdr_skip(x, 2);
> + mac = (uint8_t *)sflowxdr_str(x);
> + printf(" partnerID="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
> + sflowxdr_skip(x, 2);
> + printf(" aggID=%"PRIu32, sflowxdr_next(x));
> + state.all = sflowxdr_next_n(x);
> + printf(" actorAdmin=0x%"PRIx32, state.v.actorAdmin);
> + printf(" actorOper=0x%"PRIx32, state.v.actorOper);
> + printf(" partnerAdmin=0x%"PRIx32, state.v.partnerAdmin);
> + printf(" partnerOper=0x%"PRIx32, state.v.partnerOper);
> + printf(" LACPUDsRx=%"PRIu32, sflowxdr_next(x));
> + printf(" markerPDUsRx=%"PRIu32, sflowxdr_next(x));
> + printf(" markerRespPDUsRx=%"PRIu32, sflowxdr_next(x));
> + printf(" unknownRx=%"PRIu32, sflowxdr_next(x));
> + printf(" illegalRx=%"PRIu32, sflowxdr_next(x));
> + printf(" LACPUDsTx=%"PRIu32, sflowxdr_next(x));
> + printf(" markerPDUsTx=%"PRIu32, sflowxdr_next(x));
> + printf(" markerRespPDUsTx=%"PRIu32, sflowxdr_next(x));
> + printf("\n");
> + }
> }
>
> static char
> @@ -251,6 +293,25 @@ print_hex(const char *a, int len, char *buf, int bufLen)
> return b;
> }
>
> +static void
> +print_struct_ipv4(struct sflow_xdr *x, const char *prefix)
> +{
> + uint32_t src, dst;
> +
> + printf(" %s_length=%"PRIu32, prefix, sflowxdr_next(x));
> + printf(" %s_protocol=%"PRIu32, prefix, sflowxdr_next(x));
> +
> + src = sflowxdr_next_n(x);
> + dst = sflowxdr_next_n(x);
> + printf(" %s_src="IP_FMT, prefix, IP_ARGS(src));
> + printf(" %s_dst="IP_FMT, prefix, IP_ARGS(dst));
> +
> + printf(" %s_src_port=%"PRIu32, prefix, sflowxdr_next(x));
> + printf(" %s_dst_port=%"PRIu32, prefix, sflowxdr_next(x));
> + printf(" %s_tcp_flags=%"PRIu32, prefix, sflowxdr_next(x));
> + printf(" %s_tos=%"PRIu32, prefix, sflowxdr_next(x));
> +}
> +
> #define SFLOW_HEX_SCRATCH 1024
>
> static void
> @@ -266,6 +327,16 @@ process_flow_sample(struct sflow_xdr *x)
> x->agentIPStr, x->dsClass, x->dsIndex);
> printf(" fsSeqNo=%"PRIu32, x->fsSeqNo);
>
> + if (x->offset.TUNNEL4_IN) {
> + sflowxdr_setc(x, x->offset.TUNNEL4_IN);
> + print_struct_ipv4(x, "tunnel4_in");
> + }
> +
> + if (x->offset.TUNNEL4_OUT) {
> + sflowxdr_setc(x, x->offset.TUNNEL4_OUT);
> + print_struct_ipv4(x, "tunnel4_out");
> + }
> +
> if (x->offset.SWITCH) {
> sflowxdr_setc(x, x->offset.SWITCH);
> printf(" in_vlan=%"PRIu32, sflowxdr_next(x));
> @@ -374,6 +445,9 @@ process_datagram(struct sflow_xdr *x)
> case SFLOW_TAG_CTR_IFCOUNTERS:
> sflowxdr_mark_unique(x, &x->offset.IFCOUNTERS);
> break;
> + case SFLOW_TAG_CTR_LACPCOUNTERS:
> + sflowxdr_mark_unique(x, &x->offset.LACPCOUNTERS);
> + break;
>
> /* Add others here... */
> }
> @@ -442,6 +516,14 @@ process_datagram(struct sflow_xdr *x)
> sflowxdr_mark_unique(x, &x->offset.SWITCH);
> break;
>
> + case SFLOW_TAG_PKT_TUNNEL4_OUT:
> + sflowxdr_mark_unique(x, &x->offset.TUNNEL4_OUT);
> + break;
> +
> + case SFLOW_TAG_PKT_TUNNEL4_IN:
> + sflowxdr_mark_unique(x, &x->offset.TUNNEL4_IN);
> + break;
> +
> /* Add others here... */
> }
>
> --
> 1.8.1.4
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list