diff options
author | 2016-12-11 13:56:24 +0200 | |
---|---|---|
committer | 2016-12-11 13:56:24 +0200 | |
commit | fd9485d62a78e027b107717476a9b0df005a012d (patch) | |
tree | 83cffe2383c84d08c849340d68b8485833cc320e | |
parent | 4152f8eb4d4c6d7bfe05dd4a3649f7f570d31c3e (diff) |
Cisco VIC card - support for receive all mode, and work around for IPv6 issues
Signed-off-by: Ido Barnea <ibarnea@cisco.com>
-rw-r--r-- | src/dpdk/drivers/net/enic/base/vnic_dev.c | 5 | ||||
-rw-r--r-- | src/dpdk/drivers/net/enic/enic_clsf.c | 55 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 121 |
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(ð_mask, 0, sizeof(eth_mask)); + memset(ð_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, + ð_mask, ð_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, ¶ms->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, ¶ms->input, &enic->rte_dev->data->dev_conf.fdir_conf.mask); + break; + default: +#endif + enic->fdir.copy_fltr_fn(&fltr, ¶ms->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; -} - ///////////////////////////////////////////////////////////////////////////////////// |