From 548349603423bea41ec2989583231c1a117f6a9e Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Fri, 9 Dec 2011 15:48:26 -0800 Subject: [PATCH] openflow: New Nicira Extended PACKET_IN format. The new PACKET_IN format implemented in this patch includes flow metadata such as the cookie, table_id, and registers. Signed-off-by: Ethan Jackson --- include/openflow/nicira-ext.h | 67 ++++++++++++- lib/learning-switch.c | 2 + lib/ofp-print.c | 27 ++++++ lib/ofp-util.c | 175 ++++++++++++++++++++++++++++++---- lib/ofp-util.h | 15 ++- ofproto/connmgr.c | 24 ++++- ofproto/connmgr.h | 3 + ofproto/ofproto-dpif.c | 40 ++++++-- ofproto/ofproto.c | 27 ++++++ tests/ofp-print.at | 30 ++++++ tests/ofproto-dpif.at | 76 +++++++-------- utilities/ovs-ofctl.8.in | 22 +++++ utilities/ovs-ofctl.c | 44 +++++++++ 13 files changed, 482 insertions(+), 70 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 1dcd32b5..bb0fb3a7 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -162,7 +162,11 @@ enum nicira_type { /* Use the upper 8 bits of the 'command' member in struct ofp_flow_mod to * designate the table to which a flow is to be added? See the big comment * on struct nxt_flow_mod_table_id for more information. */ - NXT_FLOW_MOD_TABLE_ID = 15 + NXT_FLOW_MOD_TABLE_ID = 15, + + /* Alternative PACKET_IN message formats. */ + NXT_SET_PACKET_IN_FORMAT = 16, /* Set Packet In format. */ + NXT_PACKET_IN = 17 /* Nicira Packet In. */ }; /* Header for Nicira vendor stats request and reply messages. */ @@ -246,6 +250,67 @@ struct nxt_flow_mod_table_id { }; OFP_ASSERT(sizeof(struct nxt_flow_mod_table_id) == 24); +enum nx_packet_in_format { + NXPIF_OPENFLOW10 = 0, /* Standard OpenFlow 1.0 compatible. */ + NXPIF_NXM = 1 /* Nicira Extended. */ +}; + +/* NXT_SET_PACKET_IN_FORMAT request. */ +struct nxt_set_packet_in_format { + struct nicira_header nxh; + ovs_be32 format; /* One of NXPIF_*. */ +}; +OFP_ASSERT(sizeof(struct nxt_set_packet_in_format) == 20); + +/* NXT_PACKET_IN (analogous to OFPT_PACKET_IN). + * + * The NXT_PACKET_IN format is intended to model the OpenFlow-1.2 PACKET_IN + * with some minor tweaks. Most notably NXT_PACKET_IN includes the cookie of + * the rule which triggered the NXT_PACKET_IN message, and the match fields are + * in NXM format. + * + * The match fields in the NXT_PACKET_IN are intended to contain flow + * processing metadata collected at the time the NXT_PACKET_IN message was + * triggered. It is minimally required to contain the NXM_OF_IN_PORT of the + * packet, but may include other NXM headers such as flow registers. The match + * fields are allowed to contain non-metadata (e.g. NXM_OF_ETH_SRC etc). + * However, this information can typically be found in the packet directly, so + * it may be redundant. + * + * Whereas in most cases a controller can expect to only get back NXM fields + * that it set up itself (e.g. flow dumps will ordinarily report only NXM + * fields from flows that the controller added), NXT_PACKET_IN messages might + * contain fields that the controller does not understand, because the switch + * might support fields (new registers, new protocols, etc.) that the + * controller does not.  The controller must prepared to tolerate these. + * + * The 'cookie' and 'table_id' fields have no meaning when 'reason' is + * OFPR_NO_MATCH. In this case they should be set to 0. */ +struct nxt_packet_in { + struct nicira_header nxh; + ovs_be32 buffer_id; /* ID assigned by datapath. */ + ovs_be16 total_len; /* Full length of frame. */ + uint8_t reason; /* Reason packet is sent (one of OFPR_*). */ + uint8_t table_id; /* ID of the table that was looked up. */ + ovs_be64 cookie; /* Cookie of the rule that was looked up. */ + ovs_be16 match_len; /* Size of nx_match. */ + uint8_t pad[6]; /* Align to 64-bits. */ + /* Followed by: + * - Exactly match_len (possibly 0) bytes containing the nx_match, then + * - Exactly (match_len + 7)/8*8 - match_len (between 0 and 7) bytes of + * all-zero bytes, then + * - Exactly 2 all-zero padding bytes, then + * - An Ethernet frame whose length is inferred from nxh.header.length. + * + * The padding bytes preceding the Ethernet frame ensure that the IP + * header (if any) following the Ethernet header is 32-bit aligned. */ + + /* uint8_t nxm_fields[...]; */ /* Match. */ + /* uint8_t pad[2]; */ /* Align to 64 bit + 16 bit. */ + /* uint8_t data[0]; */ /* Ethernet frame. */ +}; +OFP_ASSERT(sizeof(struct nxt_packet_in) == 40); + /* Configures the "role" of the sending controller. The default role is: * * - Other (NX_ROLE_OTHER), which allows the controller access to all diff --git a/lib/learning-switch.c b/lib/learning-switch.c index ecc5509e..2fc6392f 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -257,6 +257,8 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn, case OFPUTIL_NXT_ROLE_REPLY: case OFPUTIL_NXT_FLOW_MOD_TABLE_ID: case OFPUTIL_NXT_SET_FLOW_FORMAT: + case OFPUTIL_NXT_SET_PACKET_IN_FORMAT: + case OFPUTIL_NXT_PACKET_IN: case OFPUTIL_NXT_FLOW_MOD: case OFPUTIL_NXT_FLOW_REMOVED: case OFPUTIL_NXST_FLOW_REQUEST: diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 98791f4b..67edc543 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -92,6 +92,14 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, return; } + if (pin.table_id) { + ds_put_format(string, " table_id=%"PRIu8, pin.table_id); + } + + if (pin.cookie) { + ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie)); + } + ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len); ofputil_format_port(pin.fmd.in_port, string); @@ -1264,6 +1272,20 @@ ofp_print_nxt_set_flow_format(struct ds *string, } } +static void +ofp_print_nxt_set_packet_in_format(struct ds *string, + const struct nxt_set_packet_in_format *nspf) +{ + uint32_t format = ntohl(nspf->format); + + ds_put_cstr(string, " format="); + if (ofputil_packet_in_format_is_valid(format)) { + ds_put_cstr(string, ofputil_packet_in_format_to_string(format)); + } else { + ds_put_format(string, "%"PRIu32, format); + } +} + static void ofp_to_string__(const struct ofp_header *oh, const struct ofputil_msg_type *type, struct ds *string, @@ -1311,6 +1333,7 @@ ofp_to_string__(const struct ofp_header *oh, break; case OFPUTIL_OFPT_PACKET_IN: + case OFPUTIL_NXT_PACKET_IN: ofp_print_packet_in(string, msg, verbosity); break; @@ -1414,6 +1437,10 @@ ofp_to_string__(const struct ofp_header *oh, ofp_print_nxt_set_flow_format(string, msg); break; + case OFPUTIL_NXT_SET_PACKET_IN_FORMAT: + ofp_print_nxt_set_packet_in_format(string, msg); + break; + case OFPUTIL_NXT_FLOW_MOD: ofp_print_flow_mod(string, msg, code, verbosity); break; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 68738424..1c9ceaf8 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -363,6 +363,14 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length, NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT", sizeof(struct nxt_set_flow_format), 0 }, + { OFPUTIL_NXT_SET_PACKET_IN_FORMAT, + NXT_SET_PACKET_IN_FORMAT, "NXT_SET_PACKET_IN_FORMAT", + sizeof(struct nxt_set_packet_in_format), 0 }, + + { OFPUTIL_NXT_PACKET_IN, + NXT_PACKET_IN, "NXT_PACKET_IN", + sizeof(struct nxt_packet_in), 1 }, + { OFPUTIL_NXT_FLOW_MOD, NXT_FLOW_MOD, "NXT_FLOW_MOD", sizeof(struct nx_flow_mod), 8 }, @@ -839,6 +847,39 @@ ofputil_flow_format_from_string(const char *s) : -1); } +bool +ofputil_packet_in_format_is_valid(enum nx_packet_in_format packet_in_format) +{ + switch (packet_in_format) { + case NXPIF_OPENFLOW10: + case NXPIF_NXM: + return true; + } + + return false; +} + +const char * +ofputil_packet_in_format_to_string(enum nx_packet_in_format packet_in_format) +{ + switch (packet_in_format) { + case NXPIF_OPENFLOW10: + return "openflow10"; + case NXPIF_NXM: + return "nxm"; + default: + NOT_REACHED(); + } +} + +int +ofputil_packet_in_format_from_string(const char *s) +{ + return (!strcmp(s, "openflow10") ? NXPIF_OPENFLOW10 + : !strcmp(s, "nxm") ? NXPIF_NXM + : -1); +} + static bool regs_fully_wildcarded(const struct flow_wildcards *wc) { @@ -927,6 +968,18 @@ ofputil_make_set_flow_format(enum nx_flow_format flow_format) return msg; } +struct ofpbuf * +ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format) +{ + struct nxt_set_packet_in_format *spif; + struct ofpbuf *msg; + + spif = make_nxmsg(sizeof *spif, NXT_SET_PACKET_IN_FORMAT, &msg); + spif->format = htonl(packet_in_format); + + return msg; +} + /* Returns an OpenFlow message that can be used to turn the flow_mod_table_id * extension on or off (according to 'flow_mod_table_id'). */ struct ofpbuf * @@ -1564,6 +1617,42 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, pin->reason = opi->reason; pin->buffer_id = ntohl(opi->buffer_id); pin->total_len = ntohs(opi->total_len); + } else if (code == OFPUTIL_NXT_PACKET_IN) { + const struct nxt_packet_in *npi; + struct cls_rule rule; + struct ofpbuf b; + int error; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + + npi = ofpbuf_pull(&b, sizeof *npi); + error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL, + NULL); + if (error) { + return error; + } + + if (!ofpbuf_try_pull(&b, 2)) { + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + + pin->packet = b.data; + pin->packet_len = b.size; + pin->reason = npi->reason; + pin->table_id = npi->table_id; + pin->cookie = npi->cookie; + + pin->fmd.in_port = rule.flow.in_port; + + pin->fmd.tun_id = rule.flow.tun_id; + pin->fmd.tun_id_mask = rule.wc.tun_id_mask; + + memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs); + memcpy(pin->fmd.reg_masks, rule.wc.reg_masks, + sizeof pin->fmd.reg_masks); + + pin->buffer_id = ntohl(npi->buffer_id); + pin->total_len = ntohs(npi->total_len); } else { NOT_REACHED(); } @@ -1571,30 +1660,76 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, return 0; } -/* Converts abstract ofputil_packet_in 'pin' into an OFPT_PACKET_IN message - * and returns the message. */ +/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message + * in the format specified by 'packet_in_format'. */ struct ofpbuf * -ofputil_encode_packet_in(const struct ofputil_packet_in *pin) +ofputil_encode_packet_in(const struct ofputil_packet_in *pin, + enum nx_packet_in_format packet_in_format) { - struct ofp_packet_in opi; - struct ofpbuf *rw_packet; - - rw_packet = ofpbuf_clone_data_with_headroom( - pin->packet, MIN(pin->send_len, pin->packet_len), - offsetof(struct ofp_packet_in, data)); + size_t send_len = MIN(pin->send_len, pin->packet_len); + struct ofpbuf *packet; /* Add OFPT_PACKET_IN. */ - memset(&opi, 0, sizeof opi); - opi.header.version = OFP_VERSION; - opi.header.type = OFPT_PACKET_IN; - opi.total_len = htons(pin->packet_len); - opi.in_port = htons(pin->fmd.in_port); - opi.reason = pin->reason; - opi.buffer_id = htonl(pin->buffer_id); - ofpbuf_push(rw_packet, &opi, offsetof(struct ofp_packet_in, data)); - update_openflow_length(rw_packet); - - return rw_packet; + if (packet_in_format == NXPIF_OPENFLOW10) { + size_t header_len = offsetof(struct ofp_packet_in, data); + struct ofp_packet_in *opi; + + packet = ofpbuf_new(send_len + header_len); + opi = ofpbuf_put_zeros(packet, header_len); + opi->header.version = OFP_VERSION; + opi->header.type = OFPT_PACKET_IN; + opi->total_len = htons(pin->total_len); + opi->in_port = htons(pin->fmd.in_port); + opi->reason = pin->reason; + opi->buffer_id = htonl(pin->buffer_id); + + ofpbuf_put(packet, pin->packet, send_len); + } else if (packet_in_format == NXPIF_NXM) { + struct nxt_packet_in *npi; + struct cls_rule rule; + size_t match_len; + size_t i; + + /* Estimate of required PACKET_IN length includes the NPI header, space + * for the match (2 times sizeof the metadata seems like enough), 2 + * bytes for padding, and the packet length. */ + packet = ofpbuf_new(sizeof *npi + sizeof(struct flow_metadata) * 2 + + 2 + send_len); + + cls_rule_init_catchall(&rule, 0); + cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id, + pin->fmd.tun_id_mask); + + for (i = 0; i < FLOW_N_REGS; i++) { + cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i], + pin->fmd.reg_masks[i]); + } + + cls_rule_set_in_port(&rule, pin->fmd.in_port); + + ofpbuf_put_zeros(packet, sizeof *npi); + match_len = nx_put_match(packet, &rule, 0, 0); + ofpbuf_put_zeros(packet, 2); + ofpbuf_put(packet, pin->packet, send_len); + + npi = packet->data; + npi->nxh.header.version = OFP_VERSION; + npi->nxh.header.type = OFPT_VENDOR; + npi->nxh.vendor = htonl(NX_VENDOR_ID); + npi->nxh.subtype = htonl(NXT_PACKET_IN); + + npi->buffer_id = htonl(pin->buffer_id); + npi->total_len = htons(pin->total_len); + npi->reason = pin->reason; + npi->table_id = pin->table_id; + npi->cookie = pin->cookie; + npi->match_len = htons(match_len); + } else { + NOT_REACHED(); + } + update_openflow_length(packet); + + return packet; } /* Returns a string representing the message type of 'type'. The string is the diff --git a/lib/ofp-util.h b/lib/ofp-util.h index c3fafbaa..13195c76 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -77,6 +77,8 @@ enum ofputil_msg_code { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, OFPUTIL_NXT_FLOW_MOD, OFPUTIL_NXT_FLOW_REMOVED, + OFPUTIL_NXT_SET_PACKET_IN_FORMAT, + OFPUTIL_NXT_PACKET_IN, /* NXST_* stat requests. */ OFPUTIL_NXST_FLOW_REQUEST, @@ -124,6 +126,12 @@ enum nx_flow_format ofputil_min_flow_format(const struct cls_rule *); struct ofpbuf *ofputil_make_set_flow_format(enum nx_flow_format); +/* PACKET_IN. */ +bool ofputil_packet_in_format_is_valid(enum nx_packet_in_format); +int ofputil_packet_in_format_from_string(const char *); +const char *ofputil_packet_in_format_to_string(enum nx_packet_in_format); +struct ofpbuf *ofputil_make_set_packet_in_format(enum nx_packet_in_format); + /* NXT_FLOW_MOD_TABLE_ID extension. */ struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id); @@ -218,6 +226,8 @@ struct ofputil_packet_in { size_t packet_len; uint8_t reason; /* One of OFPR_*. */ + uint8_t table_id; + ovs_be64 cookie; uint32_t buffer_id; int send_len; @@ -228,7 +238,10 @@ struct ofputil_packet_in { int ofputil_decode_packet_in(struct ofputil_packet_in *, const struct ofp_header *); -struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *); +struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *, + enum nx_packet_in_format); +int ofputil_decode_packet_in(struct ofputil_packet_in *pi, + const struct ofp_header *oh); /* OpenFlow protocol utility functions. */ void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **); diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index 33e65921..46d6d796 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -48,6 +48,7 @@ struct ofconn { struct rconn *rconn; /* OpenFlow connection. */ enum ofconn_type type; /* Type. */ enum nx_flow_format flow_format; /* Currently selected flow format. */ + enum nx_packet_in_format packet_in_format; /* OFPT_PACKET_IN format. */ bool flow_mod_table_id; /* NXT_FLOW_MOD_TABLE_ID enabled? */ /* Asynchronous flow table operation support. */ @@ -769,6 +770,25 @@ ofconn_set_flow_format(struct ofconn *ofconn, enum nx_flow_format flow_format) ofconn->flow_format = flow_format; } +/* Returns the currently configured packet in format for 'ofconn', one of + * NXPIF_*. + * + * The default, if no other format has been set, is NXPIF_OPENFLOW10. */ +enum nx_packet_in_format +ofconn_get_packet_in_format(struct ofconn *ofconn) +{ + return ofconn->packet_in_format; +} + +/* Sets the packet in format for 'ofconn' to 'packet_in_format' (one of + * NXPIF_*). */ +void +ofconn_set_packet_in_format(struct ofconn *ofconn, + enum nx_packet_in_format packet_in_format) +{ + ofconn->packet_in_format = packet_in_format; +} + /* Returns true if the NXT_FLOW_MOD_TABLE_ID extension is enabled, false * otherwise. * @@ -906,6 +926,7 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type) ofconn->rconn = rconn; ofconn->type = type; ofconn->flow_format = NXFF_OPENFLOW10; + ofconn->packet_in_format = NXPIF_OPENFLOW10; ofconn->flow_mod_table_id = false; list_init(&ofconn->opgroups); ofconn->role = NX_ROLE_OTHER; @@ -1212,7 +1233,8 @@ schedule_packet_in(struct ofconn *ofconn, struct ofputil_packet_in pin, * immediately call into do_send_packet_in() or it might buffer it for a * while (until a later call to pinsched_run()). */ pinsched_send(ofconn->schedulers[pin.reason == OFPR_NO_MATCH ? 0 : 1], - flow->in_port, ofputil_encode_packet_in(&pin), + flow->in_port, + ofputil_encode_packet_in(&pin, ofconn->packet_in_format), do_send_packet_in, ofconn); } diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h index d8a5e56b..0df840b5 100644 --- a/ofproto/connmgr.h +++ b/ofproto/connmgr.h @@ -85,6 +85,9 @@ void ofconn_set_role(struct ofconn *, enum nx_role); enum nx_flow_format ofconn_get_flow_format(struct ofconn *); void ofconn_set_flow_format(struct ofconn *, enum nx_flow_format); +enum nx_packet_in_format ofconn_get_packet_in_format(struct ofconn *); +void ofconn_set_packet_in_format(struct ofconn *, enum nx_packet_in_format); + bool ofconn_get_flow_mod_table_id(const struct ofconn *); void ofconn_set_flow_mod_table_id(struct ofconn *, bool enable); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 97ddfedf..f5280ff2 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -214,6 +214,9 @@ struct action_xlate_ctx { * we are just revalidating. */ bool may_learn; + /* Cookie of the currently matching rule, or 0. */ + ovs_be64 cookie; + /* If nonnull, called just before executing a resubmit action. * * This is normally null so the client has to set it manually after @@ -247,7 +250,8 @@ struct action_xlate_ctx { static void action_xlate_ctx_init(struct action_xlate_ctx *, struct ofproto_dpif *, const struct flow *, - ovs_be16 initial_tci, const struct ofpbuf *); + ovs_be16 initial_tci, ovs_be64 cookie, + const struct ofpbuf *); static struct ofpbuf *xlate_actions(struct action_xlate_ctx *, const union ofp_action *in, size_t n_in); @@ -2415,6 +2419,10 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, struct ofpbuf *packet, pin.packet_len = packet->size; pin.total_len = packet->size; pin.reason = OFPR_NO_MATCH; + + pin.table_id = 0; + pin.cookie = 0; + pin.buffer_id = 0; /* not yet known */ pin.send_len = 0; /* not used for flow table misses */ @@ -3196,7 +3204,8 @@ facet_account(struct ofproto_dpif *ofproto, struct facet *facet) struct action_xlate_ctx ctx; action_xlate_ctx_init(&ctx, ofproto, &facet->flow, - facet->flow.vlan_tci, NULL); + facet->flow.vlan_tci, + facet->rule->up.flow_cookie, NULL); ctx.may_learn = true; ofpbuf_delete(xlate_actions(&ctx, facet->rule->up.actions, facet->rule->up.n_actions)); @@ -3385,7 +3394,8 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet) bool should_install; action_xlate_ctx_init(&ctx, ofproto, &facet->flow, - subfacet->initial_tci, NULL); + subfacet->initial_tci, new_rule->up.flow_cookie, + NULL); odp_actions = xlate_actions(&ctx, new_rule->up.actions, new_rule->up.n_actions); actions_changed = (subfacet->actions_len != odp_actions->size @@ -3535,7 +3545,8 @@ flow_push_stats(const struct rule_dpif *rule, push.bytes = bytes; push.used = used; - action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, NULL); + action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, + rule->up.flow_cookie, NULL); push.ctx.resubmit_hook = push_resubmit; ofpbuf_delete(xlate_actions(&push.ctx, rule->up.actions, rule->up.n_actions)); @@ -3677,7 +3688,7 @@ subfacet_make_actions(struct ofproto_dpif *p, struct subfacet *subfacet, struct action_xlate_ctx ctx; action_xlate_ctx_init(&ctx, p, &facet->flow, subfacet->initial_tci, - packet); + rule->up.flow_cookie, packet); odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions); facet->tags = ctx.tags; facet->may_install = ctx.may_set_up_flow; @@ -3955,7 +3966,8 @@ rule_execute(struct rule *rule_, const struct flow *flow, struct ofpbuf *odp_actions; size_t size; - action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet); + action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, + rule->up.flow_cookie, packet); odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions); size = packet->size; if (execute_odp_actions(ofproto, flow, odp_actions->data, @@ -4225,8 +4237,12 @@ xlate_table_action(struct action_xlate_ctx *ctx, } if (rule) { + ovs_be64 old_cookie = ctx->cookie; + ctx->recurse++; + ctx->cookie = rule->up.flow_cookie; do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx); + ctx->cookie = old_cookie; ctx->recurse--; } @@ -4323,6 +4339,9 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len) pin.packet = packet->data; pin.packet_len = packet->size; pin.reason = OFPR_ACTION; + pin.table_id = ctx->table_id; + pin.cookie = ctx->cookie; + pin.buffer_id = 0; pin.send_len = len; pin.total_len = packet->size; @@ -4728,13 +4747,15 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, static void action_xlate_ctx_init(struct action_xlate_ctx *ctx, struct ofproto_dpif *ofproto, const struct flow *flow, - ovs_be16 initial_tci, const struct ofpbuf *packet) + ovs_be16 initial_tci, ovs_be64 cookie, + const struct ofpbuf *packet) { ctx->ofproto = ofproto; ctx->flow = *flow; ctx->base_flow = ctx->flow; ctx->base_flow.tun_id = 0; ctx->base_flow.vlan_tci = initial_tci; + ctx->cookie = cookie; ctx->packet = packet; ctx->may_learn = packet != NULL; ctx->resubmit_hook = NULL; @@ -5520,7 +5541,7 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, flow); - action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet); + action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, 0, packet); odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions); dpif_execute(ofproto->dpif, key.data, key.size, odp_actions->data, odp_actions->size, packet); @@ -5810,7 +5831,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], trace.result = &result; trace.flow = flow; - action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci, packet); + action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci, + rule->up.flow_cookie, packet); trace.ctx.resubmit_hook = trace_resubmit; odp_actions = xlate_actions(&trace.ctx, rule->up.actions, rule->up.n_actions); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index af35aba2..8f3c1586 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2862,6 +2862,29 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } +static int +handle_nxt_set_packet_in_format(struct ofconn *ofconn, + const struct ofp_header *oh) +{ + const struct nxt_set_packet_in_format *msg; + uint32_t format; + + msg = (const struct nxt_set_packet_in_format *) oh; + format = ntohl(msg->format); + if (format != NXFF_OPENFLOW10 && format != NXPIF_NXM) { + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); + } + + if (format != ofconn_get_packet_in_format(ofconn) + && ofconn_has_pending_opgroups(ofconn)) { + /* Avoid sending async message in surprsing packet in format. */ + return OFPROTO_POSTPONE; + } + + ofconn_set_packet_in_format(ofconn, format); + return 0; +} + static int handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -2929,6 +2952,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPUTIL_NXT_SET_FLOW_FORMAT: return handle_nxt_set_flow_format(ofconn, oh); + case OFPUTIL_NXT_SET_PACKET_IN_FORMAT: + return handle_nxt_set_packet_in_format(ofconn, oh); + case OFPUTIL_NXT_FLOW_MOD: return handle_flow_mod(ofconn, oh); @@ -2972,6 +2998,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPUTIL_OFPST_AGGREGATE_REPLY: case OFPUTIL_NXT_ROLE_REPLY: case OFPUTIL_NXT_FLOW_REMOVED: + case OFPUTIL_NXT_PACKET_IN: case OFPUTIL_NXST_FLOW_REPLY: case OFPUTIL_NXST_AGGREGATE_REPLY: default: diff --git a/tests/ofp-print.at b/tests/ofp-print.at index aa3a2186..2ca07c46 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -641,6 +641,36 @@ NXT_ROLE_REPLY (xid=0x2): role=slave ]) AT_CLEANUP +AT_SETUP([NXT_SET_PACKET_IN]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 04 00 14 00 00 00 02 00 00 23 20 00 00 00 10 \ +00 00 00 01 \ +"], [0], [dnl +NXT_SET_PACKET_IN_FORMAT (xid=0x2): format=nxm +]) +AT_CLEANUP + +AT_SETUP([NXT_PACKET_IN]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 04 00 aa 00 00 00 00 00 00 23 20 00 00 00 11 \ +ff ff ff ff 00 40 01 07 00 00 00 00 00 00 00 09 \ +00 3a 00 00 00 00 00 00 00 00 00 02 00 01 00 01 \ +20 08 00 00 00 00 00 00 00 06 00 01 00 04 00 00 \ +00 01 00 01 02 04 00 00 00 02 00 01 04 04 00 00 \ +00 03 00 01 06 04 00 00 00 04 00 01 08 04 00 00 \ +00 05 00 00 00 00 00 00 00 00 82 82 82 82 82 82 \ +80 81 81 81 81 81 81 00 00 50 08 00 45 00 00 28 \ +00 00 00 00 00 06 32 05 53 53 53 53 54 54 54 54 \ +00 55 00 56 00 00 00 00 00 00 00 00 50 00 00 00 \ +31 6d 00 00 00 00 00 00 00 00 \ +"], [0], [dnl +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) +priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d +]) +AT_CLEANUP + AT_SETUP([NXT_SET_FLOW_FORMAT]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index c33f6ac5..615eb570 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -201,21 +201,21 @@ OVS_VSWITCHD_START([dnl AT_CAPTURE_FILE([ofctl_monitor.log]) AT_DATA([flows.txt], [dnl cookie=0x0 dl_src=10:11:11:11:11:11 actions=controller -cookie=0x1 dl_src=20:22:22:22:22:22 actions=controller,resubmit:80 +cookie=0x1 dl_src=20:22:22:22:22:22 actions=controller,resubmit(80,1) cookie=0x2 dl_src=30:33:33:33:33:33 actions=mod_vlan_vid:15,controller -cookie=0x3 in_port=80 actions=mod_vlan_vid:80,controller,resubmit:81 -cookie=0x4 in_port=81 actions=mod_dl_src:80:81:81:81:81:81,controller,resubmit:82 -cookie=0x5 in_port=82 actions=mod_dl_dst:82:82:82:82:82:82,controller,resubmit:83 -cookie=0x6 in_port=83 actions=mod_nw_src:83.83.83.83,controller,resubmit:84 -cookie=0x7 in_port=84 actions=mod_nw_dst:84.84.84.84,controller,resubmit:85 -cookie=0x8 in_port=85 actions=mod_tp_src:85,controller,resubmit:86 -cookie=0x9 in_port=86 actions=mod_tp_dst:86,controller,controller +cookie=0x3 table=1 in_port=80 actions=load:1->NXM_NX_REG0[[]],mod_vlan_vid:80,controller,resubmit(81,2) +cookie=0x4 table=2 in_port=81 actions=load:2->NXM_NX_REG1[[]],mod_dl_src:80:81:81:81:81:81,controller,resubmit(82,3) +cookie=0x5 table=3 in_port=82 actions=load:3->NXM_NX_REG2[[]],mod_dl_dst:82:82:82:82:82:82,controller,resubmit(83,4) +cookie=0x6 table=4 in_port=83 actions=load:4->NXM_NX_REG3[[]],mod_nw_src:83.83.83.83,controller,resubmit(84,5) +cookie=0x7 table=5 in_port=84 actions=load:5->NXM_NX_REG4[[]],load:6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,controller,resubmit(85,6) +cookie=0x8 table=6 in_port=85 actions=mod_tp_src:85,controller,resubmit(86,7) +cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,controller ]) AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) dnl Flow miss. -AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> ofctl_monitor.log]) +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --pidfile 2> ofctl_monitor.log]) for i in 1 2 3 ; do ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)' @@ -234,7 +234,7 @@ priority:0,tunnel:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07 ]) dnl Singleton controller action. -AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> ofctl_monitor.log]) +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --pidfile 2> ofctl_monitor.log]) for i in 1 2 3 ; do ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=10)' @@ -253,7 +253,7 @@ priority:0,tunnel:0,in_port:0000,tci(0) mac(10:11:11:11:11:11->50:54:00:00:00:07 ]) dnl Modified controller action. -AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> ofctl_monitor.log]) +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --pidfile 2> ofctl_monitor.log]) for i in 1 2 3 ; do ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=30:33:33:33:33:33,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=10)' @@ -272,7 +272,7 @@ priority:0,tunnel:0,in_port:0000,tci(vlan:15,pcp:0) mac(30:33:33:33:33:33->50:54 ]) dnl Checksum TCP. -AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> ofctl_monitor.log]) +AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log]) for i in 1 ; do ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=20:22:22:22:22:22,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=11)' @@ -280,31 +280,31 @@ done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=60 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->192.168.0.2) port(8->11) tcp_csum:1a03 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(8->11) tcp_csum:3205 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->11) tcp_csum:31b8 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d ]) @@ -317,45 +317,45 @@ done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=60 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x0 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->192.168.0.2) port(8->11) udp_csum:2c37 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(8->11) udp_csum:4439 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->11) udp_csum:43ec dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1 dnl -OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1 ]) AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_DURATION | sort], [0], [dnl cookie=0x0, duration=?s, table=0, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535 - cookie=0x1, duration=?s, table=0, n_packets=2, n_bytes=120, dl_src=20:22:22:22:22:22 actions=CONTROLLER:65535,resubmit:80 + cookie=0x1, duration=?s, table=0, n_packets=2, n_bytes=120, dl_src=20:22:22:22:22:22 actions=CONTROLLER:65535,resubmit(80,1) cookie=0x2, duration=?s, table=0, n_packets=3, n_bytes=180, dl_src=30:33:33:33:33:33 actions=mod_vlan_vid:15,CONTROLLER:65535 - cookie=0x3, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=80 actions=mod_vlan_vid:80,CONTROLLER:65535,resubmit:81 - cookie=0x4, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=81 actions=mod_dl_src:80:81:81:81:81:81,CONTROLLER:65535,resubmit:82 - cookie=0x5, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=82 actions=mod_dl_dst:82:82:82:82:82:82,CONTROLLER:65535,resubmit:83 - cookie=0x6, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=83 actions=mod_nw_src:83.83.83.83,CONTROLLER:65535,resubmit:84 - cookie=0x7, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=84 actions=mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit:85 - cookie=0x8, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit:86 - cookie=0x9, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535 + cookie=0x3, duration=?s, table=1, n_packets=2, n_bytes=120, in_port=80 actions=load:0x1->NXM_NX_REG0[[]],mod_vlan_vid:80,CONTROLLER:65535,resubmit(81,2) + cookie=0x4, duration=?s, table=2, n_packets=2, n_bytes=120, in_port=81 actions=load:0x2->NXM_NX_REG1[[]],mod_dl_src:80:81:81:81:81:81,CONTROLLER:65535,resubmit(82,3) + cookie=0x5, duration=?s, table=3, n_packets=2, n_bytes=120, in_port=82 actions=load:0x3->NXM_NX_REG2[[]],mod_dl_dst:82:82:82:82:82:82,CONTROLLER:65535,resubmit(83,4) + cookie=0x6, duration=?s, table=4, n_packets=2, n_bytes=120, in_port=83 actions=load:0x4->NXM_NX_REG3[[]],mod_nw_src:83.83.83.83,CONTROLLER:65535,resubmit(84,5) + cookie=0x7, duration=?s, table=5, n_packets=2, n_bytes=120, in_port=84 actions=load:0x5->NXM_NX_REG4[[]],load:0x6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6) + cookie=0x8, duration=?s, table=6, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7) + cookie=0x9, duration=?s, table=7, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535 NXST_FLOW reply (xid=0x4): ]) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 6c78c68f..9ad9554f 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1049,6 +1049,28 @@ above table, overrides \fBovs\-ofctl\fR's default choice of flow format. If a command cannot work as requested using the requested flow format, \fBovs\-ofctl\fR will report a fatal error. . +. +.IP "\fB\-P \fIformat\fR" +.IQ "\fB\-\-packet\-in\-format=\fIformat\fR" +\fBovs\-ofctl\fR supports the following packet_in formats, in order of +increasing capability: +.RS +.IP "\fBopenflow10\fR" +This is the standard OpenFlow 1.0 packet in format. It should be supported by +all OpenFlow switches. +. +.IP "\fBnxm\fR (Nicira Extended Match)" +This packet_in format includes flow metadata encoded using the NXM format. +. +.RE +.IP +Usually, \fBovs\-ofctl\fR prefers the \fBnxm\fR packet_in format, but will +allow the switch to choose its default if \fBnxm\fR is unsupported. When +\fIformat\fR is one of the formats listed in the above table, \fBovs\-ofctl\fR +will insist on the selected format. If the switch does not support the +requested format, \fBovs\-ofctl\fR will report a fatal error. This option only +affects the \fBmonitor\fR and \fBsnoop\fR commands. +. .IP "\fB\-m\fR" .IQ "\fB\-\-more\fR" Increases the verbosity of OpenFlow messages printed and logged by diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index ec7eee50..995a6c6c 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -68,6 +68,11 @@ static bool readd; * particular flow format or -1 to let ovs-ofctl choose intelligently. */ static int preferred_flow_format = -1; +/* -P, --packet-in-format: Packet IN format to use in monitor and snoop + * commands. Either one of NXPIF_* to force a particular packet_in format, or + * -1 to let ovs-ofctl choose the default. */ +static int preferred_packet_in_format = -1; + /* -m, --more: Additional verbosity for ofp-print functions. */ static int verbosity; @@ -100,6 +105,7 @@ parse_options(int argc, char *argv[]) {"strict", no_argument, NULL, OPT_STRICT}, {"readd", no_argument, NULL, OPT_READD}, {"flow-format", required_argument, NULL, 'F'}, + {"packet-in-format", required_argument, NULL, 'P'}, {"more", no_argument, NULL, 'm'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, @@ -137,6 +143,14 @@ parse_options(int argc, char *argv[]) } break; + case 'P': + preferred_packet_in_format = + ofputil_packet_in_format_from_string(optarg); + if (preferred_packet_in_format < 0) { + ovs_fatal(0, "unknown packet-in format `%s'", optarg); + } + break; + case 'm': verbosity++; break; @@ -207,6 +221,7 @@ usage(void) " --strict use strict match for flow commands\n" " --readd replace flows that haven't changed\n" " -F, --flow-format=FORMAT force particular flow format\n" + " -P, --packet-in-format=FRMT force particular packet in format\n" " -m, --more be more verbose printing OpenFlow\n" " -t, --timeout=SECS give up after SECS seconds\n" " -h, --help display this help message\n" @@ -767,6 +782,17 @@ do_del_flows(int argc, char *argv[]) do_flow_mod__(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); } +static void +set_packet_in_format(struct vconn *vconn, + enum nx_packet_in_format packet_in_format) +{ + struct ofpbuf *spif = ofputil_make_set_packet_in_format(packet_in_format); + transact_noreply(vconn, spif); + VLOG_DBG("%s: using user-specified packet in format %s", + vconn_get_name(vconn), + ofputil_packet_in_format_to_string(packet_in_format)); +} + static void monitor_vconn(struct vconn *vconn) { @@ -774,6 +800,24 @@ monitor_vconn(struct vconn *vconn) bool exiting = false; int error, fd; + if (preferred_packet_in_format >= 0) { + set_packet_in_format(vconn, preferred_packet_in_format); + } else { + struct ofpbuf *spif, *reply; + + spif = ofputil_make_set_packet_in_format(NXPIF_NXM); + run(vconn_transact_noreply(vconn, spif, &reply), + "talking to %s", vconn_get_name(vconn)); + if (reply) { + char *s = ofp_to_string(reply->data, reply->size, 2); + VLOG_DBG("%s: failed to set packet in format to nxm, controller" + " replied: %s. Falling back to the switch default.", + vconn_get_name(vconn), s); + free(s); + ofpbuf_delete(reply); + } + } + /* Daemonization will close stderr but we really want to keep it, so make a * copy. */ fd = dup(STDERR_FILENO); -- 2.30.2