#ifdef __CHECKER__
#define OVS_BITWISE __attribute__((bitwise))
+#define OVS_FORCE __attribute__((force))
#else
#define OVS_BITWISE
+#define OVS_FORCE
#endif
/* The ovs_be<N> types indicate that an object is in big-endian, not
#include "dynamic-string.h"
#include "flow.h"
#include "hash.h"
+#include "ofp-util.h"
#include "packets.h"
static struct cls_table *find_table(const struct classifier *,
cls_rule_init_catchall(struct cls_rule *rule, unsigned int priority)
{
memset(&rule->flow, 0, sizeof rule->flow);
- flow_wildcards_init(&rule->wc, OVSFW_ALL | FWW_ALL);
+ flow_wildcards_init_catchall(&rule->wc);
rule->priority = priority;
}
-/* Converts the ofp_match in 'match' (with format 'flow_format', one of NXFF_*)
- * into a cls_rule in 'rule', with the given 'priority'. 'cookie' is used
- * when 'flow_format' is NXFF_TUN_ID_FROM_COOKIE. */
-void
-cls_rule_from_match(const struct ofp_match *match, unsigned int priority,
- int flow_format, uint64_t cookie,
- struct cls_rule *rule)
-{
- uint32_t wildcards = ntohl(match->wildcards) & OVSFW_ALL;
-
- rule->priority = !wildcards ? UINT16_MAX : priority;
-
- rule->flow.tun_id = 0;
- if (flow_format != NXFF_TUN_ID_FROM_COOKIE) {
- wildcards |= NXFW_TUN_ID;
- } else {
- if (!(wildcards & NXFW_TUN_ID)) {
- rule->flow.tun_id = htonl(ntohll(cookie) >> 32);
- }
- }
- if (wildcards & OFPFW_DL_DST) {
- /* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but
- * internally to OVS it excludes the multicast bit, which has to be set
- * separately with FWW_ETH_MCAST. */
- wildcards |= FWW_ETH_MCAST;
- }
- flow_wildcards_init(&rule->wc, wildcards);
-
- rule->flow.nw_src = match->nw_src;
- rule->flow.nw_dst = match->nw_dst;
- rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
- : ntohs(match->in_port));
- rule->flow.dl_vlan = match->dl_vlan;
- rule->flow.dl_vlan_pcp = match->dl_vlan_pcp;
- rule->flow.dl_type = 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;
- rule->flow.nw_proto = match->nw_proto;
-
- cls_rule_zero_wildcarded_fields(rule);
-}
-
-/* Converts 'rule' into an OpenFlow match structure 'match' with the given flow
- * format 'flow_format' (one of NXFF_*). */
-void
-cls_rule_to_match(const struct cls_rule *rule, int flow_format,
- struct ofp_match *match)
-{
- match->wildcards = htonl(rule->wc.wildcards
- & (flow_format == NXFF_TUN_ID_FROM_COOKIE
- ? OVSFW_ALL : OFPFW_ALL));
- match->in_port = htons(rule->flow.in_port == ODPP_LOCAL ? OFPP_LOCAL
- : rule->flow.in_port);
- match->dl_vlan = rule->flow.dl_vlan;
- match->dl_vlan_pcp = rule->flow.dl_vlan_pcp;
- 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 = 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;
- 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);
-}
-
/* 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.
void
cls_rule_set_in_port(struct cls_rule *rule, uint16_t odp_port)
{
- rule->wc.wildcards &= ~OFPFW_IN_PORT;
+ rule->wc.wildcards &= ~FWW_IN_PORT;
rule->flow.in_port = odp_port;
}
void
cls_rule_set_dl_type(struct cls_rule *rule, ovs_be16 dl_type)
{
- rule->wc.wildcards &= ~OFPFW_DL_TYPE;
+ rule->wc.wildcards &= ~FWW_DL_TYPE;
rule->flow.dl_type = dl_type;
}
void
cls_rule_set_dl_src(struct cls_rule *rule, const uint8_t dl_src[ETH_ADDR_LEN])
{
- rule->wc.wildcards &= ~OFPFW_DL_SRC;
+ rule->wc.wildcards &= ~FWW_DL_SRC;
memcpy(rule->flow.dl_src, dl_src, ETH_ADDR_LEN);
}
void
cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
{
- rule->wc.wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
+ rule->wc.wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN);
}
case 0xffff:
if (tci == htons(0)) {
/* Match only packets that have no 802.1Q header. */
- rule->wc.wildcards &= ~(OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP);
+ rule->wc.wildcards &= ~(FWW_DL_VLAN | FWW_DL_VLAN_PCP);
rule->flow.dl_vlan = htons(OFP_VLAN_NONE);
rule->flow.dl_vlan_pcp = 0;
return true;
} else if (tci & htons(VLAN_CFI)) {
/* Match only packets that have a specific 802.1Q VID and PCP. */
- rule->wc.wildcards &= ~(OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP);
+ rule->wc.wildcards &= ~(FWW_DL_VLAN | FWW_DL_VLAN_PCP);
rule->flow.dl_vlan = htons(vlan_tci_to_vid(tci));
rule->flow.dl_vlan_pcp = vlan_tci_to_pcp(tci);
return true;
} else {
/* Match only packets that have a specific 802.1Q VID. */
cls_rule_set_dl_vlan(rule, tci & htons(VLAN_VID_MASK));
- rule->wc.wildcards |= OFPFW_DL_VLAN_PCP;
+ rule->wc.wildcards |= FWW_DL_VLAN_PCP;
rule->flow.dl_vlan_pcp = 0;
return true;
}
} else {
/* Match only packets that have a specific 802.1Q PCP. */
cls_rule_set_dl_vlan_pcp(rule, vlan_tci_to_pcp(tci));
- rule->wc.wildcards |= OFPFW_DL_VLAN;
+ rule->wc.wildcards |= FWW_DL_VLAN;
rule->flow.dl_vlan = 0;
return true;
}
case 0x0000:
/* Match anything. */
- rule->wc.wildcards |= OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP;
+ rule->wc.wildcards |= FWW_DL_VLAN | FWW_DL_VLAN_PCP;
rule->flow.dl_vlan = htons(0);
rule->flow.dl_vlan_pcp = 0;
return true;
dl_vlan &= htons(VLAN_VID_MASK);
}
- rule->wc.wildcards &= ~OFPFW_DL_VLAN;
+ rule->wc.wildcards &= ~FWW_DL_VLAN;
rule->flow.dl_vlan = dl_vlan;
}
void
cls_rule_set_dl_vlan_pcp(struct cls_rule *rule, uint8_t dl_vlan_pcp)
{
- rule->wc.wildcards &= ~OFPFW_DL_VLAN_PCP;
+ rule->wc.wildcards &= ~FWW_DL_VLAN_PCP;
rule->flow.dl_vlan_pcp = dl_vlan_pcp & 0x07;
}
void
cls_rule_set_tp_src(struct cls_rule *rule, ovs_be16 tp_src)
{
- rule->wc.wildcards &= ~OFPFW_TP_SRC;
+ rule->wc.wildcards &= ~FWW_TP_SRC;
rule->flow.tp_src = tp_src;
}
void
cls_rule_set_tp_dst(struct cls_rule *rule, ovs_be16 tp_dst)
{
- rule->wc.wildcards &= ~OFPFW_TP_DST;
+ rule->wc.wildcards &= ~FWW_TP_DST;
rule->flow.tp_dst = tp_dst;
}
void
cls_rule_set_nw_proto(struct cls_rule *rule, uint8_t nw_proto)
{
- rule->wc.wildcards &= ~OFPFW_NW_PROTO;
+ rule->wc.wildcards &= ~FWW_NW_PROTO;
rule->flow.nw_proto = nw_proto;
}
void
cls_rule_set_nw_tos(struct cls_rule *rule, uint8_t nw_tos)
{
- rule->wc.wildcards &= ~OFPFW_NW_TOS;
+ rule->wc.wildcards &= ~FWW_NW_TOS;
rule->flow.nw_tos = nw_tos & IP_DSCP_MASK;
}
void
cls_rule_set_icmp_type(struct cls_rule *rule, uint8_t icmp_type)
{
- rule->wc.wildcards &= ~OFPFW_ICMP_TYPE;
+ rule->wc.wildcards &= ~FWW_TP_SRC;
rule->flow.icmp_type = htons(icmp_type);
}
void
cls_rule_set_icmp_code(struct cls_rule *rule, uint8_t icmp_code)
{
- rule->wc.wildcards &= ~OFPFW_ICMP_CODE;
+ rule->wc.wildcards &= ~FWW_TP_DST;
rule->flow.icmp_code = htons(icmp_code);
}
flow_equal_except(const struct flow *a, const struct flow *b,
const struct flow_wildcards *wildcards)
{
- const uint32_t wc = wildcards->wildcards;
+ const flow_wildcards_t wc = wildcards->wildcards;
int i;
BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + FLOW_N_REGS * 4);
}
}
- return ((wc & NXFW_TUN_ID || a->tun_id == b->tun_id)
+ return ((wc & FWW_TUN_ID || a->tun_id == b->tun_id)
&& !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask)
&& !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask)
- && (wc & OFPFW_IN_PORT || a->in_port == b->in_port)
- && (wc & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
- && (wc & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
- && (wc & OFPFW_TP_SRC || a->tp_src == b->tp_src)
- && (wc & OFPFW_TP_DST || a->tp_dst == b->tp_dst)
- && (wc & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
- && (wc & OFPFW_DL_DST
+ && (wc & FWW_IN_PORT || a->in_port == b->in_port)
+ && (wc & FWW_DL_VLAN || a->dl_vlan == b->dl_vlan)
+ && (wc & FWW_DL_TYPE || a->dl_type == b->dl_type)
+ && (wc & FWW_TP_SRC || a->tp_src == b->tp_src)
+ && (wc & FWW_TP_DST || a->tp_dst == b->tp_dst)
+ && (wc & FWW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
+ && (wc & FWW_DL_DST
|| (!((a->dl_dst[0] ^ b->dl_dst[0]) & 0xfe)
&& a->dl_dst[1] == b->dl_dst[1]
&& a->dl_dst[2] == b->dl_dst[2]
&& a->dl_dst[3] == b->dl_dst[3]
&& a->dl_dst[4] == b->dl_dst[4]
&& a->dl_dst[5] == b->dl_dst[5]))
- && (wc & FWW_ETH_MCAST || !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01))
- && (wc & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
- && (wc & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp)
- && (wc & OFPFW_NW_TOS || a->nw_tos == b->nw_tos));
+ && (wc & FWW_ETH_MCAST
+ || !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01))
+ && (wc & FWW_NW_PROTO || a->nw_proto == b->nw_proto)
+ && (wc & FWW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp)
+ && (wc & FWW_NW_TOS || a->nw_tos == b->nw_tos));
}
static void
zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
{
- const uint32_t wc = wildcards->wildcards;
+ const flow_wildcards_t wc = wildcards->wildcards;
int i;
BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + 4 * FLOW_N_REGS);
for (i = 0; i < FLOW_N_REGS; i++) {
flow->regs[i] &= wildcards->reg_masks[i];
}
- if (wc & NXFW_TUN_ID) {
+ if (wc & FWW_TUN_ID) {
flow->tun_id = 0;
}
flow->nw_src &= wildcards->nw_src_mask;
flow->nw_dst &= wildcards->nw_dst_mask;
- if (wc & OFPFW_IN_PORT) {
+ if (wc & FWW_IN_PORT) {
flow->in_port = 0;
}
- if (wc & OFPFW_DL_VLAN) {
+ if (wc & FWW_DL_VLAN) {
flow->dl_vlan = 0;
}
- if (wc & OFPFW_DL_TYPE) {
+ if (wc & FWW_DL_TYPE) {
flow->dl_type = 0;
}
- if (wc & OFPFW_TP_SRC) {
+ if (wc & FWW_TP_SRC) {
flow->tp_src = 0;
}
- if (wc & OFPFW_TP_DST) {
+ if (wc & FWW_TP_DST) {
flow->tp_dst = 0;
}
- if (wc & OFPFW_DL_SRC) {
+ if (wc & FWW_DL_SRC) {
memset(flow->dl_src, 0, sizeof flow->dl_src);
}
- if (wc & OFPFW_DL_DST) {
+ if (wc & FWW_DL_DST) {
flow->dl_dst[0] &= 0x01;
memset(&flow->dl_dst[1], 0, 5);
}
if (wc & FWW_ETH_MCAST) {
flow->dl_dst[0] &= 0xfe;
}
- if (wc & OFPFW_NW_PROTO) {
+ if (wc & FWW_NW_PROTO) {
flow->nw_proto = 0;
}
- if (wc & OFPFW_DL_VLAN_PCP) {
+ if (wc & FWW_DL_VLAN_PCP) {
flow->dl_vlan_pcp = 0;
}
- if (wc & OFPFW_NW_TOS) {
+ if (wc & FWW_NW_TOS) {
flow->nw_tos = 0;
}
}
struct cls_rule *);
void cls_rule_init_catchall(struct cls_rule *, unsigned int priority);
-void cls_rule_from_match(const struct ofp_match *, unsigned int priority,
- int flow_format, uint64_t cookie, struct cls_rule *);
-void cls_rule_to_match(const struct cls_rule *, int flow_format,
- struct ofp_match *);
-
void cls_rule_zero_wildcarded_fields(struct cls_rule *);
void cls_rule_set_in_port(struct cls_rule *, uint16_t odp_port);
\f
/* flow_wildcards functions. */
-/* Return 'wildcards' in "normal form":
- *
- * - Forces unknown bits to 0.
- *
- * - Forces nw_src and nw_dst masks greater than 32 to exactly 32.
- */
-static inline uint32_t
-flow_wildcards_normalize(uint32_t wildcards)
-{
- wildcards &= wildcards & (OVSFW_ALL | FWW_ALL);
- if (wildcards & (0x20 << OFPFW_NW_SRC_SHIFT)) {
- wildcards &= ~(0x1f << OFPFW_NW_SRC_SHIFT);
- }
- if (wildcards & (0x20 << OFPFW_NW_DST_SHIFT)) {
- wildcards &= ~(0x1f << OFPFW_NW_DST_SHIFT);
- }
- return wildcards;
-}
-
-/* Initializes 'wc' from 'wildcards', which may be any combination of the
- * OFPFW_* and OVSFW_* wildcard bits.
- *
- * All registers (NXM_NX_REG*) are always completely wildcarded, because
- * 'wildcards' doesn't have enough bits to give the details on which
- * particular bits should be wildcarded (if any). The caller may use
- * flow_wildcards_set_reg_mask() to update the register wildcard masks. */
+/* Initializes 'wc' as a set of wildcards that matches every packet. */
void
-flow_wildcards_init(struct flow_wildcards *wc, uint32_t wildcards)
+flow_wildcards_init_catchall(struct flow_wildcards *wc)
{
- wc->wildcards = flow_wildcards_normalize(wildcards) | FWW_REGS;
- wc->nw_src_mask = ofputil_wcbits_to_netmask(wildcards >> OFPFW_NW_SRC_SHIFT);
- wc->nw_dst_mask = ofputil_wcbits_to_netmask(wildcards >> OFPFW_NW_DST_SHIFT);
+ wc->wildcards = FWW_ALL;
+ wc->nw_src_mask = htonl(0);
+ wc->nw_dst_mask = htonl(0);
memset(wc->reg_masks, 0, sizeof wc->reg_masks);
}
bool
flow_wildcards_is_exact(const struct flow_wildcards *wc)
{
- return !wc->wildcards;
-}
+ int i;
-static inline uint32_t
-combine_nw_bits(uint32_t wb1, uint32_t wb2, int shift)
-{
- uint32_t sb1 = (wb1 >> shift) & 0x3f;
- uint32_t sb2 = (wb2 >> shift) & 0x3f;
- return MAX(sb1, sb2) << shift;
+ if (wc->wildcards
+ || wc->nw_src_mask != htonl(UINT32_MAX)
+ || wc->nw_dst_mask != htonl(UINT32_MAX)) {
+ return false;
+ }
+
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ if (wc->reg_masks[i] != htonl(UINT32_MAX)) {
+ return false;
+ }
+ }
+
+ return true;
}
/* Initializes 'dst' as the combination of wildcards in 'src1' and 'src2'.
const struct flow_wildcards *src1,
const struct flow_wildcards *src2)
{
- uint32_t wb1 = src1->wildcards;
- uint32_t wb2 = src2->wildcards;
int i;
- dst->wildcards = (wb1 | wb2) & ~(OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK);
- dst->wildcards |= combine_nw_bits(wb1, wb2, OFPFW_NW_SRC_SHIFT);
- dst->wildcards |= combine_nw_bits(wb1, wb2, OFPFW_NW_DST_SHIFT);
+ dst->wildcards = src1->wildcards | src2->wildcards;
dst->nw_src_mask = src1->nw_src_mask & src2->nw_src_mask;
dst->nw_dst_mask = src1->nw_dst_mask & src2->nw_dst_mask;
for (i = 0; i < FLOW_N_REGS; i++) {
uint32_t
flow_wildcards_hash(const struct flow_wildcards *wc)
{
- /* There is no need to include nw_src_mask or nw_dst_mask because they do
- * not add any information (they can be computed from wc->wildcards). */
- BUILD_ASSERT_DECL(sizeof wc->wildcards == 4);
- BUILD_ASSERT_DECL(sizeof wc->reg_masks == 4 * FLOW_N_REGS);
- BUILD_ASSERT_DECL(offsetof(struct flow_wildcards, wildcards) == 0);
- BUILD_ASSERT_DECL(offsetof(struct flow_wildcards, reg_masks) == 4);
- return hash_words((const uint32_t *) wc, 1 + FLOW_N_REGS, 0);
+ /* If you change struct flow_wildcards and thereby trigger this
+ * assertion, please check that the new struct flow_wildcards has no holes
+ * in it before you update the assertion. */
+ BUILD_ASSERT_DECL(sizeof *wc == 12 + FLOW_N_REGS * 4);
+ return hash_bytes(wc, sizeof *wc, 0);
}
/* Returns true if 'a' and 'b' represent the same wildcards, false if they are
{
int i;
- if (a->wildcards != b->wildcards) {
+ if (a->wildcards != b->wildcards
+ || a->nw_src_mask != b->nw_src_mask
+ || a->nw_dst_mask != b->nw_dst_mask) {
return false;
}
}
}
-#define OFPFW_NW_MASK (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK)
- return ((a->wildcards & ~(b->wildcards | OFPFW_NW_MASK))
+ return (a->wildcards & ~b->wildcards
|| (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
|| (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask);
}
static bool
-set_nw_mask(struct flow_wildcards *wc, ovs_be32 mask,
- ovs_be32 *maskp, int shift)
+set_nw_mask(ovs_be32 *maskp, ovs_be32 mask)
{
if (ip_is_cidr(mask)) {
- wc->wildcards &= ~(0x3f << shift);
- wc->wildcards |= ofputil_netmask_to_wcbits(mask) << shift;
*maskp = mask;
return true;
} else {
bool
flow_wildcards_set_nw_src_mask(struct flow_wildcards *wc, ovs_be32 mask)
{
- return set_nw_mask(wc, mask, &wc->nw_src_mask, OFPFW_NW_SRC_SHIFT);
+ return set_nw_mask(&wc->nw_src_mask, mask);
}
/* Sets the IP (or ARP) destination wildcard mask to CIDR 'mask' (consisting of
bool
flow_wildcards_set_nw_dst_mask(struct flow_wildcards *wc, ovs_be32 mask)
{
- return set_nw_mask(wc, mask, &wc->nw_dst_mask, OFPFW_NW_DST_SHIFT);
+ return set_nw_mask(&wc->nw_dst_mask, mask);
}
/* Sets the wildcard mask for register 'idx' in 'wc' to 'mask'.
void
flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
{
- if (mask != wc->reg_masks[idx]) {
- wc->reg_masks[idx] = mask;
- if (mask != UINT32_MAX) {
- wc->wildcards |= FWW_REGS;
- } else {
- int i;
-
- for (i = 0; i < FLOW_N_REGS; i++) {
- if (wc->reg_masks[i] != UINT32_MAX) {
- wc->wildcards |= FWW_REGS;
- return;
- }
- }
- wc->wildcards &= ~FWW_REGS;
- }
- }
+ wc->reg_masks[idx] = mask;
}
return hash_bytes(flow, FLOW_SIG_SIZE, basis);
}
-/* Open vSwitch internal-only wildcard bits.
+/* Open vSwitch flow wildcard bits.
*
* These are used only internally to Open vSwitch, in the 'wildcards' member of
* struct flow_wildcards. They never appear in the wire protocol in this
* form. */
-/* Set to 1 if any bits in any of the reg_masks are wildcarded. This maintains
- * the invariant that 'wildcards' is nonzero if and only if any bits are
- * wildcarded. */
-#define FWW_REGS (1u << 31)
-
-/* Set to 1 if bit 0 (the multicast bit) of the flow's dl_dst is wildcarded.
- *
- * (We reinterpret OFPFW_DL_DST as excluding bit 0. Both OFPFW_DL_DST and
- * FWW_ETH_MCAST have to be set to wildcard the entire Ethernet destination
- * address.) */
-#define FWW_ETH_MCAST (1u << 30)
-
-/* Avoid collisions. */
-#define FWW_ALL (FWW_REGS | FWW_ETH_MCAST)
-BUILD_ASSERT_DECL(!(FWW_ALL & OVSFW_ALL));
+typedef unsigned int OVS_BITWISE flow_wildcards_t;
+
+/* Same values and meanings as corresponding OFPFW_* bits. */
+#define FWW_IN_PORT ((OVS_FORCE flow_wildcards_t) (1 << 0))
+#define FWW_DL_VLAN ((OVS_FORCE flow_wildcards_t) (1 << 1))
+#define FWW_DL_SRC ((OVS_FORCE flow_wildcards_t) (1 << 2))
+#define FWW_DL_DST ((OVS_FORCE flow_wildcards_t) (1 << 3))
+ /* excluding the multicast bit */
+#define FWW_DL_TYPE ((OVS_FORCE flow_wildcards_t) (1 << 4))
+#define FWW_NW_PROTO ((OVS_FORCE flow_wildcards_t) (1 << 5))
+#define FWW_TP_SRC ((OVS_FORCE flow_wildcards_t) (1 << 6))
+#define FWW_TP_DST ((OVS_FORCE flow_wildcards_t) (1 << 7))
+/* Same meanings as corresponding OFPFW_* bits, but differ in value. */
+#define FWW_DL_VLAN_PCP ((OVS_FORCE flow_wildcards_t) (1 << 8))
+#define FWW_NW_TOS ((OVS_FORCE flow_wildcards_t) (1 << 9))
+/* No OFPFW_* bits, but they do have corresponding OVSFW_* bits. */
+#define FWW_TUN_ID ((OVS_FORCE flow_wildcards_t) (1 << 10))
+/* No corresponding OFPFW_* or OVSFW_* bits. */
+#define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 11))
+ /* multicast bit only */
+#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 12)) - 1))
/* Information on wildcards for a flow, as a supplement to "struct flow".
*
- * The flow_wildcards_*() functions below both depend on and maintain the
- * following important invariants:
- *
- * 1. 'wildcards' is nonzero if and only if at least one bit or field is
- * wildcarded.
- *
- * 2. Bits in 'wildcards' not included in OVSFW_ALL or FWW_ALL are set to 0.
- * (This is a corollary to invariant #1.)
- *
- * 3. The fields in 'wildcards' masked by OFPFW_NW_SRC_MASK and
- * OFPFW_NW_DST_MASK have values between 0 and 32, inclusive.
- *
- * 4. The fields masked by OFPFW_NW_SRC_MASK and OFPFW_NW_DST_MASK correspond
- * correctly to the masks in 'nw_src_mask' and 'nw_dst_mask', respectively.
- *
- * 5. FWW_REGS is set to 1 in 'wildcards' if and only if at least one bit in
- * 'reg_masks[]' is nonzero. (This allows wildcarded 'reg_masks[]' to
- * satisfy invariant #1.)
- *
- * 6. If FWW_REGS is set to 0 in 'wildcards', then the values of all of the
- * other members can be correctly predicted based on 'wildcards' alone.
- */
+ * Note that the meaning of 1-bits in 'wildcards' is opposite that of 1-bits in
+ * the rest of the members. */
struct flow_wildcards {
- uint32_t wildcards; /* OFPFW_* | OVSFW_* | FWW_*. */
+ flow_wildcards_t wildcards; /* 1-bit in each FWW_* wildcarded field. */
uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
ovs_be32 nw_src_mask; /* 1-bit in each significant nw_src bit. */
ovs_be32 nw_dst_mask; /* 1-bit in each significant nw_dst bit. */
};
-void flow_wildcards_init(struct flow_wildcards *, uint32_t wildcards);
+void flow_wildcards_init_catchall(struct flow_wildcards *);
void flow_wildcards_init_exact(struct flow_wildcards *);
bool flow_wildcards_is_exact(const struct flow_wildcards *);
struct hmap_node hmap_node;
enum nxm_field_index index; /* NFI_* value. */
uint32_t header; /* NXM_* value. */
- uint32_t wildcard; /* Wildcard bit, if exactly one. */
+ flow_wildcards_t wildcard; /* FWW_* bit, if exactly one. */
ovs_be16 dl_type; /* dl_type prerequisite, if nonzero. */
uint8_t nw_proto; /* nw_proto prerequisite, if nonzero. */
const char *name; /* "NXM_*" string. */
static int
parse_tci(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
{
- enum { OFPFW_DL_TCI = OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP };
- if ((rule->wc.wildcards & OFPFW_DL_TCI) != OFPFW_DL_TCI) {
+ const flow_wildcards_t FWW_DL_TCI = FWW_DL_VLAN | FWW_DL_VLAN_PCP;
+
+ if ((rule->wc.wildcards & FWW_DL_TCI) != FWW_DL_TCI) {
return NXM_DUP_TYPE;
} else {
return cls_rule_set_dl_tci_masked(rule, tci, mask) ? 0 : NXM_INVALID;
/* Ethernet header. */
case NFI_NXM_OF_ETH_DST:
- if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
- != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
+ if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
+ != (FWW_DL_DST | FWW_ETH_MCAST)) {
return NXM_DUP_TYPE;
} else {
- wc->wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
+ wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
return 0;
}
case NFI_NXM_OF_ETH_DST_W:
- if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
- != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
+ if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
+ != (FWW_DL_DST | FWW_ETH_MCAST)) {
return NXM_DUP_TYPE;
} else if (eth_addr_equals(mask, eth_mcast_1)) {
wc->wildcards &= ~FWW_ETH_MCAST;
flow->dl_dst[0] = *(uint8_t *) value & 0x01;
} else if (eth_addr_equals(mask, eth_mcast_0)) {
- wc->wildcards &= ~OFPFW_DL_DST;
+ wc->wildcards &= ~FWW_DL_DST;
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
flow->dl_dst[0] &= 0xfe;
} else if (eth_addr_equals(mask, eth_all_0s)) {
return 0;
} else if (eth_addr_equals(mask, eth_all_1s)) {
- wc->wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
+ wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
return 0;
} else {
nxm_put_eth_dst(struct ofpbuf *b,
uint32_t wc, const uint8_t value[ETH_ADDR_LEN])
{
- switch (wc & (OFPFW_DL_DST | FWW_ETH_MCAST)) {
- case OFPFW_DL_DST | FWW_ETH_MCAST:
+ switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) {
+ case FWW_DL_DST | FWW_ETH_MCAST:
break;
- case OFPFW_DL_DST:
+ case FWW_DL_DST:
nxm_put_header(b, NXM_OF_ETH_DST_W);
ofpbuf_put(b, value, ETH_ADDR_LEN);
ofpbuf_put(b, eth_mcast_1, ETH_ADDR_LEN);
int
nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
{
- const uint32_t wc = cr->wc.wildcards;
+ const flow_wildcards_t wc = cr->wc.wildcards;
const struct flow *flow = &cr->flow;
const size_t start_len = b->size;
ovs_be16 vid, pcp;
int i;
/* Metadata. */
- if (!(wc & OFPFW_IN_PORT)) {
+ if (!(wc & FWW_IN_PORT)) {
uint16_t in_port = flow->in_port;
if (in_port == ODPP_LOCAL) {
in_port = OFPP_LOCAL;
/* Ethernet. */
nxm_put_eth_dst(b, wc, flow->dl_dst);
- if (!(wc & OFPFW_DL_SRC)) {
+ if (!(wc & FWW_DL_SRC)) {
nxm_put_eth(b, NXM_OF_ETH_SRC, flow->dl_src);
}
- if (!(wc & OFPFW_DL_TYPE)) {
+ if (!(wc & FWW_DL_TYPE)) {
nxm_put_16(b, NXM_OF_ETH_TYPE, flow->dl_type);
}
/* 802.1Q. */
vid = flow->dl_vlan & htons(VLAN_VID_MASK);
pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
- switch (wc & (OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP)) {
- case OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP:
+ switch (wc & (FWW_DL_VLAN | FWW_DL_VLAN_PCP)) {
+ case FWW_DL_VLAN | FWW_DL_VLAN_PCP:
break;
- case OFPFW_DL_VLAN:
+ case FWW_DL_VLAN:
nxm_put_16w(b, NXM_OF_VLAN_TCI_W, pcp | htons(VLAN_CFI),
htons(VLAN_PCP_MASK | VLAN_CFI));
break;
- case OFPFW_DL_VLAN_PCP:
+ case FWW_DL_VLAN_PCP:
if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
nxm_put_16(b, NXM_OF_VLAN_TCI, 0);
} else {
break;
}
- if (!(wc & OFPFW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
+ if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
/* IP. */
- if (!(wc & OFPFW_NW_TOS)) {
+ if (!(wc & FWW_NW_TOS)) {
nxm_put_8(b, NXM_OF_IP_TOS, flow->nw_tos & 0xfc);
}
nxm_put_32m(b, NXM_OF_IP_SRC, flow->nw_src, cr->wc.nw_src_mask);
nxm_put_32m(b, NXM_OF_IP_DST, flow->nw_dst, cr->wc.nw_dst_mask);
- if (!(wc & OFPFW_NW_PROTO)) {
+ if (!(wc & FWW_NW_PROTO)) {
nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
switch (flow->nw_proto) {
/* TCP. */
case IP_TYPE_TCP:
- if (!(wc & OFPFW_TP_SRC)) {
+ if (!(wc & FWW_TP_SRC)) {
nxm_put_16(b, NXM_OF_TCP_SRC, flow->tp_src);
}
- if (!(wc & OFPFW_TP_DST)) {
+ if (!(wc & FWW_TP_DST)) {
nxm_put_16(b, NXM_OF_TCP_DST, flow->tp_dst);
}
break;
/* UDP. */
case IP_TYPE_UDP:
- if (!(wc & OFPFW_TP_SRC)) {
+ if (!(wc & FWW_TP_SRC)) {
nxm_put_16(b, NXM_OF_UDP_SRC, flow->tp_src);
}
- if (!(wc & OFPFW_TP_DST)) {
+ if (!(wc & FWW_TP_DST)) {
nxm_put_16(b, NXM_OF_UDP_DST, flow->tp_dst);
}
break;
/* ICMP. */
case IP_TYPE_ICMP:
- if (!(wc & OFPFW_TP_SRC)) {
+ if (!(wc & FWW_TP_SRC)) {
nxm_put_8(b, NXM_OF_ICMP_TYPE, ntohs(flow->tp_src));
}
- if (!(wc & OFPFW_TP_DST)) {
+ if (!(wc & FWW_TP_DST)) {
nxm_put_8(b, NXM_OF_ICMP_CODE, ntohs(flow->tp_dst));
}
break;
}
}
- } else if (!(wc & OFPFW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
+ } else if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
/* ARP. */
- if (!(wc & OFPFW_NW_PROTO)) {
+ if (!(wc & FWW_NW_PROTO)) {
nxm_put_16(b, NXM_OF_ARP_OP, htons(flow->nw_proto));
}
nxm_put_32m(b, NXM_OF_ARP_SPA, flow->nw_src, cr->wc.nw_src_mask);
}
/* Tunnel ID. */
- if (!(wc & NXFW_TUN_ID)) {
+ if (!(wc & FWW_TUN_ID)) {
nxm_put_64(b, NXM_NX_TUN_ID, htonll(ntohl(flow->tun_id)));
}
DEFINE_FIELD(HEADER, WILDCARD, DL_TYPE, NW_PROTO) \
DEFINE_FIELD(HEADER##_W, WILDCARD, DL_TYPE, NW_PROTO)
-/* NXM_ bit OFPFW_* bit dl_type nw_proto */
-/* ------------ -------------- ----------- ------------- */
-DEFINE_FIELD (OF_IN_PORT, OFPFW_IN_PORT, 0, 0)
-DEFINE_FIELD_M(OF_ETH_DST, 0, 0, 0)
-DEFINE_FIELD (OF_ETH_SRC, OFPFW_DL_SRC, 0, 0)
-DEFINE_FIELD (OF_ETH_TYPE, OFPFW_DL_TYPE, 0, 0)
-DEFINE_FIELD_M(OF_VLAN_TCI, 0, 0, 0)
-DEFINE_FIELD (OF_IP_TOS, OFPFW_NW_TOS, ETH_TYPE_IP, 0)
-DEFINE_FIELD (OF_IP_PROTO, OFPFW_NW_PROTO, ETH_TYPE_IP, 0)
-DEFINE_FIELD_M(OF_IP_SRC, 0, ETH_TYPE_IP, 0)
-DEFINE_FIELD_M(OF_IP_DST, 0, ETH_TYPE_IP, 0)
-DEFINE_FIELD (OF_TCP_SRC, OFPFW_TP_SRC, ETH_TYPE_IP, IP_TYPE_TCP)
-DEFINE_FIELD (OF_TCP_DST, OFPFW_TP_DST, ETH_TYPE_IP, IP_TYPE_TCP)
-DEFINE_FIELD (OF_UDP_SRC, OFPFW_TP_SRC, ETH_TYPE_IP, IP_TYPE_UDP)
-DEFINE_FIELD (OF_UDP_DST, OFPFW_TP_DST, ETH_TYPE_IP, IP_TYPE_UDP)
-DEFINE_FIELD (OF_ICMP_TYPE, OFPFW_TP_SRC, ETH_TYPE_IP, IP_TYPE_ICMP)
-DEFINE_FIELD (OF_ICMP_CODE, OFPFW_TP_DST, ETH_TYPE_IP, IP_TYPE_ICMP)
-DEFINE_FIELD (OF_ARP_OP, OFPFW_NW_PROTO, ETH_TYPE_ARP, 0)
-DEFINE_FIELD_M(OF_ARP_SPA, 0, ETH_TYPE_ARP, 0)
-DEFINE_FIELD_M(OF_ARP_TPA, 0, ETH_TYPE_ARP, 0)
-DEFINE_FIELD (NX_TUN_ID, NXFW_TUN_ID, 0, 0)
+/* NXM_ suffix FWW_* bit dl_type nw_proto */
+/* ------------ ------------ ----------- ------------- */
+DEFINE_FIELD (OF_IN_PORT, FWW_IN_PORT, 0, 0)
+DEFINE_FIELD_M(OF_ETH_DST, 0, 0, 0)
+DEFINE_FIELD (OF_ETH_SRC, FWW_DL_SRC, 0, 0)
+DEFINE_FIELD (OF_ETH_TYPE, FWW_DL_TYPE, 0, 0)
+DEFINE_FIELD_M(OF_VLAN_TCI, 0, 0, 0)
+DEFINE_FIELD (OF_IP_TOS, FWW_NW_TOS, ETH_TYPE_IP, 0)
+DEFINE_FIELD (OF_IP_PROTO, FWW_NW_PROTO, ETH_TYPE_IP, 0)
+DEFINE_FIELD_M(OF_IP_SRC, 0, ETH_TYPE_IP, 0)
+DEFINE_FIELD_M(OF_IP_DST, 0, ETH_TYPE_IP, 0)
+DEFINE_FIELD (OF_TCP_SRC, FWW_TP_SRC, ETH_TYPE_IP, IP_TYPE_TCP)
+DEFINE_FIELD (OF_TCP_DST, FWW_TP_DST, ETH_TYPE_IP, IP_TYPE_TCP)
+DEFINE_FIELD (OF_UDP_SRC, FWW_TP_SRC, ETH_TYPE_IP, IP_TYPE_UDP)
+DEFINE_FIELD (OF_UDP_DST, FWW_TP_DST, ETH_TYPE_IP, IP_TYPE_UDP)
+DEFINE_FIELD (OF_ICMP_TYPE, FWW_TP_SRC, ETH_TYPE_IP, IP_TYPE_ICMP)
+DEFINE_FIELD (OF_ICMP_CODE, FWW_TP_DST, ETH_TYPE_IP, IP_TYPE_ICMP)
+DEFINE_FIELD (OF_ARP_OP, FWW_NW_PROTO, ETH_TYPE_ARP, 0)
+DEFINE_FIELD_M(OF_ARP_SPA, 0, ETH_TYPE_ARP, 0)
+DEFINE_FIELD_M(OF_ARP_TPA, 0, ETH_TYPE_ARP, 0)
+DEFINE_FIELD (NX_TUN_ID, FWW_TUN_ID, 0, 0)
-DEFINE_FIELD_M(NX_REG0, 0, 0, 0)
+DEFINE_FIELD_M(NX_REG0, 0, 0, 0)
#if FLOW_N_REGS >= 2
-DEFINE_FIELD_M(NX_REG1, 0, 0, 0)
+DEFINE_FIELD_M(NX_REG1, 0, 0, 0)
#endif
#if FLOW_N_REGS >= 3
-DEFINE_FIELD_M(NX_REG2, 0, 0, 0)
+DEFINE_FIELD_M(NX_REG2, 0, 0, 0)
#endif
#if FLOW_N_REGS >= 4
-DEFINE_FIELD_M(NX_REG3, 0, 0, 0)
+DEFINE_FIELD_M(NX_REG3, 0, 0, 0)
#endif
#if FLOW_N_REGS > 4
#error
}
#define FIELDS \
- FIELD(F_IN_PORT, "in_port", OFPFW_IN_PORT) \
- FIELD(F_DL_VLAN, "dl_vlan", OFPFW_DL_VLAN) \
- FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", OFPFW_DL_VLAN_PCP) \
- FIELD(F_DL_SRC, "dl_src", OFPFW_DL_SRC) \
- FIELD(F_DL_DST, "dl_dst", OFPFW_DL_DST) \
- FIELD(F_DL_TYPE, "dl_type", OFPFW_DL_TYPE) \
+ FIELD(F_IN_PORT, "in_port", FWW_IN_PORT) \
+ FIELD(F_DL_VLAN, "dl_vlan", FWW_DL_VLAN) \
+ FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", FWW_DL_VLAN_PCP) \
+ FIELD(F_DL_SRC, "dl_src", FWW_DL_SRC) \
+ FIELD(F_DL_DST, "dl_dst", FWW_DL_DST) \
+ FIELD(F_DL_TYPE, "dl_type", FWW_DL_TYPE) \
FIELD(F_NW_SRC, "nw_src", 0) \
FIELD(F_NW_DST, "nw_dst", 0) \
- FIELD(F_NW_PROTO, "nw_proto", OFPFW_NW_PROTO) \
- FIELD(F_NW_TOS, "nw_tos", OFPFW_NW_TOS) \
- FIELD(F_TP_SRC, "tp_src", OFPFW_TP_SRC) \
- FIELD(F_TP_DST, "tp_dst", OFPFW_TP_DST) \
- FIELD(F_ICMP_TYPE, "icmp_type", OFPFW_ICMP_TYPE) \
- FIELD(F_ICMP_CODE, "icmp_code", OFPFW_ICMP_CODE)
+ FIELD(F_NW_PROTO, "nw_proto", FWW_NW_PROTO) \
+ FIELD(F_NW_TOS, "nw_tos", FWW_NW_TOS) \
+ FIELD(F_TP_SRC, "tp_src", FWW_TP_SRC) \
+ FIELD(F_TP_DST, "tp_dst", FWW_TP_DST) \
+ FIELD(F_ICMP_TYPE, "icmp_type", FWW_TP_SRC) \
+ FIELD(F_ICMP_CODE, "icmp_code", FWW_TP_DST)
enum field_index {
#define FIELD(ENUM, NAME, WILDCARD) ENUM,
struct field {
enum field_index index;
const char *name;
- uint32_t wildcard;
+ flow_wildcards_t wildcard; /* FWW_* bit. */
};
static bool
parse_ofp_str(&pf, buffer, string);
ofm = buffer->data;
- cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &ofm->match);
+ ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &ofm->match);
ofm->command = htons(command);
ofm->cookie = htonll(pf.cookie);
ofm->idle_timeout = htons(pf.idle_timeout);
#include <inttypes.h>
#include <stdlib.h>
#include "byte-order.h"
+#include "classifier.h"
#include "nx-match.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#endif
}
+/* A list of the FWW_* and OFPFW_ bits that have the same value, meaning, and
+ * name. */
+#define WC_INVARIANT_LIST \
+ WC_INVARIANT_BIT(IN_PORT) \
+ WC_INVARIANT_BIT(DL_VLAN) \
+ WC_INVARIANT_BIT(DL_SRC) \
+ WC_INVARIANT_BIT(DL_DST) \
+ WC_INVARIANT_BIT(DL_TYPE) \
+ WC_INVARIANT_BIT(NW_PROTO) \
+ WC_INVARIANT_BIT(TP_SRC) \
+ WC_INVARIANT_BIT(TP_DST)
+
+/* Verify that all of the invariant bits (as defined on WC_INVARIANT_LIST)
+ * actually have the same names and values. */
+#define WC_INVARIANT_BIT(NAME) BUILD_ASSERT_DECL(FWW_##NAME == OFPFW_##NAME);
+ WC_INVARIANT_LIST
+#undef WC_INVARIANT_BIT
+
+/* WC_INVARIANTS is the invariant bits (as defined on WC_INVARIANT_LIST) all
+ * OR'd together. */
+enum {
+ WC_INVARIANTS = 0
+#define WC_INVARIANT_BIT(NAME) | FWW_##NAME
+ WC_INVARIANT_LIST
+#undef WC_INVARIANT_BIT
+};
+
+/* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
+ * 'priority'.
+ *
+ * 'flow_format' must either NXFF_OPENFLOW10 or NXFF_TUN_ID_FROM_COOKIE. In
+ * the latter case only, 'flow''s tun_id field will be taken from the high bits
+ * of 'cookie', if 'match''s wildcards do not indicate that tun_id is
+ * wildcarded. */
+void
+ofputil_cls_rule_from_match(const struct ofp_match *match,
+ unsigned int priority, int flow_format,
+ uint64_t cookie, struct cls_rule *rule)
+{
+ struct flow_wildcards *wc = &rule->wc;
+ unsigned int ofpfw;
+
+ /* Initialize rule->priority. */
+ ofpfw = ntohl(match->wildcards);
+ ofpfw &= flow_format == NXFF_TUN_ID_FROM_COOKIE ? OVSFW_ALL : OFPFW_ALL;
+ rule->priority = !ofpfw ? UINT16_MAX : priority;
+
+ /* Initialize most of rule->wc. */
+ wc->wildcards = ofpfw & WC_INVARIANTS;
+ if (ofpfw & OFPFW_DL_VLAN_PCP) {
+ wc->wildcards |= FWW_DL_VLAN_PCP;
+ }
+ if (ofpfw & OFPFW_NW_TOS) {
+ wc->wildcards |= FWW_NW_TOS;
+ }
+ memset(wc->reg_masks, 0, sizeof wc->reg_masks);
+ wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_SRC_SHIFT);
+ wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_DST_SHIFT);
+
+ if (!(ofpfw & NXFW_TUN_ID)) {
+ rule->flow.tun_id = htonl(ntohll(cookie) >> 32);
+ } else {
+ wc->wildcards |= FWW_TUN_ID;
+ rule->flow.tun_id = 0;
+ }
+
+ if (ofpfw & OFPFW_DL_DST) {
+ /* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but
+ * Open vSwitch breaks the Ethernet destination into bits as FWW_DL_DST
+ * and FWW_ETH_MCAST. */
+ wc->wildcards |= FWW_ETH_MCAST;
+ }
+
+ /* Initialize rule->flow. */
+ rule->flow.nw_src = match->nw_src;
+ rule->flow.nw_dst = match->nw_dst;
+ rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
+ : ntohs(match->in_port));
+ rule->flow.dl_vlan = match->dl_vlan;
+ rule->flow.dl_vlan_pcp = match->dl_vlan_pcp;
+ rule->flow.dl_type = 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;
+ rule->flow.nw_proto = match->nw_proto;
+
+ /* Clean up. */
+ cls_rule_zero_wildcarded_fields(rule);
+}
+
+/* Extract 'flow' with 'wildcards' into the OpenFlow match structure
+ * 'match'.
+ *
+ * 'flow_format' must either NXFF_OPENFLOW10 or NXFF_TUN_ID_FROM_COOKIE. In
+ * the latter case only, 'match''s NXFW_TUN_ID bit will be filled in; otherwise
+ * it is always set to 0. */
+void
+ofputil_cls_rule_to_match(const struct cls_rule *rule, int flow_format,
+ struct ofp_match *match)
+{
+ const struct flow_wildcards *wc = &rule->wc;
+ unsigned int ofpfw;
+
+ /* Figure out OpenFlow wildcards. */
+ ofpfw = wc->wildcards & WC_INVARIANTS;
+ ofpfw |= ofputil_netmask_to_wcbits(wc->nw_src_mask) << OFPFW_NW_SRC_SHIFT;
+ ofpfw |= ofputil_netmask_to_wcbits(wc->nw_dst_mask) << OFPFW_NW_DST_SHIFT;
+ if (wc->wildcards & FWW_DL_VLAN_PCP) {
+ ofpfw |= OFPFW_DL_VLAN_PCP;
+ }
+ if (wc->wildcards & FWW_NW_TOS) {
+ ofpfw |= OFPFW_NW_TOS;
+ }
+ if (flow_format == NXFF_TUN_ID_FROM_COOKIE && wc->wildcards & FWW_TUN_ID) {
+ ofpfw |= NXFW_TUN_ID;
+ }
+
+ /* Compose match structure. */
+ match->wildcards = htonl(ofpfw);
+ match->in_port = htons(rule->flow.in_port == ODPP_LOCAL ? OFPP_LOCAL
+ : rule->flow.in_port);
+ match->dl_vlan = rule->flow.dl_vlan;
+ match->dl_vlan_pcp = rule->flow.dl_vlan_pcp;
+ 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 = 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;
+ 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);
+}
+
/* Returns a transaction ID to use for an outgoing OpenFlow message. */
static ovs_be32
alloc_xid(void)
#include "flow.h"
#include "openvswitch/types.h"
+struct cls_rule;
struct ofpbuf;
struct ofp_action_header;
ovs_be32 ofputil_wcbits_to_netmask(int wcbits);
int ofputil_netmask_to_wcbits(ovs_be32 netmask);
+/* Work with OpenFlow 1.0 ofp_match. */
+void ofputil_cls_rule_from_match(const struct ofp_match *,
+ unsigned int priority, int flow_format,
+ uint64_t cookie, struct cls_rule *);
+void ofputil_cls_rule_to_match(const struct cls_rule *, int flow_format,
+ struct ofp_match *);
+void normalize_match(struct ofp_match *);
+char *ofp_match_to_literal_string(const struct ofp_match *match);
+
/* OpenFlow protocol utility functions. */
void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
void *make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **);
const struct flow *, int max_ports);
bool action_outputs_to_port(const union ofp_action *, uint16_t port);
-void normalize_match(struct ofp_match *);
-char *ofp_match_to_literal_string(const struct ofp_match *match);
-
int ofputil_pull_actions(struct ofpbuf *, unsigned int actions_len,
union ofp_action **, size_t *);
\f
ofs->length = htons(len);
ofs->table_id = 0;
ofs->pad = 0;
- cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofs->match);
+ ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofs->match);
calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec);
ofs->cookie = rule->flow_cookie;
ofs->priority = htons(rule->cr.priority);
struct cls_rule target;
struct rule *rule;
- cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, &target);
+ ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0,
+ &target);
cls_cursor_init(&cursor, &ofconn->ofproto->cls, &target);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply);
size_t act_len = sizeof *rule->actions * rule->n_actions;
query_stats(ofproto, rule, &packet_count, &byte_count);
- cls_rule_to_match(&rule->cr, NXFF_OPENFLOW10, &match);
+ ofputil_cls_rule_to_match(&rule->cr, NXFF_OPENFLOW10, &match);
ds_put_format(results, "duration=%llds, ",
(time_msec() - rule->created) / 1000);
}
request = (struct ofp_aggregate_stats_request *) osr->body;
- cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, &target);
+ ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0,
+ &target);
msg = start_ofp_stats_reply(osr, sizeof *reply);
reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg);
}
/* Translate the message. */
- cls_rule_from_match(&ofm->match, ntohs(ofm->priority), ofconn->flow_format,
- ofm->cookie, &fm.cr);
+ ofputil_cls_rule_from_match(&ofm->match, ntohs(ofm->priority),
+ ofconn->flow_format, ofm->cookie, &fm.cr);
fm.cookie = ofm->cookie;
fm.command = ntohs(ofm->command);
fm.idle_timeout = ntohs(ofm->idle_timeout);
struct ofpbuf *buf;
ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
- cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match);
+ ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match);
ofr->cookie = rule->flow_cookie;
ofr->priority = htons(rule->cr.priority);
ofr->reason = reason;
#include <assert.h>
/* Fields in a rule. */
-#define CLS_FIELDS \
- /* struct flow all-caps */ \
- /* wildcard bit(s) member name name */ \
- /* ----------------- ----------- -------- */ \
- CLS_FIELD(NXFW_TUN_ID, tun_id, TUN_ID) \
- CLS_FIELD(OFPFW_NW_SRC_MASK, nw_src, NW_SRC) \
- CLS_FIELD(OFPFW_NW_DST_MASK, nw_dst, NW_DST) \
- CLS_FIELD(OFPFW_IN_PORT, in_port, IN_PORT) \
- CLS_FIELD(OFPFW_DL_VLAN, dl_vlan, DL_VLAN) \
- CLS_FIELD(OFPFW_DL_TYPE, dl_type, DL_TYPE) \
- CLS_FIELD(OFPFW_TP_SRC, tp_src, TP_SRC) \
- CLS_FIELD(OFPFW_TP_DST, tp_dst, TP_DST) \
- CLS_FIELD(OFPFW_DL_SRC, dl_src, DL_SRC) \
- CLS_FIELD(OFPFW_DL_DST | FWW_ETH_MCAST, \
- dl_dst, DL_DST) \
- CLS_FIELD(OFPFW_NW_PROTO, nw_proto, NW_PROTO) \
- CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \
- CLS_FIELD(OFPFW_NW_TOS, nw_tos, NW_TOS)
+#define CLS_FIELDS \
+ /* struct flow all-caps */ \
+ /* FWW_* bit(s) member name name */ \
+ /* -------------------------- ----------- -------- */ \
+ CLS_FIELD(FWW_TUN_ID, tun_id, TUN_ID) \
+ CLS_FIELD(0, nw_src, NW_SRC) \
+ CLS_FIELD(0, nw_dst, NW_DST) \
+ CLS_FIELD(FWW_IN_PORT, in_port, IN_PORT) \
+ CLS_FIELD(FWW_DL_VLAN, dl_vlan, DL_VLAN) \
+ CLS_FIELD(FWW_DL_TYPE, dl_type, DL_TYPE) \
+ CLS_FIELD(FWW_TP_SRC, tp_src, TP_SRC) \
+ CLS_FIELD(FWW_TP_DST, tp_dst, TP_DST) \
+ CLS_FIELD(FWW_DL_SRC, dl_src, DL_SRC) \
+ CLS_FIELD(FWW_DL_DST | FWW_ETH_MCAST, dl_dst, DL_DST) \
+ CLS_FIELD(FWW_NW_PROTO, nw_proto, NW_PROTO) \
+ CLS_FIELD(FWW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \
+ CLS_FIELD(FWW_NW_TOS, nw_tos, NW_TOS)
/* Field indexes.
*
struct cls_field {
int ofs; /* Offset in struct flow. */
int len; /* Length in bytes. */
- uint32_t wildcards; /* OFPFW_* bit or bits for this field. */
+ flow_wildcards_t wildcards; /* FWW_* bit or bits for this field. */
const char *name; /* Name (for debugging). */
};
for (f_idx = 0; f_idx < CLS_N_FIELDS; f_idx++) {
const struct cls_field *f = &cls_fields[f_idx];
- void *wild_field = (char *) &wild->flow + f->ofs;
- void *fixed_field = (char *) fixed + f->ofs;
-
- if ((wild->wc.wildcards & f->wildcards) == f->wildcards ||
- !memcmp(wild_field, fixed_field, f->len)) {
- /* Definite match. */
- continue;
+ bool eq;
+
+ if (f->wildcards) {
+ void *wild_field = (char *) &wild->flow + f->ofs;
+ void *fixed_field = (char *) fixed + f->ofs;
+ eq = ((wild->wc.wildcards & f->wildcards) == f->wildcards
+ || !memcmp(wild_field, fixed_field, f->len));
+ } else if (f_idx == CLS_F_IDX_NW_SRC) {
+ eq = !((fixed->nw_src ^ wild->flow.nw_src) & wild->wc.nw_src_mask);
+ } else if (f_idx == CLS_F_IDX_NW_DST) {
+ eq = !((fixed->nw_dst ^ wild->flow.nw_dst) & wild->wc.nw_dst_mask);
+ } else {
+ NOT_REACHED();
}
- if (wild->wc.wildcards & f->wildcards) {
- uint32_t test = get_unaligned_u32(wild_field);
- uint32_t ip = get_unaligned_u32(fixed_field);
- uint32_t mask;
- int shift;
-
- shift = (f_idx == CLS_F_IDX_NW_SRC
- ? OFPFW_NW_SRC_SHIFT : OFPFW_NW_DST_SHIFT);
- mask = ofputil_wcbits_to_netmask(wild->wc.wildcards >> shift);
- if (!((test ^ ip) & mask)) {
- continue;
- }
+ if (!eq) {
+ return false;
}
-
- return false;
}
return true;
}
make_rule(int wc_fields, unsigned int priority, int value_pat)
{
const struct cls_field *f;
- struct flow_wildcards wc;
struct test_rule *rule;
- uint32_t wildcards;
- struct flow flow;
- wildcards = 0;
- memset(&flow, 0, sizeof flow);
+ rule = xzalloc(sizeof *rule);
+ cls_rule_init_catchall(&rule->cls_rule, wc_fields ? priority : UINT_MAX);
for (f = &cls_fields[0]; f < &cls_fields[CLS_N_FIELDS]; f++) {
int f_idx = f - cls_fields;
- if (wc_fields & (1u << f_idx)) {
- wildcards |= f->wildcards;
+ int value_idx = (value_pat & (1u << f_idx)) != 0;
+ memcpy((char *) &rule->cls_rule.flow + f->ofs,
+ values[f_idx][value_idx], f->len);
+
+ if (f->wildcards) {
+ rule->cls_rule.wc.wildcards &= ~f->wildcards;
+ } else if (f_idx == CLS_F_IDX_NW_SRC) {
+ rule->cls_rule.wc.nw_src_mask = htonl(UINT32_MAX);
+ } else if (f_idx == CLS_F_IDX_NW_DST) {
+ rule->cls_rule.wc.nw_dst_mask = htonl(UINT32_MAX);
} else {
- int value_idx = (value_pat & (1u << f_idx)) != 0;
- memcpy((char *) &flow + f->ofs, values[f_idx][value_idx], f->len);
+ NOT_REACHED();
}
}
-
- rule = xzalloc(sizeof *rule);
- flow_wildcards_init(&wc, wildcards);
- cls_rule_init(&flow, &wc, !wildcards ? UINT_MAX : priority,
- &rule->cls_rule);
return rule;
}
flow_extract(packet, 0, 1, &flow);
cls_rule_init_exact(&flow, 0, &rule);
- cls_rule_to_match(&rule, NXFF_OPENFLOW10, &extracted_match);
+ ofputil_cls_rule_to_match(&rule, NXFF_OPENFLOW10, &extracted_match);
if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
char *exp_s = ofp_match_to_string(&expected_match, 2);
req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
- cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
+ ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(pf.out_port);
req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
- cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
+ ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(pf.out_port);