Signed-off-by: Romain Lenglet <rleng...@vmware.com> --- ofproto/automake.mk | 2 + ofproto/ofproto-dpif-ipfix.c | 126 +++++++++++++++++++++++++++++++++++++++++++ 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 | 4 +- utilities/ovs-vsctl.8.in | 25 +++++++-- utilities/ovs-vsctl.c | 13 +++++ vswitchd/bridge.c | 27 ++++++++++ vswitchd/vswitch.ovsschema | 20 ++++++- vswitchd/vswitch.xml | 26 +++++++++ 13 files changed, 316 insertions(+), 7 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..cda8796 --- /dev/null +++ b/ofproto/ofproto-dpif-ipfix.c @@ -0,0 +1,126 @@ +/* + * 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 "util.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 = xzalloc(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 3d9e769..6e74551 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]; @@ -1087,6 +1089,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); @@ -1634,6 +1637,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_); @@ -8032,6 +8056,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 f2274ef..fb94f12 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 918b9b4..f91567f 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -639,6 +639,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 413472a..82a0d37 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; @@ -230,6 +236,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 326d5a4..d015699 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 : [] @@ -788,7 +789,7 @@ AT_CHECK([RUN_OVS_VSCTL([clear netflow `cat netflow-uuid` targets])], AT_CHECK([RUN_OVS_VSCTL([destroy b br2])], [1], [], [ovs-vsctl: no row "br2" in table Bridge ], [OVS_VSCTL_CLEANUP]) -AT_CHECK([RUN_OVS_VSCTL([add i br1 name x])], +AT_CHECK([RUN_OVS_VSCTL([add in br1 name x])], [1], [], [ovs-vsctl: cannot modify read-only column name in table Interface ], [OVS_VSCTL_CLEANUP]) AT_CHECK([RUN_OVS_VSCTL([set port br1 name br2])], @@ -1089,6 +1090,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 cf6cf88..cdd4e9a 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, @@ -917,6 +921,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 1ba8588..9384974 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1431,6 +1431,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); @@ -1455,6 +1456,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); @@ -1468,6 +1470,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. */ @@ -1517,6 +1520,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); } @@ -2496,6 +2503,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 82c3bff..d36eb20 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -183,6 +183,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_dp_desc(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); bridge_configure_dp_desc(br); @@ -940,6 +942,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..632d01c 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": "1621253653 17915", "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,18 @@ "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": {"type": "integer", + "minInteger": 0, + "maxInteger": 4294967295}, + "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 18643c2..7151bc1 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, @@ -3194,4 +3198,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.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev