0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/skbuff.h>
0013 #include <linux/rtnetlink.h>
0014 #include <net/netlink.h>
0015 #include <net/pkt_sched.h>
0016 #include <net/pkt_cls.h>
0017
0018 #include <linux/tc_act/tc_defact.h>
0019 #include <net/tc_act/tc_defact.h>
0020
0021 static unsigned int simp_net_id;
0022 static struct tc_action_ops act_simp_ops;
0023
0024 #define SIMP_MAX_DATA 32
0025 static int tcf_simp_act(struct sk_buff *skb, const struct tc_action *a,
0026 struct tcf_result *res)
0027 {
0028 struct tcf_defact *d = to_defact(a);
0029
0030 spin_lock(&d->tcf_lock);
0031 tcf_lastuse_update(&d->tcf_tm);
0032 bstats_update(&d->tcf_bstats, skb);
0033
0034
0035
0036
0037
0038 pr_info("simple: %s_%llu\n",
0039 (char *)d->tcfd_defdata,
0040 u64_stats_read(&d->tcf_bstats.packets));
0041 spin_unlock(&d->tcf_lock);
0042 return d->tcf_action;
0043 }
0044
0045 static void tcf_simp_release(struct tc_action *a)
0046 {
0047 struct tcf_defact *d = to_defact(a);
0048 kfree(d->tcfd_defdata);
0049 }
0050
0051 static int alloc_defdata(struct tcf_defact *d, const struct nlattr *defdata)
0052 {
0053 d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL);
0054 if (unlikely(!d->tcfd_defdata))
0055 return -ENOMEM;
0056 nla_strscpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
0057 return 0;
0058 }
0059
0060 static int reset_policy(struct tc_action *a, const struct nlattr *defdata,
0061 struct tc_defact *p, struct tcf_proto *tp,
0062 struct netlink_ext_ack *extack)
0063 {
0064 struct tcf_chain *goto_ch = NULL;
0065 struct tcf_defact *d;
0066 int err;
0067
0068 err = tcf_action_check_ctrlact(p->action, tp, &goto_ch, extack);
0069 if (err < 0)
0070 return err;
0071 d = to_defact(a);
0072 spin_lock_bh(&d->tcf_lock);
0073 goto_ch = tcf_action_set_ctrlact(a, p->action, goto_ch);
0074 memset(d->tcfd_defdata, 0, SIMP_MAX_DATA);
0075 nla_strscpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
0076 spin_unlock_bh(&d->tcf_lock);
0077 if (goto_ch)
0078 tcf_chain_put_by_act(goto_ch);
0079 return 0;
0080 }
0081
0082 static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = {
0083 [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) },
0084 [TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA },
0085 };
0086
0087 static int tcf_simp_init(struct net *net, struct nlattr *nla,
0088 struct nlattr *est, struct tc_action **a,
0089 struct tcf_proto *tp, u32 flags,
0090 struct netlink_ext_ack *extack)
0091 {
0092 struct tc_action_net *tn = net_generic(net, simp_net_id);
0093 bool bind = flags & TCA_ACT_FLAGS_BIND;
0094 struct nlattr *tb[TCA_DEF_MAX + 1];
0095 struct tcf_chain *goto_ch = NULL;
0096 struct tc_defact *parm;
0097 struct tcf_defact *d;
0098 bool exists = false;
0099 int ret = 0, err;
0100 u32 index;
0101
0102 if (nla == NULL)
0103 return -EINVAL;
0104
0105 err = nla_parse_nested_deprecated(tb, TCA_DEF_MAX, nla, simple_policy,
0106 NULL);
0107 if (err < 0)
0108 return err;
0109
0110 if (tb[TCA_DEF_PARMS] == NULL)
0111 return -EINVAL;
0112
0113 parm = nla_data(tb[TCA_DEF_PARMS]);
0114 index = parm->index;
0115 err = tcf_idr_check_alloc(tn, &index, a, bind);
0116 if (err < 0)
0117 return err;
0118 exists = err;
0119 if (exists && bind)
0120 return 0;
0121
0122 if (tb[TCA_DEF_DATA] == NULL) {
0123 if (exists)
0124 tcf_idr_release(*a, bind);
0125 else
0126 tcf_idr_cleanup(tn, index);
0127 return -EINVAL;
0128 }
0129
0130 if (!exists) {
0131 ret = tcf_idr_create(tn, index, est, a,
0132 &act_simp_ops, bind, false, flags);
0133 if (ret) {
0134 tcf_idr_cleanup(tn, index);
0135 return ret;
0136 }
0137
0138 d = to_defact(*a);
0139 err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch,
0140 extack);
0141 if (err < 0)
0142 goto release_idr;
0143
0144 err = alloc_defdata(d, tb[TCA_DEF_DATA]);
0145 if (err < 0)
0146 goto put_chain;
0147
0148 tcf_action_set_ctrlact(*a, parm->action, goto_ch);
0149 ret = ACT_P_CREATED;
0150 } else {
0151 if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
0152 err = -EEXIST;
0153 goto release_idr;
0154 }
0155
0156 err = reset_policy(*a, tb[TCA_DEF_DATA], parm, tp, extack);
0157 if (err)
0158 goto release_idr;
0159 }
0160
0161 return ret;
0162 put_chain:
0163 if (goto_ch)
0164 tcf_chain_put_by_act(goto_ch);
0165 release_idr:
0166 tcf_idr_release(*a, bind);
0167 return err;
0168 }
0169
0170 static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
0171 int bind, int ref)
0172 {
0173 unsigned char *b = skb_tail_pointer(skb);
0174 struct tcf_defact *d = to_defact(a);
0175 struct tc_defact opt = {
0176 .index = d->tcf_index,
0177 .refcnt = refcount_read(&d->tcf_refcnt) - ref,
0178 .bindcnt = atomic_read(&d->tcf_bindcnt) - bind,
0179 };
0180 struct tcf_t t;
0181
0182 spin_lock_bh(&d->tcf_lock);
0183 opt.action = d->tcf_action;
0184 if (nla_put(skb, TCA_DEF_PARMS, sizeof(opt), &opt) ||
0185 nla_put_string(skb, TCA_DEF_DATA, d->tcfd_defdata))
0186 goto nla_put_failure;
0187
0188 tcf_tm_dump(&t, &d->tcf_tm);
0189 if (nla_put_64bit(skb, TCA_DEF_TM, sizeof(t), &t, TCA_DEF_PAD))
0190 goto nla_put_failure;
0191 spin_unlock_bh(&d->tcf_lock);
0192
0193 return skb->len;
0194
0195 nla_put_failure:
0196 spin_unlock_bh(&d->tcf_lock);
0197 nlmsg_trim(skb, b);
0198 return -1;
0199 }
0200
0201 static int tcf_simp_walker(struct net *net, struct sk_buff *skb,
0202 struct netlink_callback *cb, int type,
0203 const struct tc_action_ops *ops,
0204 struct netlink_ext_ack *extack)
0205 {
0206 struct tc_action_net *tn = net_generic(net, simp_net_id);
0207
0208 return tcf_generic_walker(tn, skb, cb, type, ops, extack);
0209 }
0210
0211 static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index)
0212 {
0213 struct tc_action_net *tn = net_generic(net, simp_net_id);
0214
0215 return tcf_idr_search(tn, a, index);
0216 }
0217
0218 static struct tc_action_ops act_simp_ops = {
0219 .kind = "simple",
0220 .id = TCA_ID_SIMP,
0221 .owner = THIS_MODULE,
0222 .act = tcf_simp_act,
0223 .dump = tcf_simp_dump,
0224 .cleanup = tcf_simp_release,
0225 .init = tcf_simp_init,
0226 .walk = tcf_simp_walker,
0227 .lookup = tcf_simp_search,
0228 .size = sizeof(struct tcf_defact),
0229 };
0230
0231 static __net_init int simp_init_net(struct net *net)
0232 {
0233 struct tc_action_net *tn = net_generic(net, simp_net_id);
0234
0235 return tc_action_net_init(net, tn, &act_simp_ops);
0236 }
0237
0238 static void __net_exit simp_exit_net(struct list_head *net_list)
0239 {
0240 tc_action_net_exit(net_list, simp_net_id);
0241 }
0242
0243 static struct pernet_operations simp_net_ops = {
0244 .init = simp_init_net,
0245 .exit_batch = simp_exit_net,
0246 .id = &simp_net_id,
0247 .size = sizeof(struct tc_action_net),
0248 };
0249
0250 MODULE_AUTHOR("Jamal Hadi Salim(2005)");
0251 MODULE_DESCRIPTION("Simple example action");
0252 MODULE_LICENSE("GPL");
0253
0254 static int __init simp_init_module(void)
0255 {
0256 int ret = tcf_register_action(&act_simp_ops, &simp_net_ops);
0257 if (!ret)
0258 pr_info("Simple TC action Loaded\n");
0259 return ret;
0260 }
0261
0262 static void __exit simp_cleanup_module(void)
0263 {
0264 tcf_unregister_action(&act_simp_ops, &simp_net_ops);
0265 }
0266
0267 module_init(simp_init_module);
0268 module_exit(simp_cleanup_module);