Example #1
0
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());
}
Example #2
0
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());
  }
}
Example #4
0
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());
}
Example #5
0
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;
}