cls_table_next_rule(const struct cls_table *table, const struct cls_rule *rule)
{
struct cls_rule *next
- = CONTAINER_OF(rule->list.next, struct cls_rule, hmap_node);
+ = CONTAINER_OF(rule->list.next, struct cls_rule, list);
return (next->priority < rule->priority
? next
&next->hmap_node)));
}
-static void
-cls_rule_init__(struct cls_rule *rule,
- const struct flow *flow, uint32_t wildcards)
+/* 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;
- flow_wildcards_init(&rule->wc, wildcards);
+ rule->wc = *wildcards;
+ rule->priority = priority;
cls_rule_zero_wildcarded_fields(rule);
}
-/* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
- * 'wildcards' and 'priority'.*/
+/* 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_from_flow(const struct flow *flow, uint32_t wildcards,
- unsigned int priority, struct cls_rule *rule)
+cls_rule_init_exact(const struct flow *flow,
+ unsigned int priority, struct cls_rule *rule)
{
- cls_rule_init__(rule, flow, wildcards);
+ rule->flow = *flow;
+ flow_wildcards_init_exact(&rule->wc);
rule->priority = priority;
}
int flow_format, uint64_t cookie,
struct cls_rule *rule)
{
- uint32_t wildcards;
- struct flow flow;
-
- flow_from_match(match, flow_format, cookie, &flow, &wildcards);
- cls_rule_init__(rule, &flow, wildcards);
- rule->priority = rule->wc.wildcards ? priority : UINT16_MAX;
+ flow_from_match(match, flow_format, cookie, &rule->flow, &rule->wc);
+ rule->priority = !rule->wc.wildcards ? UINT16_MAX : priority;
+ cls_rule_zero_wildcarded_fields(rule);
}
/* Initializes 'rule' as a "catch-all" rule that matches every packet, with
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);
+ flow_wildcards_init(&rule->wc, OVSFW_ALL | FWW_ALL);
rule->priority = priority;
}
void
cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
{
- rule->wc.wildcards &= ~OFPFW_DL_DST;
+ rule->wc.wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN);
}
+bool
+cls_rule_set_dl_tci(struct cls_rule *rule, ovs_be16 tci)
+{
+ return cls_rule_set_dl_tci_masked(rule, tci, htons(0xffff));
+}
+
+bool
+cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
+{
+ switch (ntohs(mask)) {
+ 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->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->flow.dl_vlan = htons(vlan_tci_to_vid(tci));
+ rule->flow.dl_vlan_pcp = vlan_tci_to_pcp(tci);
+ return true;
+ } else {
+ /* Impossible. */
+ return false;
+ }
+
+ case 0x1fff:
+ if (!(tci & htons(VLAN_CFI))) {
+ return false;
+ } 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->flow.dl_vlan_pcp = 0;
+ return true;
+ }
+
+ case 0xf000:
+ if (!(tci & htons(VLAN_CFI))) {
+ return false;
+ } 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->flow.dl_vlan = 0;
+ return true;
+ }
+
+ case 0x0000:
+ /* Match anything. */
+ rule->wc.wildcards |= OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP;
+ rule->flow.dl_vlan = htons(0);
+ rule->flow.dl_vlan_pcp = 0;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void
+cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan)
+{
+ if (dl_vlan != htons(OFP_VLAN_NONE)) {
+ dl_vlan &= htons(VLAN_VID_MASK);
+ }
+
+ rule->wc.wildcards &= ~OFPFW_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->flow.dl_vlan_pcp = dl_vlan_pcp & 0x07;
+}
+
void
cls_rule_set_tp_src(struct cls_rule *rule, ovs_be16 tp_src)
{
void
cls_rule_set_nw_src(struct cls_rule *rule, ovs_be32 nw_src)
{
- flow_wildcards_set_nw_src_mask(&rule->wc, htonl(UINT32_MAX));
- rule->flow.nw_src = nw_src;
+ cls_rule_set_nw_src_masked(rule, nw_src, htonl(UINT32_MAX));
+}
+
+bool
+cls_rule_set_nw_src_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask)
+{
+ if (flow_wildcards_set_nw_src_mask(&rule->wc, mask)) {
+ rule->flow.nw_src = ip & mask;
+ return true;
+ } else {
+ return false;
+ }
}
void
cls_rule_set_nw_dst(struct cls_rule *rule, ovs_be32 nw_dst)
{
- flow_wildcards_set_nw_dst_mask(&rule->wc, htonl(UINT32_MAX));
- rule->flow.nw_dst = nw_dst;
+ cls_rule_set_nw_dst_masked(rule, nw_dst, htonl(UINT32_MAX));
+}
+
+bool
+cls_rule_set_nw_dst_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask)
+{
+ if (flow_wildcards_set_nw_dst_mask(&rule->wc, mask)) {
+ rule->flow.nw_dst = ip & mask;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void
+cls_rule_set_nw_tos(struct cls_rule *rule, uint8_t nw_tos)
+{
+ rule->wc.wildcards &= ~OFPFW_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->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->flow.icmp_code = htons(icmp_code);
}
/* Converts 'rule' to a string and returns the string. The caller must free
const struct flow_wildcards *wildcards)
{
const uint32_t wc = wildcards->wildcards;
+ int i;
+
+ BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + FLOW_N_REGS * 4);
- BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37);
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
+ return false;
+ }
+ }
return ((wc & NXFW_TUN_ID || a->tun_id == b->tun_id)
&& !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask)
&& (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 || eth_addr_equals(a->dl_dst, b->dl_dst))
+ && (wc & OFPFW_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));
zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
{
const uint32_t wc = wildcards->wildcards;
+ int i;
- BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37);
+ 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) {
flow->tun_id = 0;
}
memset(flow->dl_src, 0, sizeof flow->dl_src);
}
if (wc & OFPFW_DL_DST) {
- memset(flow->dl_dst, 0, sizeof flow->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) {
flow->nw_proto = 0;