Skip to content

Commit 5161601

Browse files
Neerav ParikhJeff Kirsher
authored andcommitted
i40e: Add support for getlink, setlink ndo ops
Add support for bridge offload ndo_ops getlink and setlink to enable bridge hardware mode as per the mode set via IFLA_BRIDGE_MODE. The support is only enabled in case of a PF VSI and not available for any other VSI type. By default the i40e driver inserts a bridge as part of the bring-up when a FDIR type VSI and/or a FCoE VSI is created. This bridge is created in VEB mode by default i.e. after creating the bridge using "Add VEB" AQ command the loopback for the PF's default VSI is enabled. The patch adds capability where all the VSIs created as downlink to the bridge inherits the loopback property and enables loopback only if the uplink bridge is operating in VEB mode. Hence, there is no need to explicitly enable loopback as part of allocating resources for SR-IOV VFs and call to do that has been removed. In case a user-request is made either via "bridge" utility or using the bridge netlink interface that requires to change the hardware bridge mode then that would require a PF reset and rebuild of the switch hierarchy. Also update the copyright year. Change-ID: I4d78fc1c83158efda29ba7be92239b74f75d6d25 Signed-off-by: Neerav Parikh <[email protected]> Tested-By: Jim Young <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 9666448 commit 5161601

File tree

6 files changed

+196
-22
lines changed

6 files changed

+196
-22
lines changed

drivers/net/ethernet/intel/i40e/i40e.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <net/ip6_checksum.h>
5151
#include <linux/ethtool.h>
5252
#include <linux/if_vlan.h>
53+
#include <linux/if_bridge.h>
5354
#include <linux/clocksource.h>
5455
#include <linux/net_tstamp.h>
5556
#include <linux/ptp_clock_kernel.h>
@@ -410,6 +411,7 @@ struct i40e_veb {
410411
u16 uplink_seid;
411412
u16 stats_idx; /* index of VEB parent */
412413
u8 enabled_tc;
414+
u16 bridge_mode; /* Bridge Mode (VEB/VEPA) */
413415
u16 flags;
414416
u16 bw_limit;
415417
u8 bw_max_quanta;
@@ -735,6 +737,7 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr);
735737
int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr);
736738
void i40e_ptp_init(struct i40e_pf *pf);
737739
void i40e_ptp_stop(struct i40e_pf *pf);
740+
int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi);
738741
#if IS_ENABLED(CONFIG_CONFIGFS_FS)
739742
int i40e_configfs_init(void);
740743
void i40e_configfs_exit(void);

drivers/net/ethernet/intel/i40e/i40e_debugfs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -921,9 +921,10 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid)
921921
return;
922922
}
923923
dev_info(&pf->pdev->dev,
924-
"veb idx=%d,%d stats_ic=%d seid=%d uplink=%d\n",
924+
"veb idx=%d,%d stats_ic=%d seid=%d uplink=%d mode=%s\n",
925925
veb->idx, veb->veb_idx, veb->stats_idx, veb->seid,
926-
veb->uplink_seid);
926+
veb->uplink_seid,
927+
veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB");
927928
i40e_dbg_dump_eth_stats(pf, &veb->stats);
928929
}
929930

drivers/net/ethernet/intel/i40e/i40e_fcoe.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*******************************************************************************
22
*
33
* Intel Ethernet Controller XL710 Family Linux Driver
4-
* Copyright(c) 2013 - 2014 Intel Corporation.
4+
* Copyright(c) 2013 - 2015 Intel Corporation.
55
*
66
* This program is free software; you can redistribute it and/or modify it
77
* under the terms and conditions of the GNU General Public License,
@@ -385,8 +385,7 @@ int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt)
385385
ctxt->flags = I40E_AQ_VSI_TYPE_PF;
386386

387387
/* FCoE VSI would need the following sections */
388-
info->valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID |
389-
I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
388+
info->valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
390389

391390
/* FCoE VSI does not need these sections */
392391
info->valid_sections &= cpu_to_le16(~(I40E_AQ_VSI_PROP_SECURITY_VALID |
@@ -395,7 +394,12 @@ int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt)
395394
I40E_AQ_VSI_PROP_INGRESS_UP_VALID |
396395
I40E_AQ_VSI_PROP_EGRESS_UP_VALID));
397396

