lib/lockfile.h \
lib/mac-learning.c \
lib/mac-learning.h \
+ lib/match.c \
+ lib/match.h \
lib/memory.c \
lib/memory.h \
lib/meta-flow.c \
static struct cls_rule *next_rule_in_list__(struct cls_rule *);
static struct cls_rule *next_rule_in_list(struct cls_rule *);
+\f
+/* cls_rule. */
-/* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
- * 'wildcards' and 'priority'. */
-void
-cls_rule_init(const struct flow *flow, const struct flow_wildcards *wildcards,
- unsigned int priority, struct cls_rule *rule)
-{
- rule->flow = *flow;
- rule->wc = *wildcards;
- rule->priority = priority;
- cls_rule_zero_wildcarded_fields(rule);
-}
-
-/* Converts the flow in 'flow' into an exact-match cls_rule in 'rule', with the
- * given 'priority'. (For OpenFlow 1.0, exact-match rule are always highest
- * priority, so 'priority' should be at least 65535.) */
-void
-cls_rule_init_exact(const struct flow *flow,
- unsigned int priority, struct cls_rule *rule)
-{
- rule->flow = *flow;
- rule->flow.skb_priority = 0;
- flow_wildcards_init_exact(&rule->wc);
- rule->priority = priority;
-}
-
-/* Initializes 'rule' as a "catch-all" rule that matches every packet, with
- * priority 'priority'. */
-void
-cls_rule_init_catchall(struct cls_rule *rule, unsigned int priority)
-{
- memset(&rule->flow, 0, sizeof rule->flow);
- flow_wildcards_init_catchall(&rule->wc);
- rule->priority = priority;
-}
-
-/* For each bit or field wildcarded in 'rule', sets the corresponding bit or
- * field in 'flow' to all-0-bits. It is important to maintain this invariant
- * in a clr_rule that might be inserted into a classifier.
- *
- * It is never necessary to call this function directly for a cls_rule that is
- * initialized or modified only by cls_rule_*() functions. It is useful to
- * restore the invariant in a cls_rule whose 'wc' member is modified by hand.
- */
-void
-cls_rule_zero_wildcarded_fields(struct cls_rule *rule)
-{
- flow_zero_wildcards(&rule->flow, &rule->wc);
-}
-
-void
-cls_rule_set_reg(struct cls_rule *rule, unsigned int reg_idx, uint32_t value)
-{
- cls_rule_set_reg_masked(rule, reg_idx, value, UINT32_MAX);
-}
-
-void
-cls_rule_set_reg_masked(struct cls_rule *rule, unsigned int reg_idx,
- uint32_t value, uint32_t mask)
-{
- assert(reg_idx < FLOW_N_REGS);
- flow_wildcards_set_reg_mask(&rule->wc, reg_idx, mask);
- rule->flow.regs[reg_idx] = value & mask;
-}
-
-void
-cls_rule_set_metadata(struct cls_rule *rule, ovs_be64 metadata)
-{
- cls_rule_set_metadata_masked(rule, metadata, htonll(UINT64_MAX));
-}
-
-void
-cls_rule_set_metadata_masked(struct cls_rule *rule, ovs_be64 metadata,
- ovs_be64 mask)
-{
- rule->wc.masks.metadata = mask;
- rule->flow.metadata = metadata & mask;
-}
-
-void
-cls_rule_set_tun_id(struct cls_rule *rule, ovs_be64 tun_id)
-{
- cls_rule_set_tun_id_masked(rule, tun_id, htonll(UINT64_MAX));
-}
-
-void
-cls_rule_set_tun_id_masked(struct cls_rule *rule,
- ovs_be64 tun_id, ovs_be64 mask)
-{
- rule->wc.masks.tun_id = mask;
- rule->flow.tun_id = tun_id & mask;
-}
-
-void
-cls_rule_set_in_port(struct cls_rule *rule, uint16_t ofp_port)
-{
- rule->wc.masks.in_port = UINT16_MAX;
- rule->flow.in_port = ofp_port;
-}
-
-void
-cls_rule_set_dl_type(struct cls_rule *rule, ovs_be16 dl_type)
-{
- rule->wc.masks.dl_type = htons(UINT16_MAX);
- rule->flow.dl_type = dl_type;
-}
-
-/* Modifies 'value_src' so that the Ethernet address must match
- * 'value_dst' exactly. 'mask_dst' is set to all 1s */
-static void
-cls_rule_set_eth(const uint8_t value_src[ETH_ADDR_LEN],
- uint8_t value_dst[ETH_ADDR_LEN],
- uint8_t mask_dst[ETH_ADDR_LEN])
-{
- memcpy(value_dst, value_src, ETH_ADDR_LEN);
- memset(mask_dst, 0xff, ETH_ADDR_LEN);
-}
-
-/* Modifies 'value_src' so that the Ethernet address must match
- * 'value_src' after each byte is ANDed with the appropriate byte in
- * 'mask_src'. 'mask_dst' is set to 'mask_src' */
-static void
-cls_rule_set_eth_masked(const uint8_t value_src[ETH_ADDR_LEN],
- const uint8_t mask_src[ETH_ADDR_LEN],
- uint8_t value_dst[ETH_ADDR_LEN],
- uint8_t mask_dst[ETH_ADDR_LEN])
-{
- size_t i;
-
- for (i = 0; i < ETH_ADDR_LEN; i++) {
- value_dst[i] = value_src[i] & mask_src[i];
- mask_dst[i] = mask_src[i];
- }
-}
-
-/* Modifies 'rule' so that the source Ethernet address
- * must match 'dl_src' exactly. */
-void
-cls_rule_set_dl_src(struct cls_rule *rule, const uint8_t dl_src[ETH_ADDR_LEN])
-{
- cls_rule_set_eth(dl_src, rule->flow.dl_src, rule->wc.masks.dl_src);
-}
-
-/* Modifies 'rule' so that the source Ethernet address
- * must match 'dl_src' after each byte is ANDed with
- * the appropriate byte in 'mask'. */
-void
-cls_rule_set_dl_src_masked(struct cls_rule *rule,
- const uint8_t dl_src[ETH_ADDR_LEN],
- const uint8_t mask[ETH_ADDR_LEN])
-{
- cls_rule_set_eth_masked(dl_src, mask,
- rule->flow.dl_src, rule->wc.masks.dl_src);
-}
-
-/* Modifies 'rule' so that the destination Ethernet address
- * must match 'dl_dst' exactly. */
-void
-cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
-{
- cls_rule_set_eth(dl_dst, rule->flow.dl_dst, rule->wc.masks.dl_dst);
-}
-
-/* Modifies 'rule' so that the destination Ethernet address
- * must match 'dl_src' after each byte is ANDed with
- * the appropriate byte in 'mask'. */
-void
-cls_rule_set_dl_dst_masked(struct cls_rule *rule,
- const uint8_t dl_dst[ETH_ADDR_LEN],
- const uint8_t mask[ETH_ADDR_LEN])
-{
- cls_rule_set_eth_masked(dl_dst, mask,
- rule->flow.dl_dst, rule->wc.masks.dl_dst);
-}
-
-void
-cls_rule_set_dl_tci(struct cls_rule *rule, ovs_be16 tci)
-{
- cls_rule_set_dl_tci_masked(rule, tci, htons(0xffff));
-}
-
-void
-cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
-{
- rule->flow.vlan_tci = tci & mask;
- rule->wc.masks.vlan_tci = mask;
-}
-
-/* Modifies 'rule' so that the VLAN VID is wildcarded. If the PCP is already
- * wildcarded, then 'rule' will match a packet regardless of whether it has an
- * 802.1Q header or not. */
-void
-cls_rule_set_any_vid(struct cls_rule *rule)
-{
- if (rule->wc.masks.vlan_tci & htons(VLAN_PCP_MASK)) {
- rule->wc.masks.vlan_tci &= ~htons(VLAN_VID_MASK);
- rule->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
- } else {
- cls_rule_set_dl_tci_masked(rule, htons(0), htons(0));
- }
-}
-
-/* Modifies 'rule' depending on 'dl_vlan':
+/* Initializes 'rule' to match packets specified by 'match' at the given
+ * 'priority'.
*
- * - If 'dl_vlan' is htons(OFP_VLAN_NONE), makes 'rule' match only packets
- * without an 802.1Q header.
+ * 'match' must satisfy the invariant described in the comment at the
+ * definition of struct match.
*
- * - Otherwise, makes 'rule' match only packets with an 802.1Q header whose
- * VID equals the low 12 bits of 'dl_vlan'.
- */
-void
-cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan)
-{
- flow_set_dl_vlan(&rule->flow, dl_vlan);
- if (dl_vlan == htons(OFP10_VLAN_NONE)) {
- rule->wc.masks.vlan_tci = htons(UINT16_MAX);
- } else {
- rule->wc.masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
- }
-}
-
-/* Sets the VLAN VID that 'flow' matches to 'vid', which is interpreted as an
- * OpenFlow 1.2 "vlan_vid" value, that is, the low 13 bits of 'vlan_tci' (VID
- * plus CFI). */
-void
-cls_rule_set_vlan_vid(struct cls_rule *rule, ovs_be16 vid)
-{
- cls_rule_set_vlan_vid_masked(rule, vid, htons(VLAN_VID_MASK | VLAN_CFI));
-}
-
-
-/* Sets the VLAN VID that 'flow' matches to 'vid', which is interpreted as an
- * OpenFlow 1.2 "vlan_vid" value, that is, the low 13 bits of 'vlan_tci' (VID
- * plus CFI), with the corresponding 'mask'. */
-void
-cls_rule_set_vlan_vid_masked(struct cls_rule *rule,
- ovs_be16 vid, ovs_be16 mask)
-{
- ovs_be16 pcp_mask = htons(VLAN_PCP_MASK);
- ovs_be16 vid_mask = htons(VLAN_VID_MASK | VLAN_CFI);
-
- mask &= vid_mask;
- flow_set_vlan_vid(&rule->flow, vid & mask);
- rule->wc.masks.vlan_tci = mask | (rule->wc.masks.vlan_tci & pcp_mask);
-}
-
-/* Modifies 'rule' so that the VLAN PCP is wildcarded. If the VID is already
- * wildcarded, then 'rule' will match a packet regardless of whether it has an
- * 802.1Q header or not. */
-void
-cls_rule_set_any_pcp(struct cls_rule *rule)
-{
- if (rule->wc.masks.vlan_tci & htons(VLAN_VID_MASK)) {
- rule->wc.masks.vlan_tci &= ~htons(VLAN_PCP_MASK);
- rule->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
- } else {
- cls_rule_set_dl_tci_masked(rule, htons(0), htons(0));
- }
-}
-
-/* Modifies 'rule' so that it matches only packets with an 802.1Q header whose
- * PCP equals the low 3 bits of 'dl_vlan_pcp'. */
-void
-cls_rule_set_dl_vlan_pcp(struct cls_rule *rule, uint8_t dl_vlan_pcp)
-{
- flow_set_vlan_pcp(&rule->flow, dl_vlan_pcp);
- rule->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_PCP_MASK);
-}
-
-void
-cls_rule_set_tp_src(struct cls_rule *rule, ovs_be16 tp_src)
-{
- cls_rule_set_tp_src_masked(rule, tp_src, htons(UINT16_MAX));
-}
-
-void
-cls_rule_set_tp_src_masked(struct cls_rule *rule, ovs_be16 port, ovs_be16 mask)
-{
- rule->flow.tp_src = port & mask;
- rule->wc.masks.tp_src = mask;
-}
-
-void
-cls_rule_set_tp_dst(struct cls_rule *rule, ovs_be16 tp_dst)
-{
- cls_rule_set_tp_dst_masked(rule, tp_dst, htons(UINT16_MAX));
-}
-
+ * (OpenFlow uses priorities between 0 and UINT16_MAX, inclusive, but
+ * internally Open vSwitch supports a wider range.) */
void
-cls_rule_set_tp_dst_masked(struct cls_rule *rule, ovs_be16 port, ovs_be16 mask)
+cls_rule_init(struct cls_rule *rule,
+ const struct match *match, unsigned int priority)
{
- rule->flow.tp_dst = port & mask;
- rule->wc.masks.tp_dst = mask;
-}
-
-void
-cls_rule_set_nw_proto(struct cls_rule *rule, uint8_t nw_proto)
-{
- rule->flow.nw_proto = nw_proto;
- rule->wc.masks.nw_proto = UINT8_MAX;
-}
-
-void
-cls_rule_set_nw_src(struct cls_rule *rule, ovs_be32 nw_src)
-{
- rule->flow.nw_src = nw_src;
- rule->wc.masks.nw_src = htonl(UINT32_MAX);
-}
-
-void
-cls_rule_set_nw_src_masked(struct cls_rule *rule,
- ovs_be32 nw_src, ovs_be32 mask)
-{
- rule->flow.nw_src = nw_src & mask;
- rule->wc.masks.nw_src = mask;
-}
-
-void
-cls_rule_set_nw_dst(struct cls_rule *rule, ovs_be32 nw_dst)
-{
- rule->flow.nw_dst = nw_dst;
- rule->wc.masks.nw_dst = htonl(UINT32_MAX);
-}
-
-void
-cls_rule_set_nw_dst_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask)
-{
- rule->flow.nw_dst = ip & mask;
- rule->wc.masks.nw_dst = mask;
-}
-
-void
-cls_rule_set_nw_dscp(struct cls_rule *rule, uint8_t nw_dscp)
-{
- rule->wc.masks.nw_tos |= IP_DSCP_MASK;
- rule->flow.nw_tos &= ~IP_DSCP_MASK;
- rule->flow.nw_tos |= nw_dscp & IP_DSCP_MASK;
-}
-
-void
-cls_rule_set_nw_ecn(struct cls_rule *rule, uint8_t nw_ecn)
-{
- rule->wc.masks.nw_tos |= IP_ECN_MASK;
- rule->flow.nw_tos &= ~IP_ECN_MASK;
- rule->flow.nw_tos |= nw_ecn & IP_ECN_MASK;
-}
-
-void
-cls_rule_set_nw_ttl(struct cls_rule *rule, uint8_t nw_ttl)
-{
- rule->wc.masks.nw_ttl = UINT8_MAX;
- rule->flow.nw_ttl = nw_ttl;
-}
-
-void
-cls_rule_set_nw_frag(struct cls_rule *rule, uint8_t nw_frag)
-{
- rule->wc.masks.nw_frag |= FLOW_NW_FRAG_MASK;
- rule->flow.nw_frag = nw_frag;
-}
-
-void
-cls_rule_set_nw_frag_masked(struct cls_rule *rule,
- uint8_t nw_frag, uint8_t mask)
-{
- rule->flow.nw_frag = nw_frag & mask;
- rule->wc.masks.nw_frag = mask;
-}
-
-void
-cls_rule_set_icmp_type(struct cls_rule *rule, uint8_t icmp_type)
-{
- cls_rule_set_tp_src(rule, htons(icmp_type));
-}
-
-void
-cls_rule_set_icmp_code(struct cls_rule *rule, uint8_t icmp_code)
-{
- cls_rule_set_tp_dst(rule, htons(icmp_code));
-}
-
-void
-cls_rule_set_arp_sha(struct cls_rule *rule, const uint8_t sha[ETH_ADDR_LEN])
-{
- cls_rule_set_eth(sha, rule->flow.arp_sha, rule->wc.masks.arp_sha);
-}
-
-void
-cls_rule_set_arp_sha_masked(struct cls_rule *rule,
- const uint8_t arp_sha[ETH_ADDR_LEN],
- const uint8_t mask[ETH_ADDR_LEN])
-{
- cls_rule_set_eth_masked(arp_sha, mask,
- rule->flow.arp_sha, rule->wc.masks.arp_sha);
-}
-
-void
-cls_rule_set_arp_tha(struct cls_rule *rule, const uint8_t tha[ETH_ADDR_LEN])
-{
- cls_rule_set_eth(tha, rule->flow.arp_tha, rule->wc.masks.arp_tha);
-}
-
-void
-cls_rule_set_arp_tha_masked(struct cls_rule *rule,
- const uint8_t arp_tha[ETH_ADDR_LEN],
- const uint8_t mask[ETH_ADDR_LEN])
-{
- cls_rule_set_eth_masked(arp_tha, mask,
- rule->flow.arp_tha, rule->wc.masks.arp_tha);
-}
-
-void
-cls_rule_set_ipv6_src(struct cls_rule *rule, const struct in6_addr *src)
-{
- rule->flow.ipv6_src = *src;
- rule->wc.masks.ipv6_src = in6addr_exact;
-}
-
-void
-cls_rule_set_ipv6_src_masked(struct cls_rule *rule, const struct in6_addr *src,
- const struct in6_addr *mask)
-{
- rule->flow.ipv6_src = ipv6_addr_bitand(src, mask);
- rule->wc.masks.ipv6_src = *mask;
-}
-
-void
-cls_rule_set_ipv6_dst(struct cls_rule *rule, const struct in6_addr *dst)
-{
- rule->flow.ipv6_dst = *dst;
- rule->wc.masks.ipv6_dst = in6addr_exact;
-}
-
-void
-cls_rule_set_ipv6_dst_masked(struct cls_rule *rule, const struct in6_addr *dst,
- const struct in6_addr *mask)
-{
- rule->flow.ipv6_dst = ipv6_addr_bitand(dst, mask);
- rule->wc.masks.ipv6_dst = *mask;
-}
-
-void
-cls_rule_set_ipv6_label(struct cls_rule *rule, ovs_be32 ipv6_label)
-{
- cls_rule_set_ipv6_label_masked(rule, ipv6_label, htonl(UINT32_MAX));
-}
-
-void
-cls_rule_set_ipv6_label_masked(struct cls_rule *rule, ovs_be32 ipv6_label,
- ovs_be32 mask)
-{
- rule->flow.ipv6_label = ipv6_label & mask;
- rule->wc.masks.ipv6_label = mask;
-}
-
-void
-cls_rule_set_nd_target(struct cls_rule *rule, const struct in6_addr *target)
-{
- rule->flow.nd_target = *target;
- rule->wc.masks.nd_target = in6addr_exact;
-}
-
-void
-cls_rule_set_nd_target_masked(struct cls_rule *rule,
- const struct in6_addr *target,
- const struct in6_addr *mask)
-{
- rule->flow.nd_target = ipv6_addr_bitand(target, mask);
- rule->wc.masks.nd_target = *mask;
+ rule->match = *match;
+ rule->priority = priority;
}
-/* Returns true if 'a' and 'b' have the same priority, wildcard the same
- * fields, and have the same values for fixed fields, otherwise false. */
+/* Returns true if 'a' and 'b' match the same packets at the same priority,
+ * false if they differ in some way. */
bool
cls_rule_equal(const struct cls_rule *a, const struct cls_rule *b)
{
- return (a->priority == b->priority
- && flow_wildcards_equal(&a->wc, &b->wc)
- && flow_equal(&a->flow, &b->flow));
+ return a->priority == b->priority && match_equal(&a->match, &b->match);
}
-/* Returns a hash value for the flow, wildcards, and priority in 'rule',
- * starting from 'basis'. */
+/* Returns a hash value for 'rule', folding in 'basis'. */
uint32_t
cls_rule_hash(const struct cls_rule *rule, uint32_t basis)
{
- uint32_t h0 = flow_hash(&rule->flow, basis);
- uint32_t h1 = flow_wildcards_hash(&rule->wc, h0);
- return hash_int(rule->priority, h1);
-}
-
-static void
-format_eth_masked(struct ds *s, const char *name, const uint8_t eth[6],
- const uint8_t mask[6])
-{
- if (!eth_addr_is_zero(mask)) {
- ds_put_format(s, "%s=", name);
- eth_format_masked(eth, mask, s);
- ds_put_char(s, ',');
- }
-}
-
-static void
-format_ip_netmask(struct ds *s, const char *name, ovs_be32 ip,
- ovs_be32 netmask)
-{
- if (netmask) {
- ds_put_format(s, "%s=", name);
- ip_format_masked(ip, netmask, s);
- ds_put_char(s, ',');
- }
-}
-
-static void
-format_ipv6_netmask(struct ds *s, const char *name,
- const struct in6_addr *addr,
- const struct in6_addr *netmask)
-{
- if (!ipv6_mask_is_any(netmask)) {
- ds_put_format(s, "%s=", name);
- print_ipv6_masked(s, addr, netmask);
- ds_put_char(s, ',');
- }
-}
-
-
-static void
-format_be16_masked(struct ds *s, const char *name,
- ovs_be16 value, ovs_be16 mask)
-{
- if (mask != htons(0)) {
- ds_put_format(s, "%s=", name);
- if (mask == htons(UINT16_MAX)) {
- ds_put_format(s, "%"PRIu16, ntohs(value));
- } else {
- ds_put_format(s, "0x%"PRIx16"/0x%"PRIx16,
- ntohs(value), ntohs(mask));
- }
- ds_put_char(s, ',');
- }
+ return match_hash(&rule->match, hash_int(rule->priority, basis));
}
+/* Appends a string describing 'rule' to 's'. */
void
cls_rule_format(const struct cls_rule *rule, struct ds *s)
{
- const struct flow_wildcards *wc = &rule->wc;
- size_t start_len = s->length;
- const struct flow *f = &rule->flow;
- bool skip_type = false;
- bool skip_proto = false;
-
- int i;
-
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
-
- if (rule->priority != OFP_DEFAULT_PRIORITY) {
- ds_put_format(s, "priority=%d,", rule->priority);
- }
-
- if (wc->masks.dl_type) {
- skip_type = true;
- if (f->dl_type == htons(ETH_TYPE_IP)) {
- if (wc->masks.nw_proto) {
- skip_proto = true;
- if (f->nw_proto == IPPROTO_ICMP) {
- ds_put_cstr(s, "icmp,");
- } else if (f->nw_proto == IPPROTO_TCP) {
- ds_put_cstr(s, "tcp,");
- } else if (f->nw_proto == IPPROTO_UDP) {
- ds_put_cstr(s, "udp,");
- } else {
- ds_put_cstr(s, "ip,");
- skip_proto = false;
- }
- } else {
- ds_put_cstr(s, "ip,");
- }
- } else if (f->dl_type == htons(ETH_TYPE_IPV6)) {
- if (wc->masks.nw_proto) {
- skip_proto = true;
- if (f->nw_proto == IPPROTO_ICMPV6) {
- ds_put_cstr(s, "icmp6,");
- } else if (f->nw_proto == IPPROTO_TCP) {
- ds_put_cstr(s, "tcp6,");
- } else if (f->nw_proto == IPPROTO_UDP) {
- ds_put_cstr(s, "udp6,");
- } else {
- ds_put_cstr(s, "ipv6,");
- skip_proto = false;
- }
- } else {
- ds_put_cstr(s, "ipv6,");
- }
- } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
- ds_put_cstr(s, "arp,");
- } else {
- skip_type = false;
- }
- }
- for (i = 0; i < FLOW_N_REGS; i++) {
- switch (wc->masks.regs[i]) {
- case 0:
- break;
- case UINT32_MAX:
- ds_put_format(s, "reg%d=0x%"PRIx32",", i, f->regs[i]);
- break;
- default:
- ds_put_format(s, "reg%d=0x%"PRIx32"/0x%"PRIx32",",
- i, f->regs[i], wc->masks.regs[i]);
- break;
- }
- }
- switch (wc->masks.tun_id) {
- case 0:
- break;
- case CONSTANT_HTONLL(UINT64_MAX):
- ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_id));
- break;
- default:
- ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
- ntohll(f->tun_id), ntohll(wc->masks.tun_id));
- break;
- }
- switch (wc->masks.metadata) {
- case 0:
- break;
- case CONSTANT_HTONLL(UINT64_MAX):
- ds_put_format(s, "metadata=%#"PRIx64",", ntohll(f->metadata));
- break;
- default:
- ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
- ntohll(f->metadata), ntohll(wc->masks.metadata));
- break;
- }
- if (wc->masks.in_port) {
- ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
- }
- if (wc->masks.vlan_tci) {
- ovs_be16 vid_mask = wc->masks.vlan_tci & htons(VLAN_VID_MASK);
- ovs_be16 pcp_mask = wc->masks.vlan_tci & htons(VLAN_PCP_MASK);
- ovs_be16 cfi = wc->masks.vlan_tci & htons(VLAN_CFI);
-
- if (cfi && f->vlan_tci & htons(VLAN_CFI)
- && (!vid_mask || vid_mask == htons(VLAN_VID_MASK))
- && (!pcp_mask || pcp_mask == htons(VLAN_PCP_MASK))
- && (vid_mask || pcp_mask)) {
- if (vid_mask) {
- ds_put_format(s, "dl_vlan=%"PRIu16",",
- vlan_tci_to_vid(f->vlan_tci));
- }
- if (pcp_mask) {
- ds_put_format(s, "dl_vlan_pcp=%d,",
- vlan_tci_to_pcp(f->vlan_tci));
- }
- } else if (wc->masks.vlan_tci == htons(0xffff)) {
- ds_put_format(s, "vlan_tci=0x%04"PRIx16",", ntohs(f->vlan_tci));
- } else {
- ds_put_format(s, "vlan_tci=0x%04"PRIx16"/0x%04"PRIx16",",
- ntohs(f->vlan_tci), ntohs(wc->masks.vlan_tci));
- }
- }
- format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src);
- format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst);
- if (!skip_type && wc->masks.dl_type) {
- ds_put_format(s, "dl_type=0x%04"PRIx16",", ntohs(f->dl_type));
- }
- if (f->dl_type == htons(ETH_TYPE_IPV6)) {
- format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src);
- format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst);
- if (wc->masks.ipv6_label) {
- if (wc->masks.ipv6_label == htonl(UINT32_MAX)) {
- ds_put_format(s, "ipv6_label=0x%05"PRIx32",",
- ntohl(f->ipv6_label));
- } else {
- ds_put_format(s, "ipv6_label=0x%05"PRIx32"/0x%05"PRIx32",",
- ntohl(f->ipv6_label),
- ntohl(wc->masks.ipv6_label));
- }
- }
- } else {
- format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src);
- format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
- }
- if (!skip_proto && wc->masks.nw_proto) {
- if (f->dl_type == htons(ETH_TYPE_ARP)) {
- ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto);
- } else {
- ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto);
- }
- }
- if (f->dl_type == htons(ETH_TYPE_ARP)) {
- format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
- format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
- }
- if (wc->masks.nw_tos & IP_DSCP_MASK) {
- ds_put_format(s, "nw_tos=%"PRIu8",", f->nw_tos & IP_DSCP_MASK);
- }
- if (wc->masks.nw_tos & IP_ECN_MASK) {
- ds_put_format(s, "nw_ecn=%"PRIu8",", f->nw_tos & IP_ECN_MASK);
- }
- if (wc->masks.nw_ttl) {
- ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
- }
- switch (wc->masks.nw_frag) {
- case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
- ds_put_format(s, "nw_frag=%s,",
- f->nw_frag & FLOW_NW_FRAG_ANY
- ? (f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "first")
- : (f->nw_frag & FLOW_NW_FRAG_LATER ? "<error>" : "no"));
- break;
-
- case FLOW_NW_FRAG_ANY:
- ds_put_format(s, "nw_frag=%s,",
- f->nw_frag & FLOW_NW_FRAG_ANY ? "yes" : "no");
- break;
-
- case FLOW_NW_FRAG_LATER:
- ds_put_format(s, "nw_frag=%s,",
- f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
- break;
- }
- if (f->nw_proto == IPPROTO_ICMP) {
- format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
- format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
- } else if (f->nw_proto == IPPROTO_ICMPV6) {
- format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
- format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
- format_ipv6_netmask(s, "nd_target", &f->nd_target,
- &wc->masks.nd_target);
- format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha);
- format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha);
- } else {
- format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src);
- format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
- }
-
- if (s->length > start_len && ds_last(s) == ',') {
- s->length--;
- }
-}
-
-/* Converts 'rule' to a string and returns the string. The caller must free
- * the string (with free()). */
-char *
-cls_rule_to_string(const struct cls_rule *rule)
-{
- struct ds s = DS_EMPTY_INITIALIZER;
- cls_rule_format(rule, &s);
- return ds_steal_cstr(&s);
-}
-
-void
-cls_rule_print(const struct cls_rule *rule)
-{
- char *s = cls_rule_to_string(rule);
- puts(s);
- free(s);
+ match_format(&rule->match, s, rule->priority);
}
\f
/* Initializes 'cls' as a classifier that initially contains no classification
struct cls_rule *old_rule;
struct cls_table *table;
- table = find_table(cls, &rule->wc);
+ table = find_table(cls, &rule->match.wc);
if (!table) {
- table = insert_table(cls, &rule->wc);
+ table = insert_table(cls, &rule->match.wc);
}
old_rule = insert_rule(table, rule);
struct cls_rule *head;
struct cls_table *table;
- table = find_table(cls, &rule->wc);
- head = find_equal(table, &rule->flow, rule->hmap_node.hash);
+ table = find_table(cls, &rule->match.wc);
+ head = find_equal(table, &rule->match.flow, rule->hmap_node.hash);
if (head != rule) {
list_remove(&rule->list);
} else if (list_is_empty(&rule->list)) {
struct cls_rule *head, *rule;
struct cls_table *table;
- table = find_table(cls, &target->wc);
+ table = find_table(cls, &target->match.wc);
if (!table) {
return NULL;
}
- head = find_equal(table, &target->flow, flow_hash(&target->flow, 0));
+ head = find_equal(table, &target->match.flow,
+ flow_hash(&target->match.flow, 0));
FOR_EACH_RULE_IN_LIST (rule, head) {
if (target->priority >= rule->priority) {
return target->priority == rule->priority ? rule : NULL;
return NULL;
}
+/* Finds and returns a rule in 'cls' with priority 'priority' and exactly the
+ * same matching criteria as 'target'. Returns a null pointer if 'cls' doesn't
+ * contain an exact match. */
+struct cls_rule *
+classifier_find_match_exactly(const struct classifier *cls,
+ const struct match *target,
+ unsigned int priority)
+{
+ struct cls_rule *retval;
+ struct cls_rule cr;
+
+ cls_rule_init(&cr, target, priority);
+ retval = classifier_find_rule_exactly(cls, &cr);
+
+ return retval;
+}
+
/* Checks if 'target' would overlap any other rule in 'cls'. Two rules are
* considered to overlap if both rules have the same priority and a packet
* could match both. */
struct flow_wildcards wc;
struct cls_rule *head;
- flow_wildcards_combine(&wc, &target->wc, &table->wc);
+ flow_wildcards_combine(&wc, &target->match.wc, &table->wc);
HMAP_FOR_EACH (head, hmap_node, &table->rules) {
struct cls_rule *rule;
FOR_EACH_RULE_IN_LIST (rule, head) {
if (rule->priority == target->priority
- && flow_equal_except(&target->flow, &rule->flow, &wc)) {
+ && flow_equal_except(&target->match.flow,
+ &rule->match.flow, &wc)) {
return true;
}
}
* This is the matching rule used by OpenFlow 1.0 non-strict OFPT_FLOW_MOD
* commands and by OpenFlow 1.0 aggregate and flow stats.
*
- * Ignores rule->priority and criteria->priority. */
+ * Ignores rule->priority. */
bool
cls_rule_is_loose_match(const struct cls_rule *rule,
- const struct cls_rule *criteria)
+ const struct match *criteria)
{
- return (!flow_wildcards_has_extra(&rule->wc, &criteria->wc)
- && flow_equal_except(&rule->flow, &criteria->flow, &criteria->wc));
+ return (!flow_wildcards_has_extra(&rule->match.wc, &criteria->wc)
+ && flow_equal_except(&rule->match.flow, &criteria->flow,
+ &criteria->wc));
}
\f
/* Iteration. */
rule_matches(const struct cls_rule *rule, const struct cls_rule *target)
{
return (!target
- || flow_equal_except(&rule->flow, &target->flow, &target->wc));
+ || flow_equal_except(&rule->match.flow, &target->match.flow,
+ &target->match.wc));
}
static struct cls_rule *
search_table(const struct cls_table *table, const struct cls_rule *target)
{
- if (!target || !flow_wildcards_has_extra(&table->wc, &target->wc)) {
+ if (!target || !flow_wildcards_has_extra(&table->wc, &target->match.wc)) {
struct cls_rule *rule;
HMAP_FOR_EACH (rule, hmap_node, &table->rules) {
flow_zero_wildcards(&f, &table->wc);
HMAP_FOR_EACH_WITH_HASH (rule, hmap_node, flow_hash(&f, 0),
&table->rules) {
- if (flow_equal(&f, &rule->flow)) {
+ if (flow_equal(&f, &rule->match.flow)) {
return rule;
}
}
struct cls_rule *head;
HMAP_FOR_EACH_WITH_HASH (head, hmap_node, hash, &table->rules) {
- if (flow_equal(&head->flow, flow)) {
+ if (flow_equal(&head->match.flow, flow)) {
return head;
}
}
{
struct cls_rule *head;
- new->hmap_node.hash = flow_hash(&new->flow, 0);
+ new->hmap_node.hash = flow_hash(&new->match.flow, 0);
- head = find_equal(table, &new->flow, new->hmap_node.hash);
+ head = find_equal(table, &new->match.flow, new->hmap_node.hash);
if (!head) {
hmap_insert(&table->rules, &new->hmap_node, new->hmap_node.hash);
list_init(&new->list);
#include "flow.h"
#include "hmap.h"
#include "list.h"
+#include "match.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
return table->is_catchall;
}
-/* A flow classification rule.
- *
- * Use one of the cls_rule_*() functions to initialize a cls_rule.
- *
- * The cls_rule_*() functions below maintain the following important
- * invariant that the classifier depends on:
- *
- * - If a bit or a field is wildcarded in 'wc', then the corresponding bit or
- * field in 'flow' is set to all-0-bits. (The
- * cls_rule_zero_wildcarded_fields() function can be used to restore this
- * invariant after adding wildcards.)
- */
+/* A rule in a "struct classifier" */
struct cls_rule {
struct hmap_node hmap_node; /* Within struct cls_table 'rules'. */
struct list list; /* List of identical, lower-priority rules. */
- struct flow flow; /* All field values. */
- struct flow_wildcards wc; /* Wildcards for fields. */
+ struct match match; /* Matching rule. */
unsigned int priority; /* Larger numbers are higher priorities. */
};
-void cls_rule_init(const struct flow *, const struct flow_wildcards *,
- unsigned int priority, struct cls_rule *);
-void cls_rule_init_exact(const struct flow *, unsigned int priority,
- struct cls_rule *);
-void cls_rule_init_catchall(struct cls_rule *, unsigned int priority);
-
-void cls_rule_zero_wildcarded_fields(struct cls_rule *);
-
-bool cls_rule_is_loose_match(const struct cls_rule *rule,
- const struct cls_rule *criteria);
-
-void cls_rule_set_reg(struct cls_rule *, unsigned int reg_idx, uint32_t value);
-void cls_rule_set_reg_masked(struct cls_rule *, unsigned int reg_idx,
- uint32_t value, uint32_t mask);
-void cls_rule_set_metadata(struct cls_rule *, ovs_be64 metadata);
-void cls_rule_set_metadata_masked(struct cls_rule *, ovs_be64 metadata,
- ovs_be64 mask);
-void cls_rule_set_tun_id(struct cls_rule *, ovs_be64 tun_id);
-void cls_rule_set_tun_id_masked(struct cls_rule *,
- ovs_be64 tun_id, ovs_be64 mask);
-void cls_rule_set_in_port(struct cls_rule *, uint16_t ofp_port);
-void cls_rule_set_dl_type(struct cls_rule *, ovs_be16);
-void cls_rule_set_dl_src(struct cls_rule *, const uint8_t[6]);
-void cls_rule_set_dl_src_masked(struct cls_rule *, const uint8_t dl_src[6],
- const uint8_t mask[6]);
-void cls_rule_set_dl_dst(struct cls_rule *, const uint8_t[6]);
-void cls_rule_set_dl_dst_masked(struct cls_rule *, const uint8_t dl_dst[6],
- const uint8_t mask[6]);
-void cls_rule_set_dl_tci(struct cls_rule *, ovs_be16 tci);
-void cls_rule_set_dl_tci_masked(struct cls_rule *,
- ovs_be16 tci, ovs_be16 mask);
-void cls_rule_set_any_vid(struct cls_rule *);
-void cls_rule_set_dl_vlan(struct cls_rule *, ovs_be16);
-void cls_rule_set_vlan_vid(struct cls_rule *, ovs_be16);
-void cls_rule_set_vlan_vid_masked(struct cls_rule *,
- ovs_be16 vid, ovs_be16 mask);
-void cls_rule_set_any_pcp(struct cls_rule *);
-void cls_rule_set_dl_vlan_pcp(struct cls_rule *, uint8_t);
-void cls_rule_set_tp_src(struct cls_rule *, ovs_be16);
-void cls_rule_set_tp_src_masked(struct cls_rule *,
- ovs_be16 port, ovs_be16 mask);
-void cls_rule_set_tp_dst(struct cls_rule *, ovs_be16);
-void cls_rule_set_tp_dst_masked(struct cls_rule *,
- ovs_be16 port, ovs_be16 mask);
-void cls_rule_set_nw_proto(struct cls_rule *, uint8_t);
-void cls_rule_set_nw_src(struct cls_rule *, ovs_be32);
-void cls_rule_set_nw_src_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask);
-void cls_rule_set_nw_dst(struct cls_rule *, ovs_be32);
-void cls_rule_set_nw_dst_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask);
-void cls_rule_set_nw_dscp(struct cls_rule *, uint8_t);
-void cls_rule_set_nw_ecn(struct cls_rule *, uint8_t);
-void cls_rule_set_nw_ttl(struct cls_rule *, uint8_t);
-void cls_rule_set_nw_frag(struct cls_rule *, uint8_t nw_frag);
-void cls_rule_set_nw_frag_masked(struct cls_rule *,
- uint8_t nw_frag, uint8_t mask);
-void cls_rule_set_icmp_type(struct cls_rule *, uint8_t);
-void cls_rule_set_icmp_code(struct cls_rule *, uint8_t);
-void cls_rule_set_arp_sha(struct cls_rule *, const uint8_t[6]);
-void cls_rule_set_arp_sha_masked(struct cls_rule *, const uint8_t[6],
- const uint8_t [6]);
-void cls_rule_set_arp_tha(struct cls_rule *, const uint8_t[6]);
-void cls_rule_set_arp_tha_masked(struct cls_rule *, const uint8_t[6],
- const uint8_t [6]);
-void cls_rule_set_ipv6_src(struct cls_rule *, const struct in6_addr *);
-void cls_rule_set_ipv6_src_masked(struct cls_rule *, const struct in6_addr *,
- const struct in6_addr *);
-void cls_rule_set_ipv6_dst(struct cls_rule *, const struct in6_addr *);
-void cls_rule_set_ipv6_dst_masked(struct cls_rule *, const struct in6_addr *,
- const struct in6_addr *);
-void cls_rule_set_ipv6_label(struct cls_rule *, ovs_be32);
-void cls_rule_set_ipv6_label_masked(struct cls_rule *, ovs_be32, ovs_be32);
-void cls_rule_set_nd_target(struct cls_rule *, const struct in6_addr *);
-void cls_rule_set_nd_target_masked(struct cls_rule *, const struct in6_addr *,
- const struct in6_addr *);
+void cls_rule_init(struct cls_rule *,
+ const struct match *, unsigned int priority);
bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *);
uint32_t cls_rule_hash(const struct cls_rule *, uint32_t basis);
void cls_rule_format(const struct cls_rule *, struct ds *);
-char *cls_rule_to_string(const struct cls_rule *);
-void cls_rule_print(const struct cls_rule *);
+
+bool cls_rule_is_loose_match(const struct cls_rule *rule,
+ const struct match *criteria);
void classifier_init(struct classifier *);
void classifier_destroy(struct classifier *);
struct cls_rule *classifier_find_rule_exactly(const struct classifier *,
const struct cls_rule *);
+struct cls_rule *classifier_find_match_exactly(const struct classifier *,
+ const struct match *,
+ unsigned int priority);
\f
/* Iteration. */
#include "byte-order.h"
#include "dynamic-string.h"
+#include "match.h"
#include "meta-flow.h"
#include "nx-match.h"
#include "ofp-actions.h"
learn_check(const struct ofpact_learn *learn, const struct flow *flow)
{
const struct ofpact_learn_spec *spec;
- struct cls_rule rule;
+ struct match match;
- cls_rule_init_catchall(&rule, 0);
+ match_init_catchall(&match);
for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
enum ofperr error;
/* Check the destination. */
switch (spec->dst_type) {
case NX_LEARN_DST_MATCH:
- error = mf_check_src(&spec->dst, &rule.flow);
+ error = mf_check_src(&spec->dst, &match.flow);
if (error) {
return error;
}
- mf_write_subfield(&spec->dst, &spec->src_imm, &rule);
+ mf_write_subfield(&spec->dst, &spec->src_imm, &match);
break;
case NX_LEARN_DST_LOAD:
- error = mf_check_dst(&spec->dst, &rule.flow);
+ error = mf_check_dst(&spec->dst, &match.flow);
if (error) {
return error;
}
{
const struct ofpact_learn_spec *spec;
- cls_rule_init_catchall(&fm->cr, learn->priority);
+ match_init_catchall(&fm->match);
+ fm->priority = learn->priority;
fm->cookie = htonll(0);
fm->cookie_mask = htonll(0);
fm->new_cookie = htonll(learn->cookie);
switch (spec->dst_type) {
case NX_LEARN_DST_MATCH:
- mf_write_subfield(&spec->dst, &value, &fm->cr);
+ mf_write_subfield(&spec->dst, &value, &fm->match);
break;
case NX_LEARN_DST_LOAD:
*
* Prints an error on stderr and aborts the program if 'arg' syntax is invalid.
*
- * If 'flow' is nonnull, then it should be the flow from a cls_rule that is
+ * If 'flow' is nonnull, then it should be the flow from a struct match that is
* the matching rule for the learning action. This helps to better validate
* the action's arguments.
*
char *name, *value;
struct ofpact_learn *learn;
- struct cls_rule rule;
+ struct match match;
enum ofperr error;
learn = ofpact_put_LEARN(ofpacts);
learn->priority = OFP_DEFAULT_PRIORITY;
learn->table_id = 1;
- cls_rule_init_catchall(&rule, 0);
+ match_init_catchall(&match);
while (ofputil_parse_key_value(&arg, &name, &value)) {
if (!strcmp(name, "table")) {
learn->table_id = atoi(value);
}
if ((spec->dst_type == NX_LEARN_DST_MATCH
|| spec->dst_type == NX_LEARN_DST_LOAD)
- && !mf_are_prereqs_ok(spec->dst.field, &rule.flow)) {
+ && !mf_are_prereqs_ok(spec->dst.field, &match.flow)) {
ovs_fatal(0, "%s: cannot specify destination field %s because "
"prerequisites are not satisfied",
orig, spec->dst.field->name);
}
- /* Update 'rule' to allow for satisfying destination
+ /* Update 'match' to allow for satisfying destination
* prerequisites. */
if (spec->src_type == NX_LEARN_SRC_IMMEDIATE
&& spec->dst_type == NX_LEARN_DST_MATCH) {
- mf_write_subfield(&spec->dst, &spec->src_imm, &rule);
+ mf_write_subfield(&spec->dst, &spec->src_imm, &match);
}
}
}
learn_format(const struct ofpact_learn *learn, struct ds *s)
{
const struct ofpact_learn_spec *spec;
- struct cls_rule rule;
+ struct match match;
- cls_rule_init_catchall(&rule, 0);
+ match_init_catchall(&match);
ds_put_format(s, "learn(table=%"PRIu8, learn->table_id);
if (learn->idle_timeout != OFP_FLOW_PERMANENT) {
/* The output port is known, or we always flood everything, so add a
* new flow. */
memset(&fm, 0, sizeof fm);
- cls_rule_init(&flow, &sw->wc, 0, &fm.cr);
- ofputil_normalize_rule_quiet(&fm.cr);
+ match_init(&fm.match, &flow, &sw->wc);
+ ofputil_normalize_match_quiet(&fm.match);
+ fm.priority = 0;
fm.table_id = 0xff;
fm.command = OFPFC_ADD;
fm.idle_timeout = sw->max_idle;
--- /dev/null
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "match.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "byte-order.h"
+#include "dynamic-string.h"
+#include "packets.h"
+
+/* Converts the flow in 'flow' into a match in 'match', with the given
+ * 'wildcards'. */
+void
+match_init(struct match *match,
+ const struct flow *flow, const struct flow_wildcards *wc)
+{
+ match->flow = *flow;
+ match->wc = *wc;
+ match_zero_wildcarded_fields(match);
+}
+
+/* Converts the flow in 'flow' into an exact-match match in 'match'. */
+void
+match_init_exact(struct match *match, const struct flow *flow)
+{
+ match->flow = *flow;
+ match->flow.skb_priority = 0;
+ flow_wildcards_init_exact(&match->wc);
+}
+
+/* Initializes 'match' as a "catch-all" match that matches every packet. */
+void
+match_init_catchall(struct match *match)
+{
+ memset(&match->flow, 0, sizeof match->flow);
+ flow_wildcards_init_catchall(&match->wc);
+}
+
+/* For each bit or field wildcarded in 'match', sets the corresponding bit or
+ * field in 'flow' to all-0-bits. It is important to maintain this invariant
+ * in a match that might be inserted into a classifier.
+ *
+ * It is never necessary to call this function directly for a match that is
+ * initialized or modified only by match_*() functions. It is useful to
+ * restore the invariant in a match whose 'wc' member is modified by hand.
+ */
+void
+match_zero_wildcarded_fields(struct match *match)
+{
+ flow_zero_wildcards(&match->flow, &match->wc);
+}
+
+void
+match_set_reg(struct match *match, unsigned int reg_idx, uint32_t value)
+{
+ match_set_reg_masked(match, reg_idx, value, UINT32_MAX);
+}
+
+void
+match_set_reg_masked(struct match *match, unsigned int reg_idx,
+ uint32_t value, uint32_t mask)
+{
+ assert(reg_idx < FLOW_N_REGS);
+ flow_wildcards_set_reg_mask(&match->wc, reg_idx, mask);
+ match->flow.regs[reg_idx] = value & mask;
+}
+
+void
+match_set_metadata(struct match *match, ovs_be64 metadata)
+{
+ match_set_metadata_masked(match, metadata, htonll(UINT64_MAX));
+}
+
+void
+match_set_metadata_masked(struct match *match,
+ ovs_be64 metadata, ovs_be64 mask)
+{
+ match->wc.masks.metadata = mask;
+ match->flow.metadata = metadata & mask;
+}
+
+void
+match_set_tun_id(struct match *match, ovs_be64 tun_id)
+{
+ match_set_tun_id_masked(match, tun_id, htonll(UINT64_MAX));
+}
+
+void
+match_set_tun_id_masked(struct match *match, ovs_be64 tun_id, ovs_be64 mask)
+{
+ match->wc.masks.tun_id = mask;
+ match->flow.tun_id = tun_id & mask;
+}
+
+void
+match_set_in_port(struct match *match, uint16_t ofp_port)
+{
+ match->wc.masks.in_port = UINT16_MAX;
+ match->flow.in_port = ofp_port;
+}
+
+void
+match_set_dl_type(struct match *match, ovs_be16 dl_type)
+{
+ match->wc.masks.dl_type = htons(UINT16_MAX);
+ match->flow.dl_type = dl_type;
+}
+
+/* Modifies 'value_src' so that the Ethernet address must match 'value_dst'
+ * exactly. 'mask_dst' is set to all 1s. */
+static void
+set_eth(const uint8_t value_src[ETH_ADDR_LEN],
+ uint8_t value_dst[ETH_ADDR_LEN],
+ uint8_t mask_dst[ETH_ADDR_LEN])
+{
+ memcpy(value_dst, value_src, ETH_ADDR_LEN);
+ memset(mask_dst, 0xff, ETH_ADDR_LEN);
+}
+
+/* Modifies 'value_src' so that the Ethernet address must match 'value_src'
+ * after each byte is ANDed with the appropriate byte in 'mask_src'.
+ * 'mask_dst' is set to 'mask_src' */
+static void
+set_eth_masked(const uint8_t value_src[ETH_ADDR_LEN],
+ const uint8_t mask_src[ETH_ADDR_LEN],
+ uint8_t value_dst[ETH_ADDR_LEN],
+ uint8_t mask_dst[ETH_ADDR_LEN])
+{
+ size_t i;
+
+ for (i = 0; i < ETH_ADDR_LEN; i++) {
+ value_dst[i] = value_src[i] & mask_src[i];
+ mask_dst[i] = mask_src[i];
+ }
+}
+
+/* Modifies 'rule' so that the source Ethernet address must match 'dl_src'
+ * exactly. */
+void
+match_set_dl_src(struct match *match, const uint8_t dl_src[ETH_ADDR_LEN])
+{
+ set_eth(dl_src, match->flow.dl_src, match->wc.masks.dl_src);
+}
+
+/* Modifies 'rule' so that the source Ethernet address must match 'dl_src'
+ * after each byte is ANDed with the appropriate byte in 'mask'. */
+void
+match_set_dl_src_masked(struct match *match,
+ const uint8_t dl_src[ETH_ADDR_LEN],
+ const uint8_t mask[ETH_ADDR_LEN])
+{
+ set_eth_masked(dl_src, mask, match->flow.dl_src, match->wc.masks.dl_src);
+}
+
+/* Modifies 'match' so that the Ethernet address must match 'dl_dst'
+ * exactly. */
+void
+match_set_dl_dst(struct match *match, const uint8_t dl_dst[ETH_ADDR_LEN])
+{
+ set_eth(dl_dst, match->flow.dl_dst, match->wc.masks.dl_dst);
+}
+
+/* Modifies 'match' so that the Ethernet address must match 'dl_dst' after each
+ * byte is ANDed with the appropriate byte in 'mask'.
+ *
+ * This function will assert-fail if 'mask' is invalid. Only 'mask' values
+ * accepted by flow_wildcards_is_dl_dst_mask_valid() are allowed. */
+void
+match_set_dl_dst_masked(struct match *match,
+ const uint8_t dl_dst[ETH_ADDR_LEN],
+ const uint8_t mask[ETH_ADDR_LEN])
+{
+ set_eth_masked(dl_dst, mask, match->flow.dl_dst, match->wc.masks.dl_dst);
+}
+
+void
+match_set_dl_tci(struct match *match, ovs_be16 tci)
+{
+ match_set_dl_tci_masked(match, tci, htons(0xffff));
+}
+
+void
+match_set_dl_tci_masked(struct match *match, ovs_be16 tci, ovs_be16 mask)
+{
+ match->flow.vlan_tci = tci & mask;
+ match->wc.masks.vlan_tci = mask;
+}
+
+/* Modifies 'match' so that the VLAN VID is wildcarded. If the PCP is already
+ * wildcarded, then 'match' will match a packet regardless of whether it has an
+ * 802.1Q header or not. */
+void
+match_set_any_vid(struct match *match)
+{
+ if (match->wc.masks.vlan_tci & htons(VLAN_PCP_MASK)) {
+ match->wc.masks.vlan_tci &= ~htons(VLAN_VID_MASK);
+ match->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
+ } else {
+ match_set_dl_tci_masked(match, htons(0), htons(0));
+ }
+}
+
+/* Modifies 'match' depending on 'dl_vlan':
+ *
+ * - If 'dl_vlan' is htons(OFP_VLAN_NONE), makes 'match' match only packets
+ * without an 802.1Q header.
+ *
+ * - Otherwise, makes 'match' match only packets with an 802.1Q header whose
+ * VID equals the low 12 bits of 'dl_vlan'.
+ */
+void
+match_set_dl_vlan(struct match *match, ovs_be16 dl_vlan)
+{
+ flow_set_dl_vlan(&match->flow, dl_vlan);
+ if (dl_vlan == htons(OFP10_VLAN_NONE)) {
+ match->wc.masks.vlan_tci = htons(UINT16_MAX);
+ } else {
+ match->wc.masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
+ }
+}
+
+/* Sets the VLAN VID that 'match' matches to 'vid', which is interpreted as an
+ * OpenFlow 1.2 "vlan_vid" value, that is, the low 13 bits of 'vlan_tci' (VID
+ * plus CFI). */
+void
+match_set_vlan_vid(struct match *match, ovs_be16 vid)
+{
+ match_set_vlan_vid_masked(match, vid, htons(VLAN_VID_MASK | VLAN_CFI));
+}
+
+
+/* Sets the VLAN VID that 'flow' matches to 'vid', which is interpreted as an
+ * OpenFlow 1.2 "vlan_vid" value, that is, the low 13 bits of 'vlan_tci' (VID
+ * plus CFI), with the corresponding 'mask'. */
+void
+match_set_vlan_vid_masked(struct match *match, ovs_be16 vid, ovs_be16 mask)
+{
+ ovs_be16 pcp_mask = htons(VLAN_PCP_MASK);
+ ovs_be16 vid_mask = htons(VLAN_VID_MASK | VLAN_CFI);
+
+ mask &= vid_mask;
+ flow_set_vlan_vid(&match->flow, vid & mask);
+ match->wc.masks.vlan_tci = mask | (match->wc.masks.vlan_tci & pcp_mask);
+}
+
+/* Modifies 'match' so that the VLAN PCP is wildcarded. If the VID is already
+ * wildcarded, then 'match' will match a packet regardless of whether it has an
+ * 802.1Q header or not. */
+void
+match_set_any_pcp(struct match *match)
+{
+ if (match->wc.masks.vlan_tci & htons(VLAN_VID_MASK)) {
+ match->wc.masks.vlan_tci &= ~htons(VLAN_PCP_MASK);
+ match->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
+ } else {
+ match_set_dl_tci_masked(match, htons(0), htons(0));
+ }
+}
+
+/* Modifies 'match' so that it matches only packets with an 802.1Q header whose
+ * PCP equals the low 3 bits of 'dl_vlan_pcp'. */
+void
+match_set_dl_vlan_pcp(struct match *match, uint8_t dl_vlan_pcp)
+{
+ flow_set_vlan_pcp(&match->flow, dl_vlan_pcp);
+ match->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_PCP_MASK);
+}
+
+void
+match_set_tp_src(struct match *match, ovs_be16 tp_src)
+{
+ match_set_tp_src_masked(match, tp_src, htons(UINT16_MAX));
+}
+
+void
+match_set_tp_src_masked(struct match *match, ovs_be16 port, ovs_be16 mask)
+{
+ match->flow.tp_src = port & mask;
+ match->wc.masks.tp_src = mask;
+}
+
+void
+match_set_tp_dst(struct match *match, ovs_be16 tp_dst)
+{
+ match_set_tp_dst_masked(match, tp_dst, htons(UINT16_MAX));
+}
+
+void
+match_set_tp_dst_masked(struct match *match, ovs_be16 port, ovs_be16 mask)
+{
+ match->flow.tp_dst = port & mask;
+ match->wc.masks.tp_dst = mask;
+}
+
+void
+match_set_nw_proto(struct match *match, uint8_t nw_proto)
+{
+ match->flow.nw_proto = nw_proto;
+ match->wc.masks.nw_proto = UINT8_MAX;
+}
+
+void
+match_set_nw_src(struct match *match, ovs_be32 nw_src)
+{
+ match->flow.nw_src = nw_src;
+ match->wc.masks.nw_src = htonl(UINT32_MAX);
+}
+
+void
+match_set_nw_src_masked(struct match *match,
+ ovs_be32 nw_src, ovs_be32 mask)
+{
+ match->flow.nw_src = nw_src & mask;
+ match->wc.masks.nw_src = mask;
+}
+
+void
+match_set_nw_dst(struct match *match, ovs_be32 nw_dst)
+{
+ match->flow.nw_dst = nw_dst;
+ match->wc.masks.nw_dst = htonl(UINT32_MAX);
+}
+
+void
+match_set_nw_dst_masked(struct match *match, ovs_be32 ip, ovs_be32 mask)
+{
+ match->flow.nw_dst = ip & mask;
+ match->wc.masks.nw_dst = mask;
+}
+
+void
+match_set_nw_dscp(struct match *match, uint8_t nw_dscp)
+{
+ match->wc.masks.nw_tos |= IP_DSCP_MASK;
+ match->flow.nw_tos &= ~IP_DSCP_MASK;
+ match->flow.nw_tos |= nw_dscp & IP_DSCP_MASK;
+}
+
+void
+match_set_nw_ecn(struct match *match, uint8_t nw_ecn)
+{
+ match->wc.masks.nw_tos |= IP_ECN_MASK;
+ match->flow.nw_tos &= ~IP_ECN_MASK;
+ match->flow.nw_tos |= nw_ecn & IP_ECN_MASK;
+}
+
+void
+match_set_nw_ttl(struct match *match, uint8_t nw_ttl)
+{
+ match->wc.masks.nw_ttl = UINT8_MAX;
+ match->flow.nw_ttl = nw_ttl;
+}
+
+void
+match_set_nw_frag(struct match *match, uint8_t nw_frag)
+{
+ match->wc.masks.nw_frag |= FLOW_NW_FRAG_MASK;
+ match->flow.nw_frag = nw_frag;
+}
+
+void
+match_set_nw_frag_masked(struct match *match,
+ uint8_t nw_frag, uint8_t mask)
+{
+ match->flow.nw_frag = nw_frag & mask;
+ match->wc.masks.nw_frag = mask;
+}
+
+void
+match_set_icmp_type(struct match *match, uint8_t icmp_type)
+{
+ match_set_tp_src(match, htons(icmp_type));
+}
+
+void
+match_set_icmp_code(struct match *match, uint8_t icmp_code)
+{
+ match_set_tp_dst(match, htons(icmp_code));
+}
+
+void
+match_set_arp_sha(struct match *match, const uint8_t sha[ETH_ADDR_LEN])
+{
+ memcpy(match->flow.arp_sha, sha, ETH_ADDR_LEN);
+ memset(match->wc.masks.arp_sha, UINT8_MAX, ETH_ADDR_LEN);
+}
+
+void
+match_set_arp_sha_masked(struct match *match,
+ const uint8_t arp_sha[ETH_ADDR_LEN],
+ const uint8_t mask[ETH_ADDR_LEN])
+{
+ set_eth_masked(arp_sha, mask,
+ match->flow.arp_sha, match->wc.masks.arp_sha);
+}
+
+void
+match_set_arp_tha(struct match *match, const uint8_t tha[ETH_ADDR_LEN])
+{
+ memcpy(match->flow.arp_tha, tha, ETH_ADDR_LEN);
+ memset(match->wc.masks.arp_tha, UINT8_MAX, ETH_ADDR_LEN);
+}
+
+void
+match_set_arp_tha_masked(struct match *match,
+ const uint8_t arp_tha[ETH_ADDR_LEN],
+ const uint8_t mask[ETH_ADDR_LEN])
+{
+ set_eth_masked(arp_tha, mask,
+ match->flow.arp_tha, match->wc.masks.arp_tha);
+}
+
+void
+match_set_ipv6_src(struct match *match, const struct in6_addr *src)
+{
+ match->flow.ipv6_src = *src;
+ match->wc.masks.ipv6_src = in6addr_exact;
+}
+
+void
+match_set_ipv6_src_masked(struct match *match, const struct in6_addr *src,
+ const struct in6_addr *mask)
+{
+ match->flow.ipv6_src = ipv6_addr_bitand(src, mask);
+ match->wc.masks.ipv6_src = *mask;
+}
+
+void
+match_set_ipv6_dst(struct match *match, const struct in6_addr *dst)
+{
+ match->flow.ipv6_dst = *dst;
+ match->wc.masks.ipv6_dst = in6addr_exact;
+}
+
+void
+match_set_ipv6_dst_masked(struct match *match, const struct in6_addr *dst,
+ const struct in6_addr *mask)
+{
+ match->flow.ipv6_dst = ipv6_addr_bitand(dst, mask);
+ match->wc.masks.ipv6_dst = *mask;
+}
+
+void
+match_set_ipv6_label(struct match *match, ovs_be32 ipv6_label)
+{
+ match->wc.masks.ipv6_label = htonl(UINT32_MAX);
+ match->flow.ipv6_label = ipv6_label;
+}
+
+
+void
+match_set_ipv6_label_masked(struct match *match, ovs_be32 ipv6_label,
+ ovs_be32 mask)
+{
+ match->flow.ipv6_label = ipv6_label & mask;
+ match->wc.masks.ipv6_label = mask;
+}
+
+void
+match_set_nd_target(struct match *match, const struct in6_addr *target)
+{
+ match->flow.nd_target = *target;
+ match->wc.masks.nd_target = in6addr_exact;
+}
+
+void
+match_set_nd_target_masked(struct match *match,
+ const struct in6_addr *target,
+ const struct in6_addr *mask)
+{
+ match->flow.nd_target = ipv6_addr_bitand(target, mask);
+ match->wc.masks.nd_target = *mask;
+}
+
+/* Returns true if 'a' and 'b' wildcard the same fields and have the same
+ * values for fixed fields, otherwise false. */
+bool
+match_equal(const struct match *a, const struct match *b)
+{
+ return (flow_wildcards_equal(&a->wc, &b->wc)
+ && flow_equal(&a->flow, &b->flow));
+}
+
+/* Returns a hash value for the flow and wildcards in 'match', starting from
+ * 'basis'. */
+uint32_t
+match_hash(const struct match *match, uint32_t basis)
+{
+ return flow_wildcards_hash(&match->wc, flow_hash(&match->flow, basis));
+}
+
+static void
+format_eth_masked(struct ds *s, const char *name, const uint8_t eth[6],
+ const uint8_t mask[6])
+{
+ if (!eth_addr_is_zero(mask)) {
+ ds_put_format(s, "%s=", name);
+ eth_format_masked(eth, mask, s);
+ ds_put_char(s, ',');
+ }
+}
+
+static void
+format_ip_netmask(struct ds *s, const char *name, ovs_be32 ip,
+ ovs_be32 netmask)
+{
+ if (netmask) {
+ ds_put_format(s, "%s=", name);
+ ip_format_masked(ip, netmask, s);
+ ds_put_char(s, ',');
+ }
+}
+
+static void
+format_ipv6_netmask(struct ds *s, const char *name,
+ const struct in6_addr *addr,
+ const struct in6_addr *netmask)
+{
+ if (!ipv6_mask_is_any(netmask)) {
+ ds_put_format(s, "%s=", name);
+ print_ipv6_masked(s, addr, netmask);
+ ds_put_char(s, ',');
+ }
+}
+
+
+static void
+format_be16_masked(struct ds *s, const char *name,
+ ovs_be16 value, ovs_be16 mask)
+{
+ if (mask != htons(0)) {
+ ds_put_format(s, "%s=", name);
+ if (mask == htons(UINT16_MAX)) {
+ ds_put_format(s, "%"PRIu16, ntohs(value));
+ } else {
+ ds_put_format(s, "0x%"PRIx16"/0x%"PRIx16,
+ ntohs(value), ntohs(mask));
+ }
+ 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
+match_format(const struct match *match, struct ds *s, unsigned int priority)
+{
+ const struct flow_wildcards *wc = &match->wc;
+ size_t start_len = s->length;
+ const struct flow *f = &match->flow;
+ bool skip_type = false;
+ bool skip_proto = false;
+
+ int i;
+
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+
+ if (priority != OFP_DEFAULT_PRIORITY) {
+ ds_put_format(s, "priority=%u,", priority);
+ }
+
+ if (wc->masks.dl_type) {
+ skip_type = true;
+ if (f->dl_type == htons(ETH_TYPE_IP)) {
+ if (wc->masks.nw_proto) {
+ skip_proto = true;
+ if (f->nw_proto == IPPROTO_ICMP) {
+ ds_put_cstr(s, "icmp,");
+ } else if (f->nw_proto == IPPROTO_TCP) {
+ ds_put_cstr(s, "tcp,");
+ } else if (f->nw_proto == IPPROTO_UDP) {
+ ds_put_cstr(s, "udp,");
+ } else {
+ ds_put_cstr(s, "ip,");
+ skip_proto = false;
+ }
+ } else {
+ ds_put_cstr(s, "ip,");
+ }
+ } else if (f->dl_type == htons(ETH_TYPE_IPV6)) {
+ if (wc->masks.nw_proto) {
+ skip_proto = true;
+ if (f->nw_proto == IPPROTO_ICMPV6) {
+ ds_put_cstr(s, "icmp6,");
+ } else if (f->nw_proto == IPPROTO_TCP) {
+ ds_put_cstr(s, "tcp6,");
+ } else if (f->nw_proto == IPPROTO_UDP) {
+ ds_put_cstr(s, "udp6,");
+ } else {
+ ds_put_cstr(s, "ipv6,");
+ skip_proto = false;
+ }
+ } else {
+ ds_put_cstr(s, "ipv6,");
+ }
+ } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
+ ds_put_cstr(s, "arp,");
+ } else {
+ skip_type = false;
+ }
+ }
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ switch (wc->masks.regs[i]) {
+ case 0:
+ break;
+ case UINT32_MAX:
+ ds_put_format(s, "reg%d=0x%"PRIx32",", i, f->regs[i]);
+ break;
+ default:
+ ds_put_format(s, "reg%d=0x%"PRIx32"/0x%"PRIx32",",
+ i, f->regs[i], wc->masks.regs[i]);
+ break;
+ }
+ }
+ switch (wc->masks.tun_id) {
+ case 0:
+ break;
+ case CONSTANT_HTONLL(UINT64_MAX):
+ ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_id));
+ break;
+ default:
+ ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
+ ntohll(f->tun_id), ntohll(wc->masks.tun_id));
+ break;
+ }
+ switch (wc->masks.metadata) {
+ case 0:
+ break;
+ case CONSTANT_HTONLL(UINT64_MAX):
+ ds_put_format(s, "metadata=%#"PRIx64",", ntohll(f->metadata));
+ break;
+ default:
+ ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
+ ntohll(f->metadata), ntohll(wc->masks.metadata));
+ break;
+ }
+ if (wc->masks.in_port) {
+ ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
+ }
+ if (wc->masks.vlan_tci) {
+ ovs_be16 vid_mask = wc->masks.vlan_tci & htons(VLAN_VID_MASK);
+ ovs_be16 pcp_mask = wc->masks.vlan_tci & htons(VLAN_PCP_MASK);
+ ovs_be16 cfi = wc->masks.vlan_tci & htons(VLAN_CFI);
+
+ if (cfi && f->vlan_tci & htons(VLAN_CFI)
+ && (!vid_mask || vid_mask == htons(VLAN_VID_MASK))
+ && (!pcp_mask || pcp_mask == htons(VLAN_PCP_MASK))
+ && (vid_mask || pcp_mask)) {
+ if (vid_mask) {
+ ds_put_format(s, "dl_vlan=%"PRIu16",",
+ vlan_tci_to_vid(f->vlan_tci));
+ }
+ if (pcp_mask) {
+ ds_put_format(s, "dl_vlan_pcp=%d,",
+ vlan_tci_to_pcp(f->vlan_tci));
+ }
+ } else if (wc->masks.vlan_tci == htons(0xffff)) {
+ ds_put_format(s, "vlan_tci=0x%04"PRIx16",", ntohs(f->vlan_tci));
+ } else {
+ ds_put_format(s, "vlan_tci=0x%04"PRIx16"/0x%04"PRIx16",",
+ ntohs(f->vlan_tci), ntohs(wc->masks.vlan_tci));
+ }
+ }
+ format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src);
+ format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst);
+ if (!skip_type && wc->masks.dl_type) {
+ ds_put_format(s, "dl_type=0x%04"PRIx16",", ntohs(f->dl_type));
+ }
+ if (f->dl_type == htons(ETH_TYPE_IPV6)) {
+ format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src);
+ format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst);
+ if (wc->masks.ipv6_label) {
+ if (wc->masks.ipv6_label == htonl(UINT32_MAX)) {
+ ds_put_format(s, "ipv6_label=0x%05"PRIx32",",
+ ntohl(f->ipv6_label));
+ } else {
+ ds_put_format(s, "ipv6_label=0x%05"PRIx32"/0x%05"PRIx32",",
+ ntohl(f->ipv6_label),
+ ntohl(wc->masks.ipv6_label));
+ }
+ }
+ } else {
+ format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src);
+ format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
+ }
+ if (!skip_proto && wc->masks.nw_proto) {
+ if (f->dl_type == htons(ETH_TYPE_ARP)) {
+ ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto);
+ } else {
+ ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto);
+ }
+ }
+ if (f->dl_type == htons(ETH_TYPE_ARP)) {
+ format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
+ format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
+ }
+ if (wc->masks.nw_tos & IP_DSCP_MASK) {
+ ds_put_format(s, "nw_tos=%"PRIu8",", f->nw_tos & IP_DSCP_MASK);
+ }
+ if (wc->masks.nw_tos & IP_ECN_MASK) {
+ ds_put_format(s, "nw_ecn=%"PRIu8",", f->nw_tos & IP_ECN_MASK);
+ }
+ if (wc->masks.nw_ttl) {
+ ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
+ }
+ switch (wc->masks.nw_frag) {
+ case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
+ ds_put_format(s, "nw_frag=%s,",
+ f->nw_frag & FLOW_NW_FRAG_ANY
+ ? (f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "first")
+ : (f->nw_frag & FLOW_NW_FRAG_LATER ? "<error>" : "no"));
+ break;
+
+ case FLOW_NW_FRAG_ANY:
+ ds_put_format(s, "nw_frag=%s,",
+ f->nw_frag & FLOW_NW_FRAG_ANY ? "yes" : "no");
+ break;
+
+ case FLOW_NW_FRAG_LATER:
+ ds_put_format(s, "nw_frag=%s,",
+ f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
+ break;
+ }
+ if (f->nw_proto == IPPROTO_ICMP) {
+ format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
+ format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
+ } else if (f->nw_proto == IPPROTO_ICMPV6) {
+ format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
+ format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
+ format_ipv6_netmask(s, "nd_target", &f->nd_target,
+ &wc->masks.nd_target);
+ format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha);
+ format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha);
+ } else {
+ format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src);
+ format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
+ }
+
+ if (s->length > start_len && ds_last(s) == ',') {
+ s->length--;
+ }
+}
+
+/* Converts 'match' to a string and returns the string. If 'priority' is
+ * different from OFP_DEFAULT_PRIORITY, includes it in the string. The caller
+ * must free the string (with free()). */
+char *
+match_to_string(const struct match *match, unsigned int priority)
+{
+ struct ds s = DS_EMPTY_INITIALIZER;
+ match_format(match, &s, priority);
+ return ds_steal_cstr(&s);
+}
+
+void
+match_print(const struct match *match)
+{
+ char *s = match_to_string(match, OFP_DEFAULT_PRIORITY);
+ puts(s);
+ free(s);
+}
--- /dev/null
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MATCH_H
+#define MATCH_H 1
+
+#include "flow.h"
+
+/* A flow classification match.
+ *
+ * Use one of the match_*() functions to initialize a "struct match".
+ *
+ * The match_*() functions below maintain the following important invariant.
+ * If a bit or a field is wildcarded in 'wc', then the corresponding bit or
+ * field in 'flow' is set to all-0-bits. (The match_zero_wildcarded_fields()
+ * function can be used to restore this invariant after adding wildcards.) */
+struct match {
+ struct flow flow;
+ struct flow_wildcards wc;
+};
+
+void match_init(struct match *,
+ const struct flow *, const struct flow_wildcards *);
+void match_init_catchall(struct match *);
+void match_init_exact(struct match *, const struct flow *);
+
+void match_zero_wildcarded_fields(struct match *);
+
+void match_set_reg(struct match *, unsigned int reg_idx, uint32_t value);
+void match_set_reg_masked(struct match *, unsigned int reg_idx,
+ uint32_t value, uint32_t mask);
+void match_set_metadata(struct match *, ovs_be64 metadata);
+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_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]);
+void match_set_dl_src_masked(struct match *, const uint8_t dl_src[6],
+ const uint8_t mask[6]);
+void match_set_dl_dst(struct match *, const uint8_t[6]);
+void match_set_dl_dst_masked(struct match *, const uint8_t dl_dst[6],
+ const uint8_t mask[6]);
+void match_set_dl_tci(struct match *, ovs_be16 tci);
+void match_set_dl_tci_masked(struct match *, ovs_be16 tci, ovs_be16 mask);
+void match_set_any_vid(struct match *);
+void match_set_dl_vlan(struct match *, ovs_be16);
+void match_set_vlan_vid(struct match *, ovs_be16);
+void match_set_vlan_vid_masked(struct match *, ovs_be16 vid, ovs_be16 mask);
+void match_set_any_pcp(struct match *);
+void match_set_dl_vlan_pcp(struct match *, uint8_t);
+void match_set_tp_src(struct match *, ovs_be16);
+void match_set_tp_src_masked(struct match *, ovs_be16 port, ovs_be16 mask);
+void match_set_tp_dst(struct match *, ovs_be16);
+void match_set_tp_dst_masked(struct match *, ovs_be16 port, ovs_be16 mask);
+void match_set_nw_proto(struct match *, uint8_t);
+void match_set_nw_src(struct match *, ovs_be32);
+void match_set_nw_src_masked(struct match *, ovs_be32 ip, ovs_be32 mask);
+void match_set_nw_dst(struct match *, ovs_be32);
+void match_set_nw_dst_masked(struct match *, ovs_be32 ip, ovs_be32 mask);
+void match_set_nw_dscp(struct match *, uint8_t);
+void match_set_nw_ecn(struct match *, uint8_t);
+void match_set_nw_ttl(struct match *, uint8_t);
+void match_set_nw_frag(struct match *, uint8_t nw_frag);
+void match_set_nw_frag_masked(struct match *, uint8_t nw_frag, uint8_t mask);
+void match_set_icmp_type(struct match *, uint8_t);
+void match_set_icmp_code(struct match *, uint8_t);
+void match_set_arp_sha(struct match *, const uint8_t[6]);
+void match_set_arp_sha_masked(struct match *,
+ const uint8_t arp_sha[6],
+ const uint8_t mask[6]);
+void match_set_arp_tha(struct match *, const uint8_t[6]);
+void match_set_arp_tha_masked(struct match *,
+ const uint8_t arp_tha[6],
+ const uint8_t mask[6]);
+void match_set_ipv6_src(struct match *, const struct in6_addr *);
+void match_set_ipv6_src_masked(struct match *, const struct in6_addr *,
+ const struct in6_addr *);
+void match_set_ipv6_dst(struct match *, const struct in6_addr *);
+void match_set_ipv6_dst_masked(struct match *, const struct in6_addr *,
+ const struct in6_addr *);
+void match_set_ipv6_label(struct match *, ovs_be32);
+void match_set_ipv6_label_masked(struct match *, ovs_be32, ovs_be32);
+void match_set_nd_target(struct match *, const struct in6_addr *);
+void match_set_nd_target_masked(struct match *, const struct in6_addr *,
+ const struct in6_addr *);
+
+bool match_equal(const struct match *, const struct match *);
+uint32_t match_hash(const struct match *, uint32_t basis);
+
+void match_format(const struct match *, struct ds *, unsigned int priority);
+char *match_to_string(const struct match *, unsigned int priority);
+void match_print(const struct match *);
+
+#endif /* match.h */
}
}
-/* Makes 'rule' match field 'mf' exactly, with the value matched taken from
- * 'value'. The caller is responsible for ensuring that 'rule' meets 'mf''s
+/* Makes 'match' match field 'mf' exactly, with the value matched taken from
+ * 'value'. The caller is responsible for ensuring that 'match' meets 'mf''s
* prerequisites. */
void
mf_set_value(const struct mf_field *mf,
- const union mf_value *value, struct cls_rule *rule)
+ const union mf_value *value, struct match *match)
{
switch (mf->id) {
case MFF_TUN_ID:
- cls_rule_set_tun_id(rule, value->be64);
+ match_set_tun_id(match, value->be64);
break;
case MFF_METADATA:
- cls_rule_set_metadata(rule, value->be64);
+ match_set_metadata(match, value->be64);
break;
case MFF_IN_PORT:
- cls_rule_set_in_port(rule, ntohs(value->be16));
+ match_set_in_port(match, ntohs(value->be16));
break;
CASE_MFF_REGS:
- cls_rule_set_reg(rule, mf->id - MFF_REG0, ntohl(value->be32));
+ match_set_reg(match, mf->id - MFF_REG0, ntohl(value->be32));
break;
case MFF_ETH_SRC:
- cls_rule_set_dl_src(rule, value->mac);
+ match_set_dl_src(match, value->mac);
break;
case MFF_ETH_DST:
- cls_rule_set_dl_dst(rule, value->mac);
+ match_set_dl_dst(match, value->mac);
break;
case MFF_ETH_TYPE:
- cls_rule_set_dl_type(rule, value->be16);
+ match_set_dl_type(match, value->be16);
break;
case MFF_VLAN_TCI:
- cls_rule_set_dl_tci(rule, value->be16);
+ match_set_dl_tci(match, value->be16);
break;
case MFF_DL_VLAN:
- cls_rule_set_dl_vlan(rule, value->be16);
+ match_set_dl_vlan(match, value->be16);
break;
case MFF_VLAN_VID:
- cls_rule_set_vlan_vid(rule, value->be16);
+ match_set_vlan_vid(match, value->be16);
break;
case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
- cls_rule_set_dl_vlan_pcp(rule, value->u8);
+ match_set_dl_vlan_pcp(match, value->u8);
break;
case MFF_IPV4_SRC:
- cls_rule_set_nw_src(rule, value->be32);
+ match_set_nw_src(match, value->be32);
break;
case MFF_IPV4_DST:
- cls_rule_set_nw_dst(rule, value->be32);
+ match_set_nw_dst(match, value->be32);
break;
case MFF_IPV6_SRC:
- cls_rule_set_ipv6_src(rule, &value->ipv6);
+ match_set_ipv6_src(match, &value->ipv6);
break;
case MFF_IPV6_DST:
- cls_rule_set_ipv6_dst(rule, &value->ipv6);
+ match_set_ipv6_dst(match, &value->ipv6);
break;
case MFF_IPV6_LABEL:
- cls_rule_set_ipv6_label(rule, value->be32);
+ match_set_ipv6_label(match, value->be32);
break;
case MFF_IP_PROTO:
- cls_rule_set_nw_proto(rule, value->u8);
+ match_set_nw_proto(match, value->u8);
break;
case MFF_IP_DSCP:
- cls_rule_set_nw_dscp(rule, value->u8);
+ match_set_nw_dscp(match, value->u8);
break;
case MFF_IP_ECN:
- cls_rule_set_nw_ecn(rule, value->u8);
+ match_set_nw_ecn(match, value->u8);
break;
case MFF_IP_TTL:
- cls_rule_set_nw_ttl(rule, value->u8);
+ match_set_nw_ttl(match, value->u8);
break;
case MFF_IP_FRAG:
- cls_rule_set_nw_frag(rule, value->u8);
+ match_set_nw_frag(match, value->u8);
break;
case MFF_ARP_OP:
- cls_rule_set_nw_proto(rule, ntohs(value->be16));
+ match_set_nw_proto(match, ntohs(value->be16));
break;
case MFF_ARP_SPA:
- cls_rule_set_nw_src(rule, value->be32);
+ match_set_nw_src(match, value->be32);
break;
case MFF_ARP_TPA:
- cls_rule_set_nw_dst(rule, value->be32);
+ match_set_nw_dst(match, value->be32);
break;
case MFF_ARP_SHA:
case MFF_ND_SLL:
- cls_rule_set_arp_sha(rule, value->mac);
+ match_set_arp_sha(match, value->mac);
break;
case MFF_ARP_THA:
case MFF_ND_TLL:
- cls_rule_set_arp_tha(rule, value->mac);
+ match_set_arp_tha(match, value->mac);
break;
case MFF_TCP_SRC:
case MFF_UDP_SRC:
- cls_rule_set_tp_src(rule, value->be16);
+ match_set_tp_src(match, value->be16);
break;
case MFF_TCP_DST:
case MFF_UDP_DST:
- cls_rule_set_tp_dst(rule, value->be16);
+ match_set_tp_dst(match, value->be16);
break;
case MFF_ICMPV4_TYPE:
case MFF_ICMPV6_TYPE:
- cls_rule_set_icmp_type(rule, value->u8);
+ match_set_icmp_type(match, value->u8);
break;
case MFF_ICMPV4_CODE:
case MFF_ICMPV6_CODE:
- cls_rule_set_icmp_code(rule, value->u8);
+ match_set_icmp_code(match, value->u8);
break;
case MFF_ND_TARGET:
- cls_rule_set_nd_target(rule, &value->ipv6);
+ match_set_nd_target(match, &value->ipv6);
break;
case MFF_N_IDS:
}
}
-/* Makes 'rule' match field 'mf' exactly, with the value matched taken from
- * 'value'. The caller is responsible for ensuring that 'rule' meets 'mf''s
+/* Makes 'match' match field 'mf' exactly, with the value matched taken from
+ * 'value'. The caller is responsible for ensuring that 'match' meets 'mf''s
* prerequisites. */
void
mf_set_flow_value(const struct mf_field *mf,
return is_all_zeros((const uint8_t *) &value, mf->n_bytes);
}
-/* Makes 'rule' wildcard field 'mf'.
+/* Makes 'match' wildcard field 'mf'.
*
- * The caller is responsible for ensuring that 'rule' meets 'mf''s
+ * The caller is responsible for ensuring that 'match' meets 'mf''s
* prerequisites. */
void
-mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
+mf_set_wild(const struct mf_field *mf, struct match *match)
{
switch (mf->id) {
case MFF_TUN_ID:
- cls_rule_set_tun_id_masked(rule, htonll(0), htonll(0));
+ match_set_tun_id_masked(match, htonll(0), htonll(0));
break;
case MFF_METADATA:
- cls_rule_set_metadata_masked(rule, htonll(0), htonll(0));
+ match_set_metadata_masked(match, htonll(0), htonll(0));
case MFF_IN_PORT:
- rule->flow.in_port = 0;
- rule->wc.masks.in_port = 0;
+ match->flow.in_port = 0;
+ match->wc.masks.in_port = 0;
break;
CASE_MFF_REGS:
- cls_rule_set_reg_masked(rule, mf->id - MFF_REG0, 0, 0);
+ match_set_reg_masked(match, mf->id - MFF_REG0, 0, 0);
break;
case MFF_ETH_SRC:
- memset(rule->flow.dl_src, 0, ETH_ADDR_LEN);
- memset(rule->wc.masks.dl_src, 0, ETH_ADDR_LEN);
+ memset(match->flow.dl_src, 0, ETH_ADDR_LEN);
+ memset(match->wc.masks.dl_src, 0, ETH_ADDR_LEN);
break;
case MFF_ETH_DST:
- memset(rule->flow.dl_dst, 0, ETH_ADDR_LEN);
- memset(rule->wc.masks.dl_dst, 0, ETH_ADDR_LEN);
+ memset(match->flow.dl_dst, 0, ETH_ADDR_LEN);
+ memset(match->wc.masks.dl_dst, 0, ETH_ADDR_LEN);
break;
case MFF_ETH_TYPE:
- rule->flow.dl_type = htons(0);
- rule->wc.masks.dl_type = htons(0);
+ match->flow.dl_type = htons(0);
+ match->wc.masks.dl_type = htons(0);
break;
case MFF_VLAN_TCI:
- cls_rule_set_dl_tci_masked(rule, htons(0), htons(0));
+ match_set_dl_tci_masked(match, htons(0), htons(0));
break;
case MFF_DL_VLAN:
case MFF_VLAN_VID:
- cls_rule_set_any_vid(rule);
+ match_set_any_vid(match);
break;
case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
- cls_rule_set_any_pcp(rule);
+ match_set_any_pcp(match);
break;
case MFF_IPV4_SRC:
case MFF_ARP_SPA:
- cls_rule_set_nw_src_masked(rule, htonl(0), htonl(0));
+ match_set_nw_src_masked(match, htonl(0), htonl(0));
break;
case MFF_IPV4_DST:
case MFF_ARP_TPA:
- cls_rule_set_nw_dst_masked(rule, htonl(0), htonl(0));
+ match_set_nw_dst_masked(match, htonl(0), htonl(0));
break;
case MFF_IPV6_SRC:
- memset(&rule->wc.masks.ipv6_src, 0, sizeof rule->wc.masks.ipv6_src);
- memset(&rule->flow.ipv6_src, 0, sizeof rule->flow.ipv6_src);
+ memset(&match->wc.masks.ipv6_src, 0, sizeof match->wc.masks.ipv6_src);
+ memset(&match->flow.ipv6_src, 0, sizeof match->flow.ipv6_src);
break;
case MFF_IPV6_DST:
- memset(&rule->wc.masks.ipv6_dst, 0, sizeof rule->wc.masks.ipv6_dst);
- memset(&rule->flow.ipv6_dst, 0, sizeof rule->flow.ipv6_dst);
+ memset(&match->wc.masks.ipv6_dst, 0, sizeof match->wc.masks.ipv6_dst);
+ memset(&match->flow.ipv6_dst, 0, sizeof match->flow.ipv6_dst);
break;
case MFF_IPV6_LABEL:
- rule->wc.masks.ipv6_label = htonl(0);
- rule->flow.ipv6_label = htonl(0);
+ match->wc.masks.ipv6_label = htonl(0);
+ match->flow.ipv6_label = htonl(0);
break;
case MFF_IP_PROTO:
- rule->wc.masks.nw_proto = 0;
- rule->flow.nw_proto = 0;
+ match->wc.masks.nw_proto = 0;
+ match->flow.nw_proto = 0;
break;
case MFF_IP_DSCP:
- rule->wc.masks.nw_tos &= ~IP_DSCP_MASK;
- rule->flow.nw_tos &= ~IP_DSCP_MASK;
+ match->wc.masks.nw_tos &= ~IP_DSCP_MASK;
+ match->flow.nw_tos &= ~IP_DSCP_MASK;
break;
case MFF_IP_ECN:
- rule->wc.masks.nw_tos &= ~IP_ECN_MASK;
- rule->flow.nw_tos &= ~IP_ECN_MASK;
+ match->wc.masks.nw_tos &= ~IP_ECN_MASK;
+ match->flow.nw_tos &= ~IP_ECN_MASK;
break;
case MFF_IP_TTL:
- rule->wc.masks.nw_ttl = 0;
- rule->flow.nw_ttl = 0;
+ match->wc.masks.nw_ttl = 0;
+ match->flow.nw_ttl = 0;
break;
case MFF_IP_FRAG:
- rule->wc.masks.nw_frag |= FLOW_NW_FRAG_MASK;
- rule->flow.nw_frag &= ~FLOW_NW_FRAG_MASK;
+ match->wc.masks.nw_frag |= FLOW_NW_FRAG_MASK;
+ match->flow.nw_frag &= ~FLOW_NW_FRAG_MASK;
break;
case MFF_ARP_OP:
- rule->wc.masks.nw_proto = 0;
- rule->flow.nw_proto = 0;
+ match->wc.masks.nw_proto = 0;
+ match->flow.nw_proto = 0;
break;
case MFF_ARP_SHA:
case MFF_ND_SLL:
- memset(rule->flow.arp_sha, 0, ETH_ADDR_LEN);
- memset(rule->wc.masks.arp_sha, 0, ETH_ADDR_LEN);
+ memset(match->flow.arp_sha, 0, ETH_ADDR_LEN);
+ memset(match->wc.masks.arp_sha, 0, ETH_ADDR_LEN);
break;
case MFF_ARP_THA:
case MFF_ND_TLL:
- memset(rule->flow.arp_tha, 0, ETH_ADDR_LEN);
- memset(rule->wc.masks.arp_tha, 0, ETH_ADDR_LEN);
+ memset(match->flow.arp_tha, 0, ETH_ADDR_LEN);
+ memset(match->wc.masks.arp_tha, 0, ETH_ADDR_LEN);
break;
case MFF_TCP_SRC:
case MFF_UDP_SRC:
case MFF_ICMPV4_TYPE:
case MFF_ICMPV6_TYPE:
- rule->wc.masks.tp_src = htons(0);
- rule->flow.tp_src = htons(0);
+ match->wc.masks.tp_src = htons(0);
+ match->flow.tp_src = htons(0);
break;
case MFF_TCP_DST:
case MFF_UDP_DST:
case MFF_ICMPV4_CODE:
case MFF_ICMPV6_CODE:
- rule->wc.masks.tp_dst = htons(0);
- rule->flow.tp_dst = htons(0);
+ match->wc.masks.tp_dst = htons(0);
+ match->flow.tp_dst = htons(0);
break;
case MFF_ND_TARGET:
- memset(&rule->wc.masks.nd_target, 0, sizeof rule->wc.masks.nd_target);
- memset(&rule->flow.nd_target, 0, sizeof rule->flow.nd_target);
+ memset(&match->wc.masks.nd_target, 0,
+ sizeof match->wc.masks.nd_target);
+ memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
break;
case MFF_N_IDS:
}
}
-/* Makes 'rule' match field 'mf' with the specified 'value' and 'mask'.
+/* Makes 'match' match field 'mf' with the specified 'value' and 'mask'.
* 'value' specifies a value to match and 'mask' specifies a wildcard pattern,
* with a 1-bit indicating that the corresponding value bit must match and a
* 0-bit indicating a don't-care.
*
* If 'mask' is NULL or points to all-1-bits, then this call is equivalent to
- * mf_set_value(mf, value, rule). If 'mask' points to all-0-bits, then this
- * call is equivalent to mf_set_wild(mf, rule).
+ * mf_set_value(mf, value, match). If 'mask' points to all-0-bits, then this
+ * call is equivalent to mf_set_wild(mf, match).
*
* 'mask' must be a valid mask for 'mf' (see mf_is_mask_valid()). The caller
- * is responsible for ensuring that 'rule' meets 'mf''s prerequisites. */
+ * is responsible for ensuring that 'match' meets 'mf''s prerequisites. */
void
mf_set(const struct mf_field *mf,
const union mf_value *value, const union mf_value *mask,
- struct cls_rule *rule)
+ struct match *match)
{
if (!mask || is_all_ones((const uint8_t *) mask, mf->n_bytes)) {
- mf_set_value(mf, value, rule);
+ mf_set_value(mf, value, match);
return;
} else if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) {
- mf_set_wild(mf, rule);
+ mf_set_wild(mf, match);
return;
}
NOT_REACHED();
case MFF_TUN_ID:
- cls_rule_set_tun_id_masked(rule, value->be64, mask->be64);
+ match_set_tun_id_masked(match, value->be64, mask->be64);
break;
case MFF_METADATA:
- cls_rule_set_metadata_masked(rule, value->be64, mask->be64);
+ match_set_metadata_masked(match, value->be64, mask->be64);
break;
CASE_MFF_REGS:
- cls_rule_set_reg_masked(rule, mf->id - MFF_REG0,
- ntohl(value->be32), ntohl(mask->be32));
+ match_set_reg_masked(match, mf->id - MFF_REG0,
+ ntohl(value->be32), ntohl(mask->be32));
break;
case MFF_ETH_DST:
- cls_rule_set_dl_dst_masked(rule, value->mac, mask->mac);
+ match_set_dl_dst_masked(match, value->mac, mask->mac);
break;
case MFF_ETH_SRC:
- cls_rule_set_dl_src_masked(rule, value->mac, mask->mac);
+ match_set_dl_src_masked(match, value->mac, mask->mac);
break;
case MFF_ARP_SHA:
case MFF_ND_SLL:
- cls_rule_set_arp_sha_masked(rule, value->mac, mask->mac);
+ match_set_arp_sha_masked(match, value->mac, mask->mac);
break;
case MFF_ARP_THA:
case MFF_ND_TLL:
- cls_rule_set_arp_tha_masked(rule, value->mac, mask->mac);
+ match_set_arp_tha_masked(match, value->mac, mask->mac);
break;
case MFF_VLAN_TCI:
- cls_rule_set_dl_tci_masked(rule, value->be16, mask->be16);
+ match_set_dl_tci_masked(match, value->be16, mask->be16);
break;
case MFF_VLAN_VID:
- cls_rule_set_vlan_vid_masked(rule, value->be16, mask->be16);
+ match_set_vlan_vid_masked(match, value->be16, mask->be16);
break;
case MFF_IPV4_SRC:
- cls_rule_set_nw_src_masked(rule, value->be32, mask->be32);
+ match_set_nw_src_masked(match, value->be32, mask->be32);
break;
case MFF_IPV4_DST:
- cls_rule_set_nw_dst_masked(rule, value->be32, mask->be32);
+ match_set_nw_dst_masked(match, value->be32, mask->be32);
break;
case MFF_IPV6_SRC:
- cls_rule_set_ipv6_src_masked(rule, &value->ipv6, &mask->ipv6);
+ match_set_ipv6_src_masked(match, &value->ipv6, &mask->ipv6);
break;
case MFF_IPV6_DST:
- cls_rule_set_ipv6_dst_masked(rule, &value->ipv6, &mask->ipv6);
+ match_set_ipv6_dst_masked(match, &value->ipv6, &mask->ipv6);
break;
case MFF_IPV6_LABEL:
if ((mask->be32 & htonl(IPV6_LABEL_MASK)) == htonl(IPV6_LABEL_MASK)) {
- mf_set_value(mf, value, rule);
+ mf_set_value(mf, value, match);
} else {
- cls_rule_set_ipv6_label_masked(rule, value->be32, mask->be32);
+ match_set_ipv6_label_masked(match, value->be32, mask->be32);
}
break;
case MFF_ND_TARGET:
- cls_rule_set_nd_target_masked(rule, &value->ipv6, &mask->ipv6);
+ match_set_nd_target_masked(match, &value->ipv6, &mask->ipv6);
break;
case MFF_IP_FRAG:
- cls_rule_set_nw_frag_masked(rule, value->u8, mask->u8);
+ match_set_nw_frag_masked(match, value->u8, mask->u8);
break;
case MFF_ARP_SPA:
- cls_rule_set_nw_src_masked(rule, value->be32, mask->be32);
+ match_set_nw_src_masked(match, value->be32, mask->be32);
break;
case MFF_ARP_TPA:
- cls_rule_set_nw_dst_masked(rule, value->be32, mask->be32);
+ match_set_nw_dst_masked(match, value->be32, mask->be32);
break;
case MFF_TCP_SRC:
case MFF_UDP_SRC:
- cls_rule_set_tp_src_masked(rule, value->be16, mask->be16);
+ match_set_tp_src_masked(match, value->be16, mask->be16);
break;
case MFF_TCP_DST:
case MFF_UDP_DST:
- cls_rule_set_tp_dst_masked(rule, value->be16, mask->be16);
+ match_set_tp_dst_masked(match, value->be16, mask->be16);
break;
case MFF_N_IDS:
return error;
}
-/* Copies the value and wildcard bit pattern for 'mf' from 'rule' into the
+/* Copies the value and wildcard bit pattern for 'mf' from 'match' into the
* 'value' and 'mask', respectively. */
void
-mf_get(const struct mf_field *mf, const struct cls_rule *rule,
+mf_get(const struct mf_field *mf, const struct match *match,
union mf_value *value, union mf_value *mask)
{
- mf_get_value(mf, &rule->flow, value);
- mf_get_mask(mf, &rule->wc, mask);
+ mf_get_value(mf, &match->flow, value);
+ mf_get_mask(mf, &match->wc, mask);
}
/* Assigns a random value for field 'mf' to 'value'. */
}
}
\f
-/* Makes subfield 'sf' within 'rule' exactly match the 'sf->n_bits'
+/* Makes subfield 'sf' within 'match' exactly match the 'sf->n_bits'
* least-significant bits in 'x'.
*/
void
mf_write_subfield(const struct mf_subfield *sf, const union mf_subvalue *x,
- struct cls_rule *rule)
+ struct match *match)
{
const struct mf_field *field = sf->field;
union mf_value value, mask;
- mf_get(field, rule, &value, &mask);
+ mf_get(field, match, &value, &mask);
bitwise_copy(x, sizeof *x, 0, &value, field->n_bytes, sf->ofs, sf->n_bits);
bitwise_one ( &mask, field->n_bytes, sf->ofs, sf->n_bits);
- mf_set(field, &value, &mask, rule);
+ mf_set(field, &value, &mask, match);
}
/* Initializes 'x' to the value of 'sf' within 'flow'. 'sf' must be valid for
#include "ofp-errors.h"
#include "packets.h"
-struct cls_rule;
struct ds;
+struct match;
/* The comment on each of these indicates the member in "union mf_value" used
* to represent its value. */
/* Prerequisites. */
bool mf_are_prereqs_ok(const struct mf_field *, const struct flow *);
-void mf_force_prereqs(const struct mf_field *, struct cls_rule *);
+void mf_force_prereqs(const struct mf_field *, struct match *);
/* Field values. */
bool mf_is_value_valid(const struct mf_field *, const union mf_value *value);
void mf_get_value(const struct mf_field *, const struct flow *,
union mf_value *value);
void mf_set_value(const struct mf_field *, const union mf_value *value,
- struct cls_rule *);
+ struct match *);
void mf_set_flow_value(const struct mf_field *, const union mf_value *value,
struct flow *);
bool mf_is_zero(const struct mf_field *, const struct flow *);
-void mf_get(const struct mf_field *, const struct cls_rule *,
+void mf_get(const struct mf_field *, const struct match *,
union mf_value *value, union mf_value *mask);
void mf_set(const struct mf_field *,
const union mf_value *value, const union mf_value *mask,
- struct cls_rule *);
+ struct match *);
-void mf_set_wild(const struct mf_field *, struct cls_rule *);
+void mf_set_wild(const struct mf_field *, struct match *);
void mf_random_value(const struct mf_field *, union mf_value *value);
/* Subfields. */
void mf_write_subfield(const struct mf_subfield *, const union mf_subvalue *,
- struct cls_rule *);
+ struct match *);
void mf_read_subfield(const struct mf_subfield *, const struct flow *,
union mf_subvalue *);
static enum ofperr
nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
- uint16_t priority, struct cls_rule *rule,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
uint32_t header;
assert((cookie != NULL) == (cookie_mask != NULL));
- cls_rule_init_catchall(rule, priority);
+ match_init_catchall(match);
if (cookie) {
*cookie = *cookie_mask = htonll(0);
}
} else {
continue;
}
- } else if (!mf_are_prereqs_ok(mf, &rule->flow)) {
+ } else if (!mf_are_prereqs_ok(mf, &match->flow)) {
error = OFPERR_OFPBMC_BAD_PREREQ;
- } else if (!mf_is_all_wild(mf, &rule->wc)) {
+ } else if (!mf_is_all_wild(mf, &match->wc)) {
error = OFPERR_OFPBMC_DUP_FIELD;
} else if (header != OXM_OF_IN_PORT) {
unsigned int width = mf->n_bytes;
error = OFPERR_OFPBMC_BAD_VALUE;
} else if (!NXM_HASMASK(header)) {
error = 0;
- mf_set_value(mf, &value, rule);
+ mf_set_value(mf, &value, match);
} else {
union mf_value mask;
error = OFPERR_OFPBMC_BAD_MASK;
} else {
error = 0;
- mf_set(mf, &value, &mask, rule);
+ mf_set(mf, &value, &mask, match);
}
}
} else {
memcpy(&port_of11, p + 4, sizeof port_of11);
error = ofputil_port_from_ofp11(port_of11, &port);
if (!error) {
- cls_rule_set_in_port(rule, port);
+ match_set_in_port(match, port);
}
}
static enum ofperr
nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
- uint16_t priority, struct cls_rule *rule,
+ struct match *match,
ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
uint8_t *p = NULL;
}
}
- return nx_pull_raw(p, match_len, strict, priority, rule,
- cookie, cookie_mask);
+ return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask);
}
/* Parses the nx_match formatted match description in 'b' with length
- * 'match_len'. The results are stored in 'rule', which is initialized with
- * 'priority'. If 'cookie' and 'cookie_mask' contain valid pointers, then the
- * cookie and mask will be stored in them if a "NXM_NX_COOKIE*" match is
- * defined. Otherwise, 0 is stored in both.
+ * 'match_len'. Stores the results in 'match'. If 'cookie' and 'cookie_mask'
+ * are valid pointers, then stores the cookie and mask in them if 'b' contains
+ * a "NXM_NX_COOKIE*" match. Otherwise, stores 0 in both.
*
- * Fails with an error when encountering unknown NXM headers.
+ * Fails with an error upon encountering an unknown NXM header.
*
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-nx_pull_match(struct ofpbuf *b, unsigned int match_len,
- uint16_t priority, struct cls_rule *rule,
+nx_pull_match(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, priority, rule, cookie,
- cookie_mask);
+ return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask);
}
-/* Behaves the same as nx_pull_match() with one exception. Skips over unknown
- * NXM headers instead of failing with an error when they are encountered. */
+/* 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,
- uint16_t priority, struct cls_rule *rule,
+ struct match *match,
ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
- return nx_pull_match__(b, match_len, false, priority, rule, cookie,
- cookie_mask);
+ return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask);
}
static enum ofperr
-oxm_pull_match__(struct ofpbuf *b, bool strict,
- uint16_t priority, struct cls_rule *rule)
+oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
{
struct ofp11_match_header *omh = b->data;
uint8_t *p;
}
return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh,
- strict, priority, rule, NULL, NULL);
+ strict, match, NULL, NULL);
}
-/* Parses the oxm formatted match description preceeded by a struct
- * ofp11_match in 'b' with length 'match_len'. The results are stored in
- * 'rule', which is initialized with 'priority'.
+/* Parses the oxm formatted match description preceeded by a struct ofp11_match
+ * in 'b' with length 'match_len'. Stores the result in 'match'.
*
* Fails with an error when encountering unknown OXM headers.
*
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-oxm_pull_match(struct ofpbuf *b, uint16_t priority, struct cls_rule *rule)
+oxm_pull_match(struct ofpbuf *b, struct match *match)
{
- return oxm_pull_match__(b, true, priority, rule);
+ return oxm_pull_match__(b, true, match);
}
/* Behaves the same as oxm_pull_match() with one exception. Skips over unknown
* PXM headers instead of failing with an error when they are encountered. */
enum ofperr
-oxm_pull_match_loose(struct ofpbuf *b, uint16_t priority,
- struct cls_rule *rule)
+oxm_pull_match_loose(struct ofpbuf *b, struct match *match)
{
- return oxm_pull_match__(b, false, priority, rule);
+ return oxm_pull_match__(b, false, match);
}
\f
/* nx_put_match() and helpers.
}
static void
-nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr)
+nxm_put_frag(struct ofpbuf *b, const struct match *match)
{
- uint8_t nw_frag = cr->flow.nw_frag;
- uint8_t nw_frag_mask = cr->wc.masks.nw_frag;
+ uint8_t nw_frag = match->flow.nw_frag;
+ uint8_t nw_frag_mask = match->wc.masks.nw_frag;
switch (nw_frag_mask) {
case 0:
}
static void
-nxm_put_ip(struct ofpbuf *b, const struct cls_rule *cr,
+nxm_put_ip(struct ofpbuf *b, const struct match *match,
uint8_t icmp_proto, uint32_t icmp_type, uint32_t icmp_code,
bool oxm)
{
- const struct flow *flow = &cr->flow;
+ const struct flow *flow = &match->flow;
- nxm_put_frag(b, cr);
+ nxm_put_frag(b, match);
- if (cr->wc.masks.nw_tos & IP_DSCP_MASK) {
+ if (match->wc.masks.nw_tos & IP_DSCP_MASK) {
nxm_put_8(b, oxm ? OXM_OF_IP_DSCP : NXM_OF_IP_TOS,
flow->nw_tos & IP_DSCP_MASK);
}
- if (cr->wc.masks.nw_tos & IP_ECN_MASK) {
+ if (match->wc.masks.nw_tos & IP_ECN_MASK) {
nxm_put_8(b, oxm ? OXM_OF_IP_ECN : NXM_NX_IP_ECN,
flow->nw_tos & IP_ECN_MASK);
}
- if (!oxm && cr->wc.masks.nw_ttl) {
+ if (!oxm && match->wc.masks.nw_ttl) {
nxm_put_8(b, NXM_NX_IP_TTL, flow->nw_ttl);
}
- if (cr->wc.masks.nw_proto) {
+ if (match->wc.masks.nw_proto) {
nxm_put_8(b, oxm ? OXM_OF_IP_PROTO : NXM_OF_IP_PROTO, flow->nw_proto);
if (flow->nw_proto == IPPROTO_TCP) {
nxm_put_16m(b, oxm ? OXM_OF_TCP_SRC : NXM_OF_TCP_SRC,
- flow->tp_src, cr->wc.masks.tp_src);
+ flow->tp_src, match->wc.masks.tp_src);
nxm_put_16m(b, oxm ? OXM_OF_TCP_DST : NXM_OF_TCP_DST,
- flow->tp_dst, cr->wc.masks.tp_dst);
+ flow->tp_dst, match->wc.masks.tp_dst);
} else if (flow->nw_proto == IPPROTO_UDP) {
nxm_put_16m(b, oxm ? OXM_OF_UDP_SRC : NXM_OF_UDP_SRC,
- flow->tp_src, cr->wc.masks.tp_src);
+ flow->tp_src, match->wc.masks.tp_src);
nxm_put_16m(b, oxm ? OXM_OF_UDP_DST : NXM_OF_UDP_DST,
- flow->tp_dst, cr->wc.masks.tp_dst);
+ flow->tp_dst, match->wc.masks.tp_dst);
} else if (flow->nw_proto == icmp_proto) {
- if (cr->wc.masks.tp_src) {
+ if (match->wc.masks.tp_src) {
nxm_put_8(b, icmp_type, ntohs(flow->tp_src));
}
- if (cr->wc.masks.tp_dst) {
+ if (match->wc.masks.tp_dst) {
nxm_put_8(b, icmp_code, ntohs(flow->tp_dst));
}
}
}
}
-/* Appends to 'b' the nx_match format that expresses 'cr' (except for
- * 'cr->priority', because priority is not part of nx_match). For Flow Mod and
+/* Appends to 'b' the nx_match format that expresses 'match'. For Flow Mod and
* Flow Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied.
* Otherwise, 'cookie_mask' should be zero.
*
*
* Returns the number of bytes appended to 'b', excluding padding.
*
- * If 'cr' is a catch-all rule that matches every packet, then this function
+ * If 'match' is a catch-all rule that matches every packet, then this function
* appends nothing to 'b' and returns 0. */
static int
-nx_put_raw(struct ofpbuf *b, bool oxm, const struct cls_rule *cr,
+nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
ovs_be64 cookie, ovs_be64 cookie_mask)
{
- const struct flow *flow = &cr->flow;
+ const struct flow *flow = &match->flow;
const size_t start_len = b->size;
int match_len;
int i;
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
/* Metadata. */
- if (cr->wc.masks.in_port) {
+ if (match->wc.masks.in_port) {
uint16_t in_port = flow->in_port;
if (oxm) {
nxm_put_32(b, OXM_OF_IN_PORT, ofputil_port_to_ofp11(in_port));
/* Ethernet. */
nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_SRC : NXM_OF_ETH_SRC,
- flow->dl_src, cr->wc.masks.dl_src);
+ flow->dl_src, match->wc.masks.dl_src);
nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_DST : NXM_OF_ETH_DST,
- flow->dl_dst, cr->wc.masks.dl_dst);
+ flow->dl_dst, match->wc.masks.dl_dst);
nxm_put_16m(b, oxm ? OXM_OF_ETH_TYPE : NXM_OF_ETH_TYPE,
ofputil_dl_type_to_openflow(flow->dl_type),
- cr->wc.masks.dl_type);
+ match->wc.masks.dl_type);
/* 802.1Q. */
if (oxm) {
ovs_be16 VID_CFI_MASK = htons(VLAN_VID_MASK | VLAN_CFI);
ovs_be16 vid = flow->vlan_tci & VID_CFI_MASK;
- ovs_be16 mask = cr->wc.masks.vlan_tci & VID_CFI_MASK;
+ ovs_be16 mask = match->wc.masks.vlan_tci & VID_CFI_MASK;
if (mask == htons(VLAN_VID_MASK | VLAN_CFI)) {
nxm_put_16(b, OXM_OF_VLAN_VID, vid);
nxm_put_16m(b, OXM_OF_VLAN_VID, vid, mask);
}
- if (vid && vlan_tci_to_pcp(cr->wc.masks.vlan_tci)) {
+ if (vid && vlan_tci_to_pcp(match->wc.masks.vlan_tci)) {
nxm_put_8(b, OXM_OF_VLAN_PCP, vlan_tci_to_pcp(flow->vlan_tci));
}
} else {
- nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci, cr->wc.masks.vlan_tci);
+ nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci,
+ match->wc.masks.vlan_tci);
}
/* L3. */
if (flow->dl_type == htons(ETH_TYPE_IP)) {
/* IP. */
nxm_put_32m(b, oxm ? OXM_OF_IPV4_SRC : NXM_OF_IP_SRC,
- flow->nw_src, cr->wc.masks.nw_src);
+ flow->nw_src, match->wc.masks.nw_src);
nxm_put_32m(b, oxm ? OXM_OF_IPV4_DST : NXM_OF_IP_DST,
- flow->nw_dst, cr->wc.masks.nw_dst);
- nxm_put_ip(b, cr, IPPROTO_ICMP,
+ flow->nw_dst, match->wc.masks.nw_dst);
+ nxm_put_ip(b, match, IPPROTO_ICMP,
oxm ? OXM_OF_ICMPV4_TYPE : NXM_OF_ICMP_TYPE,
oxm ? OXM_OF_ICMPV4_CODE : NXM_OF_ICMP_CODE, oxm);
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
/* IPv6. */
nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_SRC : NXM_NX_IPV6_SRC,
- &flow->ipv6_src, &cr->wc.masks.ipv6_src);
+ &flow->ipv6_src, &match->wc.masks.ipv6_src);
nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_DST : NXM_NX_IPV6_DST,
- &flow->ipv6_dst, &cr->wc.masks.ipv6_dst);
- nxm_put_ip(b, cr, IPPROTO_ICMPV6,
+ &flow->ipv6_dst, &match->wc.masks.ipv6_dst);
+ nxm_put_ip(b, match, IPPROTO_ICMPV6,
oxm ? OXM_OF_ICMPV6_TYPE : NXM_NX_ICMPV6_TYPE,
oxm ? OXM_OF_ICMPV6_CODE : NXM_NX_ICMPV6_CODE, oxm);
nxm_put_32m(b, oxm ? OXM_OF_IPV6_FLABEL : NXM_NX_IPV6_LABEL,
- flow->ipv6_label, cr->wc.masks.ipv6_label);
+ flow->ipv6_label, match->wc.masks.ipv6_label);
if (flow->nw_proto == IPPROTO_ICMPV6
&& (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
flow->tp_src == htons(ND_NEIGHBOR_ADVERT))) {
nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_ND_TARGET : NXM_NX_ND_TARGET,
- &flow->nd_target, &cr->wc.masks.nd_target);
+ &flow->nd_target, &match->wc.masks.nd_target);
if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
nxm_put_eth_masked(b, oxm ? OXM_OF_IPV6_ND_SLL : NXM_NX_ND_SLL,
- flow->arp_sha, cr->wc.masks.arp_sha);
+ flow->arp_sha, match->wc.masks.arp_sha);
}
if (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
nxm_put_eth_masked(b, oxm ? OXM_OF_IPV6_ND_TLL : NXM_NX_ND_TLL,
- flow->arp_tha, cr->wc.masks.arp_tha);
+ flow->arp_tha, match->wc.masks.arp_tha);
}
}
} else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
/* ARP. */
- if (cr->wc.masks.nw_proto) {
+ if (match->wc.masks.nw_proto) {
nxm_put_16(b, oxm ? OXM_OF_ARP_OP : NXM_OF_ARP_OP,
htons(flow->nw_proto));
}
nxm_put_32m(b, oxm ? OXM_OF_ARP_SPA : NXM_OF_ARP_SPA,
- flow->nw_src, cr->wc.masks.nw_src);
+ flow->nw_src, match->wc.masks.nw_src);
nxm_put_32m(b, oxm ? OXM_OF_ARP_TPA : NXM_OF_ARP_TPA,
- flow->nw_dst, cr->wc.masks.nw_dst);
+ flow->nw_dst, match->wc.masks.nw_dst);
nxm_put_eth_masked(b, oxm ? OXM_OF_ARP_SHA : NXM_NX_ARP_SHA,
- flow->arp_sha, cr->wc.masks.arp_sha);
+ flow->arp_sha, match->wc.masks.arp_sha);
nxm_put_eth_masked(b, oxm ? OXM_OF_ARP_THA : NXM_NX_ARP_THA,
- flow->arp_tha, cr->wc.masks.arp_tha);
+ flow->arp_tha, match->wc.masks.arp_tha);
}
/* Tunnel ID. */
- nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.masks.tun_id);
+ nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, match->wc.masks.tun_id);
/* Registers. */
for (i = 0; i < FLOW_N_REGS; i++) {
nxm_put_32m(b, NXM_NX_REG(i),
- htonl(flow->regs[i]), htonl(cr->wc.masks.regs[i]));
+ htonl(flow->regs[i]), htonl(match->wc.masks.regs[i]));
}
/* OpenFlow 1.1+ Metadata. */
- nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, cr->wc.masks.metadata);
+ nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, match->wc.masks.metadata);
/* Cookie. */
nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
return match_len;
}
-/* Appends to 'b' the nx_match format that expresses 'cr' (except for
- * 'cr->priority', because priority is not part of nx_match), plus enough zero
+/* Appends to 'b' the nx_match format that expresses 'match', plus enough zero
* bytes to pad the nx_match out to a multiple of 8. For Flow Mod and Flow
* Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied.
* Otherwise, 'cookie_mask' should be zero.
* value can be zero if it appended nothing at all to 'b' (which happens if
* 'cr' is a catch-all rule that matches every packet). */
int
-nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
+nx_put_match(struct ofpbuf *b, const struct match *match,
ovs_be64 cookie, ovs_be64 cookie_mask)
{
- int match_len = nx_put_raw(b, false, cr, cookie, cookie_mask);
+ int match_len = nx_put_raw(b, false, match, cookie, cookie_mask);
ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len);
return match_len;
/* Appends to 'b' an struct ofp11_match_header followed by the oxm format that
- * expresses 'cr' (except for 'cr->priority', because priority is not part of
- * nx_match), plus enough zero bytes to pad the data appended out to a multiple
- * of 8.
+ * expresses 'cr', plus enough zero bytes to pad the data appended out to a
+ * multiple of 8.
*
* This function can cause 'b''s data to be reallocated.
*
* Returns the number of bytes appended to 'b', excluding the padding. Never
* returns zero. */
int
-oxm_put_match(struct ofpbuf *b, const struct cls_rule *cr)
+oxm_put_match(struct ofpbuf *b, const struct match *match)
{
int match_len;
struct ofp11_match_header *omh;
ovs_be64 cookie = htonll(0), cookie_mask = htonll(0);
ofpbuf_put_uninit(b, sizeof *omh);
- match_len = nx_put_raw(b, true, cr, cookie, cookie_mask) + sizeof *omh;
+ match_len = nx_put_raw(b, true, match, cookie, cookie_mask) + sizeof *omh;
ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len);
omh = (struct ofp11_match_header *)((char *)b->data + start_len);
#include "flow.h"
#include "ofp-errors.h"
#include "openvswitch/types.h"
-#include "ofp-errors.h"
-struct cls_rule;
struct ds;
-struct flow;
+struct match;
struct mf_subfield;
struct ofpact_reg_move;
struct ofpact_reg_load;
*/
enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len,
- uint16_t priority, struct cls_rule *,
+ struct match *,
ovs_be64 *cookie, ovs_be64 *cookie_mask);
enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len,
- uint16_t priority,
- struct cls_rule *, ovs_be64 *cookie,
+ struct match *, ovs_be64 *cookie,
ovs_be64 *cookie_mask);
-enum ofperr oxm_pull_match(struct ofpbuf *, uint16_t priority,
- struct cls_rule *);
-enum ofperr oxm_pull_match_loose(struct ofpbuf *, uint16_t priority,
- struct cls_rule *);
-int nx_put_match(struct ofpbuf *, const struct cls_rule *,
+enum ofperr oxm_pull_match(struct ofpbuf *, struct match *);
+enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *);
+int nx_put_match(struct ofpbuf *, const struct match *,
ovs_be64 cookie, ovs_be64 cookie_mask);
-int oxm_put_match(struct ofpbuf *, const struct cls_rule *);
+int oxm_put_match(struct ofpbuf *, const struct match *);
char *nx_match_to_string(const uint8_t *, unsigned int match_len);
char *oxm_match_to_string(const uint8_t *, unsigned int match_len);
}
static void
-parse_field(const struct mf_field *mf, const char *s, struct cls_rule *rule)
+parse_field(const struct mf_field *mf, const char *s, struct match *match)
{
union mf_value value, mask;
char *error;
ovs_fatal(0, "%s", error);
}
- mf_set(mf, &value, &mask, rule);
+ mf_set(mf, &value, &mask, match);
}
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
NOT_REACHED();
}
- cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
+ match_init_catchall(&fm->match);
+ fm->priority = OFP_DEFAULT_PRIORITY;
fm->cookie = htonll(0);
fm->cookie_mask = htonll(0);
if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) {
const struct protocol *p;
if (parse_protocol(name, &p)) {
- cls_rule_set_dl_type(&fm->cr, htons(p->dl_type));
+ match_set_dl_type(&fm->match, htons(p->dl_type));
if (p->nw_proto) {
- cls_rule_set_nw_proto(&fm->cr, p->nw_proto);
+ match_set_nw_proto(&fm->match, p->nw_proto);
}
} else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) {
fm->flags |= OFPFF_SEND_FLOW_REM;
} else if (!strcmp(name, "out_port")) {
fm->out_port = atoi(value);
} else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
- fm->cr.priority = str_to_u16(value, name);
+ fm->priority = str_to_u16(value, name);
} else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
fm->idle_timeout = str_to_u16(value, name);
} else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
fm->new_cookie = htonll(str_to_u64(value));
}
} else if (mf_from_name(name)) {
- parse_field(mf_from_name(name), value, &fm->cr);
+ parse_field(mf_from_name(name), value, &fm->match);
} else if (!strcmp(name, "duration")
|| !strcmp(name, "n_packets")
|| !strcmp(name, "n_bytes")) {
struct ofpbuf ofpacts;
ofpbuf_init(&ofpacts, 32);
- str_to_ofpacts(&fm->cr.flow, act_str, &ofpacts);
+ str_to_ofpacts(&fm->match.flow, act_str, &ofpacts);
fm->ofpacts_len = ofpacts.size;
fm->ofpacts = ofpbuf_steal_data(&ofpacts);
} else {
| NXFMF_OWN | NXFMF_ACTIONS);
fmr->out_port = OFPP_NONE;
fmr->table_id = 0xff;
- cls_rule_init_catchall(&fmr->match, 0);
+ match_init_catchall(&fmr->match);
for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
} else if (!strcmp(name, "!own")) {
fmr->flags &= ~NXFMF_OWN;
} else if (parse_protocol(name, &p)) {
- cls_rule_set_dl_type(&fmr->match, htons(p->dl_type));
+ match_set_dl_type(&fmr->match, htons(p->dl_type));
if (p->nw_proto) {
- cls_rule_set_nw_proto(&fmr->match, p->nw_proto);
+ match_set_nw_proto(&fmr->match, p->nw_proto);
}
} else {
char *value;
parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
uint16_t command, bool verbose)
{
- struct cls_rule rule_copy;
+ struct match match_copy;
parse_ofp_str(fm, command, string, verbose);
- /* Normalize a copy of the rule. This ensures that non-normalized flows
+ /* Normalize a copy of the match. This ensures that non-normalized flows
* get logged but doesn't affect what gets sent to the switch, so that the
* switch can do whatever it likes with the flow. */
- rule_copy = fm->cr;
- ofputil_normalize_rule(&rule_copy);
+ match_copy = fm->match;
+ ofputil_normalize_match(&match_copy);
}
void
fsr->aggregate = aggregate;
fsr->cookie = fm.cookie;
fsr->cookie_mask = fm.cookie_mask;
- fsr->match = fm.cr;
+ fsr->match = fm.match;
fsr->out_port = fm.out_port;
fsr->table_id = fm.table_id;
}
/* nx_match_to_string() doesn't print priority. */
need_priority = true;
} else {
- cls_rule_format(&fm.cr, s);
+ match_format(&fm.match, s, fm.priority);
- /* cls_rule_format() does print priority. */
+ /* match_format() does print priority. */
need_priority = false;
}
if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
ds_put_format(s, "hard:%"PRIu16" ", fm.hard_timeout);
}
- if (fm.cr.priority != OFP_DEFAULT_PRIORITY && need_priority) {
- ds_put_format(s, "pri:%"PRIu16" ", fm.cr.priority);
+ if (fm.priority != OFP_DEFAULT_PRIORITY && need_priority) {
+ ds_put_format(s, "pri:%"PRIu16" ", fm.priority);
}
if (fm.buffer_id != UINT32_MAX) {
ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
}
ds_put_char(string, ' ');
- cls_rule_format(&fr.rule, string);
+ match_format(&fr.match, string, fr.priority);
ds_put_format(string, " reason=%s",
ofp_flow_removed_reason_to_string(fr.reason));
ofputil_format_port(fsr.out_port, string);
}
- /* A flow stats request doesn't include a priority, but cls_rule_format()
- * will print one unless it is OFP_DEFAULT_PRIORITY. */
- fsr.match.priority = OFP_DEFAULT_PRIORITY;
-
ds_put_char(string, ' ');
- cls_rule_format(&fsr.match, string);
+ match_format(&fsr.match, string, OFP_DEFAULT_PRIORITY);
}
void
ds_put_format(string, "hard_age=%d, ", fs->hard_age);
}
- cls_rule_format(&fs->rule, string);
+ match_format(&fs->match, string, fs->priority);
if (string->string[string->length - 1] != ' ') {
ds_put_char(string, ' ');
}
}
ds_put_char(string, ' ');
- cls_rule_format(&request.match, string);
+ match_format(&request.match, string, OFP_DEFAULT_PRIORITY);
ds_chomp(string, ' ');
}
}
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
for (;;) {
struct ofputil_flow_update update;
- struct cls_rule match;
+ struct match match;
int retval;
update.match = &match;
ds_put_format(string, " cookie=%#"PRIx64, ntohll(update.cookie));
ds_put_char(string, ' ');
- cls_rule_format(update.match, string);
+ match_format(update.match, string, OFP_DEFAULT_PRIORITY);
if (update.ofpacts_len) {
if (string->string[string->length - 1] != ' ') {
}
/* Converts the OpenFlow 1.0 wildcards in 'ofpfw' (OFPFW10_*) into a
- * flow_wildcards in 'wc' for use in struct cls_rule. It is the caller's
+ * flow_wildcards in 'wc' for use in struct match. It is the caller's
* responsibility to handle the special case where the flow match's dl_vlan is
* set to OFP_VLAN_NONE. */
void
{
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
- /* Initialize most of rule->wc. */
+ /* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
if (!(ofpfw & OFPFW10_IN_PORT)) {
}
}
-/* Converts the ofp10_match in 'match' into a cls_rule in 'rule', with the
- * given 'priority'. */
+/* Converts the ofp10_match in 'ofmatch' into a struct match in 'match'. */
void
-ofputil_cls_rule_from_ofp10_match(const struct ofp10_match *match,
- unsigned int priority, struct cls_rule *rule)
-{
- uint32_t ofpfw = ntohl(match->wildcards) & OFPFW10_ALL;
-
- /* Initialize rule->priority, rule->wc. */
- memset(rule->flow.zeros, 0, sizeof rule->flow.zeros);
- rule->priority = !ofpfw ? UINT16_MAX : priority;
- ofputil_wildcard_from_ofpfw10(ofpfw, &rule->wc);
-
- /* Initialize most of rule->flow. */
- rule->flow.nw_src = match->nw_src;
- rule->flow.nw_dst = match->nw_dst;
- rule->flow.in_port = ntohs(match->in_port);
- rule->flow.dl_type = ofputil_dl_type_from_openflow(match->dl_type);
- rule->flow.tp_src = match->tp_src;
- rule->flow.tp_dst = match->tp_dst;
- memcpy(rule->flow.dl_src, match->dl_src, ETH_ADDR_LEN);
- memcpy(rule->flow.dl_dst, match->dl_dst, ETH_ADDR_LEN);
- rule->flow.nw_tos = match->nw_tos & IP_DSCP_MASK;
- rule->flow.nw_proto = match->nw_proto;
+ofputil_match_from_ofp10_match(const struct ofp10_match *ofmatch,
+ struct match *match)
+{
+ uint32_t ofpfw = ntohl(ofmatch->wildcards) & OFPFW10_ALL;
+
+ /* Initialize match->wc. */
+ memset(match->flow.zeros, 0, sizeof match->flow.zeros);
+ ofputil_wildcard_from_ofpfw10(ofpfw, &match->wc);
+
+ /* Initialize most of match->flow. */
+ match->flow.nw_src = ofmatch->nw_src;
+ match->flow.nw_dst = ofmatch->nw_dst;
+ match->flow.in_port = ntohs(ofmatch->in_port);
+ match->flow.dl_type = ofputil_dl_type_from_openflow(ofmatch->dl_type);
+ match->flow.tp_src = ofmatch->tp_src;
+ match->flow.tp_dst = ofmatch->tp_dst;
+ memcpy(match->flow.dl_src, ofmatch->dl_src, ETH_ADDR_LEN);
+ memcpy(match->flow.dl_dst, ofmatch->dl_dst, ETH_ADDR_LEN);
+ match->flow.nw_tos = ofmatch->nw_tos & IP_DSCP_MASK;
+ match->flow.nw_proto = ofmatch->nw_proto;
/* Translate VLANs. */
if (!(ofpfw & OFPFW10_DL_VLAN) &&
- match->dl_vlan == htons(OFP10_VLAN_NONE)) {
+ ofmatch->dl_vlan == htons(OFP10_VLAN_NONE)) {
/* Match only packets without 802.1Q header.
*
* When OFPFW10_DL_VLAN_PCP is wildcarded, this is obviously correct.
* because we can't have a specific PCP without an 802.1Q header.
* However, older versions of OVS treated this as matching packets
* withut an 802.1Q header, so we do here too. */
- rule->flow.vlan_tci = htons(0);
- rule->wc.masks.vlan_tci = htons(0xffff);
+ match->flow.vlan_tci = htons(0);
+ match->wc.masks.vlan_tci = htons(0xffff);
} else {
ovs_be16 vid, pcp, tci;
- vid = match->dl_vlan & htons(VLAN_VID_MASK);
- pcp = htons((match->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
+ vid = ofmatch->dl_vlan & htons(VLAN_VID_MASK);
+ pcp = htons((ofmatch->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
tci = vid | pcp | htons(VLAN_CFI);
- rule->flow.vlan_tci = tci & rule->wc.masks.vlan_tci;
+ match->flow.vlan_tci = tci & match->wc.masks.vlan_tci;
}
/* Clean up. */
- cls_rule_zero_wildcarded_fields(rule);
+ match_zero_wildcarded_fields(match);
}
-/* Convert 'rule' into the OpenFlow 1.0 match structure 'match'. */
+/* Convert 'match' into the OpenFlow 1.0 match structure 'ofmatch'. */
void
-ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule,
- struct ofp10_match *match)
+ofputil_match_to_ofp10_match(const struct match *match,
+ struct ofp10_match *ofmatch)
{
- const struct flow_wildcards *wc = &rule->wc;
+ const struct flow_wildcards *wc = &match->wc;
uint32_t ofpfw;
/* Figure out most OpenFlow wildcards. */
}
/* Translate VLANs. */
- match->dl_vlan = htons(0);
- match->dl_vlan_pcp = 0;
- if (rule->wc.masks.vlan_tci == htons(0)) {
+ ofmatch->dl_vlan = htons(0);
+ ofmatch->dl_vlan_pcp = 0;
+ if (match->wc.masks.vlan_tci == htons(0)) {
ofpfw |= OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP;
- } else if (rule->wc.masks.vlan_tci & htons(VLAN_CFI)
- && !(rule->flow.vlan_tci & htons(VLAN_CFI))) {
- match->dl_vlan = htons(OFP10_VLAN_NONE);
+ } else if (match->wc.masks.vlan_tci & htons(VLAN_CFI)
+ && !(match->flow.vlan_tci & htons(VLAN_CFI))) {
+ ofmatch->dl_vlan = htons(OFP10_VLAN_NONE);
ofpfw |= OFPFW10_DL_VLAN_PCP;
} else {
- if (!(rule->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
+ if (!(match->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
ofpfw |= OFPFW10_DL_VLAN;
} else {
- match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci));
+ ofmatch->dl_vlan = htons(vlan_tci_to_vid(match->flow.vlan_tci));
}
- if (!(rule->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
+ if (!(match->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
ofpfw |= OFPFW10_DL_VLAN_PCP;
} else {
- match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci);
+ ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlan_tci);
}
}
/* Compose most of the match structure. */
- match->wildcards = htonl(ofpfw);
- match->in_port = htons(rule->flow.in_port);
- memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
- memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
- match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
- match->nw_src = rule->flow.nw_src;
- match->nw_dst = rule->flow.nw_dst;
- match->nw_tos = rule->flow.nw_tos & IP_DSCP_MASK;
- match->nw_proto = rule->flow.nw_proto;
- match->tp_src = rule->flow.tp_src;
- match->tp_dst = rule->flow.tp_dst;
- memset(match->pad1, '\0', sizeof match->pad1);
- memset(match->pad2, '\0', sizeof match->pad2);
+ ofmatch->wildcards = htonl(ofpfw);
+ ofmatch->in_port = htons(match->flow.in_port);
+ memcpy(ofmatch->dl_src, match->flow.dl_src, ETH_ADDR_LEN);
+ memcpy(ofmatch->dl_dst, match->flow.dl_dst, ETH_ADDR_LEN);
+ ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type);
+ ofmatch->nw_src = match->flow.nw_src;
+ ofmatch->nw_dst = match->flow.nw_dst;
+ ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK;
+ ofmatch->nw_proto = match->flow.nw_proto;
+ ofmatch->tp_src = match->flow.tp_src;
+ ofmatch->tp_dst = match->flow.tp_dst;
+ memset(ofmatch->pad1, '\0', sizeof ofmatch->pad1);
+ memset(ofmatch->pad2, '\0', sizeof ofmatch->pad2);
}
enum ofperr
-ofputil_pull_ofp11_match(struct ofpbuf *buf, unsigned int priority,
- struct cls_rule *rule, uint16_t *padded_match_len)
+ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match,
+ uint16_t *padded_match_len)
{
struct ofp11_match_header *omh = buf->data;
uint16_t match_len;
if (padded_match_len) {
*padded_match_len = match_len;
}
- return ofputil_cls_rule_from_ofp11_match(om, priority, rule);
+ return ofputil_match_from_ofp11_match(om, match);
}
case OFPMT_OXM:
if (padded_match_len) {
*padded_match_len = ROUND_UP(match_len, 8);
}
- return oxm_pull_match(buf, priority, rule);
+ return oxm_pull_match(buf, match);
default:
return OFPERR_OFPBMC_BAD_TYPE;
}
}
-/* Converts the ofp11_match in 'match' into a cls_rule in 'rule', with the
- * given 'priority'. Returns 0 if successful, otherwise an OFPERR_* value. */
+/* Converts the ofp11_match in 'match' into a struct match in 'match. Returns
+ * 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
-ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match,
- unsigned int priority,
- struct cls_rule *rule)
+ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
+ struct match *match)
{
- uint16_t wc = ntohl(match->wildcards);
+ uint16_t wc = ntohl(ofmatch->wildcards);
uint8_t dl_src_mask[ETH_ADDR_LEN];
uint8_t dl_dst_mask[ETH_ADDR_LEN];
bool ipv4, arp;
int i;
- cls_rule_init_catchall(rule, priority);
+ match_init_catchall(match);
if (!(wc & OFPFW11_IN_PORT)) {
uint16_t ofp_port;
enum ofperr error;
- error = ofputil_port_from_ofp11(match->in_port, &ofp_port);
+ error = ofputil_port_from_ofp11(ofmatch->in_port, &ofp_port);
if (error) {
return OFPERR_OFPBMC_BAD_VALUE;
}
- cls_rule_set_in_port(rule, ofp_port);
+ match_set_in_port(match, ofp_port);
}
for (i = 0; i < ETH_ADDR_LEN; i++) {
- dl_src_mask[i] = ~match->dl_src_mask[i];
+ dl_src_mask[i] = ~ofmatch->dl_src_mask[i];
}
- cls_rule_set_dl_src_masked(rule, match->dl_src, dl_src_mask);
+ match_set_dl_src_masked(match, ofmatch->dl_src, dl_src_mask);
for (i = 0; i < ETH_ADDR_LEN; i++) {
- dl_dst_mask[i] = ~match->dl_dst_mask[i];
+ dl_dst_mask[i] = ~ofmatch->dl_dst_mask[i];
}
- cls_rule_set_dl_dst_masked(rule, match->dl_dst, dl_dst_mask);
+ match_set_dl_dst_masked(match, ofmatch->dl_dst, dl_dst_mask);
if (!(wc & OFPFW11_DL_VLAN)) {
- if (match->dl_vlan == htons(OFPVID11_NONE)) {
+ if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) {
/* Match only packets without a VLAN tag. */
- rule->flow.vlan_tci = htons(0);
- rule->wc.masks.vlan_tci = htons(UINT16_MAX);
+ match->flow.vlan_tci = htons(0);
+ match->wc.masks.vlan_tci = htons(UINT16_MAX);
} else {
- if (match->dl_vlan == htons(OFPVID11_ANY)) {
+ if (ofmatch->dl_vlan == htons(OFPVID11_ANY)) {
/* Match any packet with a VLAN tag regardless of VID. */
- rule->flow.vlan_tci = htons(VLAN_CFI);
- rule->wc.masks.vlan_tci = htons(VLAN_CFI);
- } else if (ntohs(match->dl_vlan) < 4096) {
+ match->flow.vlan_tci = htons(VLAN_CFI);
+ match->wc.masks.vlan_tci = htons(VLAN_CFI);
+ } else if (ntohs(ofmatch->dl_vlan) < 4096) {
/* Match only packets with the specified VLAN VID. */
- rule->flow.vlan_tci = htons(VLAN_CFI) | match->dl_vlan;
- rule->wc.masks.vlan_tci = htons(VLAN_CFI | VLAN_VID_MASK);
+ match->flow.vlan_tci = htons(VLAN_CFI) | ofmatch->dl_vlan;
+ match->wc.masks.vlan_tci = htons(VLAN_CFI | VLAN_VID_MASK);
} else {
/* Invalid VID. */
return OFPERR_OFPBMC_BAD_VALUE;
}
if (!(wc & OFPFW11_DL_VLAN_PCP)) {
- if (match->dl_vlan_pcp <= 7) {
- rule->flow.vlan_tci |= htons(match->dl_vlan_pcp
- << VLAN_PCP_SHIFT);
- rule->wc.masks.vlan_tci |= htons(VLAN_PCP_MASK);
+ if (ofmatch->dl_vlan_pcp <= 7) {
+ match->flow.vlan_tci |= htons(ofmatch->dl_vlan_pcp
+ << VLAN_PCP_SHIFT);
+ match->wc.masks.vlan_tci |= htons(VLAN_PCP_MASK);
} else {
/* Invalid PCP. */
return OFPERR_OFPBMC_BAD_VALUE;
}
if (!(wc & OFPFW11_DL_TYPE)) {
- cls_rule_set_dl_type(rule,
- ofputil_dl_type_from_openflow(match->dl_type));
+ match_set_dl_type(match,
+ ofputil_dl_type_from_openflow(ofmatch->dl_type));
}
- ipv4 = rule->flow.dl_type == htons(ETH_TYPE_IP);
- arp = rule->flow.dl_type == htons(ETH_TYPE_ARP);
+ ipv4 = match->flow.dl_type == htons(ETH_TYPE_IP);
+ arp = match->flow.dl_type == htons(ETH_TYPE_ARP);
if (ipv4 && !(wc & OFPFW11_NW_TOS)) {
- if (match->nw_tos & ~IP_DSCP_MASK) {
+ if (ofmatch->nw_tos & ~IP_DSCP_MASK) {
/* Invalid TOS. */
return OFPERR_OFPBMC_BAD_VALUE;
}
- cls_rule_set_nw_dscp(rule, match->nw_tos);
+ match_set_nw_dscp(match, ofmatch->nw_tos);
}
if (ipv4 || arp) {
if (!(wc & OFPFW11_NW_PROTO)) {
- cls_rule_set_nw_proto(rule, match->nw_proto);
+ match_set_nw_proto(match, ofmatch->nw_proto);
}
- cls_rule_set_nw_src_masked(rule, match->nw_src, ~match->nw_src_mask);
- cls_rule_set_nw_dst_masked(rule, match->nw_dst, ~match->nw_dst_mask);
+ match_set_nw_src_masked(match, ofmatch->nw_src, ~ofmatch->nw_src_mask);
+ match_set_nw_dst_masked(match, ofmatch->nw_dst, ~ofmatch->nw_dst_mask);
}
#define OFPFW11_TP_ALL (OFPFW11_TP_SRC | OFPFW11_TP_DST)
if (ipv4 && (wc & OFPFW11_TP_ALL) != OFPFW11_TP_ALL) {
- switch (rule->flow.nw_proto) {
+ switch (match->flow.nw_proto) {
case IPPROTO_ICMP:
/* "A.2.3 Flow Match Structures" in OF1.1 says:
*
* but I'm pretty sure we should support ICMP too, otherwise
* that's a regression from OF1.0. */
if (!(wc & OFPFW11_TP_SRC)) {
- uint16_t icmp_type = ntohs(match->tp_src);
+ uint16_t icmp_type = ntohs(ofmatch->tp_src);
if (icmp_type < 0x100) {
- cls_rule_set_icmp_type(rule, icmp_type);
+ match_set_icmp_type(match, icmp_type);
} else {
return OFPERR_OFPBMC_BAD_FIELD;
}
}
if (!(wc & OFPFW11_TP_DST)) {
- uint16_t icmp_code = ntohs(match->tp_dst);
+ uint16_t icmp_code = ntohs(ofmatch->tp_dst);
if (icmp_code < 0x100) {
- cls_rule_set_icmp_code(rule, icmp_code);
+ match_set_icmp_code(match, icmp_code);
} else {
return OFPERR_OFPBMC_BAD_FIELD;
}
case IPPROTO_TCP:
case IPPROTO_UDP:
if (!(wc & (OFPFW11_TP_SRC))) {
- cls_rule_set_tp_src(rule, match->tp_src);
+ match_set_tp_src(match, ofmatch->tp_src);
}
if (!(wc & (OFPFW11_TP_DST))) {
- cls_rule_set_tp_dst(rule, match->tp_dst);
+ match_set_tp_dst(match, ofmatch->tp_dst);
}
break;
}
}
- if (rule->flow.dl_type == htons(ETH_TYPE_MPLS) ||
- rule->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+ if (match->flow.dl_type == htons(ETH_TYPE_MPLS) ||
+ match->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC };
if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) {
}
}
- if (match->metadata_mask != htonll(UINT64_MAX)) {
- cls_rule_set_metadata_masked(rule, match->metadata,
- ~match->metadata_mask);
- }
+ match_set_metadata_masked(match, ofmatch->metadata,
+ ~ofmatch->metadata_mask);
return 0;
}
-/* Convert 'rule' into the OpenFlow 1.1 match structure 'match'. */
+/* Convert 'match' into the OpenFlow 1.1 match structure 'ofmatch'. */
void
-ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
- struct ofp11_match *match)
+ofputil_match_to_ofp11_match(const struct match *match,
+ struct ofp11_match *ofmatch)
{
uint32_t wc = 0;
int i;
- memset(match, 0, sizeof *match);
- match->omh.type = htons(OFPMT_STANDARD);
- match->omh.length = htons(OFPMT11_STANDARD_LENGTH);
+ memset(ofmatch, 0, sizeof *ofmatch);
+ ofmatch->omh.type = htons(OFPMT_STANDARD);
+ ofmatch->omh.length = htons(OFPMT11_STANDARD_LENGTH);
- if (!rule->wc.masks.in_port) {
+ if (!match->wc.masks.in_port) {
wc |= OFPFW11_IN_PORT;
} else {
- match->in_port = ofputil_port_to_ofp11(rule->flow.in_port);
+ ofmatch->in_port = ofputil_port_to_ofp11(match->flow.in_port);
}
- memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
+ memcpy(ofmatch->dl_src, match->flow.dl_src, ETH_ADDR_LEN);
for (i = 0; i < ETH_ADDR_LEN; i++) {
- match->dl_src_mask[i] = ~rule->wc.masks.dl_src[i];
+ ofmatch->dl_src_mask[i] = ~match->wc.masks.dl_src[i];
}
- memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
+ memcpy(ofmatch->dl_dst, match->flow.dl_dst, ETH_ADDR_LEN);
for (i = 0; i < ETH_ADDR_LEN; i++) {
- match->dl_dst_mask[i] = ~rule->wc.masks.dl_dst[i];
+ ofmatch->dl_dst_mask[i] = ~match->wc.masks.dl_dst[i];
}
- if (rule->wc.masks.vlan_tci == htons(0)) {
+ if (match->wc.masks.vlan_tci == htons(0)) {
wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP;
- } else if (rule->wc.masks.vlan_tci & htons(VLAN_CFI)
- && !(rule->flow.vlan_tci & htons(VLAN_CFI))) {
- match->dl_vlan = htons(OFPVID11_NONE);
+ } else if (match->wc.masks.vlan_tci & htons(VLAN_CFI)
+ && !(match->flow.vlan_tci & htons(VLAN_CFI))) {
+ ofmatch->dl_vlan = htons(OFPVID11_NONE);
wc |= OFPFW11_DL_VLAN_PCP;
} else {
- if (!(rule->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
- match->dl_vlan = htons(OFPVID11_ANY);
+ if (!(match->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
+ ofmatch->dl_vlan = htons(OFPVID11_ANY);
} else {
- match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci));
+ ofmatch->dl_vlan = htons(vlan_tci_to_vid(match->flow.vlan_tci));
}
- if (!(rule->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
+ if (!(match->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
wc |= OFPFW11_DL_VLAN_PCP;
} else {
- match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci);
+ ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlan_tci);
}
}
- if (!rule->wc.masks.dl_type) {
+ if (!match->wc.masks.dl_type) {
wc |= OFPFW11_DL_TYPE;
} else {
- match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
+ ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type);
}
- if (!(rule->wc.masks.nw_tos & IP_DSCP_MASK)) {
+ if (!(match->wc.masks.nw_tos & IP_DSCP_MASK)) {
wc |= OFPFW11_NW_TOS;
} else {
- match->nw_tos = rule->flow.nw_tos & IP_DSCP_MASK;
+ ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK;
}
- if (!rule->wc.masks.nw_proto) {
+ if (!match->wc.masks.nw_proto) {
wc |= OFPFW11_NW_PROTO;
} else {
- match->nw_proto = rule->flow.nw_proto;
+ ofmatch->nw_proto = match->flow.nw_proto;
}
- match->nw_src = rule->flow.nw_src;
- match->nw_src_mask = ~rule->wc.masks.nw_src;
- match->nw_dst = rule->flow.nw_dst;
- match->nw_dst_mask = ~rule->wc.masks.nw_dst;
+ ofmatch->nw_src = match->flow.nw_src;
+ ofmatch->nw_src_mask = ~match->wc.masks.nw_src;
+ ofmatch->nw_dst = match->flow.nw_dst;
+ ofmatch->nw_dst_mask = ~match->wc.masks.nw_dst;
- if (!rule->wc.masks.tp_src) {
+ if (!match->wc.masks.tp_src) {
wc |= OFPFW11_TP_SRC;
} else {
- match->tp_src = rule->flow.tp_src;
+ ofmatch->tp_src = match->flow.tp_src;
}
- if (!rule->wc.masks.tp_dst) {
+ if (!match->wc.masks.tp_dst) {
wc |= OFPFW11_TP_DST;
} else {
- match->tp_dst = rule->flow.tp_dst;
+ ofmatch->tp_dst = match->flow.tp_dst;
}
/* MPLS not supported. */
wc |= OFPFW11_MPLS_LABEL;
wc |= OFPFW11_MPLS_TC;
- match->metadata = rule->flow.metadata;
- match->metadata_mask = ~rule->wc.masks.metadata;
+ ofmatch->metadata = match->flow.metadata;
+ ofmatch->metadata_mask = ~match->wc.masks.metadata;
- match->wildcards = htonl(wc);
+ ofmatch->wildcards = htonl(wc);
}
/* Given a 'dl_type' value in the format used in struct flow, returns the
return true;
}
-/* Returns a bit-mask of ofputil_protocols that can be used for sending 'rule'
+/* 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
* use OpenFlow 1.0 protocol for backward compatibility. */
enum ofputil_protocol
-ofputil_usable_protocols(const struct cls_rule *rule)
+ofputil_usable_protocols(const struct match *match)
{
- const struct flow_wildcards *wc = &rule->wc;
+ const struct flow_wildcards *wc = &match->wc;
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
}
/* Only NXM supports matching IPv6 traffic. */
- if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)) {
+ if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
return OFPUTIL_P_NXM_ANY;
}
ofm = ofpbuf_pull(&b, sizeof *ofm);
- error = ofputil_pull_ofp11_match(&b, ntohs(ofm->priority), &fm->cr,
- NULL);
+ error = ofputil_pull_ofp11_match(&b, &fm->match, NULL);
if (error) {
return error;
}
}
/* Translate the message. */
+ fm->priority = ntohs(ofm->priority);
if (ofm->command == OFPFC_ADD) {
fm->cookie = htonll(0);
fm->cookie_mask = htonll(0);
if (raw == OFPRAW_OFPT10_FLOW_MOD) {
/* Standard OpenFlow 1.0 flow_mod. */
const struct ofp10_flow_mod *ofm;
- uint16_t priority;
enum ofperr error;
/* Get the ofp10_flow_mod. */
ofm = ofpbuf_pull(&b, sizeof *ofm);
- /* Set priority based on original wildcards. Normally we'd allow
- * ofputil_cls_rule_from_match() to do this for us, but
- * ofputil_normalize_rule() can put wildcards where the original
- * flow didn't have them. */
- priority = ntohs(ofm->priority);
- if (!(ofm->match.wildcards & htonl(OFPFW10_ALL))) {
- priority = UINT16_MAX;
- }
-
/* Translate the rule. */
- ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr);
- ofputil_normalize_rule(&fm->cr);
+ ofputil_match_from_ofp10_match(&ofm->match, &fm->match);
+ ofputil_normalize_match(&fm->match);
/* Now get the actions. */
error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
return error;
}
+ /* OpenFlow 1.0 says that exact-match rules have to have the
+ * highest possible priority. */
+ fm->priority = (ofm->match.wildcards & htonl(OFPFW10_ALL)
+ ? ntohs(ofm->priority)
+ : UINT16_MAX);
+
/* Translate the message. */
command = ntohs(ofm->command);
fm->cookie = htonll(0);
/* Dissect the message. */
nfm = ofpbuf_pull(&b, sizeof *nfm);
- error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
- &fm->cr, &fm->cookie, &fm->cookie_mask);
+ error = nx_pull_match(&b, ntohs(nfm->match_len),
+ &fm->match, &fm->cookie, &fm->cookie_mask);
if (error) {
return error;
}
* existing cookie. */
return OFPERR_NXBRC_NXM_INVALID;
}
+ fm->priority = ntohs(nfm->priority);
fm->new_cookie = nfm->cookie;
fm->idle_timeout = ntohs(nfm->idle_timeout);
fm->hard_timeout = ntohs(nfm->hard_timeout);
ofm->command = fm->command;
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
- ofm->priority = htons(fm->cr.priority);
+ ofm->priority = htons(fm->priority);
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = ofputil_port_to_ofp11(fm->out_port);
ofm->out_group = htonl(OFPG11_ANY);
ofm->flags = htons(fm->flags);
- oxm_put_match(msg, &fm->cr);
+ oxm_put_match(msg, &fm->match);
ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len, msg);
break;
}
msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
fm->ofpacts_len);
ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
- ofputil_cls_rule_to_ofp10_match(&fm->cr, &ofm->match);
+ ofputil_match_to_ofp10_match(&fm->match, &ofm->match);
ofm->cookie = fm->new_cookie;
ofm->command = ofputil_tid_command(fm, protocol);
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
- ofm->priority = htons(fm->cr.priority);
+ ofm->priority = htons(fm->priority);
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = htons(fm->out_port);
ofm->flags = htons(fm->flags);
nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
nfm->command = ofputil_tid_command(fm, protocol);
nfm->cookie = fm->new_cookie;
- match_len = nx_put_match(msg, &fm->cr, fm->cookie, fm->cookie_mask);
+ match_len = nx_put_match(msg, &fm->match, fm->cookie, fm->cookie_mask);
nfm = msg->l3;
nfm->idle_timeout = htons(fm->idle_timeout);
nfm->hard_timeout = htons(fm->hard_timeout);
- nfm->priority = htons(fm->cr.priority);
+ nfm->priority = htons(fm->priority);
nfm->buffer_id = htonl(fm->buffer_id);
nfm->out_port = htons(fm->out_port);
nfm->flags = htons(fm->flags);
for (i = 0; i < n_fms; i++) {
const struct ofputil_flow_mod *fm = &fms[i];
- usable_protocols &= ofputil_usable_protocols(&fm->cr);
+ usable_protocols &= ofputil_usable_protocols(&fm->match);
if (fm->table_id != 0xff) {
usable_protocols &= OFPUTIL_P_TID;
}
bool aggregate)
{
fsr->aggregate = aggregate;
- ofputil_cls_rule_from_ofp10_match(&ofsr->match, 0, &fsr->match);
+ ofputil_match_from_ofp10_match(&ofsr->match, &fsr->match);
fsr->out_port = ntohs(ofsr->out_port);
fsr->table_id = ofsr->table_id;
fsr->cookie = fsr->cookie_mask = htonll(0);
}
fsr->cookie = ofsr->cookie;
fsr->cookie_mask = ofsr->cookie_mask;
- error = ofputil_pull_ofp11_match(b, 0, &fsr->match, NULL);
+ error = ofputil_pull_ofp11_match(b, &fsr->match, NULL);
if (error) {
return error;
}
enum ofperr error;
nfsr = ofpbuf_pull(b, sizeof *nfsr);
- error = nx_pull_match(b, ntohs(nfsr->match_len), 0, &fsr->match,
+ error = nx_pull_match(b, ntohs(nfsr->match_len), &fsr->match,
&fsr->cookie, &fsr->cookie_mask);
if (error) {
return error;
: OFPRAW_OFPST10_FLOW_REQUEST);
msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
- ofputil_cls_rule_to_ofp10_match(&fsr->match, &ofsr->match);
+ ofputil_match_to_ofp10_match(&fsr->match, &ofsr->match);
ofsr->table_id = fsr->table_id;
ofsr->out_port = htons(fsr->out_port);
break;
return EINVAL;
}
- if (ofputil_pull_ofp11_match(msg, ntohs(ofs->priority), &fs->rule,
- &padded_match_len)) {
+ if (ofputil_pull_ofp11_match(msg, &fs->match, &padded_match_len)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad match");
return EINVAL;
}
return EINVAL;
}
+ fs->priority = ntohs(ofs->priority);
fs->table_id = ofs->table_id;
fs->duration_sec = ntohl(ofs->duration_sec);
fs->duration_nsec = ntohl(ofs->duration_nsec);
}
fs->cookie = get_32aligned_be64(&ofs->cookie);
- ofputil_cls_rule_from_ofp10_match(&ofs->match, ntohs(ofs->priority),
- &fs->rule);
+ ofputil_match_from_ofp10_match(&ofs->match, &fs->match);
+ fs->priority = ntohs(ofs->priority);
fs->table_id = ofs->table_id;
fs->duration_sec = ntohl(ofs->duration_sec);
fs->duration_nsec = ntohl(ofs->duration_nsec);
"claims invalid length %zu", match_len, length);
return EINVAL;
}
- if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule,
- NULL, NULL)) {
+ if (nx_pull_match(msg, match_len, &fs->match, NULL, NULL)) {
return EINVAL;
}
fs->table_id = nfs->table_id;
fs->duration_sec = ntohl(nfs->duration_sec);
fs->duration_nsec = ntohl(nfs->duration_nsec);
+ fs->priority = ntohs(nfs->priority);
fs->idle_timeout = ntohs(nfs->idle_timeout);
fs->hard_timeout = ntohs(nfs->hard_timeout);
fs->idle_age = -1;
struct ofp11_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
- oxm_put_match(reply, &fs->rule);
+ oxm_put_match(reply, &fs->match);
ofpacts_put_openflow11_instructions(fs->ofpacts, fs->ofpacts_len,
reply);
ofs->pad = 0;
ofs->duration_sec = htonl(fs->duration_sec);
ofs->duration_nsec = htonl(fs->duration_nsec);
- ofs->priority = htons(fs->rule.priority);
+ ofs->priority = htons(fs->priority);
ofs->idle_timeout = htons(fs->idle_timeout);
ofs->hard_timeout = htons(fs->hard_timeout);
memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->length = htons(reply->size - start_ofs);
ofs->table_id = fs->table_id;
ofs->pad = 0;
- ofputil_cls_rule_to_ofp10_match(&fs->rule, &ofs->match);
+ ofputil_match_to_ofp10_match(&fs->match, &ofs->match);
ofs->duration_sec = htonl(fs->duration_sec);
ofs->duration_nsec = htonl(fs->duration_nsec);
- ofs->priority = htons(fs->rule.priority);
+ ofs->priority = htons(fs->priority);
ofs->idle_timeout = htons(fs->idle_timeout);
ofs->hard_timeout = htons(fs->hard_timeout);
memset(ofs->pad2, 0, sizeof ofs->pad2);
int match_len;
ofpbuf_put_uninit(reply, sizeof *nfs);
- match_len = nx_put_match(reply, &fs->rule, 0, 0);
+ match_len = nx_put_match(reply, &fs->match, 0, 0);
ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
nfs->pad = 0;
nfs->duration_sec = htonl(fs->duration_sec);
nfs->duration_nsec = htonl(fs->duration_nsec);
- nfs->priority = htons(fs->rule.priority);
+ nfs->priority = htons(fs->priority);
nfs->idle_timeout = htons(fs->idle_timeout);
nfs->hard_timeout = htons(fs->hard_timeout);
nfs->idle_age = htons(fs->idle_age < 0 ? 0
ofr = ofpbuf_pull(&b, sizeof *ofr);
- error = ofputil_pull_ofp11_match(&b, ntohs(ofr->priority),
- &fr->rule, NULL);
+ error = ofputil_pull_ofp11_match(&b, &fr->match, NULL);
if (error) {
return error;
}
+ fr->priority = ntohs(ofr->priority);
fr->cookie = ofr->cookie;
fr->reason = ofr->reason;
/* XXX: ofr->table_id is ignored */
ofr = ofpbuf_pull(&b, sizeof *ofr);
- ofputil_cls_rule_from_ofp10_match(&ofr->match, ntohs(ofr->priority),
- &fr->rule);
+ ofputil_match_from_ofp10_match(&ofr->match, &fr->match);
+ fr->priority = ntohs(ofr->priority);
fr->cookie = ofr->cookie;
fr->reason = ofr->reason;
fr->duration_sec = ntohl(ofr->duration_sec);
int error;
nfr = ofpbuf_pull(&b, sizeof *nfr);
- error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority),
- &fr->rule, NULL, NULL);
+ error = nx_pull_match(&b, ntohs(nfr->match_len), &fr->match,
+ NULL, NULL);
if (error) {
return error;
}
return OFPERR_OFPBRC_BAD_LEN;
}
+ fr->priority = ntohs(nfr->priority);
fr->cookie = nfr->cookie;
fr->reason = nfr->reason;
fr->duration_sec = ntohl(nfr->duration_sec);
htonl(0), NXM_TYPICAL_LEN);
ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
ofr->cookie = fr->cookie;
- ofr->priority = htons(fr->rule.priority);
+ ofr->priority = htons(fr->priority);
ofr->reason = fr->reason;
ofr->table_id = 0;
ofr->duration_sec = htonl(fr->duration_sec);
ofr->hard_timeout = htons(fr->hard_timeout);
ofr->packet_count = htonll(fr->packet_count);
ofr->byte_count = htonll(fr->byte_count);
- oxm_put_match(msg, &fr->rule);
+ oxm_put_match(msg, &fr->match);
break;
}
msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
htonl(0), 0);
ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
- ofputil_cls_rule_to_ofp10_match(&fr->rule, &ofr->match);
+ ofputil_match_to_ofp10_match(&fr->match, &ofr->match);
ofr->cookie = fr->cookie;
- ofr->priority = htons(fr->rule.priority);
+ ofr->priority = htons(fr->priority);
ofr->reason = fr->reason;
ofr->duration_sec = htonl(fr->duration_sec);
ofr->duration_nsec = htonl(fr->duration_nsec);
msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_REMOVED, OFP10_VERSION,
htonl(0), NXM_TYPICAL_LEN);
nfr = ofpbuf_put_zeros(msg, sizeof *nfr);
- match_len = nx_put_match(msg, &fr->rule, 0, 0);
+ match_len = nx_put_match(msg, &fr->match, 0, 0);
nfr = msg->l3;
nfr->cookie = fr->cookie;
- nfr->priority = htons(fr->rule.priority);
+ nfr->priority = htons(fr->priority);
nfr->reason = fr->reason;
nfr->duration_sec = htonl(fr->duration_sec);
nfr->duration_nsec = htonl(fr->duration_nsec);
static void
ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin,
- struct cls_rule *rule,
- struct ofpbuf *b)
+ struct match *match, struct ofpbuf *b)
{
pin->packet = b->data;
pin->packet_len = b->size;
- pin->fmd.in_port = rule->flow.in_port;
- pin->fmd.tun_id = rule->flow.tun_id;
- pin->fmd.metadata = rule->flow.metadata;
- memcpy(pin->fmd.regs, rule->flow.regs, sizeof pin->fmd.regs);
+ pin->fmd.in_port = match->flow.in_port;
+ pin->fmd.tun_id = match->flow.tun_id;
+ pin->fmd.metadata = match->flow.metadata;
+ memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs);
}
enum ofperr
raw = ofpraw_pull_assert(&b);
if (raw == OFPRAW_OFPT12_PACKET_IN) {
const struct ofp12_packet_in *opi;
- struct cls_rule rule;
+ struct match match;
int error;
opi = ofpbuf_pull(&b, sizeof *opi);
- error = oxm_pull_match_loose(&b, 0, &rule);
+ error = oxm_pull_match_loose(&b, &match);
if (error) {
return error;
}
pin->buffer_id = ntohl(opi->buffer_id);
pin->total_len = ntohs(opi->total_len);
- ofputil_decode_packet_in_finish(pin, &rule, &b);
+ ofputil_decode_packet_in_finish(pin, &match, &b);
} else if (raw == OFPRAW_OFPT10_PACKET_IN) {
const struct ofp_packet_in *opi;
pin->total_len = ntohs(opi->total_len);
} else if (raw == OFPRAW_NXT_PACKET_IN) {
const struct nx_packet_in *npi;
- struct cls_rule rule;
+ struct match match;
int error;
npi = ofpbuf_pull(&b, sizeof *npi);
- error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL,
+ error = nx_pull_match_loose(&b, ntohs(npi->match_len), &match, NULL,
NULL);
if (error) {
return error;
pin->buffer_id = ntohl(npi->buffer_id);
pin->total_len = ntohs(npi->total_len);
- ofputil_decode_packet_in_finish(pin, &rule, &b);
+ ofputil_decode_packet_in_finish(pin, &match, &b);
} else {
NOT_REACHED();
}
}
static void
-ofputil_packet_in_to_rule(const struct ofputil_packet_in *pin,
- struct cls_rule *rule)
+ofputil_packet_in_to_match(const struct ofputil_packet_in *pin,
+ struct match *match)
{
int i;
- cls_rule_init_catchall(rule, 0);
+ match_init_catchall(match);
if (pin->fmd.tun_id != htonll(0)) {
- cls_rule_set_tun_id(rule, pin->fmd.tun_id);
+ match_set_tun_id(match, pin->fmd.tun_id);
}
if (pin->fmd.metadata != htonll(0)) {
- cls_rule_set_metadata(rule, pin->fmd.metadata);
+ match_set_metadata(match, pin->fmd.metadata);
}
for (i = 0; i < FLOW_N_REGS; i++) {
if (pin->fmd.regs[i]) {
- cls_rule_set_reg(rule, i, pin->fmd.regs[i]);
+ match_set_reg(match, i, pin->fmd.regs[i]);
}
}
- cls_rule_set_in_port(rule, pin->fmd.in_port);
+ match_set_in_port(match, pin->fmd.in_port);
}
/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message
/* Add OFPT_PACKET_IN. */
if (protocol == OFPUTIL_P_OF12) {
struct ofp12_packet_in *opi;
- struct cls_rule rule;
+ struct match match;
- ofputil_packet_in_to_rule(pin, &rule);
+ ofputil_packet_in_to_match(pin, &match);
/* The final argument is just an estimate of the space required. */
packet = ofpraw_alloc_xid(OFPRAW_OFPT12_PACKET_IN, OFP12_VERSION,
htonl(0), (sizeof(struct flow_metadata) * 2
+ 2 + send_len));
ofpbuf_put_zeros(packet, sizeof *opi);
- oxm_put_match(packet, &rule);
+ oxm_put_match(packet, &match);
ofpbuf_put_zeros(packet, 2);
ofpbuf_put(packet, pin->packet, send_len);
ofpbuf_put(packet, pin->packet, send_len);
} else if (packet_in_format == NXPIF_NXM) {
struct nx_packet_in *npi;
- struct cls_rule rule;
+ struct match match;
size_t match_len;
- ofputil_packet_in_to_rule(pin, &rule);
+ ofputil_packet_in_to_match(pin, &match);
/* The final argument is just an estimate of the space required. */
packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
htonl(0), (sizeof(struct flow_metadata) * 2
+ 2 + send_len));
ofpbuf_put_zeros(packet, sizeof *npi);
- match_len = nx_put_match(packet, &rule, 0, 0);
+ match_len = nx_put_match(packet, &match, 0, 0);
ofpbuf_put_zeros(packet, 2);
ofpbuf_put(packet, pin->packet, send_len);
rq->out_port = ntohs(nfmr->out_port);
rq->table_id = nfmr->table_id;
- return nx_pull_match(msg, ntohs(nfmr->match_len), OFP_DEFAULT_PRIORITY,
- &rq->match, NULL, NULL);
+ return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL, NULL);
}
void
/* Converts an NXST_FLOW_MONITOR reply (also known as a flow update) in 'msg'
* into an abstract ofputil_flow_update in 'update'. The caller must have
- * initialized update->match to point to space allocated for a cls_rule.
+ * initialized update->match to point to space allocated for a match.
*
* Uses 'ofpacts' to store the abstract OFPACT_* version of the update's
* actions (except for NXFME_ABBREV, which never includes actions). The caller
update->hard_timeout = ntohs(nfuf->hard_timeout);
update->table_id = nfuf->table_id;
update->cookie = nfuf->cookie;
+ update->priority = ntohs(nfuf->priority);
- error = nx_pull_match(msg, match_len, ntohs(nfuf->priority),
- update->match, NULL, NULL);
+ error = nx_pull_match(msg, match_len, update->match, NULL, NULL);
if (error) {
return error;
}
nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf);
nfuf->reason = htons(update->reason);
- nfuf->priority = htons(update->match->priority);
+ nfuf->priority = htons(update->priority);
nfuf->idle_timeout = htons(update->idle_timeout);
nfuf->hard_timeout = htons(update->hard_timeout);
nfuf->match_len = htons(match_len);
#include "ofp-util.def"
static void
-ofputil_normalize_rule__(struct cls_rule *rule, bool may_log)
+ofputil_normalize_match__(struct match *match, bool may_log)
{
enum {
MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */
struct flow_wildcards wc;
/* Figure out what fields may be matched. */
- if (rule->flow.dl_type == htons(ETH_TYPE_IP)) {
+ if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
may_match = MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR;
- if (rule->flow.nw_proto == IPPROTO_TCP ||
- rule->flow.nw_proto == IPPROTO_UDP ||
- rule->flow.nw_proto == IPPROTO_ICMP) {
+ if (match->flow.nw_proto == IPPROTO_TCP ||
+ match->flow.nw_proto == IPPROTO_UDP ||
+ match->flow.nw_proto == IPPROTO_ICMP) {
may_match |= MAY_TP_ADDR;
}
- } else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)) {
+ } else if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
- if (rule->flow.nw_proto == IPPROTO_TCP ||
- rule->flow.nw_proto == IPPROTO_UDP) {
+ if (match->flow.nw_proto == IPPROTO_TCP ||
+ match->flow.nw_proto == IPPROTO_UDP) {
may_match |= MAY_TP_ADDR;
- } else if (rule->flow.nw_proto == IPPROTO_ICMPV6) {
+ } else if (match->flow.nw_proto == IPPROTO_ICMPV6) {
may_match |= MAY_TP_ADDR;
- if (rule->flow.tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
+ if (match->flow.tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
may_match |= MAY_ND_TARGET | MAY_ARP_SHA;
- } else if (rule->flow.tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+ } else if (match->flow.tp_src == htons(ND_NEIGHBOR_ADVERT)) {
may_match |= MAY_ND_TARGET | MAY_ARP_THA;
}
}
- } else if (rule->flow.dl_type == htons(ETH_TYPE_ARP)) {
+ } else if (match->flow.dl_type == htons(ETH_TYPE_ARP)) {
may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
} else {
may_match = 0;
}
/* Clear the fields that may not be matched. */
- wc = rule->wc;
+ wc = match->wc;
if (!(may_match & MAY_NW_ADDR)) {
wc.masks.nw_src = wc.masks.nw_dst = htonl(0);
}
}
/* Log any changes. */
- if (!flow_wildcards_equal(&wc, &rule->wc)) {
+ if (!flow_wildcards_equal(&wc, &match->wc)) {
bool log = may_log && !VLOG_DROP_INFO(&bad_ofmsg_rl);
- char *pre = log ? cls_rule_to_string(rule) : NULL;
+ char *pre = log ? match_to_string(match, OFP_DEFAULT_PRIORITY) : NULL;
- rule->wc = wc;
- cls_rule_zero_wildcarded_fields(rule);
+ match->wc = wc;
+ match_zero_wildcarded_fields(match);
if (log) {
- char *post = cls_rule_to_string(rule);
+ char *post = match_to_string(match, OFP_DEFAULT_PRIORITY);
VLOG_INFO("normalization changed ofp_match, details:");
VLOG_INFO(" pre: %s", pre);
VLOG_INFO("post: %s", post);
}
}
-/* "Normalizes" the wildcards in 'rule'. That means:
+/* "Normalizes" the wildcards in 'match'. That means:
*
* 1. If the type of level N is known, then only the valid fields for that
* level may be specified. For example, ARP does not have a TOS field,
- * so nw_tos must be wildcarded if 'rule' specifies an ARP flow.
+ * so nw_tos must be wildcarded if 'match' specifies an ARP flow.
* Similarly, IPv4 does not have any IPv6 addresses, so ipv6_src and
- * ipv6_dst (and other fields) must be wildcarded if 'rule' specifies an
+ * ipv6_dst (and other fields) must be wildcarded if 'match' specifies an
* IPv4 flow.
*
* 2. If the type of level N is not known (or not understood by Open
* vSwitch), then no fields at all for that level may be specified. For
* example, Open vSwitch does not understand SCTP, an L4 protocol, so the
- * L4 fields tp_src and tp_dst must be wildcarded if 'rule' specifies an
+ * L4 fields tp_src and tp_dst must be wildcarded if 'match' specifies an
* SCTP flow.
*
- * If this function changes 'rule', it logs a rate-limited informational
+ * If this function changes 'match', it logs a rate-limited informational
* message. */
void
-ofputil_normalize_rule(struct cls_rule *rule)
+ofputil_normalize_match(struct match *match)
{
- ofputil_normalize_rule__(rule, true);
+ ofputil_normalize_match__(match, true);
}
-/* Same as ofputil_normalize_rule() without the logging. Thus, this function
- * is suitable for a program's internal use, whereas ofputil_normalize_rule()
+/* Same as ofputil_normalize_match() without the logging. Thus, this function
+ * is suitable for a program's internal use, whereas ofputil_normalize_match()
* sense for use on flows received from elsewhere (so that a bug in the program
* that sent them can be reported and corrected). */
void
-ofputil_normalize_rule_quiet(struct cls_rule *rule)
+ofputil_normalize_match_quiet(struct match *match)
{
- ofputil_normalize_rule__(rule, false);
+ ofputil_normalize_match__(match, false);
}
/* Parses a key or a key-value pair from '*stringp'.
#include "classifier.h"
#include "compiler.h"
#include "flow.h"
+#include "match.h"
#include "netdev.h"
#include "openflow/nicira-ext.h"
#include "openvswitch/types.h"
-struct cls_rule;
struct ofpbuf;
/* Port numbers. */
const char *ofputil_protocol_to_string(enum ofputil_protocol);
char *ofputil_protocols_to_string(enum ofputil_protocol);
enum ofputil_protocol ofputil_protocols_from_string(const char *);
-enum ofputil_protocol ofputil_usable_protocols(const struct cls_rule *);
+enum ofputil_protocol ofputil_usable_protocols(const struct match *);
struct ofpbuf *ofputil_encode_set_protocol(enum ofputil_protocol current,
enum ofputil_protocol want,
/* Work with ofp10_match. */
void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *);
-void ofputil_cls_rule_from_ofp10_match(const struct ofp10_match *,
- unsigned int priority,
- struct cls_rule *);
-void ofputil_normalize_rule(struct cls_rule *);
-void ofputil_normalize_rule_quiet(struct cls_rule *);
-void ofputil_cls_rule_to_ofp10_match(const struct cls_rule *,
- struct ofp10_match *);
+void ofputil_match_from_ofp10_match(const struct ofp10_match *,
+ struct match *);
+void ofputil_normalize_match(struct match *);
+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 *, unsigned int priority,
- struct cls_rule *,
+enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *, struct match *,
uint16_t *padded_match_len);
-enum ofperr ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *,
- unsigned int priority,
- struct cls_rule *);
-void ofputil_cls_rule_to_ofp11_match(const struct cls_rule *,
- struct ofp11_match *);
+enum ofperr ofputil_match_from_ofp11_match(const struct ofp11_match *,
+ struct match *);
+void ofputil_match_to_ofp11_match(const struct match *, struct ofp11_match *);
/* dl_type translation between OpenFlow and 'struct flow' format. */
ovs_be16 ofputil_dl_type_to_openflow(ovs_be16 flow_dl_type);
* NXM Delete <used> <used> -
*/
struct ofputil_flow_mod {
- struct cls_rule cr;
+ struct match match;
+ unsigned int priority;
ovs_be64 cookie; /* Cookie bits to match. */
ovs_be64 cookie_mask; /* 1-bit in each 'cookie' bit to match. */
ovs_be64 new_cookie; /* New cookie to install or -1. */
/* Flow stats or aggregate stats request, independent of protocol. */
struct ofputil_flow_stats_request {
bool aggregate; /* Aggregate results? */
- struct cls_rule match;
+ struct match match;
ovs_be64 cookie;
ovs_be64 cookie_mask;
uint16_t out_port;
/* Flow stats reply, independent of protocol. */
struct ofputil_flow_stats {
- struct cls_rule rule;
+ struct match match;
ovs_be64 cookie;
uint8_t table_id;
uint32_t duration_sec;
uint32_t duration_nsec;
+ uint16_t priority;
uint16_t idle_timeout;
uint16_t hard_timeout;
int idle_age; /* Seconds since last packet, -1 if unknown. */
/* Flow removed message, independent of protocol. */
struct ofputil_flow_removed {
- struct cls_rule rule;
+ struct match match;
+ uint16_t priority;
ovs_be64 cookie;
uint8_t reason; /* One of OFPRR_*. */
uint32_t duration_sec;
enum nx_flow_monitor_flags flags;
uint16_t out_port;
uint8_t table_id;
- struct cls_rule match;
+ struct match match;
};
int ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *,
uint16_t hard_timeout;
uint8_t table_id;
ovs_be64 cookie;
- struct cls_rule *match;
+ struct match *match;
+ uint16_t priority;
struct ofpact *ofpacts;
size_t ofpacts_len;
if (!connmgr_has_controllers(mgr)
&& mgr->fail_mode == OFPROTO_FAIL_STANDALONE) {
struct ofpbuf ofpacts;
- struct cls_rule rule;
+ struct match match;
ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE);
ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL;
ofpact_pad(&ofpacts);
- cls_rule_init_catchall(&rule, 0);
- ofproto_add_flow(mgr->ofproto, &rule, ofpacts.data, ofpacts.size);
+ match_init_catchall(&match);
+ ofproto_add_flow(mgr->ofproto, &match, 0, ofpacts.data, ofpacts.size);
ofpbuf_uninit(&ofpacts);
}
fu.hard_timeout = rule->hard_timeout;
fu.table_id = rule->table_id;
fu.cookie = rule->flow_cookie;
- fu.match = &rule->cr;
+ fu.match = &rule->cr.match;
if (flags & NXFMF_ACTIONS) {
fu.ofpacts = rule->ofpacts;
fu.ofpacts_len = rule->ofpacts_len;
#include "classifier.h"
#include "hmap.h"
#include "list.h"
+#include "match.h"
#include "ofp-errors.h"
#include "ofproto.h"
#include "openflow/nicira-ext.h"
/* Matching. */
uint16_t out_port;
uint8_t table_id;
- struct cls_rule match;
+ struct match match;
};
struct ofputil_flow_monitor_request;
static void
fail_open_recover(struct fail_open *fo)
{
- struct cls_rule rule;
+ struct match match;
VLOG_WARN("No longer in fail-open mode");
fo->last_disconn_secs = 0;
fo->next_bogus_packet_in = LLONG_MAX;
- cls_rule_init_catchall(&rule, FAIL_OPEN_PRIORITY);
- ofproto_delete_flow(fo->ofproto, &rule);
+ match_init_catchall(&match);
+ ofproto_delete_flow(fo->ofproto, &match, FAIL_OPEN_PRIORITY);
}
void
bool open = disconn_secs >= trigger_duration(fo);
if (open) {
struct ofpbuf ofpacts;
- struct cls_rule rule;
+ struct match match;
/* Set up a flow that matches every packet and directs them to
* OFPP_NORMAL. */
ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL;
ofpact_pad(&ofpacts);
- cls_rule_init_catchall(&rule, FAIL_OPEN_PRIORITY);
- ofproto_add_flow(fo->ofproto, &rule, ofpacts.data, ofpacts.size);
+ match_init_catchall(&match);
+ ofproto_add_flow(fo->ofproto, &match, FAIL_OPEN_PRIORITY,
+ ofpacts.data, ofpacts.size);
ofpbuf_uninit(&ofpacts);
}
/* A rule to add to or delete from ofproto's flow table. */
struct in_band_rule {
- struct cls_rule cls_rule;
+ struct hmap_node hmap_node; /* In struct in_band's "rules" hmap. */
+ struct match match;
+ unsigned int priority;
enum in_band_op op;
};
}
static void
-add_rule(struct in_band *ib, const struct cls_rule *cls_rule)
+add_rule(struct in_band *ib, const struct match *match, unsigned int priority)
{
- uint32_t hash = cls_rule_hash(cls_rule, 0);
+ uint32_t hash = match_hash(match, 0);
struct in_band_rule *rule;
- HMAP_FOR_EACH_WITH_HASH (rule, cls_rule.hmap_node, hash, &ib->rules) {
- if (cls_rule_equal(&rule->cls_rule, cls_rule)) {
+ HMAP_FOR_EACH_WITH_HASH (rule, hmap_node, hash, &ib->rules) {
+ if (match_equal(&rule->match, match)) {
rule->op = ADD;
return;
}
}
rule = xmalloc(sizeof *rule);
- rule->cls_rule = *cls_rule;
+ rule->match = *match;
+ rule->priority = priority;
rule->op = ADD;
- hmap_insert(&ib->rules, &rule->cls_rule.hmap_node, hash);
+ hmap_insert(&ib->rules, &rule->hmap_node, hash);
}
static void
{
struct in_band_rule *ib_rule;
struct in_band_remote *r;
- struct cls_rule rule;
+ struct match match;
/* Mark all the existing rules for deletion. (Afterward we will re-add any
* rules that are still valid.) */
- HMAP_FOR_EACH (ib_rule, cls_rule.hmap_node, &ib->rules) {
+ HMAP_FOR_EACH (ib_rule, hmap_node, &ib->rules) {
ib_rule->op = DELETE;
}
if (ib->n_remotes && !eth_addr_is_zero(ib->local_mac)) {
/* (a) Allow DHCP requests sent from the local port. */
- cls_rule_init_catchall(&rule, IBR_FROM_LOCAL_DHCP);
- cls_rule_set_in_port(&rule, OFPP_LOCAL);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_IP));
- cls_rule_set_dl_src(&rule, ib->local_mac);
- cls_rule_set_nw_proto(&rule, IPPROTO_UDP);
- cls_rule_set_tp_src(&rule, htons(DHCP_CLIENT_PORT));
- cls_rule_set_tp_dst(&rule, htons(DHCP_SERVER_PORT));
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_in_port(&match, OFPP_LOCAL);
+ match_set_dl_type(&match, htons(ETH_TYPE_IP));
+ match_set_dl_src(&match, ib->local_mac);
+ match_set_nw_proto(&match, IPPROTO_UDP);
+ match_set_tp_src(&match, htons(DHCP_CLIENT_PORT));
+ match_set_tp_dst(&match, htons(DHCP_SERVER_PORT));
+ add_rule(ib, &match, IBR_FROM_LOCAL_DHCP);
/* (b) Allow ARP replies to the local port's MAC address. */
- cls_rule_init_catchall(&rule, IBR_TO_LOCAL_ARP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_ARP));
- cls_rule_set_dl_dst(&rule, ib->local_mac);
- cls_rule_set_nw_proto(&rule, ARP_OP_REPLY);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_ARP));
+ match_set_dl_dst(&match, ib->local_mac);
+ match_set_nw_proto(&match, ARP_OP_REPLY);
+ add_rule(ib, &match, IBR_TO_LOCAL_ARP);
/* (c) Allow ARP requests from the local port's MAC address. */
- cls_rule_init_catchall(&rule, IBR_FROM_LOCAL_ARP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_ARP));
- cls_rule_set_dl_src(&rule, ib->local_mac);
- cls_rule_set_nw_proto(&rule, ARP_OP_REQUEST);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_ARP));
+ match_set_dl_src(&match, ib->local_mac);
+ match_set_nw_proto(&match, ARP_OP_REQUEST);
+ add_rule(ib, &match, IBR_FROM_LOCAL_ARP);
}
for (r = ib->remotes; r < &ib->remotes[ib->n_remotes]; r++) {
}
/* (d) Allow ARP replies to the next hop's MAC address. */
- cls_rule_init_catchall(&rule, IBR_TO_NEXT_HOP_ARP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_ARP));
- cls_rule_set_dl_dst(&rule, remote_mac);
- cls_rule_set_nw_proto(&rule, ARP_OP_REPLY);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_ARP));
+ match_set_dl_dst(&match, remote_mac);
+ match_set_nw_proto(&match, ARP_OP_REPLY);
+ add_rule(ib, &match, IBR_TO_NEXT_HOP_ARP);
/* (e) Allow ARP requests from the next hop's MAC address. */
- cls_rule_init_catchall(&rule, IBR_FROM_NEXT_HOP_ARP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_ARP));
- cls_rule_set_dl_src(&rule, remote_mac);
- cls_rule_set_nw_proto(&rule, ARP_OP_REQUEST);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_ARP));
+ match_set_dl_src(&match, remote_mac);
+ match_set_nw_proto(&match, ARP_OP_REQUEST);
+ add_rule(ib, &match, IBR_FROM_NEXT_HOP_ARP);
}
for (r = ib->remotes; r < &ib->remotes[ib->n_remotes]; r++) {
/* (f) Allow ARP replies containing the remote's IP address as a
* target. */
- cls_rule_init_catchall(&rule, IBR_TO_REMOTE_ARP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_ARP));
- cls_rule_set_nw_proto(&rule, ARP_OP_REPLY);
- cls_rule_set_nw_dst(&rule, a->sin_addr.s_addr);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_ARP));
+ match_set_nw_proto(&match, ARP_OP_REPLY);
+ match_set_nw_dst(&match, a->sin_addr.s_addr);
+ add_rule(ib, &match, IBR_TO_REMOTE_ARP);
/* (g) Allow ARP requests containing the remote's IP address as a
* source. */
- cls_rule_init_catchall(&rule, IBR_FROM_REMOTE_ARP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_ARP));
- cls_rule_set_nw_proto(&rule, ARP_OP_REQUEST);
- cls_rule_set_nw_src(&rule, a->sin_addr.s_addr);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_ARP));
+ match_set_nw_proto(&match, ARP_OP_REQUEST);
+ match_set_nw_src(&match, a->sin_addr.s_addr);
+ add_rule(ib, &match, IBR_FROM_REMOTE_ARP);
/* (h) Allow TCP traffic to the remote's IP and port. */
- cls_rule_init_catchall(&rule, IBR_TO_REMOTE_TCP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_IP));
- cls_rule_set_nw_proto(&rule, IPPROTO_TCP);
- cls_rule_set_nw_dst(&rule, a->sin_addr.s_addr);
- cls_rule_set_tp_dst(&rule, a->sin_port);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_IP));
+ match_set_nw_proto(&match, IPPROTO_TCP);
+ match_set_nw_dst(&match, a->sin_addr.s_addr);
+ match_set_tp_dst(&match, a->sin_port);
+ add_rule(ib, &match, IBR_TO_REMOTE_TCP);
/* (i) Allow TCP traffic from the remote's IP and port. */
- cls_rule_init_catchall(&rule, IBR_FROM_REMOTE_TCP);
- cls_rule_set_dl_type(&rule, htons(ETH_TYPE_IP));
- cls_rule_set_nw_proto(&rule, IPPROTO_TCP);
- cls_rule_set_nw_src(&rule, a->sin_addr.s_addr);
- cls_rule_set_tp_src(&rule, a->sin_port);
- add_rule(ib, &rule);
+ match_init_catchall(&match);
+ match_set_dl_type(&match, htons(ETH_TYPE_IP));
+ match_set_nw_proto(&match, IPPROTO_TCP);
+ match_set_nw_src(&match, a->sin_addr.s_addr);
+ match_set_tp_src(&match, a->sin_port);
+ add_rule(ib, &match, IBR_FROM_REMOTE_TCP);
}
}
update_rules(ib);
- HMAP_FOR_EACH_SAFE (rule, next, cls_rule.hmap_node, &ib->rules) {
+ HMAP_FOR_EACH_SAFE (rule, next, hmap_node, &ib->rules) {
switch (rule->op) {
case ADD:
- ofproto_add_flow(ib->ofproto, &rule->cls_rule,
+ ofproto_add_flow(ib->ofproto, &rule->match, rule->priority,
ofpacts.data, ofpacts.size);
break;
case DELETE:
- if (ofproto_delete_flow(ib->ofproto, &rule->cls_rule)) {
+ if (ofproto_delete_flow(ib->ofproto,
+ &rule->match, rule->priority)) {
/* ofproto doesn't have the rule anymore so there's no reason
* for us to track it any longer. */
- hmap_remove(&ib->rules, &rule->cls_rule.hmap_node);
+ hmap_remove(&ib->rules, &rule->hmap_node);
free(rule);
}
break;
if (ib) {
struct in_band_rule *rule, *next;
- HMAP_FOR_EACH_SAFE (rule, next, cls_rule.hmap_node, &ib->rules) {
- hmap_remove(&ib->rules, &rule->cls_rule.hmap_node);
+ HMAP_FOR_EACH_SAFE (rule, next, hmap_node, &ib->rules) {
+ hmap_remove(&ib->rules, &rule->hmap_node);
free(rule);
}
hmap_destroy(&ib->rules);
struct ofputil_flow_mod fm;
int error;
- cls_rule_init_catchall(&fm.cr, 0);
- cls_rule_set_reg(&fm.cr, 0, id);
+ match_init_catchall(&fm.match);
+ fm.priority = 0;
+ match_set_reg(&fm.match, 0, id);
fm.new_cookie = htonll(0);
fm.cookie = htonll(0);
fm.cookie_mask = htonll(0);
return error;
}
- *rulep = rule_dpif_lookup__(ofproto, &fm.cr.flow, TBL_INTERNAL);
+ *rulep = rule_dpif_lookup__(ofproto, &fm.match.flow, TBL_INTERNAL);
assert(*rulep != NULL);
return 0;
table_id = rule->up.table_id;
rule->tag = (victim ? victim->tag
: table_id == 0 ? 0
- : rule_calculate_tag(&rule->up.cr.flow, &rule->up.cr.wc,
+ : rule_calculate_tag(&rule->up.cr.match.flow,
+ &rule->up.cr.match.wc,
ofproto->tables[table_id].basis));
complete_operation(rule);
#include "shash.h"
#include "timeval.h"
+struct match;
struct ofpact;
struct ofputil_flow_mod;
struct simap;
/* ## OpenFlow Rule Functions ## */
/* ## ----------------------- ## */
-
-
- /* Chooses an appropriate table for 'cls_rule' within 'ofproto'. On
+ /* Chooses an appropriate table for 'match' within 'ofproto'. On
* success, stores the table ID into '*table_idp' and returns 0. On
* failure, returns an OpenFlow error code.
*
- * The choice of table should be a function of 'cls_rule' and 'ofproto''s
+ * The choice of table should be a function of 'match' and 'ofproto''s
* datapath capabilities. It should not depend on the flows already in
* 'ofproto''s flow tables. Failure implies that an OpenFlow rule with
- * 'cls_rule' as its matching condition can never be inserted into
- * 'ofproto', even starting from an empty flow table.
+ * 'match' as its matching condition can never be inserted into 'ofproto',
+ * even starting from an empty flow table.
*
* If multiple tables are candidates for inserting the flow, the function
* should choose one arbitrarily (but deterministically).
*
* If this function is NULL then table 0 is always chosen. */
enum ofperr (*rule_choose_table)(const struct ofproto *ofproto,
- const struct cls_rule *cls_rule,
+ const struct match *match,
uint8_t *table_idp);
/* Life-cycle functions for a "struct rule" (see "Life Cycle" above).
BUILD_ASSERT_DECL(OFPROTO_POSTPONE < OFPERR_OFS);
int ofproto_flow_mod(struct ofproto *, const struct ofputil_flow_mod *);
-void ofproto_add_flow(struct ofproto *, const struct cls_rule *,
+void ofproto_add_flow(struct ofproto *, const struct match *,
+ unsigned int priority,
const struct ofpact *ofpacts, size_t ofpacts_len);
-bool ofproto_delete_flow(struct ofproto *, const struct cls_rule *);
+bool ofproto_delete_flow(struct ofproto *,
+ const struct match *, unsigned int priority);
void ofproto_flush_flows(struct ofproto *);
#endif /* ofproto/ofproto-provider.h */
*
* This is a helper function for in-band control and fail-open. */
void
-ofproto_add_flow(struct ofproto *ofproto, const struct cls_rule *cls_rule,
+ofproto_add_flow(struct ofproto *ofproto, const struct match *match,
+ unsigned int priority,
const struct ofpact *ofpacts, size_t ofpacts_len)
{
const struct rule *rule;
- rule = rule_from_cls_rule(classifier_find_rule_exactly(
- &ofproto->tables[0].cls, cls_rule));
+ rule = rule_from_cls_rule(classifier_find_match_exactly(
+ &ofproto->tables[0].cls, match, priority));
if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len,
ofpacts, ofpacts_len)) {
struct ofputil_flow_mod fm;
memset(&fm, 0, sizeof fm);
- fm.cr = *cls_rule;
+ fm.match = *match;
+ fm.priority = priority;
fm.buffer_id = UINT32_MAX;
fm.ofpacts = xmemdup(ofpacts, ofpacts_len);
fm.ofpacts_len = ofpacts_len;
*
* This is a helper function for in-band control and fail-open. */
bool
-ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target)
+ofproto_delete_flow(struct ofproto *ofproto,
+ const struct match *target, unsigned int priority)
{
struct rule *rule;
- rule = rule_from_cls_rule(classifier_find_rule_exactly(
- &ofproto->tables[0].cls, target));
+ rule = rule_from_cls_rule(classifier_find_match_exactly(
+ &ofproto->tables[0].cls, target, priority));
if (!rule) {
/* No such rule -> success. */
return true;
* Returns 0 on success, otherwise an OpenFlow error code. */
static enum ofperr
collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
- const struct cls_rule *match,
+ const struct match *match,
ovs_be64 cookie, ovs_be64 cookie_mask,
uint16_t out_port, struct list *rules)
{
struct oftable *table;
+ struct cls_rule cr;
enum ofperr error;
error = check_table_id(ofproto, table_id);
}
list_init(rules);
+ cls_rule_init(&cr, match, 0);
FOR_EACH_MATCHING_TABLE (table, table_id, ofproto) {
struct cls_cursor cursor;
struct rule *rule;
- cls_cursor_init(&cursor, &table->cls, match);
+ cls_cursor_init(&cursor, &table->cls, &cr);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
if (rule->pending) {
return OFPROTO_POSTPONE;
* Returns 0 on success, otherwise an OpenFlow error code. */
static enum ofperr
collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
- const struct cls_rule *match,
+ const struct match *match, unsigned int priority,
ovs_be64 cookie, ovs_be64 cookie_mask,
uint16_t out_port, struct list *rules)
{
struct oftable *table;
+ struct cls_rule cr;
int error;
error = check_table_id(ofproto, table_id);
}
list_init(rules);
+ cls_rule_init(&cr, match, priority);
FOR_EACH_MATCHING_TABLE (table, table_id, ofproto) {
struct rule *rule;
rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,
- match));
+ &cr));
if (rule) {
if (rule->pending) {
return OFPROTO_POSTPONE;
long long int now = time_msec();
struct ofputil_flow_stats fs;
- fs.rule = rule->cr;
+ fs.match = rule->cr.match;
+ fs.priority = rule->cr.priority;
fs.cookie = rule->flow_cookie;
fs.table_id = rule->table_id;
calc_flow_duration__(rule->created, now, &fs.duration_sec,
struct oftable *table;
struct ofopgroup *group;
struct rule *victim;
+ struct cls_rule cr;
struct rule *rule;
int error;
if (fm->table_id == 0xff) {
uint8_t table_id;
if (ofproto->ofproto_class->rule_choose_table) {
- error = ofproto->ofproto_class->rule_choose_table(ofproto, &fm->cr,
+ error = ofproto->ofproto_class->rule_choose_table(ofproto,
+ &fm->match,
&table_id);
if (error) {
return error;
return OFPERR_OFPBRC_EPERM;
}
- /* Check for overlap, if requested. */
- if (fm->flags & OFPFF_CHECK_OVERLAP
- && classifier_rule_overlaps(&table->cls, &fm->cr)) {
- return OFPERR_OFPFMFC_OVERLAP;
+ /* Allocate new rule and initialize classifier rule. */
+ rule = ofproto->ofproto_class->rule_alloc();
+ if (!rule) {
+ VLOG_WARN_RL(&rl, "%s: failed to create rule (%s)",
+ ofproto->name, strerror(error));
+ return ENOMEM;
}
+ cls_rule_init(&rule->cr, &fm->match, fm->priority);
/* Serialize against pending deletion. */
- if (is_flow_deletion_pending(ofproto, &fm->cr, table - ofproto->tables)) {
+ if (is_flow_deletion_pending(ofproto, &cr, table - ofproto->tables)) {
+ ofproto->ofproto_class->rule_dealloc(rule);
return OFPROTO_POSTPONE;
}
- /* Allocate new rule. */
- rule = ofproto->ofproto_class->rule_alloc();
- if (!rule) {
- VLOG_WARN_RL(&rl, "%s: failed to create rule (%s)",
- ofproto->name, strerror(error));
- return ENOMEM;
+ /* Check for overlap, if requested. */
+ if (fm->flags & OFPFF_CHECK_OVERLAP
+ && classifier_rule_overlaps(&table->cls, &rule->cr)) {
+ ofproto->ofproto_class->rule_dealloc(rule);
+ return OFPERR_OFPFMFC_OVERLAP;
}
+
rule->ofproto = ofproto;
- rule->cr = fm->cr;
rule->pending = NULL;
rule->flow_cookie = fm->new_cookie;
rule->created = rule->modified = rule->used = time_msec();
struct list rules;
int error;
- error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+ error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
fm->cookie, fm->cookie_mask,
OFPP_NONE, &rules);
if (error) {
struct list rules;
int error;
- error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
- fm->cookie, fm->cookie_mask,
+ error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
+ fm->priority, fm->cookie, fm->cookie_mask,
OFPP_NONE, &rules);
if (error) {
struct list rules;
enum ofperr error;
- error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+ error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
fm->cookie, fm->cookie_mask,
fm->out_port, &rules);
return (error ? error
struct list rules;
enum ofperr error;
- error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
- fm->cookie, fm->cookie_mask,
+ error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
+ fm->priority, fm->cookie, fm->cookie_mask,
fm->out_port, &rules);
return (error ? error
: list_is_singleton(&rules) ? delete_flows__(ofproto, ofconn,
return;
}
- fr.rule = rule->cr;
+ fr.match = rule->cr.match;
+ fr.priority = rule->cr.priority;
fr.cookie = rule->flow_cookie;
fr.reason = reason;
calc_flow_duration__(rule->created, time_msec(),
}
if (!error) {
error = ofpacts_check(fm.ofpacts, fm.ofpacts_len,
- &fm.cr.flow, ofproto->max_ports);
+ &fm.match.flow, ofproto->max_ports);
}
if (!error) {
error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
fu.hard_timeout = rule->hard_timeout;
fu.table_id = rule->table_id;
fu.cookie = rule->flow_cookie;
- fu.match = CONST_CAST(struct cls_rule *, &rule->cr);
+ fu.match = CONST_CAST(struct match *, &rule->cr.match);
if (!(flags & NXFMF_ACTIONS)) {
fu.ofpacts = NULL;
fu.ofpacts_len = 0;
const struct ofproto *ofproto = ofconn_get_ofproto(m->ofconn);
const struct ofoperation *op;
const struct oftable *table;
+ struct cls_rule target;
+ cls_rule_init(&target, &m->match, 0);
FOR_EACH_MATCHING_TABLE (table, m->table_id, ofproto) {
struct cls_cursor cursor;
struct rule *rule;
- cls_cursor_init(&cursor, &table->cls, &m->match);
+ cls_cursor_init(&cursor, &table->cls, &target);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
assert(!rule->pending); /* XXX */
ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
if (((m->table_id == 0xff
? !(ofproto->tables[rule->table_id].flags & OFTABLE_HIDDEN)
: m->table_id == rule->table_id))
- && cls_rule_is_loose_match(&rule->cr, &m->match)) {
+ && cls_rule_is_loose_match(&rule->cr, &target.match)) {
ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
}
}
case OFOPERATION_ADD:
if (!op->error) {
ofproto_rule_destroy__(op->victim);
- if ((rule->cr.wc.masks.vlan_tci & htons(VLAN_VID_MASK))
+ if ((rule->cr.match.wc.masks.vlan_tci & htons(VLAN_VID_MASK))
== htons(VLAN_VID_MASK)) {
if (ofproto->vlan_bitmap) {
- uint16_t vid = vlan_tci_to_vid(rule->cr.flow.vlan_tci);
+ uint16_t vid;
+ vid = vlan_tci_to_vid(rule->cr.match.flow.vlan_tci);
if (!bitmap_is_set(ofproto->vlan_bitmap, vid)) {
bitmap_set1(ofproto->vlan_bitmap, vid);
ofproto->vlans_changed = true;
sf < &table->eviction_fields[table->n_eviction_fields];
sf++)
{
- if (mf_are_prereqs_ok(sf->field, &rule->cr.flow)) {
+ if (mf_are_prereqs_ok(sf->field, &rule->cr.match.flow)) {
union mf_value value;
- mf_get_value(sf->field, &rule->cr.flow, &value);
+ mf_get_value(sf->field, &rule->cr.match.flow, &value);
if (sf->ofs) {
bitwise_zero(&value, sf->field->n_bytes, 0, sf->ofs);
}
const struct cls_rule *rule;
HMAP_FOR_EACH (rule, hmap_node, &table->rules) {
- uint16_t vid = vlan_tci_to_vid(rule->flow.vlan_tci);
+ uint16_t vid = vlan_tci_to_vid(rule->match.flow.vlan_tci);
bitmap_set1(vlan_bitmap, vid);
bitmap_set1(ofproto->vlan_bitmap, vid);
}
OFPT_FLOW_MOD (xid=0x0): ADD priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2 idle:5 buf:0x10e out_port:0 actions=output:3
], [dnl
ofp_util|INFO|normalization changed ofp_match, details:
-ofp_util|INFO| pre: priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
-ofp_util|INFO|post: priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2
+ofp_util|INFO| pre: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
+ofp_util|INFO|post: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2
])
AT_CLEANUP
OFPT_FLOW_MOD (xid=0x0): ADD arp,in_port=1,dl_vlan=65535,dl_vlan_pcp=0,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0 idle:5 pri:65535 buf:0x10e out_port:0 actions=output:3
], [dnl
ofp_util|INFO|normalization changed ofp_match, details:
-ofp_util|INFO| pre: priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
-ofp_util|INFO|post: priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2
+ofp_util|INFO| pre: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
+ofp_util|INFO|post: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2
])
AT_CLEANUP
bool eq;
if (f_idx == CLS_F_IDX_NW_SRC) {
- eq = !((fixed->nw_src ^ wild->flow.nw_src)
- & wild->wc.masks.nw_src);
+ eq = !((fixed->nw_src ^ wild->match.flow.nw_src)
+ & wild->match.wc.masks.nw_src);
} else if (f_idx == CLS_F_IDX_NW_DST) {
- eq = !((fixed->nw_dst ^ wild->flow.nw_dst)
- & wild->wc.masks.nw_dst);
+ eq = !((fixed->nw_dst ^ wild->match.flow.nw_dst)
+ & wild->match.wc.masks.nw_dst);
} else if (f_idx == CLS_F_IDX_TP_SRC) {
- eq = !((fixed->tp_src ^ wild->flow.tp_src)
- & wild->wc.masks.tp_src);
+ eq = !((fixed->tp_src ^ wild->match.flow.tp_src)
+ & wild->match.wc.masks.tp_src);
} else if (f_idx == CLS_F_IDX_TP_DST) {
- eq = !((fixed->tp_dst ^ wild->flow.tp_dst)
- & wild->wc.masks.tp_dst);
+ eq = !((fixed->tp_dst ^ wild->match.flow.tp_dst)
+ & wild->match.wc.masks.tp_dst);
} else if (f_idx == CLS_F_IDX_DL_SRC) {
- eq = eth_addr_equal_except(fixed->dl_src, wild->flow.dl_src,
- wild->wc.masks.dl_src);
+ eq = eth_addr_equal_except(fixed->dl_src, wild->match.flow.dl_src,
+ wild->match.wc.masks.dl_src);
} else if (f_idx == CLS_F_IDX_DL_DST) {
- eq = eth_addr_equal_except(fixed->dl_dst, wild->flow.dl_dst,
- wild->wc.masks.dl_dst);
+ eq = eth_addr_equal_except(fixed->dl_dst, wild->match.flow.dl_dst,
+ wild->match.wc.masks.dl_dst);
} else if (f_idx == CLS_F_IDX_VLAN_TCI) {
- eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci)
- & wild->wc.masks.vlan_tci);
+ eq = !((fixed->vlan_tci ^ wild->match.flow.vlan_tci)
+ & wild->match.wc.masks.vlan_tci);
} else if (f_idx == CLS_F_IDX_TUN_ID) {
- eq = !((fixed->tun_id ^ wild->flow.tun_id)
- & wild->wc.masks.tun_id);
+ eq = !((fixed->tun_id ^ wild->match.flow.tun_id)
+ & wild->match.wc.masks.tun_id);
} else if (f_idx == CLS_F_IDX_METADATA) {
- eq = !((fixed->metadata ^ wild->flow.metadata)
- & wild->wc.masks.metadata);
+ eq = !((fixed->metadata ^ wild->match.flow.metadata)
+ & wild->match.wc.masks.metadata);
} else if (f_idx == CLS_F_IDX_NW_DSCP) {
- eq = !((fixed->nw_tos ^ wild->flow.nw_tos) &
- (wild->wc.masks.nw_tos & IP_DSCP_MASK));
+ eq = !((fixed->nw_tos ^ wild->match.flow.nw_tos) &
+ (wild->match.wc.masks.nw_tos & IP_DSCP_MASK));
} else if (f_idx == CLS_F_IDX_NW_PROTO) {
- eq = !((fixed->nw_proto ^ wild->flow.nw_proto)
- & wild->wc.masks.nw_proto);
+ eq = !((fixed->nw_proto ^ wild->match.flow.nw_proto)
+ & wild->match.wc.masks.nw_proto);
} else if (f_idx == CLS_F_IDX_DL_TYPE) {
- eq = !((fixed->dl_type ^ wild->flow.dl_type)
- & wild->wc.masks.dl_type);
+ eq = !((fixed->dl_type ^ wild->match.flow.dl_type)
+ & wild->match.wc.masks.dl_type);
} else if (f_idx == CLS_F_IDX_IN_PORT) {
- eq = !((fixed->in_port ^ wild->flow.in_port)
- & wild->wc.masks.in_port);
+ eq = !((fixed->in_port ^ wild->match.flow.in_port)
+ & wild->match.wc.masks.in_port);
} else {
NOT_REACHED();
}
for (i = 0; i < cls->n_rules; ) {
struct test_rule *pos = cls->rules[i];
- if (!flow_wildcards_has_extra(&pos->cls_rule.wc, &target->wc)
- && match(target, &pos->cls_rule.flow)) {
+ if (!flow_wildcards_has_extra(&pos->cls_rule.match.wc,
+ &target->match.wc)
+ && match(target, &pos->cls_rule.match.flow)) {
tcls_remove(cls, pos);
} else {
i++;
{
const struct cls_field *f;
struct test_rule *rule;
+ struct match match;
- rule = xzalloc(sizeof *rule);
- cls_rule_init_catchall(&rule->cls_rule, wc_fields ? priority : UINT_MAX);
+ match_init_catchall(&match);
for (f = &cls_fields[0]; f < &cls_fields[CLS_N_FIELDS]; f++) {
int f_idx = f - cls_fields;
int value_idx = (value_pat & (1u << f_idx)) != 0;
- memcpy((char *) &rule->cls_rule.flow + f->ofs,
+ memcpy((char *) &match.flow + f->ofs,
values[f_idx][value_idx], f->len);
if (f_idx == CLS_F_IDX_NW_SRC) {
- rule->cls_rule.wc.masks.nw_src = htonl(UINT32_MAX);
+ match.wc.masks.nw_src = htonl(UINT32_MAX);
} else if (f_idx == CLS_F_IDX_NW_DST) {
- rule->cls_rule.wc.masks.nw_dst = htonl(UINT32_MAX);
+ match.wc.masks.nw_dst = htonl(UINT32_MAX);
} else if (f_idx == CLS_F_IDX_TP_SRC) {
- rule->cls_rule.wc.masks.tp_src = htons(UINT16_MAX);
+ match.wc.masks.tp_src = htons(UINT16_MAX);
} else if (f_idx == CLS_F_IDX_TP_DST) {
- rule->cls_rule.wc.masks.tp_dst = htons(UINT16_MAX);
+ match.wc.masks.tp_dst = htons(UINT16_MAX);
} else if (f_idx == CLS_F_IDX_DL_SRC) {
- memset(rule->cls_rule.wc.masks.dl_src, 0xff, ETH_ADDR_LEN);
+ memset(match.wc.masks.dl_src, 0xff, ETH_ADDR_LEN);
} else if (f_idx == CLS_F_IDX_DL_DST) {
- memset(rule->cls_rule.wc.masks.dl_dst, 0xff, ETH_ADDR_LEN);
+ memset(match.wc.masks.dl_dst, 0xff, ETH_ADDR_LEN);
} else if (f_idx == CLS_F_IDX_VLAN_TCI) {
- rule->cls_rule.wc.masks.vlan_tci = htons(UINT16_MAX);
+ match.wc.masks.vlan_tci = htons(UINT16_MAX);
} else if (f_idx == CLS_F_IDX_TUN_ID) {
- rule->cls_rule.wc.masks.tun_id = htonll(UINT64_MAX);
+ match.wc.masks.tun_id = htonll(UINT64_MAX);
} else if (f_idx == CLS_F_IDX_METADATA) {
- rule->cls_rule.wc.masks.metadata = htonll(UINT64_MAX);
+ match.wc.masks.metadata = htonll(UINT64_MAX);
} else if (f_idx == CLS_F_IDX_NW_DSCP) {
- rule->cls_rule.wc.masks.nw_tos |= IP_DSCP_MASK;
+ match.wc.masks.nw_tos |= IP_DSCP_MASK;
} else if (f_idx == CLS_F_IDX_NW_PROTO) {
- rule->cls_rule.wc.masks.nw_proto = UINT8_MAX;
+ match.wc.masks.nw_proto = UINT8_MAX;
} else if (f_idx == CLS_F_IDX_DL_TYPE) {
- rule->cls_rule.wc.masks.dl_type = htons(UINT16_MAX);
+ match.wc.masks.dl_type = htons(UINT16_MAX);
} else if (f_idx == CLS_F_IDX_IN_PORT) {
- rule->cls_rule.wc.masks.in_port = UINT16_MAX;
+ match.wc.masks.in_port = UINT16_MAX;
} else {
NOT_REACHED();
}
}
+
+ rule = xzalloc(sizeof *rule);
+ cls_rule_init(&rule->cls_rule, &match, wc_fields ? priority : UINT_MAX);
return rule;
}
while (fread(&expected_match, sizeof expected_match, 1, flows)) {
struct ofpbuf *packet;
struct ofp10_match extracted_match;
- struct cls_rule rule;
+ struct match match;
struct flow flow;
n++;
}
flow_extract(packet, 0, 0, 1, &flow);
- cls_rule_init_exact(&flow, 0, &rule);
- ofputil_cls_rule_to_ofp10_match(&rule, &extracted_match);
+ match_init_exact(&match, &flow);
+ ofputil_match_to_ofp10_match(&match, &extracted_match);
if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
char *exp_s = ofp10_match_to_string(&expected_match, 2);
printf("Packet:\n");
ofp_print_packet(stdout, packet->data, packet->size);
ovs_hex_dump(stdout, packet->data, packet->size, 0, true);
- cls_rule_print(&rule);
+ match_print(&match);
printf("Expected flow:\n%s\n", exp_s);
printf("Actually extracted flow:\n%s\n", got_s);
ovs_hex_dump(stdout, &expected_match, sizeof expected_match, 0, false);
{
const struct ofputil_flow_stats *afs = afs_;
const struct ofputil_flow_stats *bfs = bfs_;
- const struct cls_rule *a = &afs->rule;
- const struct cls_rule *b = &bfs->rule;
+ const struct match *a = &afs->match;
+ const struct match *b = &bfs->match;
const struct sort_criterion *sc;
for (sc = criteria; sc < &criteria[n_criteria]; sc++) {
int ret;
if (!f) {
- ret = a->priority < b->priority ? -1 : a->priority > b->priority;
+ unsigned int a_pri = afs->priority;
+ unsigned int b_pri = bfs->priority;
+ ret = a_pri < b_pri ? -1 : a_pri > b_pri;
} else {
bool ina, inb;
*
* Takes ownership of 'version'. */
static void
-fte_insert(struct classifier *cls, const struct cls_rule *rule,
- struct fte_version *version, int index)
+fte_insert(struct classifier *cls, const struct match *match,
+ unsigned int priority, struct fte_version *version, int index)
{
struct fte *old, *fte;
fte = xzalloc(sizeof *fte);
- fte->rule = *rule;
+ cls_rule_init(&fte->rule, match, priority);
fte->versions[index] = version;
old = fte_from_cls_rule(classifier_replace(cls, &fte->rule));
version->ofpacts = fm.ofpacts;
version->ofpacts_len = fm.ofpacts_len;
- usable_protocols &= ofputil_usable_protocols(&fm.cr);
+ usable_protocols &= ofputil_usable_protocols(&fm.match);
- fte_insert(cls, &fm.cr, version, index);
+ fte_insert(cls, &fm.match, fm.priority, version, index);
}
ds_destroy(&s);
ovs_be32 send_xid;
fsr.aggregate = false;
- cls_rule_init_catchall(&fsr.match, 0);
+ match_init_catchall(&fsr.match);
fsr.out_port = OFPP_NONE;
fsr.table_id = 0xff;
fsr.cookie = fsr.cookie_mask = htonll(0);
version->ofpacts_len = fs.ofpacts_len;
version->ofpacts = xmemdup(fs.ofpacts, fs.ofpacts_len);
- fte_insert(cls, &fs.rule, version, index);
+ fte_insert(cls, &fs.match, fs.priority, version, index);
}
ofpbuf_uninit(&ofpacts);
}
struct ofputil_flow_mod fm;
struct ofpbuf *ofm;
- fm.cr = fte->rule;
+ fm.match = fte->rule.match;
+ fm.priority = fte->rule.priority;
fm.cookie = htonll(0);
fm.cookie_mask = htonll(0);
fm.new_cookie = version->cookie;
ds_init(&in);
while (!ds_get_test_line(&in, stdin)) {
struct ofpbuf nx_match;
- struct cls_rule rule;
+ struct match match;
ovs_be64 cookie, cookie_mask;
enum ofperr error;
int match_len;
match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
}
- /* Convert nx_match to cls_rule. */
+ /* Convert nx_match to match. */
if (strict) {
if (oxm) {
- error = oxm_pull_match(&nx_match, 0, &rule);
+ error = oxm_pull_match(&nx_match, &match);
} else {
- error = nx_pull_match(&nx_match, match_len, 0, &rule,
+ error = nx_pull_match(&nx_match, match_len, &match,
&cookie, &cookie_mask);
}
} else {
if (oxm) {
- error = oxm_pull_match_loose(&nx_match, 0, &rule);
+ error = oxm_pull_match_loose(&nx_match, &match);
} else {
- error = nx_pull_match_loose(&nx_match, match_len, 0, &rule,
+ error = nx_pull_match_loose(&nx_match, match_len, &match,
&cookie, &cookie_mask);
}
}
if (!error) {
char *out;
- /* Convert cls_rule back to nx_match. */
+ /* Convert match back to nx_match. */
ofpbuf_uninit(&nx_match);
ofpbuf_init(&nx_match, 0);
if (oxm) {
- match_len = oxm_put_match(&nx_match, &rule);
+ match_len = oxm_put_match(&nx_match, &match);
out = oxm_match_to_string(nx_match.data, match_len);
} else {
- match_len = nx_put_match(&nx_match, &rule,
+ match_len = nx_put_match(&nx_match, &match,
cookie, cookie_mask);
out = nx_match_to_string(nx_match.data, match_len);
}
struct ofpbuf match_in, match_expout;
struct ofp10_match match_out;
struct ofp10_match match_normal;
- struct cls_rule rule;
+ struct match match;
char *p;
/* Parse hex bytes to use for expected output. */
}
/* Convert to cls_rule and print. */
- ofputil_cls_rule_from_ofp10_match(match_in.data, OFP_DEFAULT_PRIORITY,
- &rule);
- cls_rule_print(&rule);
+ ofputil_match_from_ofp10_match(match_in.data, &match);
+ match_print(&match);
/* Convert back to ofp10_match and print differences from input. */
- ofputil_cls_rule_to_ofp10_match(&rule, &match_out);
+ ofputil_match_to_ofp10_match(&match, &match_out);
print_differences("", match_expout.data, match_expout.size,
&match_out, sizeof match_out);
/* Normalize, then convert and compare again. */
- ofputil_normalize_rule(&rule);
- ofputil_cls_rule_to_ofp10_match(&rule, &match_normal);
+ ofputil_normalize_match(&match);
+ ofputil_match_to_ofp10_match(&match, &match_normal);
print_differences("normal: ", &match_out, sizeof match_out,
&match_normal, sizeof match_normal);
putchar('\n');
}
/* "parse-ofp11-match": reads a series of ofp11_match specifications as hex
- * bytes from stdin, converts them to cls_rules, prints them as strings on
- * stdout, and then converts them back to hex bytes and prints any differences
- * from the input. */
+ * bytes from stdin, converts them to "struct match"es, prints them as strings
+ * on stdout, and then converts them back to hex bytes and prints any
+ * differences from the input. */
static void
ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
while (!ds_get_preprocessed_line(&in, stdin)) {
struct ofpbuf match_in;
struct ofp11_match match_out;
- struct cls_rule rule;
+ struct match match;
enum ofperr error;
/* Parse hex bytes. */
match_in.size, sizeof(struct ofp11_match));
}
- /* Convert to cls_rule. */
- error = ofputil_cls_rule_from_ofp11_match(match_in.data,
- OFP_DEFAULT_PRIORITY, &rule);
+ /* Convert to match. */
+ error = ofputil_match_from_ofp11_match(match_in.data, &match);
if (error) {
printf("bad ofp11_match: %s\n\n", ofperr_get_name(error));
ofpbuf_uninit(&match_in);
continue;
}
- /* Print cls_rule. */
- cls_rule_print(&rule);
+ /* Print match. */
+ match_print(&match);
/* Convert back to ofp11_match and print differences from input. */
- ofputil_cls_rule_to_ofp11_match(&rule, &match_out);
+ ofputil_match_to_ofp11_match(&match, &match_out);
print_differences("", match_in.data, match_in.size,
&match_out, sizeof match_out);
static void
ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
{
- struct cls_rule rule;
+ struct match match;
char *string_s;
struct ofputil_flow_mod fm;
struct ofpbuf nxm;
- struct cls_rule nxm_rule;
+ struct match nxm_match;
int nxm_match_len;
char *nxm_s;
- struct ofp10_match of10_match;
- struct cls_rule of10_rule;
+ struct ofp10_match of10_raw;
+ struct match of10_match;
- struct ofp11_match of11_match;
- struct cls_rule of11_rule;
+ struct ofp11_match of11_raw;
+ struct match of11_match;
enum ofperr error;
- cls_rule_init_catchall(&rule, OFP_DEFAULT_PRIORITY);
- rule.flow.vlan_tci = htons(strtoul(argv[1], NULL, 16));
- rule.wc.masks.vlan_tci = htons(strtoul(argv[2], NULL, 16));
+ match_init_catchall(&match);
+ match.flow.vlan_tci = htons(strtoul(argv[1], NULL, 16));
+ match.wc.masks.vlan_tci = htons(strtoul(argv[2], NULL, 16));
/* Convert to and from string. */
- string_s = cls_rule_to_string(&rule);
+ string_s = match_to_string(&match, OFP_DEFAULT_PRIORITY);
printf("%s -> ", string_s);
fflush(stdout);
parse_ofp_str(&fm, -1, string_s, false);
printf("%04"PRIx16"/%04"PRIx16"\n",
- ntohs(fm.cr.flow.vlan_tci),
- ntohs(fm.cr.wc.masks.vlan_tci));
+ ntohs(fm.match.flow.vlan_tci),
+ ntohs(fm.match.wc.masks.vlan_tci));
free(string_s);
/* Convert to and from NXM. */
ofpbuf_init(&nxm, 0);
- nxm_match_len = nx_put_match(&nxm, &rule, htonll(0), htonll(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, 0, &nxm_rule, NULL, NULL);
+ error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL);
printf("NXM: %s -> ", nxm_s);
if (error) {
printf("%s\n", ofperr_to_string(error));
} else {
printf("%04"PRIx16"/%04"PRIx16"\n",
- ntohs(nxm_rule.flow.vlan_tci),
- ntohs(nxm_rule.wc.masks.vlan_tci));
+ ntohs(nxm_match.flow.vlan_tci),
+ ntohs(nxm_match.wc.masks.vlan_tci));
}
free(nxm_s);
ofpbuf_uninit(&nxm);
/* Convert to and from OXM. */
ofpbuf_init(&nxm, 0);
- nxm_match_len = oxm_put_match(&nxm, &rule);
+ nxm_match_len = oxm_put_match(&nxm, &match);
nxm_s = oxm_match_to_string(nxm.data, nxm_match_len);
- error = oxm_pull_match(&nxm, 0, &nxm_rule);
+ error = oxm_pull_match(&nxm, &nxm_match);
printf("OXM: %s -> ", nxm_s);
if (error) {
printf("%s\n", ofperr_to_string(error));
} else {
- uint16_t vid = ntohs(nxm_rule.flow.vlan_tci) &
+ uint16_t vid = ntohs(nxm_match.flow.vlan_tci) &
(VLAN_VID_MASK | VLAN_CFI);
- uint16_t mask = ntohs(nxm_rule.wc.masks.vlan_tci) &
+ uint16_t mask = ntohs(nxm_match.wc.masks.vlan_tci) &
(VLAN_VID_MASK | VLAN_CFI);
printf("%04"PRIx16"/%04"PRIx16",", vid, mask);
- if (vid && vlan_tci_to_pcp(nxm_rule.wc.masks.vlan_tci)) {
- printf("%02"PRIx8"\n", vlan_tci_to_pcp(nxm_rule.flow.vlan_tci));
+ if (vid && vlan_tci_to_pcp(nxm_match.wc.masks.vlan_tci)) {
+ printf("%02"PRIx8"\n", vlan_tci_to_pcp(nxm_match.flow.vlan_tci));
} else {
printf("--\n");
}
ofpbuf_uninit(&nxm);
/* Convert to and from OpenFlow 1.0. */
- ofputil_cls_rule_to_ofp10_match(&rule, &of10_match);
- ofputil_cls_rule_from_ofp10_match(&of10_match, 0, &of10_rule);
+ ofputil_match_to_ofp10_match(&match, &of10_raw);
+ ofputil_match_from_ofp10_match(&of10_raw, &of10_match);
printf("OF1.0: %04"PRIx16"/%d,%02"PRIx8"/%d -> %04"PRIx16"/%04"PRIx16"\n",
- ntohs(of10_match.dl_vlan),
- (of10_match.wildcards & htonl(OFPFW10_DL_VLAN)) != 0,
- of10_match.dl_vlan_pcp,
- (of10_match.wildcards & htonl(OFPFW10_DL_VLAN_PCP)) != 0,
- ntohs(of10_rule.flow.vlan_tci),
- ntohs(of10_rule.wc.masks.vlan_tci));
+ ntohs(of10_raw.dl_vlan),
+ (of10_raw.wildcards & htonl(OFPFW10_DL_VLAN)) != 0,
+ of10_raw.dl_vlan_pcp,
+ (of10_raw.wildcards & htonl(OFPFW10_DL_VLAN_PCP)) != 0,
+ ntohs(of10_match.flow.vlan_tci),
+ ntohs(of10_match.wc.masks.vlan_tci));
/* Convert to and from OpenFlow 1.1. */
- ofputil_cls_rule_to_ofp11_match(&rule, &of11_match);
- ofputil_cls_rule_from_ofp11_match(&of11_match, 0, &of11_rule);
+ ofputil_match_to_ofp11_match(&match, &of11_raw);
+ ofputil_match_from_ofp11_match(&of11_raw, &of11_match);
printf("OF1.1: %04"PRIx16"/%d,%02"PRIx8"/%d -> %04"PRIx16"/%04"PRIx16"\n",
- ntohs(of11_match.dl_vlan),
- (of11_match.wildcards & htonl(OFPFW11_DL_VLAN)) != 0,
- of11_match.dl_vlan_pcp,
- (of11_match.wildcards & htonl(OFPFW11_DL_VLAN_PCP)) != 0,
- ntohs(of11_rule.flow.vlan_tci),
- ntohs(of11_rule.wc.masks.vlan_tci));
+ ntohs(of11_raw.dl_vlan),
+ (of11_raw.wildcards & htonl(OFPFW11_DL_VLAN)) != 0,
+ of11_raw.dl_vlan_pcp,
+ (of11_raw.wildcards & htonl(OFPFW11_DL_VLAN_PCP)) != 0,
+ ntohs(of11_match.flow.vlan_tci),
+ ntohs(of11_match.wc.masks.vlan_tci));
}
/* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow