openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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