This patch adds a new marking_colors_supported and marking_colors_needed arrays. Also splits the TOS marking function - which previously could specify ECN or DSCP marking into two separate calls. Also improved the documentation.
Also this patch updates the linux-generic odp_traffic_mngr.c implementation to this latest API. In addition a few bugs were fixed in the marking implementations. Signed-off-by: Barry Spinney <[email protected]> --- include/odp/api/spec/traffic_mngr.h | 137 ++++++++++++++++----- .../include/odp_traffic_mngr_internal.h | 11 +- platform/linux-generic/odp_traffic_mngr.c | 127 ++++++++++++++----- 3 files changed, 207 insertions(+), 68 deletions(-) diff --git a/include/odp/api/spec/traffic_mngr.h b/include/odp/api/spec/traffic_mngr.h index fff4c46..7ed5fc9 100644 --- a/include/odp/api/spec/traffic_mngr.h +++ b/include/odp/api/spec/traffic_mngr.h @@ -293,19 +293,35 @@ typedef struct { * form of VLAN egress marking using the odp_tm_vlan_marking() * function. This being true does not imply that all colors and * subfield values and changes are supported. Unsupported features - * can be detected by the marking function returning an error code.*/ + * can be detected by the marking function returning an error code. */ odp_bool_t vlan_marking_supported; - /** ip_tos_marking_supported indicates that this TM system supports + /** ecn_marking_supported indicates that this TM system supports + * Explicit Congestion Notification egress marking by using the + * odp_tm_ip_ecn_marking() function. Note that the ECN is the bottom + * two bits of the IPv4 TOS field or the analogous IPv6 Traffic Class + * (TC) field. Note that the ecn_marking_supported boolean being + * true does not imply that all colors are supported. */ + odp_bool_t ecn_marking_supported; + + /** drop_prec_marking_supported indicates that this TM system supports * SOME form of IPv4/IPv6 egress marking by using the - * odp_tm_ip_tos_marking() function. Note that the actually field + * odp_tm_drop_prec_marking() function. Note that the actually field * modified for IPv4 pkts is called TOS, whereas the field modified * for IPv6 pkts is called Traffic Class (TC) - but they are analogous - * fields. Note that the ip_tos_marking_supported boolean being true + * fields. Note that the drop_prec_marking_supported boolean being true * does not imply that all colors and subfield values and changes are * supported. Unsupported features can be detected by the marking * function returning an error code.*/ - odp_bool_t ip_tos_marking_supported; + odp_bool_t drop_prec_marking_supported; + + /** The marking_colors_supported array is used to indicate which colors + * can be used for marking. A value of FALSE means that this color + * should not be enabled for either vlan marking, ecn marking or + * drop precedence marking. A value of TRUE means that this color is + * supported for at least one of (and ideally all of) vlan marking, + * ecn marking or drop precedence marking. */ + odp_bool_t marking_colors_supported[ODP_NUM_PACKET_COLORS]; /** The per_level array specifies the TM system capabilities that * can vary based upon the tm_node level. */ @@ -379,7 +395,7 @@ typedef struct { uint32_t max_tm_queues; /** num_levels specifies that number of levels of hierarchical - * scheduling that will b used. This is a count of the tm_node + * scheduling that will be used. This is a count of the tm_node * stages and does not include tm_queues or tm_egress objects. */ uint8_t num_levels; @@ -402,11 +418,25 @@ typedef struct { * vlan_marking_supported. */ odp_bool_t vlan_marking_needed; - /** ip_tos_marking_needed indicates that the ODP application expects + /** ecn_marking_needed indicates that the ODP application expects + * to use some form of IPv4 TOS or IPv6 TC field egress marking by + * using the odp_tm_ecn_marking() function. See also comments for + * ecn_marking_supported. */ + odp_bool_t ecn_marking_needed; + + /** drop_prec_marking_needed indicates that the ODP application expects * to use some form of IPv4 TOS or IPv6 TC field egress marking by - * using the odp_tm_ip_tos_marking() function. See also comments for - * ip_tos_marking_supported. */ - odp_bool_t ip_tos_marking_needed; + * using the odp_tm_drop_prec_marking() function. See also comments for + * drop_prec_marking_supported. */ + odp_bool_t drop_prec_marking_needed; + + /** The marking_colors_needed array is used to indicate which colors + * are expected to be used for marking. A value of FALSE means that + * the application will not enable this color for vlan marking, + * ecn marking nor drop precedence marking. A value of TRUE means that + * the application expects to use this color in conjunction with one or + * more of the marking API's. */ + odp_bool_t marking_colors_needed[ODP_NUM_PACKET_COLORS]; /** The per_level array specifies the TM system requirements that * can vary based upon the tm_node level. */ @@ -480,7 +510,7 @@ void odp_tm_egress_init(odp_tm_egress_t *egress); * that N is larger than the capabilities_size, N will still be returned, * but only capabilities_size records will be filled in. * - * @param[out] capabilities An arary of odp_tm_capabilities_t records to + * @param[out] capabilities An array of odp_tm_capabilities_t records to * be filled in. * @param[in] capabilities_size The number of odp_tm_capabilities_t records * in the capabilities array. @@ -598,7 +628,11 @@ int odp_tm_destroy(odp_tm_t odp_tm); * field (but only for pkts that already carry a VLAN tag) of a pkt based upon * the final pkt (or shaper?) color assigned to the pkt when it reaches the * egress node. When drop_eligible_enabled is false, then the given color has - * no effect on the VLAN fields. + * no effect on the VLAN fields. See IEEE 802.1q for more details. + * + * Note that ALL ODP implementations are required to SUCCESSFULLY handle all + * calls to this function with drop_eligible_enabled == FALSE - i.e. must + * always return 0 when disabling this feature. * * @param[in] odp_tm Odp_tm is used to identify the TM system * whose egress behavior is being changed. @@ -612,39 +646,76 @@ int odp_tm_vlan_marking(odp_tm_t odp_tm, odp_packet_color_t color, odp_bool_t drop_eligible_enabled); -/** IP Tos Marking. +/** Explicit Congestion Notification Marking. + * + * The odp_tm_ecn_marking() function allows one to configure the TM + * egress so that the two bit ECN subfield of the eight bit TOS field of an + * IPv4 pkt OR the eight bit Traffic Class (TC) field of an IPv6 pkt can be + * selectively modified based upon the final color assigned to the pkt when it + * reaches the egress. Note that the IPv4 header checksum will be updated - + * but only if the IPv4 TOS field actually changes as a result of this + * setting or the odp_tm_drop_prec_marking setting. For IPv6, since there is + * no header checksum, nothing needs to be done. Note that this marking API + * will only ever cause both ECN bits to be set to 1 - but only for TCP pkts + * whose incoming ECN bits are not both 0. See RFC 3168 for more details. * - * The odp_tm_ip_tos_marking() function allows one to configure the TM - * egress so that the eight bit TOS field of an IPv4 pkt OR the analogous - * eight bit Traffic Class (TC) field of an IPv6 pkt can be selectively - * modified based upon the final color assigned to the pkt when it reaches the - * egress. Note that both the TOS/TC field and the VLAN header of a VLAN tagged - * IP pkt could be independently modified. Also note that this function - * will update the IPv4 header checksum - but only if the TOS field actually - * changes. For IPv6, since there is no header checksum, nothing needs to - * be done. + * Note that ALL ODP implementations are required to SUCCESSFULLY handle all + * calls to this function with ecn_ce_enabled == FALSE - i.e. must always + * return 0 when disabling this feature. * * @param[in] odp_tm Odp_tm is used to identify the TM system whose * egress behavior is being changed. * @param[in] color The packet color whose egress marking is * being changed. - * @param[in] dscp_enabled If true then egressed IPv4/IPv6 pkts with this - * color will have the pkt's DSCP subfield set to the - * new_dscp parameter (see below). - * @param[in] new_dscp The Differentiated Services Code Point value. - * Must be in the range 0..63. * @param[in] ecn_ce_enabled If true then egressed IPv4/IPv6 pkts whose * protocol field is TCP AND whose ECN subfield has - * one of the two values 1 or 2, will set this + * either one of the two values 1 or 2, will set this * subfield to the value ECN_CE - i.e. Congestion * Experienced (whose value is 3). * @return 0 upon success, < 0 upon failure. */ -int odp_tm_ip_tos_marking(odp_tm_t odp_tm, - odp_packet_color_t color, - odp_bool_t dscp_enabled, - uint8_t new_dscp, - odp_bool_t ecn_ce_enabled); +int odp_tm_ecn_marking(odp_tm_t odp_tm, + odp_packet_color_t color, + odp_bool_t ecn_ce_enabled); + +/** Drop Precedence Marking. + * + * The odp_tm_drop_prec_marking() function allows one to configure the TM + * egress so that the two RFC 2597 Drop Precedence bits can be modified + * based upon the final color assigned to the pkt when it reaches the egress. + * The Drop Precedence bits are contained within the six bit Differentiated + * Services Code Point subfield of the IPv4 TOS field or the IPv6 Traffic + * Class (TC) field. Specifically the Drop Precedence sub-subfield can be + * accessed with a DSCP bit mask of 0x06. When enabled for a given color, + * these two bits will be set to Medium Drop Precedence (value 0x4) if the + * color is ODP_PACKET_YELLOW, set to High Drop Precedence (value 0x6) if + * the color is ODP_PACKET_RED, otherwise set to Low Drop Precedence for any + * other color. Of course an implementation can restrict the set of colors + * which can be enabled via the marking_colors_supported array in the + * odp_tm_capabilities_t record. + * + * Note that the IPv4 header checksum will be updated - but only if the + * IPv4 TOS field actually changes as a result of this setting or the + * odp_tm_ecn_marking setting. For IPv6, since there is no header checksum, + * nothing else needs to be done. + * + * Note that ALL ODP implementations are required to SUCCESSFULLY handle all + * calls to this function with drop_prec_enabled == FALSE - i.e. must always + * return 0 when disabling this feature. + * + * @param[in] odp_tm Odp_tm is used to identify the TM system whose + * egress behavior is being changed. + * @param[in] color The packet color whose egress marking is + * being changed. + * @param[in] drop_prec_enabled If true then egressed IPv4/IPv6 pkts with this + * color will have the pkt's Drop Precedence + * sub-subfield of the DSCP subfield set to + * LOW, MEDIUM or HIGH drop precedence. + * @return 0 upon success, < 0 upon failure. + */ +int odp_tm_drop_prec_marking(odp_tm_t odp_tm, + odp_packet_color_t color, + odp_bool_t drop_prec_enabled); /** Shaper profile types and functions */ diff --git a/platform/linux-generic/include/odp_traffic_mngr_internal.h b/platform/linux-generic/include/odp_traffic_mngr_internal.h index a0853eb..90036de 100644 --- a/platform/linux-generic/include/odp_traffic_mngr_internal.h +++ b/platform/linux-generic/include/odp_traffic_mngr_internal.h @@ -67,6 +67,15 @@ typedef struct stat file_stat_t; typedef uint64_t tm_handle_t; +#define LOW_DROP_PRECEDENCE 0x02 +#define MEDIUM_DROP_PRECEDENCE 0x04 +#define HIGH_DROP_PRECEDENCE 0x06 +#define DROP_PRECEDENCE_MASK 0x06 +#define DSCP_CLASS1 0x08 +#define DSCP_CLASS2 0x10 +#define DSCP_CLASS3 0x18 +#define DSCP_CLASS4 0x20 + #define PF_RM_CURRENT_BEST 0x01 #define PF_NEW_PKT_IN 0x02 #define PF_SHAPER_DELAYED 0x10 @@ -327,7 +336,7 @@ typedef struct { typedef struct { odp_bool_t marking_enabled; - odp_bool_t dscp_enabled; + odp_bool_t drop_prec_enabled; uint8_t shifted_dscp; uint8_t inverted_dscp_mask; odp_bool_t ecn_ce_enabled; diff --git a/platform/linux-generic/odp_traffic_mngr.c b/platform/linux-generic/odp_traffic_mngr.c index 27530ff..1cc5e9b 100644 --- a/platform/linux-generic/odp_traffic_mngr.c +++ b/platform/linux-generic/odp_traffic_mngr.c @@ -1924,7 +1924,7 @@ static void egress_ipv4_tos_marking(tm_tos_marking_t *tos_marking, old_tos = ipv4_hdr_ptr->tos; new_tos = old_tos; - if (tos_marking->dscp_enabled) + if (tos_marking->drop_prec_enabled) new_tos = (new_tos & tos_marking->inverted_dscp_mask) | tos_marking->shifted_dscp; @@ -1989,10 +1989,11 @@ static void egress_ipv6_tc_marking(tm_tos_marking_t *tos_marking, } old_ver_tc_flow = odp_be_to_cpu_32(ipv6_hdr_ptr->ver_tc_flow); - old_tc = old_ver_tc_flow >> ODPH_IPV6HDR_TC_SHIFT; + old_tc = (old_ver_tc_flow & ODPH_IPV6HDR_TC_MASK) + >> ODPH_IPV6HDR_TC_SHIFT; new_tc = old_tc; - if (tos_marking->dscp_enabled) + if (tos_marking->drop_prec_enabled) new_tc = (new_tc & tos_marking->inverted_dscp_mask) | tos_marking->shifted_dscp; @@ -2006,7 +2007,7 @@ static void egress_ipv6_tc_marking(tm_tos_marking_t *tos_marking, if (new_tc == old_tc) return; - new_ver_tc_flow = (old_ver_tc_flow & ODPH_IPV6HDR_TC_MASK) | + new_ver_tc_flow = (old_ver_tc_flow & ~ODPH_IPV6HDR_TC_MASK) | (new_tc << ODPH_IPV6HDR_TC_SHIFT); ipv6_hdr_ptr->ver_tc_flow = odp_cpu_to_be_32(new_ver_tc_flow); @@ -2345,12 +2346,12 @@ int odp_tm_capabilities(odp_tm_capabilities_t capabilities[] ODP_UNUSED, { odp_tm_level_capabilities_t *per_level_cap; odp_tm_capabilities_t *cap_ptr; + odp_packet_color_t color; uint32_t level_idx; if (capabilities_size == 0) return -1; - /* TBD */ cap_ptr = &capabilities[0]; memset(cap_ptr, 0, sizeof(odp_tm_capabilities_t)); @@ -2360,7 +2361,11 @@ int odp_tm_capabilities(odp_tm_capabilities_t capabilities[] ODP_UNUSED, cap_ptr->tm_queue_wred_supported = true; cap_ptr->tm_queue_dual_slope_supported = true; cap_ptr->vlan_marking_supported = true; - cap_ptr->ip_tos_marking_supported = true; + cap_ptr->ecn_marking_supported = true; + cap_ptr->drop_prec_marking_supported = true; + + for (color = 0; color < ODP_NUM_PACKET_COLORS; color++) + cap_ptr->marking_colors_supported[color] = true; for (level_idx = 0; level_idx < cap_ptr->max_levels; level_idx++) { per_level_cap = &cap_ptr->per_level[level_idx]; @@ -2378,7 +2383,7 @@ int odp_tm_capabilities(odp_tm_capabilities_t capabilities[] ODP_UNUSED, per_level_cap->weights_supported = true; } - return 0; + return 1; } static void tm_system_capabilities_set(odp_tm_capabilities_t *cap_ptr, @@ -2386,6 +2391,7 @@ static void tm_system_capabilities_set(odp_tm_capabilities_t *cap_ptr, { odp_tm_level_requirements_t *per_level_req; odp_tm_level_capabilities_t *per_level_cap; + odp_packet_color_t color; odp_bool_t shaper_supported, wred_supported; odp_bool_t dual_slope; uint32_t num_levels, level_idx, max_nodes; @@ -2407,7 +2413,13 @@ static void tm_system_capabilities_set(odp_tm_capabilities_t *cap_ptr, cap_ptr->tm_queue_wred_supported = wred_supported; cap_ptr->tm_queue_dual_slope_supported = dual_slope; cap_ptr->vlan_marking_supported = req_ptr->vlan_marking_needed; - cap_ptr->ip_tos_marking_supported = req_ptr->ip_tos_marking_needed; + cap_ptr->ecn_marking_supported = req_ptr->ecn_marking_needed; + cap_ptr->drop_prec_marking_supported = + req_ptr->drop_prec_marking_needed; + + for (color = 0; color < ODP_NUM_PACKET_COLORS; color++) + cap_ptr->marking_colors_supported[color] = + req_ptr->marking_colors_needed[color]; for (level_idx = 0; level_idx < num_levels; level_idx++) { per_level_cap = &cap_ptr->per_level[level_idx]; @@ -2635,6 +2647,11 @@ int odp_tm_vlan_marking(odp_tm_t odp_tm, if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS < color)) return -1; + if (drop_eligible_enabled) + if ((!tm_system->requirements.vlan_marking_needed) || + (!tm_system->requirements.marking_colors_needed[color])) + return -2; + vlan_marking = &tm_system->marking.vlan_marking[color]; vlan_marking->marking_enabled = drop_eligible_enabled; vlan_marking->drop_eligible_enabled = drop_eligible_enabled; @@ -2646,37 +2663,79 @@ int odp_tm_vlan_marking(odp_tm_t odp_tm, return 0; } -static void tm_tos_marking(tm_tos_marking_t *tos_marking, - odp_bool_t dscp_enabled, - uint8_t new_dscp, - odp_bool_t ecn_ce_enabled) - +int odp_tm_ecn_marking(odp_tm_t odp_tm, + odp_packet_color_t color, + odp_bool_t ecn_ce_enabled) { - tos_marking->marking_enabled = dscp_enabled | ecn_ce_enabled; - tos_marking->dscp_enabled = dscp_enabled; - tos_marking->shifted_dscp = (new_dscp & ~ODPH_IP_TOS_DSCP_MASK) - << ODPH_IP_TOS_DSCP_SHIFT; - tos_marking->inverted_dscp_mask = (uint8_t)~ODPH_IP_TOS_DSCP_MASK; - tos_marking->ecn_ce_enabled = ecn_ce_enabled; + tm_tos_marking_t *tos_marking; + tm_system_t *tm_system; + + tm_system = GET_TM_SYSTEM(odp_tm); + if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS <= color)) + return -1; + + if (ecn_ce_enabled) + if ((!tm_system->requirements.ecn_marking_needed) || + (!tm_system->requirements.marking_colors_needed[color])) + return -2; + + tos_marking = &tm_system->marking.ip_tos_marking[color]; + tos_marking->marking_enabled = tos_marking->drop_prec_enabled | + ecn_ce_enabled; + tos_marking->ecn_ce_enabled = ecn_ce_enabled; + + if (ecn_ce_enabled) + tm_system->marking_enabled = true; + else + tm_system->marking_enabled = tm_marking_enabled(tm_system); + + return 0; } -int odp_tm_ip_tos_marking(odp_tm_t odp_tm, - odp_packet_color_t color, - odp_bool_t dscp_enabled, - uint8_t new_dscp, - odp_bool_t ecn_ce_enabled) +int odp_tm_drop_prec_marking(odp_tm_t odp_tm, + odp_packet_color_t color, + odp_bool_t drop_prec_enabled) { - tm_tos_marking_t *ip_marking; + tm_tos_marking_t *tos_marking; tm_system_t *tm_system; + uint8_t dscp_mask, new_dscp, inverted_mask, tos_mask; + uint8_t shifted_dscp; tm_system = GET_TM_SYSTEM(odp_tm); - if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS <= color) || - (ODPH_IP_TOS_MAX_DSCP < new_dscp)) + if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS <= color)) return -1; - ip_marking = &tm_system->marking.ip_tos_marking[color]; - tm_tos_marking(ip_marking, dscp_enabled, new_dscp, ecn_ce_enabled); - if (dscp_enabled | ecn_ce_enabled) + if (drop_prec_enabled) + if ((!tm_system->requirements.drop_prec_marking_needed) || + (!tm_system->requirements.marking_colors_needed[color])) + return -2; + + dscp_mask = DROP_PRECEDENCE_MASK; + if (color == ODP_PACKET_YELLOW) + new_dscp = MEDIUM_DROP_PRECEDENCE; + else if (color == ODP_PACKET_RED) + new_dscp = HIGH_DROP_PRECEDENCE; + else + new_dscp = LOW_DROP_PRECEDENCE; + + if (drop_prec_enabled) { + new_dscp = new_dscp & dscp_mask; + inverted_mask = (uint8_t)~dscp_mask; + tos_mask = (inverted_mask << ODPH_IP_TOS_DSCP_SHIFT) | + ODPH_IP_TOS_ECN_MASK; + shifted_dscp = new_dscp << ODPH_IP_TOS_DSCP_SHIFT; + } else { + tos_mask = 0xFF; /* Note that this is an inverted mask */ + shifted_dscp = 0; + } + + tos_marking = &tm_system->marking.ip_tos_marking[color]; + tos_marking->marking_enabled = drop_prec_enabled | + tos_marking->ecn_ce_enabled; + tos_marking->drop_prec_enabled = drop_prec_enabled; + tos_marking->shifted_dscp = shifted_dscp; + tos_marking->inverted_dscp_mask = tos_mask; + if (drop_prec_enabled) tm_system->marking_enabled = true; else tm_system->marking_enabled = tm_marking_enabled(tm_system); @@ -4012,18 +4071,18 @@ int odp_tm_node_fanin_info(odp_tm_node_t tm_node, return -5; info->is_last = next_shaper_obj->fanin_list_next == NULL; - if (shaper_obj->in_tm_node_obj) { - fanin_tm_node_obj = shaper_obj->enclosing_entity; + if (next_shaper_obj->in_tm_node_obj) { + fanin_tm_node_obj = next_shaper_obj->enclosing_entity; info->tm_node = MAKE_ODP_TM_NODE(fanin_tm_node_obj); info->tm_queue = ODP_TM_INVALID; } else { - fanin_tm_queue_obj = shaper_obj->enclosing_entity; + fanin_tm_queue_obj = next_shaper_obj->enclosing_entity; info->tm_queue = MAKE_ODP_TM_QUEUE(fanin_tm_queue_obj); info->tm_node = ODP_TM_INVALID; } info->sched_profile = ODP_TM_INVALID; - sched_params = shaper_obj->sched_params; + sched_params = next_shaper_obj->sched_params; if (sched_params != NULL) info->sched_profile = sched_params->sched_profile; -- 2.7.2 _______________________________________________ lng-odp mailing list [email protected] https://lists.linaro.org/mailman/listinfo/lng-odp
