mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 14:25:26 +00:00
ofproto: Break apart into generic and hardware-specific parts.
In addition to the changes to ofproto, this commit changes all of the instances of "struct flow" in the tree so that the "in_port" member is an OpenFlow port number. Previously, this member was an OpenFlow port number in some cases and an ODP port number in other cases.
This commit is contained in:
326
PORTING
326
PORTING
@@ -7,6 +7,7 @@ are most likely to be necessary in porting OVS to Unix-like platforms.
|
||||
(Porting OVS to other kinds of platforms is likely to be more
|
||||
difficult.)
|
||||
|
||||
|
||||
Vocabulary
|
||||
----------
|
||||
|
||||
@@ -26,164 +27,65 @@ is a concordance, indexed by the area of the source tree:
|
||||
Open vSwitch Architectural Overview
|
||||
-----------------------------------
|
||||
|
||||
The following diagram shows the conceptual architecture of Open
|
||||
The following diagram shows the very high-level architecture of Open
|
||||
vSwitch from a porter's perspective.
|
||||
_ _
|
||||
| +-------------------+ |
|
||||
| | ovs-vswitchd | |Generic
|
||||
| +-------------------+ |code
|
||||
userspace | | ofproto | _|
|
||||
| +---------+---------+ _
|
||||
| | netdev |dpif/wdp | |
|
||||
|_ +---||----+----||---+ |Code that
|
||||
_ || || |may need
|
||||
| +---||-----+---||---+ |porting
|
||||
| | |datapath| _|
|
||||
kernel | | +--------+
|
||||
| | |
|
||||
|_ +-------||----------+
|
||||
||
|
||||
physical
|
||||
NIC
|
||||
|
||||
Some of the components are generic. Modulo bugs, these components
|
||||
should not need to be modified as part of a port:
|
||||
+-------------------+
|
||||
| ovs-vswitchd |<-->ovsdb-server
|
||||
+-------------------+
|
||||
| ofproto |<-->OpenFlow controllers
|
||||
+--------+-+--------+
|
||||
| netdev | | ofproto|
|
||||
+--------+ |provider|
|
||||
| netdev | +--------+
|
||||
|provider|
|
||||
+--------+
|
||||
|
||||
- Near the top of the diagram, "ofproto" is the library in Open vSwitch
|
||||
that contains the core OpenFlow protocol implementation and switching
|
||||
functionality. It is built from source files in the "ofproto"
|
||||
directory.
|
||||
Some of the components are generic. Modulo bugs or inadequacies,
|
||||
these components should not need to be modified as part of a port:
|
||||
|
||||
- Above ofproto, "ovs-vswitchd", the main Open vSwitch userspace
|
||||
program, is the primary client for ofproto. It is built
|
||||
from source files in the "vswitchd" directory of the Open
|
||||
vSwitch distribution.
|
||||
- "ovs-vswitchd" is the main Open vSwitch userspace program, in
|
||||
vswitchd/. It reads the desired Open vSwitch configuration from
|
||||
the ovsdb-server program over an IPC channel and passes this
|
||||
configuration down to the "ofproto" library. It also passes
|
||||
certain status and statistical information from ofproto back
|
||||
into the database.
|
||||
|
||||
ovs-vswitchd is the most sophisticated of ofproto's clients, but
|
||||
ofproto can have other clients as well. Notably, ovs-openflowd,
|
||||
in the utilities directory, is much simpler (though less
|
||||
capable) than ovs-vswitchd, and it may be easier to get up and
|
||||
running as part of a port.
|
||||
- "ofproto" is the Open vSwitch library, in ofproto/, that
|
||||
implements an OpenFlow switch. It talks to OpenFlow controllers
|
||||
over the network and to switch hardware or software to an
|
||||
"ofproto provider", explained further below.
|
||||
|
||||
The other components require attention during a port:
|
||||
- "netdev" is the Open vSwitch library, in lib/netdev.c, that
|
||||
abstracts interacting with network devices, that is, Ethernet
|
||||
interfaces. The netdev library is a thin layer over "netdev
|
||||
provider" code, explained further below.
|
||||
|
||||
- "dpif" or "wdp" is what ofproto uses to directly monitor and
|
||||
control a "datapath", which is the term used in OVS for a
|
||||
collection of physical or virtual ports that are exposed over
|
||||
OpenFlow as a single switch. A datapath implements a flow
|
||||
table.
|
||||
|
||||
- "netdev" is the interface to "network devices", e.g. eth0 on
|
||||
Linux. ofproto expects that every port exposed by a datapath
|
||||
has a corresponding netdev that it can open with netdev_open().
|
||||
The other components may need attention during a port. You will
|
||||
almost certainly have to implement a "netdev provider". Depending on
|
||||
the type of port you are doing and the desired performance, you may
|
||||
also have to implement an "ofproto provider" or a lower-level
|
||||
component called a "dpif" provider.
|
||||
|
||||
The following sections talk about these components in more detail.
|
||||
|
||||
Which Branch?
|
||||
-------------
|
||||
|
||||
The architectural diagram shows "dpif" and "wdp" as alternatives.
|
||||
These alternatives correspond to the "master" and "wdp" branches,
|
||||
respectively, of the Open vSwitch Git repository at
|
||||
git://openvswitch.org/openvswitch. Both of these branches currently
|
||||
represent reasonable porting targets for different purposes:
|
||||
Writing a netdev Provider
|
||||
-------------------------
|
||||
|
||||
- The "master" branch is more mature and better tested. Open
|
||||
vSwitch releases are made from this branch, and most OVS
|
||||
development and testing occurs on this branch.
|
||||
A "netdev provider" implements an operating system and hardware
|
||||
specific interface to "network devices", e.g. eth0 on Linux. Open
|
||||
vSwitch must be able to open each port on a switch as a netdev, so you
|
||||
will need to implement a "netdev provider" that works with your switch
|
||||
hardware and software.
|
||||
|
||||
- The "wdp" branch has a software architecture that can take
|
||||
advantage of hardware with support for wildcards (e.g. TCAMs or
|
||||
similar). This branch has known important bugs, but is the basis
|
||||
of a few ongoing hardware projects, so we expect the quality to
|
||||
improve rapidly.
|
||||
struct netdev_class, in lib/netdev-provider.h, defines the interfaces
|
||||
required to implement a netdev. That structure contains many function
|
||||
pointers, each of which has a comment that is meant to describe its
|
||||
behavior in detail. If the requirements are unclear, please report
|
||||
this as a bug.
|
||||
|
||||
Since its architecture is better, in the medium to long term we will
|
||||
fix the problems in the "wdp" branch and merge it into "master".
|
||||
|
||||
In porting OVS, the major difference between the two branches is the
|
||||
form of the flow table in the datapath:
|
||||
|
||||
- On "master", the "dpif" datapath interface maintains a simple
|
||||
flow table, one that does not support any kind of wildcards.
|
||||
This flow table essentially acts as a cache. When a packet
|
||||
arrives on an interface, the datapath looks for it in this
|
||||
exact-match table. If there is a match, then it performs the
|
||||
associated actions. If there is no match, the datapath passes
|
||||
the packet up to "ofproto", which maintains a flow table that
|
||||
supports wildcards. If the packet matches in this flow table,
|
||||
then ofproto executes its actions and inserts a new exact-match
|
||||
entry into the dpif flow table. (Otherwise, ofproto sends the
|
||||
packet to the OpenFlow controller, if one is configured.)
|
||||
|
||||
Thus, on the "master" branch, the datapath has little
|
||||
opportunity to take advantage of hardware support for wildcards,
|
||||
since it is only ever presented with exact-match flow entries.
|
||||
|
||||
- On "wdp", the "wdp" datapath interface maintains a flow table
|
||||
similar to that of OpenFlow, one that supports wildcards. Thus,
|
||||
a wdp datapath can take advantage of hardware support for
|
||||
wildcards, since it is free to implement the flow table any way
|
||||
it likes.
|
||||
|
||||
The following sections describe the two datapath interfaces in a
|
||||
little more detail.
|
||||
|
||||
dpif: The "master" Branch Datapath
|
||||
----------------------------------
|
||||
|
||||
struct dpif_class, in lib/dpif-provider.h, defines the
|
||||
interfaces required to implement a dpif for new hardware or
|
||||
software. That structure contains many function pointers, each
|
||||
of which has a comment that is meant to describe its behavior in
|
||||
detail. If the requirements are unclear, please report this as
|
||||
a bug and we will clarify.
|
||||
|
||||
There are two existing dpif implementations that may serve as
|
||||
useful examples during a port:
|
||||
|
||||
* lib/dpif-linux.c is a Linux-specific dpif implementation that
|
||||
talks to an Open vSwitch-specific kernel module (whose sources
|
||||
are in the "datapath" directory). The kernel module performs
|
||||
all of the switching work, passing packets that do not match any
|
||||
flow table entry up to userspace. This dpif implementation is
|
||||
essentially a wrapper around calls to "ioctl".
|
||||
|
||||
* lib/dpif-netdev.c is a generic dpif implementation that performs
|
||||
all switching internally. It delegates most of its work to the
|
||||
"netdev" library (described below). Using dpif-netdev, instead
|
||||
of writing a new dpif, can be a simple way to get OVS up and
|
||||
running on new platforms, but other solutions are likely to
|
||||
yield higher performance.
|
||||
|
||||
"wdp": The "wdp" Branch Datapath
|
||||
--------------------------------
|
||||
|
||||
struct wdp_class, in ofproto/wdp-provider.h, defines the interfaces
|
||||
required to implement a wdp ("wildcarded datapath") for new hardware
|
||||
or software. That structure contains many function pointers, each of
|
||||
which has a comment that is meant to describe its behavior in detail.
|
||||
If the requirements are unclear, please report this as a bug and we
|
||||
will clarify.
|
||||
|
||||
The wdp interface is preliminary. Please let us know if it seems
|
||||
unsuitable for your purpose. We will try to improve it.
|
||||
|
||||
There is currently only one wdp implementation:
|
||||
|
||||
* ofproto/wdp-xflow.c is an adaptation of "master" branch code
|
||||
that breaks wildcarded flows up into exact-match flows in the
|
||||
same way that ofproto always does on the "master" branch. It
|
||||
delegates its work to exact-match datapath implementations whose
|
||||
interfaces are identical to "master" branch datapaths, except
|
||||
that names have been changed from "dpif" to "xfif" ("exact-match
|
||||
flow interface") and similar.
|
||||
|
||||
"netdev": Interface to network devices
|
||||
--------------------------------------
|
||||
|
||||
The netdev interface can be roughly divided into functionality for the
|
||||
following purposes:
|
||||
The netdev interface can be divided into a few rough categories:
|
||||
|
||||
* Functions required to properly implement OpenFlow features. For
|
||||
example, OpenFlow requires the ability to report the Ethernet
|
||||
@@ -196,15 +98,9 @@ following purposes:
|
||||
table. These functions must be implemented if the corresponding
|
||||
OVS features are to work, but may be omitted initially.
|
||||
|
||||
* Functions that may be needed in some implementations but not
|
||||
others. The dpif-netdev described above, for example, needs to
|
||||
be able to send and receive packets on a netdev.
|
||||
|
||||
struct netdev_class, in lib/netdev-provider.h, defines the interfaces
|
||||
required to implement a netdev. That structure contains many function
|
||||
pointers, each of which has a comment that is meant to describe its
|
||||
behavior in detail. If the requirements are unclear, please report
|
||||
this as a bug and we will clarify.
|
||||
* Functions needed in some implementations but not in others. For
|
||||
example, most kinds of ports (see below) do not need
|
||||
functionality to receive packets from a network device.
|
||||
|
||||
The existing netdev implementations may serve as useful examples
|
||||
during a port:
|
||||
@@ -218,9 +114,132 @@ during a port:
|
||||
kernel. This may serve as a model for minimal netdev
|
||||
implementations.
|
||||
|
||||
* lib/netdev-dummy.c is a fake netdev implementation useful only
|
||||
for testing.
|
||||
|
||||
|
||||
Porting Strategies
|
||||
------------------
|
||||
|
||||
After a netdev provider has been implemented for a system's network
|
||||
devices, you may choose among three basic porting strategies.
|
||||
|
||||
The lowest-effort strategy is to use the "userspace switch"
|
||||
implementation built into Open vSwitch. This ought to work, without
|
||||
writing any more code, as long as the netdev provider that you
|
||||
implemented supports receiving packets. It yields poor performance,
|
||||
however, because every packet passes through the ovs-vswitchd process.
|
||||
See INSTALL.userspace for instructions on how to configure a userspace
|
||||
switch.
|
||||
|
||||
If the userspace switch is not the right choice for your port, then
|
||||
you will have to write more code. You may implement either an
|
||||
"ofproto provider" or a "dpif provider". Which you should choose
|
||||
depends on a few different factors:
|
||||
|
||||
* Only an ofproto provider can take full advantage of hardware
|
||||
with built-in support for wildcards (e.g. an ACL table or a
|
||||
TCAM).
|
||||
|
||||
* A dpif provider can take advantage of the Open vSwitch built-in
|
||||
implementations of bonding, LACP, 802.1ag, 802.1Q VLANs, and
|
||||
other features. An ofproto provider has to provide its own
|
||||
implementations, if the hardware can support them at all.
|
||||
|
||||
* A dpif provider is usually easier to implement.
|
||||
|
||||
The following sections describe how to implement each kind of port.
|
||||
|
||||
|
||||
ofproto Providers
|
||||
-----------------
|
||||
|
||||
An "ofproto provider" is what ofproto uses to directly monitor and
|
||||
control an OpenFlow-capable switch. struct ofproto_class, in
|
||||
ofproto/private.h, defines the interfaces to implement a ofproto
|
||||
provider for new hardware or software. That structure contains many
|
||||
function pointers, each of which has a comment that is meant to
|
||||
describe its behavior in detail. If the requirements are unclear,
|
||||
please report this as a bug.
|
||||
|
||||
The ofproto provider interface is preliminary. Please let us know if
|
||||
it seems unsuitable for your purpose. We will try to improve it.
|
||||
|
||||
|
||||
Writing a dpif Provider
|
||||
-----------------------
|
||||
|
||||
Open vSwitch has a built-in ofproto provider named "ofproto-dpif",
|
||||
which is built on top of a library for manipulating datapaths, called
|
||||
"dpif". A "datapath" is a simple flow table, one that supports only
|
||||
exact-match flows, that is, flows without wildcards. When a packet
|
||||
arrives on a network device, the datapath looks for it in this
|
||||
exact-match table. If there is a match, then it performs the
|
||||
associated actions. If there is no match, the datapath passes the
|
||||
packet up to ofproto-dpif, which maintains an OpenFlow flow table
|
||||
(that supports wildcards). If the packet matches in this flow table,
|
||||
then ofproto-dpif executes its actions and inserts a new exact-match
|
||||
entry into the dpif flow table. (Otherwise, ofproto-dpif passes the
|
||||
packet up to ofproto to send the packet to the OpenFlow controller, if
|
||||
one is configured.)
|
||||
|
||||
The "dpif" library in turn delegates much of its functionality to a
|
||||
"dpif provider". The following diagram shows how dpif providers fit
|
||||
into the Open vSwitch architecture:
|
||||
|
||||
_
|
||||
| +-------------------+
|
||||
| | ovs-vswitchd |<-->ovsdb-server
|
||||
| +-------------------+
|
||||
| | ofproto |<-->OpenFlow controllers
|
||||
| +--------+-+--------+
|
||||
| | netdev | |ofproto-|
|
||||
userspace | +--------+ | dpif |
|
||||
| | netdev | +--------+
|
||||
| |provider| | dpif |
|
||||
| +---||---+ +--------+
|
||||
| || | dpif |
|
||||
| || |provider|
|
||||
|_ || +---||---+
|
||||
|| ||
|
||||
_ +---||-----+---||---+
|
||||
| | |datapath|
|
||||
kernel | | +--------+
|
||||
| | |
|
||||
|_ +--------||---------+
|
||||
||
|
||||
physical
|
||||
NIC
|
||||
|
||||
struct dpif_class, in lib/dpif-provider.h, defines the interfaces
|
||||
required to implement a dpif provider for new hardware or software.
|
||||
That structure contains many function pointers, each of which has a
|
||||
comment that is meant to describe its behavior in detail. If the
|
||||
requirements are unclear, please report this as a bug.
|
||||
|
||||
There are two existing dpif implementations that may serve as
|
||||
useful examples during a port:
|
||||
|
||||
* lib/dpif-linux.c is a Linux-specific dpif implementation that
|
||||
talks to an Open vSwitch-specific kernel module (whose sources
|
||||
are in the "datapath" directory). The kernel module performs
|
||||
all of the switching work, passing packets that do not match any
|
||||
flow table entry up to userspace. This dpif implementation is
|
||||
essentially a wrapper around calls into the kernel module.
|
||||
|
||||
* lib/dpif-netdev.c is a generic dpif implementation that performs
|
||||
all switching internally. This is how the Open vSwitch
|
||||
userspace switch is implemented.
|
||||
|
||||
|
||||
Miscellaneous Notes
|
||||
-------------------
|
||||
|
||||
ovs-vswitchd is the most sophisticated of ofproto's clients, but
|
||||
ofproto can have other clients as well. ovs-openflowd, in the
|
||||
utilities directory, is much simpler than ovs-vswitchd. It may be
|
||||
easier to initially bring up ovs-openflowd as part of a port.
|
||||
|
||||
lib/entropy.c assumes that it can obtain high-quality random number
|
||||
seeds at startup by reading from /dev/urandom. You will need to
|
||||
modify it if this is not true on your platform.
|
||||
@@ -228,6 +247,7 @@ modify it if this is not true on your platform.
|
||||
vswitchd/system-stats.c only knows how to obtain some statistics on
|
||||
Linux. Optionally you may implement them for your platform as well.
|
||||
|
||||
|
||||
Questions
|
||||
---------
|
||||
|
||||
|
@@ -142,10 +142,10 @@ cls_rule_set_tun_id_masked(struct cls_rule *rule,
|
||||
}
|
||||
|
||||
void
|
||||
cls_rule_set_in_port(struct cls_rule *rule, uint16_t odp_port)
|
||||
cls_rule_set_in_port(struct cls_rule *rule, uint16_t ofp_port)
|
||||
{
|
||||
rule->wc.wildcards &= ~FWW_IN_PORT;
|
||||
rule->flow.in_port = odp_port;
|
||||
rule->flow.in_port = ofp_port;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -506,8 +506,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
|
||||
break;
|
||||
}
|
||||
if (!(w & FWW_IN_PORT)) {
|
||||
ds_put_format(s, "in_port=%"PRIu16",",
|
||||
odp_port_to_ofp_port(f->in_port));
|
||||
ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
|
||||
}
|
||||
if (wc->vlan_tci_mask) {
|
||||
ovs_be16 vid_mask = wc->vlan_tci_mask & htons(VLAN_VID_MASK);
|
||||
|
@@ -306,7 +306,7 @@ invalid:
|
||||
|
||||
}
|
||||
|
||||
/* Initializes 'flow' members from 'packet', 'tun_id', and 'in_port.
|
||||
/* Initializes 'flow' members from 'packet', 'tun_id', and 'ofp_in_port'.
|
||||
* Initializes 'packet' header pointers as follows:
|
||||
*
|
||||
* - packet->l2 to the start of the Ethernet header.
|
||||
@@ -322,7 +322,7 @@ invalid:
|
||||
* present and has a correct length, and otherwise NULL.
|
||||
*/
|
||||
int
|
||||
flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t in_port,
|
||||
flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t ofp_in_port,
|
||||
struct flow *flow)
|
||||
{
|
||||
struct ofpbuf b = *packet;
|
||||
@@ -333,7 +333,7 @@ flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t in_port,
|
||||
|
||||
memset(flow, 0, sizeof *flow);
|
||||
flow->tun_id = tun_id;
|
||||
flow->in_port = in_port;
|
||||
flow->in_port = ofp_in_port;
|
||||
|
||||
packet->l2 = b.data;
|
||||
packet->l3 = NULL;
|
||||
|
@@ -45,7 +45,7 @@ struct flow {
|
||||
uint32_t regs[FLOW_N_REGS]; /* Registers. */
|
||||
ovs_be32 nw_src; /* IPv4 source address. */
|
||||
ovs_be32 nw_dst; /* IPv4 destination address. */
|
||||
uint16_t in_port; /* Input switch port. */
|
||||
uint16_t in_port; /* OpenFlow port number of input port. */
|
||||
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
|
||||
ovs_be16 dl_type; /* Ethernet frame type. */
|
||||
ovs_be16 tp_src; /* TCP/UDP source port. */
|
||||
|
@@ -176,9 +176,6 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
|
||||
/* Metadata. */
|
||||
case NFI_NXM_OF_IN_PORT:
|
||||
flow->in_port = ntohs(get_unaligned_be16(value));
|
||||
if (flow->in_port == OFPP_LOCAL) {
|
||||
flow->in_port = ODPP_LOCAL;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* Ethernet header. */
|
||||
@@ -739,9 +736,6 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
|
||||
/* Metadata. */
|
||||
if (!(wc & FWW_IN_PORT)) {
|
||||
uint16_t in_port = flow->in_port;
|
||||
if (in_port == ODPP_LOCAL) {
|
||||
in_port = OFPP_LOCAL;
|
||||
}
|
||||
nxm_put_16(b, NXM_OF_IN_PORT, htons(in_port));
|
||||
}
|
||||
|
||||
@@ -1272,7 +1266,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
|
||||
{
|
||||
switch (src->index) {
|
||||
case NFI_NXM_OF_IN_PORT:
|
||||
return flow->in_port == ODPP_LOCAL ? OFPP_LOCAL : flow->in_port;
|
||||
return flow->in_port;
|
||||
|
||||
case NFI_NXM_OF_ETH_DST:
|
||||
return eth_addr_to_uint64(flow->dl_dst);
|
||||
|
@@ -403,7 +403,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
|
||||
nl_msg_put_be64(buf, ODP_KEY_ATTR_TUN_ID, flow->tun_id);
|
||||
}
|
||||
|
||||
nl_msg_put_u32(buf, ODP_KEY_ATTR_IN_PORT, flow->in_port);
|
||||
nl_msg_put_u32(buf, ODP_KEY_ATTR_IN_PORT,
|
||||
ofp_port_to_odp_port(flow->in_port));
|
||||
|
||||
eth_key = nl_msg_put_unspec_uninit(buf, ODP_KEY_ATTR_ETHERNET,
|
||||
sizeof *eth_key);
|
||||
@@ -551,7 +552,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
|
||||
if (nl_attr_get_u32(nla) >= UINT16_MAX) {
|
||||
return EINVAL;
|
||||
}
|
||||
flow->in_port = nl_attr_get_u32(nla);
|
||||
flow->in_port = odp_port_to_ofp_port(nl_attr_get_u32(nla));
|
||||
break;
|
||||
|
||||
case TRANSITION(ODP_KEY_ATTR_IN_PORT, ODP_KEY_ATTR_ETHERNET):
|
||||
|
@@ -608,9 +608,6 @@ parse_field_value(struct cls_rule *rule, enum field_index index,
|
||||
if (!parse_port_name(value, &port_no)) {
|
||||
port_no = atoi(value);
|
||||
}
|
||||
if (port_no == OFPP_LOCAL) {
|
||||
port_no = ODPP_LOCAL;
|
||||
}
|
||||
cls_rule_set_in_port(rule, port_no);
|
||||
break;
|
||||
|
||||
|
@@ -150,8 +150,7 @@ ofputil_cls_rule_from_match(const struct ofp_match *match,
|
||||
/* Initialize most of rule->flow. */
|
||||
rule->flow.nw_src = match->nw_src;
|
||||
rule->flow.nw_dst = match->nw_dst;
|
||||
rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
|
||||
: ntohs(match->in_port));
|
||||
rule->flow.in_port = ntohs(match->in_port);
|
||||
rule->flow.dl_type = ofputil_dl_type_from_openflow(match->dl_type);
|
||||
rule->flow.tp_src = match->tp_src;
|
||||
rule->flow.tp_dst = match->tp_dst;
|
||||
@@ -272,8 +271,7 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule,
|
||||
|
||||
/* Compose most of the match structure. */
|
||||
match->wildcards = htonl(ofpfw);
|
||||
match->in_port = htons(rule->flow.in_port == ODPP_LOCAL ? OFPP_LOCAL
|
||||
: rule->flow.in_port);
|
||||
match->in_port = htons(rule->flow.in_port);
|
||||
memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
|
||||
memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
|
||||
match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
|
||||
|
@@ -20,6 +20,7 @@ ofproto_libofproto_a_SOURCES = \
|
||||
ofproto/netflow.h \
|
||||
ofproto/ofproto.c \
|
||||
ofproto/ofproto.h \
|
||||
ofproto/ofproto-dpif.c \
|
||||
ofproto/ofproto-sflow.c \
|
||||
ofproto/ofproto-sflow.h \
|
||||
ofproto/pktbuf.c \
|
||||
|
@@ -1036,7 +1036,7 @@ schedule_packet_in(struct ofconn *ofconn, const struct dpif_upcall *upcall,
|
||||
|
||||
/* Figure out the easy parts. */
|
||||
pin.packet = upcall->packet;
|
||||
pin.in_port = odp_port_to_ofp_port(flow->in_port);
|
||||
pin.in_port = flow->in_port;
|
||||
pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION;
|
||||
|
||||
/* Get OpenFlow buffer_id. */
|
||||
|
3888
ofproto/ofproto-dpif.c
Normal file
3888
ofproto/ofproto-dpif.c
Normal file
File diff suppressed because it is too large
Load Diff
4170
ofproto/ofproto.c
4170
ofproto/ofproto.c
File diff suppressed because it is too large
Load Diff
@@ -163,7 +163,7 @@ void ofproto_set_desc(struct ofproto *,
|
||||
int ofproto_set_snoops(struct ofproto *, const struct sset *snoops);
|
||||
int ofproto_set_netflow(struct ofproto *,
|
||||
const struct netflow_options *nf_options);
|
||||
void ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *);
|
||||
int ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *);
|
||||
|
||||
/* Configuration of ports. */
|
||||
|
||||
@@ -192,9 +192,9 @@ struct ofproto_bundle_settings {
|
||||
struct lacp_slave_settings *lacp_slaves; /* Array of n_slaves elements. */
|
||||
};
|
||||
|
||||
void ofproto_bundle_register(struct ofproto *, void *aux,
|
||||
int ofproto_bundle_register(struct ofproto *, void *aux,
|
||||
const struct ofproto_bundle_settings *);
|
||||
void ofproto_bundle_unregister(struct ofproto *, void *aux);
|
||||
int ofproto_bundle_unregister(struct ofproto *, void *aux);
|
||||
|
||||
/* Configuration of mirrors. */
|
||||
struct ofproto_mirror_settings {
|
||||
@@ -217,11 +217,11 @@ struct ofproto_mirror_settings {
|
||||
uint16_t out_vlan; /* Output VLAN, only if out_bundle is NULL. */
|
||||
};
|
||||
|
||||
void ofproto_mirror_register(struct ofproto *, void *aux,
|
||||
int ofproto_mirror_register(struct ofproto *, void *aux,
|
||||
const struct ofproto_mirror_settings *);
|
||||
void ofproto_mirror_unregister(struct ofproto *, void *aux);
|
||||
int ofproto_mirror_unregister(struct ofproto *, void *aux);
|
||||
|
||||
void ofproto_set_flood_vlans(struct ofproto *, unsigned long *flood_vlans);
|
||||
int ofproto_set_flood_vlans(struct ofproto *, unsigned long *flood_vlans);
|
||||
bool ofproto_is_mirror_output_bundle(struct ofproto *, void *aux);
|
||||
|
||||
/* Configuration querying. */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010 Nicira Networks.
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -173,6 +173,11 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
|
||||
struct packet *p;
|
||||
int error;
|
||||
|
||||
if (id == UINT32_MAX) {
|
||||
error = 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!pb) {
|
||||
VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
|
||||
"without buffers");
|
||||
@@ -204,6 +209,7 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
|
||||
"if the switch was recently in fail-open mode)", id);
|
||||
error = 0;
|
||||
}
|
||||
error:
|
||||
*bufferp = NULL;
|
||||
*in_port = UINT16_MAX;
|
||||
return error;
|
||||
|
@@ -20,6 +20,492 @@
|
||||
/* Definitions for use within ofproto. */
|
||||
|
||||
#include "ofproto/ofproto.h"
|
||||
#include "classifier.h"
|
||||
#include "list.h"
|
||||
#include "shash.h"
|
||||
#include "timeval.h"
|
||||
|
||||
/* An OpenFlow switch.
|
||||
*
|
||||
* With few exceptions, ofproto implementations may look at these fields but
|
||||
* should not modify them. */
|
||||
struct ofproto {
|
||||
const struct ofproto_class *ofproto_class;
|
||||
char *type; /* Datapath type. */
|
||||
char *name; /* Datapath name. */
|
||||
struct hmap_node hmap_node; /* In global 'all_ofprotos' hmap. */
|
||||
|
||||
/* Settings. */
|
||||
uint64_t fallback_dpid; /* Datapath ID if no better choice found. */
|
||||
uint64_t datapath_id; /* Datapath ID. */
|
||||
char *mfr_desc; /* Manufacturer. */
|
||||
char *hw_desc; /* Hardware. */
|
||||
char *sw_desc; /* Software version. */
|
||||
char *serial_desc; /* Serial number. */
|
||||
char *dp_desc; /* Datapath description. */
|
||||
|
||||
/* Datapath. */
|
||||
struct netdev_monitor *netdev_monitor;
|
||||
struct hmap ports; /* Contains "struct ofport"s. */
|
||||
struct shash port_by_name;
|
||||
|
||||
/* Flow table. */
|
||||
struct classifier cls; /* Contains "struct rule"s. */
|
||||
|
||||
/* OpenFlow connections. */
|
||||
struct connmgr *connmgr;
|
||||
};
|
||||
|
||||
struct ofproto *ofproto_lookup(const char *name);
|
||||
struct ofport *ofproto_get_port(const struct ofproto *, uint16_t ofp_port);
|
||||
|
||||
/* An OpenFlow port within a "struct ofproto".
|
||||
*
|
||||
* With few exceptions, ofproto implementations may look at these fields but
|
||||
* should not modify them. */
|
||||
struct ofport {
|
||||
struct ofproto *ofproto; /* The ofproto that contains this port. */
|
||||
struct hmap_node hmap_node; /* In struct ofproto's "ports" hmap. */
|
||||
struct netdev *netdev;
|
||||
struct ofp_phy_port opp;
|
||||
uint16_t ofp_port; /* OpenFlow port number. */
|
||||
};
|
||||
|
||||
/* An OpenFlow flow within a "struct ofproto".
|
||||
*
|
||||
* With few exceptions, ofproto implementations may look at these fields but
|
||||
* should not modify them. */
|
||||
struct rule {
|
||||
struct ofproto *ofproto; /* The ofproto that contains this rule. */
|
||||
struct cls_rule cr; /* In owning ofproto's classifier. */
|
||||
|
||||
ovs_be64 flow_cookie; /* Controller-issued identifier. */
|
||||
|
||||
long long int created; /* Creation time. */
|
||||
uint16_t idle_timeout; /* In seconds from time of last use. */
|
||||
uint16_t hard_timeout; /* In seconds from time of creation. */
|
||||
bool send_flow_removed; /* Send a flow removed message? */
|
||||
|
||||
union ofp_action *actions; /* OpenFlow actions. */
|
||||
int n_actions; /* Number of elements in actions[]. */
|
||||
};
|
||||
|
||||
static inline struct rule *
|
||||
rule_from_cls_rule(const struct cls_rule *cls_rule)
|
||||
{
|
||||
return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL;
|
||||
}
|
||||
|
||||
struct rule *ofproto_rule_lookup(struct ofproto *, const struct flow *);
|
||||
void ofproto_rule_expire(struct rule *, uint8_t reason);
|
||||
void ofproto_rule_destroy(struct rule *);
|
||||
|
||||
/* ofproto class structure, to be defined by each ofproto implementation.
|
||||
*
|
||||
*
|
||||
* Data Structures
|
||||
* ===============
|
||||
*
|
||||
* These functions work primarily with three different kinds of data
|
||||
* structures:
|
||||
*
|
||||
* - "struct ofproto", which represents an OpenFlow switch.
|
||||
*
|
||||
* - "struct ofport", which represents a port within an ofproto.
|
||||
*
|
||||
* - "struct rule", which represents an OpenFlow flow within an ofproto.
|
||||
*
|
||||
* Each of these data structures contains all of the implementation-independent
|
||||
* generic state for the respective concept, called the "base" state. None of
|
||||
* them contains any extra space for ofproto implementations to use. Instead,
|
||||
* each implementation is expected to declare its own data structure that
|
||||
* contains an instance of the generic data structure plus additional
|
||||
* implementation-specific members, called the "derived" state. The
|
||||
* implementation can use casts or (preferably) the CONTAINER_OF macro to
|
||||
* obtain access to derived state given only a pointer to the embedded generic
|
||||
* data structure.
|
||||
*
|
||||
*
|
||||
* Life Cycle
|
||||
* ==========
|
||||
*
|
||||
* Four stylized functions accompany each of these data structures:
|
||||
*
|
||||
* "alloc" "construct" "destruct" "dealloc"
|
||||
* ------------ ---------------- --------------- --------------
|
||||
* ofproto ->alloc ->construct ->destruct ->dealloc
|
||||
* ofport ->port_alloc ->port_construct ->port_destruct ->port_dealloc
|
||||
* rule ->rule_alloc ->rule_construct ->rule_destruct ->rule_dealloc
|
||||
*
|
||||
* Any instance of a given data structure goes through the following life
|
||||
* cycle:
|
||||
*
|
||||
* 1. The client calls the "alloc" function to obtain raw memory. If "alloc"
|
||||
* fails, skip all the other steps.
|
||||
*
|
||||
* 2. The client initializes all of the data structure's base state. If this
|
||||
* fails, skip to step 7.
|
||||
*
|
||||
* 3. The client calls the "construct" function. The implementation
|
||||
* initializes derived state. It may refer to the already-initialized
|
||||
* base state. If "construct" fails, skip to step 6.
|
||||
*
|
||||
* 4. The data structure is now initialized and in use.
|
||||
*
|
||||
* 5. When the data structure is no longer needed, the client calls the
|
||||
* "destruct" function. The implementation uninitializes derived state.
|
||||
* The base state has not been uninitialized yet, so the implementation
|
||||
* may still refer to it.
|
||||
*
|
||||
* 6. The client uninitializes all of the data structure's base state.
|
||||
*
|
||||
* 7. The client calls the "dealloc" to free the raw memory. The
|
||||
* implementation must not refer to base or derived state in the data
|
||||
* structure, because it has already been uninitialized.
|
||||
*
|
||||
* Each "alloc" function allocates and returns a new instance of the respective
|
||||
* data structure. The "alloc" function is not given any information about the
|
||||
* use of the new data structure, so it cannot perform much initialization.
|
||||
* Its purpose is just to ensure that the new data structure has enough room
|
||||
* for base and derived state. It may return a null pointer if memory is not
|
||||
* available, in which case none of the other functions is called.
|
||||
*
|
||||
* Each "construct" function initializes derived state in its respective data
|
||||
* structure. When "construct" is called, all of the base state has already
|
||||
* been initialized, so the "construct" function may refer to it. The
|
||||
* "construct" function is allowed to fail, in which case the client calls the
|
||||
* "dealloc" function (but not the "destruct" function).
|
||||
*
|
||||
* Each "destruct" function uninitializes and frees derived state in its
|
||||
* respective data structure. When "destruct" is called, the base state has
|
||||
* not yet been uninitialized, so the "destruct" function may refer to it. The
|
||||
* "destruct" function is not allowed to fail.
|
||||
*
|
||||
* Each "dealloc" function frees raw memory that was allocated by the the
|
||||
* "alloc" function. The memory's base and derived members might not have ever
|
||||
* been initialized (but if "construct" returned successfully, then it has been
|
||||
* "destruct"ed already). The "dealloc" function is not allowed to fail.
|
||||
*
|
||||
*
|
||||
* Conventions
|
||||
* ===========
|
||||
*
|
||||
* Most of these functions return 0 if they are successful or a positive error
|
||||
* code on failure. Depending on the function, valid error codes are either
|
||||
* errno values or OpenFlow error codes constructed with ofp_mkerr().
|
||||
*
|
||||
* Most of these functions are expected to execute synchronously, that is, to
|
||||
* block as necessary to obtain a result. Thus, these functions may return
|
||||
* EAGAIN (or EWOULDBLOCK or EINPROGRESS) only where the function descriptions
|
||||
* explicitly say those errors are a possibility. We may relax this
|
||||
* requirement in the future if and when we encounter performance problems. */
|
||||
struct ofproto_class {
|
||||
/* ## ----------------- ## */
|
||||
/* ## Factory Functions ## */
|
||||
/* ## ----------------- ## */
|
||||
|
||||
void (*enumerate_types)(struct sset *types);
|
||||
int (*enumerate_names)(const char *type, struct sset *names);
|
||||
int (*del)(const char *type, const char *name);
|
||||
|
||||
/* ## --------------------------- ## */
|
||||
/* ## Top-Level ofproto Functions ## */
|
||||
/* ## --------------------------- ## */
|
||||
|
||||
/* Life-cycle functions for an "ofproto" (see "Life Cycle" above).
|
||||
*
|
||||
* ->construct() should not modify any base members of the ofproto, even
|
||||
* though it may be tempting in a few cases. In particular, the client
|
||||
* will initialize the ofproto's 'ports' member after construction is
|
||||
* complete. An ofproto's flow table should be initially empty, so
|
||||
* ->construct() should delete flows from the underlying datapath, if
|
||||
* necessary, rather than populating the ofproto's 'cls'.
|
||||
*
|
||||
* Only one ofproto instance needs to be supported for any given datapath.
|
||||
* If a datapath is already open as part of one "ofproto", then another
|
||||
* attempt to "construct" the same datapath as part of another ofproto is
|
||||
* allowed to fail with an error. */
|
||||
struct ofproto *(*alloc)(void);
|
||||
int (*construct)(struct ofproto *ofproto);
|
||||
void (*destruct)(struct ofproto *ofproto);
|
||||
void (*dealloc)(struct ofproto *ofproto);
|
||||
|
||||
/* Performs any periodic activity required by 'ofproto'. It should:
|
||||
*
|
||||
* - Call connmgr_send_packet_in() for each received packet that missed
|
||||
* in the OpenFlow flow table or that had a OFPP_CONTROLLER output
|
||||
* action.
|
||||
*
|
||||
* - Call ofproto_rule_expire() for each OpenFlow flow that has reached
|
||||
* its hard_timeout or idle_timeout, to expire the flow.
|
||||
*/
|
||||
int (*run)(struct ofproto *ofproto);
|
||||
|
||||
/* Causes the poll loop to wake up when 'ofproto''s 'run' function needs to
|
||||
* be called, e.g. by calling the timer or fd waiting functions in
|
||||
* poll-loop.h. */
|
||||
void (*wait)(struct ofproto *ofproto);
|
||||
|
||||
/* Every "struct rule" in 'ofproto' is about to be deleted, one by one.
|
||||
* This function may prepare for that, for example by clearing state in
|
||||
* advance. It should *not* actually delete any "struct rule"s from
|
||||
* 'ofproto', only prepare for it.
|
||||
*
|
||||
* This function is optional; it's really just for optimization in case
|
||||
* it's cheaper to delete all the flows from your hardware in a single pass
|
||||
* than to do it one by one. */
|
||||
void (*flush)(struct ofproto *ofproto);
|
||||
|
||||
/* ## ---------------- ## */
|
||||
/* ## ofport Functions ## */
|
||||
/* ## ---------------- ## */
|
||||
|
||||
/* Life-cycle functions for a "struct ofport" (see "Life Cycle" above).
|
||||
*
|
||||
* ->port_construct() should not modify any base members of the ofport.
|
||||
*
|
||||
* ofports are managed by the base ofproto code. The ofproto
|
||||
* implementation should only create and destroy them in response to calls
|
||||
* to these functions. The base ofproto code will create and destroy
|
||||
* ofports in the following situations:
|
||||
*
|
||||
* - Just after the ->construct() function is called, the base ofproto
|
||||
* iterates over all of the implementation's ports, using
|
||||
* ->port_dump_start() and related functions, and constructs an ofport
|
||||
* for each dumped port.
|
||||
*
|
||||
* - If ->port_poll() reports that a specific port has changed, then the
|
||||
* base ofproto will query that port with ->port_query_by_name() and
|
||||
* construct or destruct ofports as necessary to reflect the updated
|
||||
* set of ports.
|
||||
*
|
||||
* - If ->port_poll() returns ENOBUFS to report an unspecified port set
|
||||
* change, then the base ofproto will iterate over all of the
|
||||
* implementation's ports, in the same way as at ofproto
|
||||
* initialization, and construct and destruct ofports to reflect all of
|
||||
* the changes.
|
||||
*/
|
||||
struct ofport *(*port_alloc)(void);
|
||||
int (*port_construct)(struct ofport *ofport);
|
||||
void (*port_destruct)(struct ofport *ofport);
|
||||
void (*port_dealloc)(struct ofport *ofport);
|
||||
|
||||
/* Called after 'ofport->netdev' is replaced by a new netdev object. If
|
||||
* the ofproto implementation uses the ofport's netdev internally, then it
|
||||
* should switch to using the new one. The old one has been closed.
|
||||
*
|
||||
* An ofproto implementation that doesn't need to do anything in this
|
||||
* function may use a null pointer. */
|
||||
void (*port_modified)(struct ofport *ofport);
|
||||
|
||||
/* Called after an OpenFlow OFPT_PORT_MOD request changes a port's
|
||||
* configuration. 'ofport->opp.config' contains the new configuration.
|
||||
* 'old_config' contains the previous configuration.
|
||||
*
|
||||
* The caller implements OFPPC_PORT_DOWN using netdev functions to turn
|
||||
* NETDEV_UP on and off, so this function doesn't have to do anything for
|
||||
* that bit (and it won't be called if that is the only bit that
|
||||
* changes). */
|
||||
void (*port_reconfigured)(struct ofport *ofport, ovs_be32 old_config);
|
||||
|
||||
/* Looks up a port named 'devname' in 'ofproto'. On success, initializes
|
||||
* '*port' appropriately.
|
||||
*
|
||||
* The caller owns the data in 'port' and must free it with
|
||||
* ofproto_port_destroy() when it is no longer needed. */
|
||||
int (*port_query_by_name)(const struct ofproto *ofproto,
|
||||
const char *devname, struct ofproto_port *port);
|
||||
|
||||
/* Attempts to add 'netdev' as a port on 'ofproto'. If successful, sets
|
||||
* '*ofp_portp' to the new port's port number. */
|
||||
int (*port_add)(struct ofproto *ofproto, struct netdev *netdev,
|
||||
uint16_t *ofp_portp);
|
||||
|
||||
/* Deletes port number 'ofp_port' from the datapath for 'ofproto'. */
|
||||
int (*port_del)(struct ofproto *ofproto, uint16_t ofp_port);
|
||||
|
||||
/* Attempts to begin dumping the ports in 'ofproto'. On success, returns 0
|
||||
* and initializes '*statep' with any data needed for iteration. On
|
||||
* failure, returns a positive errno value. */
|
||||
int (*port_dump_start)(const struct ofproto *ofproto, void **statep);
|
||||
|
||||
/* Attempts to retrieve another port from 'ofproto' for 'state', which was
|
||||
* initialized by a successful call to the 'port_dump_start' function for
|
||||
* 'ofproto'. On success, stores a new ofproto_port into 'port' and
|
||||
* returns 0. Returns EOF if the end of the port table has been reached,
|
||||
* or a positive errno value on error. This function will not be called
|
||||
* again once it returns nonzero once for a given iteration (but the
|
||||
* 'port_dump_done' function will be called afterward).
|
||||
*
|
||||
* The ofproto provider retains ownership of the data stored in 'port'. It
|
||||
* must remain valid until at least the next call to 'port_dump_next' or
|
||||
* 'port_dump_done' for 'state'. */
|
||||
int (*port_dump_next)(const struct ofproto *ofproto, void *state,
|
||||
struct ofproto_port *port);
|
||||
|
||||
/* Releases resources from 'ofproto' for 'state', which was initialized by
|
||||
* a successful call to the 'port_dump_start' function for 'ofproto'. */
|
||||
int (*port_dump_done)(const struct ofproto *ofproto, void *state);
|
||||
|
||||
/* Polls for changes in the set of ports in 'ofproto'. If the set of ports
|
||||
* in 'ofproto' has changed, then this function should do one of the
|
||||
* following:
|
||||
*
|
||||
* - Preferably: store the name of the device that was added to or deleted
|
||||
* from 'ofproto' in '*devnamep' and return 0. The caller is responsible
|
||||
* for freeing '*devnamep' (with free()) when it no longer needs it.
|
||||
*
|
||||
* - Alternatively: return ENOBUFS, without indicating the device that was
|
||||
* added or deleted.
|
||||
*
|
||||
* Occasional 'false positives', in which the function returns 0 while
|
||||
* indicating a device that was not actually added or deleted or returns
|
||||
* ENOBUFS without any change, are acceptable.
|
||||
*
|
||||
* The purpose of 'port_poll' is to let 'ofproto' know about changes made
|
||||
* externally to the 'ofproto' object, e.g. by a system administrator via
|
||||
* ovs-dpctl. Therefore, it's OK, and even preferable, for port_poll() to
|
||||
* not report changes made through calls to 'port_add' or 'port_del' on the
|
||||
* same 'ofproto' object. (But it's OK for it to report them too, just
|
||||
* slightly less efficient.)
|
||||
*
|
||||
* If the set of ports in 'ofproto' has not changed, returns EAGAIN. May
|
||||
* also return other positive errno values to indicate that something has
|
||||
* gone wrong. */
|
||||
int (*port_poll)(const struct ofproto *ofproto, char **devnamep);
|
||||
|
||||
/* Arranges for the poll loop to wake up when 'port_poll' will return a
|
||||
* value other than EAGAIN. */
|
||||
void (*port_poll_wait)(const struct ofproto *ofproto);
|
||||
|
||||
int (*port_is_lacp_current)(const struct ofport *port);
|
||||
|
||||
struct rule *(*rule_alloc)(void);
|
||||
int (*rule_construct)(struct rule *rule);
|
||||
void (*rule_destruct)(struct rule *rule);
|
||||
void (*rule_dealloc)(struct rule *rule);
|
||||
|
||||
void (*rule_remove)(struct rule *rule);
|
||||
|
||||
void (*rule_get_stats)(struct rule *rule, uint64_t *packet_count,
|
||||
uint64_t *byte_count);
|
||||
|
||||
void (*rule_execute)(struct rule *rule, struct flow *flow,
|
||||
struct ofpbuf *packet);
|
||||
|
||||
int (*rule_modify_actions)(struct rule *rule,
|
||||
const union ofp_action *actions, size_t n);
|
||||
|
||||
bool (*get_drop_frags)(struct ofproto *ofproto);
|
||||
void (*set_drop_frags)(struct ofproto *ofproto, bool drop_frags);
|
||||
|
||||
int (*packet_out)(struct ofproto *ofproto, struct ofpbuf *packet,
|
||||
const struct flow *flow,
|
||||
const union ofp_action *actions,
|
||||
size_t n_actions);
|
||||
|
||||
/* Configures NetFlow on 'ofproto' according to the options in
|
||||
* 'netflow_options', or turns off NetFlow if 'netflow_options' is NULL.
|
||||
*
|
||||
* EOPNOTSUPP as a return value indicates that 'ofproto' does not support
|
||||
* sFlow, as does a null pointer. */
|
||||
int (*set_netflow)(struct ofproto *ofproto,
|
||||
const struct netflow_options *netflow_options);
|
||||
|
||||
void (*get_netflow_ids)(const struct ofproto *ofproto,
|
||||
uint8_t *engine_type, uint8_t *engine_id);
|
||||
|
||||
/* Configures sFlow on 'ofproto' according to the options in
|
||||
* 'sflow_options', or turns off sFlow if 'sflow_options' is NULL.
|
||||
*
|
||||
* EOPNOTSUPP as a return value indicates that 'ofproto' does not support
|
||||
* sFlow, as does a null pointer. */
|
||||
int (*set_sflow)(struct ofproto *ofproto,
|
||||
const struct ofproto_sflow_options *sflow_options);
|
||||
|
||||
/* Configures connectivity fault management on 'ofport'.
|
||||
*
|
||||
* If 'cfm' is nonnull, takes basic configuration from the configuration
|
||||
* members in 'cfm', and the set of remote maintenance points from the
|
||||
* 'n_remote_mps' elements in 'remote_mps'. Ignores the statistics members
|
||||
* of 'cfm'.
|
||||
*
|
||||
* If 'cfm' is null, removes any connectivity fault management
|
||||
* configuration from 'ofport'.
|
||||
*
|
||||
* EOPNOTSUPP as a return value indicates that this ofproto_class does not
|
||||
* support CFM, as does a null pointer. */
|
||||
int (*set_cfm)(struct ofport *ofport, const struct cfm *cfm,
|
||||
const uint16_t *remote_mps, size_t n_remote_mps);
|
||||
|
||||
/* Stores the connectivity fault management object associated with 'ofport'
|
||||
* in '*cfmp'. Stores a null pointer in '*cfmp' if CFM is not configured
|
||||
* on 'ofport'. The caller must not modify or destroy the returned object.
|
||||
*
|
||||
* This function may be NULL if this ofproto_class does not support CFM. */
|
||||
int (*get_cfm)(struct ofport *ofport, const struct cfm **cfmp);
|
||||
|
||||
/* If 's' is nonnull, this function registers a "bundle" associated with
|
||||
* client data pointer 'aux' in 'ofproto'. A bundle is the same concept as
|
||||
* a Port in OVSDB, that is, it consists of one or more "slave" devices
|
||||
* (Interfaces, in OVSDB) along with VLAN and LACP configuration and, if
|
||||
* there is more than one slave, a bonding configuration. If 'aux' is
|
||||
* already registered then this function updates its configuration to 's'.
|
||||
* Otherwise, this function registers a new bundle.
|
||||
*
|
||||
* If 's' is NULL, this function unregisters the bundle registered on
|
||||
* 'ofproto' associated with client data pointer 'aux'. If no such bundle
|
||||
* has been registered, this has no effect.
|
||||
*
|
||||
* This function affects only the behavior of the NXAST_AUTOPATH action and
|
||||
* output to the OFPP_NORMAL port. An implementation that does not support
|
||||
* it at all may set it to NULL or return EOPNOTSUPP. An implementation
|
||||
* that supports only a subset of the functionality should implement what
|
||||
* it can and return 0. */
|
||||
int (*bundle_set)(struct ofproto *ofproto, void *aux,
|
||||
const struct ofproto_bundle_settings *s);
|
||||
|
||||
/* If 'port' is part of any bundle, removes it from that bundle. If the
|
||||
* bundle now has no ports, deletes the bundle. If the bundle now has only
|
||||
* one port, deconfigures the bundle's bonding configuration. */
|
||||
void (*bundle_remove)(struct ofport *ofport);
|
||||
|
||||
/* If 's' is nonnull, this function registers a mirror associated with
|
||||
* client data pointer 'aux' in 'ofproto'. A mirror is the same concept as
|
||||
* a Mirror in OVSDB. If 'aux' is already registered then this function
|
||||
* updates its configuration to 's'. Otherwise, this function registers a
|
||||
* new mirror.
|
||||
*
|
||||
* If 's' is NULL, this function unregisters the mirror registered on
|
||||
* 'ofproto' associated with client data pointer 'aux'. If no such mirror
|
||||
* has been registered, this has no effect.
|
||||
*
|
||||
* This function affects only the behavior of the OFPP_NORMAL action. An
|
||||
* implementation that does not support it at all may set it to NULL or
|
||||
* return EOPNOTSUPP. An implementation that supports only a subset of the
|
||||
* functionality should implement what it can and return 0. */
|
||||
int (*mirror_set)(struct ofproto *ofproto, void *aux,
|
||||
const struct ofproto_mirror_settings *s);
|
||||
|
||||
/* Configures the VLANs whose bits are set to 1 in 'flood_vlans' as VLANs
|
||||
* on which all packets are flooded, instead of using MAC learning. If
|
||||
* 'flood_vlans' is NULL, then MAC learning applies to all VLANs.
|
||||
*
|
||||
* This function affects only the behavior of the OFPP_NORMAL action. An
|
||||
* implementation that does not support it may set it to NULL or return
|
||||
* EOPNOTSUPP. */
|
||||
int (*set_flood_vlans)(struct ofproto *ofproto,
|
||||
unsigned long *flood_vlans);
|
||||
|
||||
/* Returns true if 'aux' is a registered bundle that is currently in use as
|
||||
* the output for a mirror. */
|
||||
bool (*is_mirror_output_bundle)(struct ofproto *ofproto, void *aux);
|
||||
};
|
||||
|
||||
extern const struct ofproto_class ofproto_dpif_class;
|
||||
|
||||
int ofproto_class_register(const struct ofproto_class *);
|
||||
int ofproto_class_unregister(const struct ofproto_class *);
|
||||
|
||||
void ofproto_add_flow(struct ofproto *, const struct cls_rule *,
|
||||
const union ofp_action *, size_t n_actions);
|
||||
|
@@ -7,7 +7,7 @@ m4_define([OFPROTO_START],
|
||||
trap 'kill `cat ovs-openflowd.pid`' 0
|
||||
AT_CAPTURE_FILE([ovs-openflowd.log])
|
||||
AT_CHECK(
|
||||
[ovs-openflowd --detach --pidfile --enable-dummy --log-file dummy@br0 none --datapath-id=fedcba9876543210 $1],
|
||||
[ovs-openflowd --detach --pidfile --enable-dummy --log-file --fail=closed dummy@br0 none --datapath-id=fedcba9876543210 $1],
|
||||
[0], [ignore], [ignore])
|
||||
])
|
||||
|
||||
|
@@ -52,8 +52,8 @@ dnl Tests for a bug in which ofproto ignored tun_id in tun_id_from_cookie
|
||||
dnl flow_mod commands.
|
||||
AT_CHECK([ovs-ofctl add-flow -F tun_id_from_cookie br0 tun_id=1,actions=mod_vlan_vid:4])
|
||||
AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
|
||||
cookie=0x0, duration=?s, table_id=0, n_packets=0, n_bytes=0, in_port=0 actions=output:1
|
||||
cookie=0x0, duration=?s, table_id=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
|
||||
cookie=0x0, duration=?s, table_id=0, n_packets=0, n_bytes=0, in_port=65534 actions=output:1
|
||||
cookie=0x100000000, duration=?s, table_id=0, n_packets=0, n_bytes=0, tun_id=0x1 actions=mod_vlan_vid:4
|
||||
NXST_FLOW reply:
|
||||
])
|
||||
|
@@ -41,17 +41,17 @@ normalization changed ofp_match, details:
|
||||
pre: wildcards= 0x3820f8 in_port=65534 dl_src=00:0a:e4:25:6b:b0 dl_dst=00:00:00:00:00:00 dl_vlan= 9 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3ffff8 in_port=65534 dl_src=00:0a:e4:25:6b:b0 dl_dst=00:00:00:00:00:00 dl_vlan= 9 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
normalization changed ofp_match, details:
|
||||
pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
pre: wildcards= 0x3820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
normalization changed ofp_match, details:
|
||||
pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
pre: wildcards= 0x3820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
normalization changed ofp_match, details:
|
||||
pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
pre: wildcards= 0x3820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x3fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
normalization changed ofp_match, details:
|
||||
pre: wildcards= 0x23820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x23fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
pre: wildcards= 0x23820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
post: wildcards= 0x23fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
@@ -315,7 +315,7 @@ AT_CHECK([ovs-ofctl parse-nx-match < nx-match.txt], [0], [dnl
|
||||
<any>
|
||||
|
||||
# in port
|
||||
NXM_OF_IN_PORT(fffe)
|
||||
NXM_OF_IN_PORT(0000)
|
||||
NXM_OF_IN_PORT(fffe)
|
||||
|
||||
# eth dst
|
||||
|
@@ -251,7 +251,7 @@ static ovs_be32 nw_dst_values[] = { CONSTANT_HTONL(0xc0a80002),
|
||||
static ovs_be64 tun_id_values[] = {
|
||||
0,
|
||||
CONSTANT_HTONLL(UINT64_C(0xfedcba9876543210)) };
|
||||
static uint16_t in_port_values[] = { 1, ODPP_LOCAL };
|
||||
static uint16_t in_port_values[] = { 1, OFPP_LOCAL };
|
||||
static ovs_be16 vlan_tci_values[] = { CONSTANT_HTONS(101), CONSTANT_HTONS(0) };
|
||||
static ovs_be16 dl_type_values[]
|
||||
= { CONSTANT_HTONS(ETH_TYPE_IP), CONSTANT_HTONS(ETH_TYPE_ARP) };
|
||||
|
@@ -796,7 +796,6 @@ bridge_del_ofproto_ports(struct bridge *br)
|
||||
br->name, name, strerror(error));
|
||||
}
|
||||
if (iface) {
|
||||
ofproto_port_unregister(br->ofproto, ofproto_port.ofp_port);
|
||||
netdev_close(iface->netdev);
|
||||
iface->netdev = NULL;
|
||||
}
|
||||
@@ -2672,8 +2671,6 @@ static bool
|
||||
mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
|
||||
{
|
||||
struct ofproto_mirror_settings s;
|
||||
struct port *out_port;
|
||||
struct port *port;
|
||||
|
||||
/* Set name. */
|
||||
if (strcmp(cfg->name, m->name)) {
|
||||
@@ -2685,7 +2682,7 @@ mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
|
||||
/* Get output port or VLAN. */
|
||||
if (cfg->output_port) {
|
||||
s.out_bundle = port_lookup(m->bridge, cfg->output_port->name);
|
||||
if (!out_port) {
|
||||
if (!s.out_bundle) {
|
||||
VLOG_ERR("bridge %s: mirror %s outputs to port not on bridge",
|
||||
m->bridge->name, m->name);
|
||||
return false;
|
||||
@@ -2711,6 +2708,7 @@ mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
|
||||
if (cfg->select_all) {
|
||||
size_t n_ports = hmap_count(&m->bridge->ports);
|
||||
void **ports = xmalloc(n_ports * sizeof *ports);
|
||||
struct port *port;
|
||||
size_t i;
|
||||
|
||||
i = 0;
|
||||
|
Reference in New Issue
Block a user