Commit cfd34f8e authored by Vishwanathapura, Niranjana's avatar Vishwanathapura, Niranjana Committed by Doug Ledford

IB/opa-vnic: VNIC Ethernet Management Agent (VEMA) interface

OPA VNIC EMA interface functions are the management interfaces to the OPA
VNIC netdev. Add support to add and remove VNIC ports. Implement the
required GET/SET management interface functions and processing of new
management information. Add support to send trap notifications upon various
events like interface status change, unicast/multicast mac list update and
mac address change.
Reviewed-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Reviewed-by: default avatarIra Weiny <ira.weiny@intel.com>
Signed-off-by: default avatarNiranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: default avatarSadanand Warrier <sadanand.warrier@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 174e03d7
......@@ -3,4 +3,5 @@
#
obj-$(CONFIG_INFINIBAND_OPA_VNIC) += opa_vnic.o
opa_vnic-y := opa_vnic_netdev.o opa_vnic_encap.o opa_vnic_ethtool.o
opa_vnic-y := opa_vnic_netdev.o opa_vnic_encap.o opa_vnic_ethtool.o \
opa_vnic_vema_iface.o
......@@ -99,6 +99,10 @@
#define OPA_VNIC_DLID_SD_IS_SRC_MAC(dlid_sd) (!!((dlid_sd) & 0x20))
#define OPA_VNIC_DLID_SD_GET_DLID(dlid_sd) ((dlid_sd) >> 8)
/* VNIC Ethernet link status */
#define OPA_VNIC_ETH_LINK_UP 1
#define OPA_VNIC_ETH_LINK_DOWN 2
/**
* struct opa_vesw_info - OPA vnic switch information
* @fabric_id: 10-bit fabric id
......
......@@ -160,15 +160,29 @@ struct __opa_veswport_trap {
u32 reserved;
} __packed;
/**
* struct opa_vnic_ctrl_port - OPA virtual NIC control port
* @ibdev: pointer to ib device
* @ops: opa vnic control operations
*/
struct opa_vnic_ctrl_port {
struct ib_device *ibdev;
struct opa_vnic_ctrl_ops *ops;
};
/**
* struct opa_vnic_adapter - OPA VNIC netdev private data structure
* @netdev: pointer to associated netdev
* @ibdev: ib device
* @cport: pointer to opa vnic control port
* @rn_ops: rdma netdev's net_device_ops
* @port_num: OPA port number
* @vport_num: vesw port number
* @lock: adapter lock
* @info: virtual ethernet switch port information
* @vema_mac_addr: mac address configured by vema
* @umac_hash: unicast maclist hash
* @mmac_hash: multicast maclist hash
* @mactbl: hash table of MAC entries
* @mactbl_lock: mac table lock
* @stats_lock: statistics lock
......@@ -177,6 +191,7 @@ struct __opa_veswport_trap {
struct opa_vnic_adapter {
struct net_device *netdev;
struct ib_device *ibdev;
struct opa_vnic_ctrl_port *cport;
const struct net_device_ops *rn_ops;
u8 port_num;
......@@ -186,6 +201,9 @@ struct opa_vnic_adapter {
struct mutex lock;
struct __opa_veswport_info info;
u8 vema_mac_addr[ETH_ALEN];
u32 umac_hash;
u32 mmac_hash;
struct hlist_head __rcu *mactbl;
/* Lock used to protect updates to mac table */
......@@ -225,6 +243,11 @@ struct opa_vnic_mac_tbl_node {
#define v_warn(format, arg...) \
netdev_warn(adapter->netdev, format, ## arg)
#define c_err(format, arg...) \
dev_err(&cport->ibdev->dev, format, ## arg)
#define c_info(format, arg...) \
dev_info(&cport->ibdev->dev, format, ## arg)
/* The maximum allowed entries in the mac table */
#define OPA_VNIC_MAC_TBL_MAX_ENTRIES 2048
/* Limit of smac entries in mac table */
......@@ -264,11 +287,32 @@ void opa_vnic_rem_netdev(struct opa_vnic_adapter *adapter);
void opa_vnic_encap_skb(struct opa_vnic_adapter *adapter, struct sk_buff *skb);
u8 opa_vnic_get_vl(struct opa_vnic_adapter *adapter, struct sk_buff *skb);
u8 opa_vnic_calc_entropy(struct opa_vnic_adapter *adapter, struct sk_buff *skb);
void opa_vnic_process_vema_config(struct opa_vnic_adapter *adapter);
void opa_vnic_release_mac_tbl(struct opa_vnic_adapter *adapter);
void opa_vnic_query_mac_tbl(struct opa_vnic_adapter *adapter,
struct opa_veswport_mactable *tbl);
int opa_vnic_update_mac_tbl(struct opa_vnic_adapter *adapter,
struct opa_veswport_mactable *tbl);
void opa_vnic_query_ucast_macs(struct opa_vnic_adapter *adapter,
struct opa_veswport_iface_macs *macs);
void opa_vnic_query_mcast_macs(struct opa_vnic_adapter *adapter,
struct opa_veswport_iface_macs *macs);
void opa_vnic_get_summary_counters(struct opa_vnic_adapter *adapter,
struct opa_veswport_summary_counters *cntrs);
void opa_vnic_get_error_counters(struct opa_vnic_adapter *adapter,
struct opa_veswport_error_counters *cntrs);
void opa_vnic_get_vesw_info(struct opa_vnic_adapter *adapter,
struct opa_vesw_info *info);
void opa_vnic_set_vesw_info(struct opa_vnic_adapter *adapter,
struct opa_vesw_info *info);
void opa_vnic_get_per_veswport_info(struct opa_vnic_adapter *adapter,
struct opa_per_veswport_info *info);
void opa_vnic_set_per_veswport_info(struct opa_vnic_adapter *adapter,
struct opa_per_veswport_info *info);
void opa_vnic_vema_report_event(struct opa_vnic_adapter *adapter, u8 event);
struct opa_vnic_adapter *opa_vnic_add_vport(struct opa_vnic_ctrl_port *cport,
u8 port_num, u8 vport_num);
void opa_vnic_rem_vport(struct opa_vnic_adapter *adapter);
void opa_vnic_set_ethtool_ops(struct net_device *netdev);
#endif /* _OPA_VNIC_INTERNAL_H */
......@@ -52,6 +52,7 @@
#include <linux/module.h>
#include <linux/if_vlan.h>
#include <linux/crc32.h>
#include "opa_vnic_internal.h"
......@@ -111,6 +112,79 @@ static u16 opa_vnic_select_queue(struct net_device *netdev, struct sk_buff *skb,
return rc;
}
/* opa_vnic_process_vema_config - process vema configuration updates */
void opa_vnic_process_vema_config(struct opa_vnic_adapter *adapter)
{
struct __opa_veswport_info *info = &adapter->info;
struct rdma_netdev *rn = netdev_priv(adapter->netdev);
u8 port_num[OPA_VESW_MAX_NUM_DEF_PORT] = { 0 };
struct net_device *netdev = adapter->netdev;
u8 i, port_count = 0;
u16 port_mask;
/* If the base_mac_addr is changed, update the interface mac address */
if (memcmp(info->vport.base_mac_addr, adapter->vema_mac_addr,
ARRAY_SIZE(info->vport.base_mac_addr))) {
struct sockaddr saddr;
memcpy(saddr.sa_data, info->vport.base_mac_addr,
ARRAY_SIZE(info->vport.base_mac_addr));
mutex_lock(&adapter->lock);
eth_mac_addr(netdev, &saddr);
memcpy(adapter->vema_mac_addr,
info->vport.base_mac_addr, ETH_ALEN);
mutex_unlock(&adapter->lock);
}
rn->set_id(netdev, info->vesw.vesw_id);
/* Handle MTU limit change */
rtnl_lock();
netdev->max_mtu = max_t(unsigned int, info->vesw.eth_mtu_non_vlan,
netdev->min_mtu);
if (netdev->mtu > netdev->max_mtu)
dev_set_mtu(netdev, netdev->max_mtu);
rtnl_unlock();
/* Update flow to default port redirection table */
port_mask = info->vesw.def_port_mask;
for (i = 0; i < OPA_VESW_MAX_NUM_DEF_PORT; i++) {
if (port_mask & 1)
port_num[port_count++] = i;
port_mask >>= 1;
}
/*
* Build the flow table. Flow table is required when destination LID
* is not available. Up to OPA_VNIC_FLOW_TBL_SIZE flows supported.
* Each flow need a default port number to get its dlid from the
* u_ucast_dlid array.
*/
for (i = 0; i < OPA_VNIC_FLOW_TBL_SIZE; i++)
adapter->flow_tbl[i] = port_count ? port_num[i % port_count] :
OPA_VNIC_INVALID_PORT;
/* Operational state can only be DROP_ALL or FORWARDING */
if (info->vport.config_state == OPA_VNIC_STATE_FORWARDING) {
info->vport.oper_state = OPA_VNIC_STATE_FORWARDING;
netif_dormant_off(netdev);
} else {
info->vport.oper_state = OPA_VNIC_STATE_DROP_ALL;
netif_dormant_on(netdev);
}
}
/*
* Set the power on default values in adapter's vema interface structure.
*/
static inline void opa_vnic_set_pod_values(struct opa_vnic_adapter *adapter)
{
adapter->info.vport.max_mac_tbl_ent = OPA_VNIC_MAC_TBL_MAX_ENTRIES;
adapter->info.vport.max_smac_ent = OPA_VNIC_MAX_SMAC_LIMIT;
adapter->info.vport.config_state = OPA_VNIC_STATE_DROP_ALL;
adapter->info.vport.eth_link_status = OPA_VNIC_ETH_LINK_DOWN;
}
/* opa_vnic_set_mac_addr - change mac address */
static int opa_vnic_set_mac_addr(struct net_device *netdev, void *addr)
{
......@@ -124,8 +198,62 @@ static int opa_vnic_set_mac_addr(struct net_device *netdev, void *addr)
mutex_lock(&adapter->lock);
rc = eth_mac_addr(netdev, addr);
mutex_unlock(&adapter->lock);
if (rc)
return rc;
return rc;
adapter->info.vport.uc_macs_gen_count++;
opa_vnic_vema_report_event(adapter,
OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE);
return 0;
}
/*
* opa_vnic_mac_send_event - post event on possible mac list exchange
* Send trap when digest from uc/mc mac list differs from previous run.
* Digest is evaluated similar to how cksum does.
*/
static void opa_vnic_mac_send_event(struct net_device *netdev, u8 event)
{
struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev);
struct netdev_hw_addr *ha;
struct netdev_hw_addr_list *hw_list;
u32 *ref_crc;
u32 l, crc = 0;
switch (event) {
case OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE:
hw_list = &netdev->uc;
adapter->info.vport.uc_macs_gen_count++;
ref_crc = &adapter->umac_hash;
break;
case OPA_VESWPORT_TRAP_IFACE_MCAST_MAC_CHANGE:
hw_list = &netdev->mc;
adapter->info.vport.mc_macs_gen_count++;
ref_crc = &adapter->mmac_hash;
break;
default:
return;
}
netdev_hw_addr_list_for_each(ha, hw_list) {
crc = crc32_le(crc, ha->addr, ETH_ALEN);
}
l = netdev_hw_addr_list_count(hw_list) * ETH_ALEN;
crc = ~crc32_le(crc, (void *)&l, sizeof(l));
if (crc != *ref_crc) {
*ref_crc = crc;
opa_vnic_vema_report_event(adapter, event);
}
}
/* opa_vnic_set_rx_mode - handle uc/mc mac list change */
static void opa_vnic_set_rx_mode(struct net_device *netdev)
{
opa_vnic_mac_send_event(netdev,
OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE);
opa_vnic_mac_send_event(netdev,
OPA_VESWPORT_TRAP_IFACE_MCAST_MAC_CHANGE);
}
/* opa_netdev_open - activate network interface */
......@@ -140,6 +268,10 @@ static int opa_netdev_open(struct net_device *netdev)
return rc;
}
/* Update eth link status and send trap */
adapter->info.vport.eth_link_status = OPA_VNIC_ETH_LINK_UP;
opa_vnic_vema_report_event(adapter,
OPA_VESWPORT_TRAP_ETH_LINK_STATUS_CHANGE);
return 0;
}
......@@ -155,6 +287,10 @@ static int opa_netdev_close(struct net_device *netdev)
return rc;
}
/* Update eth link status and send trap */
adapter->info.vport.eth_link_status = OPA_VNIC_ETH_LINK_DOWN;
opa_vnic_vema_report_event(adapter,
OPA_VESWPORT_TRAP_ETH_LINK_STATUS_CHANGE);
return 0;
}
......@@ -164,6 +300,7 @@ static const struct net_device_ops opa_netdev_ops = {
.ndo_stop = opa_netdev_close,
.ndo_start_xmit = opa_netdev_start_xmit,
.ndo_get_stats64 = opa_vnic_get_stats64,
.ndo_set_rx_mode = opa_vnic_set_rx_mode,
.ndo_select_queue = opa_vnic_select_queue,
.ndo_set_mac_address = opa_vnic_set_mac_addr,
};
......@@ -212,6 +349,9 @@ struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev,
SET_NETDEV_DEV(netdev, ibdev->dev.parent);
opa_vnic_set_ethtool_ops(netdev);
opa_vnic_set_pod_values(adapter);
rc = register_netdev(netdev);
if (rc)
goto netdev_err;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment