mirror of
https://github.com/openvswitch/ovs
synced 2025-10-21 14:49:41 +00:00
Introduce ofputil_protocol, to abstract the protocol in use on a connection.
Open vSwitch already handles a few different protocol variations, but it does so in a nonuniform manner: - OpenFlow 1.0 and NXM flow formats are distinguished using the NXFF_* constant values from nicira-ext.h. - The "flow_mod_table_id" feature setting is maintained in ofproto as part of an OpenFlow connection's (ofconn's) state. There's no way to easily communicate this state among components. It's not much of a problem yet, but as more protocol support is added it seems better to have an abstract, uniform way to represent protocol versions and variants. This commit implements that by introducing a new type "enum ofputil_protocol". Each ofputil_protocol value represents a variant of a protocol version. Each value is a separate bit, so a single enum can also represent a set of protocols, which is often useful as well. Reviewed-by: Simon Horman <horms@verge.net.au> Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
517
lib/ofp-util.c
517
lib/ofp-util.c
@@ -838,39 +838,248 @@ ofputil_msg_type_code(const struct ofputil_msg_type *type)
|
||||
return type->code;
|
||||
}
|
||||
|
||||
/* Flow formats. */
|
||||
/* Protocols. */
|
||||
|
||||
bool
|
||||
ofputil_flow_format_is_valid(enum nx_flow_format flow_format)
|
||||
struct proto_abbrev {
|
||||
enum ofputil_protocol protocol;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Most users really don't care about some of the differences between
|
||||
* protocols. These abbreviations help with that. */
|
||||
static const struct proto_abbrev proto_abbrevs[] = {
|
||||
{ OFPUTIL_P_ANY, "any" },
|
||||
{ OFPUTIL_P_OF10_ANY, "OpenFlow10" },
|
||||
{ OFPUTIL_P_NXM_ANY, "NXM" },
|
||||
};
|
||||
#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
|
||||
|
||||
enum ofputil_protocol ofputil_flow_dump_protocols[] = {
|
||||
OFPUTIL_P_NXM,
|
||||
OFPUTIL_P_OF10,
|
||||
};
|
||||
size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols);
|
||||
|
||||
/* Returns the ofputil_protocol that is initially in effect on an OpenFlow
|
||||
* connection that has negotiated the given 'version'. 'version' should
|
||||
* normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow
|
||||
* 1.0, 0x02 for OpenFlow 1.1). Returns 0 if 'version' is not supported or
|
||||
* outside the valid range. */
|
||||
enum ofputil_protocol
|
||||
ofputil_protocol_from_ofp_version(int version)
|
||||
{
|
||||
switch (flow_format) {
|
||||
case NXFF_OPENFLOW10:
|
||||
case NXFF_NXM:
|
||||
return true;
|
||||
switch (version) {
|
||||
case OFP_VERSION: return OFPUTIL_P_OF10;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *
|
||||
ofputil_flow_format_to_string(enum nx_flow_format flow_format)
|
||||
/* Returns true if 'protocol' is a single OFPUTIL_P_* value, false
|
||||
* otherwise. */
|
||||
bool
|
||||
ofputil_protocol_is_valid(enum ofputil_protocol protocol)
|
||||
{
|
||||
switch (flow_format) {
|
||||
case NXFF_OPENFLOW10:
|
||||
return "openflow10";
|
||||
case NXFF_NXM:
|
||||
return "nxm";
|
||||
return protocol & OFPUTIL_P_ANY && is_pow2(protocol);
|
||||
}
|
||||
|
||||
/* Returns the equivalent of 'protocol' with the Nicira flow_mod_table_id
|
||||
* extension turned on or off if 'enable' is true or false, respectively.
|
||||
*
|
||||
* This extension is only useful for protocols whose "standard" version does
|
||||
* not allow specific tables to be modified. In particular, this is true of
|
||||
* OpenFlow 1.0. In later versions of OpenFlow, a flow_mod request always
|
||||
* specifies a table ID and so there is no need for such an extension. When
|
||||
* 'protocol' is such a protocol that doesn't need a flow_mod_table_id
|
||||
* extension, this function just returns its 'protocol' argument unchanged
|
||||
* regardless of the value of 'enable'. */
|
||||
enum ofputil_protocol
|
||||
ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable)
|
||||
{
|
||||
switch (protocol) {
|
||||
case OFPUTIL_P_OF10:
|
||||
case OFPUTIL_P_OF10_TID:
|
||||
return enable ? OFPUTIL_P_OF10_TID : OFPUTIL_P_OF10;
|
||||
|
||||
case OFPUTIL_P_NXM:
|
||||
case OFPUTIL_P_NXM_TID:
|
||||
return enable ? OFPUTIL_P_NXM_TID : OFPUTIL_P_NXM;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ofputil_flow_format_from_string(const char *s)
|
||||
/* Returns the "base" version of 'protocol'. That is, if 'protocol' includes
|
||||
* some extension to a standard protocol version, the return value is the
|
||||
* standard version of that protocol without any extension. If 'protocol' is a
|
||||
* standard protocol version, returns 'protocol' unchanged. */
|
||||
enum ofputil_protocol
|
||||
ofputil_protocol_to_base(enum ofputil_protocol protocol)
|
||||
{
|
||||
return (!strcmp(s, "openflow10") ? NXFF_OPENFLOW10
|
||||
: !strcmp(s, "nxm") ? NXFF_NXM
|
||||
: -1);
|
||||
return ofputil_protocol_set_tid(protocol, false);
|
||||
}
|
||||
|
||||
/* Returns 'new_base' with any extensions taken from 'cur'. */
|
||||
enum ofputil_protocol
|
||||
ofputil_protocol_set_base(enum ofputil_protocol cur,
|
||||
enum ofputil_protocol new_base)
|
||||
{
|
||||
bool tid = (cur & OFPUTIL_P_TID) != 0;
|
||||
|
||||
switch (new_base) {
|
||||
case OFPUTIL_P_OF10:
|
||||
case OFPUTIL_P_OF10_TID:
|
||||
return ofputil_protocol_set_tid(OFPUTIL_P_OF10, tid);
|
||||
|
||||
case OFPUTIL_P_NXM:
|
||||
case OFPUTIL_P_NXM_TID:
|
||||
return ofputil_protocol_set_tid(OFPUTIL_P_NXM, tid);
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a string form of 'protocol', if a simple form exists (that is, if
|
||||
* 'protocol' is either a single protocol or it is a combination of protocols
|
||||
* that have a single abbreviation). Otherwise, returns NULL. */
|
||||
const char *
|
||||
ofputil_protocol_to_string(enum ofputil_protocol protocol)
|
||||
{
|
||||
const struct proto_abbrev *p;
|
||||
|
||||
/* Use a "switch" statement for single-bit names so that we get a compiler
|
||||
* warning if we forget any. */
|
||||
switch (protocol) {
|
||||
case OFPUTIL_P_NXM:
|
||||
return "NXM-table_id";
|
||||
|
||||
case OFPUTIL_P_NXM_TID:
|
||||
return "NXM+table_id";
|
||||
|
||||
case OFPUTIL_P_OF10:
|
||||
return "OpenFlow10-table_id";
|
||||
|
||||
case OFPUTIL_P_OF10_TID:
|
||||
return "OpenFlow10+table_id";
|
||||
}
|
||||
|
||||
/* Check abbreviations. */
|
||||
for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
|
||||
if (protocol == p->protocol) {
|
||||
return p->name;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns a string that represents 'protocols'. The return value might be a
|
||||
* comma-separated list if 'protocols' doesn't have a simple name. The return
|
||||
* value is "none" if 'protocols' is 0.
|
||||
*
|
||||
* The caller must free the returned string (with free()). */
|
||||
char *
|
||||
ofputil_protocols_to_string(enum ofputil_protocol protocols)
|
||||
{
|
||||
struct ds s;
|
||||
|
||||
assert(!(protocols & ~OFPUTIL_P_ANY));
|
||||
if (protocols == 0) {
|
||||
return xstrdup("none");
|
||||
}
|
||||
|
||||
ds_init(&s);
|
||||
while (protocols) {
|
||||
const struct proto_abbrev *p;
|
||||
int i;
|
||||
|
||||
if (s.length) {
|
||||
ds_put_char(&s, ',');
|
||||
}
|
||||
|
||||
for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
|
||||
if ((protocols & p->protocol) == p->protocol) {
|
||||
ds_put_cstr(&s, p->name);
|
||||
protocols &= ~p->protocol;
|
||||
goto match;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) {
|
||||
enum ofputil_protocol bit = 1u << i;
|
||||
|
||||
if (protocols & bit) {
|
||||
ds_put_cstr(&s, ofputil_protocol_to_string(bit));
|
||||
protocols &= ~bit;
|
||||
goto match;
|
||||
}
|
||||
}
|
||||
NOT_REACHED();
|
||||
|
||||
match: ;
|
||||
}
|
||||
return ds_steal_cstr(&s);
|
||||
}
|
||||
|
||||
static enum ofputil_protocol
|
||||
ofputil_protocol_from_string__(const char *s, size_t n)
|
||||
{
|
||||
const struct proto_abbrev *p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) {
|
||||
enum ofputil_protocol bit = 1u << i;
|
||||
const char *name = ofputil_protocol_to_string(bit);
|
||||
|
||||
if (name && n == strlen(name) && !strncasecmp(s, name, n)) {
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
|
||||
for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
|
||||
if (n == strlen(p->name) && !strncasecmp(s, p->name, n)) {
|
||||
return p->protocol;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns the nonempty set of protocols represented by 's', which can be a
|
||||
* single protocol name or abbreviation or a comma-separated list of them.
|
||||
*
|
||||
* Aborts the program with an error message if 's' is invalid. */
|
||||
enum ofputil_protocol
|
||||
ofputil_protocols_from_string(const char *s)
|
||||
{
|
||||
const char *orig_s = s;
|
||||
enum ofputil_protocol protocols;
|
||||
|
||||
protocols = 0;
|
||||
while (*s) {
|
||||
enum ofputil_protocol p;
|
||||
size_t n;
|
||||
|
||||
n = strcspn(s, ",");
|
||||
if (n == 0) {
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
p = ofputil_protocol_from_string__(s, n);
|
||||
if (!p) {
|
||||
ovs_fatal(0, "%.*s: unknown flow protocol", (int) n, s);
|
||||
}
|
||||
protocols |= p;
|
||||
|
||||
s += n;
|
||||
}
|
||||
|
||||
if (!protocols) {
|
||||
ovs_fatal(0, "%s: no flow protocol specified", orig_s);
|
||||
}
|
||||
return protocols;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -919,12 +1128,12 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
|
||||
* (e.g. to add or remove a flow). Only NXM can handle tunnel IDs, registers,
|
||||
* or fixing the Ethernet multicast bit. Otherwise, it's better to use
|
||||
* NXFF_OPENFLOW10 for backward compatibility. */
|
||||
enum nx_flow_format
|
||||
ofputil_min_flow_format(const struct cls_rule *rule)
|
||||
/* Returns a bit-mask of ofputil_protocols that can be used for sending 'rule'
|
||||
* to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs,
|
||||
* registers, or fixing the Ethernet multicast bit. Otherwise, it's better to
|
||||
* use OpenFlow 1.0 protocol for backward compatibility. */
|
||||
enum ofputil_protocol
|
||||
ofputil_usable_protocols(const struct cls_rule *rule)
|
||||
{
|
||||
const struct flow_wildcards *wc = &rule->wc;
|
||||
|
||||
@@ -932,74 +1141,161 @@ ofputil_min_flow_format(const struct cls_rule *rule)
|
||||
|
||||
/* Only NXM supports separately wildcards the Ethernet multicast bit. */
|
||||
if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching ARP hardware addresses. */
|
||||
if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching IPv6 traffic. */
|
||||
if (!(wc->wildcards & FWW_DL_TYPE)
|
||||
&& (rule->flow.dl_type == htons(ETH_TYPE_IPV6))) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching registers. */
|
||||
if (!regs_fully_wildcarded(wc)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching tun_id. */
|
||||
if (wc->tun_id_mask != htonll(0)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching fragments. */
|
||||
if (wc->nw_frag_mask) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching IPv6 flow label. */
|
||||
if (!(wc->wildcards & FWW_IPV6_LABEL)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching IP ECN bits. */
|
||||
if (!(wc->wildcards & FWW_NW_ECN)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports matching IP TTL/hop limit. */
|
||||
if (!(wc->wildcards & FWW_NW_TTL)) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Only NXM supports bitwise matching on transport port. */
|
||||
if ((wc->tp_src_mask && wc->tp_src_mask != htons(UINT16_MAX)) ||
|
||||
(wc->tp_dst_mask && wc->tp_dst_mask != htons(UINT16_MAX))) {
|
||||
return NXFF_NXM;
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
/* Other formats can express this rule. */
|
||||
return NXFF_OPENFLOW10;
|
||||
return OFPUTIL_P_ANY;
|
||||
}
|
||||
|
||||
/* Returns an OpenFlow message that can be used to set the flow format to
|
||||
* 'flow_format'. */
|
||||
/* Returns an OpenFlow message that, sent on an OpenFlow connection whose
|
||||
* protocol is 'current', at least partly transitions the protocol to 'want'.
|
||||
* Stores in '*next' the protocol that will be in effect on the OpenFlow
|
||||
* connection if the switch processes the returned message correctly. (If
|
||||
* '*next != want' then the caller will have to iterate.)
|
||||
*
|
||||
* If 'current == want', returns NULL and stores 'current' in '*next'. */
|
||||
struct ofpbuf *
|
||||
ofputil_make_set_flow_format(enum nx_flow_format flow_format)
|
||||
ofputil_encode_set_protocol(enum ofputil_protocol current,
|
||||
enum ofputil_protocol want,
|
||||
enum ofputil_protocol *next)
|
||||
{
|
||||
enum ofputil_protocol cur_base, want_base;
|
||||
bool cur_tid, want_tid;
|
||||
|
||||
cur_base = ofputil_protocol_to_base(current);
|
||||
want_base = ofputil_protocol_to_base(want);
|
||||
if (cur_base != want_base) {
|
||||
*next = ofputil_protocol_set_base(current, want_base);
|
||||
|
||||
switch (want_base) {
|
||||
case OFPUTIL_P_NXM:
|
||||
return ofputil_encode_nx_set_flow_format(NXFF_NXM);
|
||||
|
||||
case OFPUTIL_P_OF10:
|
||||
return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10);
|
||||
|
||||
case OFPUTIL_P_OF10_TID:
|
||||
case OFPUTIL_P_NXM_TID:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
cur_tid = (current & OFPUTIL_P_TID) != 0;
|
||||
want_tid = (want & OFPUTIL_P_TID) != 0;
|
||||
if (cur_tid != want_tid) {
|
||||
*next = ofputil_protocol_set_tid(current, want_tid);
|
||||
return ofputil_make_flow_mod_table_id(want_tid);
|
||||
}
|
||||
|
||||
assert(current == want);
|
||||
|
||||
*next = current;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns an NXT_SET_FLOW_FORMAT message that can be used to set the flow
|
||||
* format to 'nxff'. */
|
||||
struct ofpbuf *
|
||||
ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff)
|
||||
{
|
||||
struct nx_set_flow_format *sff;
|
||||
struct ofpbuf *msg;
|
||||
|
||||
assert(ofputil_nx_flow_format_is_valid(nxff));
|
||||
|
||||
sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
|
||||
sff->format = htonl(flow_format);
|
||||
sff->format = htonl(nxff);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Returns the base protocol if 'flow_format' is a valid NXFF_* value, false
|
||||
* otherwise. */
|
||||
enum ofputil_protocol
|
||||
ofputil_nx_flow_format_to_protocol(enum nx_flow_format flow_format)
|
||||
{
|
||||
switch (flow_format) {
|
||||
case NXFF_OPENFLOW10:
|
||||
return OFPUTIL_P_OF10;
|
||||
|
||||
case NXFF_NXM:
|
||||
return OFPUTIL_P_NXM;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if 'flow_format' is a valid NXFF_* value, false otherwise. */
|
||||
bool
|
||||
ofputil_nx_flow_format_is_valid(enum nx_flow_format flow_format)
|
||||
{
|
||||
return ofputil_nx_flow_format_to_protocol(flow_format) != 0;
|
||||
}
|
||||
|
||||
/* Returns a string version of 'flow_format', which must be a valid NXFF_*
|
||||
* value. */
|
||||
const char *
|
||||
ofputil_nx_flow_format_to_string(enum nx_flow_format flow_format)
|
||||
{
|
||||
switch (flow_format) {
|
||||
case NXFF_OPENFLOW10:
|
||||
return "openflow10";
|
||||
case NXFF_NXM:
|
||||
return "nxm";
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
struct ofpbuf *
|
||||
ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format)
|
||||
{
|
||||
@@ -1029,13 +1325,11 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
|
||||
* flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error
|
||||
* code.
|
||||
*
|
||||
* 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
|
||||
* enabled, false otherwise.
|
||||
*
|
||||
* Does not validate the flow_mod actions. */
|
||||
enum ofperr
|
||||
ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
|
||||
const struct ofp_header *oh, bool flow_mod_table_id)
|
||||
const struct ofp_header *oh,
|
||||
enum ofputil_protocol protocol)
|
||||
{
|
||||
const struct ofputil_msg_type *type;
|
||||
uint16_t command;
|
||||
@@ -1068,7 +1362,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
|
||||
|
||||
/* Translate the rule. */
|
||||
ofputil_cls_rule_from_match(&ofm->match, priority, &fm->cr);
|
||||
ofputil_normalize_rule(&fm->cr, NXFF_OPENFLOW10);
|
||||
ofputil_normalize_rule(&fm->cr);
|
||||
|
||||
/* Translate the message. */
|
||||
fm->cookie = ofm->cookie;
|
||||
@@ -1118,7 +1412,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
if (flow_mod_table_id) {
|
||||
if (protocol & OFPUTIL_P_TID) {
|
||||
fm->command = command & 0xff;
|
||||
fm->table_id = command >> 8;
|
||||
} else {
|
||||
@@ -1130,26 +1424,28 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
|
||||
}
|
||||
|
||||
/* Converts 'fm' into an OFPT_FLOW_MOD or NXT_FLOW_MOD message according to
|
||||
* 'flow_format' and returns the message.
|
||||
* 'protocol' and returns the message.
|
||||
*
|
||||
* 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
|
||||
* enabled, false otherwise. */
|
||||
struct ofpbuf *
|
||||
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
|
||||
enum nx_flow_format flow_format,
|
||||
bool flow_mod_table_id)
|
||||
enum ofputil_protocol protocol)
|
||||
{
|
||||
size_t actions_len = fm->n_actions * sizeof *fm->actions;
|
||||
struct ofp_flow_mod *ofm;
|
||||
struct nx_flow_mod *nfm;
|
||||
struct ofpbuf *msg;
|
||||
uint16_t command;
|
||||
int match_len;
|
||||
|
||||
command = (flow_mod_table_id
|
||||
command = (protocol & OFPUTIL_P_TID
|
||||
? (fm->command & 0xff) | (fm->table_id << 8)
|
||||
: fm->command);
|
||||
|
||||
if (flow_format == NXFF_OPENFLOW10) {
|
||||
struct ofp_flow_mod *ofm;
|
||||
|
||||
switch (protocol) {
|
||||
case OFPUTIL_P_OF10:
|
||||
case OFPUTIL_P_OF10_TID:
|
||||
msg = ofpbuf_new(sizeof *ofm + actions_len);
|
||||
ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
|
||||
ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
|
||||
@@ -1161,10 +1457,10 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
|
||||
ofm->buffer_id = htonl(fm->buffer_id);
|
||||
ofm->out_port = htons(fm->out_port);
|
||||
ofm->flags = htons(fm->flags);
|
||||
} else if (flow_format == NXFF_NXM) {
|
||||
struct nx_flow_mod *nfm;
|
||||
int match_len;
|
||||
break;
|
||||
|
||||
case OFPUTIL_P_NXM:
|
||||
case OFPUTIL_P_NXM_TID:
|
||||
msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + actions_len);
|
||||
put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
|
||||
nfm = msg->data;
|
||||
@@ -1184,7 +1480,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
|
||||
nfm->out_port = htons(fm->out_port);
|
||||
nfm->flags = htons(fm->flags);
|
||||
nfm->match_len = htons(match_len);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
@@ -1193,6 +1491,35 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Returns a bitmask with a 1-bit for each protocol that could be used to
|
||||
* send all of the 'n_fm's flow table modification requests in 'fms', and a
|
||||
* 0-bit for each protocol that is inadequate.
|
||||
*
|
||||
* (The return value will have at least one 1-bit.) */
|
||||
enum ofputil_protocol
|
||||
ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
|
||||
size_t n_fms)
|
||||
{
|
||||
enum ofputil_protocol usable_protocols;
|
||||
size_t i;
|
||||
|
||||
usable_protocols = OFPUTIL_P_ANY;
|
||||
for (i = 0; i < n_fms; i++) {
|
||||
const struct ofputil_flow_mod *fm = &fms[i];
|
||||
|
||||
usable_protocols &= ofputil_usable_protocols(&fm->cr);
|
||||
if (fm->table_id != 0xff) {
|
||||
usable_protocols &= OFPUTIL_P_TID;
|
||||
}
|
||||
if (fm->command != OFPFC_ADD && fm->cookie_mask != htonll(0)) {
|
||||
usable_protocols &= OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
}
|
||||
assert(usable_protocols);
|
||||
|
||||
return usable_protocols;
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
|
||||
const struct ofp_header *oh,
|
||||
@@ -1274,14 +1601,16 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
|
||||
|
||||
/* Converts abstract flow_stats_request 'fsr' into an OFPST_FLOW,
|
||||
* OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE request 'oh' according to
|
||||
* 'flow_format', and returns the message. */
|
||||
* 'protocol', and returns the message. */
|
||||
struct ofpbuf *
|
||||
ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
|
||||
enum nx_flow_format flow_format)
|
||||
enum ofputil_protocol protocol)
|
||||
{
|
||||
struct ofpbuf *msg;
|
||||
|
||||
if (flow_format == NXFF_OPENFLOW10) {
|
||||
switch (protocol) {
|
||||
case OFPUTIL_P_OF10:
|
||||
case OFPUTIL_P_OF10_TID: {
|
||||
struct ofp_flow_stats_request *ofsr;
|
||||
int type;
|
||||
|
||||
@@ -1290,7 +1619,11 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
|
||||
ofputil_cls_rule_to_match(&fsr->match, &ofsr->match);
|
||||
ofsr->table_id = fsr->table_id;
|
||||
ofsr->out_port = htons(fsr->out_port);
|
||||
} else if (flow_format == NXFF_NXM) {
|
||||
break;
|
||||
}
|
||||
|
||||
case OFPUTIL_P_NXM:
|
||||
case OFPUTIL_P_NXM_TID: {
|
||||
struct nx_flow_stats_request *nfsr;
|
||||
int match_len;
|
||||
int subtype;
|
||||
@@ -1304,13 +1637,33 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
|
||||
nfsr->out_port = htons(fsr->out_port);
|
||||
nfsr->match_len = htons(match_len);
|
||||
nfsr->table_id = fsr->table_id;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Returns a bitmask with a 1-bit for each protocol that could be used to
|
||||
* accurately encode 'fsr', and a 0-bit for each protocol that is inadequate.
|
||||
*
|
||||
* (The return value will have at least one 1-bit.) */
|
||||
enum ofputil_protocol
|
||||
ofputil_flow_stats_request_usable_protocols(
|
||||
const struct ofputil_flow_stats_request *fsr)
|
||||
{
|
||||
enum ofputil_protocol usable_protocols;
|
||||
|
||||
usable_protocols = ofputil_usable_protocols(&fsr->match);
|
||||
if (fsr->cookie_mask != htonll(0)) {
|
||||
usable_protocols &= OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
return usable_protocols;
|
||||
}
|
||||
|
||||
/* Converts an OFPST_FLOW or NXST_FLOW reply in 'msg' into an abstract
|
||||
* ofputil_flow_stats in 'fs'.
|
||||
*
|
||||
@@ -1516,7 +1869,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
|
||||
}
|
||||
|
||||
/* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
|
||||
* NXST_AGGREGATE reply according to 'flow_format', and returns the message. */
|
||||
* NXST_AGGREGATE reply according to 'protocol', and returns the message. */
|
||||
struct ofpbuf *
|
||||
ofputil_encode_aggregate_stats_reply(
|
||||
const struct ofputil_aggregate_stats *stats,
|
||||
@@ -1605,15 +1958,17 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
|
||||
}
|
||||
|
||||
/* Converts abstract ofputil_flow_removed 'fr' into an OFPT_FLOW_REMOVED or
|
||||
* NXT_FLOW_REMOVED message 'oh' according to 'flow_format', and returns the
|
||||
* NXT_FLOW_REMOVED message 'oh' according to 'protocol', and returns the
|
||||
* message. */
|
||||
struct ofpbuf *
|
||||
ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
|
||||
enum nx_flow_format flow_format)
|
||||
enum ofputil_protocol protocol)
|
||||
{
|
||||
struct ofpbuf *msg;
|
||||
|
||||
if (flow_format == NXFF_OPENFLOW10) {
|
||||
switch (protocol) {
|
||||
case OFPUTIL_P_OF10:
|
||||
case OFPUTIL_P_OF10_TID: {
|
||||
struct ofp_flow_removed *ofr;
|
||||
|
||||
ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0),
|
||||
@@ -1627,7 +1982,11 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
|
||||
ofr->idle_timeout = htons(fr->idle_timeout);
|
||||
ofr->packet_count = htonll(unknown_to_zero(fr->packet_count));
|
||||
ofr->byte_count = htonll(unknown_to_zero(fr->byte_count));
|
||||
} else if (flow_format == NXFF_NXM) {
|
||||
break;
|
||||
}
|
||||
|
||||
case OFPUTIL_P_NXM:
|
||||
case OFPUTIL_P_NXM_TID: {
|
||||
struct nx_flow_removed *nfr;
|
||||
int match_len;
|
||||
|
||||
@@ -1644,7 +2003,10 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
|
||||
nfr->match_len = htons(match_len);
|
||||
nfr->packet_count = htonll(fr->packet_count);
|
||||
nfr->byte_count = htonll(fr->byte_count);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
@@ -2793,12 +3155,9 @@ action_outputs_to_port(const union ofp_action *action, ovs_be16 port)
|
||||
* example, Open vSwitch does not understand SCTP, an L4 protocol, so the
|
||||
* L4 fields tp_src and tp_dst must be wildcarded if 'rule' specifies an
|
||||
* SCTP flow.
|
||||
*
|
||||
* 'flow_format' specifies the format of the flow as received or as intended to
|
||||
* be sent. This is important for IPv6 and ARP, for which NXM supports more
|
||||
* detailed matching. */
|
||||
*/
|
||||
void
|
||||
ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
|
||||
ofputil_normalize_rule(struct cls_rule *rule)
|
||||
{
|
||||
enum {
|
||||
MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */
|
||||
@@ -2821,8 +3180,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
|
||||
rule->flow.nw_proto == IPPROTO_ICMP) {
|
||||
may_match |= MAY_TP_ADDR;
|
||||
}
|
||||
} else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)
|
||||
&& flow_format == NXFF_NXM) {
|
||||
} else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)) {
|
||||
may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
|
||||
if (rule->flow.nw_proto == IPPROTO_TCP ||
|
||||
rule->flow.nw_proto == IPPROTO_UDP) {
|
||||
@@ -2836,10 +3194,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
|
||||
}
|
||||
}
|
||||
} else if (rule->flow.dl_type == htons(ETH_TYPE_ARP)) {
|
||||
may_match = MAY_NW_PROTO | MAY_NW_ADDR;
|
||||
if (flow_format == NXFF_NXM) {
|
||||
may_match |= MAY_ARP_SHA | MAY_ARP_THA;
|
||||
}
|
||||
may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
|
||||
} else {
|
||||
may_match = 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user