#if defined(CONFIG_BLOG) /* * <:copyright-BRCM:2010:DUAL/GPL:standard * * Copyright (c) 2010 Broadcom * All Rights Reserved * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed * to you under the terms of the GNU General Public License version 2 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, * with the following added to such license: * * As a special exception, the copyright holders of this software give * you permission to link this software with independent modules, and * to copy and distribute the resulting executable under terms of your * choice, provided that you also meet, for each linked independent * module, the terms and conditions of the license of that module. * An independent module is a module which is not derived from this * software. The special exception does not apply to any modifications * of the software. * * Not withstanding the above, under no circumstances may you combine * this software in any way with any other Broadcom software provided * under a license other than the GPL, without Broadcom's express prior * written consent. * :> */ /* ******************************************************************************* * * File Name : blog_rule.c * * Description: Implements packet modification rules that can be associated to * a Blog. * ******************************************************************************* */ #include #include #include #include #include #include #include #include #include /* *------------------------------------------------------------------------------ * Private functions, macros and global variables. *------------------------------------------------------------------------------ */ #if defined(CC_CONFIG_BLOG_RULE_DEBUG) #define blog_rule_assertv(cond) \ if ( !(cond) ) { \ printk( "BLOG RULE ASSERT %s : " #cond, __FUNCTION__ ); \ return; \ } #define blog_rule_assertr(cond, rtn) \ if ( !(cond) ) { \ printk( "BLOG RULE ASSERT %s : " #cond CLRN, __FUNCTION__ ); \ return rtn; \ } #else #define blog_rule_assertv(cond) #define blog_rule_assertr(cond, rtn) #endif typedef struct { struct kmem_cache *kmemCache; } blogRule_Ctrl_t; static blogRule_Ctrl_t blogRuleCtrl; /* External hooks */ blogRuleVlanHook_t blogRuleVlanHook = NULL; blogRuleVlanNotifyHook_t blogRuleVlanNotifyHook = NULL; #undef BLOG_RULE_DECL #define BLOG_RULE_DECL(x) #x static char *blogRuleCommandName[] = { BLOG_RULE_DECL(BLOG_RULE_CMD_NOP), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_MAC_DA), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_MAC_SA), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_ETHERTYPE), BLOG_RULE_DECL(BLOG_RULE_CMD_PUSH_VLAN_HDR), BLOG_RULE_DECL(BLOG_RULE_CMD_POP_VLAN_HDR), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_PBITS), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_DEI), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_VID), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_VLAN_PROTO), BLOG_RULE_DECL(BLOG_RULE_CMD_COPY_PBITS), BLOG_RULE_DECL(BLOG_RULE_CMD_COPY_DEI), BLOG_RULE_DECL(BLOG_RULE_CMD_COPY_VID), BLOG_RULE_DECL(BLOG_RULE_CMD_COPY_VLAN_PROTO), // BLOG_RULE_DECL(BLOG_RULE_CMD_XLATE_DSCP_TO_PBITS), BLOG_RULE_DECL(BLOG_RULE_CMD_POP_PPPOE_HDR), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_DSCP), BLOG_RULE_DECL(BLOG_RULE_CMD_DECR_TTL), BLOG_RULE_DECL(BLOG_RULE_CMD_DECR_HOP_LIMIT), BLOG_RULE_DECL(BLOG_RULE_CMD_DROP), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_SKB_MARK_PORT), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_SKB_MARK_QUEUE), BLOG_RULE_DECL(BLOG_RULE_CMD_OVRD_LEARNING_VID), BLOG_RULE_DECL(BLOG_RULE_CMD_SET_STA_MAC_ADDRESS), BLOG_RULE_DECL(BLOG_RULE_CMD_MAX) }; static void __printEthAddr(char *name, char *addr) { int i; printk("%s : ", name); for(i=0; inext_p; blog_rule_free(blogRule_p); blogRule_p = nextBlogRule_p; blogRuleCount++; } return blogRuleCount; } /* *------------------------------------------------------------------------------ * Function : blog_rule_init * Description : Initializes a Blog Rule with no filters and no modifications. *------------------------------------------------------------------------------ */ void blog_rule_init(blogRule_t *blogRule_p) { blog_rule_assertv(blogRule_p != NULL); memset(blogRule_p, 0, sizeof(blogRule_t)); } /* *------------------------------------------------------------------------------ * Function : blog_rule_hw_formatted_dump * Description : Dump the contents of a blogRule object specific to the hw_accel. * blogRule_p : Pointer to the blogRule_t object *------------------------------------------------------------------------------ */ void blog_rule_hw_formatted_dump(blogRule_t *blogRule_p) { int action_idx = 0; printk("filter={"); printk("nbr_of_vlan_tags=%d,", blogRule_p->filter.nbrOfVlanTags); printk("has_pppoe_header=%d,", blogRule_p->filter.hasPppoeHeader); printk("ipv4_tos_mask=%d,", blogRule_p->filter.ipv4.mask.tos); printk("ipv4_ip_proto_mask=%d,", blogRule_p->filter.ipv4.mask.ip_proto); printk("ipv4_tos_value=%d,", blogRule_p->filter.ipv4.value.tos); printk("ipv4_ip_proto_value=%d,", blogRule_p->filter.ipv4.value.ip_proto); printk("ipv6_tclass_mask=%d,", blogRule_p->filter.ipv6.mask.tclass); printk("ipv6_next_hdr_mask=%d,", blogRule_p->filter.ipv6.mask.nxtHdr); printk("ipv6_tclass_value=%d,", blogRule_p->filter.ipv6.value.tclass); printk("ipv6_next_hdr_value=%d,", blogRule_p->filter.ipv6.value.nxtHdr); printk("skb_priority=%d,", blogRule_p->filter.skb.priority); printk("skb_mark_flow_id=%d,", blogRule_p->filter.skb.markFlowId); printk("skb_mark_port=%d,", blogRule_p->filter.skb.markPort); printk("flags=%d},", blogRule_p->filter.flags); printk("action_count=%d", blogRule_p->actionCount); if (action_idx < blogRule_p->actionCount) { printk(",action="); while(action_idx < blogRule_p->actionCount) { printk("%02X", blogRule_p->action[action_idx].cmd); printk("%02X", blogRule_p->action[action_idx].toTag); switch(blogRule_p->action[action_idx].cmd) { case BLOG_RULE_CMD_NOP: case BLOG_RULE_CMD_DROP: case BLOG_RULE_CMD_DECR_HOP_LIMIT: case BLOG_RULE_CMD_PUSH_VLAN_HDR: case BLOG_RULE_CMD_POP_VLAN_HDR: case BLOG_RULE_CMD_POP_PPPOE_HDR: case BLOG_RULE_CMD_DECR_TTL: break; case BLOG_RULE_CMD_SET_MAC_DA: case BLOG_RULE_CMD_SET_MAC_SA: case BLOG_RULE_CMD_SET_STA_MAC_ADDRESS: printk("%pm", blogRule_p->action[action_idx].macAddr); break; case BLOG_RULE_CMD_SET_VID: case BLOG_RULE_CMD_COPY_VID: case BLOG_RULE_CMD_SET_ETHERTYPE: case BLOG_RULE_CMD_SET_PBITS: case BLOG_RULE_CMD_SET_DEI: case BLOG_RULE_CMD_SET_VLAN_PROTO: case BLOG_RULE_CMD_SET_DSCP: case BLOG_RULE_CMD_COPY_PBITS: case BLOG_RULE_CMD_COPY_DEI: case BLOG_RULE_CMD_COPY_VLAN_PROTO: case BLOG_RULE_CMD_SET_SKB_MARK_QUEUE: printk("%04X", blogRule_p->action[action_idx].arg); break; } ++action_idx; } } } /* *------------------------------------------------------------------------------ * Function : blog_rule_list_hw_formatted_dump * Description : Dump the contents of a linked list of blogRule objects specific to the hw_accel. * rule_p : void Pointer to the blogRule_t object *------------------------------------------------------------------------------ */ void blog_rule_list_hw_formatted_dump(void *rule_p) { blogRule_t *blogRule_p = (blogRule_t*) rule_p; int count = 0; while (blogRule_p) { if (count++ > 0) printk(","); printk("blog_rule={"); blog_rule_hw_formatted_dump(blogRule_p); printk("}"); blogRule_p = blogRule_p->next_p; } } /* *------------------------------------------------------------------------------ * Function : blog_rule_dump * Description : Prints the contents of a Blog Rule. *------------------------------------------------------------------------------ */ void blog_rule_dump(blogRule_t *blogRule_p) { int i; blogRuleFilter_t *filter_p; blogRuleFilterVlan_t *vlanFilter_p; blogRuleAction_t *action_p; blog_rule_assertv(blogRule_p != NULL); printk("Blog Rule <%px>, next <%px>\n", blogRule_p, blogRule_p->next_p); filter_p = &blogRule_p->filter; if(filter_p->flags) { printk("Flags: "); if(filter_p->flags & BLOG_RULE_FILTER_FLAGS_IS_UNICAST) { printk("IS_UNICAST "); } if(filter_p->flags & BLOG_RULE_FILTER_FLAGS_IS_MULTICAST) { printk("IS_MULTICAST "); } if(filter_p->flags & BLOG_RULE_FILTER_FLAGS_IS_BROADCAST) { printk("IS_BROADCAST "); } printk("\n"); } printk("Ethernet Filters:\n"); if(blog_rule_filterInUse(filter_p->eth.mask.h_dest)) { __printEthAddr("\tDA", filter_p->eth.value.h_dest); } if(blog_rule_filterInUse(filter_p->eth.mask.h_source)) { __printEthAddr("\tSA", filter_p->eth.value.h_source); } if(blog_rule_filterInUse(filter_p->eth.mask.h_proto)) { printk("\tEthertype : 0x%04X\n", filter_p->eth.value.h_proto); } printk("PPPoE Header: %s\n", filter_p->hasPppoeHeader ? "Yes" : "No"); printk("VLAN Filters:\n"); printk("\tNumber of Tags : <%d>\n", filter_p->nbrOfVlanTags); for(i=0; inbrOfVlanTags; ++i) { vlanFilter_p = &filter_p->vlan[i]; if(vlanFilter_p->mask.h_vlan_TCI & BLOG_RULE_PBITS_MASK) { printk("\tPBITS : <%d>, tag <%d>\n", BLOG_RULE_GET_TCI_PBITS(vlanFilter_p->value.h_vlan_TCI), i); } if(vlanFilter_p->mask.h_vlan_TCI & BLOG_RULE_DEI_MASK) { printk("\tDEI : <%d>, tag <%d>\n", BLOG_RULE_GET_TCI_DEI(vlanFilter_p->value.h_vlan_TCI), i); } if(vlanFilter_p->mask.h_vlan_TCI & BLOG_RULE_VID_MASK) { printk("\tVID : <%d>, tag <%d>\n", BLOG_RULE_GET_TCI_VID(vlanFilter_p->value.h_vlan_TCI), i); } if(vlanFilter_p->mask.h_vlan_encapsulated_proto) { printk(" etherType : <%04x>, tag <%d>\n", vlanFilter_p->value.h_vlan_encapsulated_proto, i); } } printk("IPv4 Filters:\n"); if(blog_rule_filterInUse(filter_p->ipv4.mask.tos)) { printk("\tTOS : 0x%04X -> DSCP <%d>\n", filter_p->ipv4.value.tos, filter_p->ipv4.value.tos >> BLOG_RULE_DSCP_IN_TOS_SHIFT); } if(blog_rule_filterInUse(filter_p->ipv4.mask.ip_proto)) { printk("\tIP-PROTO : %d \n", filter_p->ipv4.value.ip_proto); } printk("SKB Filters:\n"); if(blog_rule_filterInUse(filter_p->skb.priority)) { printk("\tpriority : %d\n", filter_p->skb.priority - 1); } if(blog_rule_filterInUse(filter_p->skb.markFlowId)) { printk("\tmark->flowId : %d\n", filter_p->skb.markFlowId); } if(blog_rule_filterInUse(filter_p->skb.markPort)) { printk("\tmark->port : %d\n", filter_p->skb.markPort - 1); } printk("Actions:\n"); for(i=0; iactionCount; ++i) { action_p = &blogRule_p->action[i]; if(action_p->cmd == BLOG_RULE_CMD_SET_MAC_DA || action_p->cmd == BLOG_RULE_CMD_SET_MAC_SA || action_p->cmd == BLOG_RULE_CMD_SET_STA_MAC_ADDRESS) { printk("\t"); __printEthAddr(blogRuleCommandName[action_p->cmd], action_p->macAddr); } else { printk("\t%s : arg <%d>/<0x%02X>, tag <%d>\n", blogRuleCommandName[action_p->cmd], action_p->arg, action_p->arg, action_p->toTag); } } } /* *------------------------------------------------------------------------------ * Function : blog_rule_add_action * Description : Adds an action to a Blog Rule. *------------------------------------------------------------------------------ */ int blog_rule_add_action(blogRule_t *blogRule_p, blogRuleAction_t *action_p) { int ret = 0; if(blogRule_p->actionCount == BLOG_RULE_ACTION_MAX) { printk("ERROR : Maximum number of actions reached for blogRule_p <%px>\n", blogRule_p); ret = -ENOMEM; goto out; } blogRule_p->action[blogRule_p->actionCount] = *action_p; blogRule_p->actionCount++; out: return ret; } /* *------------------------------------------------------------------------------ * Function : blog_rule_delete_action * Description : Set actionCount of all blogRule chain to 0 for deleting action *------------------------------------------------------------------------------ */ int blog_rule_delete_action( void *rule_p ) { blogRule_t *blogrule_p = (blogRule_t *)rule_p; int ret = 0; while ( blogrule_p != NULL ) { blogrule_p->actionCount = 0; blogrule_p = blogrule_p->next_p; } return ret; } /* *------------------------------------------------------------------------------ * Function : __init_blog_rule * Description : Initializes the Blog Rule subsystem. *------------------------------------------------------------------------------ */ static int __init __init_blog_rule(void) { int ret = 0; /* create a slab cache for device descriptors */ blogRuleCtrl.kmemCache = kmem_cache_create("blog_rule", sizeof(blogRule_t), 0, /* align */ SLAB_HWCACHE_ALIGN, /* flags */ NULL); /* ctor */ if(blogRuleCtrl.kmemCache == NULL) { printk("ERROR : Unable to create Blog Rule cache\n"); ret = -ENOMEM; goto out; } printk("BLOG Rule %s Initialized\n", BLOG_RULE_VERSION); out: return ret; } /* /\* */ /* *------------------------------------------------------------------------------ */ /* * Function : __exit_blog_rule */ /* * Description : Brings down the Blog Rule subsystem. */ /* *------------------------------------------------------------------------------ */ /* *\/ */ /* void __exit __exit_blog_rule(void) */ /* { */ /* kmem_cache_destroy(blogRuleCtrl.kmemCache); */ /* } */ subsys_initcall(__init_blog_rule); EXPORT_SYMBOL(blog_rule_alloc); EXPORT_SYMBOL(blog_rule_free); EXPORT_SYMBOL(blog_rule_free_list); EXPORT_SYMBOL(blog_rule_init); EXPORT_SYMBOL(blog_rule_dump); EXPORT_SYMBOL(blog_rule_add_action); EXPORT_SYMBOL(blog_rule_delete_action); EXPORT_SYMBOL(blogRuleVlanHook); EXPORT_SYMBOL(blogRuleVlanNotifyHook); #endif /* defined(CONFIG_BLOG) */