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

bcm_rx.c (14980B)


      1 /*  Feature  : BCM RX
      2  *                   
      3  *  Usage    : BCM.0> cint bcm_rx.c
      4  *                                 
      5  *  config   : bcm_rx_config.bcm   
      6  *                                 
      7  *  Log file : bcm_rx_log.txt      
      8  *                                 
      9  *  Test Topology :                
     10  *                                 
     11  *                   +------------------------------+
     12  *                   |                              |
     13  *                   |                              |
     14  *                   |                              |
     15  *  ingress_port     |                              |  cpu_port
     16  *  +----------------+          SWITCH              +-----------------+
     17  *                   |                              |                  
     18  *                   |                              |                  
     19  *                   |                              |                  
     20  *                   |                              |                  
     21  *                   |                              |                  
     22  *                   +------------------------------+                  
     23  *
     24  *
     25  *  Summary:
     26  *  ========
     27  *    This CINT script registers RX callback using BCM APIs.
     28  *    This exampls hsows how application can register RX callback function
     29  *    and process the packets received by CPU port.
     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 port and configure it in loopback mode.
     36  *      b) Add static L2 entry on cpu port with mac=00:00:00:00:00:03 and vlan=1
     37  *
     38  *    2) Step2 - Configuration (Done in rx_setup())
     39  *    ===================================================
     40  *      a) Check if RX is active, if not then Init RX and start RX thread
     41  *      b) Register RX callback function which will print the received packet along
     42  *         with the metadata of the packet.
     43  *
     44  *    3) Step3 - Verification (Done in verify())
     45  *    ==========================================
     46  *      a) Transmit multiple packets with different vlan_prio and mac=00:00:00:00:00:03
     47  *      b) Expected Result:
     48  *         ================
     49  *         The packets are looped back on ingress port and received by CPU port
     50  *         The RX callback registered in step#4 will dump the packet along with metadata
     51  *         on console
     52  */
     53 
     54 
     55 cint_reset();
     56 bcm_port_t ingress_port;
     57 
     58 /*
     59  * packet_info()
     60  *
     61  * This routine prints of some key bits of information from a bcm_pkt_t structure.
     62  */
     63 void
     64 packet_info(bcm_pkt_t * pkt)
     65 {
     66     /*
     67      * Define a mapping from reason code to its corresponding text string. All
     68      * reasons may not be used by some devices.
     69      */
     70     const char *reason_strings[] = {
     71         "Invalid", "Arp", "Bpdu", "Broadcast", "ClassBasedMove",
     72         "ClassTagPackets", "Control", "CpuLearn", "DestLookupFail",
     73         "Dhcp", "DosAttack", "E2eHolIbp", "EncapHigigError", "FilterMatch",
     74         "GreChecksum", "GreSourceRoute", "HigigControl", "HigigHdrError",
     75         "IcmpRedirect", "Igmp", "IngressFilter", "Ip", "IpfixRateViolation",
     76         "IpMcastMiss", "IpmcReserved", "IpOptionVersion", "Ipmc",
     77         "L2Cpu", "L2DestMiss", "L2LearnLimit", "L2Move", "L2MtuFail",
     78         "L2NonUnicastMiss", "L2SourceMiss", "L3AddrBindFail",
     79         "L3DestMiss", "L3HeaderError", "L3MtuFail", "L3Slowpath",
     80         "L3SourceMiss", "L3SourceMove", "MartianAddr", "McastIdxError",
     81         "McastMiss", "MimServiceError", "MplsCtrlWordError", "MplsError",
     82         "MplsInvalidAction", "MplsInvalidPayload", "MplsLabelMiss",
     83         "MplsSequenceNumber", "MplsTtl", "Multicast", "Nhop", "OAMError",
     84         "OAMSlowpath", "OAMLMDM", "ParityError", "Protocol", "SampleDest",
     85         "SampleSource", "SharedVlanMismatch", "SourceRoute", "TimeStamp",
     86         "Ttl", "Ttl1", "TunnelError", "UdpChecksum", "UnknownVlan",
     87         "UrpfFail", "VcLabelMiss", "VlanFilterMatch", "WlanClientError",
     88         "WlanSlowpath", "WlanDot1xDrop", "ExceptionFlood", "TimeSync",
     89         "EAVData", "SamePortBridge", "SplitHorizon", "L4Error", "Stp",
     90         "EgressFilterRedirect", "FilterRedirect", "Loopback", "VlanTranslate",
     91         "Mmrp", "Srp", "TunnelControl", "L2Marked", "WlanSlowpathKeepalive",
     92         "Station", "Niv", "NivPrioDrop", "NivInterfaceMiss", "NivRpfFail",
     93         "NivTagInvalid", "NivTagDrop", "NivUntagDrop", "Trill", "TrillInvalid",
     94         "TrillMiss", "TrillRpfFail", "TrillSlowpath", "TrillCoreIsIs",
     95         "TrillTtl", "TrillName", "BfdSlowpath", "Bfd", "Mirror",
     96         "RegexAction", "RegexMatch", "FailoverDrop", "WlanTunnelError",
     97         "CongestionCnmProxy", "CongestionCnmProxyError", "CongestionCnm",
     98         "MplsUnknownAch", "MplsLookupsExceeded", "MplsReservedEntropyLabel",
     99         "MplsIllegalReservedLabel", "MplsRouterAlertLabel", "NivPrune",
    100         "VirtualPortPrune", "NonUnicastDrop", "TrillPacketPortMismatch",
    101         "WlanClientMove", "WlanSourcePortMiss", "WlanClientSourceMiss",
    102         "WlanClientDestMiss", "WlanMtu", "L2GreSipMiss", "L2GreVpnIdMiss",
    103         "TimesyncUnknownVersion", "BfdUnknownVersion", "BfdInvalidVersion",
    104         "BfdLookupFailure", "BfdInvalidPacket", "VxlanSipMiss",
    105         "VxlanVpnIdMiss", "FcoeZoneCheckFail", "IpmcInterfaceMismatch",
    106         "Nat", "TcpUdpNatMiss", "IcmpNatMiss", "NatFragment", "NatMiss",
    107         "OAMCCMSlowpath", "BHHOAM", "UnknownSubtendingPort", "Reserved0",
    108         "OAMMplsLmDm", "Sat", "SampleSourceFlex"
    109     };
    110     bcm_rx_reason_t reason;
    111     int         i;
    112     int         reason_count;
    113 
    114     /* Print basic packet information first */
    115     printf
    116       ("  length %4d; rx-port %2d; COS %2d; prio_int %2d; VLAN %4d; DMA chan: %d; %s;\n",
    117        pkt->pkt_len, pkt->rx_port, pkt->cos, pkt->prio_int, pkt->vlan,
    118        pkt->dma_channel, (pkt->rx_untagged & BCM_PKT_OUTER_UNTAGGED)
    119        ? ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED)
    120           ? "Untagged" : "Inner tagged")
    121        : ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ? "Outer tagged" :
    122           "Double tagged"));
    123 
    124     /* Print additional packet information */
    125     if ((pkt->flags & BCM_PKT_STK_F_SRC_PORT) && (pkt->flags & BCM_PKT_STK_F_DST_PORT)) {
    126         /* Both destination and source GPORTs available */
    127         printf
    128           ("  dest-gport %d; src-gport %d; opcode %d;%s matched %d; classification-tag %d;\n",
    129            pkt->dst_gport, pkt->src_gport, pkt->opcode,
    130            (pkt->flags & BCM_RX_TRUNCATED) ? " Truncated;" : "", pkt->rx_matched,
    131            pkt->rx_classification_tag);
    132     } else if ((pkt->flags & BCM_PKT_STK_F_SRC_PORT)) {
    133         /* Source GPORT available */
    134         printf
    135           ("  dest-port %d; dest-mod %d; src-gport %d; opcode %d;%s matched %d; classification-tag %d;\n",
    136            pkt->dest_port, pkt->dest_mod, pkt->src_gport, pkt->opcode,
    137            (pkt->flags & BCM_RX_TRUNCATED) ? " Truncated;" : "", pkt->rx_matched,
    138            pkt->rx_classification_tag);
    139     } else if ((pkt->flags & BCM_PKT_STK_F_DST_PORT)) {
    140         /* Destination GPORT available */
    141         printf
    142           ("  dest-gport %d; %s %d; src-mod %d; opcode %d;%s matched %d; classification-tag %d;\n",
    143            pkt->dst_gport, (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port",
    144            (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port,
    145            pkt->src_mod, pkt->opcode,
    146            (pkt->flags & BCM_RX_TRUNCATED) ? " Truncated;" : "", pkt->rx_matched,
    147            pkt->rx_classification_tag);
    148     } else {
    149         /* No GPORTs */
    150         printf
    151           ("  dest-port %d; dest-mod %d;%s %d; src-mod %d; opcode %d;%s matched %d; classification-tag %d;\n",
    152            pkt->dest_port, pkt->dest_mod,
    153            (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port",
    154            (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port,
    155            pkt->src_mod, pkt->opcode,
    156            (pkt->flags & BCM_RX_TRUNCATED) ? " Truncated;" : "", pkt->rx_matched,
    157            pkt->rx_classification_tag);
    158     }
    159 
    160     /*
    161      * Print out reasons (if any) by iterating through the entire reasons
    162      * mask and printing the reason string associated with each reason.
    163      */
    164     reason_count = 0;
    165     BCM_RX_REASON_ITER(pkt->rx_reasons, reason) {
    166         reason_count++;
    167         printf(" %s", reason_strings[reason]);
    168     }
    169     if (reason_count) {
    170         printf("\nPacket sent for %d reason(s)\n", reason_count);
    171     } else {
    172         /* Assume that if there were no reasons, must be switched */
    173         printf("Packet switched to CPU\n");
    174     }
    175 }
    176 
    177 /* A little routine to print a MAC address */
    178 void
    179 mac_print(unsigned char *macAddr)
    180 {
    181 
    182     printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
    183            (macAddr[0] & 0xFF), (macAddr[1] & 0xFF), (macAddr[2] & 0xFF),
    184            (macAddr[3] & 0xFF), (macAddr[4] & 0xFF), (macAddr[5] & 0xFF));
    185 }
    186 
    187 /* Receive Task Callback
    188  *
    189  * This is called for every packet received. It prints the packet metadata
    190  * along with the entire packet.
    191  *
    192  * Param "cookie" is a pointer to current received packet count.
    193  */
    194 bcm_rx_t
    195 packetWatcher(int unit, bcm_pkt_t * pkt, void *cookie)
    196 {
    197     int        BCM_RX_HANDLED=2;
    198     int        *packet_count = (auto) cookie;
    199     int         i;
    200 
    201     /* Increment packet count */
    202     (*packet_count)++;
    203 
    204     printf("Received Packet: %2d\n", *packet_count);
    205 
    206     for (i = 0; i < pkt->tot_len; i++) {
    207         uint32      print_byte = pkt->pkt_data->data[i] & 0xFF;
    208 
    209         if ((i & 0xf) == 0) {
    210             printf("\n%03X:", i);
    211         }
    212         printf(" %02X", print_byte);
    213     }
    214     if (((i & 0xf) != 1)) {
    215         printf("\n");
    216     }
    217 
    218     printf("  DM=");
    219     mac_print(&pkt->pkt_data->data[0]);
    220     printf("  SM=");
    221     mac_print(&pkt->pkt_data->data[6]);
    222 
    223     /* print packet metadata */
    224     packet_info(pkt);
    225 
    226     printf("\n");
    227 
    228     return BCM_RX_HANDLED;
    229 }
    230 
    231 /* 
    232  * rx_setup()
    233  *
    234  * Start Rx task (if necessary) and install a single Rx callback routine.
    235  */
    236 int         rx_count;   /* Global received packet count */
    237 int
    238 rx_setup(int unit)
    239 {
    240     int         rv;
    241 
    242     /*
    243      * Use a priority above 100 to be able to co-exist with diagnostic
    244      * shell packetWatcher.
    245      */
    246     const int   priority = 101;
    247 
    248     /* Receive packets from all CPU queues. */
    249     const int   flags = BCM_RCO_F_ALL_COS;
    250 
    251     if (!bcm_rx_active(unit)) {
    252         /*
    253          * If necessary, initialize and start the receive task. 
    254          */
    255         rv = bcm_rx_init(unit);
    256         if(BCM_FAILURE(rv)) {
    257             printf("\nError in bcm_rx_init(): %s.\n",bcm_errmsg(rv));
    258             return rv;
    259         }
    260         
    261         rv = bcm_rx_start(unit, NULL);
    262         if(BCM_FAILURE(rv)) {
    263             printf("\nError in bcm_rx_start(): %s.\n",bcm_errmsg(rv));
    264             return rv;
    265         }
    266         printf("Started the Rx task\n");
    267     }
    268 
    269     /*
    270      * Register Packet Watcher Rx Callback. 
    271      */
    272     rv = bcm_rx_register(unit, "Rx PacketWatch", packetWatcher, \
    273                          priority, &rx_count,flags);
    274     if(BCM_FAILURE(rv)) {
    275         printf("\nError in bcm_rx_init(): %s.\n",bcm_errmsg(rv));
    276         return rv;
    277     }
    278     printf("Registered CINT Packet Watcher callback\n");
    279 
    280     return BCM_E_NONE;
    281 }
    282 
    283 /*
    284  * Configures the port in loopback mode and 
    285  * add L2 entry with mac-03 for CPU port.
    286  */
    287 bcm_error_t ingress_port_setup(int unit, bcm_port_t port)
    288 {
    289     const char *mac = "00:00:00:00:00:03";
    290     const int   max_vlan_pri = 8;
    291 
    292     char        command[128];   /* Buffer for diagnostic shell commands */
    293     int         vlan_pri;
    294 
    295     /* Put test port into loopback mode */
    296     BCM_IF_ERROR_RETURN(bcm_port_loopback_set(unit, port, BCM_PORT_LOOPBACK_PHY));
    297     
    298     /* Configure "tx" utility to send IEEE packets (not HiGig) */
    299     bshell(unit, "hm ieee");
    300 
    301     /* Set up L2 map to direct packets to CPU */
    302     sprintf(command, "l2 add PortBitMap=cpu0 vlan=1 mac=%s rp=0 st=1", mac);
    303     bshell(unit, command);
    304     return BCM_E_NONE;
    305 }
    306 
    307 /* This function is written so that hardcoding of port
    308    numbers in Cint scripts is removed. This function gives
    309    required number of ports
    310 */
    311 bcm_error_t portNumbersGet(int unit, int *port_list, int num_ports)
    312 {
    313 
    314     int i=0,port=0,rv=0;
    315     bcm_port_config_t configP;
    316     bcm_pbmp_t ports_pbmp;
    317 
    318     rv = bcm_port_config_get(unit,&configP);
    319     if(BCM_FAILURE(rv)) {
    320       printf("\nError in retrieving port configuration: %s.\n",bcm_errmsg(rv));
    321       return rv;
    322     }
    323 
    324     ports_pbmp = configP.e;
    325     for (i= 1; i < BCM_PBMP_PORT_MAX; i++) {
    326       if (BCM_PBMP_MEMBER(&ports_pbmp,i)&& (port < num_ports)) {
    327         port_list[port]=i;
    328         port++;
    329       }
    330     }
    331 
    332     if (( port == 0 ) || ( port != num_ports )) {
    333         printf("portNumbersGet() failed \n");
    334         return -1;
    335     }
    336 
    337     return BCM_E_NONE;
    338 
    339 }
    340 
    341 /*
    342  * This functions gets the port numbers and sets up ingress and
    343  * egress ports. Check ingress_port_setup() and egress_port_setup().
    344  */
    345 bcm_error_t test_setup(int unit)
    346 {
    347   int port_list[2], i;
    348 
    349   if (BCM_E_NONE != portNumbersGet(unit, port_list, 2)) {
    350     printf("portNumbersGet() failed\n");
    351     return -1;
    352   }
    353 
    354   ingress_port = port_list[0];
    355   if (BCM_E_NONE != ingress_port_setup(unit, ingress_port)) {
    356     printf("ingress_port_setup() failed for port %d\n", ingress_port);
    357     return -1;
    358   }
    359   return BCM_E_NONE;
    360 }
    361 
    362 /*
    363  * Test Harness
    364  *
    365  * Demonstrate use of Rx callbacks.
    366  *
    367  * Verify behavior by sending packets through the switch and back through
    368  * the CPU to the Rx callback routine.
    369  */
    370 bcm_error_t
    371 test_harness(int unit)
    372 {
    373     int         len;
    374     const char *mac = "00:00:00:00:00:03";
    375     const int   max_vlan_pri = 8;
    376     char        command[128];   /* Buffer for diagnostic shell commands */
    377     int         vlan_pri;
    378  
    379     /* Send packets, loop them back through CPU port */
    380     for (len = 100; len <= 120; len += 10) {
    381         for (vlan_pri = 0; vlan_pri < max_vlan_pri; vlan_pri += 2) {
    382             printf
    383               ("----------------------------------------------------------------\n");
    384             sprintf(command,
    385                     "tx 1 PortBitMap=%d Length=%d DestMac=%s VlanPrio=%d VLantag=1 
    386                      PatternRandom=yes",
    387                      ingress_port, len, mac, vlan_pri);
    388             bshell(unit, command);
    389             sal_sleep(1);       /* Pause long enough to print packet data */
    390         }
    391     }
    392     return BCM_E_NONE;
    393 }
    394 
    395 void verify(int unit)
    396 {
    397     bcm_error_t rv;
    398     if (BCM_FAILURE(rv = test_harness(0))) {
    399         printf("Rx verification failed: %s\n", bcm_errmsg(rv));
    400     }
    401 }
    402 
    403 bcm_error_t execute()
    404 {
    405     bcm_error_t rv;
    406     int unit =0;
    407     bshell(unit, "config show; a ; version");
    408     if (BCM_FAILURE((rv = test_setup(unit)))) {
    409         printf("test_setup() failed.\n");
    410         return -1;
    411     }
    412 
    413     if (BCM_FAILURE((rv = rx_setup(unit)))) {
    414         printf("RX Setup Failed\n");
    415         return -1;
    416     }
    417 
    418     verify(unit);
    419     return BCM_E_NONE;
    420 }
    421 
    422 const char *auto_execute = (ARGC == 1) ? ARGV[0] : "YES";
    423 if (!sal_strcmp(auto_execute, "YES")) {
    424   print execute();
    425 }