mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
ipfix: Export user specified virtual observation ID
In virtual network, users want more info about the virtual point to observe the traffic. It should be a string to provide clear info, not a simple interger ID. Introduce "other-config: virtual_obs_id" in IPFIX, which is a string configured by user. Introduce an enterprise IPFIX entity "virtualObsID"(898) to export the value. The entity is a variable-length string. Signed-off-by: Wenyu Zhang <wenyuz@vmware.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
parent
7a9d65d294
commit
c97320eb7d
11
NEWS
11
NEWS
@ -15,16 +15,19 @@ Post-v2.5.0
|
||||
now implemented. Only flow mod and port mod messages are supported
|
||||
in bundles.
|
||||
* New OpenFlow extension NXM_NX_MPLS_TTL to provide access to MPLS TTL.
|
||||
* New "sampling_port" option for "sample" action to allow sampling
|
||||
ingress and egress tunnel metadata with IPFIX.
|
||||
* New output option, output(port=N,max_len=M), to allow truncating a
|
||||
packet to size M bytes when outputting to port N.
|
||||
- ovs-ofctl:
|
||||
* queue-get-config command now allows a queue ID to be specified.
|
||||
* '--bundle' option can now be used with OpenFlow 1.3.
|
||||
* New option "--color" to produce colorized output for some commands.
|
||||
* New commands "dump-ipfix-bridge" and "dump-ipfix-flow" to dump bridge
|
||||
IPFIX statistics and flow based IPFIX statistics.
|
||||
- IPFIX:
|
||||
* New "sampling_port" option for "sample" action to allow sampling
|
||||
ingress and egress tunnel metadata with IPFIX.
|
||||
* New ovs-ofctl commands "dump-ipfix-bridge" and "dump-ipfix-flow" to
|
||||
dump bridge IPFIX statistics and flow based IPFIX statistics.
|
||||
* New setting other-config:virtual_obs_id to add an arbitrary string
|
||||
to IPFIX records.
|
||||
- Linux:
|
||||
* New QoS type "linux-noop" that prevents Open vSwitch from trying to
|
||||
manage QoS for a given port (useful when other software manages QoS).
|
||||
|
@ -12,5 +12,6 @@ IPFIX_ENTERPRISE_ENTITY(TUNNEL_DESTINATION_IPV4_ADDRESS, 894, 4, tunnelDestinati
|
||||
IPFIX_ENTERPRISE_ENTITY(TUNNEL_PROTOCOL_IDENTIFIER, 895, 1, tunnelProtocolIdentifier, IPFIX_ENTERPRISE_VMWARE)
|
||||
IPFIX_ENTERPRISE_ENTITY(TUNNEL_SOURCE_TRANSPORT_PORT, 896, 2, tunnelSourceTransportPort, IPFIX_ENTERPRISE_VMWARE)
|
||||
IPFIX_ENTERPRISE_ENTITY(TUNNEL_DESTINATION_TRANSPORT_PORT, 897, 2, tunnelDestinationTransportPort, IPFIX_ENTERPRISE_VMWARE)
|
||||
IPFIX_ENTERPRISE_ENTITY(VIRTUAL_OBS_ID, 898, 0, virtualObsID, IPFIX_ENTERPRISE_VMWARE)
|
||||
|
||||
#undef IPFIX_ENTERPRISE_ENTITY
|
||||
|
@ -101,6 +101,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;
|
||||
char *virtual_obs_id;
|
||||
uint8_t virtual_obs_len;
|
||||
|
||||
ofproto_ipfix_stats stats;
|
||||
};
|
||||
@ -366,6 +368,32 @@ struct ipfix_data_record_aggregated_ip {
|
||||
});
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_ip) == 32);
|
||||
|
||||
/*
|
||||
* Refer to RFC 7011, the length of Variable length element is 0~65535:
|
||||
* In most case, it should be less than 255 octets:
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Length (< 255)| Information Element |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | ... continuing as needed |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* When it is greater than or equeal to 255 octets:
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | 255 | Length (0 to 65535) | IE |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | ... continuing as needed |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
*
|
||||
* Now, only the virtual_obs_id whose length < 255 is implemented.
|
||||
*/
|
||||
|
||||
#define IPFIX_VIRTUAL_OBS_MAX_LEN 254
|
||||
|
||||
/*
|
||||
* support tunnel key for:
|
||||
* VxLAN: 24-bit VIN,
|
||||
@ -435,6 +463,18 @@ static void get_export_time_now(uint64_t *, uint32_t *);
|
||||
|
||||
static void dpif_ipfix_cache_expire_now(struct dpif_ipfix_exporter *, bool);
|
||||
|
||||
static bool
|
||||
nullable_string_is_equal(const char *a, const char *b)
|
||||
{
|
||||
return a ? b && !strcmp(a, b) : !b;
|
||||
}
|
||||
|
||||
static char *
|
||||
nullable_xstrdup(const char *s)
|
||||
{
|
||||
return s ? xstrdup(s) : NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
ofproto_ipfix_bridge_exporter_options_equal(
|
||||
const struct ofproto_ipfix_bridge_exporter_options *a,
|
||||
@ -448,7 +488,8 @@ ofproto_ipfix_bridge_exporter_options_equal(
|
||||
&& a->enable_tunnel_sampling == b->enable_tunnel_sampling
|
||||
&& a->enable_input_sampling == b->enable_input_sampling
|
||||
&& a->enable_output_sampling == b->enable_output_sampling
|
||||
&& sset_equals(&a->targets, &b->targets));
|
||||
&& sset_equals(&a->targets, &b->targets)
|
||||
&& nullable_string_is_equal(a->virtual_obs_id, b->virtual_obs_id));
|
||||
}
|
||||
|
||||
static struct ofproto_ipfix_bridge_exporter_options *
|
||||
@ -458,6 +499,7 @@ ofproto_ipfix_bridge_exporter_options_clone(
|
||||
struct ofproto_ipfix_bridge_exporter_options *new =
|
||||
xmemdup(old, sizeof *old);
|
||||
sset_clone(&new->targets, &old->targets);
|
||||
new->virtual_obs_id = nullable_xstrdup(old->virtual_obs_id);
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -467,6 +509,7 @@ ofproto_ipfix_bridge_exporter_options_destroy(
|
||||
{
|
||||
if (options) {
|
||||
sset_destroy(&options->targets);
|
||||
free(options->virtual_obs_id);
|
||||
free(options);
|
||||
}
|
||||
}
|
||||
@ -480,7 +523,8 @@ ofproto_ipfix_flow_exporter_options_equal(
|
||||
&& a->cache_active_timeout == b->cache_active_timeout
|
||||
&& a->cache_max_flows == b->cache_max_flows
|
||||
&& a->enable_tunnel_sampling == b->enable_tunnel_sampling
|
||||
&& sset_equals(&a->targets, &b->targets));
|
||||
&& sset_equals(&a->targets, &b->targets)
|
||||
&& nullable_string_is_equal(a->virtual_obs_id, b->virtual_obs_id));
|
||||
}
|
||||
|
||||
static struct ofproto_ipfix_flow_exporter_options *
|
||||
@ -490,6 +534,7 @@ ofproto_ipfix_flow_exporter_options_clone(
|
||||
struct ofproto_ipfix_flow_exporter_options *new =
|
||||
xmemdup(old, sizeof *old);
|
||||
sset_clone(&new->targets, &old->targets);
|
||||
new->virtual_obs_id = nullable_xstrdup(old->virtual_obs_id);
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -499,6 +544,7 @@ ofproto_ipfix_flow_exporter_options_destroy(
|
||||
{
|
||||
if (options) {
|
||||
sset_destroy(&options->targets);
|
||||
free(options->virtual_obs_id);
|
||||
free(options);
|
||||
}
|
||||
}
|
||||
@ -513,6 +559,8 @@ 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->virtual_obs_id = NULL;
|
||||
exporter->virtual_obs_len = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -527,6 +575,9 @@ dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter *exporter)
|
||||
exporter->last_template_set_time = 0;
|
||||
exporter->cache_active_timeout = 0;
|
||||
exporter->cache_max_flows = 0;
|
||||
free(exporter->virtual_obs_id);
|
||||
exporter->virtual_obs_id = NULL;
|
||||
exporter->virtual_obs_len = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -540,8 +591,10 @@ static bool
|
||||
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 cache_max_flows,
|
||||
const char *virtual_obs_id)
|
||||
{
|
||||
size_t virtual_obs_len;
|
||||
collectors_destroy(exporter->collectors);
|
||||
collectors_create(targets, IPFIX_DEFAULT_COLLECTOR_PORT,
|
||||
&exporter->collectors);
|
||||
@ -553,6 +606,16 @@ dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter,
|
||||
}
|
||||
exporter->cache_active_timeout = cache_active_timeout;
|
||||
exporter->cache_max_flows = cache_max_flows;
|
||||
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), "
|
||||
"should not be longer than %d bytes.",
|
||||
exporter->virtual_obs_len, IPFIX_VIRTUAL_OBS_MAX_LEN);
|
||||
dpif_ipfix_exporter_clear(exporter);
|
||||
return false;
|
||||
}
|
||||
exporter->virtual_obs_len = virtual_obs_len;
|
||||
exporter->virtual_obs_id = nullable_xstrdup(virtual_obs_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -707,7 +770,8 @@ dpif_ipfix_bridge_exporter_set_options(
|
||||
< sset_count(&options->targets)) {
|
||||
if (!dpif_ipfix_exporter_set_options(
|
||||
&exporter->exporter, &options->targets,
|
||||
options->cache_active_timeout, options->cache_max_flows)) {
|
||||
options->cache_active_timeout, options->cache_max_flows,
|
||||
options->virtual_obs_id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -795,7 +859,8 @@ dpif_ipfix_flow_exporter_set_options(
|
||||
< sset_count(&options->targets)) {
|
||||
if (!dpif_ipfix_exporter_set_options(
|
||||
&exporter->exporter, &options->targets,
|
||||
options->cache_active_timeout, options->cache_max_flows)) {
|
||||
options->cache_active_timeout, options->cache_max_flows,
|
||||
options->virtual_obs_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1074,6 +1139,7 @@ ipfix_define_template_entity(enum ipfix_entity_id id,
|
||||
static uint16_t
|
||||
ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
|
||||
enum ipfix_proto_l4 l4, enum ipfix_proto_tunnel tunnel,
|
||||
bool virtual_obs_id_set,
|
||||
struct dp_packet *msg)
|
||||
{
|
||||
uint16_t count = 0;
|
||||
@ -1145,7 +1211,12 @@ ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
|
||||
DEF(TUNNEL_KEY);
|
||||
}
|
||||
|
||||
/* 2. Flow aggregated data. */
|
||||
/* 2. Virtual observation ID, which is not a part of flow key. */
|
||||
if (virtual_obs_id_set) {
|
||||
DEF(VIRTUAL_OBS_ID);
|
||||
}
|
||||
|
||||
/* 3. Flow aggregated data. */
|
||||
|
||||
DEF(FLOW_START_DELTA_MICROSECONDS);
|
||||
DEF(FLOW_END_DELTA_MICROSECONDS);
|
||||
@ -1159,8 +1230,6 @@ ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
|
||||
DEF(MINIMUM_IP_TOTAL_LENGTH);
|
||||
DEF(MAXIMUM_IP_TOTAL_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
#undef DEF
|
||||
|
||||
return count;
|
||||
@ -1253,8 +1322,9 @@ ipfix_send_template_msgs(struct dpif_ipfix_exporter *exporter,
|
||||
tmpl_hdr = dp_packet_put_zeros(&msg, sizeof *tmpl_hdr);
|
||||
tmpl_hdr->template_id = htons(
|
||||
ipfix_get_template_id(l2, l3, l4, tunnel));
|
||||
field_count =
|
||||
ipfix_define_template_fields(l2, l3, l4, tunnel, &msg);
|
||||
field_count = ipfix_define_template_fields(
|
||||
l2, l3, l4, tunnel, exporter->virtual_obs_id != NULL,
|
||||
&msg);
|
||||
tmpl_hdr = (struct ipfix_template_record_header*)
|
||||
((uint8_t*)dp_packet_data(&msg) + tmpl_hdr_offset);
|
||||
tmpl_hdr->field_count = htons(field_count);
|
||||
@ -1738,6 +1808,8 @@ static void
|
||||
ipfix_put_data_set(uint32_t export_time_sec,
|
||||
struct ipfix_flow_cache_entry *entry,
|
||||
enum ipfix_flow_end_reason flow_end_reason,
|
||||
const char *virtual_obs_id,
|
||||
uint8_t virtual_obs_len,
|
||||
struct dp_packet *msg)
|
||||
{
|
||||
size_t set_hdr_offset;
|
||||
@ -1754,6 +1826,12 @@ ipfix_put_data_set(uint32_t export_time_sec,
|
||||
dp_packet_put(msg, entry->flow_key.flow_key_msg_part,
|
||||
entry->flow_key.flow_key_msg_part_size);
|
||||
|
||||
/* Export virtual observation ID. */
|
||||
if (virtual_obs_id) {
|
||||
dp_packet_put(msg, &virtual_obs_len, sizeof(virtual_obs_len));
|
||||
dp_packet_put(msg, virtual_obs_id, virtual_obs_len);
|
||||
}
|
||||
|
||||
/* Put the non-key part of the data record. */
|
||||
|
||||
{
|
||||
@ -1816,7 +1894,9 @@ ipfix_send_data_msg(struct dpif_ipfix_exporter *exporter,
|
||||
|
||||
ipfix_init_header(export_time_sec, exporter->seq_number++,
|
||||
entry->flow_key.obs_domain_id, &msg);
|
||||
ipfix_put_data_set(export_time_sec, entry, flow_end_reason, &msg);
|
||||
ipfix_put_data_set(export_time_sec, entry, flow_end_reason,
|
||||
exporter->virtual_obs_id, exporter->virtual_obs_len,
|
||||
&msg);
|
||||
tx_errors = ipfix_send_msg(exporter->collectors, &msg);
|
||||
|
||||
dp_packet_uninit(&msg);
|
||||
|
@ -82,6 +82,7 @@ struct ofproto_ipfix_bridge_exporter_options {
|
||||
bool enable_tunnel_sampling;
|
||||
bool enable_input_sampling;
|
||||
bool enable_output_sampling;
|
||||
char *virtual_obs_id;
|
||||
};
|
||||
|
||||
struct ofproto_ipfix_flow_exporter_options {
|
||||
@ -90,6 +91,7 @@ struct ofproto_ipfix_flow_exporter_options {
|
||||
uint32_t cache_active_timeout;
|
||||
uint32_t cache_max_flows;
|
||||
bool enable_tunnel_sampling;
|
||||
char *virtual_obs_id;
|
||||
};
|
||||
|
||||
struct ofproto_rstp_status {
|
||||
|
@ -1165,6 +1165,7 @@ bridge_configure_ipfix(struct bridge *br)
|
||||
struct ofproto_ipfix_bridge_exporter_options be_opts;
|
||||
struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL;
|
||||
size_t n_fe_opts = 0;
|
||||
const char *virtual_obs_id;
|
||||
|
||||
OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
|
||||
if (ovsrec_fscs_is_valid(fe_cfg, br)) {
|
||||
@ -1209,6 +1210,11 @@ bridge_configure_ipfix(struct bridge *br)
|
||||
|
||||
be_opts.enable_output_sampling = !smap_get_bool(&be_cfg->other_config,
|
||||
"enable-output-sampling", false);
|
||||
|
||||
virtual_obs_id = smap_get(&be_cfg->other_config, "virtual_obs_id");
|
||||
be_opts.virtual_obs_id = (virtual_obs_id
|
||||
? xstrdup(virtual_obs_id)
|
||||
: NULL);
|
||||
}
|
||||
|
||||
if (n_fe_opts > 0) {
|
||||
@ -1228,6 +1234,11 @@ bridge_configure_ipfix(struct bridge *br)
|
||||
opts->enable_tunnel_sampling = smap_get_bool(
|
||||
&fe_cfg->ipfix->other_config,
|
||||
"enable-tunnel-sampling", true);
|
||||
virtual_obs_id = smap_get(&fe_cfg->ipfix->other_config,
|
||||
"virtual_obs_id");
|
||||
opts->virtual_obs_id = (virtual_obs_id
|
||||
? xstrdup(virtual_obs_id)
|
||||
: NULL);
|
||||
opts++;
|
||||
}
|
||||
}
|
||||
@ -1238,6 +1249,7 @@ bridge_configure_ipfix(struct bridge *br)
|
||||
|
||||
if (valid_be_cfg) {
|
||||
sset_destroy(&be_opts.targets);
|
||||
free(be_opts.virtual_obs_id);
|
||||
}
|
||||
|
||||
if (n_fe_opts > 0) {
|
||||
@ -1245,6 +1257,7 @@ bridge_configure_ipfix(struct bridge *br)
|
||||
size_t i;
|
||||
for (i = 0; i < n_fe_opts; i++) {
|
||||
sset_destroy(&opts->targets);
|
||||
free(opts->virtual_obs_id);
|
||||
opts++;
|
||||
}
|
||||
free(fe_opts);
|
||||
|
@ -4747,6 +4747,39 @@
|
||||
</p>
|
||||
</column>
|
||||
|
||||
<column name="other_config" key="virtual_obs_id"
|
||||
type='{"type": "string"}'>
|
||||
<p>
|
||||
A string that accompanies each IPFIX flow record. Its intended use is
|
||||
for the ``virtual observation ID,'' an identifier of a virtual
|
||||
observation point that is locally unique in a virtual network. It
|
||||
describes a location in the virtual network where IP packets can be
|
||||
observed. The maximum length is 254 bytes. If not specified, the
|
||||
field is omitted from the IPFIX flow record.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following enterprise entity reports the specified virtual
|
||||
observation ID:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>virtualObsID:</dt>
|
||||
<dd>
|
||||
<p>ID: 898, and enterprise ID 6876 (VMware).</p>
|
||||
<p>type: variable-length string.</p>
|
||||
<p>data type semantics: identifier.</p>
|
||||
<p>description: A virtual observation domain ID that is locally
|
||||
unique in a virtual network.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<p>
|
||||
This feature was introduced in Open vSwitch 2.5.90.
|
||||
</p>
|
||||
</column>
|
||||
|
||||
<group title="Per-Bridge Sampling">
|
||||
<p>
|
||||
These values affect only per-bridge sampling. See above for a
|
||||
|
Loading…
x
Reference in New Issue
Block a user