1 /* net/sched/sch_ingress.c - Ingress qdisc 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License 4 * as published by the Free Software Foundation; either version 5 * 2 of the License, or (at your option) any later version. 6 * 7 * Authors: Jamal Hadi Salim 1999 8 */ 9 10 #include <linux/config.h> 11 #include <linux/module.h> 12 #include <linux/types.h> 13 #include <linux/skbuff.h> 14 #include <linux/netdevice.h> 15 #include <linux/rtnetlink.h> 16 #include <linux/netfilter_ipv4.h> 17 #include <linux/netfilter.h> 18 #include <linux/smp.h> 19 #include <net/pkt_sched.h> 20 #include <asm/byteorder.h> 21 #include <asm/uaccess.h> 22 #include <linux/kmod.h> 23 #include <linux/stat.h> 24 #include <linux/interrupt.h> 25 #include <linux/list.h> 26 27 28 #undef DEBUG_INGRESS 29 30 #ifdef DEBUG_INGRESS /* control */ 31 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) 32 #else 33 #define DPRINTK(format,args...) 34 #endif 35 36 #if 0 /* data */ 37 #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) 38 #else 39 #define D2PRINTK(format,args...) 40 #endif 41 42 43 #define PRIV(sch) ((struct ingress_qdisc_data *) (sch)->data) 44 45 46 /* Thanks to Doron Oz for this hack 47 */ 48 static int nf_registered; 49 50 struct ingress_qdisc_data { 51 struct Qdisc *q; 52 struct tcf_proto *filter_list; 53 }; 54 55 56 /* ------------------------- Class/flow operations ------------------------- */ 57 58 59 static int ingress_graft(struct Qdisc *sch,unsigned long arg, 60 struct Qdisc *new,struct Qdisc **old) 61 { 62 #ifdef DEBUG_INGRESS 63 struct ingress_qdisc_data *p = PRIV(sch); 64 #endif 65 66 DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)\n", 67 sch, p, new, old); 68 DPRINTK("\n ingress_graft: You cannot add qdiscs to classes"); 69 return 1; 70 } 71 72 73 static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg) 74 { 75 return NULL; 76 } 77 78 79 static unsigned long ingress_get(struct Qdisc *sch,u32 classid) 80 { 81 #ifdef DEBUG_INGRESS 82 struct ingress_qdisc_data *p = PRIV(sch); 83 #endif 84 DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); 85 return TC_H_MIN(classid) + 1; 86 } 87 88 89 static unsigned long ingress_bind_filter(struct Qdisc *sch, 90 unsigned long parent, u32 classid) 91 { 92 return ingress_get(sch, classid); 93 } 94 95 96 static void ingress_put(struct Qdisc *sch, unsigned long cl) 97 { 98 } 99 100 101 static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, 102 struct rtattr **tca, unsigned long *arg) 103 { 104 #ifdef DEBUG_INGRESS 105 struct ingress_qdisc_data *p = PRIV(sch); 106 #endif 107 DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x)," 108 "arg 0x%lx\n", sch, p, classid, parent, *arg); 109 DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment"); 110 return 0; 111 } 112 113 114 115 static void ingress_walk(struct Qdisc *sch,struct qdisc_walker *walker) 116 { 117 #ifdef DEBUG_INGRESS 118 struct ingress_qdisc_data *p = PRIV(sch); 119 #endif 120 DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); 121 DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment"); 122 } 123 124 125 static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch,unsigned long cl) 126 { 127 struct ingress_qdisc_data *p = PRIV(sch); 128 129 return &p->filter_list; 130 } 131 132 133 /* --------------------------- Qdisc operations ---------------------------- */ 134 135 136 static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch) 137 { 138 struct ingress_qdisc_data *p = PRIV(sch); 139 struct tcf_result res; 140 int result; 141 142 D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); 143 result = tc_classify(skb, p->filter_list, &res); 144 D2PRINTK("result %d class 0x%04x\n", result, res.classid); 145 /* 146 * Unlike normal "enqueue" functions, ingress_enqueue returns a 147 * firewall FW_* code. 148 */ 149 #ifdef CONFIG_NET_CLS_POLICE 150 switch (result) { 151 case TC_POLICE_SHOT: 152 result = NF_DROP; 153 sch->stats.drops++; 154 break; 155 case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */ 156 case TC_POLICE_OK: 157 case TC_POLICE_UNSPEC: 158 default: 159 sch->stats.packets++; 160 sch->stats.bytes += skb->len; 161 result = NF_ACCEPT; 162 break; 163 }; 164 #else 165 sch->stats.packets++; 166 sch->stats.bytes += skb->len; 167 #endif 168 169 skb->tc_index = TC_H_MIN(res.classid); 170 return result; 171 } 172 173 174 static struct sk_buff *ingress_dequeue(struct Qdisc *sch) 175 { 176 /* 177 struct ingress_qdisc_data *p = PRIV(sch); 178 D2PRINTK("ingress_dequeue(sch %p,[qdisc %p])\n",sch,PRIV(p)); 179 */ 180 return NULL; 181 } 182 183 184 static int ingress_requeue(struct sk_buff *skb,struct Qdisc *sch) 185 { 186 /* 187 struct ingress_qdisc_data *p = PRIV(sch); 188 D2PRINTK("ingress_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,PRIV(p)); 189 */ 190 return 0; 191 } 192 193 static unsigned int ingress_drop(struct Qdisc *sch) 194 { 195 #ifdef DEBUG_INGRESS 196 struct ingress_qdisc_data *p = PRIV(sch); 197 #endif 198 DPRINTK("ingress_drop(sch %p,[qdisc %p])\n", sch, p); 199 return 0; 200 } 201 202 static unsigned int 203 ing_hook(unsigned int hook, struct sk_buff **pskb, 204 const struct net_device *indev, 205 const struct net_device *outdev, 206 int (*okfn)(struct sk_buff *)) 207 { 208 209 struct Qdisc *q; 210 struct sk_buff *skb = *pskb; 211 struct net_device *dev = skb->dev; 212 int fwres=NF_ACCEPT; 213 214 DPRINTK("ing_hook: skb %s dev=%s len=%u\n", 215 skb->sk ? "(owned)" : "(unowned)", 216 skb->dev ? (*pskb)->dev->name : "(no dev)", 217 skb->len); 218 219 /* 220 revisit later: Use a private since lock dev->queue_lock is also 221 used on the egress (might slow things for an iota) 222 */ 223 224 if (dev->qdisc_ingress) { 225 spin_lock(&dev->queue_lock); 226 if ((q = dev->qdisc_ingress) != NULL) 227 fwres = q->enqueue(skb, q); 228 spin_unlock(&dev->queue_lock); 229 } 230 231 return fwres; 232 } 233 234 /* after ipt_filter */ 235 static struct nf_hook_ops ing_ops = { 236 .hook = ing_hook, 237 .owner = THIS_MODULE, 238 .pf = PF_INET, 239 .hooknum = NF_IP_PRE_ROUTING, 240 .priority = NF_IP_PRI_FILTER + 1, 241 }; 242 243 int ingress_init(struct Qdisc *sch,struct rtattr *opt) 244 { 245 struct ingress_qdisc_data *p = PRIV(sch); 246 247 if (!nf_registered) { 248 if (nf_register_hook(&ing_ops) < 0) { 249 printk("ingress qdisc registration error \n"); 250 goto error; 251 } 252 nf_registered++; 253 } 254 255 DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); 256 memset(p, 0, sizeof(*p)); 257 p->filter_list = NULL; 258 p->q = &noop_qdisc; 259 return 0; 260 error: 261 return -EINVAL; 262 } 263 264 265 static void ingress_reset(struct Qdisc *sch) 266 { 267 struct ingress_qdisc_data *p = PRIV(sch); 268 269 DPRINTK("ingress_reset(sch %p,[qdisc %p])\n", sch, p); 270 271 /* 272 #if 0 273 */ 274 /* for future use */ 275 qdisc_reset(p->q); 276 /* 277 #endif 278 */ 279 } 280 281 /* ------------------------------------------------------------- */ 282 283 284 /* ------------------------------------------------------------- */ 285 286 static void ingress_destroy(struct Qdisc *sch) 287 { 288 struct ingress_qdisc_data *p = PRIV(sch); 289 struct tcf_proto *tp; 290 291 DPRINTK("ingress_destroy(sch %p,[qdisc %p])\n", sch, p); 292 while (p->filter_list) { 293 tp = p->filter_list; 294 p->filter_list = tp->next; 295 tp->ops->destroy(tp); 296 } 297 memset(p, 0, sizeof(*p)); 298 p->filter_list = NULL; 299 300 #if 0 301 /* for future use */ 302 qdisc_destroy(p->q); 303 #endif 304 } 305 306 307 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) 308 { 309 unsigned char *b = skb->tail; 310 struct rtattr *rta; 311 312 rta = (struct rtattr *) b; 313 RTA_PUT(skb, TCA_OPTIONS, 0, NULL); 314 rta->rta_len = skb->tail - b; 315 return skb->len; 316 317 rtattr_failure: 318 skb_trim(skb, b - skb->data); 319 return -1; 320 } 321 322 static struct Qdisc_class_ops ingress_class_ops = { 323 .graft = ingress_graft, 324 .leaf = ingress_leaf, 325 .get = ingress_get, 326 .put = ingress_put, 327 .change = ingress_change, 328 .delete = NULL, 329 .walk = ingress_walk, 330 .tcf_chain = ingress_find_tcf, 331 .bind_tcf = ingress_bind_filter, 332 .unbind_tcf = ingress_put, 333 .dump = NULL, 334 }; 335 336 struct Qdisc_ops ingress_qdisc_ops = { 337 .next = NULL, 338 .cl_ops = &ingress_class_ops, 339 .id = "ingress", 340 .priv_size = sizeof(struct ingress_qdisc_data), 341 .enqueue = ingress_enqueue, 342 .dequeue = ingress_dequeue, 343 .requeue = ingress_requeue, 344 .drop = ingress_drop, 345 .init = ingress_init, 346 .reset = ingress_reset, 347 .destroy = ingress_destroy, 348 .change = NULL, 349 .dump = ingress_dump, 350 .owner = THIS_MODULE, 351 }; 352 353 354 #ifdef MODULE 355 int init_module(void) 356 { 357 int ret = 0; 358 359 if ((ret = register_qdisc(&ingress_qdisc_ops)) < 0) { 360 printk("Unable to register Ingress qdisc\n"); 361 return ret; 362 } 363 364 return ret; 365 } 366 367 368 void cleanup_module(void) 369 { 370 unregister_qdisc(&ingress_qdisc_ops); 371 if (nf_registered) 372 nf_unregister_hook(&ing_ops); 373 } 374 #endif 375 MODULE_LICENSE("GPL"); 376
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.