summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-12-11 13:56:24 +0200
committerIdo Barnea <ibarnea@cisco.com>2016-12-11 13:56:24 +0200
commitfd9485d62a78e027b107717476a9b0df005a012d (patch)
tree83cffe2383c84d08c849340d68b8485833cc320e /src
parent4152f8eb4d4c6d7bfe05dd4a3649f7f570d31c3e (diff)
Cisco VIC card - support for receive all mode, and work around for IPv6 issues
Signed-off-by: Ido Barnea <ibarnea@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/dpdk/drivers/net/enic/base/vnic_dev.c5
-rw-r--r--src/dpdk/drivers/net/enic/enic_clsf.c55
-rw-r--r--src/main_dpdk.cpp121
3 files changed, 109 insertions, 72 deletions
diff --git a/src/dpdk/drivers/net/enic/base/vnic_dev.c b/src/dpdk/drivers/net/enic/base/vnic_dev.c
index 713b6089..e50b90e7 100644
--- a/src/dpdk/drivers/net/enic/base/vnic_dev.c
+++ b/src/dpdk/drivers/net/enic/base/vnic_dev.c
@@ -667,7 +667,12 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
(promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
(allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
+#define TREX_PATCH
+#ifdef TREX_PATCH
+ err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER_ALL, &a0, &a1, wait);
+#else
err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
+#endif
if (err)
pr_err("Can't set packet filter\n");
diff --git a/src/dpdk/drivers/net/enic/enic_clsf.c b/src/dpdk/drivers/net/enic/enic_clsf.c
index 23cb0124..8f68faab 100644
--- a/src/dpdk/drivers/net/enic/enic_clsf.c
+++ b/src/dpdk/drivers/net/enic/enic_clsf.c
@@ -107,6 +107,7 @@ enic_set_layer(struct filter_generic_1 *gp, unsigned int flag,
memcpy(gp->layer[layer].val, val, len);
}
+
/* Copy Flow Director filter to a VIC ipv4 filter (for Cisco VICs
* without advanced filter support.
*/
@@ -132,6 +133,28 @@ copy_fltr_v1(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
fltr->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
}
+#define TREX_PATCH
+#ifdef TREX_PATCH
+void
+copy_fltr_recv_all(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
+ struct rte_eth_fdir_masks *masks) {
+ struct filter_generic_1 *gp = &fltr->u.generic_1;
+ memset(gp, 0, sizeof(*gp));
+
+ struct ether_hdr eth_mask, eth_val;
+ memset(&eth_mask, 0, sizeof(eth_mask));
+ memset(&eth_val, 0, sizeof(eth_val));
+
+ eth_val.ether_type = 0x0806;
+ eth_mask.ether_type = 0;
+
+ gp->position = 0;
+ enic_set_layer(gp, 0, FILTER_GENERIC_1_L2,
+ &eth_mask, &eth_val, sizeof(struct ether_hdr));
+
+}
+#endif
+
/* Copy Flow Director filter to a VIC generic filter (requires advanced
* filter support.
*/
@@ -146,6 +169,11 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
fltr->type = FILTER_DPDK_1;
memset(gp, 0, sizeof(*gp));
+#ifdef TREX_PATCH
+ // important for this to be below 2.
+ // If added with position 2, IPv6 UDP and ICMP seems to be caught by some other rule
+ gp->position = 1;
+#endif
if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP) {
struct udp_hdr udp_mask, udp_val;
@@ -344,11 +372,23 @@ int enic_fdir_del_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
case -EINVAL:
case -ENOENT:
enic->fdir.stats.f_remove++;
+#ifdef TREX_PATCH
+ return pos;
+#else
return -EINVAL;
+#endif
default:
/* The entry is present in the table */
key = enic->fdir.nodes[pos];
+#ifdef TREX_PATCH
+ switch (params->soft_id) {
+ case 100:
+ // remove promisc when we delete 'receive all' filter
+ vnic_dev_packet_filter(enic->vdev, 1, 1, 1, 0, 1);
+ break;
+ }
+#endif
/* Delete the filter */
vnic_dev_classifier(enic->vdev, CLSF_DEL,
&key->fltr_id, NULL);
@@ -455,8 +495,19 @@ int enic_fdir_add_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
key->filter = *params;
key->rq_index = queue;
- enic->fdir.copy_fltr_fn(&fltr, &params->input,
- &enic->rte_dev->data->dev_conf.fdir_conf.mask);
+#ifdef TREX_PATCH
+ switch (params->soft_id) {
+ case 100:
+ vnic_dev_packet_filter(enic->vdev, 1, 1, 1, 1, 1);
+ copy_fltr_recv_all(&fltr, &params->input, &enic->rte_dev->data->dev_conf.fdir_conf.mask);
+ break;
+ default:
+#endif
+ enic->fdir.copy_fltr_fn(&fltr, &params->input,
+ &enic->rte_dev->data->dev_conf.fdir_conf.mask);
+#ifdef TREX_PATCH
+ }
+#endif
if (!vnic_dev_classifier(enic->vdev, CLSF_ADD, &queue, &fltr)) {
key->fltr_id = queue;
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index a88d4a7c..6d78719f 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -443,8 +443,8 @@ public:
private:
- virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl
- , uint16_t ip_id, uint8_t l4_proto, int queue);
+ virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint16_t id
+ , uint8_t l4_proto, uint8_t tos, int queue);
virtual int add_del_eth_type_rule(uint8_t port_id, enum rte_filter_op op, uint16_t eth_type);
virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
@@ -6583,7 +6583,7 @@ void CTRexExtendedDriverBaseMlnx5G::add_del_rules(enum rte_filter_op op, uint8_t
memset(&filter,0,sizeof(struct rte_eth_fdir_filter));
#if 0
- printf("40g::%s rules: port:%d type:%d ip_id:%x l4:%d q:%d\n"
+ printf("MLNX add_del_rules::%s rules: port:%d type:%d ip_id:%x l4:%d q:%d\n"
, (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
, port_id, type, ip_id, l4_proto, queue);
#endif
@@ -6599,7 +6599,6 @@ void CTRexExtendedDriverBaseMlnx5G::add_del_rules(enum rte_filter_op op, uint8_t
case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
- // filter.input.flow.ip4_flow.ttl = ttl;
filter.input.flow.ip4_flow.ip_id = ip_id;
if (l4_proto != 0)
filter.input.flow.ip4_flow.proto = l4_proto;
@@ -6607,7 +6606,6 @@ void CTRexExtendedDriverBaseMlnx5G::add_del_rules(enum rte_filter_op op, uint8_t
case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
- // filter.input.flow.ipv6_flow.hop_limits=ttl;
filter.input.flow.ipv6_flow.flow_label = ip_id;
filter.input.flow.ipv6_flow.proto = l4_proto;
break;
@@ -6745,30 +6743,13 @@ void CTRexExtendedDriverBaseVIC::update_configuration(port_cfg_t * cfg){
cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH;
cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH;
cfg->m_port_conf.rxmode.max_rx_pkt_len =9*1000-10;
-
- if (get_is_stateless()) {
- /* work in TOS mode */
- cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos = 0x01;
- cfg->m_port_conf.fdir_conf.mask.ipv6_mask.tc = 0x01;
- }else{
- #ifdef VIC_TTL_FILTER
- cfg->m_port_conf.fdir_conf.mask.ipv4_mask.ttl = 0xff;
- cfg->m_port_conf.fdir_conf.mask.ipv6_mask.hop_limits = 0xff;
- #else
- cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos = 0x01;
- cfg->m_port_conf.fdir_conf.mask.ipv6_mask.tc = 0x01;
- #endif
- }
+ cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos = 0x0f;
+ cfg->m_port_conf.fdir_conf.mask.ipv6_mask.tc = 0x0f;
}
-
-/* Add rule to send packets with protocol 'type', and ttl 'ttl' to rx queue 1 */
-// ttl is used in statefull mode, and ip_id in stateless. We configure the driver registers so that only one of them applies.
-// So, the rule will apply if packet has either the correct ttl or IP ID, depending if we are in statfull or stateless.
-void CTRexExtendedDriverBaseVIC::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl
- , uint16_t ip_id, uint8_t l4_proto, int queue) {
+void CTRexExtendedDriverBaseVIC::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type
+ , uint16_t id, uint8_t l4_proto, uint8_t tos, int queue) {
int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
- static int filter_soft_id = 0;
if ( ret != 0 ){
rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_supported "
@@ -6781,15 +6762,15 @@ void CTRexExtendedDriverBaseVIC::add_del_rules(enum rte_filter_op op, uint8_t po
memset(&filter,0,sizeof(struct rte_eth_fdir_filter));
#if 0
- printf("40g::%s rules: port:%d type:%d ttl:%d ip_id:%x l4:%d q:%d\n"
+ printf("VIC add_del_rules::%s rules: port:%d type:%d id:%d l4:%d tod:%d, q:%d\n"
, (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
- , port_id, type, ttl, ip_id, l4_proto, queue);
+ , port_id, type, id, l4_proto, tos, queue);
#endif
filter.action.rx_queue = queue;
- filter.action.behavior =RTE_ETH_FDIR_ACCEPT;
- filter.action.report_status =RTE_ETH_FDIR_NO_REPORT_STATUS;
- filter.soft_id = filter_soft_id++;
+ filter.action.behavior = RTE_ETH_FDIR_ACCEPT;
+ filter.action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS;
+ filter.soft_id = id;
filter.input.flow_type = type;
switch (type) {
@@ -6797,22 +6778,22 @@ void CTRexExtendedDriverBaseVIC::add_del_rules(enum rte_filter_op op, uint8_t po
case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
- filter.input.flow.ip4_flow.tos=ttl;
- filter.input.flow.ip4_flow.ip_id = ip_id;
- if (l4_proto != 0)
- filter.input.flow.ip4_flow.proto = l4_proto;
+ filter.input.flow.ip4_flow.tos = tos;
+ filter.input.flow.ip4_flow.proto = l4_proto;
break;
case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
- filter.input.flow.ipv6_flow.tc=ttl;
- filter.input.flow.ipv6_flow.flow_label = ip_id;
+ filter.input.flow.ipv6_flow.tc = tos;
filter.input.flow.ipv6_flow.proto = l4_proto;
break;
}
ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, op, (void*)&filter);
if ( ret != 0 ) {
+ if (((op == RTE_ETH_FILTER_ADD) && (ret == -EEXIST)) || ((op == RTE_ETH_FILTER_DELETE) && (ret == -ENOENT)))
+ return;
+
rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_ctrl: err=%d, port=%u\n",
ret, port_id);
}
@@ -6831,38 +6812,46 @@ int CTRexExtendedDriverBaseVIC::add_del_eth_type_rule(uint8_t port_id, enum rte_
return ret;
}
-extern "C" int rte_eth_fdir_stats_reset(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len);
-
int CTRexExtendedDriverBaseVIC::configure_rx_filter_rules_statefull(CPhyEthIF * _if) {
uint32_t port_id = _if->get_port_id();
-#ifndef VIC_TTL_FILTER
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 0x1, 0, 17, MAIN_DPDK_RX_Q); /*TCP/UDP */
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, 0x1, 0, 6, MAIN_DPDK_RX_Q);
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, 0x1, 0, 132, MAIN_DPDK_RX_Q); /*SCTP*/
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 0x1, 0, 1, MAIN_DPDK_RX_Q); /*ICMP*/
-
- /* Ipv6*/
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 0x1, 0, 0, MAIN_DPDK_RX_Q); /*Any protocol on Ipv6*/
-#else
- uint16_t hops = get_rx_check_hops();
- int i;
- for (i = 0; i < 2; i++) {
- uint8_t ttl = TTL_RESERVE_DUPLICATE - i - hops;
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, ttl, 0, 17, MAIN_DPDK_RX_Q);
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, ttl, 0, 6, MAIN_DPDK_RX_Q);
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, ttl, 0, RX_CHECK_V6_OPT_TYPE, MAIN_DPDK_RX_Q);
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, ttl, 0, RX_CHECK_V6_OPT_TYPE, MAIN_DPDK_RX_Q);
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, ttl, 0, RX_CHECK_V6_OPT_TYPE, MAIN_DPDK_RX_Q);
- /* Rules for latency measurement packets */
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, ttl, 0, IPPROTO_ICMP, MAIN_DPDK_RX_Q);
- add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, ttl, 0, 138, MAIN_DPDK_RX_Q);
- }
-#endif
+
+ set_rcv_all(_if, false);
+
+ // Rules to direct all IP packets with tos lsb bit 1 to RX Q.
+ // IPv4
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 1, 17, 0x1, MAIN_DPDK_RX_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, 1, 6, 0x1, MAIN_DPDK_RX_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, 1, 132, 0x1, MAIN_DPDK_RX_Q); /*SCTP*/
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 1, 1, 0x1, MAIN_DPDK_RX_Q); /*ICMP*/
+ // Ipv6
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 6, 0x1, MAIN_DPDK_RX_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 1, 17, 0x1, MAIN_DPDK_RX_Q);
+
+ // Because of some issue with VIC firmware, IPv6 UDP and ICMP go by default to q 1, so we
+ // need these rules to make them go to q 0.
+ // rule appply to all packets with 0 on tos lsb.
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 6, 0, MAIN_DPDK_DATA_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 1, 17, 0, MAIN_DPDK_DATA_Q);
return 0;
}
+int CTRexExtendedDriverBaseVIC::set_rcv_all(CPhyEthIF * _if, bool set_on) {
+ uint8_t port_id = _if->get_rte_port_id();
+
+ // soft ID 100 tells VIC driver to add rule for all ether types.
+ // Added with highest priority (implicitly in the driver), so if it exists, it applies before all other rules
+ if (set_on) {
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 100, 30, 0, MAIN_DPDK_RX_Q);
+ } else {
+ add_del_rules(RTE_ETH_FILTER_DELETE, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 100, 30, 0, MAIN_DPDK_RX_Q);
+ }
+
+ return 0;
+
+}
+
void CTRexExtendedDriverBaseVIC::clear_extended_stats(CPhyEthIF * _if){
rte_eth_stats_reset(_if->get_port_id());
}
@@ -6895,7 +6884,6 @@ void CTRexExtendedDriverBaseVIC::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSta
prev_stats->rx_nombuf = stats1.rx_nombuf;
}
-
int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
struct rte_eth_fdir_info fdir_info;
@@ -6916,7 +6904,6 @@ int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
exit(1);
}
-
int CTRexExtendedDriverBaseVIC::configure_rx_filter_rules(CPhyEthIF * _if) {
if (get_is_stateless()) {
@@ -6944,18 +6931,12 @@ int CTRexExtendedDriverBaseVIC::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd
return (0);
}
-
CFlowStatParser *CTRexExtendedDriverBaseVIC::get_flow_stat_parser() {
CFlowStatParser *parser = new CFlowStatParser();
assert (parser);
return parser;
}
-int CTRexExtendedDriverBaseVIC::set_rcv_all(CPhyEthIF * _if, bool set_on) {
- //printf(" NOT supported yet \n");
- return 0;
-}
-
/////////////////////////////////////////////////////////////////////////////////////