2
0
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:
Ben Pfaff
2011-05-11 12:13:10 -07:00
parent f79e673f3d
commit abe529af47
20 changed files with 5188 additions and 3832 deletions

326
PORTING
View File

@@ -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
---------

View File

@@ -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);

View File

@@ -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;

View File

@@ -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. */

View File

@@ -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);

View File

@@ -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):

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 \

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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);

View File

@@ -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])
])

View File

@@ -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:
])

View File

@@ -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

View File

@@ -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) };

View File

@@ -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;