From: Ethan Jackson Date: Tue, 5 Apr 2011 19:37:52 +0000 (-0700) Subject: autopath: Create the autopath action. X-Git-Tag: v1.2.0~469 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=3b6a2571f07e153e850a9bf2044699d8d4434ef0;p=sliver-openvswitch.git autopath: Create the autopath action. The newly created autopath action will be the way OpenFlow interacts with the existing bonding infrastructure. --- diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 663059f69..292a98738 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -223,7 +223,8 @@ enum nx_action_subtype { NXAST_REG_LOAD, /* struct nx_action_reg_load */ NXAST_NOTE, /* struct nx_action_note */ NXAST_SET_TUNNEL64, /* struct nx_action_set_tunnel64 */ - NXAST_MULTIPATH /* struct nx_action_multipath */ + NXAST_MULTIPATH, /* struct nx_action_multipath */ + NXAST_AUTOPATH /* struct nx_action_autopath */ }; /* Header for Nicira-defined actions. */ @@ -610,6 +611,51 @@ enum nx_mp_algorithm { #define NXFW_ALL NXFW_TUN_ID #define OVSFW_ALL (OFPFW_ALL | NXFW_ALL) +/* Action structure for NXAST_AUTOPATH. + * + * This action performs the following steps in sequence: + * + * 1. Hashes the flow using an implementation-defined hash function. + * + * The hashed fields' values are drawn from the current state of the + * flow, including all modifications that have been made by actions up to + * this point. + * + * 2. Selects an OpenFlow 'port'. + * + * 'port' is selected in an implementation-defined manner, taking into + * account 'id' and the hash value calculated in step 1. + * + * Generally a switch will have been configured with a set of ports that + * may be chosen given 'id'. The switch may take into account any number + * of factors when choosing 'port' from its configured set. Factors may + * include carrier, load, and the results of configuration protocols such + * as LACP. + * + * 3. Stores 'port' in dst[ofs:ofs+n_bits]. + * + * The format and semantics of 'dst' and 'ofs_nbits' are similar to those + * for the NXAST_REG_LOAD action, except that 'dst' must be + * NXM_NX_REG(idx) for 'idx' in the switch's supported range. + * + * The switch will reject actions in which ofs+n_bits is greater than the width + * of 'dst', with error type OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT. + */ +struct nx_action_autopath { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 20. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_MULTIPATH. */ + + /* Where to store the result. */ + ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ + ovs_be32 dst; /* Destination register. */ + + ovs_be32 id; /* Autopath ID. */ + ovs_be32 pad; +}; +OFP_ASSERT(sizeof(struct nx_action_autopath) == 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/automake.mk b/lib/automake.mk index ffebefa59..802cc9920 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -10,6 +10,8 @@ noinst_LIBRARIES += lib/libopenvswitch.a lib_libopenvswitch_a_SOURCES = \ lib/aes128.c \ lib/aes128.h \ + lib/autopath.c \ + lib/autopath.h \ lib/backtrace.c \ lib/backtrace.h \ lib/bitmap.c \ diff --git a/lib/autopath.c b/lib/autopath.c new file mode 100644 index 000000000..889b037bf --- /dev/null +++ b/lib/autopath.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 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. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "autopath.h" + +#include +#include + +#include "flow.h" +#include "nx-match.h" +#include "ofp-util.h" +#include "openflow/nicira-ext.h" +#include "vlog.h" + +VLOG_DEFINE_THIS_MODULE(autopath); + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + +/* Loads 'ofp_port' into the appropriate register in accordance with the + * autopath action. */ +void +autopath_execute(const struct nx_action_autopath *ap, struct flow *flow, + uint16_t ofp_port) +{ + uint32_t *reg = &flow->regs[NXM_NX_REG_IDX(ntohl(ap->dst))]; + int ofs = nxm_decode_ofs(ap->ofs_nbits); + int n_bits = nxm_decode_n_bits(ap->ofs_nbits); + uint32_t mask = n_bits == 32 ? UINT32_MAX : (UINT32_C(1) << n_bits) - 1; + *reg = (*reg & ~(mask << ofs)) | ((ofp_port & mask) << ofs); +} + +void +autopath_parse(struct nx_action_autopath *ap, const char *s_) +{ + char *s; + uint32_t reg; + int id_int, ofs, n_bits; + char *id_str, *dst, *save_ptr; + + s = xstrdup(s_); + save_ptr = NULL; + id_str = strtok_r(s, ", ", &save_ptr); + dst = strtok_r(NULL, ", ", &save_ptr); + + if (!dst) { + ovs_fatal(0, "%s: not enough arguments to autopath action", s_); + } + + id_int = atoi(id_str); + if (id_int < 1 || id_int > UINT32_MAX) { + ovs_fatal(0, "%s: autopath id %d is not in valid range " + "1 to %"PRIu32, s_, id_int, UINT32_MAX); + } + + nxm_parse_field_bits(dst, ®, &ofs, &n_bits); + if (!NXM_IS_NX_REG(reg) || NXM_NX_REG_IDX(reg) >= FLOW_N_REGS) { + ovs_fatal(0, "%s: destination field must be a register", s_); + } + + if (n_bits < 16) { + ovs_fatal(0, "%s: %d-bit destination field has %u possible values, " + "less than required 65536", s_, n_bits, 1u << n_bits); + } + + memset(ap, 0, sizeof *ap); + ap->type = htons(OFPAT_VENDOR); + ap->len = htons(sizeof *ap); + ap->vendor = htonl(NX_VENDOR_ID); + ap->subtype = htons(NXAST_AUTOPATH); + ap->id = htonl(id_int); + ap->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits); + ap->dst = htonl(reg); + + free(s); +} + +int +autopath_check(const struct nx_action_autopath *ap) +{ + uint32_t dst = ntohl(ap->dst); + int ofs = nxm_decode_ofs(ap->ofs_nbits); + int n_bits = nxm_decode_n_bits(ap->ofs_nbits); + + if (!NXM_IS_NX_REG(dst) || NXM_NX_REG_IDX(dst) >= FLOW_N_REGS) { + VLOG_WARN_RL(&rl, "unsupported destination field %#"PRIx32, dst); + } else if (ofs + n_bits > nxm_field_bits(dst)) { + VLOG_WARN_RL(&rl, "destination overflows output field"); + } else if (n_bits < 16) { + VLOG_WARN_RL(&rl, "minimum of 16 bits required in output field"); + } else { + return 0; + } + + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); +} diff --git a/lib/autopath.h b/lib/autopath.h new file mode 100644 index 000000000..ba55f90d3 --- /dev/null +++ b/lib/autopath.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AUTOPATH_H +#define AUTOPATH_H 1 + +#include + +struct flow; +struct nx_action_autopath; + +/* NXAST_AUTOPATH helper functions. + * + * See include/openflow/nicira-ext.h for NXAST_AUTOPATH specification. */ + +void autopath_execute(const struct nx_action_autopath *, struct flow *, + uint16_t ofp_port); +void autopath_parse(struct nx_action_autopath *, const char *); +int autopath_check(const struct nx_action_autopath *); + +#endif /* autopath.h */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index de7cd9c72..4c4811b65 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -22,6 +22,7 @@ #include #include +#include "autopath.h" #include "byte-order.h" #include "dynamic-string.h" #include "netdev.h" @@ -453,6 +454,10 @@ str_to_action(char *str, struct ofpbuf *b) struct nx_action_multipath *nam; nam = ofpbuf_put_uninit(b, sizeof *nam); multipath_parse(nam, arg); + } else if (!strcasecmp(act, "autopath")) { + struct nx_action_autopath *naa; + naa = ofpbuf_put_uninit(b, sizeof *naa); + autopath_parse(naa, arg); } else if (!strcasecmp(act, "output")) { put_output_action(b, str_to_u32(arg)); } else if (!strcasecmp(act, "enqueue")) { diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 1cd946260..f5eb9ad06 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -219,6 +219,7 @@ nx_action_len(enum nx_action_subtype subtype) case NXAST_NOTE: return -1; case NXAST_SET_TUNNEL64: return sizeof(struct nx_action_set_tunnel64); case NXAST_MULTIPATH: return sizeof(struct nx_action_multipath); + case NXAST_AUTOPATH: return sizeof (struct nx_action_autopath); default: return -1; } } @@ -244,6 +245,7 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah) const struct nx_action_reg_move *move; const struct nx_action_reg_load *load; const struct nx_action_multipath *nam; + const struct nx_action_autopath *naa; switch ((enum nx_action_subtype) subtype) { case NXAST_RESUBMIT: @@ -295,6 +297,15 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah) multipath_format(nam, string); return; + case NXAST_AUTOPATH: + naa = (const struct nx_action_autopath *)nah; + ds_put_format(string, "autopath(%u,", ntohl(naa->id)); + nxm_format_field_bits(string, ntohl(naa->dst), + nxm_decode_ofs(naa->ofs_nbits), + nxm_decode_n_bits(naa->ofs_nbits)); + ds_put_char(string, ')'); + return; + case NXAST_SNAT__OBSOLETE: default: break; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index cc448bcd6..c49b07988 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -19,6 +19,7 @@ #include #include #include +#include "autopath.h" #include "byte-order.h" #include "classifier.h" #include "dynamic-string.h" @@ -2014,6 +2015,14 @@ check_nicira_action(const union ofp_action *a, unsigned int len, } return multipath_check((const struct nx_action_multipath *) a); + case NXAST_AUTOPATH: + error = check_nx_action_exact_len( + nah, len, sizeof(struct nx_action_autopath)); + if (error) { + return error; + } + return autopath_check((const struct nx_action_autopath *) a); + case NXAST_SNAT__OBSOLETE: default: VLOG_WARN_RL(&bad_ofmsg_rl, diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 186527713..0b85e618c 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -24,6 +24,7 @@ #include #include #include +#include "autopath.h" #include "byte-order.h" #include "cfm.h" #include "classifier.h" @@ -2222,8 +2223,11 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_set_tunnel *nast; const struct nx_action_set_queue *nasq; const struct nx_action_multipath *nam; + const struct nx_action_autopath *naa; enum nx_action_subtype subtype = ntohs(nah->subtype); + const struct ofhooks *ofhooks = ctx->ofproto->ofhooks; struct xlate_reg_state state; + uint16_t autopath_port; ovs_be64 tun_id; assert(nah->vendor == htonl(NX_VENDOR_ID)); @@ -2285,6 +2289,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, multipath_execute(nam, &ctx->flow); break; + case NXAST_AUTOPATH: + naa = (const struct nx_action_autopath *) nah; + autopath_port = (ofhooks->autopath_cb + ? ofhooks->autopath_cb(&ctx->flow, ntohl(naa->id), + &ctx->tags, ctx->ofproto->aux) + : OFPP_NONE); + autopath_execute(naa, &ctx->flow, autopath_port); + break; + /* If you add a new action here that modifies flow data, don't forget to * update the flow key in ctx->flow at the same time. */ @@ -4415,5 +4428,6 @@ static const struct ofhooks default_ofhooks = { default_normal_ofhook_cb, NULL, NULL, + NULL, NULL }; diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 96f009888..9a56beec2 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -161,6 +161,9 @@ struct ofhooks { size_t actions_len, uint64_t n_bytes, void *aux); void (*account_checkpoint_cb)(void *aux); + + uint16_t (*autopath_cb)(const struct flow *, uint32_t id, + tag_type *, void *aux); }; void ofproto_revalidate(struct ofproto *, tag_type); struct tag_set *ofproto_get_revalidate_set(struct ofproto *); diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 2ce3368e1..d9742c8ec 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -642,6 +642,19 @@ Currently, \fIfields\fR must be either \fBeth_src\fR or the \fBiter_hash\fR algorithm uses \fIarg\fR. .IP Refer to \fBnicira\-ext.h\fR for more details. +. +.IP "\fBautopath(\fIid\fB, \fIdst\fB[\fIstart\fB..\fIend\fB])\fR" +Given \fIid\fR, chooses an OpenFlow port and populates it in +\fIdst\fB[\fIstart\fB..\fIend\fB]\fR, which must be an NXM register as +described above. +.IP +Currently, \fIid\fR should be the OpenFlow port number of an interface on the +bridge. If it isn't then \fIdst\fB[\fIstart\fB..\fIend\fB]\fR will be +populated with the OpenFlow port "none". If \fIid\fR is a member of a bond, +the normal bond selection logic will be used to choose the destination port. +Otherwise, the register will be populated with \fIid\fR itself. +.IP +Refer to \fBnicira\-ext.h\fR for more details. .RE . .IP diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 59100ccee..7997402e1 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -2694,11 +2694,37 @@ bridge_account_checkpoint_ofhook_cb(void *br_) } } +static uint16_t +bridge_autopath_ofhook_cb(const struct flow *flow, uint32_t ofp_port, + tag_type *tags, void *br_) +{ + struct bridge *br = br_; + uint16_t odp_port = ofp_port_to_odp_port(ofp_port); + struct port *port = port_from_dp_ifidx(br, odp_port); + uint16_t ret; + + if (!port) { + ret = ODPP_NONE; + } else if (list_is_short(&port->ifaces)) { + ret = odp_port; + } else { + struct iface *iface; + + /* Autopath does not support VLAN hashing. */ + iface = bond_choose_output_slave(port->bond, flow, + OFP_VLAN_NONE, tags); + ret = iface ? iface->dp_ifidx : ODPP_NONE; + } + + return odp_port_to_ofp_port(ret); +} + static struct ofhooks bridge_ofhooks = { bridge_normal_ofhook_cb, bridge_special_ofhook_cb, bridge_account_flow_ofhook_cb, bridge_account_checkpoint_ofhook_cb, + bridge_autopath_ofhook_cb, }; /* Port functions. */