|
@@ -78,6 +78,8 @@ struct cls_fl_filter {
|
|
|
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)
|
|
@@ -203,9 +205,9 @@ static void fl_destroy_filter(struct rcu_head *head)
|
|
|
|
|
|
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;
|
|
@@ -213,10 +215,10 @@ static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f)
|
|
|
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,
|
|
@@ -226,11 +228,17 @@ 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;
|
|
@@ -239,23 +247,22 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
|
|
|
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;
|
|
@@ -264,10 +271,10 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
|
|
|
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)
|