@@ -22,6 +22,7 @@
#include "openvswitch/tun-metadata.h"
struct ds;
+struct ofproto;
/* A flow classification match.
*
@@ -211,7 +212,8 @@ bool minimatch_equal(const struct minimatch *a, const struct minimatch *b);
bool minimatch_matches_flow(const struct minimatch *, const struct flow *);
-void minimatch_format(const struct minimatch *, struct ds *, int priority);
+void minimatch_format(const struct ofproto *, const struct minimatch *,
+ struct ds *, int priority);
char *minimatch_to_string(const struct minimatch *, int priority);
#endif /* match.h */
@@ -27,6 +27,7 @@
struct flow;
struct ofpbuf;
+struct ofproto;
struct ofputil_flow_mod;
struct ofputil_flow_monitor_request;
struct ofputil_flow_stats_request;
@@ -62,8 +63,9 @@ char *parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *,
enum ofputil_protocol *usable_protocols)
OVS_WARN_UNUSED_RESULT;
-char *parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
- const char *s, const struct simap *portno_names);
+char *parse_ofp_exact_flow(struct ofproto *, struct flow *flow,
+ struct flow_wildcards *wc, const char *s,
+ const struct simap *portno_names);
char *parse_ofp_meter_mod_str(struct ofputil_meter_mod *, const char *string,
int command,
@@ -221,7 +221,8 @@ void ofputil_normalize_match_quiet(struct match *);
void ofputil_match_to_ofp10_match(const struct match *, struct ofp10_match *);
/* Work with ofp11_match. */
-enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *, struct match *,
+enum ofperr ofputil_pull_ofp11_match(struct ofproto *,struct ofpbuf *,
+ struct match *,
uint16_t *padded_match_len);
enum ofperr ofputil_pull_ofp11_mask(struct ofpbuf *, struct match *,
struct mf_bitmap *bm);
@@ -327,7 +328,8 @@ struct ofputil_flow_mod {
size_t ofpacts_len; /* Length of ofpacts, in bytes. */
};
-enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *,
+enum ofperr ofputil_decode_flow_mod(struct ofproto *,
+ struct ofputil_flow_mod *,
const struct ofp_header *,
enum ofputil_protocol,
struct ofpbuf *ofpacts,
@@ -347,7 +349,7 @@ struct ofputil_flow_stats_request {
uint8_t table_id;
};
-enum ofperr ofputil_decode_flow_stats_request(
+enum ofperr ofputil_decode_flow_stats_request(struct ofproto *,
struct ofputil_flow_stats_request *, const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_stats_request(
const struct ofputil_flow_stats_request *, enum ofputil_protocol);
@@ -376,7 +378,8 @@ int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *,
struct ofpbuf *msg,
bool flow_age_extension,
struct ofpbuf *ofpacts);
-void ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *,
+void ofputil_append_flow_stats_reply(struct ofproto *,
+ const struct ofputil_flow_stats *,
struct ovs_list *replies);
/* Aggregate stats reply, independent of protocol. */
@@ -450,8 +453,9 @@ struct ofputil_packet_in {
void ofputil_packet_in_destroy(struct ofputil_packet_in *);
-enum ofperr ofputil_decode_packet_in(const struct ofp_header *, bool loose,
- struct ofputil_packet_in *,
+enum ofperr ofputil_decode_packet_in(struct ofproto *,
+ const struct ofp_header *,
+ bool loose, struct ofputil_packet_in *,
size_t *total_len, uint32_t *buffer_id,
struct ofpbuf *continuation);
@@ -502,6 +506,7 @@ struct ofpbuf *ofputil_encode_packet_in_private(
uint16_t max_len, struct pktbuf *);
enum ofperr ofputil_decode_packet_in_private(
+ struct ofproto *,
const struct ofp_header *, bool loose,
struct ofputil_packet_in_private *,
size_t *total_len, uint32_t *buffer_id);
@@ -87,7 +87,7 @@ struct tun_metadata_match_entry {
};
/* Allocation of options inside struct match. This is important if we don't
- * have access to a global allocation table - either because there isn't one
+ * have access to an allocation table - either because there isn't one
* (ovs-ofctl) or if we need to keep the allocation outside of packet
* processing context (Packet-In). These structures never have dynamically
* allocated memory because the address space is never fragmented. */
@@ -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 ofproto *ofproto, const struct cls_rule *rule,
+ struct ds *s)
{
- minimatch_format(&rule->match, s, rule->priority);
+ minimatch_format(ofproto, &rule->match, s, rule->priority);
}
/* Returns true if 'rule' matches every packet, false otherwise. */
@@ -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 ofproto *, const struct cls_rule *,
+ 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);
@@ -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(NULL, &flow_filter, &wc_filter, 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);
@@ -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
@@ -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);
@@ -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(NULL, oh, true, &pi, NULL,
+ &buffer_id, NULL);
if (error) {
VLOG_WARN_RL(&rl, "failed to decode packet-in: %s",
ofperr_to_string(error));
@@ -24,6 +24,8 @@
#include "openvswitch/ofp-util.h"
#include "packets.h"
#include "tun-metadata.h"
+#include "ovs-rcu.h"
+#include "ofproto/ofproto-provider.h"
/* Converts the flow in 'flow' into a match in 'match', with the given
* 'wildcards'. */
@@ -1463,11 +1465,16 @@ 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 ofproto *ofproto, const struct minimatch *match,
+ struct ds *s, int priority)
{
struct match megamatch;
minimatch_expand(match, &megamatch);
+ if (ofproto) {
+ megamatch.flow.tunnel.metadata.tab =
+ ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab);
+ }
match_format(&megamatch, s, priority);
}
@@ -22,6 +22,7 @@
#include "classifier.h"
#include "colors.h"
+#include "ofproto/ofproto-provider.h"
#include "openvswitch/hmap.h"
#include "openflow/nicira-ext.h"
#include "openvswitch/dynamic-string.h"
@@ -473,12 +474,17 @@ 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)
+nx_pull_raw(struct ofproto *ofproto, const uint8_t *p, unsigned int match_len,
+ bool strict, struct match *match, ovs_be64 *cookie,
+ ovs_be64 *cookie_mask)
{
ovs_assert((cookie != NULL) == (cookie_mask != NULL));
match_init_catchall(match);
+ if (ofproto) {
+ match->flow.tunnel.metadata.tab =
+ ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab);
+ }
if (cookie) {
*cookie = *cookie_mask = htonll(0);
}
@@ -529,12 +535,13 @@ 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,
+nx_pull_match__(struct ofproto *ofproto, struct ofpbuf *b,
+ unsigned int match_len, bool strict, struct match *match,
ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
uint8_t *p = NULL;
@@ -549,7 +556,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(ofproto, p, match_len, strict, match, cookie,
+ cookie_mask);
}
/* Parses the nx_match formatted match description in 'b' with length
@@ -561,24 +569,28 @@ 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,
+nx_pull_match(struct ofproto *ofproto, struct ofpbuf *b,
+ unsigned int match_len, struct match *match,
ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
- return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask);
+ return nx_pull_match__(ofproto, b, match_len, true, match, cookie,
+ cookie_mask);
}
/* Behaves the same as nx_pull_match(), but skips over unknown NXM headers,
* instead of failing with an error. */
enum ofperr
-nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len,
- struct match *match,
+nx_pull_match_loose(struct ofproto *ofproto, struct ofpbuf *b,
+ unsigned int match_len, struct match *match,
ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
- return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask);
+ return nx_pull_match__(ofproto, b, match_len, false, match, cookie,
+ cookie_mask);
}
static enum ofperr
-oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
+oxm_pull_match__(struct ofproto *ofproto, struct ofpbuf *b, bool strict,
+ struct match *match)
{
struct ofp11_match_header *omh = b->data;
uint8_t *p;
@@ -605,7 +617,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
return OFPERR_OFPBMC_BAD_LEN;
}
- return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh,
+ return nx_pull_raw(ofproto, p + sizeof *omh, match_len - sizeof *omh,
strict, match, NULL, NULL);
}
@@ -616,17 +628,18 @@ 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 ofproto *ofproto, struct ofpbuf *b, struct match *match)
{
- return oxm_pull_match__(b, true, match);
+ return oxm_pull_match__(ofproto, b, true, 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 ofproto *ofproto, struct ofpbuf *b,
+ struct match *match)
{
- return oxm_pull_match__(b, false, match);
+ return oxm_pull_match__(ofproto, b, false, match);
}
/* Parses the OXM match description in the 'oxm_len' bytes in 'oxm'. Stores
@@ -636,9 +649,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(struct ofproto *ofproto, const void *oxm, size_t oxm_len,
+ struct match *match)
{
- return nx_pull_raw(oxm, oxm_len, true, match, NULL, NULL);
+ return nx_pull_raw(ofproto, oxm, oxm_len, true, match, NULL, NULL);
}
/* Verify an array of OXM TLVs treating value of each TLV as a mask,
@@ -48,15 +48,17 @@ char *mf_parse_subfield(struct mf_subfield *, const char *s)
OVS_WARN_UNUSED_RESULT;
/* Decoding matches. */
-enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len,
- struct match *,
+enum ofperr nx_pull_match(struct ofproto *, struct ofpbuf *,
+ unsigned int match_len, struct match *,
ovs_be64 *cookie, ovs_be64 *cookie_mask);
-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 *);
+enum ofperr nx_pull_match_loose(struct ofproto *, struct ofpbuf *,
+ unsigned int match_len, struct match *,
+ ovs_be64 *cookie, ovs_be64 *cookie_mask);
+enum ofperr oxm_pull_match(struct ofproto *, struct ofpbuf *, struct match *);
+enum ofperr oxm_pull_match_loose(struct ofproto *, struct ofpbuf *,
+ struct match *);
+enum ofperr oxm_decode_match(struct ofproto *, const void *, size_t,
+ struct match *);
enum ofperr oxm_pull_field_array(const void *, size_t fields_len,
struct field_array *);
@@ -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);
}
@@ -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 *
@@ -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,
@@ -26,6 +26,7 @@
#include "multipath.h"
#include "netdev.h"
#include "nx-match.h"
+#include "ofproto/ofproto-provider.h"
#include "openflow/openflow.h"
#include "openvswitch/dynamic-string.h"
#include "openvswitch/meta-flow.h"
@@ -1121,8 +1122,9 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
* Returns NULL on success, otherwise a malloc()'d string that explains the
* problem. */
char *
-parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
- const char *s, const struct simap *portno_names)
+parse_ofp_exact_flow(struct ofproto *ofproto, struct flow *flow,
+ struct flow_wildcards *wc, const char *s,
+ const struct simap *portno_names)
{
char *pos, *key, *value_s;
char *error = NULL;
@@ -1133,6 +1135,11 @@ parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
memset(wc, 0, sizeof *wc);
}
+ if (ofproto) {
+ flow->tunnel.metadata.tab = ovsrcu_get_protected(struct tun_table *,
+ &ofproto->metadata_tab);
+ }
+
pos = copy = xstrdup(s);
while (ofputil_parse_key_value(&pos, &key, &value_s)) {
const struct protocol *p;
@@ -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(NULL, oh, true,
&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(NULL, &fm, oh, protocol, &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(NULL, &fsr, oh);
if (error) {
ofp_print_error(string, error);
return;
@@ -31,6 +31,7 @@
#include "netdev.h"
#include "nx-match.h"
#include "id-pool.h"
+#include "ofproto/ofproto-provider.h"
#include "openflow/netronome-ext.h"
#include "openvswitch/dynamic-string.h"
#include "openvswitch/meta-flow.h"
@@ -278,8 +279,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 ofproto *ofproto, struct ofpbuf *buf,
+ struct match *match, uint16_t *padded_match_len)
{
struct ofp11_match_header *omh = buf->data;
uint16_t match_len;
@@ -308,7 +309,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(ofproto, buf, match);
default:
return OFPERR_OFPBMC_BAD_TYPE;
@@ -1568,7 +1569,8 @@ ofputil_encode_flow_mod_flags(enum ofputil_flow_mod_flags flags,
* Does not validate the flow_mod actions. The caller should do that, with
* ofpacts_check(). */
enum ofperr
-ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
+ofputil_decode_flow_mod(struct ofproto *ofproto,
+ struct ofputil_flow_mod *fm,
const struct ofp_header *oh,
enum ofputil_protocol protocol,
struct ofpbuf *ofpacts,
@@ -1584,7 +1586,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(ofproto, &b, &fm->match, NULL);
if (error) {
return error;
}
@@ -1678,7 +1680,7 @@ 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),
+ error = nx_pull_match(ofproto, &b, ntohs(nfm->match_len),
&fm->match, &fm->cookie, &fm->cookie_mask);
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,
+ofputil_decode_ofpst11_flow_request(struct ofproto *ofproto,
+ struct ofputil_flow_stats_request *fsr,
struct ofpbuf *b, bool aggregate)
{
const struct ofp11_flow_stats_request *ofsr;
@@ -2283,7 +2286,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(ofproto, b, &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,
+ofputil_decode_nxst_flow_request(struct ofproto *ofproto,
+ struct ofputil_flow_stats_request *fsr,
struct ofpbuf *b, bool aggregate)
{
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,
+ error = nx_pull_match(ofproto, b, ntohs(nfsr->match_len), &fsr->match,
&fsr->cookie, &fsr->cookie_mask);
if (error) {
return error;
@@ -2712,7 +2716,8 @@ ofputil_pull_queue_get_config_reply(struct ofpbuf *msg,
* request 'oh', into an abstract flow_stats_request in 'fsr'. Returns 0 if
* successful, otherwise an OpenFlow error code. */
enum ofperr
-ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
+ofputil_decode_flow_stats_request(struct ofproto *ofproto,
+ struct ofputil_flow_stats_request *fsr,
const struct ofp_header *oh)
{
struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
@@ -2725,16 +2730,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(ofproto, fsr, &b, false);
case OFPRAW_OFPST11_AGGREGATE_REQUEST:
- return ofputil_decode_ofpst11_flow_request(fsr, &b, true);
+ return ofputil_decode_ofpst11_flow_request(ofproto, fsr, &b, true);
case OFPRAW_NXST_FLOW_REQUEST:
- return ofputil_decode_nxst_flow_request(fsr, &b, false);
+ return ofputil_decode_nxst_flow_request(ofproto, fsr, &b, false);
case OFPRAW_NXST_AGGREGATE_REQUEST:
- return ofputil_decode_nxst_flow_request(fsr, &b, true);
+ return ofputil_decode_nxst_flow_request(ofproto, fsr, &b, true);
default:
/* Hey, the caller lied. */
@@ -2878,7 +2883,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(NULL, msg, &fs->match,
+ &padded_match_len)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad match");
return EINVAL;
}
@@ -2960,7 +2966,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(NULL, msg, match_len, &fs->match, NULL, NULL)) {
return EINVAL;
}
instructions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
@@ -3015,14 +3021,22 @@ unknown_to_zero(uint64_t count)
* those already present in the list of ofpbufs in 'replies'. 'replies' should
* have been initialized with ofpmp_init(). */
void
-ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
+ofputil_append_flow_stats_reply(struct ofproto *ofproto,
+ const struct ofputil_flow_stats *fs,
struct ovs_list *replies)
{
+ struct ofputil_flow_stats *fs_ = CONST_CAST(struct ofputil_flow_stats *,
+ fs);
+ 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 =
+ ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab);
+
if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
struct ofp11_flow_stats *ofs;
@@ -3108,6 +3122,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
@@ -3171,7 +3186,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(NULL, &b, &fr->match, NULL);
if (error) {
return error;
}
@@ -3207,7 +3222,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(NULL, &b, ntohs(nfr->match_len), &fr->match,
NULL, NULL);
if (error) {
return error;
@@ -3328,8 +3343,8 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
/* The caller has done basic initialization of '*pin'; the other output
* arguments needs to be initialized. */
static enum ofperr
-decode_nx_packet_in2(const struct ofp_header *oh, bool loose,
- struct ofputil_packet_in *pin,
+decode_nx_packet_in2(struct ofproto *ofproto, const struct ofp_header *oh,
+ bool loose, struct ofputil_packet_in *pin,
size_t *total_len, uint32_t *buffer_id,
struct ofpbuf *continuation)
{
@@ -3382,7 +3397,8 @@ decode_nx_packet_in2(const struct ofp_header *oh, bool loose,
}
case NXPINT_METADATA:
- error = oxm_decode_match(payload.msg, ofpbuf_msgsize(&payload),
+ error = oxm_decode_match(ofproto, payload.msg,
+ ofpbuf_msgsize(&payload),
&pin->flow_metadata);
break;
@@ -3439,8 +3455,8 @@ 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,
- struct ofputil_packet_in *pin,
+ofputil_decode_packet_in(struct ofproto *ofproto, const struct ofp_header *oh,
+ bool loose, struct ofputil_packet_in *pin,
size_t *total_lenp, uint32_t *buffer_idp,
struct ofpbuf *continuation)
{
@@ -3460,7 +3476,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(ofproto, &b,
+ &pin->flow_metadata);
if (error) {
return error;
}
@@ -3518,7 +3535,7 @@ ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
int error;
npi = ofpbuf_pull(&b, sizeof *npi);
- error = nx_pull_match_loose(&b, ntohs(npi->match_len),
+ error = nx_pull_match_loose(ofproto, &b, ntohs(npi->match_len),
&pin->flow_metadata, NULL, NULL);
if (error) {
return error;
@@ -3538,8 +3555,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(ofproto, oh, loose, pin,
+ &total_len, &buffer_id,
+ continuation);
if (error) {
return error;
}
@@ -4046,7 +4064,8 @@ parse_actions_property(struct ofpbuf *property, enum ofp_version version,
* When successful, 'pin' contains some dynamically allocated data. Call
* ofputil_packet_in_private_destroy() to free this data. */
enum ofperr
-ofputil_decode_packet_in_private(const struct ofp_header *oh, bool loose,
+ofputil_decode_packet_in_private(struct ofproto *ofproto,
+ const struct ofp_header *oh, bool loose,
struct ofputil_packet_in_private *pin,
size_t *total_len, uint32_t *buffer_id)
{
@@ -4054,8 +4073,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(ofproto, oh, loose, &pin->public,
+ total_len, buffer_id, &continuation);
if (error) {
return error;
}
@@ -6617,7 +6636,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(NULL, msg, ntohs(nfmr->match_len), &rq->match,
+ NULL, NULL);
}
void
@@ -6725,7 +6745,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(NULL, msg, match_len, update->match, NULL, NULL);
if (error) {
return error;
}
@@ -28,6 +28,7 @@
#include "ovs-thread.h"
#include "ovs-rcu.h"
#include "packets.h"
+#include "ofproto/ofproto-provider.h"
#include "tun-metadata.h"
#include "util.h"
@@ -52,14 +53,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 +83,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 +117,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,33 +134,19 @@ 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)
-{
- 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);
-}
-
enum ofperr
-tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm)
+tun_metadata_table_mod(struct ofproto *ofproto,
+ struct ofputil_tlv_table_mod *ttm)
{
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);
+ old_map = ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab);
switch (ttm->command) {
case NXTTMC_ADD:
- new_map = table_alloc(old_map);
+ new_map = tun_metadata_alloc(old_map);
LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
err = tun_metadata_add_entry(new_map, ofp_map->index,
@@ -171,14 +154,14 @@ tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm)
ofp_map->option_type,
ofp_map->option_len);
if (err) {
- table_free(new_map);
- goto out;
+ tun_metadata_free(new_map);
+ return err;
}
}
break;
case NXTTMC_DELETE:
- new_map = table_alloc(old_map);
+ new_map = tun_metadata_alloc(old_map);
LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
tun_metadata_del_entry(new_map, ofp_map->index);
@@ -186,27 +169,28 @@ tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm)
break;
case NXTTMC_CLEAR:
- new_map = table_alloc(NULL);
+ new_map = tun_metadata_alloc(NULL);
break;
default:
OVS_NOT_REACHED();
}
- ovsrcu_set(&metadata_tab, new_map);
- ovsrcu_postpone(table_free, old_map);
+ ovsrcu_set(&ofproto->metadata_tab, new_map);
+ ovsrcu_postpone(tun_metadata_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(struct ofproto *ofproto,
+ struct ofputil_tlv_table_reply *ttr)
{
- struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
+ struct tun_table *map;
int i;
+ map = ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab);
+
ttr->max_option_space = TUN_METADATA_TOT_OPT_SIZE;
ttr->max_fields = TUN_METADATA_NUM_OPTS;
ovs_list_init(&ttr->mappings);
@@ -233,14 +217,14 @@ 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);
+ struct tun_table *map = tnl->metadata.tab;
unsigned int idx = mf->id - MFF_TUN_METADATA0;
struct tun_metadata_loc *loc;
@@ -260,14 +244,14 @@ 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);
+ struct tun_table *map = tnl->metadata.tab;
unsigned int idx = mf->id - MFF_TUN_METADATA0;
struct tun_metadata_loc *loc;
@@ -333,11 +317,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 +338,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);
+ 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 +346,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 +380,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 +460,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 +504,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 +555,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 +585,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(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 +642,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 +664,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];
+ 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 +722,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 +733,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 +765,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 +774,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,8 +831,6 @@ 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);
@@ -978,7 +838,7 @@ tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src,
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,
+ unsigned int idx, const struct flow_tnl *mask,
bool *is_masked)
{
union mf_value mask_opts;
@@ -997,63 +857,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)) {
@@ -32,11 +32,15 @@ union mf_value;
struct ofputil_tlv_table_mod;
struct ofputil_tlv_table_reply;
struct tun_table;
+struct ofproto;
-void tun_metadata_init(void);
+struct tun_table *tun_metadata_alloc(const struct tun_table *old_map);
+void tun_metadata_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 ofproto *,
+ struct ofputil_tlv_table_mod *);
+void tun_metadata_table_request(struct ofproto *,
+ struct ofputil_tlv_table_reply *);
void tun_metadata_read(const struct flow_tnl *,
const struct mf_field *, union mf_value *);
@@ -48,17 +52,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(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,
@@ -958,7 +958,7 @@ sflow_read_set_action(const struct nlattr *attr,
/* Do not handle multi-encap for now. */
sflow_actions->tunnel_err = true;
} else {
- if (odp_tun_key_from_attr(attr, false, &sflow_actions->tunnel)
+ if (odp_tun_key_from_attr(attr, &sflow_actions->tunnel)
== ODP_FIT_ERROR) {
/* Tunnel parsing error. */
sflow_actions->tunnel_err = true;
@@ -1267,8 +1267,7 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
memcpy(&cookie, nl_attr_get(userdata), sizeof cookie.ipfix);
if (upcall->out_tun_key) {
- odp_tun_key_from_attr(upcall->out_tun_key, false,
- &output_tunnel_key);
+ odp_tun_key_from_attr(upcall->out_tun_key, &output_tunnel_key);
}
dpif_ipfix_bridge_sample(upcall->ipfix, packet, flow,
flow->in_port.odp_port,
@@ -1287,8 +1286,7 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
memcpy(&cookie, nl_attr_get(userdata), sizeof cookie.flow_sample);
if (upcall->out_tun_key) {
- odp_tun_key_from_attr(upcall->out_tun_key, false,
- &output_tunnel_key);
+ odp_tun_key_from_attr(upcall->out_tun_key, &output_tunnel_key);
}
/* The flow reflects exactly the contents of the packet.
@@ -1870,8 +1868,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
odp_actions);
}
- if (odp_flow_key_to_mask(ukey->mask, ukey->mask_len, ukey->key,
- ukey->key_len, &dp_mask, &flow)
+ if (odp_flow_key_to_mask(ukey->mask, ukey->mask_len, &dp_mask, &flow)
== ODP_FIT_ERROR) {
goto exit;
}
@@ -396,6 +396,8 @@ const char *xlate_strerror(enum xlate_error error)
return "Recirculation conflict";
case XLATE_TOO_MANY_MPLS_LABELS:
return "Too many MPLS labels";
+ case XLATE_INVALID_TUNNEL_METADATA:
+ return "Invalid tunnel metadata";
}
return "Unknown error";
}
@@ -3052,6 +3054,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
if (xport->peer) {
const struct xport *peer = xport->peer;
struct flow old_flow = ctx->xin->flow;
+ struct flow_tnl old_flow_tnl_wc = ctx->wc->masks.tunnel;
bool old_conntrack = ctx->conntracked;
bool old_was_mpls = ctx->was_mpls;
ovs_version_t old_version = ctx->tables_version;
@@ -3066,6 +3069,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
flow->in_port.ofp_port = peer->ofp_port;
flow->metadata = htonll(0);
memset(&flow->tunnel, 0, sizeof flow->tunnel);
+ flow->tunnel.metadata.tab = ofproto_dpif_get_metadata_tab(ctx->xbridge->ofproto);
+ ctx->wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab;
memset(flow->regs, 0, sizeof flow->regs);
flow->actset_output = OFPP_UNSET;
ctx->conntracked = false;
@@ -3111,6 +3116,15 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
/* Restore calling bridge's lookup version. */
ctx->tables_version = old_version;
+ /* Since this packet came in on a patch port (from the perspective of
+ * the peer bridge), it cannot have useful tunnel information. As a
+ * result, any wildcards generated on that tunnel also cannot be valid.
+ * The tunnel wildcards must be restored to their original version since
+ * the peer bridge uses a separate tunnel metadata table and therefore
+ * any generated wildcards will be garbage in the context of our
+ * metadata table. */
+ ctx->wc->masks.tunnel = old_flow_tnl_wc;
+
/* The peer bridge popping MPLS should have no effect on the original
* bridge. */
ctx->was_mpls = old_was_mpls;
@@ -5093,6 +5107,7 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
{
xin->ofproto = ofproto;
xin->flow = *flow;
+ xin->upcall_flow = flow;
xin->flow.in_port.ofp_port = in_port;
xin->flow.actset_output = OFPP_UNSET;
xin->packet = packet;
@@ -5494,6 +5509,28 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
ctx.error = XLATE_NO_RECIRCULATION_CONTEXT;
goto exit;
}
+
+ /* Tunnel metadata in udpif format must be normalized before translation. */
+ if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
+ struct tun_table *tun_tab = ofproto_dpif_get_metadata_tab(xin->ofproto);
+ int err;
+
+ err = tun_metadata_from_geneve_udpif(tun_tab, &xin->upcall_flow->tunnel,
+ &xin->upcall_flow->tunnel,
+ &flow->tunnel);
+ if (err) {
+ XLATE_REPORT_ERROR(&ctx, "Invalid Geneve tunnel metadata");
+ ctx.error = XLATE_INVALID_TUNNEL_METADATA;
+ goto exit;
+ }
+ } else if (!flow->tunnel.metadata.tab) {
+ /* If the original flow did not come in on a tunnel, then it won't have
+ * FLOW_TNL_F_UDPIF set. However, we still need to have a metadata
+ * table in case we generate tunnel actions. */
+ flow->tunnel.metadata.tab = ofproto_dpif_get_metadata_tab(xin->ofproto);
+ }
+ ctx.wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab;
+
/* The bridge is now known so obtain its table version. */
ctx.tables_version = ofproto_dpif_get_tables_version(ctx.xbridge->ofproto);
@@ -5650,9 +5687,48 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
}
}
+ /* Translate tunnel metadata masks to udpif format if necessary. */
+ if (xin->upcall_flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
+ if (ctx.wc->masks.tunnel.metadata.present.map) {
+ const struct flow_tnl *upcall_tnl = &xin->upcall_flow->tunnel;
+ struct geneve_opt opts[TLV_TOT_OPT_SIZE /
+ sizeof(struct geneve_opt)];
+
+ tun_metadata_to_geneve_udpif_mask(&flow->tunnel,
+ &ctx.wc->masks.tunnel,
+ upcall_tnl->metadata.opts.gnv,
+ upcall_tnl->metadata.present.len,
+ opts);
+ memset(&ctx.wc->masks.tunnel.metadata, 0,
+ sizeof ctx.wc->masks.tunnel.metadata);
+ memcpy(&ctx.wc->masks.tunnel.metadata.opts.gnv, opts,
+ upcall_tnl->metadata.present.len);
+ }
+ ctx.wc->masks.tunnel.metadata.present.len = 0xff;
+ ctx.wc->masks.tunnel.metadata.tab = NULL;
+ ctx.wc->masks.tunnel.flags |= FLOW_TNL_F_UDPIF;
+ } else if (!xin->upcall_flow->tunnel.metadata.tab) {
+ /* If we didn't have options in UDPIF format and didn't have an existing
+ * metadata table, then it means that there were no options at all when
+ * we started processing and any wildcards we picked up were from
+ * action generation. Without options on the incoming packet, wildcards
+ * aren't meaningful. To avoid them possibly getting misinterpreted,
+ * just clear everything. */
+ if (ctx.wc->masks.tunnel.metadata.present.map) {
+ memset(&ctx.wc->masks.tunnel.metadata, 0,
+ sizeof ctx.wc->masks.tunnel.metadata);
+ } else {
+ ctx.wc->masks.tunnel.metadata.tab = NULL;
+ }
+ }
+
xlate_wc_finish(&ctx);
exit:
+ /* Reset the table to what it was when we came in. If we only fetched
+ * it locally, then it has no meaning outside of flow translation. */
+ flow->tunnel.metadata.tab = xin->upcall_flow->tunnel.metadata.tab;
+
ofpbuf_uninit(&ctx.stack);
ofpbuf_uninit(&ctx.action_set);
ofpbuf_uninit(&ctx.frozen_actions);
@@ -51,6 +51,10 @@ struct xlate_in {
* this flow when actions change header fields. */
struct flow flow;
+ /* Pointer to the original flow received during the upcall. xlate_actions()
+ * will never modify this flow. */
+ const struct flow *upcall_flow;
+
/* The packet corresponding to 'flow', or a null pointer if we are
* revalidating without a packet to refer to. */
const struct dp_packet *packet;
@@ -194,6 +198,7 @@ enum xlate_error {
XLATE_NO_RECIRCULATION_CONTEXT,
XLATE_RECIRCULATION_CONFLICT,
XLATE_TOO_MANY_MPLS_LABELS,
+ XLATE_INVALID_TUNNEL_METADATA,
};
const char *xlate_strerror(enum xlate_error error);
@@ -356,6 +356,12 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
/* Initial mappings of port to bridge mappings. */
static struct shash init_ofp_ports = SHASH_INITIALIZER(&init_ofp_ports);
+struct tun_table *
+ofproto_dpif_get_metadata_tab(const struct ofproto_dpif *ofproto)
+{
+ return ovsrcu_get(struct tun_table *, &ofproto->up.metadata_tab);
+}
+
/* Executes 'fm'. The caller retains ownership of 'fm' and everything in
* it. */
void
@@ -4725,7 +4731,8 @@ struct trace_ctx {
};
static void
-trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule)
+trace_format_rule(struct ofproto *ofproto, struct ds *result, int level,
+ const struct rule_dpif *rule)
{
const struct rule_actions *actions;
ovs_be64 cookie;
@@ -4742,7 +4749,7 @@ trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule)
ds_put_format(result, "Rule: table=%"PRIu8" cookie=%#"PRIx64" ",
rule ? rule->up.table_id : 0, ntohll(cookie));
- cls_rule_format(&rule->up.cr, result);
+ cls_rule_format(ofproto, &rule->up.cr, result);
ds_put_char(result, '\n');
actions = rule_dpif_get_actions(rule);
@@ -4844,7 +4851,7 @@ trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int indentation)
trace_format_megaflow(result, indentation, "Resubmitted megaflow",
trace);
}
- trace_format_rule(result, indentation, rule);
+ trace_format_rule(&xin->ofproto->up, result, indentation, rule);
}
static void
@@ -4961,24 +4968,46 @@ parse_flow_and_packet(int argc, const char *argv[],
error = "Invalid datapath flow";
goto exit;
}
+
+ flow->tunnel.metadata.tab = ofproto_dpif_get_metadata_tab(*ofprotop);
+
+ /* Convert Geneve options to OpenFlow format now. This isn't actually
+ * required in order to get the right results since the ofproto xlate
+ * actions will handle this for us. However, converting now ensures
+ * that our formatting code will always be able to consistently print
+ * in OpenFlow format, which is what we use here. */
+ if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
+ struct flow_tnl tnl;
+ int err;
+
+ memcpy(&tnl, &flow->tunnel, sizeof tnl);
+ err = tun_metadata_from_geneve_udpif(flow->tunnel.metadata.tab,
+ &tnl, &tnl, &flow->tunnel);
+ if (err) {
+ error = "Failed to parse Geneve options";
+ goto exit;
+ }
+ }
} else {
- char *err = parse_ofp_exact_flow(flow, NULL, argv[argc - 1], NULL);
+ char *err;
+ if (argc != 3) {
+ error = "Must specify bridge name";
+ goto exit;
+ }
+
+ *ofprotop = ofproto_dpif_lookup(argv[1]);
+ if (!*ofprotop) {
+ error = "Unknown bridge name";
+ goto exit;
+ }
+
+ err = parse_ofp_exact_flow(&(*ofprotop)->up, flow, NULL,
+ argv[argc - 1], NULL);
if (err) {
m_err = xasprintf("Bad openflow flow syntax: %s", err);
free(err);
goto exit;
- } else {
- if (argc != 3) {
- error = "Must specify bridge name";
- goto exit;
- }
-
- *ofprotop = ofproto_dpif_lookup(argv[1]);
- if (!*ofprotop) {
- error = "Unknown bridge name";
- goto exit;
- }
}
}
@@ -178,6 +178,7 @@ int ofproto_dpif_delete_internal_flow(struct ofproto_dpif *, struct match *,
int priority);
const struct uuid *ofproto_dpif_get_uuid(const struct ofproto_dpif *);
+struct tun_table *ofproto_dpif_get_metadata_tab(const struct ofproto_dpif *);
/* struct rule_dpif has struct rule as it's first member. */
#define RULE_CAST(RULE) ((struct rule *)RULE)
@@ -50,6 +50,7 @@
#include "openvswitch/shash.h"
#include "simap.h"
#include "timeval.h"
+#include "tun-metadata.h"
#include "versions.h"
struct match;
@@ -129,6 +130,9 @@ struct ofproto {
struct cmap groups; /* Contains "struct ofgroup"s. */
uint32_t n_groups[4] OVS_GUARDED; /* # of existing groups of each type. */
struct ofputil_group_features ogf;
+
+ /* Tunnel TLV mapping table. */
+ OVSRCU_TYPE(struct tun_table *) metadata_tab;
};
void ofproto_init_tables(struct ofproto *, int n_tables);
@@ -544,7 +544,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
ofproto->ogf.max_groups[i] = OFPG_MAX;
ofproto->ogf.ofpacts[i] = (UINT64_C(1) << N_OFPACTS) - 1;
}
- tun_metadata_init();
+ ovsrcu_set(&ofproto->metadata_tab, tun_metadata_alloc(NULL));
error = ofproto->ofproto_class->construct(ofproto);
if (error) {
@@ -1562,6 +1562,8 @@ ofproto_destroy__(struct ofproto *ofproto)
cmap_destroy(&ofproto->groups);
hmap_remove(&all_ofprotos, &ofproto->hmap_node);
+ tun_metadata_free(ovsrcu_get_protected(struct tun_table *,
+ &ofproto->metadata_tab));
free(ofproto->name);
free(ofproto->type);
free(ofproto->mfr_desc);
@@ -3548,7 +3550,8 @@ handle_nxt_resume(struct ofconn *ofconn, const struct ofp_header *oh)
struct ofputil_packet_in_private pin;
enum ofperr error;
- error = ofputil_decode_packet_in_private(oh, false, &pin, NULL, NULL);
+ error = ofputil_decode_packet_in_private(ofproto, oh, false, &pin,
+ NULL, NULL);
if (error) {
return error;
}
@@ -4251,7 +4254,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
struct ovs_list replies;
enum ofperr error;
- error = ofputil_decode_flow_stats_request(&fsr, request);
+ error = ofputil_decode_flow_stats_request(ofproto, &fsr, request);
if (error) {
return error;
}
@@ -4305,7 +4308,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
fs.ofpacts_len = actions->ofpacts_len;
fs.flags = flags;
- ofputil_append_flow_stats_reply(&fs, &replies);
+ ofputil_append_flow_stats_reply(ofproto, &fs, &replies);
}
rule_collection_unref(&rules);
@@ -4317,7 +4320,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
}
static void
-flow_stats_ds(struct rule *rule, struct ds *results)
+flow_stats_ds(struct ofproto *ofproto, struct rule *rule, struct ds *results)
{
uint64_t packet_count, byte_count;
const struct rule_actions *actions;
@@ -4337,7 +4340,7 @@ flow_stats_ds(struct rule *rule, struct ds *results)
ds_put_format(results, "duration=%llds, ", (time_msec() - created) / 1000);
ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
- cls_rule_format(&rule->cr, results);
+ cls_rule_format(ofproto, &rule->cr, results);
ds_put_char(results, ',');
ds_put_cstr(results, "actions=");
@@ -4357,7 +4360,7 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
struct rule *rule;
CLS_FOR_EACH (rule, cr, &table->cls) {
- flow_stats_ds(rule, results);
+ flow_stats_ds(p, rule, results);
}
}
}
@@ -4414,7 +4417,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
struct ofpbuf *reply;
enum ofperr error;
- error = ofputil_decode_flow_stats_request(&request, oh);
+ error = ofputil_decode_flow_stats_request(ofproto, &request, oh);
if (error) {
return error;
}
@@ -5484,8 +5487,8 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
}
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
- error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
- &ofpacts,
+ error = ofputil_decode_flow_mod(ofproto, &fm, oh,
+ ofconn_get_protocol(ofconn), &ofpacts,
u16_to_ofp(ofproto->max_ports),
ofproto->n_tables);
if (!error) {
@@ -7473,7 +7476,7 @@ handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
uint64_t ofpacts_stub[1024 / 8];
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
- error = ofputil_decode_flow_mod(&fm, badd.msg,
+ error = ofputil_decode_flow_mod(ofproto, &fm, badd.msg,
ofconn_get_protocol(ofconn),
&ofpacts,
u16_to_ofp(ofproto->max_ports),
@@ -7516,7 +7519,7 @@ handle_tlv_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
return error;
}
- error = tun_metadata_table_mod(&ttm);
+ error = tun_metadata_table_mod(ofconn_get_ofproto(ofconn), &ttm);
ofputil_uninit_tlv_table(&ttm.mappings);
return error;
@@ -7528,7 +7531,8 @@ handle_tlv_table_request(struct ofconn *ofconn, const struct ofp_header *oh)
struct ofputil_tlv_table_reply ttr;
struct ofpbuf *b;
- tun_metadata_table_request(&ttr);
+ tun_metadata_table_request(ofconn_get_ofproto(ofconn), &ttr);
+
b = ofputil_encode_tlv_table_reply(oh, &ttr);
ofputil_uninit_tlv_table(&ttr.mappings);
@@ -658,7 +658,7 @@ process_packet_in(const struct ofp_header *msg)
struct ofputil_packet_in pin;
struct ofpbuf continuation;
- enum ofperr error = ofputil_decode_packet_in(msg, true, &pin,
+ enum ofperr error = ofputil_decode_packet_in(NULL, msg, true, &pin,
NULL, NULL, &continuation);
if (error) {
@@ -163,7 +163,7 @@ parse_filter(char *filter_parse)
memset(&flow_filter, 0, sizeof(flow_filter));
memset(&wc_filter, 0, sizeof(wc_filter));
- error = parse_ofp_exact_flow(&flow_filter, &wc_filter, filter,
+ error = parse_ofp_exact_flow(NULL, &flow_filter, &wc_filter, filter,
NULL);
if (error) {
ovs_fatal(0, "Failed to parse filter (%s)", error);
@@ -196,8 +196,7 @@ parse_filter(char *filter_parse)
struct minimatch minimatch;
odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
- odp_flow_key_to_mask(odp_mask.data, odp_mask.size, odp_key.data,
- odp_key.size, &wc, &flow);
+ odp_flow_key_to_mask(odp_mask.data, odp_mask.size, &wc, &flow);
match_init(&match, &flow, &wc);
match_init(&match_filter, &flow_filter, &wc);
@@ -513,10 +513,6 @@ ovs-ofctl add-flow br0 tun_metadata0=1234,actions=controller
A mapping should not be changed while it is in active
use by a flow. The result of doing so is undefined.
-Currently, the TLV mapping table is shared between all OpenFlow
-switches in a given instance of Open vSwitch. This restriction will
-be lifted in the future to allow for easier management.
-
These commands are Nicira extensions to OpenFlow and require Open vSwitch
2.5 or later.
@@ -1828,7 +1828,7 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests,
struct ofputil_packet_in pin;
struct ofpbuf continuation;
- error = ofputil_decode_packet_in(b->data, true, &pin,
+ error = ofputil_decode_packet_in(NULL, b->data, true, &pin,
NULL, NULL,
&continuation);
if (error) {
@@ -2927,7 +2927,7 @@ fte_version_format(const struct fte *fte, int index, struct ds *s)
if (version->table_id) {
ds_put_format(s, "table=%"PRIu8" ", version->table_id);
}
- cls_rule_format(&fte->rule, s);
+ cls_rule_format(NULL, &fte->rule, s);
if (version->cookie != htonll(0)) {
ds_put_format(s, " cookie=0x%"PRIx64, ntohll(version->cookie));
}
@@ -3518,16 +3518,16 @@ ofctl_parse_nxm__(bool oxm, enum ofp_version version)
/* Convert nx_match to match. */
if (strict) {
if (oxm) {
- error = oxm_pull_match(&nx_match, &match);
+ error = oxm_pull_match(NULL, &nx_match, &match);
} else {
- error = nx_pull_match(&nx_match, match_len, &match,
+ error = nx_pull_match(NULL, &nx_match, match_len, &match,
&cookie, &cookie_mask);
}
} else {
if (oxm) {
- error = oxm_pull_match_loose(&nx_match, &match);
+ error = oxm_pull_match_loose(NULL, &nx_match, &match);
} else {
- error = nx_pull_match_loose(&nx_match, match_len, &match,
+ error = nx_pull_match_loose(NULL, &nx_match, match_len, &match,
&cookie, &cookie_mask);
}
}
@@ -3938,7 +3938,7 @@ ofctl_check_vlan(struct ovs_cmdl_context *ctx)
ofpbuf_init(&nxm, 0);
nxm_match_len = nx_put_match(&nxm, &match, htonll(0), htonll(0));
nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
- error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL);
+ error = nx_pull_match(NULL, &nxm, nxm_match_len, &nxm_match, NULL, NULL);
printf("NXM: %s -> ", nxm_s);
if (error) {
printf("%s\n", ofperr_to_string(error));
@@ -3954,7 +3954,7 @@ ofctl_check_vlan(struct ovs_cmdl_context *ctx)
ofpbuf_init(&nxm, 0);
nxm_match_len = oxm_put_match(&nxm, &match, OFP12_VERSION);
nxm_s = oxm_match_to_string(&nxm, nxm_match_len);
- error = oxm_pull_match(&nxm, &nxm_match);
+ error = oxm_pull_match(NULL, &nxm, &nxm_match);
printf("OXM: %s -> ", nxm_s);
if (error) {
printf("%s\n", ofperr_to_string(error));