Пример #1
0
int ${pd_prefix}mirroring_add_coalescing_session(int mirror_id, int egress_port,
                                                 const int8_t *header,
                                                 const int8_t header_length,
                                                 const int16_t min_pkt_size,
                                                 const int8_t timeout) {
  mirroring_mapping_t *mapping;
  coalescing_session_t *coalescing_session;
  p4_pd_dev_target_t dev_tgt;
  dev_tgt.device_id = 0; // XXX get it as input
  dev_tgt.dev_pipe_id = PD_DEV_PIPE_ALL; // XXX get it as input

  RMT_LOG(P4_LOG_LEVEL_VERBOSE,
          "adding coalescing session mirror_id: %d, header_length: %hd, min_pkt_size: %hd\n",
          mirror_id, header_length, min_pkt_size);

  // Sanity checks to ensure that mirror_id is in the correct range (relative to
  // coalescing_sessions_offset).
  assert(mirror_id >= coalescing_sessions_offset);
  assert(mirror_id < coalescing_sessions_offset + MAX_COALESCING_SESSIONS);

  // NEED to fix this api to get the correct info - currently not used..so
  // just getting it to compile
  ${pd_prefix}mirror_session_create(0/*shdl*/,
                                    dev_tgt,
                                    PD_MIRROR_TYPE_COAL/*type*/,
                                    PD_DIR_EGRESS,
                                    mirror_id,
                                    egress_port,
                                    0/*max_pkt_len*/,
                                    0/*cos*/,
                                    false/*c2c*/,
                                    0, /*extract_len*/
                                    0, /*timeout_usec*/
                                    NULL, /*int_hdr*/
                                    0 /*int_hdr_len*/
                                    );

  mapping = get_mirroring_mapping(mirror_id);
  assert(NULL != mapping);
  mapping->coalescing_session = coalescing_sessions + mirror_id - coalescing_sessions_offset;

  coalescing_session = mapping->coalescing_session;
  coalescing_session->length = 0;
  coalescing_session->sequence_number = 0;

  assert(header_length <= MAX_HEADER_LENGTH);
  memcpy(coalescing_session->config.header, (uint8_t*)header, header_length);
  coalescing_session->config.header_length = header_length;

  coalescing_session->config.min_pkt_size = min_pkt_size;
  // FIXME: We are assuming timeout is in seconds. It should be in 'base time'.
  coalescing_session->config.timeout = timeout;

  return 0;
}
Пример #2
0
int mirroring_receive(phv_data_t *phv, int *metadata_recirc, void *pkt_data,
                      int len, uint64_t packet_id,
                      pkt_instance_type_t instance_type) {
  int mirror_id = fields_get_clone_spec(phv);
  coalescing_session_t *coalescing_session = get_coalescing_session(mirror_id);
  if(NULL != coalescing_session) {
    RMT_LOG(P4_LOG_LEVEL_VERBOSE,
      "Queuing digest for mirror %d %d\n", mirror_id, *metadata_recirc);
    pkt_digest_t *pkt_digest = malloc(sizeof(pkt_digest_t));
    pkt_digest->mirror_id = mirror_id;
    pkt_digest->length = 0;
    deparser_extract_digest(phv, metadata_recirc, pkt_digest->buffer, &(pkt_digest->length));

    cb_write(rmt_mirroring_cb, pkt_digest);
  }
  else if(NULL != get_mirroring_mapping(mirror_id)) {
    uint8_t *metadata;
    deparser_produce_metadata(phv, &metadata);
//::  if enable_intrinsic:
//::    bytes = 0
//::    for header_instance in ordered_header_instances_non_virtual:
//::      h_info = header_info[header_instance]
//::      is_metadata = h_info["is_metadata"]
//::      if is_metadata: bytes += h_info["byte_width_phv"]
//::    #endfor
     uint8_t extracted_metadata[${bytes}];
     metadata_extract(extracted_metadata, metadata, NULL); /* NULL ? */
    // do not set deflection_flag and dod bits for mirrored packet
    metadata_set_deflection_flag(extracted_metadata, 0);
    metadata_set_deflect_on_drop(extracted_metadata, 0);
    metadata_dump(metadata, extracted_metadata);
//::  #endif

    return queuing_receive(metadata, metadata_recirc, pkt_data, len, packet_id,
                           instance_type);
  }
  else {
    RMT_LOG(P4_LOG_LEVEL_WARN,
            "Received packet with invalid mirror id %d\n", mirror_id);
  }

  free(pkt_data);
  free(metadata_recirc);

  return 0;
}
Пример #3
0
int mirroring_receive(phv_data_t *phv, int *metadata_recirc, void *pkt_data,
                      int len, uint64_t packet_id,
                      pkt_instance_type_t instance_type) {
  int mirror_id = fields_get_clone_spec(phv);
  if(NULL != get_mirroring_mapping(mirror_id)) {
    uint8_t *metadata;
    deparser_produce_metadata(phv, &metadata);
    return queuing_receive(metadata, metadata_recirc, pkt_data, len, packet_id,
                           instance_type);
  }
  else {
    RMT_LOG(P4_LOG_LEVEL_WARN,
            "Received packet with invalid mirror id %d\n", mirror_id);
  }

  free(pkt_data);
  free(metadata_recirc);

  return 0;
}
Пример #4
0
static coalescing_session_t*
get_coalescing_session(int mirror_id) {
  mirroring_mapping_t *mapping = get_mirroring_mapping(mirror_id);
  return ((NULL == mapping) ? NULL : mapping->coalescing_session);
}
Пример #5
0
int ${pd_prefix}mirroring_mapping_get_egress_port(int mirror_id) {
  mirroring_mapping_t *mapping = get_mirroring_mapping(mirror_id);
  return (mapping ? mapping->egress_port : -1);
}
Пример #6
0
void
SimpleSwitch::egress_thread(size_t worker_id) {
  PHV *phv;

  while (1) {
    std::unique_ptr<Packet> packet;
    size_t port;
    egress_buffers.pop_back(worker_id, &port, &packet);

    Deparser *deparser = this->get_deparser("deparser");
    Pipeline *egress_mau = this->get_pipeline("egress");

    phv = packet->get_phv();

    if (with_queueing_metadata) {
      auto enq_timestamp =
          phv->get_field("queueing_metadata.enq_timestamp").get<ts_res::rep>();
      phv->get_field("queueing_metadata.deq_timedelta").set(
          get_ts().count() - enq_timestamp);
      phv->get_field("queueing_metadata.deq_qdepth").set(
          egress_buffers.size(port));
    }

    phv->get_field("standard_metadata.egress_port").set(port);

    Field &f_egress_spec = phv->get_field("standard_metadata.egress_spec");
    f_egress_spec.set(0);

    phv->get_field("standard_metadata.packet_length").set(
        packet->get_register(PACKET_LENGTH_REG_IDX));

    egress_mau->apply(packet.get());

    Field &f_clone_spec = phv->get_field("standard_metadata.clone_spec");
    unsigned int clone_spec = f_clone_spec.get_uint();

    // EGRESS CLONING
    if (clone_spec) {
      BMLOG_DEBUG_PKT(*packet, "Cloning packet at egress");
      int egress_port = get_mirroring_mapping(clone_spec & 0xFFFF);
      if (egress_port >= 0) {
        f_clone_spec.set(0);
        p4object_id_t field_list_id = clone_spec >> 16;
        std::unique_ptr<Packet> packet_copy =
            packet->clone_with_phv_reset_metadata_ptr();
        PHV *phv_copy = packet_copy->get_phv();
        FieldList *field_list = this->get_field_list(field_list_id);
        for (const auto &p : *field_list) {
          phv_copy->get_field(p.header, p.offset)
            .set(phv->get_field(p.header, p.offset));
        }
        phv_copy->get_field("standard_metadata.instance_type")
            .set(PKT_INSTANCE_TYPE_EGRESS_CLONE);
        enqueue(egress_port, std::move(packet_copy));
      }
    }

    // TODO(antonin): should not be done like this in egress pipeline
    int egress_spec = f_egress_spec.get_int();
    if (egress_spec == 511) {  // drop packet
      BMLOG_DEBUG_PKT(*packet, "Dropping packet at the end of egress");
      continue;
    }

    deparser->deparse(packet.get());

    // RECIRCULATE
    if (phv->has_field("intrinsic_metadata.recirculate_flag")) {
      Field &f_recirc = phv->get_field("intrinsic_metadata.recirculate_flag");
      if (f_recirc.get_int()) {
        BMLOG_DEBUG_PKT(*packet, "Recirculating packet");
        p4object_id_t field_list_id = f_recirc.get_int();
        f_recirc.set(0);
        FieldList *field_list = this->get_field_list(field_list_id);
        // TODO(antonin): just like for resubmit, there is no need for a copy
        // here, but it is more convenient for this first prototype
        std::unique_ptr<Packet> packet_copy = packet->clone_no_phv_ptr();
        PHV *phv_copy = packet_copy->get_phv();
        phv_copy->reset_metadata();
        for (const auto &p : *field_list) {
          phv_copy->get_field(p.header, p.offset)
              .set(phv->get_field(p.header, p.offset));
        }
        phv_copy->get_field("standard_metadata.instance_type")
            .set(PKT_INSTANCE_TYPE_RECIRC);
        size_t packet_size = packet_copy->get_data_size();
        packet_copy->set_register(PACKET_LENGTH_REG_IDX, packet_size);
        phv_copy->get_field("standard_metadata.packet_length").set(packet_size);
        input_buffer.push_front(std::move(packet_copy));
        continue;
      }
    }

    output_buffer.push_front(std::move(packet));
  }
Пример #7
0
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));
  }
}