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