Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sFlow for tunnels: Tunnel extension & IPv6 encapsulation support #574

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/sflow/sfcapd.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ static int verbose = 0;
typedef ssize_t (*packet_function_t)(int, void *, size_t, int, struct sockaddr *, socklen_t *);

static option_t sfcapdConfig[] = {
{.name = "gre", .valBool = 0, .flags = OPTDEFAULT}, {.name = "maxworkers", .valUint64 = 2, .flags = OPTDEFAULT}, {.name = NULL}};
{.name = "gre", .valBool = 0, .flags = OPTDEFAULT}, {.name = "6in4", .valBool = 0, .flags = OPTDEFAULT}, {.name = "maxworkers", .valUint64 = 2, .flags = OPTDEFAULT}, {.name = NULL}};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one option .name = "tunnel" ..


/* module limited globals */
static FlowSource_t *FlowSource;
Expand All @@ -115,7 +115,7 @@ static void IntHandler(int signal);
static inline FlowSource_t *GetFlowSource(struct sockaddr_storage *ss);

static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, time_t twin, time_t t_begin, char *time_extension, int compress,
int parse_gre);
int parse_gre, int parse_6in4);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One argument -> int parse_tunnel


/* Functions */
static void usage(char *name) {
Expand All @@ -140,7 +140,7 @@ static void usage(char *name) {
"-i interval\tMetric interval in s for metric exporter\n"
"-m socket\t\tEnable metric exporter on socket.\n"
"-M dir \t\tSet the output directory for dynamic sources.\n"
"-o options \tAdd sfcpad options, separated with ','. Available: 'gre'\n"
"-o options \tAdd sfcpad options, separated with ','. Available: 'gre', '6in4'\n"
"-P pidfile\tset the PID file\n"
"-R IP[/port]\tRepeat incoming packets to IP address/port. Max 8 repeaters.\n"
"-A\t\tEnable source address spoofing for packet repeater -R.\n"
Expand Down Expand Up @@ -272,7 +272,7 @@ static int SendRepeaterMessage(int fd, void *in_buff, size_t cnt, struct sockadd
} // End of SendRepeaterMessage

static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, time_t twin, time_t t_begin, char *time_extension, int compress,
int parse_gre) {
int parse_gre, int parse_6in4) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one option -> int parse_tunnel

struct sockaddr_storage sf_sender;
socklen_t sf_sender_size = sizeof(sf_sender);

Expand Down Expand Up @@ -430,7 +430,7 @@ static void run(packet_function_t receive_packet, int socket, int pfd, int rfd,

fs->received = tv;
/* Process data - have a look at the common header */
Process_sflow(in_buff, cnt, fs, parse_gre);
Process_sflow(in_buff, cnt, fs, parse_gre, parse_6in4);

// each Process_xx function has to process the entire input buffer, therefore it's empty
// now.
Expand Down Expand Up @@ -458,7 +458,7 @@ int main(int argc, char **argv) {
FlowSource_t *fs;
int family, bufflen, metricInterval;
time_t twin;
int sock, do_daemonize, expire, spec_time_extension, parse_gre;
int sock, do_daemonize, expire, spec_time_extension, parse_gre, parse_6in4;
int subdir_index, compress, srcSpoofing;
uint64_t workers;
#ifdef PCAP
Expand Down Expand Up @@ -495,6 +495,7 @@ int main(int argc, char **argv) {
options = NULL;
workers = 0;
parse_gre = 0;
parse_6in4 = 0;

int c;
while ((c = getopt(argc, argv, "46AB:b:C:d:DeEf:g:hI:i:jJ:l:m:M:n:o:p:P:R:S:T:t:u:vVW:w:x:X:yz::Z:")) != EOF) {
Expand Down Expand Up @@ -786,6 +787,7 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
OptGetBool(sfcapdConfig, "gre", &parse_gre);
OptGetBool(sfcapdConfig, "6in4", &parse_6in4);

if (datadir && !AddFlowSource(&FlowSource, Ident, ANYIP, datadir)) {
LogError("Failed to add default data collector directory");
Expand Down Expand Up @@ -920,7 +922,7 @@ int main(int argc, char **argv) {
sigaction(SIGPIPE, &act, NULL);

LogInfo("Startup sfcapd.");
run(receive_packet, sock, pfd, rfd, twin, t_start, time_extension, compress, parse_gre);
run(receive_packet, sock, pfd, rfd, twin, t_start, time_extension, compress, parse_gre, parse_6in4);

// shutdown
close(sock);
Expand Down
47 changes: 45 additions & 2 deletions src/sflow/sflow_nfdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ int Init_sflow(int verbose, char *extensionList) {
} // End of Init_sflow

// called by sfcapd for each packet
void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs, int parse_gre) {
SFSample sample = {.rawSample = in_buff, .rawSampleLen = in_buff_cnt, .sourceIP.s_addr = fs->sa_family == PF_INET ? htonl(fs->ip.V4) : 0, .parse_gre = parse_gre};
void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs, int parse_gre, int parse_6in4) {
SFSample sample = {.rawSample = in_buff, .rawSampleLen = in_buff_cnt, .sourceIP.s_addr = fs->sa_family == PF_INET ? htonl(fs->ip.V4) : 0,
.parse_gre = parse_gre, .parse_6in4 = parse_6in4};

dbg_printf("startDatagram =================================\n");
// catch SFABORT in sflow code
Expand Down Expand Up @@ -301,6 +302,19 @@ void StoreSflowRecord(SFSample *sample, FlowSource_t *fs) {
recordSize += EXipReceivedV6Size;
}

// Tunnels
int tun_isV4 = sample->tun_ipsrc.type == SFLADDRESSTYPE_IP_V4;
if (tun_isV4 && ExtensionsEnabled[EXtunIPv4ID]) {
recordSize += EXtunIPv4Size;
}

int tun_isV6 = sample->tun_ipsrc.type == SFLADDRESSTYPE_IP_V6;
if (isV6 && ExtensionsEnabled[EXtunIPv6ID]) {
recordSize += EXtunIPv6Size;
}
dbg_printf("Tunnel: IPv4: %u, IPv6: %u\n", tun_isV4, tun_isV6);


recordSize += sizeof(recordHeaderV3_t);
if (!IsAvailable(fs->dataBlock, recordSize)) {
// flush block - get an empty one
Expand Down Expand Up @@ -458,6 +472,35 @@ void StoreSflowRecord(SFSample *sample, FlowSource_t *fs) {
dbg_printf("Add IPv6 route IP extension\n");
}

// Tunnels
if (tun_isV4 && ExtensionsEnabled[EXtunIPv4ID]) {
PushExtension(recordHeader, EXtunIPv4, tunIPv4);
tunIPv4->tunSrcAddr = ntohl(sample->tun_ipsrc.address.ip_v4.addr);
tunIPv4->tunDstAddr = ntohl(sample->tun_ipdst.address.ip_v4.addr);
tunIPv4->tunProto = sample->tun_proto;
dbg_printf("Add IPv4 tunnel extension\n");
}

if (tun_isV6 && ExtensionsEnabled[EXtunIPv6ID]) {
PushExtension(recordHeader, EXtunIPv6, tunIPv6);

u_char *b = sample->tun_ipsrc.address.ip_v6.addr;
uint64_t *u = (uint64_t *)b;
tunIPv6->tunSrcAddr[0] = ntohll(*u);
u = (uint64_t *)&(b[8]);
tunIPv6->tunSrcAddr[1] = ntohll(*u);

b = sample->tun_ipdst.address.ip_v6.addr;
u = (uint64_t *)b;
tunIPv6->tunDstAddr[0] = ntohll(*u);
u = (uint64_t *)&(b[8]);
tunIPv6->tunDstAddr[1] = ntohll(*u);

tunIPv6->tunProto = sample->tun_proto;
dbg_printf("Add IPv6 tunnel extension\n");
}


// update first_seen, last_seen
if (genericFlow->msecFirst < fs->msecFirst) // the very first time stamp need to be set
fs->msecFirst = genericFlow->msecFirst;
Expand Down
2 changes: 1 addition & 1 deletion src/sflow/sflow_nfdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

int Init_sflow(int verbose, char *extensionList);

void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs, int parse_gre);
void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs, int parse_gre, int parse_6in4);

void StoreSflowRecord(SFSample *sample, FlowSource_t *fs);

Expand Down
24 changes: 23 additions & 1 deletion src/sflow/sflow_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ static void decodeIPLayer4(SFSample *sample, uint8_t *ptr) {
switch (ntohs(gre.protocol_type)) {
case 0x6558: { /* Transparent Ethernet bridging */
sample->headerProtocol = SFLHEADER_ETHERNET_ISO8023;
; } break;
} break;
case 0x0800: { /* IPv4 */
sample->headerProtocol = SFLHEADER_IPv4;
} break;
Expand All @@ -715,6 +715,26 @@ static void decodeIPLayer4(SFSample *sample, uint8_t *ptr) {
dbg_printf("GRE: Header type: %u\n", sample->headerProtocol);
sample->datap = sample->headerDescriptionStart; /* Reset parsing pointer for metadata */
sample->header = ptr + gre_header_length; /* Set parsing pointer for header to end of GRE header */
if (sample->tun_ipsrc.type == SFLADDRESSTYPE_UNDEFINED) { /* Use outermost header for tunnel IPs */
sample->tun_ipsrc = sample->ipsrc;
sample->tun_ipdst = sample->ipdst;
sample->tun_proto = sample->dcd_ipProtocol;
}
readFlowSample_header(sample);
return;
}
}
case 41: { /* 6in4 */
dbg_printf("6in4\n");
if (sample->parse_6in4) {
sample->headerProtocol = SFLHEADER_IPv6;
sample->datap = sample->headerDescriptionStart; /* Reset parsing pointer for metadata */
sample->header = ptr; /* Set parsing pointer for header to end of IPv4 header */
if (sample->tun_ipsrc.type == SFLADDRESSTYPE_UNDEFINED) { /* Use outermost header for tunnel IPs */
sample->tun_ipsrc = sample->ipsrc;
sample->tun_ipdst = sample->ipdst;
sample->tun_proto = sample->dcd_ipProtocol;
}
readFlowSample_header(sample);
return;
}
Expand Down Expand Up @@ -3643,6 +3663,7 @@ void readSFlowDatagram(SFSample *sample, FlowSource_t *fs, int verbose) {
#endif

int parse_gre = sample->parse_gre;
int parse_6in4 = sample->parse_6in4;

/* log some datagram info */
dbg_printf("datagramSourceIP %s\n", IP_to_a(sample->sourceIP.s_addr, buf, 51));
Expand Down Expand Up @@ -3680,6 +3701,7 @@ void readSFlowDatagram(SFSample *sample, FlowSource_t *fs, int verbose) {
// fix bug sflowtool */
memset(sampleData, 0, sizeof(SFSample) - sampleDataOffset);
sample->parse_gre = parse_gre;
sample->parse_6in4 = parse_6in4;

if ((uint8_t *)sample->datap >= sample->endp) {
LogError("SFLOW: readSFlowDatagram() unexpected end of datagram after sample %d of %d\n", samp, samplesInPacket);
Expand Down
8 changes: 7 additions & 1 deletion src/sflow/sflow_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,13 @@ typedef struct _SFSample {
#define SF_ABORT_DECODE_ERROR 2
#define SF_ABORT_LENGTH_ERROR 3

int parse_gre;
/* tunnels */
int parse_gre; /* Enable GRE tunnel introspection */
int parse_6in4; /* Enable 6in4 tunnel introspection */
Comment on lines +283 to +284
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One single option int parse_tunnel

SFLAddress tun_ipsrc;
SFLAddress tun_ipdst;
uint32_t tun_proto;


} SFSample;

Expand Down
Loading