/*
- * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
}
+/* Appends a formatted representation of 'sv' to 's'. */
+void
+mf_subvalue_format(const union mf_subvalue *sv, struct ds *s)
+{
+ ds_put_hex(s, sv, sizeof *sv);
+}
+
/* Returns true if 'wc' wildcards all the bits in field 'mf', false if 'wc'
* specifies at least one bit in the field.
*
return !wc->masks.tunnel.ip_src;
case MFF_TUN_DST:
return !wc->masks.tunnel.ip_dst;
+ case MFF_TUN_IPV6_SRC:
+ return ipv6_mask_is_any(&wc->masks.tunnel.ipv6_src);
+ case MFF_TUN_IPV6_DST:
+ return ipv6_mask_is_any(&wc->masks.tunnel.ipv6_dst);
case MFF_TUN_ID:
return !wc->masks.tunnel.tun_id;
case MFF_TUN_TOS:
return !wc->masks.skb_priority;
case MFF_PKT_MARK:
return !wc->masks.pkt_mark;
+ case MFF_CT_STATE:
+ return !wc->masks.ct_state;
+ case MFF_CT_ZONE:
+ return !wc->masks.ct_zone;
+ case MFF_CT_MARK:
+ return !wc->masks.ct_mark;
+ case MFF_CT_LABEL:
+ return ovs_u128_is_zero(&wc->masks.ct_label);
CASE_MFF_REGS:
return !wc->masks.regs[mf->id - MFF_REG0];
CASE_MFF_XREGS:
case MFF_TUN_ID:
case MFF_TUN_SRC:
case MFF_TUN_DST:
+ case MFF_TUN_IPV6_SRC:
+ case MFF_TUN_IPV6_DST:
case MFF_TUN_TOS:
case MFF_TUN_TTL:
case MFF_TUN_GBP_ID:
case MFF_IN_PORT:
case MFF_SKB_PRIORITY:
case MFF_PKT_MARK:
+ case MFF_CT_ZONE:
+ case MFF_CT_MARK:
+ case MFF_CT_LABEL:
CASE_MFF_REGS:
CASE_MFF_XREGS:
case MFF_ETH_SRC:
case MFF_TUN_FLAGS:
return !(value->be16 & ~htons(FLOW_TNL_PUB_F_MASK));
+ case MFF_CT_STATE:
+ return !(value->be32 & ~htonl(CS_SUPPORTED_MASK));
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
case MFF_TUN_DST:
value->be32 = flow->tunnel.ip_dst;
break;
+ case MFF_TUN_IPV6_SRC:
+ value->ipv6 = flow->tunnel.ipv6_src;
+ break;
+ case MFF_TUN_IPV6_DST:
+ value->ipv6 = flow->tunnel.ipv6_dst;
+ break;
case MFF_TUN_FLAGS:
value->be16 = htons(flow->tunnel.flags & FLOW_TNL_PUB_F_MASK);
break;
value->be32 = htonl(flow->pkt_mark);
break;
+ case MFF_CT_STATE:
+ value->be32 = htonl(flow->ct_state);
+ break;
+
+ case MFF_CT_ZONE:
+ value->be16 = htons(flow->ct_zone);
+ break;
+
+ case MFF_CT_MARK:
+ value->be32 = htonl(flow->ct_mark);
+ break;
+
+ case MFF_CT_LABEL:
+ value->be128 = hton128(flow->ct_label);
+ break;
+
CASE_MFF_REGS:
value->be32 = htonl(flow->regs[mf->id - MFF_REG0]);
break;
case MFF_TUN_DST:
match_set_tun_dst(match, value->be32);
break;
+ case MFF_TUN_IPV6_SRC:
+ match_set_tun_ipv6_src(match, &value->ipv6);
+ break;
+ case MFF_TUN_IPV6_DST:
+ match_set_tun_ipv6_dst(match, &value->ipv6);
+ break;
case MFF_TUN_FLAGS:
match_set_tun_flags(match, ntohs(value->be16));
break;
match_set_pkt_mark(match, ntohl(value->be32));
break;
+ case MFF_CT_STATE:
+ match_set_ct_state(match, ntohl(value->be32));
+ break;
+
+ case MFF_CT_ZONE:
+ match_set_ct_zone(match, ntohs(value->be16));
+ break;
+
+ case MFF_CT_MARK:
+ match_set_ct_mark(match, ntohl(value->be32));
+ break;
+
+ case MFF_CT_LABEL:
+ match_set_ct_label(match, ntoh128(value->be128));
+ break;
+
CASE_MFF_REGS:
match_set_reg(match, mf->id - MFF_REG0, ntohl(value->be32));
break;
case MFF_TUN_DST:
flow->tunnel.ip_dst = value->be32;
break;
+ case MFF_TUN_IPV6_SRC:
+ flow->tunnel.ipv6_src = value->ipv6;
+ break;
+ case MFF_TUN_IPV6_DST:
+ flow->tunnel.ipv6_dst = value->ipv6;
+ break;
case MFF_TUN_FLAGS:
flow->tunnel.flags = (flow->tunnel.flags & ~FLOW_TNL_PUB_F_MASK) |
ntohs(value->be16);
flow->pkt_mark = ntohl(value->be32);
break;
+ case MFF_CT_STATE:
+ flow->ct_state = ntohl(value->be32);
+ break;
+
+ case MFF_CT_ZONE:
+ flow->ct_zone = ntohs(value->be16);
+ break;
+
+ case MFF_CT_MARK:
+ flow->ct_mark = ntohl(value->be32);
+ break;
+
+ case MFF_CT_LABEL:
+ flow->ct_label = ntoh128(value->be128);
+ break;
+
CASE_MFF_REGS:
flow->regs[mf->id - MFF_REG0] = ntohl(value->be32);
break;
case MFF_TUN_DST:
match_set_tun_dst_masked(match, htonl(0), htonl(0));
break;
+ case MFF_TUN_IPV6_SRC:
+ memset(&match->wc.masks.tunnel.ipv6_src, 0,
+ sizeof match->wc.masks.tunnel.ipv6_src);
+ memset(&match->flow.tunnel.ipv6_src, 0,
+ sizeof match->flow.tunnel.ipv6_src);
+ break;
+ case MFF_TUN_IPV6_DST:
+ memset(&match->wc.masks.tunnel.ipv6_dst, 0,
+ sizeof match->wc.masks.tunnel.ipv6_dst);
+ memset(&match->flow.tunnel.ipv6_dst, 0,
+ sizeof match->flow.tunnel.ipv6_dst);
+ break;
case MFF_TUN_FLAGS:
match_set_tun_flags_masked(match, 0, 0);
break;
match->wc.masks.pkt_mark = 0;
break;
+ case MFF_CT_STATE:
+ match->flow.ct_state = 0;
+ match->wc.masks.ct_state = 0;
+ break;
+
+ case MFF_CT_ZONE:
+ match->flow.ct_zone = 0;
+ match->wc.masks.ct_zone = 0;
+ break;
+
+ case MFF_CT_MARK:
+ match->flow.ct_mark = 0;
+ match->wc.masks.ct_mark = 0;
+ break;
+
+ case MFF_CT_LABEL:
+ memset(&match->flow.ct_label, 0, sizeof(match->flow.ct_label));
+ memset(&match->wc.masks.ct_label, 0, sizeof(match->wc.masks.ct_label));
+ break;
+
CASE_MFF_REGS:
match_set_reg_masked(match, mf->id - MFF_REG0, 0, 0);
break;
}
switch (mf->id) {
+ case MFF_CT_ZONE:
case MFF_RECIRC_ID:
case MFF_CONJ_ID:
case MFF_IN_PORT:
case MFF_TUN_DST:
match_set_tun_dst_masked(match, value->be32, mask->be32);
break;
+ case MFF_TUN_IPV6_SRC:
+ match_set_tun_ipv6_src_masked(match, &value->ipv6, &mask->ipv6);
+ break;
+ case MFF_TUN_IPV6_DST:
+ match_set_tun_ipv6_dst_masked(match, &value->ipv6, &mask->ipv6);
+ break;
case MFF_TUN_FLAGS:
match_set_tun_flags_masked(match, ntohs(value->be16), ntohs(mask->be16));
break;
ntohl(mask->be32));
break;
+ case MFF_CT_STATE:
+ match_set_ct_state_masked(match, ntohl(value->be32), ntohl(mask->be32));
+ break;
+
+ case MFF_CT_MARK:
+ match_set_ct_mark_masked(match, ntohl(value->be32), ntohl(mask->be32));
+ break;
+
+ case MFF_CT_LABEL:
+ match_set_ct_label_masked(match, ntoh128(value->be128),
+ mask ? ntoh128(mask->be128) : OVS_U128_MAX);
+ break;
+
case MFF_ETH_DST:
match_set_dl_dst_masked(match, value->mac, mask->mac);
break;
mf_from_ipv4_string(const struct mf_field *mf, const char *s,
ovs_be32 *ip, ovs_be32 *mask)
{
- int prefix;
-
ovs_assert(mf->n_bytes == sizeof *ip);
-
- if (ovs_scan(s, IP_SCAN_FMT"/"IP_SCAN_FMT,
- IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask))) {
- /* OK. */
- } else if (ovs_scan(s, IP_SCAN_FMT"/%d", IP_SCAN_ARGS(ip), &prefix)) {
- if (prefix <= 0 || prefix > 32) {
- return xasprintf("%s: network prefix bits not between 0 and "
- "32", s);
- }
- *mask = be32_prefix_mask(prefix);
- } else if (ovs_scan(s, IP_SCAN_FMT, IP_SCAN_ARGS(ip))) {
- *mask = OVS_BE32_MAX;
- } else {
- return xasprintf("%s: invalid IP address", s);
- }
- return NULL;
+ return ip_parse_masked(s, ip, mask);
}
static char *
mf_from_ipv6_string(const struct mf_field *mf, const char *s,
- struct in6_addr *value, struct in6_addr *mask)
+ struct in6_addr *ipv6, struct in6_addr *mask)
{
- char *str = xstrdup(s);
- char *save_ptr = NULL;
- const char *name, *netmask;
- int retval;
-
- ovs_assert(mf->n_bytes == sizeof *value);
-
- name = strtok_r(str, "/", &save_ptr);
- retval = name ? lookup_ipv6(name, value) : EINVAL;
- if (retval) {
- char *err;
-
- err = xasprintf("%s: could not convert to IPv6 address", str);
- free(str);
-
- return err;
- }
-
- netmask = strtok_r(NULL, "/", &save_ptr);
- if (netmask) {
- if (inet_pton(AF_INET6, netmask, mask) != 1) {
- int prefix = atoi(netmask);
- if (prefix <= 0 || prefix > 128) {
- free(str);
- return xasprintf("%s: prefix bits not between 1 and 128", s);
- } else {
- *mask = ipv6_create_mask(prefix);
- }
- }
- } else {
- *mask = in6addr_exact;
- }
- free(str);
-
- return NULL;
+ ovs_assert(mf->n_bytes == sizeof *ipv6);
+ return ipv6_parse_masked(s, ipv6, mask);
}
static char *
htons(FLOW_TNL_PUB_F_MASK), maskp);
}
+static char *
+mf_from_ct_state_string(const char *s, ovs_be32 *flagsp, ovs_be32 *maskp)
+{
+ int err;
+ char *err_str;
+ uint32_t flags, mask;
+
+ err = parse_flags(s, ct_state_to_string, '\0', "ct_state", &err_str,
+ &flags, CS_SUPPORTED_MASK, maskp ? &mask : NULL);
+ if (err < 0) {
+ return err_str;
+ }
+
+ *flagsp = htonl(flags);
+ if (maskp) {
+ *maskp = htonl(mask);
+ }
+
+ return NULL;
+}
+
/* 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 *
(uint8_t *) value, (uint8_t *) mask);
break;
+ case MFS_CT_STATE:
+ ovs_assert(mf->n_bytes == sizeof(ovs_be32));
+ error = mf_from_ct_state_string(s, &value->be32, &mask->be32);
+ break;
+
case MFS_ETHERNET:
error = mf_from_ethernet_string(mf, s, &value->mac, &mask->mac);
break;
TCP_FLAGS(mask), TCP_FLAGS(OVS_BE16_MAX));
}
+static void
+mf_format_ct_state_string(ovs_be32 value, ovs_be32 mask, struct ds *s)
+{
+ format_flags_masked(s, NULL, ct_state_to_string, ntohl(value),
+ ntohl(mask), UINT16_MAX);
+}
+
/* 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
mf_format_integer_string(mf, (uint8_t *) value, (uint8_t *) mask, s);
break;
+ case MFS_CT_STATE:
+ mf_format_ct_state_string(value->be32,
+ mask ? mask->be32 : OVS_BE32_MAX, s);
+ break;
+
case MFS_ETHERNET:
eth_format_masked(value->mac, mask ? &mask->mac : NULL, s);
break;
break;
case MFS_IPV6:
- print_ipv6_masked(s, &value->ipv6, mask ? &mask->ipv6 : NULL);
+ ipv6_format_masked(&value->ipv6, mask ? &mask->ipv6 : NULL, s);
break;
case MFS_FRAG: