1 /* 2 * net/sched/gact.c Generic actions 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 * copyright Jamal Hadi Salim (2002-4) 10 * 11 */ 12 13 #include <asm/uaccess.h> 14 #include <asm/system.h> 15 #include <linux/bitops.h> 16 #include <linux/types.h> 17 #include <linux/kernel.h> 18 #include <linux/sched.h> 19 #include <linux/string.h> 20 #include <linux/mm.h> 21 #include <linux/socket.h> 22 #include <linux/sockios.h> 23 #include <linux/in.h> 24 #include <linux/errno.h> 25 #include <linux/interrupt.h> 26 #include <linux/netdevice.h> 27 #include <linux/skbuff.h> 28 #include <linux/rtnetlink.h> 29 #include <linux/module.h> 30 #include <linux/init.h> 31 #include <linux/proc_fs.h> 32 #include <net/sock.h> 33 #include <net/pkt_sched.h> 34 #include <linux/tc_act/tc_gact.h> 35 #include <net/tc_act/tc_gact.h> 36 37 /* use generic hash table */ 38 #define MY_TAB_SIZE 16 39 #define MY_TAB_MASK 15 40 41 static u32 idx_gen; 42 static struct tcf_gact *tcf_gact_ht[MY_TAB_SIZE]; 43 static DEFINE_RWLOCK(gact_lock); 44 45 /* ovewrride the defaults */ 46 #define tcf_st tcf_gact 47 #define tc_st tc_gact 48 #define tcf_t_lock gact_lock 49 #define tcf_ht tcf_gact_ht 50 51 #define CONFIG_NET_ACT_INIT 1 52 #include <net/pkt_act.h> 53 54 #ifdef CONFIG_GACT_PROB 55 static int gact_net_rand(struct tcf_gact *p) 56 { 57 if (net_random()%p->pval) 58 return p->action; 59 return p->paction; 60 } 61 62 static int gact_determ(struct tcf_gact *p) 63 { 64 if (p->bstats.packets%p->pval) 65 return p->action; 66 return p->paction; 67 } 68 69 typedef int (*g_rand)(struct tcf_gact *p); 70 static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ }; 71 #endif 72 73 static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, 74 struct tc_action *a, int ovr, int bind) 75 { 76 struct rtattr *tb[TCA_GACT_MAX]; 77 struct tc_gact *parm; 78 struct tcf_gact *p; 79 int ret = 0; 80 81 if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0) 82 return -EINVAL; 83 84 if (tb[TCA_GACT_PARMS - 1] == NULL || 85 RTA_PAYLOAD(tb[TCA_GACT_PARMS - 1]) < sizeof(*parm)) 86 return -EINVAL; 87 parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]); 88 89 if (tb[TCA_GACT_PROB-1] != NULL) 90 #ifdef CONFIG_GACT_PROB 91 if (RTA_PAYLOAD(tb[TCA_GACT_PROB-1]) < sizeof(struct tc_gact_p)) 92 return -EINVAL; 93 #else 94 return -EOPNOTSUPP; 95 #endif 96 97 p = tcf_hash_check(parm->index, a, ovr, bind); 98 if (p == NULL) { 99 p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); 100 if (p == NULL) 101 return -ENOMEM; 102 ret = ACT_P_CREATED; 103 } else { 104 if (!ovr) { 105 tcf_hash_release(p, bind); 106 return -EEXIST; 107 } 108 } 109 110 spin_lock_bh(&p->lock); 111 p->action = parm->action; 112 #ifdef CONFIG_GACT_PROB 113 if (tb[TCA_GACT_PROB-1] != NULL) { 114 struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]); 115 p->paction = p_parm->paction; 116 p->pval = p_parm->pval; 117 p->ptype = p_parm->ptype; 118 } 119 #endif 120 spin_unlock_bh(&p->lock); 121 if (ret == ACT_P_CREATED) 122 tcf_hash_insert(p); 123 return ret; 124 } 125 126 static int 127 tcf_gact_cleanup(struct tc_action *a, int bind) 128 { 129 struct tcf_gact *p = PRIV(a, gact); 130 131 if (p != NULL) 132 return tcf_hash_release(p, bind); 133 return 0; 134 } 135 136 static int 137 tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) 138 { 139 struct tcf_gact *p = PRIV(a, gact); 140 int action = TC_ACT_SHOT; 141 142 spin_lock(&p->lock); 143 #ifdef CONFIG_GACT_PROB 144 if (p->ptype && gact_rand[p->ptype] != NULL) 145 action = gact_rand[p->ptype](p); 146 else 147 action = p->action; 148 #else 149 action = p->action; 150 #endif 151 p->bstats.bytes += skb->len; 152 p->bstats.packets++; 153 if (action == TC_ACT_SHOT) 154 p->qstats.drops++; 155 p->tm.lastuse = jiffies; 156 spin_unlock(&p->lock); 157 158 return action; 159 } 160 161 static int 162 tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 163 { 164 unsigned char *b = skb->tail; 165 struct tc_gact opt; 166 struct tcf_gact *p = PRIV(a, gact); 167 struct tcf_t t; 168 169 opt.index = p->index; 170 opt.refcnt = p->refcnt - ref; 171 opt.bindcnt = p->bindcnt - bind; 172 opt.action = p->action; 173 RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); 174 #ifdef CONFIG_GACT_PROB 175 if (p->ptype) { 176 struct tc_gact_p p_opt; 177 p_opt.paction = p->paction; 178 p_opt.pval = p->pval; 179 p_opt.ptype = p->ptype; 180 RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); 181 } 182 #endif 183 t.install = jiffies_to_clock_t(jiffies - p->tm.install); 184 t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); 185 t.expires = jiffies_to_clock_t(p->tm.expires); 186 RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t); 187 return skb->len; 188 189 rtattr_failure: 190 skb_trim(skb, b - skb->data); 191 return -1; 192 } 193 194 static struct tc_action_ops act_gact_ops = { 195 .kind = "gact", 196 .type = TCA_ACT_GACT, 197 .capab = TCA_CAP_NONE, 198 .owner = THIS_MODULE, 199 .act = tcf_gact, 200 .dump = tcf_gact_dump, 201 .cleanup = tcf_gact_cleanup, 202 .lookup = tcf_hash_search, 203 .init = tcf_gact_init, 204 .walk = tcf_generic_walker 205 }; 206 207 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); 208 MODULE_DESCRIPTION("Generic Classifier actions"); 209 MODULE_LICENSE("GPL"); 210 211 static int __init 212 gact_init_module(void) 213 { 214 #ifdef CONFIG_GACT_PROB 215 printk("GACT probability on\n"); 216 #else 217 printk("GACT probability NOT on\n"); 218 #endif 219 return tcf_register_action(&act_gact_ops); 220 } 221 222 static void __exit 223 gact_cleanup_module(void) 224 { 225 tcf_unregister_action(&act_gact_ops); 226 } 227 228 module_init(gact_init_module); 229 module_exit(gact_cleanup_module); 230