398-
info->switch_id = cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
397+
if (i40e_is_vsi_uplink_mode_veb(vsi)) {
398+
info->valid_sections |=
399+
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
400+
info->switch_id =
401+
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
402+
}
399403
enabled_tc = i40e_get_fcoe_tc_map(pf);
400404
i40e_vsi_setup_queue_map(vsi, ctxt, enabled_tc, true);
401405

drivers/net/ethernet/intel/i40e/i40e_main.c

Lines changed: 178 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5871,6 +5871,26 @@ static void i40e_verify_eeprom(struct i40e_pf *pf)
58715871
}
58725872
}
58735873

5874+
/**
5875+
* i40e_config_bridge_mode - Configure the HW bridge mode
5876+
* @veb: pointer to the bridge instance
5877+
*
5878+
* Configure the loop back mode for the LAN VSI that is downlink to the
5879+
* specified HW bridge instance. It is expected this function is called
5880+
* when a new HW bridge is instantiated.
5881+
**/
5882+
static void i40e_config_bridge_mode(struct i40e_veb *veb)
5883+
{
5884+
struct i40e_pf *pf = veb->pf;
5885+
5886+
dev_info(&pf->pdev->dev, "enabling bridge mode: %s\n",
5887+
veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB");
5888+
if (veb->bridge_mode & BRIDGE_MODE_VEPA)
5889+
i40e_disable_pf_switch_lb(pf);
5890+
else
5891+
i40e_enable_pf_switch_lb(pf);
5892+
}
5893+
58745894
/**
58755895
* i40e_reconstitute_veb - rebuild the VEB and anything connected to it
58765896
* @veb: pointer to the VEB instance
@@ -5917,8 +5937,7 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)
59175937
if (ret)
59185938
goto end_reconstitute;
59195939

5920-
/* Enable LB mode for the main VSI now that it is on a VEB */
5921-
i40e_enable_pf_switch_lb(pf);
5940+
i40e_config_bridge_mode(veb);
59225941

59235942
/* create the remaining VSIs attached to this VEB */
59245943
for (v = 0; v < pf->num_alloc_vsi; v++) {
@@ -7737,6 +7756,118 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
77377756
return err;
77387757
}
77397758

7759+
#ifdef HAVE_BRIDGE_ATTRIBS
7760+
/**
7761+
* i40e_ndo_bridge_setlink - Set the hardware bridge mode
7762+
* @dev: the netdev being configured
7763+
* @nlh: RTNL message
7764+
*
7765+
* Inserts a new hardware bridge if not already created and
7766+
* enables the bridging mode requested (VEB or VEPA). If the
7767+
* hardware bridge has already been inserted and the request
7768+
* is to change the mode then that requires a PF reset to
7769+
* allow rebuild of the components with required hardware
7770+
* bridge mode enabled.
7771+
**/
7772+
static int i40e_ndo_bridge_setlink(struct net_device *dev,
7773+
struct nlmsghdr *nlh)
7774+
{
7775+
struct i40e_netdev_priv *np = netdev_priv(dev);
7776+
struct i40e_vsi *vsi = np->vsi;
7777+
struct i40e_pf *pf = vsi->back;
7778+
struct i40e_veb *veb = NULL;
7779+
struct nlattr *attr, *br_spec;
7780+
int i, rem;
7781+
7782+
/* Only for PF VSI for now */
7783+
if (vsi->seid != pf->vsi[pf->lan_vsi]->seid)
7784+
return -EOPNOTSUPP;
7785+
7786+
/* Find the HW bridge for PF VSI */
7787+
for (i = 0; i < I40E_MAX_VEB && !veb; i++) {
7788+
if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)
7789+
veb = pf->veb[i];
7790+
}
7791+
7792+
br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
7793+
7794+
nla_for_each_nested(attr, br_spec, rem) {
7795+
__u16 mode;
7796+
7797+
if (nla_type(attr) != IFLA_BRIDGE_MODE)
7798+
continue;
7799+
7800+
mode = nla_get_u16(attr);
7801+
if ((mode != BRIDGE_MODE_VEPA) &&
7802+
(mode != BRIDGE_MODE_VEB))
7803+
return -EINVAL;
7804+
7805+
/* Insert a new HW bridge */
7806+
if (!veb) {
7807+
veb = i40e_veb_setup(pf, 0, vsi->uplink_seid, vsi->seid,
7808+
vsi->tc_config.enabled_tc);
7809+
if (veb) {
7810+
veb->bridge_mode = mode;
7811+
i40e_config_bridge_mode(veb);
7812+
} else {
7813+
/* No Bridge HW offload available */
7814+
return -ENOENT;
7815+
}
7816+
break;
7817+
} else if (mode != veb->bridge_mode) {
7818+
/* Existing HW bridge but different mode needs reset */
7819+
veb->bridge_mode = mode;
7820+
i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
7821+
break;
7822+
}
7823+
}
7824+
7825+
return 0;
7826+
}
7827+
7828+
/**
7829+
* i40e_ndo_bridge_getlink - Get the hardware bridge mode
7830+
* @skb: skb buff
7831+
* @pid: process id
7832+
* @seq: RTNL message seq #
7833+
* @dev: the netdev being configured
7834+
* @filter_mask: unused
7835+
*
7836+
* Return the mode in which the hardware bridge is operating in
7837+
* i.e VEB or VEPA.
7838+
**/
7839+
#ifdef HAVE_BRIDGE_FILTER
7840+
static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
7841+
struct net_device *dev,
7842+
u32 __always_unused filter_mask)
7843+
#else
7844+
static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
7845+
struct net_device *dev)
7846+
#endif /* HAVE_BRIDGE_FILTER */
7847+
{
7848+
struct i40e_netdev_priv *np = netdev_priv(dev);
7849+
struct i40e_vsi *vsi = np->vsi;
7850+
struct i40e_pf *pf = vsi->back;
7851+
struct i40e_veb *veb = NULL;
7852+
int i;
7853+
7854+
/* Only for PF VSI for now */
7855+
if (vsi->seid != pf->vsi[pf->lan_vsi]->seid)
7856+
return -EOPNOTSUPP;
7857+
7858+
/* Find the HW bridge for the PF VSI */
7859+
for (i = 0; i < I40E_MAX_VEB && !veb; i++) {
7860+
if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)
7861+
veb = pf->veb[i];
7862+
}
7863+
7864+
if (!veb)
7865+
return 0;
7866+
7867+
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode);
7868+
}
7869+
#endif /* HAVE_BRIDGE_ATTRIBS */
7870+
77407871
const struct net_device_ops i40e_netdev_ops = {
77417872
.ndo_open = i40e_open,
77427873
.ndo_stop = i40e_close,
@@ -7771,6 +7902,10 @@ const struct net_device_ops i40e_netdev_ops = {
77717902
#endif
77727903
.ndo_get_phys_port_id = i40e_get_phys_port_id,
77737904
.ndo_fdb_add = i40e_ndo_fdb_add,
7905+
#ifdef HAVE_BRIDGE_ATTRIBS
7906+
.ndo_bridge_getlink = i40e_ndo_bridge_getlink,
7907+
.ndo_bridge_setlink = i40e_ndo_bridge_setlink,
7908+
#endif /* HAVE_BRIDGE_ATTRIBS */
77747909
};
77757910

77767911
/**
@@ -7882,6 +8017,30 @@ static void i40e_vsi_delete(struct i40e_vsi *vsi)
78828017
i40e_aq_delete_element(&vsi->back->hw, vsi->seid, NULL);
78838018
}
78848019

8020+
/**
8021+
* i40e_is_vsi_uplink_mode_veb - Check if the VSI's uplink bridge mode is VEB
8022+
* @vsi: the VSI being queried
8023+
*
8024+
* Returns 1 if HW bridge mode is VEB and return 0 in case of VEPA mode
8025+
**/
8026+
int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi)
8027+
{
8028+
struct i40e_veb *veb;
8029+
struct i40e_pf *pf = vsi->back;
8030+
8031+
/* Uplink is not a bridge so default to VEB */
8032+
if (vsi->veb_idx == I40E_NO_VEB)
8033+
return 1;
8034+
8035+
veb = pf->veb[vsi->veb_idx];
8036+
/* Uplink is a bridge in VEPA mode */
8037+
if (veb && (veb->bridge_mode & BRIDGE_MODE_VEPA))
8038+
return 0;
8039+
8040+
/* Uplink is a bridge in VEB mode */
8041+
return 1;
8042+
}
8043+
78858044
/**
78868045
* i40e_add_vsi - Add a VSI to the switch
78878046
* @vsi: the VSI being configured
@@ -7969,10 +8128,12 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
79698128
ctxt.uplink_seid = vsi->uplink_seid;
79708129
ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
79718130
ctxt.flags = I40E_AQ_VSI_TYPE_PF;
7972-
ctxt.info.valid_sections |=
8131+
if (i40e_is_vsi_uplink_mode_veb(vsi)) {
8132+
ctxt.info.valid_sections |=
79738133
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
7974-
ctxt.info.switch_id =
8134+
ctxt.info.switch_id =
79758135
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
8136+
}
79768137
i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true);
79778138
break;
79788139

@@ -7983,13 +8144,15 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
79838144
ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
79848145
ctxt.flags = I40E_AQ_VSI_TYPE_VMDQ2;
79858146

7986-
ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
7987-
79888147
/* This VSI is connected to VEB so the switch_id
79898148
* should be set to zero by default.
79908149
*/
7991-
ctxt.info.switch_id = 0;
7992-
ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
8150+
if (i40e_is_vsi_uplink_mode_veb(vsi)) {
8151+
ctxt.info.valid_sections |=
8152+
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
8153+
ctxt.info.switch_id =
8154+
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
8155+
}
79938156

