[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