[PATCH] sFlow LAG and Tunnel export

Neil McKee neil.mckee at inmon.com
Thu Nov 28 12:46:44 UTC 2013


Eliminates hash-table from ofproto-dpif-sflow. Instead a callback
to ofproto-dpif is used to look up counter and packet info. The
ofp-port is now supplied in the sFlow cookie for this purpose,
rather than the odp-port as it was before.  This brings it into
line with other upcall consumers.  The cookie is split
into two variants: one for single-output and one for multi-output,
which serves to keep it under 64-bits in both cases. The
sFlow LAG and Tunnel structures are added.  Not all
fields are populated, but this is allowed by the standard.
The simple presence of the Tunnel structure would be worthwhile
even if no fields were populated because it signals the presence
of a tunnel to the sFlow collector.  More details can always be
filled in later if performance and complexity considerations
allow. It is more likely that this can happen on the receive
path than the transmit path, because the transmit path may
include tunnels defined in openflow rules.  With sFlow
monitoring the expectation is that observations from the
upstream switch port can always be used to fill in any gaps,
and the preference is always to minimize the impact on
performance, so this approach is within the spirit of the
standard.
Finally, new unit tests are added for the Tunnel and LAG export.

Signed-off-by: Neil McKee <neil.mckee at inmon.com>
---
 lib/lacp.c                    |   64 ++++++
 lib/lacp.h                    |   23 ++
 lib/odp-util.c                |   53 +++--
 lib/odp-util.h                |   19 +-
 lib/sflow.h                   |   45 +++-
 lib/sflow_agent.c             |   15 ++
 lib/sflow_api.h               |    1 +
 lib/sflow_receiver.c          |   30 +++
 ofproto/ofproto-dpif-sflow.c  |  496
+++++++++++++++++++++++++++++++----------
 ofproto/ofproto-dpif-sflow.h  |   25 ++-
 ofproto/ofproto-dpif-upcall.c |    6 +-
 ofproto/ofproto-dpif-xlate.c  |   58 ++---
 ofproto/ofproto-dpif.c        |   39 +++-
 tests/odp.at                  |    2 +-
 tests/ofproto-dpif.at         |  211 ++++++++++++++++++
 tests/test-sflow.c            |  104 +++++++++
 16 files changed, 992 insertions(+), 199 deletions(-)

diff --git a/lib/lacp.c b/lib/lacp.c
index fce65b3..256ce75 100644
--- a/lib/lacp.c
+++ b/lib/lacp.c
@@ -123,6 +123,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;
@@ -323,9 +328,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;
     }
@@ -538,6 +545,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
@@ -967,3 +975,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 593b80d..4295f7b 100644
--- a/lib/lacp.h
+++ b/lib/lacp.h
@@ -70,4 +70,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 0fd1c51..3112e33 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -286,12 +286,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) {
                 ds_put_cstr(ds, ",slow_path(");
@@ -317,8 +326,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]);
             }
@@ -489,7 +498,8 @@ parse_odp_action(const char *s, const struct simap
*port_names,

     {
         uint32_t pid;
-        uint32_t output;
+        uint32_t n_outputs;
+        uint32_t output_port;
         uint32_t probability;
         uint32_t collector_set_id;
         uint32_t obs_domain_id;
@@ -500,9 +510,9 @@ parse_odp_action(const char *s, const struct simap
*port_names,
         if (ovs_scan(s, "userspace(pid=%"SCNi32")%n", &pid, &n)) {
             odp_put_userspace_action(pid, NULL, 0, actions);
             return n;
-        } else if (ovs_scan(s, "userspace(pid=%"SCNi32",sFlow(vid=%i,"
-                            "pcp=%i,output=%"SCNi32"))%n",
-                            &pid, &vid, &pcp, &output, &n)) {
+        } else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i,"
+
 "pcp=%i,n_outputs=%"SCNu32",output_port=%"SCNu32"))%n",
+                          &pid, &vid, &pcp, &n_outputs, &output_port, &n)
> 0 && n > 0) {
             union user_action_cookie cookie;
             uint16_t tci;

@@ -511,11 +521,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 (ovs_scan(s, "userspace(pid=%"SCNi32",slow_path%n",
                             &pid, &n)) {
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 821b2c4..3c5ce02 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -186,7 +186,8 @@ enum slow_path_reason commit_odp_actions(const struct
flow *,

 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. */
@@ -197,10 +198,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..239e9a9 100644
--- a/lib/sflow.h
+++ b/lib/sflow.h
@@ -267,6 +267,10 @@ typedef struct _SFLExtended_vlan_tunnel {
     innermost. */
 } SFLExtended_vlan_tunnel;

+typedef struct _SFLExtended_vni {
+    uint32_t vni;            /* virtual network identifier */
+} SFLExtended_vni;
+
 enum SFLFlow_type_tag {
     /* enterprise = 0, format = ... */
     SFLFLOW_HEADER    = 1,      /* Packet headers are sampled */
@@ -285,6 +289,10 @@ 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,
+    SFLFLOW_EX_VNI_EGRESS          = 1029,
+    SFLFLOW_EX_VNI_INGRESS         = 1030,
 };

 typedef union _SFLFlow_type {
@@ -304,6 +312,7 @@ typedef union _SFLFlow_type {
     SFLExtended_mpls_FTN mpls_ftn;
     SFLExtended_mpls_LDP_FEC mpls_ldp_fec;
     SFLExtended_vlan_tunnel vlan_tunnel;
+    SFLExtended_vni tunnel_vni;
 } SFLFlow_type;

 typedef struct _SFLFlow_sample_element {
@@ -382,6 +391,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 +490,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 +527,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 +537,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..282b175 100644
--- a/lib/sflow_receiver.c
+++ b/lib/sflow_receiver.c
@@ -460,6 +460,14 @@ 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:
+ case SFLFLOW_EX_IPV4_TUNNEL_INGRESS:
+    elemSiz = sizeof(SFLSampled_ipv4);
+    break;
+ case SFLFLOW_EX_VNI_EGRESS:
+ case SFLFLOW_EX_VNI_INGRESS:
+    elemSiz = sizeof(SFLExtended_vni);
+    break;
  default:
     sflError(receiver, "unexpected packet_data_tag");
     return -1;
@@ -556,6 +564,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);
@@ -587,6 +597,11 @@ int sfl_receiver_writeFlowSample(SFLReceiver
*receiver, SFL_FLOW_SAMPLE_TYPE *fs
     case SFLFLOW_EX_MPLS_FTN: putMplsFtn(receiver,
&elem->flowType.mpls_ftn); break;
     case SFLFLOW_EX_MPLS_LDP_FEC: putMplsLdpFec(receiver,
&elem->flowType.mpls_ldp_fec); break;
     case SFLFLOW_EX_VLAN_TUNNEL: putVlanTunnel(receiver,
&elem->flowType.vlan_tunnel); break;
+    case SFLFLOW_EX_VNI_EGRESS:
+    case SFLFLOW_EX_VNI_INGRESS:
+ putNet32(receiver, elem->flowType.tunnel_vni.vni);
+ break;
+
     default:
  sflError(receiver, "unexpected packet_data_tag");
  return -1;
@@ -630,6 +645,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 +747,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/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 158887f..1ae2f10 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,25 @@
 #include "vlog.h"
 #include "lib/odp-util.h"
 #include "ofproto-provider.h"
+#include "lacp.h"
+#include "lib/byte-order.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 +135,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 +143,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, &current, NULL, NULL,
NULL)) {
+    if (!netdev_get_features(port_lookup.ofport->netdev, &current, 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 +173,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 +187,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 +340,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 +384,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 +441,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 +527,220 @@ 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;
+}
+
+enum sflow_tunnel_type {
+    SFLOW_TUNNEL_UNKNOWN,
+    SFLOW_TUNNEL_GRE,
+    SFLOW_TUNNEL_GRE64,
+    SFLOW_TUNNEL_IPSEC_GRE,
+    SFLOW_TUNNEL_IPSEC_GRE64,
+    SFLOW_TUNNEL_VXLAN,
+    SFLOW_TUNNEL_LISP
+};
+
+static enum sflow_tunnel_type
+dpif_sflow_tunnel_type(const char *netdev_type)
+{
+    if(!strcmp(netdev_type, "gre")) {
+ return SFLOW_TUNNEL_GRE;
+    }
+    if(!strcmp(netdev_type, "gre64")) {
+ return SFLOW_TUNNEL_GRE64;
+    }
+    if(!strcmp(netdev_type, "ipsec_gre")) {
+ return SFLOW_TUNNEL_IPSEC_GRE;
+    }
+    if(!strcmp(netdev_type, "ipsec_gre64")) {
+ return SFLOW_TUNNEL_IPSEC_GRE64;
+    }
+    if(!strcmp(netdev_type, "ipsec_gre64")) {
+ return SFLOW_TUNNEL_IPSEC_GRE64;
+    }
+    if(!strcmp(netdev_type, "vxlan")) {
+ return SFLOW_TUNNEL_VXLAN;
+    }
+    if(!strcmp(netdev_type, "lisp")) {
+ return SFLOW_TUNNEL_LISP;
+    }
+    return SFLOW_TUNNEL_UNKNOWN;
+}
+
+enum sflow_tunnel_direction {
+    SFLOW_TUNNEL_INGRESS=1,
+    SFLOW_TUNNEL_EGRESS=2
+};
+
+enum sflow_tunnel_flags {
+    SFLOW_TUNNEL_FLAGS_NONE=0,
+    SFLOW_TUNNEL_FLAGS_IPV4=1,
+    SFLOW_TUNNEL_FLAGS_VNI=2
+};
+
+/* Implements sFlow standard:  http://sflow.org/sflow_tunnels.txt.
+ * Returns bitmask of enum sflow_tunnel_flags.
+ */
+static int
+dpif_sflow_tunnel(SFLSampled_ipv4 *tunnel4,
+  SFLExtended_vni *tunnel_vni,
+  const enum sflow_tunnel_direction direction,
+  const struct dpif_sflow_port_lookup *port_lookup,
+  const struct flow *flow)
+{
+    const struct netdev_tunnel_config *tcfg;
+
+    tcfg = netdev_get_tunnel_config(port_lookup->ofport->netdev);
+    if(tcfg == NULL) {
+ return SFLOW_TUNNEL_FLAGS_NONE;
+    }
+    else {
+      const char *netdev_type;
+      enum sflow_tunnel_type tunnel_type;
+ int ret = SFLOW_TUNNEL_FLAGS_IPV4;
+
+ /* Infer the ip protocol that was (or will be)
+ * seen on the wire from the tunnel type.
+ */
+ netdev_type = netdev_get_type(port_lookup->ofport->netdev);
+ tunnel_type = dpif_sflow_tunnel_type(netdev_type);
+ switch(tunnel_type) {
+ case SFLOW_TUNNEL_GRE:
+ case SFLOW_TUNNEL_GRE64:
+    tunnel4->protocol = IPPROTO_GRE;
+    break;
+ case SFLOW_TUNNEL_VXLAN:
+ case SFLOW_TUNNEL_LISP:
+    tunnel4->protocol = IPPROTO_UDP;
+    break;
+ case SFLOW_TUNNEL_IPSEC_GRE:
+ case SFLOW_TUNNEL_IPSEC_GRE64:
+    tunnel4->protocol = IPPROTO_ESP;
+    break;
+ case SFLOW_TUNNEL_UNKNOWN:
+    break;
+ }
+
+ if(direction == SFLOW_TUNNEL_INGRESS) {
+    tunnel4->src_ip.addr = flow->tunnel.ip_src;
+    tunnel4->dst_ip.addr = flow->tunnel.ip_dst;
+    tunnel4->tos = flow->tunnel.ip_tos;
+
+    /* XXX For VXLAN and LISP where the
+     * l4_ports are relevant too, can we
+     * reach into the struct ofpbuf *packet to
+     * read them out for ingress tunnel packets?
+     * They doesn't seem to be recorded for
+     * us in the flow->tunnel struct.
+     */
+    /* tunnel4->src_port = flow->tunnel.src_port; */
+    /* tunnel4->dst_port = flow->tunnel.dst_port; */
+
+    if(tunnel_type == SFLOW_TUNNEL_GRE64
+       || tunnel_type == SFLOW_TUNNEL_IPSEC_GRE64) {
+ /* XXX The key is 64-bit (appears on the wire
+ * as 32-bit key + overload of 32-bit sequence_no
+ * field). However we only have 32-bits in the sFlow
+ * VNI field. If this key really can be treated exactly
+ * like a VNI then perhaps a new structure should be
+ * added to report it?
+ */
+    }
+    else {
+ if(flow->tunnel.flags & FLOW_TNL_F_KEY) {
+    /* This assumes the 32-bit key is the least-significant
+       32-bits of flow->tunnel.tun_id. */
+    tunnel_vni->vni = (uint32_t)(ntohll(flow->tunnel.tun_id));
+    ret |= SFLOW_TUNNEL_FLAGS_VNI;
+ }
+ else if(tcfg->in_key_present) {
+    /* If the netdev_tunnel_config specifies an
+     * "in_key" then it acts as a filter so this packet
+     * would only have reached here if it had this key.
+     */
+    /* XXX. This might be redundant if flow->tunnel.tun_id
+     * is always filled in on ingress tunnel packets. */
+    tunnel_vni->vni = tcfg->in_key_flow ?
+ ntohll(flow->tunnel.tun_id) :
+ ntohll(tcfg->in_key);
+    ret |= SFLOW_TUNNEL_FLAGS_VNI;
+ }
+    }
+ }
+ else {
+    /* The EGRESS path is rather different.  The
+     * details on the tunneling that is going to happen
+     * may only be encoded in the actions. */
+
+    /* XXX Is this what tcfg->ip_src_flow means?
+     * Probably not.  We may have to look at the
+     * openflow actions to figure out what the
+     * details are going to be.
+     */
+    tunnel4->src_ip.addr = tcfg->ip_src_flow ?
+ flow->tunnel.ip_src :
+ tcfg->ip_src;
+
+    tunnel4->dst_ip.addr = tcfg->ip_dst_flow ?
+ flow->tunnel.ip_dst :
+ tcfg->ip_dst;
+
+    /* The tos=inherit option means that the tos bits
+       are copied from the flow being tunneled. */
+    tunnel4->tos = tcfg->tos_inherit ?
+ flow->nw_tos :
+ tcfg->tos;
+
+    /* src_port, dst_port only relevant for VXLAN and LISP. */
+    if(tunnel_type == SFLOW_TUNNEL_VXLAN
+       || tunnel_type == SFLOW_TUNNEL_LISP) {
+ /* src_port is added down in the datapath just before sending.
+ * It is computed as a hash over the whole flow, including the
+ * tunneled addresses (to add entropy for ECMP load-balancing).
+ * Theoretically we could compute the exact same digest here,
+ * but that would represent an unwelcome dependency.
+ */
+ tunnel4->src_port = 0;
+ tunnel4->dst_port = tcfg->dst_port;
+    }
+
+    /* Where applicable, the VNI is the tunnel key. */
+    if(tunnel_type == SFLOW_TUNNEL_GRE64
+       || tunnel_type == SFLOW_TUNNEL_IPSEC_GRE64) {
+ /* ignore non-standard 64-bit key for now.
+ * See comment for ingress path above. */
+    }
+    else {
+ /* XXX what does tcfg->out_key_flow really mean? */
+ if(tcfg->out_key_present) {
+    tunnel_vni->vni = tcfg->out_key_flow ?
+ ntohll(flow->tunnel.tun_id) :
+ ntohll(tcfg->out_key);
+    ret |= SFLOW_TUNNEL_FLAGS_VNI;
+ }
+    }
+ }
+
+ return ret;
+    }
 }

 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 +749,15 @@ 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;
+    SFLFlow_sample_element in_vniElem, out_vniElem;
+    int in_ifindex, out_ifindex;
+    int in_tunnel_flags, out_tunnel_flags;

     ovs_mutex_lock(&mutex);
+
     sampler = ds->sflow_agent->samplers;
     if (!sampler) {
         goto out;
@@ -590,11 +766,35 @@ 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);
+    memset(&in_vniElem, 0, sizeof in_vniElem);
+    in_tunnel_flags = dpif_sflow_tunnel(&in_tunnelElem.flowType.ipv4,
+ &in_vniElem.flowType.tunnel_vni,
+ SFLOW_TUNNEL_INGRESS,
+ &in_lookup,
+ flow);
+    if(in_tunnel_flags) {
+ in_tunnelElem.tag = SFLFLOW_EX_IPV4_TUNNEL_INGRESS;
+ SFLADD_ELEMENT(&fs, &in_tunnelElem);
+ if(in_tunnel_flags & SFLOW_TUNNEL_FLAGS_VNI) {
+    in_vniElem.tag = SFLFLOW_EX_VNI_INGRESS;
+    SFLADD_ELEMENT(&fs, &in_vniElem);
+ }
+    }
+ }
     }

     /* Make the assumption that the random number generator in the
datapath converges
@@ -623,11 +823,63 @@ 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) {
+ 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) {
+ 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);
+    memset(&out_vniElem, 0, sizeof out_vniElem);
+    out_tunnel_flags = dpif_sflow_tunnel(&out_tunnelElem.flowType.ipv4,
+ &out_vniElem.flowType.tunnel_vni,
+ SFLOW_TUNNEL_EGRESS,
+ &out_lookup,
+ flow);
+    if(out_tunnel_flags) {
+ out_tunnelElem.tag = SFLFLOW_EX_IPV4_TUNNEL_EGRESS;
+ SFLADD_ELEMENT(&fs, &out_tunnelElem);
+ if(out_tunnel_flags & SFLOW_TUNNEL_FLAGS_VNI) {
+    out_vniElem.tag = SFLFLOW_EX_VNI_EGRESS;
+    SFLADD_ELEMENT(&fs, &out_vniElem);
+ }
+    }
+ }
+    }
+ }
+    }
+    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);
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 dde6430..9f54d0d 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -469,7 +469,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) {
@@ -711,8 +712,7 @@ handle_upcalls(struct udpif *udpif, struct list
*upcalls)
                 memset(&cookie, 0, sizeof cookie);
                 memcpy(&cookie, nl_attr_get(dupcall->userdata),
                        sizeof cookie.sflow);
-                dpif_sflow_received(sflow, dupcall->packet, &flow,
odp_in_port,
-                                    &cookie);
+                dpif_sflow_received(sflow, dupcall->packet, &flow,
&cookie);
                 dpif_sflow_unref(sflow);
             }
             break;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a331c0b..8c17d93 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -178,7 +178,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.
*/
+    ofp_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.
*/

@@ -1479,34 +1479,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;
     }
 }

@@ -1515,7 +1500,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;
@@ -1525,8 +1510,8 @@ 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);
+    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);
@@ -1578,8 +1563,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;
 }

