}
 EXPORT_SYMBOL(tcf_exts_dump_stats);
 
+int tcf_exts_get_dev(struct net_device *dev, struct tcf_exts *exts,
+                    struct net_device **hw_dev)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       const struct tc_action *a;
+       LIST_HEAD(actions);
+
+       if (tc_no_actions(exts))
+               return -EINVAL;
+
+       tcf_exts_to_list(exts, &actions);
+       list_for_each_entry(a, &actions, list) {
+               if (a->ops->get_dev) {
+                       a->ops->get_dev(a, dev_net(dev), hw_dev);
+                       break;
+               }
+       }
+       if (*hw_dev)
+               return 0;
+#endif
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(tcf_exts_get_dev);
+
 static int __init tc_filter_init(void)
 {
        rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL);
 
        u32 handle;
        u32 flags;
        struct rcu_head rcu;
+       struct tc_to_netdev tc;
+       struct net_device *hw_dev;
 };
 
 static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
 
 static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f)
 {
-       struct net_device *dev = tp->q->dev_queue->dev;
        struct tc_cls_flower_offload offload = {0};
-       struct tc_to_netdev tc;
+       struct net_device *dev = f->hw_dev;
+       struct tc_to_netdev *tc = &f->tc;
 
        if (!tc_can_offload(dev, tp))
                return;
        offload.command = TC_CLSFLOWER_DESTROY;
        offload.cookie = (unsigned long)f;
 
-       tc.type = TC_SETUP_CLSFLOWER;
-       tc.cls_flower = &offload;
+       tc->type = TC_SETUP_CLSFLOWER;
+       tc->cls_flower = &offload;
 
-       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
+       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
 }
 
 static int fl_hw_replace_filter(struct tcf_proto *tp,
 {
        struct net_device *dev = tp->q->dev_queue->dev;
        struct tc_cls_flower_offload offload = {0};
-       struct tc_to_netdev tc;
+       struct tc_to_netdev *tc = &f->tc;
        int err;
 
-       if (!tc_can_offload(dev, tp))
-               return tc_skip_sw(f->flags) ? -EINVAL : 0;
+       if (!tc_can_offload(dev, tp)) {
+               if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev))
+                       return tc_skip_sw(f->flags) ? -EINVAL : 0;
+               dev = f->hw_dev;
+               tc->egress_dev = true;
+       } else {
+               f->hw_dev = dev;
+       }
 
        offload.command = TC_CLSFLOWER_REPLACE;
        offload.cookie = (unsigned long)f;
        offload.key = &f->key;
        offload.exts = &f->exts;
 
-       tc.type = TC_SETUP_CLSFLOWER;
-       tc.cls_flower = &offload;
+       tc->type = TC_SETUP_CLSFLOWER;
+       tc->cls_flower = &offload;
 
        err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
-                                           &tc);
+                                           tc);
 
        if (tc_skip_sw(f->flags))
                return err;
-
        return 0;
 }
 
 static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
 {
-       struct net_device *dev = tp->q->dev_queue->dev;
        struct tc_cls_flower_offload offload = {0};
-       struct tc_to_netdev tc;
+       struct net_device *dev = f->hw_dev;
+       struct tc_to_netdev *tc = &f->tc;
 
        if (!tc_can_offload(dev, tp))
                return;
        offload.cookie = (unsigned long)f;
        offload.exts = &f->exts;
 
-       tc.type = TC_SETUP_CLSFLOWER;
-       tc.cls_flower = &offload;
+       tc->type = TC_SETUP_CLSFLOWER;
+       tc->cls_flower = &offload;
 
-       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
+       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
 }
 
 static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)