txrx.c (10719B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: txrx.c 8 * Purpose: 9 * Requires: 10 */ 11 12 #include <bcm/error.h> 13 #include <bcm/pkt.h> 14 #include <bcm/topo.h> 15 #include <shared/bsl.h> 16 #ifdef BCM_RPC_SUPPORT 17 #include <bcm_int/rpc/rlink.h> 18 #endif 19 #include <bcm_int/control.h> 20 21 #include <bcmx/tx.h> 22 #include <bcmx/rx.h> 23 24 #include <appl/diag/system.h> 25 #include <appl/diag/decode.h> 26 27 #include <appl/cputrans/ct_tun.h> 28 29 #include "bcmx.h" 30 31 static volatile int dump; 32 33 static volatile int pkt_count; 34 static volatile int rmt_count; 35 static volatile int tx_async_count; 36 37 char bcmx_cmd_rx_usage[] = 38 " [+|- dump] [source | start | stop | reg | unreg]\n" 39 " Test the bcmx rx subsystem. \n" 40 #ifndef COMPILER_STRING_CONST_LIMIT 41 " start - Make tunnel connect requests and register handler\n" 42 " stop - Make tunnel disconnect requests\n" 43 " reg - Register local BCMX handler (dump)\n" 44 " unreg - Unregister local BCMX handler (dump)\n" 45 " dump - Set/clear/toggle whether pkts are dumped\n" 46 " rlclear - Call rlink_clear function\n" 47 " txtunnel- Setup tx tunnel registration\n" 48 " notxtun - Tear down tx tunnel\n" 49 #endif 50 ; 51 52 STATIC bcm_rx_t _bcmx_rx_handler(int unit, 53 bcm_pkt_t *pkt, 54 void *cookie); 55 56 cmd_result_t 57 bcmx_cmd_rx(int unit, args_t *args) 58 { 59 int rv = CMD_OK; 60 char *ch; 61 62 if ((ch = ARG_GET(args)) == NULL) { 63 cli_out("BCMX RX is %srunning; seen %d packet%s (%d remote); " 64 "pkt dump is %s\n", 65 bcmx_rx_running() ? "" : "not ", 66 pkt_count, pkt_count == 1 ? "" : "s", 67 rmt_count, 68 dump ? "on" : "off"); 69 return CMD_OK; 70 } 71 72 while (ch) { 73 if (!strcmp("start", ch)) { 74 rv = bcmx_rx_start(); 75 pkt_count = 0; 76 cli_out("BCMX RX start returns %s\n", bcm_errmsg(rv)); 77 } else if (!strcmp("rlclear", ch)) { 78 #ifdef BCM_RPC_SUPPORT 79 bcm_rlink_clear(); 80 #else 81 cli_out("Function rlink_clear unavailable\n"); 82 return CMD_FAIL; 83 #endif /* BCM_RPC_SUPPORT */ 84 } else if (!strcmp("stop", ch)) { 85 rv = bcmx_rx_stop(); 86 cli_out("BCMX RX stop returns %s\n", bcm_errmsg(rv)); 87 } else if (!strcmp("reg", ch)) { 88 rv = bcmx_rx_register( 89 "bcmx_diag", 90 _bcmx_rx_handler, 91 100, 92 NULL, 93 BCM_RCO_F_ALL_COS); 94 cli_out("BCMX RX register returns %s\n", bcm_errmsg(rv)); 95 } else if (!strcmp("unreg", ch)) { 96 rv = bcmx_rx_unregister(_bcmx_rx_handler, 100); 97 cli_out("BCMX RX unregister returns %s\n", bcm_errmsg(rv)); 98 } else if (!strcmp("-dump", ch)) { 99 dump = FALSE; 100 } else if (!strcmp("dump", ch)) { 101 dump = !dump; 102 } else if (!strcmp("+dump", ch)) { 103 dump = TRUE; 104 } else if (!strcmp("txtunnel", ch)) { 105 #ifdef BCM_RPC_SUPPORT 106 rv = ct_tx_tunnel_setup(); 107 pkt_count = 0; 108 cli_out("BCM TX Tunnel Setup returns %s\n", bcm_errmsg(rv)); 109 #else 110 cli_out("BCM TX Tunnel Setup unavailable\n"); 111 return CMD_FAIL; 112 #endif /* BCM_RPC_SUPPORT */ 113 } else if (!strcmp("notxtun", ch)) { 114 #ifdef BCM_RPC_SUPPORT 115 rv = ct_tx_tunnel_stop(); 116 pkt_count = 0; 117 cli_out("BCM TX Tunnel Stop returns %s\n", bcm_errmsg(rv)); 118 #else 119 cli_out("BCM TX Tunnel Stop unavailable\n"); 120 return CMD_FAIL; 121 #endif /* BCM_RPC_SUPPORT */ 122 } else { 123 return CMD_USAGE; 124 } 125 ch = ARG_GET(args); 126 } 127 128 return rv < 0 ? CMD_FAIL : CMD_OK; 129 } 130 131 132 STATIC bcm_rx_t 133 _bcmx_rx_handler(int unit, bcm_pkt_t *pkt, void *cookie) 134 { 135 136 pkt_count++; 137 if (dump) { 138 cli_out("BCMX RX %d: %p from: (%d, %d), len %d.\n", unit, 139 (void *)pkt, pkt->src_mod, pkt->src_port, pkt->pkt_len); 140 #ifdef BROADCOM_DEBUG 141 bcm_pkt_dump(-1, pkt, dump); 142 #endif /* BROADCOM_DEBUG */ 143 } 144 145 if (BCM_IS_REMOTE(unit)) { 146 rmt_count++; 147 } 148 /* Don't want to interfere with other stuff that's going on */ 149 return BCM_RX_NOT_HANDLED; 150 } 151 152 #define TX_UNIT 0 153 154 STATIC void _bcmx_tx_handler(int unit, bcm_pkt_t *pkt, void *cookie) 155 { 156 COMPILER_REFERENCE(unit); 157 COMPILER_REFERENCE(pkt); 158 COMPILER_REFERENCE(cookie); 159 tx_async_count++; 160 } 161 162 char bcmx_cmd_tx_usage[] = 163 " tx <user-port-list> [<opts>]\n" 164 #ifndef COMPILER_STRING_CONST_LIMIT 165 " Options include:\n" 166 " Length=<n> Of packet in bytes\n" 167 " Count=<n> Number of packets to send\n" 168 " Delay=<n> Delay between packets (us)\n" 169 " VLantag=<n> VLAN ID to use\n" 170 " VlanPrio=<n> VLAN priority to use\n" 171 " L2Lookup=(T|F) Should L2 lookup be done\n" 172 " DestMac=<mac> Destination MAC address\n" 173 " SrcMac=<mac> Source MAC address\n" 174 " SrcMod=<n> Source module ID\n" 175 " SrcPort=<n> Source port\n" 176 " COSqueue=<n> COS queue on which to send\n" 177 " Pattern=<n> Packet data pattern\n" 178 " PatternInc=<n> Increment for packet data pattern\n" 179 " UnTagged=(T|F) All pkts to be sent untagged\n" 180 " BestEffort=(T|F) If tunnelled, use best effort\n" 181 " Reliable=(T|F) If tunnelled, use reliable transport\n" 182 " Flood=(T|F) Flood the packet\n" 183 #endif 184 " Send out a packet to the indicated user ports\n" 185 " If L2 Lookup is true, user-port-list is ignored.\n"; 186 187 cmd_result_t 188 bcmx_cmd_tx(int unit, args_t *args) 189 { 190 char *ch; 191 static int len = 68; 192 bcm_pkt_t *pkt = NULL; 193 int rv; 194 int xfer; 195 bcmx_lplist_t ports; 196 static int src_port = 0, src_mod = 0; 197 static int vlan_id = 1; 198 static int vlan_prio = 0; 199 static int l2_lookup = FALSE; 200 static int cos = 0; 201 static uint32 pattern = 0x12345678; 202 static uint32 pat_inc = 0; 203 static bcm_mac_t src_mac, dest_mac; 204 static int count = 1; 205 static int delay = 0; 206 uint16 vtag; 207 parse_table_t pt; 208 int i; 209 int untagged = FALSE; 210 int best_effort = FALSE; 211 int reliable = FALSE; 212 int flood = FALSE; 213 int async = FALSE; 214 int bcmx_flags = 0; 215 216 ch = ARG_GET(args); 217 if (ch == NULL) { 218 cli_out("BCMX TX async count=%d\n",tx_async_count); 219 return CMD_OK; 220 } 221 222 bcmx_lplist_init(&ports, 0, 0); 223 if (bcmx_lplist_parse(&ports, ch) < 0) { 224 cli_out("%s: Error: could not parse portlist: %s\n", 225 ARG_CMD(args), ch); 226 rv = CMD_FAIL; 227 goto done; 228 } 229 230 if (ports.lp_last < 0) { 231 cli_out("No ports specified.\n"); 232 rv = CMD_FAIL; 233 goto done; 234 } 235 236 parse_table_init(unit, &pt); 237 238 parse_table_add(&pt, "Length", PQ_DFL|PQ_INT, 0, 239 &len, NULL); 240 parse_table_add(&pt, "DeLay", PQ_DFL|PQ_INT, 0, 241 &delay, NULL); 242 parse_table_add(&pt, "Count", PQ_DFL|PQ_INT, 0, 243 &count, NULL); 244 parse_table_add(&pt, "VLantag", PQ_DFL|PQ_HEX, 0, 245 &vlan_id, NULL); 246 parse_table_add(&pt, "VlanPrio", PQ_DFL|PQ_INT, 0, 247 &vlan_prio, NULL); 248 parse_table_add(&pt, "L2Lookup", PQ_DFL|PQ_BOOL, 0, 249 &l2_lookup, NULL); 250 parse_table_add(&pt, "DestMac", PQ_DFL|PQ_MAC, 0, 251 &dest_mac, NULL); 252 parse_table_add(&pt, "SrcMac", PQ_DFL|PQ_MAC, 0, 253 &src_mac, NULL); 254 parse_table_add(&pt, "SrcMod", PQ_DFL|PQ_INT, 0, 255 &src_mod, NULL); 256 parse_table_add(&pt, "SrcPort", PQ_DFL|PQ_INT, 0, 257 &src_port, NULL); 258 parse_table_add(&pt, "COSqueue", PQ_DFL|PQ_INT, 0, 259 &cos, NULL); 260 parse_table_add(&pt, "Pattern", PQ_DFL|PQ_HEX, 0, 261 &pattern, NULL); 262 parse_table_add(&pt, "PatternInc", PQ_DFL|PQ_INT, 0, 263 &pat_inc, NULL); 264 parse_table_add(&pt, "UnTagged", PQ_DFL|PQ_BOOL, 0, 265 &untagged, NULL); 266 parse_table_add(&pt, "BestEffort", PQ_DFL|PQ_BOOL, 0, 267 &best_effort, NULL); 268 parse_table_add(&pt, "Reliable", PQ_DFL|PQ_BOOL, 0, 269 &reliable, NULL); 270 parse_table_add(&pt, "Flood", PQ_DFL|PQ_BOOL, 0, 271 &flood, NULL); 272 parse_table_add(&pt, "Async", PQ_DFL|PQ_BOOL, 0, 273 &async, NULL); 274 275 /* Parse remaining arguments */ 276 if (0 > parse_arg_eq(args, &pt)) { 277 cli_out("%s: Error: Invalid option or malformed expression: %s\n", 278 ARG_CMD(args), ARG_CUR(args)); 279 parse_arg_eq_done(&pt); 280 rv = CMD_FAIL; 281 goto done; 282 } 283 parse_arg_eq_done(&pt); 284 285 if (BCM_FAILURE(bcm_pkt_alloc(TX_UNIT, len, BCM_TX_CRC_APPEND, &pkt))) { 286 rv = CMD_FAIL; 287 goto done; 288 } 289 290 for (i = 0; i < len/4; i++) { 291 sal_memcpy(&pkt->_pkt_data.data[i * 4], &pattern, 4); 292 pattern += pat_inc; 293 } 294 sal_memcpy(pkt->_pkt_data.data, dest_mac, sizeof(bcm_mac_t)); 295 sal_memcpy(&pkt->_pkt_data.data[6], src_mac, sizeof(bcm_mac_t)); 296 297 vtag = (vlan_prio << 13) | vlan_id; 298 pkt->_pkt_data.data[12] = 0x81; /* vlan 1 */ 299 pkt->_pkt_data.data[13] = 0; 300 pkt->_pkt_data.data[14] = vtag >> 8; 301 pkt->_pkt_data.data[15] = vtag & 0xff; 302 303 /* Packet flags indicate tunnel mode */ 304 if (best_effort) { 305 pkt->flags |= BCM_TX_BEST_EFFORT; 306 bcmx_flags |= BCMX_TX_F_CPU_TUNNEL; 307 } 308 if (reliable) { 309 pkt->flags |= BCM_TX_RELIABLE; 310 bcmx_flags |= BCMX_TX_F_CPU_TUNNEL; 311 } 312 313 if (async) { 314 pkt->call_back = _bcmx_tx_handler; 315 } 316 317 for ( xfer = 0; xfer < count; xfer++ ) { 318 if (l2_lookup) { /* Don't need to look for dest port */ 319 rv = bcmx_tx(pkt, BCMX_TX_F_L2_LOOKUP|bcmx_flags); 320 } else if (flood) { 321 rv = bcmx_tx_flood(pkt, bcmx_flags); 322 } else if (BCMX_LPLIST_COUNT(&ports) == 1 323 && !untagged) { /* Single port (tagged) transmit */ 324 rv = bcmx_tx_uc(pkt, bcmx_lplist_first(&ports), bcmx_flags); 325 } else { 326 if (untagged) { 327 rv = bcmx_tx_lplist(pkt, NULL, &ports, bcmx_flags); 328 } else { 329 rv = bcmx_tx_lplist(pkt, &ports, NULL, bcmx_flags); 330 } 331 } 332 if (rv < 0) { 333 cli_out("BCMX TX ERROR: return value is %d (%s)\n", 334 rv, bcm_errmsg(rv)); 335 break; 336 } 337 sal_usleep(delay); 338 } 339 340 done: 341 if (pkt != NULL) { 342 bcm_pkt_free(TX_UNIT, pkt); 343 } 344 bcmx_lplist_free(&ports); 345 346 return CMD_OK; 347 }