Files
Kernel/net/core/blog_rule.c

431 lines
13 KiB
C

/*
* <:copyright-BRCM:2010:DUAL/GPL:standard
*
* Copyright (c) 2010 Broadcom Corporation
* 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 <linux/slab.h>
#include <linux/blog.h>
#include <linux/if_ether.h>
#include <linux/if_pppox.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <net/ip.h>
#include <linux/blog_rule.h>
/*
*------------------------------------------------------------------------------
* 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;
#if (defined(CONFIG_BCM_ARL) || defined(CONFIG_BCM_ARL_MODULE))
blogArlHook_t bcm_arl_process_hook_g = NULL;
#endif
#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_MAX)
};
static void __printEthAddr(char *name, char *addr)
{
int i;
printk("%s : ", name);
for(i=0; i<ETH_ALEN; ++i)
{
printk("%02X", addr[i]);
if(i != ETH_ALEN-1) printk(":");
}
printk("\n");
}
/*
*------------------------------------------------------------------------------
* Public API
*------------------------------------------------------------------------------
*/
/*
*------------------------------------------------------------------------------
* Function : blog_rule_alloc
* Description : Allocates a Blog Rule from the Blog Rule cache. Once the Blog
* Rule is not needed, it must be freed back to the Blog Rule
* cache via blog_rule_free().
*------------------------------------------------------------------------------
*/
blogRule_t *blog_rule_alloc(void)
{
return kmem_cache_alloc(blogRuleCtrl.kmemCache, GFP_ATOMIC);
}
/*
*------------------------------------------------------------------------------
* Function : blog_rule_free
* Description : Frees a Blog Rule previously allocated via blog_rule_alloc().
*------------------------------------------------------------------------------
*/
void blog_rule_free(blogRule_t *blogRule_p)
{
kmem_cache_free(blogRuleCtrl.kmemCache, blogRule_p);
}
/*
*------------------------------------------------------------------------------
* Function : blog_rule_free_list
* Description : Frees all Blog Rules linked to a Blog.
*------------------------------------------------------------------------------
*/
int blog_rule_free_list(Blog_t *blog_p)
{
blogRule_t *blogRule_p;
blogRule_t *nextBlogRule_p;
int blogRuleCount;
blogRule_p = (blogRule_t *)blog_p->blogRule_p;
blogRuleCount = 0;
while(blogRule_p != NULL)
{
nextBlogRule_p = blogRule_p->next_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_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 <0x%08X>, next <0x%08X>\n",
(unsigned int)blogRule_p, (unsigned int)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; i<filter_p->nbrOfVlanTags; ++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);
}
}
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; i<blogRule_p->actionCount; ++i)
{
action_p = &blogRule_p->action[i];
if(action_p->cmd == BLOG_RULE_CMD_SET_MAC_SA)
{
printk("\t");
__printEthAddr(blogRuleCommandName[action_p->cmd],
action_p->macAddr);
}
else
{
printk("\t%s : arg <%d>, tag <%d>\n",
blogRuleCommandName[action_p->cmd],
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 <0x%08X>\n",
(unsigned int)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);
#if (defined(CONFIG_BCM_ARL) || defined(CONFIG_BCM_ARL_MODULE))
EXPORT_SYMBOL(bcm_arl_process_hook_g);
#endif