ovs-fields(7)
โจ NAME โจ
ovs-fields โ protocol header fields in OpenFlow and Open vSwitch ๐
๐ INTRODUCTION ๐
Bestie, buckle up, because this doc is the full, unhinged, comprehensive rundown of every single field โ standard and non-standard โ that OpenFlow or Open vSwitch supports, no matter where it came from. Like, no gatekeeping. All of them. ๐
## ๐ฆ Fields ๐ฆ
A field is just a property of a packet. Simple. The ones you already know and love are data fields โ fields you can literally pull out of a packet. Most data fields get copied straight out of the protocol headers, like:
- at layer 2: the Ethernet source and destination addresses, or the VLAN ID
- at layer 3: the IPv4 or IPv6 source and destination
- at layer 4: the TCP or UDP ports
Other data fields are computed instead of copied โ like ip_frag, which tells you whether a packet is a fragment, but is not copied directly from the IP header. It's giving math, not copy-paste. ๐งฎ
Data fields that are always there, just because of the basic networking technology in use, are called root fields. Open vSwitch 2.7 and earlier treated Ethernet fields as root fields, and lowkey that's still the default mode of operation for Open vSwitch bridges. So when a packet shows up from a non-Ethernet interface โ say a layer-3 VXLAN-GPE tunnel โ Open vSwitch 2.7 and earlier force-fits that packet into this Ethernet-centric point of view by pretending an Ethernet header exists whose Ethernet type indicates the packet's actual type. (And whose source and destination addresses are all-zero, because fake header, fake addresses, we move ๐ .)
Open vSwitch 2.8 and later implement the "packet type-aware pipeline" concept introduced in OpenFlow 1.5. A pipeline like that has no root fields at all. Instead, there's a new metadata field, packet_type, that tells you the basic type of the packet โ which can be Ethernet, IPv4, IPv6, or another type. For backward compatibility though, by default Open vSwitch 2.8 imitates the behavior of Open vSwitch 2.7 and earlier. Later versions of Open vSwitch may change the default, and in the meantime controllers can turn off this legacy behavior, on a port-by-port basis, by setting options:packet_type to ptap in the Interface table. This is significant only for ports that can handle non-Ethernet packets, which currently is just VXLAN-GPE, and GRE tunnel ports. See ovs-vwitchd.conf.db(5) for more info. ๐
Non-root data fields are not always present, bestie. A packet contains ARP fields, for example, only when its packet type is ARP, or when it's an Ethernet packet whose Ethernet header indicates the Ethertype for ARP, 0x0806. In this documentation we say a field is applicable when it's present in a packet, and inapplicable when it's not. (And heads up โ these are not standard terms. We made them up. ๐) The conditions that determine whether a field is applicable are called prerequisites. Some VLAN-related fields are a special case: they're always applicable for Ethernet packets, but they have a designated value or bit that indicates whether a VLAN header is present, with the remaining values or bits indicating the VLAN header's content (if it is present).
An inapplicable field does not have a value. Not even a nominal ``value'' like all-zero-bits. Nothing. Void. ๐ณ๏ธ And in many circumstances, OpenFlow and Open vSwitch allow references only to applicable fields. For example, you may match (see Matching, below) a given field only if the match includes the field's prerequisite โ like, matching an ARP field is only allowed if you also match on Ethertype 0x0806, or on the packet_type for ARP in a packet type-aware bridge.
Sometimes a packet may contain multiple instances of a header. Example: a packet may contain multiple VLAN or MPLS headers, and tunnels can cause any data field to recur. OpenFlow and Open vSwitch do not address these cases uniformly:
- For VLAN and MPLS headers, only the outermost header is accessible, so inner headers may be accessed only by "popping" (removing) the outer header. (Open vSwitch supports only a single VLAN header in any case.)
- For tunnels, e.g. GRE or VXLAN, the outer header and inner headers are treated as different data fields.
Many network protocols are built in layers, like a stack of concatenated headers. Each header typically contains a "next type" field that indicates the type of the protocol header that follows โ e.g. Ethernet contains an Ethertype, and IPv4 contains a IP protocol type. The exceptional cases, where protocols are layered but an outer layer does not indicate the protocol type for the inner layer, or gives only an ambiguous indication, are troublesome. ๐ฉ An MPLS header, for example, only indicates whether another MPLS header or some other protocol follows, and in that latter case the inner protocol must be known from the context. In these exceptional cases, OpenFlow and Open vSwitch cannot provide insight into the inner protocol data fields without additional context, and thus they treat all later data fields as inapplicable until an OpenFlow action explicitly specifies what protocol follows. In the case of MPLS, the OpenFlow "pop MPLS" action that removes the last MPLS header from a packet provides this context, as the Ethertype of the payload. See Layer 2.5: MPLS for more information.
OpenFlow and Open vSwitch also support some fields that are not data fields. Metadata fields relate to the origin or treatment of a packet, but they are not extracted from the packet data itself. One example: the physical port on which a packet arrived at the switch. Register fields act like variables โ they give an OpenFlow switch space for temporary storage while processing a packet. Existing metadata and register fields have no prerequisites. Free real estate. ๐
A field's value consists of an integral number of bytes. For data fields, sometimes those bytes are taken directly from the packet. Other data fields are copied from a packet with padding (usually with zeros, and in the most significant positions). And the remaining data fields are transformed in other ways as they're copied from the packets, to make them more useful for matching. Glow-up for the sake of matching, honestly. โจ
## ๐ Matching ๐
The most important use of fields in OpenFlow is matching โ figuring out whether particular field values agree with a set of constraints called a match. A match consists of zero or more constraints on individual fields, and all of them must be met to satisfy the match. (A match that contains no constraints is always satisfied. Baby match, always thriving. ๐ซถ) OpenFlow and Open vSwitch support a number of forms of matching on individual fields:
- Exact match, e.g.
nw_src=10.1.2.3โ only a particular value of the field is matched; for example, only one particular source IP address. Exact matches are written asfield=value. The forms accepted for value depend on the field. All fields support exact matches. - Bitwise match, e.g.
nw_src=10.1.0.0/255.255.0.0โ specific bits in the field must have specified values; for example, only source IP addresses in a particular subnet. Bitwise matches are written asfield=value/mask, where value and mask take one of the forms accepted for an exact match on field. Some fields accept other forms for bitwise matches; for example,nw_src=10.1.0.0/255.255.0.0may also be writtennw_src=10.1.0.0/16.
Most OpenFlow switches do not allow every bitwise matching on every field (and before OpenFlow 1.2, the protocol did not even provide for the possibility for most fields). Even switches that do allow bitwise matching on a given field may restrict the masks that are allowed, e.g. by allowing matches only on contiguous sets of bits starting from the most significant bit, that is, "CIDR" masks [RFC 4632]. Open vSwitch does not allow bitwise matching on every field, but it allows arbitrary bitwise masks on any field that does support bitwise matching. (Older versions had some restrictions, as documented in the descriptions of individual fields.)
- Wildcard, e.g. "any
nw_src" โ the value of the field is not constrained. Wildcarded fields may be written asfield=*, although it is unusual to mention them at all. (When specifying a wildcard explicitly in a command invocation, be sure to use quoting to protect against shell expansion. Protect yourself bestie ๐)
There is a tiny difference between wildcarding a field and not specifying any match on a field: wildcarding a field requires satisfying the field's prerequisites.
Some types of matches on individual fields cannot be expressed directly with OpenFlow and Open vSwitch. But they can be expressed indirectly:
- Set match, e.g. "
tcp_dstโ {80,443,8080}" โ the value of a field is one of a specified set of values; for example, the TCP destination port is80,443, or8080.
For matches used in flows (see Flows, below), multiple flows can simulate set matches.
- Range match, e.g. "
1000โคtcp_dstโค1999" โ the value of the field must lie within a numerical range, for example, TCP destination ports between1000and1999.
Range matches can be expressed as a collection of bitwise matches. For example, suppose that the goal is to match TCP source ports 1000 to 1999, inclusive. The binary representations of 1000 and 1999 are:
01111101000
11111001111
The following series of bitwise matches will match 1000 and 1999 and all the values in between:
01111101xxx
0111111xxxx
10xxxxxxxxx
110xxxxxxxx
1110xxxxxxx
11110xxxxxx
1111100xxxx
which can be written as the following matches:
tcp,tp_src=0x03e8/0xfff8
tcp,tp_src=0x03f0/0xfff0
tcp,tp_src=0x0400/0xfe00
tcp,tp_src=0x0600/0xff00
tcp,tp_src=0x0700/0xff80
tcp,tp_src=0x0780/0xffc0
tcp,tp_src=0x07c0/0xfff0
- Inequality match, e.g. "
tcp_dstโ80" โ the value of the field differs from a specified value, for example, all TCP destination ports except80.
okay so inequality matches, let's finish that thought bc it's actually so clever ๐
An inequality match on an n-bit field can be expressed as a disjunction of n 1-bit matches. Like, for example, the inequality match vlan_pcp โ 5 can be expressed as vlan_pcp = 0/4 or vlan_pcp = 2/2 or vlan_pcp = 0/1. Yes bestie, that's real, that's the whole trick. And for matches used in flows (peep Flows, below), sometimes you can more compactly express inequality as a higher-priority flow that matches the exceptional case paired with a lower-priority flow that matches the general case. Iconic behaviour tbh.
Alternatively, an inequality match may be converted to a pair of range matches, e.g. tcp_src โ 80 may be expressed as 0 โค tcp_src < 80 or 80 < tcp_src โค 65535, and then each range match may in turn be converted to a bitwise match. Chain of slay. ๐ฅ
- Conjunctive match, e.g.
tcp_src โ {80, 443, 8080} and tcp_dst โ {80, 443, 8080}โ as an OpenFlow extension, Open vSwitch supports matching on conditions on conjunctions of the previously mentioned forms of matching. See the documentation forconj_idfor more information.
Okay so all of these supported forms of matching are special cases of bitwise matching, and that's the โจkeyโจ realization. In some cases this influences the design of field values. ip_frag is the most prominent example: it is designed to make all of the practically useful checks for IP fragmentation possible as a single bitwise match. One field, doing the absolute most. main character energy fr fr ๐
๐ธ Shorthands ๐ธ
Some matches are very commonly used, so Open vSwitch accepts shorthand notations. In some cases, Open vSwitch also uses shorthand notations when it displays matches. The following shorthands are defined, with their long forms shown on the right side:
ethโpacket_type=(0,0)(Open vSwitch 2.8 and later)ipโeth_type=0x0800ipv6โeth_type=0x86ddicmpโeth_type=0x0800,ip_proto=1icmp6โeth_type=0x86dd,ip_proto=58tcpโeth_type=0x0800,ip_proto=6tcp6โeth_type=0x86dd,ip_proto=6udpโeth_type=0x0800,ip_proto=17udp6โeth_type=0x86dd,ip_proto=17sctpโeth_type=0x0800,ip_proto=132sctp6โeth_type=0x86dd,ip_proto=132arpโeth_type=0x0806rarpโeth_type=0x8035mplsโeth_type=0x8847mplsmโeth_type=0x8848
No cap, memorizing these fifteen will save you so much typing. ๐ซถ
๐ Evolution of OpenFlow Fields ๐
The discussion so far applies to all OpenFlow and Open vSwitch versions. This section starts to draw in specific information by explaining, in broad terms, the treatment of fields and matches in each OpenFlow version. So like, grab a snack, because we're doing a whole history lesson and honestly it's tea. ๐
๐ OpenFlow 1.0 ๐
OpenFlow 1.0 defined the OpenFlow protocol format of a match as a fixed-length data structure that could match on the following fields:
- Ingress port.
- Ethernet source and destination MAC.
- Ethertype (with a special value to match frames that lack an Ethertype).
- VLAN ID and priority.
- IPv4 source, destination, protocol, and DSCP.
- TCP source and destination port.
- UDP source and destination port.
- ICMPv4 type and code.
- ARP IPv4 addresses (SPA and TPA) and opcode.
Each supported field corresponded to some member of the data structure. Some members represented multiple fields, in the case of the TCP, UDP, ICMPv4, and ARP fields whose presence is mutually exclusive. This also meant that some members were poor fits for their fields: only the low 8 bits of the 16-bit ARP opcode could be represented, and the ICMPv4 type and code were padded with 8 bits of zeros to fit in the 16-bit members primarily meant for TCP and UDP ports. That is such a squeeze, bestie, it's giving "we ran out of room in the spreadsheet". ๐ An additional bitmap member indicated, for each member, whether its field should be an "exact" or "wildcarded" match (see Matching), with additional support for CIDR prefix matching on the IPv4 source and destination fields.
Simplicity was recognized early on as the main virtue of this approach. Obviously, any fixed-length data structure cannot support matching new protocols that do not fit. There was no room, for example, for matching IPv6 fields, which was not a priority at the time. Lack of room to support matching the Ethernet addresses inside ARP packets actually caused more of a design problem later, leading to an Open vSwitch extension action specialized for dropping "spoofed" ARP packets in which the frame and ARP Ethernet source addressed differed. (This extension was never standardized. Open vSwitch dropped support for it a few releases after it added support for full ARP matching.)
the way that a design shortcut in 1.0 came back around later... it's giving technical debt, and the debt ate. ๐ญ
The design of the OpenFlow fixed-length matches also illustrates compromises, in both directions, between the strengths and weaknesses of software and hardware that have always influenced the design of OpenFlow. Support for matching ARP fields that do fit in the data structure was only added late in the design process (and remained optional in OpenFlow 1.0), for example, because common switch ASICs did not support matching these fields.
The compromises in favor of software occurred for more complicated reasons. The OpenFlow designers did not know how to implement matching in software that was fast, dynamic, and general. (A way was later found [Srinivasan].) Thus, the designers sought to support dynamic, general matching that would be fast in realistic special cases, in particular when all of the matches were microflows, that is, matches that specify every field present in a packet, because such matches can be implemented as a single hash table lookup. Contemporary research supported the feasibility of this approach: the number of microflows in a campus network had been measured to peak at about 10,000 [Casado, section 3.2]. (Calculations show that this can only be true in a lightly loaded network [Pepelnjak].) So like, the vibes were based on a measurement, and the measurement was based on a lightly loaded network. Not me pointing that out. ๐
As a result, OpenFlow 1.0 required switches to treat microflow matches as the highest possible priority. This let software switches perform the microflow hash table lookup first. Only on failure to match a microflow did the switch need to fall back to checking the more general and presumed slower matches. Also, the OpenFlow 1.0 flow match was minimally flexible, with no support for general bitwise matching, partly on the basis that this seemed more likely amenable to relatively efficient software implementation. (CIDR masking for IPv4 addresses was added relatively late in the OpenFlow 1.0 design process.)
Microflow matching was later discovered to aid some hardware implementations. The TCAM chips used for matching in hardware do not support priority in the same way as OpenFlow but instead tie priority to ordering [Pagiamtzis]. Thus, adding a new match with a priority between the priorities of existing matches can require reordering an arbitrary number of TCAM entries. On the other hand, when microflows are highest priority, they can be managed as a set-aside portion of the TCAM entries. Look at that, an accidental W for the hardware girlies. ๐
The emphasis on matching microflows also led designers to carefully consider the bandwidth requirements between switch and controller: to maximize the number of microflow setups per second, one must minimize the size of each flow's description. This favored the fixed-length format in use, because it expressed common TCP and UDP microflows in fewer bytes than more flexible "type-length-value" (TLV) formats. (Early versions of OpenFlow also avoided TLVs in general to head off protocol fragmentation.)
๐ฉท Inapplicable Fields ๐ฉท
OpenFlow 1.0 does not clearly specify how to treat inapplicable fields. The members for inapplicable fields are always present in the match data structure, as are the bits that indicate whether the fields are matched, and the "correct" member and bit values for inapplicable fields is unclear. OpenFlow 1.0 implementations changed their behavior over time as priorities shifted. The early OpenFlow reference implementation, motivated to make every flow a microflow to enable hashing, treated inapplicable fields as exact matches on a value of 0. Initially, this behavior was implemented in the reference controller only.
Later, the reference switch was also changed to actually force any wildcarded inapplicable fields into exact matches on 0. The latter behavior sometimes caused problems, because the modified flow was the one reported back to the controller later when it queried the flow table, and the modifications sometimes meant that the controller could not properly recognize the flow that it had added. In retrospect, perhaps this problem should have alerted the designers to a design error, but the ability to use a single hash table was held to be more important than almost every other consideration at the time. ๐ญ the hash table said "I'm the moment" and honestly it was
When more flexible match formats were introduced much later, they disallowed any mention of inapplicable fields as part of a match. This raised the question of how to translate between this new format and the OpenFlow 1.0 fixed format. It seemed somewhat inconsistent and backward to treat fields as exact-match in one format and forbid matching them in the other, so instead the treatment of inapplicable fields in the fixed-length format was changed from exact match on 0 to wildcarding. (A better classifier had by now eliminated software performance problems with wildcards.)
The OpenFlow 1.0.1 errata (released only in 2012) added some additional explanation [OpenFlow 1.0.1, section 3.4], but it did not mandate specific behavior because of variation among implementations.
โจ OpenFlow 1.1 โจ
The OpenFlow 1.1 protocol match format was designed as a type/length/value (TLV) format to allow for future flexibility. The specification standardized only a single type OFPMT_STANDARD (0) with a fixed-size payload, described here. The additional fields and bitwise masks in OpenFlow 1.1 cause this match structure to be over twice as large as in OpenFlow 1.0, 88 bytes versus 40. Glow-up but at what cost, bestie. ๐
OpenFlow 1.1 added support for the following fields:
- SCTP source and destination port.
- MPLS label and traffic control (TC) fields.
- One 64-bit register (named "metadata").
OpenFlow 1.1 increased the width of the ingress port number field (and all other port numbers in the protocol) from 16 bits to 32 bits.
OpenFlow 1.1 increased matching flexibility by introducing arbitrary bitwise matching on Ethernet and IPv4 address fields and on the new "metadata" register field. Switches were not required to support all possible masks [OpenFlow 1.1, section 4.3].
Ok so bestie, if you read the OpenFlow 1.1 spec super literally, it says ICMPv4 type and code matching got totally uninvited [OpenFlow 1.1, section A.2.3] ๐ญ but that's like, almost definitely an editing oopsie because ICMP matching is described elsewhere [OpenFlow 1.1, Table 3, Table 4, Figure 4]. And Open vSwitch? It does support ICMPv4 type and code matching with OpenFlow 1.1. Slay.
OpenFlow 1.1 was like, "we learned from 1.0's inapplicable fields drama," so it required the switch to ignore the specified field values [OpenFlow 1.1, section A.2.3]. It also implied the switch should ignore the bits that say whether to match inapplicable fields. Periodt.
๐ฆ Physical Ingress Port ๐ฆ
OpenFlow 1.1 introduced a new pseudo-field, the physical ingress port. It's only a pseudo-field because you can't match on it. It shows up in exactly one place in the protocol: the packet-in message that passes a packet received at the switch to an OpenFlow controller.
A packet's ingress port and physical ingress port are identical except for packets processed by a switch feature like bonding or tunneling that makes a packet look like it arrived on a "virtual" port associated with the bond or tunnel. For those packets, the ingress port is the virtual port and the physical ingress port is, naturally, the physical port. Open vSwitch implements both bonding and tunneling, but its bonding implementation doesn't use virtual ports and its tunnels are typically not on the same OpenFlow switch as their physical ingress ports (which need not be part of any switch), so the ingress port and physical ingress port are always the same in Open vSwitch. No cap.
โจ OpenFlow 1.2 โจ
OpenFlow 1.2 abandoned the fixed-length approach to matching. One reason was size, since adding support for IPv6 address matching (now seen as important), with bitwise masks, would have added 64 bytes to the match length, increasing it from 88 bytes in OpenFlow 1.1 to over 150 bytes. Extensibility had also become important as controller writers increasingly wanted support for new fields without having to change messages throughout the OpenFlow protocol. The challenges of carefully defining fixed-length matches to avoid problems with inapplicable fields had also become clear over time. It's giving "we need flexibility, bestie" ๐
Therefore, OpenFlow 1.2 adopted a flow format using a flexible type-length-value (TLV) representation, in which each TLV expresses a match on one field. These TLVs were in turn encapsulated inside the outer TLV wrapper introduced in OpenFlow 1.1 with the new identifier OFPMT_OXM (1). (This wrapper fulfilled its intended purpose of reducing the amount of churn in the protocol when changing match formats; some messages that included matches remained unchanged from OpenFlow 1.1 to 1.2 and later versions.)
OpenFlow 1.2 added support for the following fields:
- ARP hardware addresses (SHA and THA).
- IPv4 ECN.
- IPv6 source and destination addresses, flow label, DSCP, ECN, and protocol.
- TCP, UDP, and SCTP port numbers when encapsulated inside IPv6.
- ICMPv6 type and code.
- ICMPv6 Neighbor Discovery target address and source and target Ethernet addresses.
The OpenFlow 1.2 format, called OXM (OpenFlow Extensible Match), was modeled closely on an extension to OpenFlow 1.0 introduced in Open vSwitch 1.1 called NXM (Nicira Extended Match). Each OXM or NXM TLV has the following format:
type
<---------------->
16 7 1 8 length bytes
+------------+-----+--+------+ +------------+
|vendor/class|field|HM|length| | body |
+------------+-----+--+------+ +------------+
The most significant 16 bits of the NXM or OXM header, called vendor by NXM and class by OXM, identify an organization permitted to allocate identifiers for fields. NXM allocates only two vendors, 0x0000 for fields supported by OpenFlow 1.0 and 0x0001 for fields implemented as an Open vSwitch extension. OXM assigns classes as follows:
0x0000(OFPXMC_NXM_0).0x0001(OFPXMC_NXM_1). Reserved for NXM compatibility.0x0002to0x7fffโ Reserved for allocation to ONF members, but none yet assigned.0x8000(OFPXMC_OPENFLOW_BASIC) โ Used for most standard OpenFlow fields.0x8001(OFPXMC_PACKET_REGS) โ Used for packet register fields in OpenFlow 1.5 and later.0x8002to0xfffeโ Reserved for the OpenFlow specification.0xffff(OFPXMC_EXPERIMENTER) โ Experimental use.
When class is 0xffff, the OXM header is extended to 64 bits by using the first 32 bits of the body as an experimenter field whose most significant byte is zero and whose remaining bytes are an Organizationally Unique Identifier (OUI) assigned by the IEEE [IEEE OUI], as shown below.
type experimenter
<----------> <---------->
16 7 1 8 8 24 (length - 4) bytes
+------+-----+--+------+ +------+-----+ +------------------+
|class |field|HM|length| | zero | OUI | | body |
+------+-----+--+------+ +------+-----+ +------------------+
0xffff 0x00
OpenFlow says that support for experimenter fields is optional. Open vSwitch 2.4 and later does support them, so that it can support the following experimenter classes:
0x4f4e4600(ONFOXM_ET) โ Used by official Open Networking Foundation extensions in OpenFlow 1.3 and later. e.g. [TCP Flags Match Field Extension].0x005ad650(NXOXM_NSH) โ Used by Open vSwitch for NSH extensions, in the absence of an official ONF-assigned class. (This OUI is randomly generated.)
Taken as a unit, class (or vendor), field, and experimenter (when present) uniquely identify a particular field.
When hasmask (abbreviated HM above) is 0, the OXM is an exact match on an entire field. In this case, the body (excluding the experimenter field, if present) is a single value to be matched.
When hasmask is 1, the OXM is a bitwise match. The body (excluding the experimenter field) consists of a value to match, followed by the bitwise mask to apply. A 1-bit in the mask indicates that the corresponding bit in the value should be matched and a 0-bit that it should be ignored. For example, for an IP address field, a value of 192.168.0.0 followed by a mask of 255.255.0.0 would match addresses in the 196.168.0.0/16 subnet. (Yes, bestie, the original says 196.168.0.0/16 โ we are not fixing it ๐
)
- Some fields might not support masking at all, and some fields that do support masking might restrict it to certain patterns. For example, fields that have IP address values might be restricted to CIDR masks. The descriptions of individual fields note these restrictions.
- An OXM TLV with a mask that is all zeros is not useful (although it is not forbidden), because it is has the same effect as omitting the TLV entirely.
- It is not meaningful to pair a 0-bit in an OXM mask with a 1-bit in its value, and Open vSwitch rejects such an OXM with the error
OFPBMC_BAD_WILDCARDS, as required by OpenFlow 1.3 and later.
The length identifies the number of bytes in the body, including the 4-byte experimenter header, if it is present. Each OXM TLV has a fixed length; that is, given class, field, experimenter (if present), and hasmask, length is a constant. The length is included explicitly to allow software to minimally parse OXM TLVs of unknown types.
OXM TLVs must be ordered so that a field's prerequisites are satisfied before it is parsed. For example, an OXM TLV that matches on the IPv4 source address field is only allowed following an OXM TLV that matches on the Ethertype for IPv4. Similarly, an OXM TLV that matches on the TCP source port must follow a TLV that matches an Ethertype of IPv4 or IPv6 and one that matches an IP protocol of TCP (in that order). The order of OXM TLVs is not otherwise restricted; no canonical ordering is defined.
A given field may be matched only once in a series of OXM TLVs.
๐ OpenFlow 1.3 ๐
OpenFlow 1.3 showed OXM to be largely successful, by adding new fields without making any changes to how flow matches otherwise worked. It added OXMs for the following fields supported by Open vSwitch:
- Tunnel ID for ports associated with e.g. VXLAN or keyed GRE.
- MPLS
bottom of stack(BOS) bit.
OpenFlow 1.3 also added OXMs for the following fields not documented here and not yet implemented by Open vSwitch:
- IPv6 extension header handling.
- PBB I-SID.
๐ OpenFlow 1.4 ๐
OpenFlow 1.4 added OXMs for the following fields not documented here and not yet implemented by Open vSwitch:
- PBB UCA.
โญ OpenFlow 1.5 โญ
OpenFlow 1.5 added OXMs for the following fields supported by Open vSwitch:
- Packet type.
- TCP flags.
- Packet registers.
- The output port in the OpenFlow action set.
โจ FIELDS REFERENCE โจ
Okay bestie, this is the part where we actually get into it. ๐ The sections below document every single field Open vSwitch supports. Each section gives you a lil intro on a group of related fields, and then breaks down each individual field one by one.
And before every field's own deets, there's a lil table covering these properties (yes, all of them, no skipping ๐):
Name ๐ท๏ธ
The field's name โ this is what's used for parsing and formatting the field, like in ovs-ofctl commands. For historical reasons, some fields have an extra name that also gets accepted when parsing. When that exists, it's listed too, e.g. ``tun (aka tunnel_id).''
Width ๐
How wide the field is, always a multiple of 8 bits. Some fields don't use every bit, so there might be an explanation riding along. For example, OpenFlow embeds the 2-bit IP ECN field as the low bits in an 8-bit byte, so its width is expressed as ``8 bits (only the least-significant 2 bits may be nonzero).''
Format ๐ค
How a value for the field gets formatted or parsed by things like ovs-ofctl. Some of the possibilities are generic:
decimal
Formats as a decimal number. On input, accepts decimal numbers or hexadecimal numbers prefixed by 0x.
hexadecimal
Formats as a hexadecimal number prefixed by 0x. On input, accepts decimal numbers or hexadecimal numbers prefixed by 0x. (The default for parsing is not hexadecimal: only a 0x prefix causes input to be treated as hexadecimal.)
Ethernet
Formats and accepts the common Ethernet address format xx:xx:xx:xx:xx:xx.
IPv4
Formats and accepts the dotted-quad format a.b.c.d. For bitwise matches, formats and accepts address/length CIDR notation in addition to address/mask.
IPv6
Formats and accepts the common IPv6 address formats, plus CIDR notation for bitwise matches.
OpenFlow 1.0 port
Accepts 16-bit port numbers in decimal, plus OpenFlow well-known port names (e.g. IN_PORT) in uppercase or lowercase.
OpenFlow 1.1+ port
Same syntax as OpenFlow 1.0 ports but for 32-bit OpenFlow 1.1+ port number fields.
Other, field-specific formats get explained right along with their fields. ๐ซถ
Masking ๐ญ
For most fields, this says arbitrary bitwise masks,'' meaning a flow can match any combination of bits in the field. Some fields instead say exact match only,'' which means a flow matching on this field has to match the whole field, not just certain bits. Either way, this reports masking support for the latest version of Open vSwitch using OXM or NXM โ that is, either OpenFlow 1.2+ or OpenFlow 1.0 plus Open vSwitch NXM extensions. Specifically: OpenFlow 1.0 (without NXM) and 1.1 don't always support masking even if Open vSwitch itself does, so go check the OpenFlow 1.0 and OpenFlow 1.1 rows to learn about masking with those protocol versions. ๐
Prerequisites ๐ง
The requirements that have to be met to match on this field. Like, ip_src has IPv4 as a prerequisite, meaning a match must include eth_type=0x0800 to match on the IPv4 source address. These prerequisites are currently in use:
- none โ (no requirements)
- VLAN VID โ
vlan_tci=0x1000/0x1000(i.e. a VLAN header is present) - ARP โ
eth_type=0x0806(ARP) oreth_type=0x8035(RARP) - IPv4 โ
eth_type=0x0800 - IPv6 โ
eth_type=0x86dd - IPv4/IPv6 โ IPv4 or IPv6
- MPLS โ
eth_type=0x8847oreth_type=0x8848 - TCP โ IPv4/IPv6 and
ip_proto=6 - UDP โ IPv4/IPv6 and
ip_proto=17 - SCTP โ IPv4/IPv6 and
ip_proto=132 - ICMPv4 โ IPv4 and
ip_proto=1 - ICMPv6 โ IPv6 and
ip_proto=58 - ND solicit โ ICMPv6 and
icmp_type=135andicmp_code=0 - ND advert โ ICMPv6 and
icmp_type=136andicmp_code=0 - ND โ ND solicit or ND advert
Also, the TCP, UDP, and SCTP prerequisites have this special requirement that nw_frag is not being used to select ``later fragments.'' Why? Because only the first fragment of a fragmented IPv4 or IPv6 datagram actually contains the TCP or UDP header. no cap ๐ง
Access ๐
Most fields are read/write,'' which means common OpenFlow actions like `set_field` can modify them. Fields that are read-only'' can't be modified in those general-purpose ways, although there may be other ways that actions can modify them.
OpenFlow 1.0
OpenFlow 1.1
These rows report how much support OpenFlow 1.0 or OpenFlow 1.1, respectively, actually has for a field. For OpenFlow 1.0, supported fields are reported as either yes (exact match only)'' for fields that don't support any bitwise masking, or yes (CIDR match only)'' for fields that support CIDR masking. OpenFlow 1.1 supported fields report either yes (exact match only)'' or just plain yes'' for fields that do support arbitrary masks. These OpenFlow versions supported a fixed collection of fields that cannot be extended, so a whole lot of fields are reported as ``not supported.'' ๐
OXM
NXM
These rows report the OXM and NXM code points that correspond to a given field. Either or both may be ``none.''
A field that has only an OXM code point is usually one that was standardized before it was added to Open vSwitch. A field that has only an NXM code point is usually one that's not yet standardized. When a field has both OXM and NXM code points, it usually means it was introduced as an Open vSwitch extension under the NXM code point, then later standardized under the OXM code point. A field can have more than one OXM code point if it was standardized in OpenFlow 1.4 or later and additionally introduced as an official ONF extension for OpenFlow 1.3. (And a field that has neither OXM nor NXM code point is typically an obsolete field that's supported in some other form using OXM or NXM.)
Each code point in these rows is described in the form NAME (number) since OpenFlow spec and Open vSwitch version,'' e.g. OXM_OF_ETH_TYPE (5) since OpenFlow 1.2 and Open vSwitch 1.7.''
So, breaking down that format:
- NAME specifies a name for the code point, starting with a prefix that designates a class and, in some cases, a vendor, as listed in the following table:
- Prefix
NXM_OFโ Vendor(none)โ Class0x0000 - Prefix
NXM_NXโ Vendor(none)โ Class0x0001 - Prefix
ERICOXM_OFโ Vendor(none)โ Class0x1000 - Prefix
OXM_OFโ Vendor(none)โ Class0x8000 - Prefix
OXM_OF_PKT_REGโ Vendor(none)โ Class0x8001 - Prefix
NXOXM_ETโ Vendor0x00002320โ Class0xffff - Prefix
NXOXM_NSHโ Vendor0x005ad650โ Class0xffff - Prefix
ONFOXM_ETโ Vendor0x4f4e4600โ Class0xffff - The number is the field number within the class and vendor.
- The OpenFlow spec is the version of OpenFlow that standardized the code point. It's omitted for NXM code points because they are nonstandard.
- The version is the version of Open vSwitch that first supported the code point.
For more info on OXM/NXM classes and vendors, head back to OpenFlow 1.2 under Evolution of OpenFlow Fields. ๐ฆ
conj_idโ 4 bytes, maskable? no ๐ , read-write? no, prereqs: none, NXM/OXM support: OVS 2.4+
Okay so picture this: one single OpenFlow flow matches exactly one value per field. That's the law. But bestie, real life is messy and sometimes you need to match any of a bunch of values across one field โ or across several. โจ
For a single field? Easy peasy. Just yeet multiple flows into the flow table, one per value. Like, if you want IP source a, b, c, or d to hit the controller:
ip,ip_src=a actions=controller
ip,ip_src=b actions=controller
ip,ip_src=c actions=controller
ip,ip_src=d actions=controller
And same vibe for destination e, f, g, or h:
ip,ip_dst=e actions=controller
ip,ip_dst=f actions=controller
ip,ip_dst=g actions=controller
ip,ip_dst=h actions=controller
Drop all of those into one flow table and you get a disjunctive effect: packet goes to the controller if ip_src โ {a,b,c,d} or ip_dst โ {e,f,g,h} (or literally both, it's giving overachiever energy). ๐ซถ
Petty footnote (the original is pedantic and so am I ๐ ): if both of those flow sets are sitting in the flow table, they should have different priorities, because OpenFlow says the results are undefined when two flows with the same priority can both match a single packet. Not a vibe. Don't do it.
But what if you want CONJUNCTIVE matching tho? ๐ง โจ
Conjunctive = packet hits the controller only if ip_src โ {a,b,c,d} AND ip_dst โ {e,f,g,h}. Both. Simultaneously. No cap.
Doing that by hand is 4 ร 4 = 16 flows โ one for every possible ip_src/ip_dst pairing. Cute for our lil example, absolutely not it for bigger sets or more dimensions. ๐
Enter: the conjunction action, a solution built right into Open vSwitch. It ties groups of individual OpenFlow flows into higher-level "conjunctive flows". Each group = one dimension. Each flow inside a group matches one possible value for that dimension. A packet that matches one flow from every group matches the conjunctive flow. ๐
How to actually build one
- Give the conjunctive flow a 32-bit id, which must be unique within an OpenFlow table.
- Give each of the
n โฅ 2dimensions a unique number from1tonโ the ordering is unimportant, bestie, we're not ranking them. - Add one flow to the OpenFlow flow table for each possible value of each dimension, with
conjunction(id, k/n)as the flow's actions, wherekis the number assigned to that flow's dimension.
Together those flows spell out the conjunctive flow's match condition. Once the match condition is met, Open vSwitch goes and looks up one more flow โ the one specifying the conjunctive flow's actions and collecting its statistics. It finds it by setting conj_id to the specified id and searching the flow table again. ๐ฆ
The example, iconic, showstopping
Whenever the IP source matches one of the dimension-1 values, and the IP destination matches one of the dimension-2 values, Open vSwitch searches for a flow matching conj_id against conjunction ID 1234 and lands on the first flow in this list:
conj_id=1234 actions=controller
ip,ip_src=10.0.0.1 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.4 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.6 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.7 actions=conjunction(1234, 1/2)
ip,ip_dst=10.0.0.2 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.5 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.7 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.8 actions=conjunction(1234, 2/2)
The subtleties (there are many, buckle up) ๐ธ
- In the example above, every flow in a single dimension has the same form โ dimension 1 matches on
ip_src, dimension 2 onip_dstโ but that is not a requirement. Different flows within one dimension can match on different bits within a field (e.g. IP network prefixes of different lengths, or TCP/UDP port ranges as bitwise matches), or even on entirely different fields (e.g. to match packets for TCP source port80or TCP destination port80). Flexible queen. ๐ - Flows within a dimension can spread their matches across more than one field, e.g. to match only specific pairs of IP source and destination addresses, or L4 port numbers.
- A flow can have multiple
conjunctionactions with differentidvalues. Super useful for multiple conjunctive flows with overlapping sets. So like, if one conjunctive flow matches packets with bothip_src โ {a,b}andip_dst โ {d,e}, and a second one matchesip_src โ {b,c}andip_dst โ {f,g}, then the flow matchingip_src=bgets two conjunction actions โ one per conjunctive flow. And fyi: the order ofconjunctionactions inside a list of actions is not significant. - A flow with
conjunctionactions may also includenoteactions for annotations โ but no other kind of actions. Not because we're strict, but because they'd literally never be executed. Pointless. ๐ - All flows making up a conjunctive flow with a given
idmust have the same priority. Flows with the sameidbut different priorities are currently treated as different conjunctive flows โ i.e. right nowidvalues only need to be unique within an OpenFlow table at a given priority. > Heads up bestie: this behavior isn't guaranteed to stay the same in later releases, so please please please just useidvalues unique within an OpenFlow table. Future-proof your life. ๐ซถ - Conjunctive flows must not overlap with each other at a given priority โ meaning any given packet must be able to match at most one conjunctive flow at a given priority. Overlapping conjunctive flows give you unpredictable results. Chaos. Not the fun kind. ๐ญ (The individual flows that constitute a conjunctive flow may overlap with those constituting the same or another conjunctive flow, though.)
- After a conjunctive flow match, the search for the flow with
conj_id=idhappens in the same general-purpose way as any other flow table search โ so you can useconj_id=idflows to act differently depending on circumstances. โจ One exception: the search for theconj_id=idflow itself ignores conjunctive flows, to avoid recursion. And if that search fails? Open vSwitch acts as if the conjunctive flow had not matched at all and keeps searching the flow table for other matching flows. - OpenFlow prerequisite checking happens for the
conj_id=idflow the same as for any other flow. E.g. in an OpenFlow 1.1+ context, putting amod_nw_srcaction into the example above would require adding anipmatch, like this:
conj_id=1234,ip actions=mod_nw_src:1.2.3.4,controller
- OpenFlow prerequisite checking also happens for the individual flows that make up a conjunctive match, same as any other flow.
- The flows constituting a conjunctive flow do not have useful statistics. They're never updated with byte or packet counts, and so on. (For such a flow, therefore, the idle and hard timeouts work much the same way.)
- Sometimes you get a choice about which flows carry a particular match. Say we added an extra constraint to our example: match on
ip_src โ {a,b,c,d}andip_dst โ {e,f,g,h}andtcp_dst = i. One way is to slap the new constraint on theconj_idflow, like:
conj_id=1234,tcp,tcp_dst=i actions=mod_nw_src:1.2.3.4,controller
Not recommended, because of the cost of the extra flow table lookup. Instead, put the constraint on the individual flows โ either in one of the dimensions, or (slightly better) in all of them. ๐
- A conjunctive match must have
n โฅ 2dimensions (otherwise, like, why are you even conjunctive matching?). Open vSwitch enforces this. ๐จ - Each dimension within a conjunctive match should ordinarily have more than one flow. Open vSwitch does not enforce this. Do with that what you will. ๐
Conjunction ID Field โ the deets ๐
- Name:
conj_id - Width:
32 bits - Format:
decimal - Masking: not maskable ๐
- Prerequisites:
none - Access: read-only ๐
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
none - NXM:
NXM_NX_CONJ_ID (37)since Open vSwitch2.4
Used for conjunctive matching. See above for more information. ๐
๐ฅ TUNNEL FIELDS ๐ฅ
๐ซ Summary ๐ซ
okay bestie, here comes the tunnel fam ๐ every single one of them, with bytes, maskability, read/write vibes, prereqs, and NXM/OXM support:
tun_idakatunnel_idโ 8 bytes ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OF 1.3+ and OVS 1.1+tun_srcโ 4 bytes ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.0+tun_dstโ 4 bytes ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.0+tun_ipv6_srcโ 16 bytes ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.5+tun_ipv6_dstโ 16 bytes ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.5+tun_gbp_idโ 2 bytes ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.4+tun_gbp_flagsโ 1 byte ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.4+tun_erspan_verโ 1 (low 4 bits) ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.10+tun_erspan_idxโ 4 (low 20 bits) ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.10+tun_erspan_dirโ 1 (low 1 bits) ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.10+tun_erspan_hwidโ 1 (low 6 bits) ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.10+tun_gtpu_flagsโ 1 byte ยท mask: yes ยท RW?: no ยท prereqs: none ยท NXM/OXM: OVS 2.13+tun_gtpu_msgtypeโ 1 byte ยท mask: yes ยท RW?: no ยท prereqs: none ยท NXM/OXM: OVS 2.13+tun_metadata0throughtun_metadata63โ the whole 64-strong crew ๐ซถ every single one of them: 124 bytes each ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.5+tun_metadata0tun_metadata1tun_metadata2tun_metadata3tun_metadata4tun_metadata5tun_metadata6tun_metadata7tun_metadata8tun_metadata9tun_metadata10tun_metadata11tun_metadata12tun_metadata13tun_metadata14tun_metadata15tun_metadata16tun_metadata17tun_metadata18tun_metadata19tun_metadata20tun_metadata21tun_metadata22tun_metadata23tun_metadata24tun_metadata25tun_metadata26tun_metadata27tun_metadata28tun_metadata29tun_metadata30tun_metadata31tun_metadata32tun_metadata33tun_metadata34tun_metadata35tun_metadata36tun_metadata37tun_metadata38tun_metadata39tun_metadata40tun_metadata41tun_metadata42tun_metadata43tun_metadata44tun_metadata45tun_metadata46tun_metadata47tun_metadata48tun_metadata49tun_metadata50tun_metadata51tun_metadata52tun_metadata53tun_metadata54tun_metadata55tun_metadata56tun_metadata57tun_metadata58tun_metadata59tun_metadata60tun_metadata61tun_metadata62tun_metadata63
tun_flagsโ 2 (low 1 bits) ยท mask: yes ยท RW?: yes ยท prereqs: none ยท NXM/OXM: OVS 2.5+
So like, what are these even for? ๐ This whole group is about tunnels, and Open vSwitch does tunnels in several forms (GRE, VXLAN, and so on). Most of these fields do show up in the wire format of a packet, so from that angle they're legit data fields โ but from an OpenFlow flow table's point of view they're metadata, because they do not appear in packets that get forwarded to the controller or to ordinary (non-tunnel) output ports. it's giving "depends who's asking" energy ๐ญ
Open vSwitch supports a whole spectrum of usage models for mapping tunnels to OpenFlow ports, and this is the part where you pick your fighter:
๐ "Port-based" tunnels
In this model, an OpenFlow port represents one tunnel: it matches a particular type of tunnel traffic between two IP endpoints, with a particular tunnel key (if keys are in use). In this situation, in_port alone is enough to tell one tunnel from another, so the tunnel header fields are likeโฆ barely important for OpenFlow processing? (They're still populated and you may use them if it's convenient, but no pressure.) The tunnel header fields also play no role in sending packets out such an OpenFlow port, because the OpenFlow port itself fully specifies the tunnel headers. periodt ๐
These Open vSwitch commands create a bridge br-int, add port tap0 to the bridge as OpenFlow port 1, set up a port-based GRE tunnel between the local host and remote IP 192.168.1.1 using GRE key 5001 as OpenFlow port 2, and arrange to forward all traffic from tap0 to the tunnel and vice versa:
ovs-vsctl add-br br-int
ovs-vsctl add-port br-int tap0 -- set interface tap0 ofport_request=1
ovs-vsctl add-port br-int gre0 -- \
set interface gre0 ofport_request=2 type=gre \
options:remote_ip=192.168.1.1 options:key=5001
ovs-ofctl add-flow br-int in_port=1,actions=2
ovs-ofctl add-flow br-int in_port=2,actions=1
๐ฆ "Flow-based" tunnels
In this model, one OpenFlow port represents all possible tunnels of a given type with an endpoint on the current host โ for example, all GRE tunnels. So now in_port only tells you that traffic was received on that particular kind of tunnel. And this is where the tunnel header fields become the main characters ๐ they're literally what lets the OpenFlow tables discriminate among tunnels based on their IP endpoints or keys. Tunnel header fields also determine the IP endpoints and keys of packets sent out such a tunnel port. no cap.
These Open vSwitch commands create a bridge br-int, add port tap0 to the bridge as OpenFlow port 1, set up a flow-based GRE tunnel port 3, and arrange to forward all traffic from tap0 to remote IP 192.168.1.1 over a GRE tunnel with key 5001 and vice versa:
ovs-vsctl add-br br-int
ovs-vsctl add-port br-int tap0 -- set interface tap0 ofport_request=1
ovs-vsctl add-port br-int allgre -- \
set interface allgre ofport_request=3 type=gre \
options:remote_ip=flow options:key=flow
ovs-ofctl add-flow br-int \
'in_port=1 actions=set_tunnel:5001,set_field:192.168.1.1->tun_dst,3'
ovs-ofctl add-flow br-int 'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1'
๐ธ Mixed models.
you can absolutely define both flow-based and port-based tunnels at the same time, bestie. For example, it is valid and possibly useful to create and configure both the gre0 and allgre tunnel ports described above. iconic behavior honestly.
Traffic is attributed on ingress to the most specific matching tunnel. For example, gre0 is more specific than allgre. Therefore, if both exist, then gre0 will be the ingress port for any GRE traffic received from 192.168.1.1 with key 5001.
On egress, traffic may be directed to any appropriate tunnel port. If both gre0 and allgre are configured as already described, then the actions 2 and set_tunnel:5001,set_field:192.168.1.1->tun_dst,3 send the same tunnel traffic. two paths, one destiny โจ
๐ง Intermediate models.
Ports may be configured as partially flow-based. For example, one may define an OpenFlow port that represents tunnels between a pair of endpoints but leaves the flow table to discriminate on the flow key. lowkey the best of both worlds, fr fr ๐
okok so ovs-vswitchd.conf.db(5) is literally where all the deets of tunnel configuration live, if you wanna go read the whole thing ๐
These fields have no prerequisites whatsoever โ none, zero, nada โ which means a flow can match on any or all of them, in any combination you like. Mix and match, it's giving freedom ๐
And the rule that never changes: these fields are zeros for packets that did not arrive on a tunnel. No tunnel, no data, just vibes and zeros ๐ซถ
Tunnel ID Field
- Name:
tun_id(akatunnel_id) - Width: 64 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_TUNNEL_ID(38) since OpenFlow 1.3 and Open vSwitch 1.10 - NXM:
NXM_NX_TUN_ID(16) since Open vSwitch 1.1
Many kinds of tunnels support a tunnel ID:
- VXLAN and Geneve have a 24-bit virtual network identifier (VNI).
- GRE has an optional 32-bit key.
- ERSPAN has a 10-bit key (Session ID).
- GTPU has a 32-bit key (Tunnel Endpoint ID).
When a packet is received from a tunnel, this field holds the tunnel ID in its least significant bits, zero-extended so it fits. And it's zero in all of these situations, bestie, so keep up: the tunnel doesn't support an ID at all, or it's a tunnel type with an optional ID and no ID is currently in use, or an ID of zero was received, or the packet wasn't received over a tunnel in the first place. Zero, zero, zero, zero ๐ซ
When a packet is output to a tunnel port, though? The tunnel configuration is the one calling the shots on whether the tunnel ID is taken from this field or bound to a fixed value. That's the port-based vs flow-based tunnel gossip from earlier in this page โ go reread it if you skipped, iykyk โจ
Here's where this field comes from in a typical keyed GRE tunnel, diagrammed with immaculate ASCII aura ๐:
Ethernet IPv4 GRE Ethernet
<-----------> <---------------> <------------> <---------->
48 48 16 8 32 32 16 16 32 48 48 16
+---+---+-----+ +---+-----+---+---+ +---+------+---+ +---+---+----+
|dst|src|type | |...|proto|src|dst| |...| type |key| |dst|src|type| ...
+---+---+-----+ +---+-----+---+---+ +---+------+---+ +---+---+----+
0x800 47 0x6558
Tunnel IPv4 Source Field
- Name:
tun_src - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_IPV4_SRC(31) since Open vSwitch 2.0
When a packet is received from a tunnel, this field is the source address in the outer IP header of the tunneled packet. Not over a tunnel? Then it's zero, no cap ๐
When a packet is output to a flow-based tunnel port, this field has opinions about the IPv4 source address used to send the packet. If it's zero, the kernel picks an appropriate IP address using the routing table โ basically it does the homework itself ๐
Same typical keyed GRE tunnel diagram, because slay, consistency:
Ethernet IPv4 GRE Ethernet
<-----------> <---------------> <------------> <---------->
48 48 16 8 32 32 16 16 32 48 48 16
+---+---+-----+ +---+-----+---+---+ +---+------+---+ +---+---+----+
|dst|src|type | |...|proto|src|dst| |...| type |key| |dst|src|type| ...
+---+---+-----+ +---+-----+---+---+ +---+------+---+ +---+---+----+
0x800 47 0x6558
Tunnel IPv4 Destination Field
- Name:
tun_dst - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_IPV4_DST(32) since Open vSwitch 2.0
When a packet is received from a tunnel, this field is the destination address in the outer IP header of the tunneled packet. And once again: zero if the packet did not arrive over a tunnel ๐
When a packet is output to a flow-based tunnel port, this field is the one specifying where the tunnel packet gets sent. It's the destination, the where-to, the address the packet is heading to ๐ฏ
And yes, the diagram is back, she's iconic:
Ethernet IPv4 GRE Ethernet
<-----------> <---------------> <------------> <---------->
48 48 16 8 32 32 16 16 32 48 48 16
+---+---+-----+ +---+-----+---+---+ +---+------+---+ +---+---+----+
|dst|src|type | |...|proto|src|dst| |...| type |key| |dst|src|type| ...
+---+---+-----+ +---+-----+---+---+ +---+------+---+ +---+---+----+
0x800 47 0x6558
Tunnel IPv6 Source Field
- Name:
tun_ipv6_src - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_IPV6_SRC(109) since Open vSwitch 2.5
Basically tun_src but for tunnels riding over IPv6. Same energy, bigger address ๐ฆ
Tunnel IPv6 Destination Field
- Name:
tun_ipv6_dst - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_IPV6_DST(110) since Open vSwitch 2.5
And that's tun_dst but for tunnels over IPv6. Twin energy, one is just v6-coded ๐
VXLAN Group-Based Policy Fields
The VXLAN header is defined like this [RFC 7348], where the I bit must be set to 1, unlabeled bits or those labeled reserved must be set to 0, and Open vSwitch hands you the VNI through tun_id:
VXLAN flags
<------------->
1 1 1 1 1 1 1 1 24 24 8
+-+-+-+-+-+-+-+-+--------+---+--------+
| | | | |I| | | |reserved|VNI|reserved|
+-+-+-+-+-+-+-+-+--------+---+--------+
VXLAN Group-Based Policy [VXLAN Group Policy Option] adds new interpretations to bits that already existed in the VXLAN header, reinterpreting it like below, with the changes highlighted (glow up fr):
GBP flags
<------------->
1 1 1 1 1 1 1 1 24 24 8
+-+-+-+-+-+-+-+-+---------------+---+--------+
| |D| | |A| | | |group policy ID|VNI|reserved|
+-+-+-+-+-+-+-+-+---------------+---+--------+
Open vSwitch makes the GBP fields and flags available through the following fields. Heads up though, bestie: only packets that arrive over a VXLAN tunnel with the GBP extension enabled have these fields set. In every other packet they're zero on receive and just plain ignored on transmit. So don't be surprised when everything reads zero ๐
VXLAN Group-Based Policy ID Field
- Name:
tun_gbp_id - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_GBP_ID(38) since Open vSwitch 2.4
For a packet tunneled over VXLAN with the Group-Based Policy (GBP) extension, this field is the GBP policy ID, exactly like the picture above shows ๐
VXLAN Group-Based Policy Flags Field
- Name:
tun_gbp_flags - Width: 8 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_GBP_FLAGS(39) since Open vSwitch 2.4
For a packet tunneled over VXLAN with the Group-Based Policy (GBP) extension, this field is the GBP policy flags, as shown above. The field has the format below:
GBP Flags
<------------->
1 1 1 1 1 1 1 1
+-+-+-+-+-+-+-+-+
| |D| | |A| | | |
+-+-+-+-+-+-+-+-+
Unlabeled bits are reserved and must be transmitted as 0. The VXLAN GBP draft defines what the other bits mean, and here's the translation:
- D (Don't Learn) โ when this bit is set, it means the egress tunnel endpoint must not learn the source address of the encapsulated frame. Like, no learning today, thank you ๐ โโ๏ธ
- A (Applied) โ when this bit is set, it means the group policy has already been applied to this packet. Devices must not apply policies when the A bit is set. Already done, don't double-dip ๐
ERSPAN Metadata Fields
These fields give you access to features in the ERSPAN tunneling protocol [ERSPAN], which comes in two major versions: version 1 (aka type II) and version 2 (aka type III). Two eras, both valid ๐
Version aside, ERSPAN is always encapsulated inside a fixed 8-byte GRE header โ a 4-byte GRE base header plus a 4-byte sequence number. The ERSPAN version 1 header format is:
GRE ERSPAN v1 Ethernet
<------------> <---------------------> <---------->
16 16 32 4 18 10 12 20 48 48 16
+---+------+---+ +---+---+-------+---+---+ +---+---+----+
|...| type |seq| |ver|...|session|...|idx| |dst|src|type| ...
+---+------+---+ +---+---+-------+---+---+ +---+---+----+
0x88be 1 tun_id
And the ERSPAN version 2 header format is:
GRE ERSPAN v2 Ethernet
<------------> <----------------------------------------> <---------->
16 16 32 4 18 10 32 22 6 1 3 48 48 16
+---+------+---+ +---+---+-------+---------+---+----+---+---+ +---+---+----+
|...| type |seq| |ver|...|session|timestamp|...|hwid|dir|...| |dst|src|type| ...
+---+------+---+ +---+---+-------+---------+---+----+---+---+ +---+---+----+
0x22eb 2 tun_id 0/1
ERSPAN Version Field
- Name:
tun_erspan_ver - Width: 8 bits (only the least-significant 4 bits may be nonzero)
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_ET_ERSPAN_VER(12) since Open vSwitch 2.10
This is the ERSPAN version number: 1 for version 1, or 2 for version 2. Pick your fighter ๐ฅ
ERSPAN Index Field
- Name:
tun_erspan_idx - Width: 32 bits (only the least-significant 20 bits may be nonzero)
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_ET_ERSPAN_IDX(11) since Open vSwitch 2.10
โฆand the rest of this one's story is coming right up, bestie, stay tuned ๐
This field is a 20-bit index/port number tied to the ERSPAN traffic's source port and direction (ingress/egress). Heads up bestie: this one is platform dependent. ๐
ERSPAN Direction Field
- Name:
tun_erspan_dir - Width: 8 bits (only the least-significant 1 bits may be nonzero)
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_ET_ERSPAN_DIR(13) since Open vSwitch 2.10
For ERSPAN v2, this is the mirrored traffic's direction: 0 for ingress traffic, 1 for egress traffic. no cap โจ
ERSPAN Hardware ID Field
- Name:
tun_erspan_hwid - Width: 8 bits (only the least-significant 6 bits may be nonzero)
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_ET_ERSPAN_HWID(14) since Open vSwitch 2.10
A 6-bit unique identifier of an ERSPAN v2 engine within a system. ๐
GTP-U Metadata Fields
These fields give you access to set-up GPRS Tunnelling Protocol for User Plane (GTPv1-U), based on 3GPP TS 29.281. A GTP-U header has this format, bestie:
8 8 16 32
+-----+--------+------+----+
|flags|msg type|length|TEID| ...
+-----+--------+------+----+
The flags and message type have the Open vSwitch GTP-U specific fields described below. Open vSwitch makes the TEID (Tunnel Endpoint Identifier) โ which identifies a tunnel endpoint in the receiving GTP-U protocol entity โ available via tun_id. ๐
GTP-U Flags Field
- Name:
tun_gtpu_flags - Width: 8 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_ET_GTPU_FLAGS(15) since Open vSwitch 2.13
This field holds the 8-bit GTP-U flags, encoded like this:
GTP-U Tunnel Flags
<------------------->
3 1 1 1 1 1
+-------+--+---+-+-+--+
|version|PT|rsv|E|S|PN|
+-------+--+---+-+-+--+
1 0
And the flags themselves are:
versionโ used to determine the version of the GTP-U protocol, which should be set to1.PTโ Protocol type, used as a protocol discriminator between GTP (1) and GTP' (0).rsvโ Reserved. Must be zero.Eโ If1, indicates the presence of a meaningful value of the Next Extension Header field.Sโ If1, indicates the presence of a meaningful value of the Sequence Number field.PNโ If1, indicates the presence of a meaningful value of the N-PDU Number field.
GTP-U Message Type Field
- Name:
tun_gtpu_msgtype - Width: 8 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_ET_GTPU_MSGTYPE(16) since Open vSwitch 2.13
This field tells you whether it's a signalling message used for path management, or a user plane message which carries the original packet. The complete range of message types can be referred to [3GPP TS 29.281]. ๐ฆ
Geneve Fields
These fields provide access to additional features in the Geneve tunneling protocol [Geneve]. Their names are kinda generic on purpose โ the hope is that the same fields could be reused for other protocols in the future; for example, the NSH protocol [NSH] supports TLV options whose form is identical to that for Geneve options. reusing the slay โจ
Generic Tunnel Option 0 Field
- Name:
tun_metadata0 - Width: 992 bits (124 bytes)
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_METADATA0(40) since Open vSwitch 2.5
Everything above specifically covers generic tunnel option 0, but Open vSwitch supports 64 options, numbered 0 through 63, whose NXM field numbers are 40 through 103. not me doing the math ๐ญ
These fields provide OpenFlow access to the generic type-length-value options defined by the Geneve tunneling protocol, or by other protocols with options in the same TLV format as Geneve options. Each of these options has the following wire format:
header body
<-------------------> <------------------>
16 8 3 5 4ร(length - 1) bytes
+-----+----+---+------+--------------------+
|class|type|res|length| value |
+-----+----+---+------+--------------------+
0
Taken together, the class and type in the option format mean that there are about 16 million distinct kinds of TLV options โ way too many to give individual OXM code points. So Open vSwitch requires you, the user, to define the TLV options of interest by binding up to 64 TLV options to generic tunnel option NXM code points. Each option may have up to 124 bytes in its body, which is the maximum the TLV format allows, but bound options may total at most 252 bytes of body. it's giving budget ๐ซถ
Open vSwitch extensions to the OpenFlow protocol bind TLV options to NXM code points. The ovs-ofctl(8) program offers one way to use these extensions, e.g. to configure a mapping from a TLV option with class 0xffff, type 0, and a body length of 4 bytes:
ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"
Once a TLV option is properly bound, it can be accessed and modified like any other field, e.g. to send packets that have value 1234 for the option described above to the controller:
ovs-ofctl add-flow br0 tun_metadata0=1234,actions=controller
An option not received or not bound is matched as all zeros. ๐
Tunnel Flags Field
- Name:
tun_flags - Width: 16 bits (only the least-significant 1 bits may be nonzero)
- Format: tunnel flags
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_TUN_FLAGS(104) since Open vSwitch 2.5
Flags indicating various aspects of the tunnel encapsulation. ๐
Matches on this field are most conveniently written in terms of symbolic names (given in the diagram below), each preceded by either + for a flag that must be set, or - for a flag that must be unset, without any other delimiters between the flags. Flags not mentioned are wildcarded. For example, tun_flags=+oam matches only OAM packets. Matches can also be written as flags/mask, where flags and mask are 16-bit numbers in decimal or in hexadecimal prefixed by 0x.
Currently, only one flag is defined:
oamโ The tunnel protocol indicated that this is an OAM (Operations and Management) control packet.
The switch may reject matches against unknown flags.
Newer versions of Open vSwitch may introduce additional flags with new meanings. It is therefore not recommended to use an exact match on this field, since the behavior of these new flags is unknown and should be ignored. bestie, don't exact-match this one, i'm begging ๐
For non-tunneled packets, the value is 0.
๐ธ METADATA FIELDS ๐ธ
Summary:
in_portโ 2 Bytes, Mask: no, RW?: yes, Prereqs: none, NXM/OXM Support: OVS 1.1+in_port_oxmโ 4 Bytes, Mask: no, RW?: yes, Prereqs: none, NXM/OXM Support: OF 1.2+ and OVS 1.7+skb_priorityโ 4 Bytes, Mask: no, RW?: no, Prereqs: none, NXM/OXM Support: (none)pkt_markโ 4 Bytes, Mask: yes, RW?: yes, Prereqs: none, NXM/OXM Support: OVS 2.0+actset_outputโ 4 Bytes, Mask: no, RW?: no, Prereqs: none, NXM/OXM Support: OF 1.3+ and OVS 2.4+packet_typeโ 4 Bytes, Mask: no, RW?: no, Prereqs: none, NXM/OXM Support: OF 1.5+ and OVS 2.8+
These fields relate to the origin or treatment of a packet, but they are not extracted from the packet data itself. iconique โจ
Ingress Port Field
- Name:
in_port - Width: 16 bits
- Format: OpenFlow 1.0 port
- Masking: not maskable
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM: none
- NXM:
NXM_OF_IN_PORT(0) since Open vSwitch 1.1
The OpenFlow port on which the packet being processed arrived. This is a 16-bit field that holds an OpenFlow 1.0 port number. For receiving a packet, the only values that appear in this field are:
1through0xfeff(65,279), inclusive. โ Conventional OpenFlow port numbers.OFPP_LOCAL(0xfffeor 65,534). โ The ``local'' port, which in Open vSwitch is always named the same as the bridge itself. This represents a connection between the switch and the local TCP/IP stack. This port is where an IP address is most commonly configured on an Open vSwitch switch.
OpenFlow does not require a switch to have a local port, but all existing versions of Open vSwitch have always included a local port. Future Directions: Future versions of Open vSwitch might be able to optionally omit the local port, if someone submits code to implement such a feature.
OFPP_NONE(OpenFlow 1.0) orOFPP_ANY(OpenFlow 1.1+) (0xffffor 65,535).OFPP_CONTROLLER(0xfffdor 65,533). โ When a controller injects a packet into an OpenFlow switch with a ``packet-out'' request, it can specify one of these ingress ports to indicate that the packet was generated internally rather than having been received on some port.
OpenFlow 1.0 specified OFPP_NONE for this purpose. Despite that, some controllers used OFPP_CONTROLLER, and some switches only accepted OFPP_CONTROLLER, so OpenFlow 1.0.2 required support for both ports. OpenFlow 1.1 and later were more clearly drafted to allow only OFPP_CONTROLLER. For maximum compatibility, Open vSwitch allows both ports with all OpenFlow versions. ๐ซถ
Values not mentioned above will never appear when receiving a packet, including the following notable values:
0โ Zero is not a valid OpenFlow port number.OFPP_MAX(0xff00or 65,280) โ okay so this one is messy bestie. It only got clearly specified as a valid port number as of OpenFlow 1.3.3. Before that? Status unclear, chaos, nobody knew. So Open vSwitch has never allowedOFPP_MAXto be used as a port number, which means packets will never be received on this port. (Other OpenFlow switches, of course, might use it. their problem tbh ๐ )OFPP_UNSET(0xfff7or 65,527)OFPP_IN_PORT(0xfff8or 65,528)OFPP_TABLE(0xfff9or 65,529)OFPP_NORMAL(0xfffaor 65,530)OFPP_FLOOD(0xfffbor 65,531)OFPP_ALL(0xfffcor 65,532)
These port numbers are used only in output actions and never show up as ingress ports. iconic, no notes
Most of these port numbers were defined way back in OpenFlow 1.0, but OFPP_UNSET is the baby of the family โ it only got introduced in OpenFlow 1.5.
Values that will never appear when receiving a packet may still be matched against in the flow table. yes bestie, the plot twist is real ๐ There are still circumstances in which those flows can be matched:
- The
resubmitOpen vSwitch extension action lets a flow table lookup happen with an arbitrary ingress port. - An action that modifies the ingress port field (more on that below ๐), such as e.g.
loadorset_field, followed by an action or instruction that performs another flow table lookup, such asresubmitorgoto_table.
This field is heavily used for matching in OpenFlow tables, but for packet egress it has only very limited roles:
- OpenFlow requires suppressing output actions to
in_port. That is, the following two flows both drop all packets that arrive on port 1:
in_port=1,actions=1
in_port=1,actions=drop
(This behavior is occasionally useful for flooding to a subset of ports. Specifying actions=1,2,3,4, for example, outputs to ports 1, 2, 3, and 4, omitting the ingress port. sneaky but make it fashion โจ)
- OpenFlow has a special port
OFPP_IN_PORT(with value0xfff8) that outputs to the ingress port. For example, in a switch that has four ports numbered 1 through 4,actions=1,2,3,4,in_portoutputs to ports 1, 2, 3, and 4, including the ingress port.
Because the ingress port field has so little influence on packet processing, it does not ordinarily make sense to modify the ingress port field. It's writable only to support that occasional use case where the ingress port's roles in packet egress, described above, become troublesome. For example, actions=load:0->NXM_OF_IN_PORT[],output:123 will output to port 123 regardless of whether it is the ingress port. If the ingress port is important, then one may save and restore it on the stack:
actions=push:NXM_OF_IN_PORT[],load:0->NXM_OF_IN_PORT[],output:123,pop:NXM_OF_IN_PORT[]
or, in Open vSwitch 2.7 or later, use the clone action to save and restore it:
actions=clone(load:0->NXM_OF_IN_PORT[],output:123)
The ability to modify the ingress port is an Open vSwitch extension to OpenFlow.
๐ฆ OXM Ingress Port Field ๐ฆ
- Name:
in_port_oxm - Width: 32 bits
- Format: OpenFlow 1.1+ port
- Masking: not maskable
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_IN_PORT(0) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM: none
OpenFlow 1.1 and later use a 32-bit port number, so this field supplies a 32-bit view of the ingress port. glow up fr fr Current versions of Open vSwitch support only a 16-bit range of ports:
- OpenFlow 1.0 ports
0x0000to0xfeff, inclusive, map to OpenFlow 1.1 port numbers with the same values. - OpenFlow 1.0 ports
0xff00to0xffff, inclusive, map to OpenFlow 1.1 port numbers0xffffff00to0xffffffff. - OpenFlow 1.1 ports
0x0000ff00to0xfffffeffare not mapped and not supported. friendship ended ๐
in_port and in_port_oxm are two views of the same information, so all of the comments on in_port apply to in_port_oxm too. Modifying in_port changes in_port_oxm, and vice versa. same soul, two fits ๐ซถ
Setting in_port_oxm to an unsupported value yields unspecified behavior. don't do it bestie, it's giving chaos ๐ญ
๐ธ Output Queue Field ๐ธ
- Name:
skb_priority - Width: 32 bits
- Format: hexadecimal
- Masking: not maskable
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM: none
Future Directions: Open vSwitch implements the output queue as a field, but does not currently expose it through OXM or NXM for matching purposes. If this turns out to be a useful feature, it could be implemented in future versions. manifesting โจ Only the set_queue, enqueue, and pop_queue actions currently influence the output queue.
This field influences how packets in the flow will be queued, for quality of service (QoS) purposes, when they egress the switch. Its range of meaningful values, and their meanings, varies greatly from one OpenFlow implementation to another. Even within a single implementation, there is no guarantee that all OpenFlow ports have the same queues configured or that all OpenFlow ports in an implementation can be configured the same way queue-wise. it's giving "everyone's doing their own thing"
Configuring queues on OpenFlow is not well standardized. On Linux, Open vSwitch supports queue configuration via OVSDB, specifically the QoS and Queue tables (see ovs-vswitchd.conf.db(5) for details). Ports of Open vSwitch to other platforms might require queue configuration through some separate protocol (such as a CLI). Even on Linux, Open vSwitch exposes only a fraction of the kernel's queuing features through OVSDB, so advanced or unusual uses might require use of separate utilities (e.g. tc). OpenFlow switches other than Open vSwitch might use OF-CONFIG or any of the configuration methods mentioned above. Finally, some OpenFlow switches have a fixed number of fixed-function queues (e.g. eight queues with strictly defined priorities) and others do not support any control over queuing. range, honestly
The only output queue that all OpenFlow implementations must support is zero, to identify a default queue, whose properties are implementation-defined. Outputting a packet to a queue that does not exist on the output port yields unpredictable behavior: among the possibilities are that the packet might be dropped or transmitted with a very high or very low priority. not the roulette ๐
OpenFlow 1.0 only allowed output queues to be specified as part of an enqueue action that specified both a queue and an output port. That is, OpenFlow 1.0 treats the queue as an argument to an action, not as a field.
To increase flexibility, OpenFlow 1.1 added an action to set the output queue. This model was carried forward, without change, through OpenFlow 1.5.
Open vSwitch implements the native queuing model of each OpenFlow version it supports. versatile queen ๐ Open vSwitch also includes an extension for setting the output queue as an action in OpenFlow 1.0.
When a packet ingresses into an OpenFlow switch, the output queue is ordinarily set to 0, indicating the default queue. However, Open vSwitch supports various ways to forward a packet from one OpenFlow switch to another within a single host. In these cases, Open vSwitch maintains the output queue across the forwarding step. For example:
- A hop across an Open vSwitch ``patch port'' (which does not actually involve queuing) preserves the output queue.
- When a flow sets the output queue then outputs to an OpenFlow tunnel port, the encapsulation preserves the output queue. If the kernel TCP/IP stack routes the encapsulated packet directly to a physical interface, then that output honors the output queue. Alternatively, if the kernel routes the encapsulated packet to another Open vSwitch bridge, then the output queue set previously becomes the initial output queue on ingress to the second bridge and will thus be used for further output actions (unless overridden by a new ``set queue'' action).
(This description reflects the current behavior of Open vSwitch on Linux. This behavior relies on details of the Linux TCP/IP stack. It could be difficult to make ports to other operating systems behave the same way. linux girlies stay winning i guess ๐)
๐ Packet Mark Field ๐
- Name:
pkt_mark - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_PKT_MARK(33) since Open vSwitch 2.0
Packet mark comes to Open vSwitch from the Linux kernel, in which the sk_buff data structure that represents a packet contains a 32-bit member named skb_mark. The value of skb_mark propagates along with the packet it accompanies wherever the packet goes in the kernel. loyal to the end ๐ซถ It has no predefined semantics but various kernel-user interfaces can set and match on it, which makes it suitable for ``marking'' packets at one point in their handling and then acting on the mark later. With iptables, for example, one can mark some traffic specially at ingress and then handle that traffic differently at egress based on the marked value.
Packet mark is an attempt at a generalization of the skb_mark concept beyond Linux, at least through more generic naming. Like skb_priority, packet mark is preserved across forwarding steps within a machine. Unlike skb_priority, packet mark has no direct effect on packet forwarding: the value set in packet mark does not matter unless some later OpenFlow table or switch matches on packet mark, or unless the packet passes through some other kernel subsystem that has been configured to interpret packet mark in specific ways, e.g. through iptables configuration mentioned above.
Preserving packet mark across kernel forwarding steps relies heavily on kernel support, which ports to non-Linux operating systems may not have. Regardless of operating system support, Open vSwitch supports packet mark within a single bridge and across patch ports.
The value of packet mark when a packet ingresses into the first Open vSwitch bridge is typically zero, but it could be nonzero if its value was previously set by some kernel subsystem.
๐ Action Set Output Port Field
- Name:
actset_output - Width: 32 bits
- Format: OpenFlow 1.1+ port
- Masking: not maskable
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
ONFOXM_ET_ACTSET_OUTPUT(43) since OpenFlow 1.3 and Open vSwitch 2.4;OXM_OF_ACTSET_OUTPUT(43) since OpenFlow 1.5 and Open vSwitch 2.4 - NXM: none
So this one holds the output port that's currently chillin' in the OpenFlow action set โ like, from an output action inside a write_actions instruction. Its value is an OpenFlow port number. โจ And if there's no output port in the OpenFlow action set, or if that output port is just gonna get ignored (say, because there's an output group in the action set instead ๐), then the value is OFPP_UNSET. Simple as.
Open vSwitch is generous and lets any table match this field. OpenFlow though? OpenFlow only requires it to be matchable from inside an OpenFlow egress table โ which, btw, is a feature Open vSwitch does not yet implement. ๐
๐ฆ Packet Type Field
- Name:
packet_type - Width: 32 bits
- Format: packet type
- Masking: not maskable
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_PACKET_TYPE(44) since OpenFlow 1.5 and Open vSwitch 2.8 - NXM: none
The type of the packet, in the format OpenFlow 1.5 laid out:
Packet type
<--------->
16 16
+---+-------+
|ns |ns_type| ...
+---+-------+
The upper 16 bits, ns, are a namespace. What ns_type means depends entirely on the namespace. The packet type field gets specified and displayed in the format (ns,ns_type). ๐
Open vSwitch currently supports these classes of packet types for matching:
(0,0)โ Ethernet.(1,ethertype)โ the specified ethertype. Open vSwitch can forward packets with any ethertype, but it can only match on and process data fields for these supported packet types:(1,0x800)โ IPv4(1,0x806)โ ARP(1,0x86dd)โ IPv6(1,0x8847)โ MPLS(1,0x8848)โ MPLS multicast(1,0x8035)โ RARP(1,0x894f)โ NSH
Now consider the glow-up difference between a packet with packet_type=(0,0), dl_type=0x800 and one with packet_type=(1,0x800). The first one is an Ethernet frame that contains an IPv4 packet, like this:
Ethernet IPv4
<-----------> <--------------->
48 48 16 8 32 32
+---+---+-----+ +---+-----+---+---+
|dst|src|type | |...|proto|src|dst| ...
+---+---+-----+ +---+-----+---+---+
0x800
The second one? It's an IPv4 packet with no outer frame around it at all, just raw and unbothered, like this:
IPv4
<--------------->
8 32 32
+---+-----+---+---+
|...|proto|src|dst| ...
+---+-----+---+---+
Matching on packet_type is a pre-requisite for matching on any data field ๐ฅ โ but for backward compatibility, when there's a match on a data field and no packet_type match, Open vSwitch just acts like you'd matched (0,0) (Ethernet) anyway. Same energy in reverse: when Open vSwitch sends flow match info to a controller โ like in a reply to a request to dump the flow table โ it omits a match on packet type (0,0) if a data field match would've implied it. Efficient, iconic. ๐
โจ CONNECTION TRACKING FIELDS โจ
๐ธ Summary:
ct_stateโ 4 bytes โ Mask: yes โ RW?: no โ Prereqs: none โ NXM/OXM Support: OVS 2.5+ct_zoneโ 2 bytes โ Mask: no โ RW?: no โ Prereqs: none โ NXM/OXM Support: OVS 2.5+ct_markโ 4 bytes โ Mask: yes โ RW?: yes โ Prereqs: none โ NXM/OXM Support: OVS 2.5+ct_labelโ 16 bytes โ Mask: yes โ RW?: yes โ Prereqs: none โ NXM/OXM Support: OVS 2.5+ct_nw_srcโ 4 bytes โ Mask: yes โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+ct_nw_dstโ 4 bytes โ Mask: yes โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+ct_ipv6_srcโ 16 bytes โ Mask: yes โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+ct_ipv6_dstโ 16 bytes โ Mask: yes โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+ct_nw_protoโ 1 byte โ Mask: no โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+ct_tp_srcโ 2 bytes โ Mask: yes โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+ct_tp_dstโ 2 bytes โ Mask: yes โ RW?: no โ Prereqs: CT โ NXM/OXM Support: OVS 2.8+
Open vSwitch supports ``connection tracking,โโ bestie โ that's the whole thing that lets bidirectional streams of packets get statefully grouped into connections. ๐ซถ Like, Open vSwitch connection tracking can spot the patterns of TCP packets that mean a connection was successfully initiated, and also the ones that mean a connection got torn down. It can even identify related connections โ say, FTP data connections spawned off FTP control connections. Chef's kiss.
An individual packet cruising through the pipeline can be in one of two states, untrackedโโ or tracked,โโ and you tell them apart via the ``trkโโ flag in ct_state. A packet is untracked at the start of the Open vSwitch pipeline and stays untracked until the pipeline invokes the ct action. Every one of the connection tracking fields is all zeroes in an untracked packet. The moment a flow in the Open vSwitch pipeline invokes the ct action, that action initializes the connection tracking fields and boom ๐ฅ โ the packet becomes tracked for the rest of its processing.
The connection tracker keeps connection state in an internal table, but it only adds a new entry to that table when a ct action for a new connection invokes ct with the commit parameter. For any given connection, if a pipeline has executed ct but not yet with commit, the connection is called uncommitted. State for an uncommitted connection is ephemeral and does not persist past the end of the pipeline, so some features are only available to committed connections. Typically you'd leave a connection uncommitted as a way to drop its packets. ๐ซ
Connection tracking is an Open vSwitch extension to OpenFlow. Open vSwitch 2.5 added the initial support for connection tracking. Later versions added many refinements and extensions on top of that. A lot of these capabilities depend on the Open vSwitch datapath rather than just the userspace version โ the capabilities column in the Datapath table (see ovs-vswitchd.conf.db(5)) reports the detailed capabilities of a particular Open vSwitch datapath. ๐
๐ Connection Tracking State Field
- Name:
ct_state - Width: 32 bits
- Format: ct state
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_STATE(105) since Open vSwitch 2.5
This field holds several flags that you can use to figure out the state of the connection the packet belongs to. ๐ต๏ธโโ๏ธ
Matches on this field are most conveniently written in terms of symbolic names (list below ๐), each one preceded by either + for a flag that must be set, or - for a flag that must be unset, with no other delimiters between the flags. Flags you don't mention are wildcarded. So for example, tcp,ct_state=+trk-new matches TCP packets that have been run through the connection tracker and do not establish a new connection. Matches can also be written as flags/mask, where flags and mask are 32-bit numbers in decimal, or in hexadecimal prefixed by 0x.
The following flags are defined:
new(0x01) โ A new connection. Set to 1 if this is an uncommitted connection.est(0x02) โ Part of an existing connection. Set to 1 if packets of a committed connection have been seen by conntrack from both directions.rel(0x04) โ Related to an existing connection, e.g. an ICMP ``destination unreachableโโ message or an FTP data connection. This flag will only be 1 if the connection to which this one is related is committed.
Connections identified as rel are separate from the originating connection and must be committed separately. All packets for a related connection will have the rel flag set, not just the initial packet.
rpl(0x08) โ This packet is in the reply direction, meaning it's going the opposite way from the packet that initiated the connection. This flag will only be 1 if the connection is committed.inv(0x10) โ The state is invalid, meaning the connection tracker couldn't identify the connection. This flag is a catch-all for problems in the connection or in the connection tracker itself, such as:- L3/L4 protocol handler is not loaded/unavailable. With the Linux kernel datapath, this may mean that the
nf_conntrack_ipv4ornf_conntrack_ipv6modules are not loaded. - L3/L4 protocol handler determines that the packet is malformed.
- Packets are unexpected length for protocol.
- L3/L4 protocol handler is not loaded/unavailable. With the Linux kernel datapath, this may mean that the
trk(0x20) โ This packet is tracked, meaning it has previously traversed the connection tracker. If this flag is not set, then no other flags will be set. If this flag is set, then the packet is tracked and other flags may also be set.snat(0x40) โ This packet was transformed by source address/port translation by a precedingctaction. Open vSwitch 2.6 added this flag. โจdnat(0x80) โ This packet was transformed by destination address/port translation by a precedingctaction. Open vSwitch 2.6 added this flag. โจ
There are additional constraints on these flags, listed in decreasing order of precedence below:
- If
trkis unset, no other flags are set. - If
trkis set, one or more other flags may be set. - If
invis set, only thetrkflag is also set. newandestare mutually exclusive.newandrplare mutually exclusive.relmay be set in conjunction with any other flags.
Future versions of Open vSwitch may define new flags. ๐ฎ
๐ Connection Tracking Zone Field
- Name:
ct_zone - Width: 16 bits
- Format: hexadecimal
- Masking: not maskable
- Prerequisites: none
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_ZONE(106) since Open vSwitch 2.5
So a connection tracking zone is literally just the zone value that got passed to the most recent ct action, bestie. And the whole point of zones? Every zone is its own independent connection tracking context ๐ซง โ so if you wanna track the same packet in multiple contexts you gotta hit the ct action multiple times. No shortcuts, no vibes-only path. โจ
๐ท๏ธ Connection Tracking Mark Field
- Name:
ct_mark - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_MARK(107) since Open vSwitch 2.5
This one is the metadata that gets committed โ by an action inside the exec parameter to the ct action โ to the connection that the current packet belongs to. It's giving "sticky note for the connection" energy ๐ and honestly? Obsessed.
๐ Connection Tracking Label Field
- Name:
ct_label - Width: 128 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_LABEL(108) since Open vSwitch 2.5
Same deal but thicc ๐ โ the label committed, by an action within the exec parameter to the ct action, to the connection the current packet belongs to. 128 whole bits to play with, queen behavior.
Open vSwitch 2.8 introduced the matching support for connection tracker original direction 5-tuple fields. ๐
For non-committed non-related connections, the conntrack original direction tuple fields always have the same values as the corresponding headers in the packet itself. But for any other packets of a committed connection, those conntrack original direction tuple fields reflect the values from that initial non-committed non-related packet โ which means they may be different from the actual packet headers. ๐ณ Why? Because the actual packet headers may be:
- in reverse direction (for reply packets) ๐
- transformed by NAT (when the
natoption was applied to the connection) ๐ช - or be of a different protocol (i.e., when an ICMP response is sent to an UDP packet) ๐
And for related connections, e.g. an FTP data connection, the original direction tuple contains the original direction headers from the parent connection โ e.g. an FTP control connection. ๐
The following fields are populated by the ct action, and they require a match to a valid connection tracking state as a prerequisite, in addition to the IP or IPv6 ethertype match. Examples of valid connection tracking state matches include ct_state=+new, ct_state=+est, ct_state=+rel, and ct_state=+trk-inv. ๐ซถ
๐ซ Connection Tracking Original Direction IPv4 Source Address Field
- Name:
ct_nw_src - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_NW_SRC(120) since Open vSwitch 2.8
Matches IPv4 conntrack original direction tuple source address. See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8. โจ
๐ธ Connection Tracking Original Direction IPv4 Destination Address Field
- Name:
ct_nw_dst - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_NW_DST(121) since Open vSwitch 2.8
Matches IPv4 conntrack original direction tuple destination address. See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8. ๐
๐ฆ Connection Tracking Original Direction IPv6 Source Address Field
- Name:
ct_ipv6_src - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_IPV6_SRC(122) since Open vSwitch 2.8
Matches IPv6 conntrack original direction tuple source address. See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8. ๐
๐ง Connection Tracking Original Direction IPv6 Destination Address Field
- Name:
ct_ipv6_dst - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_IPV6_DST(123) since Open vSwitch 2.8
Matches IPv6 conntrack original direction tuple destination address. See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8. โญ
๐ฅ Connection Tracking Original Direction IP Protocol Field
- Name:
ct_nw_proto - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_NW_PROTO(119) since Open vSwitch 2.8
Matches the conntrack original direction tuple IP protocol type, which you specify as a decimal number between 0 and 255, inclusive โ like 1 to match ICMP packets, or 6 to match TCP packets. ๐ In the case of, for example, an ICMP response to an UDP packet, this may be different from the IP protocol type of the packet itself. See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8.
๐ Connection Tracking Original Direction Transport Layer Source Port Field
- Name:
ct_tp_src - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_TP_SRC(124) since Open vSwitch 2.8
Bitwise match on the conntrack original direction tuple transport source, when MFF_CT_NW_PROTO has value 6 for TCP, 17 for UDP, or 132 for SCTP. And when MFF_CT_NW_PROTO has value 1 for ICMP, or 58 for ICMPv6, the lower 8 bits of MFF_CT_TP_SRC matches the conntrack original direction ICMP type. ๐ซง See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8.
๐ Connection Tracking Original Direction Transport Layer Source Port Field
- Name:
ct_tp_dst - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: CT
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_CT_TP_DST(125) since Open vSwitch 2.8
Bitwise match on the conntrack original direction tuple transport destination port, when MFF_CT_NW_PROTO has value 6 for TCP, 17 for UDP, or 132 for SCTP. And when MFF_CT_NW_PROTO has value 1 for ICMP, or 58 for ICMPv6, the lower 8 bits of MFF_CT_TP_DST matches the conntrack original direction ICMP code. ๐
See the paragraphs above for the general description of the conntrack original direction tuple. Introduced in Open vSwitch 2.8.
Summary
Bestie, every single one of these is a little scratchpad for the switch ๐. Receipts first, no cap:
metadataโ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.2+ and OVS 1.8+reg0โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.1+reg1โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.1+reg2โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.1+reg3โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.1+reg4โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.3+reg5โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.7+reg6โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.7+reg7โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 1.7+reg8โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg9โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg10โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg11โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg12โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg13โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg14โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg15โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+reg16โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg17โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg18โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg19โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg20โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg21โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg22โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg23โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg24โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg25โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg26โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg27โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg28โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg29โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg30โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+reg31โ 4 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+xreg0โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg1โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg2โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg3โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg4โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg5โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg6โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg7โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 2.4+xreg8โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg9โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg10โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg11โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg12โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg13โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg14โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xreg15โ 8 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OF 1.3+ and OVS 3.7+xxreg0โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+xxreg1โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+xxreg2โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+xxreg3โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 2.6+xxreg4โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+xxreg5โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+xxreg6โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+xxreg7โ 16 bytes, masking: yes, read/write: yes, prereqs: none, NXM/OXM support: OVS 3.7+
These fields give an OpenFlow switch space for temporary storage while the pipeline is running. Whereas metadata fields can have a meaningful initial value and can persist across some hops across OpenFlow switches, registers are always initially 0 and their values never persist across inter-switch hops (not even across patch ports). ๐ซถ
OpenFlow Metadata Field
- Name:
metadata - Width: 64 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes
- OXM:
OXM_OF_METADATA(2) since OpenFlow 1.2 and Open vSwitch 1.8 - NXM: none
This one is the OG, bestie โ the oldest standardized OpenFlow register field, and it showed up way back in OpenFlow 1.1 ๐ . The whole reason it exists is to model the limited number of user-defined bits that some ASIC-based switches are able to carry through their pipelines. And because hardware be like that, OpenFlow lets switches support writing and masking only an implementation-defined subset of the bits, or honestly even no bits at all ๐ญ. The Open vSwitch software switch always supports all 64 bits, but obviously an Open vSwitch port to an ASIC would be stuck with the exact same restriction as the ASIC itself, no cap.
It's got an OXM code point, but OpenFlow 1.4 and earlier only let you modify it with a specialized instruction, not with a set-field action. OpenFlow 1.5 removes that restriction. And Open vSwitch? Doesn't enforce it, regardless of OpenFlow version. Periodt. โจ
Register 0 Field
- Name:
reg0 - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_REG0(0) since Open vSwitch 1.1
This is the first of several Open vSwitch registers, and every single one of them has the same properties, so once you get this one you basically get all of them ๐. Open vSwitch 1.1 introduced registers 0, 1, 2, and 3; version 1.3 added register 4; version 1.7 added registers 5, 6, and 7; version 2.6 added registers 8 through 15; and version 3.7 added registers 16 through 31. Iconic growth arc, honestly.
Code points for registers 0 through 15 are defined within NXM_NX code point prefix, while registers 16 through 31 are defined within NXOXM_ET starting with NXOXM_ET_REG16 (17), due to limited space within the NXM_NX class. Not me feeling bad for the NXM_NX class, there's just not enough room ๐.
Extended Register 0 Field
- Name:
xreg0 - Width: 64 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_PKT_REG0(0) since OpenFlow 1.3 and Open vSwitch 2.4 - NXM: none
This is the first of the registers that got introduced in OpenFlow 1.5. OpenFlow 1.5 calls these fields just the "packet registers," but Open vSwitch already had 32-bit registers going by that name, so Open vSwitch uses the name "extended registers" to try and reduce the confusion ๐ฆ. The standard allows for up to 128 registers, each 64 bits wide, but Open vSwitch only implements 4 (in versions 2.4 and 2.5), 8 (in version 2.6 and later), or 16 (in version 3.7 and later). Like, the standard said 128 and OVS said "we'll see" ๐ญ.
Code points for all of the extended registers are defined within OXM_OF_PKT_REG code point prefix.
Each of the 64-bit extended registers overlays two of the 32-bit registers: xreg0 overlays reg0 and reg1, with reg0 supplying the most-significant bits of xreg0 and reg1 the least-significant. Similarly, xreg1 overlays reg2 and reg3, and so on. The way that they just stack on top of each other? Main character energy, fr fr.
The OpenFlow specification says, "In most cases, the packet registers can not be matched in tables, i.e. they usually can not be used in the flow entry match structure" [OpenFlow 1.5, section 7.2.3.10], but there is no reason for a software switch to impose such a restriction, and Open vSwitch does not. ๐ She chose chaos and honestly? We love that for her.
Double-Extended Register 0 Field
- Name:
xxreg0 - Width: 128 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: none
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_XXREG0(111) since Open vSwitch 2.6
This is the first of the double-extended registers introduce in Open vSwitch 2.6 ๐. Each of the 128-bit extended registers overlays four of the 32-bit registers: xxreg0 overlays reg0 through reg3, with reg0 supplying the most-significant bits of xxreg0 and reg3 the least-significant. xxreg1 similarly overlays reg4 through reg7, and so on. Open vSwitch only implements 4 128-bit registers (in versions 2.6 and later) and 8 (in version 3.7 and later). We keep growing, it's giving glow-up ๐.
Code points for double-extended registers 0 through 3 are defined within NXM_NX code point prefix, while registers 4 through 7 are defined within NXOXM_ET starting with NXOXM_ET_XXREG4 (33), due to limited space within the NXM_NX class. Same space-crunch saga, different register ๐.
๐ฆ LAYER 2 (ETHERNET) FIELDS ๐ฆ
๐ธ Summary: ๐ธ
eth_srcakadl_srcโ 6 bytes ยท maskable: yes ยท read/write: yes ยท prereq: Ethernet ยท NXM/OXM: OF 1.2+ and OVS 1.1+eth_dstakadl_dstโ 6 bytes ยท maskable: yes ยท read/write: yes ยท prereq: Ethernet ยท NXM/OXM: OF 1.2+ and OVS 1.1+eth_typeakadl_typeโ 2 bytes ยท maskable: no ยท read/write: no ยท prereq: Ethernet ยท NXM/OXM: OF 1.2+ and OVS 1.1+
okay so real talk โ Ethernet is literally the only layer-2 protocol Open vSwitch supports, periodt. And like basically every other piece of software out there, Open vSwitch and OpenFlow treat an Ethernet frame as starting with the 14-byte header and ending with the final byte of the payload. That means the frame check sequence is not considered part of the frame. ๐
๐ Ethernet Source Field ๐
- Name:
eth_src(akadl_src) - Width: 48 bits
- Format: Ethernet
- Masking: arbitrary bitwise masks
- Prerequisites: Ethernet
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes
- OXM:
OXM_OF_ETH_SRC(4) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ETH_SRC(2) since Open vSwitch 1.1
It's the Ethernet source address, bestie:
Ethernet
<---------->
48 48 16
+---+---+----+
|dst|src|type| ...
+---+---+----+
๐ Ethernet Destination Field ๐
- Name:
eth_dst(akadl_dst) - Width: 48 bits
- Format: Ethernet
- Masking: arbitrary bitwise masks
- Prerequisites: Ethernet
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes
- OXM:
OXM_OF_ETH_DST(3) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ETH_DST(1) since Open vSwitch 1.1
And here's the Ethernet destination address:
Ethernet
<---------->
48 48 16
+---+---+----+
|dst|src|type| ...
+---+---+----+
Open vSwitch 1.8 and later? Obsessed โ they support arbitrary masks for source and/or destination. Earlier versions could only mask the destination, and only with these four masks:
01:00:00:00:00:00โ Match only the multicast bit. Sodl_dst=01:00:00:00:00:00/01:00:00:00:00:00matches all multicast (including broadcast) Ethernet packets, anddl_dst=00:00:00:00:00:00/01:00:00:00:00:00matches all unicast Ethernet packets.fe:ff:ff:ff:ff:ffโ Match all bits except the multicast bit. This is probably not useful. ๐ff:ff:ff:ff:ff:ffโ Exact match (equivalent to omitting the mask).00:00:00:00:00:00โ Wildcard all bits (equivalent todl_dst=*).
๐ Ethernet Type Field ๐
- Name:
eth_type(akadl_type) - Width: 16 bits
- Format: hexadecimal
- Masking: not maskable
- Prerequisites: Ethernet
- Access: read-only
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_ETH_TYPE(5) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ETH_TYPE(3) since Open vSwitch 1.1
The most commonly seen Ethernet frames today use a format called Ethernet II, where the last two bytes of the Ethernet header specify the Ethertype. For a frame like that, this field gets copied from those header bytes, like so:
Ethernet
<---------------->
48 48 16
+---+---+----------+
|dst|src| type | ...
+---+---+----------+
โฅ0x600
Every Ethernet type has a value 0x600 (1,536) or greater. But when those last two bytes of the Ethernet header are too small to be an Ethernet type, then whatever value is sitting there is actually the total length of the frame in bytes, excluding the Ethernet header. An 802.2 LLC header typically comes right after the Ethernet header in that case. And heads up: OpenFlow and Open vSwitch only support LLC headers with DSAP and SSAP 0xaa and control byte 0x03, which is the combo that says a SNAP header follows. Then, OpenFlow and Open vSwitch only support a SNAP header with organization 0x000000. When all that lines up, this field gets copied from the type field in the SNAP header, like this:
Ethernet LLC SNAP
<------------> <------------> <----------------->
48 48 16 8 8 8 24 16
+---+---+------+ +----+----+----+ +--------+----------+
|dst|src| type | |DSAP|SSAP|cntl| | org | type | ...
+---+---+------+ +----+----+----+ +--------+----------+
<0x600 0xaa 0xaa 0x03 0x000000 โฅ0x600
When an 802.1Q header is squeezed in after the Ethernet source and destination, this field gets populated with the encapsulated Ethertype, not the 802.1Q Ethertype. With an Ethernet II inner frame, the result is giving:
Ethernet 802.1Q Ethertype
<------> <--------> <-------->
48 48 16 16 16
+----+---+ +------+---+ +----------+
|dst |src| | TPID |TCI| | type | ...
+----+---+ +------+---+ +----------+
0x8100 โฅ0x600
And LLC + SNAP encapsulation with an 802.1Q header looks like this:
Ethernet 802.1Q Ethertype LLC SNAP
<------> <--------> <-------> <------------> <----------------->
48 48 16 16 16 8 8 8 24 16
+----+---+ +------+---+ +---------+ +----+----+----+ +--------+----------+
|dst |src| | TPID |TCI| | type | |DSAP|SSAP|cntl| | org | type | ...
+----+---+ +------+---+ +---------+ +----+----+----+ +--------+----------+
0x8100 <0x600 0xaa 0xaa 0x03 0x000000 โฅ0x600
And when a packet doesn't match any of the header formats described above, Open vSwitch and OpenFlow set this field to 0x5ff (OFP_DL_TYPE_NOT_ETH_TYPE). ๐
๐ VLAN FIELDS ๐
๐ธ Summary: ๐ธ
dl_vlanโ 2 bytes (low 12 bits) ยท maskable: no ยท read/write: yes ยท prereq: Ethernetdl_vlan_pcpโ 1 byte (low 3 bits) ยท maskable: no ยท read/write: yes ยท prereq: Ethernetvlan_vidโ 2 bytes (low 12 bits) ยท maskable: yes ยท read/write: yes ยท prereq: Ethernet ยท NXM/OXM: OF 1.2+ and OVS 1.7+vlan_pcpโ 1 byte (low 3 bits) ยท maskable: no ยท read/write: yes ยท prereq: VLAN VID ยท NXM/OXM: OF 1.2+ and OVS 1.7+vlan_tciโ 2 bytes ยท maskable: yes ยท read/write: yes ยท prereq: Ethernet ยท NXM/OXM: OVS 1.1+
ngl the 802.1Q VLAN header causes more drama than any other 4 bytes in networking. ๐ญ OpenFlow 1.0, 1.1, and 1.2+ all treat VLANs differently, and Open vSwitch extensions throw yet another variant into the mix. Open vSwitch reconciles all four treatments as best it can.
โจ VLAN Header Format โจ
An 802.1Q VLAN header is made of two 16-bit fields:
TPID TCI
<-------> <--------->
16 3 1 12
+---------+---+---+---+
|Ethertype|PCP|CFI|VID|
+---------+---+---+---+
0x8100 0
The first 16 bits of the VLAN header, the TPID (Tag Protocol IDentifier), is an Ethertype. When the VLAN header is inserted just after the source and destination MAC addresses in a Ethertype frame, the TPID is what signals the presence of the VLAN. The standard TPID โ the only one Open vSwitch supports โ is 0x8100. OpenFlow 1.0 explicitly supports only TPID 0x8100. OpenFlow 1.1 (but not earlier or later versions) also requires support for TPID 0x88a8 (Open vSwitch does not support this). OpenFlow 1.2 through 1.5 don't require support for specific TPIDs (though the push vlan header action does say that only 0x8100 and 0x88a8 should be pushed). And literally no version of OpenFlow gives you a way to distinguish or match on the TPID. ๐
The remaining 16 bits of the VLAN header, the TCI (Tag Control Information), breaks down into three subfields:
- PCP (Priority Control Point) โ a 3-bit 802.1p priority. The lowest priority is value 1, the second-lowest is value 0, and priority increases from 2 up to highest priority 7.
- CFI (Canonical Format Indicator) โ a 1-bit field. On an Ethernet network its value is always 0, which is why it later got repurposed under the name DEI (Drop Eligibility Indicator). By either name, OpenFlow and Open vSwitch don't provide any way to match or set this bit.
- VID (VLAN IDentifier) โ a 12-bit VLAN. If the VID is 0, then the frame is not part of a VLAN โ in that case the VLAN header is called a priority tag, because it's only meaningful for assigning the frame a priority. VID
0xfff(4,095) is reserved.
See eth_type for illustrations of a complete Ethernet frame with the 802.1Q tag included. ๐ซถ
โจ Multiple VLANs โจ
Open vSwitch can match only a single VLAN header. If more than one VLAN header is present, then eth_type holds the TPID of the inner VLAN header. Open vSwitch stops parsing the packet after the inner TPID, so matching further into the packet (e.g. on the inner TCI or L3 fields) is not possible. ๐ซ
OpenFlow only directly supports matching a single VLAN header. In OpenFlow 1.1 or later, one OpenFlow table can match on the outermost VLAN header and pop it off, and a later OpenFlow table can match on the next outermost header. Open vSwitch does not support this.
โจ VLAN Field Details โจ
The four variants have three different levels of expressiveness: OpenFlow 1.0 and 1.1 VLAN matching are less powerful than OpenFlow 1.2+ VLAN matching, which is less powerful than Open vSwitch extension VLAN matching. It's giving โจtiersโจ.
๐ง OpenFlow 1.0 VLAN Fields ๐ง
OpenFlow 1.0 uses two fields, called dl_vlan and dl_vlan_pcp, each of which can be either exact-matched or wildcarded, to specify VLAN matches:
- When both
dl_vlananddl_vlan_pcpare wildcarded, the flow matches packets without an 802.1Q header or with any 802.1Q header. - The match
dl_vlan=0xffffcauses a flow to match only packets without an 802.1Q header. Such a flow should also wildcarddl_vlan_pcp, since a packet without an 802.1Q header does not have a PCP. OpenFlow does not specify what to do if a match on PCP is actually present, but Open vSwitch ignores it. - Otherwise, the flow matches only packets with an 802.1Q header. If
dl_vlanis not wildcarded, then the flow only matches packets with the VLAN ID specified indl_vlanโs low 12 bits. Ifdl_vlan_pcpis not wildcarded, then the flow only matches packets with the priority specified indl_vlan_pcpโs low 3 bits.
bestie, important: OpenFlow does not tell you how to read the high 4 bits ofdl_vlanor the high 5 bits ofdl_vlan_pcp. And Open vSwitch? It simply ignores them. ๐
๐ธ OpenFlow 1.1 VLAN Fields ๐ธ
okay so VLAN matching in OpenFlow 1.1 is giving very similar energy to 1.0, no cap. The one little glow-up: when dl_vlan matches on 0xfffe (OFVPID_ANY), the flow matches only packets that have an 802.1Q header โ any VLAN ID, she's not picky. If dl_vlan_pcp is wildcarded, the flow matches any packet with an 802.1Q header, regardless of VLAN ID or priority. And if dl_vlan_pcp is not wildcarded, then the flow only matches packets with the priority specified in dl_vlan_pcpโs low 3 bits. โจ
Also, OpenFlow 1.1 calls it OFPVID_NONE instead of OFP_VLAN_NONE for a dl_vlan of 0xffff โ different name, same meaning, it's giving rebrand. ๐
And in OpenFlow 1.1, Open vSwitch reports error OFPBMC_BAD_VALUE if you try to match on dl_vlan between 4,096 and 0xfffd, inclusive, or dl_vlan_pcp greater than 7. So likeโฆ don't. โ
๐ฆ OpenFlow 1.2 VLAN Fields ๐ฆ
๐ OpenFlow 1.2+ VLAN ID Field ๐
- Name:
vlan_vid - Width: 16 bits (only the least-significant 12 bits may be nonzero)
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: Ethernet
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_VLAN_VID(6) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM: none
The OpenFlow standard describes this field as consisting of 12+1 bits. On ingress, its value is 0 if no 802.1Q header is present, and otherwise it holds the VLAN VID in its least significant 12 bits, with bit 12 (0x1000 aka OFPVID_PRESENT) also set to 1. The three most significant bits are always zero, bestie, always:
OXM_OF_VLAN_VID
<------------->
3 1 12
+---+--+--------+
| |P |VLAN ID |
+---+--+--------+
0
Because of how this field is formatted, you can use it to match the VLAN ID in every single way the OpenFlow 1.0 and 1.1 formats offer, plus a few new ones. Obsessed:
- Fully wildcarded โ Matches any packet, that is, one without an 802.1Q header or with an 802.1Q header with any TCI value.
- Value
0x0000(OFPVID_NONE), mask0xffff(or no mask) โ Matches only packets without an 802.1Q header. - Value
0x1000, mask0x1000โ Matches any packet with an 802.1Q header, regardless of VLAN ID. - Value
0x1009, mask0xffff(or no mask) โ Match only packets with an 802.1Q header with VLAN ID 9. - Value
0x1001, mask0x1001โ Matches only packets that have an 802.1Q header with an odd-numbered VLAN ID. (This is just an example; one can match on any desired VLAN ID bit pattern.)
๐ OpenFlow 1.2+ VLAN Priority Field ๐
- Name:
vlan_pcp - Width: 8 bits (only the least-significant 3 bits may be nonzero)
- Format: decimal
- Masking: not maskable
- Prerequisites: VLAN VID
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_VLAN_PCP(7) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM: none
The 3 least significant bits are the ones you use to match the PCP bits in an 802.1Q header. Every other bit is always zero, periodt:
OXM_OF_VLAN_VID
<------------->
5 3
+--------+------+
| zero | PCP |
+--------+------+
0
You can only use this field when vlan_vid is not wildcarded and does not exact match on 0 (which, reminder, only matches when there's no 802.1Q header at all). ๐ซ
See VLAN Comparison Chart, below, for some examples. ๐
๐ Open vSwitch Extension VLAN Field ๐
The vlan_tci extension can describe more kinds of VLAN matches than the other variants โ like, a lot more. And it's also simpler than the other variants. Serving both looks and brains. ๐
โญ VLAN TCI Field โญ
- Name:
vlan_tci - Width: 16 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: Ethernet
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM: none
- NXM:
NXM_OF_VLAN_TCI(4) since Open vSwitch 1.1
For a packet without an 802.1Q header, this field is zero. For a packet with an 802.1Q header, this field is the TCI with the bit in CFI's position (marked P for present below) forced to 1. So for a packet in VLAN 9 with priority 7, it has the value 0xf009:
NXM_VLAN_TCI
<---------->
3 1 12
+----+--+----+
|PCP |P |VID |
+----+--+----+
7 1 9
Usage examples, because I know you want them:
vlan_tci=0โ Match packets without an 802.1Q header.vlan_tci=0x1000/0x1000โ Match packets with an 802.1Q header, regardless of VLAN and priority values.vlan_tci=0xf123โ Match packets tagged with priority 7 in VLAN0x123.vlan_tci=0x1123/0x1fffโ Match packets tagged with VLAN0x123(and any priority).vlan_tci=0x5000/0xf000โ Match packets tagged with priority 2 (in any VLAN).vlan_tci=0/0xfffโ Match packets with no 802.1Q header or tagged with VLAN 0 (and any priority).vlan_tci=0x5000/0xe000โ Match packets with no 802.1Q header or tagged with priority 2 (in any VLAN).vlan_tci=0/0xefffโ Match packets with no 802.1Q header or tagged with VLAN 0 and priority 0.
See VLAN Comparison Chart, below, for more examples. ๐ซถ
๐ VLAN Comparison Chart ๐
The following table describes each of several possible matching criteria on 802.1Q header may be expressed with each variation of the VLAN matching fields:
[1]โ OpenFlow 1.0:????/1,??/?ยท OpenFlow 1.1:????/1,??/?ยท OpenFlow 1.2+:0000/0000,--ยท NXM:0000/0000[2]โ OpenFlow 1.0:ffff/0,??/?ยท OpenFlow 1.1:ffff/0,??/?ยท OpenFlow 1.2+:0000/ffff,--ยท NXM:0000/ffff[3]โ OpenFlow 1.0:0xxx/0,??/1ยท OpenFlow 1.1:0xxx/0,??/1ยท OpenFlow 1.2+:1xxx/ffff,--ยท NXM:1xxx/1fff[4]โ OpenFlow 1.0:????/1,0y/0ยท OpenFlow 1.1:fffe/0,0y/0ยท OpenFlow 1.2+:1000/1000,0yยท NXM:z000/f000[5]โ OpenFlow 1.0:0xxx/0,0y/0ยท OpenFlow 1.1:0xxx/0,0y/0ยท OpenFlow 1.2+:1xxx/ffff,0yยท NXM:zxxx/ffff[6]โ OpenFlow 1.0:(none)ยท OpenFlow 1.1:(none)ยท OpenFlow 1.2+:1001/1001,--ยท NXM:1001/1001[7]โ OpenFlow 1.0:(none)ยท OpenFlow 1.1:(none)ยท OpenFlow 1.2+:(none)ยท NXM:3000/3000[8]โ OpenFlow 1.0:(none)ยท OpenFlow 1.1:(none)ยท OpenFlow 1.2+:(none)ยท NXM:0000/0fff[9]โ OpenFlow 1.0:(none)ยท OpenFlow 1.1:(none)ยท OpenFlow 1.2+:(none)ยท NXM:0000/f000[10]โ OpenFlow 1.0:(none)ยท OpenFlow 1.1:(none)ยท OpenFlow 1.2+:(none)ยท NXM:0000/efff
All numbers in the table are expressed in hexadecimal. The columns in the table are interpreted as follows:
- Criteria โ See the list below.
- OpenFlow 1.0
- OpenFlow 1.1 โ
wwww/x,yy/zmeans VLAN ID match valuewwwwwith wildcard bitxand VLAN PCP match valueyywith wildcard bitz.?means that the given bits are ignored (and conventionally0forwwwworyy, conventionally1forxorz).(none)means that OpenFlow 1.0 (or 1.1) cannot match with these criteria. - OpenFlow 1.2+ โ
xxxx/yyyy,zzmeansvlan_vidwith valuexxxxand maskyyyy, andvlan_pcp(which is not maskable) with valuezz.--means thatvlan_pcpis omitted.(none)means that OpenFlow 1.2 cannot match with these criteria. - NXM โ
xxxx/yyyymeansvlan_tciwith valuexxxxand maskyyyy.
The matching criteria described by the table 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.
OpenFlow 1.0 doesn't define the behavior if dl_vlan is set to 0xffff and dl_vlan_pcp is not wildcarded. (Open vSwitch always ignores dl_vlan_pcp when dl_vlan is set to 0xffff.)
OpenFlow 1.1 says explicitly to ignore dl_vlan_pcp when dl_vlan is set to 0xffff.
OpenFlow 1.2 doesn't say how to interpret a match with vlan_vid value 0 and a mask with OFPVID_PRESENT (0x1000) set to 1 and some other bits in the mask set to 1 also. Open vSwitch interprets it the same way as a mask of 0x1000.
Any NXM match with vlan_tci value 0 and the CFI bit set to 1 in the mask is equivalent to the one listed in the table.
[3]โ Matches only packets that have an 802.1Q header with VIDxxx(and any PCP).[4]โ Matches only packets that have an 802.1Q header with PCPy(and any VID).
OpenFlow 1.0 doesn't clearly define the behavior for this case. Open vSwitch implements it this way.
In the NXM value, z equals (y << 1) | 1.
[5]โ Matches only packets that have an 802.1Q header with VIDxxxand PCPy.
In the NXM value, z equals (y << 1) | 1.
[6]โ Matches only packets that have an 802.1Q header with an odd-numbered VID (and any PCP). Only possible with OpenFlow 1.2 and NXM. (This is just an example; one can match on any desired VID bit pattern.)[7]โ 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.)[8]โ Matches packets with no 802.1Q header or with an 802.1Q header with a VID of 0. Only possible with NXM.[9]โ Matches packets with no 802.1Q header or with an 802.1Q header with a PCP of 0. Only possible with NXM.[10]โ Matches packets with no 802.1Q header or with an 802.1Q header with both VID and PCP of 0. Only possible with NXM.
๐ LAYER 2.5: MPLS FIELDS ๐
โจ Summary โจ
mpls_labelโ bytes:4(low 20 bits) ยท maskable: no ยท read/write: yes ยท prereq:MPLSยท NXM/OXM support:OF 1.2+ and OVS 1.11+mpls_tcโ bytes:1(low 3 bits) ยท maskable: no ยท read/write: yes ยท prereq:MPLSยท NXM/OXM support:OF 1.2+ and OVS 1.11+mpls_bosโ bytes:1(low 1 bits) ยท maskable: no ยท read/write: no ยท prereq:MPLSยท NXM/OXM support:OF 1.3+ and OVS 1.11+mpls_ttlโ bytes:1ยท maskable: no ยท read/write: yes ยท prereq:MPLSยท NXM/OXM support:OVS 2.6+
okay bestie so one or more MPLS headers โ we usually call them MPLS labels, that's the vibe โ come right after an Ethernet type field that says "hey, MPLS" [RFC 3032]. Ethertype 0x8847 handles all the unicast stuff. Multicast MPLS splits into two specific classes: one rocks Ethertype 0x8847 and the other goes 0x8848 [RFC 5332].
The most common overall packet format is Ethernet II, and look at her:
Ethernet MPLS
<------------> <------------>
48 48 16 20 3 1 8
+---+---+------+ +-----+--+-+---+
|dst|src| type | |label|TC|S|TTL| ...
+---+---+------+ +-----+--+-+---+
0x8847
(SNAP encapsulation may be used but it's not ordinarily seen in Ethernet networks, so don't stress.)
MPLS can also be encapsulated inside an 802.1Q header, and when that happens the combination is giving:
Ethernet 802.1Q Ethertype MPLS
<------> <--------> <-------> <------------>
48 48 16 16 16 20 3 1 8
+----+---+ +------+---+ +---------+ +-----+--+-+---+
|dst |src| | TPID |TCI| | type | |label|TC|S|TTL| ...
+----+---+ +------+---+ +---------+ +-----+--+-+---+
0x8100 0x8847
Now the fields living inside an MPLS label, one by one:
- Label, 20 bits. โ An identifier. That's the whole job.
- Traffic control (TC), 3 bits. โ Used for quality of service.
- Bottom of stack (BOS), 1 bit (labeled just
Sin the diagrams above).0indicates that another MPLS label follows this one.1indicates that this MPLS label is the last one in the stack, so that some other protocol follows this one.
- Time to live (TTL), 8 bits. โ Each hop across an MPLS network decrements the TTL by
1. If it reaches0, the packet is discarded. OpenFlow does not make the MPLS TTL available as a match field, but actions are available to set and decrement the TTL. Open vSwitch 2.6 and later makes the MPLS TTL available as an extension.
๐ MPLS Label Stacks ๐
Unlike every other encapsulation OpenFlow and Open vSwitch support, MPLS labels are routinely used in "stacks" two or three deep and sometimes even deeper. Open vSwitch currently supports up to three labels.
The OpenFlow specification only supports matching on the outermost MPLS label at any given time. To match on the second label, you must first "pop" the outer label and advance to another OpenFlow table, where the inner label may be matched. To match on the third label, you pop the two outer labels, and so on. It's giving layers, ok ๐
๐ฆ MPLS Inner Protocol ๐ฆ
Unlike all other forms of encapsulation that Open vSwitch and OpenFlow support, an MPLS label does not indicate what inner protocol it encapsulates. Different deployments figure out the inner protocol in different ways [RFC 3032]:
- A few reserved label values do indicate an inner protocol. Label
0, the "IPv4 Explicit NULL Label," indicates inner IPv4. Label2, the "IPv6 Explicit NULL Label," indicates inner IPv6. - Some deployments use a single inner protocol consistently.
- In some deployments, the inner protocol must be inferred from the innermost label.
- In some deployments, the inner protocol must be inferred from the innermost label and the encapsulated data, e.g. to distinguish between inner IPv4 and IPv6 based on whether the first nibble of the inner protocol data are
4or6. OpenFlow and Open vSwitch do not currently support these cases.
Open vSwitch and OpenFlow do not infer the inner protocol, even if reserved label values are in use. Instead, the flow table must specify the inner protocol at the time it pops the bottommost MPLS label, using the Ethertype argument to the pop_mpls action. No guessing allowed, bestie, you have to say it out loud.
๐ Field Details ๐
MPLS Label Field
- Name:
mpls_label - Width:
32bits (only the least-significant20bits may be nonzero) - Format: decimal
- Masking: not maskable
- Prerequisites:
MPLS - Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_MPLS_LABEL(34) since OpenFlow 1.2 and Open vSwitch1.11 - NXM: none
The least significant 20 bits hold the "label" field from the MPLS label. Other bits are zero:
OXM_OF_MPLS_LABEL
<--------------->
12 20
+--------+--------+
| zero | label |
+--------+--------+
0
Most label values are available for any use by deployments. Values under 16 are reserved.
MPLS Traffic Class Field
- Name:
mpls_tc - Width:
8bits (only the least-significant3bits may be nonzero) - Format: decimal
- Masking: not maskable
- Prerequisites:
MPLS - Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_MPLS_TC(35) since OpenFlow 1.2 and Open vSwitch1.11 - NXM: none
The least significant 3 bits hold the TC field from the MPLS label. Other bits are zero:
OXM_OF_MPLS_TC
<------------>
5 3
+--------+-----+
| zero | TC |
+--------+-----+
0
This field is intended for use for Quality of Service (QoS) and Explicit Congestion Notification purposes, but its particular interpretation is deployment specific.
Before 2009, this field was named EXP and reserved for experimental use [RFC 5462]. glow-up era fr.
MPLS Bottom of Stack Field
- Name:
mpls_bos - Width:
8bits (only the least-significant1bits may be nonzero) - Format: decimal
- Masking: not maskable
- Prerequisites:
MPLS - Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_MPLS_BOS(36) since OpenFlow 1.3 and Open vSwitch1.11 - NXM: none
The least significant bit holds the BOS field from the MPLS label. Other bits are zero:
OXM_OF_MPLS_BOS
<------------->
7 1
+--------+------+
| zero | BOS |
+--------+------+
0
This field is useful as part of processing a series of incoming MPLS labels. A flow that includes a pop_mpls action should generally match on mpls_bos:
- When
mpls_bosis0, there is another MPLS label following this one, so the Ethertype passed topop_mplsshould be an MPLS Ethertype. For example:table=0, dl_type=0x8847, mpls_bos=0, actions=pop_mpls:0x8847, goto_table:1 - When
mpls_bosis1, this MPLS label is the last one, so the Ethertype passed topop_mplsshould be a non-MPLS Ethertype such as IPv4. For example:table=1, dl_type=0x8847, mpls_bos=1, actions=pop_mpls:0x0800, goto_table:2
MPLS Time-to-Live Field
- Name:
mpls_ttl - Width:
8bits - Format: decimal
- Masking: not maskable
- Prerequisites:
MPLS - Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_MPLS_TTL(30) since Open vSwitch2.6
Holds the 8-bit time-to-live field from the MPLS label:
NXM_NX_MPLS_TTL
<------------->
8
+---------------+
| TTL |
+---------------+
๐ LAYER 3: IPV4 AND IPV6 FIELDS ๐
โจ Summary โจ
ip_srcakanw_srcโ bytes:4ยท mask: yes ยท read/write: yes ยท prereq:IPv4ยท NXM/OXM support:OF 1.2+ and OVS 1.1+ip_dstakanw_dstโ bytes:4ยท mask: yes ยท read/write: yes ยท prereq:IPv4ยท NXM/OXM support:OF 1.2+ and OVS 1.1+ipv6_srcโ bytes:16ยท mask: yes ยท read/write: yes ยท prereq:IPv6ยท NXM/OXM support:OF 1.2+ and OVS 1.1+ipv6_dstโ bytes:16ยท mask: yes ยท read/write: yes ยท prereq:IPv6ยท NXM/OXM support:OF 1.2+ and OVS 1.1+ipv6_labelโ bytes:4(low 20 bits) ยท mask: yes ยท read/write: yes ยท prereq:IPv6ยท NXM/OXM support:OF 1.2+ and OVS 1.4+nw_protoakaip_protoโ bytes:1ยท mask: no ยท read/write: no ยท prereq:IPv4/IPv6ยท NXM/OXM support:OF 1.2+ and OVS 1.1+nw_ttlโ bytes:1ยท mask: no ยท read/write: yes ยท prereq:IPv4/IPv6ยท NXM/OXM support:OVS 1.4+ip_fragakanw_fragโ bytes:1(low 2 bits) ยท mask: yes ยท read/write: no ยท prereq:IPv4/IPv6ยท NXM/OXM support:OVS 1.3+nw_tosโ bytes:1ยท mask: no ยท read/write: yes ยท prereq:IPv4/IPv6ยท NXM/OXM support:OVS 1.1+ip_dscpโ bytes:1(low 6 bits) ยท mask: no ยท read/write: yes ยท prereq:IPv4/IPv6ยท NXM/OXM support:OF 1.2+ and OVS 1.7+nw_ecnakaip_ecnโ bytes:1(low 2 bits) ยท mask: no ยท read/write: yes ยท prereq:IPv4/IPv6ยท NXM/OXM support:OF 1.2+ and OVS 1.4+
๐ธ IPv4 Specific Fields ๐ธ
These fields are applicable only to IPv4 flows, that is, flows that match on the IPv4 Ethertype 0x0800.
IPv4 Source Address Field
- Name:
ip_src(akanw_src) - Width:
32bits - Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites:
IPv4 - Access: read/write
- OpenFlow 1.0: yes (CIDR match only)
- OpenFlow 1.1: yes
- OXM:
OXM_OF_IPV4_SRC(11) since OpenFlow 1.2 and Open vSwitch1.7 - NXM:
NXM_OF_IP_SRC(7) since Open vSwitch1.1
The source address from the IPv4 header, she's right there:
Ethernet IPv4
<-----------> <--------------->
48 48 16 8 32 32
+---+---+-----+ +---+-----+---+---+
|dst|src|type | |...|proto|src|dst| ...
+---+---+-----+ +---+-----+---+---+
0x800
For historical reasons, in an ARP or RARP flow, Open vSwitch interprets matches on nw_src as actually referring to the ARP SPA. iconic legacy behavior, we don't make the rules ๐
IPv4 Destination Address Field ๐
- Name:
ip_dst(akanw_dst) - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: IPv4
- Access: read/write
- OpenFlow 1.0: yes (CIDR match only)
- OpenFlow 1.1: yes
- OXM:
OXM_OF_IPV4_DST(12) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_IP_DST(8) since Open vSwitch 1.1
It's literally just the destination address chillin' in the IPv4 header, bestie:
Ethernet IPv4
<-----------> <--------------->
48 48 16 8 32 32
+---+---+-----+ +---+-----+---+---+
|dst|src|type | |...|proto|src|dst| ...
+---+---+-----+ +---+-----+---+---+
0x800
okay so tiny little historical plot twist ๐ โ for historical reasons, in an ARP or RARP flow, Open vSwitch reads matches on nw_dst as actually pointing at the ARP TPA. Not a bug, just โจloreโจ.
IPv6 Specific Fields ๐
These ones are IPv6-only, like a very exclusive club โ they apply only to IPv6 flows, meaning flows that match on the IPv6 Ethertype 0x86dd. No 0x86dd? Then you're not on the list, sorry bestie ๐ซถ.
IPv6 Source Address Field ๐ฆ
- Name:
ipv6_src - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: IPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_IPV6_SRC(26) since OpenFlow 1.2 and Open vSwitch 1.1 - NXM:
NXM_NX_IPV6_SRC(19) since Open vSwitch 1.1
The source address straight out of the IPv6 header:
Ethernet IPv6
<------------> <-------------->
48 48 16 8 128 128
+---+---+------+ +---+----+---+---+
|dst|src| type | |...|next|src|dst| ...
+---+---+------+ +---+----+---+---+
0x86dd
๐ซ Open vSwitch 1.8 added support for bitwise matching; earlier versions supported only CIDR masks. So if you're on the old stuff, that's the vibe you're stuck with.
IPv6 Destination Address Field ๐ธ
- Name:
ipv6_dst - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: IPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_IPV6_DST(27) since OpenFlow 1.2 and Open vSwitch 1.1 - NXM:
NXM_NX_IPV6_DST(20) since Open vSwitch 1.1
The destination address, same deal, straight from the IPv6 header:
Ethernet IPv6
<------------> <-------------->
48 48 16 8 128 128
+---+---+------+ +---+----+---+---+
|dst|src| type | |...|next|src|dst| ...
+---+---+------+ +---+----+---+---+
0x86dd
๐ซ Open vSwitch 1.8 added support for bitwise matching; earlier versions supported only CIDR masks. Yes, same energy as ipv6_src, they're a matching set fr fr.
IPv6 Flow Label Field ๐
- Name:
ipv6_label - Width: 32 bits (only the least-significant 20 bits may be nonzero)
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: IPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_IPV6_FLABEL(28) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_IPV6_LABEL(27) since Open vSwitch 1.4
The least significant 20 bits hold the flow label field from the IPv6 header. Other bits are zero, no notes:
OXM_OF_IPV6_FLABEL
<---------------->
12 20
+--------+---------+
| zero | label |
+--------+---------+
0
IPv4/IPv6 Fields ๐
These fields exist with at least approximately the same meaning in both IPv4 and IPv6, so they're treated as one single field for matching purposes. Any flow that matches on the IPv4 Ethertype 0x0800 or the IPv6 Ethertype 0x86dd may match on these fields. One field, two protocols, zero drama ๐
IPv4/v6 Protocol Field ๐ฅ
- Name:
nw_proto(akaip_proto) - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: IPv4/IPv6
- Access: read-only
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_IP_PROTO(10) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_IP_PROTO(6) since Open vSwitch 1.1
Matches the IPv4 or IPv6 protocol type. Simple as that โจ
another lil historical moment: for historical reasons, in an ARP or RARP flow, Open vSwitch reads matches on nw_proto as actually referring to the ARP opcode. The ARP opcode is a 16-bit field, so for matching purposes ARP opcodes greater than 255 are treated as 0; this works adequately because in practice ARP and RARP only use opcodes 1 through 4. So like. it's fine. it works. don't stress ๐ซถ
In the case of fragmented traffic, a difference exists in the way the field acts for IPv4 and IPv6 later fragments. For IPv6 fragments with nonzero offset, nw_proto is set to the IPv6 protocol type for fragments (44). Conversely, for IPv4 later fragments, the field is set based on the protocol type present in the header. Different behaviour, same field name โ iykyk ๐ญ
IPv4/v6 TTL/Hop Limit Field โญ
- Name:
nw_ttl - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: IPv4/IPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_IP_TTL(29) since Open vSwitch 1.4
The main reason to match on the TTL or hop limit field is to detect whether a dec_ttl action will fail due to a TTL exceeded error. Another way that a controller can detect TTL exceeded is to listen for OFPR_INVALID_TTL ``packet-inโโ messages via OpenFlow. Two routes to the same receipts, pick your fave ๐
IPv4/v6 Fragment Bitmask Field ๐
- Name:
ip_frag(akanw_frag) - Width: 8 bits (only the least-significant 2 bits may be nonzero)
- Format: frag
- Masking: arbitrary bitwise masks
- Prerequisites: IPv4/IPv6
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXM_NX_IP_FRAG(26) since Open vSwitch 1.3
Specifies what kinds of IP fragments or non-fragments to match. The value for this field is most conveniently specified as one of the following:
noโ Match only non-fragmented packets.yesโ Matches all fragments.firstโ Matches only fragments with offset 0.laterโ Matches only fragments with nonzero offset.not_laterโ Matches non-fragmented packets and fragments with zero offset.
The field is internally formatted as 2 bits: bit 0 is 1 for an IP fragment with any offset (and otherwise 0), and bit 1 is 1 for an IP fragment with nonzero offset (and otherwise 0), like so:
NXM_NX_IP_FRAG
<------------>
6 1 1
+----+-----+---+
|zero|later|any|
+----+-----+---+
0
Even though 2 bits have 4 possible values, this field only uses 3 of them:
- A packet that is not an IP fragment has value 0.
- A packet that is an IP fragment with offset 0 (the first fragment) has bit 0 set and thus value 1.
- A packet that is an IP fragment with nonzero offset has bits 0 and 1 set and thus value 3.
The switch may reject matches against values that can never appear. ๐
It is important to understand how this field interacts with the OpenFlow fragment handling mode. No skipping this part bestie, it's the whole point ๐
- In
OFPC_FRAG_DROPmode, the OpenFlow switch drops all IP fragments before they reach the flow table, so every packet that is available for matching will have value 0 in this field. - Open vSwitch does not implement
OFPC_FRAG_REASMmode, but if it did then IP fragments would be reassembled before they reached the flow table and again every packet available for matching would always have value 0. - In
OFPC_FRAG_NORMALmode, all three values are possible, but OpenFlow 1.0 says that fragmentsโ transport ports are always 0, even for the first fragment, so this does not provide much extra information. - In
OFPC_FRAG_NX_MATCHmode, all three values are possible. For fragments with offset 0, Open vSwitch makes L4 header information available.
Thus, this field is likely to be most useful for an Open vSwitch switch configured in OFPC_FRAG_NX_MATCH mode. See the description of the set-frags command in ovs-ofctl(8), for more details. go read that one too, it's giving necessary context ๐
IPv4/IPv6 TOS Fields โจ
IPv4 and IPv6 contain a one-byte ``type of serviceโโ or TOS field that has the following format:
type of service
<------------->
6 2
+--------+------+
| DSCP | ECN |
+--------+------+
IPv4/v6 DSCP (Bits 2-7) Field ๐
- Name:
nw_tos - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: IPv4/IPv6
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM: none
- NXM:
NXM_OF_IP_TOS(5) since Open vSwitch 1.1
This field is the TOS byte with the two ECN bits cleared to 0:
NXM_OF_IP_TOS
<----------->
6 2
+------+------+
| DSCP | zero |
+------+------+
0
IPv4/v6 DSCP (Bits 0-5) Field ๐ฆ
- Name:
ip_dscp - Width: 8 bits (only the least-significant 6 bits may be nonzero)
- Format: decimal
- Masking: not maskable
- Prerequisites: IPv4/IPv6
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_IP_DSCP(8) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM: none
This field is the TOS byte shifted right to put the DSCP bits in the 6 least-significant bits:
OXM_OF_IP_DSCP
<------------>
2 6
+-------+------+
| zero | DSCP |
+-------+------+
0
IPv4/v6 ECN Field ๐ธ
- Name:
nw_ecn(akaip_ecn) - Width: 8 bits (only the least-significant 2 bits may be nonzero)
- Format: decimal
- Masking: not maskable
- Prerequisites: IPv4/IPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_IP_ECN(9) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_IP_ECN(28) since Open vSwitch 1.4
This field is the TOS byte with the DSCP bits cleared to 0:
OXM_OF_IP_ECN
<----------->
6 2
+-------+-----+
| zero | ECN |
+-------+-----+
0
๐ฆ LAYER 3: ARP FIELDS ๐ฆ
โจ Summary โจ
Name Bytes Mask RW? Prereqs NXM/OXM Support
โโโโโโโโ โโโโโโ โโโโโ โโโโ โโโโโโโโ โโโโโโโโโโโโโโโโโโโโโ
arp_op 2 no yes ARP OF 1.2+ and OVS 1.1+
arp_spa 4 yes yes ARP OF 1.2+ and OVS 1.1+
arp_tpa 4 yes yes ARP OF 1.2+ and OVS 1.1+
arp_sha 6 yes yes ARP OF 1.2+ and OVS 1.1+
arp_tha 6 yes yes ARP OF 1.2+ and OVS 1.1+
Okay bestie, so Address Resolution Protocol โ ARP โ is technically a generic protocol that can be used to get the hardware address matching any higher-level protocol address. But in contemporary usage, ARP is only used on Ethernet networks to get the Ethernet address for a given IPv4 address. OpenFlow and Open vSwitch only support this usage of ARP. For this use case, an ARP packet has the format below, and the ARP fields that OVS exposes are literally highlighted:
Ethernet ARP
<-----------> <---------------------------------->
48 48 16 16 16 8 8 16 48 32 48 32
+---+---+-----+ +---+-----+---+---+--+---+---+---+---+
|dst|src|type | |hrd| pro |hln|pln|op|sha|spa|tha|tpa|
+---+---+-----+ +---+-----+---+---+--+---+---+---+---+
0x806 1 0x800 6 4
Oh and these ARP fields are also used for RARP, the Reverse Address Resolution Protocol, because RARP literally shares ARPโs wire format. ๐ค
๐ซ ARP Opcode Field ๐ซ
- Name:
arp_op - Width: 16 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ARP
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_ARP_OP(21) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ARP_OP(15) since Open vSwitch 1.1
Even though this is a 16-bit field, Open vSwitch does not support ARP opcodes greater than 255; it treats them to zero. This works adequately because in practice ARP and RARP only use opcodes 1 through 4. ๐
๐ซ ARP Source IPv4 Address Field ๐ซ
- Name:
arp_spa - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: ARP
- Access: read/write
- OpenFlow 1.0: yes (CIDR match only)
- OpenFlow 1.1: yes
- OXM:
OXM_OF_ARP_SPA(22) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ARP_SPA(16) since Open vSwitch 1.1
๐ซ ARP Target IPv4 Address Field ๐ซ
- Name:
arp_tpa - Width: 32 bits
- Format: IPv4
- Masking: arbitrary bitwise masks
- Prerequisites: ARP
- Access: read/write
- OpenFlow 1.0: yes (CIDR match only)
- OpenFlow 1.1: yes
- OXM:
OXM_OF_ARP_TPA(23) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ARP_TPA(17) since Open vSwitch 1.1
๐ซ ARP Source Ethernet Address Field ๐ซ
- Name:
arp_sha - Width: 48 bits
- Format: Ethernet
- Masking: arbitrary bitwise masks
- Prerequisites: ARP
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_ARP_SHA(24) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ARP_SHA(17) since Open vSwitch 1.1
๐ซ ARP Target Ethernet Address Field ๐ซ
- Name:
arp_tha - Width: 48 bits
- Format: Ethernet
- Masking: arbitrary bitwise masks
- Prerequisites: ARP
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_ARP_THA(25) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ARP_THA(18) since Open vSwitch 1.1
โจ LAYER 3: NSH FIELDS โจ
okay besties, buckle UP โ this is the Service Function Chaining corner of the manual and it comes with a whole diagram, so grab a snack ๐
๐ธ Summary:
| Name | Bytes | Mask | RW? | Prereqs | NXM/OXM Support |
|---|---|---|---|---|---|
nsh_flags | 1 | yes | yes | NSH | OVS 2.8+ |
nsh_ttl | 1 | no | yes | NSH | OVS 2.9+ |
nsh_mdtype | 1 | no | no | NSH | OVS 2.8+ |
nsh_np | 1 | no | no | NSH | OVS 2.8+ |
nsh_spi aka nsp | 4 (low 24 bits) | no | yes | NSH | OVS 2.8+ |
nsh_si aka nsi | 1 | no | yes | NSH | OVS 2.8+ |
nsh_c1 aka nshc1 | 4 | yes | yes | NSH | OVS 2.8+ |
nsh_c2 aka nshc2 | 4 | yes | yes | NSH | OVS 2.8+ |
nsh_c3 aka nshc3 | 4 | yes | yes | NSH | OVS 2.8+ |
nsh_c4 aka nshc4 | 4 | yes | yes | NSH | OVS 2.8+ |
ngl that table isn't a Markdown table in the original โ original lays it out like a lil spreadsheet with the header row Name / Bytes / Mask / RW? / Prereqs / NXM/OXM Support and the rows below it, so keep that energy in your head ๐ซถ
So like. Service functions are literally everywhere in modern networks and they are essential, no cap. These lil guys bring you security, WAN acceleration, server load balancing โ the whole glow-up package. And they can be spun up at so many different spots in the network infra: the wide area network, the data center, you name it, they're chilling there ๐
Before the SFC architecture got defined in [RFC 7665] and the protocol spelled out in this document, service function deployment models were lowkey static and totally bound to topology for insertion and policy selection. And bestie, they did not adapt well to the elastic service environments that virtualization unlocked. Not the vibe. ๐ญ
New data center network and cloud architectures need way more flexible service function deployment models. Plus, the whole transition to virtual platforms demands an agile service insertion model that supports dynamic and elastic service delivery. Specifically, these functions are non-negotiable:
- The movement of service functions and application workloads in the network.
- The ability to easily bind service policy to granular information, such as per-subscriber state.
- The capability to steer traffic to the requisite service function(s).
The Network Service Header (NSH) spec defines a brand new data plane protocol โ it's an encapsulation for service function chains. The NSH is designed to encapsulate an original packet or frame, and then in turn gets encapsulated by an outer transport encapsulation (which is the thing that actually delivers the NSH to NSH-aware network elements), and it looks like this:
+-----------------------+----------------------------+---------------------+
|Transport Encapsulation|Network Service Header (NSH)|Original Packet/Frame|
+-----------------------+----------------------------+---------------------+
The NSH is composed of these elements:
- Service Function Path identification.
- Indication of location within a Service Function Path.
- Optional, per packet metadata (fixed length or variable).
[RFC 7665] gives you the overview of a service chaining architecture โ it clearly defines the roles of the various elements and the scope of a service function chaining encapsulation. Figure 3 of [RFC 7665] depicts the SFC architectural components after classification. And the NSH? It's the SFC encapsulation referenced in [RFC 7665]. slay โจ
๐ฆ flags field (2 bits)
- Name:
nsh_flags - Width: 8 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_FLAGS(1) since Open vSwitch 2.8
๐ฆ TTL field (6 bits)
- Name:
nsh_ttl - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_TTL(10) since Open vSwitch 2.9
๐ฆ mdtype field (8 bits)
- Name:
nsh_mdtype - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: NSH
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_MDTYPE(2) since Open vSwitch 2.8
๐ฆ np (next protocol) field (8 bits)
- Name:
nsh_np - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: NSH
- Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_NP(3) since Open vSwitch 2.8
๐ฆ spi (service path identifier) field (24 bits)
- Name:
nsh_spi(akansp) - Width: 32 bits (only the least-significant 24 bits may be nonzero)
- Format: hexadecimal
- Masking: not maskable
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_SPI(4) since Open vSwitch 2.8
๐ฆ si (service index) field (8 bits)
- Name:
nsh_si(akansi) - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_SI(5) since Open vSwitch 2.8
๐ฆ c1 (Network Platform Context) field (32 bits)
- Name:
nsh_c1(akanshc1) - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_C1(6) since Open vSwitch 2.8
๐ฆ c2 (Network Shared Context) field (32 bits)
- Name:
nsh_c2(akanshc2) - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_C2(7) since Open vSwitch 2.8
๐ฆ c3 (Service Platform Context) field (32 bits)
- Name:
nsh_c3(akanshc3) - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_C3(8) since Open vSwitch 2.8
๐ฆ c4 (Service Shared Context) field (32 bits)
- Name:
nsh_c4(akanshc4) - Width: 32 bits
- Format: hexadecimal
- Masking: arbitrary bitwise masks
- Prerequisites: NSH
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
NXOXM_NSH_C4(9) since Open vSwitch 2.8
okay the NSH field lineup is fully served ๐ keep scrolling bestie, there's more of this manual to go โ we're not done yet ๐ซถ
๐ธ LAYER 4: TCP, UDP, AND SCTP FIELDS ๐ธ
okay bestie we're at LAYER 4 now and it's giving โจtransport layer realnessโจ ๐
๐ Summary:
tcp_srcakatp_srcโ 2 bytes โ mask: yes โ RW?: yes โ prereq:TCPโ NXM/OXM Support:OF 1.2+andOVS 1.1+tcp_dstakatp_dstโ 2 bytes โ mask: yes โ RW?: yes โ prereq:TCPโ NXM/OXM Support:OF 1.2+andOVS 1.1+tcp_flagsโ 2 bytes (low 12 bits) โ mask: yes โ RW?: no โ prereq:TCPโ NXM/OXM Support:OF 1.3+andOVS 2.1+udp_srcโ 2 bytes โ mask: yes โ RW?: yes โ prereq:UDPโ NXM/OXM Support:OF 1.2+andOVS 1.1+udp_dstโ 2 bytes โ mask: yes โ RW?: yes โ prereq:UDPโ NXM/OXM Support:OF 1.2+andOVS 1.1+sctp_srcโ 2 bytes โ mask: yes โ RW?: yes โ prereq:SCTPโ NXM/OXM Support:OF 1.2+andOVS 2.0+sctp_dstโ 2 bytes โ mask: yes โ RW?: yes โ prereq:SCTPโ NXM/OXM Support:OF 1.2+andOVS 2.0+
okay so for matching purposes, no distinction is made whether these protocols are encapsulated within IPv4 or IPv6. fr fr. no cap. ๐
๐ TCP
this diagram shows TCP inside IPv4. Open vSwitch also supports TCP in IPv6 (slay โจ). Only TCP fields implemented as Open vSwitch fields are shown:
Ethernet IPv4 TCP
<-----------> <---------------> <------------------->
48 48 16 8 32 32 16 16 12
+---+---+-----+ +---+-----+---+---+ +---+---+---+-----+---+
|dst|src|type | |...|proto|src|dst| |src|dst|...|flags|...| ...
+---+---+-----+ +---+-----+---+---+ +---+---+---+-----+---+
0x800 6
๐ TCP Source Port Field
- Name:
tcp_src(akatp_src) - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites:
TCP - Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_TCP_SRC(13) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_TCP_SRC(9) since Open vSwitch 1.1
Open vSwitch 1.6 added support for bitwise matching.
๐ TCP Destination Port Field
- Name:
tcp_dst(akatp_dst) - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites:
TCP - Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_TCP_DST(14) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_TCP_DST(10) since Open vSwitch 1.1
Open vSwitch 1.6 added support for bitwise matching.
๐ฅ TCP Flags Field
- Name:
tcp_flags - Width: 16 bits (only the least-significant 12 bits may be nonzero)
- Format: TCP flags
- Masking: arbitrary bitwise masks
- Prerequisites:
TCP - Access: read-only
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
ONFOXM_ET_TCP_FLAGS(42) since OpenFlow 1.3 and Open vSwitch 2.4;OXM_OF_TCP_FLAGS(42) since OpenFlow 1.5 and Open vSwitch 2.3 - NXM:
NXM_NX_TCP_FLAGS(34) since Open vSwitch 2.1
this field holds the TCP flags ๐ . TCP currently defines 9 flag bits. an additional 3 bits are reserved. for more info, see [RFC 793], [RFC 3168], and [RFC 3540]. ๐ฆ
matches on this field are most conveniently written in terms of symbolic names (given in the diagram below), each preceded by either + for a flag that must be set, or - for a flag that must be unset, without any other delimiters between the flags. flags not mentioned are wildcarded. for example, tcp,tcp_flags=+syn-ack matches TCP SYNs that are not ACKs, and tcp,tcp_flags=+[200] matches TCP packets with the reserved [200] flag set. matches can also be written as flags/mask, where flags and mask are 16-bit numbers in decimal or in hexadecimal prefixed by 0x.
the flag bits are:
reserved later RFCs RFC 793
<---------------> <--------> <--------------------->
4 1 1 1 1 1 1 1 1 1 1 1 1
+----+-----+-----+-----+--+---+---+---+---+---+---+---+---+
|zero|[800]|[400]|[200]|NS|CWR|ECE|URG|ACK|PSH|RST|SYN|FIN|
+----+-----+-----+-----+--+---+---+---+---+---+---+---+---+
0
๐ UDP
this diagram shows UDP inside IPv4. Open vSwitch also supports UDP in IPv6 โจ. Only UDP fields that Open vSwitch exposes as fields are shown:
Ethernet IPv4 UDP
<-----------> <---------------> <--------->
48 48 16 8 32 32 16 16
+---+---+-----+ +---+-----+---+---+ +---+---+---+
|dst|src|type | |...|proto|src|dst| |src|dst|...| ...
+---+---+-----+ +---+-----+---+---+ +---+---+---+
0x800 17
๐ UDP Source Port Field
- Name:
udp_src - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites:
UDP - Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_UDP_SRC(15) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_UDP_SRC(11) since Open vSwitch 1.1
๐ UDP Destination Port Field
- Name:
udp_dst - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites:
UDP - Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_UDP_DST(16) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_UDP_DST(12) since Open vSwitch 1.1
๐ SCTP
this diagram shows SCTP inside IPv4. Open vSwitch also supports SCTP in IPv6 ๐. Only SCTP fields that Open vSwitch exposes as fields are shown:
Ethernet IPv4 SCTP
<-----------> <---------------> <--------->
48 48 16 8 32 32 16 16
+---+---+-----+ +---+-----+---+---+ +---+---+---+
|dst|src|type | |...|proto|src|dst| |src|dst|...| ...
+---+---+-----+ +---+-----+---+---+ +---+---+---+
0x800 132
๐ SCTP Source Port Field
- Name:
sctp_src - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites:
SCTP - Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_SCTP_SRC(17) since OpenFlow 1.2 and Open vSwitch 2.0 - NXM: none
๐ SCTP Destination Port Field
- Name:
sctp_dst - Width: 16 bits
- Format: decimal
- Masking: arbitrary bitwise masks
- Prerequisites:
SCTP - Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_SCTP_DST(18) since OpenFlow 1.2 and Open vSwitch 2.0 - NXM: none
โจ LAYER 4: ICMPV4 AND ICMPV6 FIELDS โจ
Okay bestie, this is the ping-pong layer, the "are you alive??" layer, and it has OPINIONS ๐
๐ Summary
Here's the whole squad at a glance โ bytes, whether they're maskable, whether you can read/write them, what has to be true first, and which NXM/OXM supports them:
icmp_typeโ 1 byte, mask: no, RW: yes, prereq: ICMPv4, NXM/OXM support: OF 1.2+ and OVS 1.1+icmp_codeโ 1 byte, mask: no, RW: yes, prereq: ICMPv4, NXM/OXM support: OF 1.2+ and OVS 1.1+icmpv6_typeโ 1 byte, mask: no, RW: yes, prereq: ICMPv6, NXM/OXM support: OF 1.2+ and OVS 1.1+icmpv6_codeโ 1 byte, mask: no, RW: yes, prereq: ICMPv6, NXM/OXM support: OF 1.2+ and OVS 1.1+nd_targetโ 16 bytes, mask: yes, RW: yes, prereq: ND, NXM/OXM support: OF 1.2+ and OVS 1.1+nd_sllโ 6 bytes, mask: yes, RW: yes, prereq: ND solicit, NXM/OXM support: OF 1.2+ and OVS 1.1+nd_tllโ 6 bytes, mask: yes, RW: yes, prereq: ND advert, NXM/OXM support: OF 1.2+ and OVS 1.1+nd_reservedโ 4 bytes, mask: no, RW: yes, prereq: ND, NXM/OXM support: OVS 2.11+nd_options_typeโ 1 byte, mask: no, RW: yes, prereq: ND, NXM/OXM support: OVS 2.11+
๐ฉท ICMPv4
Look at the packet layout, it's literally so symmetrical:
Ethernet IPv4 ICMPv4
<-----------> <---------------> <----------->
48 48 16 8 32 32 8 8
+---+---+-----+ +---+-----+---+---+ +----+----+---+
|dst|src|type | |...|proto|src|dst| |type|code|...| ...
+---+---+-----+ +---+-----+---+---+ +----+----+---+
0x800 1
๐ ICMPv4 Type Field
- Name:
icmp_type - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ICMPv4
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_ICMPV4_TYPE(19) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ICMP_TYPE(13) since Open vSwitch 1.1
Blast from the past moment: for historical reasons, when you're in an ICMPv4 flow, Open vSwitch reads a match on tp_src as actually meaning the ICMP type. Yes, fr fr, that's just how it is. ๐
๐ ICMPv4 Code Field
- Name:
icmp_code - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ICMPv4
- Access: read/write
- OpenFlow 1.0: yes (exact match only)
- OpenFlow 1.1: yes (exact match only)
- OXM:
OXM_OF_ICMPV4_CODE(20) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_OF_ICMP_CODE(14) since Open vSwitch 1.1
Same backstory, different field: for historical reasons, in an ICMPv4 flow Open vSwitch treats a match on tp_dst as actually pointing at the ICMP code. The audacity of legacy behaviour, honestly. ๐
๐ฉต ICMPv6
V6 edition, still cute, still paying attention:
Ethernet IPv6 ICMPv6
<------------> <--------------> <----------->
48 48 16 8 128 128 8 8
+---+---+------+ +---+----+---+---+ +----+----+---+
|dst|src| type | |...|next|src|dst| |type|code|...| ...
+---+---+------+ +---+----+---+---+ +----+----+---+
0x86dd 58
๐ ICMPv6 Type Field
- Name:
icmpv6_type - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ICMPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_ICMPV6_TYPE(29) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ICMPV6_TYPE(21) since Open vSwitch 1.1
๐ ICMPv6 Code Field
- Name:
icmpv6_code - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ICMPv6
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_ICMPV6_CODE(30) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ICMPV6_CODE(22) since Open vSwitch 1.1
๐ธ ICMPv6 Neighbor Discovery
This is the "hey neighbour, who dis" protocol and it stacks up like this:
Ethernet IPv6 ICMPv6 ICMPv6 ND
<------------> <--------------> <--------------> <--------------->
48 48 16 8 128 128 8 8 128
+---+---+------+ +---+----+---+---+ +-------+----+---+ +------+----------+
|dst|src| type | |...|next|src|dst| | type |code|...| |target|option ...|
+---+---+------+ +---+----+---+---+ +-------+----+---+ +------+----------+
0x86dd 58 135/136 0
๐ ICMPv6 Neighbor Discovery Target IPv6 Field
- Name:
nd_target - Width: 128 bits
- Format: IPv6
- Masking: arbitrary bitwise masks
- Prerequisites: ND
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_IPV6_ND_TARGET(31) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ND_TARGET(23) since Open vSwitch 1.1
๐ ICMPv6 Neighbor Discovery Source Ethernet Address Field
- Name:
nd_sll - Width: 48 bits
- Format: Ethernet
- Masking: arbitrary bitwise masks
- Prerequisites: ND solicit
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_IPV6_ND_SLL(32) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ND_SLL(24) since Open vSwitch 1.1
๐ ICMPv6 Neighbor Discovery Target Ethernet Address Field
- Name:
nd_tll - Width: 48 bits
- Format: Ethernet
- Masking: arbitrary bitwise masks
- Prerequisites: ND advert
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM:
OXM_OF_IPV6_ND_TLL(33) since OpenFlow 1.2 and Open vSwitch 1.7 - NXM:
NXM_NX_ND_TLL(25) since Open vSwitch 1.1
๐ ICMPv6 Neighbor Discovery Reserved Field Field
(Yes the name really does say "Field Field", we are not editing the original's whole vibe okay ๐ญ)
- Name:
nd_reserved - Width: 32 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ND
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
ERICOXM_OF_ICMPV6_ND_RESERVED(1) since Open vSwitch 2.11
What's it for? It sets the R, S, and O bits in Neighbor Advertisement Messages. That's it, that's the job. ๐
๐ ICMPv6 Neighbor Discovery Options Type Field Field
- Name:
nd_options_type - Width: 8 bits
- Format: decimal
- Masking: not maskable
- Prerequisites: ND
- Access: read/write
- OpenFlow 1.0: not supported
- OpenFlow 1.1: not supported
- OXM: none
- NXM:
ERICOXM_OF_ICMPV6_ND_OPTIONS_TYPE(2) since Open vSwitch 2.11
Decoding the numbers: a value of 1 means the option is Source Link Layer. A value of 2 means the option is Target Link Layer. For the full lore, go read RFC 4861 โ it's giving โจrequired readingโจ.
โจ REFERENCES โจ
bestie this is the receipts section ๐ every single one of these is real, look them up, i'm not making anything up, slay:
Casadoโ M. Casado, M. J. Freedman, J. Pettit, J. Luo, N. McKeown, and S. Shenker, ``Ethane: Taking Control the Enterprise,โโ Computer Communications Review, October 2007. the og enterprise-control paper fr ๐ERSPANโ M. Foschiano, K. Ghosh, M. Mehta, ``Cisco Systemsโ Encapsulated Remote Switch Port Analyzer (ERSPAN),โโhttps://tools.ietf.org/html/draft-foschiano-erspan-03.EXT-56โ J. Tonsing, ``Permit one of a set of prerequisites to apply, e.g. donโt preclude non-Ethernet media,โโhttps://rs.opennetworking.org/bugs/browse/EXT-56(ONF members only). members only, so exclusive of them ๐ญEXT-112โ J. Tourrilhes, ``Support non-Ethernet packets throughout the pipeline,โโhttps://rs.opennetworking.org/bugs/browse/EXT-112(ONF members only).EXT-134โ J. Tourrilhes, ``Match first nibble of the MPLS payload,โโhttps://rs.opennetworking.org/bugs/browse/EXT-134(ONF members only).Geneveโ J. Gross, I. Ganga, and T. Sridhar, editors, ``Geneve: Generic Network Virtualization Encapsulation,โโhttps://datatracker.ietf.org/doc/draft-ietf-nvo3-geneve/.IEEE OUIโ IEEE Standards Association, ``MAC Address Block Large (MA-L),โโhttps://standards.ieee.org/develop/regauth/oui/index.html. the source of truth for who owns which MAC prefix, iconicNSHโ P. Quinn and U. Elzur, editors, ``Network Service Header,โโhttps://datatracker.ietf.org/doc/draft-ietf-sfc-nsh/.OpenFlow 1.0.1โ Open Networking Foundation, ``OpenFlow Switch Errata, Version 1.0.1,โโ June 2012.OpenFlow 1.1โ OpenFlow Consortium, ``OpenFlow Switch Specification Version 1.1.0 Implemented (Wire Protocol 0x02),โโ February 2011.OpenFlow 1.5โ Open Networking Foundation, ``OpenFlow Switch Specification Version 1.5.0 (Protocol version 0x06),โโ December 2014.OpenFlow Extensions 1.3.x Package 2โ Open Networking Foundation, ``OpenFlow Extensions 1.3.x Package 2,โโ December 2013.TCP Flags Match Field Extensionโ Open Networking Foundation, ``TCP flags match field Extension,โโ December 2014. In [OpenFlow Extensions 1.3.x Package 2].Pepelnjakโ I. Pepelnjak, ``OpenFlow and Fermi Estimates,โโhttp://blog.ipspace.net/2013/09/openflow-and-fermi-estimates.html.RFC 793โ ``Transmission Control Protocol,โโhttp://www.ietf.org/rfc/rfc793.txt.RFC 3032โ E. Rosen, D. Tappan, G. Fedorkow, Y. Rekhter, D. Farinacci, T. Li, and A. Conta, ``MPLS Label Stack Encoding,โโhttp://www.ietf.org/rfc/rfc3032.txt.RFC 3168โ K. Ramakrishnan, S. Floyd, and D. Black, ``The Addition of Explicit Congestion Notification (ECN) to IP,โโhttps://tools.ietf.org/html/rfc3168.RFC 3540โ N. Spring, D. Wetherall, and D. Ely, ``Robust Explicit Congestion Notification (ECN) Signaling with Nonces,โโhttps://tools.ietf.org/html/rfc3540.RFC 4632โ V. Fuller and T. Li, ``Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan,โโhttps://tools.ietf.org/html/rfc4632.RFC 5462โ L. Andersson and R. Asati,Multiprotocol Label Switching (MPLS) Label Stack Entry:EXPโโ Field Renamed to ``Traffic Classโโ Field,โโhttp://www.ietf.org/rfc/rfc5462.txt.RFC 7348โ M. Mahalingam, D. Dutt, K. Duda, P. Agarwal, L. Kreeger, T. Sridhar, M. Bursell, and C. Wright, ``Virtual eXtensible Local Area Network (VXLAN): A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks, โโhttps://tools.ietf.org/html/rfc7348. yes the space before the closing quote is in the original, i am not touching it ๐RFC 7665โ J. Halpern, Ed. and C. Pignataro, Ed., ``Service Function Chaining (SFC) Architecture,โโhttps://tools.ietf.org/html/rfc7665.Srinivasanโ V. Srinivasan, S. Suriy, and G. Varghese, ``Packet Classification using Tuple Space Search,โโ SIGCOMM 1999. tuple space my beloved, the algorithm that ate ๐งPagiamtzisโ K. Pagiamtzis and A. Sheikholeslami, ``Content-addressable memory (CAM) circuits and architectures: A tutorial and survey,โโ IEEE Journal of Solid-State Circuits, vol. 41, no. 3, pp. 712-727, March 2006.VXLAN Group Policy Optionโ M. Smith and L. Kreeger, `` VXLAN Group Policy Option.โโ Internet-Draft.https://tools.ietf.org/html/draft-smith-vxlan-group-policy. and yes, that leading space is real too, i love a chaotic citation ๐ซถ
๐ AUTHORS ๐
Ben Pfaff, with advice from Justin Pettit and Jean Tourrilhes. no cap, that's the whole section โ three icons, one credit line, main character energy all around ๐
and that's the whole page, bestie ๐ you just read all of ovs-fields(7) and you understood it, i'm so proud, genuinely ate and left no crumbs ๐
little housekeeping so you know where this came from: this page ships with Open vSwitch 4.0.0 and lives at section ovs-fields(7) in the manual. that's your source, your version and your date all wrapped up with a bow ๐ go forth and match some packets โจ๐
๐ฆ
๐ฆ where this page comes from
- arch rolling: openvswitch 4.0.0-1 ยท Apache-2.0
- nixpkgs unstable: openvswitch 4.0.0
- nixpkgs unstable: openvswitch-dpdk 4.0.0
- ubuntu stonking: openvswitch-common 4.0.0-1 ยท Apache-2.0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms