[RFC PATCH 7/7] Get notifications from PF driver and configure filter block based on request data
Satha Koteswara Rao
satha.rao at caviumnetworks.com
Wed Dec 21 00:46:51 PST 2016
---
drivers/net/ethernet/cavium/thunder/pf_filter.c | 1678 +++++++++++++++++++++++
1 file changed, 1678 insertions(+)
create mode 100644 drivers/net/ethernet/cavium/thunder/pf_filter.c
diff --git a/drivers/net/ethernet/cavium/thunder/pf_filter.c b/drivers/net/ethernet/cavium/thunder/pf_filter.c
new file mode 100644
index 0000000..5a04da6
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/pf_filter.c
@@ -0,0 +1,1678 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/mman.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include "pf_globals.h"
+#include "pf_locals.h"
+#include "nic.h"
+
+u32 intr_to_ingressgrp[MAX_NUMNODES][TNS_MAC_FILTER_MAX_SYS_PORTS];
+struct vf_register_s vf_reg_data[MAX_NUMNODES][TNS_MAX_VF];
+struct ing_grp_gblvif ingressgrp_gblvif[MAX_NUMNODES][TNS_MAX_INGRESS_GROUP];
+
+u32 macfilter_freeindex[MAX_NUMNODES];
+u32 vlanfilter_freeindex[MAX_NUMNODES];
+
+int tns_filter_valid_entry(int node, int req_type, int vf, int vlan)
+{
+ if (req_type == NIC_MBOX_MSG_UC_MC) {
+ if (vf_reg_data[node][vf].vf_in_mcast_promis ||
+ (macfilter_freeindex[node] >= TNS_MAC_FILTER_MAX_INDEX))
+ return TNS_ERR_MAX_LIMIT;
+ if (vf_reg_data[node][vf].filter_count >= TNS_MAX_MAC_PER_VF) {
+ tns_enable_mcast_promis(node, vf);
+ vf_reg_data[node][vf].vf_in_mcast_promis = 1;
+ return TNS_ERR_MAX_LIMIT;
+ }
+ } else if (req_type == NIC_MBOX_MSG_VLAN ||
+ req_type == NIC_MBOX_MSG_ADMIN_VLAN) {
+ if (vf_reg_data[node][vf].vlan_count >= TNS_MAX_VLAN_PER_VF)
+ return TNS_ERR_MAX_LIMIT;
+
+ if (vlanfilter_freeindex[node] >= TNS_VLAN_FILTER_MAX_INDEX) {
+ int ret;
+ struct vlan_filter_entry tbl_entry;
+ int vlan_tbl_idx = -1;
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.key_value = 0x0ull;
+ tbl_entry.mask.key_type.key_value = ~0x0ull;
+ tbl_entry.key.key_type.s.ingress_grp =
+ intr_to_ingressgrp[node][vf];
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+ tbl_entry.key.key_type.s.vlan = vlan;
+ tbl_entry.mask.key_type.s.vlan = 0x0;
+
+ ret = filter_tbl_lookup(node, VLAN_FILTER_TABLE,
+ &tbl_entry, &vlan_tbl_idx);
+ if (ret || vlan_tbl_idx == -1)
+ return TNS_ERR_MAX_LIMIT;
+ }
+ } else {
+ filter_dbg(FERR, "Invalid Request %d VF %d\n", req_type, vf);
+ }
+
+ return TNS_NO_ERR;
+}
+
+int dump_port_cfg_etry(struct itt_entry_s *port_cfg_entry)
+{
+ filter_dbg(FINFO, "PortConfig Entry\n");
+ filter_dbg(FINFO, "pkt_dir: 0x%x\n",
+ port_cfg_entry->pkt_dir);
+ filter_dbg(FINFO, "is_admin_vlan_enabled: 0x%x\n",
+ port_cfg_entry->is_admin_vlan_enabled);
+ filter_dbg(FINFO, "default_evif: 0x%x\n",
+ port_cfg_entry->default_evif);
+ filter_dbg(FINFO, "admin_vlan: 0x%x\n",
+ port_cfg_entry->admin_vlan);
+
+ return TNS_NO_ERR;
+}
+
+int dump_evif_entry(struct evif_entry *evif_dat)
+{
+ filter_dbg(FINFO, "EVIF Entry\n");
+ filter_dbg(FINFO, "prt_bmap_136_73: 0x%llx\n",
+ evif_dat->prt_bmap_136_73);
+ filter_dbg(FINFO, "prt_bmap_72_9: 0x%llx\n",
+ evif_dat->prt_bmap_72_9);
+ filter_dbg(FINFO, "prt_bmap_8: 0x%x\n", evif_dat->prt_bmap_8);
+ filter_dbg(FINFO, "mre_ptr: 0x%x\n", evif_dat->mre_ptr);
+ filter_dbg(FINFO, "insert_ptr2: 0x%x\n", evif_dat->insert_ptr2);
+ filter_dbg(FINFO, "insert_ptr1: 0x%x\n", evif_dat->insert_ptr1);
+ filter_dbg(FINFO, "insert_ptr0: 0x%x\n", evif_dat->insert_ptr0);
+ filter_dbg(FINFO, "data31_0: 0x%x\n", evif_dat->data31_0);
+ filter_dbg(FINFO, "rewrite_ptr1: 0x%x\n", evif_dat->rewrite_ptr1);
+ filter_dbg(FINFO, "rewrite_ptr0: 0x%x\n", evif_dat->rewrite_ptr0);
+ filter_dbg(FINFO, "prt_bmap7_0: 0x%x\n", evif_dat->prt_bmap7_0);
+ filter_dbg(FINFO, "q_mirror_en: 0x%x\n", evif_dat->q_mirror_en);
+ filter_dbg(FINFO, "mirror_en: 0x%x\n", evif_dat->mirror_en);
+ filter_dbg(FINFO, "mtu_prf: 0x%x\n", evif_dat->mtu_prf);
+ filter_dbg(FINFO, "truncate: 0x%x\n", evif_dat->truncate);
+ filter_dbg(FINFO, "rsp_type: 0x%x\n", evif_dat->rsp_type);
+
+ return TNS_NO_ERR;
+}
+
+static inline int validate_port(int port_num)
+{
+ if (port_num < 0 && port_num >= TNS_MAC_FILTER_MAX_SYS_PORTS) {
+ filter_dbg(FERR, "%s Invalid Port: %d (Valid range 0-136)\n",
+ __func__, port_num);
+ return TNS_ERR_WRONG_PORT_NUMBER;
+ }
+ return TNS_NO_ERR;
+}
+
+int enable_port(int port_num, struct evif_entry *tbl_entry)
+{
+ s64 port_base;
+
+ if (validate_port(port_num))
+ return TNS_ERR_WRONG_PORT_NUMBER;
+
+ if (port_num < 8) {
+ tbl_entry->prt_bmap7_0 = tbl_entry->prt_bmap7_0 |
+ (0x1 << port_num);
+ } else if (port_num == 8) {
+ tbl_entry->prt_bmap_8 = 1;
+ } else if (port_num <= 72) {
+ port_base = port_num - 9;
+ tbl_entry->prt_bmap_72_9 = tbl_entry->prt_bmap_72_9 |
+ (0x1ull << port_base);
+ } else if (port_num <= TNS_MAC_FILTER_MAX_SYS_PORTS) {
+ port_base = port_num - 73;
+ tbl_entry->prt_bmap_136_73 = tbl_entry->prt_bmap_136_73 |
+ (0x1ull << port_base);
+ }
+
+ return TNS_NO_ERR;
+}
+
+int disable_port(int port_num, struct evif_entry *tbl_entry)
+{
+ s64 port_base;
+
+ if (validate_port(port_num))
+ return TNS_ERR_WRONG_PORT_NUMBER;
+
+ if (port_num < 8) {
+ tbl_entry->prt_bmap7_0 = tbl_entry->prt_bmap7_0 &
+ ~(0x1 << port_num);
+ } else if (port_num == 8) {
+ tbl_entry->prt_bmap_8 = 0;
+ } else if (port_num <= 72) {
+ port_base = port_num - 9;
+ tbl_entry->prt_bmap_72_9 = tbl_entry->prt_bmap_72_9 &
+ ~(0x1ull << port_base);
+ } else if (port_num <= TNS_MAC_FILTER_MAX_SYS_PORTS) {
+ port_base = port_num - 73;
+ tbl_entry->prt_bmap_136_73 = tbl_entry->prt_bmap_136_73 &
+ ~(0x1ull << port_base);
+ }
+
+ return TNS_NO_ERR;
+}
+
+int disable_all_ports(struct evif_entry *tbl_entry)
+{
+ tbl_entry->prt_bmap_136_73 = 0x0ull;
+ tbl_entry->prt_bmap_72_9 = 0x0ull;
+ tbl_entry->prt_bmap_8 = 0x0;
+ tbl_entry->prt_bmap7_0 = 0x0;
+
+ return TNS_NO_ERR;
+}
+
+int is_vlan_port_enabled(int vf, vlan_port_bitmap_t vlan_vif)
+{
+ int port_base = (vf / 8), port_offset = (vf % 8);
+
+ if (validate_port(vf))
+ return TNS_ERR_WRONG_PORT_NUMBER;
+
+ if (vlan_vif[port_base] & (1 << port_offset))
+ return 1;
+
+ return 0;
+}
+
+int enable_vlan_port(int port_num, vlan_port_bitmap_t vlan_vif)
+{
+ int port_base = (port_num / 8), port_offset = (port_num % 8);
+
+ if (validate_port(port_num))
+ return TNS_ERR_WRONG_PORT_NUMBER;
+
+ vlan_vif[port_base] = vlan_vif[port_base] | (1 << port_offset);
+
+ return TNS_NO_ERR;
+}
+
+int disable_vlan_port(int port_num, vlan_port_bitmap_t vlan_vif)
+{
+ int port_base = (port_num / 8), port_offset = (port_num % 8);
+
+ if (validate_port(port_num))
+ return TNS_ERR_WRONG_PORT_NUMBER;
+
+ vlan_vif[port_base] = vlan_vif[port_base] & ~(1 << port_offset);
+
+ return TNS_NO_ERR;
+}
+
+int disable_vlan_vif_ports(vlan_port_bitmap_t vlan_vif)
+{
+ memset((void *)(&vlan_vif[0]), 0x0, sizeof(vlan_port_bitmap_t));
+
+ return TNS_NO_ERR;
+}
+
+int dump_vlan_vif_portss(vlan_port_bitmap_t vlan_vif)
+{
+ int i;
+
+ filter_dbg(FINFO, "Port Bitmap (0...135) 0x ");
+ for (i = 0; i < (TNS_MAC_FILTER_MAX_SYS_PORTS / 8); i++)
+ filter_dbg(FINFO, "%x ", vlan_vif[i]);
+ filter_dbg(FINFO, "\n");
+
+ return TNS_NO_ERR;
+}
+
+static inline int getingress_grp(int node, int vf)
+{
+ int i;
+
+ for (i = 0; i < TNS_MAX_INGRESS_GROUP; i++) {
+ if (ingressgrp_gblvif[node][i].is_valid &&
+ (ingressgrp_gblvif[node][i].ingress_grp ==
+ intr_to_ingressgrp[node][vf]))
+ return i;
+ }
+ return -1;
+}
+
+inline int vf_bcast_vif(int node, int vf, int *bcast_vif)
+{
+ int ing_grp = getingress_grp(node, vf);
+
+ if (ing_grp == -1)
+ return TNS_ERR_ENTRY_NOT_FOUND;
+
+ *bcast_vif = ingressgrp_gblvif[node][ing_grp].bcast_vif;
+
+ return TNS_NO_ERR;
+}
+
+inline int vf_mcast_vif(int node, int vf, int *mcast_vif)
+{
+ int ing_grp = getingress_grp(node, vf);
+
+ if (ing_grp == -1)
+ return TNS_ERR_ENTRY_NOT_FOUND;
+
+ *mcast_vif = ingressgrp_gblvif[node][ing_grp].mcast_vif;
+
+ return TNS_NO_ERR;
+}
+
+inline int vf_pfvf_id(int node, int vf, int *pfvf)
+{
+ int ing_grp = getingress_grp(node, vf);
+
+ if (ing_grp == -1)
+ return TNS_ERR_ENTRY_NOT_FOUND;
+
+ *pfvf = ingressgrp_gblvif[node][ing_grp].pf_vf;
+
+ return TNS_NO_ERR;
+}
+
+bool is_vf_registered_entry(int node, int vf, int index)
+{
+ int i;
+
+ for (i = 0; i < vf_reg_data[node][vf].filter_count; i++) {
+ if (vf_reg_data[node][vf].filter_index[i] == index)
+ return true;
+ }
+
+ return false;
+}
+
+bool is_vlan_registered(int node, int vf, int vlan)
+{
+ int i;
+
+ for (i = 0; i < vf_reg_data[node][vf].vlan_count; i++) {
+ if (vf_reg_data[node][vf].vlan[i] == vlan)
+ return true;
+ }
+
+ return false;
+}
+
+int is_empty_vif(int node, int vf, struct evif_entry *evif_dat)
+{
+ int i;
+
+ for (i = 0; i < TNS_MAX_VF; i++)
+ if (intr_to_ingressgrp[node][vf] ==
+ intr_to_ingressgrp[node][i] &&
+ (vf_reg_data[node][i].vf_in_promis ||
+ vf_reg_data[node][i].vf_in_mcast_promis))
+ disable_port(i, evif_dat);
+ disable_port(intr_to_ingressgrp[node][vf], evif_dat);
+
+ if (evif_dat->prt_bmap7_0 || evif_dat->prt_bmap_8 ||
+ evif_dat->prt_bmap_72_9 || evif_dat->prt_bmap_136_73)
+ return 0;
+
+ return 1;
+}
+
+int is_empty_vlan(int node, int vf, int vlan, vlan_port_bitmap_t vlan_vif)
+{
+ int i, pf_vf;
+ int ret;
+
+ ret = vf_pfvf_id(node, vf, &pf_vf);
+ if (ret)
+ return ret;
+
+ if (vf_reg_data[node][pf_vf].vf_in_promis &&
+ !is_vlan_registered(node, pf_vf, vlan))
+ disable_vlan_port(pf_vf, vlan_vif);
+
+ disable_vlan_port(intr_to_ingressgrp[node][vf], vlan_vif);
+ for (i = 0; i < sizeof(vlan_port_bitmap_t); i++)
+ if (vlan_vif[i])
+ break;
+
+ if (i == sizeof(vlan_port_bitmap_t))
+ return 1;
+
+ return 0;
+}
+
+int filter_tbl_lookup(int node, int table_id, void *entry, int *index)
+{
+ switch (table_id) {
+ case MAC_FILTER_TABLE:
+ {
+ struct mac_filter_entry tbl_entry;
+ struct mac_filter_entry *inp = (struct mac_filter_entry *)entry;
+ int i;
+ int ret;
+
+ for (i = 0; i < TNS_MAC_FILTER_MAX_INDEX; i++) {
+ ret = tbl_read(node, MAC_FILTER_TABLE, i,
+ &tbl_entry.key, &tbl_entry.mask,
+ &tbl_entry.data);
+
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ if ((tbl_entry.key.key_type.key_value ==
+ inp->key.key_type.key_value) &&
+ (tbl_entry.mask.key_type.key_value ==
+ inp->mask.key_type.key_value)) {
+ //Found an Entry
+ *index = i;
+ inp->data.data = tbl_entry.data.data;
+ return TNS_NO_ERR;
+ }
+ //Unable to find entry
+ *index = -1;
+ }
+ break;
+ }
+ case VLAN_FILTER_TABLE:
+ {
+ struct vlan_filter_entry tbl_entry;
+ struct vlan_filter_entry *inp_entry;
+ int i;
+ int ret;
+
+ inp_entry = (struct vlan_filter_entry *)entry;
+ for (i = 1; i < TNS_VLAN_FILTER_MAX_INDEX; i++) {
+ ret = tbl_read(node, VLAN_FILTER_TABLE, i,
+ &tbl_entry.key, &tbl_entry.mask,
+ &tbl_entry.data);
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ if ((tbl_entry.key.key_type.key_value ==
+ inp_entry->key.key_type.key_value) &&
+ (tbl_entry.mask.key_type.key_value ==
+ inp_entry->mask.key_type.key_value)) {
+ //Found an Entry
+ *index = i;
+ inp_entry->data.data = tbl_entry.data.data;
+ return TNS_NO_ERR;
+ }
+ }
+ //Unable to find entry
+ *index = -1;
+ break;
+ }
+ default:
+ filter_dbg(FERR, "Wrong Table ID: %d\n", table_id);
+ return TNS_ERR_INVALID_TBL_ID;
+ }
+
+ return TNS_NO_ERR;
+}
+
+int tns_enable_mcast_promis(int node, int vf)
+{
+ int mcast_vif;
+ int j;
+ int ret;
+ struct evif_entry evif_dat;
+ int ing_grp = getingress_grp(node, vf);
+ int pports;
+
+ if (ing_grp == -1)
+ return TNS_ERROR_INVALID_ARG;
+
+ ret = vf_mcast_vif(node, vf, &mcast_vif);
+ if (ret) {
+ filter_dbg(FERR, "Error: Unable to get multicast VIF\n");
+ return ret;
+ }
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL, &evif_dat);
+ if (ret)
+ return ret;
+
+ enable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+
+ pports = ingressgrp_gblvif[node][ing_grp].valid_mcast_promis_ports;
+ //Enable VF in multicast MAC promiscuous group
+ for (j = 0; j < pports; j++) {
+ if (MCAST_PROMIS(node, ing_grp, j) == vf) {
+ filter_dbg(FDEBUG, "VF found in MCAST promis group\n");
+ return TNS_NO_ERR;
+ }
+ }
+ MCAST_PROMIS(node, ing_grp, pports) = vf;
+ ingressgrp_gblvif[node][ing_grp].valid_mcast_promis_ports += 1;
+ filter_dbg(FINFO, "VF %d permanently entered into MCAST promisc mode\n",
+ vf);
+
+ return TNS_NO_ERR;
+}
+
+int remove_vf_from_regi_mcast_vif(int node, int vf)
+{
+ int ret;
+ int mcast_vif;
+ struct evif_entry evif_dat;
+
+ ret = vf_mcast_vif(node, vf, &mcast_vif);
+ if (ret) {
+ filter_dbg(FERR, "Error: Unable to get multicast VIF\n");
+ return ret;
+ }
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL, &evif_dat);
+ if (ret)
+ return ret;
+ disable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+
+ return TNS_NO_ERR;
+}
+
+int remove_vf_from_mcast_promis_grp(int node, int vf)
+{
+ int j, k;
+ int ing_grp = getingress_grp(node, vf);
+ int pports;
+
+ if (ing_grp == -1)
+ return TNS_ERROR_INVALID_ARG;
+
+ pports = ingressgrp_gblvif[node][ing_grp].valid_mcast_promis_ports;
+ for (j = 0; j < pports; j++) {
+ if (MCAST_PROMIS(node, ing_grp, j) != vf)
+ continue;
+
+ filter_dbg(FDEBUG, "VF found in MCAST promis group %d\n",
+ intr_to_ingressgrp[node][vf]);
+ for (k = j; k < (pports - 1); k++)
+ MCAST_PROMIS(node, ing_grp, k) =
+ MCAST_PROMIS(node, ing_grp, (k + 1));
+ VALID_MCAST_PROMIS(node, ing_grp) -= 1;
+ remove_vf_from_regi_mcast_vif(node, vf);
+ return TNS_NO_ERR;
+ }
+ filter_dbg(FDEBUG, "VF %d not found in multicast promiscuous group\n",
+ vf);
+
+ return TNS_ERR_ENTRY_NOT_FOUND;
+}
+
+int registered_vf_filter_index(int node, int vf, int mac_idx, int action)
+{
+ int f_count = vf_reg_data[node][vf].filter_count, j;
+
+ if (!action) {
+ for (j = 0; j < f_count; j++) {
+ if (vf_reg_data[node][vf].filter_index[j] == mac_idx) {
+ int i, k = j + 1;
+
+ for (i = j; i < f_count - 1; i++, k++)
+ vf_reg_data[node][vf].filter_index[i] =
+ vf_reg_data[node][vf].filter_index[k];
+ break;
+ }
+ }
+ if (j == vf_reg_data[node][vf].filter_count)
+ filter_dbg(FDEBUG, "VF not in registered filtr list\n");
+ else
+ vf_reg_data[node][vf].filter_count -= 1;
+ } else {
+ vf_reg_data[node][vf].filter_index[f_count] = mac_idx;
+ vf_reg_data[node][vf].filter_count += 1;
+ filter_dbg(FINFO, "%s Added at Filter count %d Index %d\n",
+ __func__, vf_reg_data[node][vf].filter_count,
+ mac_idx);
+ }
+
+ /* We are restricting each VF to register atmost 11 filter entries
+ * (including unicast & multicast)
+ */
+ if (vf_reg_data[node][vf].filter_count <= TNS_MAX_MAC_PER_VF) {
+ vf_reg_data[node][vf].vf_in_mcast_promis = 0;
+ if (!vf_reg_data[node][vf].vf_in_promis)
+ remove_vf_from_mcast_promis_grp(node, vf);
+ filter_dbg(FINFO, "VF %d removed from MCAST promis mode\n", vf);
+ }
+
+ return TNS_NO_ERR;
+}
+
+int add_mac_filter_mcast_entry(int node, int table_id, int vf, int mac_idx,
+ void *mac_DA)
+{
+ int ret;
+ struct mac_filter_entry tbl_entry;
+ struct mac_filter_keymask_s key, mask;
+ union mac_filter_data_s data;
+ int vif = -1, k, j;
+ struct evif_entry evif_dat;
+ int ing_grp = getingress_grp(node, vf);
+
+ if (ing_grp == -1)
+ return TNS_ERROR_INVALID_ARG;
+
+ if (vf_reg_data[node][vf].filter_count >= TNS_MAX_MAC_PER_VF) {
+ if (!vf_reg_data[node][vf].vf_in_mcast_promis) {
+ tns_enable_mcast_promis(node, vf);
+ vf_reg_data[node][vf].vf_in_mcast_promis = 1;
+ }
+ return TNS_ERR_MAX_LIMIT;
+ }
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+ for (j = 5, k = 0; j >= 0; j--, k++) {
+ tbl_entry.key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+ tbl_entry.mask.key_type.s.mac_DA[k] = 0x0;
+ }
+ ret = filter_tbl_lookup(node, MAC_FILTER_TABLE, &tbl_entry, &mac_idx);
+ if (ret)
+ return ret;
+ if (mac_idx != -1 &&
+ !(mac_idx >= (TNS_MAC_FILTER_MAX_INDEX - TNS_MAX_INGRESS_GROUP) &&
+ mac_idx < TNS_MAC_FILTER_MAX_INDEX)) {
+ int evif = tbl_entry.data.s.evif;
+
+ filter_dbg(FINFO, "Multicast MAC found at %d evif: %d\n",
+ mac_idx, evif);
+ ret = tbl_read(node, MAC_EVIF_TABLE, evif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+ if (is_vf_registered_entry(node, vf, mac_idx)) {
+ //No Need to register again
+ return TNS_NO_ERR;
+ }
+ enable_port(vf, &evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, evif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+ registered_vf_filter_index(node, vf, mac_idx, 1);
+ dump_evif_entry(&evif_dat);
+ return TNS_NO_ERR;
+ }
+
+ //New multicast MAC registration
+ if (alloc_table_index(node, MAC_FILTER_TABLE, &mac_idx)) {
+ filter_dbg(FERR, "%s Filter Table Full\n", __func__);
+ return TNS_ERR_MAX_LIMIT;
+ }
+ key.is_valid = 1;
+ mask.is_valid = 1;
+ key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ mask.key_type.s.ingress_grp = 0;
+ for (j = 5, k = 0; j >= 0; j--, k++) {
+ key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+ mask.key_type.s.mac_DA[k] = 0x0;
+ }
+ if (alloc_table_index(node, MAC_EVIF_TABLE, &vif)) {
+ filter_dbg(FERR, "%s EVIF Table Full\n", __func__);
+ return TNS_ERR_MAX_LIMIT;
+ }
+ evif_dat.insert_ptr0 = 0xFFFF;
+ evif_dat.insert_ptr1 = 0xFFFF;
+ evif_dat.insert_ptr2 = 0xFFFF;
+ evif_dat.mre_ptr = 0x7FFF;
+ evif_dat.rewrite_ptr0 = 0xFF;
+ evif_dat.rewrite_ptr1 = 0xFF;
+ evif_dat.data31_0 = 0x0;
+ evif_dat.q_mirror_en = 0x0;
+ evif_dat.mirror_en = 0x0;
+ evif_dat.mtu_prf = 0x0;
+ evif_dat.truncate = 0x0;
+ evif_dat.rsp_type = 0x3;
+ disable_all_ports(&evif_dat);
+ for (j = 0; j < VALID_MCAST_PROMIS(node, ing_grp); j++)
+ enable_port(MCAST_PROMIS(node, ing_grp, j), &evif_dat);
+ enable_port(vf, &evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL, &evif_dat);
+ if (ret)
+ return ret;
+ data.data = 0x0ull;
+ data.s.evif = vif;
+ ret = tbl_write(node, MAC_FILTER_TABLE, mac_idx, &key, &mask, &data);
+ if (ret)
+ return ret;
+ macfilter_freeindex[node] += 1;
+ registered_vf_filter_index(node, vf, mac_idx, 1);
+
+ return TNS_NO_ERR;
+}
+
+int del_mac_filter_entry(int node, int table_id, int vf, int mac_idx,
+ void *mac_DA, int addr_type)
+{
+ int ret;
+ struct mac_filter_entry tbl_entry;
+ int old_mac_idx = -1, vif;
+ int j, k;
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+
+ for (j = 5, k = 0; j >= 0; j--, k++) {
+ tbl_entry.key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+ tbl_entry.mask.key_type.s.mac_DA[k] = 0x0;
+ }
+
+ ret = filter_tbl_lookup(node, MAC_FILTER_TABLE, (void *)&tbl_entry,
+ &old_mac_idx);
+ if (ret)
+ return ret;
+
+ if (old_mac_idx == -1) {
+ filter_dbg(FDEBUG, "Invalid Delete, entry not found\n");
+ return TNS_ERR_ENTRY_NOT_FOUND;
+ }
+ if (mac_idx != -1 && mac_idx != old_mac_idx) {
+ filter_dbg(FDEBUG, "Found and requested are mismatched\n");
+ return TNS_ERR_ENTRY_NOT_FOUND;
+ }
+ if (old_mac_idx == vf) {
+ filter_dbg(FDEBUG, "Primary Unicast MAC delete not allowed\n");
+ return TNS_ERR_MAC_FILTER_INVALID_ENTRY;
+ }
+
+ //Remove MAC Filter entry from VF register MAC filter list
+ registered_vf_filter_index(node, vf, old_mac_idx, 0);
+
+ //Remove VIF entry (output portmask) related to this filter entry
+ vif = tbl_entry.data.s.evif;
+ if (addr_type) {
+ struct evif_entry evif_dat;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+
+ disable_port(vf, &evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+
+ dump_evif_entry(&evif_dat);
+ //In case of multicast MAC check for empty portmask
+ if (!is_empty_vif(node, vf, &evif_dat))
+ return TNS_NO_ERR;
+ }
+ invalidate_table_entry(node, MAC_FILTER_TABLE, old_mac_idx);
+ free_table_index(node, MAC_FILTER_TABLE, old_mac_idx);
+ free_table_index(node, MAC_EVIF_TABLE, vif);
+ macfilter_freeindex[node] -= 1;
+
+ return TNS_NO_ERR;
+}
+
+int add_mac_filter_entry(int node, int table_id, int vf, int mac_idx,
+ void *mac_DA)
+{
+ int ret;
+ struct mac_filter_entry tbl_entry;
+ int old_mac_idx = -1;
+ int j, k;
+ struct mac_filter_keymask_s key, mask;
+ union mac_filter_data_s data;
+
+ /* We are restricting each VF to register atmost 11 filter entries
+ * (including unicast & multicast)
+ */
+ if (mac_idx != vf &&
+ vf_reg_data[node][vf].filter_count >= TNS_MAX_MAC_PER_VF) {
+ if (!vf_reg_data[node][vf].vf_in_mcast_promis) {
+ tns_enable_mcast_promis(node, vf);
+ vf_reg_data[node][vf].vf_in_mcast_promis = 1;
+ }
+ return TNS_ERR_MAX_LIMIT;
+ }
+
+ //Adding Multicast MAC will be handled differently
+ if ((((u8 *)mac_DA)[0]) & 0x1) {
+ filter_dbg(FDEBUG, "%s It is multicast MAC entry\n", __func__);
+ return add_mac_filter_mcast_entry(node, table_id, vf, mac_idx,
+ mac_DA);
+ }
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+ for (j = 5, k = 0; j >= 0; j--, k++) {
+ tbl_entry.key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+ tbl_entry.mask.key_type.s.mac_DA[k] = 0x0;
+ }
+ ret = filter_tbl_lookup(node, MAC_FILTER_TABLE, (void *)&tbl_entry,
+ &old_mac_idx);
+ if (ret)
+ return ret;
+ if (old_mac_idx != -1) {
+ filter_dbg(FINFO, "Duplicate entry found at %d\n", old_mac_idx);
+ if (tbl_entry.data.s.evif != vf) {
+ filter_dbg(FDEBUG, "Registered VF %d Requested VF %d\n",
+ (int)tbl_entry.data.s.evif, (int)vf);
+ return TNS_ERR_DUPLICATE_MAC;
+ }
+ return TNS_NO_ERR;
+ }
+ if (alloc_table_index(node, MAC_FILTER_TABLE, &mac_idx)) {
+ filter_dbg(FERR, "(%s) Filter Table Full\n", __func__);
+ return TNS_ERR_MAX_LIMIT;
+ }
+ if (mac_idx == -1) {
+ filter_dbg(FERR, "!!!ERROR!!! reached maximum limit\n");
+ return TNS_ERR_MAX_LIMIT;
+ }
+ key.is_valid = 1;
+ mask.is_valid = 1;
+ key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ mask.key_type.s.ingress_grp = 0;
+ for (j = 5, k = 0; j >= 0; j--, k++) {
+ key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+ mask.key_type.s.mac_DA[k] = 0x0;
+ }
+ filter_dbg(FINFO, "VF id: %d with ingress_grp: %d ", vf,
+ key.key_type.s.ingress_grp);
+ filter_dbg(FINFO, "MAC: %x: %x: %x %x: %x %x Added at Index: %d\n",
+ ((u8 *)mac_DA)[0], ((u8 *)mac_DA)[1],
+ ((u8 *)mac_DA)[2], ((u8 *)mac_DA)[3],
+ ((u8 *)mac_DA)[4], ((u8 *)mac_DA)[5], mac_idx);
+
+ data.data = 0x0ull;
+ data.s.evif = vf;
+ ret = tbl_write(node, MAC_FILTER_TABLE, mac_idx, &key, &mask, &data);
+ if (ret)
+ return ret;
+
+ if (mac_idx != vf) {
+ registered_vf_filter_index(node, vf, mac_idx, 1);
+ macfilter_freeindex[node] += 1;
+ }
+
+ return TNS_NO_ERR;
+}
+
+int vf_interface_up(int node, int tbl_id, int vf, void *mac_DA)
+{
+ int ret;
+
+ //Enable unicast MAC entry for this VF
+ ret = add_mac_filter_entry(node, tbl_id, vf, vf, mac_DA);
+ if (ret)
+ return ret;
+
+ return TNS_NO_ERR;
+}
+
+int del_vlan_entry(int node, int vf, int vlan, int vlanx)
+{
+ int ret;
+ struct vlan_filter_entry tbl_entry;
+ int vlan_tbl_idx = -1, i;
+ vlan_port_bitmap_t vlan_vif;
+ int vlan_cnt = vf_reg_data[node][vf].vlan_count;
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.key_value = 0x0ull;
+ tbl_entry.mask.key_type.key_value = 0xFFFFFFFFFFFFFFFFull;
+ tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+ tbl_entry.key.key_type.s.vlan = vlan;
+ tbl_entry.mask.key_type.s.vlan = 0x0;
+
+ filter_dbg(FINFO, "%s VF %d with ingress_grp %d VLANID %d\n",
+ __func__, vf, tbl_entry.key.key_type.s.ingress_grp,
+ tbl_entry.key.key_type.s.vlan);
+
+ ret = filter_tbl_lookup(node, VLAN_FILTER_TABLE, &tbl_entry,
+ &vlan_tbl_idx);
+ if (ret)
+ return ret;
+
+ if (vlan_tbl_idx == -1) {
+ filter_dbg(FINFO, "VF %d VLAN %d filter not registered\n",
+ vf, vlan);
+ return TNS_NO_ERR;
+ }
+
+ if (vlan_tbl_idx < 1 && vlan_tbl_idx >= TNS_VLAN_FILTER_MAX_INDEX) {
+ filter_dbg(FERR, "Invalid VLAN Idx: %d\n", vlan_tbl_idx);
+ return TNS_ERR_VLAN_FILTER_INVLAID_ENTRY;
+ }
+
+ vlanx = tbl_entry.data.s.filter_idx;
+ ret = tbl_read(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+
+ disable_vlan_port(vf, vlan_vif);
+ ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < vlan_cnt; i++) {
+ if (vf_reg_data[node][vf].vlan[i] == vlan) {
+ int j;
+
+ for (j = i; j < vlan_cnt - 1; j++)
+ vf_reg_data[node][vf].vlan[j] =
+ vf_reg_data[node][vf].vlan[j + 1];
+ vf_reg_data[node][vf].vlan_count -= 1;
+ break;
+ }
+ }
+ if (is_empty_vlan(node, vf, vlan, vlan_vif)) {
+ free_table_index(node, VLAN_FILTER_TABLE, vlanx);
+ vlanfilter_freeindex[node] -= 1;
+ invalidate_table_entry(node, VLAN_FILTER_TABLE, vlanx);
+ }
+
+ return TNS_NO_ERR;
+}
+
+int add_vlan_entry(int node, int vf, int vlan, int vlanx)
+{
+ int ret;
+ int pf_vf;
+ struct vlan_filter_entry tbl_entry;
+ int vlan_tbl_idx = -1;
+ vlan_port_bitmap_t vlan_vif;
+
+ if (vf_reg_data[node][vf].vlan_count >= TNS_MAX_VLAN_PER_VF) {
+ filter_dbg(FDEBUG, "Reached maximum limit per VF count: %d\n",
+ vf_reg_data[node][vf].vlan_count);
+ return TNS_ERR_MAX_LIMIT;
+ }
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.key_value = 0x0ull;
+ tbl_entry.mask.key_type.key_value = 0xFFFFFFFFFFFFFFFFull;
+ tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+ tbl_entry.key.key_type.s.vlan = vlan;
+ tbl_entry.mask.key_type.s.vlan = 0x0;
+
+ ret = filter_tbl_lookup(node, VLAN_FILTER_TABLE, &tbl_entry,
+ &vlan_tbl_idx);
+ if (ret)
+ return ret;
+
+ if (vlan_tbl_idx != -1) {
+ filter_dbg(FINFO, "Duplicate entry found at %d\n",
+ vlan_tbl_idx);
+ if (vlan_tbl_idx < 1 &&
+ vlan_tbl_idx >= TNS_VLAN_FILTER_MAX_INDEX) {
+ filter_dbg(FDEBUG, "Invalid VLAN Idx %d\n",
+ vlan_tbl_idx);
+ return TNS_ERR_VLAN_FILTER_INVLAID_ENTRY;
+ }
+
+ vlanx = tbl_entry.data.s.filter_idx;
+ ret = tbl_read(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+
+ enable_vlan_port(vf, vlan_vif);
+ ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+
+ vf_reg_data[node][vf].vlan[vf_reg_data[node][vf].vlan_count] =
+ vlan;
+ vf_reg_data[node][vf].vlan_count += 1;
+
+ return TNS_NO_ERR;
+ }
+
+ if (alloc_table_index(node, VLAN_FILTER_TABLE, &vlanx)) {
+ filter_dbg(FDEBUG, "%s VLAN Filter Table Full\n", __func__);
+ return TNS_ERR_MAX_LIMIT;
+ }
+ disable_vlan_vif_ports(vlan_vif);
+ enable_vlan_port(vf, vlan_vif);
+ enable_vlan_port(intr_to_ingressgrp[node][vf], vlan_vif);
+ ret = vf_pfvf_id(node, vf, &pf_vf);
+
+ if (ret)
+ return ret;
+
+ if (vf_reg_data[node][pf_vf].vf_in_promis)
+ enable_vlan_port(pf_vf, vlan_vif);
+
+ dump_vlan_vif_portss(vlan_vif);
+ ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+
+ tbl_entry.key.is_valid = 1;
+ tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+ tbl_entry.key.key_type.s.vlan = vlan;
+ tbl_entry.key.key_type.s.reserved = 0x0;
+ tbl_entry.key.key_type.s.reserved1 = 0x0;
+ tbl_entry.mask.is_valid = 1;
+ tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+ tbl_entry.mask.key_type.s.vlan = 0x0;
+ tbl_entry.mask.key_type.s.reserved = 0xF;
+ tbl_entry.mask.key_type.s.reserved1 = 0xFFFFFFFF;
+ tbl_entry.data.data = 0x0ull;
+ tbl_entry.data.s.filter_idx = vlanx;
+ ret = tbl_write(node, VLAN_FILTER_TABLE, vlanx, &tbl_entry.key,
+ &tbl_entry.mask, &tbl_entry.data);
+ if (ret)
+ return ret;
+
+ filter_dbg(FINFO, "VF %d with ingress_grp %d VLAN %d Added at %d\n",
+ vf, tbl_entry.key.key_type.s.ingress_grp,
+ tbl_entry.key.key_type.s.vlan, vlanx);
+
+ vlanfilter_freeindex[node] += 1;
+ vf_reg_data[node][vf].vlan[vf_reg_data[node][vf].vlan_count] = vlan;
+ vf_reg_data[node][vf].vlan_count += 1;
+
+ return TNS_NO_ERR;
+}
+
+int enable_promiscuous_mode(int node, int vf)
+{
+ int ret = tns_enable_mcast_promis(node, vf);
+ int pf_vf;
+
+ if (ret)
+ return ret;
+
+ vf_reg_data[node][vf].vf_in_promis = 1;
+ ret = vf_pfvf_id(node, vf, &pf_vf);
+ if (ret)
+ return ret;
+
+ if (vf == pf_vf) {
+ //PFVF interface, enable full promiscuous mode
+ int i;
+ int vif = intr_to_ingressgrp[node][vf];
+ struct evif_entry evif_dat;
+ struct itt_entry_s port_cfg_entry;
+
+ for (i = 0; i < macfilter_freeindex[node]; i++) {
+ struct mac_filter_entry tbl_entry;
+
+ ret = tbl_read(node, MAC_FILTER_TABLE, i,
+ &tbl_entry.key, &tbl_entry.mask,
+ &tbl_entry.data);
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ if (tbl_entry.key.key_type.s.ingress_grp ==
+ intr_to_ingressgrp[node][vf]) {
+ int vif = tbl_entry.data.s.evif;
+ struct evif_entry evif_dat;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL,
+ NULL, &evif_dat);
+ if (ret)
+ return ret;
+
+ enable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL,
+ NULL, (void *)&evif_dat);
+ if (ret)
+ return ret;
+ }
+ }
+ /*If pfVf interface enters in promiscuous mode we will forward
+ * packets destined to corresponding LMAC
+ */
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+ enable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+
+ /* Update default_evif of LMAC from NULLVif to pfVf interface,
+ * so that pfVf will shows all dropped packets as well
+ */
+ ret = tbl_read(node, PORT_CONFIG_TABLE,
+ intr_to_ingressgrp[node][vf], NULL, NULL,
+ &port_cfg_entry);
+ if (ret)
+ return ret;
+
+ port_cfg_entry.default_evif = vf;
+ ret = tbl_write(node, PORT_CONFIG_TABLE,
+ intr_to_ingressgrp[node][vf], NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+
+ filter_dbg(FINFO, "%s Port %d pkt_dir %d defaultVif %d",
+ __func__, vf, port_cfg_entry.pkt_dir,
+ port_cfg_entry.default_evif);
+ filter_dbg(FINFO, " adminVlan %d %s\n",
+ port_cfg_entry.admin_vlan,
+ port_cfg_entry.is_admin_vlan_enabled ? "Enable" :
+ "Disable");
+
+ for (i = 1; i < vlanfilter_freeindex[node]; i++) {
+ struct vlan_filter_entry tbl_entry;
+
+ ret = tbl_read(node, VLAN_FILTER_TABLE, i,
+ &tbl_entry.key, &tbl_entry.mask,
+ &tbl_entry.data);
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ if (tbl_entry.key.key_type.s.ingress_grp ==
+ intr_to_ingressgrp[node][vf]) {
+ int vlanx = tbl_entry.data.s.filter_idx;
+ vlan_port_bitmap_t vlan_vif;
+
+ ret = tbl_read(node, VLAN_EVIF_TABLE, vlanx,
+ NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+ enable_vlan_port(vf, vlan_vif);
+ ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx,
+ NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+ }
+ }
+ } else {
+ //VF interface enable multicast promiscuous mode
+ int i;
+ int ret;
+
+ for (i = TNS_MAX_VF; i < macfilter_freeindex[node]; i++) {
+ struct mac_filter_entry tbl_entry;
+
+ ret = tbl_read(node, MAC_FILTER_TABLE, i,
+ &tbl_entry.key, &tbl_entry.mask,
+ &tbl_entry.data);
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ /* We found filter entry, lets verify either this is
+ * unicast or multicast
+ */
+ if (((((u8 *)tbl_entry.key.key_type.s.mac_DA)[5]) &
+ 0x1) && (tbl_entry.key.key_type.s.ingress_grp ==
+ intr_to_ingressgrp[node][vf])) {
+ int vif = tbl_entry.data.s.evif;
+ struct evif_entry evif_dat;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL,
+ NULL, &evif_dat);
+ if (ret)
+ return ret;
+ enable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL,
+ NULL, (void *)&evif_dat);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+
+ return TNS_NO_ERR;
+}
+
+int disable_promiscuous_mode(int node, int vf)
+{
+ int i, pf_vf;
+ int ret;
+
+ vf_reg_data[node][vf].vf_in_promis = 0;
+ ret = vf_pfvf_id(node, vf, &pf_vf);
+ if (ret)
+ return ret;
+
+ for (i = TNS_MAX_VF; i < macfilter_freeindex[node]; i++) {
+ struct mac_filter_entry tbl_entry;
+
+ ret = tbl_read(node, MAC_FILTER_TABLE, i, &tbl_entry.key,
+ &tbl_entry.mask, &tbl_entry.data);
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ //We found an entry belongs to this group
+ if (tbl_entry.key.key_type.s.ingress_grp ==
+ intr_to_ingressgrp[node][vf]) {
+ int vif = tbl_entry.data.s.evif;
+ struct evif_entry evif_dat;
+
+ if (is_vf_registered_entry(node, vf, i))
+ continue;
+
+ //Is this multicast entry
+ if (((((u8 *)tbl_entry.key.key_type.s.mac_DA)[5]) &
+ 0x1) && vf_reg_data[node][vf].vf_in_mcast_promis)
+ continue;
+
+ //Disable port bitmap in EVIF entry
+ ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL,
+ NULL, &evif_dat);
+ if (ret)
+ return ret;
+ disable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+ }
+ }
+ /* If pfVf interface exit from promiscuous mode, then we will change
+ * portbitmap corresponding to LMAC
+ */
+ if (vf == pf_vf) {
+ int vif = intr_to_ingressgrp[node][vf];
+ struct evif_entry evif_dat;
+ struct itt_entry_s port_cfg_entry;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+
+ disable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+
+ for (i = 1; i < vlanfilter_freeindex[node]; i++) {
+ struct vlan_filter_entry tbl_entry;
+
+ ret = tbl_read(node, VLAN_FILTER_TABLE, i,
+ &tbl_entry.key, &tbl_entry.mask,
+ &tbl_entry.data);
+ if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+ return ret;
+ else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+ continue;
+
+ if (tbl_entry.key.key_type.s.ingress_grp ==
+ intr_to_ingressgrp[node][vf]) {
+ int vlanx = tbl_entry.data.s.filter_idx;
+ vlan_port_bitmap_t vlan_vif;
+ int vlan = tbl_entry.key.key_type.s.vlan;
+
+ if (!is_vlan_registered(node, vf, vlan)) {
+ ret = tbl_read(node, VLAN_EVIF_TABLE,
+ vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+ disable_vlan_port(vf, vlan_vif);
+ ret = tbl_write(node, VLAN_EVIF_TABLE,
+ vlanx, NULL, NULL,
+ (void *)(&vlan_vif[0]));
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ //Update default_evif of LMAC to NULLVif
+ ret = tbl_read(node, PORT_CONFIG_TABLE,
+ intr_to_ingressgrp[node][vf], NULL, NULL,
+ &port_cfg_entry);
+ if (ret)
+ return ret;
+
+ port_cfg_entry.default_evif = TNS_NULL_VIF;
+ ret = tbl_write(node, PORT_CONFIG_TABLE,
+ intr_to_ingressgrp[node][vf], NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ filter_dbg(FINFO, "%s Port %d pkt_dir %d defaultVif %d ",
+ __func__, vf, port_cfg_entry.pkt_dir,
+ port_cfg_entry.default_evif);
+ filter_dbg(FINFO, "adminVlan %d %s\n",
+ port_cfg_entry.admin_vlan,
+ port_cfg_entry.is_admin_vlan_enabled ? "Enable" :
+ "Disable");
+ }
+ if (!vf_reg_data[node][vf].vf_in_mcast_promis)
+ remove_vf_from_mcast_promis_grp(node, vf);
+
+ return TNS_NO_ERR;
+}
+
+/* CRB-1S configuration
+ * Valid LMAC's - 3 (128, 132, & 133)
+ * PFVF - 3 (0, 64, & 96)
+ * bcast_vif - 3 (136, 140, & 141)
+ * mcast_vif - 3 (144, 148, & 149)
+ * null_vif - 1 (152)
+ */
+int mac_filter_config(void)
+{
+ int node, j;
+
+ for (node = 0; node < nr_node_ids; node++) {
+ int lmac;
+
+ //Reset inerface to Ingress Group
+ for (j = 0; j < TNS_MAC_FILTER_MAX_SYS_PORTS; j++)
+ intr_to_ingressgrp[node][j] = j;
+
+ if (!pf_vf_map_data[node].valid)
+ continue;
+
+ for (j = 0; j < TNS_MAX_INGRESS_GROUP; j++)
+ ingressgrp_gblvif[node][j].is_valid = 0;
+
+ for (lmac = 0; lmac < pf_vf_map_data[node].lmac_cnt; lmac++) {
+ int slm = pf_vf_map_data[node].pf_vf[lmac].sys_lmac;
+ int valid_pf = pf_vf_map_data[node].pf_vf[lmac].pf_id;
+ int num_vfs = pf_vf_map_data[node].pf_vf[lmac].num_vfs;
+ struct evif_entry evif_dat;
+ int bvif, mvif;
+ int ret;
+
+ bvif = TNS_BASE_BCAST_VIF + slm;
+ mvif = TNS_BASE_MCAST_VIF + slm;
+
+ //Map inerface to Ingress Group
+ for (j = valid_pf; j < (valid_pf + num_vfs); j++) {
+ struct itt_entry_s port_cfg_entry;
+ int ret;
+
+ intr_to_ingressgrp[node][j] = TNS_MAX_VF + slm;
+
+ ret = tbl_read(node, PORT_CONFIG_TABLE, j, NULL,
+ NULL, (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ port_cfg_entry.default_evif =
+ intr_to_ingressgrp[node][j];
+ ret = tbl_write(node, PORT_CONFIG_TABLE, j,
+ NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ }
+
+ //LMAC Configuration
+ ingressgrp_gblvif[node][slm].is_valid = 1;
+ ingressgrp_gblvif[node][slm].ingress_grp = TNS_MAX_VF +
+ slm;
+ ingressgrp_gblvif[node][slm].pf_vf = valid_pf;
+ ingressgrp_gblvif[node][slm].bcast_vif = bvif;
+ ingressgrp_gblvif[node][slm].mcast_vif = mvif;
+ ingressgrp_gblvif[node][slm].null_vif = TNS_NULL_VIF;
+ MCAST_PROMIS(node, slm, 0) = TNS_MAX_VF + slm;
+ VALID_MCAST_PROMIS(node, slm) = 1;
+
+ filter_dbg(FINFO, "lmac %d syslm %d num_vfs %d ",
+ lmac, slm,
+ pf_vf_map_data[node].pf_vf[lmac].num_vfs);
+ filter_dbg(FINFO, "ingress_grp %d pfVf %d bCast %d ",
+ ingressgrp_gblvif[node][slm].ingress_grp,
+ ingressgrp_gblvif[node][slm].pf_vf,
+ ingressgrp_gblvif[node][slm].bcast_vif);
+ filter_dbg(FINFO, "mCast: %d\n",
+ ingressgrp_gblvif[node][slm].mcast_vif);
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, bvif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+
+ evif_dat.rewrite_ptr0 = 0xFF;
+ evif_dat.rewrite_ptr1 = 0xFF;
+ enable_port(ingressgrp_gblvif[node][slm].ingress_grp,
+ &evif_dat);
+
+ ret = tbl_write(node, MAC_EVIF_TABLE, bvif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, mvif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return ret;
+
+ evif_dat.rewrite_ptr0 = 0xFF;
+ evif_dat.rewrite_ptr1 = 0xFF;
+ enable_port(ingressgrp_gblvif[node][slm].ingress_grp,
+ &evif_dat);
+
+ ret = tbl_write(node, MAC_EVIF_TABLE, mvif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return ret;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, TNS_NULL_VIF, NULL,
+ NULL, &evif_dat);
+ if (ret)
+ return ret;
+
+ evif_dat.rewrite_ptr0 = 0xFF;
+ evif_dat.rewrite_ptr1 = 0xFF;
+
+ ret = tbl_write(node, MAC_EVIF_TABLE, TNS_NULL_VIF,
+ NULL, NULL, (void *)&evif_dat);
+ if (ret)
+ return ret;
+ }
+ j = 0;
+ alloc_table_index(node, VLAN_FILTER_TABLE, &j);
+
+ for (j = 0; j < TNS_MAX_VF; j++) {
+ vf_reg_data[node][j].vf_in_mcast_promis = 0;
+ vf_reg_data[node][j].filter_count = 1;
+ vf_reg_data[node][j].filter_index[0] = j;
+ vf_reg_data[node][j].vlan_count = 0;
+ alloc_table_index(node, MAC_FILTER_TABLE, &j);
+ }
+ for (j = 0; j <= TNS_NULL_VIF; j++)
+ alloc_table_index(node, MAC_EVIF_TABLE, &j);
+ macfilter_freeindex[node] = TNS_MAX_VF;
+ vlanfilter_freeindex[node] = 1;
+ }
+
+ return TNS_NO_ERR;
+}
+
+int add_admin_vlan(int node, int vf, int vlan)
+{
+ int index = -1;
+ int ret;
+ struct itt_entry_s port_cfg_entry;
+
+ ret = add_vlan_entry(node, vf, vlan, index);
+ if (ret) {
+ filter_dbg(FERR, "Add admin VLAN for VF: %d Failed %d\n",
+ vf, ret);
+ return ret;
+ }
+
+ ret = tbl_read(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ port_cfg_entry.is_admin_vlan_enabled = 1;
+ port_cfg_entry.admin_vlan = vlan;
+ ret = tbl_write(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ filter_dbg(FINFO, "%s Port %d dir %d defaultVif %d adminVlan %d %s\n",
+ __func__, vf, port_cfg_entry.pkt_dir,
+ port_cfg_entry.default_evif, port_cfg_entry.admin_vlan,
+ port_cfg_entry.is_admin_vlan_enabled ? "Enable" : "Disable");
+
+ return TNS_NO_ERR;
+}
+
+int del_admin_vlan(int node, int vf, int vlan)
+{
+ int index = -1;
+ int ret;
+ struct itt_entry_s port_cfg_entry;
+
+ ret = del_vlan_entry(node, vf, vlan, index);
+ if (ret) {
+ filter_dbg(FERR, "Delete admin VLAN: %d for VF %d failed %d\n",
+ vlan, vf, ret);
+ return ret;
+ }
+
+ ret = tbl_read(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ port_cfg_entry.is_admin_vlan_enabled = 0;
+ port_cfg_entry.admin_vlan = 0x0;
+ ret = tbl_write(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+ (void *)&port_cfg_entry);
+ if (ret)
+ return ret;
+ filter_dbg(FINFO, "%s Port %d dir %d defaultVif %d adminVlan %d %s\n",
+ __func__, vf, port_cfg_entry.pkt_dir,
+ port_cfg_entry.default_evif, port_cfg_entry.admin_vlan,
+ port_cfg_entry.is_admin_vlan_enabled ? "Enable" : "Disable");
+
+ return TNS_NO_ERR;
+}
+
+void link_status_notification(int node, int vf, void *arg)
+{
+ int status = *((int *)arg);
+ int bcast_vif;
+ int ret;
+ struct evif_entry evif_dat;
+
+ filter_dbg(FINFO, "VF %d Link %s\n", vf, status ? "up " : "down");
+ if (status) {
+ ret = vf_bcast_vif(node, vf, &bcast_vif);
+ if (ret)
+ return;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return;
+
+ enable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return;
+ } else {
+ ret = vf_bcast_vif(node, vf, &bcast_vif);
+ if (ret)
+ return;
+
+ ret = tbl_read(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+ &evif_dat);
+ if (ret)
+ return;
+
+ disable_port(vf, &evif_dat);
+ dump_evif_entry(&evif_dat);
+ ret = tbl_write(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+ (void *)&evif_dat);
+ if (ret)
+ return;
+ }
+}
+
+void mac_update_notification(int node, int vf_id, void *arg)
+{
+ u8 *mac = (u8 *)arg;
+
+ filter_dbg(FINFO, "VF:%d MAC %02x:%02x:%02x:%02x:%02x:%02x Updated\n",
+ vf_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ vf_interface_up(node, MAC_FILTER_TABLE, vf_id, arg);
+}
+
+void promisc_update_notification(int node, int vf_id, void *arg)
+{
+ int on = *(int *)arg;
+
+ filter_dbg(FERR, "VF %d %s promiscuous mode\n", vf_id,
+ on ? "enter" : "left");
+ if (on)
+ enable_promiscuous_mode(node, vf_id);
+ else
+ disable_promiscuous_mode(node, vf_id);
+}
+
+void uc_mc_update_notification(int node, int vf_id, void *arg)
+{
+ struct uc_mc_msg *uc_mc_cfg = (struct uc_mc_msg *)arg;
+ u8 *mac;
+
+ mac = (u8 *)uc_mc_cfg->mac_addr;
+ if (uc_mc_cfg->is_flush) {
+ filter_dbg(FINFO, "\nNOTIFICATION VF:%d %s %s\n", vf_id,
+ uc_mc_cfg->addr_type ? "mc" : "uc", "flush");
+ } else {
+ filter_dbg(FINFO, "\nNOTIFICATION VF:%d %s %s ", vf_id,
+ uc_mc_cfg->addr_type ? "mc" : "uc",
+ uc_mc_cfg->is_add ? "add" : "del");
+ filter_dbg(FINFO, "MAC ADDRESS %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ if (uc_mc_cfg->is_add) {
+ if (uc_mc_cfg->addr_type)
+ add_mac_filter_mcast_entry(node,
+ MAC_FILTER_TABLE,
+ vf_id, -1, mac);
+ else
+ add_mac_filter_entry(node, MAC_FILTER_TABLE,
+ vf_id, -1, mac);
+ } else {
+ del_mac_filter_entry(node, MAC_FILTER_TABLE, vf_id, -1,
+ mac, uc_mc_cfg->addr_type);
+ }
+ }
+}
+
+void admin_vlan_update_notification(int node, int vf_id, void *arg)
+{
+ struct vlan_msg *vlan_cfg = (struct vlan_msg *)arg;
+
+ filter_dbg(FINFO, "\nNOTIFICATION ADMIN VF %d VLAN id %d %s\n", vf_id,
+ vlan_cfg->vlan_id, (vlan_cfg->vlan_add) ? "add" : "del");
+ if (vlan_cfg->vlan_add)
+ add_admin_vlan(node, vf_id, vlan_cfg->vlan_id);
+ else
+ del_admin_vlan(node, vf_id, vlan_cfg->vlan_id);
+}
+
+void vlan_update_notification(int node, int vf_id, void *arg)
+{
+ struct vlan_msg *vlan_cfg = (struct vlan_msg *)arg;
+
+ filter_dbg(FINFO, "\nNOTIFICATION VF %d VLAN id %d %s\n", vf_id,
+ vlan_cfg->vlan_id, (vlan_cfg->vlan_add) ? "add" : "del");
+ if (vlan_cfg->vlan_add && vlan_cfg->vlan_id) {
+ int index = -1;
+ int ret = add_vlan_entry(node, vf_id, vlan_cfg->vlan_id,
+ index);
+
+ if (ret)
+ filter_dbg(FERR, "Adding VLAN failed: %d\n", ret);
+ else
+ filter_dbg(FINFO, "VF: %d with VLAN: %d added\n",
+ vf_id, vlan_cfg->vlan_id);
+ } else if (!vlan_cfg->vlan_add && vlan_cfg->vlan_id) {
+ int index = -1;
+ int ret = del_vlan_entry(node, vf_id, vlan_cfg->vlan_id,
+ index);
+
+ if (ret)
+ filter_dbg(FERR, "Deleting VLAN failed: %d\n", ret);
+ else
+ filter_dbg(FINFO, "VF: %d with VLAN: %d deleted\n",
+ vf_id, vlan_cfg->vlan_id);
+ }
+}
+
+void pf_notify_msg_handler(int node, void *arg)
+{
+ union nic_mbx *mbx = (union nic_mbx *)arg;
+ int status;
+
+ switch (mbx->msg.msg) {
+ case NIC_MBOX_MSG_ADMIN_VLAN:
+ admin_vlan_update_notification(node, mbx->vlan_cfg.vf_id,
+ &mbx->vlan_cfg);
+ break;
+ case NIC_MBOX_MSG_VLAN:
+ vlan_update_notification(node, mbx->vlan_cfg.vf_id,
+ &mbx->vlan_cfg);
+ break;
+ case NIC_MBOX_MSG_UC_MC:
+ uc_mc_update_notification(node, mbx->vlan_cfg.vf_id,
+ &mbx->uc_mc_cfg);
+ break;
+ case NIC_MBOX_MSG_SET_MAC:
+ mac_update_notification(node, mbx->mac.vf_id,
+ (void *)mbx->mac.mac_addr);
+ break;
+ case NIC_MBOX_MSG_CFG_DONE:
+ case NIC_MBOX_MSG_OP_UP:
+ status = true;
+ link_status_notification(node, mbx->mac.vf_id, (void *)&status);
+ break;
+ case NIC_MBOX_MSG_SHUTDOWN:
+ case NIC_MBOX_MSG_OP_DOWN:
+ status = false;
+ link_status_notification(node, mbx->mac.vf_id, (void *)&status);
+ break;
+ case NIC_MBOX_MSG_PROMISC:
+ status = mbx->promisc_cfg.on;
+ promisc_update_notification(node, mbx->promisc_cfg.vf_id,
+ (void *)&status);
+ break;
+ }
+}
+
+int pf_filter_init(void)
+{
+ mac_filter_config();
+
+ return 0;
+}
--
1.8.3.1
More information about the linux-arm-kernel
mailing list