VLOG_DEFINE_THIS_MODULE(ipfix);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
/* Cf. IETF RFC 5101 Section 10.3.4. */
#define IPFIX_DEFAULT_COLLECTOR_PORT 4739
struct dpif_ipfix {
struct dpif_ipfix_bridge_exporter bridge_exporter;
struct hmap flow_exporter_map; /* dpif_ipfix_flow_exporter_map_nodes. */
- int ref_cnt;
+ atomic_int ref_cnt;
};
#define IPFIX_VERSION 0x000a
#define IPFIX_TEMPLATE_INTERVAL 600
/* Cf. IETF RFC 5101 Section 3.1. */
+OVS_PACKED(
struct ipfix_header {
ovs_be16 version; /* IPFIX_VERSION. */
ovs_be16 length; /* Length in bytes including this header. */
ovs_be32 export_time; /* Seconds since the epoch. */
ovs_be32 seq_number; /* Message sequence number. */
ovs_be32 obs_domain_id; /* Observation Domain ID. */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_header) == 16);
#define IPFIX_SET_ID_TEMPLATE 2
#define IPFIX_SET_ID_OPTION_TEMPLATE 3
/* Cf. IETF RFC 5101 Section 3.3.2. */
+OVS_PACKED(
struct ipfix_set_header {
ovs_be16 set_id; /* IPFIX_SET_ID_* or valid template ID for Data Sets. */
ovs_be16 length; /* Length of the set in bytes including header. */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_set_header) == 4);
/* Alternatives for templates at each layer. A template is defined by
#define IPFIX_TEMPLATE_ID_MIN 256
/* Cf. IETF RFC 5101 Section 3.4.1. */
+OVS_PACKED(
struct ipfix_template_record_header {
ovs_be16 template_id;
ovs_be16 field_count;
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_template_record_header) == 4);
enum ipfix_entity_id {
#include "ofproto/ipfix-entities.def"
};
+OVS_PACKED(
struct ipfix_template_field_specifier {
ovs_be16 element_id; /* IPFIX_ENTITY_ID_*. */
ovs_be16 field_length; /* Length of the field's value, in bytes. */
/* No Enterprise ID, since only standard element IDs are specified. */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_template_field_specifier) == 4);
/* Part of data record for common metadata and Ethernet entities. */
+OVS_PACKED(
struct ipfix_data_record_common {
ovs_be32 observation_point_id; /* OBSERVATION_POINT_ID */
ovs_be64 packet_delta_count; /* PACKET_DELTA_COUNT */
ovs_be16 ethernet_type; /* ETHERNET_TYPE */
ovs_be16 ethernet_total_length; /* ETHERNET_TOTAL_LENGTH */
uint8_t ethernet_header_length; /* ETHERNET_HEADER_LENGTH */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_common) == 37);
/* Part of data record for VLAN entities. */
+OVS_PACKED(
struct ipfix_data_record_vlan {
ovs_be16 vlan_id; /* VLAN_ID */
ovs_be16 dot1q_vlan_id; /* DOT1Q_VLAN_ID */
uint8_t dot1q_priority; /* DOT1Q_PRIORITY */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_vlan) == 5);
/* Part of data record for IP entities. */
+OVS_PACKED(
struct ipfix_data_record_ip {
uint8_t ip_version; /* IP_VERSION */
uint8_t ip_ttl; /* IP_TTL */
uint8_t ip_diff_serv_code_point; /* IP_DIFF_SERV_CODE_POINT */
uint8_t ip_precedence; /* IP_PRECEDENCE */
uint8_t ip_class_of_service; /* IP_CLASS_OF_SERVICE */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ip) == 6);
/* Part of data record for IPv4 entities. */
+OVS_PACKED(
struct ipfix_data_record_ipv4 {
ovs_be32 source_ipv4_address; /* SOURCE_IPV4_ADDRESS */
ovs_be32 destination_ipv4_address; /* DESTINATION_IPV4_ADDRESS */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ipv4) == 8);
/* Part of data record for IPv4 entities. */
+OVS_PACKED(
struct ipfix_data_record_ipv6 {
uint8_t source_ipv6_address[16]; /* SOURCE_IPV6_ADDRESS */
uint8_t destination_ipv6_address[16]; /* DESTINATION_IPV6_ADDRESS */
ovs_be32 flow_label_ipv6; /* FLOW_LABEL_IPV6 */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ipv6) == 36);
/* Part of data record for TCP/UDP entities. */
+OVS_PACKED(
struct ipfix_data_record_tcpudp {
ovs_be16 source_transport_port; /* SOURCE_TRANSPORT_PORT */
ovs_be16 destination_transport_port; /* DESTINATION_TRANSPORT_PORT */
-} __attribute__((packed));
+});
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_tcpudp) == 4);
static bool
struct dpif_ipfix *di,
const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options,
const struct ofproto_ipfix_flow_exporter_options *flow_exporters_options,
- size_t n_flow_exporters_options)
+ size_t n_flow_exporters_options) OVS_EXCLUDED(mutex)
{
int i;
struct ofproto_ipfix_flow_exporter_options *options;
struct dpif_ipfix_flow_exporter_map_node *node, *next;
size_t n_broken_flow_exporters_options = 0;
+ ovs_mutex_lock(&mutex);
dpif_ipfix_bridge_exporter_set_options(&di->bridge_exporter,
bridge_exporter_options);
ovs_assert(hmap_count(&di->flow_exporter_map) ==
(n_flow_exporters_options - n_broken_flow_exporters_options));
+ ovs_mutex_unlock(&mutex);
}
struct dpif_ipfix *
di = xzalloc(sizeof *di);
dpif_ipfix_exporter_clear(&di->bridge_exporter.exporter);
hmap_init(&di->flow_exporter_map);
- di->ref_cnt = 1;
+ atomic_init(&di->ref_cnt, 1);
return di;
}
{
struct dpif_ipfix *di = CONST_CAST(struct dpif_ipfix *, di_);
if (di) {
- ovs_assert(di->ref_cnt > 0);
- di->ref_cnt++;
+ int orig;
+ atomic_add(&di->ref_cnt, 1, &orig);
+ ovs_assert(orig > 0);
}
return di;
}
uint32_t
dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix *di)
+ OVS_EXCLUDED(mutex)
{
- return di->bridge_exporter.probability;
+ uint32_t ret;
+ ovs_mutex_lock(&mutex);
+ ret = di->bridge_exporter.probability;
+ ovs_mutex_unlock(&mutex);
+ return ret;
}
static void
-dpif_ipfix_clear(struct dpif_ipfix *di)
+dpif_ipfix_clear(struct dpif_ipfix *di) OVS_REQUIRES(mutex)
{
struct dpif_ipfix_flow_exporter_map_node *node, *next;
}
void
-dpif_ipfix_unref(struct dpif_ipfix *di)
+dpif_ipfix_unref(struct dpif_ipfix *di) OVS_EXCLUDED(mutex)
{
+ int orig;
+
if (!di) {
return;
}
- ovs_assert(di->ref_cnt > 0);
- if (!--di->ref_cnt) {
+ atomic_sub(&di->ref_cnt, 1, &orig);
+ ovs_assert(orig > 0);
+ if (orig == 1) {
+ ovs_mutex_lock(&mutex);
dpif_ipfix_clear(di);
hmap_destroy(&di->flow_exporter_map);
free(di);
+ ovs_mutex_unlock(&mutex);
}
}
void
dpif_ipfix_bridge_sample(struct dpif_ipfix *di, struct ofpbuf *packet,
- const struct flow *flow)
+ const struct flow *flow) OVS_EXCLUDED(mutex)
{
+ uint64_t packet_delta_count;
+
+ ovs_mutex_lock(&mutex);
/* Use the sampling probability as an approximation of the number
* of matched packets. */
- uint64_t packet_delta_count = UINT32_MAX / di->bridge_exporter.probability;
-
+ packet_delta_count = UINT32_MAX / di->bridge_exporter.probability;
dpif_ipfix_sample(&di->bridge_exporter.exporter, packet, flow,
packet_delta_count,
di->bridge_exporter.options->obs_domain_id,
di->bridge_exporter.options->obs_point_id);
+ ovs_mutex_unlock(&mutex);
}
void
dpif_ipfix_flow_sample(struct dpif_ipfix *di, struct ofpbuf *packet,
const struct flow *flow, uint32_t collector_set_id,
uint16_t probability, uint32_t obs_domain_id,
- uint32_t obs_point_id)
+ uint32_t obs_point_id) OVS_EXCLUDED(mutex)
{
struct dpif_ipfix_flow_exporter_map_node *node;
/* Use the sampling probability as an approximation of the number
* of matched packets. */
uint64_t packet_delta_count = USHRT_MAX / probability;
+ ovs_mutex_lock(&mutex);
node = dpif_ipfix_find_flow_exporter_map_node(di, collector_set_id);
-
- if (!node) {
- return;
+ if (node) {
+ dpif_ipfix_sample(&node->exporter.exporter, packet, flow,
+ packet_delta_count, obs_domain_id, obs_point_id);
}
-
- dpif_ipfix_sample(&node->exporter.exporter, packet, flow,
- packet_delta_count, obs_domain_id, obs_point_id);
+ ovs_mutex_unlock(&mutex);
}