From f694937d4ec5342b218b760cabbf7a48d19110e8 Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Wed, 10 Aug 2011 13:05:17 -0700 Subject: [PATCH] nicra-ext: New action NXAST_OUTPUT_REG. The NXAST_OUTPUT_REG action outputs to the OpenFlow port contained in a supplied NXM field. --- NEWS | 3 +++ include/openflow/nicira-ext.h | 33 ++++++++++++++++++++++++++++++++- lib/ofp-parse.c | 23 ++++++++++++++++++++++- lib/ofp-print.c | 8 ++++++++ lib/ofp-util.c | 22 ++++++++++++++++++++++ lib/ofp-util.h | 3 ++- ofproto/ofproto-dpif.c | 19 +++++++++++++++++++ tests/ofproto-dpif.at | 19 +++++++++++++++++++ tests/ovs-ofctl.at | 2 ++ utilities/ovs-ofctl.8.in | 9 ++++++++- 10 files changed, 137 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index a55af1371..ae6f55e7a 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ Post-v1.2.0 ------------------------ + - OpenFlow: + - Added an OpenFlow extension which allows the "output" action to accept + NXM fields. - ovs-appctl: - New "version" command to determine version of running daemon - ovs-vswitchd: diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index bbe96b35b..4fab6f17c 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -280,7 +280,8 @@ enum nx_action_subtype { NXAST_AUTOPATH, /* struct nx_action_autopath */ NXAST_BUNDLE, /* struct nx_action_bundle */ NXAST_BUNDLE_LOAD, /* struct nx_action_bundle */ - NXAST_RESUBMIT_TABLE /* struct nx_action_resubmit */ + NXAST_RESUBMIT_TABLE, /* struct nx_action_resubmit */ + NXAST_OUTPUT_REG /* struct nx_action_output_reg */ }; /* Header for Nicira-defined actions. */ @@ -781,6 +782,36 @@ enum nx_bd_algorithm { NX_BD_ALG_HRW /* Highest Random Weight. */ }; +/* Action structure for NXAST_OUTPUT_REG. + * + * Outputs to the OpenFlow port number written to src[ofs:ofs+nbits]. + * + * The format and semantics of 'src' and 'ofs_nbits' are similar to those for + * the NXAST_REG_LOAD action. + * + * The acceptable nxm_header values for 'src' are the same as the acceptable + * nxm_header values for the 'src' field of NXAST_REG_MOVE. + * + * The 'max_len' field indicates the number of bytes to send when the chosen + * port is OFPP_CONTROLLER. Its semantics are equivalent to the 'max_len' + * field of OFPAT_OUTPUT. + * + * The 'zero' field is required to be zeroed for forward compatibility. */ +struct nx_action_output_reg { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* 24. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_OUTPUT_REG. */ + + ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ + ovs_be32 src; /* Source. */ + + ovs_be16 max_len; /* Max length to send to controller. */ + + uint8_t zero[6]; /* Reserved, must be zero. */ +}; +OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24); + /* Flexible flow specifications (aka NXM = Nicira Extended Match). * * OpenFlow 1.0 has "struct ofp_match" for specifying flow matches. This diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 89620a61a..e352bd436 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -316,6 +316,27 @@ parse_port_name(const char *name, uint16_t *port) return false; } +static void +parse_output(struct ofpbuf *b, char *arg) +{ + if (strchr(arg, '[')) { + struct nx_action_output_reg *naor; + int ofs, n_bits; + uint32_t src; + + nxm_parse_field_bits(arg, &src, &ofs, &n_bits); + + naor = put_action(b, sizeof *naor, OFPAT_VENDOR); + naor->vendor = htonl(NX_VENDOR_ID); + naor->subtype = htons(NXAST_OUTPUT_REG); + naor->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits); + naor->src = htonl(src); + naor->max_len = htons(UINT16_MAX); + } else { + put_output_action(b, str_to_u32(arg)); + } +} + static void parse_resubmit(struct nx_action_resubmit *nar, char *arg) { @@ -541,7 +562,7 @@ str_to_action(char *str, struct ofpbuf *b) } else if (!strcasecmp(act, "bundle_load")) { bundle_parse_load(b, arg); } else if (!strcasecmp(act, "output")) { - put_output_action(b, str_to_u32(arg)); + parse_output(b, arg); } else if (!strcasecmp(act, "enqueue")) { char *sp = NULL; char *port_s = strtok_r(arg, ":q", &sp); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index d1a661bf2..4c94ebb8f 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -218,6 +218,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a, const struct nx_action_reg_load *load; const struct nx_action_multipath *nam; const struct nx_action_autopath *naa; + const struct nx_action_output_reg *naor; uint16_t port; switch (code) { @@ -361,6 +362,13 @@ ofp_print_action(struct ds *s, const union ofp_action *a, bundle_format((const struct nx_action_bundle *) a, s); break; + case OFPUTIL_NXAST_OUTPUT_REG: + naor = (const struct nx_action_output_reg *) a; + ds_put_cstr(s, "output:"); + nxm_format_field_bits(s, ntohl(naor->src), + nxm_decode_ofs(naor->ofs_nbits), + nxm_decode_n_bits(naor->ofs_nbits)); + default: break; } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index b0aeaf4f1..b0e74055d 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1979,6 +1979,22 @@ check_resubmit_table(const struct nx_action_resubmit *nar) return 0; } +static int +check_output_reg(const struct nx_action_output_reg *naor, + const struct flow *flow) +{ + size_t i; + + for (i = 0; i < sizeof naor->zero; i++) { + if (naor->zero[i]) { + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + } + } + + return nxm_src_check(naor->src, nxm_decode_ofs(naor->ofs_nbits), + nxm_decode_n_bits(naor->ofs_nbits), flow); +} + int validate_actions(const union ofp_action *actions, size_t n_actions, const struct flow *flow, int max_ports) @@ -2057,6 +2073,11 @@ validate_actions(const union ofp_action *actions, size_t n_actions, max_ports, flow); break; + case OFPUTIL_NXAST_OUTPUT_REG: + error = check_output_reg((const struct nx_action_output_reg *) a, + flow); + break; + case OFPUTIL_NXAST_RESUBMIT_TABLE: error = check_resubmit_table( (const struct nx_action_resubmit *) a); @@ -2170,6 +2191,7 @@ ofputil_decode_nxast_action(const union ofp_action *a) NXAST_ACTION(NXAST_BUNDLE, struct nx_action_bundle, true); NXAST_ACTION(NXAST_BUNDLE_LOAD, struct nx_action_bundle, true); NXAST_ACTION(NXAST_RESUBMIT_TABLE, struct nx_action_resubmit, false); + NXAST_ACTION(NXAST_OUTPUT_REG, struct nx_action_output_reg, false); #undef NXAST_ACTION case NXAST_SNAT__OBSOLETE: diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 9f3685ca7..b110d7166 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -304,7 +304,8 @@ enum ofputil_action_code { OFPUTIL_NXAST_AUTOPATH, OFPUTIL_NXAST_BUNDLE, OFPUTIL_NXAST_BUNDLE_LOAD, - OFPUTIL_NXAST_RESUBMIT_TABLE + OFPUTIL_NXAST_RESUBMIT_TABLE, + OFPUTIL_NXAST_OUTPUT_REG }; int ofputil_decode_action(const union ofp_action *); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 010d98b42..fdef4afa5 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3019,6 +3019,19 @@ xlate_output_action__(struct action_xlate_ctx *ctx, } } +static void +xlate_output_reg_action(struct action_xlate_ctx *ctx, + const struct nx_action_output_reg *naor) +{ + uint64_t ofp_port; + + ofp_port = nxm_read_field_bits(naor->src, naor->ofs_nbits, &ctx->flow); + + if (ofp_port <= UINT16_MAX) { + xlate_output_action__(ctx, ofp_port, ntohs(naor->max_len)); + } +} + static void xlate_output_action(struct action_xlate_ctx *ctx, const struct ofp_action_output *oao) @@ -3154,6 +3167,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, const struct nx_action_multipath *nam; const struct nx_action_autopath *naa; const struct nx_action_bundle *nab; + const struct nx_action_output_reg *naor; enum ofputil_action_code code; ovs_be64 tun_id; @@ -3279,6 +3293,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, bundle_execute_load(nab, &ctx->flow, slave_enabled_cb, ctx->ofproto); break; + + case OFPUTIL_NXAST_OUTPUT_REG: + naor = (const struct nx_action_output_reg *) ia; + xlate_output_reg_action(ctx, naor); + break; } } } diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index a255a6bdb..c504dfe65 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -42,3 +42,22 @@ AT_CHECK([tail -1 stdout], [0], ]) OFPROTO_STOP AT_CLEANUP + +AT_SETUP([ofproto-dpif - output]) +OFPROTO_START +AT_DATA([flows.txt], [dnl +in_port=1 actions=resubmit:2,resubmit:3,resubmit:4,resubmit:5,resubmit:6,resubmit:7 +in_port=2 actions=output:9 +in_port=3 actions=load:55->NXM_NX_REG0[[]],output:NXM_NX_REG0[[]],load:66->NXM_NX_REG1[[]] +in_port=4 actions=output:10,output:NXM_NX_REG0[[]],output:NXM_NX_REG1[[]],output:11 +in_port=5 actions=load:77->NXM_NX_REG0[[0..15]],load:88->NXM_NX_REG0[[16..31]] +in_port=6 actions=output:NXM_NX_REG0[[0..15]],output:NXM_NX_REG0[[16..31]] +in_port=7 actions=load:0x110000ff->NXM_NX_REG0[[]],output:NXM_NX_REG0[[]] +]) +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) +AT_CHECK([ovs-appctl -t test-openflowd ofproto/trace br0 '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=1,tos=0),icmp(type=8,code=0)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: 9,55,10,55,66,11,77,88 +]) +OFPROTO_STOP +AT_CLEANUP diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 1edfb6244..d1acb6b32 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -24,6 +24,7 @@ actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3) actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:) actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2 actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3) +actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3 ]]) AT_CHECK([ovs-ofctl parse-flows flows.txt @@ -52,6 +53,7 @@ NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_N NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:) NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2 NXT_FLOW_MOD: ADD table:255 actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3) +NXT_FLOW_MOD: ADD table:255 actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3 ]]) AT_CLEANUP diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index b0e709e6f..f4e223eaf 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -571,7 +571,14 @@ of the following keywords: . .RS .IP \fBoutput\fR:\fIport\fR -Outputs the packet on the port specified by \fIport\fR. +.IQ \fBoutput\fR:\fIsrc\fB[\fIstart\fB..\fIend\fB] +Outputs the packet. If \fIport\fR is an OpenFlow port number, outputs directly +to it. Otherwise, outputs to the OpenFlow port number read from \fIsrc\fR +which must be an NXM field as described above. Outputting to an NXM field is +an OpenFlow extension which is not supported by standard OpenFlow switches. +.IP +Example: \fBoutput:NXM_NX_REG0[16..31]\fR outputs to the OpenFlow port number +written in the upper half of register 0. . .IP \fBenqueue\fR:\fIport\fB:\fIqueue\fR Enqueues the packet on the specified \fIqueue\fR within port -- 2.43.0