2 * Copyright (c) 2012 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "ofproto-dpif-ipfix.h"
20 #include "byte-order.h"
21 #include "collectors.h"
29 #include "poll-loop.h"
36 VLOG_DEFINE_THIS_MODULE(ipfix
);
38 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
39 static struct ovs_mutex mutex
= OVS_MUTEX_INITIALIZER
;
41 /* Cf. IETF RFC 5101 Section 10.3.4. */
42 #define IPFIX_DEFAULT_COLLECTOR_PORT 4739
44 struct dpif_ipfix_exporter
{
45 struct collectors
*collectors
;
47 time_t last_template_set_time
;
48 struct hmap cache_flow_key_map
; /* ipfix_flow_cache_entry. */
49 struct list cache_flow_start_timestamp_list
; /* ipfix_flow_cache_entry. */
50 uint32_t cache_active_timeout
; /* In seconds. */
51 uint32_t cache_max_flows
;
54 struct dpif_ipfix_bridge_exporter
{
55 struct dpif_ipfix_exporter exporter
;
56 struct ofproto_ipfix_bridge_exporter_options
*options
;
60 struct dpif_ipfix_flow_exporter
{
61 struct dpif_ipfix_exporter exporter
;
62 struct ofproto_ipfix_flow_exporter_options
*options
;
65 struct dpif_ipfix_flow_exporter_map_node
{
66 struct hmap_node node
;
67 struct dpif_ipfix_flow_exporter exporter
;
71 struct dpif_ipfix_bridge_exporter bridge_exporter
;
72 struct hmap flow_exporter_map
; /* dpif_ipfix_flow_exporter_map_node. */
76 #define IPFIX_VERSION 0x000a
78 /* When using UDP, IPFIX Template Records must be re-sent regularly.
79 * The standard default interval is 10 minutes (600 seconds).
80 * Cf. IETF RFC 5101 Section 10.3.6. */
81 #define IPFIX_TEMPLATE_INTERVAL 600
83 /* Cf. IETF RFC 5101 Section 3.1. */
86 ovs_be16 version
; /* IPFIX_VERSION. */
87 ovs_be16 length
; /* Length in bytes including this header. */
88 ovs_be32 export_time
; /* Seconds since the epoch. */
89 ovs_be32 seq_number
; /* Message sequence number. */
90 ovs_be32 obs_domain_id
; /* Observation Domain ID. */
92 BUILD_ASSERT_DECL(sizeof(struct ipfix_header
) == 16);
94 #define IPFIX_SET_ID_TEMPLATE 2
95 #define IPFIX_SET_ID_OPTION_TEMPLATE 3
97 /* Cf. IETF RFC 5101 Section 3.3.2. */
99 struct ipfix_set_header
{
100 ovs_be16 set_id
; /* IPFIX_SET_ID_* or valid template ID for Data Sets. */
101 ovs_be16 length
; /* Length of the set in bytes including header. */
103 BUILD_ASSERT_DECL(sizeof(struct ipfix_set_header
) == 4);
105 /* Alternatives for templates at each layer. A template is defined by
106 * a combination of one value for each layer. */
107 enum ipfix_proto_l2
{
108 IPFIX_PROTO_L2_ETH
= 0, /* No VLAN. */
112 enum ipfix_proto_l3
{
113 IPFIX_PROTO_L3_UNKNOWN
= 0,
118 enum ipfix_proto_l4
{
119 IPFIX_PROTO_L4_UNKNOWN
= 0,
120 IPFIX_PROTO_L4_TCP_UDP
,
124 /* Any Template ID > 255 is usable for Template Records. */
125 #define IPFIX_TEMPLATE_ID_MIN 256
127 /* Cf. IETF RFC 5101 Section 3.4.1. */
129 struct ipfix_template_record_header
{
130 ovs_be16 template_id
;
131 ovs_be16 field_count
;
133 BUILD_ASSERT_DECL(sizeof(struct ipfix_template_record_header
) == 4);
135 enum ipfix_entity_id
{
136 #define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) IPFIX_ENTITY_ID_##ENUM = ID,
137 #include "ofproto/ipfix-entities.def"
140 enum ipfix_entity_size
{
141 #define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) IPFIX_ENTITY_SIZE_##ENUM = SIZE,
142 #include "ofproto/ipfix-entities.def"
146 struct ipfix_template_field_specifier
{
147 ovs_be16 element_id
; /* IPFIX_ENTITY_ID_*. */
148 ovs_be16 field_length
; /* Length of the field's value, in bytes. */
149 /* No Enterprise ID, since only standard element IDs are specified. */
151 BUILD_ASSERT_DECL(sizeof(struct ipfix_template_field_specifier
) == 4);
153 /* Part of data record flow key for common metadata and Ethernet entities. */
155 struct ipfix_data_record_flow_key_common
{
156 ovs_be32 observation_point_id
; /* OBSERVATION_POINT_ID */
157 uint8_t source_mac_address
[6]; /* SOURCE_MAC_ADDRESS */
158 uint8_t destination_mac_address
[6]; /* DESTINATION_MAC_ADDRESS */
159 ovs_be16 ethernet_type
; /* ETHERNET_TYPE */
160 uint8_t ethernet_header_length
; /* ETHERNET_HEADER_LENGTH */
162 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_common
) == 19);
164 /* Part of data record flow key for VLAN entities. */
166 struct ipfix_data_record_flow_key_vlan
{
167 ovs_be16 vlan_id
; /* VLAN_ID */
168 ovs_be16 dot1q_vlan_id
; /* DOT1Q_VLAN_ID */
169 uint8_t dot1q_priority
; /* DOT1Q_PRIORITY */
171 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_vlan
) == 5);
173 /* Part of data record flow key for IP entities. */
174 /* XXX: Replace IP_TTL with MINIMUM_TTL and MAXIMUM_TTL? */
176 struct ipfix_data_record_flow_key_ip
{
177 uint8_t ip_version
; /* IP_VERSION */
178 uint8_t ip_ttl
; /* IP_TTL */
179 uint8_t protocol_identifier
; /* PROTOCOL_IDENTIFIER */
180 uint8_t ip_diff_serv_code_point
; /* IP_DIFF_SERV_CODE_POINT */
181 uint8_t ip_precedence
; /* IP_PRECEDENCE */
182 uint8_t ip_class_of_service
; /* IP_CLASS_OF_SERVICE */
184 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_ip
) == 6);
186 /* Part of data record flow key for IPv4 entities. */
188 struct ipfix_data_record_flow_key_ipv4
{
189 ovs_be32 source_ipv4_address
; /* SOURCE_IPV4_ADDRESS */
190 ovs_be32 destination_ipv4_address
; /* DESTINATION_IPV4_ADDRESS */
192 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_ipv4
) == 8);
194 /* Part of data record flow key for IPv6 entities. */
196 struct ipfix_data_record_flow_key_ipv6
{
197 uint8_t source_ipv6_address
[16]; /* SOURCE_IPV6_ADDRESS */
198 uint8_t destination_ipv6_address
[16]; /* DESTINATION_IPV6_ADDRESS */
199 ovs_be32 flow_label_ipv6
; /* FLOW_LABEL_IPV6 */
201 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_ipv6
) == 36);
203 /* Part of data record flow key for TCP/UDP entities. */
205 struct ipfix_data_record_flow_key_tcpudp
{
206 ovs_be16 source_transport_port
; /* SOURCE_TRANSPORT_PORT */
207 ovs_be16 destination_transport_port
; /* DESTINATION_TRANSPORT_PORT */
209 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_flow_key_tcpudp
) == 4);
211 /* Cf. IETF RFC 5102 Section 5.11.3. */
212 enum ipfix_flow_end_reason
{
214 ACTIVE_TIMEOUT
= 0x02,
215 END_OF_FLOW_DETECTED
= 0x03,
217 LACK_OF_RESOURCES
= 0x05
220 /* Part of data record for common aggregated elements. */
222 struct ipfix_data_record_aggregated_common
{
223 ovs_be32 flow_start_delta_microseconds
; /* FLOW_START_DELTA_MICROSECONDS */
224 ovs_be32 flow_end_delta_microseconds
; /* FLOW_END_DELTA_MICROSECONDS */
225 ovs_be64 packet_delta_count
; /* PACKET_DELTA_COUNT */
226 ovs_be64 layer2_octet_delta_count
; /* LAYER2_OCTET_DELTA_COUNT */
227 uint8_t flow_end_reason
; /* FLOW_END_REASON */
229 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_common
) == 25);
231 /* Part of data record for IP aggregated elements. */
233 struct ipfix_data_record_aggregated_ip
{
234 ovs_be64 octet_delta_sum_of_squares
; /* OCTET_DELTA_SUM_OF_SQUARES */
235 ovs_be64 minimum_ip_total_length
; /* MINIMUM_IP_TOTAL_LENGTH */
236 ovs_be64 maximum_ip_total_length
; /* MAXIMUM_IP_TOTAL_LENGTH */
238 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_ip
) == 24);
240 #define MAX_FLOW_KEY_LEN \
241 (sizeof(struct ipfix_data_record_flow_key_common) \
242 + sizeof(struct ipfix_data_record_flow_key_vlan) \
243 + sizeof(struct ipfix_data_record_flow_key_ip) \
244 + sizeof(struct ipfix_data_record_flow_key_ipv6) \
245 + sizeof(struct ipfix_data_record_flow_key_tcpudp))
247 #define MAX_DATA_RECORD_LEN \
249 + sizeof(struct ipfix_data_record_aggregated_common) \
250 + sizeof(struct ipfix_data_record_aggregated_ip))
252 /* Max length of a data set. To simplify the implementation, each
253 * data record is sent in a separate data set, so each data set
254 * contains at most one data record. */
255 #define MAX_DATA_SET_LEN \
256 (sizeof(struct ipfix_set_header) \
257 + MAX_DATA_RECORD_LEN)
259 /* Max length of an IPFIX message. Arbitrarily set to accomodate low
261 #define MAX_MESSAGE_LEN 1024
263 /* Cache structures. */
266 struct ipfix_flow_key
{
267 uint32_t obs_domain_id
;
268 uint16_t template_id
;
269 size_t flow_key_msg_part_size
;
270 uint64_t flow_key_msg_part
[DIV_ROUND_UP(MAX_FLOW_KEY_LEN
, 8)];
273 /* Flow cache entry. */
274 struct ipfix_flow_cache_entry
{
275 struct hmap_node flow_key_map_node
;
276 struct list cache_flow_start_timestamp_list_node
;
277 struct ipfix_flow_key flow_key
;
278 /* Common aggregated elements. */
279 uint64_t flow_start_timestamp_usec
;
280 uint64_t flow_end_timestamp_usec
;
281 uint64_t packet_delta_count
;
282 uint64_t layer2_octet_delta_count
;
283 uint64_t octet_delta_sum_of_squares
; /* 0 if not IP. */
284 uint16_t minimum_ip_total_length
; /* 0 if not IP. */
285 uint16_t maximum_ip_total_length
; /* 0 if not IP. */
288 static void dpif_ipfix_cache_expire(struct dpif_ipfix_exporter
*, bool,
289 const uint64_t, const uint32_t);
291 static void get_export_time_now(uint64_t *, uint32_t *);
293 static void dpif_ipfix_cache_expire_now(struct dpif_ipfix_exporter
*, bool);
296 ofproto_ipfix_bridge_exporter_options_equal(
297 const struct ofproto_ipfix_bridge_exporter_options
*a
,
298 const struct ofproto_ipfix_bridge_exporter_options
*b
)
300 return (a
->obs_domain_id
== b
->obs_domain_id
301 && a
->obs_point_id
== b
->obs_point_id
302 && a
->sampling_rate
== b
->sampling_rate
303 && a
->cache_active_timeout
== b
->cache_active_timeout
304 && a
->cache_max_flows
== b
->cache_max_flows
305 && sset_equals(&a
->targets
, &b
->targets
));
308 static struct ofproto_ipfix_bridge_exporter_options
*
309 ofproto_ipfix_bridge_exporter_options_clone(
310 const struct ofproto_ipfix_bridge_exporter_options
*old
)
312 struct ofproto_ipfix_bridge_exporter_options
*new =
313 xmemdup(old
, sizeof *old
);
314 sset_clone(&new->targets
, &old
->targets
);
319 ofproto_ipfix_bridge_exporter_options_destroy(
320 struct ofproto_ipfix_bridge_exporter_options
*options
)
323 sset_destroy(&options
->targets
);
329 ofproto_ipfix_flow_exporter_options_equal(
330 const struct ofproto_ipfix_flow_exporter_options
*a
,
331 const struct ofproto_ipfix_flow_exporter_options
*b
)
333 return (a
->collector_set_id
== b
->collector_set_id
334 && a
->cache_active_timeout
== b
->cache_active_timeout
335 && a
->cache_max_flows
== b
->cache_max_flows
336 && sset_equals(&a
->targets
, &b
->targets
));
339 static struct ofproto_ipfix_flow_exporter_options
*
340 ofproto_ipfix_flow_exporter_options_clone(
341 const struct ofproto_ipfix_flow_exporter_options
*old
)
343 struct ofproto_ipfix_flow_exporter_options
*new =
344 xmemdup(old
, sizeof *old
);
345 sset_clone(&new->targets
, &old
->targets
);
350 ofproto_ipfix_flow_exporter_options_destroy(
351 struct ofproto_ipfix_flow_exporter_options
*options
)
354 sset_destroy(&options
->targets
);
360 dpif_ipfix_exporter_init(struct dpif_ipfix_exporter
*exporter
)
362 exporter
->collectors
= NULL
;
363 exporter
->seq_number
= 1;
364 exporter
->last_template_set_time
= TIME_MIN
;
365 hmap_init(&exporter
->cache_flow_key_map
);
366 list_init(&exporter
->cache_flow_start_timestamp_list
);
367 exporter
->cache_active_timeout
= 0;
368 exporter
->cache_max_flows
= 0;
372 dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter
*exporter
)
374 /* Flush the cache with flow end reason "forced end." */
375 dpif_ipfix_cache_expire_now(exporter
, true);
377 collectors_destroy(exporter
->collectors
);
378 exporter
->collectors
= NULL
;
379 exporter
->seq_number
= 1;
380 exporter
->last_template_set_time
= TIME_MIN
;
381 exporter
->cache_active_timeout
= 0;
382 exporter
->cache_max_flows
= 0;
386 dpif_ipfix_exporter_destroy(struct dpif_ipfix_exporter
*exporter
)
388 dpif_ipfix_exporter_clear(exporter
);
389 hmap_destroy(&exporter
->cache_flow_key_map
);
393 dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter
*exporter
,
394 const struct sset
*targets
,
395 const uint32_t cache_active_timeout
,
396 const uint32_t cache_max_flows
)
398 collectors_destroy(exporter
->collectors
);
399 collectors_create(targets
, IPFIX_DEFAULT_COLLECTOR_PORT
,
400 &exporter
->collectors
);
401 if (exporter
->collectors
== NULL
) {
402 VLOG_WARN_RL(&rl
, "no collectors could be initialized, "
403 "IPFIX exporter disabled");
404 dpif_ipfix_exporter_clear(exporter
);
407 exporter
->cache_active_timeout
= cache_active_timeout
;
408 exporter
->cache_max_flows
= cache_max_flows
;
413 dpif_ipfix_bridge_exporter_init(struct dpif_ipfix_bridge_exporter
*exporter
)
415 dpif_ipfix_exporter_init(&exporter
->exporter
);
416 exporter
->options
= NULL
;
417 exporter
->probability
= 0;
421 dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter
*exporter
)
423 dpif_ipfix_exporter_clear(&exporter
->exporter
);
424 ofproto_ipfix_bridge_exporter_options_destroy(exporter
->options
);
425 exporter
->options
= NULL
;
426 exporter
->probability
= 0;
430 dpif_ipfix_bridge_exporter_destroy(struct dpif_ipfix_bridge_exporter
*exporter
)
432 dpif_ipfix_bridge_exporter_clear(exporter
);
433 dpif_ipfix_exporter_destroy(&exporter
->exporter
);
437 dpif_ipfix_bridge_exporter_set_options(
438 struct dpif_ipfix_bridge_exporter
*exporter
,
439 const struct ofproto_ipfix_bridge_exporter_options
*options
)
441 bool options_changed
;
443 if (!options
|| sset_is_empty(&options
->targets
)) {
444 /* No point in doing any work if there are no targets. */
445 dpif_ipfix_bridge_exporter_clear(exporter
);
451 || !ofproto_ipfix_bridge_exporter_options_equal(
452 options
, exporter
->options
));
454 /* Configure collectors if options have changed or if we're
455 * shortchanged in collectors (which indicates that opening one or
456 * more of the configured collectors failed, so that we should
459 || collectors_count(exporter
->exporter
.collectors
)
460 < sset_count(&options
->targets
)) {
461 if (!dpif_ipfix_exporter_set_options(
462 &exporter
->exporter
, &options
->targets
,
463 options
->cache_active_timeout
, options
->cache_max_flows
)) {
468 /* Avoid reconfiguring if options didn't change. */
469 if (!options_changed
) {
473 ofproto_ipfix_bridge_exporter_options_destroy(exporter
->options
);
474 exporter
->options
= ofproto_ipfix_bridge_exporter_options_clone(options
);
475 exporter
->probability
=
476 MAX(1, UINT32_MAX
/ exporter
->options
->sampling_rate
);
478 /* Run over the cache as some entries might have expired after
479 * changing the timeouts. */
480 dpif_ipfix_cache_expire_now(&exporter
->exporter
, false);
483 static struct dpif_ipfix_flow_exporter_map_node
*
484 dpif_ipfix_find_flow_exporter_map_node(
485 const struct dpif_ipfix
*di
, const uint32_t collector_set_id
)
488 struct dpif_ipfix_flow_exporter_map_node
*exporter_node
;
490 HMAP_FOR_EACH_WITH_HASH (exporter_node
, node
,
491 hash_int(collector_set_id
, 0),
492 &di
->flow_exporter_map
) {
493 if (exporter_node
->exporter
.options
->collector_set_id
494 == collector_set_id
) {
495 return exporter_node
;
503 dpif_ipfix_flow_exporter_init(struct dpif_ipfix_flow_exporter
*exporter
)
505 dpif_ipfix_exporter_init(&exporter
->exporter
);
506 exporter
->options
= NULL
;
510 dpif_ipfix_flow_exporter_clear(struct dpif_ipfix_flow_exporter
*exporter
)
512 dpif_ipfix_exporter_clear(&exporter
->exporter
);
513 ofproto_ipfix_flow_exporter_options_destroy(exporter
->options
);
514 exporter
->options
= NULL
;
518 dpif_ipfix_flow_exporter_destroy(struct dpif_ipfix_flow_exporter
*exporter
)
520 dpif_ipfix_flow_exporter_clear(exporter
);
521 dpif_ipfix_exporter_destroy(&exporter
->exporter
);
525 dpif_ipfix_flow_exporter_set_options(
526 struct dpif_ipfix_flow_exporter
*exporter
,
527 const struct ofproto_ipfix_flow_exporter_options
*options
)
529 bool options_changed
;
531 if (sset_is_empty(&options
->targets
)) {
532 /* No point in doing any work if there are no targets. */
533 dpif_ipfix_flow_exporter_clear(exporter
);
539 || !ofproto_ipfix_flow_exporter_options_equal(
540 options
, exporter
->options
));
542 /* Configure collectors if options have changed or if we're
543 * shortchanged in collectors (which indicates that opening one or
544 * more of the configured collectors failed, so that we should
547 || collectors_count(exporter
->exporter
.collectors
)
548 < sset_count(&options
->targets
)) {
549 if (!dpif_ipfix_exporter_set_options(
550 &exporter
->exporter
, &options
->targets
,
551 options
->cache_active_timeout
, options
->cache_max_flows
)) {
556 /* Avoid reconfiguring if options didn't change. */
557 if (!options_changed
) {
561 ofproto_ipfix_flow_exporter_options_destroy(exporter
->options
);
562 exporter
->options
= ofproto_ipfix_flow_exporter_options_clone(options
);
564 /* Run over the cache as some entries might have expired after
565 * changing the timeouts. */
566 dpif_ipfix_cache_expire_now(&exporter
->exporter
, false);
572 dpif_ipfix_set_options(
573 struct dpif_ipfix
*di
,
574 const struct ofproto_ipfix_bridge_exporter_options
*bridge_exporter_options
,
575 const struct ofproto_ipfix_flow_exporter_options
*flow_exporters_options
,
576 size_t n_flow_exporters_options
) OVS_EXCLUDED(mutex
)
579 struct ofproto_ipfix_flow_exporter_options
*options
;
580 struct dpif_ipfix_flow_exporter_map_node
*node
, *next
;
581 size_t n_broken_flow_exporters_options
= 0;
583 ovs_mutex_lock(&mutex
);
584 dpif_ipfix_bridge_exporter_set_options(&di
->bridge_exporter
,
585 bridge_exporter_options
);
587 /* Add new flow exporters and update current flow exporters. */
588 options
= (struct ofproto_ipfix_flow_exporter_options
*)
589 flow_exporters_options
;
590 for (i
= 0; i
< n_flow_exporters_options
; i
++) {
591 node
= dpif_ipfix_find_flow_exporter_map_node(
592 di
, options
->collector_set_id
);
594 node
= xzalloc(sizeof *node
);
595 dpif_ipfix_flow_exporter_init(&node
->exporter
);
596 hmap_insert(&di
->flow_exporter_map
, &node
->node
,
597 hash_int(options
->collector_set_id
, 0));
599 if (!dpif_ipfix_flow_exporter_set_options(&node
->exporter
, options
)) {
600 n_broken_flow_exporters_options
++;
605 ovs_assert(hmap_count(&di
->flow_exporter_map
) >=
606 (n_flow_exporters_options
- n_broken_flow_exporters_options
));
608 /* Remove dropped flow exporters, if any needs to be removed. */
609 if (hmap_count(&di
->flow_exporter_map
) > n_flow_exporters_options
) {
610 HMAP_FOR_EACH_SAFE (node
, next
, node
, &di
->flow_exporter_map
) {
611 /* This is slow but doesn't take any extra memory, and
612 * this table is not supposed to contain many rows anyway. */
613 options
= (struct ofproto_ipfix_flow_exporter_options
*)
614 flow_exporters_options
;
615 for (i
= 0; i
< n_flow_exporters_options
; i
++) {
616 if (node
->exporter
.options
->collector_set_id
617 == options
->collector_set_id
) {
622 if (i
== n_flow_exporters_options
) { // Not found.
623 hmap_remove(&di
->flow_exporter_map
, &node
->node
);
624 dpif_ipfix_flow_exporter_destroy(&node
->exporter
);
630 ovs_assert(hmap_count(&di
->flow_exporter_map
) ==
631 (n_flow_exporters_options
- n_broken_flow_exporters_options
));
632 ovs_mutex_unlock(&mutex
);
636 dpif_ipfix_create(void)
638 struct dpif_ipfix
*di
;
639 di
= xzalloc(sizeof *di
);
640 dpif_ipfix_bridge_exporter_init(&di
->bridge_exporter
);
641 hmap_init(&di
->flow_exporter_map
);
642 atomic_init(&di
->ref_cnt
, 1);
647 dpif_ipfix_ref(const struct dpif_ipfix
*di_
)
649 struct dpif_ipfix
*di
= CONST_CAST(struct dpif_ipfix
*, di_
);
652 atomic_add(&di
->ref_cnt
, 1, &orig
);
653 ovs_assert(orig
> 0);
659 dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix
*di
)
663 ovs_mutex_lock(&mutex
);
664 ret
= di
->bridge_exporter
.probability
;
665 ovs_mutex_unlock(&mutex
);
670 dpif_ipfix_clear(struct dpif_ipfix
*di
) OVS_REQUIRES(mutex
)
672 struct dpif_ipfix_flow_exporter_map_node
*exp_node
, *exp_next
;
674 dpif_ipfix_bridge_exporter_clear(&di
->bridge_exporter
);
676 HMAP_FOR_EACH_SAFE (exp_node
, exp_next
, node
, &di
->flow_exporter_map
) {
677 hmap_remove(&di
->flow_exporter_map
, &exp_node
->node
);
678 dpif_ipfix_flow_exporter_destroy(&exp_node
->exporter
);
684 dpif_ipfix_unref(struct dpif_ipfix
*di
) OVS_EXCLUDED(mutex
)
692 atomic_sub(&di
->ref_cnt
, 1, &orig
);
693 ovs_assert(orig
> 0);
695 ovs_mutex_lock(&mutex
);
696 dpif_ipfix_clear(di
);
697 dpif_ipfix_bridge_exporter_destroy(&di
->bridge_exporter
);
698 hmap_destroy(&di
->flow_exporter_map
);
700 ovs_mutex_unlock(&mutex
);
705 ipfix_init_header(uint32_t export_time_sec
, uint32_t seq_number
,
706 uint32_t obs_domain_id
, struct ofpbuf
*msg
)
708 struct ipfix_header
*hdr
;
710 hdr
= ofpbuf_put_zeros(msg
, sizeof *hdr
);
711 hdr
->version
= htons(IPFIX_VERSION
);
712 hdr
->length
= htons(sizeof *hdr
); /* Updated in ipfix_send_msg. */
713 hdr
->export_time
= htonl(export_time_sec
);
714 hdr
->seq_number
= htonl(seq_number
);
715 hdr
->obs_domain_id
= htonl(obs_domain_id
);
719 ipfix_send_msg(const struct collectors
*collectors
, struct ofpbuf
*msg
)
721 struct ipfix_header
*hdr
;
723 /* Adjust the length in the header. */
725 hdr
->length
= htons(msg
->size
);
727 collectors_send(collectors
, msg
->data
, msg
->size
);
732 ipfix_get_template_id(enum ipfix_proto_l2 l2
, enum ipfix_proto_l3 l3
,
733 enum ipfix_proto_l4 l4
)
735 uint16_t template_id
;
737 template_id
= template_id
* NUM_IPFIX_PROTO_L3
+ l3
;
738 template_id
= template_id
* NUM_IPFIX_PROTO_L4
+ l4
;
739 return IPFIX_TEMPLATE_ID_MIN
+ template_id
;
743 ipfix_define_template_entity(enum ipfix_entity_id id
,
744 enum ipfix_entity_size size
, struct ofpbuf
*msg
)
746 struct ipfix_template_field_specifier
*field
;
748 field
= ofpbuf_put_zeros(msg
, sizeof *field
);
749 field
->element_id
= htons(id
);
750 field
->field_length
= htons(size
);
754 ipfix_define_template_fields(enum ipfix_proto_l2 l2
, enum ipfix_proto_l3 l3
,
755 enum ipfix_proto_l4 l4
, struct ofpbuf
*msg
)
761 ipfix_define_template_entity(IPFIX_ENTITY_ID_##ID, \
762 IPFIX_ENTITY_SIZE_##ID, msg); \
768 DEF(OBSERVATION_POINT_ID
);
770 /* Common Ethernet entities. */
771 DEF(SOURCE_MAC_ADDRESS
);
772 DEF(DESTINATION_MAC_ADDRESS
);
774 DEF(ETHERNET_HEADER_LENGTH
);
776 if (l2
== IPFIX_PROTO_L2_VLAN
) {
782 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
785 DEF(PROTOCOL_IDENTIFIER
);
786 DEF(IP_DIFF_SERV_CODE_POINT
);
788 DEF(IP_CLASS_OF_SERVICE
);
790 if (l3
== IPFIX_PROTO_L3_IPV4
) {
791 DEF(SOURCE_IPV4_ADDRESS
);
792 DEF(DESTINATION_IPV4_ADDRESS
);
793 } else { /* l3 == IPFIX_PROTO_L3_IPV6 */
794 DEF(SOURCE_IPV6_ADDRESS
);
795 DEF(DESTINATION_IPV6_ADDRESS
);
796 DEF(FLOW_LABEL_IPV6
);
800 if (l4
!= IPFIX_PROTO_L4_UNKNOWN
) {
801 DEF(SOURCE_TRANSPORT_PORT
);
802 DEF(DESTINATION_TRANSPORT_PORT
);
805 /* 2. Flow aggregated data. */
807 DEF(FLOW_START_DELTA_MICROSECONDS
);
808 DEF(FLOW_END_DELTA_MICROSECONDS
);
809 DEF(PACKET_DELTA_COUNT
);
810 DEF(LAYER2_OCTET_DELTA_COUNT
);
811 DEF(FLOW_END_REASON
);
813 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
814 DEF(OCTET_DELTA_SUM_OF_SQUARES
);
815 DEF(MINIMUM_IP_TOTAL_LENGTH
);
816 DEF(MAXIMUM_IP_TOTAL_LENGTH
);
825 ipfix_send_template_msg(struct dpif_ipfix_exporter
*exporter
,
826 uint32_t export_time_sec
, uint32_t obs_domain_id
)
828 uint64_t msg_stub
[DIV_ROUND_UP(MAX_MESSAGE_LEN
, 8)];
830 size_t set_hdr_offset
, tmpl_hdr_offset
;
831 struct ipfix_set_header
*set_hdr
;
832 struct ipfix_template_record_header
*tmpl_hdr
;
833 uint16_t field_count
;
834 enum ipfix_proto_l2 l2
;
835 enum ipfix_proto_l3 l3
;
836 enum ipfix_proto_l4 l4
;
838 ofpbuf_use_stub(&msg
, msg_stub
, sizeof msg_stub
);
840 ipfix_init_header(export_time_sec
, exporter
->seq_number
, obs_domain_id
,
842 set_hdr_offset
= msg
.size
;
844 /* Add a Template Set. */
845 set_hdr
= ofpbuf_put_zeros(&msg
, sizeof *set_hdr
);
846 set_hdr
->set_id
= htons(IPFIX_SET_ID_TEMPLATE
);
848 /* Define one template for each possible combination of
850 for (l2
= 0; l2
< NUM_IPFIX_PROTO_L2
; l2
++) {
851 for (l3
= 0; l3
< NUM_IPFIX_PROTO_L3
; l3
++) {
852 for (l4
= 0; l4
< NUM_IPFIX_PROTO_L4
; l4
++) {
853 if (l3
== IPFIX_PROTO_L3_UNKNOWN
&&
854 l4
!= IPFIX_PROTO_L4_UNKNOWN
) {
857 tmpl_hdr_offset
= msg
.size
;
858 tmpl_hdr
= ofpbuf_put_zeros(&msg
, sizeof *tmpl_hdr
);
859 tmpl_hdr
->template_id
= htons(
860 ipfix_get_template_id(l2
, l3
, l4
));
861 field_count
= ipfix_define_template_fields(l2
, l3
, l4
, &msg
);
862 tmpl_hdr
= (struct ipfix_template_record_header
*)
863 ((uint8_t*)msg
.data
+ tmpl_hdr_offset
);
864 tmpl_hdr
->field_count
= htons(field_count
);
869 set_hdr
= (struct ipfix_set_header
*)((uint8_t*)msg
.data
+ set_hdr_offset
);
870 set_hdr
->length
= htons(msg
.size
- set_hdr_offset
);
872 /* XXX: Add Options Template Sets, at least to define a Flow Keys
873 * Option Template. */
875 ipfix_send_msg(exporter
->collectors
, &msg
);
880 static inline uint32_t
881 ipfix_hash_flow_key(const struct ipfix_flow_key
*flow_key
, uint32_t basis
)
884 hash
= hash_int(flow_key
->obs_domain_id
, basis
);
885 hash
= hash_int(flow_key
->template_id
, hash
);
886 hash
= hash_bytes(flow_key
->flow_key_msg_part
,
887 flow_key
->flow_key_msg_part_size
, hash
);
892 ipfix_flow_key_equal(const struct ipfix_flow_key
*a
,
893 const struct ipfix_flow_key
*b
)
895 /* The template ID determines the flow key size, so not need to
897 return (a
->obs_domain_id
== b
->obs_domain_id
898 && a
->template_id
== b
->template_id
899 && memcmp(a
->flow_key_msg_part
, b
->flow_key_msg_part
,
900 a
->flow_key_msg_part_size
) == 0);
903 static struct ipfix_flow_cache_entry
*
904 ipfix_cache_find_entry(const struct dpif_ipfix_exporter
*exporter
,
905 const struct ipfix_flow_key
*flow_key
)
907 struct ipfix_flow_cache_entry
*entry
;
909 HMAP_FOR_EACH_WITH_HASH (entry
, flow_key_map_node
,
910 ipfix_hash_flow_key(flow_key
, 0),
911 &exporter
->cache_flow_key_map
) {
912 if (ipfix_flow_key_equal(&entry
->flow_key
, flow_key
)) {
921 ipfix_cache_next_timeout_msec(const struct dpif_ipfix_exporter
*exporter
,
922 long long int *next_timeout_msec
)
924 struct ipfix_flow_cache_entry
*entry
;
926 LIST_FOR_EACH (entry
, cache_flow_start_timestamp_list_node
,
927 &exporter
->cache_flow_start_timestamp_list
) {
928 *next_timeout_msec
= entry
->flow_start_timestamp_usec
/ 1000LL
929 + 1000LL * exporter
->cache_active_timeout
;
937 ipfix_cache_aggregate_entries(struct ipfix_flow_cache_entry
*from_entry
,
938 struct ipfix_flow_cache_entry
*to_entry
)
940 uint64_t *to_start
, *to_end
, *from_start
, *from_end
;
941 uint16_t *to_min_len
, *to_max_len
, *from_min_len
, *from_max_len
;
943 to_start
= &to_entry
->flow_start_timestamp_usec
;
944 to_end
= &to_entry
->flow_end_timestamp_usec
;
945 from_start
= &from_entry
->flow_start_timestamp_usec
;
946 from_end
= &from_entry
->flow_end_timestamp_usec
;
948 if (*to_start
> *from_start
) {
949 *to_start
= *from_start
;
951 if (*to_end
< *from_end
) {
955 to_entry
->packet_delta_count
+= from_entry
->packet_delta_count
;
956 to_entry
->layer2_octet_delta_count
+= from_entry
->layer2_octet_delta_count
;
958 to_entry
->octet_delta_sum_of_squares
+=
959 from_entry
->octet_delta_sum_of_squares
;
961 to_min_len
= &to_entry
->minimum_ip_total_length
;
962 to_max_len
= &to_entry
->maximum_ip_total_length
;
963 from_min_len
= &from_entry
->minimum_ip_total_length
;
964 from_max_len
= &from_entry
->maximum_ip_total_length
;
966 if (!*to_min_len
|| (*from_min_len
&& *to_min_len
> *from_min_len
)) {
967 *to_min_len
= *from_min_len
;
969 if (*to_max_len
< *from_max_len
) {
970 *to_max_len
= *from_max_len
;
974 /* Add an entry into a flow cache. The entry is either aggregated into
975 * an existing entry with the same flow key and free()d, or it is
976 * inserted into the cache. */
978 ipfix_cache_update(struct dpif_ipfix_exporter
*exporter
,
979 struct ipfix_flow_cache_entry
*entry
)
981 struct ipfix_flow_cache_entry
*old_entry
;
983 old_entry
= ipfix_cache_find_entry(exporter
, &entry
->flow_key
);
985 if (old_entry
== NULL
) {
986 hmap_insert(&exporter
->cache_flow_key_map
, &entry
->flow_key_map_node
,
987 ipfix_hash_flow_key(&entry
->flow_key
, 0));
989 /* As the latest entry added into the cache, it should
990 * logically have the highest flow_start_timestamp_usec, so
991 * append it at the tail. */
992 list_push_back(&exporter
->cache_flow_start_timestamp_list
,
993 &entry
->cache_flow_start_timestamp_list_node
);
995 /* Enforce exporter->cache_max_flows limit. */
996 if (hmap_count(&exporter
->cache_flow_key_map
)
997 > exporter
->cache_max_flows
) {
998 dpif_ipfix_cache_expire_now(exporter
, false);
1001 ipfix_cache_aggregate_entries(entry
, old_entry
);
1007 ipfix_cache_entry_init(struct ipfix_flow_cache_entry
*entry
,
1008 struct ofpbuf
*packet
, const struct flow
*flow
,
1009 uint64_t packet_delta_count
, uint32_t obs_domain_id
,
1010 uint32_t obs_point_id
)
1012 struct ipfix_flow_key
*flow_key
;
1014 enum ipfix_proto_l2 l2
;
1015 enum ipfix_proto_l3 l3
;
1016 enum ipfix_proto_l4 l4
;
1017 uint8_t ethernet_header_length
;
1018 uint16_t ethernet_total_length
;
1020 flow_key
= &entry
->flow_key
;
1021 ofpbuf_use_stack(&msg
, flow_key
->flow_key_msg_part
,
1022 sizeof flow_key
->flow_key_msg_part
);
1024 /* Choose the right template ID matching the protocols in the
1025 * sampled packet. */
1026 l2
= (flow
->vlan_tci
== 0) ? IPFIX_PROTO_L2_ETH
: IPFIX_PROTO_L2_VLAN
;
1028 switch(ntohs(flow
->dl_type
)) {
1030 l3
= IPFIX_PROTO_L3_IPV4
;
1033 l3
= IPFIX_PROTO_L3_IPV6
;
1036 l3
= IPFIX_PROTO_L3_UNKNOWN
;
1039 l4
= IPFIX_PROTO_L4_UNKNOWN
;
1040 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
1041 switch(flow
->nw_proto
) {
1042 case IPPROTO_TCP
: /* TCP */
1043 case IPPROTO_UDP
: /* UDP */
1044 l4
= IPFIX_PROTO_L4_TCP_UDP
;
1049 flow_key
->obs_domain_id
= obs_domain_id
;
1050 flow_key
->template_id
= ipfix_get_template_id(l2
, l3
, l4
);
1052 /* The fields defined in the ipfix_data_record_* structs and sent
1053 * below must match exactly the templates defined in
1054 * ipfix_define_template_fields. */
1056 ethernet_header_length
= (l2
== IPFIX_PROTO_L2_VLAN
)
1057 ? VLAN_ETH_HEADER_LEN
: ETH_HEADER_LEN
;
1058 ethernet_total_length
= packet
->size
;
1060 /* Common Ethernet entities. */
1062 struct ipfix_data_record_flow_key_common
*data_common
;
1064 data_common
= ofpbuf_put_zeros(&msg
, sizeof *data_common
);
1065 data_common
->observation_point_id
= htonl(obs_point_id
);
1066 memcpy(data_common
->source_mac_address
, flow
->dl_src
,
1067 sizeof flow
->dl_src
);
1068 memcpy(data_common
->destination_mac_address
, flow
->dl_dst
,
1069 sizeof flow
->dl_dst
);
1070 data_common
->ethernet_type
= flow
->dl_type
;
1071 data_common
->ethernet_header_length
= ethernet_header_length
;
1074 if (l2
== IPFIX_PROTO_L2_VLAN
) {
1075 struct ipfix_data_record_flow_key_vlan
*data_vlan
;
1076 uint16_t vlan_id
= vlan_tci_to_vid(flow
->vlan_tci
);
1077 uint8_t priority
= vlan_tci_to_pcp(flow
->vlan_tci
);
1079 data_vlan
= ofpbuf_put_zeros(&msg
, sizeof *data_vlan
);
1080 data_vlan
->vlan_id
= htons(vlan_id
);
1081 data_vlan
->dot1q_vlan_id
= htons(vlan_id
);
1082 data_vlan
->dot1q_priority
= priority
;
1085 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
1086 struct ipfix_data_record_flow_key_ip
*data_ip
;
1088 data_ip
= ofpbuf_put_zeros(&msg
, sizeof *data_ip
);
1089 data_ip
->ip_version
= (l3
== IPFIX_PROTO_L3_IPV4
) ? 4 : 6;
1090 data_ip
->ip_ttl
= flow
->nw_ttl
;
1091 data_ip
->protocol_identifier
= flow
->nw_proto
;
1092 data_ip
->ip_diff_serv_code_point
= flow
->nw_tos
>> 2;
1093 data_ip
->ip_precedence
= flow
->nw_tos
>> 5;
1094 data_ip
->ip_class_of_service
= flow
->nw_tos
;
1096 if (l3
== IPFIX_PROTO_L3_IPV4
) {
1097 struct ipfix_data_record_flow_key_ipv4
*data_ipv4
;
1098 data_ipv4
= ofpbuf_put_zeros(&msg
, sizeof *data_ipv4
);
1099 data_ipv4
->source_ipv4_address
= flow
->nw_src
;
1100 data_ipv4
->destination_ipv4_address
= flow
->nw_dst
;
1101 } else { /* l3 == IPFIX_PROTO_L3_IPV6 */
1102 struct ipfix_data_record_flow_key_ipv6
*data_ipv6
;
1104 data_ipv6
= ofpbuf_put_zeros(&msg
, sizeof *data_ipv6
);
1105 memcpy(data_ipv6
->source_ipv6_address
, &flow
->ipv6_src
,
1106 sizeof flow
->ipv6_src
);
1107 memcpy(data_ipv6
->destination_ipv6_address
, &flow
->ipv6_dst
,
1108 sizeof flow
->ipv6_dst
);
1109 data_ipv6
->flow_label_ipv6
= flow
->ipv6_label
;
1113 if (l4
!= IPFIX_PROTO_L4_UNKNOWN
) {
1114 struct ipfix_data_record_flow_key_tcpudp
*data_tcpudp
;
1116 data_tcpudp
= ofpbuf_put_zeros(&msg
, sizeof *data_tcpudp
);
1117 data_tcpudp
->source_transport_port
= flow
->tp_src
;
1118 data_tcpudp
->destination_transport_port
= flow
->tp_dst
;
1121 flow_key
->flow_key_msg_part_size
= msg
.size
;
1125 uint64_t layer2_octet_delta_count
;
1127 /* Calculate the total matched octet count by considering as
1128 * an approximation that all matched packets have the same
1130 layer2_octet_delta_count
= packet_delta_count
* ethernet_total_length
;
1132 xgettimeofday(&now
);
1133 entry
->flow_end_timestamp_usec
= now
.tv_usec
+ 1000000LL * now
.tv_sec
;
1134 entry
->flow_start_timestamp_usec
= entry
->flow_end_timestamp_usec
;
1135 entry
->packet_delta_count
= packet_delta_count
;
1136 entry
->layer2_octet_delta_count
= layer2_octet_delta_count
;
1139 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
1140 uint16_t ip_total_length
=
1141 ethernet_total_length
- ethernet_header_length
;
1143 entry
->octet_delta_sum_of_squares
=
1144 packet_delta_count
* ip_total_length
* ip_total_length
;
1145 entry
->minimum_ip_total_length
= ip_total_length
;
1146 entry
->maximum_ip_total_length
= ip_total_length
;
1148 entry
->octet_delta_sum_of_squares
= 0;
1149 entry
->minimum_ip_total_length
= 0;
1150 entry
->maximum_ip_total_length
= 0;
1154 /* Send each single data record in its own data set, to simplify the
1155 * implementation by avoiding having to group record by template ID
1156 * before sending. */
1158 ipfix_put_data_set(uint32_t export_time_sec
,
1159 struct ipfix_flow_cache_entry
*entry
,
1160 enum ipfix_flow_end_reason flow_end_reason
,
1163 size_t set_hdr_offset
;
1164 struct ipfix_set_header
*set_hdr
;
1166 set_hdr_offset
= msg
->size
;
1168 /* Put a Data Set. */
1169 set_hdr
= ofpbuf_put_zeros(msg
, sizeof *set_hdr
);
1170 set_hdr
->set_id
= htons(entry
->flow_key
.template_id
);
1172 /* Copy the flow key part of the data record. */
1174 ofpbuf_put(msg
, entry
->flow_key
.flow_key_msg_part
,
1175 entry
->flow_key
.flow_key_msg_part_size
);
1177 /* Put the non-key part of the data record. */
1180 struct ipfix_data_record_aggregated_common
*data_aggregated_common
;
1181 uint64_t export_time_usec
, flow_start_delta_usec
, flow_end_delta_usec
;
1183 /* Calculate the negative deltas relative to the export time
1184 * in seconds sent in the header, not the exact export
1186 export_time_usec
= 1000000LL * export_time_sec
;
1187 flow_start_delta_usec
= export_time_usec
1188 - entry
->flow_start_timestamp_usec
;
1189 flow_end_delta_usec
= export_time_usec
1190 - entry
->flow_end_timestamp_usec
;
1192 data_aggregated_common
= ofpbuf_put_zeros(
1193 msg
, sizeof *data_aggregated_common
);
1194 data_aggregated_common
->flow_start_delta_microseconds
= htonl(
1195 flow_start_delta_usec
);
1196 data_aggregated_common
->flow_end_delta_microseconds
= htonl(
1197 flow_end_delta_usec
);
1198 data_aggregated_common
->packet_delta_count
= htonll(
1199 entry
->packet_delta_count
);
1200 data_aggregated_common
->layer2_octet_delta_count
= htonll(
1201 entry
->layer2_octet_delta_count
);
1202 data_aggregated_common
->flow_end_reason
= flow_end_reason
;
1205 if (entry
->octet_delta_sum_of_squares
) { /* IP packet. */
1206 struct ipfix_data_record_aggregated_ip
*data_aggregated_ip
;
1208 data_aggregated_ip
= ofpbuf_put_zeros(
1209 msg
, sizeof *data_aggregated_ip
);
1210 data_aggregated_ip
->octet_delta_sum_of_squares
= htonll(
1211 entry
->octet_delta_sum_of_squares
);
1212 data_aggregated_ip
->minimum_ip_total_length
= htonll(
1213 entry
->minimum_ip_total_length
);
1214 data_aggregated_ip
->maximum_ip_total_length
= htonll(
1215 entry
->maximum_ip_total_length
);
1218 set_hdr
= (struct ipfix_set_header
*)((uint8_t*)msg
->data
+ set_hdr_offset
);
1219 set_hdr
->length
= htons(msg
->size
- set_hdr_offset
);
1222 /* Send an IPFIX message with a single data record. */
1224 ipfix_send_data_msg(struct dpif_ipfix_exporter
*exporter
,
1225 uint32_t export_time_sec
,
1226 struct ipfix_flow_cache_entry
*entry
,
1227 enum ipfix_flow_end_reason flow_end_reason
)
1229 uint64_t msg_stub
[DIV_ROUND_UP(MAX_MESSAGE_LEN
, 8)];
1231 ofpbuf_use_stub(&msg
, msg_stub
, sizeof msg_stub
);
1233 ipfix_init_header(export_time_sec
, exporter
->seq_number
++,
1234 entry
->flow_key
.obs_domain_id
, &msg
);
1235 ipfix_put_data_set(export_time_sec
, entry
, flow_end_reason
, &msg
);
1236 ipfix_send_msg(exporter
->collectors
, &msg
);
1238 ofpbuf_uninit(&msg
);
1242 dpif_ipfix_sample(struct dpif_ipfix_exporter
*exporter
,
1243 struct ofpbuf
*packet
, const struct flow
*flow
,
1244 uint64_t packet_delta_count
, uint32_t obs_domain_id
,
1245 uint32_t obs_point_id
)
1247 struct ipfix_flow_cache_entry
*entry
;
1249 /* Create a flow cache entry from the sample. */
1250 entry
= xmalloc(sizeof *entry
);
1251 ipfix_cache_entry_init(entry
, packet
, flow
, packet_delta_count
,
1252 obs_domain_id
, obs_point_id
);
1253 ipfix_cache_update(exporter
, entry
);
1257 dpif_ipfix_bridge_sample(struct dpif_ipfix
*di
, struct ofpbuf
*packet
,
1258 const struct flow
*flow
) OVS_EXCLUDED(mutex
)
1260 uint64_t packet_delta_count
;
1262 ovs_mutex_lock(&mutex
);
1263 /* Use the sampling probability as an approximation of the number
1264 * of matched packets. */
1265 packet_delta_count
= UINT32_MAX
/ di
->bridge_exporter
.probability
;
1266 dpif_ipfix_sample(&di
->bridge_exporter
.exporter
, packet
, flow
,
1268 di
->bridge_exporter
.options
->obs_domain_id
,
1269 di
->bridge_exporter
.options
->obs_point_id
);
1270 ovs_mutex_unlock(&mutex
);
1274 dpif_ipfix_flow_sample(struct dpif_ipfix
*di
, struct ofpbuf
*packet
,
1275 const struct flow
*flow
, uint32_t collector_set_id
,
1276 uint16_t probability
, uint32_t obs_domain_id
,
1277 uint32_t obs_point_id
) OVS_EXCLUDED(mutex
)
1279 struct dpif_ipfix_flow_exporter_map_node
*node
;
1280 /* Use the sampling probability as an approximation of the number
1281 * of matched packets. */
1282 uint64_t packet_delta_count
= USHRT_MAX
/ probability
;
1284 ovs_mutex_lock(&mutex
);
1285 node
= dpif_ipfix_find_flow_exporter_map_node(di
, collector_set_id
);
1287 dpif_ipfix_sample(&node
->exporter
.exporter
, packet
, flow
,
1288 packet_delta_count
, obs_domain_id
, obs_point_id
);
1290 ovs_mutex_unlock(&mutex
);
1294 dpif_ipfix_cache_expire(struct dpif_ipfix_exporter
*exporter
,
1295 bool forced_end
, const uint64_t export_time_usec
,
1296 const uint32_t export_time_sec
)
1298 struct ipfix_flow_cache_entry
*entry
, *next_entry
;
1299 uint64_t max_flow_start_timestamp_usec
;
1300 bool template_msg_sent
= false;
1301 enum ipfix_flow_end_reason flow_end_reason
;
1303 if (list_is_empty(&exporter
->cache_flow_start_timestamp_list
)) {
1307 max_flow_start_timestamp_usec
= export_time_usec
-
1308 1000000LL * exporter
->cache_active_timeout
;
1310 LIST_FOR_EACH_SAFE (entry
, next_entry
, cache_flow_start_timestamp_list_node
,
1311 &exporter
->cache_flow_start_timestamp_list
) {
1313 flow_end_reason
= FORCED_END
;
1314 } else if (entry
->flow_start_timestamp_usec
1315 <= max_flow_start_timestamp_usec
) {
1316 flow_end_reason
= ACTIVE_TIMEOUT
;
1317 } else if (hmap_count(&exporter
->cache_flow_key_map
)
1318 > exporter
->cache_max_flows
) {
1319 /* Enforce exporter->cache_max_flows. */
1320 flow_end_reason
= LACK_OF_RESOURCES
;
1322 /* Remaining flows haven't expired yet. */
1326 list_remove(&entry
->cache_flow_start_timestamp_list_node
);
1327 hmap_remove(&exporter
->cache_flow_key_map
,
1328 &entry
->flow_key_map_node
);
1330 if (!template_msg_sent
1331 && (exporter
->last_template_set_time
+ IPFIX_TEMPLATE_INTERVAL
)
1332 <= export_time_sec
) {
1333 ipfix_send_template_msg(exporter
, export_time_sec
,
1334 entry
->flow_key
.obs_domain_id
);
1335 exporter
->last_template_set_time
= export_time_sec
;
1336 template_msg_sent
= true;
1339 /* XXX: Group multiple data records for the same obs domain id
1340 * into the same message. */
1341 ipfix_send_data_msg(exporter
, export_time_sec
, entry
, flow_end_reason
);
1347 get_export_time_now(uint64_t *export_time_usec
, uint32_t *export_time_sec
)
1349 struct timeval export_time
;
1350 xgettimeofday(&export_time
);
1352 *export_time_usec
= export_time
.tv_usec
+ 1000000LL * export_time
.tv_sec
;
1354 /* The IPFIX start and end deltas are negative deltas relative to
1355 * the export time, so set the export time 1 second off to
1356 * calculate those deltas. */
1357 if (export_time
.tv_usec
== 0) {
1358 *export_time_sec
= export_time
.tv_sec
;
1360 *export_time_sec
= export_time
.tv_sec
+ 1;
1365 dpif_ipfix_cache_expire_now(struct dpif_ipfix_exporter
*exporter
,
1368 uint64_t export_time_usec
;
1369 uint32_t export_time_sec
;
1371 get_export_time_now(&export_time_usec
, &export_time_sec
);
1372 dpif_ipfix_cache_expire(exporter
, forced_end
, export_time_usec
,
1377 dpif_ipfix_run(struct dpif_ipfix
*di
) OVS_EXCLUDED(mutex
)
1379 uint64_t export_time_usec
;
1380 uint32_t export_time_sec
;
1381 struct dpif_ipfix_flow_exporter_map_node
*flow_exporter_node
;
1383 ovs_mutex_lock(&mutex
);
1384 get_export_time_now(&export_time_usec
, &export_time_sec
);
1385 if (di
->bridge_exporter
.probability
> 0) { /* Bridge exporter enabled. */
1386 dpif_ipfix_cache_expire(
1387 &di
->bridge_exporter
.exporter
, false, export_time_usec
,
1390 HMAP_FOR_EACH (flow_exporter_node
, node
, &di
->flow_exporter_map
) {
1391 dpif_ipfix_cache_expire(
1392 &flow_exporter_node
->exporter
.exporter
, false, export_time_usec
,
1395 ovs_mutex_unlock(&mutex
);
1399 dpif_ipfix_wait(struct dpif_ipfix
*di
) OVS_EXCLUDED(mutex
)
1401 long long int next_timeout_msec
= LLONG_MAX
;
1402 struct dpif_ipfix_flow_exporter_map_node
*flow_exporter_node
;
1404 ovs_mutex_lock(&mutex
);
1405 if (di
->bridge_exporter
.probability
> 0) { /* Bridge exporter enabled. */
1406 if (ipfix_cache_next_timeout_msec(
1407 &di
->bridge_exporter
.exporter
, &next_timeout_msec
)) {
1408 poll_timer_wait_until(next_timeout_msec
);
1411 HMAP_FOR_EACH (flow_exporter_node
, node
, &di
->flow_exporter_map
) {
1412 if (ipfix_cache_next_timeout_msec(
1413 &flow_exporter_node
->exporter
.exporter
, &next_timeout_msec
)) {
1414 poll_timer_wait_until(next_timeout_msec
);
1417 ovs_mutex_unlock(&mutex
);