From: Adrian Moreno <amore...@redhat.com> Add options to the IPFIX table configure the interval to send statistics and template information.
Signed-off-by: Adrian Moreno <amore...@redhat.com> --- - v2: - Fixed a potential race condition in unit test. - v1: - Added unit test. --- NEWS | 2 ++ ofproto/ofproto-dpif-ipfix.c | 38 ++++++++++++++++++++-------- ofproto/ofproto.h | 9 +++++++ tests/system-traffic.at | 49 ++++++++++++++++++++++++++++++++++++ vswitchd/bridge.c | 17 +++++++++++++ vswitchd/vswitch.ovsschema | 12 ++++++++- vswitchd/vswitch.xml | 20 +++++++++++++++ 7 files changed, 136 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 4f9291bf1..6f0f9e3a0 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,8 @@ Post-v3.0.0 * Add new experimental PMD load based sleeping feature. PMD threads can request to sleep up to a user configured 'pmd-maxsleep' value under low load conditions. + - IPFIX template and statistics intervals can be configured through two new + options in the IPFIX table: 'template_interval' and 'stats_interval'. v3.0.0 - 15 Aug 2022 diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c index fa71fda0f..fdb48b5fd 100644 --- a/ofproto/ofproto-dpif-ipfix.c +++ b/ofproto/ofproto-dpif-ipfix.c @@ -140,6 +140,8 @@ struct dpif_ipfix_exporter { struct ovs_list cache_flow_start_timestamp_list; /* ipfix_flow_cache_entry. */ uint32_t cache_active_timeout; /* In seconds. */ uint32_t cache_max_flows; + uint32_t stats_interval; + uint32_t template_interval; char *virtual_obs_id; uint8_t virtual_obs_len; @@ -174,11 +176,6 @@ struct dpif_ipfix { #define IPFIX_VERSION 0x000a -/* When using UDP, IPFIX Template Records must be re-sent regularly. - * The standard default interval is 10 minutes (600 seconds). - * Cf. IETF RFC 5101 Section 10.3.6. */ -#define IPFIX_TEMPLATE_INTERVAL 600 - /* Cf. IETF RFC 5101 Section 3.1. */ OVS_PACKED( struct ipfix_header { @@ -637,6 +634,8 @@ ofproto_ipfix_bridge_exporter_options_equal( && a->sampling_rate == b->sampling_rate && a->cache_active_timeout == b->cache_active_timeout && a->cache_max_flows == b->cache_max_flows + && a->stats_interval == b->stats_interval + && a->template_interval == b->template_interval && a->enable_tunnel_sampling == b->enable_tunnel_sampling && a->enable_input_sampling == b->enable_input_sampling && a->enable_output_sampling == b->enable_output_sampling @@ -674,6 +673,8 @@ ofproto_ipfix_flow_exporter_options_equal( return (a->collector_set_id == b->collector_set_id && a->cache_active_timeout == b->cache_active_timeout && a->cache_max_flows == b->cache_max_flows + && a->stats_interval == b->stats_interval + && a->template_interval == b->template_interval && a->enable_tunnel_sampling == b->enable_tunnel_sampling && sset_equals(&a->targets, &b->targets) && nullable_string_is_equal(a->virtual_obs_id, b->virtual_obs_id)); @@ -712,6 +713,9 @@ dpif_ipfix_exporter_init(struct dpif_ipfix_exporter *exporter) ovs_list_init(&exporter->cache_flow_start_timestamp_list); exporter->cache_active_timeout = 0; exporter->cache_max_flows = 0; + exporter->stats_interval = OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + exporter->template_interval = OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + exporter->last_stats_sent_time = 0; exporter->virtual_obs_id = NULL; exporter->virtual_obs_len = 0; hmap_init(&exporter->domains); @@ -734,6 +738,9 @@ dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter *exporter) exporter->last_stats_sent_time = 0; exporter->cache_active_timeout = 0; exporter->cache_max_flows = 0; + exporter->stats_interval = OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + exporter->template_interval = OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + exporter->last_stats_sent_time = 0; free(exporter->virtual_obs_id); exporter->virtual_obs_id = NULL; exporter->virtual_obs_len = 0; @@ -761,6 +768,8 @@ dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter, const struct sset *targets, const uint32_t cache_active_timeout, const uint32_t cache_max_flows, + const uint32_t stats_interval, + const uint32_t template_interval, const char *virtual_obs_id) OVS_REQUIRES(mutex) { size_t virtual_obs_len; @@ -775,6 +784,8 @@ dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter, } exporter->cache_active_timeout = cache_active_timeout; exporter->cache_max_flows = cache_max_flows; + exporter->stats_interval = stats_interval; + exporter->template_interval = template_interval; virtual_obs_len = virtual_obs_id ? strlen(virtual_obs_id) : 0; if (virtual_obs_len > IPFIX_VIRTUAL_OBS_MAX_LEN) { VLOG_WARN_RL(&rl, "Virtual obsevation ID too long (%d bytes), " @@ -1007,6 +1018,7 @@ dpif_ipfix_bridge_exporter_set_options( if (!dpif_ipfix_exporter_set_options( &exporter->exporter, &options->targets, options->cache_active_timeout, options->cache_max_flows, + options->stats_interval, options->template_interval, options->virtual_obs_id)) { return; } @@ -1022,6 +1034,14 @@ dpif_ipfix_bridge_exporter_set_options( exporter->probability = MAX(1, UINT32_MAX / exporter->options->sampling_rate); + /* Configure static observation_domain_id. */ + struct dpif_ipfix_domain *dom; + HMAP_FOR_EACH_SAFE (dom, hmap_node, &(exporter->exporter.domains)) { + dpif_ipfix_exporter_del_domain(&exporter->exporter, dom); + } + dpif_ipfix_exporter_insert_domain(&exporter->exporter, + options->obs_domain_id); + /* Run over the cache as some entries might have expired after * changing the timeouts. */ dpif_ipfix_cache_expire_now(&exporter->exporter, false); @@ -1102,6 +1122,7 @@ dpif_ipfix_flow_exporter_set_options( if (!dpif_ipfix_exporter_set_options( &exporter->exporter, &options->targets, options->cache_active_timeout, options->cache_max_flows, + options->stats_interval, options->template_interval, options->virtual_obs_id)) { return false; } @@ -2882,7 +2903,7 @@ dpif_ipfix_should_send_template(struct dpif_ipfix_exporter *exporter, observation_domain_id); } - if ((domain->last_template_set_time + IPFIX_TEMPLATE_INTERVAL) + if ((domain->last_template_set_time + exporter->template_interval) <= export_time_sec) { domain->last_template_set_time = export_time_sec; return true; @@ -2922,10 +2943,7 @@ dpif_ipfix_cache_expire(struct dpif_ipfix_exporter *exporter, break; } - /* XXX: Make frequency of the (Options) Template and Exporter Process - * Statistics transmission configurable. - * Cf. IETF RFC 5101 Section 4.3. and 10.3.6. */ - if ((exporter->last_stats_sent_time + IPFIX_TEMPLATE_INTERVAL) + if ((exporter->last_stats_sent_time + exporter->stats_interval) <= export_time_sec) { exporter->last_stats_sent_time = export_time_sec; ipfix_send_exporter_data_msg(exporter, export_time_sec); diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 4e15167ab..c79f372bc 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -72,6 +72,11 @@ struct ofproto_sflow_options { char *control_ip; }; +/* When using UDP, IPFIX Template Records must be re-sent regularly. + * The standard default interval is 10 minutes (600 seconds). + * Cf. IETF RFC 5101 Section 10.3.6. */ +#define OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL 600 + struct ofproto_ipfix_bridge_exporter_options { struct sset targets; uint32_t sampling_rate; @@ -79,6 +84,8 @@ struct ofproto_ipfix_bridge_exporter_options { uint32_t obs_point_id; /* Bridge-wide Observation Point ID. */ uint32_t cache_active_timeout; uint32_t cache_max_flows; + uint32_t template_interval; + uint32_t stats_interval; bool enable_tunnel_sampling; bool enable_input_sampling; bool enable_output_sampling; @@ -90,6 +97,8 @@ struct ofproto_ipfix_flow_exporter_options { struct sset targets; uint32_t cache_active_timeout; uint32_t cache_max_flows; + uint32_t template_interval; + uint32_t stats_interval; bool enable_tunnel_sampling; char *virtual_obs_id; }; diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 1421ab0ab..8f757416f 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -7540,3 +7540,52 @@ AT_CHECK([test $(tcpdump -r ipfix.pcap --count "udp port 5555 and udp[[20:4]] = OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ipfix - configure template timeout]) +AT_SKIP_IF([test $HAVE_TCPDUMP = no]) +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") + +dnl Create a dummy IPFIX collector just in localhost so that port seems open. +OVS_DAEMONIZE([nc -l -u 127.0.0.1 5555 > /dev/null], [nc.pid]) + +OVS_DAEMONIZE([tcpdump -n -i lo udp port 5555 -w ipfix.pcap], [tcpdump.pid]) +sleep 1 + +dnl Configure a Flow Sample Collector Set with id = 1. +AT_CHECK([ovs-vsctl -- --id=@br get Bridge br0 \ + -- --id=@i create IPFIX targets=\"127.0.0.1:5555\" template_interval=1 stats_interval=1 \ + -- create Flow_Sample_Collector_Set bridge=@br id=1 ipfix=@i], + [ignore], [ignore]) + +dnl Push flows that will allow communication between the network namespaces +dnl and sample all ICMP traffic with multiple observation domain IDs. +AT_DATA([flows.txt], [dnl +table=0,priority=100,in_port=ovs-p0,ip,icmp actions=sample(probability=65535,collector_set_id=1,obs_domain_id=1),NORMAL +table=0,priority=100,in_port=ovs-p1,ip,icmp actions=sample(probability=65535,collector_set_id=1,obs_domain_id=2),NORMAL +table=0,priority=0,actions=NORMAL +]) +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + +NS_CHECK_EXEC([at_ns0], [ping -q -c 5 10.1.1.2 | FORMAT_PING], [0], [dnl +5 packets transmitted, 5 received, 0% packet loss, time 0ms +]) + +sleep 1 +kill $(cat tcpdump.pid) +wait $(cat tcpdump.pid) 2> /dev/null + +dnl Check template (Flow ID = 0x02) with Template ID 256 (the first one) was +dnl sent to both ObservationDomains at least 4 times. +AT_CHECK([test $(tcpdump -r ipfix.pcap --count "udp port 5555 and udp[[20:4]] = 0x00000001 and udp[[24:2]] = 0x02 and udp[[28:2]] = 0x0100" 2>/dev/null | tr -d "packets") -ge 4]) +AT_CHECK([test $(tcpdump -r ipfix.pcap --count "udp port 5555 and udp[[20:4]] = 0x00000002 and udp[[24:2]] = 0x02 and udp[[28:2]] = 0x0100" 2>/dev/null | tr -d "packets") -ge 4]) +dnl Check statistics (ObservationDomain = 0 and Template ID = 462) where sent +dnl sent at least 4 times. +AT_CHECK([test $(tcpdump -r ipfix.pcap --count "udp port 5555 and udp[[20:4]] = 0x00000000 and udp[[24:2]] = 0x01ce" 2>/dev/null | tr -d "packets") -ge 4]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index bfb2adef1..17f32b9ca 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1542,6 +1542,17 @@ bridge_configure_ipfix(struct bridge *br) if (be_cfg->cache_max_flows) { be_opts.cache_max_flows = *be_cfg->cache_max_flows; } + if (be_cfg->stats_interval) { + be_opts.stats_interval = *be_cfg->stats_interval; + } else { + be_opts.stats_interval = OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + } + if (be_cfg->template_interval) { + be_opts.template_interval = *be_cfg->template_interval; + } else { + be_opts.template_interval = + OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + } be_opts.enable_tunnel_sampling = smap_get_bool(&be_cfg->other_config, "enable-tunnel-sampling", true); @@ -1570,6 +1581,12 @@ bridge_configure_ipfix(struct bridge *br) ? *fe_cfg->ipfix->cache_active_timeout : 0; opts->cache_max_flows = fe_cfg->ipfix->cache_max_flows ? *fe_cfg->ipfix->cache_max_flows : 0; + opts->stats_interval = fe_cfg->ipfix->stats_interval + ? *fe_cfg->ipfix->stats_interval + : OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; + opts->template_interval = fe_cfg->ipfix->template_interval + ? *fe_cfg->ipfix->template_interval + : OFPROTO_IPFIX_DEFAULT_TEMPLATE_INTERVAL; opts->enable_tunnel_sampling = smap_get_bool( &fe_cfg->ipfix->other_config, "enable-tunnel-sampling", true); diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index 1a49cdffe..8ab609dfb 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -1,6 +1,6 @@ {"name": "Open_vSwitch", "version": "8.3.1", - "cksum": "3012963480 26720", + "cksum": "142028610 27127", "tables": { "Open_vSwitch": { "columns": { @@ -531,6 +531,16 @@ "minInteger": 0, "maxInteger": 4294967295}, "min": 0, "max": 1}}, + "stats_interval": { + "type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 3600}, + "min": 0, "max": 1}}, + "template_interval": { + "type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 3600}, + "min": 0, "max": 1}}, "other_config": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}, diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 8c4acfb18..bf153db6c 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -6595,6 +6595,26 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \ disabled. </column> + <column name="stats_interval"> + <p> + Interval (in seconds) for sending IPFIX exporting process statistics + according to IETF RFC 5101 Section 4.3. + </p> + <p> + Default value is 600 + </p> + </column> + + <column name="template_interval"> + <p> + Interval (in seconds) for sending IPFIX Template information for each + Observation Domain ID. + </p> + <p> + Default value is 600 + </p> + </column> + <column name="other_config" key="enable-tunnel-sampling" type='{"type": "boolean"}'> <p> -- 2.38.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev