receive the generated messages.)
+VLAN Matching
+=============
+
+The 802.1Q VLAN header causes more trouble than any other 4 bytes in
+networking. More specifically, three versions of OpenFlow and Open
+vSwitch have among them four different ways to match the contents and
+presence of the VLAN header. The following table describes how each
+version works.
+
+ Match NXM OF1.0 OF1.1 OF1.2
+ ----- --------- ----------- ----------- ------------
+ [1] 0000/0000 ????/1,??/? ????/1,??/? 0000/0000,--
+ [2] 0000/ffff ffff/0,??/? ffff/0,??/? 0000/ffff,--
+ [3] 1xxx/1fff 0xxx/0,??/1 0xxx/0,??/1 1xxx/ffff,--
+ [4] z000/f000 ????/1,0y/0 fffe/0,0y/0 1000/1000,0y
+ [5] zxxx/ffff 0xxx/0,0y/0 0xxx/0,0y/0 1xxx/ffff,0y
+ [6] 0000/0fff <none> <none> <none>
+ [7] 0000/f000 <none> <none> <none>
+ [8] 0000/efff <none> <none> <none>
+ [9] 1001/1001 <none> <none> 1001/1001,--
+ [10] 3000/3000 <none> <none> <none>
+
+Each column is interpreted as follows.
+
+ - Match: See the list below.
+
+ - NXM: xxxx/yyyy means NXM_OF_VLAN_TCI_W with value xxxx and mask
+ yyyy. A mask of 0000 is equivalent to omitting
+ NXM_OF_VLAN_TCI(_W), a mask of ffff is equivalent to
+ NXM_OF_VLAN_TCI.
+
+ - OF1.0 and OF1.1: wwww/x,yy/z means dl_vlan wwww, OFPFW_DL_VLAN
+ x, dl_vlan_pcp yy, and OFPFW_DL_VLAN_PCP z. ? means that the
+ given nibble is ignored (and conventionally 0 for wwww or z,
+ conventionally 1 for x or z). <none> means that the given match
+ is not supported.
+
+ - OF1.2: xxxx/yyyy,zz means OXM_OF_VLAN_VID_W with value xxxx and
+ mask yyyy, and OXM_OF_VLAN_PCP (which is not maskable) with
+ value zz. A mask of 0000 is equivalent to omitting
+ OXM_OF_VLAN_VID(_W), a mask of ffff is equivalent to
+ OXM_OF_VLAN_VID. -- means that OXM_OF_VLAN_PCP is omitted.
+ <none> means that the given match is not supported.
+
+The matches are:
+
+ [1] Matches any packet, that is, one without an 802.1Q header or with
+ an 802.1Q header with any TCI value.
+
+ [2] Matches only packets without an 802.1Q header.
+
+ NXM: Any match with (vlan_tci == 0) and (vlan_tci_mask & 0x1000)
+ != 0 is equivalent to the one listed in the table.
+
+ OF1.0: The spec doesn't define behavior if dl_vlan is set to
+ 0xffff and OFPFW_DL_VLAN_PCP is not set.
+
+ OF1.1: The spec says explicitly to ignore dl_vlan_pcp when
+ dl_vlan is set to 0xffff.
+
+ OF1.2: The spec doesn't say what should happen if (vlan_vid == 0)
+ and (vlan_vid_mask & 0x1000) != 0 but (vlan_vid_mask != 0x1000),
+ but it would be straightforward to also interpret as [2].
+
+ [3] Matches only packets that have an 802.1Q header with VID xxx (and
+ any PCP).
+
+ [4] Matches only packets that have an 802.1Q header with PCP y (and
+ any VID).
+
+ NXM: z is ((y << 1) | 1).
+
+ OF1.0: The spec isn't very clear, but OVS implements it this way.
+
+ OF1.2: Presumably other masks such that (vlan_vid_mask & 0x1fff)
+ == 0x1000 would also work, but the spec doesn't define their
+ behavior.
+
+ [5] Matches only packets that have an 802.1Q header with VID xxx and
+ PCP y.
+
+ NXM: z is ((y << 1) | 1).
+
+ OF1.2: Presumably other masks such that (vlan_vid_mask & 0x1fff)
+ == 0x1fff would also work.
+
+ [6] Matches packets with no 802.1Q header or with an 802.1Q header
+ with a VID of 0. Only possible with NXM.
+
+ [7] Matches packets with no 802.1Q header or with an 802.1Q header
+ with a PCP of 0. Only possible with NXM.
+
+ [8] Matches packets with no 802.1Q header or with an 802.1Q header
+ with both VID and PCP of 0. Only possible with NXM.
+
+ [9] Matches only packets that have an 802.1Q header with an
+ odd-numbered VID (and any PCP). Only possible with NXM and
+ OF1.2. (This is just an example; one can match on any desired
+ VID bit pattern.)
+
+[10] Matches only packets that have an 802.1Q header with an
+ odd-numbered PCP (and any VID). Only possible with NXM. (This
+ is just an example; one can match on any desired VID bit
+ pattern.)
+
+Additional notes:
+
+ - OF1.2: The top three bits of OXM_OF_VLAN_VID are fixed to zero,
+ so bits 13, 14, and 15 in the masks listed in the table may be
+ set to arbitrary values, as long as the corresponding value bits
+ are also zero. The suggested ffff mask for [2], [3], and [5]
+ allows a shorter OXM representation (the mask is omitted) than
+ the minimal 1fff mask.
+
+
Flow Cookies
============
])
AT_CLEANUP
+dnl Check all of the patterns mentioned in the "VLAN Matching" section
+dnl in the DESIGN file at top level.
+AT_SETUP([ovs-ofctl check-vlan])
+AT_KEYWORDS([VLAN])
+
+dnl [1]
+AT_CHECK([ovs-ofctl check-vlan 0000 0000], [0], [dnl
+ -> 0000/0000
+NXM: <any> -> 0000/0000
+OF1.0: 0000/1,00/1 -> 0000/0000
+OF1.1: 0000/1,00/1 -> 0000/0000
+])
+
+dnl [2]
+AT_CHECK([ovs-ofctl check-vlan 0000 ffff], [0], [dnl
+vlan_tci=0x0000 -> 0000/ffff
+NXM: NXM_OF_VLAN_TCI(0000) -> 0000/ffff
+OF1.0: ffff/0,00/1 -> 0000/ffff
+OF1.1: ffff/0,00/1 -> 0000/ffff
+])
+
+dnl [3]
+AT_CHECK([ovs-ofctl check-vlan 1abc 1fff], [0], [dnl
+dl_vlan=2748 -> 1abc/1fff
+NXM: NXM_OF_VLAN_TCI_W(1abc/1fff) -> 1abc/1fff
+OF1.0: 0abc/0,00/1 -> 1abc/1fff
+OF1.1: 0abc/0,00/1 -> 1abc/1fff
+])
+
+dnl [4]
+AT_CHECK([ovs-ofctl check-vlan b000 f000], [0], [dnl
+dl_vlan_pcp=5 -> b000/f000
+NXM: NXM_OF_VLAN_TCI_W(b000/f000) -> b000/f000
+OF1.0: 0000/1,05/0 -> b000/f000
+OF1.1: fffe/0,05/0 -> b000/f000
+])
+
+dnl [5]
+AT_CHECK([ovs-ofctl check-vlan babc ffff], [0], [dnl
+dl_vlan=2748,dl_vlan_pcp=5 -> babc/ffff
+NXM: NXM_OF_VLAN_TCI(babc) -> babc/ffff
+OF1.0: 0abc/0,05/0 -> babc/ffff
+OF1.1: 0abc/0,05/0 -> babc/ffff
+])
+
+dnl [6]
+AT_CHECK([ovs-ofctl check-vlan 0000 0fff], [0], [dnl
+vlan_tci=0x0000/0x0fff -> 0000/0fff
+NXM: NXM_OF_VLAN_TCI_W(0000/0fff) -> 0000/0fff
+OF1.0: 0000/0,00/1 -> 1000/1fff
+OF1.1: 0000/0,00/1 -> 1000/1fff
+])
+
+dnl [7]
+AT_CHECK([ovs-ofctl check-vlan 0000 f000], [0], [dnl
+vlan_tci=0x0000/0xf000 -> 0000/f000
+NXM: NXM_OF_VLAN_TCI_W(0000/f000) -> 0000/f000
+OF1.0: ffff/0,00/1 -> 0000/ffff
+OF1.1: ffff/0,00/1 -> 0000/ffff
+])
+
+dnl [8]
+AT_CHECK([ovs-ofctl check-vlan 0000 efff], [0], [dnl
+vlan_tci=0x0000/0xefff -> 0000/efff
+NXM: NXM_OF_VLAN_TCI_W(0000/efff) -> 0000/efff
+OF1.0: 0000/0,00/0 -> 1000/ffff
+OF1.1: 0000/0,00/0 -> 1000/ffff
+])
+
+dnl [9]
+AT_CHECK([ovs-ofctl check-vlan 1001 1001], [0], [dnl
+vlan_tci=0x1001/0x1001 -> 1001/1001
+NXM: NXM_OF_VLAN_TCI_W(1001/1001) -> 1001/1001
+OF1.0: 0001/0,00/1 -> 1001/1fff
+OF1.1: 0001/0,00/1 -> 1001/1fff
+])
+
+dnl [10]
+AT_CHECK([ovs-ofctl check-vlan 3000 3000], [0], [dnl
+vlan_tci=0x3000/0x3000 -> 3000/3000
+NXM: NXM_OF_VLAN_TCI_W(3000/3000) -> 3000/3000
+OF1.0: 0000/1,01/0 -> 3000/f000
+OF1.1: fffe/0,01/0 -> 3000/f000
+])
+AT_CHECK
+AT_CLEANUP
+
dnl Check that "-F openflow10" rejects a flow_mod with unsupported features,
dnl such as tunnels and metadata.
AT_SETUP([ovs-ofctl -F option and NXM features])
ds_destroy(&in);
}
+/* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and
+ * mask values to and from various formats and prints the results. */
+static void
+ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
+{
+ struct cls_rule rule;
+
+ char *string_s;
+ struct ofputil_flow_mod fm;
+
+ struct ofpbuf nxm;
+ struct cls_rule nxm_rule;
+ int nxm_match_len;
+ char *nxm_s;
+
+ struct ofp10_match of10_match;
+ struct cls_rule of10_rule;
+
+ struct ofp11_match of11_match;
+ struct cls_rule of11_rule;
+
+ enum ofperr error;
+
+ cls_rule_init_catchall(&rule, OFP_DEFAULT_PRIORITY);
+ rule.flow.vlan_tci = htons(strtoul(argv[1], NULL, 16));
+ rule.wc.vlan_tci_mask = htons(strtoul(argv[2], NULL, 16));
+
+ /* Convert to and from string. */
+ string_s = cls_rule_to_string(&rule);
+ 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.vlan_tci_mask));
+
+ /* Convert to and from NXM. */
+ ofpbuf_init(&nxm, 0);
+ nxm_match_len = nx_put_match(&nxm, false, &rule, 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);
+ 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.vlan_tci_mask));
+ }
+ free(nxm_s);
+ 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);
+ 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.vlan_tci_mask));
+
+ /* 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);
+ 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.vlan_tci_mask));
+}
+
/* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
* version. */
static void
{ "parse-ofp11-match", 0, 0, ofctl_parse_ofp11_match },
{ "parse-ofp11-actions", 0, 0, ofctl_parse_ofp11_actions },
{ "parse-ofp11-instructions", 0, 0, ofctl_parse_ofp11_instructions },
+ { "check-vlan", 2, 2, ofctl_check_vlan },
{ "print-error", 1, 1, ofctl_print_error },
{ "ofp-print", 1, 2, ofctl_ofp_print },