release. The protocol is documented at
http://tools.ietf.org/html/draft-gross-geneve-00
- The OVS database now reports controller rate limiting statistics.
+ - sflow now exports information about LACP-based bonds, port names, and
+ OpenFlow port numbers.
- ovs-dpctl functionality is now available for datapaths integrated
into ovs-vswitchd, via ovs-appctl. Some existing ovs-appctl
commands are now redundant and will be removed in a future
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. */
+
+ uint32_t count_rx_pdus; /* dot3adAggPortStatsLACPDUsRx */
+ uint32_t count_rx_pdus_bad; /* dot3adAggPortStatsIllegalRx */
+ uint32_t count_tx_pdus; /* dot3adAggPortStatsLACPDUsTx */
};
static struct ovs_mutex mutex;
if (!slave) {
goto out;
}
+ slave->count_rx_pdus++;
pdu = parse_lacp_packet(packet);
if (!pdu) {
+ slave->count_rx_pdus_bad++;
VLOG_WARN_RL(&rl, "%s: received an unparsable LACP PDU.", lacp->name);
goto out;
}
slave->ntt_actor = actor;
compose_lacp_pdu(&actor, &slave->partner, &pdu);
send_pdu(slave->aux, &pdu, sizeof pdu);
+ slave->count_tx_pdus++;
duration = (slave->partner.state & LACP_STATE_TIME
? LACP_FAST_TIME_TX
out:
lacp_unlock();
}
+
+/* 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->count_rx_pdus;
+ stats->dot3adAggPortStatsIllegalRx = slave->count_rx_pdus_bad;
+ stats->dot3adAggPortStatsLACPDUsTx = slave->count_tx_pdus;
+ } else {
+ ret = false;
+ }
+ ovs_mutex_unlock(&mutex);
+ return ret;
+
+}
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 */
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 */
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 {
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 {
/* Counter types */
+#define SFL_UNDEF_COUNTER(c) c=-1
+#define SFL_UNDEF_GAUGE(c) c=0
+
/* Generic interface counters - see RFC 1573, 2233 */
typedef struct _SFLIf_counters {
u_int32_t ifPromiscuousMode;
} SFLIf_counters;
+#define SFL_CTR_GENERIC_XDR_SIZE 88
+
/* Ethernet interface counters - see RFC 2358 */
typedef struct _SFLEthernet_counters {
u_int32_t dot3StatsAlignmentErrors;
u_int32_t dot3StatsSymbolErrors;
} SFLEthernet_counters;
+#define SFL_CTR_ETHERNET_XDR_SIZE 52
+
/* Token ring counters - see RFC 1748 */
typedef struct _SFLTokenring_counters {
u_int32_t discards;
} SFLVlan_counters;
+/* OpenFlow port */
+typedef struct {
+ u_int64_t datapath_id;
+ u_int32_t port_no;
+} SFLOpenFlowPort;
+
+#define SFL_CTR_OPENFLOWPORT_XDR_SIZE 12
+
+/* port name */
+typedef struct {
+ SFLString portName;
+} SFLPortName;
+
+#define SFL_MAX_PORTNAME_LEN 255
+
+/* 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;
+
+#define SFL_CTR_LACP_XDR_SIZE 56
+
/* Counters data */
enum SFLCounters_type_tag {
SFLCOUNTERS_ETHERNET = 2,
SFLCOUNTERS_TOKENRING = 3,
SFLCOUNTERS_VG = 4,
- SFLCOUNTERS_VLAN = 5
+ SFLCOUNTERS_VLAN = 5,
+ SFLCOUNTERS_LACP = 7,
+ SFLCOUNTERS_OPENFLOWPORT = 1004,
+ SFLCOUNTERS_PORTNAME = 1005
};
typedef union _SFLCounters_type {
SFLTokenring_counters tokenring;
SFLVg_counters vg;
SFLVlan_counters vlan;
+ SFLLACP_counters lacp;
+ SFLOpenFlowPort ofPort;
+ SFLPortName portName;
} SFLCounters_type;
typedef struct _SFLCounters_sample_element {
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 __________________
-----------------___________________________------------------
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 */
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;
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);
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;
cs->num_elements++;
siz += 8; /* tag, length */
switch(elem->tag) {
- case SFLCOUNTERS_GENERIC: elemSiz = sizeof(elem->counterBlock.generic); break;
- case SFLCOUNTERS_ETHERNET: elemSiz = sizeof(elem->counterBlock.ethernet); break;
+ case SFLCOUNTERS_GENERIC: elemSiz = SFL_CTR_GENERIC_XDR_SIZE; break;
+ case SFLCOUNTERS_ETHERNET: elemSiz = SFL_CTR_ETHERNET_XDR_SIZE; break;
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 = SFL_CTR_LACP_XDR_SIZE; break;
+ case SFLCOUNTERS_OPENFLOWPORT: elemSiz = SFL_CTR_OPENFLOWPORT_XDR_SIZE; break;
+ case SFLCOUNTERS_PORTNAME: elemSiz = stringEncodingLength(&elem->counterBlock.portName.portName); break;
default:
sflError(receiver, "unexpected counters_tag");
return -1;
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;
+ case SFLCOUNTERS_OPENFLOWPORT:
+ putNet64(receiver, elem->counterBlock.ofPort.datapath_id);
+ putNet32(receiver, elem->counterBlock.ofPort.port_no);
+ break;
+ case SFLCOUNTERS_PORTNAME:
+ putString(receiver, &elem->counterBlock.portName.portName);
+ break;
default:
sflError(receiver, "unexpected counters_tag");
return -1;
#include "vlog.h"
#include "lib/odp-util.h"
#include "ofproto-provider.h"
+#include "lacp.h"
VLOG_DEFINE_THIS_MODULE(sflow);
OVS_REQUIRES(mutex)
{
struct dpif_sflow *ds = ds_;
- SFLCounters_sample_element elem;
+ SFLCounters_sample_element elem, lacp_elem, of_elem, name_elem;
enum netdev_features current;
struct dpif_sflow_port *dsp;
SFLIf_counters *counters;
struct netdev_stats stats;
enum netdev_flags flags;
+ struct lacp_slave_stats lacp_stats;
+ const char *ifName;
dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
if (!dsp) {
counters->ifPromiscuousMode = 0;
SFLADD_ELEMENT(cs, &elem);
+
+ /* Include LACP counters and identifiers if this port is part of a LAG. */
+ if (ofproto_port_get_lacp_stats(dsp->ofport, &lacp_stats) == 0) {
+ memset(&lacp_elem, 0, sizeof lacp_elem);
+ lacp_elem.tag = SFLCOUNTERS_LACP;
+ memcpy(&lacp_elem.counterBlock.lacp.actorSystemID,
+ lacp_stats.dot3adAggPortActorSystemID,
+ ETH_ADDR_LEN);
+ memcpy(&lacp_elem.counterBlock.lacp.partnerSystemID,
+ lacp_stats.dot3adAggPortPartnerOperSystemID,
+ ETH_ADDR_LEN);
+ lacp_elem.counterBlock.lacp.attachedAggID =
+ lacp_stats.dot3adAggPortAttachedAggID;
+ lacp_elem.counterBlock.lacp.portState.v.actorAdmin =
+ lacp_stats.dot3adAggPortActorAdminState;
+ lacp_elem.counterBlock.lacp.portState.v.actorOper =
+ lacp_stats.dot3adAggPortActorOperState;
+ lacp_elem.counterBlock.lacp.portState.v.partnerAdmin =
+ lacp_stats.dot3adAggPortPartnerAdminState;
+ lacp_elem.counterBlock.lacp.portState.v.partnerOper =
+ lacp_stats.dot3adAggPortPartnerOperState;
+ lacp_elem.counterBlock.lacp.LACPDUsRx =
+ lacp_stats.dot3adAggPortStatsLACPDUsRx;
+ SFL_UNDEF_COUNTER(lacp_elem.counterBlock.lacp.markerPDUsRx);
+ SFL_UNDEF_COUNTER(lacp_elem.counterBlock.lacp.markerResponsePDUsRx);
+ SFL_UNDEF_COUNTER(lacp_elem.counterBlock.lacp.unknownRx);
+ lacp_elem.counterBlock.lacp.illegalRx =
+ lacp_stats.dot3adAggPortStatsIllegalRx;
+ lacp_elem.counterBlock.lacp.LACPDUsTx =
+ lacp_stats.dot3adAggPortStatsLACPDUsTx;
+ SFL_UNDEF_COUNTER(lacp_elem.counterBlock.lacp.markerPDUsTx);
+ SFL_UNDEF_COUNTER(lacp_elem.counterBlock.lacp.markerResponsePDUsTx);
+ SFLADD_ELEMENT(cs, &lacp_elem);
+ }
+
+ /* Include Port name. */
+ if ((ifName = netdev_get_name(dsp->ofport->netdev)) != NULL) {
+ memset(&name_elem, 0, sizeof name_elem);
+ name_elem.tag = SFLCOUNTERS_PORTNAME;
+ name_elem.counterBlock.portName.portName.str = (char *)ifName;
+ name_elem.counterBlock.portName.portName.len = strlen(ifName);
+ SFLADD_ELEMENT(cs, &name_elem);
+ }
+
+ /* Include OpenFlow DPID and openflow port number. */
+ memset(&of_elem, 0, sizeof of_elem);
+ of_elem.tag = SFLCOUNTERS_OPENFLOWPORT;
+ of_elem.counterBlock.ofPort.datapath_id =
+ ofproto_get_datapath_id(dsp->ofport->ofproto);
+ of_elem.counterBlock.ofPort.port_no =
+ (OVS_FORCE uint32_t)dsp->ofport->ofp_port;
+ SFLADD_ELEMENT(cs, &of_elem);
+
sfl_poller_writeCountersSample(poller, cs);
}
return error;
}
+static int
+port_get_lacp_stats(const struct ofport *ofport_, struct lacp_slave_stats *stats)
+{
+ struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+ if (ofport->bundle && ofport->bundle->lacp) {
+ if (lacp_get_slave_stats(ofport->bundle->lacp, ofport, stats)) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
struct port_dump_state {
uint32_t bucket;
uint32_t offset;
port_poll,
port_poll_wait,
port_is_lacp_current,
+ port_get_lacp_stats,
NULL, /* rule_choose_table */
rule_alloc,
rule_construct,
* not support LACP. */
int (*port_is_lacp_current)(const struct ofport *port);
+ /* Get LACP port stats. Returns -1 if LACP is not enabled on 'port'.
+ *
+ * This function may be a null pointer if the ofproto implementation does
+ * not support LACP. */
+ int (*port_get_lacp_stats)(const struct ofport *port,
+ struct lacp_slave_stats *stats);
+
+
/* ## ----------------------- ## */
/* ## OpenFlow Rule Functions ## */
/* ## ----------------------- ## */
? ofproto->ofproto_class->port_is_lacp_current(ofport)
: -1);
}
+
+int
+ofproto_port_get_lacp_stats(const struct ofport *port, struct lacp_slave_stats *stats)
+{
+ struct ofproto *ofproto = port->ofproto;
+ int error;
+
+ if (ofproto->ofproto_class->port_get_lacp_stats) {
+ error = ofproto->ofproto_class->port_get_lacp_stats(port, stats);
+ } else {
+ error = EOPNOTSUPP;
+ }
+
+ return error;
+}
\f
/* Bundles. */
#include "smap.h"
#include "sset.h"
#include "stp.h"
+#include "lacp.h"
#ifdef __cplusplus
extern "C" {
int ofproto_port_get_bfd_status(struct ofproto *, ofp_port_t ofp_port,
struct smap *);
int ofproto_port_is_lacp_current(struct ofproto *, ofp_port_t ofp_port);
+int ofproto_port_get_lacp_stats(const struct ofport *, struct lacp_slave_stats *);
int ofproto_port_set_stp(struct ofproto *, ofp_port_t ofp_port,
const struct ofproto_port_stp_settings *);
int ofproto_port_get_stp_status(struct ofproto *, ofp_port_t ofp_port,
hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00
])
- AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
+ AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR|PORTNAME|OPENFLOWPORT' | head -18 | sed 's/ /\
/g']], [0], [dnl
IFCOUNTERS
dgramSeqNo=2
out_discards=0
out_errors=0
promiscuous=0
+OPENFLOWPORT
+ datapath_id=18364758544493064720
+ port_no=1
+OPENFLOWPORT
+ datapath_id=18364758544493064720
+ port_no=1
+OPENFLOWPORT
+ datapath_id=18364758544493064720
+ port_no=2
+OPENFLOWPORT
+ datapath_id=18364758544493064720
+ port_no=2
+OPENFLOWPORT
+ datapath_id=18364758544493064720
+ port_no=65534
+OPENFLOWPORT
+ datapath_id=18364758544493064720
+ port_no=65534
+PORTNAME
+ portName=br0
+PORTNAME
+ portName=br0
+PORTNAME
+ portName=p1
+PORTNAME
+ portName=p1
+PORTNAME
+ portName=p2
+PORTNAME
+ portName=p2
])
AT_CLEANUP])
CHECK_SFLOW_SAMPLING_PACKET([127.0.0.1], [IPv4])
CHECK_SFLOW_SAMPLING_PACKET([[[::1]]], [IPv6])
+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([ovstest 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
+
# CHECK_NETFLOW_EXPIRATION(LOOPBACK_ADDR, IP_VERSION_TYPE)
#
# Test that basic NetFlow reports flow statistics correctly:
/* Structure element tag numbers. */
#define SFLOW_TAG_CTR_IFCOUNTERS 1
+#define SFLOW_TAG_CTR_LACPCOUNTERS 7
+#define SFLOW_TAG_CTR_OPENFLOWPORT 1004
+#define SFLOW_TAG_CTR_PORTNAME 1005
#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
+
+/* string sizes */
+#define SFL_MAX_PORTNAME_LEN 255
struct sflow_addr {
enum {
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;
+ uint32_t OPENFLOWPORT;
+ uint32_t PORTNAME;
} offset;
/* Flow sample fields. */
printf(" promiscuous=%"PRIu32, sflowxdr_next(x));
printf("\n");
}
+ if (x->offset.LACPCOUNTERS) {
+ uint8_t *mac;
+ union {
+ ovs_be32 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");
+ }
+ if (x->offset.OPENFLOWPORT) {
+ sflowxdr_setc(x, x->offset.OPENFLOWPORT);
+ printf("OPENFLOWPORT");
+ printf(" datapath_id=%"PRIu64, sflowxdr_next_int64(x));
+ printf(" port_no=%"PRIu32, sflowxdr_next(x));
+ printf("\n");
+ }
+ if (x->offset.PORTNAME) {
+ uint32_t pnLen;
+ const char *pnBytes;
+ char portName[SFL_MAX_PORTNAME_LEN + 1];
+ sflowxdr_setc(x, x->offset.PORTNAME);
+ printf("PORTNAME");
+ pnLen = sflowxdr_next(x);
+ SFLOWXDR_assert(x, (pnLen <= SFL_MAX_PORTNAME_LEN));
+ pnBytes = sflowxdr_str(x);
+ memcpy(portName, pnBytes, pnLen);
+ portName[pnLen] = '\0';
+ printf(" portName=%s", portName);
+ printf("\n");
+ }
}
static char
return b;
}
+static void
+print_struct_ipv4(struct sflow_xdr *x, const char *prefix)
+{
+ ovs_be32 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
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));
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;
+ case SFLOW_TAG_CTR_PORTNAME:
+ sflowxdr_mark_unique(x, &x->offset.PORTNAME);
+ break;
+ case SFLOW_TAG_CTR_OPENFLOWPORT:
+ sflowxdr_mark_unique(x, &x->offset.OPENFLOWPORT);
+ break;
/* Add others here... */
}
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... */
}