+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.vlan_tci_mask = 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.vlan_tci_mask & htons(VLAN_PCP_MASK)) {
+ rule->wc.vlan_tci_mask &= ~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':
+ *
+ * - If 'dl_vlan' is htons(OFP_VLAN_NONE), makes 'rule' match only packets
+ * without an 802.1Q header.
+ *
+ * - 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)
+{
+ if (dl_vlan == htons(OFP_VLAN_NONE)) {
+ cls_rule_set_dl_tci(rule, htons(0));
+ } else {
+ dl_vlan &= htons(VLAN_VID_MASK);
+ rule->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
+ rule->flow.vlan_tci |= htons(VLAN_CFI) | dl_vlan;
+ rule->wc.vlan_tci_mask |= htons(VLAN_VID_MASK | VLAN_CFI);
+ }
+}
+
+/* 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.vlan_tci_mask & htons(VLAN_VID_MASK)) {
+ rule->wc.vlan_tci_mask &= ~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)
+{
+ dl_vlan_pcp &= 0x07;
+ rule->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
+ rule->flow.vlan_tci |= htons((dl_vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
+ rule->wc.vlan_tci_mask |= htons(VLAN_CFI | VLAN_PCP_MASK);
+}
+