void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
}
static bool
-is_delimiter(char c)
+is_delimiter(unsigned char c)
{
return isspace(c) || c == ',';
}
return true;
}
-static bool
-tun_parms_fully_wildcarded(const struct flow_wildcards *wc)
-{
- return (!wc->masks.tunnel.ip_src &&
- !wc->masks.tunnel.ip_dst &&
- !wc->masks.tunnel.ip_ttl &&
- !wc->masks.tunnel.ip_tos &&
- !wc->masks.tunnel.flags);
-}
-
/* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
* 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
{
const struct flow_wildcards *wc = &match->wc;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
- /* tunnel params other than tun_id can't be sent in a flow_mod */
- if (!tun_parms_fully_wildcarded(wc)) {
+ /* These tunnel params can't be sent in a flow_mod */
+ if (wc->masks.tunnel.ip_ttl
+ || wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) {
return OFPUTIL_P_NONE;
}
| OFPUTIL_P_OF13_OXM;
}
- /* NXM and OXM support matching tun_id. */
- if (wc->masks.tunnel.tun_id != htonll(0)) {
+ /* NXM and OXM support matching tun_id, tun_src, and tun_dst. */
+ if (wc->masks.tunnel.tun_id != htonll(0)
+ || wc->masks.tunnel.ip_src != htonl(0)
+ || wc->masks.tunnel.ip_dst != htonl(0)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
return error;
}
- error = ofpacts_pull_openflow11_instructions(&b, b.size, ofpacts);
+ error = ofpacts_pull_openflow11_instructions(&b, b.size, ofm->table_id,
+ ofpacts);
if (error) {
return error;
}
}
if (ofpacts_pull_openflow11_instructions(msg, length - sizeof *ofs -
- padded_match_len, ofpacts)) {
+ padded_match_len,
+ ofs->table_id, ofpacts)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions");
return EINVAL;
}
fr->priority = ntohs(nfr->priority);
fr->cookie = nfr->cookie;
fr->reason = nfr->reason;
- fr->table_id = 255;
+ fr->table_id = nfr->table_id ? nfr->table_id - 1 : 255;
fr->duration_sec = ntohl(nfr->duration_sec);
fr->duration_nsec = ntohl(nfr->duration_nsec);
fr->idle_timeout = ntohs(nfr->idle_timeout);
nfr->cookie = fr->cookie;
nfr->priority = htons(fr->priority);
nfr->reason = fr->reason;
+ nfr->table_id = fr->table_id + 1;
nfr->duration_sec = htonl(fr->duration_sec);
nfr->duration_nsec = htonl(fr->duration_nsec);
nfr->idle_timeout = htons(fr->idle_timeout);
pin->fmd.in_port = match->flow.in_port;
pin->fmd.tun_id = match->flow.tunnel.tun_id;
+ pin->fmd.tun_src = match->flow.tunnel.ip_src;
+ pin->fmd.tun_dst = match->flow.tunnel.ip_dst;
pin->fmd.metadata = match->flow.metadata;
memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs);
}
if (pin->fmd.tun_id != htonll(0)) {
match_set_tun_id(match, pin->fmd.tun_id);
}
+ if (pin->fmd.tun_src != htonl(0)) {
+ match_set_tun_src(match, pin->fmd.tun_src);
+ }
+ if (pin->fmd.tun_dst != htonl(0)) {
+ match_set_tun_dst(match, pin->fmd.tun_dst);
+ }
if (pin->fmd.metadata != htonll(0)) {
match_set_metadata(match, pin->fmd.metadata);
}
return packet;
}
+/* Returns a string form of 'reason'. The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFPUTIL_PACKET_IN_REASON_BUFSIZE. */
const char *
-ofputil_packet_in_reason_to_string(enum ofp_packet_in_reason reason)
+ofputil_packet_in_reason_to_string(enum ofp_packet_in_reason reason,
+ char *reasonbuf, size_t bufsize)
{
- static char s[INT_STRLEN(int) + 1];
-
switch (reason) {
case OFPR_NO_MATCH:
return "no_match";
case OFPR_N_REASONS:
default:
- sprintf(s, "%d", (int) reason);
- return s;
+ snprintf(reasonbuf, bufsize, "%d", (int) reason);
+ return reasonbuf;
}
}
int i;
for (i = 0; i < OFPR_N_REASONS; i++) {
- if (!strcasecmp(s, ofputil_packet_in_reason_to_string(i))) {
+ char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
+ const char *reason_s;
+
+ reason_s = ofputil_packet_in_reason_to_string(i, reasonbuf,
+ sizeof reasonbuf);
+ if (!strcasecmp(s, reason_s)) {
*reason = i;
return true;
}
}
rr->role = ntohl(orr->role);
- if (raw == OFPRAW_OFPT12_ROLE_REPLY
- || orr->role == htonl(OFPCR12_ROLE_NOCHANGE)) {
+ if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+ ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
+ : orr->generation_id == htonll(UINT64_MAX)) {
rr->have_generation_id = false;
rr->generation_id = 0;
} else {
buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0);
orr = ofpbuf_put_zeros(buf, sizeof *orr);
- orr->role = htonl(rr->role);
- /*
- * OpenFlow specification does not specify use of generation_id field
- * on reply messages. Intuitively, it would seem a good idea to return
- * the current value. However, the current value is undefined
- * initially, and there is no way to insert an undefined value in the
- * message. Therefore we leave the generation_id zeroed on reply
- * messages.
- *
- * A request for clarification has been filed with the Open Networking
- * Foundation as EXT-272.
- */
- orr->generation_id = htonll(0);
+ orr->role = htonl(rr->role);
+ orr->generation_id = htonll(rr->have_generation_id
+ ? rr->generation_id
+ : UINT64_MAX);
} else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
struct nx_role_request *nrr;
/* Converts the OpenFlow 1.1+ port number 'ofp11_port' into an OpenFlow 1.0
* port number and stores the latter in '*ofp10_port', for the purpose of
* decoding OpenFlow 1.1+ protocol messages. Returns 0 if successful,
- * otherwise an OFPERR_* number.
+ * otherwise an OFPERR_* number. On error, stores OFPP_NONE in '*ofp10_port'.
*
* See the definition of OFP11_MAX for an explanation of the mapping. */
enum ofperr
*ofp10_port = ofp11_port_h - OFPP11_OFFSET;
return 0;
} else {
+ *ofp10_port = OFPP_NONE;
VLOG_WARN_RL(&bad_ofmsg_rl, "port %"PRIu32" is outside the supported "
"range 0 through %d or 0x%"PRIx32" through 0x%"PRIx32,
ofp11_port_h, OFPP_MAX - 1,
int
ofputil_action_code_from_name(const char *name)
{
- static const char *names[OFPUTIL_N_ACTIONS] = {
+ static const char *const names[OFPUTIL_N_ACTIONS] = {
NULL,
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME,
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#include "ofp-util.def"
};
- const char **p;
+ const char *const *p;
for (p = names; p < &names[ARRAY_SIZE(names)]; p++) {
if (*p && !strcasecmp(name, *p)) {
* will be for Open Flow version 'ofp_version'. Returns message
* as a struct ofpbuf. Returns encoded message on success, NULL on error */
struct ofpbuf *
-ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port)
+ofputil_encode_dump_ports_request(enum ofp_version ofp_version, uint16_t port)
{
struct ofpbuf *request;
struct ofp13_port_stats *ps13)
{
ofputil_port_stats_to_ofp11(ops, &ps13->ps);
-
- /* OF 1.3 adds duration fields */
- /* FIXME: Need to implement port alive duration (sec + nsec) */
- ps13->duration_sec = htonl(~0);
- ps13->duration_nsec = htonl(~0);
+ ps13->duration_sec = htonl(ops->duration_sec);
+ ps13->duration_nsec = htonl(ops->duration_nsec);
}
ops->stats.rx_over_errors = ntohll(get_32aligned_be64(&ps10->rx_over_err));
ops->stats.rx_crc_errors = ntohll(get_32aligned_be64(&ps10->rx_crc_err));
ops->stats.collisions = ntohll(get_32aligned_be64(&ps10->collisions));
+ ops->duration_sec = ops->duration_nsec = UINT32_MAX;
return 0;
}
ops->stats.rx_over_errors = ntohll(ps11->rx_over_err);
ops->stats.rx_crc_errors = ntohll(ps11->rx_crc_err);
ops->stats.collisions = ntohll(ps11->collisions);
+ ops->duration_sec = ops->duration_nsec = UINT32_MAX;
return 0;
}
ofputil_port_stats_from_ofp13(struct ofputil_port_stats *ops,
const struct ofp13_port_stats *ps13)
{
- enum ofperr error =
- ofputil_port_stats_from_ofp11(ops, &ps13->ps);
+ enum ofperr error = ofputil_port_stats_from_ofp11(ops, &ps13->ps);
if (!error) {
- /* FIXME: Get ps13->duration_sec and ps13->duration_nsec,
- * Add to netdev_stats? */
+ ops->duration_sec = ntohl(ps13->duration_sec);
+ ops->duration_nsec = ntohl(ps13->duration_nsec);
}
-
return error;
}