mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
Implement IPFIX export
Define a new NXAST_SAMPLE OpenFlow vendor action and the corresponding OFPACT_SAMPLE OVS action, to do per-flow packet sampling, translated into a new SAMPLE "flow_sample" dp action. Make the userspace action's userdata size vary depending on the union member used. Add a new "flow_sample" upcall to do per-flow packet sampling. Add a new "ipfix" upcall to do per-bridge packet sampling to IPFIX collectors. Extend the OVSDB schema to support configuring IPFIX collector sets. Add support for configuring multiple IPFIX collectors for per-flow packet sampling. Add support for configuring per-bridge IPFIX sampling. Automatically generate standard IPFIX entity definitions from the IANA specs. Send one IPFIX data record message for every packet sampled by an OpenFlow sample action or received by a bridge configured with IPFIX sampling, and periodically send IPFIX template set messages. Signed-off-by: Romain Lenglet <rlenglet@vmware.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
parent
d8558b4ae8
commit
29089a540c
18
FAQ
18
FAQ
@ -9,12 +9,13 @@ General
|
||||
Q: What is Open vSwitch?
|
||||
|
||||
A: Open vSwitch is a production quality open source software switch
|
||||
designed to be used as a vswitch in virtualized server environments. A
|
||||
vswitch forwards traffic between different VMs on the same physical host
|
||||
and also forwards traffic between VMs and the physical network. Open
|
||||
vSwitch supports standard management interfaces (e.g. sFlow, NetFlow,
|
||||
RSPAN, CLI), and is open to programmatic extension and control using
|
||||
OpenFlow and the OVSDB management protocol.
|
||||
designed to be used as a vswitch in virtualized server
|
||||
environments. A vswitch forwards traffic between different VMs on
|
||||
the same physical host and also forwards traffic between VMs and
|
||||
the physical network. Open vSwitch supports standard management
|
||||
interfaces (e.g. sFlow, NetFlow, IPFIX, RSPAN, CLI), and is open to
|
||||
programmatic extension and control using OpenFlow and the OVSDB
|
||||
management protocol.
|
||||
|
||||
Open vSwitch as designed to be compatible with modern switching
|
||||
chipsets. This means that it can be ported to existing high-fanout
|
||||
@ -153,6 +154,11 @@ A: The following table lists the Linux kernel versions against which the
|
||||
It should build against almost any kernel, certainly against 2.6.18
|
||||
and later.
|
||||
|
||||
Q: What Linux kernel versions does IPFIX flow monitoring work with?
|
||||
|
||||
A: IPFIX flow monitoring requires the Linux kernel module from Open
|
||||
vSwitch version 1.10.90 or later.
|
||||
|
||||
Q: Should userspace or kernel be upgraded first to minimize downtime?
|
||||
|
||||
In general, the Open vSwitch userspace should be used with the
|
||||
|
1
NEWS
1
NEWS
@ -82,6 +82,7 @@ v1.10.0 - xx xxx xxxx
|
||||
retire that meaning of ANY in favor of the OpenFlow 1.1 meaning.
|
||||
- Patch ports no longer require kernel support, so they now work
|
||||
with FreeBSD and the kernel module built into Linux 3.3 and later.
|
||||
- New "sample" action.
|
||||
|
||||
|
||||
v1.9.0 - 26 Feb 2013
|
||||
|
17
WHY-OVS
17
WHY-OVS
@ -21,7 +21,7 @@ vSwitch cope with the above requirements.
|
||||
migratable between different hosts. This may include traditional
|
||||
"soft state" (such as an entry in an L2 learning table), L3 forwarding
|
||||
state, policy routing state, ACLs, QoS policy, monitoring
|
||||
configuration (e.g. NetFlow, sFlow), etc.
|
||||
configuration (e.g. NetFlow, IPFIX, sFlow), etc.
|
||||
|
||||
Open vSwitch has support for both configuring and migrating both slow
|
||||
(configuration) and fast network state between instances. For
|
||||
@ -38,13 +38,14 @@ vSwitch cope with the above requirements.
|
||||
environments, and so forth.
|
||||
|
||||
Open vSwitch supports a number of features that allow a network
|
||||
control system to respond and adapt as the environment changes. This
|
||||
includes simple accounting and visibility support such as NetFlow and
|
||||
sFlow. But perhaps more useful, Open vSwitch supports a network state
|
||||
database (OVSDB) that supports remote triggers. Therefore, a piece of
|
||||
orchestration software can "watch" various aspects of the network and
|
||||
respond if/when they change. This is used heavily today, for example,
|
||||
to respond to and track VM migrations.
|
||||
control system to respond and adapt as the environment changes.
|
||||
This includes simple accounting and visibility support such as
|
||||
NetFlow, IPFIX, and sFlow. But perhaps more useful, Open vSwitch
|
||||
supports a network state database (OVSDB) that supports remote
|
||||
triggers. Therefore, a piece of orchestration software can "watch"
|
||||
various aspects of the network and respond if/when they change.
|
||||
This is used heavily today, for example, to respond to and track VM
|
||||
migrations.
|
||||
|
||||
Open vSwitch also supports OpenFlow as a method of exporting remote
|
||||
access to control traffic. There are a number of uses for this
|
||||
|
158
debian/control
vendored
158
debian/control
vendored
@ -16,13 +16,13 @@ Architecture: all
|
||||
Depends: module-assistant, bzip2, debhelper (>= 5.0.37), ${misc:Depends}
|
||||
Suggests: openvswitch-switch
|
||||
Description: Open vSwitch datapath module source - module-assistant version
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
This package provides the Open vSwitch datapath module source code
|
||||
that is needed by openvswitch-switch. The kernel module can be built
|
||||
@ -33,13 +33,13 @@ Package: openvswitch-datapath-dkms
|
||||
Architecture: all
|
||||
Depends: dkms (>= 1.95), make, libc6-dev, ${misc:Depends}, ${python:Depends}
|
||||
Description: Open vSwitch datapath module source - DKMS version
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
This package provides the Open vSwitch datapath module source code
|
||||
that is needed by openvswitch-switch. DKMS can built the kernel
|
||||
@ -52,13 +52,13 @@ Depends:
|
||||
python (>= 2.7) | python-argparse
|
||||
Suggests: ethtool
|
||||
Description: Open vSwitch common components
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
openvswitch-common provides components required by both openvswitch-switch
|
||||
and openvswitch-controller.
|
||||
@ -68,34 +68,34 @@ Architecture: linux-any
|
||||
Suggests: openvswitch-datapath-module
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, openvswitch-common (= ${binary:Version}), module-init-tools, procps, uuid-runtime, netbase
|
||||
Description: Open vSwitch switch implementations
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
openvswitch-switch provides the userspace components and utilities for
|
||||
the Open vSwitch kernel-based switch.
|
||||
the Open vSwitch kernel-based switch.
|
||||
|
||||
Package: openvswitch-ipsec
|
||||
Architecture: linux-any
|
||||
Depends:
|
||||
${shlibs:Depends}, ${misc:Depends}, python,
|
||||
ipsec-tools (>=0.8~alpha20101208),
|
||||
ipsec-tools (>=0.8~alpha20101208),
|
||||
racoon (>=0.8~alpha20101208),
|
||||
openvswitch-common (= ${binary:Version}),
|
||||
openvswitch-switch (= ${binary:Version}),
|
||||
python-openvswitch (= ${source:Version})
|
||||
Description: Open vSwitch GRE-over-IPsec support
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
The ovs-monitor-ipsec script provides support for encrypting GRE
|
||||
tunnels with IPsec.
|
||||
@ -106,13 +106,13 @@ Depends:
|
||||
${misc:Depends}, openvswitch-common (>= ${source:Version}),
|
||||
openvswitch-common (<< ${source:Version}.1~)
|
||||
Description: Open vSwitch public key infrastructure dependency package
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
openvswitch-pki provides PKI (public key infrastructure) support for
|
||||
Open vSwitch switches and controllers, reducing the risk of
|
||||
@ -124,13 +124,13 @@ Depends:
|
||||
${shlibs:Depends}, openvswitch-common (= ${binary:Version}),
|
||||
openvswitch-pki (= ${source:Version}), ${misc:Depends}
|
||||
Description: Open vSwitch controller implementation
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
The Open vSwitch controller enables OpenFlow switches that connect to it
|
||||
to act as MAC-learning Ethernet switches.
|
||||
@ -144,13 +144,13 @@ Depends:
|
||||
openvswitch-controller (= ${binary:Version}),
|
||||
openvswitch-switch (= ${binary:Version})
|
||||
Description: Debug symbols for Open vSwitch packages
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
This package contains the debug symbols for all the other openvswitch-*
|
||||
packages. Install it to debug one of them or to examine a core dump
|
||||
@ -161,13 +161,13 @@ Architecture: all
|
||||
Section: python
|
||||
Depends: ${misc:Depends}, ${python:Depends}
|
||||
Description: Python bindings for Open vSwitch
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
This package contains the full Python bindings for Open vSwitch database.
|
||||
|
||||
@ -176,13 +176,13 @@ Architecture: all
|
||||
Section: utils
|
||||
Depends: ${python:Depends}, python-openvswitch, ${misc:Depends}
|
||||
Description: Open vSwitch graphical monitoring tool
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
This package is a GUI tool for monitoring and troubleshooting local
|
||||
or remote Open vSwitch installations. It presents GUI tables that
|
||||
@ -194,13 +194,13 @@ Package: openvswitch-test
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${python:Depends}, python-twisted-web, python (>= 2.7) | python-argparse
|
||||
Description: Open vSwitch test package
|
||||
Open vSwitch is a production quality, multilayer, software-based, Ethernet
|
||||
virtual switch. It is designed to enable massive network automation through
|
||||
programmatic extension, while still supporting standard management interfaces
|
||||
and protocols (e.g. NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In
|
||||
addition, it is designed to support distribution across multiple physical
|
||||
servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus
|
||||
1000V.
|
||||
Open vSwitch is a production quality, multilayer, software-based,
|
||||
Ethernet virtual switch. It is designed to enable massive network
|
||||
automation through programmatic extension, while still supporting
|
||||
standard management interfaces and protocols (e.g. NetFlow, IPFIX,
|
||||
sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
|
||||
to support distribution across multiple physical servers similar to
|
||||
VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
|
||||
.
|
||||
This package contains utilities that are useful to diagnose
|
||||
performance and connectivity issues in Open vSwitch setup.
|
||||
|
@ -312,6 +312,7 @@ enum nx_action_subtype {
|
||||
NXAST_DEC_MPLS_TTL, /* struct nx_action_header */
|
||||
NXAST_STACK_PUSH, /* struct nx_action_stack */
|
||||
NXAST_STACK_POP, /* struct nx_action_stack */
|
||||
NXAST_SAMPLE, /* struct nx_action_sample */
|
||||
};
|
||||
|
||||
/* Header for Nicira-defined actions. */
|
||||
@ -2233,4 +2234,29 @@ struct nx_action_mpls_ttl {
|
||||
};
|
||||
OFP_ASSERT(sizeof(struct nx_action_mpls_ttl) == 16);
|
||||
|
||||
/* Action structure for NXAST_SAMPLE.
|
||||
*
|
||||
* Samples matching packets with the given probability and sends them
|
||||
* each to the set of collectors identified with the given ID. The
|
||||
* probability is expressed as a number of packets to be sampled out
|
||||
* of USHRT_MAX packets, and must be >0.
|
||||
*
|
||||
* When sending packet samples to IPFIX collectors, the IPFIX flow
|
||||
* record sent for each sampled packet is associated with the given
|
||||
* observation domain ID and observation point ID. Each IPFIX flow
|
||||
* record contain the sampled packet's headers when executing this
|
||||
* rule. If a sampled packet's headers are modified by previous
|
||||
* actions in the flow, those modified headers are sent. */
|
||||
struct nx_action_sample {
|
||||
ovs_be16 type; /* OFPAT_VENDOR. */
|
||||
ovs_be16 len; /* Length is 24. */
|
||||
ovs_be32 vendor; /* NX_VENDOR_ID. */
|
||||
ovs_be16 subtype; /* NXAST_SAMPLE. */
|
||||
ovs_be16 probability; /* Fraction of packets to sample. */
|
||||
ovs_be32 collector_set_id; /* ID of collector set in OVSDB. */
|
||||
ovs_be32 obs_domain_id; /* ID of sampling observation domain. */
|
||||
ovs_be32 obs_point_id; /* ID of sampling observation point. */
|
||||
};
|
||||
OFP_ASSERT(sizeof(struct nx_action_sample) == 24);
|
||||
|
||||
#endif /* openflow/nicira-ext.h */
|
||||
|
112
lib/odp-util.c
112
lib/odp-util.c
@ -262,43 +262,60 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
|
||||
nl_attr_get_u32(a[OVS_USERSPACE_ATTR_PID]));
|
||||
|
||||
userdata_attr = a[OVS_USERSPACE_ATTR_USERDATA];
|
||||
if (userdata_attr && nl_attr_get_size(userdata_attr) == sizeof(uint64_t)) {
|
||||
uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]);
|
||||
|
||||
if (userdata_attr) {
|
||||
const uint8_t *userdata = nl_attr_get(userdata_attr);
|
||||
size_t userdata_len = nl_attr_get_size(userdata_attr);
|
||||
bool userdata_unspec = true;
|
||||
union user_action_cookie cookie;
|
||||
|
||||
memcpy(&cookie, &userdata, sizeof cookie);
|
||||
if (userdata_len >= sizeof cookie.type
|
||||
&& userdata_len <= sizeof cookie) {
|
||||
|
||||
switch (cookie.type) {
|
||||
case USER_ACTION_COOKIE_SFLOW:
|
||||
ds_put_format(ds, ",sFlow("
|
||||
"vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")",
|
||||
vlan_tci_to_vid(cookie.sflow.vlan_tci),
|
||||
vlan_tci_to_pcp(cookie.sflow.vlan_tci),
|
||||
cookie.sflow.output);
|
||||
break;
|
||||
memset(&cookie, 0, sizeof cookie);
|
||||
memcpy(&cookie, userdata, userdata_len);
|
||||
|
||||
case USER_ACTION_COOKIE_SLOW_PATH:
|
||||
ds_put_cstr(ds, ",slow_path(");
|
||||
format_flags(ds, slow_path_reason_to_string,
|
||||
cookie.slow_path.reason, ',');
|
||||
ds_put_format(ds, ")");
|
||||
break;
|
||||
userdata_unspec = false;
|
||||
|
||||
case USER_ACTION_COOKIE_UNSPEC:
|
||||
default:
|
||||
ds_put_format(ds, ",userdata=0x%"PRIx64, userdata);
|
||||
break;
|
||||
if (userdata_len == sizeof cookie.sflow
|
||||
&& cookie.type == USER_ACTION_COOKIE_SFLOW) {
|
||||
ds_put_format(ds, ",sFlow("
|
||||
"vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")",
|
||||
vlan_tci_to_vid(cookie.sflow.vlan_tci),
|
||||
vlan_tci_to_pcp(cookie.sflow.vlan_tci),
|
||||
cookie.sflow.output);
|
||||
} else if (userdata_len == sizeof cookie.slow_path
|
||||
&& cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
|
||||
ds_put_cstr(ds, ",slow_path(");
|
||||
format_flags(ds, slow_path_reason_to_string,
|
||||
cookie.slow_path.reason, ',');
|
||||
ds_put_format(ds, ")");
|
||||
} else if (userdata_len == sizeof cookie.flow_sample
|
||||
&& cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
|
||||
ds_put_format(ds, ",flow_sample(probability=%"PRIu16
|
||||
",collector_set_id=%"PRIu32
|
||||
",obs_domain_id=%"PRIu32
|
||||
",obs_point_id=%"PRIu32")",
|
||||
cookie.flow_sample.probability,
|
||||
cookie.flow_sample.collector_set_id,
|
||||
cookie.flow_sample.obs_domain_id,
|
||||
cookie.flow_sample.obs_point_id);
|
||||
} else if (userdata_len == sizeof cookie.ipfix
|
||||
&& cookie.type == USER_ACTION_COOKIE_IPFIX) {
|
||||
ds_put_format(ds, ",ipfix");
|
||||
} else {
|
||||
userdata_unspec = true;
|
||||
}
|
||||
}
|
||||
} else if (userdata_attr) {
|
||||
const uint8_t *userdata = nl_attr_get(userdata_attr);
|
||||
size_t len = nl_attr_get_size(userdata_attr);
|
||||
size_t i;
|
||||
|
||||
ds_put_format(ds, ",userdata(");
|
||||
for (i = 0; i < len; i++) {
|
||||
ds_put_format(ds, "%02x", userdata[i]);
|
||||
if (userdata_unspec) {
|
||||
size_t i;
|
||||
ds_put_format(ds, ",userdata(");
|
||||
for (i = 0; i < userdata_len; i++) {
|
||||
ds_put_format(ds, "%02x", userdata[i]);
|
||||
}
|
||||
ds_put_char(ds, ')');
|
||||
}
|
||||
ds_put_char(ds, ')');
|
||||
}
|
||||
|
||||
ds_put_char(ds, ')');
|
||||
@ -456,7 +473,10 @@ parse_odp_action(const char *s, const struct simap *port_names,
|
||||
{
|
||||
unsigned long long int pid;
|
||||
unsigned long long int output;
|
||||
char userdata_s[32];
|
||||
unsigned long long int probability;
|
||||
unsigned long long int collector_set_id;
|
||||
unsigned long long int obs_domain_id;
|
||||
unsigned long long int obs_point_id;
|
||||
int vid, pcp;
|
||||
int n = -1;
|
||||
|
||||
@ -477,7 +497,8 @@ parse_odp_action(const char *s, const struct simap *port_names,
|
||||
cookie.type = USER_ACTION_COOKIE_SFLOW;
|
||||
cookie.sflow.vlan_tci = htons(tci);
|
||||
cookie.sflow.output = output;
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie.sflow,
|
||||
actions);
|
||||
return n;
|
||||
} else if (sscanf(s, "userspace(pid=%lli,slow_path%n", &pid, &n) > 0
|
||||
&& n > 0) {
|
||||
@ -499,15 +520,30 @@ parse_odp_action(const char *s, const struct simap *port_names,
|
||||
}
|
||||
n++;
|
||||
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path,
|
||||
actions);
|
||||
return n;
|
||||
} else if (sscanf(s, "userspace(pid=%lli,userdata="
|
||||
"%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s,
|
||||
&n) > 0 && n > 0) {
|
||||
uint64_t userdata;
|
||||
} else if (sscanf(s, "userspace(pid=%lli,flow_sample(probability=%lli,"
|
||||
"collector_set_id=%lli,obs_domain_id=%lli,"
|
||||
"obs_point_id=%lli))%n",
|
||||
&pid, &probability, &collector_set_id,
|
||||
&obs_domain_id, &obs_point_id, &n) > 0 && n > 0) {
|
||||
union user_action_cookie cookie;
|
||||
|
||||
userdata = strtoull(userdata_s, NULL, 0);
|
||||
odp_put_userspace_action(pid, &userdata, sizeof(userdata),
|
||||
cookie.type = USER_ACTION_COOKIE_FLOW_SAMPLE;
|
||||
cookie.flow_sample.probability = probability;
|
||||
cookie.flow_sample.collector_set_id = collector_set_id;
|
||||
cookie.flow_sample.obs_domain_id = obs_domain_id;
|
||||
cookie.flow_sample.obs_point_id = obs_point_id;
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie.flow_sample,
|
||||
actions);
|
||||
return n;
|
||||
} else if (sscanf(s, "userspace(pid=%lli,ipfix)%n", &pid, &n) > 0
|
||||
&& n > 0) {
|
||||
union user_action_cookie cookie;
|
||||
|
||||
cookie.type = USER_ACTION_COOKIE_IPFIX;
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie.ipfix,
|
||||
actions);
|
||||
return n;
|
||||
} else if (sscanf(s, "userspace(pid=%lli,userdata(%n", &pid, &n) > 0
|
||||
|
@ -127,8 +127,10 @@ void commit_odp_actions(const struct flow *, struct flow *base,
|
||||
|
||||
enum user_action_cookie_type {
|
||||
USER_ACTION_COOKIE_UNSPEC,
|
||||
USER_ACTION_COOKIE_SFLOW, /* Packet for sFlow sampling. */
|
||||
USER_ACTION_COOKIE_SLOW_PATH /* Userspace must process this flow. */
|
||||
USER_ACTION_COOKIE_SFLOW, /* Packet for per-bridge sFlow sampling. */
|
||||
USER_ACTION_COOKIE_SLOW_PATH, /* Userspace must process this flow. */
|
||||
USER_ACTION_COOKIE_FLOW_SAMPLE, /* Packet for per-flow sampling. */
|
||||
USER_ACTION_COOKIE_IPFIX, /* Packet for per-bridge IPFIX sampling. */
|
||||
};
|
||||
|
||||
/* user_action_cookie is passed as argument to OVS_ACTION_ATTR_USERSPACE.
|
||||
@ -147,8 +149,20 @@ union user_action_cookie {
|
||||
uint16_t unused;
|
||||
uint32_t reason; /* enum slow_path_reason. */
|
||||
} slow_path;
|
||||
|
||||
struct {
|
||||
uint16_t type; /* USER_ACTION_COOKIE_FLOW_SAMPLE. */
|
||||
uint16_t probability; /* Sampling probability. */
|
||||
uint32_t collector_set_id; /* ID of IPFIX collector set. */
|
||||
uint32_t obs_domain_id; /* Observation Domain ID. */
|
||||
uint32_t obs_point_id; /* Observation Point ID. */
|
||||
} flow_sample;
|
||||
|
||||
struct {
|
||||
uint16_t type; /* USER_ACTION_COOKIE_IPFIX. */
|
||||
} ipfix;
|
||||
};
|
||||
BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 8);
|
||||
BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 16);
|
||||
|
||||
size_t odp_put_userspace_action(uint32_t pid,
|
||||
const void *userdata, size_t userdata_size,
|
||||
|
@ -217,6 +217,25 @@ dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
sample_from_openflow(const struct nx_action_sample *nas,
|
||||
struct ofpbuf *out)
|
||||
{
|
||||
struct ofpact_sample *sample;
|
||||
|
||||
sample = ofpact_put_SAMPLE(out);
|
||||
sample->probability = ntohs(nas->probability);
|
||||
sample->collector_set_id = ntohl(nas->collector_set_id);
|
||||
sample->obs_domain_id = ntohl(nas->obs_domain_id);
|
||||
sample->obs_point_id = ntohl(nas->obs_point_id);
|
||||
|
||||
if (sample->probability == 0) {
|
||||
return OFPERR_OFPBAC_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
|
||||
{
|
||||
@ -434,6 +453,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
|
||||
ofpact_put_POP_MPLS(out)->ethertype = nxapm->ethertype;
|
||||
break;
|
||||
}
|
||||
|
||||
case OFPUTIL_NXAST_SAMPLE:
|
||||
error = sample_from_openflow(
|
||||
(const struct nx_action_sample *) a, out);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
@ -1199,6 +1223,9 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
|
||||
*dl_type = ofpact_get_POP_MPLS(a)->ethertype;
|
||||
return 0;
|
||||
|
||||
case OFPACT_SAMPLE:
|
||||
return 0;
|
||||
|
||||
case OFPACT_CLEAR_ACTIONS:
|
||||
case OFPACT_WRITE_METADATA:
|
||||
case OFPACT_GOTO_TABLE:
|
||||
@ -1393,6 +1420,19 @@ ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
|
||||
naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
ofpact_sample_to_nxast(const struct ofpact_sample *os,
|
||||
struct ofpbuf *out)
|
||||
{
|
||||
struct nx_action_sample *nas;
|
||||
|
||||
nas = ofputil_put_NXAST_SAMPLE(out);
|
||||
nas->probability = htons(os->probability);
|
||||
nas->collector_set_id = htonl(os->collector_set_id);
|
||||
nas->obs_domain_id = htonl(os->obs_domain_id);
|
||||
nas->obs_point_id = htonl(os->obs_point_id);
|
||||
}
|
||||
|
||||
static void
|
||||
ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
|
||||
{
|
||||
@ -1489,6 +1529,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
|
||||
ofpact_get_POP_MPLS(a)->ethertype;
|
||||
break;
|
||||
|
||||
case OFPACT_SAMPLE:
|
||||
ofpact_sample_to_nxast(ofpact_get_SAMPLE(a), out);
|
||||
break;
|
||||
|
||||
case OFPACT_OUTPUT:
|
||||
case OFPACT_ENQUEUE:
|
||||
case OFPACT_SET_VLAN_VID:
|
||||
@ -1621,6 +1665,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
|
||||
case OFPACT_EXIT:
|
||||
case OFPACT_PUSH_MPLS:
|
||||
case OFPACT_POP_MPLS:
|
||||
case OFPACT_SAMPLE:
|
||||
ofpact_to_nxast(a, out);
|
||||
break;
|
||||
}
|
||||
@ -1784,6 +1829,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
|
||||
case OFPACT_MULTIPATH:
|
||||
case OFPACT_NOTE:
|
||||
case OFPACT_EXIT:
|
||||
case OFPACT_SAMPLE:
|
||||
ofpact_to_nxast(a, out);
|
||||
break;
|
||||
}
|
||||
@ -1912,6 +1958,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
|
||||
case OFPACT_EXIT:
|
||||
case OFPACT_PUSH_MPLS:
|
||||
case OFPACT_POP_MPLS:
|
||||
case OFPACT_SAMPLE:
|
||||
case OFPACT_CLEAR_ACTIONS:
|
||||
case OFPACT_GOTO_TABLE:
|
||||
default:
|
||||
@ -2003,6 +2050,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
|
||||
const struct ofpact_controller *controller;
|
||||
const struct ofpact_metadata *metadata;
|
||||
const struct ofpact_tunnel *tunnel;
|
||||
const struct ofpact_sample *sample;
|
||||
uint16_t port;
|
||||
|
||||
switch (a->type) {
|
||||
@ -2204,6 +2252,15 @@ ofpact_format(const struct ofpact *a, struct ds *s)
|
||||
ds_put_cstr(s, "exit");
|
||||
break;
|
||||
|
||||
case OFPACT_SAMPLE:
|
||||
sample = ofpact_get_SAMPLE(a);
|
||||
ds_put_format(
|
||||
s, "sample(probability=%"PRIu16",collector_set_id=%"PRIu32
|
||||
",obs_domain_id=%"PRIu32",obs_point_id=%"PRIu32")",
|
||||
sample->probability, sample->collector_set_id,
|
||||
sample->obs_domain_id, sample->obs_point_id);
|
||||
break;
|
||||
|
||||
case OFPACT_CLEAR_ACTIONS:
|
||||
ds_put_format(s, "%s",
|
||||
ofpact_instruction_name_from_type(
|
||||
|
@ -94,6 +94,7 @@
|
||||
/* Other. */ \
|
||||
DEFINE_OFPACT(NOTE, ofpact_note, data) \
|
||||
DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \
|
||||
DEFINE_OFPACT(SAMPLE, ofpact_sample, ofpact) \
|
||||
\
|
||||
/* Instructions */ \
|
||||
/* XXX Write-Actions */ \
|
||||
@ -441,6 +442,17 @@ struct ofpact_note {
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
/* OFPACT_SAMPLE.
|
||||
*
|
||||
* Used for NXAST_SAMPLE. */
|
||||
struct ofpact_sample {
|
||||
struct ofpact ofpact;
|
||||
uint16_t probability; // Always >0.
|
||||
uint32_t collector_set_id;
|
||||
uint32_t obs_domain_id;
|
||||
uint32_t obs_point_id;
|
||||
};
|
||||
|
||||
/* OFPACT_DEC_TTL.
|
||||
*
|
||||
* Used for OFPAT11_DEC_NW_TTL, NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */
|
||||
|
@ -389,6 +389,34 @@ parse_metadata(struct ofpbuf *b, char *arg)
|
||||
om->metadata = htonll(str_to_u64(arg));
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sample(struct ofpbuf *b, char *arg)
|
||||
{
|
||||
struct ofpact_sample *os = ofpact_put_SAMPLE(b);
|
||||
char *key, *value;
|
||||
|
||||
while (ofputil_parse_key_value(&arg, &key, &value)) {
|
||||
if (!strcmp(key, "probability")) {
|
||||
os->probability = str_to_u16(value, "probability");
|
||||
if (os->probability == 0) {
|
||||
ovs_fatal(0, "invalid probability value \"%s\"", value);
|
||||
}
|
||||
} else if (!strcmp(key, "collector_set_id")) {
|
||||
os->collector_set_id = str_to_u32(value);
|
||||
} else if (!strcmp(key, "obs_domain_id")) {
|
||||
os->obs_domain_id = str_to_u32(value);
|
||||
} else if (!strcmp(key, "obs_point_id")) {
|
||||
os->obs_point_id = str_to_u32(value);
|
||||
} else {
|
||||
ovs_fatal(0, "invalid key \"%s\" in \"sample\" argument",
|
||||
key);
|
||||
}
|
||||
}
|
||||
if (os->probability == 0) {
|
||||
ovs_fatal(0, "non-zero \"probability\" must be specified on sample");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_named_action(enum ofputil_action_code code, const struct flow *flow,
|
||||
char *arg, struct ofpbuf *ofpacts)
|
||||
@ -591,12 +619,17 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
|
||||
ofpact_put_POP_MPLS(ofpacts)->ethertype =
|
||||
htons(str_to_u16(arg, "pop_mpls"));
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_STACK_PUSH:
|
||||
nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg);
|
||||
break;
|
||||
case OFPUTIL_NXAST_STACK_POP:
|
||||
nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg);
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_SAMPLE:
|
||||
parse_sample(ofpacts, arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ NXAST_ACTION(NXAST_SET_MPLS_TTL, nx_action_mpls_ttl, 0, "set_mpls_ttl")
|
||||
NXAST_ACTION(NXAST_DEC_MPLS_TTL, nx_action_header, 0, "dec_mpls_ttl")
|
||||
NXAST_ACTION(NXAST_PUSH_MPLS, nx_action_push_mpls, 0, "push_mpls")
|
||||
NXAST_ACTION(NXAST_POP_MPLS, nx_action_pop_mpls, 0, "pop_mpls")
|
||||
NXAST_ACTION(NXAST_SAMPLE, nx_action_sample, 0, "sample")
|
||||
|
||||
#undef OFPAT10_ACTION
|
||||
#undef OFPAT11_ACTION
|
||||
|
@ -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 \
|
||||
@ -33,4 +35,18 @@ ofproto_libofproto_a_SOURCES = \
|
||||
ofproto/tunnel.c \
|
||||
ofproto/tunnel.h
|
||||
|
||||
# Distribute this generated file in order not to require Python at
|
||||
# build time if ofproto/ipfix.xml is not modified.
|
||||
ofproto_libofproto_a_SOURCES += ofproto/ipfix-entities.def
|
||||
|
||||
BUILT_SOURCES += ofproto/ipfix-entities.def
|
||||
|
||||
CLEANFILES += ofproto/ipfix-entities.def
|
||||
|
||||
MAN_FRAGMENTS += ofproto/ofproto-unixctl.man ofproto/ofproto-dpif-unixctl.man
|
||||
|
||||
# IPFIX entity definition macros generation from IANA's XML definition.
|
||||
EXTRA_DIST += ofproto/ipfix.xml
|
||||
dist_noinst_SCRIPTS = ofproto/ipfix-gen-entities
|
||||
ofproto/ipfix-entities.def: ofproto/ipfix.xml ofproto/ipfix-gen-entities
|
||||
$(run_python) $(srcdir)/ofproto/ipfix-gen-entities $< > $@
|
||||
|
140
ofproto/ipfix-gen-entities
Executable file
140
ofproto/ipfix-gen-entities
Executable file
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2012 Nicira, Inc.
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without warranty of any kind.
|
||||
|
||||
import getopt
|
||||
import re
|
||||
import sys
|
||||
import xml.sax
|
||||
import xml.sax.handler
|
||||
|
||||
class IpfixEntityHandler(xml.sax.handler.ContentHandler):
|
||||
|
||||
RECORD_FIELDS = ['name', 'dataType', 'elementId', 'status']
|
||||
|
||||
# Cf. RFC 5101, Section 6.
|
||||
DATA_TYPE_SIZE = {
|
||||
'unsigned8': 1,
|
||||
'unsigned16': 2,
|
||||
'unsigned32': 4,
|
||||
'unsigned64': 8,
|
||||
'signed8': 1,
|
||||
'signed16': 2,
|
||||
'signed32': 4,
|
||||
'signed64': 8,
|
||||
'float32': 4,
|
||||
'float64': 8,
|
||||
'boolean': 1, # Not clear.
|
||||
'macAddress': 6,
|
||||
'octetArray': 0, # Not clear.
|
||||
'string': 0, # Not clear.
|
||||
'dateTimeSeconds': 4,
|
||||
'dateTimeMilliseconds': 8,
|
||||
'dateTimeMicroseconds': 8,
|
||||
'dateTimeNanoseconds': 8,
|
||||
'ipv4Address': 4,
|
||||
'ipv6Address': 16,
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.current_field_name = None
|
||||
self.current_field_value = []
|
||||
self.current_record = dict()
|
||||
|
||||
def startDocument(self):
|
||||
print """\
|
||||
/* IPFIX entities. */
|
||||
#ifndef IPFIX_ENTITY
|
||||
#define IPFIX_ENTITY(ENUM, ID, SIZE, NAME)
|
||||
#endif
|
||||
"""
|
||||
|
||||
def endDocument(self):
|
||||
print """
|
||||
#undef IPFIX_ENTITY"""
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name in self.RECORD_FIELDS:
|
||||
self.current_field_name = name
|
||||
else:
|
||||
self.current_field_name = None
|
||||
self.current_field_value = []
|
||||
|
||||
@staticmethod
|
||||
def camelcase_to_uppercase(s):
|
||||
return re.sub('(.)([A-Z]+)', r'\1_\2', s).upper()
|
||||
|
||||
def endElement(self, name):
|
||||
if self.current_field_name is not None:
|
||||
self.current_record[self.current_field_name] = ''.join(
|
||||
self.current_field_value).strip()
|
||||
elif (name == 'record'
|
||||
and self.current_record.get('status') == 'current'
|
||||
and 'dataType' in self.current_record):
|
||||
|
||||
self.current_record['enumName'] = self.camelcase_to_uppercase(
|
||||
self.current_record['name'])
|
||||
self.current_record['dataTypeSize'] = self.DATA_TYPE_SIZE.get(
|
||||
self.current_record['dataType'], 0)
|
||||
|
||||
print 'IPFIX_ENTITY(%(enumName)s, %(elementId)s, ' \
|
||||
'%(dataTypeSize)i, %(name)s)' % self.current_record
|
||||
self.current_record.clear()
|
||||
|
||||
def characters(self, content):
|
||||
if self.current_field_name is not None:
|
||||
self.current_field_value.append(content)
|
||||
|
||||
def print_ipfix_entity_macros(xml_file):
|
||||
xml.sax.parse(xml_file, IpfixEntityHandler())
|
||||
|
||||
def usage(name):
|
||||
print """\
|
||||
%(name)s: IPFIX entity definition generator
|
||||
Prints C macros defining IPFIX entities from the standard IANA file at
|
||||
<http://www.iana.org/assignments/ipfix/ipfix.xml>
|
||||
usage: %(name)s [OPTIONS] XML
|
||||
where XML is the standard IANA XML file defining IPFIX entities
|
||||
|
||||
The following options are also available:
|
||||
-h, --help display this help message
|
||||
-V, --version display version information\
|
||||
""" % {'name': name}
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# try:
|
||||
try:
|
||||
options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
|
||||
['help', 'version'])
|
||||
except getopt.GetoptError, geo:
|
||||
sys.stderr.write('%s: %s\n' % (sys.argv[0], geo.msg))
|
||||
sys.exit(1)
|
||||
|
||||
for key, value in options:
|
||||
if key in ['-h', '--help']:
|
||||
usage()
|
||||
elif key in ['-V', '--version']:
|
||||
print 'ipfix-gen-entities (Open vSwitch)'
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
if len(args) != 1:
|
||||
sys.stderr.write('%s: exactly 1 non-option arguments required '
|
||||
'(use --help for help)\n' % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
print_ipfix_entity_macros(args[0])
|
||||
|
||||
# except Exception, e:
|
||||
# sys.stderr.write('%s: %s\n' % (sys.argv[0], e))
|
||||
# sys.exit(1)
|
||||
|
||||
# Local variables:
|
||||
# mode: python
|
||||
# End:
|
8752
ofproto/ipfix.xml
Normal file
8752
ofproto/ipfix.xml
Normal file
File diff suppressed because it is too large
Load Diff
848
ofproto/ofproto-dpif-ipfix.c
Normal file
848
ofproto/ofproto-dpif-ipfix.c
Normal file
@ -0,0 +1,848 @@
|
||||
/*
|
||||
* 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 "byte-order.h"
|
||||
#include "collectors.h"
|
||||
#include "flow.h"
|
||||
#include "hash.h"
|
||||
#include "hmap.h"
|
||||
#include "ofpbuf.h"
|
||||
#include "ofproto.h"
|
||||
#include "packets.h"
|
||||
#include "sset.h"
|
||||
#include "util.h"
|
||||
#include "timeval.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_exporter {
|
||||
struct collectors *collectors;
|
||||
uint32_t seq_number;
|
||||
time_t last_template_set_time;
|
||||
};
|
||||
|
||||
struct dpif_ipfix_bridge_exporter {
|
||||
struct dpif_ipfix_exporter exporter;
|
||||
struct ofproto_ipfix_bridge_exporter_options *options;
|
||||
uint32_t probability;
|
||||
};
|
||||
|
||||
struct dpif_ipfix_flow_exporter {
|
||||
struct dpif_ipfix_exporter exporter;
|
||||
struct ofproto_ipfix_flow_exporter_options *options;
|
||||
};
|
||||
|
||||
struct dpif_ipfix_flow_exporter_map_node {
|
||||
struct hmap_node node;
|
||||
struct dpif_ipfix_flow_exporter exporter;
|
||||
};
|
||||
|
||||
struct dpif_ipfix {
|
||||
struct dpif_ipfix_bridge_exporter bridge_exporter;
|
||||
struct hmap flow_exporter_map; /* dpif_ipfix_flow_exporter_map_nodes. */
|
||||
};
|
||||
|
||||
#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. */
|
||||
struct ipfix_header {
|
||||
ovs_be16 version; /* IPFIX_VERSION. */
|
||||
ovs_be16 length; /* Length in bytes including this header. */
|
||||
ovs_be32 export_time; /* Seconds since the epoch. */
|
||||
ovs_be32 seq_number; /* Message sequence number. */
|
||||
ovs_be32 obs_domain_id; /* Observation Domain ID. */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_header) == 16);
|
||||
|
||||
#define IPFIX_SET_ID_TEMPLATE 2
|
||||
#define IPFIX_SET_ID_OPTION_TEMPLATE 3
|
||||
|
||||
/* Cf. IETF RFC 5101 Section 3.3.2. */
|
||||
struct ipfix_set_header {
|
||||
ovs_be16 set_id; /* IPFIX_SET_ID_* or valid template ID for Data Sets. */
|
||||
ovs_be16 length; /* Length of the set in bytes including header. */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_set_header) == 4);
|
||||
|
||||
/* Alternatives for templates at each layer. A template is defined by
|
||||
* a combination of one value for each layer. */
|
||||
enum ipfix_proto_l2 {
|
||||
IPFIX_PROTO_L2_ETH = 0, /* No VLAN. */
|
||||
IPFIX_PROTO_L2_VLAN,
|
||||
NUM_IPFIX_PROTO_L2
|
||||
};
|
||||
enum ipfix_proto_l3 {
|
||||
IPFIX_PROTO_L3_UNKNOWN = 0,
|
||||
IPFIX_PROTO_L3_IPV4,
|
||||
IPFIX_PROTO_L3_IPV6,
|
||||
NUM_IPFIX_PROTO_L3
|
||||
};
|
||||
enum ipfix_proto_l4 {
|
||||
IPFIX_PROTO_L4_UNKNOWN = 0,
|
||||
IPFIX_PROTO_L4_TCP_UDP,
|
||||
NUM_IPFIX_PROTO_L4
|
||||
};
|
||||
|
||||
/* Any Template ID > 255 is usable for Template Records. */
|
||||
#define IPFIX_TEMPLATE_ID_MIN 256
|
||||
|
||||
/* Cf. IETF RFC 5101 Section 3.4.1. */
|
||||
struct ipfix_template_record_header {
|
||||
ovs_be16 template_id;
|
||||
ovs_be16 field_count;
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_template_record_header) == 4);
|
||||
|
||||
enum ipfix_entity_id {
|
||||
#define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) IPFIX_ENTITY_ID_##ENUM = ID,
|
||||
#include "ofproto/ipfix-entities.def"
|
||||
};
|
||||
|
||||
enum ipfix_entity_size {
|
||||
#define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) IPFIX_ENTITY_SIZE_##ENUM = SIZE,
|
||||
#include "ofproto/ipfix-entities.def"
|
||||
};
|
||||
|
||||
struct ipfix_template_field_specifier {
|
||||
ovs_be16 element_id; /* IPFIX_ENTITY_ID_*. */
|
||||
ovs_be16 field_length; /* Length of the field's value, in bytes. */
|
||||
/* No Enterprise ID, since only standard element IDs are specified. */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_template_field_specifier) == 4);
|
||||
|
||||
/* Part of data record for common metadata and Ethernet entities. */
|
||||
struct ipfix_data_record_common {
|
||||
ovs_be32 observation_point_id; /* OBSERVATION_POINT_ID */
|
||||
ovs_be64 packet_delta_count; /* PACKET_DELTA_COUNT */
|
||||
ovs_be64 layer2_octet_delta_count; /* LAYER2_OCTET_DELTA_COUNT */
|
||||
uint8_t source_mac_address[6]; /* SOURCE_MAC_ADDRESS */
|
||||
uint8_t destination_mac_address[6]; /* DESTINATION_MAC_ADDRESS */
|
||||
ovs_be16 ethernet_type; /* ETHERNET_TYPE */
|
||||
ovs_be16 ethernet_total_length; /* ETHERNET_TOTAL_LENGTH */
|
||||
uint8_t ethernet_header_length; /* ETHERNET_HEADER_LENGTH */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_common) == 37);
|
||||
|
||||
/* Part of data record for VLAN entities. */
|
||||
struct ipfix_data_record_vlan {
|
||||
ovs_be16 vlan_id; /* VLAN_ID */
|
||||
ovs_be16 dot1q_vlan_id; /* DOT1Q_VLAN_ID */
|
||||
uint8_t dot1q_priority; /* DOT1Q_PRIORITY */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_vlan) == 5);
|
||||
|
||||
/* Part of data record for IP entities. */
|
||||
struct ipfix_data_record_ip {
|
||||
uint8_t ip_version; /* IP_VERSION */
|
||||
uint8_t ip_ttl; /* IP_TTL */
|
||||
uint8_t protocol_identifier; /* PROTOCOL_IDENTIFIER */
|
||||
uint8_t ip_diff_serv_code_point; /* IP_DIFF_SERV_CODE_POINT */
|
||||
uint8_t ip_precedence; /* IP_PRECEDENCE */
|
||||
uint8_t ip_class_of_service; /* IP_CLASS_OF_SERVICE */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ip) == 6);
|
||||
|
||||
/* Part of data record for IPv4 entities. */
|
||||
struct ipfix_data_record_ipv4 {
|
||||
ovs_be32 source_ipv4_address; /* SOURCE_IPV4_ADDRESS */
|
||||
ovs_be32 destination_ipv4_address; /* DESTINATION_IPV4_ADDRESS */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ipv4) == 8);
|
||||
|
||||
/* Part of data record for IPv4 entities. */
|
||||
struct ipfix_data_record_ipv6 {
|
||||
uint8_t source_ipv6_address[16]; /* SOURCE_IPV6_ADDRESS */
|
||||
uint8_t destination_ipv6_address[16]; /* DESTINATION_IPV6_ADDRESS */
|
||||
ovs_be32 flow_label_ipv6; /* FLOW_LABEL_IPV6 */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_ipv6) == 36);
|
||||
|
||||
/* Part of data record for TCP/UDP entities. */
|
||||
struct ipfix_data_record_tcpudp {
|
||||
ovs_be16 source_transport_port; /* SOURCE_TRANSPORT_PORT */
|
||||
ovs_be16 destination_transport_port; /* DESTINATION_TRANSPORT_PORT */
|
||||
} __attribute__((packed));
|
||||
BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_tcpudp) == 4);
|
||||
|
||||
static bool
|
||||
ofproto_ipfix_bridge_exporter_options_equal(
|
||||
const struct ofproto_ipfix_bridge_exporter_options *a,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *b)
|
||||
{
|
||||
return (a->obs_domain_id == b->obs_domain_id
|
||||
&& a->obs_point_id == b->obs_point_id
|
||||
&& a->sampling_rate == b->sampling_rate
|
||||
&& sset_equals(&a->targets, &b->targets));
|
||||
}
|
||||
|
||||
static struct ofproto_ipfix_bridge_exporter_options *
|
||||
ofproto_ipfix_bridge_exporter_options_clone(
|
||||
const struct ofproto_ipfix_bridge_exporter_options *old)
|
||||
{
|
||||
struct ofproto_ipfix_bridge_exporter_options *new =
|
||||
xmemdup(old, sizeof *old);
|
||||
sset_clone(&new->targets, &old->targets);
|
||||
return new;
|
||||
}
|
||||
|
||||
static void
|
||||
ofproto_ipfix_bridge_exporter_options_destroy(
|
||||
struct ofproto_ipfix_bridge_exporter_options *options)
|
||||
{
|
||||
if (options) {
|
||||
sset_destroy(&options->targets);
|
||||
free(options);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ofproto_ipfix_flow_exporter_options_equal(
|
||||
const struct ofproto_ipfix_flow_exporter_options *a,
|
||||
const struct ofproto_ipfix_flow_exporter_options *b)
|
||||
{
|
||||
return (a->collector_set_id == b->collector_set_id
|
||||
&& sset_equals(&a->targets, &b->targets));
|
||||
}
|
||||
|
||||
static struct ofproto_ipfix_flow_exporter_options *
|
||||
ofproto_ipfix_flow_exporter_options_clone(
|
||||
const struct ofproto_ipfix_flow_exporter_options *old)
|
||||
{
|
||||
struct ofproto_ipfix_flow_exporter_options *new =
|
||||
xmemdup(old, sizeof *old);
|
||||
sset_clone(&new->targets, &old->targets);
|
||||
return new;
|
||||
}
|
||||
|
||||
static void
|
||||
ofproto_ipfix_flow_exporter_options_destroy(
|
||||
struct ofproto_ipfix_flow_exporter_options *options)
|
||||
{
|
||||
if (options) {
|
||||
sset_destroy(&options->targets);
|
||||
free(options);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter *exporter)
|
||||
{
|
||||
collectors_destroy(exporter->collectors);
|
||||
exporter->collectors = NULL;
|
||||
exporter->seq_number = 1;
|
||||
exporter->last_template_set_time = TIME_MIN;
|
||||
}
|
||||
|
||||
static bool
|
||||
dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter,
|
||||
const struct sset *targets)
|
||||
{
|
||||
collectors_destroy(exporter->collectors);
|
||||
collectors_create(targets, IPFIX_DEFAULT_COLLECTOR_PORT,
|
||||
&exporter->collectors);
|
||||
if (exporter->collectors == NULL) {
|
||||
VLOG_WARN_RL(&rl, "no collectors could be initialized, "
|
||||
"IPFIX exporter disabled");
|
||||
dpif_ipfix_exporter_clear(exporter);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter *exporter)
|
||||
{
|
||||
dpif_ipfix_exporter_clear(&exporter->exporter);
|
||||
ofproto_ipfix_bridge_exporter_options_destroy(exporter->options);
|
||||
exporter->options = NULL;
|
||||
exporter->probability = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dpif_ipfix_bridge_exporter_set_options(
|
||||
struct dpif_ipfix_bridge_exporter *exporter,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *options)
|
||||
{
|
||||
bool options_changed;
|
||||
|
||||
if (!options || sset_is_empty(&options->targets)) {
|
||||
/* No point in doing any work if there are no targets. */
|
||||
dpif_ipfix_bridge_exporter_clear(exporter);
|
||||
return;
|
||||
}
|
||||
|
||||
options_changed = (
|
||||
!exporter->options
|
||||
|| !ofproto_ipfix_bridge_exporter_options_equal(
|
||||
options, exporter->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(exporter->exporter.collectors)
|
||||
< sset_count(&options->targets)) {
|
||||
if (!dpif_ipfix_exporter_set_options(&exporter->exporter,
|
||||
&options->targets)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid reconfiguring if options didn't change. */
|
||||
if (!options_changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
ofproto_ipfix_bridge_exporter_options_destroy(exporter->options);
|
||||
exporter->options = ofproto_ipfix_bridge_exporter_options_clone(options);
|
||||
exporter->probability =
|
||||
MAX(1, UINT32_MAX / exporter->options->sampling_rate);
|
||||
}
|
||||
|
||||
static struct dpif_ipfix_flow_exporter_map_node*
|
||||
dpif_ipfix_find_flow_exporter_map_node(
|
||||
const struct dpif_ipfix *di, const uint32_t collector_set_id)
|
||||
{
|
||||
struct dpif_ipfix_flow_exporter_map_node *exporter_node;
|
||||
|
||||
HMAP_FOR_EACH_WITH_HASH (exporter_node, node,
|
||||
hash_int(collector_set_id, 0),
|
||||
&di->flow_exporter_map) {
|
||||
if (exporter_node->exporter.options->collector_set_id
|
||||
== collector_set_id) {
|
||||
return exporter_node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
dpif_ipfix_flow_exporter_clear(struct dpif_ipfix_flow_exporter *exporter)
|
||||
{
|
||||
dpif_ipfix_exporter_clear(&exporter->exporter);
|
||||
ofproto_ipfix_flow_exporter_options_destroy(exporter->options);
|
||||
exporter->options = NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
dpif_ipfix_flow_exporter_set_options(
|
||||
struct dpif_ipfix_flow_exporter *exporter,
|
||||
const struct ofproto_ipfix_flow_exporter_options *options)
|
||||
{
|
||||
bool options_changed;
|
||||
|
||||
if (sset_is_empty(&options->targets)) {
|
||||
/* No point in doing any work if there are no targets. */
|
||||
dpif_ipfix_flow_exporter_clear(exporter);
|
||||
return true;
|
||||
}
|
||||
|
||||
options_changed = (
|
||||
!exporter->options
|
||||
|| !ofproto_ipfix_flow_exporter_options_equal(
|
||||
options, exporter->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(exporter->exporter.collectors)
|
||||
< sset_count(&options->targets)) {
|
||||
if (!dpif_ipfix_exporter_set_options(&exporter->exporter,
|
||||
&options->targets)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid reconfiguring if options didn't change. */
|
||||
if (!options_changed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ofproto_ipfix_flow_exporter_options_destroy(exporter->options);
|
||||
exporter->options = ofproto_ipfix_flow_exporter_options_clone(options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
dpif_ipfix_set_options(
|
||||
struct dpif_ipfix *di,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options,
|
||||
const struct ofproto_ipfix_flow_exporter_options *flow_exporters_options,
|
||||
size_t n_flow_exporters_options)
|
||||
{
|
||||
int i;
|
||||
struct ofproto_ipfix_flow_exporter_options *options;
|
||||
struct dpif_ipfix_flow_exporter_map_node *node, *next;
|
||||
size_t n_broken_flow_exporters_options = 0;
|
||||
|
||||
dpif_ipfix_bridge_exporter_set_options(&di->bridge_exporter,
|
||||
bridge_exporter_options);
|
||||
|
||||
/* Add new flow exporters and update current flow exporters. */
|
||||
options = (struct ofproto_ipfix_flow_exporter_options *)
|
||||
flow_exporters_options;
|
||||
for (i = 0; i < n_flow_exporters_options; i++) {
|
||||
node = dpif_ipfix_find_flow_exporter_map_node(
|
||||
di, options->collector_set_id);
|
||||
if (!node) {
|
||||
node = xzalloc(sizeof *node);
|
||||
dpif_ipfix_exporter_clear(&node->exporter.exporter);
|
||||
hmap_insert(&di->flow_exporter_map, &node->node,
|
||||
hash_int(options->collector_set_id, 0));
|
||||
}
|
||||
if (!dpif_ipfix_flow_exporter_set_options(&node->exporter, options)) {
|
||||
n_broken_flow_exporters_options++;
|
||||
}
|
||||
options++;
|
||||
}
|
||||
|
||||
ovs_assert(hmap_count(&di->flow_exporter_map) >=
|
||||
(n_flow_exporters_options - n_broken_flow_exporters_options));
|
||||
|
||||
/* Remove dropped flow exporters, if any needs to be removed. */
|
||||
if (hmap_count(&di->flow_exporter_map) > n_flow_exporters_options) {
|
||||
HMAP_FOR_EACH_SAFE (node, next, node, &di->flow_exporter_map) {
|
||||
/* This is slow but doesn't take any extra memory, and
|
||||
* this table is not supposed to contain many rows anyway. */
|
||||
options = (struct ofproto_ipfix_flow_exporter_options *)
|
||||
flow_exporters_options;
|
||||
for (i = 0; i < n_flow_exporters_options; i++) {
|
||||
if (node->exporter.options->collector_set_id
|
||||
== options->collector_set_id) {
|
||||
break;
|
||||
}
|
||||
options++;
|
||||
}
|
||||
if (i == n_flow_exporters_options) { // Not found.
|
||||
hmap_remove(&di->flow_exporter_map, &node->node);
|
||||
dpif_ipfix_flow_exporter_clear(&node->exporter);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ovs_assert(hmap_count(&di->flow_exporter_map) ==
|
||||
(n_flow_exporters_options - n_broken_flow_exporters_options));
|
||||
}
|
||||
|
||||
struct dpif_ipfix *
|
||||
dpif_ipfix_create(void)
|
||||
{
|
||||
struct dpif_ipfix *di;
|
||||
di = xzalloc(sizeof *di);
|
||||
dpif_ipfix_exporter_clear(&di->bridge_exporter.exporter);
|
||||
hmap_init(&di->flow_exporter_map);
|
||||
return di;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix *di)
|
||||
{
|
||||
return di->bridge_exporter.probability;
|
||||
}
|
||||
|
||||
static void
|
||||
dpif_ipfix_clear(struct dpif_ipfix *di)
|
||||
{
|
||||
struct dpif_ipfix_flow_exporter_map_node *node, *next;
|
||||
|
||||
dpif_ipfix_bridge_exporter_clear(&di->bridge_exporter);
|
||||
|
||||
HMAP_FOR_EACH_SAFE (node, next, node, &di->flow_exporter_map) {
|
||||
hmap_remove(&di->flow_exporter_map, &node->node);
|
||||
dpif_ipfix_flow_exporter_clear(&node->exporter);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dpif_ipfix_destroy(struct dpif_ipfix *di)
|
||||
{
|
||||
if (di) {
|
||||
dpif_ipfix_clear(di);
|
||||
hmap_destroy(&di->flow_exporter_map);
|
||||
free(di);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ipfix_init_header(uint32_t seq_number, uint32_t obs_domain_id,
|
||||
struct ofpbuf *msg)
|
||||
{
|
||||
struct ipfix_header *hdr;
|
||||
|
||||
hdr = ofpbuf_put_zeros(msg, sizeof *hdr);
|
||||
hdr->version = htons(IPFIX_VERSION);
|
||||
hdr->length = htons(sizeof *hdr); /* Updated in ipfix_send_msg. */
|
||||
hdr->export_time = htonl(time_wall());
|
||||
hdr->seq_number = htonl(seq_number);
|
||||
hdr->obs_domain_id = htonl(obs_domain_id);
|
||||
}
|
||||
|
||||
static void
|
||||
ipfix_send_msg(const struct collectors *collectors, struct ofpbuf *msg)
|
||||
{
|
||||
struct ipfix_header *hdr;
|
||||
|
||||
/* Adjust the length in the header. */
|
||||
hdr = msg->data;
|
||||
hdr->length = htons(msg->size);
|
||||
|
||||
collectors_send(collectors, msg->data, msg->size);
|
||||
msg->size = 0;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ipfix_get_template_id(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
|
||||
enum ipfix_proto_l4 l4)
|
||||
{
|
||||
uint16_t template_id;
|
||||
template_id = l2;
|
||||
template_id = template_id * NUM_IPFIX_PROTO_L3 + l3;
|
||||
template_id = template_id * NUM_IPFIX_PROTO_L4 + l4;
|
||||
return IPFIX_TEMPLATE_ID_MIN + template_id;
|
||||
}
|
||||
|
||||
static void
|
||||
ipfix_define_template_entity(enum ipfix_entity_id id,
|
||||
enum ipfix_entity_size size, struct ofpbuf *msg)
|
||||
{
|
||||
struct ipfix_template_field_specifier *field;
|
||||
|
||||
field = ofpbuf_put_zeros(msg, sizeof *field);
|
||||
field->element_id = htons(id);
|
||||
field->field_length = htons(size);
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
|
||||
enum ipfix_proto_l4 l4, struct ofpbuf *msg)
|
||||
{
|
||||
uint16_t count = 0;
|
||||
|
||||
#define DEF(ID) \
|
||||
{ \
|
||||
ipfix_define_template_entity(IPFIX_ENTITY_ID_##ID, \
|
||||
IPFIX_ENTITY_SIZE_##ID, msg); \
|
||||
count++; \
|
||||
}
|
||||
|
||||
DEF(OBSERVATION_POINT_ID);
|
||||
DEF(PACKET_DELTA_COUNT);
|
||||
DEF(LAYER2_OCTET_DELTA_COUNT);
|
||||
|
||||
/* Common Ethernet entities. */
|
||||
DEF(SOURCE_MAC_ADDRESS);
|
||||
DEF(DESTINATION_MAC_ADDRESS);
|
||||
DEF(ETHERNET_TYPE);
|
||||
DEF(ETHERNET_TOTAL_LENGTH);
|
||||
DEF(ETHERNET_HEADER_LENGTH);
|
||||
|
||||
if (l2 == IPFIX_PROTO_L2_VLAN) {
|
||||
DEF(VLAN_ID);
|
||||
DEF(DOT1Q_VLAN_ID);
|
||||
DEF(DOT1Q_PRIORITY);
|
||||
}
|
||||
|
||||
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
|
||||
DEF(IP_VERSION);
|
||||
DEF(IP_TTL);
|
||||
DEF(PROTOCOL_IDENTIFIER);
|
||||
DEF(IP_DIFF_SERV_CODE_POINT);
|
||||
DEF(IP_PRECEDENCE);
|
||||
DEF(IP_CLASS_OF_SERVICE);
|
||||
|
||||
if (l3 == IPFIX_PROTO_L3_IPV4) {
|
||||
DEF(SOURCE_IPV4_ADDRESS);
|
||||
DEF(DESTINATION_IPV4_ADDRESS);
|
||||
} else { /* l3 == IPFIX_PROTO_L3_IPV6 */
|
||||
DEF(SOURCE_IPV6_ADDRESS);
|
||||
DEF(DESTINATION_IPV6_ADDRESS);
|
||||
DEF(FLOW_LABEL_IPV6);
|
||||
}
|
||||
}
|
||||
|
||||
if (l4 != IPFIX_PROTO_L4_UNKNOWN) {
|
||||
DEF(SOURCE_TRANSPORT_PORT);
|
||||
DEF(DESTINATION_TRANSPORT_PORT);
|
||||
}
|
||||
|
||||
#undef DEF
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
ipfix_send_template_msg(struct dpif_ipfix_exporter *exporter,
|
||||
uint32_t obs_domain_id)
|
||||
{
|
||||
uint64_t msg_stub[DIV_ROUND_UP(1500, 8)];
|
||||
struct ofpbuf msg;
|
||||
size_t set_hdr_offset, tmpl_hdr_offset;
|
||||
struct ipfix_set_header *set_hdr;
|
||||
struct ipfix_template_record_header *tmpl_hdr;
|
||||
uint16_t field_count;
|
||||
enum ipfix_proto_l2 l2;
|
||||
enum ipfix_proto_l3 l3;
|
||||
enum ipfix_proto_l4 l4;
|
||||
|
||||
ofpbuf_use_stub(&msg, msg_stub, sizeof msg_stub);
|
||||
|
||||
ipfix_init_header(exporter->seq_number, obs_domain_id, &msg);
|
||||
set_hdr_offset = msg.size;
|
||||
|
||||
/* Add a Template Set. */
|
||||
set_hdr = ofpbuf_put_zeros(&msg, sizeof *set_hdr);
|
||||
set_hdr->set_id = htons(IPFIX_SET_ID_TEMPLATE);
|
||||
|
||||
/* Define one template for each possible combination of
|
||||
* protocols. */
|
||||
for (l2 = 0; l2 < NUM_IPFIX_PROTO_L2; l2++) {
|
||||
for (l3 = 0; l3 < NUM_IPFIX_PROTO_L3; l3++) {
|
||||
for (l4 = 0; l4 < NUM_IPFIX_PROTO_L4; l4++) {
|
||||
if (l3 == IPFIX_PROTO_L3_UNKNOWN &&
|
||||
l4 != IPFIX_PROTO_L4_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
tmpl_hdr_offset = msg.size;
|
||||
tmpl_hdr = ofpbuf_put_zeros(&msg, sizeof *tmpl_hdr);
|
||||
tmpl_hdr->template_id = htons(
|
||||
ipfix_get_template_id(l2, l3, l4));
|
||||
field_count = ipfix_define_template_fields(l2, l3, l4, &msg);
|
||||
tmpl_hdr = (struct ipfix_template_record_header*)
|
||||
((uint8_t*)msg.data + tmpl_hdr_offset);
|
||||
tmpl_hdr->field_count = htons(field_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_hdr = (struct ipfix_set_header*)((uint8_t*)msg.data + set_hdr_offset);
|
||||
set_hdr->length = htons(msg.size - set_hdr_offset);
|
||||
|
||||
/* TODO: Add Options Template Sets, at least to define a Flow Keys
|
||||
* Option Template. */
|
||||
|
||||
ipfix_send_msg(exporter->collectors, &msg);
|
||||
|
||||
ofpbuf_uninit(&msg);
|
||||
}
|
||||
|
||||
static void
|
||||
ipfix_send_data_msg(struct dpif_ipfix_exporter *exporter, struct ofpbuf *packet,
|
||||
const struct flow *flow, uint64_t packet_delta_count,
|
||||
uint32_t obs_domain_id, uint32_t obs_point_id)
|
||||
{
|
||||
uint64_t msg_stub[DIV_ROUND_UP(1500, 8)];
|
||||
struct ofpbuf msg;
|
||||
size_t set_hdr_offset;
|
||||
struct ipfix_set_header *set_hdr;
|
||||
enum ipfix_proto_l2 l2;
|
||||
enum ipfix_proto_l3 l3;
|
||||
enum ipfix_proto_l4 l4;
|
||||
|
||||
ofpbuf_use_stub(&msg, msg_stub, sizeof msg_stub);
|
||||
|
||||
ipfix_init_header(exporter->seq_number, obs_domain_id, &msg);
|
||||
exporter->seq_number++;
|
||||
set_hdr_offset = msg.size;
|
||||
|
||||
/* Choose the right template ID matching the protocols in the
|
||||
* sampled packet. */
|
||||
l2 = (flow->vlan_tci == 0) ? IPFIX_PROTO_L2_ETH : IPFIX_PROTO_L2_VLAN;
|
||||
|
||||
switch(ntohs(flow->dl_type)) {
|
||||
case ETH_TYPE_IP:
|
||||
l3 = IPFIX_PROTO_L3_IPV4;
|
||||
break;
|
||||
case ETH_TYPE_IPV6:
|
||||
l3 = IPFIX_PROTO_L3_IPV6;
|
||||
break;
|
||||
default:
|
||||
l3 = IPFIX_PROTO_L3_UNKNOWN;
|
||||
}
|
||||
|
||||
l4 = IPFIX_PROTO_L4_UNKNOWN;
|
||||
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
|
||||
switch(flow->nw_proto) {
|
||||
case IPPROTO_TCP: /* TCP */
|
||||
case IPPROTO_UDP: /* UDP */
|
||||
l4 = IPFIX_PROTO_L4_TCP_UDP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a Data Set. */
|
||||
set_hdr = ofpbuf_put_zeros(&msg, sizeof *set_hdr);
|
||||
set_hdr->set_id = htons(ipfix_get_template_id(l2, l3, l4));
|
||||
|
||||
/* The fields defined in the ipfix_data_record_* structs and sent
|
||||
* below must match exactly the templates defined in
|
||||
* ipfix_define_template_fields. */
|
||||
|
||||
/* Common Ethernet entities. */
|
||||
{
|
||||
struct ipfix_data_record_common *data_common;
|
||||
uint16_t ethernet_total_length;
|
||||
uint8_t ethernet_header_length;
|
||||
uint64_t layer2_octet_delta_count;
|
||||
|
||||
ethernet_total_length = packet->size;
|
||||
ethernet_header_length = (l2 == IPFIX_PROTO_L2_VLAN)
|
||||
? VLAN_ETH_HEADER_LEN : ETH_HEADER_LEN;
|
||||
|
||||
/* Calculate the total matched octet count by considering as
|
||||
* an approximation that all matched packets have the same
|
||||
* length. */
|
||||
layer2_octet_delta_count = packet_delta_count * ethernet_total_length;
|
||||
|
||||
data_common = ofpbuf_put_zeros(&msg, sizeof *data_common);
|
||||
data_common->observation_point_id = htonl(obs_point_id);
|
||||
data_common->packet_delta_count = htonll(packet_delta_count);
|
||||
data_common->layer2_octet_delta_count =
|
||||
htonll(layer2_octet_delta_count);
|
||||
memcpy(data_common->source_mac_address, flow->dl_src,
|
||||
sizeof flow->dl_src);
|
||||
memcpy(data_common->destination_mac_address, flow->dl_dst,
|
||||
sizeof flow->dl_dst);
|
||||
data_common->ethernet_type = flow->dl_type;
|
||||
data_common->ethernet_total_length = htons(ethernet_total_length);
|
||||
data_common->ethernet_header_length = ethernet_header_length;
|
||||
}
|
||||
|
||||
if (l2 == IPFIX_PROTO_L2_VLAN) {
|
||||
struct ipfix_data_record_vlan *data_vlan;
|
||||
uint16_t vlan_id = vlan_tci_to_vid(flow->vlan_tci);
|
||||
uint8_t priority = vlan_tci_to_pcp(flow->vlan_tci);
|
||||
|
||||
data_vlan = ofpbuf_put_zeros(&msg, sizeof *data_vlan);
|
||||
data_vlan->vlan_id = htons(vlan_id);
|
||||
data_vlan->dot1q_vlan_id = htons(vlan_id);
|
||||
data_vlan->dot1q_priority = priority;
|
||||
}
|
||||
|
||||
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
|
||||
struct ipfix_data_record_ip *data_ip;
|
||||
|
||||
data_ip = ofpbuf_put_zeros(&msg, sizeof *data_ip);
|
||||
data_ip->ip_version = (l3 == IPFIX_PROTO_L3_IPV4) ? 4 : 6;
|
||||
data_ip->ip_ttl = flow->nw_ttl;
|
||||
data_ip->protocol_identifier = flow->nw_proto;
|
||||
data_ip->ip_diff_serv_code_point = flow->nw_tos >> 2;
|
||||
data_ip->ip_precedence = flow->nw_tos >> 5;
|
||||
data_ip->ip_class_of_service = flow->nw_tos;
|
||||
|
||||
if (l3 == IPFIX_PROTO_L3_IPV4) {
|
||||
struct ipfix_data_record_ipv4 *data_ipv4;
|
||||
data_ipv4 = ofpbuf_put_zeros(&msg, sizeof *data_ipv4);
|
||||
data_ipv4->source_ipv4_address = flow->nw_src;
|
||||
data_ipv4->destination_ipv4_address = flow->nw_dst;
|
||||
} else { /* l3 == IPFIX_PROTO_L3_IPV6 */
|
||||
struct ipfix_data_record_ipv6 *data_ipv6;
|
||||
|
||||
data_ipv6 = ofpbuf_put_zeros(&msg, sizeof *data_ipv6);
|
||||
memcpy(data_ipv6->source_ipv6_address, &flow->ipv6_src,
|
||||
sizeof flow->ipv6_src);
|
||||
memcpy(data_ipv6->destination_ipv6_address, &flow->ipv6_dst,
|
||||
sizeof flow->ipv6_dst);
|
||||
data_ipv6->flow_label_ipv6 = flow->ipv6_label;
|
||||
}
|
||||
}
|
||||
|
||||
if (l4 != IPFIX_PROTO_L4_UNKNOWN) {
|
||||
struct ipfix_data_record_tcpudp *data_tcpudp;
|
||||
|
||||
data_tcpudp = ofpbuf_put_zeros(&msg, sizeof *data_tcpudp);
|
||||
data_tcpudp->source_transport_port = flow->tp_src;
|
||||
data_tcpudp->destination_transport_port = flow->tp_dst;
|
||||
}
|
||||
|
||||
set_hdr = (struct ipfix_set_header*)((uint8_t*)msg.data + set_hdr_offset);
|
||||
set_hdr->length = htons(msg.size - set_hdr_offset);
|
||||
|
||||
ipfix_send_msg(exporter->collectors, &msg);
|
||||
|
||||
ofpbuf_uninit(&msg);
|
||||
}
|
||||
|
||||
static void
|
||||
dpif_ipfix_sample(struct dpif_ipfix_exporter *exporter,
|
||||
struct ofpbuf *packet, const struct flow *flow,
|
||||
uint64_t packet_delta_count, uint32_t obs_domain_id,
|
||||
uint32_t obs_point_id)
|
||||
{
|
||||
time_t now = time_wall();
|
||||
if ((exporter->last_template_set_time + IPFIX_TEMPLATE_INTERVAL) <= now) {
|
||||
ipfix_send_template_msg(exporter, obs_domain_id);
|
||||
exporter->last_template_set_time = now;
|
||||
}
|
||||
|
||||
ipfix_send_data_msg(exporter, packet, flow, packet_delta_count,
|
||||
obs_domain_id, obs_point_id);
|
||||
}
|
||||
|
||||
void
|
||||
dpif_ipfix_bridge_sample(struct dpif_ipfix *di, struct ofpbuf *packet,
|
||||
const struct flow *flow)
|
||||
{
|
||||
/* Use the sampling probability as an approximation of the number
|
||||
* of matched packets. */
|
||||
uint64_t packet_delta_count = UINT32_MAX / di->bridge_exporter.probability;
|
||||
|
||||
dpif_ipfix_sample(&di->bridge_exporter.exporter, packet, flow,
|
||||
packet_delta_count,
|
||||
di->bridge_exporter.options->obs_domain_id,
|
||||
di->bridge_exporter.options->obs_point_id);
|
||||
}
|
||||
|
||||
void
|
||||
dpif_ipfix_flow_sample(struct dpif_ipfix *di, struct ofpbuf *packet,
|
||||
const struct flow *flow, uint32_t collector_set_id,
|
||||
uint16_t probability, uint32_t obs_domain_id,
|
||||
uint32_t obs_point_id)
|
||||
{
|
||||
struct dpif_ipfix_flow_exporter_map_node *node;
|
||||
/* Use the sampling probability as an approximation of the number
|
||||
* of matched packets. */
|
||||
uint64_t packet_delta_count = USHRT_MAX / probability;
|
||||
|
||||
node = dpif_ipfix_find_flow_exporter_map_node(di, collector_set_id);
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
dpif_ipfix_sample(&node->exporter.exporter, packet, flow,
|
||||
packet_delta_count, obs_domain_id, obs_point_id);
|
||||
}
|
42
ofproto/ofproto-dpif-ipfix.h
Normal file
42
ofproto/ofproto-dpif-ipfix.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct flow;
|
||||
struct ofpbuf;
|
||||
struct ofproto_ipfix_bridge_exporter_options;
|
||||
struct ofproto_ipfix_flow_exporter_options;
|
||||
|
||||
struct dpif_ipfix *dpif_ipfix_create(void);
|
||||
uint32_t dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix *);
|
||||
void dpif_ipfix_destroy(struct dpif_ipfix *);
|
||||
void dpif_ipfix_set_options(
|
||||
struct dpif_ipfix *,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *,
|
||||
const struct ofproto_ipfix_flow_exporter_options *, size_t);
|
||||
|
||||
void dpif_ipfix_bridge_sample(struct dpif_ipfix *, struct ofpbuf *,
|
||||
const struct flow *);
|
||||
void dpif_ipfix_flow_sample(struct dpif_ipfix *, struct ofpbuf *,
|
||||
const struct flow *, uint32_t, uint16_t, uint32_t,
|
||||
uint32_t);
|
||||
|
||||
#endif /* ofproto/ofproto-dpif-ipfix.h */
|
@ -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"
|
||||
@ -325,7 +326,8 @@ static void xlate_table_action(struct action_xlate_ctx *, uint16_t in_port,
|
||||
static size_t put_userspace_action(const struct ofproto_dpif *,
|
||||
struct ofpbuf *odp_actions,
|
||||
const struct flow *,
|
||||
const union user_action_cookie *);
|
||||
const union user_action_cookie *,
|
||||
const size_t);
|
||||
|
||||
static void compose_slow_path(const struct ofproto_dpif *, const struct flow *,
|
||||
enum slow_path_reason,
|
||||
@ -695,6 +697,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];
|
||||
@ -820,6 +823,9 @@ static int send_packet(const struct ofport_dpif *, struct ofpbuf *packet);
|
||||
static size_t compose_sflow_action(const struct ofproto_dpif *,
|
||||
struct ofpbuf *odp_actions,
|
||||
const struct flow *, uint32_t odp_port);
|
||||
static void compose_ipfix_action(const struct ofproto_dpif *,
|
||||
struct ofpbuf *odp_actions,
|
||||
const struct flow *);
|
||||
static void add_mirror_actions(struct action_xlate_ctx *ctx,
|
||||
const struct flow *flow);
|
||||
/* Global variables. */
|
||||
@ -1349,6 +1355,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);
|
||||
@ -1913,6 +1920,32 @@ set_sflow(struct ofproto *ofproto_,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set_ipfix(
|
||||
struct ofproto *ofproto_,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options,
|
||||
const struct ofproto_ipfix_flow_exporter_options *flow_exporters_options,
|
||||
size_t n_flow_exporters_options)
|
||||
{
|
||||
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
|
||||
struct dpif_ipfix *di = ofproto->ipfix;
|
||||
|
||||
if (bridge_exporter_options || flow_exporters_options) {
|
||||
if (!di) {
|
||||
di = ofproto->ipfix = dpif_ipfix_create();
|
||||
}
|
||||
dpif_ipfix_set_options(
|
||||
di, bridge_exporter_options, flow_exporters_options,
|
||||
n_flow_exporters_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)
|
||||
{
|
||||
@ -4006,9 +4039,11 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
|
||||
hmap_destroy(&todo);
|
||||
}
|
||||
|
||||
static enum { SFLOW_UPCALL, MISS_UPCALL, BAD_UPCALL }
|
||||
static enum { SFLOW_UPCALL, MISS_UPCALL, BAD_UPCALL, FLOW_SAMPLE_UPCALL,
|
||||
IPFIX_UPCALL }
|
||||
classify_upcall(const struct dpif_upcall *upcall)
|
||||
{
|
||||
size_t userdata_len;
|
||||
union user_action_cookie cookie;
|
||||
|
||||
/* First look at the upcall type. */
|
||||
@ -4030,23 +4065,30 @@ classify_upcall(const struct dpif_upcall *upcall)
|
||||
VLOG_WARN_RL(&rl, "action upcall missing cookie");
|
||||
return BAD_UPCALL;
|
||||
}
|
||||
if (nl_attr_get_size(upcall->userdata) != sizeof(cookie)) {
|
||||
userdata_len = nl_attr_get_size(upcall->userdata);
|
||||
if (userdata_len < sizeof cookie.type
|
||||
|| userdata_len > sizeof cookie) {
|
||||
VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %zu",
|
||||
nl_attr_get_size(upcall->userdata));
|
||||
userdata_len);
|
||||
return BAD_UPCALL;
|
||||
}
|
||||
memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
|
||||
switch (cookie.type) {
|
||||
case USER_ACTION_COOKIE_SFLOW:
|
||||
memset(&cookie, 0, sizeof cookie);
|
||||
memcpy(&cookie, nl_attr_get(upcall->userdata), userdata_len);
|
||||
if (userdata_len == sizeof cookie.sflow
|
||||
&& cookie.type == USER_ACTION_COOKIE_SFLOW) {
|
||||
return SFLOW_UPCALL;
|
||||
|
||||
case USER_ACTION_COOKIE_SLOW_PATH:
|
||||
} else if (userdata_len == sizeof cookie.slow_path
|
||||
&& cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
|
||||
return MISS_UPCALL;
|
||||
|
||||
case USER_ACTION_COOKIE_UNSPEC:
|
||||
default:
|
||||
VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64,
|
||||
nl_attr_get_u64(upcall->userdata));
|
||||
} else if (userdata_len == sizeof cookie.flow_sample
|
||||
&& cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
|
||||
return FLOW_SAMPLE_UPCALL;
|
||||
} else if (userdata_len == sizeof cookie.ipfix
|
||||
&& cookie.type == USER_ACTION_COOKIE_IPFIX) {
|
||||
return IPFIX_UPCALL;
|
||||
} else {
|
||||
VLOG_WARN_RL(&rl, "invalid user cookie of type %"PRIu16
|
||||
" and size %zu", cookie.type, userdata_len);
|
||||
return BAD_UPCALL;
|
||||
}
|
||||
}
|
||||
@ -4066,11 +4108,56 @@ handle_sflow_upcall(struct dpif_backer *backer,
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
|
||||
memset(&cookie, 0, sizeof cookie);
|
||||
memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof cookie.sflow);
|
||||
dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
|
||||
odp_in_port, &cookie);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_flow_sample_upcall(struct dpif_backer *backer,
|
||||
const struct dpif_upcall *upcall)
|
||||
{
|
||||
struct ofproto_dpif *ofproto;
|
||||
union user_action_cookie cookie;
|
||||
struct flow flow;
|
||||
|
||||
if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
|
||||
&flow, NULL, &ofproto, NULL, NULL)
|
||||
|| !ofproto->ipfix) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&cookie, 0, sizeof cookie);
|
||||
memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof cookie.flow_sample);
|
||||
|
||||
/* The flow reflects exactly the contents of the packet. Sample
|
||||
* the packet using it. */
|
||||
dpif_ipfix_flow_sample(ofproto->ipfix, upcall->packet, &flow,
|
||||
cookie.flow_sample.collector_set_id,
|
||||
cookie.flow_sample.probability,
|
||||
cookie.flow_sample.obs_domain_id,
|
||||
cookie.flow_sample.obs_point_id);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_ipfix_upcall(struct dpif_backer *backer,
|
||||
const struct dpif_upcall *upcall)
|
||||
{
|
||||
struct ofproto_dpif *ofproto;
|
||||
struct flow flow;
|
||||
|
||||
if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
|
||||
&flow, NULL, &ofproto, NULL, NULL)
|
||||
|| !ofproto->ipfix) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The flow reflects exactly the contents of the packet. Sample
|
||||
* the packet using it. */
|
||||
dpif_ipfix_bridge_sample(ofproto->ipfix, upcall->packet, &flow);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_upcalls(struct dpif_backer *backer, unsigned int max_batch)
|
||||
{
|
||||
@ -4108,6 +4195,16 @@ handle_upcalls(struct dpif_backer *backer, unsigned int max_batch)
|
||||
ofpbuf_uninit(buf);
|
||||
break;
|
||||
|
||||
case FLOW_SAMPLE_UPCALL:
|
||||
handle_flow_sample_upcall(backer, upcall);
|
||||
ofpbuf_uninit(buf);
|
||||
break;
|
||||
|
||||
case IPFIX_UPCALL:
|
||||
handle_ipfix_upcall(backer, upcall);
|
||||
ofpbuf_uninit(buf);
|
||||
break;
|
||||
|
||||
case BAD_UPCALL:
|
||||
ofpbuf_uninit(buf);
|
||||
break;
|
||||
@ -5747,6 +5844,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
|
||||
ofp_port_to_odp_port(ofproto, flow.in_port));
|
||||
|
||||
compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
|
||||
compose_ipfix_action(ofproto, &odp_actions, &flow);
|
||||
|
||||
nl_msg_put_u32(&odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port);
|
||||
error = dpif_execute(ofproto->backer->dpif,
|
||||
@ -5796,9 +5894,10 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
|
||||
ofpbuf_use_stack(&buf, stub, stub_size);
|
||||
if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
|
||||
uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie, &buf);
|
||||
odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf);
|
||||
} else {
|
||||
put_userspace_action(ofproto, &buf, flow, &cookie);
|
||||
put_userspace_action(ofproto, &buf, flow, &cookie,
|
||||
sizeof cookie.slow_path);
|
||||
}
|
||||
*actionsp = buf.data;
|
||||
*actions_lenp = buf.size;
|
||||
@ -5808,14 +5907,43 @@ static size_t
|
||||
put_userspace_action(const struct ofproto_dpif *ofproto,
|
||||
struct ofpbuf *odp_actions,
|
||||
const struct flow *flow,
|
||||
const union user_action_cookie *cookie)
|
||||
const union user_action_cookie *cookie,
|
||||
const size_t cookie_size)
|
||||
{
|
||||
uint32_t pid;
|
||||
|
||||
pid = dpif_port_get_pid(ofproto->backer->dpif,
|
||||
ofp_port_to_odp_port(ofproto, flow->in_port));
|
||||
|
||||
return odp_put_userspace_action(pid, cookie, sizeof *cookie, odp_actions);
|
||||
return odp_put_userspace_action(pid, cookie, cookie_size, odp_actions);
|
||||
}
|
||||
|
||||
/* Compose SAMPLE action for sFlow or IPFIX. The given probability is
|
||||
* the number of packets out of UINT32_MAX to sample. The given
|
||||
* cookie is passed back in the callback for each sampled packet.
|
||||
*/
|
||||
static size_t
|
||||
compose_sample_action(const struct ofproto_dpif *ofproto,
|
||||
struct ofpbuf *odp_actions,
|
||||
const struct flow *flow,
|
||||
const uint32_t probability,
|
||||
const union user_action_cookie *cookie,
|
||||
const size_t cookie_size)
|
||||
{
|
||||
size_t sample_offset, actions_offset;
|
||||
int cookie_offset;
|
||||
|
||||
sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE);
|
||||
|
||||
nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability);
|
||||
|
||||
actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS);
|
||||
cookie_offset = put_userspace_action(ofproto, odp_actions, flow, cookie,
|
||||
cookie_size);
|
||||
|
||||
nl_msg_end_nested(odp_actions, actions_offset);
|
||||
nl_msg_end_nested(odp_actions, sample_offset);
|
||||
return cookie_offset;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5850,7 +5978,7 @@ compose_sflow_cookie(const struct ofproto_dpif *ofproto,
|
||||
}
|
||||
}
|
||||
|
||||
/* Compose SAMPLE action for sFlow. */
|
||||
/* Compose SAMPLE action for sFlow bridge sampling. */
|
||||
static size_t
|
||||
compose_sflow_action(const struct ofproto_dpif *ofproto,
|
||||
struct ofpbuf *odp_actions,
|
||||
@ -5859,32 +5987,60 @@ compose_sflow_action(const struct ofproto_dpif *ofproto,
|
||||
{
|
||||
uint32_t probability;
|
||||
union user_action_cookie cookie;
|
||||
size_t sample_offset, actions_offset;
|
||||
int cookie_offset;
|
||||
|
||||
if (!ofproto->sflow || flow->in_port == OFPP_NONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE);
|
||||
|
||||
/* Number of packets out of UINT_MAX to sample. */
|
||||
probability = dpif_sflow_get_probability(ofproto->sflow);
|
||||
nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability);
|
||||
|
||||
actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS);
|
||||
compose_sflow_cookie(ofproto, htons(0), odp_port,
|
||||
odp_port == OVSP_NONE ? 0 : 1, &cookie);
|
||||
cookie_offset = put_userspace_action(ofproto, odp_actions, flow, &cookie);
|
||||
|
||||
nl_msg_end_nested(odp_actions, actions_offset);
|
||||
nl_msg_end_nested(odp_actions, sample_offset);
|
||||
return cookie_offset;
|
||||
return compose_sample_action(ofproto, odp_actions, flow, probability,
|
||||
&cookie, sizeof cookie.sflow);
|
||||
}
|
||||
|
||||
/* SAMPLE action must be first action in any given list of actions.
|
||||
* At this point we do not have all information required to build it. So try to
|
||||
* build sample action as complete as possible. */
|
||||
static void
|
||||
compose_flow_sample_cookie(uint16_t probability, uint32_t collector_set_id,
|
||||
uint32_t obs_domain_id, uint32_t obs_point_id,
|
||||
union user_action_cookie *cookie)
|
||||
{
|
||||
cookie->type = USER_ACTION_COOKIE_FLOW_SAMPLE;
|
||||
cookie->flow_sample.probability = probability;
|
||||
cookie->flow_sample.collector_set_id = collector_set_id;
|
||||
cookie->flow_sample.obs_domain_id = obs_domain_id;
|
||||
cookie->flow_sample.obs_point_id = obs_point_id;
|
||||
}
|
||||
|
||||
static void
|
||||
compose_ipfix_cookie(union user_action_cookie *cookie)
|
||||
{
|
||||
cookie->type = USER_ACTION_COOKIE_IPFIX;
|
||||
}
|
||||
|
||||
/* Compose SAMPLE action for IPFIX bridge sampling. */
|
||||
static void
|
||||
compose_ipfix_action(const struct ofproto_dpif *ofproto,
|
||||
struct ofpbuf *odp_actions,
|
||||
const struct flow *flow)
|
||||
{
|
||||
uint32_t probability;
|
||||
union user_action_cookie cookie;
|
||||
|
||||
if (!ofproto->ipfix || flow->in_port == OFPP_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
probability = dpif_ipfix_get_bridge_exporter_probability(ofproto->ipfix);
|
||||
compose_ipfix_cookie(&cookie);
|
||||
|
||||
compose_sample_action(ofproto, odp_actions, flow, probability,
|
||||
&cookie, sizeof cookie.ipfix);
|
||||
}
|
||||
|
||||
/* SAMPLE action for sFlow must be first action in any given list of
|
||||
* actions. At this point we do not have all information required to
|
||||
* build it. So try to build sample action as complete as possible. */
|
||||
static void
|
||||
add_sflow_action(struct action_xlate_ctx *ctx)
|
||||
{
|
||||
@ -5895,6 +6051,14 @@ add_sflow_action(struct action_xlate_ctx *ctx)
|
||||
ctx->sflow_n_outputs = 0;
|
||||
}
|
||||
|
||||
/* SAMPLE action for IPFIX must be 1st or 2nd action in any given list
|
||||
* of actions, eventually after the SAMPLE action for sFlow. */
|
||||
static void
|
||||
add_ipfix_action(struct action_xlate_ctx *ctx)
|
||||
{
|
||||
compose_ipfix_action(ctx->ofproto, ctx->odp_actions, &ctx->flow);
|
||||
}
|
||||
|
||||
/* Fix SAMPLE action according to data collected while composing ODP actions.
|
||||
* We need to fix SAMPLE actions OVS_SAMPLE_ATTR_ACTIONS attribute, i.e. nested
|
||||
* USERSPACE action's user-cookie which is required for sflow. */
|
||||
@ -6540,6 +6704,23 @@ xlate_fin_timeout(struct action_xlate_ctx *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xlate_sample_action(struct action_xlate_ctx *ctx,
|
||||
const struct ofpact_sample *os)
|
||||
{
|
||||
union user_action_cookie cookie;
|
||||
/* Scale the probability from 16-bit to 32-bit while representing
|
||||
* the same percentage. */
|
||||
uint32_t probability = (os->probability << 16) | os->probability;
|
||||
|
||||
commit_odp_actions(&ctx->flow, &ctx->base_flow, ctx->odp_actions);
|
||||
|
||||
compose_flow_sample_cookie(os->probability, os->collector_set_id,
|
||||
os->obs_domain_id, os->obs_point_id, &cookie);
|
||||
compose_sample_action(ctx->ofproto, ctx->odp_actions, &ctx->flow,
|
||||
probability, &cookie, sizeof cookie.flow_sample);
|
||||
}
|
||||
|
||||
static bool
|
||||
may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx)
|
||||
{
|
||||
@ -6820,6 +7001,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OFPACT_SAMPLE:
|
||||
xlate_sample_action(ctx, ofpact_get_SAMPLE(a));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6954,6 +7139,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
|
||||
initial_vals.tunnel_ip_tos = ctx->base_flow.tunnel.ip_tos;
|
||||
|
||||
add_sflow_action(ctx);
|
||||
add_ipfix_action(ctx);
|
||||
|
||||
if (tunnel_ecn_ok(ctx) && (!in_port || may_receive(in_port, ctx))) {
|
||||
do_xlate_actions(ofpacts, ofpacts_len, ctx);
|
||||
@ -6963,6 +7149,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
|
||||
if (in_port && !stp_forward_in_state(in_port->stp_state)) {
|
||||
ofpbuf_clear(ctx->odp_actions);
|
||||
add_sflow_action(ctx);
|
||||
add_ipfix_action(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8852,6 +9039,7 @@ const struct ofproto_class ofproto_dpif_class = {
|
||||
set_netflow,
|
||||
get_netflow_ids,
|
||||
set_sflow,
|
||||
set_ipfix,
|
||||
set_cfm,
|
||||
get_cfm_status,
|
||||
set_stp,
|
||||
|
@ -1109,6 +1109,20 @@ 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
|
||||
* 'bridge_exporter_options' and the 'flow_exporters_options'
|
||||
* array, or turns off IPFIX if 'bridge_exporter_options' and
|
||||
* 'flow_exporters_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_bridge_exporter_options
|
||||
*bridge_exporter_options,
|
||||
const struct ofproto_ipfix_flow_exporter_options
|
||||
*flow_exporters_options, size_t n_flow_exporters_options);
|
||||
|
||||
/* Configures connectivity fault management on 'ofport'.
|
||||
*
|
||||
* If 'cfm_settings' is nonnull, configures CFM according to its members.
|
||||
|
@ -640,6 +640,19 @@ ofproto_set_sflow(struct ofproto *ofproto,
|
||||
return oso ? EOPNOTSUPP : 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ofproto_set_ipfix(struct ofproto *ofproto,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *bo,
|
||||
const struct ofproto_ipfix_flow_exporter_options *fo,
|
||||
size_t n_fo)
|
||||
{
|
||||
if (ofproto->ofproto_class->set_ipfix) {
|
||||
return ofproto->ofproto_class->set_ipfix(ofproto, bo, fo, n_fo);
|
||||
} else {
|
||||
return (bo || fo) ? EOPNOTSUPP : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Spanning Tree Protocol (STP) configuration. */
|
||||
|
||||
|
@ -68,6 +68,19 @@ struct ofproto_sflow_options {
|
||||
char *control_ip;
|
||||
};
|
||||
|
||||
|
||||
struct ofproto_ipfix_bridge_exporter_options {
|
||||
struct sset targets;
|
||||
uint32_t sampling_rate;
|
||||
uint32_t obs_domain_id; /* Bridge-wide Observation Domain ID. */
|
||||
uint32_t obs_point_id; /* Bridge-wide Observation Point ID. */
|
||||
};
|
||||
|
||||
struct ofproto_ipfix_flow_exporter_options {
|
||||
uint32_t collector_set_id;
|
||||
struct sset targets;
|
||||
};
|
||||
|
||||
struct ofproto_stp_settings {
|
||||
stp_identifier system_id;
|
||||
uint16_t priority;
|
||||
@ -229,6 +242,10 @@ 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_bridge_exporter_options *,
|
||||
const struct ofproto_ipfix_flow_exporter_options *,
|
||||
size_t);
|
||||
int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *);
|
||||
int ofproto_get_stp_status(struct ofproto *, struct ofproto_stp_status *);
|
||||
|
||||
|
@ -88,8 +88,9 @@ userspace(pid=6633,sFlow(vid=9,pcp=7,output=10))
|
||||
userspace(pid=9765,slow_path())
|
||||
userspace(pid=9765,slow_path(cfm))
|
||||
userspace(pid=9765,slow_path(cfm,match))
|
||||
userspace(pid=9123,userdata=0x815309)
|
||||
userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f))
|
||||
userspace(pid=6633,flow_sample(probability=123,collector_set_id=1234,obs_domain_id=2345,obs_point_id=3456))
|
||||
userspace(pid=6633,ipfix)
|
||||
set(in_port(2))
|
||||
set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15))
|
||||
set(eth_type(0x1234))
|
||||
|
@ -114,6 +114,9 @@ ffff 0010 00002320 0014 04d2 162e 02 00
|
||||
# actions=dec_ttl(32768,12345,90,765,1024)
|
||||
ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
|
||||
|
||||
# actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
ffff 0018 00002320 001d 3039 00005BA0 00008707 0000B26E
|
||||
|
||||
])
|
||||
sed '/^[[#&]]/d' < test-data > input.txt
|
||||
sed -n 's/^# //p; /^$/p' < test-data > expout
|
||||
@ -289,6 +292,9 @@ ffff 0010 00002320 0014 04d2 162e 02 00
|
||||
# actions=dec_ttl(32768,12345,90,765,1024)
|
||||
ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
|
||||
|
||||
# actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
ffff 0018 00002320 001d 3039 00005BA0 00008707 0000B26E
|
||||
|
||||
])
|
||||
sed '/^[[#&]]/d' < test-data > input.txt
|
||||
sed -n 's/^# //p; /^$/p' < test-data > expout
|
||||
|
@ -12,6 +12,7 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
|
||||
actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
|
||||
actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src
|
||||
in_port=0 actions=resubmit:0
|
||||
actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
|
||||
AT_CHECK([ovs-ofctl parse-flows flows.txt
|
||||
@ -28,6 +29,7 @@ OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTR
|
||||
OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
|
||||
OFPT_FLOW_MOD: ADD actions=load:0xa6badbfffefe59fa->NXM_NX_IPV6_SRC[0..63],load:0xfe8001234567890a->NXM_NX_IPV6_SRC[64..127]
|
||||
OFPT_FLOW_MOD: ADD in_port=0 actions=resubmit:0
|
||||
OFPT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
AT_CLEANUP
|
||||
|
||||
@ -43,6 +45,7 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
|
||||
actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
|
||||
actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src
|
||||
in_port=0 actions=resubmit:0
|
||||
actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
|
||||
AT_CHECK([ovs-ofctl --protocols OpenFlow12 parse-flows flows.txt
|
||||
@ -59,6 +62,7 @@ OFPT_FLOW_MOD (OF1.2): ADD table:255 priority=60000 cookie:0x123456789abcdef har
|
||||
OFPT_FLOW_MOD (OF1.2): ADD table:255 actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
|
||||
OFPT_FLOW_MOD (OF1.2): ADD table:255 actions=set_field:fe80:123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src
|
||||
OFPT_FLOW_MOD (OF1.2): ADD table:255 in_port=0 actions=resubmit:0
|
||||
OFPT_FLOW_MOD (OF1.2): ADD table:255 actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
AT_CLEANUP
|
||||
|
||||
@ -116,6 +120,7 @@ send_flow_rem,actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[
|
||||
check_overlap,actions=output:1,exit,output:2
|
||||
actions=fin_timeout(idle_timeout=5,hard_timeout=15)
|
||||
actions=controller(max_len=123,reason=invalid_ttl,id=555)
|
||||
actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
|
||||
AT_CHECK([ovs-ofctl parse-flows flows.txt
|
||||
@ -150,6 +155,7 @@ NXT_FLOW_MOD: ADD table:255 send_flow_rem actions=output:1,output:NXM_NX_REG0[],
|
||||
NXT_FLOW_MOD: ADD table:255 check_overlap actions=output:1,exit,output:2
|
||||
NXT_FLOW_MOD: ADD table:255 actions=fin_timeout(idle_timeout=5,hard_timeout=15)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=controller(reason=invalid_ttl,max_len=123,id=555)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
AT_CLEANUP
|
||||
|
||||
@ -183,6 +189,7 @@ dl_dst=01:00:00:00:00:00/01:00:00:00:00:00,actions=drop
|
||||
dl_dst=00:00:00:00:00:00/01:00:00:00:00:00,actions=drop
|
||||
dl_dst=aa:bb:cc:dd:ee:ff/fe:ff:ff:ff:ff:ff,actions=drop
|
||||
dl_dst=aa:bb:cc:dd:ee:ff/00:00:00:00:00:00,actions=drop
|
||||
actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
])
|
||||
AT_CHECK([ovs-ofctl -F nxm parse-flows flows.txt], [0], [stdout])
|
||||
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
|
||||
@ -215,6 +222,7 @@ NXT_FLOW_MOD: ADD dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop
|
||||
NXT_FLOW_MOD: ADD dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=drop
|
||||
NXT_FLOW_MOD: ADD dl_dst=aa:bb:cc:dd:ee:ff/fe:ff:ff:ff:ff:ff actions=drop
|
||||
NXT_FLOW_MOD: ADD actions=drop
|
||||
NXT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
@ -245,6 +253,7 @@ reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG
|
||||
actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[]
|
||||
actions=push:NXM_NX_REG0[0..31],pop:NXM_NX_REG0[]
|
||||
vlan_tci=0x1123/0x1fff,actions=drop
|
||||
actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout], [stderr])
|
||||
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
|
||||
@ -274,6 +283,7 @@ NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_R
|
||||
NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[]
|
||||
NXT_FLOW_MOD: ADD <any> actions=push:NXM_NX_REG0[],pop:NXM_NX_REG0[]
|
||||
NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop
|
||||
NXT_FLOW_MOD: ADD <any> actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
|
||||
]])
|
||||
AT_CLEANUP
|
||||
|
||||
|
@ -632,6 +632,7 @@ external_ids : {}
|
||||
fail_mode : []
|
||||
flood_vlans : []
|
||||
flow_tables : {}
|
||||
ipfix : []
|
||||
mirrors : []
|
||||
name : "br0"
|
||||
netflow : []
|
||||
@ -822,7 +823,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])],
|
||||
@ -1123,6 +1124,7 @@ external_ids : {}
|
||||
fail_mode : []
|
||||
flood_vlans : []
|
||||
flow_tables : {}
|
||||
ipfix : []
|
||||
mirrors : []
|
||||
name : "br0"
|
||||
netflow : []
|
||||
|
@ -1241,6 +1241,30 @@ flow's creation, not since the receipt of the FIN or RST.)
|
||||
.RE
|
||||
.IP
|
||||
This action was added in Open vSwitch 1.5.90.
|
||||
.
|
||||
.IP "\fBsample(\fIargument\fR[\fB,\fIargument\fR]...\fB)\fR"
|
||||
Samples packets and sends one sample for every sampled packet.
|
||||
.IP
|
||||
\fIargument\fR takes the following forms:
|
||||
.RS
|
||||
.IP "\fBprobability=\fIpackets\fR"
|
||||
The number of sampled packets out of 65535. Must be greater or equal to 1.
|
||||
.IP "\fBcollector_set_id=\fIid\fR"
|
||||
The unsigned 32-bit integer identifier of the set of sample collectors
|
||||
to send sampled packets to. Defaults to 0.
|
||||
.IP "\fBobs_domain_id=\fIid\fR"
|
||||
When sending samples to IPFIX collectors, the unsigned 32-bit integer
|
||||
Observation Domain ID sent in every IPFIX flow record. Defaults to 0.
|
||||
.IP "\fBobs_point_id=\fIid\fR"
|
||||
When sending samples to IPFIX collectors, the unsigned 32-bit integer
|
||||
Observation Point ID sent in every IPFIX flow record. Defaults to 0.
|
||||
.RE
|
||||
.IP
|
||||
Refer to \fBovs\-vswitchd.conf.db\fR(8) for more details on
|
||||
configuring sample collector sets.
|
||||
.IP
|
||||
This action was added in Open vSwitch 1.10.90.
|
||||
.
|
||||
.IP "\fBexit\fR"
|
||||
This action causes Open vSwitch to immediately halt execution of further
|
||||
actions. Those actions which have already been executed are unaffected. Any
|
||||
@ -1555,3 +1579,4 @@ Prints the flow entries in the switch.
|
||||
.BR ovs\-appctl (8),
|
||||
.BR ovs\-controller (8),
|
||||
.BR ovs\-vswitchd (8)
|
||||
.BR ovs\-vswitchd.conf.db (8)
|
||||
|
@ -172,10 +172,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.
|
||||
@ -526,8 +527,14 @@ The global SSL configuration for \fBovs\-vswitchd\fR. The record
|
||||
attached to the \fBOpen_vSwitch\fR table may be identified by
|
||||
specifying \fB.\fR as the record name.
|
||||
.IP "\fBsFlow\fR"
|
||||
An sFlow configuration attached to a bridge. Records may be
|
||||
An sFlow exporter configuration attached to a bridge. Records may be
|
||||
identified by bridge name.
|
||||
.IP "\fBIPFIX\fR"
|
||||
An IPFIX exporter configuration attached to a bridge. Records may be
|
||||
identified by bridge name.
|
||||
.IP "\fBFlow_Sample_Collector_Set\fR"
|
||||
An IPFIX exporter configuration attached to a bridge for sampling
|
||||
packets on a per-flow basis using OpenFlow \fBsample\fR actions.
|
||||
.PP
|
||||
Record names must be specified in full and with correct
|
||||
capitalization. Names of tables and columns are not case-sensitive,
|
||||
@ -931,6 +938,20 @@ 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 one IPFIX flow record per packet
|
||||
sample to UDP port 4739 on host 192.168.0.34, with Observation Domain
|
||||
ID 123 and Observation Point ID 456:
|
||||
.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=123 obs_point_id=456"
|
||||
.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:
|
||||
|
@ -1453,6 +1453,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);
|
||||
|
||||
@ -1477,6 +1478,8 @@ 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;
|
||||
const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset;
|
||||
|
||||
/* Reset the Open_vSwitch table. */
|
||||
ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0);
|
||||
@ -1490,6 +1493,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. */
|
||||
@ -1539,6 +1543,14 @@ cmd_emer_reset(struct vsctl_context *ctx)
|
||||
ovsrec_sflow_delete(sflow);
|
||||
}
|
||||
|
||||
OVSREC_IPFIX_FOR_EACH_SAFE (ipfix, next_ipfix, idl) {
|
||||
ovsrec_ipfix_delete(ipfix);
|
||||
}
|
||||
|
||||
OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, idl) {
|
||||
ovsrec_flow_sample_collector_set_delete(fscset);
|
||||
}
|
||||
|
||||
vsctl_context_invalidate_cache(ctx);
|
||||
}
|
||||
|
||||
@ -1668,6 +1680,7 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br)
|
||||
{
|
||||
struct vsctl_bridge *child, *next_child;
|
||||
struct vsctl_port *port, *next_port;
|
||||
const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset;
|
||||
|
||||
HMAP_FOR_EACH_SAFE (child, next_child, children_node, &br->children) {
|
||||
del_bridge(ctx, child);
|
||||
@ -1677,6 +1690,13 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br)
|
||||
del_port(ctx, port);
|
||||
}
|
||||
|
||||
OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset,
|
||||
ctx->idl) {
|
||||
if (fscset->bridge == br->br_cfg) {
|
||||
ovsrec_flow_sample_collector_set_delete(fscset);
|
||||
}
|
||||
}
|
||||
|
||||
del_cached_bridge(ctx, br);
|
||||
}
|
||||
|
||||
@ -2464,7 +2484,8 @@ struct vsctl_table_class {
|
||||
static const struct vsctl_table_class tables[] = {
|
||||
{&ovsrec_table_bridge,
|
||||
{{&ovsrec_table_bridge, &ovsrec_bridge_col_name, NULL},
|
||||
{NULL, NULL, NULL}}},
|
||||
{&ovsrec_table_flow_sample_collector_set, NULL,
|
||||
&ovsrec_flow_sample_collector_set_col_bridge}}},
|
||||
|
||||
{&ovsrec_table_controller,
|
||||
{{&ovsrec_table_bridge,
|
||||
@ -2518,6 +2539,17 @@ 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},
|
||||
{&ovsrec_table_flow_sample_collector_set, NULL,
|
||||
&ovsrec_flow_sample_collector_set_col_ipfix}}},
|
||||
|
||||
{&ovsrec_table_flow_sample_collector_set,
|
||||
{{NULL, NULL, NULL},
|
||||
{NULL, NULL, NULL}}},
|
||||
|
||||
{NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
|
||||
};
|
||||
|
||||
|
@ -200,6 +200,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 *);
|
||||
@ -388,8 +389,9 @@ bridge_init(const char *remote)
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_mirror_col_statistics);
|
||||
|
||||
ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
|
||||
|
||||
ovsdb_idl_omit(idl, &ovsrec_sflow_col_external_ids);
|
||||
ovsdb_idl_omit(idl, &ovsrec_ipfix_col_external_ids);
|
||||
ovsdb_idl_omit(idl, &ovsrec_flow_sample_collector_set_col_external_ids);
|
||||
|
||||
ovsdb_idl_omit(idl, &ovsrec_manager_col_external_ids);
|
||||
ovsdb_idl_omit(idl, &ovsrec_manager_col_inactivity_probe);
|
||||
@ -612,6 +614,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);
|
||||
@ -944,6 +947,79 @@ 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 *be_cfg = br->cfg->ipfix;
|
||||
const struct ovsrec_flow_sample_collector_set *fe_cfg;
|
||||
struct ofproto_ipfix_bridge_exporter_options be_opts;
|
||||
struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL;
|
||||
size_t n_fe_opts = 0;
|
||||
|
||||
OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
|
||||
if (fe_cfg->bridge == br->cfg) {
|
||||
n_fe_opts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!be_cfg && n_fe_opts == 0) {
|
||||
ofproto_set_ipfix(br->ofproto, NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (be_cfg) {
|
||||
memset(&be_opts, 0, sizeof be_opts);
|
||||
|
||||
sset_init(&be_opts.targets);
|
||||
sset_add_array(&be_opts.targets, be_cfg->targets, be_cfg->n_targets);
|
||||
|
||||
if (be_cfg->sampling) {
|
||||
be_opts.sampling_rate = *be_cfg->sampling;
|
||||
} else {
|
||||
be_opts.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
|
||||
}
|
||||
if (be_cfg->obs_domain_id) {
|
||||
be_opts.obs_domain_id = *be_cfg->obs_domain_id;
|
||||
}
|
||||
if (be_cfg->obs_point_id) {
|
||||
be_opts.obs_point_id = *be_cfg->obs_point_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (n_fe_opts > 0) {
|
||||
struct ofproto_ipfix_flow_exporter_options *opts;
|
||||
fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts);
|
||||
opts = fe_opts;
|
||||
OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
|
||||
if (fe_cfg->bridge == br->cfg) {
|
||||
opts->collector_set_id = fe_cfg->id;
|
||||
sset_init(&opts->targets);
|
||||
sset_add_array(&opts->targets, fe_cfg->ipfix->targets,
|
||||
fe_cfg->ipfix->n_targets);
|
||||
opts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts,
|
||||
n_fe_opts);
|
||||
|
||||
if (be_cfg) {
|
||||
sset_destroy(&be_opts.targets);
|
||||
}
|
||||
|
||||
if (n_fe_opts > 0) {
|
||||
struct ofproto_ipfix_flow_exporter_options *opts = fe_opts;
|
||||
size_t i;
|
||||
for (i = 0; i < n_fe_opts; i++) {
|
||||
sset_destroy(&opts->targets);
|
||||
opts++;
|
||||
}
|
||||
free(fe_opts);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
port_configure_stp(const struct ofproto *ofproto, struct port *port,
|
||||
struct ofproto_port_stp_settings *port_s,
|
||||
|
@ -6,6 +6,7 @@ digraph Open_vSwitch {
|
||||
Bridge [];
|
||||
Bridge -> sFlow [label="sflow?"];
|
||||
Bridge -> Mirror [label="mirrors*"];
|
||||
Bridge -> IPFIX [label="ipfix?"];
|
||||
Bridge -> Port [label="ports*"];
|
||||
Bridge -> Controller [label="controller*"];
|
||||
Bridge -> Flow_Table [label="flow_tables value*"];
|
||||
@ -13,6 +14,10 @@ digraph Open_vSwitch {
|
||||
QoS [style=bold];
|
||||
QoS -> Queue [label="queues value*"];
|
||||
sFlow [];
|
||||
Flow_Sample_Collector_Set [style=bold];
|
||||
Flow_Sample_Collector_Set -> Bridge [label="bridge"];
|
||||
Flow_Sample_Collector_Set -> IPFIX [label="ipfix?"];
|
||||
IPFIX [];
|
||||
Open_vSwitch [style=bold];
|
||||
Open_vSwitch -> Bridge [label="bridges*"];
|
||||
Open_vSwitch -> SSL [label="ssl?"];
|
||||
|
@ -1,6 +1,6 @@
|
||||
{"name": "Open_vSwitch",
|
||||
"version": "7.1.0",
|
||||
"cksum": "2234055133 17444",
|
||||
"cksum": "432130924 19191",
|
||||
"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"},
|
||||
@ -383,6 +387,48 @@
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}}},
|
||||
"IPFIX": {
|
||||
"columns": {
|
||||
"targets": {
|
||||
"type": {"key": "string", "min": 1, "max": "unlimited"}},
|
||||
"sampling": {
|
||||
"type": {"key": {"type": "integer",
|
||||
"minInteger": 1,
|
||||
"maxInteger": 4294967295},
|
||||
"min": 0, "max": 1}},
|
||||
"obs_domain_id": {
|
||||
"type": {"key": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4294967295},
|
||||
"min": 0, "max": 1}},
|
||||
"obs_point_id": {
|
||||
"type": {"key": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4294967295},
|
||||
"min": 0, "max": 1}},
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}}},
|
||||
"Flow_Sample_Collector_Set": {
|
||||
"columns": {
|
||||
"id": {
|
||||
"type": {"key": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4294967295},
|
||||
"min": 1, "max": 1}},
|
||||
"bridge": {
|
||||
"type": {"key": {"type": "uuid",
|
||||
"refTable": "Bridge"},
|
||||
"min": 1, "max": 1}},
|
||||
"ipfix": {
|
||||
"type": {"key": {"type": "uuid",
|
||||
"refTable": "IPFIX"},
|
||||
"min": 0, "max": 1}},
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"isRoot": true,
|
||||
"indexes": [["id", "bridge"]]},
|
||||
"Controller": {
|
||||
"columns": {
|
||||
"target": {
|
||||
|
@ -1,78 +1,92 @@
|
||||
.\" Generated from vswitch.gv with cksum "2197927206 1028"
|
||||
.\" Generated from vswitch.gv with cksum "2412173910 1224"
|
||||
.PS
|
||||
linethick = 1;
|
||||
linethick = 1;
|
||||
box at 3.269320992,2.78572 wid 0.5900294246 height 0.348215 "Bridge"
|
||||
box at 1.639964024,1.91216 wid 0.4050050488 height 0.23902 "Bridge"
|
||||
linethick = 1;
|
||||
box at 0.2708346627,1.9151825 wid 0.5416693254 height 0.348215 "sFlow"
|
||||
box at 5.72978744,1.31461 wid 0.3718099512 height 0.23902 "sFlow"
|
||||
linethick = 1;
|
||||
box at 0.996312758,1.9151825 wid 0.5706825992 height 0.348215 "Mirror"
|
||||
box at 6.22790512,1.31461 wid 0.3917250976 height 0.23902 "Mirror"
|
||||
linethick = 1;
|
||||
box at 2.795400377,1.9151825 wid 0.5223225 height 0.348215 "Port"
|
||||
box at 0.2589399268,1.31461 wid 0.35853 height 0.23902 "IPFIX"
|
||||
linethick = 1;
|
||||
box at 3.646577123,1.9151825 wid 0.831815992 height 0.348215 "Controller"
|
||||
box at 0.736994268,1.31461 wid 0.35853 height 0.23902 "Port"
|
||||
linethick = 1;
|
||||
box at 4.681541746,1.9151825 wid 0.889898254 height 0.348215 "Flow_Table"
|
||||
box at 1.321254756,1.31461 wid 0.570970976 height 0.23902 "Controller"
|
||||
linethick = 1;
|
||||
box at 6.103442877,1.9151825 wid 0.715790754 height 0.348215 "NetFlow"
|
||||
box at 2.03167,1.31461 wid 0.610839512 height 0.23902 "Flow_Table"
|
||||
linethick = 1;
|
||||
box at 5.17191476,1.31461 wid 0.491329512 height 0.23902 "NetFlow"
|
||||
linethick = 0.5;
|
||||
box at 2.244036746,1.044645 wid 0.5223225 height 0.348215 "QoS"
|
||||
box at 2.244036746,1.044645 wid 0.466766944444444 height 0.292659444444444
|
||||
box at 0.35853,0.71706 wid 0.35853 height 0.23902 "QoS"
|
||||
box at 0.35853,0.71706 wid 0.302974444444444 height 0.183464444444444
|
||||
linethick = 0.5;
|
||||
box at 2.244036746,0.1741075 wid 0.5997028373 height 0.348215 "Queue"
|
||||
box at 2.244036746,0.1741075 wid 0.544147281744444 height 0.292659444444444
|
||||
box at 0.35853,0.11951 wid 0.4116450244 height 0.23902 "Queue"
|
||||
box at 0.35853,0.11951 wid 0.356089468844444 height 0.183464444444444
|
||||
linethick = 0.5;
|
||||
box at 4.052804742,3.6562575 wid 1.122018373 height 0.348215 "Open_vSwitch"
|
||||
box at 4.052804742,3.6562575 wid 1.06646281744444 height 0.292659444444444
|
||||
linethick = 1;
|
||||
box at 4.052804742,2.78572 wid 0.5223225 height 0.348215 "SSL"
|
||||
linethick = 1;
|
||||
box at 4.855649246,2.78572 wid 0.744762242 height 0.348215 "Manager"
|
||||
linethick = 1;
|
||||
box at 3.056561627,1.044645 wid 0.754442619 height 0.348215 "Interface"
|
||||
linethick = 1;
|
||||
spline -> from 2.976332891,2.75298779 to 2.976332891,2.75298779 to 2.604160699,2.706535909 to 1.945268276,2.607573206 to 1.402540377,2.437505 to 1.042625353,2.324752983 to 0.970266276,2.249190328 to 0.6287230754,2.08929 to 0.6011862332,2.076406045 to 0.5725420673,2.06282566 to 0.5439884373,2.049105989
|
||||
"sflow?" at 1.620174752,2.35045125
|
||||
linethick = 1;
|
||||
spline -> from 2.97514896,2.6812555 to 2.97514896,2.6812555 to 2.785302142,2.613214289 to 2.533333768,2.52177303 to 2.311729742,2.437505 to 1.95348615,2.301283292 to 1.543358523,2.137134741 to 1.277600835,2.029675592
|
||||
"mirrors*" at 2.592251746,2.35045125
|
||||
linethick = 1;
|
||||
spline -> from 3.102665293,2.610428569 to 3.102665293,2.610428569 to 3.058372345,2.557708818 to 3.013382967,2.497746195 to 2.979188254,2.437505 to 2.917484556,2.32886192 to 2.871032675,2.19584379 to 2.840250469,2.091240004
|
||||
"ports*" at 3.187142252,2.35045125
|
||||
linethick = 1;
|
||||
spline -> from 3.345719363,2.60952321 to 3.345719363,2.60952321 to 3.41111414,2.458537186 to 3.504923261,2.242017099 to 3.570387681,2.091100718
|
||||
"controller*" at 3.849725754,2.35045125
|
||||
linethick = 1;
|
||||
spline -> from 3.563284095,2.664959038 to 3.563284095,2.664959038 to 3.610362763,2.646503643 to 3.658695005,2.628187534 to 3.704589742,2.6116125 to 3.942559873,2.525881967 to 4.036647566,2.578949933 to 4.246272996,2.437505 to 4.380335771,2.347038743 to 4.495594936,2.203852735 to 4.573734382,2.090195359
|
||||
"flow_tables value*" at 5.063603244,2.35045125
|
||||
linethick = 1;
|
||||
spline -> from 3.560568018,2.655696519 to 3.560568018,2.655696519 to 3.607925258,2.638425055 to 3.657093216,2.622894666 to 3.704589742,2.6116125 to 4.143340642,2.507426572 to 5.333887727,2.659805456 to 5.726186746,2.437505 to 5.863383456,2.359713769 to 5.963947948,2.209215246 to 6.026557005,2.089638215
|
||||
"netflow?" at 6.204982371,2.35045125
|
||||
box at 0.683884024,2.50971 wid 1.367720244 height 0.23902 "Flow_Sample_Collector_Set"
|
||||
box at 0.683884024,2.50971 wid 1.31216468844444 height 0.183464444444444
|
||||
linethick = 0.5;
|
||||
spline -> from 1.285331208,1.9151825 to 1.285331208,1.9151825 to 1.629994415,1.9151825 to 2.201067015,1.9151825 to 2.533403411,1.9151825
|
||||
"select_src_port*" at 1.905502123,2.00223625
|
||||
box at 2.177759024,2.50971 wid 0.770170244 height 0.23902 "Open_vSwitch"
|
||||
box at 2.177759024,2.50971 wid 0.714614688444444 height 0.183464444444444
|
||||
linethick = 1;
|
||||
box at 2.177759024,1.91216 wid 0.35853 height 0.23902 "SSL"
|
||||
linethick = 1;
|
||||
box at 2.728795732,1.91216 wid 0.511215976 height 0.23902 "Manager"
|
||||
linethick = 1;
|
||||
box at 0.916259268,0.71706 wid 0.517860732 height 0.23902 "Interface"
|
||||
linethick = 1;
|
||||
spline -> from 1.83949792,1.821380204 to 1.83949792,1.821380204 to 1.872052444,1.809763832 to 1.905897676,1.799533776 to 1.938739024,1.79265 to 2.331687904,1.7101881 to 5.21254816,1.889883336 to 5.55052244,1.67314 to 5.63322336,1.620173168 to 5.6791152,1.516773116 to 5.70397328,1.43459804
|
||||
"sflow?" at 5.80627384,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 1.839450116,1.821284596 to 1.839450116,1.821284596 to 1.872052444,1.809668224 to 1.905897676,1.799485972 to 1.938739024,1.79265 to 2.378774844,1.701153144 to 5.58780956,1.888544824 to 5.98219256,1.67314 to 6.07541036,1.622133132 to 6.1404238,1.518541864 to 6.18010112,1.43579314
|
||||
"mirrors*" at 6.30725976,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 1.44033452,1.898966096 to 1.44033452,1.898966096 to 1.223830204,1.877406492 to 0.873952728,1.820806556 to 0.610839512,1.67314 to 0.505861928,1.614245472 to 0.4118171188,1.51466974 to 0.3474107896,1.435362904
|
||||
"ipfix?" at 0.733647988,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 1.439569656,1.871861228 to 1.439569656,1.871861228 to 1.302372176,1.836725288 to 1.12195988,1.775010324 to 0.989255976,1.67314 to 0.907176508,1.610086524 to 0.84111138,1.512853188 to 0.797179504,1.43555412
|
||||
"ports*" at 1.132046524,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 1.43842236,1.800203032 to 1.43842236,1.800203032 to 1.39420366,1.765545132 to 1.353140024,1.72309518 to 1.327899512,1.67314 to 1.291090432,1.600334508 to 1.29022996,1.508168396 to 1.298165424,1.435506316
|
||||
"controller*" at 1.573564268,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 1.733755472,1.79241098 to 1.733755472,1.79241098 to 1.76205544,1.754837036 to 1.792697804,1.71281732 to 1.819229024,1.67314 to 1.870666128,1.596127756 to 1.923776372,1.506495256 to 1.96402734,1.436127768
|
||||
"flow_tables value*" at 2.327146524,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 1.83949792,1.821523616 to 1.83949792,1.821523616 to 1.872100248,1.809907244 to 1.90594548,1.799629384 to 1.938739024,1.79265 to 2.27451432,1.721230824 to 4.744929432,1.870188088 to 5.02611256,1.67314 to 5.103077,1.61912148 to 5.13940804,1.516964332 to 5.15661748,1.435458512
|
||||
"netflow?" at 5.32154128,1.613385
|
||||
linethick = 0.5;
|
||||
spline -> from 1.262209732,1.740239284 to 1.262209732,1.740239284 to 1.2953598,1.724778538 to 1.329693799,1.711546368 to 1.363818869,1.702353492 to 1.82882518,1.577483593 to 1.983711212,1.571981796 to 2.447185377,1.702353492 to 2.479917587,1.711616011 to 2.512649797,1.724848181 to 2.544128433,1.740239284
|
||||
"output_port?" at 1.905502123,1.789407242
|
||||
spline -> from 6.03429892,1.412082356 to 6.03429892,1.412082356 to 6.01469928,1.420209036 to 5.9946216,1.427714264 to 5.9755,1.43412 to 5.56247344,1.571030656 to 5.44869992,1.583650912 to 5.01607372,1.626674512 to 4.690146048,1.65903782 to 4.606536852,1.636187508 to 4.279127256,1.626674512 to 2.80920206,1.583842128 to 2.396749148,1.813492544 to 0.976014268,1.43412 to 0.956271216,1.42886156 to 0.936289144,1.421882176 to 0.916689504,1.413898908
|
||||
"select_src_port*" at 4.647600488,1.613385
|
||||
linethick = 0.5;
|
||||
spline -> from 1.066861117,1.739821426 to 1.066861117,1.739821426 to 1.126266596,1.618155105 to 1.224115011,1.465428006 to 1.363818869,1.39286 to 1.791148317,1.171047045 to 2.022641649,1.165684534 to 2.447185377,1.39286 to 2.583616014,1.465915507 to 2.675823346,1.618572963 to 2.730910959,1.740169641
|
||||
"select_dst_port*" at 1.905502123,1.47991375
|
||||
spline -> from 6.03429892,1.412082356 to 6.03429892,1.412082356 to 6.01469928,1.420209036 to 5.9946216,1.427714264 to 5.9755,1.43412 to 5.56247344,1.571030656 to 5.44869992,1.583650912 to 5.01607372,1.626674512 to 4.690146048,1.65903782 to 4.606536852,1.636187508 to 4.279127256,1.626674512 to 2.80920206,1.583842128 to 2.396749148,1.813492544 to 0.976014268,1.43412 to 0.956271216,1.42886156 to 0.936289144,1.421882176 to 0.916689504,1.413898908
|
||||
"output_port?" at 4.647600488,1.613385
|
||||
linethick = 0.5;
|
||||
spline -> from 6.03429892,1.412082356 to 6.03429892,1.412082356 to 6.01469928,1.420209036 to 5.9946216,1.427714264 to 5.9755,1.43412 to 5.56247344,1.571030656 to 5.44869992,1.583650912 to 5.01607372,1.626674512 to 4.690146048,1.65903782 to 4.606536852,1.636187508 to 4.279127256,1.626674512 to 2.80920206,1.583842128 to 2.396749148,1.813492544 to 0.976014268,1.43412 to 0.956271216,1.42886156 to 0.936289144,1.421882176 to 0.916689504,1.413898908
|
||||
"select_dst_port*" at 4.647600488,1.613385
|
||||
linethick = 1;
|
||||
spline -> from 2.682021573,1.738149994 to 2.682021573,1.738149994 to 2.646921501,1.683340953 to 2.608269636,1.6226819 to 2.572890992,1.5669675 to 2.49948727,1.451151191 to 2.417238887,1.320570566 to 2.353376256,1.218961429
|
||||
"qos?" at 2.722832371,1.47991375
|
||||
spline -> from 0.659121552,1.193092232 to 0.659121552,1.193092232 to 0.63507614,1.155470484 to 0.60854492,1.1138332 to 0.584260488,1.07559 to 0.533827268,0.996091948 to 0.4774089872,0.906459448 to 0.43358228,0.836713412
|
||||
"qos?" at 0.6871825,1.015835
|
||||
linethick = 1;
|
||||
spline -> from 2.848259414,1.73898571 to 2.848259414,1.73898571 to 2.893527364,1.587999686 to 2.958504283,1.371479599 to 3.003772233,1.220563218
|
||||
"interfaces+" at 3.337083631,1.47991375
|
||||
spline -> from 0.773277504,1.19366588 to 0.773277504,1.19366588 to 0.804350104,1.090026808 to 0.848951236,0.941404172 to 0.880023836,0.837812904
|
||||
"interfaces+" at 1.108765976,1.015835
|
||||
linethick = 1;
|
||||
spline -> from 2.244036746,0.86844821 to 2.244036746,0.86844821 to 2.244036746,0.717462186 to 2.244036746,0.5009699562 to 2.244036746,0.3500117894
|
||||
"queues value*" at 2.727707381,0.60937625
|
||||
spline -> from 0.35853,0.59611588 to 0.35853,0.59611588 to 0.35853,0.492476808 to 0.35853,0.3438732936 to 0.35853,0.2402533432
|
||||
"queues value*" at 0.690480976,0.418285
|
||||
linethick = 1;
|
||||
spline -> from 3.657511074,3.480617854 to 3.657511074,3.480617854 to 3.582018062,3.433121328 to 3.509171484,3.375735496 to 3.453108869,3.3080425 to 3.370999772,3.208801225 to 3.324478248,3.070350941 to 3.298849624,2.960941788
|
||||
"bridges*" at 3.733630873,3.22098875
|
||||
spline -> from 0.877346812,2.38876588 to 0.877346812,2.38876588 to 1.043226692,2.285126808 to 1.280955984,2.136504172 to 1.446740256,2.032912904
|
||||
"bridge" at 1.390952988,2.210935
|
||||
linethick = 1;
|
||||
spline -> from 4.052804742,3.48006071 to 4.052804742,3.48006071 to 4.052804742,3.329074686 to 4.052804742,3.112554599 to 4.052804742,2.961638218
|
||||
"ssl?" at 4.173774633,3.22098875
|
||||
spline -> from 0.640764816,2.38852686 to 0.640764816,2.38852686 to 0.559115584,2.158876444 to 0.3827570672,1.66286214 to 0.3015046084,1.434311216
|
||||
"ipfix?" at 0.640717012,1.91216
|
||||
linethick = 1;
|
||||
spline -> from 4.215281861,3.48006071 to 4.215281861,3.48006071 to 4.354567861,3.329074686 to 4.554234342,3.112554599 to 4.693450699,2.961638218
|
||||
"manager_options*" at 5.140976617,3.22098875
|
||||
spline -> from 1.906375716,2.389148312 to 1.906375716,2.389148312 to 1.85455618,2.356545984 to 1.804553196,2.317155488 to 1.766070976,2.27069 to 1.70971006,2.2025693 to 1.677776988,2.107534948 to 1.660185116,2.032434864
|
||||
"bridges*" at 1.958625488,2.210935
|
||||
linethick = 1;
|
||||
spline -> from 2.177759024,2.38876588 to 2.177759024,2.38876588 to 2.177759024,2.285126808 to 2.177759024,2.136504172 to 2.177759024,2.032912904
|
||||
"ssl?" at 2.260746768,2.210935
|
||||
linethick = 1;
|
||||
spline -> from 2.289237952,2.38876588 to 2.289237952,2.38876588 to 2.384845952,2.285126808 to 2.52190002,2.136504172 to 2.617460216,2.032912904
|
||||
"manager_options*" at 2.924696524,2.210935
|
||||
.PE
|
||||
|
@ -340,7 +340,11 @@
|
||||
</column>
|
||||
|
||||
<column name="sflow">
|
||||
sFlow configuration.
|
||||
sFlow(R) configuration.
|
||||
</column>
|
||||
|
||||
<column name="ipfix">
|
||||
IPFIX configuration.
|
||||
</column>
|
||||
|
||||
<column name="flood_vlans">
|
||||
@ -3129,8 +3133,8 @@
|
||||
</table>
|
||||
|
||||
<table name="sFlow">
|
||||
<p>An sFlow(R) target. sFlow is a protocol for remote monitoring
|
||||
of switches.</p>
|
||||
<p>A set of sFlow(R) targets. sFlow is a protocol for remote
|
||||
monitoring of switches.</p>
|
||||
|
||||
<column name="agent">
|
||||
Name of the network device whose IP address should be reported as the
|
||||
@ -3171,4 +3175,75 @@
|
||||
</group>
|
||||
</table>
|
||||
|
||||
<table name="IPFIX">
|
||||
<p>A set of IPFIX collectors. IPFIX is a protocol that exports a
|
||||
number of details about flows.</p>
|
||||
|
||||
<column name="targets">
|
||||
IPFIX target collectors in the form
|
||||
<code><var>ip</var>:<var>port</var></code>.
|
||||
</column>
|
||||
|
||||
<column name="sampling">
|
||||
For per-bridge packet sampling, i.e. when this row is referenced
|
||||
from a <ref table="Bridge"/>, the rate at which packets should
|
||||
be sampled and sent to each target collector. If not specified,
|
||||
defaults to 400, which means one out of 400 packets, on average,
|
||||
will be sent to each target collector. Ignored for per-flow
|
||||
sampling, i.e. when this row is referenced from a <ref
|
||||
table="Flow_Sample_Collector_Set"/>.
|
||||
</column>
|
||||
|
||||
<column name="obs_domain_id">
|
||||
For per-bridge packet sampling, i.e. when this row is referenced
|
||||
from a <ref table="Bridge"/>, the IPFIX Observation Domain ID
|
||||
sent in each IPFIX packet. If not specified, defaults to 0.
|
||||
Ignored for per-flow sampling, i.e. when this row is referenced
|
||||
from a <ref table="Flow_Sample_Collector_Set"/>.
|
||||
</column>
|
||||
|
||||
<column name="obs_point_id">
|
||||
For per-bridge packet sampling, i.e. when this row is referenced
|
||||
from a <ref table="Bridge"/>, the IPFIX Observation Point ID
|
||||
sent in each IPFIX flow record. If not specified, defaults to
|
||||
0. Ignored for per-flow sampling, i.e. when this row is
|
||||
referenced from a <ref table="Flow_Sample_Collector_Set"/>.
|
||||
</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>
|
||||
|
||||
<table name="Flow_Sample_Collector_Set">
|
||||
<p>A set of IPFIX collectors of packet samples generated by
|
||||
OpenFlow <code>sample</code> actions.</p>
|
||||
|
||||
<column name="id">
|
||||
The ID of this collector set, unique among the bridge's
|
||||
collector sets, to be used as the <code>collector_set_id</code>
|
||||
in OpenFlow <code>sample</code> actions.
|
||||
</column>
|
||||
|
||||
<column name="bridge">
|
||||
The bridge into which OpenFlow <code>sample</code> actions can
|
||||
be added to send packet samples to this set of IPFIX collectors.
|
||||
</column>
|
||||
|
||||
<column name="ipfix">
|
||||
Configuration of the set of IPFIX collectors to send one flow
|
||||
record per sampled packet to.
|
||||
</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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user