From: Pravin B Shelar Date: Thu, 22 Nov 2012 02:51:36 +0000 (-0800) Subject: vswitchd: Log all tunnel parameters of given flow. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4fe3445afbbcda01e426d26cdcc1c7daa5d9f823;p=openvswitch vswitchd: Log all tunnel parameters of given flow. Signed-off-by: Pravin B Shelar --- diff --git a/lib/flow.c b/lib/flow.c index 3085848d..57eddba2 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -479,6 +479,50 @@ flow_to_string(const struct flow *flow) return ds_cstr(&ds); } +const char * +flow_tun_flag_to_string(uint32_t flags) +{ + switch (flags) { + case FLOW_TNL_F_DONT_FRAGMENT: + return "df"; + case FLOW_TNL_F_CSUM: + return "csum"; + case FLOW_TNL_F_KEY: + return "key"; + default: + return NULL; + } +} + +void +format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t), + uint32_t flags, char del) +{ + uint32_t bad = 0; + + if (!flags) { + return; + } + while (flags) { + uint32_t bit = rightmost_1bit(flags); + const char *s; + + s = bit_to_string(bit); + if (s) { + ds_put_format(ds, "%s%c", s, del); + } else { + bad |= bit; + } + + flags &= ~bit; + } + + if (bad) { + ds_put_format(ds, "0x%"PRIx32"%c", bad, del); + } + ds_chomp(ds, del); +} + void flow_format(struct ds *ds, const struct flow *flow) { diff --git a/lib/flow.h b/lib/flow.h index 804fee60..fa7410e2 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -56,6 +56,9 @@ BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER); #define FLOW_TNL_F_DONT_FRAGMENT (1 << 0) #define FLOW_TNL_F_CSUM (1 << 1) #define FLOW_TNL_F_KEY (1 << 2) + +const char *flow_tun_flag_to_string(uint32_t flags); + struct flow_tnl { ovs_be64 tun_id; ovs_be32 ip_src; @@ -123,6 +126,9 @@ void flow_zero_wildcards(struct flow *, const struct flow_wildcards *); void flow_get_metadata(const struct flow *, struct flow_metadata *); char *flow_to_string(const struct flow *); +void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t), + uint32_t flags, char del); + void flow_format(struct ds *, const struct flow *); void flow_print(FILE *, const struct flow *); static inline int flow_compare_3way(const struct flow *, const struct flow *); diff --git a/lib/match.c b/lib/match.c index 29ee1535..9eb121d7 100644 --- a/lib/match.c +++ b/lib/match.c @@ -62,14 +62,19 @@ match_wc_init(struct match *match, const struct flow *flow) } } - if (flow->tunnel.ip_dst || flow->tunnel.tun_id) { - memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id); + if (flow->tunnel.ip_dst) { + if (flow->tunnel.flags & FLOW_TNL_F_KEY) { + memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id); + } memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src); memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst); memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags); memset(&wc->masks.tunnel.ip_tos, 0xff, sizeof wc->masks.tunnel.ip_tos); memset(&wc->masks.tunnel.ip_ttl, 0xff, sizeof wc->masks.tunnel.ip_ttl); + } else if (flow->tunnel.tun_id) { + memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id); } + memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata); memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port); memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); @@ -195,6 +200,71 @@ match_set_tun_id_masked(struct match *match, ovs_be64 tun_id, ovs_be64 mask) match->flow.tunnel.tun_id = tun_id & mask; } +void +match_set_tun_src(struct match *match, ovs_be32 src) +{ + match_set_tun_src_masked(match, src, htonl(UINT32_MAX)); +} + +void +match_set_tun_src_masked(struct match *match, ovs_be32 src, ovs_be32 mask) +{ + match->wc.masks.tunnel.ip_src = mask; + match->flow.tunnel.ip_src = src & mask; +} + +void +match_set_tun_dst(struct match *match, ovs_be32 dst) +{ + match_set_tun_dst_masked(match, dst, htonl(UINT32_MAX)); +} + +void +match_set_tun_dst_masked(struct match *match, ovs_be32 dst, ovs_be32 mask) +{ + match->wc.masks.tunnel.ip_dst = mask; + match->flow.tunnel.ip_dst = dst & mask; +} + +void +match_set_tun_ttl(struct match *match, uint8_t ttl) +{ + match_set_tun_ttl_masked(match, ttl, UINT8_MAX); +} + +void +match_set_tun_ttl_masked(struct match *match, uint8_t ttl, uint8_t mask) +{ + match->wc.masks.tunnel.ip_ttl = mask; + match->flow.tunnel.ip_ttl = ttl & mask; +} + +void +match_set_tun_tos(struct match *match, uint8_t tos) +{ + match_set_tun_tos_masked(match, tos, UINT8_MAX); +} + +void +match_set_tun_tos_masked(struct match *match, uint8_t tos, uint8_t mask) +{ + match->wc.masks.tunnel.ip_tos = mask; + match->flow.tunnel.ip_tos = tos & mask; +} + +void +match_set_tun_flags(struct match *match, uint16_t flags) +{ + match_set_tun_flags_masked(match, flags, UINT16_MAX); +} + +void +match_set_tun_flags_masked(struct match *match, uint16_t flags, uint16_t mask) +{ + match->wc.masks.tunnel.flags = mask; + match->flow.tunnel.flags = flags & mask; +} + void match_set_in_port(struct match *match, uint16_t ofp_port) { @@ -643,6 +713,39 @@ format_be16_masked(struct ds *s, const char *name, } } +static void +format_flow_tunnel(struct ds *s, const struct match *match) +{ + const struct flow_wildcards *wc = &match->wc; + const struct flow_tnl *tnl = &match->flow.tunnel; + + switch (wc->masks.tunnel.tun_id) { + case 0: + break; + case CONSTANT_HTONLL(UINT64_MAX): + ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(tnl->tun_id)); + break; + default: + ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",", + ntohll(tnl->tun_id), + ntohll(wc->masks.tunnel.tun_id)); + break; + } + format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src); + format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst); + + if (wc->masks.tunnel.ip_tos) { + ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos); + } + if (wc->masks.tunnel.ip_ttl) { + ds_put_format(s, "tun_ttl=%"PRIu8",", tnl->ip_ttl); + } + if (wc->masks.tunnel.flags) { + format_flags(s, flow_tun_flag_to_string, tnl->flags, '|'); + ds_put_char(s, ','); + } +} + /* Appends a string representation of 'match' to 's'. If 'priority' is * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */ void @@ -717,18 +820,9 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) break; } } - switch (wc->masks.tunnel.tun_id) { - case 0: - break; - case CONSTANT_HTONLL(UINT64_MAX): - ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tunnel.tun_id)); - break; - default: - ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",", - ntohll(f->tunnel.tun_id), - ntohll(wc->masks.tunnel.tun_id)); - break; - } + + format_flow_tunnel(s, match); + switch (wc->masks.metadata) { case 0: break; diff --git a/lib/match.h b/lib/match.h index 28433b9e..fa3196a5 100644 --- a/lib/match.h +++ b/lib/match.h @@ -50,6 +50,16 @@ void match_set_metadata_masked(struct match *, ovs_be64 metadata, ovs_be64 mask); void match_set_tun_id(struct match *, ovs_be64 tun_id); void match_set_tun_id_masked(struct match *, ovs_be64 tun_id, ovs_be64 mask); +void match_set_tun_src(struct match *match, ovs_be32 src); +void match_set_tun_src_masked(struct match *match, ovs_be32 src, ovs_be32 mask); +void match_set_tun_dst(struct match *match, ovs_be32 dst); +void match_set_tun_dst_masked(struct match *match, ovs_be32 dst, ovs_be32 mask); +void match_set_tun_ttl(struct match *match, uint8_t ttl); +void match_set_tun_ttl_masked(struct match *match, uint8_t ttl, uint8_t mask); +void match_set_tun_tos(struct match *match, uint8_t tos); +void match_set_tun_tos_masked(struct match *match, uint8_t tos, uint8_t mask); +void match_set_tun_flags(struct match *match, uint16_t flags); +void match_set_tun_flags_masked(struct match *match, uint16_t flags, uint16_t mask); void match_set_in_port(struct match *, uint16_t ofp_port); void match_set_dl_type(struct match *, ovs_be16); void match_set_dl_src(struct match *, const uint8_t[6]); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 0b97049a..720c917c 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -55,6 +55,51 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { true, NXM_NX_TUN_ID, "NXM_NX_TUN_ID", NXM_NX_TUN_ID, "NXM_NX_TUN_ID", + }, { + MFF_TUN_SRC, "tun_src", NULL, + MF_FIELD_SIZES(be32), + MFM_NONE, + MFS_IPV4, + MFP_NONE, + false, + 0, NULL, + 0, NULL, + }, { + MFF_TUN_DST, "tun_dst", NULL, + MF_FIELD_SIZES(be32), + MFM_NONE, + MFS_IPV4, + MFP_NONE, + false, + 0, NULL, + 0, NULL, + }, { + MFF_TUN_FLAGS, "tun_flags", NULL, + MF_FIELD_SIZES(be16), + MFM_NONE, + MFS_TNL_FLAGS, + MFP_NONE, + false, + 0, NULL, + 0, NULL, + }, { + MFF_TUN_TOS, "tun_tos", NULL, + MF_FIELD_SIZES(u8), + MFM_NONE, + MFS_DECIMAL, + MFP_NONE, + false, + 0, NULL, + 0, NULL, + }, { + MFF_TUN_TTL, "tun_ttl", NULL, + MF_FIELD_SIZES(u8), + MFM_NONE, + MFS_DECIMAL, + MFP_NONE, + false, + 0, NULL, + 0, NULL, }, { MFF_METADATA, "metadata", NULL, MF_FIELD_SIZES(be64), @@ -574,6 +619,11 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) { switch (mf->id) { case MFF_TUN_ID: + case MFF_TUN_SRC: + case MFF_TUN_DST: + case MFF_TUN_TOS: + case MFF_TUN_TTL: + case MFF_TUN_FLAGS: return !wc->masks.tunnel.tun_id; case MFF_METADATA: return !wc->masks.metadata; @@ -671,6 +721,11 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc, { switch (mf->id) { case MFF_TUN_ID: + case MFF_TUN_SRC: + case MFF_TUN_DST: + case MFF_TUN_TOS: + case MFF_TUN_TTL: + case MFF_TUN_FLAGS: mask->be64 = wc->masks.tunnel.tun_id; break; case MFF_METADATA: @@ -887,6 +942,11 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) { switch (mf->id) { case MFF_TUN_ID: + case MFF_TUN_SRC: + case MFF_TUN_DST: + case MFF_TUN_TOS: + case MFF_TUN_TTL: + case MFF_TUN_FLAGS: case MFF_METADATA: case MFF_IN_PORT: CASE_MFF_REGS: @@ -955,6 +1015,22 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, case MFF_TUN_ID: value->be64 = flow->tunnel.tun_id; break; + case MFF_TUN_SRC: + value->be32 = flow->tunnel.ip_src; + break; + case MFF_TUN_DST: + value->be32 = flow->tunnel.ip_dst; + break; + case MFF_TUN_FLAGS: + value->be16 = htons(flow->tunnel.flags); + break; + case MFF_TUN_TTL: + value->u8 = flow->tunnel.ip_ttl; + break; + case MFF_TUN_TOS: + value->u8 = flow->tunnel.ip_tos; + break; + case MFF_METADATA: value->be64 = flow->metadata; break; @@ -1098,6 +1174,22 @@ mf_set_value(const struct mf_field *mf, case MFF_TUN_ID: match_set_tun_id(match, value->be64); break; + case MFF_TUN_SRC: + match_set_tun_src(match, value->be32); + break; + case MFF_TUN_DST: + match_set_tun_dst(match, value->be32); + break; + case MFF_TUN_FLAGS: + match_set_tun_flags(match, ntohs(value->be16)); + break; + case MFF_TUN_TOS: + match_set_tun_tos(match, value->u8); + break; + case MFF_TUN_TTL: + match_set_tun_ttl(match, value->u8); + break; + case MFF_METADATA: match_set_metadata(match, value->be64); break; @@ -1241,6 +1333,22 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_TUN_ID: flow->tunnel.tun_id = value->be64; break; + case MFF_TUN_SRC: + flow->tunnel.ip_src = value->be32; + break; + case MFF_TUN_DST: + flow->tunnel.ip_dst = value->be32; + break; + case MFF_TUN_FLAGS: + flow->tunnel.flags = ntohs(value->be16); + break; + case MFF_TUN_TOS: + flow->tunnel.ip_tos = value->u8; + break; + case MFF_TUN_TTL: + flow->tunnel.ip_ttl = value->u8; + break; + case MFF_METADATA: flow->metadata = value->be64; break; @@ -1399,6 +1507,22 @@ mf_set_wild(const struct mf_field *mf, struct match *match) case MFF_TUN_ID: match_set_tun_id_masked(match, htonll(0), htonll(0)); break; + case MFF_TUN_SRC: + match_set_tun_src_masked(match, htonl(0), htonl(0)); + break; + case MFF_TUN_DST: + match_set_tun_dst_masked(match, htonl(0), htonl(0)); + break; + case MFF_TUN_FLAGS: + match_set_tun_flags_masked(match, 0, 0); + break; + case MFF_TUN_TOS: + match_set_tun_tos_masked(match, 0, 0); + break; + case MFF_TUN_TTL: + match_set_tun_ttl_masked(match, 0, 0); + break; + case MFF_METADATA: match_set_metadata_masked(match, htonll(0), htonll(0)); @@ -1579,6 +1703,22 @@ mf_set(const struct mf_field *mf, case MFF_TUN_ID: match_set_tun_id_masked(match, value->be64, mask->be64); break; + case MFF_TUN_SRC: + match_set_tun_src_masked(match, value->be32, mask->be32); + break; + case MFF_TUN_DST: + match_set_tun_dst_masked(match, value->be32, mask->be32); + break; + case MFF_TUN_FLAGS: + match_set_tun_flags_masked(match, ntohs(value->be16), ntohs(mask->be16)); + break; + case MFF_TUN_TTL: + match_set_tun_ttl_masked(match, value->u8, mask->u8); + break; + case MFF_TUN_TOS: + match_set_tun_tos_masked(match, value->u8, mask->u8); + break; + case MFF_METADATA: match_set_metadata_masked(match, value->be64, mask->be64); break; @@ -1737,6 +1877,11 @@ mf_random_value(const struct mf_field *mf, union mf_value *value) switch (mf->id) { case MFF_TUN_ID: + case MFF_TUN_SRC: + case MFF_TUN_DST: + case MFF_TUN_TOS: + case MFF_TUN_TTL: + case MFF_TUN_FLAGS: case MFF_METADATA: case MFF_IN_PORT: CASE_MFF_REGS: @@ -1995,6 +2140,69 @@ mf_from_frag_string(const char *s, uint8_t *valuep, uint8_t *maskp) "\"yes\", \"first\", \"later\", \"not_first\"", s); } +static int +parse_flow_tun_flags(const char *s_, const char *(*bit_to_string)(uint32_t), + ovs_be16 *res) +{ + uint32_t result = 0; + char *save_ptr = NULL; + char *name; + int rc = 0; + char *s = xstrdup(s_); + + for (name = strtok_r((char *)s, " |", &save_ptr); name; + name = strtok_r(NULL, " |", &save_ptr)) { + int name_len; + unsigned long long int flags; + uint32_t bit; + int n0; + + if (sscanf(name, "%lli%n", &flags, &n0) > 0 && n0 > 0) { + result |= flags; + continue; + } + name_len = strlen(name); + for (bit = 1; bit; bit <<= 1) { + const char *fname = bit_to_string(bit); + size_t len; + + if (!fname) { + continue; + } + + len = strlen(fname); + if (len != name_len) { + continue; + } + if (!strncmp(name, fname, len)) { + result |= bit; + break; + } + } + + if (!bit) { + rc = -ENOENT; + goto out; + } + } + + *res = htons(result); +out: + free(s); + return rc; +} + +static char * +mf_from_tun_flags_string(const char *s, ovs_be16 *valuep) +{ + if (!parse_flow_tun_flags(s, flow_tun_flag_to_string, valuep)) { + return NULL; + } + + return xasprintf("%s: unknown tunnel flags (valid flags are \"df\", " + "\"csum\", \"key\"", s); +} + /* Parses 's', a string value for field 'mf', into 'value' and 'mask'. Returns * NULL if successful, otherwise a malloc()'d string describing the error. */ char * @@ -2027,6 +2235,9 @@ mf_parse(const struct mf_field *mf, const char *s, case MFS_FRAG: return mf_from_frag_string(s, &value->u8, &mask->u8); + + case MFS_TNL_FLAGS: + return mf_from_tun_flags_string(s, &value->be16); } NOT_REACHED(); } @@ -2104,6 +2315,12 @@ mf_format_frag_string(const uint8_t *valuep, const uint8_t *maskp, ds_put_cstr(s, ""); } +static void +mf_format_tnl_flags_string(const ovs_be16 *valuep, struct ds *s) +{ + format_flags(s, flow_tun_flag_to_string, ntohs(*valuep), '|'); +} + /* Appends to 's' a string representation of field 'mf' whose value is in * 'value' and 'mask'. 'mask' may be NULL to indicate an exact match. */ void @@ -2149,6 +2366,10 @@ mf_format(const struct mf_field *mf, mf_format_frag_string(&value->u8, &mask->u8, s); break; + case MFS_TNL_FLAGS: + mf_format_tnl_flags_string(&value->be16, s); + break; + default: NOT_REACHED(); } diff --git a/lib/meta-flow.h b/lib/meta-flow.h index 60bfecaa..1c49306e 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -32,6 +32,11 @@ struct match; enum mf_field_id { /* Metadata. */ MFF_TUN_ID, /* be64 */ + MFF_TUN_SRC, /* be32 */ + MFF_TUN_DST, /* be32 */ + MFF_TUN_FLAGS, /* be16 */ + MFF_TUN_TTL, /* u8 */ + MFF_TUN_TOS, /* u8 */ MFF_METADATA, /* be64 */ MFF_IN_PORT, /* be16 */ @@ -195,7 +200,8 @@ enum mf_string { MFS_IPV4, MFS_IPV6, MFS_OFP_PORT, /* An OpenFlow port number or name. */ - MFS_FRAG /* no, yes, first, later, not_later */ + MFS_FRAG, /* no, yes, first, later, not_later */ + MFS_TNL_FLAGS, /* FLOW_TNL_F_* flags */ }; struct mf_field { diff --git a/lib/odp-util.c b/lib/odp-util.c index aa9cb465..de97fd21 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -190,38 +190,6 @@ slow_path_reason_to_string(uint32_t data) } } -static void -format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t), - uint32_t flags) -{ - uint32_t bad = 0; - - ds_put_format(ds, "("); - if (!flags) { - goto out; - } - while (flags) { - uint32_t bit = rightmost_1bit(flags); - const char *s; - - s = bit_to_string(bit); - if (s) { - ds_put_format(ds, "%s,", s); - } else { - bad |= bit; - } - - flags &= ~bit; - } - - if (bad) { - ds_put_format(ds, "0x%"PRIx32",", bad); - } - ds_chomp(ds, ','); -out: - ds_put_format(ds, ")"); -} - static int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t), uint32_t *res) @@ -305,8 +273,10 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr) break; case USER_ACTION_COOKIE_SLOW_PATH: - ds_put_cstr(ds, ",slow_path"); - format_flags(ds, slow_path_reason_to_string, cookie.slow_path.reason); + ds_put_cstr(ds, ",slow_path("); + format_flags(ds, slow_path_reason_to_string, + cookie.slow_path.reason, ','); + ds_put_format(ds, ")"); break; case USER_ACTION_COOKIE_UNSPEC: @@ -703,7 +673,7 @@ ovs_frag_type_to_string(enum ovs_frag_type type) } static const char * -tun_flag_to_string(uint32_t flags) +odp_tun_flag_to_string(uint32_t flags) { switch (flags) { case OVS_TNL_F_DONT_FRAGMENT: @@ -767,14 +737,15 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) case OVS_KEY_ATTR_IPV4_TUNNEL: ipv4_tun_key = nl_attr_get(a); ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT"," - "tos=0x%"PRIx8",ttl=%"PRIu8",flags", + "tos=0x%"PRIx8",ttl=%"PRIu8",flags(", ntohll(ipv4_tun_key->tun_id), IP_ARGS(&ipv4_tun_key->ipv4_src), IP_ARGS(&ipv4_tun_key->ipv4_dst), ipv4_tun_key->ipv4_tos, ipv4_tun_key->ipv4_ttl); - format_flags(ds, tun_flag_to_string, ipv4_tun_key->tun_flags); - ds_put_format(ds, ")"); + format_flags(ds, odp_tun_flag_to_string, + ipv4_tun_key->tun_flags, ','); + ds_put_format(ds, "))"); break; case OVS_KEY_ATTR_IN_PORT: @@ -1018,7 +989,8 @@ parse_odp_key_attr(const char *s, const struct simap *port_names, tun_key.ipv4_tos = tos; tun_key.ipv4_ttl = ttl; - res = parse_flags(&s[n], tun_flag_to_string, &tun_key.tun_flags); + res = parse_flags(&s[n], odp_tun_flag_to_string, + &tun_key.tun_flags); if (res < 0) { return res; } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index fb8d6a1e..4facf0a5 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -979,6 +979,16 @@ regs_fully_wildcarded(const struct flow_wildcards *wc) return true; } +static bool +tun_parms_fully_wildcarded(const struct flow_wildcards *wc) +{ + return (!wc->masks.tunnel.ip_src && + !wc->masks.tunnel.ip_dst && + !wc->masks.tunnel.ip_ttl && + !wc->masks.tunnel.ip_tos && + !wc->masks.tunnel.flags); +} + /* Returns a bit-mask of ofputil_protocols that can be used for sending 'match' * to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs, * registers, or fixing the Ethernet multicast bit. Otherwise, it's better to @@ -990,6 +1000,11 @@ ofputil_usable_protocols(const struct match *match) BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18); + /* tunnel params other than tun_id can't be sent in a flow_mod */ + if (!tun_parms_fully_wildcarded(wc)) { + return OFPUTIL_P_NONE; + } + /* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */ if (!eth_mask_is_exact(wc->masks.dl_src) && !eth_addr_is_zero(wc->masks.dl_src)) { @@ -1630,7 +1645,6 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms, usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM; } } - assert(usable_protocols); return usable_protocols; } diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 1d9158c8..8cb363cc 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -31,6 +31,18 @@ OFPT_FLOW_MOD: ADD in_port=0 actions=resubmit:0 ]]) AT_CLEANUP +AT_SETUP([ovs-ofctl parse-flows (With Tunnel-Parameters)]) +AT_DATA([flows.txt], [[ +tun_id=0x1234000056780000/0xffff0000ffff0000,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=0x3,tun_ttl=20,tun_flags=key|csum actions=drop +]]) + +AT_CHECK([ovs-ofctl parse-flows flows.txt +], [1], [usable protocols: none +], [stderr]) + +AT_CLEANUP + + AT_SETUP([ovs-ofctl parse-flows (NXM)]) AT_DATA([flows.txt], [[ # comment