Connection Tracking reSync/Packet-Reinjection
Loopback is defined as sending a packet to one of the TX queues and receive it back on one of the RX queues. One of the main use-cases is supporting packet re-injection for connection tracking. Packet re-injection sends a packet that is received by the application before the connection tracking sees it, back to the RX queue so it can be seen by the connection tracking.
The way to achieve this is by encapsulating the packet with predefined header that has the destination MAC equal to the self MAC, the rest of the outer can hold information needed to perform the routing on the RX.
Enable loopback:
testpmd> port stop all testpmd> port config all loopback
1
testpmd> port start allEnable metadata (metadata is only used to differentiate between packets that should loopback or not. It is not relevant to the feature itself):
testpmd> port stop all testpmd> port config
0
tx_metadata0x12345678
testpmd> port start all testpmd> startCreate a TX encapsulation flow:
testpmd> set vxlan ip-version ipv4 vni
0x123
udp-src12345
udp-dst4789
ip-src1.1
.1.2
ip-dst1.1
.1.67
eth-src04
:3f:72
:d2:af:7f eth-dst04
:3f:72
:d2:af:7e testpmd> flow create0
egress group0
priority3
pattern eth / end actions count / jump group5
/ end testpmd> flow create0
egress group5
priority3
pattern eth / end actions vxlan_encap / count / endCreate an RX rule that matches the values in the outer header, and decapsulates the packet:
testpmd> flow create
0
ingress pattern eth / ipv4 / udp / vxlan vni is111
/ end actions vxlan_decap/ jump group3
/ endSend the packet that should be looped back with the correct metadata or manual encapsulate or modify the destination MAC.
Enable loopback:
port[index].dev_conf.lpbk_mode =
1
;Enable metadata (metadata is only used to differentiate between packets that should loopback or not. It is not relevant to the feature itself):
rte_flow_dynf_metadata_register();
Create a TX encapsulation flow:
struct rte_flow * generate_loopback_encap_flow( uint16_t port_id, uint8_t vni[], uint8_t host_addr[], struct rte_flow_error *error) { struct rte_flow_attr attr; struct rte_flow_item pattern[MAX_PATTERN_NUM]; struct rte_flow_action action[MAX_ACTION_NUM]; struct rte_flow *flow = NULL; struct rte_flow_item_eth eth; struct rte_flow_item_ipv4 ip = { .hdr.version_ihl = RTE_IPV4_VHL_DEF,
/* Can be any value. */
.hdr.dst_addr = rte_cpu_to_be_32(0x01010101
),/* Can be any value. */
.hdr.src_addr = rte_cpu_to_be_32(0x01010101
), .hdr.next_proto_id =17
, }; struct rte_flow_item_udp udp = { .hdr.dst_port = rte_cpu_to_be_16(4789
),/* Vxlan dport. */
/* Can be any value. */
.hdr.src_port = rte_cpu_to_be_16(1
) }; struct rte_flow_item_vxlan vxlan; struct rte_flow_item vxlan_items[] = { { .type = RTE_FLOW_ITEM_TYPE_ETH, .spec = ð, }, { .type = RTE_FLOW_ITEM_TYPE_IPV4, .spec = &ip, }, { .type = RTE_FLOW_ITEM_TYPE_UDP, .spec = &udp, }, { .type = RTE_FLOW_ITEM_TYPE_VXLAN, .spec = &vxlan, }, { .type = RTE_FLOW_ITEM_TYPE_END, } }; struct rte_flow_action_vxlan_encap encap_action = { .definition = vxlan_items, }; struct rte_flow_item_meta meta_spec = { .data =0x1
,/* The meta value to match on. */
}; struct rte_flow_item_meta meta_mask = { .data =0xffffffff
, };/* Set the host mac address to the dest mac address.
* The source mac address can be any address but for simplicity
we use the same address. */
memcpy(eth.dst.addr_bytes, host_addr, RTE_ETHER_ADDR_LEN); memcpy(eth.src.addr_bytes, host_addr, RTE_ETHER_ADDR_LEN); eth.type = rte_cpu_to_be_16(0x0800
);/* Set the request VNI. */
memcpy(vxlan.vni, vni,3
);/* Create the encap action. */
action[0
].type = RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP; action[0
].conf = &encap_action; action[1
].type = RTE_FLOW_ACTION_TYPE_END; memset(pattern,0
, sizeof(pattern)); attr.egress =1
; pattern[0
].type = RTE_FLOW_ITEM_TYPE_META; pattern[0
].spec = &meta_spec; pattern[0
].mask = &meta_mask;/* the final level must be always type end */
pattern[1
].type = RTE_FLOW_ITEM_TYPE_END; flow = rte_flow_create(port_id, &attr, pattern, action, error);return
flow; }Create an RX rule that matches the values in the outer header, and decapsulates the packet:
struct rte_flow * generate_loopback_match_flow( uint16_t port_id, uint8_t vni[], struct rte_flow_error *error) { struct rte_flow_attr attr; struct rte_flow_action action[MAX_ACTION_NUM]; struct rte_flow *flow = NULL; struct rte_flow_item_eth eth = {{{
0
}}}; struct rte_flow_item_ipv4 ip = {{0
}}; struct rte_flow_item_udp udp = {{0
}}; struct rte_flow_item_vxlan vxlan = {0
}; struct rte_flow_item_vxlan vxlan_mask ={.vni ="\xff\xff\xff"
}; struct rte_flow_item pattern[] = { { .type = RTE_FLOW_ITEM_TYPE_ETH, .spec = ð, .mask = ð, }, { .type = RTE_FLOW_ITEM_TYPE_IPV4, .spec = &ip, .mask = &ip, }, { .type = RTE_FLOW_ITEM_TYPE_UDP, .spec = &udp, .mask = &udp, }, { .type = RTE_FLOW_ITEM_TYPE_VXLAN, .spec = &vxlan, .mask = &vxlan_mask, }, { .type = RTE_FLOW_ITEM_TYPE_END, }, }; struct rte_flow_action_jump jump = { .group =3
, };/* Set the request VNI. */
memcpy(vxlan.vni, vni,3
);/* Create the encap action. */
action[0
].type = RTE_FLOW_ACTION_TYPE_VXLAN_DECAP; action[1
].type = RTE_FLOW_ACTION_TYPE_JUMP; action[1
].conf = &jump; action[2
].type = RTE_FLOW_ACTION_TYPE_END; attr.ingress =1
;/* the final level must be always type end */
pattern[1
].type = RTE_FLOW_ITEM_TYPE_END; flow = rte_flow_create(port_id, &attr, pattern, action, error);return
flow; }Send the packet that should be looped back with the correct metadata or manual encapsulate or modify the destination MAC.