/*****************************************************************//** * \brief Include all ports to default vlan * * \param unit [IN] unit number * * \return OPENNSL_E_XXX OpenNSL API return code ********************************************************************/ int switch_default_vlan_config(int unit) { opennsl_port_config_t pcfg; opennsl_pbmp_t upbm; int rv; OPENNSL_PBMP_CLEAR(upbm); /* * Create VLAN with id DEFAULT_VLAN and * add ethernet ports to the VLAN */ rv = opennsl_port_config_get(unit, &pcfg); if (rv != OPENNSL_E_NONE) { printf("Failed to get port configuration. Error %s\n", opennsl_errmsg(rv)); return rv; } rv = opennsl_vlan_port_add(unit, DEFAULT_VLAN, pcfg.e, upbm); if (rv != OPENNSL_E_NONE) { printf("Failed to add ports to VLAN. Error %s\n", opennsl_errmsg(rv)); return rv; } return 0; }
/*****************************************************************//** * \brief Form a packet and send multiple packets from the specified port * * \param unit [IN] Unit number. * \param port [IN] Port number. * \param count [IN] Number of packets to be transmitted. * * \return OPENNSL_E_XXX OpenNSL API return code ********************************************************************/ void example_multi_pkt_send(int unit, int port, int count) { int i; int rv; char data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x2f, 0x2e, 0x42, 0x46, 0x74, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x82, 0x2f, 0x2e, 0x42, 0x46, 0x74, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 }; for (i = 0; i < count; i++) { rv = example_pkt_send(unit, port, data, (int) sizeof(data)); if (!OPENNSL_SUCCESS(rv)) { printf("Error Sending Packet: %d. Error: %s\n", i + 1, opennsl_errmsg(rv)); } else { printf("Transmitted Packet %d of size %zu\n", i + 1, sizeof(data)); } } }
BcmUnit::~BcmUnit() { if (attached_.load(std::memory_order_acquire)) { auto rv = opennsl_detach(unit_); CHECK(OPENNSL_SUCCESS(rv)) << "failed to detach BCM unit " << unit_ << ": " << opennsl_errmsg(rv); } // Unregister ourselves from BcmAPI. BcmAPI::unitDestroyed(this); }
void BcmPort::updateStat(std::chrono::seconds now, stats::MonotonicCounter* stat, opennsl_stat_val_t type) { // Use the non-sync API to just get the values accumulated in software. // The Broadom SDK's counter thread syncs the HW counters to software every // 500000us (defined in config.bcm). uint64_t value; auto ret = opennsl_stat_get(unit_, port_, type, &value); if (OPENNSL_FAILURE(ret)) { LOG(ERROR) << "Failed to get stat " << type << " for port " << port_ << " :" << opennsl_errmsg(ret); return; } stat->updateValue(now, value); }
bool BcmRoute::deleteLpmRoute(int unitNumber, opennsl_vrf_t vrf, const folly::IPAddress& prefix, uint8_t prefixLength) { opennsl_l3_route_t rt; initL3RouteFromArgs(&rt, vrf, prefix, prefixLength); auto rc = opennsl_l3_route_delete(unitNumber, &rt); if (OPENNSL_FAILURE(rc)) { LOG(ERROR) << "Failed to delete a route entry for " << prefix << "/" << static_cast<int>(prefixLength) << " Error: " << opennsl_errmsg(rc); return false; } else { VLOG(3) << "deleted a route entry for " << prefix.str() << "/" << static_cast<int>(prefixLength); } return true; }
void BcmPort::updateStats() { // TODO: It would be nicer to use a monotonic clock, but unfortunately // the ServiceData code currently expects everyone to use system time. auto now = duration_cast<seconds>(system_clock::now().time_since_epoch()); updateStat(now, &inBytes_, opennsl_spl_snmpIfHCInOctets); updateStat(now, &inUnicastPkts_, opennsl_spl_snmpIfHCInUcastPkts); updateStat(now, &inMulticastPkts_, opennsl_spl_snmpIfHCInMulticastPkts); updateStat(now, &inBroadcastPkts_, opennsl_spl_snmpIfHCInBroadcastPkts); updateStat(now, &inDiscards_, opennsl_spl_snmpIfInDiscards); updateStat(now, &inErrors_, opennsl_spl_snmpIfInErrors); updateStat(now, &outBytes_, opennsl_spl_snmpIfHCOutOctets); updateStat(now, &outUnicastPkts_, opennsl_spl_snmpIfHCOutUcastPkts); updateStat(now, &outMulticastPkts_, opennsl_spl_snmpIfHCOutMulticastPkts); updateStat(now, &outBroadcastPkts_, opennsl_spl_snmpIfHCOutBroadcastPckts); updateStat(now, &outDiscards_, opennsl_spl_snmpIfOutDiscards); updateStat(now, &outErrors_, opennsl_spl_snmpIfOutErrors); setAdditionalStats(now); // Update the queue length stat uint32_t qlength; auto ret = opennsl_port_queued_count_get(unit_, port_, &qlength); if (OPENNSL_FAILURE(ret)) { LOG(ERROR) << "Failed to get queue length for port " << port_ << " :" << opennsl_errmsg(ret); } else { SpinLockHolder guard(outQueueLen_.first.get()); outQueueLen_.second->addValue(now, qlength); // TODO: outQueueLen_ only exports the average queue length over the last // 60 seconds, 10 minutes, etc. // We should also export the current value. We could use a simple counter // or a dynamic counter for this. } // Update the packet length histograms updatePktLenHist(now, &inPktLengths_, kInPktLengthStats); updatePktLenHist(now, &outPktLengths_, kOutPktLengthStats); };
void BcmPort::updatePktLenHist( std::chrono::seconds now, stats::ExportedHistogramMapImpl::LockableHistogram* hist, const std::vector<opennsl_stat_val_t>& stats) { // Get the counter values uint64_t counters[10]; // opennsl_stat_multi_get() unfortunately doesn't correctly const qualify // it's stats arguments right now. opennsl_stat_val_t* statsArg = const_cast<opennsl_stat_val_t*>(&stats.front()); auto ret = opennsl_stat_multi_get(unit_, port_, stats.size(), statsArg, counters); if (OPENNSL_FAILURE(ret)) { LOG(ERROR) << "Failed to get packet length stats for port " << port_ << " :" << opennsl_errmsg(ret); return; } // Update the histogram auto guard = hist->makeLockGuard(); for (int idx = 0; idx < stats.size(); ++idx) { hist->addValueLocked(guard, now.count(), idx, counters[idx]); } }
void BcmPort::updateStats() { // TODO: It would be nicer to use a monotonic clock, but unfortunately // the ServiceData code currently expects everyone to use system time. if (!shouldReportStats()) { return; } auto now = duration_cast<seconds>(system_clock::now().time_since_epoch()); HwPortStats curPortStats; updateStat( now, kInBytes, opennsl_spl_snmpIfHCInOctets, &curPortStats.inBytes_); updateStat( now, kInUnicastPkts, opennsl_spl_snmpIfHCInUcastPkts, &curPortStats.inUnicastPkts_); updateStat( now, kInMulticastPkts, opennsl_spl_snmpIfHCInMulticastPkts, &curPortStats.inMulticastPkts_); updateStat( now, kInBroadcastPkts, opennsl_spl_snmpIfHCInBroadcastPkts, &curPortStats.inBroadcastPkts_); updateStat( now, kInDiscards, opennsl_spl_snmpIfInDiscards, &curPortStats.inDiscards_); updateStat( now, kInErrors, opennsl_spl_snmpIfInErrors, &curPortStats.inErrors_); updateStat( now, kInIpv4HdrErrors, opennsl_spl_snmpIpInHdrErrors, &curPortStats.inIpv4HdrErrors_); updateStat( now, kInIpv6HdrErrors, opennsl_spl_snmpIpv6IfStatsInHdrErrors, &curPortStats.inIpv6HdrErrors_); updateStat( now, kInPause, opennsl_spl_snmpDot3InPauseFrames, &curPortStats.inPause_); // Egress Stats updateStat( now, kOutBytes, opennsl_spl_snmpIfHCOutOctets, &curPortStats.outBytes_); updateStat( now, kOutUnicastPkts, opennsl_spl_snmpIfHCOutUcastPkts, &curPortStats.outUnicastPkts_); updateStat( now, kOutMulticastPkts, opennsl_spl_snmpIfHCOutMulticastPkts, &curPortStats.outMulticastPkts_); updateStat( now, kOutBroadcastPkts, opennsl_spl_snmpIfHCOutBroadcastPckts, &curPortStats.outBroadcastPkts_); updateStat( now, kOutDiscards, opennsl_spl_snmpIfOutDiscards, &curPortStats.outDiscards_); updateStat( now, kOutErrors, opennsl_spl_snmpIfOutErrors, &curPortStats.outErrors_); updateStat( now, kOutPause, opennsl_spl_snmpDot3OutPauseFrames, &curPortStats.outPause_); setAdditionalStats(now, &curPortStats); // Compute non pause discards const auto kUninit = hardware_stats_constants::STAT_UNINITIALIZED(); if (isMmuLossy() && portStats_.inDiscards_ != kUninit && portStats_.inPause_ != kUninit) { // If MMU setup as lossy, all incoming pause frames will be // discarded and will count towards in discards. This makes in discards // counter somewhat useless. So instead calculate "in_non_pause_discards", // as std::max(0, (inDiscardsSincePrev - inPauseSincePrev)). // std::max(..) is used, since stats from h/w are synced non atomically, // So depending on what get synced later # of pause maybe be slightly // higher than # of discards. auto inPauseSincePrev = curPortStats.inPause_ - portStats_.inPause_; auto inDiscardsSincePrev = curPortStats.inDiscards_ - portStats_.inDiscards_; if (inPauseSincePrev >= 0 && inDiscardsSincePrev >=0) { // Account for counter rollover. auto inNonPauseDiscardsSincePrev = std::max(0L, (inDiscardsSincePrev - inPauseSincePrev)); // Init current port stats from prev value or 0 curPortStats.inNonPauseDiscards_ = (portStats_.inNonPauseDiscards_ == kUninit ? 0 : portStats_.inNonPauseDiscards_); // Counters are cumalative curPortStats.inNonPauseDiscards_ += inNonPauseDiscardsSincePrev; auto inNonPauseDiscards = getPortCounterIf(kInNonPauseDiscards); inNonPauseDiscards->updateValue(now, curPortStats.inNonPauseDiscards_); } } portStats_ = curPortStats; // Update the queue length stat uint32_t qlength; auto ret = opennsl_port_queued_count_get(unit_, port_, &qlength); if (OPENNSL_FAILURE(ret)) { LOG(ERROR) << "Failed to get queue length for port " << port_ << " :" << opennsl_errmsg(ret); } else { outQueueLen_.addValue(now.count(), qlength); // TODO: outQueueLen_ only exports the average queue length over the last // 60 seconds, 10 minutes, etc. // We should also export the current value. We could use a simple counter // or a dynamic counter for this. } // Update the packet length histograms updatePktLenHist(now, &inPktLengths_, kInPktLengthStats); updatePktLenHist(now, &outPktLengths_, kOutPktLengthStats); };
/*****************************************************************//** * \brief Main function for packet transmission * * \param argc, argv commands line arguments * * \return OPENNSL_E_XXX OpenNSL API return code ********************************************************************/ int main(int argc, char *argv[]) { opennsl_error_t rv; int count; opennsl_port_t port; int unit = DEFAULT_UNIT; int choice; int index = 0; if(strcmp(argv[0], "gdb") == 0) { index = 1; } if((argc != (index + 1)) || ((argc > (index + 1)) && (strcmp(argv[index + 1], "--help") == 0))) { printf("%s\n\r", example_usage); return OPENNSL_E_PARAM; } /* Initialize the system. */ printf("Initializing the system.\r\n"); rv = opennsl_driver_init((opennsl_init_t *) NULL); if(rv != OPENNSL_E_NONE) { printf("\r\nFailed to initialize the system. Error %s\r\n", opennsl_errmsg(rv)); return rv; } /* Add ports to default vlan. */ printf("Adding ports to default vlan.\r\n"); rv = example_switch_default_vlan_config(unit); if(rv != OPENNSL_E_NONE) { printf("\r\nFailed to add default ports. rv: %s\r\n", opennsl_errmsg(rv)); return rv; } while (1) { printf("\r\nUser menu: Select one of the following options\r\n"); printf("1. Transmit a packet\n"); printf("2. Display OpenNSL version\n"); printf("9. Launch diagnostic shell\n"); printf("0. Quit the application\n"); if(example_read_user_choice(&choice) != OPENNSL_E_NONE) { printf("Invalid option entered. Please re-enter.\n"); continue; } switch(choice){ case 1: { printf("\r\nEnter the port on which packet needs to be transmitted.\r\n"); if(example_read_user_choice(&port) != OPENNSL_E_NONE) { printf("Invalid option entered. Please re-enter.\n"); continue; } printf("\r\nEnter number of packets to be sent.\r\n"); if(example_read_user_choice(&count) != OPENNSL_E_NONE) { printf("Invalid option entered. Please re-enter.\n"); continue; } /* Transmit packet(s) on the specified port */ example_multi_pkt_send(unit, port, count); break; } /* End of case 1 */ case 2: { printf("OpenNSL version: %s\n", opennsl_version_get()); break; } case 9: { opennsl_driver_shell(); break; } case 0: { printf("Exiting the application.\n"); return OPENNSL_E_NONE; } default: break; } /* End of switch */ } /* End of while */ return OPENNSL_E_NONE; }
/**************************************************************************//** * \brief To add a given set of ports and VLAN to spanning tree instance. * * \param unit [IN] Unit number. * \param *info [IN] Pointer to a location where STG information * is stored * * \return OPENNSL_E_xxx OpenNSL API return code *****************************************************************************/ int example_stg_create(int unit, stg_info_s *info) { int rv; opennsl_pbmp_t pbmp; /* create VLAN */ rv = opennsl_vlan_create(DEFAULT_UNIT, info->vlan_1); if (rv != OPENNSL_E_NONE) { printf("Error, in opennsl_vlan_create, vid=%d, \n", info->vlan_1); return rv; } if(verbose >= 2) { printf("VLAN %d is created.\n", info->vlan_1); } OPENNSL_PBMP_CLEAR(pbmp); OPENNSL_PBMP_PORT_ADD(pbmp, info->port_1); OPENNSL_PBMP_PORT_ADD(pbmp, info->port_2); rv = opennsl_vlan_port_add(unit, info->vlan_1, pbmp, pbmp); if (rv != OPENNSL_E_NONE) { printf("OPENNSL FAIL %d: %s\n", rv, opennsl_errmsg(rv)); return rv; } if(verbose >= 2) { printf("Added ports %d, %d to VLAN %d.\n", info->port_1, info->port_2, info->vlan_1); } /* add the vlans to the stg */ rv = opennsl_stg_vlan_add(unit, info->stg, info->vlan_1); if (rv != OPENNSL_E_NONE) { printf("Error, in opennsl_stg_vlan_add, vid=%d, \n", info->vlan_1); return rv; } if(verbose >= 2) { printf("Attached VLAN %d to Spanning Tree Group %d.\n", info->vlan_1, info->stg); } /* add two ports to the stg and attach stp state for each of them */ rv = opennsl_stg_stp_set(unit, info->stg, info->port_1, info->stp_state_1); if (rv != OPENNSL_E_NONE) { printf("Error, in opennsl_stg_stp_set, stg=%d, \n", info->stg); return rv; } if(verbose >= 2) { printf("STP state of port %d is set to \"%s\".\n", info->port_1, stp_state_str[info->stp_state_1]); } rv = opennsl_stg_stp_set(unit, info->stg, info->port_2, info->stp_state_2); if (rv != OPENNSL_E_NONE) { printf("Error, in opennsl_stg_stp_set, stg=%d, \n", info->stg); return rv; } if(verbose >= 2) { printf("STP state of port %d is set to \"%s\".\n", info->port_2, stp_state_str[info->stp_state_2]); } return OPENNSL_E_NONE; }