]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
flow_offload: add ops to tc_action_ops for flow action setup
authorBaowen Zheng <baowen.zheng@corigine.com>
Fri, 17 Dec 2021 18:16:21 +0000 (19:16 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sun, 19 Dec 2021 14:08:48 +0000 (14:08 +0000)
Add a new ops to tc_action_ops for flow action setup.

Refactor function tc_setup_flow_action to use this new ops.

We make this change to facilitate to add standalone action module.

We will also use this ops to offload action independent of filter
in following patch.

Signed-off-by: Baowen Zheng <baowen.zheng@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
14 files changed:
include/net/act_api.h
net/sched/act_csum.c
net/sched/act_ct.c
net/sched/act_gact.c
net/sched/act_gate.c
net/sched/act_mirred.c
net/sched/act_mpls.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_skbedit.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c
net/sched/cls_api.c

index b5b624c7e488836b7031a4c948f75038371d5cec..b418bb0e44e01830ac5b85053e98a76d4de68d1b 100644 (file)
@@ -88,6 +88,16 @@ static inline void tcf_tm_dump(struct tcf_t *dtm, const struct tcf_t *stm)
        dtm->expires = jiffies_to_clock_t(stm->expires);
 }
 
+static inline enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
+{
+       if (WARN_ON_ONCE(hw_stats > TCA_ACT_HW_STATS_ANY))
+               return FLOW_ACTION_HW_STATS_DONT_CARE;
+       else if (!hw_stats)
+               return FLOW_ACTION_HW_STATS_DISABLED;
+
+       return hw_stats;
+}
+
 #ifdef CONFIG_NET_CLS_ACT
 
 #define ACT_P_CREATED 1
@@ -121,6 +131,8 @@ struct tc_action_ops {
        struct psample_group *
        (*get_psample_group)(const struct tc_action *a,
                             tc_action_priv_destructor *destructor);
+       int     (*offload_act_setup)(struct tc_action *act, void *entry_data,
+                                    u32 *index_inc, bool bind);
 };
 
 struct tc_action_net {
index a15ec95e69c3612594685c0e90fac63cb3d56ea0..4428852a03d7812c58f1d40763567077e066740f 100644 (file)
@@ -695,6 +695,22 @@ static size_t tcf_csum_get_fill_size(const struct tc_action *act)
        return nla_total_size(sizeof(struct tc_csum));
 }
 
