SRv6 Push/Remove Actions
Added support for pushing/removing IPv6 extension header into/from the original IPv6 packets directly. This method is more efficient than using tunnel encap/decap (e.g. VxLAN) with SRv6 in the outer header.
Note:
The maximal pushing length should be <= 128B.
The application should make sure that the SRv6 is the only present extension header after pushing (no fragmentation either).
Currently, only TCP and UDP protocols are supported in L4.
To generate the correct checksum after pushing, the application should set IPv6
dst_addr
in the origin packet with the final address in SRv6 segment[0].
Hardware requirements:
REMOVE action: ConnectX-6 Dx and above
PUSH action: ConnectX-7 and above
Service Routing Header (SRH) can be used for SRv6 offload of an endpoint device (match + header add/remove). The user can create a rule to match on SRH and to validate it, or create an SRH with segment_list as source node.
The match can be on the 1st 32 Bits of SRH: Routing Type, Next Header, Segment-Left.

Supported device type = endpoint node
SR-SourceNode = Start SRv6 source route through Push/Encap (SRH)
SR-EndNode = Hold the latest IP; End SRv6 source route through Pop/Decap (SRH); Also use match to validate that segment-left=0 & validate routing type=SRv6
Supported Operations
Match: Required for SR-EndNode
Push/Encap: Required for SR-SourceNode
Pop/Decap: Required for SR-EndNode
IPv6 Extension Header Manipulation
IPv6 extension header manipulation ( add/remove header) is performed through on of the following methods:
Use encap/decap for adding IPv6 tunnel with Segment routing Header (SRH)
Use the original/legacy encap/decap API (no API change)
Enable adding any tunnel type, e.g. GRE/VxLAN, NVGRE
Use the push/pop [newly added API] of IPv6 extension headers into/from IPv6 packets
Before push, there should be no IPv6 extension header - IPv6.dst_addr = seg_list[0]
After push - IPv6.dst_addr = seg_list[n]
After pop - IPv6.dst_addr = seg_list[0]
After push IPv6 routing should be the only present extension (not supporting multiple extensions)
Push/Pop are complex actions, hence impacting on PPS and #rules should be limited
Assumptions / Limitations
Match is available on 1st 32 bits (partial/relevant fields)
Cannot match on further last Entry/flags/tag/…/ TLV options)
Only TCP, UDP, and IPv6 are supported by the Next Header field
Push/Encap - size (encap buffer or push buffer) <= 128B (may limit the total # of segment list entries)
Push
SRH next layer exclusively accommodates TCP and UDP
Push is supported on BlueField-3 / ConnectX-7
Remove Action
The remove action is unified in the template table and the action must be fully masked in the action template.
> set ipv6_ext_remove 1
ipv6_ext type is 43
/ end_set
> flow pattern_template 0
create transfer relaxed no pattern_template_id 1
template represented_port ethdev_port_id is 0
/ eth / ipv6 / ipv6_routing_ext / udp src is 100
/ end
> flow actions_template 0
create transfer actions_template_id 1
template ipv6_ext_remove index 1
/ represented_port ethdev_port_id 1
/ end mask ipv6_ext_remove index 1
/ represented_port ethdev_port_id 1
/ end
> flow template_table 0
create group 0
priority 0
transfer table_id 1
rules_number 128
pattern_template 1
actions_template 1
Push Action
> set ipv6_ext_push 1
ipv6_ext type is 43
/ ipv6_routing_ext ext_type is 4
ext_next_hdr is 17
ext_seg_left is 2
/ end_set
> flow pattern_template 0
create transfer relaxed no pattern_template_id 1
template represented_port ethdev_port_id is 0
/ eth / ipv6 / udp src is 1
/ end
> flow actions_template 0
create transfer actions_template_id 1
template ipv6_ext_push index 1
/ represented_port ethdev_port_id 1
/ end mask ipv6_ext_push index 1
/ represented_port ethdev_port_id 1
/ end
> flow template_table 0
create group 0
priority 0
transfer table_id 1
rules_number 128
pattern_template 1
actions_template 1
Remove Action
const
struct rte_flow_action_ipv6_ext_remove remove_v = { .type = IPPROTO_ROUTING };
const
struct rte_flow_action_ipv6_ext_remove remove_m = { .type = UINT8_MAX };
const
struct rte_flow_action_queue queue_v = { .index = 0
};
const
struct rte_flow_action_queue queue_m = { .index = UINT16_MAX };
const
struct rte_flow_action actions[3
] = {
[0
] = {
.type = RTE_FLOW_ACTION_TYPE_IPV6_EXT_REMOVE,
.conf = &remove_v,
},
[1
] = {
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue_v,
},
[2
] = { .type = RTE_FLOW_ACTION_TYPE_END }
};
const
struct rte_flow_action masks[3
] = {
[0
] = {
.type = RTE_FLOW_ACTION_TYPE_IPV6_EXT_REMOVE,
.conf = &remove_m,
},
[1
] = {
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue_m,
},
[2
] = { .type = RTE_FLOW_ACTION_TYPE_END }
};
const
struct rte_flow_actions_template_attr at_attr = { .ingress = 1
};
rte_flow_actions_template_create(port_id, &at_attr, actions, masks, error);
Push Action
const
struct rte_flow_action_ipv6_ext_push push_v = { .type = IPPROTO_ROUTING, .size = 40
, .data = {0x11
, 4
, 4
, 2
, 1
, 0
, 0
, 0
, 3
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 0
, 4
} };
const
struct rte_flow_action_queue queue_v = { .index = 0
};
const
struct rte_flow_action_queue queue_m = { .index = UINT16_MAX };
const
struct rte_flow_action actions[3
] = {
[0
] = {
.type = RTE_FLOW_ACTION_TYPE_IPV6_EXT_PUSH,
.conf = &push_v,
},
[1
] = {
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue_v,
},
[2
] = { .type = RTE_FLOW_ACTION_TYPE_END }
};
const
struct rte_flow_action masks[3
] = {
[0
] = {
.type = RTE_FLOW_ACTION_TYPE_IPV6_EXT_PUSH,
.conf = NULL,
},
[1
] = {
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue_m,
},
[2
] = { .type = RTE_FLOW_ACTION_TYPE_END }
};
const
struct rte_flow_actions_template_attr at_attr = { .ingress = 1
};
rte_flow_actions_template_create(port_id, &at_attr, actions, masks, error);