void Deparser::deparse(Packet *pkt) const { PHV *phv = pkt->get_phv(); BMELOG(deparser_start, *pkt, *this); // TODO(antonin) // this is temporary while we experiment with the debugger DEBUGGER_NOTIFY_CTR( Debugger::PacketId::make(pkt->get_packet_id(), pkt->get_copy_id()), DBG_CTR_DEPARSER | get_id()); update_checksums(pkt); char *data = pkt->prepend(get_headers_size(*phv)); int bytes_parsed = 0; // invalidating headers, and resetting header stacks is done in the Packet // destructor, when the PHV is released for (auto it = headers.begin(); it != headers.end(); ++it) { Header &header = phv->get_header(*it); if (header.is_valid()) { BMELOG(deparser_emit, *pkt, *it); header.deparse(data + bytes_parsed); bytes_parsed += header.get_nbytes_packet(); // header.mark_invalid(); } } // phv->reset_header_stacks(); BMELOG(deparser_done, *pkt, *this); DEBUGGER_NOTIFY_CTR( Debugger::PacketId::make(pkt->get_packet_id(), pkt->get_copy_id()), DBG_CTR_EXIT(DBG_CTR_DEPARSER) | get_id()); }
void Deparser::update_checksums(Packet *pkt) const { for (const Checksum *checksum : checksums) { checksum->update(pkt); BMELOG(checksum_update, *pkt, *checksum); } }
void SimpleSwitch::transmit_thread() { while (1) { std::unique_ptr<Packet> packet; output_buffer.pop_back(&packet); BMELOG(packet_out, *packet); BMLOG_DEBUG_PKT(*packet, "Transmitting packet of size {} out of port {}", packet->get_data_size(), packet->get_egress_port()); transmit_fn(packet->get_egress_port(), packet->data(), packet->get_data_size()); } }
void Parser::parse(Packet *pkt) const { BMELOG(parser_start, *pkt, *this); // TODO(antonin) // this is temporary while we experiment with the debugger DEBUGGER_NOTIFY_CTR( Debugger::PacketId::make(pkt->get_packet_id(), pkt->get_copy_id()), DBG_CTR_PARSER | get_id()); BMLOG_DEBUG_PKT(*pkt, "Parser '{}': start", get_name()); const char *data = pkt->data(); if (!init_state) return; const ParseState *next_state = init_state; size_t bytes_parsed = 0; while (next_state) { next_state = (*next_state)(pkt, data, &bytes_parsed); BMLOG_TRACE("Bytes parsed: {}", bytes_parsed); } pkt->remove(bytes_parsed); BMELOG(parser_done, *pkt, *this); DEBUGGER_NOTIFY_CTR( Debugger::PacketId::make(pkt->get_packet_id(), pkt->get_copy_id()), DBG_CTR_EXIT(DBG_CTR_PARSER) | get_id()); BMLOG_DEBUG_PKT(*pkt, "Parser '{}': end", get_name()); }
int SwitchWContexts::do_swap() { int rc = 1; if (!enable_swap || !swap_requested()) return rc; boost::unique_lock<boost::shared_mutex> lock(ongoing_swap_mutex); for (size_t cxt_id = 0; cxt_id < nb_cxts; cxt_id++) { auto &cxt = contexts[cxt_id]; if (!cxt.swap_requested()) continue; // TODO(antonin): we spin until no more packets exist for this context, is // there a better way of doing this? while (phv_source->phvs_in_use(cxt_id) > 0) { } int swap_done = cxt.do_swap(); if (swap_done == 0) phv_source->set_phv_factory(cxt_id, &cxt.get_phv_factory()); rc &= swap_done; } Debugger::get()->config_change(); BMELOG(config_change); return rc; }
int SimpleSwitch::receive(int port_num, const char *buffer, int len) { static int pkt_id = 0; // this is a good place to call this, because blocking this thread will not // block the processing of existing packet instances, which is a requirement if (do_swap() == 0) { check_queueing_metadata(); } // we limit the packet buffer to original size + 512 bytes, which means we // cannot add more than 512 bytes of header data to the packet, which should // be more than enough auto packet = new_packet_ptr(port_num, pkt_id++, len, bm::PacketBuffer(len + 512, buffer, len)); BMELOG(packet_in, *packet); PHV *phv = packet->get_phv(); // many current P4 programs assume this // it is also part of the original P4 spec phv->reset_metadata(); // setting standard metadata phv->get_field("standard_metadata.ingress_port").set(port_num); // using packet register 0 to store length, this register will be updated for // each add_header / remove_header primitive call packet->set_register(PACKET_LENGTH_REG_IDX, len); phv->get_field("standard_metadata.packet_length").set(len); Field &f_instance_type = phv->get_field("standard_metadata.instance_type"); f_instance_type.set(PKT_INSTANCE_TYPE_NORMAL); if (phv->has_field("intrinsic_metadata.ingress_global_timestamp")) { phv->get_field("intrinsic_metadata.ingress_global_timestamp") .set(get_ts().count()); } input_buffer.push_front(std::move(packet)); return 0; }