| /* |
| * Copyright (c) 2012, 2016, 2018, 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. |
| */ |
| |
| |
| /** |
| * @defgroup isis_acl ISIS_ACL |
| * @{ |
| */ |
| #include "sw.h" |
| #include "hsl.h" |
| #include "hsl_dev.h" |
| #include "hsl_acl.h" |
| #include "isis_acl.h" |
| #include "isis_reg.h" |
| #include "isis_acl_prv.h" |
| |
| //#define ISIS_ACL_DEBUG |
| //#define ISIS_SW_ENTRY |
| #define ISIS_HW_ENTRY |
| |
| static isis_acl_list_t *sw_list_ent[SW_MAX_NR_DEV]; |
| static isis_acl_rule_t *sw_rule_ent[SW_MAX_NR_DEV]; |
| |
| static isis_acl_rule_t *sw_rule_tmp[SW_MAX_NR_DEV]; |
| static isis_acl_rule_t *hw_rule_tmp[SW_MAX_NR_DEV]; |
| #ifdef ISIS_SW_ENTRY |
| static a_uint8_t *sw_filter_mem = NULL; |
| #endif |
| |
| static sw_error_t |
| _isis_filter_valid_set(a_uint32_t dev_id, a_uint32_t flt_idx, a_uint32_t flag); |
| |
| static sw_error_t |
| _isis_filter_ports_bind(a_uint32_t dev_id, a_uint32_t flt_idx, |
| a_uint32_t ports); |
| |
| #ifdef ISIS_SW_ENTRY |
| static sw_error_t |
| _isis_filter_write(a_uint32_t dev_id, a_uint32_t reg[], a_uint32_t flt_idx, |
| a_uint32_t op); |
| |
| static sw_error_t |
| _isis_filter_read(a_uint32_t dev_id, a_uint32_t reg[], a_uint32_t flt_idx, |
| a_uint32_t op); |
| #endif |
| |
| static sw_error_t |
| _isis_filter_down_to_hw(a_uint32_t dev_id, hw_filter_t * filter, |
| a_uint32_t flt_idx); |
| |
| static sw_error_t |
| _isis_filter_up_to_sw(a_uint32_t dev_id, hw_filter_t * filter, |
| a_uint32_t flt_idx); |
| |
| static void |
| _isis_acl_list_dump(a_uint32_t dev_id) |
| { |
| a_uint32_t i; |
| isis_acl_list_t *sw_list; |
| |
| aos_printk("\ndev_id=%d list control infomation:", dev_id); |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_list = &(sw_list_ent[dev_id][i]); |
| if (ENT_USED & sw_list->status) |
| { |
| aos_printk |
| ("\nlist_id=%02d list_pri=%02d rule_nr=%02d [pts_map]:0x%02x idx=%02d ", |
| sw_list->list_id, sw_list->list_pri, sw_list->rule_nr, |
| sw_list->bind_pts, i); |
| } |
| } |
| aos_printk("\n"); |
| } |
| |
| static void |
| _isis_acl_sw_rule_dump(char *info, isis_acl_rule_t * sw_rule) |
| { |
| #ifdef ISIS_ACL_DEBUG |
| a_uint32_t flt_idx, i; |
| |
| aos_printk("\n%s", info); |
| for (flt_idx = 0; flt_idx < ISIS_MAX_FILTER; flt_idx++) |
| { |
| aos_printk("\n%d software filter:", flt_idx); |
| aos_printk("\nact:"); |
| for (i = 0; i < 3; i++) |
| { |
| aos_printk("%08x ", sw_rule[flt_idx].filter.act[i]); |
| } |
| |
| aos_printk("\nvlu:"); |
| for (i = 0; i < 5; i++) |
| { |
| aos_printk("%08x ", sw_rule[flt_idx].filter.vlu[i]); |
| } |
| |
| aos_printk("\nmsk:"); |
| for (i = 0; i < 5; i++) |
| { |
| aos_printk("%08x ", sw_rule[flt_idx].filter.msk[i]); |
| } |
| |
| aos_printk("\nctl:status[%02d] list_id[%02d] rule_id[%02d]", |
| sw_rule[flt_idx].status, |
| sw_rule[flt_idx].list_id, sw_rule[flt_idx].rule_id); |
| |
| aos_printk("\n\n"); |
| } |
| #else |
| return; |
| #endif |
| } |
| |
| static isis_acl_list_t * |
| _isis_acl_list_loc(a_uint32_t dev_id, a_uint32_t list_id) |
| { |
| a_uint32_t i; |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| if ((ENT_USED & sw_list_ent[dev_id][i].status) |
| && (list_id == sw_list_ent[dev_id][i].list_id)) |
| { |
| return &(sw_list_ent[dev_id][i]); |
| } |
| } |
| return NULL; |
| } |
| |
| static sw_error_t |
| _isis_filter_valid_set(a_uint32_t dev_id, a_uint32_t flt_idx, a_uint32_t flag) |
| { |
| #ifdef ISIS_SW_ENTRY |
| hw_filter_t filter; |
| |
| _isis_filter_up_to_sw(dev_id, &filter, flt_idx); |
| |
| filter.msk[4] &= 0xfffffff8; |
| filter.msk[4] |= (flag & 0x7); |
| |
| _isis_filter_down_to_hw(dev_id, &filter, flt_idx); |
| |
| return SW_OK; |
| #else |
| #ifdef ISIS_HW_ENTRY |
| hw_filter_t filter; |
| |
| filter = sw_rule_ent[dev_id][flt_idx].filter; |
| |
| filter.msk[4] &= 0xfffffff8; |
| filter.msk[4] |= (flag & 0x7); |
| |
| _isis_filter_down_to_hw(dev_id, &filter, flt_idx); |
| return SW_OK; |
| #else |
| sw_error_t rv; |
| a_uint32_t addr, data = 0; |
| |
| /* read filter mask at first */ |
| addr = ISIS_RULE_FUNC_ADDR; |
| data = (flt_idx & 0x7f) | (0x1 << 8) | (0x1 << 10) | (0x1 << 31); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| /* get filter mask and modify it */ |
| addr = ISIS_RULE_FUNC_ADDR + 20; |
| HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| data &= 0xfffffff8; |
| data |= (flag & 0x7); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| /* write back filter mask */ |
| addr = ISIS_RULE_FUNC_ADDR; |
| data = (flt_idx & 0x7f) | (0x1 << 8) | (0x1 << 31); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| return SW_OK; |
| #endif |
| #endif |
| } |
| |
| static sw_error_t |
| _isis_filter_ports_bind(a_uint32_t dev_id, a_uint32_t flt_idx, a_uint32_t ports) |
| { |
| #ifdef ISIS_SW_ENTRY |
| hw_filter_t filter; |
| |
| _isis_filter_up_to_sw(dev_id, &filter, flt_idx); |
| |
| filter.vlu[4] &= 0xffffff80; |
| filter.vlu[4] |= (ports & 0x7f); |
| |
| _isis_filter_down_to_hw(dev_id, &filter, flt_idx); |
| |
| return SW_OK; |
| #else |
| #ifdef ISIS_HW_ENTRY |
| hw_filter_t filter; |
| |
| filter = sw_rule_ent[dev_id][flt_idx].filter; |
| |
| filter.vlu[4] &= 0xffffff80; |
| filter.vlu[4] |= (ports & 0x7f); |
| |
| _isis_filter_down_to_hw(dev_id, &filter, flt_idx); |
| |
| return SW_OK; |
| #else |
| sw_error_t rv; |
| a_uint32_t addr, data; |
| |
| /* read filter value at first */ |
| addr = ISIS_RULE_FUNC_ADDR; |
| data = (flt_idx & 0x7f) | (0x1 << 10) | (0x1 << 31); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| /* get filter value and modify it */ |
| addr = ISIS_RULE_FUNC_ADDR + 20; |
| HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| data &= 0xffffff80; |
| data |= (ports & 0x7f); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| /* write back filter value */ |
| addr = ISIS_RULE_FUNC_ADDR; |
| data = (flt_idx & 0x7f) | (0x1 << 31); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| return SW_OK; |
| #endif |
| #endif |
| } |
| |
| #ifdef ISIS_SW_ENTRY |
| static sw_error_t |
| _isis_filter_write(a_uint32_t dev_id, a_uint32_t reg[], a_uint32_t flt_idx, |
| a_uint32_t op) |
| { |
| a_uint32_t i, addr, data, idx = 6; |
| sw_error_t rv; |
| |
| if (ISIS_FILTER_ACT_OP == op) |
| { |
| idx = 4; |
| } |
| |
| for (i = 1; i < idx; i++) |
| { |
| addr = ISIS_RULE_FUNC_ADDR + (i << 2); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(reg[i - 1])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| addr = ISIS_RULE_FUNC_ADDR; |
| data = (flt_idx & 0x7f) | (op << 8) | (0x1 << 31); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| |
| return rv; |
| } |
| |
| static sw_error_t |
| _isis_filter_read(a_uint32_t dev_id, a_uint32_t reg[], a_uint32_t flt_idx, |
| a_uint32_t op) |
| { |
| a_uint32_t i, addr, data, idx = 6; |
| sw_error_t rv; |
| |
| addr = ISIS_RULE_FUNC_ADDR; |
| data = (flt_idx & 0x7f) | (op << 8) | (0x1 << 10) | (0x1 << 31); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&data), sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| if (ISIS_FILTER_ACT_OP == op) |
| { |
| idx = 4; |
| } |
| |
| for (i = 1; i < idx; i++) |
| { |
| addr = ISIS_RULE_FUNC_ADDR + (i << 2); |
| HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(reg[i - 1])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| return SW_OK; |
| } |
| #endif |
| |
| static sw_error_t |
| _isis_filter_down_to_hw(a_uint32_t dev_id, hw_filter_t * filter, |
| a_uint32_t flt_idx) |
| { |
| #ifdef ISIS_SW_ENTRY |
| a_uint8_t *tbl = sw_filter_mem + sizeof (hw_filter_t) * flt_idx; |
| |
| aos_mem_copy(tbl, filter, sizeof (hw_filter_t)); |
| #else |
| #ifdef ISIS_HW_ENTRY |
| sw_error_t rv; |
| a_uint32_t i, base, addr; |
| |
| base = ISIS_FILTER_ACT_ADDR + (flt_idx << 4); |
| for (i = 0; i < 3; i++) |
| { |
| addr = base + (i << 2); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(filter->act[i])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| base = ISIS_FILTER_VLU_ADDR + (flt_idx << 5); |
| for (i = 0; i < 5; i++) |
| { |
| addr = base + (i << 2); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(filter->vlu[i])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| base = ISIS_FILTER_MSK_ADDR + (flt_idx << 5); |
| for (i = 0; i < 5; i++) |
| { |
| addr = base + (i << 2); |
| HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(filter->msk[i])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| #else |
| sw_error_t rv; |
| |
| rv = _isis_filter_write(dev_id, &(filter->act[0]), flt_idx, |
| ISIS_FILTER_ACT_OP); |
| SW_RTN_ON_ERROR(rv); |
| |
| rv = _isis_filter_write(dev_id, &(filter->vlu[0]), flt_idx, |
| ISIS_FILTER_VLU_OP); |
| SW_RTN_ON_ERROR(rv); |
| |
| rv = _isis_filter_write(dev_id, &(filter->msk[0]), flt_idx, |
| ISIS_FILTER_MSK_OP); |
| SW_RTN_ON_ERROR(rv); |
| #endif |
| #endif |
| |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_filter_up_to_sw(a_uint32_t dev_id, hw_filter_t * filter, |
| a_uint32_t flt_idx) |
| { |
| #ifdef ISIS_SW_ENTRY |
| a_uint8_t *tbl = sw_filter_mem + sizeof (hw_filter_t) * flt_idx; |
| |
| aos_mem_copy(filter, tbl, sizeof (hw_filter_t)); |
| #else |
| #ifdef ISIS_HW_ENTRY |
| sw_error_t rv; |
| a_uint32_t i, base, addr; |
| |
| base = ISIS_FILTER_VLU_ADDR + (flt_idx << 5); |
| for (i = 0; i < 5; i++) |
| { |
| addr = base + (i << 2); |
| HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(filter->vlu[i])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| base = ISIS_FILTER_MSK_ADDR + (flt_idx << 5); |
| for (i = 0; i < 5; i++) |
| { |
| addr = base + (i << 2); |
| HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), |
| (a_uint8_t *) (&(filter->msk[i])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| base = ISIS_FILTER_ACT_ADDR + (flt_idx << 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 *) (&(filter->act[i])), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| } |
| #else |
| sw_error_t rv; |
| |
| rv = _isis_filter_read(dev_id, &(filter->vlu[0]), flt_idx, |
| ISIS_FILTER_VLU_OP); |
| SW_RTN_ON_ERROR(rv); |
| |
| rv = _isis_filter_read(dev_id, &(filter->msk[0]), flt_idx, |
| ISIS_FILTER_MSK_OP); |
| SW_RTN_ON_ERROR(rv); |
| |
| rv = _isis_filter_read(dev_id, &(filter->act[0]), flt_idx, |
| ISIS_FILTER_ACT_OP); |
| SW_RTN_ON_ERROR(rv); |
| #endif |
| #endif |
| |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_list_insert(a_uint32_t dev_id, a_uint32_t * src_idx, |
| a_uint32_t * dst_idx, isis_acl_rule_t * src_rule, |
| isis_acl_rule_t * dst_rule) |
| { |
| a_uint32_t i, data, rule_id, list_id, list_pri; |
| |
| rule_id = 0; |
| list_id = src_rule[*src_idx].list_id; |
| list_pri = src_rule[*src_idx].list_pri; |
| |
| for (i = *src_idx; i < ISIS_MAX_FILTER; i++) |
| { |
| if (!(ENT_USED & src_rule[i].status)) |
| { |
| continue; // was: break; |
| } |
| |
| if (src_rule[i].list_id != list_id) |
| { |
| break; |
| } |
| |
| SW_GET_FIELD_BY_REG(MAC_RUL_M4, RULE_TYP, data, |
| src_rule[i].filter.msk[4]); |
| if (!data) |
| { |
| continue; |
| } |
| |
| if (ISIS_MAX_FILTER <= *dst_idx) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| if (ENT_USED & dst_rule[*dst_idx].status) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| SW_GET_FIELD_BY_REG(MAC_RUL_M4, RULE_VALID, data, |
| src_rule[i].filter.msk[4]); |
| if ((FLT_START == data) && (*dst_idx % 2)) |
| { |
| if (*src_idx != i) |
| { |
| dst_rule[*dst_idx].list_id = list_id; |
| dst_rule[*dst_idx].list_pri = list_pri; |
| dst_rule[*dst_idx].rule_id = rule_id - 1; |
| dst_rule[*dst_idx].status |= ENT_USED; |
| } |
| |
| (*dst_idx)++; |
| if (ISIS_MAX_FILTER <= *dst_idx) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| if (ENT_USED & dst_rule[*dst_idx].status) |
| { |
| return SW_NO_RESOURCE; |
| } |
| } |
| |
| aos_mem_copy(&(dst_rule[*dst_idx].filter), &(src_rule[i].filter), |
| sizeof (hw_filter_t)); |
| dst_rule[*dst_idx].list_id = list_id; |
| dst_rule[*dst_idx].list_pri = list_pri; |
| dst_rule[*dst_idx].rule_id = rule_id; |
| dst_rule[*dst_idx].status |= ENT_USED; |
| if (ENT_DEACTIVE & src_rule[i].status) |
| { |
| dst_rule[*dst_idx].status |= ENT_DEACTIVE; |
| } |
| (*dst_idx)++; |
| |
| if ((FLT_END == data) && (*dst_idx % 2)) |
| { |
| if (ISIS_MAX_FILTER > *dst_idx) |
| { |
| dst_rule[*dst_idx].list_id = list_id; |
| dst_rule[*dst_idx].list_pri = list_pri; |
| dst_rule[*dst_idx].rule_id = rule_id; |
| dst_rule[*dst_idx].status |= ENT_USED; |
| (*dst_idx)++; |
| } |
| } |
| |
| if ((FLT_END == data) || (FLT_STARTEND == data)) |
| { |
| rule_id++; |
| } |
| } |
| |
| *src_idx = i; |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_alloc(a_uint32_t dev_id, isis_acl_list_t * sw_list, |
| a_uint32_t filter_nr) |
| { |
| a_uint32_t free_flt_nr, load_idx, begin_idx, start_idx, end_idx, i; |
| a_uint32_t largest_nr, largest_idx; |
| sw_error_t rv; |
| |
| /* calculate the proper location, [start_idx, end_idx) */ |
| start_idx = 0; |
| end_idx = ISIS_MAX_FILTER; |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| if (ENT_USED & sw_rule_ent[dev_id][i].status) |
| { |
| if (sw_rule_ent[dev_id][i].list_pri < sw_list->list_pri) |
| { |
| start_idx = i + 1; |
| } |
| else if (sw_rule_ent[dev_id][i].list_pri > sw_list->list_pri) |
| { |
| end_idx = i; |
| break; |
| } |
| } |
| } |
| |
| /* find the larget free filters block */ |
| largest_nr = 0; |
| largest_idx = 0; |
| free_flt_nr = 0; |
| begin_idx = start_idx; |
| for (i = start_idx; i < end_idx; i++) |
| { |
| if (!(ENT_USED & sw_rule_ent[dev_id][i].status)) |
| { |
| free_flt_nr++; |
| } |
| else |
| { |
| if (free_flt_nr > largest_nr) |
| { |
| largest_nr = free_flt_nr; |
| largest_idx = begin_idx; |
| } |
| free_flt_nr = 0; |
| begin_idx = i + 1; |
| } |
| } |
| |
| if (free_flt_nr > largest_nr) |
| { |
| largest_nr = free_flt_nr; |
| largest_idx = begin_idx; |
| } |
| |
| if ((!largest_nr) || ((largest_nr + 1) < filter_nr)) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| if (ENT_USED & sw_rule_ent[dev_id][i].status) |
| { |
| aos_mem_copy(&(sw_rule_tmp[dev_id][i]), &(sw_rule_ent[dev_id][i]), |
| sizeof (isis_acl_rule_t)); |
| } |
| } |
| |
| begin_idx = 0; |
| load_idx = largest_idx; |
| rv = _isis_acl_list_insert(dev_id, &begin_idx, &load_idx, |
| hw_rule_tmp[dev_id], sw_rule_tmp[dev_id]); |
| return rv; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_reorder(a_uint32_t dev_id, isis_acl_list_t * sw_list) |
| { |
| a_uint32_t i, src_idx, dst_idx; |
| sw_error_t rv; |
| |
| dst_idx = 0; |
| for (i = 0; i < ISIS_MAX_FILTER;) |
| { |
| if (ENT_USED & sw_rule_ent[dev_id][i].status) |
| { |
| if (sw_rule_ent[dev_id][i].list_pri <= sw_list->list_pri) |
| { |
| rv = _isis_acl_list_insert(dev_id, &i, &dst_idx, |
| sw_rule_ent[dev_id], |
| sw_rule_tmp[dev_id]); |
| SW_RTN_ON_ERROR(rv); |
| } |
| else |
| { |
| break; |
| } |
| } |
| else |
| { |
| i++; |
| } |
| } |
| |
| src_idx = 0; |
| rv = _isis_acl_list_insert(dev_id, &src_idx, &dst_idx, hw_rule_tmp[dev_id], |
| sw_rule_tmp[dev_id]); |
| SW_RTN_ON_ERROR(rv); |
| |
| for (; i < ISIS_MAX_FILTER;) |
| { |
| if (ENT_USED & sw_rule_ent[dev_id][i].status) |
| { |
| rv = _isis_acl_list_insert(dev_id, &i, &dst_idx, |
| sw_rule_ent[dev_id], |
| sw_rule_tmp[dev_id]); |
| SW_RTN_ON_ERROR(rv); |
| } |
| else |
| { |
| i++; |
| } |
| } |
| |
| return SW_OK; |
| } |
| |
| static void |
| _isis_acl_rule_sync(a_uint32_t dev_id, a_uint32_t flt_idx, a_uint32_t flt_nr) |
| { |
| a_uint32_t i, data; |
| |
| for (i = flt_idx; i < (flt_idx + flt_nr); i++) |
| { |
| if (aos_mem_cmp |
| (&(sw_rule_ent[dev_id][i]), &(sw_rule_tmp[dev_id][i]), |
| sizeof (isis_acl_rule_t))) |
| { |
| SW_GET_FIELD_BY_REG(MAC_RUL_M4, RULE_TYP, data, |
| sw_rule_tmp[dev_id][i].filter.msk[4]); |
| if (data) |
| { |
| _isis_filter_down_to_hw(dev_id, |
| &(sw_rule_tmp[dev_id][i].filter), i); |
| } |
| else |
| { |
| _isis_filter_valid_set(dev_id, i, 0); |
| } |
| |
| aos_mem_copy(&(sw_rule_ent[dev_id][i]), &(sw_rule_tmp[dev_id][i]), |
| sizeof (isis_acl_rule_t)); |
| } |
| } |
| } |
| |
| static sw_error_t |
| _isis_acl_list_creat(a_uint32_t dev_id, a_uint32_t list_id, a_uint32_t list_pri) |
| { |
| a_uint32_t i, loc = ISIS_MAX_FILTER; |
| isis_acl_list_t *sw_list; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if ((ISIS_MAX_LIST_ID < list_id) || (ISIS_MAX_LIST_PRI < list_pri)) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_list = &(sw_list_ent[dev_id][i]); |
| if (ENT_USED & sw_list->status) |
| { |
| if (list_id == sw_list->list_id) |
| { |
| return SW_ALREADY_EXIST; |
| } |
| } |
| else |
| { |
| loc = i; |
| } |
| } |
| |
| if (ISIS_MAX_FILTER == loc) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| sw_list = &(sw_list_ent[dev_id][loc]); |
| aos_mem_zero(sw_list, sizeof (isis_acl_list_t)); |
| sw_list->list_id = list_id; |
| sw_list->list_pri = list_pri; |
| sw_list->status |= ENT_USED; |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_list_destroy(a_uint32_t dev_id, a_uint32_t list_id) |
| { |
| isis_acl_list_t *sw_list; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < list_id) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| sw_list = _isis_acl_list_loc(dev_id, list_id); |
| if (NULL == sw_list) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| if (0 != sw_list->bind_pts) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| if (0 != sw_list->rule_nr) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| aos_mem_zero(sw_list, sizeof (isis_acl_list_t)); |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_add(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr, |
| fal_acl_rule_t * rule) |
| { |
| sw_error_t rv; |
| isis_acl_list_t *sw_list; |
| isis_acl_rule_t *sw_rule; |
| a_uint32_t i, free_flt_nr, old_flt_nr, old_flt_idx, new_flt_nr, bind_pts; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < list_id) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| if ((0 == rule_nr) || (NULL == rule)) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| sw_list = _isis_acl_list_loc(dev_id, list_id); |
| if (NULL == sw_list) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| if (rule_id != sw_list->rule_nr) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| old_flt_idx = 0; |
| old_flt_nr = 0; |
| free_flt_nr = 0; |
| aos_mem_zero(hw_rule_tmp[dev_id], |
| ISIS_HW_RULE_TMP_CNT * sizeof (isis_acl_rule_t)); |
| aos_mem_zero(sw_rule_tmp[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_rule_t)); |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][i]); |
| if (ENT_USED & sw_rule->status) |
| { |
| if (sw_rule->list_id == sw_list->list_id) |
| { |
| aos_mem_copy(&(hw_rule_tmp[dev_id][old_flt_nr]), sw_rule, |
| sizeof (isis_acl_rule_t)); |
| if (!old_flt_nr) |
| { |
| old_flt_idx = i; |
| } |
| old_flt_nr++; |
| } |
| } |
| else |
| { |
| free_flt_nr++; |
| } |
| } |
| |
| if (!free_flt_nr) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| /* parse rule entry and alloc rule resource */ |
| new_flt_nr = old_flt_nr; |
| for (i = 0; i < rule_nr; i++) |
| { |
| rv = _isis_acl_rule_sw_to_hw(dev_id, &rule[i], hw_rule_tmp[dev_id], |
| &new_flt_nr); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| if (free_flt_nr < (new_flt_nr - old_flt_nr)) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| for (i = old_flt_nr; i < new_flt_nr; i++) |
| { |
| hw_rule_tmp[dev_id][i].status |= ENT_USED; |
| hw_rule_tmp[dev_id][i].list_id = sw_list->list_id; |
| hw_rule_tmp[dev_id][i].list_pri = sw_list->list_pri; |
| bind_pts = sw_list->bind_pts; |
| SW_SET_REG_BY_FIELD(MAC_RUL_V4, SRC_PT, bind_pts, |
| (hw_rule_tmp[dev_id][i].filter.vlu[4])); |
| } |
| |
| for (i = 0; i < old_flt_nr; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][old_flt_idx + i]); |
| sw_rule->status &= (~ENT_USED); |
| sw_rule->status |= (ENT_TMP); |
| } |
| |
| rv = _isis_acl_rule_alloc(dev_id, sw_list, new_flt_nr); |
| if (SW_OK != rv) |
| { |
| aos_mem_zero(sw_rule_tmp[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_rule_t)); |
| rv = _isis_acl_rule_reorder(dev_id, sw_list); |
| } |
| |
| for (i = 0; i < old_flt_nr; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][i + old_flt_idx]); |
| sw_rule->status |= (ENT_USED); |
| sw_rule->status &= (~ENT_TMP); |
| } |
| SW_RTN_ON_ERROR(rv); |
| |
| _isis_acl_rule_sync(dev_id, 0, ISIS_MAX_FILTER); |
| sw_list->rule_nr += rule_nr; |
| |
| _isis_acl_sw_rule_dump("sw rule after add", sw_rule_ent[dev_id]); |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_delete(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr) |
| { |
| isis_acl_rule_t *sw_rule; |
| isis_acl_list_t *sw_list; |
| a_uint32_t i, flt_idx = 0, src_idx, dst_idx, del_nr = 0, flt_nr = 0; |
| sw_error_t rv; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < list_id) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| sw_list = _isis_acl_list_loc(dev_id, list_id); |
| if (NULL == sw_list) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| if (sw_list->rule_nr < (rule_id + rule_nr)) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| aos_mem_zero(hw_rule_tmp[dev_id], |
| ISIS_HW_RULE_TMP_CNT * sizeof (isis_acl_rule_t)); |
| aos_mem_zero(sw_rule_tmp[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_rule_t)); |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][i]); |
| if ((ENT_USED & sw_rule->status) && (sw_rule->list_id == list_id)) |
| { |
| if (!flt_nr) |
| { |
| flt_idx = i; |
| } |
| |
| if ((sw_rule->rule_id >= rule_id) |
| && (sw_rule->rule_id < (rule_id + rule_nr))) |
| { |
| del_nr++; |
| } |
| else |
| { |
| aos_mem_copy(&(hw_rule_tmp[dev_id][flt_idx + flt_nr]), sw_rule, |
| sizeof (isis_acl_rule_t)); |
| } |
| flt_nr++; |
| } |
| } |
| |
| if (!del_nr) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| _isis_acl_sw_rule_dump("hw rule before del", hw_rule_tmp[dev_id]); |
| |
| for (i = 0; i < flt_nr; i++) |
| { |
| sw_rule = &(hw_rule_tmp[dev_id][flt_idx + i]); |
| if (ENT_USED & sw_rule->status) |
| { |
| break; |
| } |
| } |
| |
| if (i != flt_nr) |
| { |
| src_idx = flt_idx + i; |
| dst_idx = flt_idx; |
| rv = _isis_acl_list_insert(dev_id, &src_idx, &dst_idx, |
| hw_rule_tmp[dev_id], sw_rule_tmp[dev_id]); |
| SW_RTN_ON_ERROR(rv); |
| } |
| |
| _isis_acl_rule_sync(dev_id, flt_idx, flt_nr); |
| sw_list->rule_nr -= rule_nr; |
| |
| _isis_acl_sw_rule_dump("sw rule after del", sw_rule_ent[dev_id]); |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_query(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, fal_acl_rule_t * rule) |
| { |
| sw_error_t rv; |
| isis_acl_rule_t *sw_rule; |
| a_uint32_t flt_nr = 0, i; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < list_id) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| aos_mem_zero(hw_rule_tmp[dev_id], |
| ISIS_HW_RULE_TMP_CNT * sizeof (isis_acl_rule_t)); |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][i]); |
| if (ENT_USED & sw_rule->status) |
| { |
| if ((sw_rule->list_id == list_id) && (sw_rule->rule_id == rule_id)) |
| { |
| aos_mem_copy(&(hw_rule_tmp[dev_id][flt_nr]), sw_rule, |
| sizeof (isis_acl_rule_t)); |
| flt_nr++; |
| } |
| } |
| } |
| |
| if (!flt_nr) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| aos_mem_zero(rule, sizeof (fal_acl_rule_t)); |
| rv = _isis_acl_rule_hw_to_sw(dev_id, rule, hw_rule_tmp[dev_id], 0, flt_nr); |
| return rv; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_bind(a_uint32_t dev_id, a_uint32_t list_id, a_uint32_t ports) |
| { |
| sw_error_t rv; |
| a_uint32_t i; |
| isis_acl_rule_t *sw_rule; |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][i]); |
| |
| if ((ENT_USED & sw_rule->status) |
| && (list_id == sw_rule->list_id) |
| && (!(ENT_DEACTIVE & sw_rule->status))) |
| { |
| rv = _isis_filter_ports_bind(dev_id, i, ports); |
| SW_RTN_ON_ERROR(rv); |
| |
| SW_SET_REG_BY_FIELD(MAC_RUL_V4, SRC_PT, ports, |
| (sw_rule->filter.vlu[4])); |
| } |
| } |
| |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_list_bind(a_uint32_t dev_id, a_uint32_t list_id, |
| fal_acl_direc_t direc, fal_acl_bind_obj_t obj_t, |
| a_uint32_t obj_idx) |
| { |
| sw_error_t rv; |
| a_uint32_t ports; |
| isis_acl_list_t *sw_list; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < list_id) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| if (FAL_ACL_DIREC_IN != direc) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| sw_list = _isis_acl_list_loc(dev_id, list_id); |
| if (NULL == sw_list) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| if (FAL_ACL_BIND_PORT == obj_t) |
| { |
| ports = (sw_list->bind_pts) | (0x1 << obj_idx); |
| } |
| else if (FAL_ACL_BIND_PORTBITMAP == obj_t) |
| { |
| ports = (sw_list->bind_pts) | obj_idx; |
| } |
| else |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| rv = _isis_acl_rule_bind(dev_id, list_id, ports); |
| SW_RTN_ON_ERROR(rv); |
| |
| sw_list->bind_pts = ports; |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_list_unbind(a_uint32_t dev_id, a_uint32_t list_id, |
| fal_acl_direc_t direc, fal_acl_bind_obj_t obj_t, |
| a_uint32_t obj_idx) |
| { |
| sw_error_t rv; |
| a_uint32_t ports; |
| isis_acl_list_t *sw_list; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < list_id) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| if (FAL_ACL_DIREC_IN != direc) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| sw_list = _isis_acl_list_loc(dev_id, list_id); |
| if (NULL == sw_list) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| if (FAL_ACL_BIND_PORT == obj_t) |
| { |
| ports = (sw_list->bind_pts) & (~(0x1UL << obj_idx)); |
| } |
| else if (FAL_ACL_BIND_PORTBITMAP == obj_t) |
| { |
| ports = (sw_list->bind_pts) & (~obj_idx); |
| } |
| else |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| rv = _isis_acl_rule_bind(dev_id, list_id, ports); |
| SW_RTN_ON_ERROR(rv); |
| |
| sw_list->bind_pts = ports; |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_status_set(a_uint32_t dev_id, a_bool_t enable) |
| { |
| sw_error_t rv; |
| a_uint32_t val; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (A_TRUE == enable) |
| { |
| val = 1; |
| } |
| else if (A_FALSE == enable) |
| { |
| val = 0; |
| } |
| else |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| HSL_REG_FIELD_SET(rv, dev_id, MOD_ENABLE, 0, ACL_EN, (a_uint8_t *) (&val), |
| sizeof (a_uint32_t)); |
| return rv; |
| } |
| |
| static sw_error_t |
| _isis_acl_status_get(a_uint32_t dev_id, a_bool_t * enable) |
| { |
| sw_error_t rv; |
| a_uint32_t val = 0; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| HSL_REG_FIELD_GET(rv, dev_id, MOD_ENABLE, 0, ACL_EN, (a_uint8_t *) (&val), |
| sizeof (a_uint32_t)); |
| SW_RTN_ON_ERROR(rv); |
| |
| if (val) |
| { |
| *enable = A_TRUE; |
| } |
| else |
| { |
| *enable = A_FALSE; |
| } |
| |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_port_udf_profile_set(a_uint32_t dev_id, fal_port_t port_id, |
| fal_acl_udf_type_t udf_type, a_uint32_t offset, |
| a_uint32_t length) |
| { |
| sw_error_t rv; |
| a_uint32_t reg = 0; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_UDF_MAX_OFFSET < offset) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| if (ISIS_UDF_MAX_OFFSET < length) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| if ((FAL_ACL_UDF_TYPE_L2_SNAP == udf_type) |
| || (FAL_ACL_UDF_TYPE_L3_PLUS == udf_type)) |
| { |
| HSL_REG_ENTRY_GET(rv, dev_id, WIN_RULE_CTL1, port_id, |
| (a_uint8_t *) (®), sizeof (a_uint32_t)); |
| } |
| else |
| { |
| HSL_REG_ENTRY_GET(rv, dev_id, WIN_RULE_CTL0, port_id, |
| (a_uint8_t *) (®), sizeof (a_uint32_t)); |
| } |
| SW_RTN_ON_ERROR(rv); |
| |
| switch (udf_type) |
| { |
| case FAL_ACL_UDF_TYPE_L2: |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL0, L2_OFFSET, offset, reg); |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL0, L2_LENGTH, length, reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L3: |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL0, L3_OFFSET, offset, reg); |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL0, L3_LENGTH, length, reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L4: |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL0, L4_OFFSET, offset, reg); |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL0, L4_LENGTH, length, reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L2_SNAP: |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL1, L2S_OFFSET, offset, reg); |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL1, L2S_LENGTH, length, reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L3_PLUS: |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL1, L3P_OFFSET, offset, reg); |
| SW_SET_REG_BY_FIELD(WIN_RULE_CTL1, L3P_LENGTH, length, reg); |
| break; |
| default: |
| return SW_BAD_PARAM; |
| } |
| |
| if ((FAL_ACL_UDF_TYPE_L2_SNAP == udf_type) |
| || (FAL_ACL_UDF_TYPE_L3_PLUS == udf_type)) |
| { |
| HSL_REG_ENTRY_SET(rv, dev_id, WIN_RULE_CTL1, port_id, |
| (a_uint8_t *) (®), sizeof (a_uint32_t)); |
| } |
| else |
| { |
| HSL_REG_ENTRY_SET(rv, dev_id, WIN_RULE_CTL0, port_id, |
| (a_uint8_t *) (®), sizeof (a_uint32_t)); |
| } |
| |
| return rv; |
| } |
| |
| static sw_error_t |
| _isis_acl_port_udf_profile_get(a_uint32_t dev_id, fal_port_t port_id, |
| fal_acl_udf_type_t udf_type, a_uint32_t * offset, |
| a_uint32_t * length) |
| { |
| sw_error_t rv; |
| a_uint32_t reg = 0; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if ((FAL_ACL_UDF_TYPE_L2_SNAP == udf_type) |
| || (FAL_ACL_UDF_TYPE_L3_PLUS == udf_type)) |
| { |
| HSL_REG_ENTRY_GET(rv, dev_id, WIN_RULE_CTL1, port_id, |
| (a_uint8_t *) (®), sizeof (a_uint32_t)); |
| } |
| else |
| { |
| HSL_REG_ENTRY_GET(rv, dev_id, WIN_RULE_CTL0, port_id, |
| (a_uint8_t *) (®), sizeof (a_uint32_t)); |
| } |
| SW_RTN_ON_ERROR(rv); |
| |
| switch (udf_type) |
| { |
| case FAL_ACL_UDF_TYPE_L2: |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL0, L2_OFFSET, (*offset), reg); |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL0, L2_LENGTH, (*length), reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L3: |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL0, L3_OFFSET, (*offset), reg); |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL0, L3_LENGTH, (*length), reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L4: |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL0, L4_OFFSET, (*offset), reg); |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL0, L4_LENGTH, (*length), reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L2_SNAP: |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL1, L2S_OFFSET, (*offset), reg); |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL1, L2S_LENGTH, (*length), reg); |
| break; |
| case FAL_ACL_UDF_TYPE_L3_PLUS: |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL1, L3P_OFFSET, (*offset), reg); |
| SW_GET_FIELD_BY_REG(WIN_RULE_CTL1, L3P_LENGTH, (*length), reg); |
| break; |
| default: |
| return SW_BAD_PARAM; |
| } |
| |
| return SW_OK; |
| } |
| |
| static sw_error_t |
| _isis_acl_rule_active(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr, a_bool_t active) |
| { |
| sw_error_t rv; |
| a_uint32_t i, ports; |
| isis_acl_list_t *sw_list; |
| isis_acl_rule_t *sw_rule; |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| sw_list = _isis_acl_list_loc(dev_id, list_id); |
| if (NULL == sw_list) |
| { |
| return SW_NOT_FOUND; |
| } |
| |
| if (sw_list->rule_nr < (rule_id + rule_nr)) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| if (A_TRUE == active) |
| { |
| ports = (sw_list->bind_pts); |
| } |
| else |
| { |
| ports = 0; |
| } |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_rule = &(sw_rule_ent[dev_id][i]); |
| |
| if ((ENT_USED & sw_rule->status) |
| && (list_id == sw_rule->list_id) |
| && (rule_id <= sw_rule->rule_id) |
| && ((rule_id + rule_nr) > sw_rule->rule_id)) |
| { |
| rv = _isis_filter_ports_bind(dev_id, i, ports); |
| SW_RTN_ON_ERROR(rv); |
| |
| SW_SET_REG_BY_FIELD(MAC_RUL_V4, SRC_PT, ports, |
| (sw_rule->filter.vlu[4])); |
| |
| if (A_TRUE == active) |
| { |
| sw_rule->status &= (~ENT_DEACTIVE); |
| } |
| else |
| { |
| sw_rule->status |= (ENT_DEACTIVE); |
| } |
| } |
| } |
| |
| return SW_OK; |
| } |
| |
| HSL_LOCAL sw_error_t |
| isis_acl_list_dump(a_uint32_t dev_id) |
| { |
| _isis_acl_list_dump(dev_id); |
| return SW_OK; |
| } |
| |
| HSL_LOCAL sw_error_t |
| isis_acl_rule_dump(a_uint32_t dev_id) |
| { |
| a_uint32_t flt_idx, i; |
| sw_error_t rv; |
| hw_filter_t filter; |
| |
| aos_printk("\nisis_acl_rule_dump:\n"); |
| |
| for (flt_idx = 0; flt_idx < ISIS_MAX_FILTER; flt_idx++) |
| { |
| aos_mem_zero(&filter, sizeof (hw_filter_t)); |
| |
| rv = _isis_filter_up_to_sw(dev_id, &filter, flt_idx); |
| if (SW_OK != rv) |
| { |
| continue; |
| } |
| |
| aos_printk("\n%d filter dump:", flt_idx); |
| |
| aos_printk("\nhardware content:"); |
| aos_printk("\nact:"); |
| for (i = 0; i < (sizeof (filter.act) / sizeof (a_uint32_t)); i++) |
| { |
| aos_printk("%08x ", filter.act[i]); |
| } |
| |
| aos_printk("\nvlu:"); |
| for (i = 0; i < (sizeof (filter.vlu) / sizeof (a_uint32_t)); i++) |
| { |
| aos_printk("%08x ", filter.vlu[i]); |
| } |
| |
| aos_printk("\nmsk:"); |
| for (i = 0; i < (sizeof (filter.msk) / sizeof (a_uint32_t)); i++) |
| { |
| aos_printk("%08x ", filter.msk[i]); |
| } |
| |
| aos_printk("\nsoftware content:"); |
| aos_printk("\nact:"); |
| for (i = 0; i < (sizeof (filter.act) / sizeof (a_uint32_t)); i++) |
| { |
| aos_printk("%08x ", sw_rule_ent[dev_id][flt_idx].filter.act[i]); |
| } |
| |
| aos_printk("\nvlu:"); |
| for (i = 0; i < (sizeof (filter.vlu) / sizeof (a_uint32_t)); i++) |
| { |
| aos_printk("%08x ", sw_rule_ent[dev_id][flt_idx].filter.vlu[i]); |
| } |
| |
| aos_printk("\nmsk:"); |
| for (i = 0; i < (sizeof (filter.msk) / sizeof (a_uint32_t)); i++) |
| { |
| aos_printk("%08x ", sw_rule_ent[dev_id][flt_idx].filter.msk[i]); |
| } |
| |
| aos_printk("\nctl:status[%02d] list_id[%02d] rule_id[%02d]", |
| sw_rule_ent[dev_id][flt_idx].status, |
| sw_rule_ent[dev_id][flt_idx].list_id, |
| sw_rule_ent[dev_id][flt_idx].rule_id); |
| |
| aos_printk("\n\n"); |
| } |
| |
| return SW_OK; |
| } |
| |
| sw_error_t |
| isis_acl_reset(a_uint32_t dev_id) |
| { |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| aos_mem_zero(sw_list_ent[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_list_t)); |
| |
| aos_mem_zero(sw_rule_ent[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_rule_t)); |
| |
| return SW_OK; |
| } |
| |
| /** |
| * @brief Creat an acl list |
| * @details Comments: |
| * If the value of list_pri is more small then the priority is more high, |
| * that means the list could be first matched. |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] list_pri acl list priority |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_list_creat(a_uint32_t dev_id, a_uint32_t list_id, a_uint32_t list_pri) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_list_creat(dev_id, list_id, list_pri); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Destroy an acl list |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @return SW_OK or error code |
| */ |
| HSL_LOCAL sw_error_t |
| isis_acl_list_destroy(a_uint32_t dev_id, a_uint32_t list_id) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_list_destroy(dev_id, list_id); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Add one rule or more rules to an existing acl list |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] rule_id first rule id of this adding operation in list |
| * @param[in] rule_nr rule number of this adding operation |
| * @param[in] rule rules content of this adding operation |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_rule_add(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr, fal_acl_rule_t * rule) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_rule_add(dev_id, list_id, rule_id, rule_nr, rule); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Delete one rule or more rules from an existing acl list |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] rule_id first rule id of this deleteing operation in list |
| * @param[in] rule_nr rule number of this deleteing operation |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_rule_delete(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_rule_delete(dev_id, list_id, rule_id, rule_nr); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Query one particular rule in a particular acl list |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] rule_id first rule id of this deleteing operation in list |
| * @param[out] rule rule content of this operation |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_rule_query(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, fal_acl_rule_t * rule) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_rule_query(dev_id, list_id, rule_id, rule); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| a_uint32_t |
| isis_acl_rule_get_offset(a_uint32_t dev_id, a_uint32_t list_id, a_uint32_t rule_id) |
| { |
| a_uint32_t i, pos=0; |
| isis_acl_rule_t *sw_rule; |
| |
| for (i = 0; i < ISIS_MAX_FILTER; i++) |
| { |
| sw_rule = &(sw_rule_ent[0][i]); |
| |
| if ((ENT_USED & sw_rule->status) |
| && (list_id == sw_rule->list_id) && (sw_rule->rule_id == rule_id) |
| && (!(ENT_DEACTIVE & sw_rule->status))) |
| { |
| pos = i; |
| break; |
| |
| } |
| } |
| |
| return pos; |
| } |
| |
| |
| sw_error_t |
| isis_acl_rule_sync_multi_portmap(a_uint32_t dev_id, a_uint32_t pos, a_uint32_t *act) |
| { |
| |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (ISIS_MAX_LIST_ID < pos) |
| { |
| return SW_NOT_SUPPORTED; |
| } |
| |
| sw_rule_ent[dev_id][pos].filter.act[1] = act[1]; |
| sw_rule_ent[dev_id][pos].filter.act[2] = act[2]; |
| |
| sw_rule_tmp[dev_id][pos].filter.act[1] = act[1]; |
| sw_rule_tmp[dev_id][pos].filter.act[2] = act[2]; |
| |
| hw_rule_tmp[dev_id][pos].filter.act[1] = act[1]; |
| hw_rule_tmp[dev_id][pos].filter.act[2] = act[2]; |
| |
| |
| return SW_OK; |
| } |
| |
| /** |
| * @brief Bind an acl list to a particular object |
| * @details Comments: |
| * If obj_t equals FAL_ACL_BIND_PORT then obj_idx means port id |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] direc direction of this binding operation |
| * @param[in] obj_t object type of this binding operation |
| * @param[in] obj_idx object index of this binding operation |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_list_bind(a_uint32_t dev_id, a_uint32_t list_id, |
| fal_acl_direc_t direc, fal_acl_bind_obj_t obj_t, |
| a_uint32_t obj_idx) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_list_bind(dev_id, list_id, direc, obj_t, obj_idx); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Unbind an acl list from a particular object |
| * @details Comments: |
| * If obj_t equals FAL_ACL_BIND_PORT then obj_idx means port id |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] direc direction of this unbinding operation |
| * @param[in] obj_t object type of this unbinding operation |
| * @param[in] obj_idx object index of this unbinding operation |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_list_unbind(a_uint32_t dev_id, a_uint32_t list_id, |
| fal_acl_direc_t direc, fal_acl_bind_obj_t obj_t, |
| a_uint32_t obj_idx) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_list_unbind(dev_id, list_id, direc, obj_t, obj_idx); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Set working status of ACL engine on a particular device |
| * @param[in] dev_id device id |
| * @param[in] enable A_TRUE or A_FALSE |
| * @return SW_OK or error code |
| */ |
| sw_error_t |
| isis_acl_status_set(a_uint32_t dev_id, a_bool_t enable) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_status_set(dev_id, enable); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Get working status of ACL engine on a particular device |
| * @param[in] dev_id device id |
| * @param[out] enable A_TRUE or A_FALSE |
| * @return SW_OK or error code |
| */ |
| HSL_LOCAL sw_error_t |
| isis_acl_status_get(a_uint32_t dev_id, a_bool_t * enable) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_status_get(dev_id, enable); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Set user define fields profile on a particular port |
| * @param[in] dev_id device id |
| * @param[in] port_id port id |
| * @param[in] udf_type udf type |
| * @param[in] offset udf offset |
| * @param[in] length udf length |
| * @return SW_OK or error code |
| */ |
| HSL_LOCAL sw_error_t |
| isis_acl_port_udf_profile_set(a_uint32_t dev_id, fal_port_t port_id, |
| fal_acl_udf_type_t udf_type, a_uint32_t offset, |
| a_uint32_t length) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_port_udf_profile_set(dev_id, port_id, udf_type, offset, |
| length); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Get user define fields profile on a particular port |
| * @param[in] dev_id device id |
| * @param[in] port_id port id |
| * @param[in] udf_type udf type |
| * @param[out] offset udf offset |
| * @param[out] length udf length |
| * @return SW_OK or error code |
| */ |
| HSL_LOCAL sw_error_t |
| isis_acl_port_udf_profile_get(a_uint32_t dev_id, fal_port_t port_id, |
| fal_acl_udf_type_t udf_type, a_uint32_t * offset, |
| a_uint32_t * length) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_port_udf_profile_get(dev_id, port_id, udf_type, offset, |
| length); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Active one or more rules in an existing acl list |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] rule_id first rule id of this deactive operation in list |
| * @param[in] rule_nr rule number of this deactive operation |
| * @return SW_OK or error code |
| */ |
| HSL_LOCAL sw_error_t |
| isis_acl_rule_active(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_rule_active(dev_id, list_id, rule_id, rule_nr, A_TRUE); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| /** |
| * @brief Deactive one or more rules in an existing acl list |
| * @param[in] dev_id device id |
| * @param[in] list_id acl list id |
| * @param[in] rule_id first rule id of this deactive operation in list |
| * @param[in] rule_nr rule number of this deactive operation |
| * @return SW_OK or error code |
| */ |
| HSL_LOCAL sw_error_t |
| isis_acl_rule_deactive(a_uint32_t dev_id, a_uint32_t list_id, |
| a_uint32_t rule_id, a_uint32_t rule_nr) |
| { |
| sw_error_t rv; |
| |
| HSL_API_LOCK; |
| rv = _isis_acl_rule_active(dev_id, list_id, rule_id, rule_nr, A_FALSE); |
| HSL_API_UNLOCK; |
| return rv; |
| } |
| |
| sw_error_t |
| isis_acl_init(a_uint32_t dev_id) |
| { |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| sw_list_ent[dev_id] = |
| (isis_acl_list_t *) aos_mem_alloc(ISIS_MAX_FILTER * |
| sizeof (isis_acl_list_t)); |
| if (NULL == sw_list_ent[dev_id]) |
| { |
| return SW_NO_RESOURCE; |
| } |
| aos_mem_zero(sw_list_ent[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_list_t)); |
| |
| sw_rule_ent[dev_id] = |
| (isis_acl_rule_t *) aos_mem_alloc(ISIS_MAX_FILTER * |
| sizeof (isis_acl_rule_t)); |
| if (NULL == sw_rule_ent[dev_id]) |
| { |
| return SW_NO_RESOURCE; |
| } |
| aos_mem_zero(sw_rule_ent[dev_id], |
| ISIS_MAX_FILTER * sizeof (isis_acl_rule_t)); |
| |
| hw_rule_tmp[dev_id] = |
| (isis_acl_rule_t *) aos_mem_alloc(ISIS_HW_RULE_TMP_CNT * |
| sizeof (isis_acl_rule_t)); |
| if (NULL == hw_rule_tmp[dev_id]) |
| { |
| return SW_NO_RESOURCE; |
| } |
| |
| sw_rule_tmp[dev_id] = |
| (isis_acl_rule_t *) aos_mem_alloc(ISIS_MAX_FILTER * |
| sizeof (isis_acl_rule_t)); |
| if (NULL == sw_rule_tmp[dev_id]) |
| { |
| return SW_NO_RESOURCE; |
| } |
| #ifdef ISIS_SW_ENTRY |
| sw_filter_mem = aos_mem_alloc(ISIS_MAX_FILTER * sizeof (hw_filter_t)); |
| if (NULL == sw_filter_mem) |
| { |
| return SW_NO_RESOURCE; |
| } |
| aos_mem_zero(sw_filter_mem, ISIS_MAX_FILTER * sizeof (hw_filter_t)); |
| #endif |
| |
| #ifndef HSL_STANDALONG |
| { |
| hsl_api_t *p_api; |
| |
| SW_RTN_ON_NULL(p_api = hsl_api_ptr_get(dev_id)); |
| |
| p_api->acl_list_creat = isis_acl_list_creat; |
| p_api->acl_list_destroy = isis_acl_list_destroy; |
| p_api->acl_list_bind = isis_acl_list_bind; |
| p_api->acl_list_unbind = isis_acl_list_unbind; |
| p_api->acl_rule_add = isis_acl_rule_add; |
| p_api->acl_rule_delete = isis_acl_rule_delete; |
| p_api->acl_rule_query = isis_acl_rule_query; |
| p_api->acl_status_set = isis_acl_status_set; |
| p_api->acl_status_get = isis_acl_status_get; |
| p_api->acl_list_dump = isis_acl_list_dump; |
| p_api->acl_rule_dump = isis_acl_rule_dump; |
| p_api->acl_port_udf_profile_set = isis_acl_port_udf_profile_set; |
| p_api->acl_port_udf_profile_get = isis_acl_port_udf_profile_get; |
| p_api->acl_rule_active = isis_acl_rule_active; |
| p_api->acl_rule_deactive = isis_acl_rule_deactive; |
| p_api->acl_rule_get_offset = isis_acl_rule_get_offset; |
| p_api->acl_rule_sync_multi_portmap = isis_acl_rule_sync_multi_portmap; |
| } |
| #endif |
| |
| return SW_OK; |
| } |
| |
| sw_error_t |
| isis_acl_cleanup(a_uint32_t dev_id) |
| { |
| HSL_DEV_ID_CHECK(dev_id); |
| |
| if (NULL != sw_list_ent[dev_id]) |
| { |
| aos_mem_free(sw_list_ent[dev_id]); |
| } |
| |
| if (NULL != sw_rule_ent[dev_id]) |
| { |
| aos_mem_free(sw_rule_ent[dev_id]); |
| } |
| |
| if (NULL != hw_rule_tmp[dev_id]) |
| { |
| aos_mem_free(hw_rule_tmp[dev_id]); |
| } |
| |
| if (NULL != sw_rule_tmp[dev_id]) |
| { |
| aos_mem_free(sw_rule_tmp[dev_id]); |
| } |
| #ifdef DESS_SW_ENTRY |
| if (NULL != sw_filter_mem) |
| { |
| aos_mem_free(sw_filter_mem); |
| } |
| #endif |
| |
| return SW_OK; |
| } |
| /** |
| * @} |
| */ |
| |