summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJesse Gross <jesse@kernel.org>2016-04-19 18:36:04 -0700
committerJesse Gross <jesse@kernel.org>2016-09-19 09:52:22 -0700
commit8d8ab6c2d5743eb229a5e7c27ccd963a2c103adb (patch)
treed198a78ddf968ab119e029ca998eba2337812cd8 /lib
parent56fb20c4a1622c0f19bd2865c6688bdc78d5b40f (diff)
downloadopenvswitch-8d8ab6c2d5743eb229a5e7c27ccd963a2c103adb.tar.gz
tun-metadata: Manage tunnel TLV mapping table on a per-bridge basis.
When using tunnel TLVs (at the moment, this means Geneve options), a controller must first map the class and type onto an appropriate OXM field so that it can be used in OVS flow operations. This table is managed using OpenFlow extensions. The original code that added support for TLVs made the mapping table global as a simplification. However, this is not really logically correct as the OpenFlow management commands are operating on a per-bridge basis. This removes the original limitation to make the table per-bridge. One nice result of this change is that it is generally clearer whether the tunnel metadata is in datapath or OpenFlow format. Rather than allowing ad-hoc format changes and trying to handle both formats in the tunnel metadata functions, the format is more clearly separated by function. Datapaths (both kernel and userspace) use datapath format and it is not changed during the upcall process. At the beginning of action translation, tunnel metadata is converted to OpenFlow format and flows and wildcards are translated back at the end of the process. As an additional benefit, this change improves performance in some flow setup situations by keeping the tunnel metadata in the original packet format in more cases. This helps when copies need to be made as the amount of data touched is only what is present in the packet rather than the maximum amount of metadata supported. Co-authored-by: Madhu Challa <challa@noironetworks.com> Signed-off-by: Madhu Challa <challa@noironetworks.com> Signed-off-by: Jesse Gross <jesse@kernel.org> Acked-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/classifier.c5
-rw-r--r--lib/classifier.h3
-rw-r--r--lib/dpctl.c5
-rw-r--r--lib/dpif-netdev.c65
-rw-r--r--lib/flow.c1
-rw-r--r--lib/learning-switch.c3
-rw-r--r--lib/match.c5
-rw-r--r--lib/nx-match.c43
-rw-r--r--lib/nx-match.h15
-rw-r--r--lib/odp-execute.c2
-rw-r--r--lib/odp-util.c88
-rw-r--r--lib/odp-util.h14
-rw-r--r--lib/ofp-parse.c4
-rw-r--r--lib/ofp-print.c6
-rw-r--r--lib/ofp-util.c76
-rw-r--r--lib/tun-metadata.c388
-rw-r--r--lib/tun-metadata.h21
17 files changed, 268 insertions, 476 deletions
diff --git a/lib/classifier.c b/lib/classifier.c
index 055114627..782ef071e 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -268,9 +268,10 @@ cls_rule_equal(const struct cls_rule *a, const struct cls_rule *b)
/* Appends a string describing 'rule' to 's'. */
void
-cls_rule_format(const struct cls_rule *rule, struct ds *s)
+cls_rule_format(const struct cls_rule *rule, const struct tun_table *tun_table,
+ struct ds *s)
{
- minimatch_format(&rule->match, s, rule->priority);
+ minimatch_format(&rule->match, tun_table, s, rule->priority);
}
/* Returns true if 'rule' matches every packet, false otherwise. */
diff --git a/lib/classifier.h b/lib/classifier.h
index 44185a37a..c57fa6fc4 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -412,7 +412,8 @@ int classifier_count(const struct classifier *);
/* Classifier rule properties. These are RCU protected and may run
* concurrently with modifiers and each other. */
bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *);
-void cls_rule_format(const struct cls_rule *, struct ds *);
+void cls_rule_format(const struct cls_rule *, const struct tun_table *,
+ struct ds *);
bool cls_rule_is_catchall(const struct cls_rule *);
bool cls_rule_is_loose_match(const struct cls_rule *rule,
const struct minimatch *criteria);
diff --git a/lib/dpctl.c b/lib/dpctl.c
index 28f2f834d..edccb7f4a 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -803,7 +803,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}
if (filter) {
- char *err = parse_ofp_exact_flow(&flow_filter, &wc_filter, filter,
+ char *err = parse_ofp_exact_flow(&flow_filter, &wc_filter, NULL, filter,
&names_portno);
if (err) {
dpctl_error(dpctl_p, 0, "Failed to parse filter (%s)", err);
@@ -829,8 +829,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
struct minimatch minimatch;
odp_flow_key_to_flow(f.key, f.key_len, &flow);
- odp_flow_key_to_mask(f.mask, f.mask_len, f.key, f.key_len,
- &wc, &flow);
+ odp_flow_key_to_mask(f.mask, f.mask_len, &wc, &flow);
match_init(&match, &flow, &wc);
match_init(&match_filter, &flow_filter, &wc);
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index ecc7cea8d..6e09e44eb 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2117,8 +2117,7 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
{
enum odp_key_fitness fitness;
- fitness = odp_flow_key_to_mask_udpif(mask_key, mask_key_len, key,
- key_len, wc, flow);
+ fitness = odp_flow_key_to_mask(mask_key, mask_key_len, wc, flow);
if (fitness) {
/* This should not happen: it indicates that
* odp_flow_key_from_mask() and odp_flow_key_to_mask()
@@ -2149,7 +2148,7 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
{
odp_port_t in_port;
- if (odp_flow_key_to_flow_udpif(key, key_len, flow)) {
+ if (odp_flow_key_to_flow(key, key_len, flow)) {
/* This should not happen: it indicates that odp_flow_key_from_flow()
* and odp_flow_key_to_flow() disagree on the acceptable form of a
* flow. Log the problem as an error, with enough details to enable
@@ -3784,27 +3783,11 @@ dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet_,
struct ofpbuf *actions, struct ofpbuf *put_actions)
{
struct dp_netdev *dp = pmd->dp;
- struct flow_tnl orig_tunnel;
- int err;
if (OVS_UNLIKELY(!dp->upcall_cb)) {
return ENODEV;
}
- /* Upcall processing expects the Geneve options to be in the translated
- * format but we need to retain the raw format for datapath use. */
- orig_tunnel.flags = flow->tunnel.flags;
- if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
- orig_tunnel.metadata.present.len = flow->tunnel.metadata.present.len;
- memcpy(orig_tunnel.metadata.opts.gnv, flow->tunnel.metadata.opts.gnv,
- flow->tunnel.metadata.present.len);
- err = tun_metadata_from_geneve_udpif(&orig_tunnel, &orig_tunnel,
- &flow->tunnel);
- if (err) {
- return err;
- }
- }
-
if (OVS_UNLIKELY(!VLOG_DROP_DBG(&upcall_rl))) {
struct ds ds = DS_EMPTY_INITIALIZER;
char *packet_str;
@@ -3831,48 +3814,8 @@ dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet_,
ds_destroy(&ds);
}
- err = dp->upcall_cb(packet_, flow, ufid, pmd->core_id, type, userdata,
- actions, wc, put_actions, dp->upcall_aux);
- if (err && err != ENOSPC) {
- return err;
- }
-
- /* Translate tunnel metadata masks to datapath format. */
- if (wc) {
- if (wc->masks.tunnel.metadata.present.map) {
- struct geneve_opt opts[TLV_TOT_OPT_SIZE /
- sizeof(struct geneve_opt)];
-
- if (orig_tunnel.flags & FLOW_TNL_F_UDPIF) {
- tun_metadata_to_geneve_udpif_mask(&flow->tunnel,
- &wc->masks.tunnel,
- orig_tunnel.metadata.opts.gnv,
- orig_tunnel.metadata.present.len,
- opts);
- } else {
- orig_tunnel.metadata.present.len = 0;
- }
-
- memset(&wc->masks.tunnel.metadata, 0,
- sizeof wc->masks.tunnel.metadata);
- memcpy(&wc->masks.tunnel.metadata.opts.gnv, opts,
- orig_tunnel.metadata.present.len);
- }
- wc->masks.tunnel.metadata.present.len = 0xff;
- }
-
- /* Restore tunnel metadata. We need to use the saved options to ensure
- * that any unknown options are not lost. The generated mask will have
- * the same structure, matching on types and lengths but wildcarding
- * option data we don't care about. */
- if (orig_tunnel.flags & FLOW_TNL_F_UDPIF) {
- memcpy(&flow->tunnel.metadata.opts.gnv, orig_tunnel.metadata.opts.gnv,
- orig_tunnel.metadata.present.len);
- flow->tunnel.metadata.present.len = orig_tunnel.metadata.present.len;
- flow->tunnel.flags |= FLOW_TNL_F_UDPIF;
- }
-
- return err;
+ return dp->upcall_cb(packet_, flow, ufid, pmd->core_id, type, userdata,
+ actions, wc, put_actions, dp->upcall_aux);
}
static inline uint32_t
diff --git a/lib/flow.c b/lib/flow.c
index ba4f8c774..f4ac8b305 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -1298,6 +1298,7 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
wc->masks.tunnel.metadata.present.map =
flow->tunnel.metadata.present.map;
WC_MASK_FIELD(wc, tunnel.metadata.opts.u8);
+ WC_MASK_FIELD(wc, tunnel.metadata.tab);
}
} else {
WC_MASK_FIELD(wc, tunnel.metadata.present.len);
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 82609e80c..30aab1210 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -523,7 +523,8 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
struct dp_packet pkt;
struct flow flow;
- error = ofputil_decode_packet_in(oh, true, &pi, NULL, &buffer_id, NULL);
+ error = ofputil_decode_packet_in(oh, true, NULL, &pi, NULL,
+ &buffer_id, NULL);
if (error) {
VLOG_WARN_RL(&rl, "failed to decode packet-in: %s",
ofperr_to_string(error));
diff --git a/lib/match.c b/lib/match.c
index d78e6a19d..3fcaec5b0 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -1463,11 +1463,14 @@ minimatch_matches_flow(const struct minimatch *match,
/* Appends a string representation of 'match' to 's'. If 'priority' is
* different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
void
-minimatch_format(const struct minimatch *match, struct ds *s, int priority)
+minimatch_format(const struct minimatch *match,
+ const struct tun_table *tun_table,struct ds *s, int priority)
{
struct match megamatch;
minimatch_expand(match, &megamatch);
+ megamatch.flow.tunnel.metadata.tab = tun_table;
+
match_format(&megamatch, s, priority);
}
diff --git a/lib/nx-match.c b/lib/nx-match.c
index b03ccf260..9201aaeac 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -474,11 +474,13 @@ nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie,
static enum ofperr
nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
- struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
ovs_assert((cookie != NULL) == (cookie_mask != NULL));
match_init_catchall(match);
+ match->flow.tunnel.metadata.tab = tun_table;
if (cookie) {
*cookie = *cookie_mask = htonll(0);
}
@@ -529,13 +531,15 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
}
}
+ match->flow.tunnel.metadata.tab = NULL;
return 0;
}
static enum ofperr
nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
struct match *match,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
uint8_t *p = NULL;
@@ -549,7 +553,8 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
}
}
- return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask);
+ return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask,
+ tun_table);
}
/* Parses the nx_match formatted match description in 'b' with length
@@ -562,9 +567,11 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
- return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask);
+ return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask,
+ tun_table);
}
/* Behaves the same as nx_pull_match(), but skips over unknown NXM headers,
@@ -572,13 +579,16 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match,
enum ofperr
nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len,
struct match *match,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
- return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask);
+ return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask,
+ tun_table);
}
static enum ofperr
-oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
+oxm_pull_match__(struct ofpbuf *b, bool strict,
+ const struct tun_table *tun_table, struct match *match)
{
struct ofp11_match_header *omh = b->data;
uint8_t *p;
@@ -606,7 +616,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
}
return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh,
- strict, match, NULL, NULL);
+ strict, match, NULL, NULL, tun_table);
}
/* Parses the oxm formatted match description preceded by a struct
@@ -616,17 +626,19 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
*
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-oxm_pull_match(struct ofpbuf *b, struct match *match)
+oxm_pull_match(struct ofpbuf *b, const struct tun_table *tun_table,
+ struct match *match)
{
- return oxm_pull_match__(b, true, match);
+ return oxm_pull_match__(b, true, tun_table, match);
}
/* Behaves the same as oxm_pull_match() with one exception. Skips over unknown
* OXM headers instead of failing with an error when they are encountered. */
enum ofperr
-oxm_pull_match_loose(struct ofpbuf *b, struct match *match)
+oxm_pull_match_loose(struct ofpbuf *b, const struct tun_table *tun_table,
+ struct match *match)
{
- return oxm_pull_match__(b, false, match);
+ return oxm_pull_match__(b, false, tun_table, match);
}
/* Parses the OXM match description in the 'oxm_len' bytes in 'oxm'. Stores
@@ -636,9 +648,10 @@ oxm_pull_match_loose(struct ofpbuf *b, struct match *match)
*
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-oxm_decode_match(const void *oxm, size_t oxm_len, struct match *match)
+oxm_decode_match(const void *oxm, size_t oxm_len,
+ const struct tun_table *tun_table, struct match *match)
{
- return nx_pull_raw(oxm, oxm_len, true, match, NULL, NULL);
+ return nx_pull_raw(oxm, oxm_len, true, match, NULL, NULL, tun_table);
}
/* Verify an array of OXM TLVs treating value of each TLV as a mask,
diff --git a/lib/nx-match.h b/lib/nx-match.h
index c366a04cc..a86cceb38 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -50,13 +50,18 @@ char *mf_parse_subfield(struct mf_subfield *, const char *s)
/* Decoding matches. */
enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len,
struct match *,
- ovs_be64 *cookie, ovs_be64 *cookie_mask);
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *);
enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len,
struct match *, ovs_be64 *cookie,
- ovs_be64 *cookie_mask);
-enum ofperr oxm_pull_match(struct ofpbuf *, struct match *);
-enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *);
-enum ofperr oxm_decode_match(const void *, size_t, struct match *);
+ ovs_be64 *cookie_mask,
+ const struct tun_table *);
+enum ofperr oxm_pull_match(struct ofpbuf *, const struct tun_table *,
+ struct match *);
+enum ofperr oxm_pull_match_loose(struct ofpbuf *, const struct tun_table *,
+ struct match *);
+enum ofperr oxm_decode_match(const void *, size_t, const struct tun_table *,
+ struct match *);
enum ofperr oxm_pull_field_array(const void *, size_t fields_len,
struct field_array *);
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 5a4390405..65a6fcde8 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -150,7 +150,7 @@ odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key)
{
enum odp_key_fitness fitness;
- fitness = odp_tun_key_from_attr(a, true, tun_key);
+ fitness = odp_tun_key_from_attr(a, tun_key);
ovs_assert(fitness != ODP_FIT_ERROR);
}
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 6d29b67d5..332698bfe 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1855,10 +1855,8 @@ ovs_frag_type_to_string(enum ovs_frag_type type)
}
static enum odp_key_fitness
-odp_tun_key_from_attr__(const struct nlattr *attr,
- const struct nlattr *flow_attrs, size_t flow_attr_len,
- const struct flow_tnl *src_tun, struct flow_tnl *tun,
- bool udpif)
+odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask,
+ struct flow_tnl *tun)
{
unsigned int left;
const struct nlattr *a;
@@ -1934,10 +1932,7 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
break;
}
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
- if (tun_metadata_from_geneve_nlattr(a, flow_attrs, flow_attr_len,
- src_tun, udpif, tun)) {
- return ODP_FIT_ERROR;
- }
+ tun_metadata_from_geneve_nlattr(a, is_mask, tun);
break;
default:
@@ -1958,11 +1953,10 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
}
enum odp_key_fitness
-odp_tun_key_from_attr(const struct nlattr *attr, bool udpif,
- struct flow_tnl *tun)
+odp_tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
{
memset(tun, 0, sizeof *tun);
- return odp_tun_key_from_attr__(attr, NULL, 0, NULL, tun, udpif);
+ return odp_tun_key_from_attr__(attr, false, tun);
}
static void
@@ -4573,7 +4567,7 @@ odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
case OVS_KEY_ATTR_TUNNEL: {
enum odp_key_fitness res;
- res = odp_tun_key_from_attr(nla, true, &md->tunnel);
+ res = odp_tun_key_from_attr(nla, &md->tunnel);
if (res == ODP_FIT_ERROR) {
memset(&md->tunnel, 0, sizeof md->tunnel);
} else if (res == ODP_FIT_PERFECT) {
@@ -5084,9 +5078,7 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
static enum odp_key_fitness
odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
- const struct nlattr *src_key, size_t src_key_len,
- struct flow *flow, const struct flow *src_flow,
- bool udpif)
+ struct flow *flow, const struct flow *src_flow)
{
const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1];
uint64_t expected_attrs;
@@ -5150,10 +5142,8 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUNNEL)) {
enum odp_key_fitness res;
- res = odp_tun_key_from_attr__(attrs[OVS_KEY_ATTR_TUNNEL],
- is_mask ? src_key : NULL,
- src_key_len, &src_flow->tunnel,
- &flow->tunnel, udpif);
+ res = odp_tun_key_from_attr__(attrs[OVS_KEY_ATTR_TUNNEL], is_mask,
+ &flow->tunnel);
if (res == ODP_FIT_ERROR) {
return ODP_FIT_ERROR;
} else if (res == ODP_FIT_PERFECT) {
@@ -5226,20 +5216,21 @@ enum odp_key_fitness
odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
struct flow *flow)
{
- return odp_flow_key_to_flow__(key, key_len, NULL, 0, flow, flow, false);
+ return odp_flow_key_to_flow__(key, key_len, flow, flow);
}
-static enum odp_key_fitness
-odp_flow_key_to_mask__(const struct nlattr *mask_key, size_t mask_key_len,
- const struct nlattr *flow_key, size_t flow_key_len,
- struct flow_wildcards *mask,
- const struct flow *src_flow,
- bool udpif)
+/* Converts the 'mask_key_len' bytes of OVS_KEY_ATTR_* attributes in 'mask_key'
+ * to a mask structure in 'mask'. 'flow' must be a previously translated flow
+ * corresponding to 'mask' and similarly flow_key/flow_key_len must be the
+ * attributes from that flow. Returns an ODP_FIT_* value that indicates how
+ * well 'key' fits our expectations for what a flow key should contain. */
+enum odp_key_fitness
+odp_flow_key_to_mask(const struct nlattr *mask_key, size_t mask_key_len,
+ struct flow_wildcards *mask, const struct flow *src_flow)
{
if (mask_key_len) {
return odp_flow_key_to_flow__(mask_key, mask_key_len,
- flow_key, flow_key_len,
- &mask->masks, src_flow, udpif);
+ &mask->masks, src_flow);
} else {
/* A missing mask means that the flow should be exact matched.
@@ -5249,47 +5240,6 @@ odp_flow_key_to_mask__(const struct nlattr *mask_key, size_t mask_key_len,
return ODP_FIT_PERFECT;
}
}
-/* Converts the 'mask_key_len' bytes of OVS_KEY_ATTR_* attributes in 'mask_key'
- * to a mask structure in 'mask'. 'flow' must be a previously translated flow
- * corresponding to 'mask' and similarly flow_key/flow_key_len must be the
- * attributes from that flow. Returns an ODP_FIT_* value that indicates how
- * well 'key' fits our expectations for what a flow key should contain. */
-enum odp_key_fitness
-odp_flow_key_to_mask(const struct nlattr *mask_key, size_t mask_key_len,
- const struct nlattr *flow_key, size_t flow_key_len,
- struct flow_wildcards *mask, const struct flow *flow)
-{
- return odp_flow_key_to_mask__(mask_key, mask_key_len,
- flow_key, flow_key_len,
- mask, flow, false);
-}
-
-/* These functions are similar to their non-"_udpif" variants but output a
- * 'flow' that is suitable for fast-path packet processing.
- *
- * Some fields have different representation for flow setup and per-
- * packet processing (i.e. different between ofproto-dpif and userspace
- * datapath). In particular, with the non-"_udpif" functions, struct
- * tun_metadata is in the per-flow format (using 'present.map' and 'opts.u8');
- * with these functions, struct tun_metadata is in the per-packet format
- * (using 'present.len' and 'opts.gnv'). */
-enum odp_key_fitness
-odp_flow_key_to_flow_udpif(const struct nlattr *key, size_t key_len,
- struct flow *flow)
-{
- return odp_flow_key_to_flow__(key, key_len, NULL, 0, flow, flow, true);
-}
-
-enum odp_key_fitness
-odp_flow_key_to_mask_udpif(const struct nlattr *mask_key, size_t mask_key_len,
- const struct nlattr *flow_key, size_t flow_key_len,
- struct flow_wildcards *mask,
- const struct flow *flow)
-{
- return odp_flow_key_to_mask__(mask_key, mask_key_len,
- flow_key, flow_key_len,
- mask, flow, true);
-}
/* Returns 'fitness' as a string, for use in debug messages. */
const char *
diff --git a/lib/odp-util.h b/lib/odp-util.h
index a41bc7630..ccdbf8e9f 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -150,11 +150,12 @@ struct odputil_keybuf {
uint32_t keybuf[DIV_ROUND_UP(ODPUTIL_FLOW_KEY_BYTES, 4)];
};
-enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, bool udpif,
+enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *,
struct flow_tnl *);
int odp_ufid_from_string(const char *s_, ovs_u128 *ufid);
void odp_format_ufid(const ovs_u128 *ufid, struct ds *);
+
void odp_flow_format(const struct nlattr *key, size_t key_len,
const struct nlattr *mask, size_t mask_len,
const struct hmap *portno_names, struct ds *,
@@ -232,20 +233,9 @@ enum odp_key_fitness odp_flow_key_to_flow(const struct nlattr *, size_t,
struct flow *);
enum odp_key_fitness odp_flow_key_to_mask(const struct nlattr *mask_key,
size_t mask_key_len,
- const struct nlattr *flow_key,
- size_t flow_key_len,
struct flow_wildcards *mask,
const struct flow *flow);
-enum odp_key_fitness odp_flow_key_to_flow_udpif(const struct nlattr *, size_t,
- struct flow *);
-enum odp_key_fitness odp_flow_key_to_mask_udpif(const struct nlattr *mask_key,
- size_t mask_key_len,
- const struct nlattr *flow_key,
- size_t flow_key_len,
- struct flow_wildcards *mask,
- const struct flow *flow);
-
const char *odp_key_fitness_to_string(enum odp_key_fitness);
void commit_odp_tunnel_action(const struct flow *, struct flow *base,
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 584ac1ae7..553991c77 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -1225,7 +1225,8 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
* problem. */
char *
parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
- const char *s, const struct simap *portno_names)
+ const struct tun_table *tun_table, const char *s,
+ const struct simap *portno_names)
{
char *pos, *key, *value_s;
char *error = NULL;
@@ -1235,6 +1236,7 @@ parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
if (wc) {
memset(wc, 0, sizeof *wc);
}
+ flow->tunnel.metadata.tab = tun_table;
pos = copy = xstrdup(s);
while (ofputil_parse_key_value(&pos, &key, &value_s)) {
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 0b3bf01a0..917dce8f9 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -118,7 +118,7 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
size_t total_len;
enum ofperr error;
- error = ofputil_decode_packet_in_private(oh, true,
+ error = ofputil_decode_packet_in_private(oh, true, NULL,
&pin, &total_len, &buffer_id);
if (error) {
ofp_print_error(string, error);
@@ -786,7 +786,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
protocol = ofputil_protocol_set_tid(protocol, true);
ofpbuf_init(&ofpacts, 64);
- error = ofputil_decode_flow_mod(&fm, oh, protocol, &ofpacts,
+ error = ofputil_decode_flow_mod(&fm, oh, protocol, NULL, &ofpacts,
OFPP_MAX, 255);
if (error) {
ofpbuf_uninit(&ofpacts);
@@ -1591,7 +1591,7 @@ ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
struct ofputil_flow_stats_request fsr;
enum ofperr error;
- error = ofputil_decode_flow_stats_request(&fsr, oh);
+ error = ofputil_decode_flow_stats_request(&fsr, oh, NULL);
if (error) {
ofp_print_error(string, error);
return;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index f83e4a30b..e2ccd6cce 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -277,8 +277,8 @@ ofputil_match_to_ofp10_match(const struct match *match,
}
enum ofperr
-ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match,
- uint16_t *padded_match_len)
+ofputil_pull_ofp11_match(struct ofpbuf *buf, const struct tun_table *tun_table,
+ struct match *match, uint16_t *padded_match_len)
{
struct ofp11_match_header *omh = buf->data;
uint16_t match_len;
@@ -307,7 +307,7 @@ ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match,
if (padded_match_len) {
*padded_match_len = ROUND_UP(match_len, 8);
}
- return oxm_pull_match(buf, match);
+ return oxm_pull_match(buf, tun_table, match);
default:
return OFPERR_OFPBMC_BAD_TYPE;
@@ -1570,6 +1570,7 @@ enum ofperr
ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
const struct ofp_header *oh,
enum ofputil_protocol protocol,
+ const struct tun_table *tun_table,
struct ofpbuf *ofpacts,
ofp_port_t max_port, uint8_t max_table)
{
@@ -1583,7 +1584,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
ofm = ofpbuf_pull(&b, sizeof *ofm);
- error = ofputil_pull_ofp11_match(&b, &fm->match, NULL);
+ error = ofputil_pull_ofp11_match(&b, tun_table, &fm->match, NULL);
if (error) {
return error;
}
@@ -1678,7 +1679,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
/* Dissect the message. */
nfm = ofpbuf_pull(&b, sizeof *nfm);
error = nx_pull_match(&b, ntohs(nfm->match_len),
- &fm->match, &fm->cookie, &fm->cookie_mask);
+ &fm->match, &fm->cookie, &fm->cookie_mask,
+ tun_table);
if (error) {
return error;
}
@@ -2267,7 +2269,8 @@ ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr,
static enum ofperr
ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr,
- struct ofpbuf *b, bool aggregate)
+ struct ofpbuf *b, bool aggregate,
+ const struct tun_table *tun_table)
{
const struct ofp11_flow_stats_request *ofsr;
enum ofperr error;
@@ -2282,7 +2285,7 @@ ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr,
fsr->out_group = ntohl(ofsr->out_group);
fsr->cookie = ofsr->cookie;
fsr->cookie_mask = ofsr->cookie_mask;
- error = ofputil_pull_ofp11_match(b, &fsr->match, NULL);
+ error = ofputil_pull_ofp11_match(b, tun_table, &fsr->match, NULL);
if (error) {
return error;
}
@@ -2292,14 +2295,15 @@ ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr,
static enum ofperr
ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
- struct ofpbuf *b, bool aggregate)
+ struct ofpbuf *b, bool aggregate,
+ const struct tun_table *tun_table)
{
const struct nx_flow_stats_request *nfsr;
enum ofperr error;
nfsr = ofpbuf_pull(b, sizeof *nfsr);
error = nx_pull_match(b, ntohs(nfsr->match_len), &fsr->match,
- &fsr->cookie, &fsr->cookie_mask);
+ &fsr->cookie, &fsr->cookie_mask, tun_table);
if (error) {
return error;
}
@@ -2712,7 +2716,8 @@ ofputil_pull_queue_get_config_reply(struct ofpbuf *msg,
* successful, otherwise an OpenFlow error code. */
enum ofperr
ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
- const struct ofp_header *oh)
+ const struct ofp_header *oh,
+ const struct tun_table *tun_table)
{
struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
enum ofpraw raw = ofpraw_pull_assert(&b);
@@ -2724,16 +2729,16 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
return ofputil_decode_ofpst10_flow_request(fsr, b.data, true);
case OFPRAW_OFPST11_FLOW_REQUEST:
- return ofputil_decode_ofpst11_flow_request(fsr, &b, false);
+ return ofputil_decode_ofpst11_flow_request(fsr, &b, false, tun_table);
case OFPRAW_OFPST11_AGGREGATE_REQUEST:
- return ofputil_decode_ofpst11_flow_request(fsr, &b, true);
+ return ofputil_decode_ofpst11_flow_request(fsr, &b, true, tun_table);
case OFPRAW_NXST_FLOW_REQUEST:
- return ofputil_decode_nxst_flow_request(fsr, &b, false);
+ return ofputil_decode_nxst_flow_request(fsr, &b, false, tun_table);
case OFPRAW_NXST_AGGREGATE_REQUEST:
- return ofputil_decode_nxst_flow_request(fsr, &b, true);
+ return ofputil_decode_nxst_flow_request(fsr, &b, true, tun_table);
default:
/* Hey, the caller lied. */
@@ -2877,7 +2882,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
return EINVAL;
}
- if (ofputil_pull_ofp11_match(msg, &fs->match, &padded_match_len)) {
+ if (ofputil_pull_ofp11_match(msg, NULL, &fs->match,
+ &padded_match_len)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad match");
return EINVAL;
}
@@ -2959,7 +2965,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
"claims invalid length %"PRIuSIZE, match_len, length);
return EINVAL;
}
- if (nx_pull_match(msg, match_len, &fs->match, NULL, NULL)) {
+ if (nx_pull_match(msg, match_len, &fs->match, NULL, NULL, NULL)) {
return EINVAL;
}
instructions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
@@ -3015,13 +3021,20 @@ unknown_to_zero(uint64_t count)
* have been initialized with ofpmp_init(). */
void
ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
- struct ovs_list *replies)
+ struct ovs_list *replies,
+ const struct tun_table *tun_table)
{
+ struct ofputil_flow_stats *fs_ = CONST_CAST(struct ofputil_flow_stats *,
+ fs);
+ const struct tun_table *orig_tun_table;
struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
size_t start_ofs = reply->size;
enum ofp_version version = ofpmp_version(replies);
enum ofpraw raw = ofpmp_decode_raw(replies);
+ orig_tun_table = fs->match.flow.tunnel.metadata.tab;
+ fs_->match.flow.tunnel.metadata.tab = tun_table;
+
if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
struct ofp11_flow_stats *ofs;
@@ -3107,6 +3120,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
}
ofpmp_postappend(replies, start_ofs);
+ fs_->match.flow.tunnel.metadata.tab = orig_tun_table;
}
/* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
@@ -3170,7 +3184,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
ofr = ofpbuf_pull(&b, sizeof *ofr);
- error = ofputil_pull_ofp11_match(&b, &fr->match, NULL);
+ error = ofputil_pull_ofp11_match(&b, NULL, &fr->match, NULL);
if (error) {
return error;
}
@@ -3206,7 +3220,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
enum ofperr error;
nfr = ofpbuf_pull(&b, sizeof *nfr);
- error = nx_pull_match(&b, ntohs(nfr->match_len), &fr->match,
+ error = nx_pull_match(&b, ntohs(nfr->match_len), &fr->match, NULL,
NULL, NULL);
if (error) {
return error;
@@ -3328,6 +3342,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
* arguments needs to be initialized. */
static enum ofperr
decode_nx_packet_in2(const struct ofp_header *oh, bool loose,
+ const struct tun_table *tun_table,
struct ofputil_packet_in *pin,
size_t *total_len, uint32_t *buffer_id,
struct ofpbuf *continuation)
@@ -3382,7 +3397,7 @@ decode_nx_packet_in2(const struct ofp_header *oh, bool loose,
case NXPINT_METADATA:
error = oxm_decode_match(payload.msg, ofpbuf_msgsize(&payload),
- &pin->flow_metadata);
+ tun_table, &pin->flow_metadata);
break;
case NXPINT_USERDATA:
@@ -3439,6 +3454,7 @@ decode_nx_packet_in2(const struct ofp_header *oh, bool loose,
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
+ const struct tun_table *tun_table,
struct ofputil_packet_in *pin,
size_t *total_lenp, uint32_t *buffer_idp,
struct ofpbuf *continuation)
@@ -3459,7 +3475,8 @@ ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
const ovs_be64 *cookie = (raw == OFPRAW_OFPT13_PACKET_IN
? ofpbuf_pull(&b, sizeof *cookie)
: NULL);
- enum ofperr error = oxm_pull_match_loose(&b, &pin->flow_metadata);
+ enum ofperr error = oxm_pull_match_loose(&b, tun_table,
+ &pin->flow_metadata);
if (error) {
return error;
}
@@ -3518,7 +3535,7 @@ ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
npi = ofpbuf_pull(&b, sizeof *npi);
error = nx_pull_match_loose(&b, ntohs(npi->match_len),
- &pin->flow_metadata, NULL, NULL);
+ &pin->flow_metadata, NULL, NULL, NULL);
if (error) {
return error;
}
@@ -3537,8 +3554,9 @@ ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
pin->packet = b.data;
pin->packet_len = b.size;
} else if (raw == OFPRAW_NXT_PACKET_IN2 || raw == OFPRAW_NXT_RESUME) {
- enum ofperr error = decode_nx_packet_in2(oh, loose, pin, &total_len,
- &buffer_id, continuation);
+ enum ofperr error = decode_nx_packet_in2(oh, loose, tun_table, pin,
+ &total_len, &buffer_id,
+ continuation);
if (error) {
return error;
}
@@ -4015,6 +4033,7 @@ parse_actions_property(struct ofpbuf *property, enum ofp_version version,
* ofputil_packet_in_private_destroy() to free this data. */
enum ofperr
ofputil_decode_packet_in_private(const struct ofp_header *oh, bool loose,
+ const struct tun_table *tun_table,
struct ofputil_packet_in_private *pin,
size_t *total_len, uint32_t *buffer_id)
{
@@ -4022,8 +4041,8 @@ ofputil_decode_packet_in_private(const struct ofp_header *oh, bool loose,
struct ofpbuf continuation;
enum ofperr error;
- error = ofputil_decode_packet_in(oh, loose, &pin->public, total_len,
- buffer_id, &continuation);
+ error = ofputil_decode_packet_in(oh, loose, tun_table, &pin->public,
+ total_len, buffer_id, &continuation);
if (error) {
return error;
}
@@ -6588,7 +6607,8 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq,
rq->out_port = u16_to_ofp(ntohs(nfmr->out_port));
rq->table_id = nfmr->table_id;
- return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL, NULL);
+ return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL,
+ NULL, NULL);
}
void
@@ -6696,7 +6716,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
update->cookie = nfuf->cookie;
update->priority = ntohs(nfuf->priority);
- error = nx_pull_match(msg, match_len, update->match, NULL, NULL);
+ error = nx_pull_match(msg, match_len, update->match, NULL, NULL, NULL);
if (error) {
return error;
}
diff --git a/lib/tun-metadata.c b/lib/tun-metadata.c
index 36006e3ba..92643b395 100644
--- a/lib/tun-metadata.c
+++ b/lib/tun-metadata.c
@@ -25,7 +25,6 @@
#include "nx-match.h"
#include "odp-netlink.h"
#include "openvswitch/ofp-util.h"
-#include "ovs-thread.h"
#include "ovs-rcu.h"
#include "packets.h"
#include "tun-metadata.h"
@@ -52,14 +51,10 @@ struct tun_table {
};
BUILD_ASSERT_DECL(TUN_METADATA_TOT_OPT_SIZE % 4 == 0);
-static struct ovs_mutex tab_mutex = OVS_MUTEX_INITIALIZER;
-static OVSRCU_TYPE(struct tun_table *) metadata_tab;
-
static enum ofperr tun_metadata_add_entry(struct tun_table *map, uint8_t idx,
uint16_t opt_class, uint8_t type,
- uint8_t len) OVS_REQUIRES(tab_mutex);
-static void tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
- OVS_REQUIRES(tab_mutex);
+ uint8_t len);
+static void tun_metadata_del_entry(struct tun_table *map, uint8_t idx);
static void memcpy_to_metadata(struct tun_metadata *dst, const void *src,
const struct tun_metadata_loc *,
unsigned int idx);
@@ -86,8 +81,8 @@ tun_key_type(uint32_t key)
/* Returns a newly allocated tun_table. If 'old_map' is nonnull then the new
* tun_table is a deep copy of the old one. */
-static struct tun_table *
-table_alloc(const struct tun_table *old_map) OVS_REQUIRES(tab_mutex)
+struct tun_table *
+tun_metadata_alloc(const struct tun_table *old_map)
{
struct tun_table *new_map;
@@ -120,8 +115,8 @@ table_alloc(const struct tun_table *old_map) OVS_REQUIRES(tab_mutex)
}
/* Frees 'map' and all the memory it owns. */
-static void
-table_free(struct tun_table *map) OVS_REQUIRES(tab_mutex)
+void
+tun_metadata_free(struct tun_table *map)
{
struct tun_meta_entry *entry;
@@ -137,74 +132,60 @@ table_free(struct tun_table *map) OVS_REQUIRES(tab_mutex)
free(map);
}
-/* Creates a global tunnel metadata mapping table, if none already exists. */
void
-tun_metadata_init(void)
+tun_metadata_postpone_free(struct tun_table *tab)
{
- ovs_mutex_lock(&tab_mutex);
-
- if (!ovsrcu_get_protected(struct tun_table *, &metadata_tab)) {
- ovsrcu_set(&metadata_tab, table_alloc(NULL));
- }
-
- ovs_mutex_unlock(&tab_mutex);
+ ovsrcu_postpone(tun_metadata_free, tab);
}
enum ofperr
-tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm)
+tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm,
+ const struct tun_table *old_tab,
+ struct tun_table **new_tab)
{
- struct tun_table *old_map, *new_map;
struct ofputil_tlv_map *ofp_map;
enum ofperr err = 0;
- ovs_mutex_lock(&tab_mutex);
-
- old_map = ovsrcu_get_protected(struct tun_table *, &metadata_tab);
-
switch (ttm->command) {
case NXTTMC_ADD:
- new_map = table_alloc(old_map);
+ *new_tab = tun_metadata_alloc(old_tab);
LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
- err = tun_metadata_add_entry(new_map, ofp_map->index,
+ err = tun_metadata_add_entry(*new_tab, ofp_map->index,
ofp_map->option_class,
ofp_map->option_type,
ofp_map->option_len);
if (err) {
- table_free(new_map);
- goto out;
+ *new_tab = NULL;
+ tun_metadata_free(*new_tab);
+ return err;
}
}
break;
case NXTTMC_DELETE:
- new_map = table_alloc(old_map);
+ *new_tab = tun_metadata_alloc(old_tab);
LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
- tun_metadata_del_entry(new_map, ofp_map->index);
+ tun_metadata_del_entry(*new_tab, ofp_map->index);
}
break;
case NXTTMC_CLEAR:
- new_map = table_alloc(NULL);
+ *new_tab = tun_metadata_alloc(NULL);
break;
default:
OVS_NOT_REACHED();
}
- ovsrcu_set(&metadata_tab, new_map);
- ovsrcu_postpone(table_free, old_map);
-
-out:
- ovs_mutex_unlock(&tab_mutex);
- return err;
+ return 0;
}
void
-tun_metadata_table_request(struct ofputil_tlv_table_reply *ttr)
+tun_metadata_table_request(const struct tun_table *tun_table,
+ struct ofputil_tlv_table_reply *ttr)
{
- struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
int i;
ttr->max_option_space = TUN_METADATA_TOT_OPT_SIZE;
@@ -212,7 +193,7 @@ tun_metadata_table_request(struct ofputil_tlv_table_reply *ttr)
ovs_list_init(&ttr->mappings);
for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
- struct tun_meta_entry *entry = &map->entries[i];
+ const struct tun_meta_entry *entry = &tun_table->entries[i];
struct ofputil_tlv_map *map;
if (!entry->valid) {
@@ -233,16 +214,16 @@ tun_metadata_table_request(struct ofputil_tlv_table_reply *ttr)
*
* 'mf' must be an MFF_TUN_METADATA* field.
*
- * This uses the global tunnel metadata mapping table created by
- * tun_metadata_init(). If no such table has been created or if 'mf' hasn't
- * been allocated in it yet, this just zeros 'value'. */
+ * This uses the tunnel metadata mapping table created by tun_metadata_alloc().
+ * If no such table has been created or if 'mf' hasn't been allocated in it yet,
+ * this just zeros 'value'. */
void
tun_metadata_read(const struct flow_tnl *tnl,
const struct mf_field *mf, union mf_value *value)
{
- struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
+ const struct tun_table *map = tnl->metadata.tab;
unsigned int idx = mf->id - MFF_TUN_METADATA0;
- struct tun_metadata_loc *loc;
+ const struct tun_metadata_loc *loc;
if (!map) {
memset(value->tun_metadata, 0, mf->n_bytes);
@@ -260,16 +241,16 @@ tun_metadata_read(const struct flow_tnl *tnl,
*
* 'mf' must be an MFF_TUN_METADATA* field.
*
- * This uses the global tunnel metadata mapping table created by
- * tun_metadata_init(). If no such table has been created or if 'mf' hasn't
- * been allocated in it yet, this function does nothing. */
+ * This uses the tunnel metadata mapping table created by tun_metadata_alloc().
+ * If no such table has been created or if 'mf' hasn't been allocated in it yet,
+ * this function does nothing. */
void
tun_metadata_write(struct flow_tnl *tnl,
const struct mf_field *mf, const union mf_value *value)
{
- struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
+ const struct tun_table *map = tnl->metadata.tab;
unsigned int idx = mf->id - MFF_TUN_METADATA0;
- struct tun_metadata_loc *loc;
+ const struct tun_metadata_loc *loc;
if (!map || !map->entries[idx].valid) {
return;
@@ -281,7 +262,7 @@ tun_metadata_write(struct flow_tnl *tnl,
}
static const struct tun_metadata_loc *
-metadata_loc_from_match(struct tun_table *map, struct match *match,
+metadata_loc_from_match(const struct tun_table *map, struct match *match,
const char *name, unsigned int idx,
unsigned int field_len, bool masked, char **err_str)
{
@@ -333,11 +314,12 @@ metadata_loc_from_match(struct tun_table *map, struct match *match,
*
* 'mf' must be an MFF_TUN_METADATA* field. 'match' must be in non-UDPIF format.
*
- * If there is global tunnel metadata matching table, this function is
- * effective only if there is already a mapping for 'mf'. Otherwise, the
- * metadata mapping table integrated into 'match' is used, adding 'mf' to its
- * mapping table if it isn't already mapped (and if there is room). If 'mf'
- * isn't or can't be mapped, this function returns without modifying 'match'.
+ * If there is a tunnel metadata mapping table associated with the switch,
+ * this function is effective only if there is already a mapping for 'mf'.
+ * Otherwise, the metadata mapping table integrated into 'match' is used,
+ * adding 'mf' to its mapping table if it isn't already mapped (and if there
+ * is room). If 'mf' isn't or can't be mapped, this function returns without
+ * modifying 'match'.
*
* 'value' may be NULL; if so, then 'mf' is made to match on an all-zeros
* value.
@@ -353,7 +335,7 @@ tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
const union mf_value *mask, struct match *match,
char **err_str)
{
- struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
+ const struct tun_table *map = match->flow.tunnel.metadata.tab;
const struct tun_metadata_loc *loc;
unsigned int idx = mf->id - MFF_TUN_METADATA0;
unsigned int field_len;
@@ -361,8 +343,6 @@ tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
unsigned int data_offset;
union mf_value data;
- ovs_assert(!(match->flow.tunnel.flags & FLOW_TNL_F_UDPIF));
-
field_len = mf_field_len(mf, value, mask, &is_masked);
loc = metadata_loc_from_match(map, match, mf->name, idx, field_len,
is_masked, err_str);
@@ -397,64 +377,23 @@ tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
loc, idx);
}
-static bool
-udpif_to_parsed(const struct flow_tnl *flow, const struct flow_tnl *mask,
- struct flow_tnl *flow_xlate, struct flow_tnl *mask_xlate)
-{
- if (flow->flags & FLOW_TNL_F_UDPIF) {
- int err;
-
- err = tun_metadata_from_geneve_udpif(flow, flow, flow_xlate);
- if (err) {
- return false;
- }
-
- if (mask) {
- tun_metadata_from_geneve_udpif(flow, mask, mask_xlate);
- if (err) {
- return false;
- }
- }
- } else {
- if (flow->metadata.present.map == 0) {
- /* There is no tunnel metadata, don't bother copying. */
- return false;
- }
-
- memcpy(flow_xlate, flow, sizeof *flow_xlate);
- if (mask) {
- memcpy(mask_xlate, mask, sizeof *mask_xlate);
- }
-
- if (!flow_xlate->metadata.tab) {
- flow_xlate->metadata.tab = ovsrcu_get(struct tun_table *,
- &metadata_tab);
- }
- }
-
- return true;
-}
-
-/* Copies all MFF_TUN_METADATA* fields from 'tnl' to 'flow_metadata'. */
+/* Copies all MFF_TUN_METADATA* fields from 'tnl' to 'flow_metadata'. This
+ * is called during action translation and therefore 'tnl' must be in
+ * non-udpif format. */
void
tun_metadata_get_fmd(const struct flow_tnl *tnl, struct match *flow_metadata)
{
- struct flow_tnl flow;
int i;
- if (!udpif_to_parsed(tnl, NULL, &flow, NULL)) {
- return;
- }
-
- ULLONG_FOR_EACH_1 (i, flow.metadata.present.map) {
+ ULLONG_FOR_EACH_1 (i, tnl->metadata.present.map) {
union mf_value opts;
- const struct tun_metadata_loc *old_loc = &flow.metadata.tab->entries[i].loc;
+ const struct tun_metadata_loc *old_loc = &tnl->metadata.tab->entries[i].loc;
const struct tun_metadata_loc *new_loc;
new_loc = metadata_loc_from_match(NULL, flow_metadata, NULL, i,
old_loc->len, false, NULL);
- memcpy_from_metadata(opts.tun_metadata, &flow.metadata, old_loc);
+ memcpy_from_metadata(opts.tun_metadata, &tnl->metadata, old_loc);
memcpy_to_metadata(&flow_metadata->flow.tunnel.metadata,
opts.tun_metadata, new_loc, i);
@@ -518,7 +457,6 @@ memcpy_from_metadata(void *dst, const struct tun_metadata *src,
static int
tun_metadata_alloc_chain(struct tun_table *map, uint8_t len,
struct tun_metadata_loc_chain *loc)
- OVS_REQUIRES(tab_mutex)
{
int alloc_len = len / 4;
int scan_start = 0;
@@ -563,7 +501,7 @@ found:
static enum ofperr
tun_metadata_add_entry(struct tun_table *map, uint8_t idx, uint16_t opt_class,
- uint8_t type, uint8_t len) OVS_REQUIRES(tab_mutex)
+ uint8_t type, uint8_t len)
{
struct tun_meta_entry *entry;
struct tun_metadata_loc_chain *cur_chain, *prev_chain;
@@ -614,7 +552,6 @@ tun_metadata_add_entry(struct tun_table *map, uint8_t idx, uint16_t opt_class,
static void
tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
- OVS_REQUIRES(tab_mutex)
{
struct tun_meta_entry *entry;
struct tun_metadata_loc_chain *chain;
@@ -645,25 +582,49 @@ tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
memset(&entry->loc, 0, sizeof entry->loc);
}
-static int
-tun_metadata_from_geneve__(const struct tun_metadata *flow_metadata,
- const struct geneve_opt *opt,
- const struct geneve_opt *flow_opt, int opts_len,
- struct tun_metadata *metadata)
+/* Converts from Geneve netlink attributes in 'attr' to tunnel metadata
+ * in 'tun'. In reality, there is very little conversion done since we are
+ * just copying over the tunnel options in the form that they were received
+ * on the wire. By always using UDPIF format, this allows us to process the
+ * flow key without any knowledge of the mapping table. We can do the
+ * conversion later if necessary. */
+void
+tun_metadata_from_geneve_nlattr(const struct nlattr *attr, bool is_mask,
+ struct flow_tnl *tun)
{
- struct tun_table *map;
- bool is_mask = flow_opt != opt;
+ int attr_len = nl_attr_get_size(attr);
+
+ memcpy(tun->metadata.opts.gnv, nl_attr_get(attr), attr_len);
+ tun->flags |= FLOW_TNL_F_UDPIF;
if (!is_mask) {
- map = ovsrcu_get(struct tun_table *, &metadata_tab);
- metadata->tab = map;
+ tun->metadata.present.len = attr_len;
} else {
- map = flow_metadata->tab;
+ /* We need to exact match on the length so we don't
+ * accidentally match on sets of options that are the same
+ * at the beginning but with additional options after. */
+ tun->metadata.present.len = 0xff;
}
+}
- if (!map) {
- return 0;
- }
+/* Converts from the flat Geneve options representation extracted directly
+ * from the tunnel header to the representation that maps options to
+ * pre-allocated locations. The original version (in UDPIF form) is passed
+ * in 'src' and the translated form in stored in 'dst'. To handle masks, the
+ * flow must also be passed in through 'flow' (in the original, raw form). */
+int
+tun_metadata_from_geneve_udpif(const struct tun_table *tun_tab,
+ const struct flow_tnl *flow,
+ const struct flow_tnl *src,
+ struct flow_tnl *dst)
+{
+ const struct geneve_opt *opt = src->metadata.opts.gnv;
+ const struct geneve_opt *flow_opt = flow->metadata.opts.gnv;
+ int opts_len = flow->metadata.present.len;
+
+ dst->metadata.tab = tun_tab;
+ dst->flags = src->flags & ~FLOW_TNL_F_UDPIF;
+ dst->metadata.present.map = 0;
while (opts_len > 0) {
int len;
@@ -678,13 +639,13 @@ tun_metadata_from_geneve__(const struct tun_metadata *flow_metadata,
return EINVAL;
}
- entry = tun_meta_find_key(&map->key_hmap,
+ entry = tun_meta_find_key(&tun_tab->key_hmap,
tun_meta_key(flow_opt->opt_class,
flow_opt->type));
if (entry) {
if (entry->loc.len == flow_opt->length * 4) {
- memcpy_to_metadata(metadata, opt + 1, &entry->loc,
- entry - map->entries);
+ memcpy_to_metadata(&dst->metadata, opt + 1, &entry->loc,
+ entry - tun_tab->entries);
} else {
return EINVAL;
}
@@ -700,115 +661,16 @@ tun_metadata_from_geneve__(const struct tun_metadata *flow_metadata,
return 0;
}
-static const struct nlattr *
-tun_metadata_find_geneve_key(const struct nlattr *key, uint32_t key_len)
-{
- const struct nlattr *tnl_key;
-
- tnl_key = nl_attr_find__(key, key_len, OVS_KEY_ATTR_TUNNEL);
- if (!tnl_key) {
- return NULL;
- }
-
- return nl_attr_find_nested(tnl_key, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
-}
-
-/* Converts from Geneve netlink attributes in 'attr' to tunnel metadata
- * in 'tun'. The result may either in be UDPIF format or not, as determined
- * by 'udpif'.
- *
- * In the event that a mask is being converted, it is also necessary to
- * pass in flow information. This includes the full set of netlink attributes
- * (i.e. not just the Geneve attribute) in 'flow_attrs'/'flow_attr_len' and
- * the previously converted tunnel metadata 'flow_tun'.
- *
- * If a flow rather than mask is being converted, 'flow_attrs' must be NULL. */
-int
-tun_metadata_from_geneve_nlattr(const struct nlattr *attr,
- const struct nlattr *flow_attrs,
- size_t flow_attr_len,
- const struct flow_tnl *flow_tun, bool udpif,
- struct flow_tnl *tun)
-{
- bool is_mask = !!flow_attrs;
- int attr_len = nl_attr_get_size(attr);
- const struct nlattr *flow;
-
- /* No need for real translation, just copy things over. */
- if (udpif) {
- memcpy(tun->metadata.opts.gnv, nl_attr_get(attr), attr_len);
-
- if (!is_mask) {
- tun->metadata.present.len = attr_len;
- tun->flags |= FLOW_TNL_F_UDPIF;
- } else {
- /* We need to exact match on the length so we don't
- * accidentally match on sets of options that are the same
- * at the beginning but with additional options after. */
- tun->metadata.present.len = 0xff;
- }
-
- return 0;
- }
-
- if (is_mask) {
- flow = tun_metadata_find_geneve_key(flow_attrs, flow_attr_len);
- if (!flow) {
- return attr_len ? EINVAL : 0;
- }
-
- if (attr_len != nl_attr_get_size(flow)) {
- return EINVAL;
- }
- } else {
- flow = attr;
- }
-
- return tun_metadata_from_geneve__(&flow_tun->metadata, nl_attr_get(attr),
- nl_attr_get(flow), nl_attr_get_size(flow),
- &tun->metadata);
-}
-
-/* Converts from the flat Geneve options representation extracted directly
- * from the tunnel header to the representation that maps options to
- * pre-allocated locations. The original version (in UDPIF form) is passed
- * in 'src' and the translated form in stored in 'dst'. To handle masks, the
- * flow must also be passed in through 'flow' (in the original, raw form). */
-int
-tun_metadata_from_geneve_udpif(const struct flow_tnl *flow,
- const struct flow_tnl *src,
- struct flow_tnl *dst)
-{
- ovs_assert(flow->flags & FLOW_TNL_F_UDPIF);
-
- if (flow == src) {
- dst->flags = flow->flags & ~FLOW_TNL_F_UDPIF;
- } else {
- dst->metadata.tab = NULL;
- }
- dst->metadata.present.map = 0;
- return tun_metadata_from_geneve__(&flow->metadata, src->metadata.opts.gnv,
- flow->metadata.opts.gnv,
- flow->metadata.present.len,
- &dst->metadata);
-}
-
static void
tun_metadata_to_geneve__(const struct tun_metadata *flow, struct ofpbuf *b,
bool *crit_opt)
{
- struct tun_table *map;
int i;
- map = flow->tab;
- if (!map) {
- map = ovsrcu_get(struct tun_table *, &metadata_tab);
- }
-
*crit_opt = false;
ULLONG_FOR_EACH_1 (i, flow->present.map) {
- struct tun_meta_entry *entry = &map->entries[i];
+ const struct tun_meta_entry *entry = &flow->tab->entries[i];
struct geneve_opt *opt;
opt = ofpbuf_put_uninit(b, sizeof *opt + entry->loc.len);
@@ -857,8 +719,6 @@ tun_metadata_to_geneve_header(const struct flow_tnl *flow,
{
struct ofpbuf b;
- ovs_assert(!(flow->flags & FLOW_TNL_F_UDPIF));
-
ofpbuf_use_stack(&b, opts, TLV_TOT_OPT_SIZE);
tun_metadata_to_geneve__(&flow->metadata, &b, crit_opt);
@@ -870,19 +730,13 @@ tun_metadata_to_geneve_mask__(const struct tun_metadata *flow,
const struct tun_metadata *mask,
struct geneve_opt *opt, int opts_len)
{
- struct tun_table *map = flow->tab;
-
- if (!map) {
- return;
- }
-
/* All of these options have already been validated, so no need
* for sanity checking. */
while (opts_len > 0) {
struct tun_meta_entry *entry;
int len = sizeof(*opt) + opt->length * 4;
- entry = tun_meta_find_key(&map->key_hmap,
+ entry = tun_meta_find_key(&flow->tab->key_hmap,
tun_meta_key(opt->opt_class, opt->type));
if (entry) {
memcpy_from_metadata(opt + 1, mask, &entry->loc);
@@ -908,7 +762,7 @@ tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf *key,
const struct flow_tnl *flow,
struct ofpbuf *b)
{
- const struct nlattr *geneve_key;
+ const struct nlattr *tnl_key, *geneve_key;
struct nlattr *geneve_mask;
struct geneve_opt *opt;
int opts_len;
@@ -917,7 +771,12 @@ tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf *key,
return;
}
- geneve_key = tun_metadata_find_geneve_key(key->data, key->size);
+ tnl_key = nl_attr_find__(key->data, key->size, OVS_KEY_ATTR_TUNNEL);
+ if (!tnl_key) {
+ return;
+ }
+
+ geneve_key = nl_attr_find_nested(tnl_key, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
if (!geneve_key) {
return;
}
@@ -969,17 +828,15 @@ tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src,
const struct geneve_opt *flow_src_opt,
int opts_len, struct geneve_opt *dst)
{
- ovs_assert(!(flow_src->flags & FLOW_TNL_F_UDPIF));
-
memcpy(dst, flow_src_opt, opts_len);
tun_metadata_to_geneve_mask__(&flow_src->metadata,
&mask_src->metadata, dst, opts_len);
}
static const struct tun_metadata_loc *
-metadata_loc_from_match_read(struct tun_table *map, const struct match *match,
- unsigned int idx, struct flow_tnl *mask,
- bool *is_masked)
+metadata_loc_from_match_read(const struct tun_table *map,
+ const struct match *match, unsigned int idx,
+ const struct flow_tnl *mask, bool *is_masked)
{
union mf_value mask_opts;
@@ -997,63 +854,66 @@ metadata_loc_from_match_read(struct tun_table *map, const struct match *match,
return &map->entries[idx].loc;
}
+/* Generates NXM formatted matches in 'b' based on the contents of 'match'.
+ * 'match' must be in non-udpif format. */
void
tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm,
const struct match *match)
{
- struct flow_tnl flow, mask;
int i;
- if (!udpif_to_parsed(&match->flow.tunnel, &match->wc.masks.tunnel,
- &flow, &mask)) {
- return;
- }
-
- ULLONG_FOR_EACH_1 (i, mask.metadata.present.map) {
+ ULLONG_FOR_EACH_1 (i, match->wc.masks.tunnel.metadata.present.map) {
const struct tun_metadata_loc *loc;
bool is_masked;
union mf_value opts;
union mf_value mask_opts;
- loc = metadata_loc_from_match_read(flow.metadata.tab, match, i,
- &mask, &is_masked);
- memcpy_from_metadata(opts.tun_metadata, &flow.metadata, loc);
- memcpy_from_metadata(mask_opts.tun_metadata, &mask.metadata, loc);
+ loc = metadata_loc_from_match_read(match->flow.tunnel.metadata.tab,
+ match, i, &match->wc.masks.tunnel,
+ &is_masked);
+ memcpy_from_metadata(opts.tun_metadata, &match->flow.tunnel.metadata,
+ loc);
+ memcpy_from_metadata(mask_opts.tun_metadata,
+ &match->wc.masks.tunnel.metadata, loc);
nxm_put__(b, MFF_TUN_METADATA0 + i, oxm, opts.tun_metadata,
is_masked ? mask_opts.tun_metadata : NULL, loc->len);
}
}
+/* Formatted matches in 's' based on the contents of 'match'. 'match' must be
+ * in non-udpif format. */
void
tun_metadata_match_format(struct ds *s, const struct match *match)
{
- struct flow_tnl flow, mask;
- unsigned int i;
+ int i;
- if (!udpif_to_parsed(&match->flow.tunnel, &match->wc.masks.tunnel,
- &flow, &mask)) {
+ if (match->flow.tunnel.flags & FLOW_TNL_F_UDPIF ||
+ (!match->flow.tunnel.metadata.tab && !match->tun_md.valid)) {
return;
}
- ULLONG_FOR_EACH_1 (i, mask.metadata.present.map) {
+ ULLONG_FOR_EACH_1 (i, match->wc.masks.tunnel.metadata.present.map) {
const struct tun_metadata_loc *loc;
bool is_masked;
union mf_value opts, mask_opts;
- loc = metadata_loc_from_match_read(flow.metadata.tab, match, i,
- &mask, &is_masked);
+ loc = metadata_loc_from_match_read(match->flow.tunnel.metadata.tab,
+ match, i, &match->wc.masks.tunnel,
+ &is_masked);
ds_put_format(s, "tun_metadata%u", i);
- memcpy_from_metadata(mask_opts.tun_metadata, &mask.metadata, loc);
+ memcpy_from_metadata(mask_opts.tun_metadata,
+ &match->wc.masks.tunnel.metadata, loc);
- if (!ULLONG_GET(flow.metadata.present.map, i)) {
+ if (!ULLONG_GET(match->flow.tunnel.metadata.present.map, i)) {
/* Indicate that we are matching on the field being not present. */
ds_put_cstr(s, "=NP");
} else if (!(is_masked &&
is_all_zeros(mask_opts.tun_metadata, loc->len))) {
ds_put_char(s, '=');
- memcpy_from_metadata(opts.tun_metadata, &flow.metadata, loc);
+ memcpy_from_metadata(opts.tun_metadata,
+ &match->flow.tunnel.metadata, loc);
ds_put_hex(s, opts.tun_metadata, loc->len);
if (!is_all_ones(mask_opts.tun_metadata, loc->len)) {
diff --git a/lib/tun-metadata.h b/lib/tun-metadata.h
index 4ce07701d..7dad9504b 100644
--- a/lib/tun-metadata.h
+++ b/lib/tun-metadata.h
@@ -33,10 +33,15 @@ struct ofputil_tlv_table_mod;
struct ofputil_tlv_table_reply;
struct tun_table;
-void tun_metadata_init(void);
+struct tun_table *tun_metadata_alloc(const struct tun_table *old_map);
+void tun_metadata_free(struct tun_table *);
+void tun_metadata_postpone_free(struct tun_table *);
-enum ofperr tun_metadata_table_mod(struct ofputil_tlv_table_mod *);
-void tun_metadata_table_request(struct ofputil_tlv_table_reply *);
+enum ofperr tun_metadata_table_mod(struct ofputil_tlv_table_mod *,
+ const struct tun_table *old_tab,
+ struct tun_table **new_tab);
+void tun_metadata_table_request(const struct tun_table *,
+ struct ofputil_tlv_table_reply *);
void tun_metadata_read(const struct flow_tnl *,
const struct mf_field *, union mf_value *);
@@ -48,17 +53,15 @@ void tun_metadata_set_match(const struct mf_field *,
char **err_str);
void tun_metadata_get_fmd(const struct flow_tnl *, struct match *flow_metadata);
-int tun_metadata_from_geneve_nlattr(const struct nlattr *attr,
- const struct nlattr *flow_attrs,
- size_t flow_attr_len,
- const struct flow_tnl *flow_tun,
- bool udpif, struct flow_tnl *tun);
+void tun_metadata_from_geneve_nlattr(const struct nlattr *attr, bool is_mask,
+ struct flow_tnl *tun);
void tun_metadata_to_geneve_nlattr(const struct flow_tnl *tun,
const struct flow_tnl *flow,
const struct ofpbuf *key,
struct ofpbuf *);
-int tun_metadata_from_geneve_udpif(const struct flow_tnl *flow,
+int tun_metadata_from_geneve_udpif(const struct tun_table *,
+ const struct flow_tnl *flow,
const struct flow_tnl *src,
struct flow_tnl *dst);
void tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src,