1/* 2 ************************************************************************** 3 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all copies. 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 ************************************************************************** 15 */ 16 17#include <linux/version.h> 18#include <linux/types.h> 19#include <linux/ip.h> 20#include <linux/tcp.h> 21#include <linux/module.h> 22#include <linux/skbuff.h> 23#include <linux/icmp.h> 24#include <linux/debugfs.h> 25#include <linux/kthread.h> 26#include <linux/pkt_sched.h> 27#include <linux/string.h> 28#include <net/route.h> 29#include <net/ip.h> 30#include <net/tcp.h> 31#include <asm/unaligned.h> 32#include <asm/uaccess.h> /* for put_user */ 33#include <net/ipv6.h> 34#include <linux/inet.h> 35#include <linux/in.h> 36#include <linux/udp.h> 37#include <linux/tcp.h> 38 39#include <linux/netfilter_ipv4.h> 40#include <linux/netfilter_bridge.h> 41#include <net/netfilter/nf_conntrack.h> 42#include <net/netfilter/nf_conntrack_helper.h> 43#include <net/netfilter/nf_conntrack_l4proto.h> 44#include <net/netfilter/nf_conntrack_l3proto.h> 45#include <net/netfilter/nf_conntrack_core.h> 46#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 47#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 48#include <linux/netfilter/xt_dscp.h> 49#include <net/netfilter/nf_conntrack_dscpremark_ext.h> 50 51/* 52 * Debug output levels 53 * 0 = OFF 54 * 1 = ASSERTS / ERRORS 55 * 2 = 1 + WARN 56 * 3 = 2 + INFO 57 * 4 = 3 + TRACE 58 */ 59#define DEBUG_LEVEL ECM_CLASSIFIER_DSCP_DEBUG_LEVEL 60 61#include "ecm_types.h" 62#include "ecm_db_types.h" 63#include "ecm_state.h" 64#include "ecm_tracker.h" 65#include "ecm_classifier.h" 66#include "ecm_front_end_types.h" 67#include "ecm_tracker_udp.h" 68#include "ecm_tracker_tcp.h" 69#include "ecm_db.h" 70#include "ecm_classifier_dscp.h" 71 72/* 73 * Magic numbers 74 */ 75#define ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC 0xFA43 76 77/* 78 * struct ecm_classifier_dscp_instance 79 * State to allow tracking of dynamic qos for a connection 80 */ 81struct ecm_classifier_dscp_instance { 82 struct ecm_classifier_instance base; /* Base type */ 83 84 struct ecm_classifier_dscp_instance *next; /* Next classifier state instance (for accouting and reporting purposes) */ 85 struct ecm_classifier_dscp_instance *prev; /* Next classifier state instance (for accouting and reporting purposes) */ 86 87 uint32_t ci_serial; /* RO: Serial of the connection */ 88 struct ecm_classifier_process_response process_response;/* Last process response computed */ 89 90 int refs; /* Integer to trap we never go negative */ 91#if (DEBUG_LEVEL > 0) 92 uint16_t magic; 93#endif 94}; 95 96/* 97 * Operational control 98 */ 99static bool ecm_classifier_dscp_enabled = true; /* Operational behaviour */ 100 101/* 102 * Management thread control 103 */ 104static bool ecm_classifier_dscp_terminate_pending = false; /* True when the user wants us to terminate */ 105 106/* 107 * Debugfs dentry object. 108 */ 109static struct dentry *ecm_classifier_dscp_dentry; 110 111/* 112 * Locking of the classifier structures 113 */ 114static DEFINE_SPINLOCK(ecm_classifier_dscp_lock); /* Protect SMP access. */ 115 116/* 117 * List of our classifier instances 118 */ 119static struct ecm_classifier_dscp_instance *ecm_classifier_dscp_instances = NULL; 120 /* list of all active instances */ 121static int ecm_classifier_dscp_count = 0; /* Tracks number of instances allocated */ 122 123/* 124 * ecm_classifier_dscp_ref() 125 * Ref 126 */ 127static void ecm_classifier_dscp_ref(struct ecm_classifier_instance *ci) 128{ 129 struct ecm_classifier_dscp_instance *cdscpi; 130 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 131 132 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 133 spin_lock_bh(&ecm_classifier_dscp_lock); 134 cdscpi->refs++; 135 DEBUG_TRACE("%p: cdscpi ref %d\n", cdscpi, cdscpi->refs); 136 DEBUG_ASSERT(cdscpi->refs > 0, "%p: ref wrap\n", cdscpi); 137 spin_unlock_bh(&ecm_classifier_dscp_lock); 138} 139 140/* 141 * ecm_classifier_dscp_deref() 142 * Deref 143 */ 144static int ecm_classifier_dscp_deref(struct ecm_classifier_instance *ci) 145{ 146 struct ecm_classifier_dscp_instance *cdscpi; 147 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 148 149 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 150 spin_lock_bh(&ecm_classifier_dscp_lock); 151 cdscpi->refs--; 152 DEBUG_ASSERT(cdscpi->refs >= 0, "%p: refs wrapped\n", cdscpi); 153 DEBUG_TRACE("%p: DSCP classifier deref %d\n", cdscpi, cdscpi->refs); 154 if (cdscpi->refs) { 155 int refs = cdscpi->refs; 156 spin_unlock_bh(&ecm_classifier_dscp_lock); 157 return refs; 158 } 159 160 /* 161 * Object to be destroyed 162 */ 163 ecm_classifier_dscp_count--; 164 DEBUG_ASSERT(ecm_classifier_dscp_count >= 0, "%p: ecm_classifier_dscp_count wrap\n", cdscpi); 165 166 /* 167 * UnLink the instance from our list 168 */ 169 if (cdscpi->next) { 170 cdscpi->next->prev = cdscpi->prev; 171 } 172 if (cdscpi->prev) { 173 cdscpi->prev->next = cdscpi->next; 174 } else { 175 DEBUG_ASSERT(ecm_classifier_dscp_instances == cdscpi, "%p: list bad %p\n", cdscpi, ecm_classifier_dscp_instances); 176 ecm_classifier_dscp_instances = cdscpi->next; 177 } 178 179 spin_unlock_bh(&ecm_classifier_dscp_lock); 180 181 /* 182 * Final 183 */ 184 DEBUG_INFO("%p: Final DSCP classifier instance\n", cdscpi); 185 kfree(cdscpi); 186 187 return 0; 188} 189 190/* 191 * ecm_classifier_dscp_process() 192 * Process new data for connection 193 */ 194static void ecm_classifier_dscp_process(struct ecm_classifier_instance *aci, ecm_tracker_sender_type_t sender, 195 struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, 196 struct ecm_classifier_process_response *process_response) 197{ 198 struct ecm_classifier_dscp_instance *cdscpi; 199 ecm_classifier_relevence_t relevance; 200 struct ecm_db_connection_instance *ci = NULL; 201 struct ecm_front_end_connection_instance *feci; 202 ecm_front_end_acceleration_mode_t accel_mode; 203 int protocol; 204 uint32_t became_relevant = 0; 205 struct nf_conn *ct; 206 enum ip_conntrack_info ctinfo; 207 struct nf_ct_dscpremark_ext *dscpcte; 208 uint32_t flow_qos_tag; 209 uint32_t return_qos_tag; 210 uint8_t flow_dscp; 211 uint8_t return_dscp; 212 bool dscp_marked = false; 213 214 cdscpi = (struct ecm_classifier_dscp_instance *)aci; 215 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 216 217 /* 218 * Are we yet to decide if this instance is relevant to the connection? 219 */ 220 spin_lock_bh(&ecm_classifier_dscp_lock); 221 relevance = cdscpi->process_response.relevance; 222 223 /* 224 * Are we relevant? 225 */ 226 if (relevance == ECM_CLASSIFIER_RELEVANCE_NO) { 227 /* 228 * Lock still held 229 */ 230 goto dscp_classifier_out; 231 } 232 233 /* 234 * Yes or maybe relevant. 235 * 236 * Need to decide our relevance to this connection. 237 * We are only relevent to a connection iff: 238 * 1. We are enabled. 239 * 2. Connection can be accelerated. 240 * 3. Connection has a ct, ct has a dscp remark extension and the rule is validated. 241 * Any other condition and we are not and will stop analysing this connection. 242 */ 243 if (!ecm_classifier_dscp_enabled) { 244 /* 245 * Lock still held 246 */ 247 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO; 248 goto dscp_classifier_out; 249 } 250 spin_unlock_bh(&ecm_classifier_dscp_lock); 251 252 /* 253 * Can we accelerate? 254 */ 255 ci = ecm_db_connection_serial_find_and_ref(cdscpi->ci_serial); 256 if (!ci) { 257 DEBUG_TRACE("%p: No ci found for %u\n", cdscpi, cdscpi->ci_serial); 258 spin_lock_bh(&ecm_classifier_dscp_lock); 259 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO; 260 goto dscp_classifier_out; 261 } 262 feci = ecm_db_connection_front_end_get_and_ref(ci); 263 accel_mode = feci->accel_state_get(feci); 264 feci->deref(feci); 265 protocol = ecm_db_connection_protocol_get(ci); 266 ecm_db_connection_deref(ci); 267 if (ECM_FRONT_END_ACCELERATION_NOT_POSSIBLE(accel_mode)) { 268 spin_lock_bh(&ecm_classifier_dscp_lock); 269 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO; 270 goto dscp_classifier_out; 271 } 272 273 /* 274 * Is there a valid conntrack? 275 */ 276 ct = nf_ct_get(skb, &ctinfo); 277 if (!ct) { 278 spin_lock_bh(&ecm_classifier_dscp_lock); 279 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO; 280 goto dscp_classifier_out; 281 } 282 283 /* 284 * Is there a DSCPREMARK extension? 285 */ 286 spin_lock_bh(&ct->lock); 287 dscpcte = nf_ct_dscpremark_ext_find(ct); 288 if (!dscpcte) { 289 spin_unlock_bh(&ct->lock); 290 spin_lock_bh(&ecm_classifier_dscp_lock); 291 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO; 292 goto dscp_classifier_out; 293 } 294 295 /* 296 * Was a DSCP rule enabled for the flow using the iptables 'DSCP' 297 * target? 298 */ 299 if (nf_conntrack_dscpremark_ext_get_dscp_rule_validity(ct) 300 == NF_CT_DSCPREMARK_EXT_RULE_VALID) { 301 dscp_marked = true; 302 } 303 304 /* 305 * Extract the priority and DSCP from skb and store into ct extension 306 * for each direction. 307 * 308 * For TCP flows, we would have the values for both the directions by 309 * the time the connection is established. For UDP flows, we copy 310 * over the values from one direction to another if we find the 311 * values for the other direction not set, which would be due to one 312 * of the following. 313 * a. We might not have seen a packet in the opposite direction 314 * b. There were no explicitly configured priority/DSCP for the opposite 315 * direction. 316 * 317 */ 318 if (sender == ECM_TRACKER_SENDER_TYPE_SRC) { 319 /* 320 * Record latest flow 321 */ 322 flow_qos_tag = skb->priority; 323 dscpcte->flow_priority = flow_qos_tag; 324 flow_dscp = ip_hdr->ds >> XT_DSCP_SHIFT; /* NOTE: XT_DSCP_SHIFT is okay for V4 and V6 */ 325 dscpcte->flow_dscp = flow_dscp; 326 327 /* 328 * Get the other side ready to return our PR 329 */ 330 if (protocol == IPPROTO_TCP) { 331 return_qos_tag = dscpcte->reply_priority; 332 return_dscp = dscpcte->reply_dscp; 333 } else { 334 /* 335 * Copy over the flow direction QoS 336 * and DSCP if the reply direction 337 * values are not set. 338 */ 339 if (dscpcte->reply_priority == 0) { 340 return_qos_tag = flow_qos_tag; 341 } else { 342 return_qos_tag = dscpcte->reply_priority; 343 } 344 345 if (dscpcte->reply_dscp == 0) { 346 return_dscp = flow_dscp; 347 } else { 348 return_dscp = dscpcte->reply_dscp; 349 } 350 } 351 DEBUG_TRACE("Flow DSCP: %x Flow priority: %d, Return DSCP: %x Return priority: %d\n", 352 dscpcte->flow_dscp, dscpcte->flow_priority, return_dscp, return_qos_tag); 353 } else { 354 /* 355 * Record latest return 356 */ 357 return_qos_tag = skb->priority; 358 dscpcte->reply_priority = return_qos_tag; 359 return_dscp = ip_hdr->ds >> XT_DSCP_SHIFT; /* NOTE: XT_DSCP_SHIFT is okay for V4 and V6 */ 360 dscpcte->reply_dscp = return_dscp; 361 362 /* 363 * Get the other side ready to return our PR 364 */ 365 if (protocol == IPPROTO_TCP) { 366 flow_qos_tag = dscpcte->flow_priority; 367 flow_dscp = dscpcte->flow_dscp; 368 } else { 369 /* 370 * Copy over the return direction QoS 371 * and DSCP if the flow direction 372 * values are not set. 373 */ 374 if (dscpcte->flow_priority == 0) { 375 flow_qos_tag = return_qos_tag; 376 } else { 377 flow_qos_tag = dscpcte->flow_priority; 378 } 379 380 if (dscpcte->flow_dscp == 0) { 381 flow_dscp = return_dscp; 382 } else { 383 flow_dscp = dscpcte->flow_dscp; 384 } 385 } 386 DEBUG_TRACE("Return DSCP: %x Return priority: %d, Flow DSCP: %x Flow priority: %d\n", 387 dscpcte->reply_dscp, dscpcte->reply_priority, flow_dscp, flow_qos_tag); 388 } 389 spin_unlock_bh(&ct->lock); 390 391 /* 392 * We are relevant to the connection 393 */ 394 became_relevant = ecm_db_time_get(); 395 396 spin_lock_bh(&ecm_classifier_dscp_lock); 397 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES; 398 cdscpi->process_response.became_relevant = became_relevant; 399 400 cdscpi->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_QOS_TAG; 401 cdscpi->process_response.flow_qos_tag = flow_qos_tag; 402 cdscpi->process_response.return_qos_tag = return_qos_tag; 403 404 /* 405 * Check if we need to set DSCP 406 */ 407 if (dscp_marked) { 408 cdscpi->process_response.flow_dscp = flow_dscp; 409 cdscpi->process_response.return_dscp = return_dscp; 410 cdscpi->process_response.process_actions |= ECM_CLASSIFIER_PROCESS_ACTION_DSCP; 411 } 412 413dscp_classifier_out: 414 415 /* 416 * Return our process response 417 */ 418 *process_response = cdscpi->process_response; 419 spin_unlock_bh(&ecm_classifier_dscp_lock); 420} 421 422/* 423 * ecm_classifier_dscp_sync_to_v4() 424 * Front end is pushing accel engine state to us 425 */ 426static void ecm_classifier_dscp_sync_to_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync) 427{ 428 struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused)); 429 430 cdscpi = (struct ecm_classifier_dscp_instance *)aci; 431 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi); 432} 433 434/* 435 * ecm_classifier_dscp_sync_from_v4() 436 * Front end is retrieving accel engine state from us 437 */ 438static void ecm_classifier_dscp_sync_from_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc) 439{ 440 struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused)); 441 442 cdscpi = (struct ecm_classifier_dscp_instance *)aci; 443 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi); 444} 445 446/* 447 * ecm_classifier_dscp_sync_to_v6() 448 * Front end is pushing accel engine state to us 449 */ 450static void ecm_classifier_dscp_sync_to_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync) 451{ 452 struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused)); 453 454 cdscpi = (struct ecm_classifier_dscp_instance *)aci; 455 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi); 456} 457 458/* 459 * ecm_classifier_dscp_sync_from_v6() 460 * Front end is retrieving accel engine state from us 461 */ 462static void ecm_classifier_dscp_sync_from_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc) 463{ 464 struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused)); 465 466 cdscpi = (struct ecm_classifier_dscp_instance *)aci; 467 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi); 468} 469 470/* 471 * ecm_classifier_dscp_type_get() 472 * Get type of classifier this is 473 */ 474static ecm_classifier_type_t ecm_classifier_dscp_type_get(struct ecm_classifier_instance *ci) 475{ 476 struct ecm_classifier_dscp_instance *cdscpi; 477 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 478 479 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 480 return ECM_CLASSIFIER_TYPE_DSCP; 481} 482 483/* 484 * ecm_classifier_dscp_last_process_response_get() 485 * Get result code returned by the last process call 486 */ 487static void ecm_classifier_dscp_last_process_response_get(struct ecm_classifier_instance *ci, 488 struct ecm_classifier_process_response *process_response) 489{ 490 struct ecm_classifier_dscp_instance *cdscpi; 491 492 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 493 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 494 495 spin_lock_bh(&ecm_classifier_dscp_lock); 496 *process_response = cdscpi->process_response; 497 spin_unlock_bh(&ecm_classifier_dscp_lock); 498} 499 500/* 501 * ecm_classifier_dscp_reclassify_allowed() 502 * Indicate if reclassify is allowed 503 */ 504static bool ecm_classifier_dscp_reclassify_allowed(struct ecm_classifier_instance *ci) 505{ 506 struct ecm_classifier_dscp_instance *cdscpi; 507 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 508 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 509 510 return true; 511} 512 513/* 514 * ecm_classifier_dscp_reclassify() 515 * Reclassify 516 */ 517static void ecm_classifier_dscp_reclassify(struct ecm_classifier_instance *ci) 518{ 519 struct ecm_classifier_dscp_instance *cdscpi; 520 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 521 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi); 522 523 /* 524 * Revert back to MAYBE relevant - we will evaluate when we get the next process() call. 525 */ 526 spin_lock_bh(&ecm_classifier_dscp_lock); 527 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_MAYBE; 528 spin_unlock_bh(&ecm_classifier_dscp_lock); 529} 530 531#ifdef ECM_STATE_OUTPUT_ENABLE 532/* 533 * ecm_classifier_dscp_state_get() 534 * Return state 535 */ 536static int ecm_classifier_dscp_state_get(struct ecm_classifier_instance *ci, struct ecm_state_file_instance *sfi) 537{ 538 int result; 539 struct ecm_classifier_dscp_instance *cdscpi; 540 struct ecm_classifier_process_response process_response; 541 542 cdscpi = (struct ecm_classifier_dscp_instance *)ci; 543 DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi); 544 545 if ((result = ecm_state_prefix_add(sfi, "dscp"))) { 546 return result; 547 } 548 549 spin_lock_bh(&ecm_classifier_dscp_lock); 550 process_response = cdscpi->process_response; 551 spin_unlock_bh(&ecm_classifier_dscp_lock); 552 553 /* 554 * Output our last process response 555 */ 556 if ((result = ecm_classifier_process_response_state_get(sfi, &process_response))) { 557 return result; 558 } 559 560 return ecm_state_prefix_remove(sfi); 561} 562#endif 563 564/* 565 * ecm_classifier_dscp_instance_alloc() 566 * Allocate an instance of the DSCP classifier 567 */ 568struct ecm_classifier_dscp_instance *ecm_classifier_dscp_instance_alloc(struct ecm_db_connection_instance *ci) 569{ 570 struct ecm_classifier_dscp_instance *cdscpi; 571 572 /* 573 * Allocate the instance 574 */ 575 cdscpi = (struct ecm_classifier_dscp_instance *)kzalloc(sizeof(struct ecm_classifier_dscp_instance), GFP_ATOMIC | __GFP_NOWARN); 576 if (!cdscpi) { 577 DEBUG_WARN("Failed to allocate DSCP instance\n"); 578 return NULL; 579 } 580 581 DEBUG_SET_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC); 582 cdscpi->refs = 1; 583 cdscpi->base.process = ecm_classifier_dscp_process; 584 cdscpi->base.sync_from_v4 = ecm_classifier_dscp_sync_from_v4; 585 cdscpi->base.sync_to_v4 = ecm_classifier_dscp_sync_to_v4; 586 cdscpi->base.sync_from_v6 = ecm_classifier_dscp_sync_from_v6; 587 cdscpi->base.sync_to_v6 = ecm_classifier_dscp_sync_to_v6; 588 cdscpi->base.type_get = ecm_classifier_dscp_type_get; 589 cdscpi->base.last_process_response_get = ecm_classifier_dscp_last_process_response_get; 590 cdscpi->base.reclassify_allowed = ecm_classifier_dscp_reclassify_allowed; 591 cdscpi->base.reclassify = ecm_classifier_dscp_reclassify; 592#ifdef ECM_STATE_OUTPUT_ENABLE 593 cdscpi->base.state_get = ecm_classifier_dscp_state_get; 594#endif 595 cdscpi->base.ref = ecm_classifier_dscp_ref; 596 cdscpi->base.deref = ecm_classifier_dscp_deref; 597 cdscpi->ci_serial = ecm_db_connection_serial_get(ci); 598 cdscpi->process_response.process_actions = 0; 599 cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_MAYBE; 600 601 spin_lock_bh(&ecm_classifier_dscp_lock); 602 603 /* 604 * Final check if we are pending termination 605 */ 606 if (ecm_classifier_dscp_terminate_pending) { 607 spin_unlock_bh(&ecm_classifier_dscp_lock); 608 DEBUG_INFO("%p: Terminating\n", ci); 609 kfree(cdscpi); 610 return NULL; 611 } 612 613 /* 614 * Link the new instance into our list at the head 615 */ 616 cdscpi->next = ecm_classifier_dscp_instances; 617 if (ecm_classifier_dscp_instances) { 618 ecm_classifier_dscp_instances->prev = cdscpi; 619 } 620 ecm_classifier_dscp_instances = cdscpi; 621 622 /* 623 * Increment stats 624 */ 625 ecm_classifier_dscp_count++; 626 DEBUG_ASSERT(ecm_classifier_dscp_count > 0, "%p: ecm_classifier_dscp_count wrap\n", cdscpi); 627 spin_unlock_bh(&ecm_classifier_dscp_lock); 628 629 DEBUG_INFO("DSCP instance alloc: %p\n", cdscpi); 630 return cdscpi; 631} 632EXPORT_SYMBOL(ecm_classifier_dscp_instance_alloc); 633 634/* 635 * ecm_classifier_dscp_init() 636 */ 637int ecm_classifier_dscp_init(struct dentry *dentry) 638{ 639 DEBUG_INFO("DSCP classifier Module init\n"); 640 641 ecm_classifier_dscp_dentry = debugfs_create_dir("ecm_classifier_dscp", dentry); 642 if (!ecm_classifier_dscp_dentry) { 643 DEBUG_ERROR("Failed to create ecm dscp directory in debugfs\n"); 644 return -1; 645 } 646 647 if (!debugfs_create_bool("enabled", S_IRUGO | S_IWUSR, ecm_classifier_dscp_dentry, 648 (u32 *)&ecm_classifier_dscp_enabled)) { 649 DEBUG_ERROR("Failed to create dscp enabled file in debugfs\n"); 650 debugfs_remove_recursive(ecm_classifier_dscp_dentry); 651 return -1; 652 } 653 654 return 0; 655} 656EXPORT_SYMBOL(ecm_classifier_dscp_init); 657 658/* 659 * ecm_classifier_dscp_exit() 660 */ 661void ecm_classifier_dscp_exit(void) 662{ 663 DEBUG_INFO("DSCP classifier Module exit\n"); 664 665 spin_lock_bh(&ecm_classifier_dscp_lock); 666 ecm_classifier_dscp_terminate_pending = true; 667 spin_unlock_bh(&ecm_classifier_dscp_lock); 668 669 /* 670 * Remove the debugfs files recursively. 671 */ 672 if (ecm_classifier_dscp_dentry) { 673 debugfs_remove_recursive(ecm_classifier_dscp_dentry); 674 } 675} 676EXPORT_SYMBOL(ecm_classifier_dscp_exit); 677