+});
+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);
+
+/* For the tunnel type that is on the top of IPSec, the protocol identifier
+ * of the upper tunnel type is used.
+ */
+static uint8_t tunnel_protocol[NUM_DPIF_IPFIX_TUNNEL] = {
+ 0, /* reserved */
+ IPPROTO_UDP, /* DPIF_IPFIX_TUNNEL_VXLAN */
+ IPPROTO_GRE, /* DPIF_IPFIX_TUNNEL_GRE */
+ IPPROTO_UDP, /* DPIF_IPFIX_TUNNEL_LISP*/
+ IPPROTO_TCP, /* DPIF_IPFIX_TUNNEL_STT*/
+ IPPROTO_GRE, /* DPIF_IPFIX_TUNNEL_IPSEC_GRE */
+ 0 , /* reserved */
+ IPPROTO_UDP, /* DPIF_IPFIX_TUNNEL_GENEVE*/
+};
+
+OVS_PACKED(
+struct ipfix_data_record_flow_key_tunnel {
+ ovs_be32 tunnel_source_ipv4_address; /* TUNNEL_SOURCE_IPV4_ADDRESS */
+ ovs_be32 tunnel_destination_ipv4_address; /* TUNNEL_DESTINATION_IPV4_ADDRESS */
+ uint8_t tunnel_protocol_identifier; /* TUNNEL_PROTOCOL_IDENTIFIER */
+ ovs_be16 tunnel_source_transport_port; /* TUNNEL_SOURCE_TRANSPORT_PORT */
+ ovs_be16 tunnel_destination_transport_port; /* TUNNEL_DESTINATION_TRANSPORT_PORT */
+ uint8_t tunnel_type; /* TUNNEL_TYPE */
+ uint8_t tunnel_key_length; /* length of TUNNEL_KEY */
+ uint8_t tunnel_key[]; /* data of TUNNEL_KEY */
+});
+BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_tunnel) == 15);
+
+/* Cf. IETF RFC 5102 Section 5.11.3. */
+enum ipfix_flow_end_reason {
+ IDLE_TIMEOUT = 0x01,
+ ACTIVE_TIMEOUT = 0x02,
+ END_OF_FLOW_DETECTED = 0x03,
+ FORCED_END = 0x04,
+ LACK_OF_RESOURCES = 0x05
+};
+
+/* Part of data record for common aggregated elements. */
+OVS_PACKED(
+struct ipfix_data_record_aggregated_common {
+ ovs_be32 flow_start_delta_microseconds; /* FLOW_START_DELTA_MICROSECONDS */
+ ovs_be32 flow_end_delta_microseconds; /* FLOW_END_DELTA_MICROSECONDS */
+ ovs_be64 packet_delta_count; /* PACKET_DELTA_COUNT */
+ ovs_be64 layer2_octet_delta_count; /* LAYER2_OCTET_DELTA_COUNT */
+ uint8_t flow_end_reason; /* FLOW_END_REASON */
+});
+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) == 32);
+
+/*
+ * support tunnel key for:
+ * VxLAN: 24-bit VIN,
+ * GRE: 32-bit key,
+ * LISP: 24-bit instance ID
+ * STT: 64-bit key
+ */
+#define MAX_TUNNEL_KEY_LEN 8
+
+#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)) \
+ + sizeof(struct ipfix_data_record_flow_key_tunnel) \
+ + MAX_TUNNEL_KEY_LEN)
+
+#define MAX_DATA_RECORD_LEN \
+ (MAX_FLOW_KEY_LEN \
+ + sizeof(struct ipfix_data_record_aggregated_common) \
+ + sizeof(struct ipfix_data_record_aggregated_ip))
+
+/* Max length of a data set. To simplify the implementation, each
+ * data record is sent in a separate data set, so each data set
+ * contains at most one data record. */
+#define MAX_DATA_SET_LEN \
+ (sizeof(struct ipfix_set_header) \
+ + MAX_DATA_RECORD_LEN)
+
+/* Max length of an IPFIX message. Arbitrarily set to accommodate low
+ * MTU. */
+#define MAX_MESSAGE_LEN 1024
+
+/* Cache structures. */
+
+/* Flow key. */
+struct ipfix_flow_key {
+ uint32_t obs_domain_id;
+ uint16_t template_id;
+ size_t flow_key_msg_part_size;
+ uint64_t flow_key_msg_part[DIV_ROUND_UP(MAX_FLOW_KEY_LEN, 8)];
+};
+
+/* Flow cache entry. */
+struct ipfix_flow_cache_entry {
+ struct hmap_node flow_key_map_node;
+ struct ovs_list cache_flow_start_timestamp_list_node;
+ struct ipfix_flow_key flow_key;
+ /* Common aggregated elements. */
+ uint64_t flow_start_timestamp_usec;
+ 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. */
+};
+
+static void dpif_ipfix_cache_expire(struct dpif_ipfix_exporter *, bool,
+ const uint64_t, const uint32_t);
+
+static void get_export_time_now(uint64_t *, uint32_t *);
+
+static void dpif_ipfix_cache_expire_now(struct dpif_ipfix_exporter *, bool);