blob: 7995737fd710e0d65568c15018a3ed9a92429708 [file] [log] [blame]
/*
* Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fal_nat.h"
#include "fal_ip.h"
#include "hsl_api.h"
#include "sw.h"
#include "hsl.h"
#include "hsl_dev.h"
#include "hsl_port_prop.h"
#include "dess_igmp.h"
#include "dess_reg.h"
#include "dess_acl.h"
#include "fal_multi.h"
#include "sal/os/aos_lock.h"
#if 0
/**
* I/F prototype for complete igmpv3 & mldv2 support
*/
/*supports 32 entries*/
#define FAL_IGMP_SG_ENTRY_MAX 32
typedef enum
{
FAL_ADDR_IPV4 = 0,
FAL_ADDR_IPV6
} fal_addr_type_t;
typedef struct
{
fal_addr_type_t type;
union
{
fal_ip4_addr_t ip4_addr;
fal_ip6_addr_t ip6_addr;
} u;
} fal_igmp_sg_addr_t;
typedef struct
{
fal_igmp_sg_addr_t source;
fal_igmp_sg_addr_t group;
fal_pbmp_t port_map;
} fal_igmp_sg_entry_t;
/**
* @brief set PortMap of IGMP sg entry.
* search entry according to source/group address,
* update PortMap if SG entry is found, otherwise create a new sg entry.
* @param[in] dev_id device id
* @param[in-out] entry SG entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
dess_igmp_sg_entry_set(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry);
/**
* @brief clear PortMap of IGMP sg entry.
* search entry according to source/group address,
* update PortMap if SG entry is found, delete the entry in case PortMap was 0.
* SW_NOT_FOUND will be returned in case search failed.
* @param[in] dev_id device id
* @param[in-out] entry SG entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
dess_igmp_sg_entry_clear(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry);
#define MULTI_DEBUG_
#ifdef MULTI_DEBUG_
#define MULTI_DEBUG(x...) aos_printk(x)
#else
#define MULTI_DEBUG(x...)
#endif
#define FAL_ACL_LIST_MULTICAST 55
#define FAL_MULTICAST_PRI 5
#define MULT_ACTION_SET 1
#define MULT_ACTION_CLEAR 1
static a_uint32_t rule_nr=1;
typedef struct
{
a_uint8_t index; //MAX is 32
fal_igmp_sg_entry_t entry; //Stores the specific ACL rule info
} multi_acl_info_t;
#endif
static a_uint32_t mul_rule_nr=1;
void
dess_multicast_init(a_uint32_t dev_id);
HSL_LOCAL sw_error_t multi_portmap_aclreg_set(a_uint32_t pos, fal_igmp_sg_entry_t * entry);
static multi_acl_info_t multi_acl_info[FAL_IGMP_SG_ENTRY_MAX];
static multi_acl_info_t multi_acl_group[FAL_IGMP_SG_ENTRY_MAX];
static int ip6_addr_is_null(fal_ip6_addr_t *ip6)
{
if (NULL == ip6)
{
aos_printk("Invalid ip6 address\n");
return -1;
}
if(0 == ip6->ul[0] && 0 == ip6->ul[1] && 0 == ip6->ul[2] && 0 == ip6->ul[3])
return 1;
else
return 0;
}
static int multi_source_is_null(fal_igmp_sg_addr_t *s)
{
if (NULL == s)
{
aos_printk("Invalid source address\n");
return -1;
}
if(0 == s->type && 0==s->u.ip4_addr)
return 1;
if(1 == s->type && 1 == ip6_addr_is_null(&(s->u.ip6_addr)))
return 1;
return 0;
}
HSL_LOCAL int iterate_multicast_acl_rule(int list_id, int start_n)
{
a_uint32_t dev_id=0;
a_uint32_t rule_id;
sw_error_t ret;
fal_acl_rule_t rule= {0};
if(start_n>=FAL_IGMP_SG_ENTRY_MAX || start_n < 0)
{
return -1;
}
for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++)
{
ret = dess_acl_rule_query(dev_id, list_id, rule_id, &rule);
if (ret==SW_NOT_FOUND )
break;//NOT found in ACL rule
if((rule_id+start_n)>=FAL_IGMP_SG_ENTRY_MAX)
{
return -1;
}
multi_acl_info[rule_id+start_n].index = rule_id; // consider here... index is NOT related start_n
//MULTI_DEBUG("normal query1: rule dest_ip4_val=%x, src ip4=%x, dst_ip6=%x, ports=%x\n",
//rule.dest_ip4_val, rule.src_ip4_val, rule.dest_ip6_val.ul[0], rule.ports);
if(rule.dest_ip4_val !=0 && ip6_addr_is_null(&rule.dest_ip6_val)) //only ip4
{
multi_acl_info[rule_id+start_n].entry.group.type = FAL_ADDR_IPV4;
multi_acl_info[rule_id+start_n].entry.source.type = FAL_ADDR_IPV4;
multi_acl_info[rule_id+start_n].entry.group.u.ip4_addr = rule.dest_ip4_val;
multi_acl_info[rule_id+start_n].entry.source.u.ip4_addr = rule.src_ip4_val;
multi_acl_info[rule_id+start_n].entry.port_map= rule.ports;
}
else if(rule.dest_ip4_val ==0 && !ip6_addr_is_null(&rule.dest_ip6_val)) //only ip6
{
multi_acl_info[rule_id+start_n].entry.group.type = FAL_ADDR_IPV6;
multi_acl_info[rule_id+start_n].entry.source.type = FAL_ADDR_IPV6;
memcpy(&(multi_acl_info[rule_id+start_n].entry.group.u.ip6_addr), &(rule.dest_ip6_val), sizeof(rule.dest_ip6_val));
memcpy(&(multi_acl_info[rule_id+start_n].entry.source.u.ip6_addr), &(rule.src_ip6_val), sizeof(rule.src_ip6_val));
multi_acl_info[rule_id+start_n].entry.port_map= rule.ports;
}
if (FAL_FIELD_FLG_TST(rule.field_flg, FAL_ACL_FIELD_MAC_VID))
{
multi_acl_info[rule_id+start_n].entry.vlan_id = rule.vid_val;
}
else
{
multi_acl_info[rule_id+start_n].entry.vlan_id = 0xffff;
}
}
return rule_id+start_n;
}
/*
** Iterate the total 32 multicast ACL entries.
After the function completes:
1. Stores all multicast related ACL rules in multi_acl_info[32]
2. return the number of multicast related ACL rules
*/
HSL_LOCAL a_uint32_t dess_multicast_acl_query(void)
{
int start_n;
int total_n;
//a_uint32_t i;
start_n = iterate_multicast_acl_rule(FAL_ACL_LIST_MULTICAST, 0);
if(-1 == start_n)
aos_printk("ACL rule1 is FULL\n");
total_n = iterate_multicast_acl_rule(FAL_ACL_LIST_MULTICAST+1, start_n);
if(-1 == total_n)
aos_printk("ACL rule2 is FULL\n");
MULTI_DEBUG("KKK, the total ACL rule number is %d, (G,S) number=%d\n", total_n, start_n);
/*
for(i=0;i<total_n;i++)
MULTI_DEBUG("KKK, indx=%d, multi_acl_info[%d].entry=[%d][%x]\n", multi_acl_info[i].index,i,
multi_acl_info[i].entry.group.type, multi_acl_info[i].entry.group.u.ip4_addr );
*/
return total_n;
}
HSL_LOCAL a_uint32_t dess_multicast_acl_total_n(a_uint32_t list_id)
{
a_uint32_t dev_id=0;
a_uint32_t ret;
a_uint32_t rule_id;
fal_acl_rule_t rule= {0};
for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++)
{
ret = dess_acl_rule_query(dev_id, list_id,
rule_id, &rule);
if(ret==SW_NOT_FOUND)
return rule_id;
}
return 0;
}
#define DESS_FILTER_ACT_ADDR 0x5a000
#define DESS_FILTER_MSK_ADDR 0x59000
HSL_LOCAL sw_error_t multi_portmap_aclreg_set_all(a_uint32_t pos, fal_igmp_sg_entry_t * entry)
{
a_uint32_t i, base, addr;
a_uint32_t dev_id=0;
a_uint32_t msk_valid=0;
sw_error_t rv = SW_OK;
/* 2'b00:start; 2'b01:continue; 2'b10:end; 2'b11:start&end*/
for(i=pos; i<pos+4; i++)
{
base = DESS_FILTER_MSK_ADDR +(i<<5);
addr = base+(4<<2); //fifth byte
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&msk_valid),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if ((((msk_valid>>6)&0x3) == 0x3) || (((msk_valid>>6)&0x3) == 0x2))
{
rv = multi_portmap_aclreg_set(i, entry);
break;
}
else if ((((msk_valid>>6)&0x3)) == 0x0 || (((msk_valid>>6)&0x3) == 0x1))
{
rv = multi_portmap_aclreg_set(i, entry);
continue;
}
else
{
aos_printk("The rule valid bit:6 7 is wrong!!!");
break;
}
}
return rv;
}
HSL_LOCAL sw_error_t multi_portmap_aclreg_set(a_uint32_t pos, fal_igmp_sg_entry_t * entry)
{
a_uint32_t i, base, addr;
a_uint32_t dev_id=0;
sw_error_t rv;
a_uint32_t act[3]= {0};
fal_pbmp_t pm;
pm = entry->port_map;
base = DESS_FILTER_ACT_ADDR + (pos << 4);
for (i = 0; i < 3; i++)
{
addr = base + (i << 2);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&act[i]),
sizeof (a_uint32_t));
//MULTI_DEBUG("2:Get register value 0x%x =%x\n", addr, act[i]);
SW_RTN_ON_ERROR(rv);
}
act[1] &= ~(0x7<<29); // clear the high 3 bits
act[1] |= (pm&0x7)<<29; //the low 3 bits of pm means redirect port 0,1,2
/* New modification: update acl ACTION register from DENY to redirect */
if (((act[2]>>6)&0x7) == 0x7) //DENY mode
{
if(pm)
{
act[2] &= ~(0x7<<6);//clear DENY bits
act[2] |= (0x1<<4); //DES_PORT_EN set 1, enable
}
}
else if (((act[2]>>4)&0x1) == 0x1) //redirect mode
{
if(pm==0)
{
act[2] &= ~(0x1<<4);//clear redirect bits
act[2] |= (0x7<<6); //set to DENY
}
}
act[2] &= ~0xf; //clear the low 4 bits of port 3,4,5,6
act[2] |= (pm>>3)&0xf;
addr = base + (1<<2);
HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&act[1]), sizeof (a_uint32_t));
addr = base + (2<<2);
HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&act[2]), sizeof (a_uint32_t));
MULTI_DEBUG("pos=%d, before sync portmap, the new act=%x %x\n", pos, act[1],act[2]);
if((rv = dess_acl_rule_sync_multi_portmap(dev_id, pos, act)) < 0)
aos_printk("Sync multicast portmap error\n");
return rv;
}
HSL_LOCAL int multi_get_dp(void)
{
a_uint32_t addr;
a_uint32_t dev_id=0;
sw_error_t rv;
int val=0;
addr = 0x624;//GLOBAL_FW_CTRL1
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&val),
sizeof (a_uint32_t));
if (rv != SW_OK)
aos_printk("Get entry value error\n");
val = (val>>24)&0x7f; //30:24, IGMP_JOIN_LEAVE_DP
return val;
}
static int old_bind_p=-1;
HSL_LOCAL int multi_acl_bind(void)
{
int bind_p;
int i;
bind_p = multi_get_dp();
if(bind_p == old_bind_p)
return 0;
old_bind_p = bind_p;
for(i=0; i<7; i++)
{
dess_acl_list_unbind(0, FAL_ACL_LIST_MULTICAST, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i);
dess_acl_list_unbind(0, FAL_ACL_LIST_MULTICAST+1, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i);
}
if(bind_p==0)
{
for(i=0; i<7; i++)
{
dess_acl_list_bind(0, FAL_ACL_LIST_MULTICAST, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i);
dess_acl_list_bind(0, FAL_ACL_LIST_MULTICAST+1, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i);
}
}
else
{
for(i=0; i<7; i++)
if((bind_p>>i) &0x1)
{
dess_acl_list_bind(0, FAL_ACL_LIST_MULTICAST, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i);
dess_acl_list_bind(0, FAL_ACL_LIST_MULTICAST+1, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i);
}
else
continue;
}
return 0;
}
/*
** Only update the related portmap from the privious input.
*/
HSL_LOCAL sw_error_t dess_multicast_acl_update( int list_id, int acl_index, fal_igmp_sg_entry_t * entry, int action)
{
a_uint32_t dev_id=0;
a_uint32_t rule_pos;
sw_error_t rv = SW_OK;
if(acl_index<0)
{
aos_printk("Something is wrong...\n");
return SW_FAIL;
}
rule_pos = dess_acl_rule_get_offset(dev_id, list_id, multi_acl_group[acl_index].index);
if(MULT_ACTION_SET == action)
{
multi_acl_group[acl_index].entry.port_map |= entry->port_map;
if(entry->port_map == 0)
{
multi_acl_group[acl_index].entry.port_map = 0;
}
}
else if(MULT_ACTION_CLEAR == action)
multi_acl_group[acl_index].entry.port_map &= ~(entry->port_map);
rv = multi_portmap_aclreg_set_all(rule_pos, &multi_acl_group[acl_index].entry);
multi_acl_bind(); //Here need extra bind since IGMP join/leave would happen
return rv;
}
HSL_LOCAL sw_error_t dess_multicast_acl_del(int list_id, int index)
{
sw_error_t rv;
int rule_id;
rule_id = multi_acl_group[index].index;
rv = dess_acl_rule_delete(0, list_id, rule_id, 1);
multi_acl_bind(); //Here need extra bind since IGMP join/leave would happen
return rv;
}
/*
** Add new acl rule with parameters: DIP, SIP, redirect port.
*/
HSL_LOCAL sw_error_t dess_multicast_acl_add(int list_id, fal_igmp_sg_entry_t * entry)
{
sw_error_t val;
a_uint32_t pos;
fal_acl_rule_t acl= {0};
/* IPv4 multicast */
if( entry->group.type == FAL_ADDR_IPV4 )
{
MULTI_DEBUG("KKK1, group[%d][%x], source[%d][%x]\n",entry->group.type,
entry->group.u.ip4_addr, entry->source.type, entry->source.u.ip4_addr);
acl.rule_type = FAL_ACL_RULE_IP4;
if(entry->group.u.ip4_addr!= 0)
{
acl.dest_ip4_val = entry->group.u.ip4_addr;
acl.dest_ip4_mask = 0xffffffff;//e->ip.dmsk.s_addr;
FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP4_DIP);
}
if(entry->source.u.ip4_addr!= 0)
{
acl.src_ip4_val = entry->source.u.ip4_addr;
acl.src_ip4_mask = 0xffffffff;//e->ip.smsk.s_addr;
FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP4_SIP);
}
if( entry->port_map==0 )
FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_DENY);
else
//FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_INVERSE_ALL);
FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_PERMIT );
/* Be careful, _dess_acl_action_parse() will block FAL_ACL_ACTION_DENY action, So we change it. */
if( entry->port_map )
{
FAL_ACTION_FLG_SET(acl.action_flg, FAL_ACL_ACTION_REDPT);
acl.ports = entry->port_map;
}
}
else if( entry->group.type == FAL_ADDR_IPV6 )
{
MULTI_DEBUG("KKK2, group[%d][%x], source[%d][%x], pm=%x\n",entry->group.type,
entry->group.u.ip6_addr.ul[0], entry->source.type, entry->source.u.ip6_addr.ul[0], entry->port_map);
acl.rule_type = FAL_ACL_RULE_IP6;
if(!ip6_addr_is_null(&(entry->group.u.ip6_addr)))
{
memcpy(&acl.dest_ip6_val, &(entry->group.u.ip6_addr), sizeof(entry->group.u.ip6_addr));
acl.dest_ip6_mask.ul[0] = 0xffffffff;
acl.dest_ip6_mask.ul[1] = 0xffffffff;
acl.dest_ip6_mask.ul[2] = 0xffffffff;
acl.dest_ip6_mask.ul[3] = 0xffffffff;
FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP6_DIP);
}
if(!ip6_addr_is_null(&(entry->source.u.ip6_addr)))
{
memcpy(&acl.src_ip6_val, &(entry->source.u.ip6_addr), sizeof(entry->source.u.ip6_addr));
acl.src_ip6_mask.ul[0] = 0xffffffff;
acl.src_ip6_mask.ul[1] = 0xffffffff;
acl.src_ip6_mask.ul[2] = 0xffffffff;
acl.src_ip6_mask.ul[3] = 0xffffffff;
FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP6_SIP);
}
if( entry->port_map==0 )
FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_DENY);
else
//FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_INVERSE_ALL);
FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_PERMIT );
/* Be careful, _dess_acl_action_parse() will block FAL_ACL_ACTION_DENY action, So we change it. */
if( entry->port_map )
{
FAL_ACTION_FLG_SET(acl.action_flg, FAL_ACL_ACTION_REDPT);
acl.ports = entry->port_map;
}
}
if (entry->vlan_id < 4096)
{
FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_MAC_VID);
acl.vid_val = entry->vlan_id;
acl.vid_op = FAL_ACL_FIELD_MASK;
acl.vid_mask = 0xfff;
}
pos = dess_multicast_acl_total_n(list_id);
MULTI_DEBUG("In dess_multicast_acl_add, list_id=%d, rule_id=%d\n", list_id, pos);
val = dess_acl_rule_add(0, list_id, pos, mul_rule_nr, &acl);
multi_acl_bind();
return val;
}
HSL_LOCAL int iterate_multicast_acl_group(a_uint32_t number, fal_igmp_sg_entry_t * entry)
{
int count=0;
int i;
if (number == 0)
return 0; //no any ACL rules based the query
for(i=0; i<number; i++)
{
/*MULTI_DEBUG("2:iterate_multicast_acl_group, index=%d, multi_acl_info[%d].entry=type[%d]-addr[%x], pm=%x, new entry=type[%d]-addr[%x], pm=%x\n",
multi_acl_info[i].index,i, multi_acl_info[i].entry.group.type, multi_acl_info[i].entry.group.u.ip6_addr.ul[0], multi_acl_info[i].entry.port_map,
entry->group.type, entry->group.u.ip6_addr.ul[0], entry->port_map);*/
if(0 == memcmp(&(multi_acl_info[i].entry.group), &(entry->group), sizeof(entry->group)))
{
memcpy(&multi_acl_group[count], &multi_acl_info[i], sizeof(multi_acl_info[i]));
count++;//return the real number of multi_acl_group[]
MULTI_DEBUG("in iterate_multicast_acl_group, count=%d, i=%d\n", count, i);
}
}
return count;
}
HSL_LOCAL int mult_acl_has_entry(fal_igmp_sg_addr_t * group, fal_igmp_sg_addr_t *source)
{
int rule_id;
int ret = 0;
#if 0
if(source != NULL)
{
MULTI_DEBUG("new group[%d]= %x %x %x %x, new source[%d]=%x %x %x %x\n",
group->type, group->u.ip6_addr.ul[0], group->u.ip6_addr.ul[1], group->u.ip6_addr.ul[2], group->u.ip6_addr.ul[3],
source->type, source->u.ip6_addr.ul[0], source->u.ip6_addr.ul[1], source->u.ip6_addr.ul[2], source->u.ip6_addr.ul[3]);
MULTI_DEBUG("old group[%d]= %x %x %x %x, old source[%d]=%x %x %x %x\n",
multi_acl_group[0].entry.group.type, multi_acl_group[0].entry.group.u.ip6_addr.ul[0],
multi_acl_group[0].entry.group.u.ip6_addr.ul[1], multi_acl_group[0].entry.group.u.ip6_addr.ul[2], multi_acl_group[0].entry.group.u.ip6_addr.ul[3],
multi_acl_group[0].entry.source.type, multi_acl_group[0].entry.source.u.ip6_addr.ul[0],
multi_acl_group[0].entry.source.u.ip6_addr.ul[1], multi_acl_group[0].entry.source.u.ip6_addr.ul[2], multi_acl_group[0].entry.source.u.ip6_addr.ul[3]);
}
#endif
if(source == NULL)
{
for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++)
{
if( (0==memcmp(&multi_acl_group[rule_id].entry.group, group, sizeof(fal_igmp_sg_addr_t))) &&
(multi_source_is_null(&multi_acl_group[rule_id].entry.source)))
{
MULTI_DEBUG("Source=0:Orignal ACL rule have this entry! rule id= %d\n", rule_id);
ret = rule_id+1; // ensure the return value is the actually number of entry
break;
}
}
}
else
{
for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++)
{
if( (0==memcmp(&multi_acl_group[rule_id].entry.group, group, sizeof(fal_igmp_sg_addr_t))) &&
(0==memcmp(&multi_acl_group[rule_id].entry.source, source, sizeof(fal_igmp_sg_addr_t))))
{
MULTI_DEBUG("Orignal ACL rule have this entry! rule id= %d\n", rule_id);
ret = rule_id+1; // ensure the return value is the actually number of entry
break;
}
}
}
return ret;
}
HSL_LOCAL int portmap_null(int index, fal_pbmp_t portmap)
{
int val;
if (index<0)
{
aos_printk("portmap_null, index error\n");
return SW_FAIL;
}
val = multi_acl_group[index].entry.port_map&(~portmap);
if( 0 == (val&0xff) )
return 1;
else
return 0;
}
HSL_LOCAL int portmap_valid(fal_igmp_sg_entry_t *g_source, fal_igmp_sg_entry_t *g_star)
{
/* return 0 means the portmap is Not valid
return 1 means the protmap is valid
*/
/* MULTI_DEBUG("portmap_valid:g_source portmap=%x, source=%x,group=%x, g_star portmap=%x, source=%x, group=%x\n",
g_source->port_map, g_source->source.u.ip4_addr, g_source->group.u.ip4_addr,
g_star->port_map, g_star->source.u.ip4_addr,g_star->group.u.ip4_addr);*/
if(multi_source_is_null(&(g_star->source)))
{
if((g_source->port_map|g_star->port_map) == g_star->port_map)
{
return 0;
}
}
return 1;
}
HSL_LOCAL int portmap_clear_type(int count, int index, fal_pbmp_t portmap)
{
if(count>=0 && index<count) //new_index must >0; this means there're (G,*) and (G,S)
{
//if the new clear portmap will cause (G,S)=(G,*), Delete the (G,S)
if((multi_acl_group[index].entry.port_map & (~portmap)) == multi_acl_group[count].entry.port_map)
return 1; //delete
//The following means there must be at least one bit clear wrong. Clear the (G,*) portmap.
if( ((multi_acl_group[index].entry.port_map & (~portmap)) & (multi_acl_group[count].entry.port_map))
!= (multi_acl_group[count].entry.port_map))
return 0;
return 2; //Normal update
}
return 0;
}
sw_error_t dess_igmp_sg_entry_set(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry)
{
int number, count;
int new_index=0;
sw_error_t rv;
int action = MULT_ACTION_SET;
int i=0;
HSL_API_LOCK;
(void)dess_multicast_init(0);
aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
aos_mem_zero(multi_acl_group, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
MULTI_DEBUG("Before query: group=%x, source=%x, portmap=%x\n", entry->group.u.ip4_addr, entry->source.u.ip4_addr, entry->port_map);
//number is the total multicast ACL rules amount, stores in multi_acl_info[];
number = dess_multicast_acl_query();
if(number > FAL_IGMP_SG_ENTRY_MAX)
return SW_FAIL;
//count the total specific multicast group ACL rules, stores in multi_acl_group[]; count <=number
count = iterate_multicast_acl_group(number, entry);
//new_index-1 is the found entry index in multi_acl_group[], the real index is [new_index-1], 0 means no entry
new_index = mult_acl_has_entry(&entry->group, &entry->source);
MULTI_DEBUG("Start entry set: number=%d, count=%d, new_index=%d, pm=%x\n", number, count, new_index, entry->port_map);
if( 0==multi_source_is_null(&entry->source) ) // new entry is (G, S)
{
MULTI_DEBUG("the new entry is (G,S)\n");
if(count>0 && 0 == portmap_valid(entry, &(multi_acl_group[count-1].entry))) //specfic group entry exist,(G,S) or (G,*)
{
//return SW_NO_CHANGE; // The new portmap is Not valid
MULTI_DEBUG("KKK, modified 1 !!!\n");
}
if(0 == new_index) //new entry, need add
{
#if 0
/*The method:
1. predict if the portmap should be modified.
2. add new acl rule with new portmap value.
*/
if((tmp_index = mult_acl_has_entry(&entry->group, NULL))>0) // (G, *) entry exist
{
/*Here the update should new (G, S) OR orignal (G,*) portmap,
be careful, entry's portmap value will be modified, so I use tmp_entry.
*/
memcpy(tmp_entry, entry, sizeof(fal_igmp_sg_entry_t));
MULTI_DEBUG("Here, (G,*) exist! tmp_index=%d\n", tmp_index);
sw_multicast_acl_update(FAL_ACL_LIST_MULTICAST+1, tmp_index-1, tmp_entry, action);
dess_multicast_acl_add(FAL_ACL_LIST_MULTICAST, tmp_entry);
return SW_OK;
}
#endif
dess_multicast_acl_add(FAL_ACL_LIST_MULTICAST, entry);
MULTI_DEBUG("Here, need add (G, S), portmap=%x\n", entry->port_map);
return SW_OK;
}
else
{
//Here update Just: the old exist entry portmap OR the new entry portmap
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, new_index-1, entry, action);
return SW_OK;
}
} //end of memcmp
else // new entry is (G, *)
{
if(0 == new_index) //new entry, need add
{
dess_multicast_acl_add(FAL_ACL_LIST_MULTICAST+1, entry);
rv = SW_OK;
}
else if(new_index > 0) // (G, *) entry exist?
{
//Update exist (G, *) portmap with new portmap
MULTI_DEBUG("(G,*) exist, before update, new_index=%d\n", new_index );
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST+1, new_index-1, entry, action);
rv = SW_OK;
}
if(new_index>0&&count>1) //(G,S*) and (G,*) exist, new entry is (G,*)
{
for(i=count-2; i>=0&&i<FAL_IGMP_SG_ENTRY_MAX; i--)
{
if(multi_acl_group[i].entry.port_map==0) //This ACL rule should be done nothing, DENY rule
continue;
if(0 == portmap_valid(&(multi_acl_group[i].entry), &(multi_acl_group[count-1].entry)))
{
MULTI_DEBUG("1:portmap is not valid, should delete, i=%d, source portmap=%x, gstar pm=%x\n",
i, multi_acl_group[i].entry.port_map, multi_acl_group[count-1].entry.port_map);
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i);
rv = SW_NO_MORE;
}
else
{
MULTI_DEBUG("1:Start update all (G,S),i=%d, gstar portmap=%x\n", i, multi_acl_group[count-1].entry.port_map);
//Update all (G,S) entry portmap with new(G, *) portmap
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action);
rv = SW_OK;
}
}
}
else if(new_index==0&&count>0) //only exist (G,S*) orignally
{
for(i=count-1; i>=0&&i<FAL_IGMP_SG_ENTRY_MAX; i--)
{
if(multi_acl_group[i].entry.port_map==0) //This ACL rule should be done nothing, DENY rule
continue;
if(0 == portmap_valid(&(multi_acl_group[i].entry), entry))
{
MULTI_DEBUG("2:portmap is not valid, should delete, i=%d, source portmap=%x, gstar pm=%x\n",
i, multi_acl_group[i].entry.port_map, entry->port_map);
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i);
rv = SW_NO_MORE;
}
else
{
MULTI_DEBUG("2:Start update all (G,S),i=%d, portmap=%x\n", i, entry->port_map);
//Update all (G,S) entry portmap with new(G, *) portmap
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action);
rv = SW_OK;
}
}
}
}
HSL_API_UNLOCK;
return rv;
}
sw_error_t dess_igmp_sg_entry_clear(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry)
{
a_uint32_t number, count;
int new_index=0;
sw_error_t rv = SW_OK;
int action= MULT_ACTION_CLEAR;
int i=0;
int pm_type;
HSL_API_LOCK;
(void)dess_multicast_init(0);
aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
aos_mem_zero(multi_acl_group, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
//number is the total multicast ACL rules amount, stores in multi_acl_info[];
number = dess_multicast_acl_query();
if(number > FAL_IGMP_SG_ENTRY_MAX)
return SW_FAIL;
//count the total specific multicast group ACL rules, stores in multi_acl_group[]; count <=number
count = iterate_multicast_acl_group(number, entry);
if(count == 0)
return SW_OK;
//new_index-1 is the found entry index in multi_acl_group[]
new_index = mult_acl_has_entry(&entry->group, &entry->source);
MULTI_DEBUG("Start entry clear: number=%d, count=%d, new_index=%d\n", number, count, new_index);
if(0 == new_index || new_index > FAL_IGMP_SG_ENTRY_MAX || count > FAL_IGMP_SG_ENTRY_MAX) //new entry, the user command is wrong
{
return SW_NO_SUCH;
}
if( 0==multi_source_is_null(&entry->source) ) // new entry is (G, S)
{
if (portmap_null(new_index-1, entry->port_map))
{
MULTI_DEBUG("KKK entry clear, new(G,S), with null portmap. \n");
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST, new_index-1);
return SW_OK;
}
else
{
MULTI_DEBUG("KKK entry clear, new(G,S), with NOT null portmap. \n");
/* If (G,*) doesn't exist, [count-1] is the last specfic group, maybe(G,*) */
if(0 == multi_source_is_null(&(multi_acl_group[count-1].entry.source)))
{
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, new_index-1, entry, action);
}
else //(G,*) exist
{
pm_type = portmap_clear_type(count-1, new_index-1, entry->port_map);
if(pm_type == 0)
return SW_NO_CHANGE;
else if(pm_type == 1)
{
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST, new_index-1);
return SW_OK;
}
else
{
//normal update; consider here...wangson
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, new_index-1, entry, action);
}
}
}
return SW_OK;
}
else //clear entry is (G,*)
{
MULTI_DEBUG("Here, new_index[%d]>=0, new portmap to clear is %x\n", new_index, entry->port_map);
if (portmap_null(new_index-1, entry->port_map))
{
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST+1, new_index-1);
rv = SW_OK;
}
else
{
MULTI_DEBUG("Update (G,*)!, new_index=%d, pm=%x\n", new_index, entry->port_map);
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST+1, new_index-1, entry, action);
}
MULTI_DEBUG("KKK, ready clear (G, S*), count=%d\n", count);
#if 0
if(count>1) // (G, S*) entry exist, if count=1 here, only exist(G,*)entry
{
//count must >=2
for(i=count-2; i>=0; i--)
{
if(portmap_null(i, entry->port_map))
{
MULTI_DEBUG("portmap_null, i=%d\n", i);
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i);
rv = SW_NO_MORE;
}
else
{
//Update all (G,S) entry portmap with new(G, *) portmap
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action);
rv = SW_OK;
}
}
}
#else
if(count>1) // (G, S*) entry exist, if count=1 here, only exist(G,*)entry
{
//count must >=2
for(i=count-2; i>=0&&i<FAL_IGMP_SG_ENTRY_MAX; i--)
{
//PortMap of entry (S,G) == (*,G) portmap after clear?
if((multi_acl_group[new_index-1].entry.port_map&(~(entry->port_map))) ==
multi_acl_group[i].entry.port_map)
dess_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i);
else
//Update all (G,S) entry portmap with new(G, *) portmap
dess_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action);
rv = SW_OK;
}
}
#endif
}
HSL_API_UNLOCK;
return rv;
}
static void
print_ip4addr(char * param_name, a_uint32_t * buf,
a_uint32_t size)
{
a_uint32_t i;
fal_ip4_addr_t ip4;
ip4 = *((fal_ip4_addr_t *) buf);
aos_printk("%s", param_name);
for (i = 0; i < 3; i++)
{
aos_printk("%d.", (ip4 >> (24 - i * 8)) & 0xff);
}
aos_printk("%d", (ip4 & 0xff));
}
static void
print_ip6addr(char * param_name, a_uint32_t * buf,
a_uint32_t size)
{
a_uint32_t i;
fal_ip6_addr_t ip6;
ip6 = *(fal_ip6_addr_t *) buf;
aos_printk("%s", param_name);
for (i = 0; i < 3; i++)
{
aos_printk("%x:%x:", (ip6.ul[i] >> 16) & 0xffff, ip6.ul[i] & 0xffff);
}
aos_printk("%x:%x", (ip6.ul[3] >> 16) & 0xffff, ip6.ul[3] & 0xffff);
}
sw_error_t dess_igmp_sg_entry_show(a_uint32_t dev_id)
{
a_uint32_t number;
int i;
HSL_API_LOCK;
(void)dess_multicast_init(0);
aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
aos_mem_zero(multi_acl_group, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
//number is the total multicast ACL rules amount, stores in multi_acl_info[];
number = dess_multicast_acl_query();
for(i=0; i<number; i++)
{
if(0 == multi_acl_info[i].entry.group.type) //ipv4
{
aos_printk("\n[%d]:", i);
print_ip4addr(" [Group IPv4 addr]:", (a_uint32_t *)&(multi_acl_info[i].entry.group.u.ip4_addr), sizeof (fal_ip4_addr_t));
print_ip4addr(" [Source IPv4 addr]:", (a_uint32_t *)&(multi_acl_info[i].entry.source.u.ip4_addr), sizeof (fal_ip4_addr_t));
aos_printk("\n [Portmap]: 0x%x ", multi_acl_info[i].entry.port_map);
aos_printk(" [Vlanid]: %d ", multi_acl_info[i].entry.vlan_id);
}
else if(1 == multi_acl_info[i].entry.group.type) //ipv6
{
aos_printk("\n[%d]:", i);
print_ip6addr(" [Group IPv6 addr]: ", (a_uint32_t *)&(multi_acl_info[i].entry.group.u.ip6_addr), sizeof (fal_ip6_addr_t));
print_ip6addr(" [Source IPv6 addr]: ", (a_uint32_t *)&(multi_acl_info[i].entry.source.u.ip6_addr), sizeof (fal_ip6_addr_t));
aos_printk("\n [Portmap]: 0x%x ", multi_acl_info[i].entry.port_map);
aos_printk(" [Vlanid]: %d ", multi_acl_info[i].entry.vlan_id);
}
}
aos_printk("\n\nTotal %d multicast ACL rules.\n", number);
HSL_API_UNLOCK;
return SW_OK;
}
void
dess_multicast_init(a_uint32_t dev_id)
{
sw_error_t val;
dess_acl_status_set(0, 1);
val = dess_acl_list_creat(0, FAL_ACL_LIST_MULTICAST, FAL_MULTICAST_PRI);
if(val !=SW_OK && val != SW_ALREADY_EXIST)
aos_printk("Multicast 1 acl list create error, val=%d\n", val);
val = dess_acl_list_creat(0, FAL_ACL_LIST_MULTICAST+1, FAL_MULTICAST_PRI+1);
if(val !=SW_OK && val != SW_ALREADY_EXIST)
aos_printk("Multicast 2 acl list create error, val=%d\n", val);
}
sw_error_t dess_igmp_sg_entry_query(a_uint32_t dev_id, fal_igmp_sg_info_t *info)
{
a_uint32_t number;
int i;
HSL_API_LOCK;
dess_multicast_init(0);
aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t));
/*number is the total multicast ACL rules amount, stores in multi_acl_info[];*/
number = dess_multicast_acl_query();
if(number > FAL_IGMP_SG_ENTRY_MAX)
{
HSL_API_UNLOCK;
return SW_FAIL;
}
info->cnt = number;
for(i=0; i<number; i++)
{
aos_mem_copy(&(info->acl_info[i]), &(multi_acl_info[i]), sizeof(multi_acl_info_t));
}
HSL_API_UNLOCK;
return SW_OK;
}