2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-21 14:49:41 +00:00
Files
openvswitch/lib/multipath.c
Justin Pettit bcd2633a5b ofproto-dpif: Store relevant fields for wildcarding in facet.
Dynamically determines the flow fields that were relevant in
processing flows based on the OpenFlow flow table and switch
configuration.  The immediate use for this functionality is to
cache action translations for similar flows in facets.  This yields
a roughly 80% improvement in flow set up rates for a complicated
flow table.

More importantly, these wildcards will be used to determine what to
wildcard for the forthcoming kernel wildcard (megaflow) patches
that will allow wildcarding in the kernel, which will provide
significant flow set up improvements.

The approach to tracking fields and caching action translations in
facets was based on an impressive prototype by Ethan Jackson.

Co-authored-by: Ethan Jackson <ethan@nicira.com>
Signed-off-by: Ethan Jackson <ethan@nicira.com>
Signed-off-by: Justin Pettit <jpettit@nicira.com>
2013-06-11 13:03:50 -07:00

288 lines
8.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2010, 2011, 2012 Nicira, Inc.
*
* 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 <config.h>
#include "multipath.h"
#include <arpa/inet.h>
#include <inttypes.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "dynamic-string.h"
#include "nx-match.h"
#include "ofp-actions.h"
#include "ofp-errors.h"
#include "ofp-util.h"
#include "openflow/nicira-ext.h"
#include "packets.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(multipath);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
/* Converts 'nam' into 'mp'. Returns 0 if successful, otherwise an
* OFPERR_*. */
enum ofperr
multipath_from_openflow(const struct nx_action_multipath *nam,
struct ofpact_multipath *mp)
{
uint32_t n_links = ntohs(nam->max_link) + 1;
size_t min_n_bits = log_2_ceil(n_links);
ofpact_init_MULTIPATH(mp);
mp->fields = ntohs(nam->fields);
mp->basis = ntohs(nam->basis);
mp->algorithm = ntohs(nam->algorithm);
mp->max_link = ntohs(nam->max_link);
mp->arg = ntohl(nam->arg);
mp->dst.field = mf_from_nxm_header(ntohl(nam->dst));
mp->dst.ofs = nxm_decode_ofs(nam->ofs_nbits);
mp->dst.n_bits = nxm_decode_n_bits(nam->ofs_nbits);
if (!flow_hash_fields_valid(mp->fields)) {
VLOG_WARN_RL(&rl, "unsupported fields %d", (int) mp->fields);
return OFPERR_OFPBAC_BAD_ARGUMENT;
} else if (mp->algorithm != NX_MP_ALG_MODULO_N
&& mp->algorithm != NX_MP_ALG_HASH_THRESHOLD
&& mp->algorithm != NX_MP_ALG_HRW
&& mp->algorithm != NX_MP_ALG_ITER_HASH) {
VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) mp->algorithm);
return OFPERR_OFPBAC_BAD_ARGUMENT;
} else if (mp->dst.n_bits < min_n_bits) {
VLOG_WARN_RL(&rl, "multipath action requires at least %zu bits for "
"%"PRIu32" links", min_n_bits, n_links);
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
return multipath_check(mp, NULL);
}
/* Checks that 'mp' is valid on flow. Returns 0 if it is valid, otherwise an
* OFPERR_*. */
enum ofperr
multipath_check(const struct ofpact_multipath *mp,
const struct flow *flow)
{
return mf_check_dst(&mp->dst, flow);
}
/* Converts 'mp' into an OpenFlow NXAST_MULTIPATH action, which it appends to
* 'openflow'. */
void
multipath_to_nxast(const struct ofpact_multipath *mp, struct ofpbuf *openflow)
{
struct nx_action_multipath *nam = ofputil_put_NXAST_MULTIPATH(openflow);
nam->fields = htons(mp->fields);
nam->basis = htons(mp->basis);
nam->algorithm = htons(mp->algorithm);
nam->max_link = htons(mp->max_link);
nam->arg = htonl(mp->arg);
nam->ofs_nbits = nxm_encode_ofs_nbits(mp->dst.ofs, mp->dst.n_bits);
nam->dst = htonl(mp->dst.field->nxm_header);
}
/* multipath_execute(). */
static uint16_t multipath_algorithm(uint32_t hash, enum nx_mp_algorithm,
unsigned int n_links, unsigned int arg);
/* Executes 'mp' based on the current contents of 'flow', writing the results
* back into 'flow'. Sets fields in 'wc' that were used to calculate
* the result. */
void
multipath_execute(const struct ofpact_multipath *mp, struct flow *flow,
struct flow_wildcards *wc)
{
/* Calculate value to store. */
uint32_t hash = flow_hash_fields(flow, mp->fields, mp->basis);
uint16_t link = multipath_algorithm(hash, mp->algorithm,
mp->max_link + 1, mp->arg);
flow_mask_hash_fields(wc, mp->fields);
nxm_reg_load(&mp->dst, link, flow);
}
static uint16_t
algorithm_hrw(uint32_t hash, unsigned int n_links)
{
uint32_t best_weight;
uint16_t best_link;
unsigned int link;
best_link = 0;
best_weight = hash_2words(hash, 0);
for (link = 1; link < n_links; link++) {
uint32_t weight = hash_2words(hash, link);
if (weight > best_weight) {
best_link = link;
best_weight = weight;
}
}
return best_link;
}
/* Works for 'x' in the range [1,65536], which is all we need. */
static unsigned int
round_up_pow2(unsigned int x)
{
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
return x + 1;
}
static uint16_t
algorithm_iter_hash(uint32_t hash, unsigned int n_links, unsigned int modulo)
{
uint16_t link;
int i;
if (modulo < n_links || modulo / 2 > n_links) {
modulo = round_up_pow2(n_links);
}
i = 0;
do {
link = hash_2words(hash, i++) % modulo;
} while (link >= n_links);
return link;
}
static uint16_t
multipath_algorithm(uint32_t hash, enum nx_mp_algorithm algorithm,
unsigned int n_links, unsigned int arg)
{
switch (algorithm) {
case NX_MP_ALG_MODULO_N:
return hash % n_links;
case NX_MP_ALG_HASH_THRESHOLD:
if (n_links == 1) {
return 0;
}
return hash / (UINT32_MAX / n_links + 1);
case NX_MP_ALG_HRW:
return (n_links <= 64
? algorithm_hrw(hash, n_links)
: algorithm_iter_hash(hash, n_links, 0));
case NX_MP_ALG_ITER_HASH:
return algorithm_iter_hash(hash, n_links, arg);
}
NOT_REACHED();
}
/* Parses 's_' as a set of arguments to the "multipath" action and initializes
* 'mp' accordingly. ovs-ofctl(8) describes the format parsed.
*
* Prints an error on stderr and aborts the program if 's_' syntax is
* invalid. */
void
multipath_parse(struct ofpact_multipath *mp, const char *s_)
{
char *s = xstrdup(s_);
char *save_ptr = NULL;
char *fields, *basis, *algorithm, *n_links_str, *arg, *dst;
int n_links;
fields = strtok_r(s, ", ", &save_ptr);
basis = strtok_r(NULL, ", ", &save_ptr);
algorithm = strtok_r(NULL, ", ", &save_ptr);
n_links_str = strtok_r(NULL, ", ", &save_ptr);
arg = strtok_r(NULL, ", ", &save_ptr);
dst = strtok_r(NULL, ", ", &save_ptr);
if (!dst) {
ovs_fatal(0, "%s: not enough arguments to multipath action", s_);
}
ofpact_init_MULTIPATH(mp);
if (!strcasecmp(fields, "eth_src")) {
mp->fields = NX_HASH_FIELDS_ETH_SRC;
} else if (!strcasecmp(fields, "symmetric_l4")) {
mp->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
} else {
ovs_fatal(0, "%s: unknown fields `%s'", s_, fields);
}
mp->basis = atoi(basis);
if (!strcasecmp(algorithm, "modulo_n")) {
mp->algorithm = NX_MP_ALG_MODULO_N;
} else if (!strcasecmp(algorithm, "hash_threshold")) {
mp->algorithm = NX_MP_ALG_HASH_THRESHOLD;
} else if (!strcasecmp(algorithm, "hrw")) {
mp->algorithm = NX_MP_ALG_HRW;
} else if (!strcasecmp(algorithm, "iter_hash")) {
mp->algorithm = NX_MP_ALG_ITER_HASH;
} else {
ovs_fatal(0, "%s: unknown algorithm `%s'", s_, algorithm);
}
n_links = atoi(n_links_str);
if (n_links < 1 || n_links > 65536) {
ovs_fatal(0, "%s: n_links %d is not in valid range 1 to 65536",
s_, n_links);
}
mp->max_link = n_links - 1;
mp->arg = atoi(arg);
mf_parse_subfield(&mp->dst, dst);
if (mp->dst.n_bits < 16 && n_links > (1u << mp->dst.n_bits)) {
ovs_fatal(0, "%s: %d-bit destination field has %u possible values, "
"less than specified n_links %d",
s_, mp->dst.n_bits, 1u << mp->dst.n_bits, n_links);
}
free(s);
}
/* Appends a description of 'mp' to 's', in the format that ovs-ofctl(8)
* describes. */
void
multipath_format(const struct ofpact_multipath *mp, struct ds *s)
{
const char *fields, *algorithm;
fields = flow_hash_fields_to_str(mp->fields);
switch (mp->algorithm) {
case NX_MP_ALG_MODULO_N:
algorithm = "modulo_n";
break;
case NX_MP_ALG_HASH_THRESHOLD:
algorithm = "hash_threshold";
break;
case NX_MP_ALG_HRW:
algorithm = "hrw";
break;
case NX_MP_ALG_ITER_HASH:
algorithm = "iter_hash";
break;
default:
algorithm = "<unknown>";
}
ds_put_format(s, "multipath(%s,%"PRIu16",%s,%d,%"PRIu16",",
fields, mp->basis, algorithm, mp->max_link + 1,
mp->arg);
mf_format_subfield(&mp->dst, s);
ds_put_char(s, ')');
}