79948157
/* Setup the VSI tx/rx queue map for TC0 only for now */
79958158
i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true);
@@ -8002,12 +8165,15 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
80028165
ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
80038166
ctxt.flags = I40E_AQ_VSI_TYPE_VF;
80048167

8005-
ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
8006-
80078168
/* This VSI is connected to VEB so the switch_id
80088169
* should be set to zero by default.
80098170
*/
8010-
ctxt.info.switch_id = cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
8171+
if (i40e_is_vsi_uplink_mode_veb(vsi)) {
8172+
ctxt.info.valid_sections |=
8173+
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
8174+
ctxt.info.switch_id =
8175+
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
8176+
}
80118177

80128178
ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
80138179
ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_ALL;
@@ -8365,7 +8531,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
83658531
__func__);
83668532
return NULL;
83678533
}
8368-
i40e_enable_pf_switch_lb(pf);
8534+
i40e_config_bridge_mode(veb);
83698535
}
83708536
for (i = 0; i < I40E_MAX_VEB && !veb; i++) {
83718537
if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)

drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*******************************************************************************
22
*
33
* Intel Ethernet Controller XL710 Family Linux Driver
4-
* Copyright(c) 2013 - 2014 Intel Corporation.
4+
* Copyright(c) 2013 - 2015 Intel Corporation.
55
*
66
* This program is free software; you can redistribute it and/or modify it
77
* under the terms and conditions of the GNU General Public License,
@@ -752,7 +752,7 @@ void i40e_enable_pf_switch_lb(struct i40e_pf *pf)
752752
*
753753
* disable switch loop back or die - no point in a return value
754754
**/
755-
static void i40e_disable_pf_switch_lb(struct i40e_pf *pf)
755+
void i40e_disable_pf_switch_lb(struct i40e_pf *pf)
756756
{
757757
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
758758
struct i40e_vsi_context ctxt;
@@ -891,7 +891,6 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
891891
}
892892
pf->num_alloc_vfs = num_alloc_vfs;
893893

894-
i40e_enable_pf_switch_lb(pf);
895894
err_alloc:
896895
if (ret)
897896
i40e_free_vfs(pf);

drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*******************************************************************************
22
*
33
* Intel Ethernet Controller XL710 Family Linux Driver
4-
* Copyright(c) 2013 - 2014 Intel Corporation.
4+
* Copyright(c) 2013 - 2015 Intel Corporation.
55
*
66
* This program is free software; you can redistribute it and/or modify it
77
* under the terms and conditions of the GNU General Public License,
@@ -127,5 +127,6 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable);
127127
void i40e_vc_notify_link_state(struct i40e_pf *pf);
128128
void i40e_vc_notify_reset(struct i40e_pf *pf);
129129
void i40e_enable_pf_switch_lb(struct i40e_pf *pf);
130+
void i40e_disable_pf_switch_lb(struct i40e_pf *pf);
130131

131132
#endif /* _I40E_VIRTCHNL_PF_H_ */

0 commit comments

Comments
 (0)