void SimpleSwitch::pipeline_thread() { Pipeline *ingress_mau = this->get_pipeline("ingress"); Pipeline *egress_mau = this->get_pipeline("egress"); Parser *parser = this->get_parser("parser"); Deparser *deparser = this->get_deparser("deparser"); PHV *phv; while (1) { std::unique_ptr<Packet> packet; input_buffer.pop_back(&packet); phv = packet->get_phv(); int ingress_port = packet->get_ingress_port(); BMLOG_DEBUG_PKT(*packet, "Processing packet received on port {}", ingress_port); phv->get_field("standard_metadata.ingress_port").set(ingress_port); ingress_port = phv->get_field("standard_metadata.ingress_port").get_int(); std::cout << ingress_port << std::endl; parser->parse(packet.get()); ingress_mau->apply(packet.get()); int egress_port = phv->get_field("standard_metadata.egress_port").get_int(); BMLOG_DEBUG_PKT(*packet, "Egress port is {}", egress_port); int learn_id = phv->get_field("intrinsic_metadata.learn_id").get_int(); BMLOG_DEBUG_PKT(*packet, "Learn id is {}", learn_id); unsigned int mgid = phv->get_field("intrinsic_metadata.mgid").get_uint(); BMLOG_DEBUG_PKT(*packet, "Mgid is {}", mgid); if (learn_id > 0) { get_learn_engine()->learn(learn_id, *packet.get()); phv->get_field("intrinsic_metadata.learn_id").set(0); } if (egress_port == 511 && mgid == 0) { BMLOG_DEBUG_PKT(*packet, "Dropping packet"); continue; } if (mgid != 0) { assert(mgid == 1); phv->get_field("intrinsic_metadata.mgid").set(0); packet_id_t copy_id = 1; const auto pre_out = pre->replicate({mgid}); for (const auto &out : pre_out) { egress_port = out.egress_port; if (ingress_port == egress_port) continue; // pruning BMLOG_DEBUG_PKT(*packet, "Replicating packet on port {}", egress_port); std::unique_ptr<Packet> packet_copy = packet->clone_with_phv_ptr(); packet_copy->set_egress_port(egress_port); egress_mau->apply(packet_copy.get()); deparser->deparse(packet_copy.get()); output_buffer.push_front(std::move(packet_copy)); } } else { packet->set_egress_port(egress_port); egress_mau->apply(packet.get()); deparser->deparse(packet.get()); output_buffer.push_front(std::move(packet)); } } }
void SimpleSwitch::ingress_thread() { PHV *phv; while (1) { std::unique_ptr<Packet> packet; input_buffer.pop_back(&packet); // TODO(antonin): only update these if swapping actually happened? Parser *parser = this->get_parser("parser"); Pipeline *ingress_mau = this->get_pipeline("ingress"); phv = packet->get_phv(); int ingress_port = packet->get_ingress_port(); (void) ingress_port; BMLOG_DEBUG_PKT(*packet, "Processing packet received on port {}", ingress_port); /* This looks like it comes out of the blue. However this is needed for ingress cloning. The parser updates the buffer state (pops the parsed headers) to make the deparser's job easier (the same buffer is re-used). But for ingress cloning, the original packet is needed. This kind of looks hacky though. Maybe a better solution would be to have the parser leave the buffer unchanged, and move the pop logic to the deparser. TODO? */ const Packet::buffer_state_t packet_in_state = packet->save_buffer_state(); parser->parse(packet.get()); ingress_mau->apply(packet.get()); packet->reset_exit(); Field &f_egress_spec = phv->get_field("standard_metadata.egress_spec"); int egress_spec = f_egress_spec.get_int(); Field &f_clone_spec = phv->get_field("standard_metadata.clone_spec"); unsigned int clone_spec = f_clone_spec.get_uint(); int learn_id = 0; unsigned int mgid = 0u; if (phv->has_field("intrinsic_metadata.lf_field_list")) { Field &f_learn_id = phv->get_field("intrinsic_metadata.lf_field_list"); learn_id = f_learn_id.get_int(); } // detect mcast support, if this is true we assume that other fields needed // for mcast are also defined if (phv->has_field("intrinsic_metadata.mcast_grp")) { Field &f_mgid = phv->get_field("intrinsic_metadata.mcast_grp"); mgid = f_mgid.get_uint(); } int egress_port; // INGRESS CLONING if (clone_spec) { BMLOG_DEBUG_PKT(*packet, "Cloning packet at ingress"); egress_port = get_mirroring_mapping(clone_spec & 0xFFFF); f_clone_spec.set(0); if (egress_port >= 0) { const Packet::buffer_state_t packet_out_state = packet->save_buffer_state(); packet->restore_buffer_state(packet_in_state); p4object_id_t field_list_id = clone_spec >> 16; auto packet_copy = copy_ingress_pkt( packet, PKT_INSTANCE_TYPE_INGRESS_CLONE, field_list_id); // we need to parse again // the alternative would be to pay the (huge) price of PHV copy for // every ingress packet parser->parse(packet_copy.get()); enqueue(egress_port, std::move(packet_copy)); packet->restore_buffer_state(packet_out_state); } } // LEARNING if (learn_id > 0) { get_learn_engine()->learn(learn_id, *packet.get()); } // RESUBMIT if (phv->has_field("intrinsic_metadata.resubmit_flag")) { Field &f_resubmit = phv->get_field("intrinsic_metadata.resubmit_flag"); if (f_resubmit.get_int()) { BMLOG_DEBUG_PKT(*packet, "Resubmitting packet"); // get the packet ready for being parsed again at the beginning of // ingress packet->restore_buffer_state(packet_in_state); p4object_id_t field_list_id = f_resubmit.get_int(); f_resubmit.set(0); // TODO(antonin): a copy is not needed here, but I don't yet have an // optimized way of doing this auto packet_copy = copy_ingress_pkt( packet, PKT_INSTANCE_TYPE_RESUBMIT, field_list_id); input_buffer.push_front(std::move(packet_copy)); continue; } } Field &f_instance_type = phv->get_field("standard_metadata.instance_type"); // MULTICAST int instance_type = f_instance_type.get_int(); if (mgid != 0) { BMLOG_DEBUG_PKT(*packet, "Multicast requested for packet"); Field &f_rid = phv->get_field("intrinsic_metadata.egress_rid"); const auto pre_out = pre->replicate({mgid}); auto packet_size = packet->get_register(PACKET_LENGTH_REG_IDX); for (const auto &out : pre_out) { egress_port = out.egress_port; // if (ingress_port == egress_port) continue; // pruning BMLOG_DEBUG_PKT(*packet, "Replicating packet on port {}", egress_port); f_rid.set(out.rid); f_instance_type.set(PKT_INSTANCE_TYPE_REPLICATION); std::unique_ptr<Packet> packet_copy = packet->clone_with_phv_ptr(); packet_copy->set_register(PACKET_LENGTH_REG_IDX, packet_size); enqueue(egress_port, std::move(packet_copy)); } f_instance_type.set(instance_type); // when doing multicast, we discard the original packet continue; } egress_port = egress_spec; BMLOG_DEBUG_PKT(*packet, "Egress port is {}", egress_port); if (egress_port == 511) { // drop packet BMLOG_DEBUG_PKT(*packet, "Dropping packet at the end of ingress"); continue; } enqueue(egress_port, std::move(packet)); } }