[ovs-dev] [PATCH 3/4] vswitchd: Add new configuration table for IPFIX collectors.
Romain Lenglet
rlenglet at vmware.com
Tue Dec 18 19:52:11 UTC 2012
Signed-off-by: Romain Lenglet <rlenglet at vmware.com>
---
ofproto/automake.mk | 2 +
ofproto/ofproto-dpif-ipfix.c | 125 +++++++++++++++++++++++++++++++++++++++++++
ofproto/ofproto-dpif-ipfix.h | 28 ++++++++++
ofproto/ofproto-dpif.c | 25 +++++++++
ofproto/ofproto-provider.h | 8 +++
ofproto/ofproto.c | 12 +++++
ofproto/ofproto.h | 7 +++
tests/ovs-vsctl.at | 2 +
utilities/ovs-vsctl.8.in | 25 +++++++--
utilities/ovs-vsctl.c | 13 +++++
vswitchd/bridge.c | 27 ++++++++++
vswitchd/vswitch.ovsschema | 17 +++++-
vswitchd/vswitch.xml | 26 +++++++++
13 files changed, 311 insertions(+), 6 deletions(-)
create mode 100644 ofproto/ofproto-dpif-ipfix.c
create mode 100644 ofproto/ofproto-dpif-ipfix.h
diff --git a/ofproto/automake.mk b/ofproto/automake.mk
index 9088292..c2d8faf 100644
--- a/ofproto/automake.mk
+++ b/ofproto/automake.mk
@@ -23,6 +23,8 @@ ofproto_libofproto_a_SOURCES = \
ofproto/ofproto-dpif.c \
ofproto/ofproto-dpif-governor.c \
ofproto/ofproto-dpif-governor.h \
+ ofproto/ofproto-dpif-ipfix.c \
+ ofproto/ofproto-dpif-ipfix.h \
ofproto/ofproto-dpif-sflow.c \
ofproto/ofproto-dpif-sflow.h \
ofproto/ofproto-provider.h \
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
new file mode 100644
index 0000000..9b3bfc3
--- /dev/null
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "ofproto-dpif-ipfix.h"
+#include "collectors.h"
+#include "ofproto.h"
+#include "sset.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(ipfix);
+
+static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+/* Cf. IETF RFC 5101 Section 10.3.4. */
+#define IPFIX_DEFAULT_COLLECTOR_PORT 4739
+
+struct dpif_ipfix {
+ struct collectors *collectors;
+ struct ofproto_ipfix_options *options;
+};
+
+struct dpif_ipfix *
+dpif_ipfix_create(void)
+{
+ struct dpif_ipfix *di;
+ di = xcalloc(1, sizeof *di);
+ return di;
+}
+
+void
+dpif_ipfix_destroy(struct dpif_ipfix *di)
+{
+ if (di) {
+ dpif_ipfix_clear(di);
+ free(di);
+ }
+}
+
+static bool
+ofproto_ipfix_options_equal(const struct ofproto_ipfix_options *a,
+ const struct ofproto_ipfix_options *b)
+{
+ return (a->obs_domain_id == b->obs_domain_id
+ && sset_equals(&a->targets, &b->targets));
+}
+
+static struct ofproto_ipfix_options *
+ofproto_ipfix_options_clone(const struct ofproto_ipfix_options *old)
+{
+ struct ofproto_ipfix_options *new = xmemdup(old, sizeof *old);
+ sset_clone(&new->targets, &old->targets);
+ return new;
+}
+
+static void
+ofproto_ipfix_options_destroy(struct ofproto_ipfix_options *options)
+{
+ if (options) {
+ sset_destroy(&options->targets);
+ free(options);
+ }
+}
+
+void
+dpif_ipfix_set_options(struct dpif_ipfix *di,
+ const struct ofproto_ipfix_options *options)
+{
+ bool options_changed;
+
+ if (sset_is_empty(&options->targets)) {
+ /* No point in doing any work if there are no targets. */
+ dpif_ipfix_clear(di);
+ return;
+ }
+
+ options_changed = (!di->options
+ || !ofproto_ipfix_options_equal(options, di->options));
+
+ /* Configure collectors if options have changed or if we're
+ * shortchanged in collectors (which indicates that opening one or
+ * more of the configured collectors failed, so that we should
+ * retry). */
+ if (options_changed
+ || collectors_count(di->collectors) < sset_count(&options->targets)) {
+ collectors_destroy(di->collectors);
+ collectors_create(&options->targets, IPFIX_DEFAULT_COLLECTOR_PORT,
+ &di->collectors);
+ if (di->collectors == NULL) {
+ VLOG_WARN_RL(&rl, "no collectors could be initialized, "
+ "IPFIX disabled");
+ dpif_ipfix_clear(di);
+ return;
+ }
+ }
+
+ /* Avoid reconfiguring if options didn't change. */
+ if (!options_changed) {
+ return;
+ }
+ ofproto_ipfix_options_destroy(di->options);
+ di->options = ofproto_ipfix_options_clone(options);
+}
+
+void
+dpif_ipfix_clear(struct dpif_ipfix *di)
+{
+ collectors_destroy(di->collectors);
+ di->collectors = NULL;
+ ofproto_ipfix_options_destroy(di->options);
+ di->options = NULL;
+}
diff --git a/ofproto/ofproto-dpif-ipfix.h b/ofproto/ofproto-dpif-ipfix.h
new file mode 100644
index 0000000..9660728
--- /dev/null
+++ b/ofproto/ofproto-dpif-ipfix.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFPROTO_DPIF_IPFIX_H
+#define OFPROTO_DPIF_IPFIX_H 1
+
+struct ofproto_ipfix_options;
+
+struct dpif_ipfix *dpif_ipfix_create(void);
+void dpif_ipfix_destroy(struct dpif_ipfix *);
+void dpif_ipfix_set_options(struct dpif_ipfix *,
+ const struct ofproto_ipfix_options *);
+void dpif_ipfix_clear(struct dpif_ipfix *);
+
+#endif /* ofproto/ofproto-dpif-ipfix.h */
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 2958d9f..b545d78 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -46,6 +46,7 @@
#include "ofp-parse.h"
#include "ofp-print.h"
#include "ofproto-dpif-governor.h"
+#include "ofproto-dpif-ipfix.h"
#include "ofproto-dpif-sflow.h"
#include "poll-loop.h"
#include "simap.h"
@@ -642,6 +643,7 @@ struct ofproto_dpif {
/* Bridging. */
struct netflow *netflow;
struct dpif_sflow *sflow;
+ struct dpif_ipfix *ipfix;
struct hmap bundles; /* Contains "struct ofbundle"s. */
struct mac_learning *ml;
struct ofmirror *mirrors[MAX_MIRRORS];
@@ -1078,6 +1080,7 @@ construct(struct ofproto *ofproto_)
ofproto->netflow = NULL;
ofproto->sflow = NULL;
+ ofproto->ipfix = NULL;
ofproto->stp = NULL;
hmap_init(&ofproto->bundles);
ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME);
@@ -1624,6 +1627,27 @@ set_sflow(struct ofproto *ofproto_,
}
static int
+set_ipfix(struct ofproto *ofproto_,
+ const struct ofproto_ipfix_options *ipfix_options)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct dpif_ipfix *di = ofproto->ipfix;
+
+ if (ipfix_options) {
+ if (!di) {
+ di = ofproto->ipfix = dpif_ipfix_create();
+ }
+ dpif_ipfix_set_options(di, ipfix_options);
+ } else {
+ if (di) {
+ dpif_ipfix_destroy(di);
+ ofproto->ipfix = NULL;
+ }
+ }
+ return 0;
+}
+
+static int
set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
{
struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
@@ -7982,6 +8006,7 @@ const struct ofproto_class ofproto_dpif_class = {
set_netflow,
get_netflow_ids,
set_sflow,
+ set_ipfix,
set_cfm,
get_cfm_fault,
get_cfm_opup,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index bc0105f..79a5832 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1101,6 +1101,14 @@ struct ofproto_class {
int (*set_sflow)(struct ofproto *ofproto,
const struct ofproto_sflow_options *sflow_options);
+ /* Configures IPFIX on 'ofproto' according to the options in
+ * 'ipfix_options', or turns off IPFIX if 'ipfix_options' is NULL.
+ *
+ * EOPNOTSUPP as a return value indicates that 'ofproto' does not support
+ * IPFIX, as does a null pointer. */
+ int (*set_ipfix)(struct ofproto *ofproto,
+ const struct ofproto_ipfix_options *ipfix_options);
+
/* Configures connectivity fault management on 'ofport'.
*
* If 'cfm_settings' is nonnull, configures CFM according to its members.
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f95d6ef..cf243be 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -682,6 +682,18 @@ ofproto_set_sflow(struct ofproto *ofproto,
return oso ? EOPNOTSUPP : 0;
}
}
+
+int
+ofproto_set_ipfix(struct ofproto *ofproto,
+ const struct ofproto_ipfix_options *oio)
+{
+ /* TODO: Check the options. */
+ if (ofproto->ofproto_class->set_ipfix) {
+ return ofproto->ofproto_class->set_ipfix(ofproto, oio);
+ } else {
+ return oio ? EOPNOTSUPP : 0;
+ }
+}
/* Spanning Tree Protocol (STP) configuration. */
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index dc5d9ce..2b07c60 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -69,6 +69,12 @@ struct ofproto_sflow_options {
char *control_ip;
};
+struct ofproto_ipfix_options {
+ /* TODO: Specify necessary options. */
+ struct sset targets;
+ uint32_t obs_domain_id; /* Observation Domain ID. */
+};
+
struct ofproto_stp_settings {
stp_identifier system_id;
uint16_t priority;
@@ -239,6 +245,7 @@ int ofproto_set_snoops(struct ofproto *, const struct sset *snoops);
int ofproto_set_netflow(struct ofproto *,
const struct netflow_options *nf_options);
int ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *);
+int ofproto_set_ipfix(struct ofproto *, const struct ofproto_ipfix_options *);
int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *);
int ofproto_get_stp_status(struct ofproto *, struct ofproto_stp_status *);
diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index 6a1cc35..fc00f36 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -598,6 +598,7 @@ external_ids : {}
fail_mode : []
flood_vlans : []
flow_tables : {}
+ipfix : []
mirrors : []
name : "br0"
netflow : []
@@ -1065,6 +1066,7 @@ external_ids : {}
fail_mode : []
flood_vlans : []
flow_tables : {}
+ipfix : []
mirrors : []
name : "br0"
netflow : []
diff --git a/utilities/ovs-vsctl.8.in b/utilities/ovs-vsctl.8.in
index e3ca78b..91ac4ea 100644
--- a/utilities/ovs-vsctl.8.in
+++ b/utilities/ovs-vsctl.8.in
@@ -158,10 +158,11 @@ Prints a brief overview of the database contents.
.IP "\fBemer\-reset\fR"
Reset the configuration into a clean state. It deconfigures OpenFlow
controllers, OVSDB servers, and SSL, and deletes port mirroring,
-\fBfail_mode\fR, NetFlow, and sFlow configuration. This command also
-removes all \fBother\-config\fR keys from all database records, except
-that \fBother\-config:hwaddr\fR is preserved if it is present in a
-Bridge record. Other networking configuration is left as-is.
+\fBfail_mode\fR, NetFlow, sFlow, and IPFIX configuration. This
+command also removes all \fBother\-config\fR keys from all database
+records, except that \fBother\-config:hwaddr\fR is preserved if it is
+present in a Bridge record. Other networking configuration is left
+as-is.
.
.SS "Bridge Commands"
These commands examine and manipulate Open vSwitch bridges.
@@ -514,6 +515,9 @@ specifying \fB.\fR as the record name.
.IP "\fBsFlow\fR"
An sFlow configuration attached to a bridge. Records may be
identified by bridge name.
+.IP "\fBIPFIX\fR"
+An IPFIX configuration attached to a bridge. Records may be
+identified by bridge name.
.PP
Record names must be specified in full and with correct
capitalization. Names of tables and columns are not case-sensitive,
@@ -893,6 +897,19 @@ Deconfigure sFlow from \fBbr0\fR, which also destroys the sFlow record
(since it is now unreferenced):
.IP
.B "ovs\-vsctl \-\- clear Bridge br0 sflow"
+.SS "IPFIX"
+.PP
+Configure bridge \fBbr0\fR to send IPFIX records to UDP port 4739 on
+host 192.168.0.34, with Observation Domain ID 1356:
+.IP
+.B "ovs\-vsctl \-\- set Bridge br0 ipfix=@i \(rs"
+.IP
+.B "\-\- \-\-id=@i create IPFIX targets=\(rs\(dq192.168.0.34:4739\(rs\(dq obs_domain_id=1356"
+.PP
+Deconfigure the IPFIX settings from \fBbr0\fR, which also destroys the
+IPFIX record (since it is now unreferenced):
+.IP
+.B "ovs\-vsctl clear Bridge br0 ipfix"
.SS "802.1D Spanning Tree Protocol (STP)"
.PP
Configure bridge \fBbr0\fR to participate in an 802.1D spanning tree:
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index bccb2c9..54d27d3 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -1432,6 +1432,7 @@ pre_cmd_emer_reset(struct vsctl_context *ctx)
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_mirrors);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_netflow);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_sflow);
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ipfix);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_flood_vlans);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_other_config);
@@ -1456,6 +1457,7 @@ cmd_emer_reset(struct vsctl_context *ctx)
const struct ovsrec_netflow *nf, *next_nf;
const struct ovsrec_ssl *ssl, *next_ssl;
const struct ovsrec_sflow *sflow, *next_sflow;
+ const struct ovsrec_ipfix *ipfix, *next_ipfix;
/* Reset the Open_vSwitch table. */
ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0);
@@ -1469,6 +1471,7 @@ cmd_emer_reset(struct vsctl_context *ctx)
ovsrec_bridge_set_mirrors(br, NULL, 0);
ovsrec_bridge_set_netflow(br, NULL);
ovsrec_bridge_set_sflow(br, NULL);
+ ovsrec_bridge_set_ipfix(br, NULL);
ovsrec_bridge_set_flood_vlans(br, NULL, 0);
/* We only want to save the "hwaddr" key from other_config. */
@@ -1518,6 +1521,10 @@ cmd_emer_reset(struct vsctl_context *ctx)
ovsrec_sflow_delete(sflow);
}
+ OVSREC_IPFIX_FOR_EACH_SAFE (ipfix, next_ipfix, idl) {
+ ovsrec_ipfix_delete(ipfix);
+ }
+
vsctl_context_invalidate_cache(ctx);
}
@@ -2497,6 +2504,12 @@ static const struct vsctl_table_class tables[] = {
{{&ovsrec_table_flow_table, &ovsrec_flow_table_col_name, NULL},
{NULL, NULL, NULL}}},
+ {&ovsrec_table_ipfix,
+ {{&ovsrec_table_bridge,
+ &ovsrec_bridge_col_name,
+ &ovsrec_bridge_col_ipfix},
+ {NULL, NULL, NULL}}},
+
{NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
};
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index d23caf2..4f116bb 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -184,6 +184,7 @@ static void bridge_configure_netflow(struct bridge *);
static void bridge_configure_forward_bpdu(struct bridge *);
static void bridge_configure_mac_table(struct bridge *);
static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number);
+static void bridge_configure_ipfix(struct bridge *);
static void bridge_configure_stp(struct bridge *);
static void bridge_configure_tables(struct bridge *);
static void bridge_configure_remotes(struct bridge *,
@@ -595,6 +596,7 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
bridge_configure_remotes(br, managers, n_managers);
bridge_configure_netflow(br);
bridge_configure_sflow(br, &sflow_bridge_number);
+ bridge_configure_ipfix(br);
bridge_configure_stp(br);
bridge_configure_tables(br);
}
@@ -939,6 +941,31 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number)
sset_destroy(&oso.targets);
}
+/* Set IPFIX configuration on 'br'. */
+static void
+bridge_configure_ipfix(struct bridge *br)
+{
+ const struct ovsrec_ipfix *cfg = br->cfg->ipfix;
+ struct ofproto_ipfix_options oio;
+
+ if (!cfg) {
+ ofproto_set_ipfix(br->ofproto, NULL);
+ return;
+ }
+
+ memset(&oio, 0, sizeof oio);
+
+ /* Collectors. */
+ sset_init(&oio.targets);
+ sset_add_array(&oio.targets, cfg->targets, cfg->n_targets);
+
+ oio.obs_domain_id = *cfg->obs_domain_id;
+
+ ofproto_set_ipfix(br->ofproto, &oio);
+
+ sset_destroy(&oio.targets);
+}
+
static void
port_configure_stp(const struct ofproto *ofproto, struct port *port,
struct ofproto_port_stp_settings *port_s,
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index 16125a5..bc0be13 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
- "version": "6.11.3",
- "cksum": "2234602985 17310",
+ "version": "6.12.0",
+ "cksum": "394944541 17792",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -70,6 +70,10 @@
"type": {"key": {"type": "uuid",
"refTable": "sFlow"},
"min": 0, "max": 1}},
+ "ipfix": {
+ "type": {"key": {"type": "uuid",
+ "refTable": "IPFIX"},
+ "min": 0, "max": 1}},
"controller": {
"type": {"key": {"type": "uuid",
"refTable": "Controller"},
@@ -379,6 +383,15 @@
"external_ids": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}}},
+ "IPFIX": {
+ "columns": {
+ "targets": {
+ "type": {"key": "string", "min": 1, "max": "unlimited"}},
+ "obs_domain_id": {
+ "type": {"key": "integer", "min": 0, "max": 1}},
+ "external_ids": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}}}},
"Controller": {
"columns": {
"target": {
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index c78899f..3464c42 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -343,6 +343,10 @@
sFlow configuration.
</column>
+ <column name="ipfix">
+ IPFIX configuration.
+ </column>
+
<column name="flood_vlans">
<p>
VLAN IDs of VLANs on which MAC address learning should be disabled,
@@ -3208,4 +3212,26 @@
</group>
</table>
+ <table name="IPFIX">
+ <p>An IPFIX target. IPFIX is a protocol that exports a number of
+ details about terminating IP flows.</p>
+
+ <column name="targets">
+ IPFIX targets in the form
+ <code><var>ip</var>:<var>port</var></code>.
+ </column>
+
+ <column name="obs_domain_id">
+ The IPFIX Observation Domain ID sent in IPFIX packets. If not
+ specified, defaults to 0.
+ </column>
+
+ <group title="Common Columns">
+ The overall purpose of these columns is described under <code>Common
+ Columns</code> at the beginning of this document.
+
+ <column name="external_ids"/>
+ </group>
+ </table>
+
</database>
--
1.8.0.1
More information about the dev
mailing list