1 /* 2 * net/sched/act_simple.c Simple example of an action 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Jamal Hadi Salim (2005-8) 10 * 11 */ 12 13 #include <linux/module.h> 14 #include <linux/slab.h> 15 #include <linux/init.h> 16 #include <linux/kernel.h> 17 #include <linux/skbuff.h> 18 #include <linux/rtnetlink.h> 19 #include <net/netlink.h> 20 #include <net/pkt_sched.h> 21 22 #include <linux/tc_act/tc_defact.h> 23 #include <net/tc_act/tc_defact.h> 24 25 static unsigned int simp_net_id; 26 static struct tc_action_ops act_simp_ops; 27 28 #define SIMP_MAX_DATA 32 29 static int tcf_simp_act(struct sk_buff *skb, const struct tc_action *a, 30 struct tcf_result *res) 31 { 32 struct tcf_defact *d = to_defact(a); 33 34 spin_lock(&d->tcf_lock); 35 tcf_lastuse_update(&d->tcf_tm); 36 bstats_update(&d->tcf_bstats, skb); 37 38 /* print policy string followed by _ then packet count 39 * Example if this was the 3rd packet and the string was "hello" 40 * then it would look like "hello_3" (without quotes) 41 */ 42 pr_info("simple: %s_%d\n", 43 (char *)d->tcfd_defdata, d->tcf_bstats.packets); 44 spin_unlock(&d->tcf_lock); 45 return d->tcf_action; 46 } 47 48 static void tcf_simp_release(struct tc_action *a) 49 { 50 struct tcf_defact *d = to_defact(a); 51 kfree(d->tcfd_defdata); 52 } 53 54 static int alloc_defdata(struct tcf_defact *d, const struct nlattr *defdata) 55 { 56 d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); 57 if (unlikely(!d->tcfd_defdata)) 58 return -ENOMEM; 59 nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); 60 return 0; 61 } 62 63 static void reset_policy(struct tcf_defact *d, const struct nlattr *defdata, 64 struct tc_defact *p) 65 { 66 spin_lock_bh(&d->tcf_lock); 67 d->tcf_action = p->action; 68 memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); 69 nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); 70 spin_unlock_bh(&d->tcf_lock); 71 } 72 73 static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = { 74 [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) }, 75 [TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA }, 76 }; 77 78 static int tcf_simp_init(struct net *net, struct nlattr *nla, 79 struct nlattr *est, struct tc_action **a, 80 int ovr, int bind, bool rtnl_held, 81 struct netlink_ext_ack *extack) 82 { 83 struct tc_action_net *tn = net_generic(net, simp_net_id); 84 struct nlattr *tb[TCA_DEF_MAX + 1]; 85 struct tc_defact *parm; 86 struct tcf_defact *d; 87 bool exists = false; 88 int ret = 0, err; 89 90 if (nla == NULL) 91 return -EINVAL; 92 93 err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy, NULL); 94 if (err < 0) 95 return err; 96 97 if (tb[TCA_DEF_PARMS] == NULL) 98 return -EINVAL; 99 100 parm = nla_data(tb[TCA_DEF_PARMS]); 101 err = tcf_idr_check_alloc(tn, &parm->index, a, bind); 102 if (err < 0) 103 return err; 104 exists = err; 105 if (exists && bind) 106 return 0; 107 108 if (tb[TCA_DEF_DATA] == NULL) { 109 if (exists) 110 tcf_idr_release(*a, bind); 111 else 112 tcf_idr_cleanup(tn, parm->index); 113 return -EINVAL; 114 } 115 116 if (!exists) { 117 ret = tcf_idr_create(tn, parm->index, est, a, 118 &act_simp_ops, bind, false); 119 if (ret) { 120 tcf_idr_cleanup(tn, parm->index); 121 return ret; 122 } 123 124 d = to_defact(*a); 125 ret = alloc_defdata(d, tb[TCA_DEF_DATA]); 126 if (ret < 0) { 127 tcf_idr_release(*a, bind); 128 return ret; 129 } 130 d->tcf_action = parm->action; 131 ret = ACT_P_CREATED; 132 } else { 133 d = to_defact(*a); 134 135 if (!ovr) { 136 tcf_idr_release(*a, bind); 137 return -EEXIST; 138 } 139 140 reset_policy(d, tb[TCA_DEF_DATA], parm); 141 } 142 143 if (ret == ACT_P_CREATED) 144 tcf_idr_insert(tn, *a); 145 return ret; 146 } 147 148 static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, 149 int bind, int ref) 150 { 151 unsigned char *b = skb_tail_pointer(skb); 152 struct tcf_defact *d = to_defact(a); 153 struct tc_defact opt = { 154 .index = d->tcf_index, 155 .refcnt = refcount_read(&d->tcf_refcnt) - ref, 156 .bindcnt = atomic_read(&d->tcf_bindcnt) - bind, 157 }; 158 struct tcf_t t; 159 160 spin_lock_bh(&d->tcf_lock); 161 opt.action = d->tcf_action; 162 if (nla_put(skb, TCA_DEF_PARMS, sizeof(opt), &opt) || 163 nla_put_string(skb, TCA_DEF_DATA, d->tcfd_defdata)) 164 goto nla_put_failure; 165 166 tcf_tm_dump(&t, &d->tcf_tm); 167 if (nla_put_64bit(skb, TCA_DEF_TM, sizeof(t), &t, TCA_DEF_PAD)) 168 goto nla_put_failure; 169 spin_unlock_bh(&d->tcf_lock); 170 171 return skb->len; 172 173 nla_put_failure: 174 spin_unlock_bh(&d->tcf_lock); 175 nlmsg_trim(skb, b); 176 return -1; 177 } 178 179 static int tcf_simp_walker(struct net *net, struct sk_buff *skb, 180 struct netlink_callback *cb, int type, 181 const struct tc_action_ops *ops, 182 struct netlink_ext_ack *extack) 183 { 184 struct tc_action_net *tn = net_generic(net, simp_net_id); 185 186 return tcf_generic_walker(tn, skb, cb, type, ops, extack); 187 } 188 189 static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index) 190 { 191 struct tc_action_net *tn = net_generic(net, simp_net_id); 192 193 return tcf_idr_search(tn, a, index); 194 } 195 196 static struct tc_action_ops act_simp_ops = { 197 .kind = "simple", 198 .id = TCA_ID_SIMP, 199 .owner = THIS_MODULE, 200 .act = tcf_simp_act, 201 .dump = tcf_simp_dump, 202 .cleanup = tcf_simp_release, 203 .init = tcf_simp_init, 204 .walk = tcf_simp_walker, 205 .lookup = tcf_simp_search, 206 .size = sizeof(struct tcf_defact), 207 }; 208 209 static __net_init int simp_init_net(struct net *net) 210 { 211 struct tc_action_net *tn = net_generic(net, simp_net_id); 212 213 return tc_action_net_init(tn, &act_simp_ops); 214 } 215 216 static void __net_exit simp_exit_net(struct list_head *net_list) 217 { 218 tc_action_net_exit(net_list, simp_net_id); 219 } 220 221 static struct pernet_operations simp_net_ops = { 222 .init = simp_init_net, 223 .exit_batch = simp_exit_net, 224 .id = &simp_net_id, 225 .size = sizeof(struct tc_action_net), 226 }; 227 228 MODULE_AUTHOR("Jamal Hadi Salim(2005)"); 229 MODULE_DESCRIPTION("Simple example action"); 230 MODULE_LICENSE("GPL"); 231 232 static int __init simp_init_module(void) 233 { 234 int ret = tcf_register_action(&act_simp_ops, &simp_net_ops); 235 if (!ret) 236 pr_info("Simple TC action Loaded\n"); 237 return ret; 238 } 239 240 static void __exit simp_cleanup_module(void) 241 { 242 tcf_unregister_action(&act_simp_ops, &simp_net_ops); 243 } 244 245 module_init(simp_init_module); 246 module_exit(simp_cleanup_module); 247