2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 18:07:40 +00:00

ipfix: add SCTP, ICMP, and ICMPv6 flow reporting

Signed-off-by: Romain Lenglet <rlenglet@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Romain Lenglet 2014-02-19 14:23:39 -08:00 committed by Ben Pfaff
parent 41064650be
commit f51e8ccbbb
2 changed files with 89 additions and 33 deletions

2
NEWS
View File

@ -4,6 +4,8 @@ Post-v2.1.0
poorly maintained and not widely used.
- New "check-ryu" Makefile target for running Ryu tests for OpenFlow
controllers against Open vSwitch. See INSTALL for details.
- Added IPFIX support for SCTP flows and templates for ICMPv4/v6 flows.
v2.1.0 - xx xxx xxxx
---------------------

View File

@ -117,7 +117,8 @@ enum ipfix_proto_l3 {
};
enum ipfix_proto_l4 {
IPFIX_PROTO_L4_UNKNOWN = 0,
IPFIX_PROTO_L4_TCP_UDP,
IPFIX_PROTO_L4_TCP_UDP_SCTP,
IPFIX_PROTO_L4_ICMP,
NUM_IPFIX_PROTO_L4
};
@ -200,13 +201,21 @@ struct ipfix_data_record_flow_key_ipv6 {
});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_ipv6) == 36);
/* Part of data record flow key for TCP/UDP entities. */
/* Part of data record flow key for TCP/UDP/SCTP entities. */
OVS_PACKED(
struct ipfix_data_record_flow_key_tcpudp {
struct ipfix_data_record_flow_key_transport {
ovs_be16 source_transport_port; /* SOURCE_TRANSPORT_PORT */
ovs_be16 destination_transport_port; /* DESTINATION_TRANSPORT_PORT */
});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_tcpudp) == 4);
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_transport) == 4);
/* Part of data record flow key for ICMP entities. */
OVS_PACKED(
struct ipfix_data_record_flow_key_icmp {
uint8_t icmp_type; /* ICMP_TYPE_IPV4 / ICMP_TYPE_IPV6 */
uint8_t icmp_code; /* ICMP_CODE_IPV4 / ICMP_CODE_IPV6 */
});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_icmp) == 2);
/* Cf. IETF RFC 5102 Section 5.11.3. */
enum ipfix_flow_end_reason {
@ -231,18 +240,21 @@ BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_common) == 25);
/* Part of data record for IP aggregated elements. */
OVS_PACKED(
struct ipfix_data_record_aggregated_ip {
ovs_be64 octet_delta_count; /* OCTET_DELTA_COUNT */
ovs_be64 octet_delta_sum_of_squares; /* OCTET_DELTA_SUM_OF_SQUARES */
ovs_be64 minimum_ip_total_length; /* MINIMUM_IP_TOTAL_LENGTH */
ovs_be64 maximum_ip_total_length; /* MAXIMUM_IP_TOTAL_LENGTH */
});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_ip) == 24);
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_ip) == 32);
#define MAX_FLOW_KEY_LEN \
(sizeof(struct ipfix_data_record_flow_key_common) \
+ sizeof(struct ipfix_data_record_flow_key_vlan) \
+ sizeof(struct ipfix_data_record_flow_key_ip) \
+ sizeof(struct ipfix_data_record_flow_key_ipv6) \
+ sizeof(struct ipfix_data_record_flow_key_tcpudp))
#define MAX_FLOW_KEY_LEN \
(sizeof(struct ipfix_data_record_flow_key_common) \
+ sizeof(struct ipfix_data_record_flow_key_vlan) \
+ sizeof(struct ipfix_data_record_flow_key_ip) \
+ MAX(sizeof(struct ipfix_data_record_flow_key_ipv4), \
sizeof(struct ipfix_data_record_flow_key_ipv6)) \
+ MAX(sizeof(struct ipfix_data_record_flow_key_icmp), \
sizeof(struct ipfix_data_record_flow_key_transport)))
#define MAX_DATA_RECORD_LEN \
(MAX_FLOW_KEY_LEN \
@ -280,6 +292,7 @@ struct ipfix_flow_cache_entry {
uint64_t flow_end_timestamp_usec;
uint64_t packet_delta_count;
uint64_t layer2_octet_delta_count;
uint64_t octet_delta_count;
uint64_t octet_delta_sum_of_squares; /* 0 if not IP. */
uint16_t minimum_ip_total_length; /* 0 if not IP. */
uint16_t maximum_ip_total_length; /* 0 if not IP. */
@ -781,18 +794,27 @@ ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
if (l3 == IPFIX_PROTO_L3_IPV4) {
DEF(SOURCE_IPV4_ADDRESS);
DEF(DESTINATION_IPV4_ADDRESS);
if (l4 == IPFIX_PROTO_L4_TCP_UDP_SCTP) {
DEF(SOURCE_TRANSPORT_PORT);
DEF(DESTINATION_TRANSPORT_PORT);
} else if (l4 == IPFIX_PROTO_L4_ICMP) {
DEF(ICMP_TYPE_IPV4);
DEF(ICMP_CODE_IPV4);
}
} else { /* l3 == IPFIX_PROTO_L3_IPV6 */
DEF(SOURCE_IPV6_ADDRESS);
DEF(DESTINATION_IPV6_ADDRESS);
DEF(FLOW_LABEL_IPV6);
if (l4 == IPFIX_PROTO_L4_TCP_UDP_SCTP) {
DEF(SOURCE_TRANSPORT_PORT);
DEF(DESTINATION_TRANSPORT_PORT);
} else if (l4 == IPFIX_PROTO_L4_ICMP) {
DEF(ICMP_TYPE_IPV6);
DEF(ICMP_CODE_IPV6);
}
}
}
if (l4 != IPFIX_PROTO_L4_UNKNOWN) {
DEF(SOURCE_TRANSPORT_PORT);
DEF(DESTINATION_TRANSPORT_PORT);
}
/* 2. Flow aggregated data. */
DEF(FLOW_START_DELTA_MICROSECONDS);
@ -802,6 +824,7 @@ ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
DEF(FLOW_END_REASON);
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
DEF(OCTET_DELTA_COUNT);
DEF(OCTET_DELTA_SUM_OF_SQUARES);
DEF(MINIMUM_IP_TOTAL_LENGTH);
DEF(MAXIMUM_IP_TOTAL_LENGTH);
@ -946,6 +969,7 @@ ipfix_cache_aggregate_entries(struct ipfix_flow_cache_entry *from_entry,
to_entry->packet_delta_count += from_entry->packet_delta_count;
to_entry->layer2_octet_delta_count += from_entry->layer2_octet_delta_count;
to_entry->octet_delta_count += from_entry->octet_delta_count;
to_entry->octet_delta_sum_of_squares +=
from_entry->octet_delta_sum_of_squares;
@ -1019,22 +1043,37 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
switch(ntohs(flow->dl_type)) {
case ETH_TYPE_IP:
l3 = IPFIX_PROTO_L3_IPV4;
switch(flow->nw_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
l4 = IPFIX_PROTO_L4_TCP_UDP_SCTP;
break;
case IPPROTO_ICMP:
l4 = IPFIX_PROTO_L4_ICMP;
break;
default:
l4 = IPFIX_PROTO_L4_UNKNOWN;
}
break;
case ETH_TYPE_IPV6:
l3 = IPFIX_PROTO_L3_IPV6;
switch(flow->nw_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
l4 = IPFIX_PROTO_L4_TCP_UDP_SCTP;
break;
case IPPROTO_ICMPV6:
l4 = IPFIX_PROTO_L4_ICMP;
break;
default:
l4 = IPFIX_PROTO_L4_UNKNOWN;
}
break;
default:
l3 = IPFIX_PROTO_L3_UNKNOWN;
}
l4 = IPFIX_PROTO_L4_UNKNOWN;
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
switch(flow->nw_proto) {
case IPPROTO_TCP: /* TCP */
case IPPROTO_UDP: /* UDP */
l4 = IPFIX_PROTO_L4_TCP_UDP;
break;
}
l4 = IPFIX_PROTO_L4_UNKNOWN;
}
flow_key->obs_domain_id = obs_domain_id;
@ -1086,6 +1125,7 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
if (l3 == IPFIX_PROTO_L3_IPV4) {
struct ipfix_data_record_flow_key_ipv4 *data_ipv4;
data_ipv4 = ofpbuf_put_zeros(&msg, sizeof *data_ipv4);
data_ipv4->source_ipv4_address = flow->nw_src;
data_ipv4->destination_ipv4_address = flow->nw_dst;
@ -1101,12 +1141,18 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
}
}
if (l4 != IPFIX_PROTO_L4_UNKNOWN) {
struct ipfix_data_record_flow_key_tcpudp *data_tcpudp;
if (l4 == IPFIX_PROTO_L4_TCP_UDP_SCTP) {
struct ipfix_data_record_flow_key_transport *data_transport;
data_tcpudp = ofpbuf_put_zeros(&msg, sizeof *data_tcpudp);
data_tcpudp->source_transport_port = flow->tp_src;
data_tcpudp->destination_transport_port = flow->tp_dst;
data_transport = ofpbuf_put_zeros(&msg, sizeof *data_transport);
data_transport->source_transport_port = flow->tp_src;
data_transport->destination_transport_port = flow->tp_dst;
} else if (l4 == IPFIX_PROTO_L4_ICMP) {
struct ipfix_data_record_flow_key_icmp *data_icmp;
data_icmp = ofpbuf_put_zeros(&msg, sizeof *data_icmp);
data_icmp->icmp_type = ntohs(flow->tp_src) & 0xff;
data_icmp->icmp_code = ntohs(flow->tp_dst) & 0xff;
}
flow_key->flow_key_msg_part_size = msg.size;
@ -1130,9 +1176,15 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
uint16_t ip_total_length =
ethernet_total_length - ethernet_header_length;
uint64_t octet_delta_count;
entry->octet_delta_sum_of_squares =
packet_delta_count * ip_total_length * ip_total_length;
/* Calculate the total matched octet count by considering as
* an approximation that all matched packets have the same
* length. */
octet_delta_count = packet_delta_count * ip_total_length;
entry->octet_delta_count = octet_delta_count;
entry->octet_delta_sum_of_squares = octet_delta_count * ip_total_length;
entry->minimum_ip_total_length = ip_total_length;
entry->maximum_ip_total_length = ip_total_length;
} else {
@ -1198,6 +1250,8 @@ ipfix_put_data_set(uint32_t export_time_sec,
data_aggregated_ip = ofpbuf_put_zeros(
msg, sizeof *data_aggregated_ip);
data_aggregated_ip->octet_delta_count = htonll(
entry->octet_delta_count);
data_aggregated_ip->octet_delta_sum_of_squares = htonll(
entry->octet_delta_sum_of_squares);
data_aggregated_ip->minimum_ip_total_length = htonll(