+static int tcf_csum_offload_act_setup(struct tc_action *act, void *entry_data,
+                                     u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               entry->id = FLOW_ACTION_CSUM;
+               entry->csum_flags = tcf_csum_update_flags(act);
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_csum_ops = {
        .kind           = "csum",
        .id             = TCA_ID_CSUM,
@@ -706,6 +722,7 @@ static struct tc_action_ops act_csum_ops = {
        .walk           = tcf_csum_walker,
        .lookup         = tcf_csum_search,
        .get_fill_size  = tcf_csum_get_fill_size,
+       .offload_act_setup = tcf_csum_offload_act_setup,
        .size           = sizeof(struct tcf_csum),
 };
 
index ab1810f2e6607ecde30069be15faea4aaee64d00..dc64f31e5191f1e18718662cc4158bbd2604f734 100644 (file)
@@ -1493,6 +1493,24 @@ static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets,
        c->tcf_tm.lastuse = max_t(u64, c->tcf_tm.lastuse, lastuse);
 }
 
+static int tcf_ct_offload_act_setup(struct tc_action *act, void *entry_data,
+                                   u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               entry->id = FLOW_ACTION_CT;
+               entry->ct.action = tcf_ct_action(act);
+               entry->ct.zone = tcf_ct_zone(act);
+               entry->ct.flow_table = tcf_ct_ft(act);
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_ct_ops = {
        .kind           =       "ct",
        .id             =       TCA_ID_CT,
@@ -1504,6 +1522,7 @@ static struct tc_action_ops act_ct_ops = {
        .walk           =       tcf_ct_walker,
        .lookup         =       tcf_ct_search,
        .stats_update   =       tcf_stats_update,
+       .offload_act_setup =    tcf_ct_offload_act_setup,
        .size           =       sizeof(struct tcf_ct),
 };
 
index d8dce173df37415de9c939625cf32df9f6750222..f77be22069f4f42f52b611d82ab1fcf21e63bd59 100644 (file)
@@ -252,6 +252,32 @@ static size_t tcf_gact_get_fill_size(const struct tc_action *act)
        return sz;
 }
 
+static int tcf_gact_offload_act_setup(struct tc_action *act, void *entry_data,
+                                     u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               if (is_tcf_gact_ok(act)) {
+                       entry->id = FLOW_ACTION_ACCEPT;
+               } else if (is_tcf_gact_shot(act)) {
+                       entry->id = FLOW_ACTION_DROP;
+               } else if (is_tcf_gact_trap(act)) {
+                       entry->id = FLOW_ACTION_TRAP;
+               } else if (is_tcf_gact_goto_chain(act)) {
+                       entry->id = FLOW_ACTION_GOTO;
+                       entry->chain_index = tcf_gact_goto_chain_index(act);
+               } else {
+                       return -EOPNOTSUPP;
+               }
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_gact_ops = {
        .kind           =       "gact",
        .id             =       TCA_ID_GACT,
@@ -263,6 +289,7 @@ static struct tc_action_ops act_gact_ops = {
        .walk           =       tcf_gact_walker,
        .lookup         =       tcf_gact_search,
        .get_fill_size  =       tcf_gact_get_fill_size,
+       .offload_act_setup =    tcf_gact_offload_act_setup,
        .size           =       sizeof(struct tcf_gact),
 };
 
index ac985c53ebafe4db2e40946dfef49cbb181cf683..1d8297497692fa319a944a1f0c1ad6ca8a7fbbff 100644 (file)
@@ -597,6 +597,52 @@ static size_t tcf_gate_get_fill_size(const struct tc_action *act)
        return nla_total_size(sizeof(struct tc_gate));
 }
 
+static void tcf_gate_entry_destructor(void *priv)
+{
+       struct action_gate_entry *oe = priv;
+
+       kfree(oe);
+}
+
+static int tcf_gate_get_entries(struct flow_action_entry *entry,
+                               const struct tc_action *act)
+{
+       entry->gate.entries = tcf_gate_get_list(act);
+
+       if (!entry->gate.entries)
+               return -EINVAL;
+
+       entry->destructor = tcf_gate_entry_destructor;
+       entry->destructor_priv = entry->gate.entries;
+
+       return 0;
+}
+
+static int tcf_gate_offload_act_setup(struct tc_action *act, void *entry_data,
+                                     u32 *index_inc, bool bind)
+{
+       int err;
+
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               entry->id = FLOW_ACTION_GATE;
+               entry->gate.prio = tcf_gate_prio(act);
+               entry->gate.basetime = tcf_gate_basetime(act);
+               entry->gate.cycletime = tcf_gate_cycletime(act);
+               entry->gate.cycletimeext = tcf_gate_cycletimeext(act);
+               entry->gate.num_entries = tcf_gate_num_entries(act);
+               err = tcf_gate_get_entries(entry, act);
+               if (err)
+                       return err;
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_gate_ops = {
        .kind           =       "gate",
        .id             =       TCA_ID_GATE,
@@ -609,6 +655,7 @@ static struct tc_action_ops act_gate_ops = {
        .stats_update   =       tcf_gate_stats_update,
        .get_fill_size  =       tcf_gate_get_fill_size,
        .lookup         =       tcf_gate_search,
+       .offload_act_setup =    tcf_gate_offload_act_setup,
        .size           =       sizeof(struct tcf_gate),
 };
 
index 952416bd65e6ae00fe048a32b37252d1ed13ef0a..8eecf55be0a250172727363c82e8a65171901e1d 100644 (file)
@@ -450,6 +450,44 @@ static size_t tcf_mirred_get_fill_size(const struct tc_action *act)
        return nla_total_size(sizeof(struct tc_mirred));
 }
 
+static void tcf_offload_mirred_get_dev(struct flow_action_entry *entry,
+                                      const struct tc_action *act)
+{
+       entry->dev = act->ops->get_dev(act, &entry->destructor);
+       if (!entry->dev)
+               return;
+       entry->destructor_priv = entry->dev;
+}
+
+static int tcf_mirred_offload_act_setup(struct tc_action *act, void *entry_data,
+                                       u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               if (is_tcf_mirred_egress_redirect(act)) {
+                       entry->id = FLOW_ACTION_REDIRECT;
+                       tcf_offload_mirred_get_dev(entry, act);
+               } else if (is_tcf_mirred_egress_mirror(act)) {
+                       entry->id = FLOW_ACTION_MIRRED;
+                       tcf_offload_mirred_get_dev(entry, act);
+               } else if (is_tcf_mirred_ingress_redirect(act)) {
+                       entry->id = FLOW_ACTION_REDIRECT_INGRESS;
+                       tcf_offload_mirred_get_dev(entry, act);
+               } else if (is_tcf_mirred_ingress_mirror(act)) {
+                       entry->id = FLOW_ACTION_MIRRED_INGRESS;
+                       tcf_offload_mirred_get_dev(entry, act);
+               } else {
+                       return -EOPNOTSUPP;
+               }
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_mirred_ops = {
        .kind           =       "mirred",
        .id             =       TCA_ID_MIRRED,
@@ -462,6 +500,7 @@ static struct tc_action_ops act_mirred_ops = {
        .walk           =       tcf_mirred_walker,
        .lookup         =       tcf_mirred_search,
        .get_fill_size  =       tcf_mirred_get_fill_size,
+       .offload_act_setup =    tcf_mirred_offload_act_setup,
        .size           =       sizeof(struct tcf_mirred),
        .get_dev        =       tcf_mirred_get_dev,
 };
index 2b30dc5627432f59c5ac94f5a7e6cee82373e7f7..a4615e1331e0283136351cfd2a7e9db41c87a81e 100644 (file)
@@ -384,6 +384,43 @@ static int tcf_mpls_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static int tcf_mpls_offload_act_setup(struct tc_action *act, void *entry_data,
+                                     u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               switch (tcf_mpls_action(act)) {
+               case TCA_MPLS_ACT_PUSH:
+                       entry->id = FLOW_ACTION_MPLS_PUSH;
+                       entry->mpls_push.proto = tcf_mpls_proto(act);
+                       entry->mpls_push.label = tcf_mpls_label(act);
+                       entry->mpls_push.tc = tcf_mpls_tc(act);
+                       entry->mpls_push.bos = tcf_mpls_bos(act);
+                       entry->mpls_push.ttl = tcf_mpls_ttl(act);
+                       break;
+               case TCA_MPLS_ACT_POP:
+                       entry->id = FLOW_ACTION_MPLS_POP;
+                       entry->mpls_pop.proto = tcf_mpls_proto(act);
+                       break;
+               case TCA_MPLS_ACT_MODIFY:
+                       entry->id = FLOW_ACTION_MPLS_MANGLE;
+                       entry->mpls_mangle.label = tcf_mpls_label(act);
+                       entry->mpls_mangle.tc = tcf_mpls_tc(act);
+                       entry->mpls_mangle.bos = tcf_mpls_bos(act);
+                       entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_mpls_ops = {
        .kind           =       "mpls",
        .id             =       TCA_ID_MPLS,
@@ -394,6 +431,7 @@ static struct tc_action_ops act_mpls_ops = {
        .cleanup        =       tcf_mpls_cleanup,
        .walk           =       tcf_mpls_walker,
        .lookup         =       tcf_mpls_search,
+       .offload_act_setup =    tcf_mpls_offload_act_setup,
        .size           =       sizeof(struct tcf_mpls),
 };
 
index cd3b8aad3192cf1fd7f4b31b0f2add8cb41df69b..31fcd279c17767a57f6190f623f3cef25f33cf99 100644 (file)
@@ -487,6 +487,39 @@ static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static int tcf_pedit_offload_act_setup(struct tc_action *act, void *entry_data,
+                                      u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+               int k;
+
+               for (k = 0; k < tcf_pedit_nkeys(act); k++) {
+                       switch (tcf_pedit_cmd(act, k)) {
+                       case TCA_PEDIT_KEY_EX_CMD_SET:
+                               entry->id = FLOW_ACTION_MANGLE;
+                               break;
+                       case TCA_PEDIT_KEY_EX_CMD_ADD:
+                               entry->id = FLOW_ACTION_ADD;
+                               break;
+                       default:
+                               return -EOPNOTSUPP;
+                       }
+                       entry->mangle.htype = tcf_pedit_htype(act, k);
+                       entry->mangle.mask = tcf_pedit_mask(act, k);
+                       entry->mangle.val = tcf_pedit_val(act, k);
+                       entry->mangle.offset = tcf_pedit_offset(act, k);
+                       entry->hw_stats = tc_act_hw_stats(act->hw_stats);
+                       entry++;
+               }
+               *index_inc = k;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_pedit_ops = {
        .kind           =       "pedit",
        .id             =       TCA_ID_PEDIT,
@@ -498,6 +531,7 @@ static struct tc_action_ops act_pedit_ops = {
        .init           =       tcf_pedit_init,
        .walk           =       tcf_pedit_walker,
        .lookup         =       tcf_pedit_search,
+       .offload_act_setup =    tcf_pedit_offload_act_setup,
        .size           =       sizeof(struct tcf_pedit),
 };
 
index c13a6245dfbab5c33d2401bf5bb3c6a8e55c232c..abb6d16a20b21b9e23e3b4e1eba07ed1e650961f 100644 (file)
@@ -405,6 +405,28 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data,
+                                       u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               entry->id = FLOW_ACTION_POLICE;
+               entry->police.burst = tcf_police_burst(act);
+               entry->police.rate_bytes_ps =
+                       tcf_police_rate_bytes_ps(act);
+               entry->police.burst_pkt = tcf_police_burst_pkt(act);
+               entry->police.rate_pkt_ps =
+                       tcf_police_rate_pkt_ps(act);
+               entry->police.mtu = tcf_police_tcfp_mtu(act);
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 MODULE_AUTHOR("Alexey Kuznetsov");
 MODULE_DESCRIPTION("Policing actions");
 MODULE_LICENSE("GPL");
@@ -420,6 +442,7 @@ static struct tc_action_ops act_police_ops = {
        .walk           =       tcf_police_walker,
        .lookup         =       tcf_police_search,
        .cleanup        =       tcf_police_cleanup,
+       .offload_act_setup =    tcf_police_offload_act_setup,
        .size           =       sizeof(struct tcf_police),
 };
 
index 91a7a93d5f6ab8cd6a1de5bd4b08ca1e71a951be..07e56903211e7e827d27066b76b523b5dea94001 100644 (file)
@@ -282,6 +282,33 @@ tcf_sample_get_group(const struct tc_action *a,
        return group;
 }
 
+static void tcf_offload_sample_get_group(struct flow_action_entry *entry,
+                                        const struct tc_action *act)
+{
+       entry->sample.psample_group =
+               act->ops->get_psample_group(act, &entry->destructor);
+       entry->destructor_priv = entry->sample.psample_group;
+}
+
+static int tcf_sample_offload_act_setup(struct tc_action *act, void *entry_data,
+                                       u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               entry->id = FLOW_ACTION_SAMPLE;
+               entry->sample.trunc_size = tcf_sample_trunc_size(act);
+               entry->sample.truncate = tcf_sample_truncate(act);
+               entry->sample.rate = tcf_sample_rate(act);
+               tcf_offload_sample_get_group(entry, act);
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_sample_ops = {
        .kind     = "sample",
        .id       = TCA_ID_SAMPLE,
@@ -294,6 +321,7 @@ static struct tc_action_ops act_sample_ops = {
        .walk     = tcf_sample_walker,
        .lookup   = tcf_sample_search,
        .get_psample_group = tcf_sample_get_group,
+       .offload_act_setup    = tcf_sample_offload_act_setup,
        .size     = sizeof(struct tcf_sample),
 };
 
index f6df717b9f17535b8937f6e7111934ccae0ca280..c380f9e6cc95e263aa7072348fa2b2159d52af2f 100644 (file)
@@ -327,6 +327,32 @@ static size_t tcf_skbedit_get_fill_size(const struct tc_action *act)
                + nla_total_size_64bit(sizeof(u64)); /* TCA_SKBEDIT_FLAGS */
 }
 
+static int tcf_skbedit_offload_act_setup(struct tc_action *act, void *entry_data,
+                                        u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               if (is_tcf_skbedit_mark(act)) {
+                       entry->id = FLOW_ACTION_MARK;
+                       entry->mark = tcf_skbedit_mark(act);
+               } else if (is_tcf_skbedit_ptype(act)) {
+                       entry->id = FLOW_ACTION_PTYPE;
+                       entry->ptype = tcf_skbedit_ptype(act);
+               } else if (is_tcf_skbedit_priority(act)) {
+                       entry->id = FLOW_ACTION_PRIORITY;
+                       entry->priority = tcf_skbedit_priority(act);
+               } else {
+                       return -EOPNOTSUPP;
+               }
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_skbedit_ops = {
        .kind           =       "skbedit",
        .id             =       TCA_ID_SKBEDIT,
@@ -339,6 +365,7 @@ static struct tc_action_ops act_skbedit_ops = {
        .walk           =       tcf_skbedit_walker,
        .get_fill_size  =       tcf_skbedit_get_fill_size,
        .lookup         =       tcf_skbedit_search,
+       .offload_act_setup =    tcf_skbedit_offload_act_setup,
        .size           =       sizeof(struct tcf_skbedit),
 };
 
index d9cd174eecb79baedebe1c2215a8eee7db66c910..e96a65a5323ec5f4751617d1376c6719212d8e33 100644 (file)
@@ -787,6 +787,52 @@ static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static void tcf_tunnel_encap_put_tunnel(void *priv)
+{
+       struct ip_tunnel_info *tunnel = priv;
+
+       kfree(tunnel);
+}
+
+static int tcf_tunnel_encap_get_tunnel(struct flow_action_entry *entry,
+                                      const struct tc_action *act)
+{
+       entry->tunnel = tcf_tunnel_info_copy(act);
+       if (!entry->tunnel)
+               return -ENOMEM;
+       entry->destructor = tcf_tunnel_encap_put_tunnel;
+       entry->destructor_priv = entry->tunnel;
+       return 0;
+}
+
+static int tcf_tunnel_key_offload_act_setup(struct tc_action *act,
+                                           void *entry_data,
+                                           u32 *index_inc,
+                                           bool bind)
+{
+       int err;
+
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               if (is_tcf_tunnel_set(act)) {
+                       entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+                       err = tcf_tunnel_encap_get_tunnel(entry, act);
+                       if (err)
+                               return err;
+               } else if (is_tcf_tunnel_release(act)) {
+                       entry->id = FLOW_ACTION_TUNNEL_DECAP;
+               } else {
+                       return -EOPNOTSUPP;
+               }
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_tunnel_key_ops = {
        .kind           =       "tunnel_key",
        .id             =       TCA_ID_TUNNEL_KEY,
@@ -797,6 +843,7 @@ static struct tc_action_ops act_tunnel_key_ops = {
        .cleanup        =       tunnel_key_release,
        .walk           =       tunnel_key_walker,
        .lookup         =       tunnel_key_search,
+       .offload_act_setup =    tcf_tunnel_key_offload_act_setup,
        .size           =       sizeof(struct tcf_tunnel_key),
 };
 
index e4dc5a555bd85caefb1f6fb8cc6c0b330484261e..0300792084f094650cceaf7cde94f071683af211 100644 (file)
@@ -368,6 +368,39 @@ static size_t tcf_vlan_get_fill_size(const struct tc_action *act)
                + nla_total_size(sizeof(u8)); /* TCA_VLAN_PUSH_VLAN_PRIORITY */
 }
 
+static int tcf_vlan_offload_act_setup(struct tc_action *act, void *entry_data,
+                                     u32 *index_inc, bool bind)
+{
+       if (bind) {
+               struct flow_action_entry *entry = entry_data;
+
+               switch (tcf_vlan_action(act)) {
+               case TCA_VLAN_ACT_PUSH:
+                       entry->id = FLOW_ACTION_VLAN_PUSH;
+                       entry->vlan.vid = tcf_vlan_push_vid(act);
+                       entry->vlan.proto = tcf_vlan_push_proto(act);
+                       entry->vlan.prio = tcf_vlan_push_prio(act);
+                       break;
+               case TCA_VLAN_ACT_POP:
+                       entry->id = FLOW_ACTION_VLAN_POP;
+                       break;
+               case TCA_VLAN_ACT_MODIFY:
+                       entry->id = FLOW_ACTION_VLAN_MANGLE;
+                       entry->vlan.vid = tcf_vlan_push_vid(act);
+                       entry->vlan.proto = tcf_vlan_push_proto(act);
+                       entry->vlan.prio = tcf_vlan_push_prio(act);
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               *index_inc = 1;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static struct tc_action_ops act_vlan_ops = {
        .kind           =       "vlan",
        .id             =       TCA_ID_VLAN,
@@ -380,6 +413,7 @@ static struct tc_action_ops act_vlan_ops = {
        .stats_update   =       tcf_vlan_stats_update,
        .get_fill_size  =       tcf_vlan_get_fill_size,
        .lookup         =       tcf_vlan_search,
+       .offload_act_setup =    tcf_vlan_offload_act_setup,
        .size           =       sizeof(struct tcf_vlan),
 };
 
index 61b5012c65dcf9d0f5c83659aa501ddb621c1a2c..53f263c9a7259c04bf011489f16cd0ef3f22bba1 100644 (file)
@@ -3474,81 +3474,25 @@ void tc_cleanup_offload_action(struct flow_action *flow_action)
 }
 EXPORT_SYMBOL(tc_cleanup_offload_action);
 
-static void tcf_mirred_get_dev(struct flow_action_entry *entry,
-                              const struct tc_action *act)
+static int tc_setup_offload_act(struct tc_action *act,
+                               struct flow_action_entry *entry,
+                               u32 *index_inc)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       entry->dev = act->ops->get_dev(act, &entry->destructor);
-       if (!entry->dev)
-               return;
-       entry->destructor_priv = entry->dev;
-#endif
-}
-
-static void tcf_tunnel_encap_put_tunnel(void *priv)
-{
-       struct ip_tunnel_info *tunnel = priv;
-
-       kfree(tunnel);
-}
-
-static int tcf_tunnel_encap_get_tunnel(struct flow_action_entry *entry,
-                                      const struct tc_action *act)
-{
-       entry->tunnel = tcf_tunnel_info_copy(act);
-       if (!entry->tunnel)
-               return -ENOMEM;
-       entry->destructor = tcf_tunnel_encap_put_tunnel;
-       entry->destructor_priv = entry->tunnel;
+       if (act->ops->offload_act_setup)
+               return act->ops->offload_act_setup(act, entry, index_inc, true);
+       else
+               return -EOPNOTSUPP;
+#else
        return 0;
-}
-
-static void tcf_sample_get_group(struct flow_action_entry *entry,
-                                const struct tc_action *act)
-{
-#ifdef CONFIG_NET_CLS_ACT
-       entry->sample.psample_group =
-               act->ops->get_psample_group(act, &entry->destructor);
-       entry->destructor_priv = entry->sample.psample_group;
 #endif
 }
 
-static void tcf_gate_entry_destructor(void *priv)
-{
-       struct action_gate_entry *oe = priv;
-
-       kfree(oe);
-}
-
-static int tcf_gate_get_entries(struct flow_action_entry *entry,
-                               const struct tc_action *act)
-{
-       entry->gate.entries = tcf_gate_get_list(act);
-
-       if (!entry->gate.entries)
-               return -EINVAL;
-
-       entry->destructor = tcf_gate_entry_destructor;
-       entry->destructor_priv = entry->gate.entries;
-
-       return 0;
-}
-
-static enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
-{
-       if (WARN_ON_ONCE(hw_stats > TCA_ACT_HW_STATS_ANY))
-               return FLOW_ACTION_HW_STATS_DONT_CARE;
-       else if (!hw_stats)
-               return FLOW_ACTION_HW_STATS_DISABLED;
-
-       return hw_stats;
-}
-
 int tc_setup_offload_action(struct flow_action *flow_action,
                            const struct tcf_exts *exts)
 {
+       int i, j, index, err = 0;
        struct tc_action *act;
-       int i, j, k, err = 0;
 
        BUILD_BUG_ON(TCA_ACT_HW_STATS_ANY != FLOW_ACTION_HW_STATS_ANY);
        BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE);
@@ -3569,151 +3513,13 @@ int tc_setup_offload_action(struct flow_action *flow_action,
 
                entry->hw_stats = tc_act_hw_stats(act->hw_stats);
                entry->hw_index = act->tcfa_index;
-
-               if (is_tcf_gact_ok(act)) {
-                       entry->id = FLOW_ACTION_ACCEPT;
-               } else if (is_tcf_gact_shot(act)) {
-                       entry->id = FLOW_ACTION_DROP;
-               } else if (is_tcf_gact_trap(act)) {
-                       entry->id = FLOW_ACTION_TRAP;
-               } else if (is_tcf_gact_goto_chain(act)) {
-                       entry->id = FLOW_ACTION_GOTO;
-                       entry->chain_index = tcf_gact_goto_chain_index(act);
-               } else if (is_tcf_mirred_egress_redirect(act)) {
-                       entry->id = FLOW_ACTION_REDIRECT;
-                       tcf_mirred_get_dev(entry, act);
-               } else if (is_tcf_mirred_egress_mirror(act)) {
-                       entry->id = FLOW_ACTION_MIRRED;
-                       tcf_mirred_get_dev(entry, act);
-               } else if (is_tcf_mirred_ingress_redirect(act)) {
-                       entry->id = FLOW_ACTION_REDIRECT_INGRESS;
-                       tcf_mirred_get_dev(entry, act);
-               } else if (is_tcf_mirred_ingress_mirror(act)) {
-                       entry->id = FLOW_ACTION_MIRRED_INGRESS;
-                       tcf_mirred_get_dev(entry, act);
-               } else if (is_tcf_vlan(act)) {
-                       switch (tcf_vlan_action(act)) {
-                       case TCA_VLAN_ACT_PUSH:
-                               entry->id = FLOW_ACTION_VLAN_PUSH;
-                               entry->vlan.vid = tcf_vlan_push_vid(act);
-                               entry->vlan.proto = tcf_vlan_push_proto(act);
-                               entry->vlan.prio = tcf_vlan_push_prio(act);
-                               break;
-                       case TCA_VLAN_ACT_POP:
-                               entry->id = FLOW_ACTION_VLAN_POP;
-                               break;
-                       case TCA_VLAN_ACT_MODIFY:
-                               entry->id = FLOW_ACTION_VLAN_MANGLE;
-                               entry->vlan.vid = tcf_vlan_push_vid(act);
-                               entry->vlan.proto = tcf_vlan_push_proto(act);
-                               entry->vlan.prio = tcf_vlan_push_prio(act);
-                               break;
-                       default:
-                               err = -EOPNOTSUPP;
-                               goto err_out_locked;
-                       }
-               } else if (is_tcf_tunnel_set(act)) {
-                       entry->id = FLOW_ACTION_TUNNEL_ENCAP;
-                       err = tcf_tunnel_encap_get_tunnel(entry, act);
-                       if (err)
-                               goto err_out_locked;
-               } else if (is_tcf_tunnel_release(act)) {
-                       entry->id = FLOW_ACTION_TUNNEL_DECAP;
-               } else if (is_tcf_pedit(act)) {
-                       for (k = 0; k < tcf_pedit_nkeys(act); k++) {
-                               switch (tcf_pedit_cmd(act, k)) {
-                               case TCA_PEDIT_KEY_EX_CMD_SET:
-                                       entry->id = FLOW_ACTION_MANGLE;
-                                       break;
-                               case TCA_PEDIT_KEY_EX_CMD_ADD:
-                                       entry->id = FLOW_ACTION_ADD;
-                                       break;
-                               default:
-                                       err = -EOPNOTSUPP;
-                                       goto err_out_locked;
-                               }
-                               entry->mangle.htype = tcf_pedit_htype(act, k);
-                               entry->mangle.mask = tcf_pedit_mask(act, k);
-                               entry->mangle.val = tcf_pedit_val(act, k);
-                               entry->mangle.offset = tcf_pedit_offset(act, k);
-                               entry->hw_stats = tc_act_hw_stats(act->hw_stats);
-                               entry = &flow_action->entries[++j];
-                       }
-               } else if (is_tcf_csum(act)) {
-                       entry->id = FLOW_ACTION_CSUM;
-                       entry->csum_flags = tcf_csum_update_flags(act);
-               } else if (is_tcf_skbedit_mark(act)) {
-                       entry->id = FLOW_ACTION_MARK;
-                       entry->mark = tcf_skbedit_mark(act);
-               } else if (is_tcf_sample(act)) {
-                       entry->id = FLOW_ACTION_SAMPLE;
-                       entry->sample.trunc_size = tcf_sample_trunc_size(act);
-                       entry->sample.truncate = tcf_sample_truncate(act);
-                       entry->sample.rate = tcf_sample_rate(act);
-                       tcf_sample_get_group(entry, act);
-               } else if (is_tcf_police(act)) {
-                       entry->id = FLOW_ACTION_POLICE;
-                       entry->police.burst = tcf_police_burst(act);
-                       entry->police.rate_bytes_ps =
-                               tcf_police_rate_bytes_ps(act);
-                       entry->police.burst_pkt = tcf_police_burst_pkt(act);
-                       entry->police.rate_pkt_ps =
-                               tcf_police_rate_pkt_ps(act);
-                       entry->police.mtu = tcf_police_tcfp_mtu(act);
-               } else if (is_tcf_ct(act)) {
-                       entry->id = FLOW_ACTION_CT;
-                       entry->ct.action = tcf_ct_action(act);
-                       entry->ct.zone = tcf_ct_zone(act);
-                       entry->ct.flow_table = tcf_ct_ft(act);
-               } else if (is_tcf_mpls(act)) {
-                       switch (tcf_mpls_action(act)) {
-                       case TCA_MPLS_ACT_PUSH:
-                               entry->id = FLOW_ACTION_MPLS_PUSH;
-                               entry->mpls_push.proto = tcf_mpls_proto(act);
-                               entry->mpls_push.label = tcf_mpls_label(act);
-                               entry->mpls_push.tc = tcf_mpls_tc(act);
-                               entry->mpls_push.bos = tcf_mpls_bos(act);
-                               entry->mpls_push.ttl = tcf_mpls_ttl(act);
-                               break;
-                       case TCA_MPLS_ACT_POP:
-                               entry->id = FLOW_ACTION_MPLS_POP;
-                               entry->mpls_pop.proto = tcf_mpls_proto(act);
-                               break;
-                       case TCA_MPLS_ACT_MODIFY:
-                               entry->id = FLOW_ACTION_MPLS_MANGLE;
-                               entry->mpls_mangle.label = tcf_mpls_label(act);
-                               entry->mpls_mangle.tc = tcf_mpls_tc(act);
-                               entry->mpls_mangle.bos = tcf_mpls_bos(act);
-                               entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
-                               break;
-                       default:
-                               err = -EOPNOTSUPP;
-                               goto err_out_locked;
-                       }
-               } else if (is_tcf_skbedit_ptype(act)) {
-                       entry->id = FLOW_ACTION_PTYPE;
-                       entry->ptype = tcf_skbedit_ptype(act);
-               } else if (is_tcf_skbedit_priority(act)) {
-                       entry->id = FLOW_ACTION_PRIORITY;
-                       entry->priority = tcf_skbedit_priority(act);
-               } else if (is_tcf_gate(act)) {
-                       entry->id = FLOW_ACTION_GATE;
-                       entry->gate.prio = tcf_gate_prio(act);
-                       entry->gate.basetime = tcf_gate_basetime(act);
-                       entry->gate.cycletime = tcf_gate_cycletime(act);
-                       entry->gate.cycletimeext = tcf_gate_cycletimeext(act);
-                       entry->gate.num_entries = tcf_gate_num_entries(act);
-                       err = tcf_gate_get_entries(entry, act);
-                       if (err)
-                               goto err_out_locked;
-               } else {
-                       err = -EOPNOTSUPP;
+               index = 0;
+               err = tc_setup_offload_act(act, entry, &index);
+               if (!err)
+                       j += index;
+               else
                        goto err_out_locked;
-               }
                spin_unlock_bh(&act->tcfa_lock);
-
-               if (!is_tcf_pedit(act))
-                       j++;
        }
 
 err_out: