Commit 0075fa0f authored by Harshitha Ramamurthy's avatar Harshitha Ramamurthy Committed by Jeff Kirsher

i40evf: Add support to apply cloud filters

This patch enables a tc filter to be applied as a cloud
filter for the VF. This patch adds functions which parse the
tc filter, extract the necessary fields needed to configure the
filter and package them in a virtchnl message to be sent to the
PF to apply them.
Signed-off-by: default avatarHarshitha Ramamurthy <harshitha.ramamurthy@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 3872c8d4
......@@ -54,6 +54,8 @@
#include <net/ip6_checksum.h>
#include <net/pkt_cls.h>
#include <net/udp.h>
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_mirred.h>
#include "i40e_type.h"
#include <linux/avf/virtchnl.h>
......@@ -184,6 +186,14 @@ struct i40evf_channel_config {
u8 total_qps;
};
/* State of cloud filter */
enum i40evf_cloud_filter_state_t {
__I40EVF_CF_INVALID, /* cloud filter not added */
__I40EVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */
__I40EVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */
__I40EVF_CF_ACTIVE, /* cloud filter is active */
};
/* Driver state. The order of these is important! */
enum i40evf_state_t {
__I40EVF_STARTUP, /* driver loaded, probe complete */
......@@ -205,6 +215,36 @@ enum i40evf_critical_section_t {
__I40EVF_IN_REMOVE_TASK, /* device being removed */
};
#define I40EVF_CLOUD_FIELD_OMAC 0x01
#define I40EVF_CLOUD_FIELD_IMAC 0x02
#define I40EVF_CLOUD_FIELD_IVLAN 0x04
#define I40EVF_CLOUD_FIELD_TEN_ID 0x08
#define I40EVF_CLOUD_FIELD_IIP 0x10
#define I40EVF_CF_FLAGS_OMAC I40EVF_CLOUD_FIELD_OMAC
#define I40EVF_CF_FLAGS_IMAC I40EVF_CLOUD_FIELD_IMAC
#define I40EVF_CF_FLAGS_IMAC_IVLAN (I40EVF_CLOUD_FIELD_IMAC |\
I40EVF_CLOUD_FIELD_IVLAN)
#define I40EVF_CF_FLAGS_IMAC_TEN_ID (I40EVF_CLOUD_FIELD_IMAC |\
I40EVF_CLOUD_FIELD_TEN_ID)
#define I40EVF_CF_FLAGS_OMAC_TEN_ID_IMAC (I40EVF_CLOUD_FIELD_OMAC |\
I40EVF_CLOUD_FIELD_IMAC |\
I40EVF_CLOUD_FIELD_TEN_ID)
#define I40EVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (I40EVF_CLOUD_FIELD_IMAC |\
I40EVF_CLOUD_FIELD_IVLAN |\
I40EVF_CLOUD_FIELD_TEN_ID)
#define I40EVF_CF_FLAGS_IIP I40E_CLOUD_FIELD_IIP
/* bookkeeping of cloud filters */
struct i40evf_cloud_filter {
enum i40evf_cloud_filter_state_t state;
struct list_head list;
struct virtchnl_filter f;
unsigned long cookie;
bool del; /* filter needs to be deleted */
bool add; /* filter needs to be added */
};
/* board specific private data structure */
struct i40evf_adapter {
struct timer_list watchdog_timer;
......@@ -287,6 +327,8 @@ struct i40evf_adapter {
#define I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20)
#define I40EVF_FLAG_AQ_ENABLE_CHANNELS BIT(21)
#define I40EVF_FLAG_AQ_DISABLE_CHANNELS BIT(22)
#define I40EVF_FLAG_AQ_ADD_CLOUD_FILTER BIT(23)
#define I40EVF_FLAG_AQ_DEL_CLOUD_FILTER BIT(24)
/* OS defined structs */
struct net_device *netdev;
......@@ -335,6 +377,10 @@ struct i40evf_adapter {
/* ADQ related members */
struct i40evf_channel_config ch_config;
u8 num_tc;
struct list_head cloud_filter_list;
/* lock to protest access to the cloud filter list */
spinlock_t cloud_filter_list_lock;
u16 num_cloud_filters;
};
......@@ -403,4 +449,6 @@ void i40evf_notify_client_open(struct i40e_vsi *vsi);
void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset);
void i40evf_enable_channels(struct i40evf_adapter *adapter);
void i40evf_disable_channels(struct i40evf_adapter *adapter);
void i40evf_add_cloud_filter(struct i40evf_adapter *adapter);
void i40evf_del_cloud_filter(struct i40evf_adapter *adapter);
#endif /* _I40EVF_H_ */
......@@ -1040,6 +1040,134 @@ void i40evf_disable_channels(struct i40evf_adapter *adapter)
NULL, 0);
}
/**
* i40evf_print_cloud_filter
* @adapter: adapter structure
* @f: cloud filter to print
*
* Print the cloud filter
**/
static void i40evf_print_cloud_filter(struct i40evf_adapter *adapter,
struct virtchnl_filter f)
{
switch (f.flow_type) {
case VIRTCHNL_TCP_V4_FLOW:
dev_info(&adapter->pdev->dev, "dst_mac: %pM src_mac: %pM vlan_id: %hu dst_ip: %pI4 src_ip %pI4 dst_port %hu src_port %hu\n",
&f.data.tcp_spec.dst_mac, &f.data.tcp_spec.src_mac,
ntohs(f.data.tcp_spec.vlan_id),
&f.data.tcp_spec.dst_ip[0], &f.data.tcp_spec.src_ip[0],
ntohs(f.data.tcp_spec.dst_port),
ntohs(f.data.tcp_spec.src_port));
break;
case VIRTCHNL_TCP_V6_FLOW:
dev_info(&adapter->pdev->dev, "dst_mac: %pM src_mac: %pM vlan_id: %hu dst_ip: %pI6 src_ip %pI6 dst_port %hu src_port %hu\n",
&f.data.tcp_spec.dst_mac, &f.data.tcp_spec.src_mac,
ntohs(f.data.tcp_spec.vlan_id),
&f.data.tcp_spec.dst_ip, &f.data.tcp_spec.src_ip,
ntohs(f.data.tcp_spec.dst_port),
ntohs(f.data.tcp_spec.src_port));
break;
}
}
/**
* i40evf_add_cloud_filter
* @adapter: adapter structure
*
* Request that the PF add cloud filters as specified
* by the user via tc tool.
**/
void i40evf_add_cloud_filter(struct i40evf_adapter *adapter)
{
struct i40evf_cloud_filter *cf;
struct virtchnl_filter *f;
int len = 0, count = 0;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
dev_err(&adapter->pdev->dev, "Cannot add cloud filter, command %d pending\n",
adapter->current_op);
return;
}
list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
if (cf->add) {
count++;
break;
}
}
if (!count) {
adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
return;
}
adapter->current_op = VIRTCHNL_OP_ADD_CLOUD_FILTER;
len = sizeof(struct virtchnl_filter);
f = kzalloc(len, GFP_KERNEL);
if (!f)
return;
list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
if (cf->add) {
memcpy(f, &cf->f, sizeof(struct virtchnl_filter));
cf->add = false;
cf->state = __I40EVF_CF_ADD_PENDING;
i40evf_send_pf_msg(adapter,
VIRTCHNL_OP_ADD_CLOUD_FILTER,
(u8 *)f, len);
}
}
kfree(f);
}
/**
* i40evf_del_cloud_filter
* @adapter: adapter structure
*
* Request that the PF delete cloud filters as specified
* by the user via tc tool.
**/
void i40evf_del_cloud_filter(struct i40evf_adapter *adapter)
{
struct i40evf_cloud_filter *cf, *cftmp;
struct virtchnl_filter *f;
int len = 0, count = 0;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
dev_err(&adapter->pdev->dev, "Cannot remove cloud filter, command %d pending\n",
adapter->current_op);
return;
}
list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
if (cf->del) {
count++;
break;
}
}
if (!count) {
adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
return;
}
adapter->current_op = VIRTCHNL_OP_DEL_CLOUD_FILTER;
len = sizeof(struct virtchnl_filter);
f = kzalloc(len, GFP_KERNEL);
if (!f)
return;
list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) {
if (cf->del) {
memcpy(f, &cf->f, sizeof(struct virtchnl_filter));
cf->del = false;
cf->state = __I40EVF_CF_DEL_PENDING;
i40evf_send_pf_msg(adapter,
VIRTCHNL_OP_DEL_CLOUD_FILTER,
(u8 *)f, len);
}
}
kfree(f);
}
/**
* i40evf_request_reset
* @adapter: adapter structure
......@@ -1163,6 +1291,42 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
adapter->ch_config.state = __I40EVF_TC_RUNNING;
netif_tx_start_all_queues(netdev);
break;
case VIRTCHNL_OP_ADD_CLOUD_FILTER: {
struct i40evf_cloud_filter *cf, *cftmp;
list_for_each_entry_safe(cf, cftmp,
&adapter->cloud_filter_list,
list) {
if (cf->state == __I40EVF_CF_ADD_PENDING) {
cf->state = __I40EVF_CF_INVALID;
dev_info(&adapter->pdev->dev, "Failed to add cloud filter, error %s\n",
i40evf_stat_str(&adapter->hw,
v_retval));
i40evf_print_cloud_filter(adapter,
cf->f);
list_del(&cf->list);
kfree(cf);
adapter->num_cloud_filters--;
}
}
}
break;
case VIRTCHNL_OP_DEL_CLOUD_FILTER: {
struct i40evf_cloud_filter *cf;
list_for_each_entry(cf, &adapter->cloud_filter_list,
list) {
if (cf->state == __I40EVF_CF_DEL_PENDING) {
cf->state = __I40EVF_CF_ACTIVE;
dev_info(&adapter->pdev->dev, "Failed to del cloud filter, error %s\n",
i40evf_stat_str(&adapter->hw,
v_retval));
i40evf_print_cloud_filter(adapter,
cf->f);
}
}
}
break;
default:
dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
v_retval,
......@@ -1257,6 +1421,29 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
}
}
break;
case VIRTCHNL_OP_ADD_CLOUD_FILTER: {
struct i40evf_cloud_filter *cf;
list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
if (cf->state == __I40EVF_CF_ADD_PENDING)
cf->state = __I40EVF_CF_ACTIVE;
}
}
break;
case VIRTCHNL_OP_DEL_CLOUD_FILTER: {
struct i40evf_cloud_filter *cf, *cftmp;
list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list,
list) {
if (cf->state == __I40EVF_CF_DEL_PENDING) {
cf->state = __I40EVF_CF_INVALID;
list_del(&cf->list);
kfree(cf);
adapter->num_cloud_filters--;
}
}
}
break;
default:
if (adapter->current_op && (v_opcode != adapter->current_op))
dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n",
......
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