struct dpif_ipfix {
struct dpif_ipfix_bridge_exporter bridge_exporter;
struct hmap flow_exporter_map; /* dpif_ipfix_flow_exporter_map_node. */
- atomic_int ref_cnt;
+ struct ovs_refcount ref_cnt;
};
#define IPFIX_VERSION 0x000a
};
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
};
});
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 {
/* 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 \
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. */
di = xzalloc(sizeof *di);
dpif_ipfix_bridge_exporter_init(&di->bridge_exporter);
hmap_init(&di->flow_exporter_map);
- atomic_init(&di->ref_cnt, 1);
+ ovs_refcount_init(&di->ref_cnt);
return di;
}
{
struct dpif_ipfix *di = CONST_CAST(struct dpif_ipfix *, di_);
if (di) {
- int orig;
- atomic_add(&di->ref_cnt, 1, &orig);
- ovs_assert(orig > 0);
+ ovs_refcount_ref(&di->ref_cnt);
}
return di;
}
void
dpif_ipfix_unref(struct dpif_ipfix *di) OVS_EXCLUDED(mutex)
{
- int orig;
-
- if (!di) {
- return;
- }
-
- atomic_sub(&di->ref_cnt, 1, &orig);
- ovs_assert(orig > 0);
- if (orig == 1) {
+ if (di && ovs_refcount_unref(&di->ref_cnt) == 1) {
ovs_mutex_lock(&mutex);
dpif_ipfix_clear(di);
dpif_ipfix_bridge_exporter_destroy(&di->bridge_exporter);
hmap_destroy(&di->flow_exporter_map);
- atomic_destroy(&di->ref_cnt);
+ ovs_refcount_destroy(&di->ref_cnt);
free(di);
ovs_mutex_unlock(&mutex);
}
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);
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);
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;
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;
- 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;
+ 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;
}
flow_key->obs_domain_id = obs_domain_id;
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;
}
}
- 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;
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
uint16_t ip_total_length =
ethernet_total_length - ethernet_header_length;
+ uint64_t octet_delta_count;
+
+ /* 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_sum_of_squares =
- packet_delta_count * ip_total_length * 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 {
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(