+ int base_n = flow_count_mpls_labels(base, wc);
+ int flow_n = flow_count_mpls_labels(flow, wc);
+ int common_n = flow_count_common_mpls_labels(flow, flow_n, base, base_n,
+ wc);
+
+ while (base_n > common_n) {
+ if (base_n - 1 == common_n && flow_n > common_n) {
+ /* If there is only one more LSE in base than there are common
+ * between base and flow; and flow has at least one more LSE than
+ * is common then the topmost LSE of base may be updated using
+ * set */
+ struct ovs_key_mpls mpls_key;
+
+ mpls_key.mpls_lse = flow->mpls_lse[flow_n - base_n];
+ commit_set_action(odp_actions, OVS_KEY_ATTR_MPLS,
+ &mpls_key, sizeof mpls_key);
+ flow_set_mpls_lse(base, 0, mpls_key.mpls_lse);
+ common_n++;
+ } else {
+ /* Otherwise, if there more LSEs in base than are common between
+ * base and flow then pop the topmost one. */
+ ovs_be16 dl_type;
+ bool popped;
+
+ /* If all the LSEs are to be popped and this is not the outermost
+ * LSE then use ETH_TYPE_MPLS as the ethertype parameter of the
+ * POP_MPLS action instead of flow->dl_type.
+ *
+ * This is because the POP_MPLS action requires its ethertype
+ * argument to be an MPLS ethernet type but in this case
+ * flow->dl_type will be a non-MPLS ethernet type.
+ *
+ * When the final POP_MPLS action occurs it use flow->dl_type and
+ * the and the resulting packet will have the desired dl_type. */
+ if ((!eth_type_mpls(flow->dl_type)) && base_n > 1) {
+ dl_type = htons(ETH_TYPE_MPLS);
+ } else {
+ dl_type = flow->dl_type;
+ }
+ nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, dl_type);
+ popped = flow_pop_mpls(base, base_n, flow->dl_type, wc);
+ ovs_assert(popped);
+ base_n--;
+ }