From 81a76618be9ea195a1e4a881ba9591728891d10b Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 7 Aug 2012 15:28:18 -0700 Subject: [PATCH] classifier: Break cls_rule 'flow' and 'wc' members into new "struct match". Signed-off-by: Ben Pfaff --- lib/automake.mk | 2 + lib/classifier.c | 813 +++---------------------------------- lib/classifier.h | 101 +---- lib/learn.c | 32 +- lib/learning-switch.c | 5 +- lib/match.c | 775 +++++++++++++++++++++++++++++++++++ lib/match.h | 109 +++++ lib/meta-flow.c | 241 +++++------ lib/meta-flow.h | 14 +- lib/nx-match.c | 171 ++++---- lib/nx-match.h | 19 +- lib/ofp-parse.c | 33 +- lib/ofp-print.c | 24 +- lib/ofp-util.c | 519 ++++++++++++----------- lib/ofp-util.h | 43 +- ofproto/connmgr.c | 8 +- ofproto/connmgr.h | 3 +- ofproto/fail-open.c | 13 +- ofproto/in-band.c | 134 +++--- ofproto/ofproto-dpif.c | 10 +- ofproto/ofproto-provider.h | 19 +- ofproto/ofproto.c | 99 +++-- tests/ofp-print.at | 8 +- tests/test-classifier.c | 92 +++-- tests/test-flows.c | 8 +- utilities/ovs-ofctl.c | 151 +++---- 26 files changed, 1781 insertions(+), 1665 deletions(-) create mode 100644 lib/match.c create mode 100644 lib/match.h diff --git a/lib/automake.mk b/lib/automake.mk index 818051750..94b86f68c 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -79,6 +79,8 @@ lib_libopenvswitch_a_SOURCES = \ 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 \ diff --git a/lib/classifier.c b/lib/classifier.c index eff36f7a6..919e05fca 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -50,763 +50,45 @@ static struct cls_rule *insert_rule(struct cls_table *, struct cls_rule *); static struct cls_rule *next_rule_in_list__(struct cls_rule *); static struct cls_rule *next_rule_in_list(struct cls_rule *); + +/* 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 ? "" : "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); } /* Initializes 'cls' as a classifier that initially contains no classification @@ -867,9 +149,9 @@ classifier_replace(struct classifier *cls, struct cls_rule *rule) 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); @@ -901,8 +183,8 @@ classifier_remove(struct classifier *cls, struct cls_rule *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)) { @@ -951,12 +233,13 @@ classifier_find_rule_exactly(const struct classifier *cls, 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; @@ -965,6 +248,23 @@ classifier_find_rule_exactly(const struct classifier *cls, 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. */ @@ -978,13 +278,14 @@ classifier_rule_overlaps(const struct classifier *cls, 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; } } @@ -1026,13 +327,14 @@ classifier_rule_overlaps(const struct classifier *cls, * 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)); } /* Iteration. */ @@ -1041,13 +343,14 @@ static bool 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) { @@ -1180,7 +483,7 @@ find_match(const struct cls_table *table, const struct flow *flow) 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; } } @@ -1195,7 +498,7 @@ find_equal(struct cls_table *table, const struct flow *flow, uint32_t hash) 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; } } @@ -1207,9 +510,9 @@ insert_rule(struct cls_table *table, struct cls_rule *new) { 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); diff --git a/lib/classifier.h b/lib/classifier.h index 932234503..3370ce8bc 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -29,6 +29,7 @@ #include "flow.h" #include "hmap.h" #include "list.h" +#include "match.h" #include "openflow/nicira-ext.h" #include "openflow/openflow.h" @@ -59,107 +60,24 @@ cls_table_is_catchall(const struct cls_table *table) 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 *); @@ -177,6 +95,9 @@ typedef void cls_cb_func(struct cls_rule *, void *aux); 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); /* Iteration. */ diff --git a/lib/learn.c b/lib/learn.c index 28b8012c6..cd7532179 100644 --- a/lib/learn.c +++ b/lib/learn.c @@ -20,6 +20,7 @@ #include "byte-order.h" #include "dynamic-string.h" +#include "match.h" #include "meta-flow.h" #include "nx-match.h" #include "ofp-actions.h" @@ -170,9 +171,9 @@ enum ofperr 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; @@ -187,16 +188,16 @@ learn_check(const struct ofpact_learn *learn, const struct flow *flow) /* 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; } @@ -297,7 +298,8 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, { 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); @@ -331,7 +333,7 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, 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: @@ -508,7 +510,7 @@ learn_parse_spec(const char *orig, char *name, char *value, * * 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. * @@ -520,7 +522,7 @@ learn_parse(char *arg, const struct flow *flow, struct ofpbuf *ofpacts) char *name, *value; struct ofpact_learn *learn; - struct cls_rule rule; + struct match match; enum ofperr error; learn = ofpact_put_LEARN(ofpacts); @@ -529,7 +531,7 @@ learn_parse(char *arg, const struct flow *flow, struct ofpbuf *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); @@ -567,17 +569,17 @@ learn_parse(char *arg, const struct flow *flow, struct ofpbuf *ofpacts) } 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); } } } @@ -616,9 +618,9 @@ void 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) { diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 235e9d442..dc19aa550 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -575,8 +575,9 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh) /* 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; diff --git a/lib/match.c b/lib/match.c new file mode 100644 index 000000000..d337c1b72 --- /dev/null +++ b/lib/match.c @@ -0,0 +1,775 @@ +/* + * 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 +#include "match.h" +#include +#include +#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 ? "" : "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); +} diff --git a/lib/match.h b/lib/match.h new file mode 100644 index 000000000..e3563d272 --- /dev/null +++ b/lib/match.h @@ -0,0 +1,109 @@ +/* + * 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 */ diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 8d64aa91d..0de9b4557 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -1086,141 +1086,141 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, } } -/* 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: @@ -1229,8 +1229,8 @@ mf_set_value(const struct mf_field *mf, } } -/* 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, @@ -1387,144 +1387,145 @@ mf_is_zero(const struct mf_field *mf, const struct flow *flow) 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: @@ -1533,27 +1534,27 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule) } } -/* 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; } @@ -1575,91 +1576,91 @@ mf_set(const struct mf_field *mf, 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: @@ -1717,14 +1718,14 @@ mf_check_dst(const struct mf_subfield *sf, const struct flow *flow) 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'. */ @@ -2152,20 +2153,20 @@ mf_format(const struct mf_field *mf, } } -/* 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 diff --git a/lib/meta-flow.h b/lib/meta-flow.h index db3ac7ada..8c8b7be8e 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -24,8 +24,8 @@ #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. */ @@ -294,7 +294,7 @@ void mf_get_mask(const struct mf_field *, const struct flow_wildcards *, /* 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); @@ -302,24 +302,24 @@ 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 *); diff --git a/lib/nx-match.c b/lib/nx-match.c index 37410a055..9f9184aec 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -92,14 +92,13 @@ nx_entry_ok(const void *p, unsigned int match_len) 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); } @@ -120,9 +119,9 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, } 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; @@ -133,7 +132,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, 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; @@ -142,7 +141,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, error = OFPERR_OFPBMC_BAD_MASK; } else { error = 0; - mf_set(mf, &value, &mask, rule); + mf_set(mf, &value, &mask, match); } } } else { @@ -154,7 +153,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, 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); } } @@ -191,7 +190,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, 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; @@ -206,42 +205,36 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, } } - 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; @@ -269,29 +262,27 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, } 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); } /* nx_put_match() and helpers. @@ -470,10 +461,10 @@ nxm_put_ipv6(struct ofpbuf *b, uint32_t header, } 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: @@ -491,54 +482,53 @@ nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr) } 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. * @@ -546,13 +536,13 @@ nxm_put_ip(struct ofpbuf *b, const struct cls_rule *cr, * * 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; @@ -560,7 +550,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct cls_rule *cr, 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)); @@ -571,18 +561,18 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct cls_rule *cr, /* 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); @@ -590,78 +580,79 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct cls_rule *cr, 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); @@ -670,8 +661,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct cls_rule *cr, 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. @@ -682,10 +672,10 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct cls_rule *cr, * 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; @@ -693,16 +683,15 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr, /* 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; @@ -710,7 +699,7 @@ oxm_put_match(struct ofpbuf *b, const struct cls_rule *cr) 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); diff --git a/lib/nx-match.h b/lib/nx-match.h index 3bfeeb739..f504ad07d 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -23,11 +23,9 @@ #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; @@ -41,19 +39,16 @@ struct nx_action_reg_move; */ 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); diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 0d904b1ed..518bbdd39 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -554,7 +554,7 @@ ofp_fatal(const char *flow, bool verbose, const char *format, ...) } 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; @@ -564,7 +564,7 @@ parse_field(const struct mf_field *mf, const char *s, struct cls_rule *rule) 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 @@ -620,7 +620,8 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, 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) { @@ -655,9 +656,9 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, 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; @@ -676,7 +677,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, } 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")) { @@ -702,7 +703,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, 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")) { @@ -725,7 +726,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, 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 { @@ -753,7 +754,7 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, | 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)) { @@ -772,9 +773,9 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, } 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; @@ -817,15 +818,15 @@ void 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 @@ -867,7 +868,7 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr, 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; } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 99e64564c..d116ef14e 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -733,9 +733,9 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity) /* 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; } @@ -755,8 +755,8 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity) 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); @@ -837,7 +837,7 @@ ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh) } 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)); @@ -983,12 +983,8 @@ ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh) 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 @@ -1014,7 +1010,7 @@ ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs) 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, ' '); } @@ -1600,7 +1596,7 @@ ofp_print_nxst_flow_monitor_request(struct ds *string, } ds_put_char(string, ' '); - cls_rule_format(&request.match, string); + match_format(&request.match, string, OFP_DEFAULT_PRIORITY); ds_chomp(string, ' '); } } @@ -1617,7 +1613,7 @@ ofp_print_nxst_flow_monitor_reply(struct ds *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; @@ -1662,7 +1658,7 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string, 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] != ' ') { diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 1a8ecb763..6622b833d 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -78,7 +78,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) } /* 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 @@ -86,7 +86,7 @@ ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { 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)) { @@ -131,34 +131,32 @@ ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) } } -/* 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. @@ -167,27 +165,27 @@ ofputil_cls_rule_from_ofp10_match(const struct ofp10_match *match, * 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. */ @@ -222,47 +220,47 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule, } /* 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; @@ -284,80 +282,79 @@ ofputil_pull_ofp11_match(struct ofpbuf *buf, unsigned int priority, 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; @@ -367,33 +364,33 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match, } 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: * @@ -403,17 +400,17 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match, * 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; } @@ -423,10 +420,10 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match, 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; @@ -441,8 +438,8 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match, } } - 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) { @@ -451,105 +448,103 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match, } } - 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 @@ -896,14 +891,14 @@ regs_fully_wildcarded(const struct flow_wildcards *wc) 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); @@ -929,7 +924,7 @@ ofputil_usable_protocols(const struct cls_rule *rule) } /* 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; } @@ -1144,8 +1139,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, 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; } @@ -1156,6 +1150,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, } /* Translate the message. */ + fm->priority = ntohs(ofm->priority); if (ofm->command == OFPFC_ADD) { fm->cookie = htonll(0); fm->cookie_mask = htonll(0); @@ -1183,24 +1178,14 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, 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); @@ -1208,6 +1193,12 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, 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); @@ -1225,8 +1216,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, /* Dissect the message. */ nfm = ofpbuf_pull(&b, sizeof *nfm); - error = nx_pull_match(&b, ntohs(nfm->match_len), 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; } @@ -1242,6 +1233,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, * 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); @@ -1297,12 +1289,12 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, 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; } @@ -1314,12 +1306,12 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, 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); @@ -1337,11 +1329,11 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, 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); @@ -1374,7 +1366,7 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms, 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; } @@ -1395,7 +1387,7 @@ ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr, 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); @@ -1422,7 +1414,7 @@ ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr, } 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; } @@ -1438,7 +1430,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, 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; @@ -1528,7 +1520,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, : 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; @@ -1635,8 +1627,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, 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; } @@ -1647,6 +1638,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, 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); @@ -1680,8 +1672,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, } 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); @@ -1709,8 +1701,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, "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; } @@ -1723,6 +1714,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, 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; @@ -1773,7 +1765,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -1783,7 +1775,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -1800,10 +1792,10 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -1817,7 +1809,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -1826,7 +1818,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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 @@ -1913,12 +1905,12 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, 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 */ @@ -1933,8 +1925,8 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, 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); @@ -1948,8 +1940,8 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, 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; } @@ -1957,6 +1949,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, 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); @@ -1990,7 +1983,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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); @@ -1999,7 +1992,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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; } @@ -2010,9 +2003,9 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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); @@ -2030,11 +2023,11 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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); @@ -2054,16 +2047,15 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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 @@ -2079,11 +2071,11 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, 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; } @@ -2098,7 +2090,7 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, 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; @@ -2113,11 +2105,11 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, 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; @@ -2134,7 +2126,7 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, 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(); } @@ -2143,26 +2135,26 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, } 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 @@ -2178,16 +2170,16 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, /* 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); @@ -2210,17 +2202,17 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, 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); @@ -2999,8 +2991,7 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq, 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 @@ -3029,7 +3020,7 @@ ofputil_append_flow_monitor_request( /* 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 @@ -3103,9 +3094,9 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update, 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; } @@ -3190,7 +3181,7 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update, 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); @@ -3582,7 +3573,7 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf) #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 */ @@ -3598,34 +3589,34 @@ ofputil_normalize_rule__(struct cls_rule *rule, bool may_log) 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); } @@ -3654,15 +3645,15 @@ ofputil_normalize_rule__(struct cls_rule *rule, bool may_log) } /* 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); @@ -3672,37 +3663,37 @@ ofputil_normalize_rule__(struct cls_rule *rule, bool may_log) } } -/* "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'. diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 9cc30289a..ee459f305 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -24,11 +24,11 @@ #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. */ @@ -96,7 +96,7 @@ enum ofputil_protocol ofputil_protocol_set_base( 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, @@ -110,23 +110,18 @@ const char *ofputil_nx_flow_format_to_string(enum nx_flow_format); /* 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); @@ -160,7 +155,8 @@ struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id); * NXM Delete - */ 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. */ @@ -188,7 +184,7 @@ enum ofputil_protocol ofputil_flow_mod_usable_protocols( /* 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; @@ -204,11 +200,12 @@ enum ofputil_protocol ofputil_flow_stats_request_usable_protocols( /* 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. */ @@ -242,7 +239,8 @@ enum ofperr ofputil_decode_aggregate_stats_reply( /* 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; @@ -457,7 +455,7 @@ struct ofputil_flow_monitor_request { 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 *, @@ -475,7 +473,8 @@ struct ofputil_flow_update { 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; diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index aaf9b3e2c..4e1ba9df2 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -1600,14 +1600,14 @@ connmgr_flushed(struct connmgr *mgr) 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); } @@ -1812,7 +1812,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule, 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; diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h index 24a33fb0e..00dd37157 100644 --- a/ofproto/connmgr.h +++ b/ofproto/connmgr.h @@ -20,6 +20,7 @@ #include "classifier.h" #include "hmap.h" #include "list.h" +#include "match.h" #include "ofp-errors.h" #include "ofproto.h" #include "openflow/nicira-ext.h" @@ -172,7 +173,7 @@ struct ofmonitor { /* Matching. */ uint16_t out_port; uint8_t table_id; - struct cls_rule match; + struct match match; }; struct ofputil_flow_monitor_request; diff --git a/ofproto/fail-open.c b/ofproto/fail-open.c index 495197e75..2c0a8f33d 100644 --- a/ofproto/fail-open.c +++ b/ofproto/fail-open.c @@ -191,14 +191,14 @@ fail_open_maybe_recover(struct fail_open *fo) 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 @@ -216,7 +216,7 @@ fail_open_flushed(struct fail_open *fo) 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. */ @@ -224,8 +224,9 @@ fail_open_flushed(struct fail_open *fo) 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); } diff --git a/ofproto/in-band.c b/ofproto/in-band.c index 43461ad49..0e4754cfd 100644 --- a/ofproto/in-band.c +++ b/ofproto/in-band.c @@ -81,7 +81,9 @@ enum in_band_op { /* 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; }; @@ -279,22 +281,23 @@ in_band_rule_check(const struct flow *flow, } 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 @@ -302,38 +305,38 @@ update_rules(struct in_band *ib) { 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++) { @@ -344,18 +347,18 @@ update_rules(struct in_band *ib) } /* (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++) { @@ -363,35 +366,35 @@ update_rules(struct in_band *ib) /* (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); } } @@ -420,18 +423,19 @@ in_band_run(struct in_band *ib) 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; @@ -486,8 +490,8 @@ in_band_destroy(struct in_band *ib) 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); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index b7e36abc8..1fac7ab5c 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -822,8 +822,9 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id, 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); @@ -844,7 +845,7 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id, 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; @@ -4666,7 +4667,8 @@ rule_construct(struct rule *rule_) 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); diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index c319d8fa4..f6cb3573f 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -29,6 +29,7 @@ #include "shash.h" #include "timeval.h" +struct match; struct ofpact; struct ofputil_flow_mod; struct simap; @@ -701,24 +702,22 @@ struct ofproto_class { /* ## 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). @@ -1219,9 +1218,11 @@ enum { OFPROTO_POSTPONE = 1 << 16 }; 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 */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 838430812..36de8e3a5 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1419,19 +1419,21 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port) * * 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; @@ -1456,12 +1458,13 @@ ofproto_flow_mod(struct ofproto *ofproto, const struct ofputil_flow_mod *fm) * * 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; @@ -2432,11 +2435,12 @@ next_matching_table(const struct ofproto *ofproto, * 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); @@ -2445,11 +2449,12 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t 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; @@ -2477,11 +2482,12 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id, * 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); @@ -2490,11 +2496,12 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t 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; @@ -2547,7 +2554,8 @@ handle_flow_stats_request(struct ofconn *ofconn, 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, @@ -2869,6 +2877,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, struct oftable *table; struct ofopgroup *group; struct rule *victim; + struct cls_rule cr; struct rule *rule; int error; @@ -2881,7 +2890,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, 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; @@ -2901,26 +2911,29 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, 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(); @@ -3060,7 +3073,7 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn, 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) { @@ -3085,8 +3098,8 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn, 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) { @@ -3142,7 +3155,7 @@ delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn, 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 @@ -3160,8 +3173,8 @@ delete_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn, 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, @@ -3178,7 +3191,8 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason) 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(), @@ -3263,7 +3277,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) } 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); @@ -3503,7 +3517,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule, 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; @@ -3606,12 +3620,14 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m, 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); @@ -3624,7 +3640,7 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m, 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); } } @@ -3992,11 +4008,12 @@ ofopgroup_complete(struct ofopgroup *group) 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; @@ -4337,10 +4354,10 @@ eviction_group_hash_rule(struct rule *rule) 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); } @@ -4651,7 +4668,7 @@ ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap) 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); } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 3c55d9108..9844592e1 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -455,8 +455,8 @@ AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\ 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 @@ -493,8 +493,8 @@ AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\ 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 diff --git a/tests/test-classifier.c b/tests/test-classifier.c index 3ee6ddb63..f279bda1e 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -186,44 +186,44 @@ match(const struct cls_rule *wild, const struct flow *fixed) 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(); } @@ -256,8 +256,9 @@ tcls_delete_matches(struct tcls *cls, const struct cls_rule *target) 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++; @@ -476,45 +477,48 @@ make_rule(int wc_fields, unsigned int priority, int value_pat) { 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; } diff --git a/tests/test-flows.c b/tests/test-flows.c index 33417e021..a4d7c09e0 100644 --- a/tests/test-flows.c +++ b/tests/test-flows.c @@ -56,7 +56,7 @@ main(int argc OVS_UNUSED, char *argv[]) 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++; @@ -69,8 +69,8 @@ main(int argc OVS_UNUSED, char *argv[]) } 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); @@ -80,7 +80,7 @@ main(int argc OVS_UNUSED, char *argv[]) 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); diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 126c72042..c7069c5bb 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -841,8 +841,8 @@ compare_flows(const void *afs_, const void *bfs_) { 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++) { @@ -850,7 +850,9 @@ compare_flows(const void *afs_, const void *bfs_) 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; @@ -1801,13 +1803,13 @@ fte_free_all(struct classifier *cls) * * 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)); @@ -1849,9 +1851,9 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index) 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); @@ -1931,7 +1933,7 @@ read_flows_from_switch(struct vconn *vconn, 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); @@ -1952,7 +1954,7 @@ read_flows_from_switch(struct vconn *vconn, 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); } @@ -1965,7 +1967,8 @@ fte_make_flow_mod(const struct fte *fte, int index, uint16_t command, 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; @@ -2177,7 +2180,7 @@ ofctl_parse_nxm__(bool oxm) 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; @@ -2190,19 +2193,19 @@ ofctl_parse_nxm__(bool oxm) 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); } } @@ -2211,14 +2214,14 @@ ofctl_parse_nxm__(bool oxm) 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); } @@ -2354,7 +2357,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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. */ @@ -2390,18 +2393,17 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) } /* 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'); @@ -2414,9 +2416,9 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) } /* "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) { @@ -2426,7 +2428,7 @@ 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. */ @@ -2439,20 +2441,19 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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); @@ -2586,71 +2587,71 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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"); } @@ -2659,26 +2660,26 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[]) 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 -- 2.43.0