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 }