struct mlx5_flow_attr *flow_attr)
 {
        struct mlx5_esw_flow_attr *esw_attr = flow_attr->esw_attr;
+       struct mlx5e_tc_int_port *int_port;
        TC_TUN_ROUTE_ATTR_INIT(attr);
        u16 vport_num;
        int err = 0;
        if (err)
                return err;
 
-       if (attr.route_dev->netdev_ops != &mlx5e_netdev_ops ||
-           !mlx5e_tc_is_vf_tunnel(attr.out_dev, attr.route_dev))
-               goto out;
-
-       err = mlx5e_tc_query_route_vport(attr.out_dev, attr.route_dev, &vport_num);
-       if (err)
-               goto out;
+       if (attr.route_dev->netdev_ops == &mlx5e_netdev_ops &&
+           mlx5e_tc_is_vf_tunnel(attr.out_dev, attr.route_dev)) {
+               err = mlx5e_tc_query_route_vport(attr.out_dev, attr.route_dev, &vport_num);
+               if (err)
+                       goto out;
 
-       esw_attr->rx_tun_attr->vni = MLX5_GET(fte_match_param, spec->match_value,
-                                             misc_parameters.vxlan_vni);
-       esw_attr->rx_tun_attr->decap_vport = vport_num;
+               esw_attr->rx_tun_attr->vni = MLX5_GET(fte_match_param, spec->match_value,
+                                                     misc_parameters.vxlan_vni);
+               esw_attr->rx_tun_attr->decap_vport = vport_num;
+       } else if (netif_is_ovs_master(attr.route_dev)) {
+               int_port = mlx5e_tc_int_port_get(mlx5e_get_int_port_priv(priv),
+                                                attr.route_dev->ifindex,
+                                                MLX5E_TC_INT_PORT_INGRESS);
+               if (IS_ERR(int_port)) {
+                       err = PTR_ERR(int_port);
+                       goto out;
+               }
+               esw_attr->int_port = int_port;
+       }
 
 out:
        if (flow_attr->tun_ip_version == 4)
 
        int err = 0;
        int out_index;
 
+       parse_attr = attr->parse_attr;
+       esw_attr = attr->esw_attr;
+
        /* We check chain range only for tc flows.
         * For ft flows, we checked attr->chain was originally 0 and set it to
         * FDB_FT_CHAIN which is outside tc range.
                err = mlx5e_attach_decap_route(priv, flow);
                if (err)
                        goto err_out;
+
+               if (!attr->chain && esw_attr->int_port) {
+                       /* If decap route device is internal port, change the
+                        * source vport value in reg_c0 back to uplink just in
+                        * case the rule performs goto chain > 0. If we have a miss
+                        * on chain > 0 we want the metadata regs to hold the
+                        * chain id so SW will resume handling of this packet
+                        * from the proper chain.
+                        */
+                       u32 metadata = mlx5_eswitch_get_vport_metadata_for_set(esw,
+                                                                       esw_attr->in_rep->vport);
+
+                       err = mlx5e_tc_match_to_reg_set(priv->mdev, &parse_attr->mod_hdr_acts,
+                                                       MLX5_FLOW_NAMESPACE_FDB, VPORT_TO_REG,
+                                                       metadata);
+                       if (err)
+                               return err;
+               }
        }
 
        if (flow_flag_test(flow, L3_TO_L2_DECAP)) {
                        goto err_out;
        }
 
-       parse_attr = attr->parse_attr;
-       esw_attr = attr->esw_attr;
-
        if (netif_is_ovs_master(parse_attr->filter_dev)) {
                struct mlx5e_tc_int_port *int_port;