Skip to content

Commit

Permalink
sflow: Export LAG, PORTNAME, and OPENFLOWPORT information also.
Browse files Browse the repository at this point in the history
Export standard sFlow LAG, PORTNAME and OPENFLOWPORT structures with each
counter-sample. Add unit-test for sFlow-LAG. Adjust other unit-tests to
accommodate these new annotations.

The sFlow-LAG structures are important for topology discovery, for
troubleshooting LAG instability,  and for correctly combining
sFlow feeds from multiple sources.

The OPENFLOWPORT and PORTNAME structures are important for systems that
aim to combine sFlow monitoring with OpenFlow controls,  as they
provide straightforward mapping (1) between sFlow agent IP and OpenFlow
datapath-id,  and (2) between interface name,ifIndex and OpenFlow
port number.

Signed-off-by: Neil McKee <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
sflow authored and blp committed Nov 11, 2014
1 parent afc63bb commit 50b9699
Show file tree
Hide file tree
Showing 14 changed files with 534 additions and 5 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Post-v2.3.0
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
Expand Down
62 changes: 62 additions & 0 deletions lib/lacp.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ 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. */

uint32_t count_rx_pdus; /* dot3adAggPortStatsLACPDUsRx */
uint32_t count_rx_pdus_bad; /* dot3adAggPortStatsIllegalRx */
uint32_t count_tx_pdus; /* dot3adAggPortStatsLACPDUsTx */
};

static struct ovs_mutex mutex;
Expand Down Expand Up @@ -328,9 +332,11 @@ lacp_process_packet(struct lacp *lacp, const void *slave_,
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;
}
Expand Down Expand Up @@ -548,6 +554,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->count_tx_pdus++;

duration = (slave->partner.state & LACP_STATE_TIME
? LACP_FAST_TIME_TX
Expand Down Expand Up @@ -978,3 +985,58 @@ lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
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;

}
23 changes: 23 additions & 0 deletions lib/lacp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
69 changes: 68 additions & 1 deletion lib/sflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,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 */
Expand All @@ -289,6 +293,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 {
Expand All @@ -308,6 +316,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 {
Expand Down Expand Up @@ -386,6 +395,9 @@ typedef struct _SFLFlow_sample_expanded {

/* 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 {
Expand Down Expand Up @@ -414,6 +426,8 @@ 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;
Expand All @@ -431,6 +445,8 @@ typedef struct _SFLEthernet_counters {
u_int32_t dot3StatsSymbolErrors;
} SFLEthernet_counters;

#define SFL_CTR_ETHERNET_XDR_SIZE 52

/* Token ring counters - see RFC 1748 */

typedef struct _SFLTokenring_counters {
Expand Down Expand Up @@ -482,6 +498,51 @@ typedef struct _SFLVlan_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 {
Expand All @@ -490,7 +551,10 @@ 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 {
Expand All @@ -499,6 +563,9 @@ 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 {
Expand Down
15 changes: 15 additions & 0 deletions lib/sflow_agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 __________________
-----------------___________________________------------------
Expand Down
1 change: 1 addition & 0 deletions lib/sflow_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
43 changes: 41 additions & 2 deletions lib/sflow_receiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,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;
Expand Down Expand Up @@ -560,6 +568,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);
Expand Down Expand Up @@ -591,6 +601,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;
Expand Down Expand Up @@ -629,11 +644,14 @@ static int computeCountersSampleSize(SFLReceiver *receiver, SFL_COUNTERS_SAMPLE_
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;
Expand Down Expand Up @@ -735,6 +753,27 @@ 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;
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;
Expand Down
Loading

0 comments on commit 50b9699

Please sign in to comment.