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); } }
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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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); }
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); }
//:: 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; }
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; }
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); }
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; }
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; }
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; }
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; }