Пример #1
0
static void *mirroring_loop(void *arg) {
  while(1) {
    const struct timeval wait_time = { .tv_sec = 1, .tv_usec = 0 };
    pkt_digest_t *pkt_digest = (pkt_digest_t *) cb_read_with_wait(rmt_mirroring_cb, &wait_time);

    struct timeval now;
    gettimeofday(&now, NULL);

    if(NULL != pkt_digest) {
      coalescing_session_t *coalescing_session = get_coalescing_session(pkt_digest->mirror_id);
      assert(NULL != coalescing_session);

      // This condition succeeds for the first digest and every digest
      // immediately after a coalesced packet is sent.
      if(0 == coalescing_session->length) {
        RMT_LOG(P4_LOG_LEVEL_VERBOSE,
                "Begin new packet for session %d\n", pkt_digest->mirror_id);
        begin_coalescing_session(coalescing_session);
      }
      const uint32_t new_length = coalescing_session->length + pkt_digest->length;

      RMT_LOG(P4_LOG_LEVEL_VERBOSE,
            "Adding %hu bytes to %u bytes in coalescing session %d\n",
            pkt_digest->length, coalescing_session->length, pkt_digest->mirror_id);
      if(new_length >= coalescing_session->config.min_pkt_size) {
        RMT_LOG(P4_LOG_LEVEL_VERBOSE,
                "Sending coalesced packet of length %u from mirror %d\n",
                coalescing_session->length + pkt_digest->length, pkt_digest->mirror_id);
        uint8_t *pkt_data = malloc(new_length);
        memcpy(pkt_data, coalescing_session->buffer, coalescing_session->length);
        memcpy(pkt_data + coalescing_session->length, pkt_digest->buffer, pkt_digest->length);

        mirroring_send(pkt_digest->mirror_id, pkt_data, new_length, coalescing_session->sequence_number);
        clear_coalescing_session(coalescing_session);
      } else {
        memcpy(coalescing_session->buffer + coalescing_session->length, pkt_digest->buffer, pkt_digest->length);
        (coalescing_session->length) += (pkt_digest->length);
      }
    }

    int i;
    for(i = 0; i < MAX_COALESCING_SESSIONS; ++i) {
      const int mirror_id = i + coalescing_sessions_offset;
      coalescing_session_t *coalescing_session = coalescing_sessions + i;
      struct timeval abs_timeout = coalescing_sessions->last_digest_time;
      abs_timeout.tv_sec += (unsigned long)coalescing_sessions->config.timeout;
      if((coalescing_session->length > 0) && !timercmp(&now, &abs_timeout, <)) {
        RMT_LOG(P4_LOG_LEVEL_VERBOSE,
                "Coalescing session timeout for mirror id %d\n", mirror_id);
        uint8_t *pkt_data = malloc(coalescing_session->length);
        memcpy(pkt_data, coalescing_session->buffer, coalescing_session->length);
        mirroring_send(mirror_id, pkt_data, coalescing_session->length,
                       coalescing_session->sequence_number);
        clear_coalescing_session(coalescing_session);
      }
    }

    free(pkt_digest);
  }
}
Пример #2
0
meter_color_t stateful_execute_meter(meter_t *meter, int index, uint32_t input) {
  pthread_mutex_lock(&meter->lock);

  meter_instance_t *instance = &meter->instances[index];

  struct timeval now;
  gettimeofday(&now, NULL);
  uint64_t time_since_init = (now.tv_sec - time_init.tv_sec) * 1000000 +
    (now.tv_usec - time_init.tv_usec);

  uint64_t usec_diff;

  uint32_t new_tokens;
  meter_queue_t *queue;
  

  meter_color_t color = METER_EXCEED_ACTION_COLOR_GREEN;

  int i;
  for(i = 1; i < METER_EXCEED_ACTION_COLOR_END_; i++) {
    queue = &instance->queues[i];
    if(!queue->valid) continue;
    usec_diff = time_since_init - queue->last_timestamp;
    new_tokens = (uint32_t) (usec_diff * queue->info_rate);
    
    if(new_tokens > 0) {
      queue->tokens += new_tokens;
      if(queue->tokens > queue->burst_size) {
	queue->tokens = queue->burst_size;
      }
      /* TODO : improve this ? */
      queue->last_timestamp += (uint32_t) (new_tokens / queue->info_rate);
    }

    RMT_LOG(P4_LOG_LEVEL_TRACE,
	    "adding %u tokens, now have %u\n",
	    new_tokens,
	    queue->tokens);

    if(queue->tokens < input) {
      color = queue->color;
    }
    else {
      queue->tokens -= input;
      break;
    }
  }

  instance->counters[color]++;

  pthread_mutex_unlock(&meter->lock);

  RMT_LOG(P4_LOG_LEVEL_VERBOSE,
	  "meter %s is marking packet %s\n",
	  meter->name,
	  color_to_str(color));

  return color;
}
Пример #3
0
int ${pd_prefix}mirroring_mapping_add(p4_pd_mirror_id_t mirror_id,
                                      uint16_t egress_port
                                     )
{
  RMT_LOG(P4_LOG_LEVEL_VERBOSE,
	  "adding mirroring mapping mirror_id -> egress_port: %d -> %d\n",
	  mirror_id, egress_port);
  mirroring_mapping_t *mapping;

  mapping = tommy_hashlin_search(&mirroring_mappings,
				 compare_mirroring_mappings,
				 &mirror_id,
				 tommy_inthash_u32(mirror_id));

  if(mapping) {
    mapping->egress_port = egress_port;
  }
  else {
    mapping = malloc(sizeof(mirroring_mapping_t));
    mapping->mirror_id = mirror_id;
    mapping->egress_port = egress_port;
    mapping->coalescing_session = NULL;

    tommy_hashlin_insert(&mirroring_mappings,
			 &mapping->node,
			 mapping,
			 tommy_inthash_u32(mapping->mirror_id));
  }
  return 0;
}
Пример #4
0
static void *pkt_out_loop(void *arg) {
  while(1) {
    transmit_pkt_t *t_pkt = (transmit_pkt_t *) cb_read(rmt_transmit_cb);
    buffered_pkt_t *b_pkt = &t_pkt->pkt;
    RMT_LOG(P4_LOG_LEVEL_TRACE, "outgoing thread: packet dequeued\n");
    if(rmt_instance->tx_fn) {
      RMT_LOG(P4_LOG_LEVEL_VERBOSE,
	      "outgoing thread: sending pkt out of port %d\n",
	      t_pkt->egress);
      rmt_instance->tx_fn(t_pkt->egress, b_pkt->pkt_data, b_pkt->pkt_len);
    }
    free(b_pkt->pkt_data);
    free(t_pkt);
  }
  return NULL;
}
Пример #5
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;
}
Пример #6
0
static void egress_cloning(pipeline_t *pipeline, uint8_t *pkt_data,
			   int pkt_len, uint64_t pkt_id) {
  RMT_LOG(P4_LOG_LEVEL_TRACE, "egress_cloning\n");

  mirroring_receive(pipeline->phv,
                    metadata_recirc_digest(pipeline->phv->metadata_recirc),
                    pkt_data, pkt_len, pkt_id,
                    PKT_INSTANCE_TYPE_EGRESS_CLONE);
}
Пример #7
0
int set_drop_tail_thr(const int thr) {
  write_atomic_int(&EGRESS_CB_SIZE, thr);
  RMT_LOG(P4_LOG_LEVEL_INFO, "Set drop tail threshold to %d\n", thr);
  int i = 0;
  for (i = 0; i < NB_THREADS_PER_PIPELINE; i++) {
    cb_resize(egress_pipeline_instances[i]->cb_in, read_atomic_int(&EGRESS_CB_SIZE), free_egress_pkt);
  }
  return 0;
}
Пример #8
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;
}
Пример #9
0
int ${pd_prefix}mirroring_mapping_add(int mirror_id, int egress_port){
  RMT_LOG(P4_LOG_LEVEL_VERBOSE,
	  "adding mirroring mapping mirror_id -> egress_port: %d -> %d\n",
	  mirror_id, egress_port);
  mirroring_mapping_t *mapping = malloc(sizeof(mirroring_mapping_t));
  mapping->mirror_id = mirror_id;
  mapping->egress_port = egress_port;
  tommy_hashlin_insert(&mirroring_mappings,
                       &mapping->node,
                       mapping,
                       tommy_inthash_u32(mapping->mirror_id));
  return 0;
}
Пример #10
0
p4_pd_status_t
p4_pd_client_cleanup(p4_pd_sess_hdl_t sess_hdl) {
  pthread_mutex_lock(&lock);

  int Rc_int;
  J1U(Rc_int, used_session_handles, (Word_t)sess_hdl);
  if (0 == Rc_int) {
    RMT_LOG(P4_LOG_LEVEL_ERROR, "Cannot find session handle %u\n", (uint32_t)sess_hdl);
  }

  pthread_mutex_unlock(&lock);

  return (p4_pd_status_t)(1 == Rc_int ? 0 : 1);
}
Пример #11
0
static void mirroring_send(const int mirror_id, uint8_t *pkt_data, const uint32_t length, const uint64_t packet_id) {
  RMT_LOG(P4_LOG_LEVEL_VERBOSE,
          "Sending coalesced packet of length %u from coalescing session %d\n", length,
          mirror_id);

  uint8_t *metadata;
  phv_data_t *phv = phv_init(0, 0);
  fields_set_clone_spec(phv, mirror_id);
  fields_set_packet_length(phv, length);
  deparser_produce_metadata(phv, &metadata);
  free(phv);

  // Send to queuing module.
  queuing_receive(metadata, NULL, pkt_data, length, packet_id,
                  PKT_INSTANCE_TYPE_COALESCED);
}
Пример #12
0
//:: if enable_pre:
static int pre_replication(queuing_pkt_t *q_pkt, uint8_t *metadata)
{
    int replication = 0;
    buffered_pkt_t *b_pkt = &q_pkt->pkt;

    uint16_t eg_mcast_group = metadata_get_eg_mcast_group(metadata);
    if (eg_mcast_group) {
      RMT_LOG(P4_LOG_LEVEL_VERBOSE, "replicating packets\n");
      mc_process_and_replicate(eg_mcast_group, metadata, q_pkt->metadata_recirc, b_pkt);
      // Free the packet once it is replicated
      free(b_pkt->pkt_data);
      free(q_pkt->metadata);
      free(q_pkt->metadata_recirc);
      free(q_pkt);
      replication = 1;
    }
    return replication;
}
Пример #13
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;
}
Пример #14
0
int rmt_process_pkt(p4_port_t ingress, void *pkt, int len) {
  RMT_LOG(P4_LOG_LEVEL_VERBOSE, "new packet, len : %d, ingress : %d\n",
	  len, ingress);

  return pkt_manager_receive(ingress, pkt, len);
}
Пример #15
0
int egress_pipeline_receive(int egress,
			    uint8_t *metadata,
			    int *metadata_recirc,
			    void *pkt, int len, uint64_t packet_id,
			    pkt_instance_type_t instance_type) {
  pipeline_t *pipeline = egress_pipeline_instances[egress %
						   NB_THREADS_PER_PIPELINE];
  
  egress_pkt_t *e_pkt = malloc(sizeof(egress_pkt_t));
  buffered_pkt_t *b_pkt = &e_pkt->pkt;
  e_pkt->egress = egress;
  e_pkt->metadata = metadata;
  e_pkt->metadata_recirc = metadata_recirc;
  b_pkt->instance_type = instance_type;
  b_pkt->pkt_data = pkt;
  b_pkt->pkt_len = len;
  b_pkt->pkt_id = packet_id;

//::  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 ? */
  uint32_t deflect_on_drop = metadata_get_deflect_on_drop(extracted_metadata);
  if (!deflect_on_drop) {
    int ret = cb_write(pipeline->cb_in, e_pkt);
    if (ret == 0) {
      free(e_pkt);
      RMT_LOG(P4_LOG_LEVEL_TRACE, "egress_pipeline: dropped a packet from tail\n");
    }
  } else {
    // For negative mirroring based on Qfull,
    // Set the deflection_flag in metadata to indicate that this packet 
    // is moving thru' the queuing system only to get delivered to 
    // negative mirror session.
    // Egress pipeline should act on the deflection_flag and perform 
    // explicit e2e mirroing as appropriate
    RMT_LOG(P4_LOG_LEVEL_TRACE, "egress_pipeline: deflect tail-dropped packet %p\n", metadata);
    metadata_set_deflection_flag(extracted_metadata, 1);
    metadata_set_deflect_on_drop(extracted_metadata, 0);
    metadata_set_egress_spec(extracted_metadata, 0);
    metadata_set_egress_port(extracted_metadata, 0);
    metadata_dump(metadata, extracted_metadata);
    int ret = cb_write(pipeline->cb_in, e_pkt);
    if (ret ==0) {
      free(e_pkt);
      RMT_LOG(P4_LOG_LEVEL_TRACE, "egress_pipeline: could not enqueue a deflected packet\n");
    }
  }
//::  #endif
//::  if not enable_intrinsic:
  int ret = cb_write(pipeline->cb_in, e_pkt);
  if (ret == 0) {
    free(e_pkt);
    RMT_LOG(P4_LOG_LEVEL_TRACE, "egress_pipeline: dropped a packet from tail\n");
  }
//::  #endif

  return 0;
}
Пример #16
0
int set_packets_per_sec(const int pps) {
  write_atomic_int(&USEC_INTERVAL, 1000000.0 / pps);
  RMT_LOG(P4_LOG_LEVEL_INFO, "Set USEC_INTERVAL to %lu\n", USEC_INTERVAL);
  return 0;
}
Пример #17
0
static void *processing_loop_egress(void *arg) {
  pipeline_t *pipeline = (pipeline_t *) arg;
  circular_buffer_t *cb_in = pipeline->cb_in;

  //Added by Ming
#ifdef SWITCH_CPU_DEBUG
  int i;
#endif

#ifdef RATE_LIMITING
  struct timeval tv;
  gettimeofday(&tv, NULL);
  uint64_t next_deque = tv.tv_sec * 1000000 + tv.tv_usec + read_atomic_int(&USEC_INTERVAL);
#endif

  while(1) {
#ifdef RATE_LIMITING
    struct timeval tv;
    gettimeofday(&tv, NULL);
    uint64_t now_us = tv.tv_sec * 1000000 + tv.tv_usec;
    //RMT_LOG(P4_LOG_LEVEL_TRACE, "next_deque %lu, now_us %lu\n", next_deque, now_us);
    if(next_deque > now_us) {
      usleep(next_deque - now_us);
    }
    next_deque += read_atomic_int(&USEC_INTERVAL);
#endif
    egress_pkt_t *e_pkt = (egress_pkt_t *) cb_read(cb_in);
    if (e_pkt == NULL) continue;
    buffered_pkt_t *b_pkt = &e_pkt->pkt;
    RMT_LOG(P4_LOG_LEVEL_TRACE, "egress_pipeline: packet dequeued\n");

    phv_clean(pipeline->phv);

    pipeline->phv->packet_id = b_pkt->pkt_id;

    parser_parse_pkt(pipeline->phv,
		     b_pkt->pkt_data, b_pkt->pkt_len,
		     pipeline->parse_state_start);
    parser_parse_metadata(pipeline->phv,
			  e_pkt->metadata, e_pkt->metadata_recirc);
    assert(!fields_get_clone_spec(pipeline->phv));

//::  if enable_intrinsic:
   /* Set dequeue metadata */
    fields_set_deq_qdepth(pipeline->phv, cb_count(cb_in));
    uint64_t enq_timestamp = fields_get_enq_timestamp(pipeline->phv);
    fields_set_deq_timedelta(pipeline->phv, get_timestamp()-enq_timestamp);
//::  #endif

    fields_set_instance_type(pipeline->phv, e_pkt->pkt.instance_type);

    free(e_pkt->metadata);
    free(e_pkt->metadata_recirc);
    if(pipeline->table_entry_fn)  /* empty egress pipeline ? */
      pipeline->table_entry_fn(pipeline->phv);

    uint8_t *pkt_data;
    int pkt_len;

    /* EGRESS MIRRORING */
    if(fields_get_clone_spec(pipeline->phv)) {
      RMT_LOG(P4_LOG_LEVEL_VERBOSE, "Egress mirroring\n");
      pipeline->deparse_fn(pipeline->phv, &pkt_data, &pkt_len);
      egress_cloning(pipeline, pkt_data, pkt_len, e_pkt->pkt.pkt_id);
      fields_set_clone_spec(pipeline->phv, 0);
    }

    update_checksums(pipeline->phv);
    pipeline->deparse_fn(pipeline->phv, &pkt_data, &pkt_len);

    free(b_pkt->pkt_data);

//:: if "egress_drop_ctl" in extra_metadata_name_map:
      // program uses the separate egress_drop_ctl register
      // a non-zero value means drop
    if(pipeline->phv->deparser_drop_signal ||
       metadata_get_egress_drop_ctl(metadata)) {
//:: else:
    if(pipeline->phv->deparser_drop_signal){
//:: #endif
      RMT_LOG(P4_LOG_LEVEL_VERBOSE, "dropping packet at egress\n");
      free(e_pkt);
      continue;
    }

    int egress = fields_get_egress_port(pipeline->phv);

    if(pipeline->phv->truncated_length && (pipeline->phv->truncated_length < pkt_len))
      pkt_len = pipeline->phv->truncated_length;
   
#ifdef SWITCH_CPU_DEBUG
	RMT_LOG(P4_LOG_LEVEL_TRACE, "Ming Packet Data: %d\n", b_pkt->pkt_len);
	for (i = 0; i < 21; i++)
		RMT_LOG(P4_LOG_LEVEL_TRACE, "%x ", b_pkt->pkt_data[i]);
	RMT_LOG(P4_LOG_LEVEL_TRACE, "\n");
#endif

    pkt_manager_transmit(egress, pkt_data, pkt_len, b_pkt->pkt_id);
    free(e_pkt);

  }

  return NULL;
}

/* name has to be ingress or egress */
pipeline_t *pipeline_create(int id) {
  pipeline_t *pipeline = malloc(sizeof(pipeline_t));
  pipeline->name = "egress";
#ifdef RATE_LIMITING
  pipeline->cb_in = cb_init(read_atomic_int(&EGRESS_CB_SIZE), CB_WRITE_DROP, CB_READ_RETURN);
#else
  pipeline->cb_in = cb_init(read_atomic_int(&EGRESS_CB_SIZE), CB_WRITE_BLOCK, CB_READ_BLOCK);
#endif
  pipeline->parse_state_start = parse_state_start;
//:: if egress_entry_table is not None:
  pipeline->table_entry_fn = tables_apply_${egress_entry_table};
//:: else:
  pipeline->table_entry_fn = NULL;
//:: #endif
  pipeline->deparse_fn = deparser_produce_pkt;
  pipeline->phv = phv_init(NB_THREADS_PER_PIPELINE + id, RMT_PIPELINE_EGRESS);

  /* packet processing loop */
  pthread_create(&pipeline->processing_thread, NULL,
		 processing_loop_egress, (void *) pipeline);

  return pipeline;
}
Пример #18
0
static void *pkt_processing_loop(void *arg) {
  while(1) {
    queuing_pkt_t *q_pkt = (queuing_pkt_t *) cb_read(rmt_queuing_cb);
    buffered_pkt_t *b_pkt = &q_pkt->pkt;
    RMT_LOG(P4_LOG_LEVEL_TRACE, "queuing system: packet dequeued\n");
    memset(metadata, 0, ${bytes});
    metadata_extract(metadata, q_pkt->metadata, q_pkt->metadata_recirc);

    /* after this point, no one should use q_pkt->metadata */

    int mirror_id = metadata_get_clone_spec(metadata);
    metadata_set_clone_spec(metadata, 0);
    int egress_port;
//:: if enable_pre:
    if (pre_replication(q_pkt, metadata)) {
      continue;
    }
//:: #endif
    if(mirror_id == 0) {
      egress_port = metadata_get_egress_spec(metadata);
      /* TODO: formalize somewhere that 511 is the drop port for this target */
//:: if "ingress_drop_ctl" in extra_metadata_name_map:
      // program uses the separate ingress_drop_ctl register
      // a non-zero value means drop
      if(egress_port = 511 || metadata_get_ingress_drop_ctl(metadata)) {
//:: else:
      if(egress_port == 511) {
//:: #endif
	RMT_LOG(P4_LOG_LEVEL_VERBOSE, "dropping packet at ingress\n");
	free(b_pkt->pkt_data);
	free(q_pkt->metadata);
	free(q_pkt->metadata_recirc);
	free(q_pkt);
	continue;
      }
    }
    else {
      RMT_LOG(P4_LOG_LEVEL_VERBOSE, "mirror id is %d\n", mirror_id);
      egress_port = ${pd_prefix}mirroring_mapping_get_egress_port(mirror_id);
      if (egress_port < 0) {
	RMT_LOG(P4_LOG_LEVEL_WARN,
		"no mapping for mirror id %d, dropping packet\n", mirror_id);
	free(b_pkt->pkt_data);
	free(q_pkt->metadata);
	free(q_pkt->metadata_recirc);
	free(q_pkt);
	continue;
      }
      RMT_LOG(P4_LOG_LEVEL_TRACE,
             "queuing system: cloned packet, mirror_id -> egress_port : %d -> %d\n",
             mirror_id, egress_port);
    }
    metadata_set_egress_port(metadata, egress_port);
    RMT_LOG(P4_LOG_LEVEL_TRACE, "egress port set to %d\n", egress_port);

    pkt_instance_type_t instance_type = b_pkt->instance_type;
    metadata_set_instance_type(metadata, instance_type);
    RMT_LOG(P4_LOG_LEVEL_TRACE, "instance type set to %d\n", instance_type);

//::  if enable_intrinsic:
    /* Set enqueue metadata */
    metadata_set_enq_qdepth(metadata, egress_pipeline_count(egress_port));
    metadata_set_enq_timestamp(metadata, get_timestamp());
//::  #endif 
    
    metadata_dump(q_pkt->metadata, metadata);
    egress_pipeline_receive(egress_port,
			    q_pkt->metadata, q_pkt->metadata_recirc,
			    b_pkt->pkt_data, b_pkt->pkt_len, b_pkt->pkt_id,
			    b_pkt->instance_type);
    free(q_pkt);
  }

  return NULL;
}