mirror of
https://github.com/openvswitch/ovs
synced 2025-08-30 22:05:19 +00:00
mpls: Fix MPLS restoration after patch port and group bucket.
This patch fixes problems with MPLS handling related to patch ports and group buckets. If a group bucket or a peer bridge across a patch port pushes MPLS headers to a non-MPLS packet and outputs, the flow translation after returning from the group bucket or patch port would undo the packet transformations so that the processing could continue with the packet as it was before entering the patch port. There were two problems with this: 1. As part of the first MPLS push on a non-MPLS packet, the flow translation would first clear the L3/4 headers of the 'flow' to mark those fields invalid. Later, when committing 'flow' changes to datapath actions before output, the necessary datapath MPLS actions are created and the corresponding changes updated to the 'base flow'. This was done using the same flow_push_mpls() function that clears the L2/3 headers, so also the 'base flow' L2/3 headers were cleared. Then, when translation returns from a patch port or group bucket, the original 'flow' is restored, now showing no sign of the MPLS labels. Since the 'base flow' now has the MPLS labels, following translations know to issue MPLS POP actions before any output actions. However, as part of checking for changes to IP headers we test that the IP protocol type was not changed. But now the 'base flow's 'nw_proto' field is zero and an assert fail crashes OVS. This is solved by not clearing the L3/4 fields of the 'base flow'. This allows the processing after the patch port to continue with L3/4 fields as if no MPLS was done, after first issuing the necessary MPLS POP actions. 2. IP header updates were done before the MPLS POP actions were issued. This caused incorrect packet output after, e.g., group action or patch port. For example, with actions: group 1234: all bucket=push_mpls,output:LOCAL ip actions=group:1234,dec_ttl,output:LOCAL,output:LOCAL the dec_ttl would only be executed before the last output to LOCAL, since at the time of committing IP changes after the group action the packet was still an MPLS packet. This is solved by checking the dl_type of both 'flow' and 'base flow' and issuing MPLS actions if they can transform the packet from an MPLS packet to a non-MPLS packet. For an IP packet the change in ttl can then be correctly committed before the last two output actions. Two test cases are added to prevent future regressions. Reported-by: Thomas Morin <thomas.morin@orange.com> Suggested-by: Takashi YAMAMOTO <yamamoto@ovn.org> Fixes:8bfd0fdac
("Enhance userspace support for MPLS, for up to 3 labels.") Fixes:1b035ef20
("mpls: Allow l3 and l4 actions to prior to a push_mpls action") Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: YAMAMOTO Takashi <yamamoto@ovn.org>
This commit is contained in:
@@ -5553,7 +5553,10 @@ commit_mpls_action(const struct flow *flow, struct flow *base,
|
||||
sizeof *mpls);
|
||||
mpls->mpls_ethertype = flow->dl_type;
|
||||
mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1];
|
||||
flow_push_mpls(base, base_n, mpls->mpls_ethertype, NULL);
|
||||
/* Update base flow's MPLS stack, but do not clear L3. We need the L3
|
||||
* headers if the flow is restored later due to returning from a patch
|
||||
* port or group bucket. */
|
||||
flow_push_mpls(base, base_n, mpls->mpls_ethertype, NULL, false);
|
||||
flow_set_mpls_lse(base, 0, mpls->mpls_lse);
|
||||
base_n++;
|
||||
}
|
||||
@@ -5916,12 +5919,21 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
|
||||
bool use_masked)
|
||||
{
|
||||
enum slow_path_reason slow1, slow2;
|
||||
bool mpls_done = false;
|
||||
|
||||
commit_set_ether_addr_action(flow, base, odp_actions, wc, use_masked);
|
||||
/* Make packet a non-MPLS packet before committing L3/4 actions,
|
||||
* which would otherwise do nothing. */
|
||||
if (eth_type_mpls(base->dl_type) && !eth_type_mpls(flow->dl_type)) {
|
||||
commit_mpls_action(flow, base, odp_actions);
|
||||
mpls_done = true;
|
||||
}
|
||||
slow1 = commit_set_nw_action(flow, base, odp_actions, wc, use_masked);
|
||||
commit_set_port_action(flow, base, odp_actions, wc, use_masked);
|
||||
slow2 = commit_set_icmp_action(flow, base, odp_actions, wc);
|
||||
commit_mpls_action(flow, base, odp_actions);
|
||||
if (!mpls_done) {
|
||||
commit_mpls_action(flow, base, odp_actions);
|
||||
}
|
||||
commit_vlan_action(flow->vlan_tci, base, odp_actions, wc);
|
||||
commit_set_priority_action(flow, base, odp_actions, wc, use_masked);
|
||||
commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked);
|
||||
|
Reference in New Issue
Block a user