@@ -1607,10 +1592,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
@@ -1780,7 +1766,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 7df0450..2e153b1 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1753,7 +1753,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;
@@ -1856,24 +1856,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);
diff --git a/tests/odp.at b/tests/odp.at
index b505345..fd4e32d 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -220,7 +220,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 b78e156..6c5409e 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -2071,6 +2071,217 @@ 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=vxlan \
+                    options:local_ip=1.1.1.1 options:remote_ip=2.2.2.2 \
+                    options:key=5 options:tos=inherit 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])
+
+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 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=17
+ tunnel4_out_src=1.1.1.1
+ tunnel4_out_dst=2.2.2.2
+ tunnel4_out_src_port=0
+ tunnel4_out_dst_port=46354
+ tunnel4_out_tcp_flags=0
+ tunnel4_out_tos=4
+ tunnel_out_vni=5
+ 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 tunnel structures ingress
+AT_SETUP([ofproto-dpif - sFlow tunnel structures ingress])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
+                    options:local_ip=1.1.1.1 options:remote_ip=2.2.2.2 \
+                    options:key=5 options:tos=inherit ofport_request=1 \
+                    -- add-port br0 p2 -- set Interface p2 type=dummy \
+                    options:ifindex=1002 ofport_request=2 -- \
+    add-br br1 -- \
+    set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \
+    set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \
+    fail-mode=secure -- \
+     -- add-port br1 p3 -- set interface p3 type=vxlan \
+    options:local_ip=2.2.2.2 options:remote_ip=1.1.1.1 \
+    options:key=5  options:tos=inherit ofport_request=3 \
+    -- add-port br1 p4 -- set Interface p4 type=dummy \
+                    options:ifindex=1004 ofport_request=4 ])
+
+AT_DATA([flows.txt], [dnl
+actions=output:1
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+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
+ovs-vsctl \
+   set Bridge br1 sflow=@sf -- \
+   --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
+     header=128 sampling=1 polling=0
+
+ifconfig -a
+ip route
+
+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=17
+ tunnel4_out_src=1.1.1.1
+ tunnel4_out_dst=2.2.2.2
+ tunnel4_out_src_port=0
+ tunnel4_out_dst_port=46354
+ tunnel4_out_tcp_flags=0
+ tunnel4_out_tos=4
+ tunnel_out_vni=5
+ 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..060864d 100644
--- a/tests/test-sflow.c
+++ b/tests/test-sflow.c
@@ -54,8 +54,13 @@ 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
+#define SFLOW_TAG_PKT_TUNNEL_VNI_OUT 1029
+#define SFLOW_TAG_PKT_TUNNEL_VNI_IN 1030

 struct sflow_addr {
     enum {
@@ -99,7 +104,12 @@ struct sflow_xdr {
     struct {
         uint32_t HEADER;
         uint32_t SWITCH;
+ uint32_t TUNNEL4_OUT;
+ uint32_t TUNNEL4_IN;
+ uint32_t TUNNEL_VNI_OUT;
+ uint32_t TUNNEL_VNI_IN;
         uint32_t IFCOUNTERS;
+ uint32_t LACPCOUNTERS;
     } offset;

     /* Flow sample fields. */
@@ -221,6 +231,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 +297,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 +331,26 @@ 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.TUNNEL_VNI_IN) {
+            sflowxdr_setc(x, x->offset.TUNNEL_VNI_IN);
+    printf( " tunnel_in_vni=%"PRIu32, sflowxdr_next(x));
+        }
+
+        if (x->offset.TUNNEL_VNI_OUT) {
+            sflowxdr_setc(x, x->offset.TUNNEL_VNI_OUT);
+    printf( " tunnel_out_vni=%"PRIu32, sflowxdr_next(x));
+        }
+
         if (x->offset.SWITCH) {
             sflowxdr_setc(x, x->offset.SWITCH);
             printf(" in_vlan=%"PRIu32, sflowxdr_next(x));
@@ -374,6 +459,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 +530,22 @@ 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;
+
+ case SFLOW_TAG_PKT_TUNNEL_VNI_OUT:
+                    sflowxdr_mark_unique(x, &x->offset.TUNNEL_VNI_OUT);
+                    break;
+
+ case SFLOW_TAG_PKT_TUNNEL_VNI_IN:
+                    sflowxdr_mark_unique(x, &x->offset.TUNNEL_VNI_IN);
+                    break;
+
                     /* Add others here... */
                 }

-- 
1.7.9.5

-- 
------
Neil McKee
InMon Corp.
http://www.inmon.com

--089e012281aca98c4204ec3c93e3
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>I rebased and cleaned up this patch, and included a l=
onger description</div><div>to capture the reasons why it&#39;s OK to leave=
 some fields unpopulated.</div><div><br></div><div>Please consider.</div><d=
iv>
<br></div><div>Neil</div><div><br></div><br clear=3D"all"><div><div>From 4d=
9113d6e15d195e43c0472a2951ecde09c1e46c Mon Sep 17 00:00:00 2001</div><div>F=
rom: Neil McKee &lt;<a href=3D"mailto:neil.mckee at inmon.com">neil.mckee at inmo=
n.com</a>&gt;</div>
<div>Date: Thu, 28 Nov 2013 05:46:44 -0700</div><div>Subject: [PATCH] sFlow=
 LAG and Tunnel export</div><div><br></div><div>Eliminates hash-table from =
ofproto-dpif-sflow. Instead a callback</div><div>to ofproto-dpif is used to=
 look up counter and packet info. The</div>
<div>ofp-port is now supplied in the sFlow cookie for this purpose,</div><d=
iv>rather than the odp-port as it was before. =A0This brings it into</div><=
div>line with other upcall consumers. =A0The cookie is split</div><div>into=
 two variants: one for single-output and one for multi-output,</div>
<div>which serves to keep it under 64-bits in both cases. The</div><div>sFl=
ow LAG and Tunnel structures are added. =A0Not all</div><div>fields are pop=
ulated, but this is allowed by the standard.</div><div>The simple presence =
of the Tunnel structure would be worthwhile</div>
<div>even if no fields were populated because it signals the presence</div>=
<div>of a tunnel to the sFlow collector. =A0More details can always be</div=
><div>filled in later if performance and complexity considerations</div><di=
v>
allow. It is more likely that this can happen on the receive</div><div>path=
 than the transmit path, because the transmit path may</div><div>include tu=
nnels defined in openflow rules. =A0With sFlow</div><div>monitoring the exp=
ectation is that observations from the</div>
<div>upstream switch port can always be used to fill in any gaps,</div><div=
>and the preference is always to minimize the impact on</div><div>performan=
ce, so this approach is within the spirit of the</div><div>standard.</div>
<div>Finally, new unit tests are added for the Tunnel and LAG export.</div>=
<div><br></div><div>Signed-off-by: Neil McKee &lt;<a href=3D"mailto:neil.mc=
kee at inmon.com">neil.mckee at inmon.com</a>&gt;</div><div>---</div><div>=A0lib/=
lacp.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 64 ++++++</div>
<div>=A0lib/lacp.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 23 ++</div>=
<div>=A0lib/odp-util.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 53 +++--</div><=
div>=A0lib/odp-util.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 19 +-</div><div>=
=A0lib/sflow.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 45 +++-</div><div>=
=A0lib/sflow_agent.c =A0 =A0 =A0 =A0 =A0 =A0 | =A0 15 ++</div>
<div>=A0lib/sflow_api.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A01 +</div><div>=
=A0lib/sflow_receiver.c =A0 =A0 =A0 =A0 =A0| =A0 30 +++</div><div>=A0ofprot=
o/ofproto-dpif-sflow.c =A0| =A0496 +++++++++++++++++++++++++++++++---------=
-</div><div>=A0ofproto/ofproto-dpif-sflow.h =A0| =A0 25 ++-</div>
<div>=A0ofproto/ofproto-dpif-upcall.c | =A0 =A06 +-</div><div>=A0ofproto/of=
proto-dpif-xlate.c =A0| =A0 58 ++---</div><div>=A0ofproto/ofproto-dpif.c =
=A0 =A0 =A0 =A0| =A0 39 +++-</div><div>=A0tests/<a href=3D"http://odp.at">o=
dp.at</a> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 =A02 +-</div>
<div>=A0tests/<a href=3D"http://ofproto-dpif.at">ofproto-dpif.at</a> =A0 =
=A0 =A0 =A0 | =A0211 ++++++++++++++++++</div><div>=A0tests/test-sflow.c =A0=
 =A0 =A0 =A0 =A0 =A0| =A0104 +++++++++</div><div>=A016 files changed, 992 i=
nsertions(+), 199 deletions(-)</div>
<div><br></div><div>diff --git a/lib/lacp.c b/lib/lacp.c</div><div>index fc=
e65b3..256ce75 100644</div><div>--- a/lib/lacp.c</div><div>+++ b/lib/lacp.c=
</div><div>@@ -123,6 +123,11 @@ struct slave {</div><div>=A0 =A0 =A0struct =
lacp_info ntt_actor; =A0 /* Used to decide if we Need To Transmit. */</div>
<div>=A0 =A0 =A0struct timer tx; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Next message=
 transmission timer. */</div><div>=A0 =A0 =A0struct timer rx; =A0 =A0 =A0 =
=A0 =A0 =A0 =A0/* Expected message receive timer. */</div><div>+ =A0 =A0str=
uct {</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>uint32_=
t rx_pdus; =A0 =A0 =A0 =A0 /* dot3adAggPortStatsLACPDUsRx */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>uint32_t rx_pdus_b=
ad; =A0 =A0 /* dot3adAggPortStatsIllegalRx */</div><div>+<span class=3D"" s=
tyle=3D"white-space:pre">	</span>uint32_t tx_pdus; =A0 =A0 =A0 =A0 /* dot3a=
dAggPortStatsLACPDUsTx */</div>
<div>+ =A0 =A0} counters;</div><div>=A0};</div><div>=A0</div><div>=A0static=
 struct ovs_mutex mutex;</div><div>@@ -323,9 +328,11 @@ lacp_process_packet=
(struct lacp *lacp, const void *slave_,</div><div>=A0 =A0 =A0if (!slave) {<=
/div><div>=A0 =A0 =A0 =A0 =A0goto out;</div>
<div>=A0 =A0 =A0}</div><div>+ =A0 =A0slave-&gt;counters.rx_pdus++;</div><di=
v>=A0</div><div>=A0 =A0 =A0pdu =3D parse_lacp_packet(packet);</div><div>=A0=
 =A0 =A0if (!pdu) {</div><div>+<span class=3D"" style=3D"white-space:pre">	=
</span>slave-&gt;counters.rx_pdus_bad++;</div>
<div>=A0 =A0 =A0 =A0 =A0VLOG_WARN_RL(&amp;rl, &quot;%s: received an unparsa=
ble LACP PDU.&quot;, lacp-&gt;name);</div><div>=A0 =A0 =A0 =A0 =A0goto out;=
</div><div>=A0 =A0 =A0}</div><div>@@ -538,6 +545,7 @@ lacp_run(struct lacp =
*lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0slave-&gt;ntt_actor =3D actor;</div><div>=
=A0 =A0 =A0 =A0 =A0 =A0 =A0compose_lacp_pdu(&amp;actor, &amp;slave-&gt;part=
ner, &amp;pdu);</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0send_pdu(slave-&gt;aux=
, &amp;pdu, sizeof pdu);</div><div>+<span class=3D"" style=3D"white-space:p=
re">	</span> =A0 =A0slave-&gt;counters.tx_pdus++;</div>
<div>=A0</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0duration =3D (slave-&gt;partn=
er.state &amp; LACP_STATE_TIME</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0? LACP_FAST_TIME_TX</div><div>@@ -967,3 +975,59 @@ lacp_=
unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],</div>
<div>=A0out:</div><div>=A0 =A0 =A0ovs_mutex_unlock(&amp;mutex);</div><div>=
=A0}</div><div>+</div><div>+/* Extract a snapshot of the current state and =
counters for a slave port.</div><div>+ =A0 Return false if the slave is not=
 active. */</div>
<div>+bool</div><div>+lacp_get_slave_stats(const struct lacp *lacp, const v=
oid *slave_, struct lacp_slave_stats *stats)</div><div>+ =A0 =A0OVS_EXCLUDE=
D(mutex)</div><div>+{</div><div>+ =A0 =A0struct slave *slave;</div><div>+ =
=A0 =A0struct lacp_info actor;</div>
<div>+ =A0 =A0bool ret;</div><div>+</div><div>+ =A0 =A0ovs_mutex_lock(&amp;=
mutex);</div><div>+</div><div>+ =A0 =A0slave =3D slave_lookup(lacp, slave_)=
;</div><div>+ =A0 =A0if(slave) {</div><div>+<span class=3D"" style=3D"white=
-space:pre">	</span>ret =3D true;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>slave_get_actor(sl=
ave, &amp;actor);</div><div>+<span class=3D"" style=3D"white-space:pre">	</=
span>memcpy(&amp;stats-&gt;dot3adAggPortActorSystemID,</div><div>+<span cla=
ss=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 actor.sys_id,</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 ETH_A=
DDR_LEN);</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>mem=
cpy(&amp;stats-&gt;dot3adAggPortPartnerOperSystemID,</div><div>+<span class=
=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 slave-&gt;partner.sys_=
id,</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 ETH_A=
DDR_LEN);</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>sta=
ts-&gt;dot3adAggPortAttachedAggID =3D (lacp-&gt;key_slave-&gt;key ?</div><d=
iv>+<span class=3D"" style=3D"white-space:pre">					</span> =A0 =A0 lacp-&g=
t;key_slave-&gt;key :</div>
<div>+<span class=3D"" style=3D"white-space:pre">					</span> =A0 =A0 lacp-=
&gt;key_slave-&gt;port_id);</div><div>+</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>/* Construct my admin-state. =A0Assume aggrega=
tion is configured on. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>stats-&gt;dot3adAg=
gPortActorAdminState =3D LACP_STATE_AGG;</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>if(lacp-&gt;active) {</div><div>+<span class=
=3D"" style=3D"white-space:pre">	</span> =A0 =A0stats-&gt;dot3adAggPortActo=
rAdminState |=3D LACP_STATE_ACT;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+<span=
 class=3D"" style=3D"white-space:pre">	</span>if(lacp-&gt;fast) {</div><div=
>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0stats-&gt;dot3=
adAggPortActorAdminState |=3D LACP_STATE_TIME;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+<span=
 class=3D"" style=3D"white-space:pre">	</span>/* XXX Not sure how to know t=
he partner admin state. It</div><div>+<span class=3D"" style=3D"white-space=
:pre">	</span> * might have to be captured and remembered during the</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> * negotiation pha=
se.</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> */</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>stats-&gt;dot3adAg=
gPortPartnerAdminState =3D 0;</div>
<div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>stats-=
&gt;dot3adAggPortActorOperState =3D actor.state;</div><div>+<span class=3D"=
" style=3D"white-space:pre">	</span>stats-&gt;dot3adAggPortPartnerOperState=
 =3D slave-&gt;partner.state;</div>
<div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>/* Rea=
d out the latest counters */</div><div>+<span class=3D"" style=3D"white-spa=
ce:pre">	</span>stats-&gt;dot3adAggPortStatsLACPDUsRx =3D slave-&gt;counter=
s.rx_pdus;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>stats-&gt;dot3adAg=
gPortStatsIllegalRx =3D slave-&gt;counters.rx_pdus_bad;</div><div>+<span cl=
ass=3D"" style=3D"white-space:pre">	</span>stats-&gt;dot3adAggPortStatsLACP=
DUsTx =3D slave-&gt;counters.tx_pdus;</div>
<div>+ =A0 =A0}</div><div>+ =A0 =A0else {</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>ret =3D false;</div><div>+ =A0 =A0}</div><div>=
+ =A0 =A0ovs_mutex_unlock(&amp;mutex);</div><div>+ =A0 =A0return ret;</div>=
<div>+</div><div>+}</div>
<div>diff --git a/lib/lacp.h b/lib/lacp.h</div><div>index 593b80d..4295f7b =
100644</div><div>--- a/lib/lacp.h</div><div>+++ b/lib/lacp.h</div><div>@@ -=
70,4 +70,27 @@ typedef void lacp_send_pdu(void *slave, const void *pdu, siz=
e_t pdu_size);</div>
<div>=A0void lacp_run(struct lacp *, lacp_send_pdu *);</div><div>=A0void la=
cp_wait(struct lacp *);</div><div>=A0</div><div>+struct lacp_slave_stats {<=
/div><div>+ =A0 =A0/* id */</div><div>+ =A0 =A0uint8_t dot3adAggPortActorSy=
stemID[ETH_ADDR_LEN];</div>
<div>+ =A0 =A0uint8_t dot3adAggPortPartnerOperSystemID[ETH_ADDR_LEN];</div>=
<div>+ =A0 =A0uint32_t dot3adAggPortAttachedAggID;</div><div>+ =A0 =A0/* st=
ate */</div><div>+ =A0 =A0uint8_t dot3adAggPortActorAdminState;</div><div>+=
 =A0 =A0uint8_t dot3adAggPortActorOperState;</div>
<div>+ =A0 =A0uint8_t dot3adAggPortPartnerAdminState;</div><div>+ =A0 =A0ui=
nt8_t dot3adAggPortPartnerOperState;</div><div>+ =A0 =A0/* counters */</div=
><div>+ =A0 =A0uint32_t dot3adAggPortStatsLACPDUsRx;</div><div>+ =A0 =A0/* =
uint32_t dot3adAggPortStatsMarkerPDUsRx; */</div>
<div>+ =A0 =A0/* uint32_t dot3adAggPortStatsMarkerResponsePDUsRx; */</div><=
div>+ =A0 =A0/* uint32_t dot3adAggPortStatsUnknownRx; */</div><div>+ =A0 =
=A0uint32_t dot3adAggPortStatsIllegalRx;</div><div>+ =A0 =A0uint32_t dot3ad=
AggPortStatsLACPDUsTx;</div>
<div>+ =A0 =A0/* uint32_t dot3adAggPortStatsMarkerPDUsTx; */</div><div>+ =
=A0 =A0/* uint32_t dot3adAggPortStatsMarkerResponsePDUsTx; */</div><div>+};=
</div><div>+</div><div>+bool lacp_get_slave_stats(const struct lacp *, cons=
t void *slave_, struct lacp_slave_stats *);</div>
<div>+</div><div>=A0#endif /* lacp.h */</div><div>diff --git a/lib/odp-util=
.c b/lib/odp-util.c</div><div>index 0fd1c51..3112e33 100644</div><div>--- a=
/lib/odp-util.c</div><div>+++ b/lib/odp-util.c</div><div>@@ -286,12 +286,21=
 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)</=
div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0userdata_unspec =3D false;</div><div>=A0</d=
iv><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0if (userdata_len =3D=3D sizeof cookie.sf=
low</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&amp;&amp; cookie.type =3D=
=3D USER_ACTION_COOKIE_SFLOW) {</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
&amp;&amp; cookie.type =3D=3D USER_ACTION_COOKIE_SFLOW_SINGLEPORT) {</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ds_put_format(ds, &quot;,sFlow(&quo=
t;</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&=
quot;vid=3D%&quot;PRIu16&quot;,pcp=3D%&quot;PRIu8&quot;,output=3D%&quot;PRI=
u32&quot;)&quot;,</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0vlan_tci_to_vid(cookie.sflow.vlan_tci),</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vlan_tci_=
to_pcp(cookie.sflow.vlan_tci),</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0cookie.sflow.output);</div><div>+ =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&quot;vid=3D%&quot;PRIu16&qu=
ot;,pcp=3D%&quot;PRIu8</div>
<div>+<span class=3D"" style=3D"white-space:pre">			</span> =A0 =A0 =A0&quo=
t;,n_outputs=3D1,output_port=3D%&quot;PRIu32&quot;)&quot;,</div><div>+ =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vlan_tci_to_vid(cook=
ie.sflow.single.vlan_tci),</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0vlan_tci_to_pcp(cookie.sflow.single.vlan_tci),</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cookie.sf=
low.single.output_port);</div><div>+<span class=3D"" style=3D"white-space:p=
re">	</span> =A0 =A0} else if (userdata_len =3D=3D sizeof cookie.sflow</div=
><div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0 =A0 &am=
p;&amp; cookie.type =3D=3D USER_ACTION_COOKIE_SFLOW_MULTIPORT) {</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ds_put_format(ds, &quot;,sFlow(&quot;=
</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&qu=
ot;vid=3D%&quot;PRIu16&quot;,pcp=3D%&quot;PRIu8</div><div>+<span class=3D""=
 style=3D"white-space:pre">			</span> =A0 =A0 =A0&quot;,n_outputs=3D%&quot;=
PRIu32&quot;,output_port=3D0)&quot;,</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vlan_tci_=
to_vid(cookie.sflow.multi.vlan_tci),</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vlan_tci_to_pcp(cookie.sflow.multi.vlan_=
tci),</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0cookie.sflow.multi.n_outputs);</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0} else if (userdata_len =3D=3D sizeof cooki=
e.slow_path</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &amp;=
&amp; cookie.type =3D=3D USER_ACTION_COOKIE_SLOW_PATH) {</div><div>=A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0ds_put_cstr(ds, &quot;,slow_path(&quot;);</div>
<div>@@ -317,8 +326,8 @@ format_odp_userspace_action(struct ds *ds, const s=
truct nlattr *attr)</div><div>=A0 =A0 =A0 =A0 =A0}</div><div>=A0</div><div>=
=A0 =A0 =A0 =A0 =A0if (userdata_unspec) {</div><div>- =A0 =A0 =A0 =A0 =A0 =
=A0size_t i;</div><div>- =A0 =A0 =A0 =A0 =A0 =A0ds_put_format(ds, &quot;,us=
erdata(&quot;);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0size_t i;<=
/div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0ds_pu=
t_format(ds, &quot;,userdata(&quot;);</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0=
for (i =3D 0; i &lt; userdata_len; i++) {</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ds_put_format(ds, &quot;%02x&quot;,=
 userdata[i]);</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0}</div><div>@@ -489,7 +=
498,8 @@ parse_odp_action(const char *s, const struct simap *port_names,</d=
iv><div>=A0</div><div>=A0 =A0 =A0{</div>
<div>=A0 =A0 =A0 =A0 =A0uint32_t pid;</div><div>- =A0 =A0 =A0 =A0uint32_t o=
utput;</div><div>+ =A0 =A0 =A0 =A0uint32_t n_outputs;</div><div>+ =A0 =A0 =
=A0 =A0uint32_t output_port;</div><div>=A0 =A0 =A0 =A0 =A0uint32_t probabil=
ity;</div><div>=A0 =A0 =A0 =A0 =A0uint32_t collector_set_id;</div>
<div>=A0 =A0 =A0 =A0 =A0uint32_t obs_domain_id;</div><div>@@ -500,9 +510,9 =
@@ parse_odp_action(const char *s, const struct simap *port_names,</div><di=
v>=A0 =A0 =A0 =A0 =A0if (ovs_scan(s, &quot;userspace(pid=3D%&quot;SCNi32&qu=
ot;)%n&quot;, &amp;pid, &amp;n)) {</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0odp_put_userspace_action(pid, NULL, 0, acti=
ons);</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0return n;</div><div>- =A0 =A0 =
=A0 =A0} else if (ovs_scan(s, &quot;userspace(pid=3D%&quot;SCNi32&quot;,sFl=
ow(vid=3D%i,&quot;</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0&quot;pcp=3D%i,output=3D%&quot;SCNi32&quot;))%n&quot;,</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&amp;pid, &am=
p;vid, &amp;pcp, &amp;output, &amp;n)) {</div><div>+ =A0 =A0 =A0 =A0} else =
if (sscanf(s, &quot;userspace(pid=3D%lli,sFlow(vid=3D%i,&quot;</div><div>+ =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&quot;pcp=3D%i,n_outputs=
=3D%&quot;SCNu32&quot;,output_port=3D%&quot;SCNu32&quot;))%n&quot;,</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&amp;pid, &amp;vi=
d, &amp;pcp, &amp;n_outputs, &amp;output_port, &amp;n) &gt; 0 &amp;&amp; n =
&gt; 0) {</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0union user_action_cookie coo=
kie;</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0uint16_t tci;</div>
<div>=A0</div><div>@@ -511,11 +521,22 @@ parse_odp_action(const char *s, co=
nst struct simap *port_names,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
tci |=3D VLAN_CFI;</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0}</div><div>=A0</di=
v><div>- =A0 =A0 =A0 =A0 =A0 =A0cookie.type =3D USER_ACTION_COOKIE_SFLOW;</=
div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0cookie.sflow.vlan_tci =3D htons(tci);</div><d=
iv>- =A0 =A0 =A0 =A0 =A0 =A0cookie.sflow.output =3D output;</div><div>- =A0=
 =A0 =A0 =A0 =A0 =A0odp_put_userspace_action(pid, &amp;cookie, sizeof cooki=
e.sflow,</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 actions);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0if(n_outpu=
ts =3D=3D 1) {</div><div>+<span class=3D"" style=3D"white-space:pre">	</spa=
n> =A0 =A0 =A0cookie.type =3D USER_ACTION_COOKIE_SFLOW_SINGLEPORT;</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0cookie.sf=
low.single.vlan_tci =3D htons(tci);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0cookie=
.sflow.single.output_port =3D output_port;</div><div>+<span class=3D"" styl=
e=3D"white-space:pre">	</span> =A0 =A0 =A0odp_put_userspace_action(pid, &am=
p;cookie,</div><div>
+<span class=3D"" style=3D"white-space:pre">				</span> =A0 =A0 =A0 sizeof =
cookie.sflow.single,</div><div>+<span class=3D"" style=3D"white-space:pre">=
				</span> =A0 =A0 =A0 actions);</div><div>+<span class=3D"" style=3D"whit=
e-space:pre">	</span> =A0 =A0}</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0else {</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0cook=
ie.type =3D USER_ACTION_COOKIE_SFLOW_MULTIPORT;</div><div>+<span class=3D""=
 style=3D"white-space:pre">	</span> =A0 =A0 =A0cookie.sflow.multi.vlan_tci =
=3D htons(tci);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0cookie=
.sflow.multi.n_outputs =3D n_outputs;</div><div>+<span class=3D"" style=3D"=
white-space:pre">	</span> =A0 =A0 =A0odp_put_userspace_action(pid, &amp;coo=
kie,</div><div>+<span class=3D"" style=3D"white-space:pre">				</span> =A0 =
=A0 =A0 sizeof cookie.sflow.multi,</div>
<div>+<span class=3D"" style=3D"white-space:pre">				</span> =A0 =A0 =A0 ac=
tions);</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =
=A0}</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0return n;</div><div>=A0 =A0 =A0 =
=A0 =A0} else if (ovs_scan(s, &quot;userspace(pid=3D%&quot;SCNi32&quot;,slo=
w_path%n&quot;,</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&amp;pid, &=
amp;n)) {</div><div>diff --git a/lib/odp-util.h b/lib/odp-util.h</div><div>=
index 821b2c4..3c5ce02 100644</div><div>--- a/lib/odp-util.h</div><div>+++ =
b/lib/odp-util.h</div><div>
@@ -186,7 +186,8 @@ enum slow_path_reason commit_odp_actions(const struct f=
low *,</div><div>=A0</div><div>=A0enum user_action_cookie_type {</div><div>=
=A0 =A0 =A0USER_ACTION_COOKIE_UNSPEC,</div><div>- =A0 =A0USER_ACTION_COOKIE=
_SFLOW, =A0 =A0 =A0 =A0/* Packet for per-bridge sFlow sampling. */</div>
<div>+ =A0 =A0USER_ACTION_COOKIE_SFLOW_SINGLEPORT, =A0/* sFlow sample (1 ou=
tput port). */</div><div>+ =A0 =A0USER_ACTION_COOKIE_SFLOW_MULTIPORT, =A0 /=
* sFlow sample (N output ports). */</div><div>=A0 =A0 =A0USER_ACTION_COOKIE=
_SLOW_PATH, =A0 =A0/* Userspace must process this flow. */</div>
<div>=A0 =A0 =A0USER_ACTION_COOKIE_FLOW_SAMPLE, =A0/* Packet for per-flow s=
ampling. */</div><div>=A0 =A0 =A0USER_ACTION_COOKIE_IPFIX, =A0 =A0 =A0 =A0/=
* Packet for per-bridge IPFIX sampling. */</div><div>@@ -197,10 +198,18 @@ =
enum user_action_cookie_type {</div>
<div>=A0union user_action_cookie {</div><div>=A0 =A0 =A0uint16_t type; =A0 =
=A0 =A0 =A0 =A0 =A0 =A0/* enum user_action_cookie_type. */</div><div>=A0</d=
iv><div>- =A0 =A0struct {</div><div>- =A0 =A0 =A0 =A0uint16_t type; =A0 =A0=
 =A0 =A0 =A0/* USER_ACTION_COOKIE_SFLOW. */</div>
<div>- =A0 =A0 =A0 =A0ovs_be16 vlan_tci; =A0 =A0 =A0/* Destination VLAN TCI=
. */</div><div>- =A0 =A0 =A0 =A0uint32_t output; =A0 =A0 =A0 =A0/* SFL_FLOW=
_SAMPLE_TYPE &#39;output&#39; value. */</div><div>+ =A0 =A0union {</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span>struct {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0uint16_t t=
ype; =A0 =A0 =A0 =A0 =A0/* USER_ACTION_COOKIE_SFLOW_SINGLEPORT. */</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0ovs_be16 vlan=
_tci; =A0 =A0 =A0/* Destination VLAN TCI. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0ofp_port_t=
 output_port; /* Output port */</div><div>+<span class=3D"" style=3D"white-=
space:pre">	</span> =A0 =A0/* XXX do we need to pad to 8 bytes -- while siz=
eof(ofp_port_t) is still 2 ?*/</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>} single;</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span>struct {</div><div>+<=
span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0uint16_t type; =
=A0 =A0 =A0 =A0 =A0/* USER_ACTION_COOKIE_SFLOW_MULTIPORT. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0ovs_be16 v=
lan_tci; =A0 =A0 =A0/* Destination VLAN TCI. */</div><div>+<span class=3D""=
 style=3D"white-space:pre">	</span> =A0 =A0uint32_t n_outputs; =A0 =A0 /* N=
umber of output ports. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>} multi;</div><div=
>=A0 =A0 =A0} sflow;</div><div>=A0</div><div>=A0 =A0 =A0struct {</div><div>=
diff --git a/lib/sflow.h b/lib/sflow.h</div><div>index 0d1f2b9..239e9a9 100=
644</div><div>
--- a/lib/sflow.h</div><div>+++ b/lib/sflow.h</div><div>@@ -267,6 +267,10 @=
@ typedef struct _SFLExtended_vlan_tunnel {</div><div>=A0<span class=3D"" s=
tyle=3D"white-space:pre">			</span> =A0 =A0innermost. */</div><div>=A0} SFL=
Extended_vlan_tunnel;</div>
<div>=A0</div><div>+typedef struct _SFLExtended_vni {</div><div>+ =A0 =A0ui=
nt32_t vni; =A0 =A0 =A0 =A0 =A0 =A0/* virtual network identifier */</div><d=
iv>+} SFLExtended_vni;</div><div>+</div><div>=A0enum SFLFlow_type_tag {</di=
v><div>=A0 =A0 =A0/* enterprise =3D 0, format =3D ... */</div>
<div>=A0 =A0 =A0SFLFLOW_HEADER =A0 =A0=3D 1, =A0 =A0 =A0/* Packet headers a=
re sampled */</div><div>@@ -285,6 +289,10 @@ enum SFLFlow_type_tag {</div><=
div>=A0 =A0 =A0SFLFLOW_EX_MPLS_FTN =A0 =A0 =3D 1010,</div><div>=A0 =A0 =A0S=
FLFLOW_EX_MPLS_LDP_FEC =3D 1011,</div>
<div>=A0 =A0 =A0SFLFLOW_EX_VLAN_TUNNEL =A0=3D 1012, =A0 /* VLAN stack */</d=
iv><div>+ =A0 =A0SFLFLOW_EX_IPV4_TUNNEL_EGRESS =A0=3D 1023, /* <a href=3D"h=
ttp://sflow.org/sflow_tunnels.txt">http://sflow.org/sflow_tunnels.txt</a> *=
/</div><div>+ =A0 =A0SFLFLOW_EX_IPV4_TUNNEL_INGRESS =3D 1024,</div>
<div>+ =A0 =A0SFLFLOW_EX_VNI_EGRESS =A0 =A0 =A0 =A0 =A0=3D 1029,</div><div>=
+ =A0 =A0SFLFLOW_EX_VNI_INGRESS =A0 =A0 =A0 =A0 =3D 1030,</div><div>=A0};</=
div><div>=A0</div><div>=A0typedef union _SFLFlow_type {</div><div>@@ -304,6=
 +312,7 @@ typedef union _SFLFlow_type {</div>
<div>=A0 =A0 =A0SFLExtended_mpls_FTN mpls_ftn;</div><div>=A0 =A0 =A0SFLExte=
nded_mpls_LDP_FEC mpls_ldp_fec;</div><div>=A0 =A0 =A0SFLExtended_vlan_tunne=
l vlan_tunnel;</div><div>+ =A0 =A0SFLExtended_vni tunnel_vni;</div><div>=A0=
} SFLFlow_type;</div>
<div>=A0</div><div>=A0typedef struct _SFLFlow_sample_element {</div><div>@@=
 -382,6 +391,9 @@ typedef struct _SFLFlow_sample_expanded {</div><div>=A0</=
div><div>=A0/* Counter types */</div><div>=A0</div><div>+#define SFL_UNDEF_=
COUNTER(c) c=3D(typeof(c))-1</div>
<div>+#define SFL_UNDEF_GAUGE(c) c=3D0</div><div>+</div><div>=A0/* Generic =
interface counters - see RFC 1573, 2233 */</div><div>=A0</div><div>=A0typed=
ef struct _SFLIf_counters {</div><div>@@ -478,6 +490,35 @@ typedef struct _=
SFLVlan_counters {</div>
<div>=A0 =A0 =A0u_int32_t discards;</div><div>=A0} SFLVlan_counters;</div><=
div>=A0</div><div>+</div><div>+/* LAG Port Statistics - see <a href=3D"http=
://sflow.org/sflow_lag.txt">http://sflow.org/sflow_lag.txt</a> */</div><div=
>+/* opaque =3D counter_data; enterprise =3D 0; format =3D 7 */</div>
<div>+</div><div>+typedef =A0union _SFLLACP_portState {</div><div>+ =A0 =A0=
uint32_t all;</div><div>+ =A0 =A0struct {</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>uint8_t actorAdmin;</div><div>+<span class=3D"=
" style=3D"white-space:pre">	</span>uint8_t actorOper;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>uint8_t partnerAdm=
in;</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>uint8_t p=
artnerOper;</div><div>+ =A0 =A0} v;</div><div>+} SFLLACP_portState;</div><d=
iv>+</div>
<div>+typedef struct _SFLLACP_counters {</div><div>+ =A0 =A0uint8_t actorSy=
stemID[8]; =A0 /* 6 bytes + 2 pad */</div><div>+ =A0 =A0uint8_t partnerSyst=
emID[8]; /* 6 bytes + 2 pad */</div><div>+ =A0 =A0uint32_t attachedAggID;</=
div><div>+ =A0 =A0SFLLACP_portState portState;</div>
<div>+ =A0 =A0uint32_t LACPDUsRx;</div><div>+ =A0 =A0uint32_t markerPDUsRx;=
</div><div>+ =A0 =A0uint32_t markerResponsePDUsRx;</div><div>+ =A0 =A0uint3=
2_t unknownRx;</div><div>+ =A0 =A0uint32_t illegalRx;</div><div>+ =A0 =A0ui=
nt32_t LACPDUsTx;</div>
<div>+ =A0 =A0uint32_t markerPDUsTx;</div><div>+ =A0 =A0uint32_t markerResp=
onsePDUsTx;</div><div>+} SFLLACP_counters;</div><div>+</div><div>=A0/* Coun=
ters data */</div><div>=A0</div><div>=A0enum SFLCounters_type_tag {</div><d=
iv>@@ -486,7 +527,8 @@ enum SFLCounters_type_tag {</div>
<div>=A0 =A0 =A0SFLCOUNTERS_ETHERNET =A0 =A0 =3D 2,</div><div>=A0 =A0 =A0SF=
LCOUNTERS_TOKENRING =A0 =A0=3D 3,</div><div>=A0 =A0 =A0SFLCOUNTERS_VG =A0 =
=A0 =A0 =A0 =A0 =3D 4,</div><div>- =A0 =A0SFLCOUNTERS_VLAN =A0 =A0 =A0 =A0 =
=3D 5</div><div>+ =A0 =A0SFLCOUNTERS_VLAN =A0 =A0 =A0 =A0 =3D 5,</div>
<div>+ =A0 =A0SFLCOUNTERS_LACP =A0 =A0 =A0 =A0 =3D 7</div><div>=A0};</div><=
div>=A0</div><div>=A0typedef union _SFLCounters_type {</div><div>@@ -495,6 =
+537,7 @@ typedef union _SFLCounters_type {</div><div>=A0 =A0 =A0SFLTokenri=
ng_counters tokenring;</div>
<div>=A0 =A0 =A0SFLVg_counters vg;</div><div>=A0 =A0 =A0SFLVlan_counters vl=
an;</div><div>+ =A0 =A0SFLLACP_counters lacp;</div><div>=A0} SFLCounters_ty=
pe;</div><div>=A0</div><div>=A0typedef struct _SFLCounters_sample_element {=
</div><div>diff --git a/lib/sflow_agent.c b/lib/sflow_agent.c</div>
<div>index 817420d..9c2e028 100644</div><div>--- a/lib/sflow_agent.c</div><=
div>+++ b/lib/sflow_agent.c</div><div>@@ -363,6 +363,21 @@ SFLPoller *sfl_a=
gent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)</div><div>
=A0 =A0 =A0return NULL;</div><div>=A0}</div><div>=A0</div><div>+/*_________=
________-----------------------------------__________________</div><div>+ =
=A0_________________ =A0sfl_agent_getPollerByBridgePort =A0________________=
__</div><div>
+ =A0-----------------___________________________________------------------=
</div><div>+*/</div><div>+</div><div>+SFLPoller *sfl_agent_getPollerByBridg=
ePort(SFLAgent *agent, uint32_t port_no)</div><div>+{</div><div>+ =A0/* fin=
d it and return it */</div>
<div>+ =A0 =A0SFLPoller *pl =3D agent-&gt;pollers;</div><div>+ =A0 =A0for(;=
 pl !=3D NULL; pl =3D pl-&gt;nxt)</div><div>+<span class=3D"" style=3D"whit=
e-space:pre">	</span>if(pl-&gt;bridgePort =3D=3D port_no) return pl;</div><=
div>+ =A0 =A0/* not found */</div>
<div>+ =A0 =A0return NULL;</div><div>+}</div><div>+</div><div>=A0/*________=
_________---------------------------__________________</div><div>=A0 =A0___=
______________ =A0sfl_agent_getReceiver =A0 =A0__________________</div><div=
>=A0 =A0-----------------___________________________------------------</div=
>
<div>diff --git a/lib/sflow_api.h b/lib/sflow_api.h</div><div>index 3cc060b=
..2730a4c 100644</div><div>--- a/lib/sflow_api.h</div><div>+++ b/lib/sflow_=
api.h</div><div>@@ -281,6 +281,7 @@ void sfl_agent_set_agentSubId(SFLAgent =
*agent, u_int32_t subId);</div>
<div>=A0 =A0 to get counters if it is not the same as the global ifIndex */=
</div><div>=A0void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t p=
ort_no);</div><div>=A0u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller=
);</div>
<div>+SFLPoller *sfl_agent_getPollerByBridgePort(SFLAgent *agent, u_int32_t=
 port_no);</div><div>=A0</div><div>=A0/* call this to indicate a discontinu=
ity with a counter like samplePool so that the</div><div>=A0 =A0 sflow coll=
ector will ignore the next delta */</div>
<div>diff --git a/lib/sflow_receiver.c b/lib/sflow_receiver.c</div><div>ind=
ex 3e5a67a..282b175 100644</div><div>--- a/lib/sflow_receiver.c</div><div>+=
++ b/lib/sflow_receiver.c</div><div>@@ -460,6 +460,14 @@ static int compute=
FlowSampleSize(SFLReceiver *receiver, SFL_FLOW_SAMPLE_TYPE *fs</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span>case SFLFLOW_EX_=
MPLS_FTN: elemSiz =3D mplsFtnEncodingLength(&amp;elem-&gt;flowType.mpls_ftn=
); break;</div><div>=A0<span class=3D"" style=3D"white-space:pre">	</span>c=
ase SFLFLOW_EX_MPLS_LDP_FEC: elemSiz =3D mplsLdpFecEncodingLength(&amp;elem=
-&gt;flowType.mpls_ldp_fec); break;</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span>case SFLFLOW_EX_=
VLAN_TUNNEL: elemSiz =3D vlanTunnelEncodingLength(&amp;elem-&gt;flowType.vl=
an_tunnel); break;</div><div>+<span class=3D"" style=3D"white-space:pre">	<=
/span>case SFLFLOW_EX_IPV4_TUNNEL_EGRESS:</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLFLOW_EX_IP=
V4_TUNNEL_INGRESS:</div><div>+<span class=3D"" style=3D"white-space:pre">	<=
/span> =A0 =A0elemSiz =3D sizeof(SFLSampled_ipv4);</div><div>+<span class=
=3D"" style=3D"white-space:pre">	</span> =A0 =A0break;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLFLOW_EX_VN=
I_EGRESS:</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>cas=
e SFLFLOW_EX_VNI_INGRESS:</div><div>+<span class=3D"" style=3D"white-space:=
pre">	</span> =A0 =A0elemSiz =3D sizeof(SFLExtended_vni);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0break;</di=
v><div>=A0<span class=3D"" style=3D"white-space:pre">	</span>default:</div>=
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0sflError=
(receiver, &quot;unexpected packet_data_tag&quot;);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0return -=
1;</div><div>@@ -556,6 +564,8 @@ int sfl_receiver_writeFlowSample(SFLReceiv=
er *receiver, SFL_FLOW_SAMPLE_TYPE *fs</div><div>=A0<span class=3D"" style=
=3D"white-space:pre">		</span>putNet32(receiver, elem-&gt;flowType.ethernet=
.eth_type);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">		</span>break;</div><di=
v>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0case SFLFLO=
W_IPV4:</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =
=A0case SFLFLOW_EX_IPV4_TUNNEL_EGRESS:</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0case SFLFL=
OW_EX_IPV4_TUNNEL_INGRESS:</div><div>=A0<span class=3D"" style=3D"white-spa=
ce:pre">		</span>putNet32(receiver, elem-&gt;flowType.ipv4.length);</div><d=
iv>=A0<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiver=
, elem-&gt;flowType.ipv4.protocol);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">		</span>put32(receiver,=
 elem-&gt;flowType.ipv4.src_ip.addr);</div><div>@@ -587,6 +597,11 @@ int sf=
l_receiver_writeFlowSample(SFLReceiver *receiver, SFL_FLOW_SAMPLE_TYPE *fs<=
/div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0case SFL=
FLOW_EX_MPLS_FTN: putMplsFtn(receiver, &amp;elem-&gt;flowType.mpls_ftn); br=
eak;</div><div>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =
=A0case SFLFLOW_EX_MPLS_LDP_FEC: putMplsLdpFec(receiver, &amp;elem-&gt;flow=
Type.mpls_ldp_fec); break;</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0case SFL=
FLOW_EX_VLAN_TUNNEL: putVlanTunnel(receiver, &amp;elem-&gt;flowType.vlan_tu=
nnel); break;</div><div>+<span class=3D"" style=3D"white-space:pre">	</span=
> =A0 =A0case SFLFLOW_EX_VNI_EGRESS:</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0case SFLFL=
OW_EX_VNI_INGRESS:</div><div>+<span class=3D"" style=3D"white-space:pre">		=
</span>putNet32(receiver, elem-&gt;flowType.tunnel_vni.vni);</div><div>+<sp=
an class=3D"" style=3D"white-space:pre">		</span>break;</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span></div><div>=A0<sp=
an class=3D"" style=3D"white-space:pre">	</span> =A0 =A0default:</div><div>=
=A0<span class=3D"" style=3D"white-space:pre">		</span>sflError(receiver, &=
quot;unexpected packet_data_tag&quot;);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">		</span>return -1;</div=
><div>@@ -630,6 +645,7 @@ static int computeCountersSampleSize(SFLReceiver =
*receiver, SFL_COUNTERS_SAMPLE_</div><div>=A0<span class=3D"" style=3D"whit=
e-space:pre">	</span>case SFLCOUNTERS_TOKENRING: elemSiz =3D sizeof(elem-&g=
t;counterBlock.tokenring); break;</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span>case SFLCOUNTERS=
_VG: elemSiz =3D sizeof(elem-&gt;counterBlock.vg); break;</div><div>=A0<spa=
n class=3D"" style=3D"white-space:pre">	</span>case SFLCOUNTERS_VLAN: elemS=
iz =3D sizeof(elem-&gt;counterBlock.vlan); break;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLCOUNTERS_L=
ACP: elemSiz =3D sizeof(elem-&gt;counterBlock.lacp); break;</div><div>=A0<s=
pan class=3D"" style=3D"white-space:pre">	</span>default:</div><div>=A0<spa=
n class=3D"" style=3D"white-space:pre">	</span> =A0 =A0sflError(receiver, &=
quot;unexpected counters_tag&quot;);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0return -=
1;</div><div>@@ -731,6 +747,20 @@ int sfl_receiver_writeCountersSample(SFLR=
eceiver *receiver, SFL_COUNTERS_SAMPLE_</div><div>=A0<span class=3D"" style=
=3D"white-space:pre">		</span>putNet32(receiver, elem-&gt;counterBlock.vlan=
.broadcastPkts);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiv=
er, elem-&gt;counterBlock.vlan.discards);</div><div>=A0<span class=3D"" sty=
le=3D"white-space:pre">		</span>break;</div><div>+<span class=3D"" style=3D=
"white-space:pre">	</span> =A0 =A0case SFLCOUNTERS_LACP:</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>putMACAddress(rec=
eiver, elem-&gt;counterBlock.lacp.actorSystemID);</div><div>+<span class=3D=
"" style=3D"white-space:pre">		</span>putMACAddress(receiver, elem-&gt;coun=
terBlock.lacp.partnerSystemID);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiver=
, elem-&gt;counterBlock.lacp.attachedAggID);</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">		</span>put32(receiver, elem-&gt;counterBlock.lacp=
.portState.all);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiver=
, elem-&gt;counterBlock.lacp.LACPDUsRx);</div><div>+<span class=3D"" style=
=3D"white-space:pre">		</span>putNet32(receiver, elem-&gt;counterBlock.lacp=
.markerPDUsRx);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiver=
, elem-&gt;counterBlock.lacp.markerResponsePDUsRx);</div><div>+<span class=
=3D"" style=3D"white-space:pre">		</span>putNet32(receiver, elem-&gt;counte=
rBlock.lacp.unknownRx);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiver=
, elem-&gt;counterBlock.lacp.illegalRx);</div><div>+<span class=3D"" style=
=3D"white-space:pre">		</span>putNet32(receiver, elem-&gt;counterBlock.lacp=
.LACPDUsTx);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>putNet32(receiver=
, elem-&gt;counterBlock.lacp.markerPDUsTx);</div><div>+<span class=3D"" sty=
le=3D"white-space:pre">		</span>putNet32(receiver, elem-&gt;counterBlock.la=
cp.markerResponsePDUsTx);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>break;</div><div>=
=A0<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0default:</div=
><div>=A0<span class=3D"" style=3D"white-space:pre">		</span>sflError(recei=
ver, &quot;unexpected counters_tag&quot;);</div>
<div>=A0<span class=3D"" style=3D"white-space:pre">		</span>return -1;</div=
><div>diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflo=
w.c</div><div>index 158887f..1ae2f10 100644</div><div>--- a/ofproto/ofproto=
-dpif-sflow.c</div>
<div>+++ b/ofproto/ofproto-dpif-sflow.c</div><div>@@ -24,8 +24,6 @@</div><d=
iv>=A0#include &quot;collectors.h&quot;</div><div>=A0#include &quot;compile=
r.h&quot;</div><div>=A0#include &quot;dpif.h&quot;</div><div>-#include &quo=
t;hash.h&quot;</div>
<div>-#include &quot;hmap.h&quot;</div><div>=A0#include &quot;netdev.h&quot=
;</div><div>=A0#include &quot;netlink.h&quot;</div><div>=A0#include &quot;o=
fpbuf.h&quot;</div><div>@@ -39,32 +37,25 @@</div><div>=A0#include &quot;vlo=
g.h&quot;</div>
<div>=A0#include &quot;lib/odp-util.h&quot;</div><div>=A0#include &quot;ofp=
roto-provider.h&quot;</div><div>+#include &quot;lacp.h&quot;</div><div>+#in=
clude &quot;lib/byte-order.h&quot;</div><div>=A0</div><div>=A0VLOG_DEFINE_T=
HIS_MODULE(sflow);</div>
<div>=A0</div><div>=A0static struct ovs_mutex mutex;</div><div>=A0</div><di=
v>-struct dpif_sflow_port {</div><div>- =A0 =A0struct hmap_node hmap_node; =
/* In struct dpif_sflow&#39;s &quot;ports&quot; hmap. */</div><div>- =A0 =
=A0SFLDataSource_instance dsi; /* sFlow library&#39;s notion of port number=
. */</div>
<div>- =A0 =A0struct ofport *ofport; =A0 =A0 =A0/* To retrive port stats. *=
/</div><div>- =A0 =A0odp_port_t odp_port;</div><div>-};</div><div>-</div><d=
iv>=A0struct dpif_sflow {</div><div>=A0 =A0 =A0struct collectors *collector=
s;</div><div>=A0 =A0 =A0SFLAgent *sflow_agent;</div>
<div>=A0 =A0 =A0struct ofproto_sflow_options *options;</div><div>=A0 =A0 =
=A0time_t next_tick;</div><div>=A0 =A0 =A0size_t n_flood, n_all;</div><div>=
- =A0 =A0struct hmap ports; =A0 =A0 =A0 =A0 =A0/* Contains &quot;struct dpi=
f_sflow_port&quot;s. */</div><div>
=A0 =A0 =A0uint32_t probability;</div><div>=A0 =A0 =A0atomic_int ref_cnt;</=
div><div>+ =A0 =A0dpif_sflow_callback port_callback;</div><div>+ =A0 =A0voi=
d *port_callback_magic;</div><div>=A0};</div><div>=A0</div><div>-static voi=
d dpif_sflow_del_port__(struct dpif_sflow *,</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s=
truct dpif_sflow_port *);</div><div>-</div><div>=A0#define RECEIVER_INDEX 1=
</div><div>=A0</div><div>=A0static struct vlog_rate_limit rl =3D VLOG_RATE_=
LIMIT_INIT(1, 5);</div><div>@@ -144,21 +135,6 @@ sflow_agent_send_packet_cb=
(void *ds_, SFLAgent *agent OVS_UNUSED,</div>
<div>=A0 =A0 =A0collectors_send(ds-&gt;collectors, pkt, pktLen);</div><div>=
=A0}</div><div>=A0</div><div>-static struct dpif_sflow_port *</div><div>-dp=
if_sflow_find_port(const struct dpif_sflow *ds, odp_port_t odp_port)</div><=
div>- =A0 =A0OVS_REQUIRES(mutex)</div>
<div>-{</div><div>- =A0 =A0struct dpif_sflow_port *dsp;</div><div>-</div><d=
iv>- =A0 =A0HMAP_FOR_EACH_IN_BUCKET (dsp, hmap_node, hash_odp_port(odp_port=
),</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &amp=
;ds-&gt;ports) {</div><div>- =A0 =A0 =A0 =A0if (dsp-&gt;odp_port =3D=3D odp=
_port) {</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0return dsp;</div><div>- =A0 =A0 =A0 =A0}</div=
><div>- =A0 =A0}</div><div>- =A0 =A0return NULL;</div><div>-}</div><div>-</=
div><div>=A0static void</div><div>=A0sflow_agent_get_counters(void *ds_, SF=
LPoller *poller,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 SFL_COUNTERS_SAMPLE_TYPE *cs)</div>
<div>@@ -167,21 +143,27 @@ sflow_agent_get_counters(void *ds_, SFLPoller *p=
oller,</div><div>=A0 =A0 =A0struct dpif_sflow *ds =3D ds_;</div><div>=A0 =
=A0 =A0SFLCounters_sample_element elem;</div><div>=A0 =A0 =A0enum netdev_fe=
atures current;</div>
<div>- =A0 =A0struct dpif_sflow_port *dsp;</div><div>=A0 =A0 =A0SFLIf_count=
ers *counters;</div><div>=A0 =A0 =A0struct netdev_stats stats;</div><div>=
=A0 =A0 =A0enum netdev_flags flags;</div><div>-</div><div>- =A0 =A0dsp =3D =
dpif_sflow_find_port(ds, u32_to_odp(poller-&gt;bridgePort));</div>
<div>- =A0 =A0if (!dsp) {</div><div>- =A0 =A0 =A0 =A0return;</div><div>+ =
=A0 =A0struct dpif_sflow_port_lookup port_lookup;</div><div>+ =A0 =A0SFLCou=
nters_sample_element lacpElem;</div><div>+ =A0 =A0struct lacp_slave_stats l=
acp_stats;</div><div>+ =A0 =A0SFLLACP_counters *lacp;</div>
<div>+</div><div>+ =A0 =A0memset(&amp;port_lookup, 0, sizeof port_lookup);<=
/div><div>+ =A0 =A0if(!(*ds-&gt;port_callback)(ds-&gt;port_callback_magic,<=
/div><div>+<span class=3D"" style=3D"white-space:pre">			</span> =A0 =A0 (o=
fp_port_t)(poller-&gt;bridgePort),</div>
<div>+<span class=3D"" style=3D"white-space:pre">			</span> =A0 =A0 &amp;po=
rt_lookup)) {</div><div>+ =A0 =A0 =A0return;</div><div>=A0 =A0 =A0}</div><d=
iv>=A0</div><div>+ =A0 =A0memset(&amp;elem, 0, sizeof elem);</div><div>=A0 =
=A0 =A0elem.tag =3D SFLCOUNTERS_GENERIC;</div>
<div>=A0 =A0 =A0counters =3D &amp;elem.counterBlock.generic;</div><div>=A0 =
=A0 =A0counters-&gt;ifIndex =3D SFL_DS_INDEX(poller-&gt;dsi);</div><div>=A0=
 =A0 =A0counters-&gt;ifType =3D 6;</div><div>- =A0 =A0if (!netdev_get_featu=
res(dsp-&gt;ofport-&gt;netdev, &amp;current, NULL, NULL, NULL)) {</div>
<div>+ =A0 =A0if (!netdev_get_features(port_lookup.ofport-&gt;netdev, &amp;=
current, NULL, NULL, NULL)) {</div><div>=A0 =A0 =A0 =A0 =A0/* The values of=
 ifDirection come from MAU MIB (RFC 2668): 0 =3D unknown,</div><div>=A0 =A0=
 =A0 =A0 =A0 =A0 1 =3D full-duplex, 2 =3D half-duplex, 3 =3D in, 4=3Dout */=
</div>
<div>=A0 =A0 =A0 =A0 =A0counters-&gt;ifSpeed =3D netdev_features_to_bps(cur=
rent, 0);</div><div>@@ -191,9 +173,9 @@ sflow_agent_get_counters(void *ds_,=
 SFLPoller *poller,</div><div>=A0 =A0 =A0 =A0 =A0counters-&gt;ifSpeed =3D 1=
00000000;</div><div>
=A0 =A0 =A0 =A0 =A0counters-&gt;ifDirection =3D 0;</div><div>=A0 =A0 =A0}</=
div><div>- =A0 =A0if (!netdev_get_flags(dsp-&gt;ofport-&gt;netdev, &amp;fla=
gs) &amp;&amp; flags &amp; NETDEV_UP) {</div><div>+ =A0 =A0if (!netdev_get_=
flags(port_lookup.ofport-&gt;netdev, &amp;flags) &amp;&amp; flags &amp; NET=
DEV_UP) {</div>
<div>=A0 =A0 =A0 =A0 =A0counters-&gt;ifStatus =3D 1; /* ifAdminStatus up. *=
/</div><div>- =A0 =A0 =A0 =A0if (netdev_get_carrier(dsp-&gt;ofport-&gt;netd=
ev)) {</div><div>+ =A0 =A0 =A0 =A0if (netdev_get_carrier(port_lookup.ofport=
-&gt;netdev)) {</div><div>
=A0 =A0 =A0 =A0 =A0 =A0 =A0counters-&gt;ifStatus |=3D 2; /* ifOperStatus us=
. */</div><div>=A0 =A0 =A0 =A0 =A0}</div><div>=A0 =A0 =A0} else {</div><div=
>@@ -205,23 +187,57 @@ sflow_agent_get_counters(void *ds_, SFLPoller *polle=
r,</div><div>=A0 =A0 =A0 =A0 2. Does the multicast counter include broadcas=
ts?</div>
<div>=A0 =A0 =A0 =A0 3. Does the rx_packets counter include multicasts/broa=
dcasts?</div><div>=A0 =A0 =A0*/</div><div>- =A0 =A0ofproto_port_get_stats(d=
sp-&gt;ofport, &amp;stats);</div><div>+ =A0 =A0ofproto_port_get_stats(port_=
lookup.ofport, &amp;stats);</div>
<div>=A0 =A0 =A0counters-&gt;ifInOctets =3D stats.rx_bytes;</div><div>=A0 =
=A0 =A0counters-&gt;ifInUcastPkts =3D stats.rx_packets;</div><div>=A0 =A0 =
=A0counters-&gt;ifInMulticastPkts =3D stats.multicast;</div><div>- =A0 =A0c=
ounters-&gt;ifInBroadcastPkts =3D -1;</div>
<div>+ =A0 =A0SFL_UNDEF_COUNTER(counters-&gt;ifInBroadcastPkts);</div><div>=
=A0 =A0 =A0counters-&gt;ifInDiscards =3D stats.rx_dropped;</div><div>=A0 =
=A0 =A0counters-&gt;ifInErrors =3D stats.rx_errors;</div><div>- =A0 =A0coun=
ters-&gt;ifInUnknownProtos =3D -1;</div>
<div>+ =A0 =A0SFL_UNDEF_COUNTER(counters-&gt;ifInUnknownProtos);</div><div>=
=A0 =A0 =A0counters-&gt;ifOutOctets =3D stats.tx_bytes;</div><div>=A0 =A0 =
=A0counters-&gt;ifOutUcastPkts =3D stats.tx_packets;</div><div>- =A0 =A0cou=
nters-&gt;ifOutMulticastPkts =3D -1;</div>
<div>- =A0 =A0counters-&gt;ifOutBroadcastPkts =3D -1;</div><div>+ =A0 =A0SF=
L_UNDEF_COUNTER(counters-&gt;ifOutMulticastPkts);</div><div>+ =A0 =A0SFL_UN=
DEF_COUNTER(counters-&gt;ifOutBroadcastPkts);</div><div>=A0 =A0 =A0counters=
-&gt;ifOutDiscards =3D stats.tx_dropped;</div>
<div>=A0 =A0 =A0counters-&gt;ifOutErrors =3D stats.tx_errors;</div><div>=A0=
 =A0 =A0counters-&gt;ifPromiscuousMode =3D 0;</div><div>=A0</div><div>=A0 =
=A0 =A0SFLADD_ELEMENT(cs, &amp;elem);</div><div>+</div><div>+ =A0 =A0if(por=
t_lookup.lacp) {</div><div>
+<span class=3D"" style=3D"white-space:pre">	</span>memset(&amp;lacp_stats,=
 0, sizeof lacp_stats);</div><div>+<span class=3D"" style=3D"white-space:pr=
e">	</span>/* Implements sFlow standard: <a href=3D"http://sflow.org/sflow_=
lag.txt">http://sflow.org/sflow_lag.txt</a> */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>if(lacp_get_slave_=
stats(port_lookup.lacp,</div><div>+<span class=3D"" style=3D"white-space:pr=
e">				</span>port_lookup.lacp_slave,</div><div>+<span class=3D"" style=3D"=
white-space:pre">				</span>&amp;lacp_stats)) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0memset(&am=
p;lacpElem, 0, sizeof lacpElem);</div><div>+<span class=3D"" style=3D"white=
-space:pre">	</span> =A0 =A0lacpElem.tag =3D SFLCOUNTERS_LACP;</div><div>+<=
span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp =3D &amp;lac=
pElem.counterBlock.lacp;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0memcpy(lac=
p-&gt;actorSystemID,</div><div>+<span class=3D"" style=3D"white-space:pre">=
		</span> =A0 lacp_stats.dot3adAggPortActorSystemID,</div><div>+<span class=
=3D"" style=3D"white-space:pre">		</span> =A0 ETH_ADDR_LEN);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0memcpy(lac=
p-&gt;partnerSystemID,</div><div>+<span class=3D"" style=3D"white-space:pre=
">		</span> =A0 lacp_stats.dot3adAggPortPartnerOperSystemID,</div><div>+<sp=
an class=3D"" style=3D"white-space:pre">		</span> =A0 ETH_ADDR_LEN);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;a=
ttachedAggID =3D lacp_stats.dot3adAggPortAttachedAggID;</div><div>+<span cl=
ass=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;portState.v.act=
orAdmin =3D lacp_stats.dot3adAggPortActorAdminState;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;p=
ortState.v.actorOper =3D lacp_stats.dot3adAggPortActorOperState;</div><div>=
+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;portSt=
ate.v.partnerAdmin =3D lacp_stats.dot3adAggPortPartnerAdminState;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;p=
ortState.v.partnerOper =3D lacp_stats.dot3adAggPortPartnerOperState;</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;LA=
CPDUsRx =3D lacp_stats.dot3adAggPortStatsLACPDUsRx;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0SFL_UNDEF_=
COUNTER(lacp-&gt;markerPDUsRx);</div><div>+<span class=3D"" style=3D"white-=
space:pre">	</span> =A0 =A0SFL_UNDEF_COUNTER(lacp-&gt;markerResponsePDUsRx)=
;</div><div>
+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0SFL_UNDEF_COUNT=
ER(lacp-&gt;unknownRx);</div><div>+<span class=3D"" style=3D"white-space:pr=
e">	</span> =A0 =A0lacp-&gt;illegalRx =3D lacp_stats.dot3adAggPortStatsIlle=
galRx;</div><div>
+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0lacp-&gt;LACPDU=
sTx =3D lacp_stats.dot3adAggPortStatsLACPDUsTx;</div><div>+<span class=3D""=
 style=3D"white-space:pre">	</span> =A0 =A0SFL_UNDEF_COUNTER(lacp-&gt;marke=
rPDUsTx);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0SFL_UNDEF_=
COUNTER(lacp-&gt;markerResponsePDUsTx);</div><div>+</div><div>+<span class=
=3D"" style=3D"white-space:pre">	</span> =A0 =A0SFLADD_ELEMENT(cs, &amp;lac=
pElem);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+ =A0 =
=A0}</div><div>+</div><div>=A0 =A0 =A0sfl_poller_writeCountersSample(poller=
, cs);</div><div>=A0}</div><div>=A0</div><div>@@ -324,7 +340,6 @@ dpif_sflo=
w_create(void)</div>
<div>=A0</div><div>=A0 =A0 =A0ds =3D xcalloc(1, sizeof *ds);</div><div>=A0 =
=A0 =A0ds-&gt;next_tick =3D time_now() + 1;</div><div>- =A0 =A0hmap_init(&a=
mp;ds-&gt;ports);</div><div>=A0 =A0 =A0ds-&gt;probability =3D 0;</div><div>=
=A0 =A0 =A0route_table_register();</div>
<div>=A0 =A0 =A0atomic_init(&amp;ds-&gt;ref_cnt, 1);</div><div>@@ -369,84 +=
384,54 @@ dpif_sflow_unref(struct dpif_sflow *ds) OVS_EXCLUDED(mutex)</div>=
<div>=A0 =A0 =A0atomic_sub(&amp;ds-&gt;ref_cnt, 1, &amp;orig);</div><div>=
=A0 =A0 =A0ovs_assert(orig &gt; 0);</div>
<div>=A0 =A0 =A0if (orig =3D=3D 1) {</div><div>- =A0 =A0 =A0 =A0struct dpif=
_sflow_port *dsp, *next;</div><div>-</div><div>=A0 =A0 =A0 =A0 =A0route_tab=
le_unregister();</div><div>=A0 =A0 =A0 =A0 =A0dpif_sflow_clear(ds);</div><d=
iv>- =A0 =A0 =A0 =A0HMAP_FOR_EACH_SAFE (dsp, next, hmap_node, &amp;ds-&gt;p=
orts) {</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0dpif_sflow_del_port__(ds, dsp);</div><div>- =
=A0 =A0 =A0 =A0}</div><div>- =A0 =A0 =A0 =A0hmap_destroy(&amp;ds-&gt;ports)=
;</div><div>=A0 =A0 =A0 =A0 =A0free(ds);</div><div>=A0 =A0 =A0}</div><div>=
=A0}</div><div>=A0</div><div>=A0static void</div>
<div>-dpif_sflow_add_poller(struct dpif_sflow *ds, struct dpif_sflow_port *=
dsp)</div><div>+dpif_sflow_add_poller(struct dpif_sflow *ds, uint32_t ifind=
ex, ofp_port_t ofp_port)</div><div>=A0 =A0 =A0OVS_REQUIRES(mutex)</div><div=
>=A0{</div>
<div>- =A0 =A0SFLPoller *poller =3D sfl_agent_addPoller(ds-&gt;sflow_agent,=
 &amp;dsp-&gt;dsi, ds,</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflow_agent_get_counters);</=
div><div>- =A0 =A0sfl_poller_set_sFlowCpInterval(poller, ds-&gt;options-&gt=
;polling_interval);</div>
<div>- =A0 =A0sfl_poller_set_sFlowCpReceiver(poller, RECEIVER_INDEX);</div>=
<div>- =A0 =A0sfl_poller_set_bridgePort(poller, odp_to_u32(dsp-&gt;odp_port=
));</div><div>+ =A0 =A0SFLDataSource_instance dsi;</div><div>+ =A0 =A0SFLPo=
ller *poller;</div>
<div>+ =A0 =A0if(ds-&gt;sflow_agent) {</div><div>+<span class=3D"" style=3D=
"white-space:pre">	</span>SFL_DS_SET(dsi, SFL_DSCLASS_IFINDEX, ifindex, 0);=
</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>poller =3D s=
fl_agent_addPoller(ds-&gt;sflow_agent, &amp;dsi, ds,</div>
<div>+<span class=3D"" style=3D"white-space:pre">				</span> =A0 =A0 sflow_=
agent_get_counters);</div><div>+<span class=3D"" style=3D"white-space:pre">=
	</span>sfl_poller_set_sFlowCpInterval(poller, ds-&gt;options-&gt;polling_i=
nterval);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>sfl_poller_set_sFl=
owCpReceiver(poller, RECEIVER_INDEX);</div><div>+<span class=3D"" style=3D"=
white-space:pre">	</span>sfl_poller_set_bridgePort(poller, (uint32_t)ofp_po=
rt);</div>
<div>+ =A0 =A0}</div><div>=A0}</div><div>=A0</div><div>=A0void</div><div>-d=
pif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport,</div><div>=
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0odp_port_t odp_port) OVS_EXCLUDED(=
mutex)</div><div>+dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport =
*ofport) OVS_EXCLUDED(mutex)</div>
<div>=A0{</div><div>- =A0 =A0struct dpif_sflow_port *dsp;</div><div>=A0 =A0=
 =A0int ifindex;</div><div>=A0</div><div>=A0 =A0 =A0ovs_mutex_lock(&amp;mut=
ex);</div><div>- =A0 =A0dpif_sflow_del_port(ds, odp_port);</div><div>-</div=
><div>+ =A0 =A0dpif_sflow_del_port(ds, ofport-&gt;ofp_port);</div>
<div>=A0 =A0 =A0ifindex =3D netdev_get_ifindex(ofport-&gt;netdev);</div><di=
v>-</div><div>- =A0 =A0if (ifindex &lt;=3D 0) {</div><div>- =A0 =A0 =A0 =A0=
/* Not an ifindex port, so do not add a cross-reference to it here */</div>=
<div>- =A0 =A0 =A0 =A0goto out;</div>
<div>+ =A0 =A0if (ifindex &gt; 0) {</div><div>+ =A0 =A0 =A0 =A0/* ifindex p=
ort, so add a poller for it here */</div><div>+ =A0 =A0 =A0 =A0dpif_sflow_a=
dd_poller(ds, ifindex, ofport-&gt;ofp_port);</div><div>=A0 =A0 =A0}</div><d=
iv>-</div><div>- =A0 =A0/* Add to table of ports. */</div>
<div>- =A0 =A0dsp =3D xmalloc(sizeof *dsp);</div><div>- =A0 =A0dsp-&gt;ofpo=
rt =3D ofport;</div><div>- =A0 =A0dsp-&gt;odp_port =3D odp_port;</div><div>=
- =A0 =A0SFL_DS_SET(dsp-&gt;dsi, SFL_DSCLASS_IFINDEX, ifindex, 0);</div><di=
v>- =A0 =A0hmap_insert(&amp;ds-&gt;ports, &amp;dsp-&gt;hmap_node, hash_odp_=
port(odp_port));</div>
<div>-</div><div>- =A0 =A0/* Add poller. */</div><div>- =A0 =A0if (ds-&gt;s=
flow_agent) {</div><div>- =A0 =A0 =A0 =A0dpif_sflow_add_poller(ds, dsp);</d=
iv><div>- =A0 =A0}</div><div>-</div><div>-out:</div><div>=A0 =A0 =A0ovs_mut=
ex_unlock(&amp;mutex);</div>
<div>=A0}</div><div>=A0</div><div>-static void</div><div>-dpif_sflow_del_po=
rt__(struct dpif_sflow *ds, struct dpif_sflow_port *dsp)</div><div>- =A0 =
=A0OVS_REQUIRES(mutex)</div><div>-{</div><div>- =A0 =A0if (ds-&gt;sflow_age=
nt) {</div>
<div>- =A0 =A0 =A0 =A0sfl_agent_removePoller(ds-&gt;sflow_agent, &amp;dsp-&=
gt;dsi);</div><div>- =A0 =A0 =A0 =A0sfl_agent_removeSampler(ds-&gt;sflow_ag=
ent, &amp;dsp-&gt;dsi);</div><div>- =A0 =A0}</div><div>- =A0 =A0hmap_remove=
(&amp;ds-&gt;ports, &amp;dsp-&gt;hmap_node);</div>
<div>- =A0 =A0free(dsp);</div><div>-}</div><div>-</div><div>=A0void</div><d=
iv>-dpif_sflow_del_port(struct dpif_sflow *ds, odp_port_t odp_port)</div><d=
iv>+dpif_sflow_del_port(struct dpif_sflow *ds, ofp_port_t ofp_port)</div><d=
iv>
=A0 =A0 =A0OVS_EXCLUDED(mutex)</div><div>=A0{</div><div>- =A0 =A0struct dpi=
f_sflow_port *dsp;</div><div>-</div><div>+ =A0 =A0SFLPoller *poller;</div><=
div>=A0 =A0 =A0ovs_mutex_lock(&amp;mutex);</div><div>- =A0 =A0dsp =3D dpif_=
sflow_find_port(ds, odp_port);</div>
<div>- =A0 =A0if (dsp) {</div><div>- =A0 =A0 =A0 =A0dpif_sflow_del_port__(d=
s, dsp);</div><div>+ =A0 =A0if(ds-&gt;sflow_agent) {</div><div>+<span class=
=3D"" style=3D"white-space:pre">	</span>poller =3D sfl_agent_getPollerByBri=
dgePort(ds-&gt;sflow_agent, (uint32_t)ofp_port);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>if(poller) {</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0sfl_agent_=
removePoller(ds-&gt;sflow_agent, &amp;poller-&gt;dsi);</div><div>+<span cla=
ss=3D"" style=3D"white-space:pre">	</span>}</div>
<div>=A0 =A0 =A0}</div><div>=A0 =A0 =A0ovs_mutex_unlock(&amp;mutex);</div><=
div>=A0}</div><div>@@ -456,7 +441,6 @@ dpif_sflow_set_options(struct dpif_s=
flow *ds,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const s=
truct ofproto_sflow_options *options)</div>
<div>=A0 =A0 =A0OVS_EXCLUDED(mutex)</div><div>=A0{</div><div>- =A0 =A0struc=
t dpif_sflow_port *dsp;</div><div>=A0 =A0 =A0bool options_changed;</div><di=
v>=A0 =A0 =A0SFLReceiver *receiver;</div><div>=A0 =A0 =A0SFLAddress agentIP=
;</div><div>@@ -543,33 +527,220 @@ dpif_sflow_set_options(struct dpif_sflow=
 *ds,</div>
<div>=A0 =A0 =A0sfl_sampler_set_sFlowFsMaximumHeaderSize(sampler, ds-&gt;op=
tions-&gt;header_len);</div><div>=A0 =A0 =A0sfl_sampler_set_sFlowFsReceiver=
(sampler, RECEIVER_INDEX);</div><div>=A0</div><div>- =A0 =A0/* Add pollers =
for the currently known ifindex-ports */</div>
<div>- =A0 =A0HMAP_FOR_EACH (dsp, hmap_node, &amp;ds-&gt;ports) {</div><div=
>- =A0 =A0 =A0 =A0dpif_sflow_add_poller(ds, dsp);</div><div>- =A0 =A0}</div=
><div>-</div><div>-</div><div>=A0out:</div><div>=A0 =A0 =A0ovs_mutex_unlock=
(&amp;mutex);</div><div>
=A0}</div><div>=A0</div><div>-int</div><div>-dpif_sflow_odp_port_to_ifindex=
(const struct dpif_sflow *ds,</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 odp_port_t odp_port) OVS_EXCLUDED(mutex)</div><=
div>+void</div><div>+dpif_sflow_set_port_lookup_callback(struct dpif_sflow =
*ds,</div>
<div>+<span class=3D"" style=3D"white-space:pre">				</span> =A0 =A0dpif_sf=
low_callback callback,</div><div>+<span class=3D"" style=3D"white-space:pre=
">				</span> =A0 =A0void *magic)</div><div>+ =A0 =A0OVS_EXCLUDED(mutex)</d=
iv><div>=A0{</div>
<div>- =A0 =A0struct dpif_sflow_port *dsp;</div><div>- =A0 =A0int ret;</div=
><div>-</div><div>=A0 =A0 =A0ovs_mutex_lock(&amp;mutex);</div><div>- =A0 =
=A0dsp =3D dpif_sflow_find_port(ds, odp_port);</div><div>- =A0 =A0ret =3D d=
sp ? SFL_DS_INDEX(dsp-&gt;dsi) : 0;</div>
<div>+ =A0 =A0ds-&gt;port_callback =3D callback;</div><div>+ =A0 =A0ds-&gt;=
port_callback_magic =3D magic;</div><div>=A0 =A0 =A0ovs_mutex_unlock(&amp;m=
utex);</div><div>- =A0 =A0return ret;</div><div>+}</div><div>+</div><div>+e=
num sflow_tunnel_type {</div>
<div>+ =A0 =A0SFLOW_TUNNEL_UNKNOWN,</div><div>+ =A0 =A0SFLOW_TUNNEL_GRE,</d=
iv><div>+ =A0 =A0SFLOW_TUNNEL_GRE64,</div><div>+ =A0 =A0SFLOW_TUNNEL_IPSEC_=
GRE,</div><div>+ =A0 =A0SFLOW_TUNNEL_IPSEC_GRE64,</div><div>+ =A0 =A0SFLOW_=
TUNNEL_VXLAN,</div><div>
+ =A0 =A0SFLOW_TUNNEL_LISP</div><div>+};</div><div>+</div><div>+static enum=
 sflow_tunnel_type</div><div>+dpif_sflow_tunnel_type(const char *netdev_typ=
e)</div><div>+{</div><div>+ =A0 =A0if(!strcmp(netdev_type, &quot;gre&quot;)=
) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>return SFLOW_TUNNE=
L_GRE;</div><div>+ =A0 =A0}</div><div>+ =A0 =A0if(!strcmp(netdev_type, &quo=
t;gre64&quot;)) {</div><div>+<span class=3D"" style=3D"white-space:pre">	</=
span>return SFLOW_TUNNEL_GRE64;</div>
<div>+ =A0 =A0}</div><div>+ =A0 =A0if(!strcmp(netdev_type, &quot;ipsec_gre&=
quot;)) {</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>ret=
urn SFLOW_TUNNEL_IPSEC_GRE;</div><div>+ =A0 =A0}</div><div>+ =A0 =A0if(!str=
cmp(netdev_type, &quot;ipsec_gre64&quot;)) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>return SFLOW_TUNNE=
L_IPSEC_GRE64;</div><div>+ =A0 =A0}</div><div>+ =A0 =A0if(!strcmp(netdev_ty=
pe, &quot;ipsec_gre64&quot;)) {</div><div>+<span class=3D"" style=3D"white-=
space:pre">	</span>return SFLOW_TUNNEL_IPSEC_GRE64;</div>
<div>+ =A0 =A0}</div><div>+ =A0 =A0if(!strcmp(netdev_type, &quot;vxlan&quot=
;)) {</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>return =
SFLOW_TUNNEL_VXLAN;</div><div>+ =A0 =A0}</div><div>+ =A0 =A0if(!strcmp(netd=
ev_type, &quot;lisp&quot;)) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>return SFLOW_TUNNE=
L_LISP;</div><div>+ =A0 =A0}</div><div>+ =A0 =A0return SFLOW_TUNNEL_UNKNOWN=
;</div><div>+}</div><div>+</div><div>+enum sflow_tunnel_direction {</div><d=
iv>+ =A0 =A0SFLOW_TUNNEL_INGRESS=3D1,</div>
<div>+ =A0 =A0SFLOW_TUNNEL_EGRESS=3D2</div><div>+};</div><div>+</div><div>+=
enum sflow_tunnel_flags {</div><div>+ =A0 =A0SFLOW_TUNNEL_FLAGS_NONE=3D0,</=
div><div>+ =A0 =A0SFLOW_TUNNEL_FLAGS_IPV4=3D1,</div><div>+ =A0 =A0SFLOW_TUN=
NEL_FLAGS_VNI=3D2</div>
<div>+};</div><div>+</div><div>+/* Implements sFlow standard: =A0<a href=3D=
"http://sflow.org/sflow_tunnels.txt">http://sflow.org/sflow_tunnels.txt</a>=
.</div><div>+ * Returns bitmask of enum sflow_tunnel_flags.</div><div>+ */<=
/div>
<div>+static int</div><div>+dpif_sflow_tunnel(SFLSampled_ipv4 *tunnel4,</di=
v><div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0SFLExtended=
_vni *tunnel_vni,</div><div>+<span class=3D"" style=3D"white-space:pre">		<=
/span> =A0const enum sflow_tunnel_direction direction,</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0const struct =
dpif_sflow_port_lookup *port_lookup,</div><div>+<span class=3D"" style=3D"w=
hite-space:pre">		</span> =A0const struct flow *flow)</div><div>+{</div><di=
v>+ =A0 =A0const struct netdev_tunnel_config *tcfg;</div>
<div>+</div><div>+ =A0 =A0tcfg =3D netdev_get_tunnel_config(port_lookup-&gt=
;ofport-&gt;netdev);</div><div>+ =A0 =A0if(tcfg =3D=3D NULL) {</div><div>+<=
span class=3D"" style=3D"white-space:pre">	</span>return SFLOW_TUNNEL_FLAGS=
_NONE;</div><div>
+ =A0 =A0}</div><div>+ =A0 =A0else {</div><div>+ =A0 =A0 =A0const char *net=
dev_type;</div><div>+ =A0 =A0 =A0enum sflow_tunnel_type tunnel_type;</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span>int ret =3D SFLOW_T=
UNNEL_FLAGS_IPV4;</div>
<div>+</div><div>+ <span class=3D"" style=3D"white-space:pre">	</span>/* In=
fer the ip protocol that was (or will be)</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span> * seen on the wire from the tunnel type.</div=
><div>
+<span class=3D"" style=3D"white-space:pre">	</span> */</div><div>+<span cl=
ass=3D"" style=3D"white-space:pre">	</span>netdev_type =3D netdev_get_type(=
port_lookup-&gt;ofport-&gt;netdev);</div><div>+<span class=3D"" style=3D"wh=
ite-space:pre">	</span>tunnel_type =3D dpif_sflow_tunnel_type(netdev_type);=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>switch(tunnel_type=
) {</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLO=
W_TUNNEL_GRE:</div><div>+<span class=3D"" style=3D"white-space:pre">	</span=
>case SFLOW_TUNNEL_GRE64:</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0tunnel4-&g=
t;protocol =3D IPPROTO_GRE;</div><div>+<span class=3D"" style=3D"white-spac=
e:pre">	</span> =A0 =A0break;</div><div>+<span class=3D"" style=3D"white-sp=
ace:pre">	</span>case SFLOW_TUNNEL_VXLAN:</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLOW_TUNNEL_=
LISP:</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =
=A0tunnel4-&gt;protocol =3D IPPROTO_UDP;</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span> =A0 =A0break;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLOW_TUNNEL_=
IPSEC_GRE:</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>ca=
se SFLOW_TUNNEL_IPSEC_GRE64:</div><div>+<span class=3D"" style=3D"white-spa=
ce:pre">	</span> =A0 =A0tunnel4-&gt;protocol =3D IPPROTO_ESP;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0break;</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>case SFLOW_TUNNE=
L_UNKNOWN:</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =
=A0 =A0break;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+</div=
><div>+<span class=3D"" style=3D"white-space:pre">	</span>if(direction =3D=
=3D SFLOW_TUNNEL_INGRESS) {</div><div>+<span class=3D"" style=3D"white-spac=
e:pre">	</span> =A0 =A0tunnel4-&gt;src_ip.addr =3D flow-&gt;tunnel.ip_src;<=
/div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0tunnel4-&g=
t;dst_ip.addr =3D flow-&gt;tunnel.ip_dst;</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span> =A0 =A0tunnel4-&gt;tos =3D flow-&gt;tunnel.ip=
_tos;</div><div>
+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0/* =
XXX For VXLAN and LISP where the</div><div>+<span class=3D"" style=3D"white=
-space:pre">	</span> =A0 =A0 * l4_ports are relevant too, can we</div><div>=
+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * reach into t=
he struct ofpbuf *packet to</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * read th=
em out for ingress tunnel packets?</div><div>+<span class=3D"" style=3D"whi=
te-space:pre">	</span> =A0 =A0 * They doesn&#39;t seem to be recorded for</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * us =
in the flow-&gt;tunnel struct.</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 */</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0/* tunnel4-=
&gt;src_port =3D flow-&gt;tunnel.src_port; */</div><div>+<span class=3D"" s=
tyle=3D"white-space:pre">	</span> =A0 =A0/* tunnel4-&gt;dst_port =3D flow-&=
gt;tunnel.dst_port; */</div>
<div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =
=A0if(tunnel_type =3D=3D SFLOW_TUNNEL_GRE64</div><div>+<span class=3D"" sty=
le=3D"white-space:pre">	</span> =A0 =A0 =A0 || tunnel_type =3D=3D SFLOW_TUN=
NEL_IPSEC_GRE64) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>/* XXX The key is=
 64-bit (appears on the wire</div><div>+<span class=3D"" style=3D"white-spa=
ce:pre">		</span> * as 32-bit key + overload of 32-bit sequence_no</div><di=
v>+<span class=3D"" style=3D"white-space:pre">		</span> * field). However w=
e only have 32-bits in the sFlow</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> * VNI field. If =
this key really can be treated exactly</div><div>+<span class=3D"" style=3D=
"white-space:pre">		</span> * like a VNI then perhaps a new structure shoul=
d be</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> * added to repor=
t it?</div><div>+<span class=3D"" style=3D"white-space:pre">		</span> */</d=
iv><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0else {</di=
v>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>if(flow-&gt;tunne=
l.flags &amp; FLOW_TNL_F_KEY) {</div><div>+<span class=3D"" style=3D"white-=
space:pre">		</span> =A0 =A0/* This assumes the 32-bit key is the least-sig=
nificant</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0 =A0 32-b=
its of flow-&gt;tunnel.tun_id. */</div><div>+<span class=3D"" style=3D"whit=
e-space:pre">		</span> =A0 =A0tunnel_vni-&gt;vni =3D (uint32_t)(ntohll(flow=
-&gt;tunnel.tun_id));</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0ret |=3D =
SFLOW_TUNNEL_FLAGS_VNI;</div><div>+<span class=3D"" style=3D"white-space:pr=
e">		</span>}</div><div>+<span class=3D"" style=3D"white-space:pre">		</spa=
n>else if(tcfg-&gt;in_key_present) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0/* If the=
 netdev_tunnel_config specifies an</div><div>+<span class=3D"" style=3D"whi=
te-space:pre">		</span> =A0 =A0 * &quot;in_key&quot; then it acts as a filt=
er so this packet</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0 * would =
only have reached here if it had this key.</div><div>+<span class=3D"" styl=
e=3D"white-space:pre">		</span> =A0 =A0 */</div><div>+<span class=3D"" styl=
e=3D"white-space:pre">		</span> =A0 =A0/* XXX. This might be redundant if f=
low-&gt;tunnel.tun_id</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0 * is alw=
ays filled in on ingress tunnel packets. */</div><div>+<span class=3D"" sty=
le=3D"white-space:pre">		</span> =A0 =A0tunnel_vni-&gt;vni =3D tcfg-&gt;in_=
key_flow ?</div>
<div>+<span class=3D"" style=3D"white-space:pre">			</span>ntohll(flow-&gt;=
tunnel.tun_id) :</div><div>+<span class=3D"" style=3D"white-space:pre">			<=
/span>ntohll(tcfg-&gt;in_key);</div><div>+<span class=3D"" style=3D"white-s=
pace:pre">		</span> =A0 =A0ret |=3D SFLOW_TUNNEL_FLAGS_VNI;</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>}</div><div>+<spa=
n class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div><div>+<span c=
lass=3D"" style=3D"white-space:pre">	</span>}</div><div>+<span class=3D"" s=
tyle=3D"white-space:pre">	</span>else {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0/* The EGR=
ESS path is rather different. =A0The</div><div>+<span class=3D"" style=3D"w=
hite-space:pre">	</span> =A0 =A0 * details on the tunneling that is going t=
o happen</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * may onl=
y be encoded in the actions. */</div><div>+</div><div>+<span class=3D"" sty=
le=3D"white-space:pre">	</span> =A0 =A0/* XXX Is this what tcfg-&gt;ip_src_=
flow means?</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * Probabl=
y not. =A0We may have to look at the</div><div>+<span class=3D"" style=3D"w=
hite-space:pre">	</span> =A0 =A0 * openflow actions to figure out what the<=
/div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * de=
tails are going to be.</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 */</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0tunnel4-&gt=
;src_ip.addr =3D tcfg-&gt;ip_src_flow ?</div><div>+<span class=3D"" style=
=3D"white-space:pre">		</span>flow-&gt;tunnel.ip_src :</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>tcfg-&gt;ip_src;<=
/div><div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =
=A0 =A0tunnel4-&gt;dst_ip.addr =3D tcfg-&gt;ip_dst_flow ?</div><div>+<span =
class=3D"" style=3D"white-space:pre">		</span>flow-&gt;tunnel.ip_dst :</div=
>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>tcfg-&gt;ip_dst;<=
/div><div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =
=A0 =A0/* The tos=3Dinherit option means that the tos bits</div><div>+<span=
 class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 are copied from =
the flow being tunneled. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0tunnel4-&g=
t;tos =3D tcfg-&gt;tos_inherit ?</div><div>+<span class=3D"" style=3D"white=
-space:pre">		</span>flow-&gt;nw_tos :</div><div>+<span class=3D"" style=3D=
"white-space:pre">		</span>tcfg-&gt;tos;</div>
<div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =
=A0/* src_port, dst_port only relevant for VXLAN and LISP. */</div><div>+<s=
pan class=3D"" style=3D"white-space:pre">	</span> =A0 =A0if(tunnel_type =3D=
=3D SFLOW_TUNNEL_VXLAN</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 || tu=
nnel_type =3D=3D SFLOW_TUNNEL_LISP) {</div><div>+<span class=3D"" style=3D"=
white-space:pre">		</span>/* src_port is added down in the datapath just be=
fore sending.</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> * It is computed=
 as a hash over the whole flow, including the</div><div>+<span class=3D"" s=
tyle=3D"white-space:pre">		</span> * tunneled addresses (to add entropy for=
 ECMP load-balancing).</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> * Theoretically =
we could compute the exact same digest here,</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">		</span> * but that would represent an unwelcome d=
ependency.</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> */</div><div>+<s=
pan class=3D"" style=3D"white-space:pre">		</span>tunnel4-&gt;src_port =3D =
0;</div><div>+<span class=3D"" style=3D"white-space:pre">		</span>tunnel4-&=
gt;dst_port =3D tcfg-&gt;dst_port;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div><di=
v>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0/=
* Where applicable, the VNI is the tunnel key. */</div><div>+<span class=3D=
"" style=3D"white-space:pre">	</span> =A0 =A0if(tunnel_type =3D=3D SFLOW_TU=
NNEL_GRE64</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0 =A0 || tu=
nnel_type =3D=3D SFLOW_TUNNEL_IPSEC_GRE64) {</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">		</span>/* ignore non-standard 64-bit key for now.=
</div><div>+<span class=3D"" style=3D"white-space:pre">		</span> * See comm=
ent for ingress path above. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0else {</div><=
div>+<span class=3D"" style=3D"white-space:pre">		</span>/* XXX what does t=
cfg-&gt;out_key_flow really mean? */</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>if(tcfg-&gt;out_k=
ey_present) {</div><div>+<span class=3D"" style=3D"white-space:pre">		</spa=
n> =A0 =A0tunnel_vni-&gt;vni =3D tcfg-&gt;out_key_flow ?</div><div>+<span c=
lass=3D"" style=3D"white-space:pre">			</span>ntohll(flow-&gt;tunnel.tun_id=
) :</div>
<div>+<span class=3D"" style=3D"white-space:pre">			</span>ntohll(tcfg-&gt;=
out_key);</div><div>+<span class=3D"" style=3D"white-space:pre">		</span> =
=A0 =A0ret |=3D SFLOW_TUNNEL_FLAGS_VNI;</div><div>+<span class=3D"" style=
=3D"white-space:pre">		</span>}</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+</div><d=
iv>+<span class=3D"" style=3D"white-space:pre">	</span>return ret;</div><di=
v>+ =A0 =A0}</div>
<div>=A0}</div><div>=A0</div><div>=A0void</div><div>=A0dpif_sflow_received(=
struct dpif_sflow *ds, struct ofpbuf *packet,</div><div>- =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0const struct flow *flow, odp_port_t odp_in_port,</di=
v><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const struct flow *flow,</d=
iv>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const union user_action_coo=
kie *cookie)</div><div>=A0 =A0 =A0OVS_EXCLUDED(mutex)</div><div>=A0{</div><=
div>@@ -578,10 +749,15 @@ dpif_sflow_received(struct dpif_sflow *ds, struct=
 ofpbuf *packet,</div><div>
=A0 =A0 =A0SFLSampled_header *header;</div><div>=A0 =A0 =A0SFLFlow_sample_e=
lement switchElem;</div><div>=A0 =A0 =A0SFLSampler *sampler;</div><div>- =
=A0 =A0struct dpif_sflow_port *in_dsp;</div><div>=A0 =A0 =A0ovs_be16 vlan_t=
ci;</div><div>+ =A0 =A0struct dpif_sflow_port_lookup in_lookup, out_lookup;=
</div>
<div>+ =A0 =A0SFLFlow_sample_element in_tunnelElem, out_tunnelElem;</div><d=
iv>+ =A0 =A0SFLFlow_sample_element in_vniElem, out_vniElem;</div><div>+ =A0=
 =A0int in_ifindex, out_ifindex;</div><div>+ =A0 =A0int in_tunnel_flags, ou=
t_tunnel_flags;</div>
<div>=A0</div><div>=A0 =A0 =A0ovs_mutex_lock(&amp;mutex);</div><div>+</div>=
<div>=A0 =A0 =A0sampler =3D ds-&gt;sflow_agent-&gt;samplers;</div><div>=A0 =
=A0 =A0if (!sampler) {</div><div>=A0 =A0 =A0 =A0 =A0goto out;</div><div>@@ =
-590,11 +766,35 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf=
 *packet,</div>
<div>=A0 =A0 =A0/* Build a flow sample. */</div><div>=A0 =A0 =A0memset(&amp=
;fs, 0, sizeof fs);</div><div>=A0</div><div>- =A0 =A0/* Look up the input i=
fIndex if this port has one. Otherwise just</div><div>- =A0 =A0 * leave it =
as 0 (meaning &#39;unknown&#39;) and continue. */</div>
<div>- =A0 =A0in_dsp =3D dpif_sflow_find_port(ds, odp_in_port);</div><div>-=
 =A0 =A0if (in_dsp) {</div><div>- =A0 =A0 =A0 =A0fs.input =3D SFL_DS_INDEX(=
in_dsp-&gt;dsi);</div><div>+ =A0 =A0memset(&amp;in_lookup, 0, sizeof in_loo=
kup);</div><div>+ =A0 =A0if((*ds-&gt;port_callback)(ds-&gt;port_callback_ma=
gic,</div>
<div>+<span class=3D"" style=3D"white-space:pre">			</span> =A0 =A0flow-&gt=
;in_port.ofp_port,</div><div>+<span class=3D"" style=3D"white-space:pre">		=
	</span> =A0 =A0&amp;in_lookup)) {</div><div>+<span class=3D"" style=3D"whi=
te-space:pre">	</span>if(in_lookup.ofport-&gt;netdev) {</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0/* Look up=
 the input ifIndex if this port has one. Otherwise just</div><div>+<span cl=
ass=3D"" style=3D"white-space:pre">	</span> =A0 =A0 * leave it as 0 (meanin=
g &#39;unknown&#39;) and continue. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0in_ifindex=
 =3D netdev_get_ifindex(in_lookup.ofport-&gt;netdev);</div><div>+<span clas=
s=3D"" style=3D"white-space:pre">	</span> =A0 =A0if(in_ifindex &gt; 0) {</d=
iv><div>+<span class=3D"" style=3D"white-space:pre">		</span>fs.input =3D i=
n_ifindex;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+<span cl=
ass=3D"" style=3D"white-space:pre">	</span>if(in_lookup.is_tunnel) {</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0memset(&amp=
;in_tunnelElem, 0, sizeof in_tunnelElem);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0memset(&am=
p;in_vniElem, 0, sizeof in_vniElem);</div><div>+<span class=3D"" style=3D"w=
hite-space:pre">	</span> =A0 =A0in_tunnel_flags =3D dpif_sflow_tunnel(&amp;=
in_tunnelElem.flowType.ipv4,</div>
<div>+<span class=3D"" style=3D"white-space:pre">						</span>&amp;in_vniEl=
em.flowType.tunnel_vni,</div><div>+<span class=3D"" style=3D"white-space:pr=
e">						</span>SFLOW_TUNNEL_INGRESS,</div><div>+<span class=3D"" style=3D"=
white-space:pre">						</span>&amp;in_lookup,</div>
<div>+<span class=3D"" style=3D"white-space:pre">						</span>flow);</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0if(in_tunne=
l_flags) {</div><div>+<span class=3D"" style=3D"white-space:pre">		</span>i=
n_tunnelElem.tag =3D SFLFLOW_EX_IPV4_TUNNEL_INGRESS;</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>SFLADD_ELEMENT(&a=
mp;fs, &amp;in_tunnelElem);</div><div>+<span class=3D"" style=3D"white-spac=
e:pre">		</span>if(in_tunnel_flags &amp; SFLOW_TUNNEL_FLAGS_VNI) {</div><di=
v>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0in_vniElem.t=
ag =3D SFLFLOW_EX_VNI_INGRESS;</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0SFLADD_EL=
EMENT(&amp;fs, &amp;in_vniElem);</div><div>+<span class=3D"" style=3D"white=
-space:pre">		</span>}</div><div>+<span class=3D"" style=3D"white-space:pre=
">	</span> =A0 =A0}</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>=A0 =
=A0 =A0}</div><div>=A0</div><div>=A0 =A0 =A0/* Make the assumption that the=
 random number generator in the datapath converges</div><div>@@ -623,11 +82=
3,63 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,</=
div>
<div>=A0 =A0 =A0switchElem.flowType.sw.src_priority =3D vlan_tci_to_pcp(flo=
w-&gt;vlan_tci);</div><div>=A0</div><div>=A0 =A0 =A0/* Retrieve data from u=
ser_action_cookie. */</div><div>- =A0 =A0vlan_tci =3D cookie-&gt;sflow.vlan=
_tci;</div><div>- =A0 =A0switchElem.flowType.sw.dst_vlan =3D vlan_tci_to_vi=
d(vlan_tci);</div>
<div>- =A0 =A0switchElem.flowType.sw.dst_priority =3D vlan_tci_to_pcp(vlan_=
tci);</div><div>+ =A0 =A0if(cookie-&gt;type =3D=3D USER_ACTION_COOKIE_SFLOW=
_MULTIPORT) {</div><div>+<span class=3D"" style=3D"white-space:pre">	</span=
>vlan_tci =3D cookie-&gt;sflow.multi.vlan_tci;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>switchElem.flowTyp=
e.sw.dst_vlan =3D vlan_tci_to_vid(vlan_tci);</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">	</span>switchElem.flowType.sw.dst_priority =3D vla=
n_tci_to_pcp(vlan_tci);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>/* See <a href=3D"=
http://www.sflow.org/sflow_version_5.txt">http://www.sflow.org/sflow_versio=
n_5.txt</a> (search for &quot;Input/output</div><div>+<span class=3D"" styl=
e=3D"white-space:pre">	</span> * port information&quot;) */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>if(cookie-&gt;sflo=
w.multi.n_outputs =3D=3D 0) {</div><div>+<span class=3D"" style=3D"white-sp=
ace:pre">	</span> =A0 =A0/* 0x40000000 | 256 means &quot;packet dropped for=
 unknown reason&quot;. */</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0fs.output =
=3D 0x40000000 | 256;</div><div>+<span class=3D"" style=3D"white-space:pre"=
>	</span>}</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>el=
se {</div><div>
+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0/* 0x80000000 m=
eans &quot;multiple output ports. */</div><div>+<span class=3D"" style=3D"w=
hite-space:pre">	</span> =A0 =A0fs.output =3D 0x80000000 | cookie-&gt;sflow=
.multi.n_outputs;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>+ =A0 =
=A0}</div><div>+ =A0 =A0else if(cookie-&gt;type =3D=3D USER_ACTION_COOKIE_S=
FLOW_SINGLEPORT) {</div><div>+<span class=3D"" style=3D"white-space:pre">	<=
/span>vlan_tci =3D cookie-&gt;sflow.single.vlan_tci;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>switchElem.flowTyp=
e.sw.dst_vlan =3D vlan_tci_to_vid(vlan_tci);</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">	</span>switchElem.flowType.sw.dst_priority =3D vla=
n_tci_to_pcp(vlan_tci);</div>
<div>+</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>if(coo=
kie-&gt;sflow.single.output_port) {</div><div>+<span class=3D"" style=3D"wh=
ite-space:pre">	</span> =A0 =A0memset(&amp;out_lookup, 0, sizeof out_lookup=
);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0if((*ds-&g=
t;port_callback)(ds-&gt;port_callback_magic,</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">				</span> =A0 =A0cookie-&gt;sflow.single.output_p=
ort,</div><div>
+<span class=3D"" style=3D"white-space:pre">				</span> =A0 =A0&amp;out_loo=
kup)) {</div><div>+<span class=3D"" style=3D"white-space:pre">		</span>if(o=
ut_lookup.ofport-&gt;netdev) {</div><div>+<span class=3D"" style=3D"white-s=
pace:pre">		</span> =A0 =A0/* Look up the output ifIndex if this port has o=
ne. Otherwise just</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0 * leave =
it as 0 (meaning &#39;unknown&#39;) and continue. */</div><div>+<span class=
=3D"" style=3D"white-space:pre">		</span> =A0 =A0out_ifindex =3D netdev_get=
_ifindex(out_lookup.ofport-&gt;netdev);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0if(out_if=
index &gt; 0) {</div><div>+<span class=3D"" style=3D"white-space:pre">			</=
span>fs.output =3D out_ifindex;</div><div>+<span class=3D"" style=3D"white-=
space:pre">		</span> =A0 =A0}</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>}</div><div>+<spa=
n class=3D"" style=3D"white-space:pre">		</span>if(out_lookup.is_tunnel) {<=
/div><div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0mems=
et(&amp;out_tunnelElem, 0, sizeof out_tunnelElem);</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0memset(&a=
mp;out_vniElem, 0, sizeof out_vniElem);</div><div>+<span class=3D"" style=
=3D"white-space:pre">		</span> =A0 =A0out_tunnel_flags =3D dpif_sflow_tunne=
l(&amp;out_tunnelElem.flowType.ipv4,</div>
<div>+<span class=3D"" style=3D"white-space:pre">							</span> &amp;out_vn=
iElem.flowType.tunnel_vni,</div><div>+<span class=3D"" style=3D"white-space=
:pre">							</span> SFLOW_TUNNEL_EGRESS,</div><div>+<span class=3D"" style=
=3D"white-space:pre">							</span> &amp;out_lookup,</div>
<div>+<span class=3D"" style=3D"white-space:pre">							</span> flow);</div=
><div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0if(out_t=
unnel_flags) {</div><div>+<span class=3D"" style=3D"white-space:pre">			</s=
pan>out_tunnelElem.tag =3D SFLFLOW_EX_IPV4_TUNNEL_EGRESS;</div>
<div>+<span class=3D"" style=3D"white-space:pre">			</span>SFLADD_ELEMENT(&=
amp;fs, &amp;out_tunnelElem);</div><div>+<span class=3D"" style=3D"white-sp=
ace:pre">			</span>if(out_tunnel_flags &amp; SFLOW_TUNNEL_FLAGS_VNI) {</div=
><div>
+<span class=3D"" style=3D"white-space:pre">			</span> =A0 =A0out_vniElem.t=
ag =3D SFLFLOW_EX_VNI_EGRESS;</div><div>+<span class=3D"" style=3D"white-sp=
ace:pre">			</span> =A0 =A0SFLADD_ELEMENT(&amp;fs, &amp;out_vniElem);</div>=
<div>+<span class=3D"" style=3D"white-space:pre">			</span>}</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0}</div><d=
iv>+<span class=3D"" style=3D"white-space:pre">		</span>}</div><div>+<span =
class=3D"" style=3D"white-space:pre">	</span> =A0 =A0}</div><div>+<span cla=
ss=3D"" style=3D"white-space:pre">	</span>}</div>
<div>+ =A0 =A0}</div><div>+ =A0 =A0else {</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>VLOG_WARN(&quot;unknown upcall cookie type: %&=
quot;PRIu16, cookie-&gt;type);</div><div>+ =A0 =A0}</div><div>=A0</div><div=
>- =A0 =A0fs.output =3D cookie-&gt;sflow.output;</div>
<div>=A0</div><div>=A0 =A0 =A0/* Submit the flow sample to be encoded into =
the next datagram. */</div><div>=A0 =A0 =A0SFLADD_ELEMENT(&amp;fs, &amp;hdr=
Elem);</div><div>diff --git a/ofproto/ofproto-dpif-sflow.h b/ofproto/ofprot=
o-dpif-sflow.h</div>
<div>index d53c95c..736256a 100644</div><div>--- a/ofproto/ofproto-dpif-sfl=
ow.h</div><div>+++ b/ofproto/ofproto-dpif-sflow.h</div><div>@@ -21,6 +21,7 =
@@</div><div>=A0#include &lt;stdint.h&gt;</div><div>=A0#include &quot;svec.=
h&quot;</div>
<div>=A0#include &quot;lib/odp-util.h&quot;</div><div>+#include &quot;lacp.=
h&quot;</div><div>=A0</div><div>=A0struct dpif;</div><div>=A0struct dpif_up=
call;</div><div>@@ -34,14 +35,28 @@ void dpif_sflow_unref(struct dpif_sflow=
 *);</div>
<div>=A0</div><div>=A0uint32_t dpif_sflow_get_probability(const struct dpif=
_sflow *);</div><div>=A0</div><div>+struct dpif_sflow_port_lookup {</div><d=
iv>+ =A0 =A0struct ofport *ofport;</div><div>+ =A0 =A0/* indicate tunnel */=
</div><div>
+ =A0 =A0bool is_tunnel;</div><div>+ =A0 =A0/* LAG/bundle details */</div><=
div>+ =A0 =A0struct lacp *lacp;</div><div>+ =A0 =A0void *lacp_slave;</div><=
div>+};</div><div>+</div><div>+typedef bool (*dpif_sflow_callback)(void *, =
ofp_port_t, =A0struct dpif_sflow_port_lookup *);</div>
<div>+</div><div>+void dpif_sflow_set_port_lookup_callback(struct dpif_sflo=
w *, dpif_sflow_callback, void *);</div><div>+</div><div>=A0void dpif_sflow=
_set_options(struct dpif_sflow *,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0const struct ofproto_sflow_options *);</div>
<div>+<span class=3D"" style=3D"white-space:pre">				</span></div><div>=A0v=
oid dpif_sflow_clear(struct dpif_sflow *);</div><div>=A0bool dpif_sflow_is_=
enabled(const struct dpif_sflow *);</div><div>=A0</div><div>-void dpif_sflo=
w_add_port(struct dpif_sflow *ds, struct ofport *ofport,</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 odp_port_t odp_port)=
;</div><div>-void dpif_sflow_del_port(struct dpif_sflow *, odp_port_t odp_p=
ort);</div><div>+void dpif_sflow_add_port(struct dpif_sflow *ds, struct ofp=
ort *ofport);</div><div>
+</div><div>+void dpif_sflow_del_port(struct dpif_sflow *, ofp_port_t ofp_p=
ort);</div><div>=A0</div><div>=A0void dpif_sflow_run(struct dpif_sflow *);<=
/div><div>=A0void dpif_sflow_wait(struct dpif_sflow *);</div><div>@@ -49,10=
 +64,6 @@ void dpif_sflow_wait(struct dpif_sflow *);</div>
<div>=A0void dpif_sflow_received(struct dpif_sflow *,</div><div>=A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct ofpbuf *,</div><div>=A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const struct flow *,</div><div=
>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 odp_port_t odp_port,</di=
v>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const union user_a=
ction_cookie *);</div><div>=A0</div><div>-int dpif_sflow_odp_port_to_ifinde=
x(const struct dpif_sflow *,</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 odp_port_t odp_port);</div>
<div>-</div><div>=A0#endif /* ofproto/ofproto-dpif-sflow.h */</div><div>dif=
f --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c</di=
v><div>index dde6430..9f54d0d 100644</div><div>--- a/ofproto/ofproto-dpif-u=
pcall.c</div>
<div>+++ b/ofproto/ofproto-dpif-upcall.c</div><div>@@ -469,7 +469,8 @@ clas=
sify_upcall(const struct upcall *upcall)</div><div>=A0 =A0 =A0memset(&amp;c=
ookie, 0, sizeof cookie);</div><div>=A0 =A0 =A0memcpy(&amp;cookie, nl_attr_=
get(dpif_upcall-&gt;userdata), userdata_len);</div>
<div>=A0 =A0 =A0if (userdata_len =3D=3D sizeof cookie.sflow</div><div>- =A0=
 =A0 =A0 =A0&amp;&amp; cookie.type =3D=3D USER_ACTION_COOKIE_SFLOW) {</div>=
<div>+ =A0 =A0 =A0 =A0&amp;&amp; (cookie.type =3D=3D USER_ACTION_COOKIE_SFL=
OW_SINGLEPORT</div><div>+<span class=3D"" style=3D"white-space:pre">	</span=
> =A0 =A0|| cookie.type =3D=3D USER_ACTION_COOKIE_SFLOW_MULTIPORT)) {</div>
<div>=A0 =A0 =A0 =A0 =A0return SFLOW_UPCALL;</div><div>=A0 =A0 =A0} else if=
 (userdata_len =3D=3D sizeof cookie.slow_path</div><div>=A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 &amp;&amp; cookie.type =3D=3D USER_ACTION_COOKIE_SLOW_PATH) {<=
/div><div>@@ -711,8 +712,7 @@ handle_upcalls(struct udpif *udpif, struct li=
st *upcalls)</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(&amp;cookie, 0, sizeof cooki=
e);</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memcpy(&amp;cookie, nl_att=
r_get(dupcall-&gt;userdata),</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 sizeof cookie.sflow);</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0dpif_sflow_received(sflow, dupcall-&gt;packet, &amp;flow, odp_in_port,</=
div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0&amp;cookie);</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dpif_sflow_rece=
ived(sflow, dupcall-&gt;packet, &amp;flow, &amp;cookie);</div><div>=A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0dpif_sflow_unref(sflow);</div><div>=A0 =A0 =A0 =
=A0 =A0 =A0 =A0}</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>diff --git a/ofproto/ofpro=
to-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c</div><div>index a331c0b..8c1=
7d93 100644</div><div>--- a/ofproto/ofproto-dpif-xlate.c</div><div>+++ b/of=
proto/ofproto-dpif-xlate.c</div>
<div>@@ -178,7 +178,7 @@ struct xlate_ctx {</div><div>=A0 =A0 =A0uint32_t o=
rig_skb_priority; /* Priority when packet arrived. */</div><div>=A0 =A0 =A0=
uint8_t table_id; =A0 =A0 =A0 =A0 =A0 /* OpenFlow table ID where flow was f=
ound. */</div><div>
=A0 =A0 =A0uint32_t sflow_n_outputs; =A0 /* Number of output ports. */</div=
><div>- =A0 =A0odp_port_t sflow_odp_port; =A0/* Output port for composing s=
Flow action. */</div><div>+ =A0 =A0ofp_port_t sflow_ofp_port; =A0/* Output =
port for composing sFlow action. */</div>
<div>=A0 =A0 =A0uint16_t user_cookie_offset;/* Used for user_action_cookie =
fixup. */</div><div>=A0 =A0 =A0bool exit; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0/* No further actions should be processed. */</div><div>=A0</div><div>@@=
 -1479,34 +1479,19 @@ compose_sample_action(const struct xbridge *xbridge,<=
/div>
<div>=A0}</div><div>=A0</div><div>=A0static void</div><div>-compose_sflow_c=
ookie(const struct xbridge *xbridge, ovs_be16 vlan_tci,</div><div>- =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 odp_port_t odp_port, unsigned int n_output=
s,</div><div>+compose_sflow_cookie(ovs_be16 vlan_tci,</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ofp_port_t ofp_port, unsigne=
d int n_outputs,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unio=
n user_action_cookie *cookie)</div><div>=A0{</div><div>- =A0 =A0int ifindex=
;</div><div>-</div><div>- =A0 =A0cookie-&gt;type =3D USER_ACTION_COOKIE_SFL=
OW;</div>
<div>- =A0 =A0cookie-&gt;sflow.vlan_tci =3D vlan_tci;</div><div>-</div><div=
>- =A0 =A0/* See <a href=3D"http://www.sflow.org/sflow_version_5.txt">http:=
//www.sflow.org/sflow_version_5.txt</a> (search for &quot;Input/output</div=
><div>- =A0 =A0 * port information&quot;) for the interpretation of cookie-=
&gt;output. */</div>
<div>- =A0 =A0switch (n_outputs) {</div><div>- =A0 =A0case 0:</div><div>- =
=A0 =A0 =A0 =A0/* 0x40000000 | 256 means &quot;packet dropped for unknown r=
eason&quot;. */</div><div>- =A0 =A0 =A0 =A0cookie-&gt;sflow.output =3D 0x40=
000000 | 256;</div><div>
- =A0 =A0 =A0 =A0break;</div><div>-</div><div>- =A0 =A0case 1:</div><div>- =
=A0 =A0 =A0 =A0ifindex =3D dpif_sflow_odp_port_to_ifindex(xbridge-&gt;sflow=
, odp_port);</div><div>- =A0 =A0 =A0 =A0if (ifindex) {</div><div>- =A0 =A0 =
=A0 =A0 =A0 =A0cookie-&gt;sflow.output =3D ifindex;</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>- =A0 =A0 =A0 =A0}</div><div=
>- =A0 =A0 =A0 =A0/* Fall through. */</div><div>- =A0 =A0default:</div><div=
>- =A0 =A0 =A0 =A0/* 0x80000000 means &quot;multiple output ports. */</div>=
<div>- =A0 =A0 =A0 =A0cookie-&gt;sflow.output =3D 0x80000000 | n_outputs;</=
div>
<div>- =A0 =A0 =A0 =A0break;</div><div>+ =A0 =A0if(n_outputs =3D=3D 1) {</d=
iv><div>+<span class=3D"" style=3D"white-space:pre">	</span>cookie-&gt;type=
 =3D USER_ACTION_COOKIE_SFLOW_SINGLEPORT;</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>cookie-&gt;sflow.single.vlan_tci =3D vlan_tci;=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>cookie-&gt;sflow.s=
ingle.output_port =3D ofp_port;</div><div>+ =A0 =A0}</div><div>+ =A0 =A0els=
e {</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>cookie-&g=
t;type =3D USER_ACTION_COOKIE_SFLOW_MULTIPORT;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>cookie-&gt;sflow.m=
ulti.vlan_tci =3D vlan_tci;</div><div>+<span class=3D"" style=3D"white-spac=
e:pre">	</span>cookie-&gt;sflow.multi.n_outputs =3D (uint32_t)n_outputs;</d=
iv><div>
=A0 =A0 =A0}</div><div>=A0}</div><div>=A0</div><div>@@ -1515,7 +1500,7 @@ s=
tatic size_t</div><div>=A0compose_sflow_action(const struct xbridge *xbridg=
e,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct ofpbuf *odp=
_actions,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const struc=
t flow *flow,</div>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 odp_port_t odp_port)</div><d=
iv>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ofp_port_t ofp_port)</div><div=
>=A0{</div><div>=A0 =A0 =A0uint32_t probability;</div><div>=A0 =A0 =A0union=
 user_action_cookie cookie;</div><div>@@ -1525,8 +1510,8 @@ compose_sflow_a=
ction(const struct xbridge *xbridge,</div>
<div>=A0 =A0 =A0}</div><div>=A0</div><div>=A0 =A0 =A0probability =3D dpif_s=
flow_get_probability(xbridge-&gt;sflow);</div><div>- =A0 =A0compose_sflow_c=
ookie(xbridge, htons(0), odp_port,</div><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 odp_port =3D=3D ODPP_NONE ? 0 : 1, &amp;cookie);</div>
<div>+ =A0 =A0compose_sflow_cookie(htons(0), ofp_port,</div><div>+ =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ofp_port =3D=3D OFPP_NONE ? 0 : 1, =
&amp;cookie);</div><div>=A0</div><div>=A0 =A0 =A0return compose_sample_acti=
on(xbridge, odp_actions, flow, =A0probability,</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &a=
mp;cookie, sizeof cookie.sflow);</div><div>@@ -1578,8 +1563,8 @@ add_sflow_=
action(struct xlate_ctx *ctx)</div><div>=A0{</div><div>=A0 =A0 =A0ctx-&gt;u=
ser_cookie_offset =3D compose_sflow_action(ctx-&gt;xbridge,</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &amp;ctx-&gt;xout-&gt;odp_actions,</div=
><div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &amp;ctx-&gt;xin-&gt;flow, ODPP_NONE);</di=
v><div>- =A0 =A0ctx-&gt;sflow_odp_port =3D 0;</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &amp;ctx-&gt;xin-&gt;flow, OFPP_NONE);</div=
><div>+ =A0 =A0ctx-&gt;sflow_ofp_port =3D 0;</div><div>=A0 =A0 =A0ctx-&gt;s=
flow_n_outputs =3D 0;</div><div>=A0}</div><div>=A0</div><div>@@ -1607,10 +1=
592,11 @@ fix_sflow_action(struct xlate_ctx *ctx)</div>
<div>=A0</div><div>=A0 =A0 =A0cookie =3D ofpbuf_at(&amp;ctx-&gt;xout-&gt;od=
p_actions, ctx-&gt;user_cookie_offset,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 sizeof cookie-&gt;sflow);</div><div>- =A0 =A0ovs_as=
sert(cookie-&gt;type =3D=3D USER_ACTION_COOKIE_SFLOW);</div>
<div>+ =A0 =A0ovs_assert(cookie-&gt;type =3D=3D USER_ACTION_COOKIE_SFLOW_SI=
NGLEPORT</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0=
 =A0 =A0 || cookie-&gt;type =3D=3D USER_ACTION_COOKIE_SFLOW_MULTIPORT);</di=
v><div>=A0</div><div>
- =A0 =A0compose_sflow_cookie(ctx-&gt;xbridge, base-&gt;vlan_tci,</div><div=
>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ctx-&gt;sflow_odp_port, =
ctx-&gt;sflow_n_outputs, cookie);</div><div>+ =A0 =A0compose_sflow_cookie(b=
ase-&gt;vlan_tci,</div><div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ctx-&gt;sflow_ofp_port, c=
tx-&gt;sflow_n_outputs, cookie);</div><div>=A0}</div><div>=A0</div><div>=A0=
static enum slow_path_reason</div><div>@@ -1780,7 +1766,7 @@ compose_output=
_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,</div>
<div>=A0 =A0 =A0 =A0 =A0nl_msg_put_odp_port(&amp;ctx-&gt;xout-&gt;odp_actio=
ns, OVS_ACTION_ATTR_OUTPUT,</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0out_port);</div><div>=A0</div><div>- =A0 =A0 =A0 =A0=
ctx-&gt;sflow_odp_port =3D odp_port;</div><div>+ =A0 =A0 =A0 =A0ctx-&gt;sfl=
ow_ofp_port =3D ofp_port;</div>
<div>=A0 =A0 =A0 =A0 =A0ctx-&gt;sflow_n_outputs++;</div><div>=A0 =A0 =A0 =
=A0 =A0ctx-&gt;xout-&gt;nf_output_iface =3D ofp_port;</div><div>=A0 =A0 =A0=
}</div><div>diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c</d=
iv><div>index 7df0450..2e153b1 100644</div>
<div>--- a/ofproto/ofproto-dpif.c</div><div>+++ b/ofproto/ofproto-dpif.c</d=
iv><div>@@ -1753,7 +1753,7 @@ port_construct(struct ofport *port_)</div><di=
v>=A0 =A0 =A0dpif_port_destroy(&amp;dpif_port);</div><div>=A0</div><div>=A0=
 =A0 =A0if (ofproto-&gt;sflow) {</div>
<div>- =A0 =A0 =A0 =A0dpif_sflow_add_port(ofproto-&gt;sflow, port_, port-&g=
t;odp_port);</div><div>+ =A0 =A0 =A0 =A0dpif_sflow_add_port(ofproto-&gt;sfl=
ow, port_);</div><div>=A0 =A0 =A0}</div><div>=A0</div><div>=A0 =A0 =A0retur=
n 0;</div><div>@@ -1856,24 +1856,47 @@ port_reconfigured(struct ofport *por=
t_, enum ofputil_port_config old_config)</div>
<div>=A0 =A0 =A0}</div><div>=A0}</div><div>=A0</div><div>+static bool</div>=
<div>+dpif_sflow_port_lookup_callback(void *magic, ofp_port_t ofp_port, str=
uct dpif_sflow_port_lookup *port_lookup)</div><div>+{</div><div>+ =A0 =A0/*=
 XXX do we need to acquire ofproto_mutex here? =A0Or should it be acquired =
in handle_sflow_upcall() below,</div>
<div>+ =A0 =A0 * so that it will not be released until after the sFlow-modu=
le has followed the pointers we are giving</div><div>+ =A0 =A0 * it here an=
d the sflow sample has been fully processed? */</div><div>+</div><div>+ =A0=
 =A0struct ofproto_dpif *ofproto =3D (struct ofproto_dpif *)magic;</div>
<div>+ =A0 =A0struct ofport_dpif *port =3D get_ofp_port(ofproto, ofp_port);=
</div><div>+ =A0 =A0if(port) {</div><div>+<span class=3D"" style=3D"white-s=
pace:pre">	</span>port_lookup-&gt;ofport =3D &amp;port-&gt;up;</div><div>+<=
span class=3D"" style=3D"white-space:pre">	</span>port_lookup-&gt;is_tunnel=
 =3D port-&gt;is_tunnel;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>if(port-&gt;bundle=
</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 &amp;&a=
mp; port-&gt;bundle-&gt;lacp) {</div><div>+<span class=3D"" style=3D"white-=
space:pre">	</span> =A0port_lookup-&gt;lacp =3D port-&gt;bundle-&gt;lacp;</=
div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0port_lookup-&g=
t;lacp_slave =3D port;</div><div>+<span class=3D"" style=3D"white-space:pre=
">	</span>}</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>r=
eturn true;</div>
<div>+ =A0 =A0}</div><div>+ =A0 =A0return false;</div><div>+}</div><div>+</=
div><div>+</div><div>=A0static int</div><div>=A0set_sflow(struct ofproto *o=
fproto_,</div><div>=A0 =A0 =A0 =A0 =A0 =A0const struct ofproto_sflow_option=
s *sflow_options)</div>
<div>=A0{</div><div>=A0 =A0 =A0struct ofproto_dpif *ofproto =3D ofproto_dpi=
f_cast(ofproto_);</div><div>=A0 =A0 =A0struct dpif_sflow *ds =3D ofproto-&g=
t;sflow;</div><div>+ =A0 =A0struct ofport_dpif *ofport;</div><div>=A0</div>=
<div>=A0 =A0 =A0if (sflow_options) {</div>
<div>=A0 =A0 =A0 =A0 =A0if (!ds) {</div><div>- =A0 =A0 =A0 =A0 =A0 =A0struc=
t ofport_dpif *ofport;</div><div>-</div><div>- =A0 =A0 =A0 =A0 =A0 =A0ds =
=3D ofproto-&gt;sflow =3D dpif_sflow_create();</div><div>- =A0 =A0 =A0 =A0 =
=A0 =A0HMAP_FOR_EACH (ofport, up.hmap_node, &amp;ofproto-&gt;up.ports) {</d=
iv>
<div>- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dpif_sflow_add_port(ds, &amp;ofport-&=
gt;up, ofport-&gt;odp_port);</div><div>- =A0 =A0 =A0 =A0 =A0 =A0}</div><div=
>- =A0 =A0 =A0 =A0 =A0 =A0ofproto-&gt;backer-&gt;need_revalidate =3D REV_RE=
CONFIGURE;</div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =
=A0 =A0ds =3D ofproto-&gt;sflow =3D dpif_sflow_create();</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0ofproto-&g=
t;backer-&gt;need_revalidate =3D REV_RECONFIGURE;</div><div>=A0 =A0 =A0 =A0=
 =A0}</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>dpif_sf=
low_set_port_lookup_callback(ds, dpif_sflow_port_lookup_callback, (void *)o=
fproto);</div>
<div>=A0 =A0 =A0 =A0 =A0dpif_sflow_set_options(ds, sflow_options);</div><di=
v>+<span class=3D"" style=3D"white-space:pre">	</span>HMAP_FOR_EACH (ofport=
, up.hmap_node, &amp;ofproto-&gt;up.ports) {</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">	</span> =A0 =A0dpif_sflow_add_port(ds, &amp;ofport=
-&gt;up);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>}</div><div>=A0 =
=A0 =A0} else {</div><div>=A0 =A0 =A0 =A0 =A0if (ds) {</div><div>=A0 =A0 =
=A0 =A0 =A0 =A0 =A0dpif_sflow_unref(ds);</div><div>diff --git a/tests/<a hr=
ef=3D"http://odp.at">odp.at</a> b/tests/<a href=3D"http://odp.at">odp.at</a=
></div>
<div>index b505345..fd4e32d 100644</div><div>--- a/tests/<a href=3D"http://=
odp.at">odp.at</a></div><div>+++ b/tests/<a href=3D"http://odp.at">odp.at</=
a></div><div>@@ -220,7 +220,7 @@ AT_SETUP([OVS datapath actions parsing and=
 formatting - valid forms])</div>
<div>=A0AT_DATA([actions.txt], [dnl</div><div>=A01,2,3</div><div>=A0userspa=
ce(pid=3D555666777)</div><div>-userspace(pid=3D6633,sFlow(vid=3D9,pcp=3D7,o=
utput=3D10))</div><div>+userspace(pid=3D6633,sFlow(vid=3D9,pcp=3D7,n_output=
s=3D1,output_port=3D10))</div>
<div>=A0userspace(pid=3D9765,slow_path())</div><div>=A0userspace(pid=3D9765=
,slow_path(cfm))</div><div>=A0userspace(pid=3D1234567,userdata(010203040506=
0708090a0b0c0d0e0f))</div><div>diff --git a/tests/<a href=3D"http://ofproto=
-dpif.at">ofproto-dpif.at</a> b/tests/<a href=3D"http://ofproto-dpif.at">of=
proto-dpif.at</a></div>
<div>index b78e156..6c5409e 100644</div><div>--- a/tests/<a href=3D"http://=
ofproto-dpif.at">ofproto-dpif.at</a></div><div>+++ b/tests/<a href=3D"http:=
//ofproto-dpif.at">ofproto-dpif.at</a></div><div>@@ -2071,6 +2071,217 @@ IF=
COUNTERS</div>
<div>=A0AT_CLEANUP</div><div>=A0</div><div>=A0</div><div>+dnl Test sFlow tu=
nnel structures.</div><div>+AT_SETUP([ofproto-dpif - sFlow tunnel structure=
s])</div><div>+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=
=3Dvxlan \</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0options:local_ip=3D1.1.1.1 op=
tions:remote_ip=3D2.2.2.2 \</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0options:key=3D5 options:tos=3Dinherit ofport_request=3D1 \</div><div>+ =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0-- add-port br0 p2 -- set Interface =
p2 type=3Ddummy \</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0options:ifindex=3D1002 ofport=
_request=3D2])</div><div>+</div><div>+AT_DATA([flows.txt], [dnl</div><div>+=
actions=3Doutput:1</div><div>+])</div><div>+AT_CHECK([ovs-ofctl add-flows b=
r0 flows.txt])</div><div>
+</div><div>+dnl set up sFlow logging</div><div>+dnl ON_EXIT([kill `cat tes=
t-sflow.pid`])</div><div>+AT_CHECK([test-sflow --log-file --detach --no-chd=
ir --pidfile 0:127.0.0.1 &gt; sflow.log], [0], [], [ignore])</div><div>
+AT_CAPTURE_FILE([sflow.log])</div><div>+SFLOW_PORT=3D`parse_listening_port=
 &lt; test-sflow.log`</div><div>+ovs-appctl time/stop</div><div>+ovs-vsctl =
\</div><div>+ =A0 set Bridge br0 sflow=3D at sf -- \</div><div>+ =A0 --id=3D at s=
f create sflow targets=3D\&quot;127.0.0.1:$SFLOW_PORT\&quot; \</div>
<div>+ =A0 =A0 header=3D128 sampling=3D1 polling=3D0</div><div>+</div><div>=
+dnl use netdev-dummy/receive to send a packet that will be sampled</div><d=
iv>+AT_CHECK([ovs-appctl netdev-dummy/receive p2 &#39;in_port(2),eth(src=3D=
50:54:00:00:00:05,dst=3D50:54:00:00:00:07),eth_type(0x0800),ipv4(src=3D192.=
168.0.1,dst=3D192.168.0.2,proto=3D6,tos=3D4,ttl=3D128,frag=3Dno),tcp(src=3D=
8,dst=3D9)&#39;], [0], [stdout])</div>
<div>+</div><div>+dnl sleep long enough to get the sFlow datagram flushed o=
ut (may be delayed for up to 1 second)</div><div>+for i in `seq 1 30`; do</=
div><div>+ =A0 =A0ovs-appctl time/warp 100</div><div>+done</div><div>+OVS_V=
SWITCHD_STOP</div>
<div>+ovs-appctl -t test-sflow exit</div><div>+</div><div>+AT_CHECK([[sort =
sflow.log | $EGREP &#39;HEADER|ERROR&#39; | sed &#39;s/ /\</div><div>+<span=
 class=3D"" style=3D"white-space:pre">	</span>/g&#39;]], [0], [dnl</div><di=
v>
+HEADER</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>dgram=
SeqNo=3D1</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>ds=
=3D127.0.0.1&gt;2:1000</div><div>+<span class=3D"" style=3D"white-space:pre=
">	</span>fsSeqNo=3D1</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_out_length=
=3D0</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_=
out_protocol=3D17</div><div>+<span class=3D"" style=3D"white-space:pre">	</=
span>tunnel4_out_src=3D1.1.1.1</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_out_dst=3D=
2.2.2.2</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>tunne=
l4_out_src_port=3D0</div><div>+<span class=3D"" style=3D"white-space:pre">	=
</span>tunnel4_out_dst_port=3D46354</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_out_tcp_fl=
ags=3D0</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>tunne=
l4_out_tos=3D4</div><div>+<span class=3D"" style=3D"white-space:pre">	</spa=
n>tunnel_out_vni=3D5</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>in_vlan=3D0</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span>in_priority=3D0</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_vlan=3D0</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_priority=3D0=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>meanSkip=3D1</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>samplePool=3D1</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>dropEvents=3D0</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span>in_ifindex=3D1=
002</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>in_format=3D0</div=
><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_ifindex=3D0</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_format=3D0=
</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>hdr_prot=3D1=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>pkt_len=3D64</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>stripped=3D4</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>hdr_len=3D60</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>hdr=3D50-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</div>
<div>+])</div><div>+AT_CLEANUP</div><div>+</div><div>+dnl Test sFlow tunnel=
 structures ingress</div><div>+AT_SETUP([ofproto-dpif - sFlow tunnel struct=
ures ingress])</div><div>+OVS_VSWITCHD_START([add-port br0 p1 -- set Interf=
ace p1 type=3Dvxlan \</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0options:local_ip=3D1.1.1.1 op=
tions:remote_ip=3D2.2.2.2 \</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0options:key=3D5 options:tos=3Dinherit ofport_request=3D1 \</div><div>+ =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0-- add-port br0 p2 -- set Interface =
p2 type=3Ddummy \</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0options:ifindex=3D1002 ofport=
_request=3D2 -- \</div><div>+<span class=3D"" style=3D"white-space:pre">		<=
/span> =A0 =A0add-br br1 -- \</div><div>+<span class=3D"" style=3D"white-sp=
ace:pre">		</span> =A0 =A0set bridge br1 other-config:hwaddr=3Daa:66:aa:66:=
00:00 -- \</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0set bridg=
e br1 datapath-type=3Ddummy other-config:datapath-id=3D1234 \</div><div>+<s=
pan class=3D"" style=3D"white-space:pre">		</span> =A0 =A0fail-mode=3Dsecur=
e -- \</div><div>+ <span class=3D"" style=3D"white-space:pre">		</span> =A0=
 =A0-- add-port br1 p3 -- set interface p3 type=3Dvxlan \</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0options:l=
ocal_ip=3D2.2.2.2 options:remote_ip=3D1.1.1.1 \</div><div>+<span class=3D""=
 style=3D"white-space:pre">		</span> =A0 =A0options:key=3D5 =A0options:tos=
=3Dinherit ofport_request=3D3 \</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span> =A0 =A0-- add-po=
rt br1 p4 -- set Interface p4 type=3Ddummy \</div><div>+ =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0options:ifindex=3D1004 ofport_request=3D4 ])</div><d=
iv>+</div><div>+AT_DATA([flows.txt], [dnl</div>
<div>+actions=3Doutput:1</div><div>+])</div><div>+AT_CHECK([ovs-ofctl add-f=
lows br0 flows.txt])</div><div>+</div><div>+dnl set up sFlow logging</div><=
div>+dnl ON_EXIT([kill `cat test-sflow.pid`])</div><div>+AT_CHECK([test-sfl=
ow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 &gt; sflow.log], [0=
], [], [ignore])</div>
<div>+AT_CAPTURE_FILE([sflow.log])</div><div>+SFLOW_PORT=3D`parse_listening=
_port &lt; test-sflow.log`</div><div>+ovs-appctl time/stop</div><div>+ovs-v=
sctl \</div><div>+ =A0 set Bridge br0 sflow=3D at sf -- \</div><div>+ =A0 --id=
=3D at sf create sflow targets=3D\&quot;127.0.0.1:$SFLOW_PORT\&quot; \</div>
<div>+ =A0 =A0 header=3D128 sampling=3D1 polling=3D0</div><div>+ovs-vsctl \=
</div><div>+ =A0 set Bridge br1 sflow=3D at sf -- \</div><div>+ =A0 --id=3D at sf=
 create sflow targets=3D\&quot;127.0.0.1:$SFLOW_PORT\&quot; \</div><div>+ =
=A0 =A0 header=3D128 sampling=3D1 polling=3D0</div>
<div>+</div><div>+ifconfig -a</div><div>+ip route</div><div>+</div><div>+dn=
l use netdev-dummy/receive to send a packet that will be sampled</div><div>=
+AT_CHECK([ovs-appctl netdev-dummy/receive p2 &#39;in_port(2),eth(src=3D50:=
54:00:00:00:05,dst=3D50:54:00:00:00:07),eth_type(0x0800),ipv4(src=3D192.168=
.0.1,dst=3D192.168.0.2,proto=3D6,tos=3D4,ttl=3D128,frag=3Dno),tcp(src=3D8,d=
st=3D9)&#39;], [0], [stdout])</div>
<div>+</div><div>+dnl sleep long enough to get the sFlow datagram flushed o=
ut (may be delayed for up to 1 second)</div><div>+for i in `seq 1 30`; do</=
div><div>+ =A0 =A0ovs-appctl time/warp 100</div><div>+done</div><div>+OVS_V=
SWITCHD_STOP</div>
<div>+ovs-appctl -t test-sflow exit</div><div>+</div><div>+AT_CHECK([[sort =
sflow.log | $EGREP &#39;HEADER|ERROR&#39; | sed &#39;s/ /\</div><div>+<span=
 class=3D"" style=3D"white-space:pre">	</span>/g&#39;]], [0], [dnl</div><di=
v>
+HEADER</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>dgram=
SeqNo=3D1</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>ds=
=3D127.0.0.1&gt;2:1000</div><div>+<span class=3D"" style=3D"white-space:pre=
">	</span>fsSeqNo=3D1</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_out_length=
=3D0</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_=
out_protocol=3D17</div><div>+<span class=3D"" style=3D"white-space:pre">	</=
span>tunnel4_out_src=3D1.1.1.1</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_out_dst=3D=
2.2.2.2</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>tunne=
l4_out_src_port=3D0</div><div>+<span class=3D"" style=3D"white-space:pre">	=
</span>tunnel4_out_dst_port=3D46354</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>tunnel4_out_tcp_fl=
ags=3D0</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>tunne=
l4_out_tos=3D4</div><div>+<span class=3D"" style=3D"white-space:pre">	</spa=
n>tunnel_out_vni=3D5</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>in_vlan=3D0</div><=
div>+<span class=3D"" style=3D"white-space:pre">	</span>in_priority=3D0</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_vlan=3D0</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_priority=3D0=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>meanSkip=3D1</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>samplePool=3D1</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>dropEvents=3D0</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span>in_ifindex=3D1=
002</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>in_format=3D0</div=
><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_ifindex=3D0</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span>out_format=3D0=
</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>hdr_prot=3D1=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>pkt_len=3D64</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>stripped=3D4</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>hdr_len=3D60</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>hdr=3D50-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</div>
<div>+])</div><div>+AT_CLEANUP</div><div>+</div><div>+dnl Test sFlow LAG st=
ructures</div><div>+AT_SETUP([ofproto-dpif - sFlow LACP structures])</div><=
div>+</div><div>+OVS_VSWITCHD_START([dnl</div><div>+ =A0 =A0 =A0 =A0add-bon=
d br0 bond p1 p2 --\</div>
<div>+ =A0 =A0 =A0 =A0set Port bond lacp=3Dactive bond-mode=3Dactive-backup=
 \</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0other_config:lacp-time=3D&quot;fast&q=
uot; \</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0other_config:lacp-system-id=3D11:=
22:33:44:55:66 \</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0other_config:lacp-syste=
m-priority=3D54321 --\</div>
<div>+ =A0 =A0 =A0 =A0set Interface p1 type=3Ddummy \</div><div>+ =A0 =A0 =
=A0 =A0 =A0 =A0other_config:lacp-port-id=3D11 \</div><div>+ =A0 =A0 =A0 =A0=
 =A0 =A0other_config:lacp-port-priority=3D111 \</div><div>+ =A0 =A0 =A0 =A0=
 =A0 =A0other_config:lacp-aggregation-key=3D3333 --\</div>
<div>+ =A0 =A0 =A0 =A0set Interface p2 type=3Ddummy \</div><div>+ =A0 =A0 =
=A0 =A0 =A0 =A0other_config:lacp-port-id=3D22 \</div><div>+ =A0 =A0 =A0 =A0=
 =A0 =A0other_config:lacp-port-priority=3D222 \</div><div>+ =A0 =A0 =A0 =A0=
 =A0 =A0other_config:lacp-aggregation-key=3D3333 ])</div>
<div>+</div><div>+ON_EXIT([kill `cat test-sflow.pid`])</div><div>+AT_CHECK(=
[test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 &gt; sflow=
.log], [0], [], [ignore])</div><div>+AT_CAPTURE_FILE([sflow.log])</div>
<div>+SFLOW_PORT=3D`parse_listening_port &lt; test-sflow.log`</div><div>+</=
div><div>+ovs-appctl time/stop</div><div>+</div><div>+ovs-vsctl \</div><div=
>+ =A0 set Interface p1 options:ifindex=3D1003 -- \</div><div>+ =A0 set Bri=
dge br0 sflow=3D at sf -- \</div>
<div>+ =A0 --id=3D at sf create sflow targets=3D\&quot;127.0.0.1:$SFLOW_PORT\&=
quot; \</div><div>+ =A0 =A0 header=3D128 sampling=3D1 polling=3D1</div><div=
>+</div><div>+dnl sleep long enough to get the sFlow datagram flushed out (=
may be delayed for up to 1 second)</div>
<div>+for i in `seq 1 30`; do</div><div>+ =A0 =A0ovs-appctl time/warp 100</=
div><div>+done</div><div>+OVS_VSWITCHD_STOP</div><div>+ovs-appctl -t test-s=
flow exit</div><div>+</div><div>+AT_CHECK([[sort sflow.log | $EGREP &#39;LA=
CPCOUNTERS|ERROR&#39; | head -n 1 | sed &#39;s/ /\</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>/g&#39;]], [0], [d=
nl</div><div>+LACPCOUNTERS</div><div>+<span class=3D"" style=3D"white-space=
:pre">	</span>sysID=3D11:22:33:44:55:66</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>partnerID=3D00:00:00:00:00:00</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>aggID=3D3333</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>actorAdmin=3D0x7</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span>actorOper=3D0x=
bf</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>partnerAdm=
in=3D0x0</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>partnerOper=3D0x2<=
/div><div>+<span class=3D"" style=3D"white-space:pre">	</span>LACPUDsRx=3D0=
</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>markerPDUsRx=
=3D4294967295</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>markerRespPDUsRx=
=3D4294967295</div><div>+<span class=3D"" style=3D"white-space:pre">	</span=
>unknownRx=3D4294967295</div><div>+<span class=3D"" style=3D"white-space:pr=
e">	</span>illegalRx=3D0</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>LACPUDsTx=3D1</div=
><div>+<span class=3D"" style=3D"white-space:pre">	</span>markerPDUsTx=3D42=
94967295</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>mark=
erRespPDUsTx=3D4294967295</div>
<div>+])</div><div>+</div><div>+AT_CLEANUP</div><div>=A0</div><div>=A0dnl T=
est that basic NetFlow reports flow statistics correctly:</div><div>=A0dnl =
- The initial packet of a flow are correctly accounted.</div><div>diff --gi=
t a/tests/test-sflow.c b/tests/test-sflow.c</div>
<div>index cba01b9..060864d 100644</div><div>--- a/tests/test-sflow.c</div>=
<div>+++ b/tests/test-sflow.c</div><div>@@ -54,8 +54,13 @@ static unixctl_c=
b_func test_sflow_exit;</div><div>=A0</div><div>=A0/* Structure element tag=
 numbers. */</div>
<div>=A0#define SFLOW_TAG_CTR_IFCOUNTERS 1</div><div>+#define SFLOW_TAG_CTR=
_LACPCOUNTERS 7</div><div>=A0#define SFLOW_TAG_PKT_HEADER 1</div><div>=A0#d=
efine SFLOW_TAG_PKT_SWITCH 1001</div><div>+#define SFLOW_TAG_PKT_TUNNEL4_OU=
T 1023</div>
<div>+#define SFLOW_TAG_PKT_TUNNEL4_IN 1024</div><div>+#define SFLOW_TAG_PK=
T_TUNNEL_VNI_OUT 1029</div><div>+#define SFLOW_TAG_PKT_TUNNEL_VNI_IN 1030</=
div><div>=A0</div><div>=A0struct sflow_addr {</div><div>=A0 =A0 =A0enum {</=
div><div>
@@ -99,7 +104,12 @@ struct sflow_xdr {</div><div>=A0 =A0 =A0struct {</div><=
div>=A0 =A0 =A0 =A0 =A0uint32_t HEADER;</div><div>=A0 =A0 =A0 =A0 =A0uint32=
_t SWITCH;</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>ui=
nt32_t TUNNEL4_OUT;</div><div>
+<span class=3D"" style=3D"white-space:pre">	</span>uint32_t TUNNEL4_IN;</d=
iv><div>+<span class=3D"" style=3D"white-space:pre">	</span>uint32_t TUNNEL=
_VNI_OUT;</div><div>+<span class=3D"" style=3D"white-space:pre">	</span>uin=
t32_t TUNNEL_VNI_IN;</div>
<div>=A0 =A0 =A0 =A0 =A0uint32_t IFCOUNTERS;</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">	</span>uint32_t LACPCOUNTERS;</div><div>=A0 =A0 =
=A0} offset;</div><div>=A0</div><div>=A0 =A0 =A0/* Flow sample fields. */</=
div><div>@@ -221,6 +231,42 @@ process_counter_sample(struct sflow_xdr *x)</=
div>
<div>=A0 =A0 =A0 =A0 =A0printf(&quot; promiscuous=3D%&quot;PRIu32, sflowxdr=
_next(x));</div><div>=A0 =A0 =A0 =A0 =A0printf(&quot;\n&quot;);</div><div>=
=A0 =A0 =A0}</div><div>+ =A0 =A0if(x-&gt;offset.LACPCOUNTERS) {</div><div>+=
<span class=3D"" style=3D"white-space:pre">	</span>uint8_t *mac;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>union {</div><div>=
+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0uint32_t all;</=
div><div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0struct=
 {</div><div>+<span class=3D"" style=3D"white-space:pre">		</span>uint8_t a=
ctorAdmin;</div>
<div>+<span class=3D"" style=3D"white-space:pre">		</span>uint8_t actorOper=
;</div><div>+<span class=3D"" style=3D"white-space:pre">		</span>uint8_t pa=
rtnerAdmin;</div><div>+<span class=3D"" style=3D"white-space:pre">		</span>=
uint8_t partnerOper;</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0} v;</div>=
<div>+<span class=3D"" style=3D"white-space:pre">	</span>} state;</div><div=
>+</div><div>+ =A0 =A0 =A0 =A0sflowxdr_setc(x, x-&gt;offset.LACPCOUNTERS);<=
/div><div>+ =A0 =A0 =A0 =A0printf(&quot;LACPCOUNTERS&quot;);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>mac =3D (uint8_t *=
)sflowxdr_str(x);</div><div>+<span class=3D"" style=3D"white-space:pre">	</=
span>printf(&quot; sysID=3D&quot;ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));</div><d=
iv>+<span class=3D"" style=3D"white-space:pre">	</span>sflowxdr_skip(x, 2);=
</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>mac =3D (uint8_t *=
)sflowxdr_str(x);</div><div>+<span class=3D"" style=3D"white-space:pre">	</=
span>printf(&quot; partnerID=3D&quot;ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));</di=
v><div>+<span class=3D"" style=3D"white-space:pre">	</span>sflowxdr_skip(x,=
 2);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; aggI=
D=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+<span class=3D"" style=3D"=
white-space:pre">	</span>state.all =3D sflowxdr_next_n(x);</div><div>+<span=
 class=3D"" style=3D"white-space:pre">	</span>printf(&quot; actorAdmin=3D0x=
%&quot;PRIx32, state.v.actorAdmin);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; acto=
rOper=3D0x%&quot;PRIx32, state.v.actorOper);</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">	</span>printf(&quot; partnerAdmin=3D0x%&quot;PRIx3=
2, state.v.partnerAdmin);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; part=
nerOper=3D0x%&quot;PRIx32, state.v.partnerOper);</div><div>+<span class=3D"=
" style=3D"white-space:pre">	</span>printf(&quot; LACPUDsRx=3D%&quot;PRIu32=
, sflowxdr_next(x));</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; mark=
erPDUsRx=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+<span class=3D"" st=
yle=3D"white-space:pre">	</span>printf(&quot; markerRespPDUsRx=3D%&quot;PRI=
u32, sflowxdr_next(x));</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; unkn=
ownRx=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>printf(&quot; illegalRx=3D%&quot;PRIu32, sflow=
xdr_next(x));</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; LACP=
UDsTx=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+<span class=3D"" style=
=3D"white-space:pre">	</span>printf(&quot; markerPDUsTx=3D%&quot;PRIu32, sf=
lowxdr_next(x));</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span>printf(&quot; mark=
erRespPDUsTx=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+ =A0 =A0 =A0 =
=A0printf(&quot;\n&quot;);</div><div>+ =A0 =A0}</div><div>=A0}</div><div>=
=A0</div><div>=A0static char</div>
<div>@@ -251,6 +297,25 @@ print_hex(const char *a, int len, char *buf, int =
bufLen)</div><div>=A0 =A0 =A0return b;</div><div>=A0}</div><div>=A0</div><d=
iv>+static void</div><div>+print_struct_ipv4(struct sflow_xdr *x, const cha=
r *prefix)</div>
<div>+{</div><div>+ =A0 =A0uint32_t src, dst;</div><div>+</div><div>+ =A0 =
=A0printf(&quot; %s_length=3D%&quot;PRIu32, =A0 =A0prefix, sflowxdr_next(x)=
);</div><div>+ =A0 =A0printf(&quot; %s_protocol=3D%&quot;PRIu32, =A0prefix,=
 sflowxdr_next(x));</div>
<div>+</div><div>+ =A0 =A0src =3D sflowxdr_next_n(x);</div><div>+ =A0 =A0ds=
t =3D sflowxdr_next_n(x);</div><div>+ =A0 =A0printf(&quot; %s_src=3D&quot;I=
P_FMT, =A0 =A0 =A0 =A0prefix, IP_ARGS(src));</div><div>+ =A0 =A0printf(&quo=
t; %s_dst=3D&quot;IP_FMT, =A0 =A0 =A0 =A0prefix, IP_ARGS(dst));</div>
<div>+</div><div>+ =A0 =A0printf(&quot; %s_src_port=3D%&quot;PRIu32, =A0pre=
fix, sflowxdr_next(x));</div><div>+ =A0 =A0printf(&quot; %s_dst_port=3D%&qu=
ot;PRIu32, =A0prefix, sflowxdr_next(x));</div><div>+ =A0 =A0printf(&quot; %=
s_tcp_flags=3D%&quot;PRIu32, prefix, sflowxdr_next(x));</div>
<div>+ =A0 =A0printf(&quot; %s_tos=3D%&quot;PRIu32, =A0 =A0 =A0 prefix, sfl=
owxdr_next(x));</div><div>+}</div><div>+</div><div>=A0#define SFLOW_HEX_SCR=
ATCH 1024</div><div>=A0</div><div>=A0static void</div><div>@@ -266,6 +331,2=
6 @@ process_flow_sample(struct sflow_xdr *x)</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 x-&gt;agentIPStr, x-&gt;dsClass, x-&gt=
;dsIndex);</div><div>=A0 =A0 =A0 =A0 =A0printf(&quot; fsSeqNo=3D%&quot;PRIu=
32, x-&gt;fsSeqNo);</div><div>=A0</div><div>+ =A0 =A0 =A0 =A0if (x-&gt;offs=
et.TUNNEL4_IN) {</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_setc(x, x-&gt;=
offset.TUNNEL4_IN);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0print_stru=
ct_ipv4(x, &quot;tunnel4_in&quot;);</div><div>+ =A0 =A0 =A0 =A0}</div><div>=
+</div><div>+ =A0 =A0 =A0 =A0if (x-&gt;offset.TUNNEL4_OUT) {</div><div>+ =
=A0 =A0 =A0 =A0 =A0 =A0sflowxdr_setc(x, x-&gt;offset.TUNNEL4_OUT);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0print_stru=
ct_ipv4(x, &quot;tunnel4_out&quot;);</div><div>+ =A0 =A0 =A0 =A0}</div><div=
>+</div><div>+ =A0 =A0 =A0 =A0if (x-&gt;offset.TUNNEL_VNI_IN) {</div><div>+=
 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_setc(x, x-&gt;offset.TUNNEL_VNI_IN);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0printf( &q=
uot; tunnel_in_vni=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+ =A0 =A0 =
=A0 =A0}</div><div>+</div><div>+ =A0 =A0 =A0 =A0if (x-&gt;offset.TUNNEL_VNI=
_OUT) {</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_setc(x, x-&gt;offset.TU=
NNEL_VNI_OUT);</div>
<div>+<span class=3D"" style=3D"white-space:pre">	</span> =A0 =A0printf( &q=
uot; tunnel_out_vni=3D%&quot;PRIu32, sflowxdr_next(x));</div><div>+ =A0 =A0=
 =A0 =A0}</div><div>+</div><div>=A0 =A0 =A0 =A0 =A0if (x-&gt;offset.SWITCH)=
 {</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_setc(x, x-&gt;offset.SWITC=
H);</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0printf(&quot; in_vlan=3D%&quot;PRIu32, sflo=
wxdr_next(x));</div><div>@@ -374,6 +459,9 @@ process_datagram(struct sflow_=
xdr *x)</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case SFLOW_TAG_CTR_IFC=
OUNTERS:</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_mark=
_unique(x, &amp;x-&gt;offset.IFCOUNTERS);</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>+ =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0case SFLOW_TAG_CTR_LACPCOUNTERS:</div><div>+ =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_mark_unique(x, &amp;x-&gt;offset.L=
ACPCOUNTERS);</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</di=
v>
<div>=A0</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Add others=
 here... */</div><div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}</div><div>@@ -44=
2,6 +530,22 @@ process_datagram(struct sflow_xdr *x)</div><div>=A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_mark_unique(x, &amp;x-&gt;offset.SW=
ITCH);</div>
<div>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>=A0</div><=
div>+<span class=3D"" style=3D"white-space:pre">		</span>case SFLOW_TAG_PKT=
_TUNNEL4_OUT:</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_m=
ark_unique(x, &amp;x-&gt;offset.TUNNEL4_OUT);</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>+</div><div>=
+<span class=3D"" style=3D"white-space:pre">		</span>case SFLOW_TAG_PKT_TUN=
NEL4_IN:</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_mark_u=
nique(x, &amp;x-&gt;offset.TUNNEL4_IN);</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>+</div><div>=
+<span class=3D"" style=3D"white-space:pre">		</span>case SFLOW_TAG_PKT_TUN=
NEL_VNI_OUT:</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_ma=
rk_unique(x, &amp;x-&gt;offset.TUNNEL_VNI_OUT);</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>+</div><div>=
+<span class=3D"" style=3D"white-space:pre">		</span>case SFLOW_TAG_PKT_TUN=
NEL_VNI_IN:</div><div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sflowxdr_mar=
k_unique(x, &amp;x-&gt;offset.TUNNEL_VNI_IN);</div>
<div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;</div><div>+</div><div>=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Add others here... */</div><d=
iv>=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}</div><div>=A0</div><div>--=A0</div>=
<div>1.7.9.5</div><div><br></div></div>-- <br>------<br>Neil McKee<br>
InMon Corp.<br><a href=3D"http://www.inmon.com" target=3D"_blank">http://ww=
w.inmon.com</a><br>
</div>

--089e012281aca98c4204ec3c93e3--


More information about the dev mailing list