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

Reply via email to