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"
19 #include "byte-order.h"
20 #include "collectors.h"
33 VLOG_DEFINE_THIS_MODULE(ipfix
);
35 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
37 /* Cf. IETF RFC 5101 Section 10.3.4. */
38 #define IPFIX_DEFAULT_COLLECTOR_PORT 4739
40 struct dpif_ipfix_exporter
{
41 struct collectors
*collectors
;
43 time_t last_template_set_time
;
46 struct dpif_ipfix_bridge_exporter
{
47 struct dpif_ipfix_exporter exporter
;
48 struct ofproto_ipfix_bridge_exporter_options
*options
;
52 struct dpif_ipfix_flow_exporter
{
53 struct dpif_ipfix_exporter exporter
;
54 struct ofproto_ipfix_flow_exporter_options
*options
;
57 struct dpif_ipfix_flow_exporter_map_node
{
58 struct hmap_node node
;
59 struct dpif_ipfix_flow_exporter exporter
;
63 struct dpif_ipfix_bridge_exporter bridge_exporter
;
64 struct hmap flow_exporter_map
; /* dpif_ipfix_flow_exporter_map_nodes. */
68 #define IPFIX_VERSION 0x000a
70 /* When using UDP, IPFIX Template Records must be re-sent regularly.
71 * The standard default interval is 10 minutes (600 seconds).
72 * Cf. IETF RFC 5101 Section 10.3.6. */
73 #define IPFIX_TEMPLATE_INTERVAL 600
75 /* Cf. IETF RFC 5101 Section 3.1. */
78 ovs_be16 version
; /* IPFIX_VERSION. */
79 ovs_be16 length
; /* Length in bytes including this header. */
80 ovs_be32 export_time
; /* Seconds since the epoch. */
81 ovs_be32 seq_number
; /* Message sequence number. */
82 ovs_be32 obs_domain_id
; /* Observation Domain ID. */
84 BUILD_ASSERT_DECL(sizeof(struct ipfix_header
) == 16);
86 #define IPFIX_SET_ID_TEMPLATE 2
87 #define IPFIX_SET_ID_OPTION_TEMPLATE 3
89 /* Cf. IETF RFC 5101 Section 3.3.2. */
91 struct ipfix_set_header
{
92 ovs_be16 set_id
; /* IPFIX_SET_ID_* or valid template ID for Data Sets. */
93 ovs_be16 length
; /* Length of the set in bytes including header. */
95 BUILD_ASSERT_DECL(sizeof(struct ipfix_set_header
) == 4);
97 /* Alternatives for templates at each layer. A template is defined by
98 * a combination of one value for each layer. */
100 IPFIX_PROTO_L2_ETH
= 0, /* No VLAN. */
104 enum ipfix_proto_l3
{
105 IPFIX_PROTO_L3_UNKNOWN
= 0,
110 enum ipfix_proto_l4
{
111 IPFIX_PROTO_L4_UNKNOWN
= 0,
112 IPFIX_PROTO_L4_TCP_UDP
,
116 /* Any Template ID > 255 is usable for Template Records. */
117 #define IPFIX_TEMPLATE_ID_MIN 256
119 /* Cf. IETF RFC 5101 Section 3.4.1. */
121 struct ipfix_template_record_header
{
122 ovs_be16 template_id
;
123 ovs_be16 field_count
;
125 BUILD_ASSERT_DECL(sizeof(struct ipfix_template_record_header
) == 4);
127 enum ipfix_entity_id
{
128 #define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) IPFIX_ENTITY_ID_##ENUM = ID,
129 #include "ofproto/ipfix-entities.def"
132 enum ipfix_entity_size
{
133 #define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) IPFIX_ENTITY_SIZE_##ENUM = SIZE,
134 #include "ofproto/ipfix-entities.def"
138 struct ipfix_template_field_specifier
{
139 ovs_be16 element_id
; /* IPFIX_ENTITY_ID_*. */
140 ovs_be16 field_length
; /* Length of the field's value, in bytes. */
141 /* No Enterprise ID, since only standard element IDs are specified. */
143 BUILD_ASSERT_DECL(sizeof(struct ipfix_template_field_specifier
) == 4);
145 /* Part of data record for common metadata and Ethernet entities. */
147 struct ipfix_data_record_common
{
148 ovs_be32 observation_point_id
; /* OBSERVATION_POINT_ID */
149 ovs_be64 packet_delta_count
; /* PACKET_DELTA_COUNT */
150 ovs_be64 layer2_octet_delta_count
; /* LAYER2_OCTET_DELTA_COUNT */
151 uint8_t source_mac_address
[6]; /* SOURCE_MAC_ADDRESS */
152 uint8_t destination_mac_address
[6]; /* DESTINATION_MAC_ADDRESS */
153 ovs_be16 ethernet_type
; /* ETHERNET_TYPE */
154 ovs_be16 ethernet_total_length
; /* ETHERNET_TOTAL_LENGTH */
155 uint8_t ethernet_header_length
; /* ETHERNET_HEADER_LENGTH */
157 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_common
) == 37);
159 /* Part of data record for VLAN entities. */
161 struct ipfix_data_record_vlan
{
162 ovs_be16 vlan_id
; /* VLAN_ID */
163 ovs_be16 dot1q_vlan_id
; /* DOT1Q_VLAN_ID */
164 uint8_t dot1q_priority
; /* DOT1Q_PRIORITY */
166 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_vlan
) == 5);
168 /* Part of data record for IP entities. */
170 struct ipfix_data_record_ip
{
171 uint8_t ip_version
; /* IP_VERSION */
172 uint8_t ip_ttl
; /* IP_TTL */
173 uint8_t protocol_identifier
; /* PROTOCOL_IDENTIFIER */
174 uint8_t ip_diff_serv_code_point
; /* IP_DIFF_SERV_CODE_POINT */
175 uint8_t ip_precedence
; /* IP_PRECEDENCE */
176 uint8_t ip_class_of_service
; /* IP_CLASS_OF_SERVICE */
178 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ip
) == 6);
180 /* Part of data record for IPv4 entities. */
182 struct ipfix_data_record_ipv4
{
183 ovs_be32 source_ipv4_address
; /* SOURCE_IPV4_ADDRESS */
184 ovs_be32 destination_ipv4_address
; /* DESTINATION_IPV4_ADDRESS */
186 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ipv4
) == 8);
188 /* Part of data record for IPv4 entities. */
190 struct ipfix_data_record_ipv6
{
191 uint8_t source_ipv6_address
[16]; /* SOURCE_IPV6_ADDRESS */
192 uint8_t destination_ipv6_address
[16]; /* DESTINATION_IPV6_ADDRESS */
193 ovs_be32 flow_label_ipv6
; /* FLOW_LABEL_IPV6 */
195 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ipv6
) == 36);
197 /* Part of data record for TCP/UDP entities. */
199 struct ipfix_data_record_tcpudp
{
200 ovs_be16 source_transport_port
; /* SOURCE_TRANSPORT_PORT */
201 ovs_be16 destination_transport_port
; /* DESTINATION_TRANSPORT_PORT */
203 BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_tcpudp
) == 4);
206 ofproto_ipfix_bridge_exporter_options_equal(
207 const struct ofproto_ipfix_bridge_exporter_options
*a
,
208 const struct ofproto_ipfix_bridge_exporter_options
*b
)
210 return (a
->obs_domain_id
== b
->obs_domain_id
211 && a
->obs_point_id
== b
->obs_point_id
212 && a
->sampling_rate
== b
->sampling_rate
213 && sset_equals(&a
->targets
, &b
->targets
));
216 static struct ofproto_ipfix_bridge_exporter_options
*
217 ofproto_ipfix_bridge_exporter_options_clone(
218 const struct ofproto_ipfix_bridge_exporter_options
*old
)
220 struct ofproto_ipfix_bridge_exporter_options
*new =
221 xmemdup(old
, sizeof *old
);
222 sset_clone(&new->targets
, &old
->targets
);
227 ofproto_ipfix_bridge_exporter_options_destroy(
228 struct ofproto_ipfix_bridge_exporter_options
*options
)
231 sset_destroy(&options
->targets
);
237 ofproto_ipfix_flow_exporter_options_equal(
238 const struct ofproto_ipfix_flow_exporter_options
*a
,
239 const struct ofproto_ipfix_flow_exporter_options
*b
)
241 return (a
->collector_set_id
== b
->collector_set_id
242 && sset_equals(&a
->targets
, &b
->targets
));
245 static struct ofproto_ipfix_flow_exporter_options
*
246 ofproto_ipfix_flow_exporter_options_clone(
247 const struct ofproto_ipfix_flow_exporter_options
*old
)
249 struct ofproto_ipfix_flow_exporter_options
*new =
250 xmemdup(old
, sizeof *old
);
251 sset_clone(&new->targets
, &old
->targets
);
256 ofproto_ipfix_flow_exporter_options_destroy(
257 struct ofproto_ipfix_flow_exporter_options
*options
)
260 sset_destroy(&options
->targets
);
266 dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter
*exporter
)
268 collectors_destroy(exporter
->collectors
);
269 exporter
->collectors
= NULL
;
270 exporter
->seq_number
= 1;
271 exporter
->last_template_set_time
= TIME_MIN
;
275 dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter
*exporter
,
276 const struct sset
*targets
)
278 collectors_destroy(exporter
->collectors
);
279 collectors_create(targets
, IPFIX_DEFAULT_COLLECTOR_PORT
,
280 &exporter
->collectors
);
281 if (exporter
->collectors
== NULL
) {
282 VLOG_WARN_RL(&rl
, "no collectors could be initialized, "
283 "IPFIX exporter disabled");
284 dpif_ipfix_exporter_clear(exporter
);
291 dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter
*exporter
)
293 dpif_ipfix_exporter_clear(&exporter
->exporter
);
294 ofproto_ipfix_bridge_exporter_options_destroy(exporter
->options
);
295 exporter
->options
= NULL
;
296 exporter
->probability
= 0;
300 dpif_ipfix_bridge_exporter_set_options(
301 struct dpif_ipfix_bridge_exporter
*exporter
,
302 const struct ofproto_ipfix_bridge_exporter_options
*options
)
304 bool options_changed
;
306 if (!options
|| sset_is_empty(&options
->targets
)) {
307 /* No point in doing any work if there are no targets. */
308 dpif_ipfix_bridge_exporter_clear(exporter
);
314 || !ofproto_ipfix_bridge_exporter_options_equal(
315 options
, exporter
->options
));
317 /* Configure collectors if options have changed or if we're
318 * shortchanged in collectors (which indicates that opening one or
319 * more of the configured collectors failed, so that we should
322 || collectors_count(exporter
->exporter
.collectors
)
323 < sset_count(&options
->targets
)) {
324 if (!dpif_ipfix_exporter_set_options(&exporter
->exporter
,
325 &options
->targets
)) {
330 /* Avoid reconfiguring if options didn't change. */
331 if (!options_changed
) {
335 ofproto_ipfix_bridge_exporter_options_destroy(exporter
->options
);
336 exporter
->options
= ofproto_ipfix_bridge_exporter_options_clone(options
);
337 exporter
->probability
=
338 MAX(1, UINT32_MAX
/ exporter
->options
->sampling_rate
);
341 static struct dpif_ipfix_flow_exporter_map_node
*
342 dpif_ipfix_find_flow_exporter_map_node(
343 const struct dpif_ipfix
*di
, const uint32_t collector_set_id
)
345 struct dpif_ipfix_flow_exporter_map_node
*exporter_node
;
347 HMAP_FOR_EACH_WITH_HASH (exporter_node
, node
,
348 hash_int(collector_set_id
, 0),
349 &di
->flow_exporter_map
) {
350 if (exporter_node
->exporter
.options
->collector_set_id
351 == collector_set_id
) {
352 return exporter_node
;
360 dpif_ipfix_flow_exporter_clear(struct dpif_ipfix_flow_exporter
*exporter
)
362 dpif_ipfix_exporter_clear(&exporter
->exporter
);
363 ofproto_ipfix_flow_exporter_options_destroy(exporter
->options
);
364 exporter
->options
= NULL
;
368 dpif_ipfix_flow_exporter_set_options(
369 struct dpif_ipfix_flow_exporter
*exporter
,
370 const struct ofproto_ipfix_flow_exporter_options
*options
)
372 bool options_changed
;
374 if (sset_is_empty(&options
->targets
)) {
375 /* No point in doing any work if there are no targets. */
376 dpif_ipfix_flow_exporter_clear(exporter
);
382 || !ofproto_ipfix_flow_exporter_options_equal(
383 options
, exporter
->options
));
385 /* Configure collectors if options have changed or if we're
386 * shortchanged in collectors (which indicates that opening one or
387 * more of the configured collectors failed, so that we should
390 || collectors_count(exporter
->exporter
.collectors
)
391 < sset_count(&options
->targets
)) {
392 if (!dpif_ipfix_exporter_set_options(&exporter
->exporter
,
393 &options
->targets
)) {
398 /* Avoid reconfiguring if options didn't change. */
399 if (!options_changed
) {
403 ofproto_ipfix_flow_exporter_options_destroy(exporter
->options
);
404 exporter
->options
= ofproto_ipfix_flow_exporter_options_clone(options
);
410 dpif_ipfix_set_options(
411 struct dpif_ipfix
*di
,
412 const struct ofproto_ipfix_bridge_exporter_options
*bridge_exporter_options
,
413 const struct ofproto_ipfix_flow_exporter_options
*flow_exporters_options
,
414 size_t n_flow_exporters_options
)
417 struct ofproto_ipfix_flow_exporter_options
*options
;
418 struct dpif_ipfix_flow_exporter_map_node
*node
, *next
;
419 size_t n_broken_flow_exporters_options
= 0;
421 dpif_ipfix_bridge_exporter_set_options(&di
->bridge_exporter
,
422 bridge_exporter_options
);
424 /* Add new flow exporters and update current flow exporters. */
425 options
= (struct ofproto_ipfix_flow_exporter_options
*)
426 flow_exporters_options
;
427 for (i
= 0; i
< n_flow_exporters_options
; i
++) {
428 node
= dpif_ipfix_find_flow_exporter_map_node(
429 di
, options
->collector_set_id
);
431 node
= xzalloc(sizeof *node
);
432 dpif_ipfix_exporter_clear(&node
->exporter
.exporter
);
433 hmap_insert(&di
->flow_exporter_map
, &node
->node
,
434 hash_int(options
->collector_set_id
, 0));
436 if (!dpif_ipfix_flow_exporter_set_options(&node
->exporter
, options
)) {
437 n_broken_flow_exporters_options
++;
442 ovs_assert(hmap_count(&di
->flow_exporter_map
) >=
443 (n_flow_exporters_options
- n_broken_flow_exporters_options
));
445 /* Remove dropped flow exporters, if any needs to be removed. */
446 if (hmap_count(&di
->flow_exporter_map
) > n_flow_exporters_options
) {
447 HMAP_FOR_EACH_SAFE (node
, next
, node
, &di
->flow_exporter_map
) {
448 /* This is slow but doesn't take any extra memory, and
449 * this table is not supposed to contain many rows anyway. */
450 options
= (struct ofproto_ipfix_flow_exporter_options
*)
451 flow_exporters_options
;
452 for (i
= 0; i
< n_flow_exporters_options
; i
++) {
453 if (node
->exporter
.options
->collector_set_id
454 == options
->collector_set_id
) {
459 if (i
== n_flow_exporters_options
) { // Not found.
460 hmap_remove(&di
->flow_exporter_map
, &node
->node
);
461 dpif_ipfix_flow_exporter_clear(&node
->exporter
);
467 ovs_assert(hmap_count(&di
->flow_exporter_map
) ==
468 (n_flow_exporters_options
- n_broken_flow_exporters_options
));
472 dpif_ipfix_create(void)
474 struct dpif_ipfix
*di
;
475 di
= xzalloc(sizeof *di
);
476 dpif_ipfix_exporter_clear(&di
->bridge_exporter
.exporter
);
477 hmap_init(&di
->flow_exporter_map
);
483 dpif_ipfix_ref(const struct dpif_ipfix
*di_
)
485 struct dpif_ipfix
*di
= CONST_CAST(struct dpif_ipfix
*, di_
);
487 ovs_assert(di
->ref_cnt
> 0);
494 dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix
*di
)
496 return di
->bridge_exporter
.probability
;
500 dpif_ipfix_clear(struct dpif_ipfix
*di
)
502 struct dpif_ipfix_flow_exporter_map_node
*node
, *next
;
504 dpif_ipfix_bridge_exporter_clear(&di
->bridge_exporter
);
506 HMAP_FOR_EACH_SAFE (node
, next
, node
, &di
->flow_exporter_map
) {
507 hmap_remove(&di
->flow_exporter_map
, &node
->node
);
508 dpif_ipfix_flow_exporter_clear(&node
->exporter
);
514 dpif_ipfix_unref(struct dpif_ipfix
*di
)
520 ovs_assert(di
->ref_cnt
> 0);
521 if (!--di
->ref_cnt
) {
522 dpif_ipfix_clear(di
);
523 hmap_destroy(&di
->flow_exporter_map
);
529 ipfix_init_header(uint32_t seq_number
, uint32_t obs_domain_id
,
532 struct ipfix_header
*hdr
;
534 hdr
= ofpbuf_put_zeros(msg
, sizeof *hdr
);
535 hdr
->version
= htons(IPFIX_VERSION
);
536 hdr
->length
= htons(sizeof *hdr
); /* Updated in ipfix_send_msg. */
537 hdr
->export_time
= htonl(time_wall());
538 hdr
->seq_number
= htonl(seq_number
);
539 hdr
->obs_domain_id
= htonl(obs_domain_id
);
543 ipfix_send_msg(const struct collectors
*collectors
, struct ofpbuf
*msg
)
545 struct ipfix_header
*hdr
;
547 /* Adjust the length in the header. */
549 hdr
->length
= htons(msg
->size
);
551 collectors_send(collectors
, msg
->data
, msg
->size
);
556 ipfix_get_template_id(enum ipfix_proto_l2 l2
, enum ipfix_proto_l3 l3
,
557 enum ipfix_proto_l4 l4
)
559 uint16_t template_id
;
561 template_id
= template_id
* NUM_IPFIX_PROTO_L3
+ l3
;
562 template_id
= template_id
* NUM_IPFIX_PROTO_L4
+ l4
;
563 return IPFIX_TEMPLATE_ID_MIN
+ template_id
;
567 ipfix_define_template_entity(enum ipfix_entity_id id
,
568 enum ipfix_entity_size size
, struct ofpbuf
*msg
)
570 struct ipfix_template_field_specifier
*field
;
572 field
= ofpbuf_put_zeros(msg
, sizeof *field
);
573 field
->element_id
= htons(id
);
574 field
->field_length
= htons(size
);
578 ipfix_define_template_fields(enum ipfix_proto_l2 l2
, enum ipfix_proto_l3 l3
,
579 enum ipfix_proto_l4 l4
, struct ofpbuf
*msg
)
585 ipfix_define_template_entity(IPFIX_ENTITY_ID_##ID, \
586 IPFIX_ENTITY_SIZE_##ID, msg); \
590 DEF(OBSERVATION_POINT_ID
);
591 DEF(PACKET_DELTA_COUNT
);
592 DEF(LAYER2_OCTET_DELTA_COUNT
);
594 /* Common Ethernet entities. */
595 DEF(SOURCE_MAC_ADDRESS
);
596 DEF(DESTINATION_MAC_ADDRESS
);
598 DEF(ETHERNET_TOTAL_LENGTH
);
599 DEF(ETHERNET_HEADER_LENGTH
);
601 if (l2
== IPFIX_PROTO_L2_VLAN
) {
607 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
610 DEF(PROTOCOL_IDENTIFIER
);
611 DEF(IP_DIFF_SERV_CODE_POINT
);
613 DEF(IP_CLASS_OF_SERVICE
);
615 if (l3
== IPFIX_PROTO_L3_IPV4
) {
616 DEF(SOURCE_IPV4_ADDRESS
);
617 DEF(DESTINATION_IPV4_ADDRESS
);
618 } else { /* l3 == IPFIX_PROTO_L3_IPV6 */
619 DEF(SOURCE_IPV6_ADDRESS
);
620 DEF(DESTINATION_IPV6_ADDRESS
);
621 DEF(FLOW_LABEL_IPV6
);
625 if (l4
!= IPFIX_PROTO_L4_UNKNOWN
) {
626 DEF(SOURCE_TRANSPORT_PORT
);
627 DEF(DESTINATION_TRANSPORT_PORT
);
636 ipfix_send_template_msg(struct dpif_ipfix_exporter
*exporter
,
637 uint32_t obs_domain_id
)
639 uint64_t msg_stub
[DIV_ROUND_UP(1500, 8)];
641 size_t set_hdr_offset
, tmpl_hdr_offset
;
642 struct ipfix_set_header
*set_hdr
;
643 struct ipfix_template_record_header
*tmpl_hdr
;
644 uint16_t field_count
;
645 enum ipfix_proto_l2 l2
;
646 enum ipfix_proto_l3 l3
;
647 enum ipfix_proto_l4 l4
;
649 ofpbuf_use_stub(&msg
, msg_stub
, sizeof msg_stub
);
651 ipfix_init_header(exporter
->seq_number
, obs_domain_id
, &msg
);
652 set_hdr_offset
= msg
.size
;
654 /* Add a Template Set. */
655 set_hdr
= ofpbuf_put_zeros(&msg
, sizeof *set_hdr
);
656 set_hdr
->set_id
= htons(IPFIX_SET_ID_TEMPLATE
);
658 /* Define one template for each possible combination of
660 for (l2
= 0; l2
< NUM_IPFIX_PROTO_L2
; l2
++) {
661 for (l3
= 0; l3
< NUM_IPFIX_PROTO_L3
; l3
++) {
662 for (l4
= 0; l4
< NUM_IPFIX_PROTO_L4
; l4
++) {
663 if (l3
== IPFIX_PROTO_L3_UNKNOWN
&&
664 l4
!= IPFIX_PROTO_L4_UNKNOWN
) {
667 tmpl_hdr_offset
= msg
.size
;
668 tmpl_hdr
= ofpbuf_put_zeros(&msg
, sizeof *tmpl_hdr
);
669 tmpl_hdr
->template_id
= htons(
670 ipfix_get_template_id(l2
, l3
, l4
));
671 field_count
= ipfix_define_template_fields(l2
, l3
, l4
, &msg
);
672 tmpl_hdr
= (struct ipfix_template_record_header
*)
673 ((uint8_t*)msg
.data
+ tmpl_hdr_offset
);
674 tmpl_hdr
->field_count
= htons(field_count
);
679 set_hdr
= (struct ipfix_set_header
*)((uint8_t*)msg
.data
+ set_hdr_offset
);
680 set_hdr
->length
= htons(msg
.size
- set_hdr_offset
);
682 /* XXX: Add Options Template Sets, at least to define a Flow Keys
683 * Option Template. */
685 ipfix_send_msg(exporter
->collectors
, &msg
);
691 ipfix_send_data_msg(struct dpif_ipfix_exporter
*exporter
, struct ofpbuf
*packet
,
692 const struct flow
*flow
, uint64_t packet_delta_count
,
693 uint32_t obs_domain_id
, uint32_t obs_point_id
)
695 uint64_t msg_stub
[DIV_ROUND_UP(1500, 8)];
697 size_t set_hdr_offset
;
698 struct ipfix_set_header
*set_hdr
;
699 enum ipfix_proto_l2 l2
;
700 enum ipfix_proto_l3 l3
;
701 enum ipfix_proto_l4 l4
;
703 ofpbuf_use_stub(&msg
, msg_stub
, sizeof msg_stub
);
705 ipfix_init_header(exporter
->seq_number
, obs_domain_id
, &msg
);
706 exporter
->seq_number
++;
707 set_hdr_offset
= msg
.size
;
709 /* Choose the right template ID matching the protocols in the
711 l2
= (flow
->vlan_tci
== 0) ? IPFIX_PROTO_L2_ETH
: IPFIX_PROTO_L2_VLAN
;
713 switch(ntohs(flow
->dl_type
)) {
715 l3
= IPFIX_PROTO_L3_IPV4
;
718 l3
= IPFIX_PROTO_L3_IPV6
;
721 l3
= IPFIX_PROTO_L3_UNKNOWN
;
724 l4
= IPFIX_PROTO_L4_UNKNOWN
;
725 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
726 switch(flow
->nw_proto
) {
727 case IPPROTO_TCP
: /* TCP */
728 case IPPROTO_UDP
: /* UDP */
729 l4
= IPFIX_PROTO_L4_TCP_UDP
;
734 /* Add a Data Set. */
735 set_hdr
= ofpbuf_put_zeros(&msg
, sizeof *set_hdr
);
736 set_hdr
->set_id
= htons(ipfix_get_template_id(l2
, l3
, l4
));
738 /* The fields defined in the ipfix_data_record_* structs and sent
739 * below must match exactly the templates defined in
740 * ipfix_define_template_fields. */
742 /* Common Ethernet entities. */
744 struct ipfix_data_record_common
*data_common
;
745 uint16_t ethernet_total_length
;
746 uint8_t ethernet_header_length
;
747 uint64_t layer2_octet_delta_count
;
749 ethernet_total_length
= packet
->size
;
750 ethernet_header_length
= (l2
== IPFIX_PROTO_L2_VLAN
)
751 ? VLAN_ETH_HEADER_LEN
: ETH_HEADER_LEN
;
753 /* Calculate the total matched octet count by considering as
754 * an approximation that all matched packets have the same
756 layer2_octet_delta_count
= packet_delta_count
* ethernet_total_length
;
758 data_common
= ofpbuf_put_zeros(&msg
, sizeof *data_common
);
759 data_common
->observation_point_id
= htonl(obs_point_id
);
760 data_common
->packet_delta_count
= htonll(packet_delta_count
);
761 data_common
->layer2_octet_delta_count
=
762 htonll(layer2_octet_delta_count
);
763 memcpy(data_common
->source_mac_address
, flow
->dl_src
,
764 sizeof flow
->dl_src
);
765 memcpy(data_common
->destination_mac_address
, flow
->dl_dst
,
766 sizeof flow
->dl_dst
);
767 data_common
->ethernet_type
= flow
->dl_type
;
768 data_common
->ethernet_total_length
= htons(ethernet_total_length
);
769 data_common
->ethernet_header_length
= ethernet_header_length
;
772 if (l2
== IPFIX_PROTO_L2_VLAN
) {
773 struct ipfix_data_record_vlan
*data_vlan
;
774 uint16_t vlan_id
= vlan_tci_to_vid(flow
->vlan_tci
);
775 uint8_t priority
= vlan_tci_to_pcp(flow
->vlan_tci
);
777 data_vlan
= ofpbuf_put_zeros(&msg
, sizeof *data_vlan
);
778 data_vlan
->vlan_id
= htons(vlan_id
);
779 data_vlan
->dot1q_vlan_id
= htons(vlan_id
);
780 data_vlan
->dot1q_priority
= priority
;
783 if (l3
!= IPFIX_PROTO_L3_UNKNOWN
) {
784 struct ipfix_data_record_ip
*data_ip
;
786 data_ip
= ofpbuf_put_zeros(&msg
, sizeof *data_ip
);
787 data_ip
->ip_version
= (l3
== IPFIX_PROTO_L3_IPV4
) ? 4 : 6;
788 data_ip
->ip_ttl
= flow
->nw_ttl
;
789 data_ip
->protocol_identifier
= flow
->nw_proto
;
790 data_ip
->ip_diff_serv_code_point
= flow
->nw_tos
>> 2;
791 data_ip
->ip_precedence
= flow
->nw_tos
>> 5;
792 data_ip
->ip_class_of_service
= flow
->nw_tos
;
794 if (l3
== IPFIX_PROTO_L3_IPV4
) {
795 struct ipfix_data_record_ipv4
*data_ipv4
;
796 data_ipv4
= ofpbuf_put_zeros(&msg
, sizeof *data_ipv4
);
797 data_ipv4
->source_ipv4_address
= flow
->nw_src
;
798 data_ipv4
->destination_ipv4_address
= flow
->nw_dst
;
799 } else { /* l3 == IPFIX_PROTO_L3_IPV6 */
800 struct ipfix_data_record_ipv6
*data_ipv6
;
802 data_ipv6
= ofpbuf_put_zeros(&msg
, sizeof *data_ipv6
);
803 memcpy(data_ipv6
->source_ipv6_address
, &flow
->ipv6_src
,
804 sizeof flow
->ipv6_src
);
805 memcpy(data_ipv6
->destination_ipv6_address
, &flow
->ipv6_dst
,
806 sizeof flow
->ipv6_dst
);
807 data_ipv6
->flow_label_ipv6
= flow
->ipv6_label
;
811 if (l4
!= IPFIX_PROTO_L4_UNKNOWN
) {
812 struct ipfix_data_record_tcpudp
*data_tcpudp
;
814 data_tcpudp
= ofpbuf_put_zeros(&msg
, sizeof *data_tcpudp
);
815 data_tcpudp
->source_transport_port
= flow
->tp_src
;
816 data_tcpudp
->destination_transport_port
= flow
->tp_dst
;
819 set_hdr
= (struct ipfix_set_header
*)((uint8_t*)msg
.data
+ set_hdr_offset
);
820 set_hdr
->length
= htons(msg
.size
- set_hdr_offset
);
822 ipfix_send_msg(exporter
->collectors
, &msg
);
828 dpif_ipfix_sample(struct dpif_ipfix_exporter
*exporter
,
829 struct ofpbuf
*packet
, const struct flow
*flow
,
830 uint64_t packet_delta_count
, uint32_t obs_domain_id
,
831 uint32_t obs_point_id
)
833 time_t now
= time_wall();
834 if ((exporter
->last_template_set_time
+ IPFIX_TEMPLATE_INTERVAL
) <= now
) {
835 ipfix_send_template_msg(exporter
, obs_domain_id
);
836 exporter
->last_template_set_time
= now
;
839 ipfix_send_data_msg(exporter
, packet
, flow
, packet_delta_count
,
840 obs_domain_id
, obs_point_id
);
844 dpif_ipfix_bridge_sample(struct dpif_ipfix
*di
, struct ofpbuf
*packet
,
845 const struct flow
*flow
)
847 /* Use the sampling probability as an approximation of the number
848 * of matched packets. */
849 uint64_t packet_delta_count
= UINT32_MAX
/ di
->bridge_exporter
.probability
;
851 dpif_ipfix_sample(&di
->bridge_exporter
.exporter
, packet
, flow
,
853 di
->bridge_exporter
.options
->obs_domain_id
,
854 di
->bridge_exporter
.options
->obs_point_id
);
858 dpif_ipfix_flow_sample(struct dpif_ipfix
*di
, struct ofpbuf
*packet
,
859 const struct flow
*flow
, uint32_t collector_set_id
,
860 uint16_t probability
, uint32_t obs_domain_id
,
861 uint32_t obs_point_id
)
863 struct dpif_ipfix_flow_exporter_map_node
*node
;
864 /* Use the sampling probability as an approximation of the number
865 * of matched packets. */
866 uint64_t packet_delta_count
= USHRT_MAX
/ probability
;
868 node
= dpif_ipfix_find_flow_exporter_map_node(di
, collector_set_id
);
874 dpif_ipfix_sample(&node
->exporter
.exporter
, packet
, flow
,
875 packet_delta_count
, obs_domain_id
, obs_point_id
);