Hi OVS developers,
I'm reporting a bug in OVS 3.3.4 where the kernel datapath rejects set_field
actions that modify nsh_si or nsh_spi on NSH MD-Type 2 packets, even though
these fields are in the base header and should be modifiable regardless of
MD type.
Environment
- OVS version: 3.3.4
- Linux kernel: 6.x
- Datapath: kernel
- OpenFlow version: 1.3
- Use case: Multi-VNF service function chaining with NSH MD-Type 2
Background
I'm implementing a service function chain where traffic is classified,
encapsulated with NSH (MD-Type 2), and routed through a sequence of VNFs.
When a VNF returns a packet, I need to decrement the Service Index (SI) and
route to the next VNF.
OpenFlow Rules (simplified)
Code
# Classify → encap with md_type=2, SPI=20, SI=2 → send to VNF2 (port 4)
table=10, priority=1000, ip, nw_src=10.0.2.0/24, tcp, tp_dst=443,
actions=...,encap(nsh(md_type=2)),set_field:20->nsh_spi,set_field:2->nsh_si,...,goto_table:12
# VNF2 returns → decrement SI from 2 to 1 → route to VNF3 (port 5)
table=11, priority=1000, in_port=4, eth_type=0x894f, nsh_spi=20, nsh_si=2,
actions=set_field:1->nsh_si,goto_table:12
# Route SPI=20/SI=1 → VNF3
table=12, priority=1000, eth_type=0x894f, nsh_spi=20, nsh_si=1,
actions=output:5
Observed Behavior
The kernel datapath rejects the set_field:1->nsh_si action with EINVAL
(repeats every ~1s):
Code
dpif(handler5)|WARN|system@ovs-system: failed to put[create] (Invalid argument)
ufid:25c32035-...
in_port(6),eth_type(0x894f),nsh(spi=0x14,si=2,c1=0x0,c2=0x0,c3=0x0,c4=0x0),
actions:set(nsh(spi=0x14,si=1,c1=0x0,c2=0x0,c3=0x0,c4=0x0)),7
dpif(handler5)|WARN|system@ovs-system: execute
set(nsh(spi=0x14,si=1,c1=0x0,c2=0x0,c3=0x0,c4=0x0)),7
failed (Invalid argument) on packet
...nsh_mdtype=2,nsh_spi=0x14,nsh_si=2...
Problem Analysis
The datapath compiles set_field:1->nsh_si into a set() action that includes
the MD-Type 1 fixed-context headers c1–c4, even though the actual packet is
MD-Type 2 (variable-length TLVs, no c1–c4). The kernel datapath validates
the action against the packet's actual MD type and rejects the mismatch.
Root Cause (Code Analysis)
The issue is in lib/odp-util.c in two places:
1. In nsh_key_to_attr() (line ~2349):
When is_mask=true, the function unconditionally includes MD1 context in the
mask, regardless of the packet's actual mdtype:
C
if (is_mask) {
nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, nsh->context,
sizeof nsh->context);
} else {
switch (nsh->mdtype) {
case NSH_M_TYPE1:
nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, nsh->context,
sizeof nsh->context);
break;
case NSH_M_TYPE2:
// ...
This causes masked set actions to always include MD1 context fields, even
for MD-Type 2 packets.
2. In commit_set_nsh_action() (line ~8729):
The comment explicitly states the limitation:
C
/* No match support for other MD formats yet. */if (key->mdtype == NSH_M_TYPE1
&& !is_all_zeros(mask->context, sizeof mask->context)) {
commit_masked_attribute(odp_actions, OVS_NSH_KEY_ATTR_MD1,
key->context, mask->context,
sizeof key->context);
}
However, the check above only applies to the masked path when
use_masked=true. When use_masked=false or for the unmasked set action, the
code falls through to nsh_key_to_attr() which has the mask bug described
above.
3. In lib/odp-execute.c (line ~442):
The userspace datapath silently ignores set actions on MD-Type 2:
C
switch (mdtype) {
case NSH_M_TYPE1:
for (int i = 0; i < 4; i++) {
// ... modify context
}
break;
case NSH_M_TYPE2:
default:
/* No support for setting any other metadata format yet. */
break;
}
This means even base header fields (spi, si, flags, ttl) that exist in both
MD types cannot be modified for MD-Type 2 packets.
Expected Behavior
The set_field action should successfully modify nsh_si and nsh_spi for
MD-Type 2 packets, since these fields are in the NSH base header (not the
MD-specific context). The datapath action should only include the base
header fields being modified, not the MD-Type 1 context.
Impact
- Kernel datapath: Action is rejected with EINVAL, preventing any NSH
field modification on MD-Type 2 packets
- Userspace datapath: Action is silently ignored (no error, but field is
not modified)
- Service function chaining: Cannot implement VNF sequencing with
MD-Type 2, forcing use of MD-Type 1 or workarounds
Questions
1. Is MD-Type 2 field modification (at least for base header fields like
spi/si) intended to be supported?
2. Should this be considered a bug or a missing feature?
3. Are there any known workarounds besides switching to MD-Type 1?
I'm happy to test patches or provide additional debugging information if
needed.
Best regards,
Tariro
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev