Switched sflow plugin to our own libsflow parser. Closes #843
This commit is contained in:
parent
7b22357404
commit
37c1404f4c
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
// This file consist of all important plugins which could be usefult for plugin
|
||||
// development
|
||||
|
||||
// For support uint32_t, uint16_t
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "all_logcpp_libraries.h"
|
||||
|
||||
#include "fast_library.h"
|
||||
|
||||
#include "fast_platform.h"
|
||||
|
||||
// Get log4cpp logger from main programm
|
||||
extern log4cpp::Category& logger;
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
enum direction { INCOMING = 0, OUTGOING, INTERNAL, OTHER };
|
||||
enum source_t { UNKNOWN = 0, MIRROR = 1, SFLOW = 2, NETFLOW = 3, TERAFLOW = 4 };
|
||||
|
||||
// simplified packet struct for lightweight save into memory
|
||||
class simple_packet_t {
|
||||
|
@ -17,6 +18,9 @@ class simple_packet_t {
|
|||
ts.tv_usec = 0;
|
||||
ts.tv_sec = 0;
|
||||
}
|
||||
// Source plugin for this traffic type
|
||||
source_t source = UNKNOWN;
|
||||
|
||||
uint32_t sample_ratio;
|
||||
/* IPv4 */
|
||||
uint32_t src_ip;
|
||||
|
@ -24,6 +28,11 @@ class simple_packet_t {
|
|||
/* IPv6 */
|
||||
struct in6_addr src_ipv6;
|
||||
struct in6_addr dst_ipv6;
|
||||
|
||||
/* ASN's */
|
||||
uint32_t src_asn = 0;
|
||||
uint32_t dst_asn = 0;
|
||||
|
||||
uint8_t ip_protocol_version; /* IPv4 or IPv6 */
|
||||
uint8_t ttl;
|
||||
uint16_t source_port;
|
||||
|
@ -49,5 +58,8 @@ class simple_packet_t {
|
|||
|
||||
// We store packet direction here because direction calculation is very difficult task for cpu
|
||||
direction packet_direction;
|
||||
|
||||
// IP address of device which send this flow
|
||||
uint32_t agent_ip_address = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,1413 +0,0 @@
|
|||
/* Copyright (c) 2002-2011 InMon Corp. Licensed under the terms of the InMon sFlow licence: */
|
||||
/* http://www.inmon.com/technology/sflowlicense.txt */
|
||||
|
||||
/*
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////// sFlow Sampling Packet Data Types ////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
#ifndef SFLOW_H
|
||||
#define SFLOW_H 1
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t addr;
|
||||
} SFLIPv4;
|
||||
|
||||
typedef struct {
|
||||
u_char addr[16];
|
||||
} SFLIPv6;
|
||||
|
||||
typedef union _SFLAddress_value {
|
||||
SFLIPv4 ip_v4;
|
||||
SFLIPv6 ip_v6;
|
||||
} SFLAddress_value;
|
||||
|
||||
enum SFLAddress_type {
|
||||
SFLADDRESSTYPE_UNDEFINED = 0,
|
||||
SFLADDRESSTYPE_IP_V4 = 1,
|
||||
SFLADDRESSTYPE_IP_V6 = 2
|
||||
};
|
||||
|
||||
typedef struct _SFLAddress {
|
||||
uint32_t type; /* enum SFLAddress_type */
|
||||
SFLAddress_value address;
|
||||
} SFLAddress;
|
||||
|
||||
/* Packet header data */
|
||||
|
||||
#define SFL_DEFAULT_HEADER_SIZE 128
|
||||
#define SFL_DEFAULT_COLLECTOR_PORT 6343
|
||||
#define SFL_DEFAULT_SAMPLING_RATE 400
|
||||
|
||||
/* The header protocol describes the format of the sampled header */
|
||||
enum SFLHeader_protocol {
|
||||
SFLHEADER_ETHERNET_ISO8023 = 1,
|
||||
SFLHEADER_ISO88024_TOKENBUS = 2,
|
||||
SFLHEADER_ISO88025_TOKENRING = 3,
|
||||
SFLHEADER_FDDI = 4,
|
||||
SFLHEADER_FRAME_RELAY = 5,
|
||||
SFLHEADER_X25 = 6,
|
||||
SFLHEADER_PPP = 7,
|
||||
SFLHEADER_SMDS = 8,
|
||||
SFLHEADER_AAL5 = 9,
|
||||
SFLHEADER_AAL5_IP = 10, /* e.g. Cisco AAL5 mux */
|
||||
SFLHEADER_IPv4 = 11,
|
||||
SFLHEADER_IPv6 = 12,
|
||||
SFLHEADER_MPLS = 13,
|
||||
SFLHEADER_POS = 14,
|
||||
SFLHEADER_IEEE80211MAC = 15,
|
||||
SFLHEADER_IEEE80211_AMPDU = 16,
|
||||
SFLHEADER_IEEE80211_AMSDU_SUBFRAME = 17
|
||||
};
|
||||
|
||||
/* raw sampled header */
|
||||
|
||||
typedef struct _SFLSampled_header {
|
||||
uint32_t header_protocol; /* (enum SFLHeader_protocol) */
|
||||
uint32_t frame_length; /* Original length of packet before sampling */
|
||||
uint32_t stripped; /* header/trailer bytes stripped by sender */
|
||||
uint32_t header_length; /* length of sampled header bytes to follow */
|
||||
uint8_t* header_bytes; /* Header bytes */
|
||||
} SFLSampled_header;
|
||||
|
||||
/* decoded ethernet header */
|
||||
|
||||
typedef struct _SFLSampled_ethernet {
|
||||
uint32_t eth_len; /* The length of the MAC packet excluding
|
||||
lower layer encapsulations */
|
||||
uint8_t src_mac[8]; /* 6 bytes + 2 pad */
|
||||
uint8_t dst_mac[8];
|
||||
uint32_t eth_type;
|
||||
} SFLSampled_ethernet;
|
||||
|
||||
/* decoded IP version 4 header */
|
||||
|
||||
typedef struct _SFLSampled_ipv4 {
|
||||
uint32_t length; /* The length of the IP packet
|
||||
excluding lower layer encapsulations */
|
||||
uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */
|
||||
SFLIPv4 src_ip; /* Source IP Address */
|
||||
SFLIPv4 dst_ip; /* Destination IP Address */
|
||||
uint32_t src_port; /* TCP/UDP source port number or equivalent */
|
||||
uint32_t dst_port; /* TCP/UDP destination port number or equivalent */
|
||||
uint32_t tcp_flags; /* TCP flags */
|
||||
uint32_t tos; /* IP type of service */
|
||||
} SFLSampled_ipv4;
|
||||
|
||||
/* decoded IP version 6 data */
|
||||
|
||||
typedef struct _SFLSampled_ipv6 {
|
||||
uint32_t length; /* The length of the IP packet
|
||||
excluding lower layer encapsulations */
|
||||
uint32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */
|
||||
SFLIPv6 src_ip; /* Source IP Address */
|
||||
SFLIPv6 dst_ip; /* Destination IP Address */
|
||||
uint32_t src_port; /* TCP/UDP source port number or equivalent */
|
||||
uint32_t dst_port; /* TCP/UDP destination port number or equivalent */
|
||||
uint32_t tcp_flags; /* TCP flags */
|
||||
uint32_t priority; /* IP priority */
|
||||
} SFLSampled_ipv6;
|
||||
|
||||
/* Extended data types */
|
||||
|
||||
/* Extended switch data */
|
||||
|
||||
typedef struct _SFLExtended_switch {
|
||||
uint32_t src_vlan; /* The 802.1Q VLAN id of incomming frame */
|
||||
uint32_t src_priority; /* The 802.1p priority */
|
||||
uint32_t dst_vlan; /* The 802.1Q VLAN id of outgoing frame */
|
||||
uint32_t dst_priority; /* The 802.1p priority */
|
||||
} SFLExtended_switch;
|
||||
|
||||
/* Extended router data */
|
||||
|
||||
typedef struct _SFLExtended_router {
|
||||
SFLAddress nexthop; /* IP address of next hop router */
|
||||
uint32_t src_mask; /* Source address prefix mask bits */
|
||||
uint32_t dst_mask; /* Destination address prefix mask bits */
|
||||
} SFLExtended_router;
|
||||
|
||||
/* Extended gateway data */
|
||||
enum SFLExtended_as_path_segment_type {
|
||||
SFLEXTENDED_AS_SET = 1, /* Unordered set of ASs */
|
||||
SFLEXTENDED_AS_SEQUENCE = 2 /* Ordered sequence of ASs */
|
||||
};
|
||||
|
||||
typedef struct _SFLExtended_as_path_segment {
|
||||
uint32_t type; /* enum SFLExtended_as_path_segment_type */
|
||||
uint32_t length; /* number of AS numbers in set/sequence */
|
||||
union {
|
||||
uint32_t* set;
|
||||
uint32_t* seq;
|
||||
} as;
|
||||
} SFLExtended_as_path_segment;
|
||||
|
||||
typedef struct _SFLExtended_gateway {
|
||||
SFLAddress nexthop; /* Address of the border router that should
|
||||
be used for the destination network */
|
||||
uint32_t as; /* AS number for this gateway */
|
||||
uint32_t src_as; /* AS number of source (origin) */
|
||||
uint32_t src_peer_as; /* AS number of source peer */
|
||||
uint32_t dst_as_path_segments; /* number of segments in path */
|
||||
SFLExtended_as_path_segment* dst_as_path; /* list of seqs or sets */
|
||||
uint32_t communities_length; /* number of communities */
|
||||
uint32_t* communities; /* set of communities */
|
||||
uint32_t localpref; /* LocalPref associated with this route */
|
||||
} SFLExtended_gateway;
|
||||
|
||||
typedef struct _SFLString {
|
||||
uint32_t len;
|
||||
char* str;
|
||||
} SFLString;
|
||||
|
||||
/* Extended user data */
|
||||
|
||||
typedef struct _SFLExtended_user {
|
||||
uint32_t src_charset; /* MIBEnum value of character set used to encode a string - See RFC 2978
|
||||
Where possible UTF-8 encoding (MIBEnum=106) should be used. A value
|
||||
of zero indicates an unknown encoding. */
|
||||
SFLString src_user;
|
||||
uint32_t dst_charset;
|
||||
SFLString dst_user;
|
||||
} SFLExtended_user;
|
||||
|
||||
/* Extended URL data */
|
||||
|
||||
enum SFLExtended_url_direction {
|
||||
SFLEXTENDED_URL_SRC = 1, /* URL is associated with source address */
|
||||
SFLEXTENDED_URL_DST = 2 /* URL is associated with destination address */
|
||||
};
|
||||
|
||||
typedef struct _SFLExtended_url {
|
||||
uint32_t direction; /* enum SFLExtended_url_direction */
|
||||
SFLString url; /* URL associated with the packet flow.
|
||||
Must be URL encoded */
|
||||
SFLString host; /* The host field from the HTTP header */
|
||||
} SFLExtended_url;
|
||||
|
||||
/* Extended MPLS data */
|
||||
|
||||
typedef struct _SFLLabelStack {
|
||||
uint32_t depth;
|
||||
uint32_t* stack; /* first entry is top of stack - see RFC 3032 for encoding */
|
||||
} SFLLabelStack;
|
||||
|
||||
typedef struct _SFLExtended_mpls {
|
||||
SFLAddress nextHop; /* Address of the next hop */
|
||||
SFLLabelStack in_stack;
|
||||
SFLLabelStack out_stack;
|
||||
} SFLExtended_mpls;
|
||||
|
||||
/* Extended NAT data
|
||||
Packet header records report addresses as seen at the sFlowDataSource.
|
||||
The extended_nat structure reports on translated source and/or destination
|
||||
addesses for this packet. If an address was not translated it should
|
||||
be equal to that reported for the header. */
|
||||
|
||||
typedef struct _SFLExtended_nat {
|
||||
SFLAddress src; /* Source address */
|
||||
SFLAddress dst; /* Destination address */
|
||||
} SFLExtended_nat;
|
||||
|
||||
typedef struct _SFLExtended_nat_port {
|
||||
uint32_t src_port;
|
||||
uint32_t dst_port;
|
||||
} SFLExtended_nat_port;
|
||||
|
||||
/* additional Extended MPLS stucts */
|
||||
|
||||
typedef struct _SFLExtended_mpls_tunnel {
|
||||
SFLString tunnel_lsp_name; /* Tunnel name */
|
||||
uint32_t tunnel_id; /* Tunnel ID */
|
||||
uint32_t tunnel_cos; /* Tunnel COS value */
|
||||
} SFLExtended_mpls_tunnel;
|
||||
|
||||
typedef struct _SFLExtended_mpls_vc {
|
||||
SFLString vc_instance_name; /* VC instance name */
|
||||
uint32_t vll_vc_id; /* VLL/VC instance ID */
|
||||
uint32_t vc_label_cos; /* VC Label COS value */
|
||||
} SFLExtended_mpls_vc;
|
||||
|
||||
/* Extended MPLS FEC
|
||||
- Definitions from MPLS-FTN-STD-MIB mplsFTNTable */
|
||||
|
||||
typedef struct _SFLExtended_mpls_FTN {
|
||||
SFLString mplsFTNDescr;
|
||||
uint32_t mplsFTNMask;
|
||||
} SFLExtended_mpls_FTN;
|
||||
|
||||
/* Extended MPLS LVP FEC
|
||||
- Definition from MPLS-LDP-STD-MIB mplsFecTable
|
||||
Note: mplsFecAddrType, mplsFecAddr information available
|
||||
from packet header */
|
||||
|
||||
typedef struct _SFLExtended_mpls_LDP_FEC {
|
||||
uint32_t mplsFecAddrPrefixLength;
|
||||
} SFLExtended_mpls_LDP_FEC;
|
||||
|
||||
/* Extended VLAN tunnel information
|
||||
Record outer VLAN encapsulations that have
|
||||
been stripped. extended_vlantunnel information
|
||||
should only be reported if all the following conditions are satisfied:
|
||||
1. The packet has nested vlan tags, AND
|
||||
2. The reporting device is VLAN aware, AND
|
||||
3. One or more VLAN tags have been stripped, either
|
||||
because they represent proprietary encapsulations, or
|
||||
because switch hardware automatically strips the outer VLAN
|
||||
encapsulation.
|
||||
Reporting extended_vlantunnel information is not a substitute for
|
||||
reporting extended_switch information. extended_switch data must
|
||||
always be reported to describe the ingress/egress VLAN information
|
||||
for the packet. The extended_vlantunnel information only applies to
|
||||
nested VLAN tags, and then only when one or more tags has been
|
||||
stripped. */
|
||||
|
||||
typedef SFLLabelStack SFLVlanStack;
|
||||
typedef struct _SFLExtended_vlan_tunnel {
|
||||
SFLVlanStack stack; /* List of stripped 802.1Q TPID/TCI layers. Each
|
||||
TPID,TCI pair is represented as a single 32 bit
|
||||
integer. Layers listed from outermost to
|
||||
innermost. */
|
||||
} SFLExtended_vlan_tunnel;
|
||||
|
||||
/*
|
||||
////////////////// IEEE 802.11 Extension structs ////////////////////
|
||||
|
||||
The 4-byte cipher_suite identifier follows the format of the cipher suite
|
||||
selector value from the 802.11i (TKIP/CCMP amendment to 802.11i)
|
||||
The most significant three bytes contain the OUI and the least significant
|
||||
byte contains the Suite Type.
|
||||
|
||||
The currently assigned values are:
|
||||
|
||||
OUI |Suite type |Meaning
|
||||
----------------------------------------------------
|
||||
00-0F-AC | 0 | Use group cipher suite
|
||||
00-0F-AC | 1 | WEP-40
|
||||
00-0F-AC | 2 | TKIP
|
||||
00-0F-AC | 3 | Reserved
|
||||
00-0F-AC | 4 | CCMP
|
||||
00-0F-AC | 5 | WEP-104
|
||||
00-0F-AC | 6-255 | Reserved
|
||||
Vendor OUI | Other | Vendor specific
|
||||
Other | Any | Reserved
|
||||
----------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef uint32_t SFLCipherSuite;
|
||||
|
||||
/* Extended wifi Payload
|
||||
Used to provide unencrypted version of 802.11 MAC data. If the
|
||||
MAC data is not encrypted then the agent must not include an
|
||||
extended_wifi_payload structure.
|
||||
If 802.11 MAC data is encrypted then the sampled_header structure
|
||||
should only contain the MAC header (since encrypted data cannot
|
||||
be decoded by the sFlow receiver). If the sFlow agent has access to
|
||||
the unencrypted payload, it should add an extended_wifi_payload
|
||||
structure containing the unencrypted data bytes from the sampled
|
||||
packet header, starting at the beginning of the 802.2 LLC and not
|
||||
including any trailing encryption footers. */
|
||||
/* opaque = flow_data; enterprise = 0; format = 1013 */
|
||||
|
||||
typedef struct _SFLExtended_wifi_payload {
|
||||
SFLCipherSuite cipherSuite;
|
||||
SFLSampled_header header;
|
||||
} SFLExtended_wifi_payload;
|
||||
|
||||
typedef enum {
|
||||
IEEE80211_A = 1,
|
||||
IEEE80211_B = 2,
|
||||
IEEE80211_G = 3,
|
||||
IEEE80211_N = 4,
|
||||
} SFL_IEEE80211_version;
|
||||
|
||||
/* opaque = flow_data; enterprise = 0; format = 1014 */
|
||||
|
||||
#define SFL_MAX_SSID_LEN 256
|
||||
|
||||
typedef struct _SFLExtended_wifi_rx {
|
||||
uint32_t ssid_len;
|
||||
char* ssid;
|
||||
char bssid[6]; /* BSSID */
|
||||
SFL_IEEE80211_version version; /* version */
|
||||
uint32_t channel; /* channel number */
|
||||
uint64_t speed;
|
||||
uint32_t rsni; /* received signal to noise ratio, see dot11FrameRprtRSNI */
|
||||
uint32_t rcpi; /* received channel power, see dot11FrameRprtLastRCPI */
|
||||
uint32_t packet_duration_us; /* amount of time that the successfully received pkt occupied RF
|
||||
medium.*/
|
||||
} SFLExtended_wifi_rx;
|
||||
|
||||
/* opaque = flow_data; enterprise = 0; format = 1015 */
|
||||
|
||||
typedef struct _SFLExtended_wifi_tx {
|
||||
uint32_t ssid_len;
|
||||
char* ssid; /* SSID string */
|
||||
char bssid[6]; /* BSSID */
|
||||
SFL_IEEE80211_version version; /* version */
|
||||
uint32_t transmissions; /* number of transmissions for sampled
|
||||
packet.
|
||||
0 = unkown
|
||||
1 = packet was successfully transmitted
|
||||
on first attempt
|
||||
n > 1 = n - 1 retransmissions */
|
||||
uint32_t packet_duration_us; /* amount of time that the successfully
|
||||
transmitted packet occupied the
|
||||
RF medium */
|
||||
uint32_t retrans_duration_us; /* amount of time that failed transmission
|
||||
attempts occupied the RF medium */
|
||||
uint32_t channel; /* channel number */
|
||||
uint64_t speed;
|
||||
uint32_t power_mw; /* transmit power in mW. */
|
||||
} SFLExtended_wifi_tx;
|
||||
|
||||
/* Extended 802.11 Aggregation Data */
|
||||
/* A flow_sample of an aggregated frame would consist of a packet
|
||||
header for the whole frame + any other extended structures that
|
||||
apply (e.g. 80211_tx/rx etc.) + an extended_wifi_aggregation
|
||||
structure which would contain an array of pdu structures (one
|
||||
for each PDU in the aggregate). A pdu is simply an array of
|
||||
flow records, in the simplest case a packet header for each PDU,
|
||||
but extended structures could be included as well. */
|
||||
|
||||
/* opaque = flow_data; enterprise = 0; format = 1016 */
|
||||
|
||||
struct _SFLFlow_Pdu; /* forward decl */
|
||||
|
||||
typedef struct _SFLExtended_aggregation {
|
||||
uint32_t num_pdus;
|
||||
struct _SFFlow_Pdu* pdus;
|
||||
} SFLExtended_aggregation;
|
||||
|
||||
/* Extended socket information,
|
||||
Must be filled in for all application transactions associated with a network socket
|
||||
Omit if transaction associated with non-network IPC */
|
||||
|
||||
/* IPv4 Socket */
|
||||
/* opaque = flow_data; enterprise = 0; format = 2100 */
|
||||
typedef struct _SFLExtended_socket_ipv4 {
|
||||
uint32_t protocol; /* IP Protocol (e.g. TCP = 6, UDP = 17) */
|
||||
SFLIPv4 local_ip; /* local IP address */
|
||||
SFLIPv4 remote_ip; /* remote IP address */
|
||||
uint32_t local_port; /* TCP/UDP local port number or equivalent */
|
||||
uint32_t remote_port; /* TCP/UDP remote port number of equivalent */
|
||||
} SFLExtended_socket_ipv4;
|
||||
|
||||
#define XDRSIZ_SFLEXTENDED_SOCKET4 20
|
||||
|
||||
/* IPv6 Socket */
|
||||
/* opaque = flow_data; enterprise = 0; format = 2101 */
|
||||
typedef struct _SFLExtended_socket_ipv6 {
|
||||
uint32_t protocol; /* IP Protocol (e.g. TCP = 6, UDP = 17) */
|
||||
SFLIPv6 local_ip; /* local IP address */
|
||||
SFLIPv6 remote_ip; /* remote IP address */
|
||||
uint32_t local_port; /* TCP/UDP local port number or equivalent */
|
||||
uint32_t remote_port; /* TCP/UDP remote port number of equivalent */
|
||||
} SFLExtended_socket_ipv6;
|
||||
|
||||
#define XDRSIZ_SFLEXTENDED_SOCKET6 44
|
||||
|
||||
typedef enum {
|
||||
MEMCACHE_PROT_OTHER = 0,
|
||||
MEMCACHE_PROT_ASCII = 1,
|
||||
MEMCACHE_PROT_BINARY = 2,
|
||||
} SFLMemcache_prot;
|
||||
|
||||
typedef enum {
|
||||
MEMCACHE_CMD_OTHER = 0,
|
||||
MEMCACHE_CMD_SET = 1,
|
||||
MEMCACHE_CMD_ADD = 2,
|
||||
MEMCACHE_CMD_REPLACE = 3,
|
||||
MEMCACHE_CMD_APPEND = 4,
|
||||
MEMCACHE_CMD_PREPEND = 5,
|
||||
MEMCACHE_CMD_CAS = 6,
|
||||
MEMCACHE_CMD_GET = 7,
|
||||
MEMCACHE_CMD_GETS = 8,
|
||||
MEMCACHE_CMD_INCR = 9,
|
||||
MEMCACHE_CMD_DECR = 10,
|
||||
MEMCACHE_CMD_DELETE = 11,
|
||||
MEMCACHE_CMD_STATS = 12,
|
||||
MEMCACHE_CMD_FLUSH = 13,
|
||||
MEMCACHE_CMD_VERSION = 14,
|
||||
MEMCACHE_CMD_QUIT = 15,
|
||||
MEMCACHE_CMD_TOUCH = 16,
|
||||
} SFLMemcache_cmd;
|
||||
|
||||
enum SFLMemcache_operation_status {
|
||||
MEMCACHE_OP_UNKNOWN = 0,
|
||||
MEMCACHE_OP_OK = 1,
|
||||
MEMCACHE_OP_ERROR = 2,
|
||||
MEMCACHE_OP_CLIENT_ERROR = 3,
|
||||
MEMCACHE_OP_SERVER_ERROR = 4,
|
||||
MEMCACHE_OP_STORED = 5,
|
||||
MEMCACHE_OP_NOT_STORED = 6,
|
||||
MEMCACHE_OP_EXISTS = 7,
|
||||
MEMCACHE_OP_NOT_FOUND = 8,
|
||||
MEMCACHE_OP_DELETED = 9,
|
||||
};
|
||||
|
||||
#define SFL_MAX_MEMCACHE_KEY 255
|
||||
|
||||
typedef struct _SFLSampled_memcache {
|
||||
uint32_t protocol; /* SFLMemcache_prot */
|
||||
uint32_t command; /* SFLMemcache_cmd */
|
||||
SFLString key; /* up to 255 chars */
|
||||
uint32_t nkeys;
|
||||
uint32_t value_bytes;
|
||||
uint32_t duration_uS;
|
||||
uint32_t status; /* SFLMemcache_operation_status */
|
||||
} SFLSampled_memcache;
|
||||
|
||||
typedef enum {
|
||||
SFHTTP_OTHER = 0,
|
||||
SFHTTP_OPTIONS = 1,
|
||||
SFHTTP_GET = 2,
|
||||
SFHTTP_HEAD = 3,
|
||||
SFHTTP_POST = 4,
|
||||
SFHTTP_PUT = 5,
|
||||
SFHTTP_DELETE = 6,
|
||||
SFHTTP_TRACE = 7,
|
||||
SFHTTP_CONNECT = 8,
|
||||
} SFLHTTP_method;
|
||||
|
||||
#define SFL_MAX_HTTP_URI 255
|
||||
#define SFL_MAX_HTTP_HOST 64
|
||||
#define SFL_MAX_HTTP_REFERRER 255
|
||||
#define SFL_MAX_HTTP_USERAGENT 128
|
||||
#define SFL_MAX_HTTP_XFF 64
|
||||
#define SFL_MAX_HTTP_AUTHUSER 32
|
||||
#define SFL_MAX_HTTP_MIMETYPE 64
|
||||
|
||||
typedef struct _SFLSampled_http {
|
||||
SFLHTTP_method method;
|
||||
uint32_t protocol; /* 1.1=1001 */
|
||||
SFLString uri; /* URI exactly as it came from the client (up to 255 bytes) */
|
||||
SFLString host; /* Host value from request header (<= 64 bytes) */
|
||||
SFLString referrer; /* Referer value from request header (<=255 bytes) */
|
||||
SFLString useragent; /* User-Agent value from request header (<= 128 bytes)*/
|
||||
SFLString xff; /* X-Forwarded-For value from request header (<= 64 bytes)*/
|
||||
SFLString authuser; /* RFC 1413 identity of user (<=32 bytes)*/
|
||||
SFLString mimetype; /* Mime-Type (<=64 bytes) */
|
||||
uint64_t req_bytes; /* Content-Length of request */
|
||||
uint64_t resp_bytes; /* Content-Length of response */
|
||||
uint32_t uS; /* duration of the operation (microseconds) */
|
||||
uint32_t status; /* HTTP status code */
|
||||
} SFLSampled_http;
|
||||
|
||||
|
||||
typedef enum {
|
||||
SFLAPP_SUCCESS = 0,
|
||||
SFLAPP_OTHER = 1,
|
||||
SFLAPP_TIMEOUT = 2,
|
||||
SFLAPP_INTERNAL_ERROR = 3,
|
||||
SFLAPP_BAD_REQUEST = 4,
|
||||
SFLAPP_FORBIDDEN = 5,
|
||||
SFLAPP_TOO_LARGE = 6,
|
||||
SFLAPP_NOT_IMPLEMENTED = 7,
|
||||
SFLAPP_NOT_FOUND = 8,
|
||||
SFLAPP_UNAVAILABLE = 9,
|
||||
SFLAPP_UNAUTHORIZED = 10,
|
||||
} EnumSFLAPPStatus;
|
||||
|
||||
static const char* SFL_APP_STATUS_names[] = { "SUCCESS", "OTHER", "TIMEOUT",
|
||||
"INTERNAL_ERROR", "BAD_REQUEST", "FORBIDDEN",
|
||||
"TOO_LARGE", "NOT_IMPLEMENTED", "NOT_FOUND",
|
||||
"UNAVAILABLE", "UNATHORIZED" };
|
||||
|
||||
/* Operation context */
|
||||
typedef struct {
|
||||
SFLString application;
|
||||
SFLString operation; /* type of operation (e.g. authorization, payment) */
|
||||
SFLString attributes; /* specific attributes associated operation */
|
||||
} SFLSampled_APP_CTXT;
|
||||
|
||||
#define SFLAPP_MAX_APPLICATION_LEN 32
|
||||
#define SFLAPP_MAX_OPERATION_LEN 32
|
||||
#define SFLAPP_MAX_ATTRIBUTES_LEN 255
|
||||
|
||||
/* Sampled Enterprise Operation */
|
||||
/* opaque = flow_data; enterprise = 0; format = 2202 */
|
||||
typedef struct {
|
||||
SFLSampled_APP_CTXT context; /* attributes describing the operation */
|
||||
SFLString status_descr; /* additional text describing status (e.g. "unknown client") */
|
||||
uint64_t req_bytes; /* size of request body (exclude headers) */
|
||||
uint64_t resp_bytes; /* size of response body (exclude headers) */
|
||||
uint32_t duration_uS; /* duration of the operation (microseconds) */
|
||||
EnumSFLAPPStatus status; /* status code */
|
||||
} SFLSampled_APP;
|
||||
|
||||
#define SFLAPP_MAX_STATUS_LEN 32
|
||||
|
||||
typedef struct {
|
||||
SFLString actor;
|
||||
} SFLSampled_APP_ACTOR;
|
||||
|
||||
#define SFLAPP_MAX_ACTOR_LEN 64
|
||||
|
||||
typedef struct _SFLExtended_vni {
|
||||
uint32_t vni; /* virtual network identifier */
|
||||
} SFLExtended_vni;
|
||||
|
||||
typedef struct _SFLExtended_decap {
|
||||
uint32_t innerHeaderOffset;
|
||||
} SFLExtended_decap;
|
||||
|
||||
enum SFLFlow_type_tag {
|
||||
/* enterprise = 0, format = ... */
|
||||
SFLFLOW_HEADER = 1, /* Packet headers are sampled */
|
||||
SFLFLOW_ETHERNET = 2, /* MAC layer information */
|
||||
SFLFLOW_IPV4 = 3, /* IP version 4 data */
|
||||
SFLFLOW_IPV6 = 4, /* IP version 6 data */
|
||||
SFLFLOW_EX_SWITCH = 1001, /* Extended switch information */
|
||||
SFLFLOW_EX_ROUTER = 1002, /* Extended router information */
|
||||
SFLFLOW_EX_GATEWAY = 1003, /* Extended gateway router information */
|
||||
SFLFLOW_EX_USER = 1004, /* Extended TACAS/RADIUS user information */
|
||||
SFLFLOW_EX_URL = 1005, /* Extended URL information */
|
||||
SFLFLOW_EX_MPLS = 1006, /* Extended MPLS information */
|
||||
SFLFLOW_EX_NAT = 1007, /* Extended NAT information */
|
||||
SFLFLOW_EX_MPLS_TUNNEL = 1008, /* additional MPLS information */
|
||||
SFLFLOW_EX_MPLS_VC = 1009,
|
||||
SFLFLOW_EX_MPLS_FTN = 1010,
|
||||
SFLFLOW_EX_MPLS_LDP_FEC = 1011,
|
||||
SFLFLOW_EX_VLAN_TUNNEL = 1012, /* VLAN stack */
|
||||
SFLFLOW_EX_80211_PAYLOAD = 1013,
|
||||
SFLFLOW_EX_80211_RX = 1014,
|
||||
SFLFLOW_EX_80211_TX = 1015,
|
||||
SFLFLOW_EX_AGGREGATION = 1016,
|
||||
SFLFLOW_EX_NAT_PORT = 1020, /* Extended NAT port information */
|
||||
SFLFLOW_EX_L2_TUNNEL_OUT = 1021, /* http://sflow.org/sflow_tunnels.txt */
|
||||
SFLFLOW_EX_L2_TUNNEL_IN = 1022,
|
||||
SFLFLOW_EX_IPV4_TUNNEL_OUT = 1023,
|
||||
SFLFLOW_EX_IPV4_TUNNEL_IN = 1024,
|
||||
SFLFLOW_EX_IPV6_TUNNEL_OUT = 1025,
|
||||
SFLFLOW_EX_IPV6_TUNNEL_IN = 1026,
|
||||
SFLFLOW_EX_DECAP_OUT = 1027,
|
||||
SFLFLOW_EX_DECAP_IN = 1028,
|
||||
SFLFLOW_EX_VNI_OUT = 1029,
|
||||
SFLFLOW_EX_VNI_IN = 1030,
|
||||
SFLFLOW_EX_SOCKET4 = 2100,
|
||||
SFLFLOW_EX_SOCKET6 = 2101,
|
||||
SFLFLOW_EX_PROXYSOCKET4 = 2102,
|
||||
SFLFLOW_EX_PROXYSOCKET6 = 2103,
|
||||
SFLFLOW_MEMCACHE = 2200,
|
||||
SFLFLOW_HTTP = 2201,
|
||||
SFLFLOW_APP = 2202, /* transaction sample */
|
||||
SFLFLOW_APP_CTXT = 2203, /* enclosing server context */
|
||||
SFLFLOW_APP_ACTOR_INIT = 2204, /* initiator */
|
||||
SFLFLOW_APP_ACTOR_TGT = 2205, /* target */
|
||||
SFLFLOW_HTTP2 = 2206,
|
||||
};
|
||||
|
||||
typedef union _SFLFlow_type {
|
||||
SFLSampled_header header;
|
||||
SFLSampled_ethernet ethernet;
|
||||
SFLSampled_ipv4 ipv4;
|
||||
SFLSampled_ipv6 ipv6;
|
||||
SFLSampled_memcache memcache;
|
||||
SFLSampled_http http;
|
||||
SFLSampled_APP app;
|
||||
SFLSampled_APP_CTXT appCtxt;
|
||||
SFLSampled_APP_ACTOR appActor;
|
||||
SFLExtended_switch sw;
|
||||
SFLExtended_router router;
|
||||
SFLExtended_gateway gateway;
|
||||
SFLExtended_user user;
|
||||
SFLExtended_url url;
|
||||
SFLExtended_mpls mpls;
|
||||
SFLExtended_nat nat;
|
||||
SFLExtended_nat_port nat_port;
|
||||
SFLExtended_mpls_tunnel mpls_tunnel;
|
||||
SFLExtended_mpls_vc mpls_vc;
|
||||
SFLExtended_mpls_FTN mpls_ftn;
|
||||
SFLExtended_mpls_LDP_FEC mpls_ldp_fec;
|
||||
SFLExtended_vlan_tunnel vlan_tunnel;
|
||||
SFLExtended_wifi_payload wifi_payload;
|
||||
SFLExtended_wifi_rx wifi_rx;
|
||||
SFLExtended_wifi_tx wifi_tx;
|
||||
SFLExtended_aggregation aggregation;
|
||||
SFLExtended_socket_ipv4 socket4;
|
||||
SFLExtended_socket_ipv6 socket6;
|
||||
SFLExtended_vni tunnel_vni;
|
||||
SFLExtended_decap tunnel_decap;
|
||||
} SFLFlow_type;
|
||||
|
||||
typedef struct _SFLFlow_sample_element {
|
||||
struct _SFLFlow_sample_element* nxt;
|
||||
uint32_t tag; /* SFLFlow_type_tag */
|
||||
uint32_t length;
|
||||
SFLFlow_type flowType;
|
||||
} SFLFlow_sample_element;
|
||||
|
||||
enum SFL_sample_tag {
|
||||
SFLFLOW_SAMPLE = 1, /* enterprise = 0 : format = 1 */
|
||||
SFLCOUNTERS_SAMPLE = 2, /* enterprise = 0 : format = 2 */
|
||||
SFLFLOW_SAMPLE_EXPANDED = 3, /* enterprise = 0 : format = 3 */
|
||||
SFLCOUNTERS_SAMPLE_EXPANDED = 4 /* enterprise = 0 : format = 4 */
|
||||
};
|
||||
|
||||
typedef struct _SFLFlow_Pdu {
|
||||
struct _SFLFlow_Pdu* nxt;
|
||||
uint32_t num_elements;
|
||||
SFLFlow_sample_element* elements;
|
||||
} SFLFlow_Pdu;
|
||||
|
||||
|
||||
/* Format of a single flow sample */
|
||||
|
||||
typedef struct _SFLFlow_sample {
|
||||
/* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 1 */
|
||||
/* uint32_t length; */
|
||||
uint32_t sequence_number; /* Incremented with each flow sample
|
||||
generated */
|
||||
uint32_t source_id; /* fsSourceId */
|
||||
uint32_t sampling_rate; /* fsPacketSamplingRate */
|
||||
uint32_t sample_pool; /* Total number of packets that could have been
|
||||
sampled (i.e. packets skipped by sampling
|
||||
process + total number of samples) */
|
||||
uint32_t drops; /* Number of times a packet was dropped due to
|
||||
lack of resources */
|
||||
uint32_t input; /* SNMP ifIndex of input interface.
|
||||
0 if interface is not known. */
|
||||
uint32_t output; /* SNMP ifIndex of output interface,
|
||||
0 if interface is not known.
|
||||
Set most significant bit to indicate
|
||||
multiple destination interfaces
|
||||
(i.e. in case of broadcast or multicast)
|
||||
and set lower order bits to indicate
|
||||
number of destination interfaces.
|
||||
Examples:
|
||||
0x00000002 indicates ifIndex = 2
|
||||
0x00000000 ifIndex unknown.
|
||||
0x80000007 indicates a packet sent
|
||||
to 7 interfaces.
|
||||
0x80000000 indicates a packet sent to
|
||||
an unknown number of
|
||||
interfaces greater than 1.*/
|
||||
uint32_t num_elements;
|
||||
SFLFlow_sample_element* elements;
|
||||
} SFLFlow_sample;
|
||||
|
||||
/* same thing, but the expanded version (for full 32-bit ifIndex numbers) */
|
||||
|
||||
typedef struct _SFLFlow_sample_expanded {
|
||||
/* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 1 */
|
||||
/* uint32_t length; */
|
||||
uint32_t sequence_number; /* Incremented with each flow sample
|
||||
generated */
|
||||
uint32_t ds_class; /* EXPANDED */
|
||||
uint32_t ds_index; /* EXPANDED */
|
||||
uint32_t sampling_rate; /* fsPacketSamplingRate */
|
||||
uint32_t sample_pool; /* Total number of packets that could have been
|
||||
sampled (i.e. packets skipped by sampling
|
||||
process + total number of samples) */
|
||||
uint32_t drops; /* Number of times a packet was dropped due to
|
||||
lack of resources */
|
||||
uint32_t inputFormat; /* EXPANDED */
|
||||
uint32_t input; /* SNMP ifIndex of input interface.
|
||||
0 if interface is not known. */
|
||||
uint32_t outputFormat; /* EXPANDED */
|
||||
uint32_t output; /* SNMP ifIndex of output interface,
|
||||
0 if interface is not known. */
|
||||
uint32_t num_elements;
|
||||
SFLFlow_sample_element* elements;
|
||||
} SFLFlow_sample_expanded;
|
||||
|
||||
/* Counter types */
|
||||
|
||||
/* Generic interface counters - see RFC 1573, 2233 */
|
||||
|
||||
typedef struct _SFLIf_counters {
|
||||
uint32_t ifIndex;
|
||||
uint32_t ifType;
|
||||
uint64_t ifSpeed;
|
||||
uint32_t ifDirection; /* Derived from MAU MIB (RFC 2668)
|
||||
0 = unknown, 1 = full-duplex,
|
||||
2 = half-duplex, 3 = in, 4 = out */
|
||||
uint32_t ifStatus; /* bit field with the following bits assigned:
|
||||
bit 0 = ifAdminStatus (0 = down, 1 = up)
|
||||
bit 1 = ifOperStatus (0 = down, 1 = up) */
|
||||
uint64_t ifInOctets;
|
||||
uint32_t ifInUcastPkts;
|
||||
uint32_t ifInMulticastPkts;
|
||||
uint32_t ifInBroadcastPkts;
|
||||
uint32_t ifInDiscards;
|
||||
uint32_t ifInErrors;
|
||||
uint32_t ifInUnknownProtos;
|
||||
uint64_t ifOutOctets;
|
||||
uint32_t ifOutUcastPkts;
|
||||
uint32_t ifOutMulticastPkts;
|
||||
uint32_t ifOutBroadcastPkts;
|
||||
uint32_t ifOutDiscards;
|
||||
uint32_t ifOutErrors;
|
||||
uint32_t ifPromiscuousMode;
|
||||
} SFLIf_counters;
|
||||
|
||||
/* Ethernet interface counters - see RFC 2358 */
|
||||
typedef struct _SFLEthernet_counters {
|
||||
uint32_t dot3StatsAlignmentErrors;
|
||||
uint32_t dot3StatsFCSErrors;
|
||||
uint32_t dot3StatsSingleCollisionFrames;
|
||||
uint32_t dot3StatsMultipleCollisionFrames;
|
||||
uint32_t dot3StatsSQETestErrors;
|
||||
uint32_t dot3StatsDeferredTransmissions;
|
||||
uint32_t dot3StatsLateCollisions;
|
||||
uint32_t dot3StatsExcessiveCollisions;
|
||||
uint32_t dot3StatsInternalMacTransmitErrors;
|
||||
uint32_t dot3StatsCarrierSenseErrors;
|
||||
uint32_t dot3StatsFrameTooLongs;
|
||||
uint32_t dot3StatsInternalMacReceiveErrors;
|
||||
uint32_t dot3StatsSymbolErrors;
|
||||
} SFLEthernet_counters;
|
||||
|
||||
/* Token ring counters - see RFC 1748 */
|
||||
|
||||
typedef struct _SFLTokenring_counters {
|
||||
uint32_t dot5StatsLineErrors;
|
||||
uint32_t dot5StatsBurstErrors;
|
||||
uint32_t dot5StatsACErrors;
|
||||
uint32_t dot5StatsAbortTransErrors;
|
||||
uint32_t dot5StatsInternalErrors;
|
||||
uint32_t dot5StatsLostFrameErrors;
|
||||
uint32_t dot5StatsReceiveCongestions;
|
||||
uint32_t dot5StatsFrameCopiedErrors;
|
||||
uint32_t dot5StatsTokenErrors;
|
||||
uint32_t dot5StatsSoftErrors;
|
||||
uint32_t dot5StatsHardErrors;
|
||||
uint32_t dot5StatsSignalLoss;
|
||||
uint32_t dot5StatsTransmitBeacons;
|
||||
uint32_t dot5StatsRecoverys;
|
||||
uint32_t dot5StatsLobeWires;
|
||||
uint32_t dot5StatsRemoves;
|
||||
uint32_t dot5StatsSingles;
|
||||
uint32_t dot5StatsFreqErrors;
|
||||
} SFLTokenring_counters;
|
||||
|
||||
/* 100 BaseVG interface counters - see RFC 2020 */
|
||||
|
||||
typedef struct _SFLVg_counters {
|
||||
uint32_t dot12InHighPriorityFrames;
|
||||
uint64_t dot12InHighPriorityOctets;
|
||||
uint32_t dot12InNormPriorityFrames;
|
||||
uint64_t dot12InNormPriorityOctets;
|
||||
uint32_t dot12InIPMErrors;
|
||||
uint32_t dot12InOversizeFrameErrors;
|
||||
uint32_t dot12InDataErrors;
|
||||
uint32_t dot12InNullAddressedFrames;
|
||||
uint32_t dot12OutHighPriorityFrames;
|
||||
uint64_t dot12OutHighPriorityOctets;
|
||||
uint32_t dot12TransitionIntoTrainings;
|
||||
uint64_t dot12HCInHighPriorityOctets;
|
||||
uint64_t dot12HCInNormPriorityOctets;
|
||||
uint64_t dot12HCOutHighPriorityOctets;
|
||||
} SFLVg_counters;
|
||||
|
||||
typedef struct _SFLVlan_counters {
|
||||
uint32_t vlan_id;
|
||||
uint64_t octets;
|
||||
uint32_t ucastPkts;
|
||||
uint32_t multicastPkts;
|
||||
uint32_t broadcastPkts;
|
||||
uint32_t discards;
|
||||
} SFLVlan_counters;
|
||||
|
||||
typedef struct _SFLWifi_counters {
|
||||
uint32_t dot11TransmittedFragmentCount;
|
||||
uint32_t dot11MulticastTransmittedFrameCount;
|
||||
uint32_t dot11FailedCount;
|
||||
uint32_t dot11RetryCount;
|
||||
uint32_t dot11MultipleRetryCount;
|
||||
uint32_t dot11FrameDuplicateCount;
|
||||
uint32_t dot11RTSSuccessCount;
|
||||
uint32_t dot11RTSFailureCount;
|
||||
uint32_t dot11ACKFailureCount;
|
||||
uint32_t dot11ReceivedFragmentCount;
|
||||
uint32_t dot11MulticastReceivedFrameCount;
|
||||
uint32_t dot11FCSErrorCount;
|
||||
uint32_t dot11TransmittedFrameCount;
|
||||
uint32_t dot11WEPUndecryptableCount;
|
||||
uint32_t dot11QoSDiscardedFragmentCount;
|
||||
uint32_t dot11AssociatedStationCount;
|
||||
uint32_t dot11QoSCFPollsReceivedCount;
|
||||
uint32_t dot11QoSCFPollsUnusedCount;
|
||||
uint32_t dot11QoSCFPollsUnusableCount;
|
||||
uint32_t dot11QoSCFPollsLostCount;
|
||||
} SFLWifi_counters;
|
||||
|
||||
/* Processor Information */
|
||||
/* opaque = counter_data; enterprise = 0; format = 1001 */
|
||||
|
||||
typedef struct _SFLProcessor_counters {
|
||||
uint32_t five_sec_cpu; /* 5 second average CPU utilization */
|
||||
uint32_t one_min_cpu; /* 1 minute average CPU utilization */
|
||||
uint32_t five_min_cpu; /* 5 minute average CPU utilization */
|
||||
uint64_t total_memory; /* total memory (in bytes) */
|
||||
uint64_t free_memory; /* free memory (in bytes) */
|
||||
} SFLProcessor_counters;
|
||||
|
||||
typedef struct _SFLRadio_counters {
|
||||
uint32_t elapsed_time; /* elapsed time in ms */
|
||||
uint32_t on_channel_time; /* time in ms spent on channel */
|
||||
uint32_t on_channel_busy_time; /* time in ms spent on channel and busy */
|
||||
} SFLRadio_counters;
|
||||
|
||||
/* host sflow */
|
||||
|
||||
enum SFLMachine_type {
|
||||
SFLMT_unknown = 0,
|
||||
SFLMT_other = 1,
|
||||
SFLMT_x86 = 2,
|
||||
SFLMT_x86_64 = 3,
|
||||
SFLMT_ia64 = 4,
|
||||
SFLMT_sparc = 5,
|
||||
SFLMT_alpha = 6,
|
||||
SFLMT_powerpc = 7,
|
||||
SFLMT_m68k = 8,
|
||||
SFLMT_mips = 9,
|
||||
SFLMT_arm = 10,
|
||||
SFLMT_hppa = 11,
|
||||
SFLMT_s390 = 12
|
||||
};
|
||||
|
||||
enum SFLOS_name {
|
||||
SFLOS_unknown = 0,
|
||||
SFLOS_other = 1,
|
||||
SFLOS_linux = 2,
|
||||
SFLOS_windows = 3,
|
||||
SFLOS_darwin = 4,
|
||||
SFLOS_hpux = 5,
|
||||
SFLOS_aix = 6,
|
||||
SFLOS_dragonfly = 7,
|
||||
SFLOS_freebsd = 8,
|
||||
SFLOS_netbsd = 9,
|
||||
SFLOS_openbsd = 10,
|
||||
SFLOS_osf = 11,
|
||||
SFLOS_solaris = 12
|
||||
};
|
||||
|
||||
typedef struct _SFLMacAddress {
|
||||
uint8_t mac[8];
|
||||
} SFLMacAddress;
|
||||
|
||||
typedef struct _SFLAdaptor {
|
||||
uint32_t ifIndex;
|
||||
uint32_t num_macs;
|
||||
SFLMacAddress macs[1];
|
||||
} SFLAdaptor;
|
||||
|
||||
typedef struct _SFLAdaptorList {
|
||||
uint32_t capacity;
|
||||
uint32_t num_adaptors;
|
||||
SFLAdaptor** adaptors;
|
||||
} SFLAdaptorList;
|
||||
|
||||
typedef struct _SFLHost_parent {
|
||||
uint32_t dsClass; /* sFlowDataSource class */
|
||||
uint32_t dsIndex; /* sFlowDataSource index */
|
||||
} SFLHost_parent;
|
||||
|
||||
|
||||
#define SFL_MAX_HOSTNAME_LEN 64
|
||||
#define SFL_MAX_OSRELEASE_LEN 32
|
||||
|
||||
typedef struct _SFLHostId {
|
||||
SFLString hostname;
|
||||
u_char uuid[16];
|
||||
uint32_t machine_type; /* enum SFLMachine_type */
|
||||
uint32_t os_name; /* enum SFLOS_name */
|
||||
SFLString os_release; /* max len 32 bytes */
|
||||
} SFLHostId;
|
||||
|
||||
typedef struct _SFLHost_nio_counters {
|
||||
uint64_t bytes_in;
|
||||
uint32_t pkts_in;
|
||||
uint32_t errs_in;
|
||||
uint32_t drops_in;
|
||||
uint64_t bytes_out;
|
||||
uint32_t pkts_out;
|
||||
uint32_t errs_out;
|
||||
uint32_t drops_out;
|
||||
} SFLHost_nio_counters;
|
||||
|
||||
typedef struct _SFLHost_cpu_counters {
|
||||
float load_one; /* 1 minute load avg. */
|
||||
float load_five; /* 5 minute load avg. */
|
||||
float load_fifteen; /* 15 minute load avg. */
|
||||
uint32_t proc_run; /* running threads */
|
||||
uint32_t proc_total; /* total threads */
|
||||
uint32_t cpu_num; /* # CPU cores */
|
||||
uint32_t cpu_speed; /* speed in MHz of CPU */
|
||||
uint32_t uptime; /* seconds since last reboot */
|
||||
uint32_t cpu_user; /* time executing in user mode processes (ms) */
|
||||
uint32_t cpu_nice; /* time executing niced processs (ms) */
|
||||
uint32_t cpu_system; /* time executing kernel mode processes (ms) */
|
||||
uint32_t cpu_idle; /* idle time (ms) */
|
||||
uint32_t cpu_wio; /* time waiting for I/O to complete (ms) */
|
||||
uint32_t cpu_intr; /* time servicing interrupts (ms) */
|
||||
uint32_t cpu_sintr; /* time servicing softirqs (ms) */
|
||||
uint32_t interrupts; /* interrupt count */
|
||||
uint32_t contexts; /* context switch count */
|
||||
} SFLHost_cpu_counters;
|
||||
|
||||
typedef struct _SFLHost_mem_counters {
|
||||
uint64_t mem_total; /* total bytes */
|
||||
uint64_t mem_free; /* free bytes */
|
||||
uint64_t mem_shared; /* shared bytes */
|
||||
uint64_t mem_buffers; /* buffers bytes */
|
||||
uint64_t mem_cached; /* cached bytes */
|
||||
uint64_t swap_total; /* swap total bytes */
|
||||
uint64_t swap_free; /* swap free bytes */
|
||||
uint32_t page_in; /* page in count */
|
||||
uint32_t page_out; /* page out count */
|
||||
uint32_t swap_in; /* swap in count */
|
||||
uint32_t swap_out; /* swap out count */
|
||||
} SFLHost_mem_counters;
|
||||
|
||||
typedef struct _SFLHost_dsk_counters {
|
||||
uint64_t disk_total;
|
||||
uint64_t disk_free;
|
||||
uint32_t part_max_used; /* as percent * 100, so 100==1% */
|
||||
uint32_t reads; /* reads issued */
|
||||
uint64_t bytes_read; /* bytes read */
|
||||
uint32_t read_time; /* read time (ms) */
|
||||
uint32_t writes; /* writes completed */
|
||||
uint64_t bytes_written; /* bytes written */
|
||||
uint32_t write_time; /* write time (ms) */
|
||||
} SFLHost_dsk_counters;
|
||||
|
||||
/* Virtual Node Statistics */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2100 */
|
||||
|
||||
typedef struct _SFLHost_vrt_node_counters {
|
||||
uint32_t mhz; /* expected CPU frequency */
|
||||
uint32_t cpus; /* the number of active CPUs */
|
||||
uint64_t memory; /* memory size in bytes */
|
||||
uint64_t memory_free; /* unassigned memory in bytes */
|
||||
uint32_t num_domains; /* number of active domains */
|
||||
} SFLHost_vrt_node_counters;
|
||||
|
||||
/* Virtual Domain Statistics */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2101 */
|
||||
|
||||
/* virDomainState imported from libvirt.h */
|
||||
enum SFLVirDomainState {
|
||||
SFL_VIR_DOMAIN_NOSTATE = 0, /* no state */
|
||||
SFL_VIR_DOMAIN_RUNNING = 1, /* the domain is running */
|
||||
SFL_VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource */
|
||||
SFL_VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user */
|
||||
SFL_VIR_DOMAIN_SHUTDOWN = 4, /* the domain is being shut down */
|
||||
SFL_VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off */
|
||||
SFL_VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */
|
||||
};
|
||||
|
||||
typedef struct _SFLHost_vrt_cpu_counters {
|
||||
uint32_t state; /* virtDomainState */
|
||||
uint32_t cpuTime; /* the CPU time used in mS */
|
||||
uint32_t cpuCount; /* number of virtual CPUs for the domain */
|
||||
} SFLHost_vrt_cpu_counters;
|
||||
|
||||
/* Virtual Domain Memory statistics */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2102 */
|
||||
|
||||
typedef struct _SFLHost_vrt_mem_counters {
|
||||
uint64_t memory; /* memory in bytes used by domain */
|
||||
uint64_t maxMemory; /* memory in bytes allowed */
|
||||
} SFLHost_vrt_mem_counters;
|
||||
|
||||
/* Virtual Domain Disk statistics */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2103 */
|
||||
|
||||
typedef struct _SFLHost_vrt_dsk_counters {
|
||||
uint64_t capacity; /* logical size in bytes */
|
||||
uint64_t allocation; /* current allocation in bytes */
|
||||
uint64_t available; /* remaining free bytes */
|
||||
uint32_t rd_req; /* number of read requests */
|
||||
uint64_t rd_bytes; /* number of read bytes */
|
||||
uint32_t wr_req; /* number of write requests */
|
||||
uint64_t wr_bytes; /* number of written bytes */
|
||||
uint32_t errs; /* read/write errors */
|
||||
} SFLHost_vrt_dsk_counters;
|
||||
|
||||
/* Virtual Domain Network statistics */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2104 */
|
||||
|
||||
typedef struct _SFLHost_vrt_nio_counters {
|
||||
uint64_t bytes_in;
|
||||
uint32_t pkts_in;
|
||||
uint32_t errs_in;
|
||||
uint32_t drops_in;
|
||||
uint64_t bytes_out;
|
||||
uint32_t pkts_out;
|
||||
uint32_t errs_out;
|
||||
uint32_t drops_out;
|
||||
} SFLHost_vrt_nio_counters;
|
||||
|
||||
/* NVML statistics */
|
||||
/* opaque = counter_data; enterprise = 5703, format=1 */
|
||||
typedef struct _SFLHost_gpu_nvml {
|
||||
uint32_t device_count; /* see nvmlGetDeviceCount */
|
||||
uint32_t processes; /* see nvmlDeviceGetComputeRunningProcesses */
|
||||
uint32_t gpu_time; /* total milliseconds in which one or more kernels was executing on GPU */
|
||||
uint32_t mem_time; /* total milliseconds during which global device memory was being
|
||||
read/written */
|
||||
uint64_t mem_total; /* bytes. see nvmlDeviceGetMemoryInfo */
|
||||
uint64_t mem_free; /* bytes. see nvmlDeviceGetMemoryInfo */
|
||||
uint32_t ecc_errors; /* see nvmlDeviceGetTotalEccErrors */
|
||||
uint32_t energy; /* mJ. see nvmlDeviceGetPowerUsage */
|
||||
uint32_t temperature; /* C. maximum across devices - see nvmlDeviceGetTemperature */
|
||||
uint32_t fan_speed; /* %. maximum across devices - see nvmlDeviceGetFanSpeed */
|
||||
} SFLHost_gpu_nvml;
|
||||
|
||||
typedef struct _SFLMemcache_counters {
|
||||
uint32_t uptime; /* not in 2204 */
|
||||
uint32_t rusage_user; /* not in 2204 */
|
||||
uint32_t rusage_system; /* not in 2204 */
|
||||
uint32_t cmd_get; /* not in 2204 */
|
||||
uint32_t accepting_conns; /* not in 2204 */
|
||||
uint32_t cmd_set;
|
||||
uint32_t cmd_touch; /* added for 2204 */
|
||||
uint32_t cmd_flush;
|
||||
uint32_t get_hits;
|
||||
uint32_t get_misses;
|
||||
uint32_t delete_hits;
|
||||
uint32_t delete_misses;
|
||||
uint32_t incr_hits;
|
||||
uint32_t incr_misses;
|
||||
uint32_t decr_hits;
|
||||
uint32_t decr_misses;
|
||||
uint32_t cas_hits;
|
||||
uint32_t cas_misses;
|
||||
uint32_t cas_badval;
|
||||
uint32_t auth_cmds;
|
||||
uint32_t auth_errors;
|
||||
uint32_t threads;
|
||||
uint32_t conn_yields;
|
||||
uint32_t listen_disabled_num;
|
||||
uint32_t curr_connections;
|
||||
uint32_t rejected_connections; /* added for 2204 */
|
||||
uint32_t total_connections;
|
||||
uint32_t connection_structures;
|
||||
uint32_t evictions;
|
||||
uint32_t reclaimed; /* added for 2204 */
|
||||
uint32_t curr_items;
|
||||
uint32_t total_items;
|
||||
uint64_t bytes_read;
|
||||
uint64_t bytes_written;
|
||||
uint64_t bytes;
|
||||
uint64_t limit_maxbytes; /* converted to 64-bit for structure 2204 */
|
||||
} SFLMemcache_counters;
|
||||
|
||||
typedef struct _SFLHTTP_counters {
|
||||
uint32_t method_option_count;
|
||||
uint32_t method_get_count;
|
||||
uint32_t method_head_count;
|
||||
uint32_t method_post_count;
|
||||
uint32_t method_put_count;
|
||||
uint32_t method_delete_count;
|
||||
uint32_t method_trace_count;
|
||||
uint32_t methd_connect_count;
|
||||
uint32_t method_other_count;
|
||||
uint32_t status_1XX_count;
|
||||
uint32_t status_2XX_count;
|
||||
uint32_t status_3XX_count;
|
||||
uint32_t status_4XX_count;
|
||||
uint32_t status_5XX_count;
|
||||
uint32_t status_other_count;
|
||||
} SFLHTTP_counters;
|
||||
|
||||
|
||||
/* Enterprise counters */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2202 */
|
||||
typedef struct _SFLAPP_counters {
|
||||
SFLString application;
|
||||
uint32_t status_OK;
|
||||
uint32_t errors_OTHER;
|
||||
uint32_t errors_TIMEOUT;
|
||||
uint32_t errors_INTERNAL_ERROR;
|
||||
uint32_t errors_BAD_REQUEST;
|
||||
uint32_t errors_FORBIDDEN;
|
||||
uint32_t errors_TOO_LARGE;
|
||||
uint32_t errors_NOT_IMPLEMENTED;
|
||||
uint32_t errors_NOT_FOUND;
|
||||
uint32_t errors_UNAVAILABLE;
|
||||
uint32_t errors_UNAUTHORIZED;
|
||||
} SFLAPP_counters;
|
||||
|
||||
/* Enterprise resource counters */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2203 */
|
||||
typedef struct {
|
||||
uint32_t user_time; /* in milliseconds */
|
||||
uint32_t system_time; /* in milliseconds */
|
||||
uint64_t mem_used;
|
||||
uint64_t mem_max;
|
||||
uint32_t fd_open;
|
||||
uint32_t fd_max;
|
||||
uint32_t conn_open;
|
||||
uint32_t conn_max;
|
||||
} SFLAPP_resources;
|
||||
|
||||
/* Enterprise application workers */
|
||||
/* opaque = counter_data; enterprise = 0; format = 2206 */
|
||||
|
||||
typedef struct {
|
||||
uint32_t workers_active;
|
||||
uint32_t workers_idle;
|
||||
uint32_t workers_max;
|
||||
uint32_t req_delayed;
|
||||
uint32_t req_dropped;
|
||||
} SFLAPP_workers;
|
||||
|
||||
typedef struct _SFLJVM_ID {
|
||||
SFLString vm_name;
|
||||
SFLString vm_vendor;
|
||||
SFLString vm_version;
|
||||
} SFLJVM_ID;
|
||||
|
||||
#define SFLJVM_MAX_VMNAME_LEN 64
|
||||
#define SFLJVM_MAX_VENDOR_LEN 32
|
||||
#define SFLJVM_MAX_VERSION_LEN 32
|
||||
|
||||
typedef struct _SFLJMX_counters {
|
||||
uint64_t hmem_initial;
|
||||
uint64_t hmem_used;
|
||||
uint64_t hmem_committed;
|
||||
uint64_t hmem_max;
|
||||
uint64_t nhmem_initial;
|
||||
uint64_t nhmem_used;
|
||||
uint64_t nhmem_committed;
|
||||
uint64_t nhmem_max;
|
||||
uint32_t gc_count;
|
||||
uint32_t gc_ms;
|
||||
uint32_t cls_loaded;
|
||||
uint32_t cls_total;
|
||||
uint32_t cls_unloaded;
|
||||
uint32_t comp_ms;
|
||||
uint32_t thread_live;
|
||||
uint32_t thread_daemon;
|
||||
uint32_t thread_started;
|
||||
uint32_t fds_open;
|
||||
uint32_t fds_max;
|
||||
} SFLJMX_counters;
|
||||
|
||||
#define XDRSIZ_JMX_COUNTERS 108
|
||||
|
||||
typedef struct _SFLVdi_counters {
|
||||
uint32_t sessions_current; /* number of current sessions */
|
||||
uint32_t sessions_total; /* total sessions started */
|
||||
uint32_t sessions_duration; /* cumulative session time (in seconds)
|
||||
across all sessions, such that average
|
||||
session duration = sessions_duration
|
||||
/ sessions_total */
|
||||
uint32_t rx_bytes; /* total bytes received */
|
||||
uint32_t tx_bytes; /* total bytes sent */
|
||||
uint32_t rx_packets; /* total packet received */
|
||||
uint32_t tx_packets; /* total packets sent */
|
||||
uint32_t rx_packets_lost; /* total received packets lost */
|
||||
uint32_t tx_packets_lost; /* total sent packets lost */
|
||||
uint32_t rtt_min_ms; /* minimum round trip latency with client
|
||||
across all current sessions
|
||||
measured in milliseconds */
|
||||
uint32_t rtt_max_ms; /* maximum round trip latency with client
|
||||
across all current sessions
|
||||
measured in millisecond */
|
||||
uint32_t rtt_avg_ms; /* average round trip latency with client
|
||||
across all current sessions
|
||||
measured in milliseconds */
|
||||
uint32_t audio_rx_bytes; /* total bytes of audio data received */
|
||||
uint32_t audio_tx_bytes; /* total bytes of audio data sent */
|
||||
uint32_t audio_tx_limit; /* administrative limit on audio transmission
|
||||
bandwidth (in bits per second) */
|
||||
uint32_t img_rx_bytes; /* total bytes of imaging data recieved */
|
||||
uint32_t img_tx_bytes; /* total bytes of imaging data sent */
|
||||
uint32_t img_frames; /* total image frames encoded */
|
||||
uint32_t img_qual_min; /* minimum image encoding quality across
|
||||
current sessions, on a scale of 0 to 100 */
|
||||
uint32_t img_qual_max; /* best image encoding quality across
|
||||
current sessions, on a scale of 0 to 100 */
|
||||
uint32_t img_qual_avg; /* average image encoding quality across
|
||||
current sessions, on a scale of 0 to 100 */
|
||||
uint32_t usb_rx_bytes; /* total bytes of usb data received */
|
||||
uint32_t usb_tx_bytes; /* total bytes of usb data sent */
|
||||
} SFLVdi_counters;
|
||||
|
||||
/* LAG Port Statistics - see IEEE8023-LAG-MIB */
|
||||
/* 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 XDRSIZ_LACP_COUNTERS 56
|
||||
|
||||
/* port name */
|
||||
/* opaque = counter_data; enterprise = 0; format = 1005 */
|
||||
typedef struct {
|
||||
SFLString portName;
|
||||
} SFLPortName;
|
||||
|
||||
#define SFL_MAX_PORTNAME_LEN 255
|
||||
|
||||
/* Counters data */
|
||||
|
||||
enum SFLCounters_type_tag {
|
||||
/* enterprise = 0, format = ... */
|
||||
SFLCOUNTERS_GENERIC = 1,
|
||||
SFLCOUNTERS_ETHERNET = 2,
|
||||
SFLCOUNTERS_TOKENRING = 3,
|
||||
SFLCOUNTERS_VG = 4,
|
||||
SFLCOUNTERS_VLAN = 5,
|
||||
SFLCOUNTERS_80211 = 6,
|
||||
SFLCOUNTERS_LACP = 7,
|
||||
SFLCOUNTERS_PROCESSOR = 1001,
|
||||
SFLCOUNTERS_RADIO = 1002,
|
||||
SFLCOUNTERS_PORTNAME = 1005,
|
||||
SFLCOUNTERS_HOST_HID = 2000, /* host id */
|
||||
SFLCOUNTERS_ADAPTORS = 2001, /* host adaptors */
|
||||
SFLCOUNTERS_HOST_PAR = 2002, /* host parent */
|
||||
SFLCOUNTERS_HOST_CPU = 2003, /* host cpu */
|
||||
SFLCOUNTERS_HOST_MEM = 2004, /* host memory */
|
||||
SFLCOUNTERS_HOST_DSK = 2005, /* host storage I/O */
|
||||
SFLCOUNTERS_HOST_NIO = 2006, /* host network I/O */
|
||||
SFLCOUNTERS_HOST_VRT_NODE = 2100, /* host virt node */
|
||||
SFLCOUNTERS_HOST_VRT_CPU = 2101, /* host virt cpu */
|
||||
SFLCOUNTERS_HOST_VRT_MEM = 2102, /* host virt mem */
|
||||
SFLCOUNTERS_HOST_VRT_DSK = 2103, /* host virt storage */
|
||||
SFLCOUNTERS_HOST_VRT_NIO = 2104, /* host virt network I/O */
|
||||
SFLCOUNTERS_JVM = 2105, /* java runtime */
|
||||
SFLCOUNTERS_JMX = 2106, /* java JMX stats */
|
||||
SFLCOUNTERS_MEMCACHE = 2200, /* memcached (deprecated) */
|
||||
SFLCOUNTERS_HTTP = 2201, /* http */
|
||||
SFLCOUNTERS_APP = 2202,
|
||||
SFLCOUNTERS_APP_RESOURCE = 2203,
|
||||
SFLCOUNTERS_MEMCACHE2 = 2204, /* memcached */
|
||||
SFLCOUNTERS_VDI = 2205,
|
||||
SFLCOUNTERS_APP_WORKERS = 2206,
|
||||
SFLCOUNTERS_HOST_GPU_NVML = (5703 << 12) + 1, /* = 23359489 */
|
||||
};
|
||||
|
||||
typedef union _SFLCounters_type {
|
||||
SFLIf_counters generic;
|
||||
SFLEthernet_counters ethernet;
|
||||
SFLTokenring_counters tokenring;
|
||||
SFLVg_counters vg;
|
||||
SFLVlan_counters vlan;
|
||||
SFLWifi_counters wifi;
|
||||
SFLProcessor_counters processor;
|
||||
SFLRadio_counters radio;
|
||||
SFLHostId hostId;
|
||||
SFLAdaptorList* adaptors;
|
||||
SFLHost_parent host_par;
|
||||
SFLHost_cpu_counters host_cpu;
|
||||
SFLHost_mem_counters host_mem;
|
||||
SFLHost_dsk_counters host_dsk;
|
||||
SFLHost_nio_counters host_nio;
|
||||
SFLHost_vrt_node_counters host_vrt_node;
|
||||
SFLHost_vrt_cpu_counters host_vrt_cpu;
|
||||
SFLHost_vrt_mem_counters host_vrt_mem;
|
||||
SFLHost_vrt_dsk_counters host_vrt_dsk;
|
||||
SFLHost_vrt_nio_counters host_vrt_nio;
|
||||
SFLHost_gpu_nvml host_gpu_nvml;
|
||||
SFLMemcache_counters memcache;
|
||||
SFLHTTP_counters http;
|
||||
SFLJVM_ID jvm;
|
||||
SFLJMX_counters jmx;
|
||||
SFLAPP_counters app;
|
||||
SFLAPP_resources appResources;
|
||||
SFLAPP_workers appWorkers;
|
||||
SFLVdi_counters vdi;
|
||||
SFLLACP_counters lacp;
|
||||
SFLPortName portName;
|
||||
} SFLCounters_type;
|
||||
|
||||
typedef struct _SFLCounters_sample_element {
|
||||
struct _SFLCounters_sample_element* nxt; /* linked list */
|
||||
uint32_t tag; /* SFLCounters_type_tag */
|
||||
uint32_t length;
|
||||
SFLCounters_type counterBlock;
|
||||
} SFLCounters_sample_element;
|
||||
|
||||
typedef struct _SFLCounters_sample {
|
||||
/* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 2 */
|
||||
/* uint32_t length; */
|
||||
uint32_t sequence_number; /* Incremented with each counters sample
|
||||
generated by this source_id */
|
||||
uint32_t source_id; /* fsSourceId */
|
||||
uint32_t num_elements;
|
||||
SFLCounters_sample_element* elements;
|
||||
} SFLCounters_sample;
|
||||
|
||||
/* same thing, but the expanded version, so ds_index can be a full 32 bits */
|
||||
typedef struct _SFLCounters_sample_expanded {
|
||||
/* uint32_t tag; */ /* SFL_sample_tag -- enterprise = 0 : format = 2 */
|
||||
/* uint32_t length; */
|
||||
uint32_t sequence_number; /* Incremented with each counters sample
|
||||
generated by this source_id */
|
||||
uint32_t ds_class; /* EXPANDED */
|
||||
uint32_t ds_index; /* EXPANDED */
|
||||
uint32_t num_elements;
|
||||
SFLCounters_sample_element* elements;
|
||||
} SFLCounters_sample_expanded;
|
||||
|
||||
#define SFLADD_ELEMENT(_sm, _el) \
|
||||
do { \
|
||||
(_el)->nxt = (_sm)->elements; \
|
||||
(_sm)->elements = (_el); \
|
||||
} while (0)
|
||||
|
||||
/* Format of a sample datagram */
|
||||
|
||||
enum SFLDatagram_version {
|
||||
SFLDATAGRAM_VERSION2 = 2,
|
||||
SFLDATAGRAM_VERSION4 = 4,
|
||||
SFLDATAGRAM_VERSION5 = 5
|
||||
};
|
||||
|
||||
typedef struct _SFLSample_datagram_hdr {
|
||||
uint32_t datagram_version; /* (enum SFLDatagram_version) = VERSION5 = 5 */
|
||||
SFLAddress agent_address; /* IP address of sampling agent */
|
||||
uint32_t sub_agent_id; /* Used to distinguishing between datagram
|
||||
streams from separate agent sub entities
|
||||
within an device. */
|
||||
uint32_t sequence_number; /* Incremented with each sample datagram
|
||||
generated */
|
||||
uint32_t uptime; /* Current time (in milliseconds since device
|
||||
last booted). Should be set as close to
|
||||
datagram transmission time as possible.*/
|
||||
uint32_t num_records; /* Number of tag-len-val flow/counter records to follow */
|
||||
} SFLSample_datagram_hdr;
|
||||
|
||||
#define SFL_MAX_DATAGRAM_SIZE 1500
|
||||
#define SFL_MIN_DATAGRAM_SIZE 200
|
||||
#define SFL_DEFAULT_DATAGRAM_SIZE 1400
|
||||
|
||||
#define SFL_DATA_PAD 400
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SFLOW_H */
|
|
@ -1,141 +1,147 @@
|
|||
#include <climits>
|
||||
#include <inttypes.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../libsflow/libsflow.h"
|
||||
#include "sflow_collector.h"
|
||||
|
||||
// sflowtool-3.32
|
||||
#include "sflow.h"
|
||||
// custom sFLOW data structures
|
||||
#include "sflow_data.h"
|
||||
|
||||
#include "../fast_library.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// UDP server
|
||||
#include <netinet/in.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../fast_library.h"
|
||||
|
||||
#include "../all_logcpp_libraries.h"
|
||||
|
||||
#ifdef ENABLE_LUA_HOOKS
|
||||
lua_State* sflow_lua_state = NULL;
|
||||
|
||||
bool sflow_lua_hooks_enabled = false;
|
||||
std::string sflow_lua_hooks_path = "/usr/src/fastnetmon/src/sflow_hooks.lua";
|
||||
#endif
|
||||
|
||||
// Ethertype of outer tag in QinQ
|
||||
uint32_t sflow_qinq_ethertype = 0x8100;
|
||||
|
||||
// Disable QinQ processing by default
|
||||
bool sflow_qinq_process = false;
|
||||
|
||||
// sFLOW v4 specification: http://www.sflow.org/rfc3176.txt
|
||||
|
||||
std::string plugin_name = "sflow";
|
||||
std::string plugin_log_prefix = plugin_name + ": ";
|
||||
|
||||
// Get logger from main program
|
||||
extern log4cpp::Category& logger;
|
||||
|
||||
#include "../simple_packet_parser_ng.h"
|
||||
|
||||
// Global configuration map
|
||||
extern std::map<std::string, std::string> configuration_map;
|
||||
|
||||
// Enable debug messages in log
|
||||
bool debug_sflow_parser = false;
|
||||
// Number of raw packets received without any errors
|
||||
uint64_t raw_udp_packets_received = 0;
|
||||
|
||||
uint32_t getData32(SFSample* sample);
|
||||
bool skipTLVRecord(SFSample* sample, uint32_t tag, uint32_t len);
|
||||
bool readFlowSample(SFSample* sample, int expanded);
|
||||
void readFlowSample_header(SFSample* sample);
|
||||
void decode_ipv4_protocol(SFSample* sample);
|
||||
void decode_ipv6_protocol(SFSample* sample);
|
||||
void print_simple_packet(simple_packet_t& packet);
|
||||
// Number of failed receives
|
||||
uint64_t udp_receive_errors = 0;
|
||||
|
||||
// sFLOW v4 specification: http://www.sflow.org/rfc3176.txt
|
||||
|
||||
std::string plugin_name = "sflow";
|
||||
std::string plugin_log_prefix = plugin_name + ": ";
|
||||
|
||||
uint64_t sflow_total_packets = 0;
|
||||
|
||||
// Incorrectly crafted sflow packets
|
||||
uint64_t sflow_bad_packets = 0;
|
||||
|
||||
// Number of flow samples, i.e. with packet headers
|
||||
uint64_t sflow_flow_samples = 0;
|
||||
|
||||
// Number of broken flow samples
|
||||
uint64_t sflow_bad_flow_samples = 0;
|
||||
|
||||
// Number of packets where we have padding at the end of packet
|
||||
uint64_t sflow_with_padding_at_the_end_of_packet = 0;
|
||||
|
||||
// Number of packets with padding inside flow sample
|
||||
uint64_t sflow_padding_flow_sample = 0;
|
||||
|
||||
// Number of packet headers from flow samples which could not be decoded correctly
|
||||
uint64_t sflow_parse_error_nested_header = 0;
|
||||
|
||||
// Number of counter samples, i.e. with port counters
|
||||
uint64_t sflow_counter_sample = 0;
|
||||
|
||||
uint64_t sflow_raw_packet_headers_total = 0;
|
||||
|
||||
// Number of records with extended information from routers
|
||||
uint64_t sflow_extended_router_data_records = 0;
|
||||
|
||||
// For switch data
|
||||
uint64_t sflow_extended_switch_data_records = 0;
|
||||
|
||||
// For gateway data
|
||||
uint64_t sflow_extended_gateway_data_records = 0;
|
||||
|
||||
// Prototypes
|
||||
|
||||
bool process_sflow_counter_sample(uint8_t* data_pointer,
|
||||
size_t data_length,
|
||||
bool expanded,
|
||||
const sflow_packet_header_unified_accessor& sflow_header_accessor);
|
||||
process_packet_pointer sflow_process_func_ptr = NULL;
|
||||
|
||||
// #include <sys/prctl.h>
|
||||
|
||||
void start_sflow_collector(std::string interface_for_binding, unsigned int sflow_port);
|
||||
|
||||
// Initialize sflow module, we need it for allocation per module structures
|
||||
void init_sflow_module() {
|
||||
}
|
||||
|
||||
// Deinitilize sflow module, we need it for deallocation module structures
|
||||
void deinit_sflow_module() {
|
||||
}
|
||||
|
||||
void start_sflow_collection(process_packet_pointer func_ptr) {
|
||||
std::string interface_for_binding = "0.0.0.0";
|
||||
std::string sflow_ports = "";
|
||||
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "plugin started";
|
||||
// prctl(PR_SET_NAME,"fastnetmon_sflow", 0, 0, 0);
|
||||
|
||||
sflow_process_func_ptr = func_ptr;
|
||||
|
||||
|
||||
std::string sflow_ports_string = "";
|
||||
|
||||
if (configuration_map.count("sflow_port") != 0) {
|
||||
sflow_ports = configuration_map["sflow_port"];
|
||||
sflow_ports_string = configuration_map["sflow_port"];
|
||||
}
|
||||
|
||||
if (configuration_map.count("sflow_host") != 0) {
|
||||
interface_for_binding = configuration_map["sflow_host"];
|
||||
std::vector<std::string> sflow_ports_for_listen;
|
||||
boost::split(sflow_ports_for_listen, sflow_ports_string, boost::is_any_of(","), boost::token_compress_on);
|
||||
|
||||
std::vector<unsigned int> sflow_ports;
|
||||
|
||||
for (auto port_string: sflow_ports_for_listen) {
|
||||
unsigned int sflow_port = convert_string_to_integer(port_string);
|
||||
|
||||
if (sflow_port == 0) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "Cannot parse port: " << port_string;
|
||||
continue;
|
||||
}
|
||||
|
||||
sflow_ports.push_back(sflow_port);
|
||||
}
|
||||
|
||||
if (configuration_map.count("sflow_qinq_process") != 0) {
|
||||
if (configuration_map["sflow_qinq_process"] == "on") {
|
||||
|
||||
sflow_qinq_process = true;
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "qinq processing enabled";
|
||||
|
||||
if (configuration_map.count("sflow_qinq_ethertype") != 0) {
|
||||
if (convert_hex_as_string_to_uint(configuration_map["sflow_qinq_ethertype"], sflow_qinq_ethertype)) {
|
||||
logger << log4cpp::Priority::WARN << plugin_log_prefix
|
||||
<< "can't parse value in sflow_qinq_ethertype variable";
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "disable qinq processing";
|
||||
sflow_qinq_process = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sflow_ports.size() == 0) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "Please specify least single port for sflow_port field!";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LUA_HOOKS
|
||||
if (configuration_map.count("sflow_lua_hooks_path") != 0) {
|
||||
sflow_lua_hooks_path = configuration_map["sflow_lua_hooks_path"];
|
||||
|
||||
sflow_lua_hooks_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LUA_HOOKS
|
||||
if (sflow_lua_hooks_enabled) {
|
||||
sflow_lua_state = init_lua_jit(sflow_lua_hooks_path);
|
||||
|
||||
if (sflow_lua_state == NULL) {
|
||||
sflow_lua_hooks_enabled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "We parsed "
|
||||
<< sflow_ports.size() << " ports for sflow";
|
||||
|
||||
boost::thread_group sflow_collector_threads;
|
||||
|
||||
std::vector<std::string> ports_for_listen;
|
||||
boost::split(ports_for_listen, sflow_ports, boost::is_any_of(","), boost::token_compress_on);
|
||||
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "We will listen on "
|
||||
<< ports_for_listen.size() << " ports";
|
||||
<< sflow_ports.size() << " ports";
|
||||
|
||||
for (std::vector<std::string>::iterator port = ports_for_listen.begin();
|
||||
port != ports_for_listen.end(); ++port) {
|
||||
unsigned int sflow_port = convert_string_to_integer(*port);
|
||||
std::string sflow_host;
|
||||
|
||||
if (sflow_port == 0) {
|
||||
sflow_port = 6343;
|
||||
}
|
||||
if (configuration_map.count("sflow_host") != 0) {
|
||||
sflow_host = configuration_map["sflow_host"];
|
||||
}
|
||||
|
||||
for (auto sflow_port: sflow_ports) {
|
||||
sflow_collector_threads.add_thread(
|
||||
new boost::thread(start_sflow_collector, interface_for_binding, sflow_port));
|
||||
new boost::thread(start_sflow_collector, sflow_host, sflow_port));
|
||||
}
|
||||
|
||||
sflow_collector_threads.join_all();
|
||||
|
@ -143,8 +149,8 @@ void start_sflow_collection(process_packet_pointer func_ptr) {
|
|||
|
||||
void start_sflow_collector(std::string interface_for_binding, unsigned int sflow_port) {
|
||||
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "plugin will listen on "
|
||||
<< interface_for_binding << ":" << sflow_port << " udp port";
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "plugin will listen on " << interface_for_binding << ":"
|
||||
<< sflow_port << " udp port";
|
||||
|
||||
unsigned int udp_buffer_size = 65536;
|
||||
char udp_buffer[udp_buffer_size];
|
||||
|
@ -163,10 +169,11 @@ void start_sflow_collector(std::string interface_for_binding, unsigned int sflow
|
|||
}
|
||||
|
||||
servaddr.sin_port = htons(sflow_port);
|
||||
int bind_result = bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
|
||||
int bind_result = bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
|
||||
|
||||
if (bind_result) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "can't listen port: " << sflow_port;
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "can't listen port: " << sflow_port << " on host "
|
||||
<< interface_for_binding;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -176,36 +183,35 @@ void start_sflow_collector(std::string interface_for_binding, unsigned int sflow
|
|||
/* We should specify timeout there for correct toolkit shutdown */
|
||||
/* Because otherwise recvfrom will stay in blocked mode forever */
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 5; /* X Secs Timeout */
|
||||
tv.tv_sec = 1; /* X Secs Timeout */
|
||||
tv.tv_usec = 0; // Not init'ing this can cause strange errors
|
||||
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
|
||||
|
||||
while (true) {
|
||||
struct sockaddr_in cliaddr;
|
||||
socklen_t address_len = sizeof(cliaddr);
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t address_len = sizeof(client_addr);
|
||||
|
||||
int received_bytes =
|
||||
recvfrom(sockfd, udp_buffer, udp_buffer_size, 0, (struct sockaddr*)&cliaddr, &address_len);
|
||||
int received_bytes = recvfrom(sockfd, udp_buffer, udp_buffer_size, 0, (struct sockaddr*)&client_addr, &address_len);
|
||||
|
||||
if (received_bytes > 0) {
|
||||
// printf("We receive %d\n", received_bytes);
|
||||
raw_udp_packets_received++;
|
||||
|
||||
SFSample sample;
|
||||
memset(&sample, 0, sizeof(sample));
|
||||
sample.rawSample = (uint8_t*)udp_buffer;
|
||||
sample.rawSampleLen = received_bytes;
|
||||
uint32_t client_ipv4_address = 0;
|
||||
|
||||
if (address_len == sizeof(struct sockaddr_in)) {
|
||||
struct sockaddr_in* peer4 = (struct sockaddr_in*)&cliaddr;
|
||||
sample.sourceIP.type = SFLADDRESSTYPE_IP_V4;
|
||||
memcpy(&sample.sourceIP.address.ip_v4, &peer4->sin_addr, 4);
|
||||
|
||||
read_sflow_datagram(&sample);
|
||||
if (client_addr.sin_family == AF_INET) {
|
||||
client_ipv4_address = client_addr.sin_addr.s_addr;
|
||||
// logger << log4cpp::Priority::ERROR << "client ip: " << convert_ip_as_uint_to_string(client_ipv4_address);
|
||||
} else if (client_addr.sin_family == AF_INET6) {
|
||||
// We do not support them now
|
||||
} else {
|
||||
// We do not support an IPv6
|
||||
// Should not happen
|
||||
}
|
||||
|
||||
parse_sflow_v5_packet((uint8_t*)udp_buffer, received_bytes, client_ipv4_address);
|
||||
} else {
|
||||
udp_receive_errors++;
|
||||
|
||||
if (received_bytes == -1) {
|
||||
|
||||
if (errno == EAGAIN) {
|
||||
|
@ -221,713 +227,322 @@ void start_sflow_collector(std::string interface_for_binding, unsigned int sflow
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t getData32_nobswap(SFSample* sample) {
|
||||
uint32_t ans = *(sample->datap)++;
|
||||
// make sure we didn't run off the end of the datagram. Thanks to
|
||||
// Sven Eschenberg for spotting a bug/overrun-vulnerabilty that was here before.
|
||||
if ((uint8_t*)sample->datap > sample->endp) {
|
||||
// SFABORT(sample, SF_ABORT_EOS);
|
||||
// Error!!!
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we tried to read data in bad place! Fault!";
|
||||
return 0;
|
||||
}
|
||||
bool process_sflow_flow_sample(uint8_t* data_pointer,
|
||||
size_t data_length,
|
||||
bool expanded,
|
||||
const sflow_packet_header_unified_accessor& sflow_header_accessor,
|
||||
uint32_t client_ipv4_address) {
|
||||
uint8_t* current_packet_end = data_pointer + data_length;
|
||||
|
||||
return ans;
|
||||
}
|
||||
sflow_sample_header_unified_accessor_t sflow_sample_header_unified_accessor;
|
||||
|
||||
bool skipBytes(SFSample* sample, uint32_t skip) {
|
||||
int quads = (skip + 3) / 4;
|
||||
sample->datap += quads;
|
||||
if (skip > sample->rawSampleLen || (uint8_t*)sample->datap > sample->endp) {
|
||||
// SFABORT(sample, SF_ABORT_EOS);
|
||||
logger << log4cpp::Priority::ERROR
|
||||
<< plugin_log_prefix << "very dangerous error from skipBytes function! We try to read from restricted memory region";
|
||||
bool read_sflow_sample_header_unified_result =
|
||||
read_sflow_sample_header_unified(sflow_sample_header_unified_accessor, data_pointer, data_length, expanded);
|
||||
|
||||
if (!read_sflow_sample_header_unified_result) {
|
||||
sflow_bad_flow_samples++;
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "could not read sample header from the packet";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t getAddress(SFSample* sample, SFLAddress* address) {
|
||||
address->type = getData32(sample);
|
||||
if (address->type == SFLADDRESSTYPE_IP_V4) {
|
||||
address->address.ip_v4.addr = getData32_nobswap(sample);
|
||||
} else {
|
||||
memcpy(&address->address.ip_v6.addr, sample->datap, 16);
|
||||
skipBytes(sample, 16);
|
||||
}
|
||||
|
||||
return address->type;
|
||||
}
|
||||
|
||||
uint32_t getData32(SFSample* sample) {
|
||||
return ntohl(getData32_nobswap(sample));
|
||||
}
|
||||
|
||||
bool readFlowSample_v2v4(SFSample* sample) {
|
||||
sample->samplesGenerated = getData32(sample);
|
||||
|
||||
uint32_t samplerId = getData32(sample);
|
||||
sample->ds_class = samplerId >> 24;
|
||||
sample->ds_index = samplerId & 0x00ffffff;
|
||||
|
||||
sample->meanSkipCount = getData32(sample);
|
||||
sample->samplePool = getData32(sample);
|
||||
sample->dropEvents = getData32(sample);
|
||||
sample->inputPort = getData32(sample);
|
||||
sample->outputPort = getData32(sample);
|
||||
|
||||
sample->packet_data_tag = getData32(sample);
|
||||
|
||||
switch (sample->packet_data_tag) {
|
||||
|
||||
case INMPACKETTYPE_HEADER:
|
||||
readFlowSample_header(sample);
|
||||
|
||||
break;
|
||||
case INMPACKETTYPE_IPV4:
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "hit INMPACKETTYPE_IPV4, very strange";
|
||||
return false;
|
||||
|
||||
break;
|
||||
case INMPACKETTYPE_IPV6:
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "hit INMPACKETTYPE_IPV6, very strange";
|
||||
return false;
|
||||
|
||||
break;
|
||||
default:
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "unexpected packet_data_tag";
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
sample->extended_data_tag = 0;
|
||||
|
||||
// We should read this data
|
||||
sample->num_extended = getData32(sample);
|
||||
|
||||
if (sample->num_extended > 0) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we have "
|
||||
<< sample->num_extended << " extended fields";
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "and sorry we haven't support for it :(";
|
||||
|
||||
if (sflow_sample_header_unified_accessor.get_number_of_flow_records() == 0) {
|
||||
sflow_bad_flow_samples++;
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "for some strange reasons we got zero flow records";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
uint8_t* flow_record_zone_start = data_pointer + sflow_sample_header_unified_accessor.get_original_payload_length();
|
||||
|
||||
void read_sflow_datagram(SFSample* sample) {
|
||||
sample->datap = (uint32_t*)sample->rawSample;
|
||||
sample->endp = (uint8_t*)sample->rawSample + sample->rawSampleLen;
|
||||
vector_tuple_t vector_tuple;
|
||||
vector_tuple.reserve(sflow_sample_header_unified_accessor.get_number_of_flow_records());
|
||||
|
||||
sample->datagramVersion = getData32(sample);
|
||||
// printf("sFLOW version %d\n", sample->datagramVersion);
|
||||
bool padding_found = false;
|
||||
|
||||
if (sample->datagramVersion != 5 && sample->datagramVersion != 4) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we do not support sFLOW v<< "
|
||||
<< sample->datagramVersion << " because it's too old. Please change version to sFLOW 4 or 5";
|
||||
return;
|
||||
bool get_records_result =
|
||||
get_records(vector_tuple, flow_record_zone_start,
|
||||
sflow_sample_header_unified_accessor.get_number_of_flow_records(), current_packet_end, padding_found);
|
||||
|
||||
// I think that it's pretty important to have counter for this case
|
||||
if (padding_found) {
|
||||
sflow_padding_flow_sample++;
|
||||
}
|
||||
|
||||
/* get the agent address */
|
||||
getAddress(sample, &sample->agent_addr);
|
||||
|
||||
/* version 5 has an agent sub-id as well */
|
||||
if (sample->datagramVersion >= 5) {
|
||||
sample->agentSubId = getData32(sample);
|
||||
// sf_log(sample,"agentSubId %u\n", sample->agentSubId);
|
||||
} else {
|
||||
sample->agentSubId = 0;
|
||||
if (!get_records_result) {
|
||||
sflow_bad_flow_samples++;
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "Could not get records for some reasons";
|
||||
return false;
|
||||
}
|
||||
|
||||
sample->sequenceNo = getData32(sample); /* this is the packet sequence number */
|
||||
sample->sysUpTime = getData32(sample);
|
||||
uint32_t samplesInPacket = getData32(sample);
|
||||
simple_packet_t packet;
|
||||
packet.source = SFLOW;
|
||||
|
||||
// printf("We have %d samples in packet\n", samplesInPacket);
|
||||
packet.agent_ip_address = client_ipv4_address;
|
||||
|
||||
uint32_t samp = 0;
|
||||
for (; samp < samplesInPacket; samp++) {
|
||||
if ((uint8_t*)sample->datap >= sample->endp) {
|
||||
logger
|
||||
<< log4cpp::Priority::INFO << plugin_log_prefix
|
||||
<< "we tried to read data outside packet! It's very dangerous, we stop all operations";
|
||||
return;
|
||||
}
|
||||
for (auto record : vector_tuple) {
|
||||
int32_t record_type = std::get<0>(record);
|
||||
uint8_t* payload_ptr = std::get<1>(record);
|
||||
int32_t record_length = std::get<2>(record);
|
||||
|
||||
// printf("Sample #%d\n", samp);
|
||||
// std::cout << "flow record " << " record_type: " << record_type
|
||||
// << " record_length: " << record_length << std::endl;
|
||||
|
||||
/* just read the tag, then call the approriate decode fn */
|
||||
sample->sampleType = getData32(sample);
|
||||
if (sample->datagramVersion >= 5) {
|
||||
switch (sample->sampleType) {
|
||||
case SFLFLOW_SAMPLE:
|
||||
// skipBytes(sample, getData32(sample));
|
||||
if (!readFlowSample(sample, 0)) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we failed in SFLFLOW_SAMPLE handler";
|
||||
return;
|
||||
}
|
||||
// raw packet header we support only it
|
||||
if (record_type == SFLOW_RECORD_TYPE_RAW_PACKET_HEADER) {
|
||||
sflow_raw_packet_headers_total++;
|
||||
|
||||
break;
|
||||
case SFLCOUNTERS_SAMPLE:
|
||||
// We do not need counters for our task, skip it
|
||||
if (!skipBytes(sample, getData32(sample))) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "we failed in SFLCOUNTERS_SAMPLE handler";
|
||||
return;
|
||||
}
|
||||
sflow_raw_protocol_header_t sflow_raw_protocol_header;
|
||||
memcpy(&sflow_raw_protocol_header, payload_ptr, sizeof(sflow_raw_protocol_header_t));
|
||||
|
||||
break;
|
||||
case SFLFLOW_SAMPLE_EXPANDED:
|
||||
// skipBytes(sample, getData32(sample));
|
||||
if (!readFlowSample(sample, 1)) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "we failed in SFLFLOW_SAMPLE_EXPANDED handler";
|
||||
return;
|
||||
}
|
||||
sflow_raw_protocol_header.network_to_host_byte_order();
|
||||
sflow_raw_protocol_header.print();
|
||||
|
||||
break;
|
||||
case SFLCOUNTERS_SAMPLE_EXPANDED:
|
||||
// We do not need counters for our task, skip it
|
||||
if (!skipBytes(sample, getData32(sample))) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "we failed in SFLCOUNTERS_SAMPLE_EXPANDED handler";
|
||||
return;
|
||||
}
|
||||
uint8_t* header_payload_pointer = payload_ptr + sizeof(sflow_raw_protocol_header_t);
|
||||
|
||||
break;
|
||||
default:
|
||||
if (!skipTLVRecord(sample, sample->sampleType, getData32(sample))) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "we failed in default handler in skipTLVRecord";
|
||||
return;
|
||||
}
|
||||
break;
|
||||
bool use_packet_length_from_wire = true;
|
||||
|
||||
// We could enable this new parser for testing purposes
|
||||
auto result = parse_raw_packet_to_simple_packet_full_ng(header_payload_pointer,
|
||||
sflow_raw_protocol_header.frame_length_before_sampling,
|
||||
sflow_raw_protocol_header.header_size, packet,
|
||||
use_packet_length_from_wire);
|
||||
|
||||
if (result != network_data_stuctures::parser_code_t::success) {
|
||||
sflow_parse_error_nested_header++;
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << plugin_log_prefix
|
||||
<< "Cannot parse nested packet using ng parser: " << parser_code_to_string(result);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// sFLOW v2 or v4 here
|
||||
switch (sample->sampleType) {
|
||||
case FLOWSAMPLE:
|
||||
if (!readFlowSample_v2v4(sample)) {
|
||||
// We have some troubles with old sFLOW parser
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case COUNTERSSAMPLE:
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we haven't support for COUNTERSSAMPLE for "
|
||||
<< "sFLOW v4 and ignore it completely";
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "unexpected sample type: " << sample->sampleType;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool skipTLVRecord(SFSample* sample, uint32_t tag, uint32_t len) {
|
||||
return skipBytes(sample, len);
|
||||
}
|
||||
// Pass pointer to raw header to FastNetMon processing functions
|
||||
packet.packet_payload_pointer = header_payload_pointer;
|
||||
packet.packet_payload_full_length = sflow_raw_protocol_header.frame_length_before_sampling;
|
||||
packet.packet_payload_length = sflow_raw_protocol_header.header_size;
|
||||
|
||||
packet.sample_ratio = sflow_sample_header_unified_accessor.sampling_rate;
|
||||
|
||||
bool length_check(SFSample* sample, const char* description, uint8_t* start, int len) {
|
||||
uint32_t actualLen = (uint8_t*)sample->datap - start;
|
||||
uint32_t adjustedLen = ((len + 3) >> 2) << 2;
|
||||
// std::cout << print_simple_packet(packet) << std::endl;
|
||||
|
||||
if (actualLen != adjustedLen) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << description
|
||||
<< " length error: expected " << len << " found " << actualLen;
|
||||
return false;
|
||||
}
|
||||
} else if (record_type == SFLOW_RECORD_TYPE_EXTENDED_ROUTER_DATA) {
|
||||
sflow_extended_router_data_records++;
|
||||
} else if (record_type == SFLOW_RECORD_TYPE_EXTENDED_SWITCH_DATA) {
|
||||
sflow_extended_switch_data_records++;
|
||||
} else if (record_type == SFLOW_RECORD_TYPE_EXTENDED_GATEWAY_DATA) {
|
||||
sflow_extended_gateway_data_records++;
|
||||
|
||||
return true;
|
||||
}
|
||||
if (record_length < sizeof(uint32_t)) {
|
||||
logger << log4cpp::Priority::ERROR << "Extended gateway data is too short: " << record_length;
|
||||
|
||||
bool readFlowSample(SFSample* sample, int expanded) {
|
||||
uint32_t num_elements, sampleLength;
|
||||
uint8_t* sampleStart;
|
||||
|
||||
sampleLength = getData32(sample);
|
||||
sampleStart = (uint8_t*)sample->datap;
|
||||
sample->samplesGenerated = getData32(sample);
|
||||
|
||||
if (expanded) {
|
||||
sample->ds_class = getData32(sample);
|
||||
sample->ds_index = getData32(sample);
|
||||
} else {
|
||||
uint32_t samplerId = getData32(sample);
|
||||
sample->ds_class = samplerId >> 24;
|
||||
sample->ds_index = samplerId & 0x00ffffff;
|
||||
}
|
||||
|
||||
sample->meanSkipCount = getData32(sample);
|
||||
// printf("Sample ratio: %d\n", sample->meanSkipCount);
|
||||
sample->samplePool = getData32(sample);
|
||||
sample->dropEvents = getData32(sample);
|
||||
|
||||
if (expanded) {
|
||||
sample->inputPortFormat = getData32(sample);
|
||||
sample->inputPort = getData32(sample);
|
||||
sample->outputPortFormat = getData32(sample);
|
||||
sample->outputPort = getData32(sample);
|
||||
} else {
|
||||
uint32_t inp, outp;
|
||||
inp = getData32(sample);
|
||||
outp = getData32(sample);
|
||||
sample->inputPortFormat = inp >> 30;
|
||||
sample->outputPortFormat = outp >> 30;
|
||||
sample->inputPort = inp & 0x3fffffff;
|
||||
sample->outputPort = outp & 0x3fffffff;
|
||||
}
|
||||
|
||||
num_elements = getData32(sample);
|
||||
uint32_t el;
|
||||
for (el = 0; el < num_elements; el++) {
|
||||
uint32_t tag, length;
|
||||
uint8_t* start;
|
||||
char buf[51];
|
||||
tag = sample->elementType = getData32(sample);
|
||||
|
||||
length = getData32(sample);
|
||||
start = (uint8_t*)sample->datap;
|
||||
|
||||
// tag analyze
|
||||
if (tag == SFLFLOW_HEADER) {
|
||||
// process data
|
||||
readFlowSample_header(sample);
|
||||
} else {
|
||||
if (!skipTLVRecord(sample, tag, length)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!length_check(sample, "flow_sample_element", start, length)) {
|
||||
return false;
|
||||
// First field here is address type for nexthop
|
||||
uint32_t nexthop_address_type = 0;
|
||||
|
||||
memcpy(&nexthop_address_type, payload_ptr, sizeof(uint32_t));
|
||||
|
||||
if (fast_ntoh(nexthop_address_type) == SFLOW_ADDRESS_TYPE_IPv4) {
|
||||
// We can parse first more important for us fields from gateway structure
|
||||
if (record_length < sizeof(sflow_extended_gateway_information_t)) {
|
||||
logger << log4cpp::Priority::ERROR << "Extended gateway data is too short for IPv structure: " << record_length;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're ready to parse it
|
||||
sflow_extended_gateway_information_t* gateway_details = (sflow_extended_gateway_information_t*)payload_ptr;
|
||||
|
||||
packet.src_asn = fast_ntoh(gateway_details->router_asn);
|
||||
packet.dst_asn = fast_ntoh(gateway_details->source_asn);
|
||||
}
|
||||
|
||||
// logger << log4cpp::Priority::DEBUG << "Address type: " << fast_ntoh(*address_type);
|
||||
} else {
|
||||
// unknown type
|
||||
}
|
||||
}
|
||||
|
||||
if (!length_check(sample, "flow_sample", sampleStart, sampleLength)) {
|
||||
return false;
|
||||
}
|
||||
sflow_process_func_ptr(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define NFT_ETHHDR_SIZ 14
|
||||
#define NFT_8022_SIZ 3
|
||||
#define NFT_MAX_8023_LEN 1500
|
||||
// Read sFLOW packet header
|
||||
// Awesome description about v5 format from AMX-IX folks:
|
||||
// Header structure from AMS-IX folks:
|
||||
// http://www.sflow.org/developers/diagrams/sFlowV5Datagram.pdf
|
||||
void parse_sflow_v5_packet(uint8_t* payload_ptr, unsigned int payload_length, uint32_t client_ipv4_address) {
|
||||
sflow_packet_header_unified_accessor sflow_header_accessor;
|
||||
uint8_t* total_packet_end = payload_ptr + payload_length;
|
||||
|
||||
#define NFT_MIN_SIZ (NFT_ETHHDR_SIZ + sizeof(struct myiphdr))
|
||||
// Increase total number of packets
|
||||
sflow_total_packets++;
|
||||
|
||||
void decode_link_layer(SFSample* sample) {
|
||||
uint8_t* start = (uint8_t*)sample->header;
|
||||
uint8_t* end = start + sample->headerLen;
|
||||
uint8_t* ptr = start;
|
||||
uint16_t type_len;
|
||||
bool read_sflow_header_result = read_sflow_header(payload_ptr, payload_length, sflow_header_accessor);
|
||||
|
||||
/* assume not found */
|
||||
sample->gotIPV4 = 0;
|
||||
sample->gotIPV6 = 0;
|
||||
|
||||
if (sample->headerLen < NFT_ETHHDR_SIZ) {
|
||||
/* not enough for an Ethernet header */
|
||||
if (!read_sflow_header_result) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "could not read sflow packet header correctly";
|
||||
sflow_bad_packets++;
|
||||
return;
|
||||
}
|
||||
|
||||
// sf_log(sample,"dstMAC %02x%02x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4],
|
||||
// ptr[5]);
|
||||
memcpy(sample->eth_dst, ptr, 6);
|
||||
ptr += 6;
|
||||
|
||||
// sf_log(sample,"srcMAC %02x%02x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4],
|
||||
// ptr[5]);
|
||||
memcpy(sample->eth_src, ptr, 6);
|
||||
ptr += 6;
|
||||
type_len = (ptr[0] << 8) + ptr[1];
|
||||
ptr += 2;
|
||||
|
||||
if (sflow_qinq_process && type_len == sflow_qinq_ethertype && ((ptr[2] << 8) + ptr[3]) == 0x8100) {
|
||||
/* Outer VLAN tag - next two bytes */
|
||||
uint32_t vlanData = (ptr[0] << 8) + ptr[1];
|
||||
uint32_t vlan = vlanData & 0x0fff;
|
||||
uint32_t priority = vlanData >> 13;
|
||||
ptr += 2;
|
||||
|
||||
sample->in_outer_vlan = vlan;
|
||||
/* now get the type_len again (next two bytes) */
|
||||
type_len = (ptr[0] << 8) + ptr[1];
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if (type_len == 0x8100) {
|
||||
/* Inner VLAN tag - next two bytes */
|
||||
uint32_t vlanData = (ptr[0] << 8) + ptr[1];
|
||||
uint32_t vlan = vlanData & 0x0fff;
|
||||
uint32_t priority = vlanData >> 13;
|
||||
ptr += 2;
|
||||
|
||||
/* _____________________________________ */
|
||||
/* | pri | c | vlan-id | */
|
||||
/* ------------------------------------- */
|
||||
/* [priority = 3bits] [Canonical Format Flag = 1bit] [vlan-id = 12 bits] */
|
||||
// sf_log(sample,"decodedVLAN %u\n", vlan);
|
||||
// sf_log(sample,"decodedPriority %u\n", priority);
|
||||
sample->in_vlan = vlan;
|
||||
/* now get the type_len again (next two bytes) */
|
||||
type_len = (ptr[0] << 8) + ptr[1];
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
/* assume type_len is an ethernet-type now */
|
||||
sample->eth_type = type_len;
|
||||
|
||||
if (type_len == 0x0800) {
|
||||
/* IPV4 */
|
||||
if ((end - ptr) < sizeof(struct myiphdr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* look at first byte of header.... */
|
||||
/* ___________________________ */
|
||||
/* | version | hdrlen | */
|
||||
/* --------------------------- */
|
||||
|
||||
if ((*ptr >> 4) != 4) return; /* not version 4 */
|
||||
if ((*ptr & 15) < 5) return; /* not IP (hdr len must be 5 quads or more) */
|
||||
|
||||
/* survived all the tests - store the offset to the start of the ip header */
|
||||
sample->gotIPV4 = 1;
|
||||
sample->offsetToIPV4 = (ptr - start);
|
||||
}
|
||||
|
||||
if (type_len == 0x86DD) {
|
||||
/* IPV6 */
|
||||
/* look at first byte of header.... */
|
||||
|
||||
if ((*ptr >> 4) != 6) return; /* not version 6 */
|
||||
|
||||
/* survived all the tests - store the offset to the start of the ip6 header */
|
||||
sample->gotIPV6 = 1;
|
||||
sample->offsetToIPV6 = (ptr - start);
|
||||
|
||||
printf("IPv6\n");
|
||||
}
|
||||
|
||||
// printf("vlan: %d\n",sample->in_vlan);
|
||||
}
|
||||
|
||||
void readFlowSample_header(SFSample* sample) {
|
||||
sample->headerProtocol = getData32(sample);
|
||||
sample->sampledPacketSize = getData32(sample);
|
||||
|
||||
if (sample->datagramVersion > 4) {
|
||||
/* stripped count introduced in sFlow version 5 */
|
||||
sample->stripped = getData32(sample);
|
||||
}
|
||||
|
||||
sample->headerLen = getData32(sample);
|
||||
sample->header = (uint8_t*)sample->datap; /* just point at the header */
|
||||
skipBytes(sample, sample->headerLen);
|
||||
|
||||
if (sample->headerProtocol == SFLHEADER_ETHERNET_ISO8023) {
|
||||
// Detect IPv4 or IPv6 here
|
||||
decode_link_layer(sample);
|
||||
|
||||
// Process IP packets next
|
||||
if (sample->gotIPV4) {
|
||||
decode_ipv4_protocol(sample);
|
||||
}
|
||||
|
||||
if (sample->gotIPV6) {
|
||||
decode_ipv6_protocol(sample);
|
||||
}
|
||||
} else {
|
||||
if (sflow_header_accessor.get_datagram_samples_count() <= 0) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "not supported protocol: " << sample->headerProtocol;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char* IP_to_a(uint32_t ipaddr, char* buf) {
|
||||
uint8_t* ip = (uint8_t*)&ipaddr;
|
||||
/* should really be: snprintf(buf, buflen,...) but snprintf() is not always available */
|
||||
sprintf(buf, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char* printAddress(SFLAddress* address, char* buf) {
|
||||
switch (address->type) {
|
||||
case SFLADDRESSTYPE_IP_V4:
|
||||
IP_to_a(address->address.ip_v4.addr, buf);
|
||||
break;
|
||||
case SFLADDRESSTYPE_IP_V6: {
|
||||
uint8_t* b = address->address.ip_v6.addr;
|
||||
/* should really be: snprintf(buf, buflen,...) but snprintf() is not always available */
|
||||
sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12],
|
||||
b[13], b[14], b[15]);
|
||||
} break;
|
||||
default:
|
||||
sprintf(buf, "-");
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void decodeIPLayer4(SFSample* sample, uint8_t* ptr) {
|
||||
uint8_t* end = sample->header + sample->headerLen;
|
||||
|
||||
if (ptr > (end - 8)) {
|
||||
/* not enough header bytes left */
|
||||
<< "Strange number of sFLOW samples: " << sflow_header_accessor.get_datagram_samples_count();
|
||||
sflow_bad_packets++;
|
||||
return;
|
||||
}
|
||||
|
||||
simple_packet_t current_packet;
|
||||
vector_sample_tuple_t samples_vector;
|
||||
samples_vector.reserve(sflow_header_accessor.get_datagram_samples_count());
|
||||
|
||||
if (sample->gotIPV6) {
|
||||
current_packet.ip_protocol_version = 6;
|
||||
uint8_t* samples_block_start = payload_ptr + sflow_header_accessor.get_original_payload_length();
|
||||
|
||||
memcpy(current_packet.src_ipv6.s6_addr, sample->ipsrc.address.ip_v6.addr, 16);
|
||||
memcpy(current_packet.dst_ipv6.s6_addr, sample->ipdst.address.ip_v6.addr, 16);
|
||||
} else {
|
||||
current_packet.ip_protocol_version = 4;
|
||||
bool discovered_padding = false;
|
||||
|
||||
current_packet.src_ip = sample->ipsrc.address.ip_v4.addr;
|
||||
current_packet.dst_ip = sample->ipdst.address.ip_v4.addr;
|
||||
bool get_all_samples_result = get_all_samples(samples_vector, samples_block_start, total_packet_end,
|
||||
sflow_header_accessor.get_datagram_samples_count(), discovered_padding);
|
||||
|
||||
if (!get_all_samples_result) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we could not extract all samples from packet";
|
||||
sflow_bad_packets++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Because sFLOW data is near real time we could get current time
|
||||
gettimeofday(¤t_packet.ts, NULL);
|
||||
|
||||
current_packet.flags = 0;
|
||||
current_packet.number_of_packets = 1;
|
||||
current_packet.length = sample->sampledPacketSize;
|
||||
current_packet.sample_ratio = sample->meanSkipCount;
|
||||
|
||||
switch (sample->dcd_ipProtocol) {
|
||||
case 1: {
|
||||
// ICMP
|
||||
current_packet.protocol = IPPROTO_ICMP;
|
||||
struct myicmphdr icmp;
|
||||
memcpy(&icmp, ptr, sizeof(icmp));
|
||||
// printf("ICMPType %u\n", icmp.type);
|
||||
// printf("ICMPCode %u\n", icmp.code);
|
||||
sample->dcd_sport = icmp.type;
|
||||
sample->dcd_dport = icmp.code;
|
||||
sample->offsetToPayload = ptr + sizeof(icmp) - sample->header;
|
||||
} break;
|
||||
case 6: {
|
||||
// TCP
|
||||
current_packet.protocol = IPPROTO_TCP;
|
||||
struct mytcphdr tcp;
|
||||
int headerBytes;
|
||||
memcpy(&tcp, ptr, sizeof(tcp));
|
||||
sample->dcd_sport = ntohs(tcp.th_sport);
|
||||
sample->dcd_dport = ntohs(tcp.th_dport);
|
||||
|
||||
current_packet.source_port = sample->dcd_sport;
|
||||
current_packet.destination_port = sample->dcd_dport;
|
||||
// TODO: flags could be broken because our flags parser implemented with PF_RING style flags
|
||||
// PF_RING
|
||||
current_packet.flags = tcp.th_flags;
|
||||
|
||||
sample->dcd_tcpFlags = tcp.th_flags;
|
||||
// printf("TCPSrcPort %u\n", sample->dcd_sport);
|
||||
// printf("TCPDstPort %u\n",sample->dcd_dport);
|
||||
// printf("TCPFlags %u\n", sample->dcd_tcpFlags);
|
||||
headerBytes = (tcp.th_off_and_unused >> 4) * 4;
|
||||
ptr += headerBytes;
|
||||
sample->offsetToPayload = ptr - sample->header;
|
||||
} break;
|
||||
case 17: {
|
||||
// UDP
|
||||
current_packet.protocol = IPPROTO_UDP;
|
||||
struct myudphdr udp;
|
||||
memcpy(&udp, ptr, sizeof(udp));
|
||||
sample->dcd_sport = ntohs(udp.uh_sport);
|
||||
sample->dcd_dport = ntohs(udp.uh_dport);
|
||||
|
||||
current_packet.source_port = sample->dcd_sport;
|
||||
current_packet.destination_port = sample->dcd_dport;
|
||||
|
||||
sample->udp_pduLen = ntohs(udp.uh_ulen);
|
||||
// printf("UDPSrcPort %u\n", sample->dcd_sport);
|
||||
// printf("UDPDstPort %u\n", sample->dcd_dport);
|
||||
// printf("UDPBytes %u\n", sample->udp_pduLen);
|
||||
sample->offsetToPayload = ptr + sizeof(udp) - sample->header;
|
||||
} break;
|
||||
default: /* some other protcol */
|
||||
sample->offsetToPayload = ptr - sample->header;
|
||||
break;
|
||||
if (discovered_padding) {
|
||||
sflow_with_padding_at_the_end_of_packet++;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LUA_HOOKS
|
||||
// sample->inputPort = fast_ntoh(sample->inputPort);
|
||||
// sample->outputPort = fast_ntoh(sample->outputPort);
|
||||
for (auto sample : samples_vector) {
|
||||
// enterprise, sample_format, data start address, data region length
|
||||
// std::cout << "We process #" << i << " sample with format " << format
|
||||
// << " enterprise " << enterprise
|
||||
// << " and length " << sample_length << std::endl;
|
||||
|
||||
if (sflow_lua_hooks_enabled) {
|
||||
// This code could be used only for tests with pcap_reader
|
||||
if (sflow_lua_state == NULL) {
|
||||
sflow_lua_state = init_lua_jit(sflow_lua_hooks_path);
|
||||
}
|
||||
int32_t enterprise = std::get<0>(sample);
|
||||
int32_t integer_format = std::get<1>(sample);
|
||||
uint8_t* data_pointer = std::get<2>(sample);
|
||||
size_t data_length = std::get<3>(sample);
|
||||
|
||||
if (call_lua_function("process_sflow", sflow_lua_state,
|
||||
convert_ip_as_uint_to_string(sample->sourceIP.address.ip_v4.addr), (void*)sample)) {
|
||||
// We will process this packet
|
||||
uint8_t* current_packet_end = data_pointer + data_length;
|
||||
|
||||
if (enterprise == 0) {
|
||||
sflow_sample_type_t sample_format = sflow_sample_type_from_integer(integer_format);
|
||||
|
||||
if (sample_format == sflow_sample_type_t::BROKEN_TYPE) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we got broken format type number: " << integer_format;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Move this code to separate function!!!
|
||||
if (sample_format == sflow_sample_type_t::FLOW_SAMPLE) {
|
||||
// std::cout << "We got flow sample" << std::endl;
|
||||
process_sflow_flow_sample(data_pointer, data_length, false, sflow_header_accessor, client_ipv4_address);
|
||||
sflow_flow_samples++;
|
||||
} else if (sample_format == sflow_sample_type_t::COUNTER_SAMPLE) {
|
||||
// std::cout << "We got counter sample" << std::endl;
|
||||
// TODO: add support for sflow counetrs
|
||||
// process_sflow_counter_sample(data_pointer, data_length, false, sflow_header_accessor);
|
||||
sflow_counter_sample++;
|
||||
} else if (sample_format == sflow_sample_type_t::EXPANDED_FLOW_SAMPLE) {
|
||||
// std::cout << "We got expanded flow sample" << std::endl;
|
||||
process_sflow_flow_sample(data_pointer, data_length, true, sflow_header_accessor, client_ipv4_address);
|
||||
sflow_flow_samples++;
|
||||
} else if (sample_format == sflow_sample_type_t::EXPANDED_COUNTER_SAMPLE) {
|
||||
// TODO:add support for sflow counetrs
|
||||
// std::cout << "We got expanded counter sample" << std::endl;
|
||||
////process_sflow_counter_sample(data_pointer, data_length, true, sflow_header_accessor);
|
||||
sflow_counter_sample++;
|
||||
} else {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we got broken format type: " << integer_format;
|
||||
}
|
||||
} else {
|
||||
logger << log4cpp::Priority::DEBUG << "We will drop this packets because LUA script decided to do it";
|
||||
return;
|
||||
// do nothing because we haven't support for custom sFLOW data formats
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Call external handler function
|
||||
sflow_process_func_ptr(current_packet);
|
||||
}
|
||||
|
||||
void decode_ipv6_protocol(SFSample* sample) {
|
||||
uint8_t* ptr = sample->header + sample->offsetToIPV6;
|
||||
uint8_t* end = sample->header + sample->headerLen;
|
||||
bool process_sflow_counter_sample(uint8_t* data_pointer,
|
||||
size_t data_length,
|
||||
bool expanded,
|
||||
const sflow_packet_header_unified_accessor& sflow_header_accessor) {
|
||||
sflow_counter_header_unified_accessor_t sflow_counter_header_unified_accessor;
|
||||
|
||||
int ipVersion = (*ptr >> 4);
|
||||
bool read_sflow_counter_header_result =
|
||||
read_sflow_counter_header(data_pointer, data_length, expanded, sflow_counter_header_unified_accessor);
|
||||
|
||||
if (ipVersion != 6) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix
|
||||
<< "sFLOW header decode error: unexpected IP version: " << ipVersion;
|
||||
return;
|
||||
if (!read_sflow_counter_header_result) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "could not read sflow counter header";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* get the tos (priority) */
|
||||
sample->dcd_ipTos = *ptr++ & 15;
|
||||
|
||||
if (debug_sflow_parser) {
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "IPTOS: " << sample->dcd_ipTos;
|
||||
if (sflow_counter_header_unified_accessor.get_number_of_counter_records() == 0) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "get zero number of counter records";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 24-bit label */
|
||||
uint32_t label = *ptr++;
|
||||
label <<= 8;
|
||||
label += *ptr++;
|
||||
label <<= 8;
|
||||
label += *ptr++;
|
||||
counter_record_sample_vector_t counter_record_sample_vector;
|
||||
counter_record_sample_vector.reserve(sflow_counter_header_unified_accessor.get_number_of_counter_records());
|
||||
|
||||
if (debug_sflow_parser) {
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "IP6_label: " << label;
|
||||
bool get_all_counter_records_result =
|
||||
get_all_counter_records(counter_record_sample_vector,
|
||||
data_pointer + sflow_counter_header_unified_accessor.get_original_payload_length(),
|
||||
data_pointer + data_length,
|
||||
sflow_counter_header_unified_accessor.get_number_of_counter_records());
|
||||
|
||||
if (!get_all_counter_records_result) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "could not get all counter records";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* payload */
|
||||
uint16_t payloadLen = (ptr[0] << 8) + ptr[1];
|
||||
ptr += 2;
|
||||
for (auto counter_record : counter_record_sample_vector) {
|
||||
uint32_t enterprise = 0;
|
||||
uint32_t format = 0;
|
||||
ssize_t length = 0;
|
||||
uint8_t* data_pointer = nullptr;
|
||||
|
||||
/* if payload is zero, that implies a jumbo payload */
|
||||
if (debug_sflow_parser) {
|
||||
if (payloadLen == 0) {
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "IPV6_payloadLen <jumbo>";
|
||||
std::tie(enterprise, format, length, data_pointer) = counter_record;
|
||||
|
||||
if (enterprise == 0) {
|
||||
sample_counter_types_t sample_type = sample_counter_types_t::BROKEN_COUNTER;
|
||||
;
|
||||
|
||||
if (format == 1) {
|
||||
sample_type = sample_counter_types_t::GENERIC_INTERFACE_COUNTERS;
|
||||
} else if (format == 2) {
|
||||
sample_type = sample_counter_types_t::ETHERNET_INTERFACE_COUNTERS;
|
||||
}
|
||||
|
||||
if (sample_type == sample_counter_types_t::ETHERNET_INTERFACE_COUNTERS) {
|
||||
// std::cout << "ETHERNET_INTERFACE_COUNTERS" << std::endl;
|
||||
|
||||
if (sizeof(ethernet_sflow_interface_counters_t) != length) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we haven't enough data for ethernet counter packet";
|
||||
return false;
|
||||
}
|
||||
|
||||
ethernet_sflow_interface_counters_t ethernet_counters(data_pointer);
|
||||
// std::cout << ethernet_counters.print() << std::endl;
|
||||
}
|
||||
|
||||
if (sample_type == sample_counter_types_t::GENERIC_INTERFACE_COUNTERS) {
|
||||
// std::cout << "GENERIC_INTERFACE_COUNTERS" << std::endl;
|
||||
|
||||
if (sizeof(generic_sflow_interface_counters_t) != length) {
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we haven't enough data for generic packet";
|
||||
return false;
|
||||
}
|
||||
|
||||
generic_sflow_interface_counters_t generic_sflow_interface_counters(data_pointer);
|
||||
// std::cout << generic_sflow_interface_counters.print() << std::endl;
|
||||
}
|
||||
} else {
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "IPV6_payloadLen " << payloadLen;
|
||||
}
|
||||
}
|
||||
|
||||
/* next header */
|
||||
uint32_t nextHeader = *ptr++;
|
||||
|
||||
/* TTL */
|
||||
sample->dcd_ipTTL = *ptr++;
|
||||
// sf_log(sample,"IPTTL %u\n", sample->dcd_ipTTL);
|
||||
|
||||
/* src and dst address */
|
||||
// char buf[101];
|
||||
sample->ipsrc.type = SFLADDRESSTYPE_IP_V6;
|
||||
memcpy(&sample->ipsrc.address, ptr, 16);
|
||||
ptr += 16;
|
||||
|
||||
if (debug_sflow_parser) {
|
||||
char buf[101];
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix
|
||||
<< "srcIP6: " << printAddress(&sample->ipsrc, buf);
|
||||
}
|
||||
|
||||
sample->ipdst.type = SFLADDRESSTYPE_IP_V6;
|
||||
memcpy(&sample->ipdst.address, ptr, 16);
|
||||
ptr += 16;
|
||||
|
||||
if (debug_sflow_parser) {
|
||||
char buf[101];
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix
|
||||
<< "dstIP6: " << printAddress(&sample->ipdst, buf);
|
||||
}
|
||||
|
||||
/* skip over some common header extensions...
|
||||
http://searchnetworking.techtarget.com/originalContent/0,289142,sid7_gci870277,00.html */
|
||||
while (nextHeader == 0 || /* hop */
|
||||
nextHeader == 43 || /* routing */
|
||||
nextHeader == 44 || /* fragment */
|
||||
/* nextHeader == 50 => encryption - don't bother coz we'll not be able to read any further */
|
||||
nextHeader == 51 || /* auth */
|
||||
nextHeader == 60) { /* destination options */
|
||||
|
||||
uint32_t optionLen, skip;
|
||||
|
||||
if (debug_sflow_parser) {
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "IP6HeaderExtension: " << nextHeader;
|
||||
logger << log4cpp::Priority::ERROR << plugin_log_prefix << "we do not support vendor specific enterprise numbers";
|
||||
}
|
||||
|
||||
nextHeader = ptr[0];
|
||||
optionLen = 8 * (ptr[1] + 1); /* second byte gives option len in 8-byte chunks, not counting first 8 */
|
||||
skip = optionLen - 2;
|
||||
ptr += skip;
|
||||
if (ptr > end) return; /* ran off the end of the header */
|
||||
// std::cout << "Counter record" << std::endl;
|
||||
}
|
||||
|
||||
/* now that we have eliminated the extension headers, nextHeader should have what we want to
|
||||
remember as the ip protocol... */
|
||||
sample->dcd_ipProtocol = nextHeader;
|
||||
|
||||
if (debug_sflow_parser) {
|
||||
logger << log4cpp::Priority::INFO << plugin_log_prefix << "IPProtocol: " << sample->dcd_ipProtocol;
|
||||
}
|
||||
|
||||
decodeIPLayer4(sample, ptr);
|
||||
}
|
||||
|
||||
void decode_ipv4_protocol(SFSample* sample) {
|
||||
char buf[51];
|
||||
uint8_t* ptr = sample->header + sample->offsetToIPV4;
|
||||
/* Create a local copy of the IP header (cannot overlay structure in case it is not
|
||||
quad-aligned...some platforms would core-dump if we tried that). It's OK coz this probably performs just as well anyway. */
|
||||
struct myiphdr ip;
|
||||
memcpy(&ip, ptr, sizeof(ip));
|
||||
/* Value copy all ip elements into sample */
|
||||
sample->ipsrc.type = SFLADDRESSTYPE_IP_V4;
|
||||
sample->ipsrc.address.ip_v4.addr = ip.saddr;
|
||||
sample->ipdst.type = SFLADDRESSTYPE_IP_V4;
|
||||
sample->ipdst.address.ip_v4.addr = ip.daddr;
|
||||
sample->dcd_ipProtocol = ip.protocol;
|
||||
sample->dcd_ipTos = ip.tos;
|
||||
sample->dcd_ipTTL = ip.ttl;
|
||||
|
||||
// printf("ip.tot_len %d\n", ntohs(ip.tot_len));
|
||||
/* Log out the decoded IP fields */
|
||||
// printf("srcIP %s\n", printAddress(&sample->ipsrc, buf));
|
||||
// printf("dstIP %s\n", printAddress(&sample->ipdst, buf));
|
||||
// printf("IPProtocol %u\n", sample->dcd_ipProtocol);
|
||||
// printf("IPTOS %u\n", sample->dcd_ipTos);
|
||||
// printf("IPTTL %u\n", sample->dcd_ipTTL);
|
||||
|
||||
/* check for fragments */
|
||||
sample->ip_fragmentOffset = ntohs(ip.frag_off) & 0x1FFF;
|
||||
if (sample->ip_fragmentOffset > 0) {
|
||||
// printf("IPFragmentOffset %u\n", sample->ip_fragmentOffset);
|
||||
} else {
|
||||
/* advance the pointer to the next protocol layer */
|
||||
/* ip headerLen is expressed as a number of quads */
|
||||
ptr += (ip.version_and_headerLen & 0x0f) * 4;
|
||||
decodeIPLayer4(sample, ptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#ifndef SFLOW_PLUGIN_H
|
||||
#define SFLOW_PLUGIN_H
|
||||
#pragma once
|
||||
|
||||
#include "../fastnetmon_types.h"
|
||||
#include "sflow_data.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void start_sflow_collection(process_packet_pointer func_ptr);
|
||||
void init_sflow_module();
|
||||
void deinit_sflow_module();
|
||||
|
||||
// For tests
|
||||
void read_sflow_datagram(SFSample* sample);
|
||||
|
||||
#endif
|
||||
// New code for v5 only
|
||||
void parse_sflow_v5_packet(uint8_t* payload_ptr, unsigned int payload_length, uint32_t client_ipv4_address);
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
#ifndef SFLOW_DATA_H
|
||||
#define SFLOW_DATA_H
|
||||
|
||||
#include "sflow.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
// Packet headers for sFLOW v4
|
||||
enum INMPacket_information_type {
|
||||
INMPACKETTYPE_HEADER = 1, /* Packet headers are sampled */
|
||||
INMPACKETTYPE_IPV4 = 2, /* IP version 4 data */
|
||||
INMPACKETTYPE_IPV6 = 3 /* IP version 4 data */
|
||||
};
|
||||
|
||||
/* when I turn on optimisation with the Microsoft compiler it seems to change
|
||||
the values of these enumerated types and break the program - not sure why */
|
||||
enum INMSample_types { FLOWSAMPLE = 1, COUNTERSSAMPLE = 2 };
|
||||
|
||||
|
||||
/* same for tcp */
|
||||
struct mytcphdr {
|
||||
uint16_t th_sport; /* source port */
|
||||
uint16_t th_dport; /* destination port */
|
||||
uint32_t th_seq; /* sequence number */
|
||||
uint32_t th_ack; /* acknowledgement number */
|
||||
uint8_t th_off_and_unused;
|
||||
uint8_t th_flags;
|
||||
uint16_t th_win; /* window */
|
||||
uint16_t th_sum; /* checksum */
|
||||
uint16_t th_urp; /* urgent pointer */
|
||||
};
|
||||
|
||||
/* and UDP */
|
||||
struct myudphdr {
|
||||
uint16_t uh_sport; /* source port */
|
||||
uint16_t uh_dport; /* destination port */
|
||||
uint16_t uh_ulen; /* udp length */
|
||||
uint16_t uh_sum; /* udp checksum */
|
||||
};
|
||||
|
||||
/* and ICMP */
|
||||
struct myicmphdr {
|
||||
uint8_t type; /* message type */
|
||||
uint8_t code; /* type sub-code */
|
||||
/* ignore the rest */
|
||||
};
|
||||
|
||||
|
||||
/* define my own IP header struct - to ease portability */
|
||||
struct myiphdr {
|
||||
uint8_t version_and_headerLen;
|
||||
uint8_t tos;
|
||||
uint16_t tot_len;
|
||||
uint16_t id;
|
||||
uint16_t frag_off;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t check;
|
||||
uint32_t saddr;
|
||||
uint32_t daddr;
|
||||
};
|
||||
|
||||
#define SASAMPLE_EXTENDED_DATA_SWITCH 1
|
||||
#define SASAMPLE_EXTENDED_DATA_ROUTER 4
|
||||
#define SASAMPLE_EXTENDED_DATA_GATEWAY 8
|
||||
#define SASAMPLE_EXTENDED_DATA_USER 16
|
||||
#define SASAMPLE_EXTENDED_DATA_URL 32
|
||||
#define SASAMPLE_EXTENDED_DATA_MPLS 64
|
||||
#define SASAMPLE_EXTENDED_DATA_NAT 128
|
||||
#define SASAMPLE_EXTENDED_DATA_MPLS_TUNNEL 256
|
||||
#define SASAMPLE_EXTENDED_DATA_MPLS_VC 512
|
||||
#define SASAMPLE_EXTENDED_DATA_MPLS_FTN 1024
|
||||
#define SASAMPLE_EXTENDED_DATA_MPLS_LDP_FEC 2048
|
||||
#define SASAMPLE_EXTENDED_DATA_VLAN_TUNNEL 4096
|
||||
#define SASAMPLE_EXTENDED_DATA_NAT_PORT 8192
|
||||
|
||||
#define SA_MAX_EXTENDED_USER_LEN 200
|
||||
#define SA_MAX_EXTENDED_URL_LEN 200
|
||||
#define SA_MAX_EXTENDED_HOST_LEN 200
|
||||
|
||||
typedef struct _SFSample {
|
||||
SFLAddress sourceIP;
|
||||
SFLAddress agent_addr;
|
||||
uint32_t agentSubId;
|
||||
|
||||
/* the raw pdu */
|
||||
uint8_t* rawSample;
|
||||
uint32_t rawSampleLen;
|
||||
uint8_t* endp;
|
||||
time_t pcapTimestamp;
|
||||
|
||||
/* decode cursor */
|
||||
uint32_t* datap;
|
||||
|
||||
uint32_t datagramVersion;
|
||||
uint32_t sampleType;
|
||||
uint32_t elementType;
|
||||
uint32_t ds_class;
|
||||
uint32_t ds_index;
|
||||
|
||||
/* generic interface counter sample */
|
||||
SFLIf_counters ifCounters;
|
||||
|
||||
/* sample stream info */
|
||||
uint32_t sysUpTime;
|
||||
uint32_t sequenceNo;
|
||||
uint32_t sampledPacketSize;
|
||||
uint32_t samplesGenerated;
|
||||
uint32_t meanSkipCount;
|
||||
uint32_t samplePool;
|
||||
uint32_t dropEvents;
|
||||
|
||||
/* the sampled header */
|
||||
uint32_t packet_data_tag;
|
||||
uint32_t headerProtocol;
|
||||
uint8_t* header;
|
||||
int headerLen;
|
||||
uint32_t stripped;
|
||||
|
||||
/* header decode */
|
||||
int gotIPV4;
|
||||
int gotIPV4Struct;
|
||||
int offsetToIPV4;
|
||||
int gotIPV6;
|
||||
int gotIPV6Struct;
|
||||
int offsetToIPV6;
|
||||
int offsetToPayload;
|
||||
SFLAddress ipsrc;
|
||||
SFLAddress ipdst;
|
||||
uint32_t dcd_ipProtocol;
|
||||
uint32_t dcd_ipTos;
|
||||
uint32_t dcd_ipTTL;
|
||||
uint32_t dcd_sport;
|
||||
uint32_t dcd_dport;
|
||||
uint32_t dcd_tcpFlags;
|
||||
uint32_t ip_fragmentOffset;
|
||||
uint32_t udp_pduLen;
|
||||
|
||||
/* ports */
|
||||
uint32_t inputPortFormat;
|
||||
uint32_t outputPortFormat;
|
||||
uint32_t inputPort;
|
||||
uint32_t outputPort;
|
||||
|
||||
/* ethernet */
|
||||
uint32_t eth_type;
|
||||
uint32_t eth_len;
|
||||
uint8_t eth_src[8];
|
||||
uint8_t eth_dst[8];
|
||||
|
||||
/* vlan */
|
||||
uint32_t in_outer_vlan;
|
||||
uint32_t in_vlan;
|
||||
uint32_t in_priority;
|
||||
uint32_t internalPriority;
|
||||
uint32_t out_vlan;
|
||||
uint32_t out_priority;
|
||||
int vlanFilterReject;
|
||||
|
||||
/* extended data fields */
|
||||
uint32_t num_extended;
|
||||
uint32_t extended_data_tag;
|
||||
|
||||
/* IP forwarding info */
|
||||
SFLAddress nextHop;
|
||||
uint32_t srcMask;
|
||||
uint32_t dstMask;
|
||||
|
||||
/* BGP info */
|
||||
SFLAddress bgp_nextHop;
|
||||
uint32_t my_as;
|
||||
uint32_t src_as;
|
||||
uint32_t src_peer_as;
|
||||
uint32_t dst_as_path_len;
|
||||
uint32_t* dst_as_path;
|
||||
/* note: version 4 dst as path segments just get printed, not stored here, however
|
||||
* the dst_peer and dst_as are filled in, since those are used for netflow encoding
|
||||
*/
|
||||
uint32_t dst_peer_as;
|
||||
uint32_t dst_as;
|
||||
|
||||
uint32_t communities_len;
|
||||
uint32_t* communities;
|
||||
uint32_t localpref;
|
||||
|
||||
/* user id */
|
||||
uint32_t src_user_charset;
|
||||
uint32_t src_user_len;
|
||||
char src_user[SA_MAX_EXTENDED_USER_LEN + 1];
|
||||
uint32_t dst_user_charset;
|
||||
uint32_t dst_user_len;
|
||||
char dst_user[SA_MAX_EXTENDED_USER_LEN + 1];
|
||||
|
||||
/* url */
|
||||
uint32_t url_direction;
|
||||
uint32_t url_len;
|
||||
char url[SA_MAX_EXTENDED_URL_LEN + 1];
|
||||
uint32_t host_len;
|
||||
char host[SA_MAX_EXTENDED_HOST_LEN + 1];
|
||||
|
||||
/* mpls */
|
||||
SFLAddress mpls_nextHop;
|
||||
|
||||
/* nat */
|
||||
SFLAddress nat_src;
|
||||
SFLAddress nat_dst;
|
||||
|
||||
/* counter blocks */
|
||||
uint32_t statsSamplingInterval;
|
||||
uint32_t counterBlockVersion;
|
||||
|
||||
/* exception handler context */
|
||||
// jmp_buf env;
|
||||
} SFSample;
|
||||
|
||||
#endif // SFLOW_DATA_H
|
Loading…
Reference in New Issue