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_ipv6.h> 18 #include <linux/netfilter.h> 19 #include <linux/smp.h> 20 #include <net/pkt_sched.h> 21 #include <asm/byteorder.h> 22 #include <asm/uaccess.h> 23 #include <linux/kmod.h> 24 #include <linux/stat.h> 25 #include <linux/interrupt.h> 26 #include <linux/list.h> 27 28 29 #undef DEBUG_INGRESS 30 31 #ifdef DEBUG_INGRESS /* control */ 32 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) 33 #else 34 #define DPRINTK(format,args...) 35 #endif 36 37 #if 0 /* data */ 38 #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) 39 #else 40 #define D2PRINTK(format,args...) 41 #endif 42 43 44 #define PRIV(sch) qdisc_priv(sch) 45 46 47 /* Thanks to Doron Oz for this hack 48 */ 49 #ifndef CONFIG_NET_CLS_ACT 50 #ifdef CONFIG_NETFILTER 51 static int nf_registered; 52 #endif 53 #endif 54 55 struct ingress_qdisc_data { 56 struct Qdisc *q; 57 struct tcf_proto *filter_list; 58 }; 59 60 61 /* ------------------------- Class/flow operations ------------------------- */ 62 63 64 static int ingress_graft(struct Qdisc *sch,unsigned long arg, 65 struct Qdisc *new,struct Qdisc **old) 66 { 67 #ifdef DEBUG_INGRESS 68 struct ingress_qdisc_data *p = PRIV(sch); 69 #endif 70 71 DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)\n", 72 sch, p, new, old); 73 DPRINTK("\n ingress_graft: You cannot add qdiscs to classes"); 74 return 1; 75 } 76 77 78 static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg) 79 { 80 return NULL; 81 } 82 83 84 static unsigned long ingress_get(struct Qdisc *sch,u32 classid) 85 { 86 #ifdef DEBUG_INGRESS 87 struct ingress_qdisc_data *p = PRIV(sch); 88 #endif 89 DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); 90 return TC_H_MIN(classid) + 1; 91 } 92 93 94 static unsigned long ingress_bind_filter(struct Qdisc *sch, 95 unsigned long parent, u32 classid) 96 { 97 return ingress_get(sch, classid); 98 } 99 100 101 static void ingress_put(struct Qdisc *sch, unsigned long cl) 102 { 103 } 104 105 106 static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, 107 struct rtattr **tca, unsigned long *arg) 108 { 109 #ifdef DEBUG_INGRESS 110 struct ingress_qdisc_data *p = PRIV(sch); 111 #endif 112 DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x)," 113 "arg 0x%lx\n", sch, p, classid, parent, *arg); 114 DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment"); 115 return 0; 116 } 117 118 119 120 static void ingress_walk(struct Qdisc *sch,struct qdisc_walker *walker) 121 { 122 #ifdef DEBUG_INGRESS 123 struct ingress_qdisc_data *p = PRIV(sch); 124 #endif 125 DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); 126 DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment"); 127 } 128 129 130 static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch,unsigned long cl) 131 { 132 struct ingress_qdisc_data *p = PRIV(sch); 133 134 return &p->filter_list; 135 } 136 137 138 /* --------------------------- Qdisc operations ---------------------------- */ 139 140 141 static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch) 142 { 143 struct ingress_qdisc_data *p = PRIV(sch); 144 struct tcf_result res; 145 int result; 146 147 D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); 148 result = tc_classify(skb, p->filter_list, &res); 149 D2PRINTK("result %d class 0x%04x\n", result, res.classid); 150 /* 151 * Unlike normal "enqueue" functions, ingress_enqueue returns a 152 * firewall FW_* code. 153 */ 154 #ifdef CONFIG_NET_CLS_ACT 155 sch->bstats.packets++; 156 sch->bstats.bytes += skb->len; 157 switch (result) { 158 case TC_ACT_SHOT: 159 result = TC_ACT_SHOT; 160 sch->qstats.drops++; 161 break; 162 case TC_ACT_STOLEN: 163 case TC_ACT_QUEUED: 164 result = TC_ACT_STOLEN; 165 break; 166 case TC_ACT_RECLASSIFY: 167 case TC_ACT_OK: 168 case TC_ACT_UNSPEC: 169 default: 170 skb->tc_index = TC_H_MIN(res.classid); 171 result = TC_ACT_OK; 172 break; 173 }; 174 /* backward compat */ 175 #else 176 #ifdef CONFIG_NET_CLS_POLICE 177 switch (result) { 178 case TC_POLICE_SHOT: 179 result = NF_DROP; 180 sch->qstats.drops++; 181 break; 182 case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */ 183 case TC_POLICE_OK: 184 case TC_POLICE_UNSPEC: 185 default: 186 sch->bstats.packets++; 187 sch->bstats.bytes += skb->len; 188 result = NF_ACCEPT; 189 break; 190 }; 191 192 #else 193 D2PRINTK("Overriding result to ACCEPT\n"); 194 result = NF_ACCEPT; 195 sch->bstats.packets++; 196 sch->bstats.bytes += skb->len; 197 #endif 198 #endif 199 200 return result; 201 } 202 203 204 static struct sk_buff *ingress_dequeue(struct Qdisc *sch) 205 { 206 /* 207 struct ingress_qdisc_data *p = PRIV(sch); 208 D2PRINTK("ingress_dequeue(sch %p,[qdisc %p])\n",sch,PRIV(p)); 209 */ 210 return NULL; 211 } 212 213 214 static int ingress_requeue(struct sk_buff *skb,struct Qdisc *sch) 215 { 216 /* 217 struct ingress_qdisc_data *p = PRIV(sch); 218 D2PRINTK("ingress_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,PRIV(p)); 219 */ 220 return 0; 221 } 222 223 static unsigned int ingress_drop(struct Qdisc *sch) 224 { 225 #ifdef DEBUG_INGRESS 226 struct ingress_qdisc_data *p = PRIV(sch); 227 #endif 228 DPRINTK("ingress_drop(sch %p,[qdisc %p])\n", sch, p); 229 return 0; 230 } 231 232 #ifndef CONFIG_NET_CLS_ACT 233 #ifdef CONFIG_NETFILTER 234 static unsigned int 235 ing_hook(unsigned int hook, struct sk_buff **pskb, 236 const struct net_device *indev, 237 const struct net_device *outdev, 238 int (*okfn)(struct sk_buff *)) 239 { 240 241 struct Qdisc *q; 242 struct sk_buff *skb = *pskb; 243 struct net_device *dev = skb->dev; 244 int fwres=NF_ACCEPT; 245 246 DPRINTK("ing_hook: skb %s dev=%s len=%u\n", 247 skb->sk ? "(owned)" : "(unowned)", 248 skb->dev ? (*pskb)->dev->name : "(no dev)", 249 skb->len); 250 251 /* 252 revisit later: Use a private since lock dev->queue_lock is also 253 used on the egress (might slow things for an iota) 254 */ 255 256 if (dev->qdisc_ingress) { 257 spin_lock(&dev->queue_lock); 258 if ((q = dev->qdisc_ingress) != NULL) 259 fwres = q->enqueue(skb, q); 260 spin_unlock(&dev->queue_lock); 261 } 262 263 return fwres; 264 } 265 266 /* after ipt_filter */ 267 static struct nf_hook_ops ing_ops = { 268 .hook = ing_hook, 269 .owner = THIS_MODULE, 270 .pf = PF_INET, 271 .hooknum = NF_IP_PRE_ROUTING, 272 .priority = NF_IP_PRI_FILTER + 1, 273 }; 274 275 static struct nf_hook_ops ing6_ops = { 276 .hook = ing_hook, 277 .owner = THIS_MODULE, 278 .pf = PF_INET6, 279 .hooknum = NF_IP6_PRE_ROUTING, 280 .priority = NF_IP6_PRI_FILTER + 1, 281 }; 282 283 #endif 284 #endif 285 286 static int ingress_init(struct Qdisc *sch,struct rtattr *opt) 287 { 288 struct ingress_qdisc_data *p = PRIV(sch); 289 290 /* Make sure either netfilter or preferably CLS_ACT is 291 * compiled in */ 292 #ifndef CONFIG_NET_CLS_ACT 293 #ifndef CONFIG_NETFILTER 294 printk("You MUST compile classifier actions into the kernel\n"); 295 return -EINVAL; 296 #else 297 printk("Ingress scheduler: Classifier actions prefered over netfilter\n"); 298 #endif 299 #endif 300 301 #ifndef CONFIG_NET_CLS_ACT 302 #ifdef CONFIG_NETFILTER 303 if (!nf_registered) { 304 if (nf_register_hook(&ing_ops) < 0) { 305 printk("ingress qdisc registration error \n"); 306 return -EINVAL; 307 } 308 nf_registered++; 309 310 if (nf_register_hook(&ing6_ops) < 0) { 311 printk("IPv6 ingress qdisc registration error, " \ 312 "disabling IPv6 support.\n"); 313 } else 314 nf_registered++; 315 } 316 #endif 317 #endif 318 319 DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); 320 p->q = &noop_qdisc; 321 return 0; 322 } 323 324 325 static void ingress_reset(struct Qdisc *sch) 326 { 327 struct ingress_qdisc_data *p = PRIV(sch); 328 329 DPRINTK("ingress_reset(sch %p,[qdisc %p])\n", sch, p); 330 331 /* 332 #if 0 333 */ 334 /* for future use */ 335 qdisc_reset(p->q); 336 /* 337 #endif 338 */ 339 } 340 341 /* ------------------------------------------------------------- */ 342 343 344 /* ------------------------------------------------------------- */ 345 346 static void ingress_destroy(struct Qdisc *sch) 347 { 348 struct ingress_qdisc_data *p = PRIV(sch); 349 struct tcf_proto *tp; 350 351 DPRINTK("ingress_destroy(sch %p,[qdisc %p])\n", sch, p); 352 while (p->filter_list) { 353 tp = p->filter_list; 354 p->filter_list = tp->next; 355 tcf_destroy(tp); 356 } 357 #if 0 358 /* for future use */ 359 qdisc_destroy(p->q); 360 #endif 361 } 362 363 364 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) 365 { 366 unsigned char *b = skb->tail; 367 struct rtattr *rta; 368 369 rta = (struct rtattr *) b; 370 RTA_PUT(skb, TCA_OPTIONS, 0, NULL); 371 rta->rta_len = skb->tail - b; 372 return skb->len; 373 374 rtattr_failure: 375 skb_trim(skb, b - skb->data); 376 return -1; 377 } 378 379 static struct Qdisc_class_ops ingress_class_ops = { 380 .graft = ingress_graft, 381 .leaf = ingress_leaf, 382 .get = ingress_get, 383 .put = ingress_put, 384 .change = ingress_change, 385 .delete = NULL, 386 .walk = ingress_walk, 387 .tcf_chain = ingress_find_tcf, 388 .bind_tcf = ingress_bind_filter, 389 .unbind_tcf = ingress_put, 390 .dump = NULL, 391 }; 392 393 static struct Qdisc_ops ingress_qdisc_ops = { 394 .next = NULL, 395 .cl_ops = &ingress_class_ops, 396 .id = "ingress", 397 .priv_size = sizeof(struct ingress_qdisc_data), 398 .enqueue = ingress_enqueue, 399 .dequeue = ingress_dequeue, 400 .requeue = ingress_requeue, 401 .drop = ingress_drop, 402 .init = ingress_init, 403 .reset = ingress_reset, 404 .destroy = ingress_destroy, 405 .change = NULL, 406 .dump = ingress_dump, 407 .owner = THIS_MODULE, 408 }; 409 410 static int __init ingress_module_init(void) 411 { 412 int ret = 0; 413 414 if ((ret = register_qdisc(&ingress_qdisc_ops)) < 0) { 415 printk("Unable to register Ingress qdisc\n"); 416 return ret; 417 } 418 419 return ret; 420 } 421 static void __exit ingress_module_exit(void) 422 { 423 unregister_qdisc(&ingress_qdisc_ops); 424 #ifndef CONFIG_NET_CLS_ACT 425 #ifdef CONFIG_NETFILTER 426 if (nf_registered) { 427 nf_unregister_hook(&ing_ops); 428 if (nf_registered > 1) 429 nf_unregister_hook(&ing6_ops); 430 } 431 #endif 432 #endif 433 } 434 module_init(ingress_module_init) 435 module_exit(ingress_module_exit) 436 MODULE_LICENSE("GPL"); 437