@@ -2029,6 +2029,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
info.dpif_class = dpif_class;
info.tp_dst_port = dst_port;
+ info.tc_modify_flow_deleted = false;
err = netdev_flow_put(dev, &match,
CONST_CAST(struct nlattr *, put->actions),
put->actions_len,
@@ -2060,7 +2061,11 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
out:
if (err && err != EEXIST && (put->flags & DPIF_FP_MODIFY)) {
/* Modified rule can't be offloaded, try and delete from HW */
- int del_err = netdev_flow_del(dev, put->ufid, put->stats);
+ int del_err = 0;
+
+ if (!info.tc_modify_flow_deleted) {
+ del_err = netdev_flow_del(dev, put->ufid, put->stats);
+ }
if (!del_err) {
/* Delete from hw success, so old flow was offloaded.
@@ -1042,8 +1042,12 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
handle = get_ufid_tc_mapping(ufid, &prio, NULL);
if (handle && prio) {
+ bool flow_deleted;
+
VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", handle, prio);
- del_filter_and_ufid_mapping(ifindex, prio, handle, ufid);
+ flow_deleted = !del_filter_and_ufid_mapping(ifindex, prio,
+ handle, ufid);
+ info->tc_modify_flow_deleted = flow_deleted;
}
if (!prio) {
@@ -188,6 +188,9 @@ void netdev_send_wait(struct netdev *, int qid);
struct offload_info {
const struct dpif_class *dpif_class;
ovs_be16 tp_dst_port; /* Destination port for tunnel in SET action */
+
+ bool tc_modify_flow_deleted; /* Indicate the tc modify flow put success
+ * to delete the original flow. */
};
struct dpif_class;
struct netdev_flow_dump;