wred_ecn.c (16266B)
1 /* Feature : WRED-ECN 2 * 3 * Usage : BCM.0> cint wred_ecn.c 4 * 5 * config : wred_ecn_config.bcm 6 * 7 * Log file : wred_ecn_log.txt 8 * 9 * Test Topology : 10 * 11 * DMAC=0x1 +------------+ DMAC=0x1 12 * SMAC=0x2 +--------> 56980 +-------> SMAC=0x2 13 * VLAN=2,Pri=4 cd0(1)| |cd1(2) VLAN=2,Pri=4 14 * | l2:mac=0x1 | 15 * TEST-1: | vlan=2 | TEST-1: 16 * IP.Protocol=1(ICMP) | port=2 | IF congested: 17 * ECN bits=01 | | ECN bits=11 18 * +------------+ If not congested: 19 * TEST-2: ECN bits=10 20 * IP.Protocol=2(IGMP) 21 * ECN bits=01 TEST-2: 22 * If congested: 23 * WRED drops 24 * If not congested: 25 * No drops or marking 26 * 27 * Summary: 28 * ======== 29 * This cint example illustrates configuration of WRED and ECN feature 30 * 31 * Detailed steps done in the CINT script: 32 * ======================================= 33 * 1) Step1 - Test Setup (Done in test_setup()) 34 * ============================================ 35 * a) Select one ingress and one egress port 36 * 2) Step2 - Configuration (Done in wred_ecn_config()) 37 * ==================================================== 38 * a) data_path_setup - sets up required data path for traffic 39 * b) set_responsive_protocol_indication - sets IP Protocol's Responsive indication setting 40 * c) ip_to_int_cn_mapping - maps IP header ECN bits to INT_CN value 41 * d) int_cn_to_mmuif_mapping - INT_CN value to WRED_RESPONSIVE and MARK_ELIGIBLE configuration 42 * e) mmu_wred_ecn_setup - MMU wred and ecn profile Settings 43 * f) egr_int_cn_update - configure outgoing INT_CN value based on congestion status in MMU 44 * g) egr_ecn_mark - Mark outgoing IP header ECN bits based on final INT_CN value 45 * 3) Step3 - Verification (Done in verify()) 46 * ================================== 47 * a) Transmit ICMP packets at line rate through Ixia connected to cd0 48 * b) Transmit IGMP packets at line rate through Ixia connected to cd0 49 * c) Expected Result: 50 * ================ 51 * For ICMP packets - In case of congestion we should see ECN marking (ECN bits=11) 52 * for packets egressing cd1. If no congestion, ECN marking will not happen (ECN bits=10) 53 * FOR IGMP packets - In case of congestion, WRED drops will be seen on cd1. 54 * This can be verified by WRED_PKT_GRE.cd1' in 'show c' output 55 * If no congestion, No wred drops will be seen. 56 */ 57 58 cint_reset(); 59 int rv = 0; 60 int unit = 0; 61 int check = 1; /*Make it '1' to dump tables that are configured by each API*/ 62 bcm_port_t ing_port = 1; /*Ingress port */ 63 bcm_port_t egr_port = 2; /*Egress port */ 64 bcm_cos_t cos = 4; /*COS Queue of Egress port on which WRED is configured */ 65 66 uint8 iphdr_ecn = 1; /*Incoming packet IP headers ECN field(2 bits). 0b01 taken as example for this test.*/ 67 uint8 resp_mapped_int_cn = 2; /*INT_CN value to which Responsive protocol is mapped to. 0b10 taken as example for this test */ 68 uint8 nonresp_mapped_int_cn = 0; /*INT_CN value to which Non-Responsive protocol is mapped to. 0b00 taken as example for this test */ 69 70 uint8 non_cong_int_cn = 2; /*INT_CN value at Dequeue from MMU when there is no congestion. 0b10 taken as example for this test */ 71 uint8 cong_int_cn = 3; /*INT_CN value at Dequeue from MMU when there is congestion. 0b11 taken as example for this test */ 72 73 /* This function is written so that hardcoding of port 74 numbers in Cint scripts is removed. This function gives 75 required number of ports 76 */ 77 bcm_error_t portNumbersGet(int unit, int *port_list, int num_ports) 78 { 79 80 int i=0,port=0,rv=0; 81 bcm_port_config_t configP; 82 bcm_pbmp_t ports_pbmp; 83 84 rv = bcm_port_config_get(unit,&configP); 85 if(BCM_FAILURE(rv)) { 86 printf("\nError in retrieving port configuration: %s.\n",bcm_errmsg(rv)); 87 return rv; 88 } 89 90 ports_pbmp = configP.e; 91 for (i= 1; i < BCM_PBMP_PORT_MAX; i++) { 92 if (BCM_PBMP_MEMBER(&ports_pbmp,i)&& (port < num_ports)) { 93 port_list[port]=i; 94 port++; 95 } 96 } 97 98 if (( port == 0 ) || ( port != num_ports )) { 99 printf("portNumbersGet() failed \n"); 100 return -1; 101 } 102 103 return BCM_E_NONE; 104 } 105 106 bcm_error_t test_setup(int unit) 107 { 108 int port_list[2], i; 109 if (BCM_E_NONE != portNumbersGet(unit, port_list, 2)) { 110 printf("portNumbersGet() failed\n"); 111 return -1; 112 } 113 114 ing_port = port_list[0]; 115 egr_port = port_list[1]; 116 117 return BCM_E_NONE; 118 } 119 120 bcm_error_t data_path_setup(int unit) 121 { 122 bcm_vlan_t vid = 2; 123 bcm_mac_t dest_mac = "00:00:00:00:00:01"; /*Destination MAC */ 124 bcm_pbmp_t pbmp,upbmp; 125 bcm_l2_addr_t l2addr; 126 127 rv = bcm_vlan_create(unit, vid); 128 if (rv != BCM_E_NONE) { 129 printf("bcm_vlan_create returned '%s'\n",bcm_errmsg(rv)); 130 return rv; 131 } 132 133 BCM_PBMP_CLEAR(pbmp); 134 BCM_PBMP_CLEAR(upbmp); 135 BCM_PBMP_PORT_ADD(pbmp, ing_port); 136 BCM_PBMP_PORT_ADD(pbmp, egr_port); 137 rv = bcm_vlan_port_add(unit, vid, pbmp, upbmp); 138 if (rv != BCM_E_NONE) { 139 printf("bcm_vlan_port_add returned '%s'\n",bcm_errmsg(rv)); 140 return rv; 141 } 142 143 bcm_l2_addr_t_init(l2addr, dest_mac, vid); 144 l2addr.port = egr_port; 145 l2addr.flags |= BCM_L2_STATIC; 146 /*WRED works ONLY on unicast. So, l2 entry with DEST-MAC and Dest-port should be present*/ 147 rv = bcm_l2_addr_add(unit, &l2addr); 148 if (rv != BCM_E_NONE) { 149 printf("bcm_l2_addr_add returned '%s'\n",bcm_errmsg(rv)); 150 return rv; 151 } 152 return BCM_E_NONE; 153 } 154 155 bcm_error_t set_responsive_protocol_indication(int unit) 156 { 157 uint8 ip_protocol_resp = 1; /*Protocol field in IP header that gets programmed as Responsive (generally TCP.) 1 = ICMP */ 158 uint8 ip_protocol_nonresp = 2; /*Protocol field in IP header that gets programmed as Responsive (generally UDP.) 2 = IGMP*/ 159 int responsive_indicator = 1; 160 161 rv = bcm_ecn_responsive_protocol_set(unit, ip_protocol_resp, responsive_indicator); 162 if (rv != BCM_E_NONE) { 163 printf("bcm_ecn_responsive_protocol_set~Resp-protocol returned '%s'\n",bcm_errmsg(rv)); 164 } 165 166 responsive_indicator = 0; 167 rv = bcm_ecn_responsive_protocol_set(unit, ip_protocol_nonresp, responsive_indicator); 168 if (rv != BCM_E_NONE) { 169 printf("bcm_ecn_responsive_protocol_set~NonResp-protocol returned '%s'\n",bcm_errmsg(rv)); 170 return rv; 171 } 172 return BCM_E_NONE; 173 } 174 175 bcm_error_t ip_to_int_cn_mapping(int unit) 176 { 177 bcm_ecn_traffic_map_info_t map; 178 bcm_ecn_traffic_action_config_t config; 179 bcm_cosq_gport_discard_t discard_cfg; 180 181 bcm_ecn_traffic_map_info_t_init(&map); 182 map.ecn = iphdr_ecn; 183 map.flags = BCM_ECN_TRAFFIC_MAP_RESPONSIVE; 184 map.int_cn = resp_mapped_int_cn; /*Responsive*/ 185 rv = bcm_ecn_traffic_map_set(unit, &map); 186 if (rv != BCM_E_NONE) { 187 printf("bcm_ecn_traffic_map_set~Resp-protocol returned '%s'\n",bcm_errmsg(rv)); 188 return rv; 189 } 190 191 bcm_ecn_traffic_map_info_t_init(&map); 192 map.ecn = iphdr_ecn; 193 map.flags = 0; 194 map.int_cn = nonresp_mapped_int_cn; /*Non-Responsive */ 195 rv = bcm_ecn_traffic_map_set(unit, &map); 196 if (rv != BCM_E_NONE) { 197 printf("bcm_ecn_traffic_map_set~NonResp-protocol returned '%s'\n",bcm_errmsg(rv)); 198 return rv; 199 } 200 return BCM_E_NONE; 201 } 202 203 bcm_error_t int_cn_to_mmuif_mapping(int unit) 204 { 205 bcm_ecn_traffic_action_config_t config; 206 207 bcm_ecn_traffic_action_config_t_init(&config); 208 config.action_type = BCM_ECN_TRAFFIC_ACTION_TYPE_ENQUEUE; 209 config.int_cn = resp_mapped_int_cn; /*Responsive*/ 210 config.action_flags = BCM_ECN_TRAFFIC_ACTION_ENQUEUE_WRED_RESPONSIVE|BCM_ECN_TRAFFIC_ACTION_ENQUEUE_MARK_ELIGIBLE; 211 rv = bcm_ecn_traffic_action_config_set(unit, &config); /*For the above INT_CN value, enable both Responsive drop and ECN Marking.*/ 212 if (rv != BCM_E_NONE) { 213 printf("bcm_ecn_traffic_action_config_set:Enqueue~Resp-protocol returned '%s'\n",bcm_errmsg(rv)); 214 return rv; 215 } 216 217 bcm_ecn_traffic_action_config_t_init(&config); 218 config.action_type = BCM_ECN_TRAFFIC_ACTION_TYPE_ENQUEUE; 219 config.int_cn = nonresp_mapped_int_cn; /*Non-Responsive */ 220 config.action_flags = 0; 221 rv = bcm_ecn_traffic_action_config_set(unit, &config);/*For the above INT_CN value, enable Non-Responsive drop, but not ECN marking*/ 222 if (rv != BCM_E_NONE) { 223 printf("bcm_ecn_traffic_action_config_set:Enqueue~NonResp-protocol returned '%s'\n",bcm_errmsg(rv)); 224 return rv; 225 } 226 return BCM_E_NONE; 227 } 228 229 bcm_error_t mmu_wred_ecn_setup(int unit) 230 { 231 bcm_cosq_gport_discard_t discard_cfg; 232 233 bcm_cosq_gport_discard_t_init(&discard_cfg); 234 discard_cfg.flags = BCM_COSQ_DISCARD_ENABLE| /*WRED_EN=1 */ 235 BCM_COSQ_DISCARD_MARK_CONGESTION| /*ECN_MARKING_EN=1 */ 236 BCM_COSQ_DISCARD_BYTES| 237 BCM_COSQ_DISCARD_COLOR_GREEN| /*Modify only GREEN Drop curve Profiles-0 or 3 or 6*/ 238 BCM_COSQ_DISCARD_RESPONSIVE_DROP| /*Responsive drop profile - 0 */ 239 BCM_COSQ_DISCARD_ECT_MARKED; /*Marking profile - 6 */ 240 discard_cfg.min_thresh = 1*208; /*Queue depth in bytes to begin dropping.(208 bytes = 1 cell in TH)*/ 241 discard_cfg.max_thresh = 4*208; /*Queue depth in bytes to drop all packets(208 bytes = 1 cell in TH)*/ 242 discard_cfg.drop_probability = 90; /*Drop probability at max threshold*/ 243 rv = bcm_cosq_gport_discard_set(unit, egr_port, cos, &discard_cfg); 244 if (rv != BCM_E_NONE) { 245 printf("bcm_cosq_gport_discard_set~Resp-protocol returned '%s'\n",bcm_errmsg(rv)); 246 return rv; 247 } 248 249 bcm_cosq_gport_discard_t_init(&discard_cfg); 250 discard_cfg.flags = BCM_COSQ_DISCARD_ENABLE| /*WRED_EN=1 */ 251 BCM_COSQ_DISCARD_MARK_CONGESTION| /*ECN_MARKING_EN=1. */ 252 BCM_COSQ_DISCARD_BYTES| 253 BCM_COSQ_DISCARD_COLOR_GREEN| /*Modify only GREEN Drop curve Profiles-0 or 3 or 6*/ 254 BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP; /*Non-Responsive drop profile - 3 */ 255 discard_cfg.min_thresh = 3*208; /*Queue depth in bytes to begin dropping.(208 bytes = 1 cell)*/ 256 discard_cfg.max_thresh = 5*208; /*Queue depth in bytes to drop all packets(208 bytes = 1 cell*/ 257 discard_cfg.drop_probability = 90; /*Drop probability at max threshold*/ 258 rv = bcm_cosq_gport_discard_set(unit, egr_port, cos, &discard_cfg); 259 if (rv != BCM_E_NONE) { 260 printf("bcm_cosq_gport_discard_set~NonResp-protocol returned '%s'\n",bcm_errmsg(rv)); 261 return rv; 262 } 263 return BCM_E_NONE; 264 } 265 266 bcm_error_t bcm_egr_int_cn_update(int unit) 267 { 268 bcm_ecn_traffic_action_config_t config; 269 270 bcm_ecn_traffic_action_config_t_init(&config); 271 config.action_type = BCM_ECN_TRAFFIC_ACTION_TYPE_DEQUEUE; 272 config.int_cn = resp_mapped_int_cn; /*Responsive */ 273 config.color = bcmColorGreen; 274 config.action_flags = BCM_ECN_TRAFFIC_ACTION_DEQUEUE_CONGESTION_INT_CN_UPDATE|BCM_ECN_TRAFFIC_ACTION_DEQUEUE_NON_CONGESTION_INT_CN_UPDATE; 275 config.congested_int_cn = cong_int_cn; /*New INT_CN value if congestion is indicated by MMU */ 276 config.non_congested_int_cn = non_cong_int_cn; /*New INT_CN value if congestion is not indicated by MMU */ 277 rv = bcm_ecn_traffic_action_config_set(unit, &config); 278 if (rv != BCM_E_NONE) { 279 printf("[bcm_ecn_traffic_action_config_set:Dequeue]~Resp-protocol returned '%s'\n",bcm_errmsg(rv)); 280 return rv; 281 } 282 283 bcm_ecn_traffic_action_config_t_init(&config); 284 config.action_type = BCM_ECN_TRAFFIC_ACTION_TYPE_DEQUEUE; 285 config.int_cn = nonresp_mapped_int_cn; /*Non-Responsive. This is not actually needed as the non-responsive protocols are NOT made 'mark eligible' previously */ 286 config.color = bcmColorGreen; 287 config.action_flags = BCM_ECN_TRAFFIC_ACTION_DEQUEUE_CONGESTION_INT_CN_UPDATE|BCM_ECN_TRAFFIC_ACTION_DEQUEUE_NON_CONGESTION_INT_CN_UPDATE; 288 config.congested_int_cn = cong_int_cn; 289 config.non_congested_int_cn = non_cong_int_cn; 290 rv = bcm_ecn_traffic_action_config_set(unit, &config); 291 if (rv != BCM_E_NONE) { 292 printf("bcm_ecn_traffic_action_config_set:Dequeue~NonResp-protocol returned '%s'\n",bcm_errmsg(rv)); 293 return rv; 294 } 295 return BCM_E_NONE; 296 } 297 298 bcm_error_t bcm_mark_ecn(int unit) 299 { 300 bcm_ecn_traffic_action_config_t config; 301 uint8 new_outgoing_noncong_ecn = 2; /*ECN bits marked in outgoing packets when there is no congestion. 0b10 taken as example */ 302 uint8 new_outgoing_cong_ecn = 3; /*ECN bits marked in outgoing packets when there is congestion. 0b11 taken as example */ 303 304 bcm_ecn_traffic_action_config_t_init(&config); 305 config.action_type = BCM_ECN_TRAFFIC_ACTION_TYPE_EGRESS; 306 config.int_cn = cong_int_cn; /*INT_CN corresponding to congestion */ 307 config.ecn = iphdr_ecn; 308 config.action_flags = BCM_ECN_TRAFFIC_ACTION_EGRESS_ECN_MARKING; 309 config.new_ecn = new_outgoing_cong_ecn; /*ECN bits in outgoing packets if congestion is present*/ 310 rv = bcm_ecn_traffic_action_config_set(unit, &config); 311 if (rv != BCM_E_NONE) { 312 printf("bcm_ecn_traffic_action_config_set:Egress~Congession returned '%s'\n",bcm_errmsg(rv)); 313 return rv; 314 } 315 316 bcm_ecn_traffic_action_config_t_init(&config); 317 config.action_type = BCM_ECN_TRAFFIC_ACTION_TYPE_EGRESS; 318 config.int_cn = non_cong_int_cn; /*INT_CN corresponding to 'no congestion' */ 319 config.ecn = iphdr_ecn; 320 config.action_flags = BCM_ECN_TRAFFIC_ACTION_EGRESS_ECN_MARKING; 321 config.new_ecn = new_outgoing_noncong_ecn; /*ECN bits in outgoing packets if congestion is NOT present. (may retain original ECN bits here too for simplicity)*/ 322 rv = bcm_ecn_traffic_action_config_set(unit, &config); 323 if (rv != BCM_E_NONE) { 324 printf("bcm_ecn_traffic_action_config_set:Egress~NonCongession returned '%s'\n",bcm_errmsg(rv)); 325 return rv; 326 } 327 return BCM_E_NONE; 328 } 329 330 bcm_error_t wred_ecn_config(int unit) 331 { 332 bcm_error_t rv; 333 334 if (BCM_FAILURE((rv = data_path_setup(unit)))) { 335 printf("data_path_setup failed. : %s.\n", bcm_errmsg(rv)); 336 return rv; 337 } 338 339 if (BCM_FAILURE((rv = set_responsive_protocol_indication(unit)))) { 340 printf("set_responsive_protocol_indication() failed. : %s.\n", bcm_errmsg(rv)); 341 return rv; 342 } 343 344 if (BCM_FAILURE((rv = ip_to_int_cn_mapping(unit)))) { 345 printf("ip_to_int_cn_mapping() failed. : %s.\n", bcm_errmsg(rv)); 346 return rv; 347 } 348 349 if (BCM_FAILURE((rv = int_cn_to_mmuif_mapping(unit)))) { 350 printf("int_cn_to_mmuif_mapping() failed. : %s\n", bcm_errmsg(rv)); 351 return rv; 352 } 353 354 if (BCM_FAILURE((rv = mmu_wred_ecn_setup(unit)))) { 355 printf("wred_ecn_setup() failed. : %s\n", bcm_errmsg(rv)); 356 return rv; 357 } 358 359 if (BCM_FAILURE((rv = bcm_egr_int_cn_update(unit)))) { 360 printf("bcm_egr_int_cn_update() failed. : %s\n", bcm_errmsg(rv)); 361 return rv; 362 } 363 364 if (BCM_FAILURE((rv = bcm_mark_ecn(unit)))) { 365 printf("bcm_mark_ecn() failed. : %s\n", bcm_errmsg(rv)); 366 return rv; 367 } 368 return BCM_E_NONE; 369 } 370 371 void verify(int unit) 372 { 373 /* Test 1: ICMP pkt (responsive) - check ECN marking in packet egressing on cd1. 374 * If congestion ECN bits = 11 375 * If no congestion ECN bits = 10 376 * 377 * Test 2: IGMP packet (non responsive) 378 * If congestion - WRED drops seen in 'show c' output for egress port cd1. 379 * If no congestion - No wred drops or marking 380 */ 381 382 if(check){ 383 bshell(unit,"vlan show"); 384 bshell(unit,"l2 show"); 385 bshell(unit,"d RESPONSIVE_PROTOCOL_MATCH"); 386 bshell(unit,"d IP_TO_INT_CN_MAPPING"); 387 bshell(unit,"d INT_CN_TO_MMUIF_MAPPING"); 388 bshell(unit,"d chg MMU_WRED_QUEUE_CONFIG"); 389 bshell(unit,"d chg MMU_WRED_DROP_CURVE_PROFILE_0_0"); 390 bshell(unit,"d chg MMU_WRED_DROP_CURVE_PROFILE_0_3"); 391 bshell(unit,"d chg MMU_WRED_DROP_CURVE_PROFILE_0_5"); 392 bshell(unit,"d EGR_INT_CN_UPDATE"); 393 bshell(unit,"d EGR_INT_CN_TO_IP_MAPPING"); 394 } 395 bshell(unit, "show c"); 396 } 397 398 bcm_error_t execute() 399 { 400 bcm_error_t rv; 401 int unit =0; 402 bshell(unit, "config show; a ; version"); 403 404 if (BCM_FAILURE((rv = test_setup(unit)))) { 405 printf("test_setup() failed.\n"); 406 return -1; 407 } 408 409 if (BCM_FAILURE((rv = wred_ecn_config(unit)))) { 410 printf("wred_ecn_config() failed.\n"); 411 return -1; 412 } 413 414 verify(unit); 415 416 return BCM_E_NONE; 417 } 418 419 const char *auto_execute = (ARGC == 1) ? ARGV[0] : "YES"; 420 if (!sal_strcmp(auto_execute, "YES")) { 421 print execute(); 422 } 423