X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fice%2Fice_fdir_filter.c;h=ce6aa09d3d71b6a463cf59dde182ff440fc440d9;hb=92533e9dfe7501a64b54260420cf00ece7352056;hp=c0f89db837267601d52994eab9ba5b660c2e8906;hpb=3f4acd90d1d10f2c73f32b1f88ec2041b9001e2d;p=dpdk.git diff --git a/drivers/net/ice/ice_fdir_filter.c b/drivers/net/ice/ice_fdir_filter.c index c0f89db837..ce6aa09d3d 100644 --- a/drivers/net/ice/ice_fdir_filter.c +++ b/drivers/net/ice/ice_fdir_filter.c @@ -19,10 +19,10 @@ #define ICE_FDIR_MAX_QREGION_SIZE 128 #define ICE_FDIR_INSET_ETH (\ - ICE_INSET_ETHERTYPE) + ICE_INSET_DMAC | ICE_INSET_SMAC | ICE_INSET_ETHERTYPE) #define ICE_FDIR_INSET_ETH_IPV4 (\ - ICE_INSET_DMAC | \ + ICE_FDIR_INSET_ETH | \ ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | ICE_INSET_IPV4_TOS | \ ICE_INSET_IPV4_TTL | ICE_INSET_IPV4_PROTO) @@ -70,41 +70,21 @@ ICE_FDIR_INSET_VXLAN_IPV4 | \ ICE_INSET_TUN_SCTP_SRC_PORT | ICE_INSET_TUN_SCTP_DST_PORT) -#define ICE_FDIR_INSET_GTPU (\ +#define ICE_FDIR_INSET_IPV4_GTPU (\ ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | ICE_INSET_GTPU_TEID) -#define ICE_FDIR_INSET_GTPU_EH (\ +#define ICE_FDIR_INSET_IPV4_GTPU_EH (\ ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | \ ICE_INSET_GTPU_TEID | ICE_INSET_GTPU_QFI) -static struct ice_pattern_match_item ice_fdir_pattern_os[] = { - {pattern_eth_ipv4, ICE_FDIR_INSET_ETH_IPV4, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp, ICE_FDIR_INSET_ETH_IPV4_UDP, ICE_INSET_NONE}, - {pattern_eth_ipv4_tcp, ICE_FDIR_INSET_ETH_IPV4_TCP, ICE_INSET_NONE}, - {pattern_eth_ipv4_sctp, ICE_FDIR_INSET_ETH_IPV4_SCTP, ICE_INSET_NONE}, - {pattern_eth_ipv6, ICE_FDIR_INSET_ETH_IPV6, ICE_INSET_NONE}, - {pattern_eth_ipv6_udp, ICE_FDIR_INSET_ETH_IPV6_UDP, ICE_INSET_NONE}, - {pattern_eth_ipv6_tcp, ICE_FDIR_INSET_ETH_IPV6_TCP, ICE_INSET_NONE}, - {pattern_eth_ipv6_sctp, ICE_FDIR_INSET_ETH_IPV6_SCTP, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_ipv4, - ICE_FDIR_INSET_VXLAN_IPV4, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_ipv4_udp, - ICE_FDIR_INSET_VXLAN_IPV4_UDP, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_ipv4_tcp, - ICE_FDIR_INSET_VXLAN_IPV4_TCP, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_ipv4_sctp, - ICE_FDIR_INSET_VXLAN_IPV4_SCTP, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_eth_ipv4, - ICE_FDIR_INSET_VXLAN_IPV4, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_eth_ipv4_udp, - ICE_FDIR_INSET_VXLAN_IPV4_UDP, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_eth_ipv4_tcp, - ICE_FDIR_INSET_VXLAN_IPV4_TCP, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp_vxlan_eth_ipv4_sctp, - ICE_FDIR_INSET_VXLAN_IPV4_SCTP, ICE_INSET_NONE}, -}; +#define ICE_FDIR_INSET_IPV6_GTPU (\ + ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | ICE_INSET_GTPU_TEID) -static struct ice_pattern_match_item ice_fdir_pattern_comms[] = { +#define ICE_FDIR_INSET_IPV6_GTPU_EH (\ + ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | \ + ICE_INSET_GTPU_TEID | ICE_INSET_GTPU_QFI) + +static struct ice_pattern_match_item ice_fdir_pattern_list[] = { {pattern_ethertype, ICE_FDIR_INSET_ETH, ICE_INSET_NONE}, {pattern_eth_ipv4, ICE_FDIR_INSET_ETH_IPV4, ICE_INSET_NONE}, {pattern_eth_ipv4_udp, ICE_FDIR_INSET_ETH_IPV4_UDP, ICE_INSET_NONE}, @@ -130,12 +110,13 @@ static struct ice_pattern_match_item ice_fdir_pattern_comms[] = { ICE_FDIR_INSET_VXLAN_IPV4_TCP, ICE_INSET_NONE}, {pattern_eth_ipv4_udp_vxlan_eth_ipv4_sctp, ICE_FDIR_INSET_VXLAN_IPV4_SCTP, ICE_INSET_NONE}, - {pattern_eth_ipv4_gtpu, ICE_FDIR_INSET_GTPU, ICE_INSET_NONE}, - {pattern_eth_ipv4_gtpu_eh, ICE_FDIR_INSET_GTPU_EH, ICE_INSET_NONE}, + {pattern_eth_ipv4_gtpu, ICE_FDIR_INSET_IPV4_GTPU, ICE_INSET_NONE}, + {pattern_eth_ipv4_gtpu_eh, ICE_FDIR_INSET_IPV4_GTPU_EH, ICE_INSET_NONE}, + {pattern_eth_ipv6_gtpu, ICE_FDIR_INSET_IPV6_GTPU, ICE_INSET_NONE}, + {pattern_eth_ipv6_gtpu_eh, ICE_FDIR_INSET_IPV6_GTPU_EH, ICE_INSET_NONE}, }; -static struct ice_flow_parser ice_fdir_parser_os; -static struct ice_flow_parser ice_fdir_parser_comms; +static struct ice_flow_parser ice_fdir_parser; static int ice_fdir_is_tunnel_profile(enum ice_fdir_tunnel_type tunnel_type); @@ -769,15 +750,15 @@ ice_fdir_cross_prof_conflict(struct ice_pf *pf, goto err; break; case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER: - cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP; if (!ice_fdir_prof_resolve_conflict (pf, cflct_ptype, is_tunnel)) goto err; - cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP; if (!ice_fdir_prof_resolve_conflict (pf, cflct_ptype, is_tunnel)) goto err; - cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP; if (!ice_fdir_prof_resolve_conflict (pf, cflct_ptype, is_tunnel)) goto err; @@ -934,30 +915,9 @@ ice_fdir_input_set_parse(uint64_t inset, enum ice_flow_field *field) } } -static int -ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, - uint64_t input_set, enum ice_fdir_tunnel_type ttype) +static void +ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct ice_flow_seg_info *seg) { - struct ice_flow_seg_info *seg; - struct ice_flow_seg_info *seg_tun = NULL; - enum ice_flow_field field[ICE_FLOW_FIELD_IDX_MAX]; - bool is_tunnel; - int i, ret; - - if (!input_set) - return -EINVAL; - - seg = (struct ice_flow_seg_info *) - ice_malloc(hw, sizeof(*seg)); - if (!seg) { - PMD_DRV_LOG(ERR, "No memory can be allocated"); - return -ENOMEM; - } - - for (i = 0; i < ICE_FLOW_FIELD_IDX_MAX; i++) - field[i] = ICE_FLOW_FIELD_IDX_MAX; - ice_fdir_input_set_parse(input_set, field); - switch (flow) { case ICE_FLTR_PTYPE_NONF_IPV4_UDP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | @@ -1001,17 +961,26 @@ ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP: case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP: case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER: - if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU) - ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | - ICE_FLOW_SEG_HDR_IPV4 | - ICE_FLOW_SEG_HDR_IPV_OTHER); - else if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) - ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | - ICE_FLOW_SEG_HDR_GTPU_IP | - ICE_FLOW_SEG_HDR_IPV4 | - ICE_FLOW_SEG_HDR_IPV_OTHER); - else - PMD_DRV_LOG(ERR, "not supported tunnel type."); + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_EH_IPV4_OTHER: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | + ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV6_GTPU_IPV6_OTHER: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV6_GTPU_EH_IPV6_OTHER: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | + ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NON_IP_L2: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH_NON_IP); @@ -1020,27 +989,57 @@ ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, PMD_DRV_LOG(ERR, "not supported filter type."); break; } +} - for (i = 0; field[i] != ICE_FLOW_FIELD_IDX_MAX; i++) { - ice_flow_set_fld(seg, field[i], - ICE_FLOW_FLD_OFF_INVAL, - ICE_FLOW_FLD_OFF_INVAL, - ICE_FLOW_FLD_OFF_INVAL, false); +static int +ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, + uint64_t inner_input_set, uint64_t outer_input_set, + enum ice_fdir_tunnel_type ttype) +{ + struct ice_flow_seg_info *seg; + struct ice_flow_seg_info *seg_tun = NULL; + enum ice_flow_field field[ICE_FLOW_FIELD_IDX_MAX]; + uint64_t input_set; + bool is_tunnel; + int k, i, ret = 0; + + if (!(inner_input_set | outer_input_set)) + return -EINVAL; + + seg_tun = (struct ice_flow_seg_info *) + ice_malloc(hw, sizeof(*seg_tun) * ICE_FD_HW_SEG_MAX); + if (!seg_tun) { + PMD_DRV_LOG(ERR, "No memory can be allocated"); + return -ENOMEM; + } + + /* use seg_tun[1] to record tunnel inner part or non-tunnel */ + for (k = 0; k <= ICE_FD_HW_SEG_TUN; k++) { + seg = &seg_tun[k]; + input_set = (k == ICE_FD_HW_SEG_TUN) ? inner_input_set : outer_input_set; + if (input_set == 0) + continue; + + for (i = 0; i < ICE_FLOW_FIELD_IDX_MAX; i++) + field[i] = ICE_FLOW_FIELD_IDX_MAX; + + ice_fdir_input_set_parse(input_set, field); + + ice_fdir_input_set_hdrs(flow, seg); + + for (i = 0; field[i] != ICE_FLOW_FIELD_IDX_MAX; i++) { + ice_flow_set_fld(seg, field[i], + ICE_FLOW_FLD_OFF_INVAL, + ICE_FLOW_FLD_OFF_INVAL, + ICE_FLOW_FLD_OFF_INVAL, false); + } } is_tunnel = ice_fdir_is_tunnel_profile(ttype); if (!is_tunnel) { ret = ice_fdir_hw_tbl_conf(pf, pf->main_vsi, pf->fdir.fdir_vsi, - seg, flow, false); + seg_tun + 1, flow, false); } else { - seg_tun = (struct ice_flow_seg_info *) - ice_malloc(hw, sizeof(*seg) * ICE_FD_HW_SEG_MAX); - if (!seg_tun) { - PMD_DRV_LOG(ERR, "No memory can be allocated"); - rte_free(seg); - return -ENOMEM; - } - rte_memcpy(&seg_tun[1], seg, sizeof(*seg)); ret = ice_fdir_hw_tbl_conf(pf, pf->main_vsi, pf->fdir.fdir_vsi, seg_tun, flow, true); } @@ -1048,9 +1047,7 @@ ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, if (!ret) { return ret; } else if (ret < 0) { - rte_free(seg); - if (is_tunnel) - rte_free(seg_tun); + rte_free(seg_tun); return (ret == -EEXIST) ? 0 : ret; } else { return ret; @@ -1086,12 +1083,7 @@ ice_fdir_init(struct ice_adapter *ad) if (ret) return ret; - if (ad->active_pkg_type == ICE_PKG_TYPE_COMMS) - parser = &ice_fdir_parser_comms; - else if (ad->active_pkg_type == ICE_PKG_TYPE_OS_DEFAULT) - parser = &ice_fdir_parser_os; - else - return -EINVAL; + parser = &ice_fdir_parser; return ice_register_parser(parser, ad); } @@ -1099,16 +1091,13 @@ ice_fdir_init(struct ice_adapter *ad) static void ice_fdir_uninit(struct ice_adapter *ad) { - struct ice_pf *pf = &ad->pf; struct ice_flow_parser *parser; + struct ice_pf *pf = &ad->pf; if (ad->hw.dcf_enabled) return; - if (ad->active_pkg_type == ICE_PKG_TYPE_COMMS) - parser = &ice_fdir_parser_comms; - else - parser = &ice_fdir_parser_os; + parser = &ice_fdir_parser; ice_unregister_parser(parser, ad); @@ -1260,7 +1249,8 @@ ice_fdir_create_filter(struct ice_adapter *ad, is_tun = ice_fdir_is_tunnel_profile(filter->tunnel_type); ret = ice_fdir_input_set_conf(pf, filter->input.flow_type, - filter->input_set, filter->tunnel_type); + filter->input_set, filter->outer_input_set, + filter->tunnel_type); if (ret) { rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, @@ -1292,6 +1282,9 @@ ice_fdir_create_filter(struct ice_adapter *ad, goto free_counter; } + if (filter->mark_flag == 1) + ice_fdir_rx_parsing_enable(ad, 1); + rte_memcpy(entry, filter, sizeof(*entry)); ret = ice_fdir_entry_insert(pf, entry, &key); if (ret) { @@ -1364,6 +1357,10 @@ ice_fdir_destroy_filter(struct ice_adapter *ad, } ice_fdir_cnt_update(pf, filter->input.flow_type, is_tun, false); + + if (filter->mark_flag == 1) + ice_fdir_rx_parsing_enable(ad, 0); + flow->rule = NULL; rte_free(filter); @@ -1536,7 +1533,7 @@ ice_fdir_parse_action(struct ice_adapter *ad, break; case RTE_FLOW_ACTION_TYPE_MARK: mark_num++; - + filter->mark_flag = 1; mark_spec = actions->conf; filter->input.fltr_id = mark_spec->id; filter->input.fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_ONE; @@ -1620,9 +1617,8 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint32_t vtc_flow_cpu; - - enum rte_flow_item_type next_type; uint16_t ether_type; + enum rte_flow_item_type next_type; for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { if (item->last) { @@ -1640,50 +1636,40 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, eth_mask = item->mask; next_type = (item + 1)->type; - if (next_type == RTE_FLOW_ITEM_TYPE_END && - (!eth_spec || !eth_mask)) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, "NULL eth spec/mask."); - return -rte_errno; - } - if (eth_spec && eth_mask) { - if (!rte_is_zero_ether_addr(ð_spec->src) || - !rte_is_zero_ether_addr(ð_mask->src)) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Src mac not support"); - return -rte_errno; - } - - if (rte_is_broadcast_ether_addr(ð_mask->dst)) { + if (!rte_is_zero_ether_addr(ð_mask->dst)) { input_set |= ICE_INSET_DMAC; rte_memcpy(&filter->input.ext_data.dst_mac, - ð_spec->dst, - RTE_ETHER_ADDR_LEN); - } else if (eth_mask->type == RTE_BE16(0xffff)) { + ð_spec->dst, + RTE_ETHER_ADDR_LEN); + } + + if (!rte_is_zero_ether_addr(ð_mask->src)) { + input_set |= ICE_INSET_SMAC; + rte_memcpy(&filter->input.ext_data.src_mac, + ð_spec->src, + RTE_ETHER_ADDR_LEN); + } + + /* Ignore this field except for ICE_FLTR_PTYPE_NON_IP_L2 */ + if (eth_mask->type == RTE_BE16(0xffff) && + next_type == RTE_FLOW_ITEM_TYPE_END) { + input_set |= ICE_INSET_ETHERTYPE; ether_type = rte_be_to_cpu_16(eth_spec->type); + if (ether_type == RTE_ETHER_TYPE_IPV4 || - ether_type == RTE_ETHER_TYPE_IPV6) { + ether_type == RTE_ETHER_TYPE_IPV6) { rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Unsupported ether_type."); + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Unsupported ether_type."); return -rte_errno; } - input_set |= ICE_INSET_ETHERTYPE; rte_memcpy(&filter->input.ext_data.ether_type, - ð_spec->type, - sizeof(eth_spec->type)); + ð_spec->type, + sizeof(eth_spec->type)); flow_type = ICE_FLTR_PTYPE_NON_IP_L2; - } else { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Invalid dst mac addr mask or ethertype mask"); } } break; @@ -1981,9 +1967,18 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, } } - if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU || - tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) + if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP) flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU_EH && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_EH_IPV4_OTHER; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU && + flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_GTPU_IPV6_OTHER; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU_EH && + flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_GTPU_EH_IPV6_OTHER; filter->tunnel_type = tunnel_type; filter->input.flow_type = flow_type; @@ -2008,14 +2003,15 @@ ice_fdir_parse(struct ice_adapter *ad, int ret; memset(filter, 0, sizeof(*filter)); - item = ice_search_pattern_match_item(pattern, array, array_len, error); + item = ice_search_pattern_match_item(ad, pattern, array, array_len, + error); if (!item) return -rte_errno; ret = ice_fdir_parse_pattern(ad, pattern, error, filter); if (ret) goto error; - input_set = filter->input_set; + input_set = filter->input_set | filter->outer_input_set; if (!input_set || input_set & ~item->input_set_mask) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_SPEC, @@ -2036,18 +2032,10 @@ error: return ret; } -static struct ice_flow_parser ice_fdir_parser_os = { - .engine = &ice_fdir_engine, - .array = ice_fdir_pattern_os, - .array_len = RTE_DIM(ice_fdir_pattern_os), - .parse_pattern_action = ice_fdir_parse, - .stage = ICE_FLOW_STAGE_DISTRIBUTOR, -}; - -static struct ice_flow_parser ice_fdir_parser_comms = { +static struct ice_flow_parser ice_fdir_parser = { .engine = &ice_fdir_engine, - .array = ice_fdir_pattern_comms, - .array_len = RTE_DIM(ice_fdir_pattern_comms), + .array = ice_fdir_pattern_list, + .array_len = RTE_DIM(ice_fdir_pattern_list), .parse_pattern_action = ice_fdir_parse, .stage = ICE_FLOW_STAGE_DISTRIBUTOR, };