요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
=============================================
Open vSwitch datapath developer documentation
=============================================
The Open vSwitch kernel module allows flexible userspace control over
flow-level packet processing on selected network devices. It can be
used to implement a plain Ethernet switch, network device bonding,
VLAN processing, network access control, flow-based network control,
and so on.
The kernel module implements multiple "datapaths" (analogous to
bridges), each of which can have multiple "vports" (analogous to ports
within a bridge). Each datapath also has associated with it a "flow
table" that userspace populates with "flows" that map from keys based
on packet headers and metadata to sets of actions. The most common
action forwards the packet to another vport; other actions are also
implemented.
When a packet arrives on a vport, the kernel module processes it by
extracting its flow key and looking it up in the flow table. If there
is a matching flow, it executes the associated actions. If there is
no match, it queues the packet to userspace for processing (as part of
its processing, userspace will likely set up a flow to handle further
packets of the same type entirely in-kernel).
Flow key compatibility
----------------------
Network protocols evolve over time. New protocols become important
and existing protocols lose their prominence. For the Open vSwitch
kernel module to remain relevant, it must be possible for newer
versions to parse additional protocols as part of the flow key. It
might even be desirable, someday, to drop support for parsing
protocols that have become obsolete. Therefore, the Netlink interface
to Open vSwitch is designed to allow carefully written userspace
applications to work with any version of the flow key, past or future.
To support this forward and backward compatibility, whenever the
kernel module passes a packet to userspace, it also passes along the
flow key that it parsed from the packet. Userspace then extracts its
own notion of a flow key from the packet and compares it against the
kernel-provided version:
- If userspace's notion of the flow key for the packet matches the
kernel's, then nothing special is necessary.
- If the kernel's flow key includes more fields than the userspace
version of the flow key, for example if the kernel decoded IPv6
headers but userspace stopped at the Ethernet type (because it
does not understand IPv6), then again nothing special is
necessary. Userspace can still set up a flow in the usual way,
as long as it uses the kernel-provided flow key to do it.
- If the userspace flow key includes more fields than the
kernel's, for example if userspace decoded an IPv6 header but
the kernel stopped at the Ethernet type, then userspace can
forward the packet manually, without setting up a flow in the
kernel. This case is bad for performance because every packet
that the kernel considers part of the flow must go to userspace,
but the forwarding behavior is correct. (If userspace can
determine that the values of the extra fields would not affect
forwarding behavior, then it could set up a flow anyway.)
How flow keys evolve over time is important to making this work, so
the following sections go into detail.
Flow key format
---------------
A flow key is passed over a Netlink socket as a sequence of Netlink
attributes. Some attributes represent packet metadata, defined as any
information about a packet that cannot be extracted from the packet
itself, e.g. the vport on which the packet was received. Most
attributes, however, are extracted from headers within the packet,
e.g. source and destination addresses from Ethernet, IP, or TCP
headers.
The <linux/openvswitch.h> header file defines the exact format of the
flow key attributes. For informal explanatory purposes here, we write
them as comma-separated strings, with parentheses indicating arguments
and nesting. For example, the following could represent a flow key
corresponding to a TCP packet that arrived on vport 1::
in_port(1), eth(src=e0:91:f5:21:d0:b2, dst=00:02:e3:0f:80:a4),
eth_type(0x0800), ipv4(src=172.16.0.20, dst=172.18.0.52, proto=17, tos=0,
frag=no), tcp(src=49163, dst=80)
Often we ellipsize arguments not important to the discussion, e.g.::
in_port(1), eth(...), eth_type(0x0800), ipv4(...), tcp(...)
Wildcarded flow key format
--------------------------
A wildcarded flow is described with two sequences of Netlink attributes
passed over the Netlink socket. A flow key, exactly as described above, and an
optional corresponding flow mask.
A wildcarded flow can represent a group of exact match flows. Each '1' bit
in the mask specifies a exact match with the corresponding bit in the flow key.
A '0' bit specifies a don't care bit, which will match either a '1' or '0' bit
of a incoming packet. Using wildcarded flow can improve the flow set up rate
by reduce the number of new flows need to be processed by the user space program.
Support for the mask Netlink attribute is optional for both the kernel and user
space program. The kernel can ignore the mask attribute, installing an exact
match flow, or reduce the number of don't care bits in the kernel to less than
what was specified by the user space program. In this case, variations in bits
that the kernel does not implement will simply result in additional flow setups.
The kernel module will also work with user space programs that neither support
nor supply flow mask attributes.
Since the kernel may ignore or modify wildcard bits, it can be difficult for
the userspace program to know exactly what matches are installed. There are
two possible approaches: reactively install flows as they miss the kernel
flow table (and therefore not attempt to determine wildcard changes at all)
or use the kernel's response messages to determine the installed wildcards.
When interacting with userspace, the kernel should maintain the match portion
of the key exactly as originally installed. This will provides a handle to
identify the flow for all future operations. However, when reporting the
mask of an installed flow, the mask should include any restrictions imposed
by the kernel.
The behavior when using overlapping wildcarded flows is undefined. It is the
responsibility of the user space program to ensure that any incoming packet
can match at most one flow, wildcarded or not. The current implementation
performs best-effort detection of overlapping wildcarded flows and may reject
some but not all of them. However, this behavior may change in future versions.
Unique flow identifiers
-----------------------
An alternative to using the original match portion of a key as the handle for
flow identification is a unique flow identifier, or "UFID". UFIDs are optional
for both the kernel and user space program.
User space programs that support UFID are expected to provide it during flow
setup in addition to the flow, then refer to the flow using the UFID for all
future operations. The kernel is not required to index flows by the original
flow key if a UFID is specified.
Basic rule for evolving flow keys
---------------------------------
Some care is needed to really maintain forward and backward
compatibility for applications that follow the rules listed under
"Flow key compatibility" above.
The basic rule is obvious::
==================================================================
New network protocol support must only supplement existing flow
key attributes. It must not change the meaning of already defined
flow key attributes.
==================================================================
This rule does have less-obvious consequences so it is worth working
through a few examples. Suppose, for example, that the kernel module
did not already implement VLAN parsing. Instead, it just interpreted
the 802.1Q TPID (0x8100) as the Ethertype then stopped parsing the
packet. The flow key for any packet with an 802.1Q header would look
essentially like this, ignoring metadata::
eth(...), eth_type(0x8100)
Naively, to add VLAN support, it makes sense to add a new "vlan" flow
key attribute to contain the VLAN tag, then continue to decode the
encapsulated headers beyond the VLAN tag using the existing field
definitions. With this change, a TCP packet in VLAN 10 would have a
flow key much like this::
eth(...), vlan(vid=10, pcp=0), eth_type(0x0800), ip(proto=6, ...), tcp(...)
But this change would negatively affect a userspace application that
has not been updated to understand the new "vlan" flow key attribute.
The application could, following the flow compatibility rules above,
ignore the "vlan" attribute that it does not understand and therefore
assume that the flow contained IP packets. This is a bad assumption
(the flow only contains IP packets if one parses and skips over the
802.1Q header) and it could cause the application's behavior to change
across kernel versions even though it follows the compatibility rules.
The solution is to use a set of nested attributes. This is, for
example, why 802.1Q support uses nested attributes. A TCP packet in
VLAN 10 is actually expressed as::
eth(...), eth_type(0x8100), vlan(vid=10, pcp=0), encap(eth_type(0x0800),
ip(proto=6, ...), tcp(...)))
Notice how the "eth_type", "ip", and "tcp" flow key attributes are
nested inside the "encap" attribute. Thus, an application that does
not understand the "vlan" key will not see either of those attributes
and therefore will not misinterpret them. (Also, the outer eth_type
is still 0x8100, not changed to 0x0800.)
Handling malformed packets
--------------------------
Don't drop packets in the kernel for malformed protocol headers, bad
checksums, etc. This would prevent userspace from implementing a
simple Ethernet switch that forwards every packet.
Instead, in such a case, include an attribute with "empty" content.
It doesn't matter if the empty content could be valid protocol values,
as long as those values are rarely seen in practice, because userspace
can always forward all packets with those values to userspace and
handle them individually.
For example, consider a packet that contains an IP header that
indicates protocol 6 for TCP, but which is truncated just after the IP
header, so that the TCP header is missing. The flow key for this
packet would include a tcp attribute with all-zero src and dst, like
this::
eth(...), eth_type(0x0800), ip(proto=6, ...), tcp(src=0, dst=0)
As another example, consider a packet with an Ethernet type of 0x8100,
indicating that a VLAN TCI should follow, but which is truncated just
after the Ethernet type. The flow key for this packet would include
an all-zero-bits vlan and an empty encap attribute, like this::
eth(...), eth_type(0x8100), vlan(0), encap()
Unlike a TCP packet with source and destination ports 0, an
all-zero-bits VLAN TCI is not that rare, so the CFI bit (aka
VLAN_TAG_PRESENT inside the kernel) is ordinarily set in a vlan
attribute expressly to allow this situation to be distinguished.
Thus, the flow key in this second example unambiguously indicates a
missing or malformed VLAN TCI.
Other rules
-----------
The other rules for flow keys are much less subtle:
- Duplicate attributes are not allowed at a given nesting level.
- Ordering of attributes is not significant.
- When the kernel sends a given flow key to userspace, it always
composes it the same way. This allows userspace to hash and
compare entire flow keys that it may not be able to fully
interpret.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Datapath, vport와 flow 처리
1-28Open vSwitch kernel module은 선택한 network device의 flow 단위 packet processing을 userspace가 유연하게 제어하게 합니다. 일반 Ethernet switch, network device bonding, VLAN processing, network access control, flow 기반 network control 등을 구현할 수 있습니다.
Kernel module은 bridge에 대응하는 여러 `datapath`를 구현하며 각 datapath에는 bridge port에 대응하는 여러 `vport`가 있을 수 있습니다. Datapath마다 userspace가 채우는 `flow table`도 있습니다. Table의 `flow`는 packet header와 metadata에서 만든 key를 action 집합에 연결합니다. 가장 흔한 action은 packet을 다른 vport로 전달하는 것이며 그 밖의 action도 구현되어 있습니다.
Packet이 vport에 도착하면 kernel이 flow key를 추출해 flow table에서 찾습니다. 일치하는 flow가 있으면 연결된 action을 실행하고, 없으면 userspace가 처리하도록 packet을 queue에 넣습니다. Userspace는 보통 같은 종류의 후속 packet이 전부 kernel 안에서 처리되도록 새 flow를 설정합니다.
Vport ingress부터 hit와 miss 처리까지의 경로입니다.
.. SPDX-License-Identifier: GPL-2.0
=============================================
Open vSwitch datapath developer documentation
=============================================
The Open vSwitch kernel module allows flexible userspace control over
flow-level packet processing on selected network devices. It can be
used to implement a plain Ethernet switch, network device bonding,
VLAN processing, network access control, flow-based network control,
and so on.
The kernel module implements multiple "datapaths" (analogous to
bridges), each of which can have multiple "vports" (analogous to ports
within a bridge). Each datapath also has associated with it a "flow
table" that userspace populates with "flows" that map from keys based
on packet headers and metadata to sets of actions. The most common
action forwards the packet to another vport; other actions are also
implemented.
When a packet arrives on a vport, the kernel module processes it by
extracting its flow key and looking it up in the flow table. If there
is a matching flow, it executes the associated actions. If there is
no match, it queues the packet to userspace for processing (as part of
its processing, userspace will likely set up a flow to handle further
packets of the same type entirely in-kernel).
과거·미래 flow key와 userspace 호환
29-70Network protocol은 시간이 흐르며 중요도가 바뀝니다. Open vSwitch가 계속 유효하려면 새 kernel이 flow key에서 추가 protocol을 parse할 수 있어야 하며, 언젠가는 낡은 protocol parsing을 제거할 수도 있어야 합니다. 그래서 Netlink interface는 주의해서 작성한 userspace application이 과거와 미래의 어떤 flow-key version과도 동작하도록 설계되었습니다.
Forward·backward compatibility를 위해 kernel은 packet을 userspace로 보낼 때 자신이 parse한 flow key도 함께 보냅니다. Userspace는 packet에서 자체 flow key를 추출해 kernel 제공 key와 비교합니다.
두 key가 일치하면 특별한 처리가 필요 없습니다. Kernel key에 userspace보다 field가 더 많아도 마찬가지입니다. 예를 들어 kernel은 IPv6 header까지 decode했지만 IPv6를 모르는 userspace가 Ethernet type에서 멈췄다면 userspace는 kernel 제공 key를 사용해 평소처럼 flow를 설치할 수 있습니다.
반대로 userspace key가 kernel key보다 자세하면, 예를 들어 userspace는 IPv6 header를 decode했지만 kernel은 Ethernet type에서 멈췄다면 userspace는 kernel flow를 설치하지 않고 packet을 직접 전달할 수 있습니다. Kernel이 그 flow로 보는 모든 packet이 userspace로 가므로 성능은 나쁘지만 forwarding 결과는 정확합니다. 추가 field 값이 forwarding behavior에 영향을 주지 않는다고 userspace가 판단할 수 있다면 flow를 설치해도 됩니다.
이 호환성이 작동하려면 flow key를 시간에 따라 어떤 방식으로 확장하는지가 중요하며 뒤 절에서 그 규칙을 구체적으로 설명합니다.
Field 범위가 다른 세 경우의 안전한 동작입니다.
Flow key compatibility
----------------------
Network protocols evolve over time. New protocols become important
and existing protocols lose their prominence. For the Open vSwitch
kernel module to remain relevant, it must be possible for newer
versions to parse additional protocols as part of the flow key. It
might even be desirable, someday, to drop support for parsing
protocols that have become obsolete. Therefore, the Netlink interface
to Open vSwitch is designed to allow carefully written userspace
applications to work with any version of the flow key, past or future.
To support this forward and backward compatibility, whenever the
kernel module passes a packet to userspace, it also passes along the
flow key that it parsed from the packet. Userspace then extracts its
own notion of a flow key from the packet and compares it against the
kernel-provided version:
- If userspace's notion of the flow key for the packet matches the
kernel's, then nothing special is necessary.
- If the kernel's flow key includes more fields than the userspace
version of the flow key, for example if the kernel decoded IPv6
headers but userspace stopped at the Ethernet type (because it
does not understand IPv6), then again nothing special is
necessary. Userspace can still set up a flow in the usual way,
as long as it uses the kernel-provided flow key to do it.
- If the userspace flow key includes more fields than the
kernel's, for example if userspace decoded an IPv6 header but
the kernel stopped at the Ethernet type, then userspace can
forward the packet manually, without setting up a flow in the
kernel. This case is bad for performance because every packet
that the kernel considers part of the flow must go to userspace,
but the forwarding behavior is correct. (If userspace can
determine that the values of the extra fields would not affect
forwarding behavior, then it could set up a flow anyway.)
How flow keys evolve over time is important to making this work, so
the following sections go into detail.
Netlink attribute 기반 flow key format
71-96Flow key는 Netlink socket을 통해 Netlink attribute sequence로 전달됩니다. 일부 attribute는 packet 자체에서 추출할 수 없는 metadata, 예를 들어 packet을 받은 vport를 표현합니다. 대부분은 Ethernet·IP·TCP header의 source·destination address처럼 packet header에서 추출합니다.
정확한 flow-key attribute format은 `<linux/openvswitch.h>`에 정의되어 있습니다. 이 문서는 설명을 위해 attribute를 comma-separated string으로 쓰고 argument와 nesting을 괄호로 나타냅니다.
Vport 1에 들어온 TCP packet의 예시는 `in_port(1)`, Ethernet source·destination, `eth_type(0x0800)`, IPv4 source·destination·protocol·TOS·fragment 상태, TCP source·destination port를 차례로 담습니다. 논의에 중요하지 않은 argument는 `in_port(1), eth(...), eth_type(0x0800), ipv4(...), tcp(...)`처럼 생략합니다. 원문의 완전한 key 예제와 축약 예제를 그대로 보존했습니다.
Flow key format
---------------
A flow key is passed over a Netlink socket as a sequence of Netlink
attributes. Some attributes represent packet metadata, defined as any
information about a packet that cannot be extracted from the packet
itself, e.g. the vport on which the packet was received. Most
attributes, however, are extracted from headers within the packet,
e.g. source and destination addresses from Ethernet, IP, or TCP
headers.
The <linux/openvswitch.h> header file defines the exact format of the
flow key attributes. For informal explanatory purposes here, we write
them as comma-separated strings, with parentheses indicating arguments
and nesting. For example, the following could represent a flow key
corresponding to a TCP packet that arrived on vport 1::
in_port(1), eth(src=e0:91:f5:21:d0:b2, dst=00:02:e3:0f:80:a4),
eth_type(0x0800), ipv4(src=172.16.0.20, dst=172.18.0.52, proto=17, tos=0,
frag=no), tcp(src=49163, dst=80)
Often we ellipsize arguments not important to the discussion, e.g.::
in_port(1), eth(...), eth_type(0x0800), ipv4(...), tcp(...)
Wildcard mask와 겹치는 flow
97-136Wildcarded flow는 Netlink socket으로 전달되는 두 attribute sequence, 즉 정확한 flow key와 선택적인 대응 flow mask로 기술합니다. Mask의 각 1 bit는 flow key의 대응 bit와 exact match해야 함을 뜻하고, 0 bit는 incoming packet의 0 또는 1 어느 쪽도 일치하는 don't-care bit입니다. Wildcard를 사용하면 userspace program이 처리해야 할 새 flow 수가 줄어 setup rate가 좋아질 수 있습니다.
Mask Netlink attribute 지원은 kernel과 userspace 모두 선택 사항입니다. Kernel은 mask를 무시하고 exact-match flow를 설치하거나 userspace가 지정한 것보다 don't-care bit 수를 줄일 수 있습니다. Kernel이 구현하지 않은 bit variation은 추가 flow setup으로 이어질 뿐입니다. Mask를 지원하거나 제공하지 않는 userspace와도 kernel module은 동작합니다.
Kernel이 wildcard bit를 무시하거나 바꿀 수 있어 userspace가 실제 설치 match를 알기 어려울 수 있습니다. 한 방법은 kernel table miss에 반응해 flow를 설치하면서 wildcard 변화를 알려 하지 않는 것입니다. 다른 방법은 kernel response message를 사용해 설치된 wildcard를 확인하는 것입니다.
Kernel은 userspace와 상호 작용할 때 원래 설치한 key의 match 부분을 정확히 유지해야 합니다. 그래야 이후 모든 operation에서 flow를 식별하는 handle이 됩니다. 반면 설치 flow의 mask를 보고할 때는 kernel이 부과한 제한까지 포함해야 합니다.
서로 겹치는 wildcarded flow의 동작은 정의되지 않습니다. Incoming packet 하나가 wildcard 여부와 관계없이 최대 flow 하나에만 일치하도록 보장하는 것은 userspace program의 책임입니다. 현재 구현은 겹침을 best-effort로 감지해 일부만 거부할 수 있으며 이 동작은 미래 version에서 바뀔 수 있습니다.
Flow key와 mask bit의 matching 의미입니다.
Wildcarded flow key format
--------------------------
A wildcarded flow is described with two sequences of Netlink attributes
passed over the Netlink socket. A flow key, exactly as described above, and an
optional corresponding flow mask.
A wildcarded flow can represent a group of exact match flows. Each '1' bit
in the mask specifies a exact match with the corresponding bit in the flow key.
A '0' bit specifies a don't care bit, which will match either a '1' or '0' bit
of a incoming packet. Using wildcarded flow can improve the flow set up rate
by reduce the number of new flows need to be processed by the user space program.
Support for the mask Netlink attribute is optional for both the kernel and user
space program. The kernel can ignore the mask attribute, installing an exact
match flow, or reduce the number of don't care bits in the kernel to less than
what was specified by the user space program. In this case, variations in bits
that the kernel does not implement will simply result in additional flow setups.
The kernel module will also work with user space programs that neither support
nor supply flow mask attributes.
Since the kernel may ignore or modify wildcard bits, it can be difficult for
the userspace program to know exactly what matches are installed. There are
two possible approaches: reactively install flows as they miss the kernel
flow table (and therefore not attempt to determine wildcard changes at all)
or use the kernel's response messages to determine the installed wildcards.
When interacting with userspace, the kernel should maintain the match portion
of the key exactly as originally installed. This will provides a handle to
identify the flow for all future operations. However, when reporting the
mask of an installed flow, the mask should include any restrictions imposed
by the kernel.
The behavior when using overlapping wildcarded flows is undefined. It is the
responsibility of the user space program to ensure that any incoming packet
can match at most one flow, wildcarded or not. The current implementation
performs best-effort detection of overlapping wildcarded flows and may reject
some but not all of them. However, this behavior may change in future versions.
고유 flow 식별자 UFID
137-149Flow 식별 handle로 원래 key의 match 부분을 사용하는 대신 unique flow identifier, 즉 `UFID`를 쓸 수 있습니다. UFID 지원은 kernel과 userspace 모두 선택 사항입니다.
UFID를 지원하는 userspace program은 flow setup 때 flow와 함께 UFID를 제공하고 이후 모든 operation에서 UFID로 flow를 참조해야 합니다. UFID가 지정되면 kernel은 원래 flow key로 flow를 index할 의무가 없습니다.
Unique flow identifiers
-----------------------
An alternative to using the original match portion of a key as the handle for
flow identification is a unique flow identifier, or "UFID". UFIDs are optional
for both the kernel and user space program.
User space programs that support UFID are expected to provide it during flow
setup in addition to the flow, then refer to the flow using the UFID for all
future operations. The kernel is not required to index flows by the original
flow key if a UFID is specified.
Flow key 확장의 기본 규칙과 VLAN nesting
150-203앞의 호환 규칙을 따르는 application과 실제 forward·backward compatibility를 유지하려면 핵심 원칙을 지켜야 합니다. 새 network protocol 지원은 기존 flow-key attribute를 보충하기만 해야 하며 이미 정의된 attribute의 의미를 바꾸어서는 안 됩니다.
예를 들어 기존 kernel이 VLAN을 parse하지 않고 802.1Q TPID `0x8100`을 Ethertype으로 해석한 뒤 parsing을 멈췄다고 합시다. Metadata를 제외한 802.1Q packet의 key는 `eth(...), eth_type(0x8100)`입니다.
단순하게 VLAN 지원을 추가하면 VLAN tag용 `vlan` attribute를 넣고 tag 안쪽 header를 기존 field 정의로 계속 decode하고 싶을 수 있습니다. 그러면 VLAN 10의 TCP packet은 `eth(...), vlan(vid=10, pcp=0), eth_type(0x0800), ip(proto=6, ...), tcp(...)`처럼 보입니다.
하지만 새 `vlan` attribute를 모르는 예전 userspace는 호환 규칙에 따라 이를 무시한 뒤 보이는 `eth_type(0x0800)`과 IP·TCP field 때문에 flow가 IP packet이라고 잘못 판단합니다. 실제로는 802.1Q header를 parse해 건너뛰어야만 IP packet임을 알 수 있으므로, 규칙을 지킨 application의 동작도 kernel version에 따라 달라질 수 있습니다.
해결책은 nested attribute입니다. 실제 VLAN 10 TCP key는 `eth(...), eth_type(0x8100), vlan(vid=10, pcp=0), encap(eth_type(0x0800), ip(proto=6, ...), tcp(...)))`로 표현합니다. `eth_type`, `ip`, `tcp`는 `encap` 안에 들어가므로 `vlan` key를 이해하지 못하는 application에는 이 field들도 보이지 않아 오해하지 않습니다. 바깥쪽 `eth_type`도 `0x0800`으로 바꾸지 않고 `0x8100`을 유지합니다.
평면 확장의 오류와 nested attribute 해법을 비교합니다.
Basic rule for evolving flow keys
---------------------------------
Some care is needed to really maintain forward and backward
compatibility for applications that follow the rules listed under
"Flow key compatibility" above.
The basic rule is obvious::
==================================================================
New network protocol support must only supplement existing flow
key attributes. It must not change the meaning of already defined
flow key attributes.
==================================================================
This rule does have less-obvious consequences so it is worth working
through a few examples. Suppose, for example, that the kernel module
did not already implement VLAN parsing. Instead, it just interpreted
the 802.1Q TPID (0x8100) as the Ethertype then stopped parsing the
packet. The flow key for any packet with an 802.1Q header would look
essentially like this, ignoring metadata::
eth(...), eth_type(0x8100)
Naively, to add VLAN support, it makes sense to add a new "vlan" flow
key attribute to contain the VLAN tag, then continue to decode the
encapsulated headers beyond the VLAN tag using the existing field
definitions. With this change, a TCP packet in VLAN 10 would have a
flow key much like this::
eth(...), vlan(vid=10, pcp=0), eth_type(0x0800), ip(proto=6, ...), tcp(...)
But this change would negatively affect a userspace application that
has not been updated to understand the new "vlan" flow key attribute.
The application could, following the flow compatibility rules above,
ignore the "vlan" attribute that it does not understand and therefore
assume that the flow contained IP packets. This is a bad assumption
(the flow only contains IP packets if one parses and skips over the
802.1Q header) and it could cause the application's behavior to change
across kernel versions even though it follows the compatibility rules.
The solution is to use a set of nested attributes. This is, for
example, why 802.1Q support uses nested attributes. A TCP packet in
VLAN 10 is actually expressed as::
eth(...), eth_type(0x8100), vlan(vid=10, pcp=0), encap(eth_type(0x0800),
ip(proto=6, ...), tcp(...)))
Notice how the "eth_type", "ip", and "tcp" flow key attributes are
nested inside the "encap" attribute. Thus, an application that does
not understand the "vlan" key will not see either of those attributes
and therefore will not misinterpret them. (Also, the outer eth_type
is still 0x8100, not changed to 0x0800.)
Malformed packet을 빈 attribute로 표현
204-238Protocol header가 malformed이거나 checksum이 잘못되었다는 이유로 kernel에서 packet을 버리면 안 됩니다. 모든 packet을 전달하는 단순 Ethernet switch를 userspace가 구현하지 못하게 되기 때문입니다.
대신 이런 경우에는 내용이 `empty`인 attribute를 포함합니다. 빈 내용이 이론상 유효한 protocol 값이어도 실제로 드문 값이면 괜찮습니다. Userspace가 그 값을 가진 모든 packet을 userspace로 보내 개별 처리할 수 있기 때문입니다.
예를 들어 IP header의 protocol이 TCP를 뜻하는 6이지만 IP header 직후 packet이 잘려 TCP header가 없다면, key에는 source와 destination이 모두 0인 `tcp(src=0, dst=0)` attribute를 넣습니다. 전체 예제는 `eth(...), eth_type(0x0800), ip(proto=6, ...), tcp(src=0, dst=0)`입니다.
또 Ethernet type이 VLAN TCI가 뒤따라야 하는 `0x8100`인데 type 직후 packet이 잘렸다면 all-zero `vlan(0)`과 빈 `encap()`을 넣습니다. Source·destination port 0인 TCP와 달리 all-zero VLAN TCI는 드물지 않으므로, 보통 vlan attribute의 CFI bit, kernel 내부 이름 `VLAN_TAG_PRESENT`를 세워 정상 zero TCI와 구별합니다. 따라서 이 예제 key는 VLAN TCI가 없거나 malformed임을 모호하지 않게 나타냅니다.
잘린 header를 empty 값으로 표현하는 예입니다.
Handling malformed packets
--------------------------
Don't drop packets in the kernel for malformed protocol headers, bad
checksums, etc. This would prevent userspace from implementing a
simple Ethernet switch that forwards every packet.
Instead, in such a case, include an attribute with "empty" content.
It doesn't matter if the empty content could be valid protocol values,
as long as those values are rarely seen in practice, because userspace
can always forward all packets with those values to userspace and
handle them individually.
For example, consider a packet that contains an IP header that
indicates protocol 6 for TCP, but which is truncated just after the IP
header, so that the TCP header is missing. The flow key for this
packet would include a tcp attribute with all-zero src and dst, like
this::
eth(...), eth_type(0x0800), ip(proto=6, ...), tcp(src=0, dst=0)
As another example, consider a packet with an Ethernet type of 0x8100,
indicating that a VLAN TCI should follow, but which is truncated just
after the Ethernet type. The flow key for this packet would include
an all-zero-bits vlan and an empty encap attribute, like this::
eth(...), eth_type(0x8100), vlan(0), encap()
Unlike a TCP packet with source and destination ports 0, an
all-zero-bits VLAN TCI is not that rare, so the CFI bit (aka
VLAN_TAG_PRESENT inside the kernel) is ordinarily set in a vlan
attribute expressly to allow this situation to be distinguished.
Thus, the flow key in this second example unambiguously indicates a
missing or malformed VLAN TCI.
중복·순서·정규화 규칙
239-251같은 nesting level에는 중복 attribute를 허용하지 않습니다. Attribute 순서는 의미가 없습니다.
Kernel이 특정 flow key를 userspace로 보낼 때는 언제나 같은 방식으로 구성해야 합니다. 덕분에 userspace가 key의 전체 내용을 해석하지 못하더라도 완전한 flow key를 그대로 hash하고 비교할 수 있습니다.
호환 가능한 canonical representation을 위한 제약입니다.
Other rules
-----------
The other rules for flow keys are much less subtle:
- Duplicate attributes are not allowed at a given nesting level.
- Ordering of attributes is not significant.
- When the kernel sends a given flow key to userspace, it always
composes it the same way. This allows userspace to hash and
compare entire flow keys that it may not be able to fully
interpret.
요약·해설
openvswitch.rst:1-251핵심은 kernel이 자신이 해석한 flow key를 userspace에 돌려주고, 새 protocol은 기존 attribute의 의미를 바꾸지 않은 채 nested attribute로만 확장한다는 것입니다. 이 규칙이 서로 다른 kernel·userspace version 사이의 정확한 forwarding을 지킵니다.
Kernel과 userspace의 해석 범위가 달라도 forwarding 정확성을 유지합니다.