Exemple #1
0
/* Create contents of routing table */
void net_routing_table_initiate(struct net_routing_table_t *routing_table)
{
	int i, j;

	struct net_t *net = routing_table->net;

	struct net_node_t *src_node, *dst_node;
	struct net_buffer_t *buffer;
	struct net_link_t *link;

	struct net_routing_table_entry_t *entry;

	/* Allocate routing table entries */
	if (routing_table->entries)
		panic("%s: network \"%s\": routing table already allocated", __FUNCTION__, net->name);
	routing_table->dim = list_count(net->node_list);
	routing_table->entries = calloc(routing_table->dim * routing_table->dim,
		sizeof(struct net_routing_table_entry_t));
	if (!routing_table->entries)
		fatal("%s: out of memory", __FUNCTION__);

	/* Initialize table with infinite costs */
	for (i = 0; i < net->node_count; i++)
	{
		for (j = 0; j < net->node_count; j++)
		{
			src_node = list_get(net->node_list, i);
			dst_node = list_get(net->node_list, j);
			entry = net_routing_table_lookup(routing_table, src_node, dst_node);
			entry->cost = i == j ? 0 : routing_table->dim;  /* Infinity or 0 */
			entry->next_node = NULL;
			entry->output_buffer = NULL;
		}
	}

	/* Set 1-hop connections */
	for (i = 0; i < net->node_count; i++)
	{
		src_node = list_get(net->node_list, i);
		for (j = 0; j < list_count(src_node->output_buffer_list); j++)
		{
			buffer = list_get(src_node->output_buffer_list, j);
			link = buffer->link;
			assert(link);
			entry = net_routing_table_lookup(routing_table, src_node, link->dst_node);
			entry->cost = 1;
			entry->next_node = link->dst_node;
			entry->output_buffer = buffer;
		}
	}
}
Exemple #2
0
/* Return TRUE if a message can be sent through the network. Return FALSE
 * otherwise, whether the reason is temporary of permanent. This function is
 * being used just in stand alone simulator. So in here if a buffer is busy
 * for any reason, the node simply discards the message and sends another
 * one. */
int net_can_send(struct net_t *net, struct net_node_t *src_node,
		struct net_node_t *dst_node, int size)
{
	struct net_routing_table_t *routing_table = net->routing_table;
	struct net_routing_table_entry_t *entry;
	struct net_buffer_t *output_buffer;
	long long cycle;

	/* Get current cycle */
	cycle = esim_domain_cycle(net_domain_index);

	/* Get output buffer */
	entry = net_routing_table_lookup(routing_table, src_node, dst_node);
	output_buffer = entry->output_buffer;


	/* No route to destination */
	if (!output_buffer)
		return 0;

	/* Output buffer is busy */
	if (output_buffer->write_busy >= cycle)
		return 0;

	/* Message does not fit in output buffer */
	if (output_buffer->count + size > output_buffer->size)
		return 0;

	/* All conditions satisfied, can send */
	return 1;
}
Exemple #3
0
/* Updating the entries in the routing table based on the routes existing in configuration file*/
void net_routing_table_route_update(struct net_routing_table_t *routing_table, struct net_node_t *src_node,
	struct net_node_t *dst_node, struct net_node_t *next_node, int vc_num)
{

	int k;
	int route_check = 0 ;

	struct net_buffer_t *buffer;
	struct net_link_t *link;
	struct net_routing_table_entry_t *entry;

	entry = net_routing_table_lookup(routing_table, src_node, dst_node);
	entry->next_node = next_node;
	entry->output_buffer = NULL ;

	/* Look for output buffer */
	buffer = NULL;
	assert(list_count(src_node->output_buffer_list));

	for (k = 0; (k < list_count(src_node->output_buffer_list) && route_check != 1); k++)
	{
		buffer = list_get(src_node->output_buffer_list, k);
		link = buffer->link;
		assert(link);

		if ((link->dst_node == next_node))
		{
			if (vc_num == 0)
			{
				entry->output_buffer = buffer;
				route_check = 1;
			}
			else
			{
				if (link->virtual_channel <= vc_num)
						fatal("Network %s: %s.to.%s: wrong virtual channel number is used in route \n %s",
								routing_table->net->name, src_node->name, dst_node->name, err_net_config);
				struct net_buffer_t *vc_buffer;
				vc_buffer = list_get(src_node->output_buffer_list, (buffer->index)+vc_num);
				assert(vc_buffer->link == buffer->link);
				entry->output_buffer = vc_buffer;
				route_check = 1;
			}
		}						
	}
	/*If there is not a route between the source node and next node , error */
	if (route_check == 0) fatal("Network %s : route %s.to.%s = %s : Missing Link \n%s ",
		routing_table->net->name, src_node->name, dst_node->name, next_node->name, err_net_routing);

	/* Find cycle in routing table */
	net_routing_table_cycle_detection(routing_table);
}
Exemple #4
0
/* Return TRUE if a message can be sent to the network. If it cannot be sent, 
 * return FALSE, and schedule 'retry_event' for the cycle when the check
 * should be performed again. This function should not be called if the
 * reason why a message cannot be sent is permanent (e.g., no route to
 * destination). */
int net_can_send_ev(struct net_t *net, struct net_node_t *src_node,
		struct net_node_t *dst_node, int size,
		int retry_event, void *retry_stack)
{
	struct net_routing_table_t *routing_table = net->routing_table;
	struct net_routing_table_entry_t *entry;
	struct net_buffer_t *output_buffer;
	long long cycle;

	/* Get current cycle */
	cycle = esim_domain_cycle(net_domain_index);

	/* Get output buffer */
	entry = net_routing_table_lookup(routing_table, src_node, dst_node);
	output_buffer = entry->output_buffer;

	/* No route to destination */
	if (!output_buffer)
		fatal("%s: no route between %s and %s.\n%s",
				net->name, src_node->name, dst_node->name,
				net_err_no_route);

	/* Message is too long */
	if (size > output_buffer->size)
		fatal("%s: message too long.\n%s", net->name,
				net_err_large_message);

	/* Output buffer is busy */
	if (output_buffer->write_busy >= cycle)
	{
		esim_schedule_event(retry_event, retry_stack,
				output_buffer->write_busy - cycle + 1);
		return 0;
	}

	/* Message does not fit in output buffer */
	if (output_buffer->count + size > output_buffer->size)
	{
		net_buffer_wait(output_buffer, retry_event, retry_stack);
		return 0;
	}

	/* All conditions satisfied, can send */
	return 1;
}
Exemple #5
0
/* Round-robin scheduler for network switch, choosing between several
 * candidate messages at the head of all input buffers that have a given
 * output buffer as an immediate target. */
struct net_buffer_t *net_node_schedule(struct net_node_t *node,
	struct net_buffer_t *output_buffer)
{
	struct net_t *net = node->net;
	struct net_routing_table_t *routing_table = net->routing_table;

	struct net_routing_table_entry_t *entry;
	struct net_buffer_t *input_buffer;
	struct net_packet_t * pkt;

	long long cycle;

	int last_input_buffer_index;
	int input_buffer_index;
	int input_buffer_count;
	int i;

	/* Checks */
	assert(output_buffer->node == node);
	assert(list_get(node->output_buffer_list,
			output_buffer->index) == output_buffer);

	/* Get current cycle */
	cycle = esim_domain_cycle(net_domain_index);

	/* If last scheduling decision was done in current cycle, return the
	 * same value. */
	if (output_buffer->sched_when == cycle)
		return output_buffer->sched_buffer;

	/* Make a new decision */
	output_buffer->sched_when = cycle;
	input_buffer_count = list_count(node->input_buffer_list);
	last_input_buffer_index = output_buffer->sched_buffer ?
		output_buffer->sched_buffer->index : 0;

	/* Output buffer must be ready to be written */
	if (output_buffer->write_busy >= cycle)
	{
		output_buffer->sched_buffer = NULL;
		return NULL;
	}

	/* Find input buffer to fetch from */
	for (i = 0; i < input_buffer_count; i++)
	{
		input_buffer_index =
			(last_input_buffer_index + i +
			1) % input_buffer_count;
		input_buffer =
			list_get(node->input_buffer_list, input_buffer_index);

		/* There must be a message at the head */
		pkt = list_get(input_buffer->msg_list, 0);
		if (!pkt)
			continue;

		/* Message must be ready */
		if (pkt->busy >= cycle)
			continue;

		/* Input buffer must be ready to be read */
		if (input_buffer->read_busy >= cycle)
			continue;

		/* Message must target this output buffer */
		entry = net_routing_table_lookup(routing_table, node,
			pkt->msg->dst_node);
		assert(entry->output_buffer);
		if (entry->output_buffer != output_buffer)
			continue;

		/* Message must fit in this output buffer */
		if (output_buffer->count + pkt->size > output_buffer->size)
			continue;

		/* All conditions satisfied - schedule */
		output_buffer->sched_buffer = input_buffer;
		return input_buffer;
	}

	/* No input buffer ready */
	output_buffer->sched_buffer = NULL;
	return NULL;
}
Exemple #6
0
void net_event_handler(int event, void *data)
{
	struct net_stack_t *stack = data;

	struct net_t *net = stack->net;
	struct net_routing_table_t *routing_table = net->routing_table;
	struct net_packet_t *pkt= stack->packet;

	struct net_node_t *src_node = pkt->msg->src_node;
	struct net_node_t *dst_node = pkt->msg->dst_node;

	struct net_node_t *node = pkt->node;
	struct net_buffer_t *buffer = pkt->buffer;

	long long cycle;

	/* Get current cycle */
	cycle = esim_domain_cycle(net_domain_index);

	if ((net_snap_period != 0) &&
	                (net->last_recorded_cycle < (cycle/net_snap_period )))
	        net_bandwidth_snapshot(net, cycle);

	if (event == EV_NET_SEND)
	{
		struct net_routing_table_entry_t *entry;
		struct net_buffer_t *output_buffer;

		if (net->magicNet)
		{
			/* Magic Net work-around */
			src_node->bytes_sent += pkt->size;
			src_node->msgs_sent++;
			dst_node->bytes_received += pkt->size;
			dst_node->msgs_received++;
			pkt->node = dst_node;
			esim_schedule_event(EV_NET_RECEIVE, stack,
				net->fixed_delay);
		}

		/* Get output buffer */
		entry = net_routing_table_lookup(routing_table, src_node,
				dst_node);
		output_buffer = entry->output_buffer;
		if (!output_buffer)
			fatal("%s: no route from %s to %s.\n%s", net->name,
					src_node->name, dst_node->name,
					net_err_no_route);

		if (pkt->msg->size > output_buffer->size)
			panic("%s: message does not fit in buffer.\n%s",
					__FUNCTION__, net_err_can_send);

		if (output_buffer->count + pkt->size > output_buffer->size)
			panic("%s: output buffer full.\n%s", __FUNCTION__,
					net_err_can_send);

		/* Insert in output buffer (1 cycle latency) */
		net_buffer_insert(output_buffer, pkt);
		output_buffer->write_busy = cycle;
		pkt->node = src_node;
		pkt->buffer = output_buffer;
		pkt->busy = cycle;

		/* Schedule next event */
		esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, 1);

	}

	else if (event == EV_NET_OUTPUT_BUFFER)
	{
		struct net_buffer_t *input_buffer;
		int lat;

		/* Debug */
		net_debug("msg "
				"a=\"obuf\" "
				"net=\"%s\" "
				"msg-->pkt=%lld-->%d "
				"node=\"%s\" "
				"buf=\"%s\"\n",
				net->name,
				pkt->msg->id,
				pkt->session_id,
				node->name,
				buffer->name);

		/* If message is not at buffer head, process later */
		assert(list_count(buffer->msg_list));

		if (list_get(buffer->msg_list, 0) != pkt)
		{
			net_buffer_wait(buffer, event, stack);
			net_debug("msg "
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->packet=%lld:%d "
					"why=\"not output buffer head\"\n",
					net->name,
					pkt->msg->id,
					pkt->session_id);
			return;
		}

		if (buffer->read_busy >= cycle)
		{
			esim_schedule_event(event, stack,
					buffer->read_busy - cycle + 1);
			net_debug("msg "
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d "
					"why=\"output buffer busy\" \n",
					net->name,
					pkt->msg->id,
					pkt->session_id);
			return;
		}

		/* If link is busy, wait */
		if (buffer->kind == net_buffer_link)
		{
			struct net_link_t *link;

			assert(buffer->link);
			link = buffer->link;
			if (link->busy >= cycle)
			{
				esim_schedule_event(event, stack,
						link->busy - cycle + 1);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"link busy\"\n",
						net->name,
						pkt->msg->id,
						pkt->session_id);

				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:link_busy\" "
						"stg=\"LB\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);
				return;
			}

			/* If buffer contain the message but doesn't have the 
			 * shared link in control, wait */
			if (link->virtual_channel > 1)
			{
				struct net_buffer_t *temp_buffer;

				temp_buffer = net_link_arbitrator_vc(link, node);
				if (temp_buffer != buffer)
				{
					net_debug("msg "
							"a=\"stall\" "
							"net=\"%s\" "
							"msg-->pkt=%lld:%d "
							"why=\"arbitrator sched\"\n",
							net->name,
							pkt->msg->id,
							pkt->session_id);
					esim_schedule_event(event, stack, 1);

					net_trace("net.packet "
							"net=\"%s\" "
							"name=\"P-%lld:%d\" "
							"state=\"%s:%s:VC_arbitration_fail\" "
							"stg=\"VCA\"\n",
							net->name, pkt->msg->id,
							pkt->session_id,
							node->name,
							buffer->name);
					return;
				}
			}

			/* If destination input buffer is busy, wait */
			assert(buffer == link->src_buffer);
			input_buffer = link->dst_buffer;
			if (input_buffer->write_busy >= cycle)
			{
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"input buffer busy\"\n",
						net->name, pkt->msg->id,
						pkt->session_id);
				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:Dest_buffer_busy\" "
						"stg=\"DBB\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				esim_schedule_event(event, stack,
						input_buffer->write_busy - cycle + 1);
				return;
			}

			/* If destination input buffer is full, wait */
			if (pkt->size > input_buffer->size)
				fatal("%s: packet does not fit in buffer.\n%s",
						net->name, net_err_large_message);
			if (input_buffer->count + pkt->size >
			input_buffer->size)
			{
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"input buffer full\"\n",
						net->name, pkt->msg->id, pkt->session_id);
				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:Dest_buffer_full\" "
						"stg=\"DBF\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				net_buffer_wait(input_buffer, event, stack);
				return;
			}

			/* Calculate latency and occupy resources */
			lat = (pkt->size - 1) / link->bandwidth + 1;
			assert(lat > 0);
			buffer->read_busy = cycle + lat - 1;
			link->busy = cycle + lat - 1;
			input_buffer->write_busy = cycle + lat - 1;

			/* Transfer message to next input buffer */
			assert(pkt->busy < cycle);
			net_buffer_extract(buffer, pkt);
			net_buffer_insert(input_buffer, pkt);
			pkt->node = input_buffer->node;
			pkt->buffer = input_buffer;
			pkt->busy = cycle + lat - 1;

			/* Stats */
			link->busy_cycles += lat;
			link->transferred_bytes += pkt->size;
			link->transferred_msgs++;

			net->topology_util_bw += pkt->size;

			node->bytes_sent += pkt->size;
			node->msgs_sent++;
			input_buffer->node->bytes_received += pkt->size;
			input_buffer->node->msgs_received++;
			net_trace("net.link_transfer net=\"%s\" link=\"%s\" "
					"transB=%lld last_size=%d busy=%lld\n",
					net->name, link->name,
					link->transferred_bytes,
					pkt->size, link->busy);
		}
		else if (buffer->kind == net_buffer_bus)
		{
			struct net_bus_t *bus, *updated_bus;
			struct net_node_t *bus_node;

			assert(!buffer->link);
			assert(buffer->bus);
			bus = buffer->bus;
			bus_node = bus->node;

			/* before initiating bus transfer we have to figure out what is the
			 * next input buffer since it is not clear from the
			 * output buffer */
			int input_buffer_detection = 0;
			struct net_routing_table_entry_t *entry;

			entry = net_routing_table_lookup(routing_table,
					pkt->node, pkt->msg->dst_node);

			for (int i = 0; i < list_count(bus_node->dst_buffer_list); i++)
			{
				input_buffer = list_get(bus_node->dst_buffer_list, i);
				if (entry->next_node == input_buffer->node)
				{
					input_buffer_detection = 1;
					break;
				}
			}
			if (input_buffer_detection == 0)
				fatal("%s: Something went wrong so there is no appropriate input"
						"buffer for the route between %s and %s \n", net->name,
						pkt->node->name,entry->next_node->name);

			/* 1. Check the destination buffer is busy or not */
			if (input_buffer->write_busy >= cycle)
			{
				esim_schedule_event(event, stack,
						input_buffer->write_busy - cycle + 1);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"input busy\"\n",
						net->name,
						pkt->msg->id,
						pkt->session_id);

				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:Dest_buffer_busy\" "
						"stg=\"DBB\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				return;
			}

			/* 2. Check the destination buffer is full or not */
			if (pkt->size > input_buffer->size)
				fatal("%s: packet  does not fit in buffer.\n%s",
						net->name, net_err_large_message);

			if (input_buffer->count + pkt->size > input_buffer->size)
			{
				net_buffer_wait(input_buffer, event, stack);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"input full\"\n",
						net->name, pkt->msg->id,
						pkt->session_id);

				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:Dest_buffer_full\" "
						"stg=\"DBF\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				return;
			}

			/* 3. Make sure if any bus is available; return one
			 * that is available the fastest */
			updated_bus = net_bus_arbitration(bus_node, buffer);
			if (updated_bus == NULL)
			{
				esim_schedule_event(event, stack, 1);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"bus arbiter\"\n",
						net->name, pkt->msg->id,
						pkt->session_id);
				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:BUS_arbit_fail\" "
						"stg=\"BA\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				return;
			}

			/* 4. assign the bus to the buffer. update the
			 * necessary data ; before here, the bus is not
			 * assign to anything and is not updated so it can be 
			 * assign to other buffers as well. If this certain
			 * buffer wins that specific bus_lane the appropriate
			 * fields will be updated. Contains: bus_lane
			 * cin_buffer and cout_buffer and busy time as well as
			 * buffer data itself */
			assert(updated_bus);
			buffer->bus = updated_bus;
			input_buffer->bus = updated_bus;
			bus = buffer->bus;
			assert(bus);


			/* Calculate latency and occupy resources */
			/* Wire delay is introduced when the packet is on transit */
			lat = bus->fix_delay + ((pkt->size - 1) / bus->bandwidth + 1) ;
			assert(lat > 0);
			buffer->read_busy = cycle + lat - 1;
			bus->busy = cycle + lat - 1;
			input_buffer->write_busy = cycle + lat - 1 ;

			/* Transfer message to next input buffer */
			assert(pkt->busy < cycle);
			net_buffer_extract(buffer, pkt);
			net_buffer_insert(input_buffer, pkt);
			pkt->node = input_buffer->node;
			pkt->buffer = input_buffer;
			pkt->busy = cycle + lat - 1;

			/* Stats */
			bus->busy_cycles += lat;
			bus->transferred_bytes += pkt->size;
			bus->transferred_msgs++;

                        net->topology_util_bw += pkt->size;

			node->bytes_sent += pkt->size;
			node->msgs_sent++;
			input_buffer->node->bytes_received += pkt->size;
			input_buffer->node->msgs_received++;
			net_trace("net.bus_transfer net=\"%s\" node=\"%s\" "
					"lane_index=%d transB=%lld last_size=%d busy=%lld\n",
					net->name, bus->node->name, bus->index,
					bus->transferred_bytes, pkt->size, bus->busy);
		}

		else if (buffer->kind == net_buffer_photonic)
		{
			struct net_bus_t *bus, *updated_bus;
			struct net_node_t *bus_node;

			assert(!buffer->link);
			assert(buffer->bus);
			bus = buffer->bus;
			bus_node = bus->node;

			/* before 1 and 2 we have to figure out what is the
			 * next input buffer since it is not clear from the
			 * output buffer */
			int input_buffer_detection = 0;
			struct net_routing_table_entry_t *entry;

			entry = net_routing_table_lookup(routing_table,
					pkt->node, pkt->msg->dst_node);

			for (int i = 0; i < list_count(bus_node->dst_buffer_list); i++)
			{
				input_buffer = list_get(bus_node->dst_buffer_list, i);
				if (entry->next_node == input_buffer->node)
				{
					input_buffer_detection = 1;
					break;
				}
			}
			if (input_buffer_detection == 0)
				fatal("%s: Something went wrong so there is no appropriate input"
						"buffer for the route between %s and %s \n", net->name,
						pkt->node->name,entry->next_node->name);

			/* 1. Check the destination buffer is busy or not */
			if (input_buffer->write_busy > cycle)
			{
				esim_schedule_event(event, stack,
						input_buffer->write_busy - cycle + 1);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"input busy\"\n",
						net->name,
						pkt->msg->id,
						pkt->session_id);

				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:Dest_buffer_busy\" "
						"stg=\"DBB\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				return;
			}

			/* 2. Check the destination buffer is full or not */
			if (pkt->size > input_buffer->size)
				fatal("%s: message does not fit in buffer.\n%s",
						net->name, net_err_large_message);

			if (input_buffer->count + pkt->size > input_buffer->size)
			{
				net_buffer_wait(input_buffer, event, stack);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"input full\"\n",
						net->name, pkt->msg->id,
						pkt->session_id);

				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:Dest_buffer_full\" "
						"stg=\"DBF\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				return;
			}


			/* 3. Make sure if any bus is available; return one
			 * that is available the fastest */
			updated_bus = net_photo_link_arbitration(bus_node, buffer);
			if (updated_bus == NULL)
			{
				esim_schedule_event(event, stack, 1);
				net_debug("msg "
						"a=\"stall\" "
						"net=\"%s\" "
						"msg-->pkt=%lld:%d "
						"why=\"bus arbiter\"\n",
						net->name, pkt->msg->id,
						pkt->session_id);

				net_trace("net.packet "
						"net=\"%s\" "
						"name=\"P-%lld:%d\" "
						"state=\"%s:%s:photonic_arbitration\" "
						"stg=\"BA\"\n",
						net->name, pkt->msg->id,
						pkt->session_id,
						node->name,
						buffer->name);

				return;
			}

			/* 4. assign the bus to the buffer. update the
			 * necessary data ; before here, the bus is not
			 * assign to anything and is not updated so it can be
			 * assign to other buffers as well. If this certain
			 * buffer wins that specific bus_lane the appropriate
			 * fields will be updated. Contains: bus_lane
			 * cin_buffer and cout_buffer and busy time as well as
			 * buffer data itself */
			assert(updated_bus);
			buffer->bus = updated_bus;
			input_buffer->bus = updated_bus;
			bus = buffer->bus;
			assert(bus);

			/* Calculate latency and occupy resources */
			lat = (pkt->size - 1) / bus->bandwidth + 1;
			assert(lat > 0);
			buffer->read_busy = cycle + lat - 1;
			bus->busy = cycle + lat - 1;
			input_buffer->write_busy = cycle + lat - 1;

			/* Transfer message to next input buffer */
			assert(pkt->busy < cycle);
			net_buffer_extract(buffer, pkt);
			net_buffer_insert(input_buffer, pkt);
			pkt->node = input_buffer->node;
			pkt->buffer = input_buffer;
			pkt->busy = cycle + lat - 1;

			/* Stats */
			bus->busy_cycles += lat;
			bus->transferred_bytes += pkt->size;
			bus->transferred_msgs++;

                        net->topology_util_bw += pkt->size;

			node->bytes_sent += pkt->size;
			node->msgs_sent++;
			input_buffer->node->bytes_received += pkt->size;
			input_buffer->node->msgs_received++;
			net_trace("net.photonic_transfer net=\"%s\" node=\"%s\" "
					"lane_index=%d transB=%lld last_size=%d busy=%lld\n",
					net->name, bus->node->name, bus->index,
					bus->transferred_bytes,pkt->size, bus->busy);
			net_debug("msg "
					"a=\"success photonic transmission\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d "
					"through = \" %d\"\n",
					net->name, pkt->msg->id,
					pkt->session_id, updated_bus->index);
		}

		/* Schedule next event */
		esim_schedule_event(EV_NET_INPUT_BUFFER, stack, lat);
	}

	else if (event == EV_NET_INPUT_BUFFER)
	{
		struct net_routing_table_entry_t *entry;
		struct net_buffer_t *output_buffer;

		int lat;

		/* Debug */
		net_debug("msg "
				"a=\"ibuf\" "
				"net=\"%s\" "
				"msg-->pkt=%lld:%d "
				"node=\"%s\" "
				"buf=\"%s\"\n",
				net->name,
				pkt->msg->id,
				pkt->session_id,
				node->name,
				buffer->name);

		/* If message is not at buffer head, process later */
		assert(list_count(buffer->msg_list));
		if (list_get(buffer->msg_list, 0) != pkt)
		{
			net_debug("msg "
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d"
					"why=\"not-head\"\n",
					net->name, pkt->msg->id,
					pkt->session_id);
			net_buffer_wait(buffer, event, stack);
			return;
		}

		/* If this is the destination node, finish */
		if (node == pkt->msg->dst_node)
		{
			esim_schedule_event(EV_NET_RECEIVE, stack, 0);
			return;
		}

		/* If source input buffer is busy, wait */
		if (buffer->read_busy >= cycle)
		{
			net_debug("pkt"
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d "
					"why=\"src-busy\"\n",
					net->name,
					pkt->msg->id,
					pkt->session_id);

			esim_schedule_event(event, stack,
					buffer->read_busy - cycle + 1);
			return;
		}

		/* Get output buffer */
		entry = net_routing_table_lookup(routing_table, node,
				dst_node);
		output_buffer = entry->output_buffer;
		if (!output_buffer)
			fatal("%s: no route from %s to %s.\n%s", net->name,
					node->name, dst_node->name, net_err_no_route);

		/* If destination output buffer is busy, wait */
		if (output_buffer->write_busy >= cycle)
		{
			net_debug("pkt "
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d "
					"why=\"dst-busy\"\n",
					net->name,
					pkt->msg->id,
					pkt->session_id);
			net_trace("net.packet "
					"net=\"%s\" "
					"name=\"P-%lld:%d\" "
					"state=\"%s:%s:Dest_buffer_busy\" "
					"stg=\"DBB\"\n",
					net->name, pkt->msg->id,
					pkt->session_id,
					node->name,
					buffer->name);

			esim_schedule_event(event, stack,
					output_buffer->write_busy - cycle + 1);
			return;
		}

		/* If destination output buffer is full, wait */
		if (pkt->size > output_buffer->size)
			fatal("%s: packet does not fit in buffer.\n%s",
					net->name, net_err_large_message);


		if (output_buffer->count + pkt->size > output_buffer->size)
		{
			net_debug("pkt "
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d "
					"why=\"dst-full\"\n",
					net->name,
					pkt->msg->id,
					pkt->session_id);

			net_trace("net.packet "
					"net=\"%s\" "
					"name=\"P-%lld:%d\" "
					"state=\"%s:%s:Dest_buffer_full\" "
					"stg=\"DBF\"\n",
					net->name, pkt->msg->id,
					pkt->session_id,
					node->name,
					buffer->name);


			net_buffer_wait(output_buffer, event, stack);
			return;
		}

		/* If scheduler says that it is not our turn, try later */
		if (net_node_schedule(node, output_buffer) != buffer)
		{
			net_debug("pkt "
					"a=\"stall\" "
					"net=\"%s\" "
					"msg-->pkt=%lld:%d "
					"why=\"sched\"\n",
					net->name,
					pkt->msg->id,
					pkt->session_id);

			net_trace("net.packet "
					"net=\"%s\" "
					"name=\"P-%lld:%d\" "
					"state=\"%s:%s:switch_arbit_fail\" "
					"stg=\"SA\"\n",
					net->name, pkt->msg->id,
					pkt->session_id,
					node->name,
					buffer->name);

			esim_schedule_event(event, stack, 1);
			return;
		}

		/* Calculate latency and occupy resources */
		assert(node->kind != net_node_end);
		assert(node->bandwidth > 0);
		lat = (pkt->size - 1) / node->bandwidth + 1;
		assert(lat > 0);
		buffer->read_busy = cycle + lat - 1;
		output_buffer->write_busy = cycle + lat - 1;

		/* Transfer message to next output buffer */
		assert(pkt->busy < cycle);
		net_buffer_extract(buffer, pkt);
		net_buffer_insert(output_buffer, pkt);
		pkt->buffer = output_buffer;
		pkt->busy = cycle + lat - 1;

		/* Schedule next event */
		esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, lat);
	}

	else if (event == EV_NET_RECEIVE)
	{
		assert (pkt);
		struct net_msg_t *msg = pkt->msg;
		/* Debug */
		net_debug("pkt "
				"a=\"receive\" "
				"net=\"%s\" "
				"msg-->pkt=%lld:%d "
				"node=\"%s\"\n",
				net->name,
				pkt->msg->id,
				pkt->session_id,
				dst_node->name);

		if (net_depacketizer(net, node, pkt) == 1)
		{
			if (pkt->msg->packet_list_count > 1)
				net_trace("net.msg net=\"%s\" name=\"M-%lld\" "
						"state=\"%s:depacketize\"\n",
						net->name, msg->id, node->name);

			if (stack->ret_event == ESIM_EV_NONE)
			{
				assert (msg);
				net_receive(net, node, msg);

			}
			/* Finish */
			net_stack_return(stack);
		}
		else
			/* Freeing packet stack, not the message */
			free(stack);
	}

	else
	{
		panic("%s: unknown event", __FUNCTION__);
	}
}
Exemple #7
0
/* This algorithm will be recursively called to do the backtracking of DFS algorithm. */
static void routing_table_cycle_detection_dfs_visit(struct net_routing_table_t *routing_table, struct list_t *buffer_list,
	struct list_t *color_list, struct list_t *parent_list, int list_elem, int buffer_count)
{
	int j;

	struct net_t *net = routing_table->net;
	struct net_buffer_t *parent_index;
	struct net_node_t *buffer_color;
	struct net_node_t *node_elem;
	struct net_buffer_t *buffer_elem;

	list_set(color_list, list_elem, NET_NODE_COLOR_GRAY);

	buffer_elem = list_get(buffer_list, list_elem);

	node_elem = buffer_elem->node;

	for (j = 0; j < routing_table->dim && !routing_table->has_cycle; j++)
	{

		struct net_node_t *node_adj;
		struct net_routing_table_entry_t *entry;

		node_adj = list_get(net->node_list, j);
		entry = net_routing_table_lookup(routing_table, node_elem, node_adj);

		if (entry->output_buffer == buffer_elem)
		{

			struct net_routing_table_entry_t *entry_adj;
			entry_adj = net_routing_table_lookup(routing_table, entry->next_node, node_adj);

			for (int i = 0; i < buffer_count; i++)
			{
				struct net_buffer_t *buffer_adj;
				buffer_adj = list_get(buffer_list, i);

				if (buffer_adj == entry_adj->output_buffer)
				{

					buffer_color = list_get(color_list, i);
					if(buffer_color == NET_NODE_COLOR_WHITE)
					{
						list_set(parent_list, i, buffer_elem);
						routing_table_cycle_detection_dfs_visit(routing_table, buffer_list, color_list, parent_list, i, buffer_count);
					}

					buffer_color = list_get(color_list, i);
					parent_index = list_get(parent_list, i);

					if (buffer_color == NET_NODE_COLOR_GRAY  && parent_index != buffer_elem)
					{
						warning("network %s: cycle found in routing table.\n%s",
							net->name, err_net_cycle);
						routing_table->has_cycle = 1;
					}
				}
			}
		}
	}
	list_set(color_list, list_elem, NET_NODE_COLOR_BLACK);
}
Exemple #8
0
void net_routing_table_dump(struct net_routing_table_t *routing_table, FILE *f)
{
	int i, j, k;

	struct net_t *net = routing_table->net;
	struct net_node_t *next_node;

	/* Routing table */
	fprintf(f, "         ");
	for (i = 0; i < net->node_count; i++)
		fprintf(f, "%2d ", i);
	fprintf(f, "\n");
	for (i = 0; i < net->node_count; i++)
	{
		fprintf(f, "node %2d: ", i);
		for (j = 0; j < net->node_count; j++)
		{
			struct net_node_t *node_i;
			struct net_node_t *node_j;
			struct net_routing_table_entry_t *entry_i_j;
			node_i = list_get(net->node_list, i);
			node_j = list_get(net->node_list, j);
			entry_i_j = net_routing_table_lookup(routing_table, node_i, node_j);
			next_node = entry_i_j->next_node;

			if (next_node)
				fprintf(f, "%2d ", next_node->index);
			else
				fprintf(f, "-- ");
		}
		fprintf(f, "\n");
	}
	fprintf(f, "\n");

	/* Node combinations */
	for (i = 0; i < net->node_count; i++)
	{
		for (j = 0; j < net->node_count; j++)
		{
			struct net_node_t *node_i;
			struct net_node_t *node_j;

			node_i = list_get(net->node_list, i);
			node_j = list_get(net->node_list, j);

			fprintf(f, "from %s to %s: ", node_i->name, node_j->name);
			k = i;
			while (k != j)
			{
				struct net_node_t *node_k;
				struct net_routing_table_entry_t *entry_k_j;

				node_k = list_get(net->node_list, k);
				entry_k_j = net_routing_table_lookup(routing_table, node_k, node_j);
				next_node = entry_k_j->next_node;

				if (!next_node)
				{
					fprintf(f, "x ");
					break;
				}
				fprintf(f, "%s ", next_node->name);
				k = next_node->index;
			}
			fprintf(f, "\n");
		}
		fprintf(f, "\n");
	}
}
Exemple #9
0
/* Calculate shortest paths Floyd-Warshall algorithm.*/
void net_routing_table_floyd_warshall(struct net_routing_table_t *routing_table)
{
	int i, j, k ;
	struct net_t *net = routing_table->net;

	struct net_node_t *next_node;
	struct net_buffer_t *buffer;
	struct net_link_t *link;

	struct net_routing_table_entry_t *entry;

	/* The 'routing_table_entry->next_node' values do
	 * not necessarily point to the immediate next hop after this. */
	for (k = 0; k < net->node_count; k++)
	{
		for (i = 0; i < net->node_count; i++)
		{
			for (j = 0; j < net->node_count; j++)
			{
				struct net_node_t *node_i;
				struct net_node_t *node_j;
				struct net_node_t *node_k;

				struct net_routing_table_entry_t *entry_i_k;
				struct net_routing_table_entry_t *entry_k_j;
				struct net_routing_table_entry_t *entry_i_j;

				node_i = list_get(net->node_list, i);
				node_j = list_get(net->node_list, j);
				node_k = list_get(net->node_list, k);

				entry_i_k = net_routing_table_lookup(routing_table, node_i, node_k);
				entry_k_j = net_routing_table_lookup(routing_table, node_k, node_j);
				entry_i_j = net_routing_table_lookup(routing_table, node_i, node_j);

				if (entry_i_k->cost + entry_k_j->cost < entry_i_j->cost)
				{
					entry_i_j->cost = entry_i_k->cost + entry_k_j->cost;
					entry_i_j->next_node = node_k;
				}
			}
		}
	}

	/* Calculate output buffers */
	for (i = 0; i < net->node_count; i++)
	{
		for (j = 0; j < net->node_count; j++)
		{
			struct net_node_t *node_i;
			struct net_node_t *node_j;
			struct net_routing_table_entry_t *entry_i_j;

			node_i = list_get(net->node_list, i);
			
			node_j = list_get(net->node_list, j);
			entry_i_j = net_routing_table_lookup(routing_table, node_i, node_j);
			next_node = entry_i_j->next_node;

			/* No route to node */
			if (!next_node)
			{
				entry_i_j->output_buffer = NULL;
				continue;
			}

			/* Follow path */
			for (;;)
			{
				entry = net_routing_table_lookup(routing_table, node_i, next_node);
				if (entry->cost <= 1)
					break;
				next_node = entry->next_node;
			}

			/* Look for output buffer */
			buffer = NULL;
			assert(list_count(node_i->output_buffer_list));
			for (k = 0; k < list_count(node_i->output_buffer_list); k++)
			{
				buffer = list_get(node_i->output_buffer_list, k);
				link = buffer->link;
				assert(link);
				if (link->dst_node == next_node)
					break;
			}
			assert(k < list_count(node_i->output_buffer_list));
			entry_i_j->output_buffer = buffer;
		}
	}

	/* Update routing table entries to point to the next hop */
	for (i = 0; i < net->node_count; i++)
	{
		for (j = 0; j < net->node_count; j++)
		{
			struct net_node_t *node_i;
			struct net_node_t *node_j;
			struct net_routing_table_entry_t *entry_i_j;

			node_i = list_get(net->node_list, i);
			node_j = list_get(net->node_list, j);
			entry_i_j = net_routing_table_lookup(routing_table, node_i, node_j);

			buffer = entry_i_j->output_buffer;
			if (buffer)
			{
				link = buffer->link;
				assert(link);
				entry_i_j->next_node = link->dst_node;
			}
		}
	}

	/* Find cycle in routing table */
	net_routing_table_cycle_detection(routing_table);
}
/* Updating the entries in the routing table based on the routes existing in
 * configuration file */
void net_routing_table_route_update(struct net_routing_table_t *routing_table,
	struct net_node_t *src_node, struct net_node_t *dst_node,
	struct net_node_t *next_node, int vc_num)
{
	int route_check = 0;

	int k;

	struct net_buffer_t *buffer;
	struct net_link_t *link;
	struct net_bus_t *bus;
	struct net_routing_table_entry_t *entry;

	entry = net_routing_table_lookup(routing_table, src_node, dst_node);
	entry->next_node = next_node;
	entry->output_buffer = NULL;

	/* Look for output buffer */
	buffer = NULL;
	assert(list_count(src_node->output_buffer_list));

	for (k = 0; (k < list_count(src_node->output_buffer_list) && route_check != 1); k++)
	{
		buffer = list_get(src_node->output_buffer_list, k);
		if (buffer->kind == net_buffer_link)
		{
			link = buffer->link;
			assert(link);
			assert(!buffer->bus);

			if ((link->dst_node == next_node))
			{
				if (vc_num == 0)
				{
					entry->output_buffer = buffer;
					route_check = 1;
				}
				else
				{
					if (link->virtual_channel <= vc_num)
						fatal("Network %s: %s.to.%s: wrong virtual channel "
							"number is used in route \n %s",
							routing_table->net->name, src_node->name,
							dst_node->name, net_err_config);

					struct net_buffer_t *vc_buffer;

					vc_buffer = list_get(src_node->output_buffer_list, (buffer->index)+vc_num);
					assert(vc_buffer->link == buffer->link);
					entry->output_buffer = vc_buffer;
					route_check = 1;
				}
			}
		}
		else if (buffer->kind == net_buffer_bus || buffer->kind == net_buffer_photonic)
		{
			assert(!buffer->link);
			bus = buffer->bus;
			assert(bus);

			struct net_node_t * bus_node;
			bus_node = bus->node;

			for (int i = 0; i < list_count(bus_node->dst_buffer_list); i++)
			{
				struct net_buffer_t *dst_buffer;
				dst_buffer = list_get(bus_node->dst_buffer_list, i);

				if (dst_buffer->node == next_node)
				{
					entry->output_buffer = buffer;
					route_check = 1;
					break;
				}
			}

			if (vc_num != 0)
				fatal("Network %s: %s.to.%s: BUS does not contain virtual channel \n %s",
						routing_table->net->name, src_node->name,
						dst_node->name, net_err_config);


		}
	}
	/*If there is not a route between the source node and next node , error */
	if (route_check == 0) fatal("Network %s : route %s.to.%s = %s : Missing connection \n%s ",
			routing_table->net->name, src_node->name, dst_node->name,
			next_node->name, net_err_route_step);

	/* Find cycle in routing table */
	net_routing_table_cycle_detection(routing_table);
}
void net_routing_table_dump(struct net_routing_table_t *routing_table, FILE *f)
{
	int i, j;

	struct net_t *net = routing_table->net;
	struct net_node_t *next_node;
	struct net_node_t *node_l;
	/* Routing table */
	fprintf(f, "         ");
	for (i = 0; i < net->node_count; i++)
	{
		node_l = list_get(net->node_list, i);
		fprintf(f, "\t%s \t\t", node_l->name);
	}

	fprintf(f, "\n");
	for (i = 0; i < net->node_count; i++)
	{
		node_l = list_get(net->node_list, i);
		fprintf(f, "%s\t\t", node_l->name);
		for (j = 0; j < net->node_count; j++)
		{
			struct net_node_t *node_i;
			struct net_node_t *node_j;
			struct net_routing_table_entry_t *entry_i_j;
			struct net_buffer_t *buffer;
			node_i = list_get(net->node_list, i);
			node_j = list_get(net->node_list, j);
			entry_i_j = net_routing_table_lookup(routing_table, node_i, node_j);
			next_node = entry_i_j->next_node;
			buffer = entry_i_j->output_buffer;

			if (next_node)
			{
				fprintf(f, "%s:\t", next_node->name);
				if (buffer)
				{
					fprintf(f,"%s   \t", buffer->name);
				}
				else
					fprintf(f,"-------- \t");
			}
			else
				fprintf(f, "--\t\t\t");
		}
		fprintf(f, "\n");

	}
	fprintf(f, "\n");

	/* Node combinations */
	/*
	int k;
	for (i = 0; i < net->node_count; i++)
	{
		for (j = 0; j < net->node_count; j++)
		{
			struct net_node_t *node_i;
			struct net_node_t *node_j;

			node_i = list_get(net->node_list, i);
			node_j = list_get(net->node_list, j);

			fprintf(f, "from %s to %s: ", node_i->name, node_j->name);
			k = i;
			while (k != j)
			{
				struct net_node_t *node_k;
				struct net_routing_table_entry_t *entry_k_j;

				node_k = list_get(net->node_list, k);
				entry_k_j = net_routing_table_lookup(routing_table, node_k, node_j);
				next_node = entry_k_j->next_node;

				if (!next_node)
				{
					fprintf(f, "x ");
					break;
				}
				fprintf(f, "%s ", next_node->name);
				k = next_node->index;
			}
			fprintf(f, "\n");
		}
		fprintf(f, "\n");
	}
	 */
}
/* Create contents of routing table */
void net_routing_table_initiate(struct net_routing_table_t *routing_table)
{
	struct net_t *net = routing_table->net;
	int i, j;
	struct net_node_t *src_node, *dst_node;
	struct net_buffer_t *buffer;
	struct net_routing_table_entry_t *entry;

	/* Allocate routing table entries */
	if (routing_table->entries)
		panic("%s: network \"%s\": routing table already allocated",
			__FUNCTION__, net->name);
	routing_table->dim = list_count(net->node_list);
	routing_table->entries =
		xcalloc(routing_table->dim * routing_table->dim,
		sizeof(struct net_routing_table_entry_t));

	/* Initialize table with infinite costs */
	for (i = 0; i < net->node_count; i++)
	{
		for (j = 0; j < net->node_count; j++)
		{
			src_node = list_get(net->node_list, i);
			dst_node = list_get(net->node_list, j);
			entry = net_routing_table_lookup(routing_table,
				src_node, dst_node);
			entry->cost = i == j ? 0 : routing_table->dim;  /* Infinity or 0 */
			entry->next_node = NULL;
			entry->output_buffer = NULL;
		}
	}

	/* Set 1-hop connections */
	for (i = 0; i < net->node_count; i++)
	{
		src_node = list_get(net->node_list, i);
		for (j = 0; j < list_count(src_node->output_buffer_list); j++)
		{
			buffer = list_get(src_node->output_buffer_list, j);
			/* For each buffer of each node we check to see if it 
			 * is connected to a link or a BUS. If it is
			 * connected to the link we update the table by
			 * getting the destination node of the Link */
			if (buffer->kind == net_buffer_link)
			{
				struct net_link_t *link;

				assert(!buffer->bus);
				link = buffer->link;
				assert(link);
				entry = net_routing_table_lookup
					(routing_table, src_node,
					link->dst_node);
				entry->cost = 1;
				entry->next_node = link->dst_node;
				entry->output_buffer = buffer;
			}

			/* If it is connected to a BUS we create a connection 
			 * between this node and all the nodes that are
			 * connected to the BUS */
			else if (buffer->kind == net_buffer_bus || buffer->kind == net_buffer_photonic)
			{
				int k;

				struct net_node_t *bus_node;
				struct net_bus_t *bus;

				assert(!buffer->link);
				assert(buffer->bus);
				bus = buffer->bus;
				bus_node = bus->node;
				for (k = 0; k < list_count(bus_node->dst_buffer_list); k++)
				{
					struct net_buffer_t *dst_buffer;
					dst_buffer = list_get(bus_node->dst_buffer_list, k);
					if (src_node != dst_buffer->node)
					{
						entry = net_routing_table_lookup(routing_table, src_node, dst_buffer->node);
						entry->cost = 1;
						entry->next_node = dst_buffer->node;
						entry->output_buffer = buffer;
					}
					/*For BUS. Even though we never get to BUS in the routing table (no routes path
					 * through BUS node. They all pass through BUS node's buffer) we still provide a
					 * Path from BUS nodes to all the nodes. There is no path from nodes that ends in
					 * BUS. Next buffer is still NULL*/
					entry = net_routing_table_lookup(routing_table, bus_node, dst_buffer->node);
					entry->cost = 1;
					entry->next_node = dst_buffer->node;

				}
			}
		}
	}
}
Exemple #13
0
void net_event_handler(int event, void *data)
{
	struct net_stack_t *stack = data;
	struct net_t *net = stack->net;
	struct net_routing_table_t *routing_table = net->routing_table;
	struct net_msg_t *msg = stack->msg;

	struct net_node_t *src_node = msg->src_node;
	struct net_node_t *dst_node = msg->dst_node;

	struct net_node_t *node = msg->node;
	struct net_buffer_t *buffer = msg->buffer;

	if (event == EV_NET_SEND)
	{
		struct net_routing_table_entry_t *entry;
		struct net_buffer_t *output_buffer;

		/* Debug */
		net_debug("msg "
			"a=\"send\" "
			"net=\"%s\" "
			"msg=%lld "
			"size=%d "
			"src=\"%s\" "
			"dst=\"%s\"\n",
			net->name,
			msg->id,
			msg->size,
			src_node->name,
			dst_node->name);

		/* Get output buffer */
		entry = net_routing_table_lookup(routing_table, src_node, dst_node);
		output_buffer = entry->output_buffer;
		if (!output_buffer)
			fatal("%s: no route from %s to %s.\n%s", net->name, src_node->name,
				dst_node->name, net_err_no_route);
		if (output_buffer->write_busy >= esim_cycle)
			panic("%s: output buffer busy.\n%s", __FUNCTION__, net_err_can_send);
		if (msg->size > output_buffer->size)
			panic("%s: message does not fit in buffer.\n%s", __FUNCTION__, net_err_can_send);
		if (output_buffer->count + msg->size > output_buffer->size)
			panic("%s: output buffer full.\n%s", __FUNCTION__, net_err_can_send);

		/* Insert in output buffer (1 cycle latency) */
		net_buffer_insert(output_buffer, msg);
		output_buffer->write_busy = esim_cycle;
		msg->node = src_node;
		msg->buffer = output_buffer;
		msg->busy = esim_cycle;

		/* Schedule next event */
		esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, 1);
	}

	else if (event == EV_NET_OUTPUT_BUFFER)
	{
		struct net_link_t *link;
		struct net_buffer_t *input_buffer;
		int lat;

		/* Debug */
		net_debug("msg "
			"a=\"obuf\" "
			"net=\"%s\" "
			"msg=%lld "
			"node=\"%s\" "
			"buf=\"%s\"\n",
			net->name,
			msg->id,
			node->name,
			buffer->name);

		/* If message is not at buffer head, process later */
		assert(list_count(buffer->msg_list));
		if (list_get(buffer->msg_list, 0) != msg)
		{
			net_buffer_wait(buffer, event, stack);
			return;
		}

		/* If source output buffer is busy, wait */
		if (buffer->read_busy >= esim_cycle)
		{
			esim_schedule_event(event, stack, buffer->read_busy - esim_cycle + 1);
			return;
		}
		
		/* If link is busy, wait */
		link = buffer->link;
		if (link->busy >= esim_cycle)
		{
			esim_schedule_event(event, stack, link->busy - esim_cycle + 1);
			return;
		}

		/* If buffer contain the message but doesn't have the shared link in control, wait*/
		if (link->virtual_channel > 1)
		{
			struct net_buffer_t *temp_buffer;
			temp_buffer = net_link_arbitrator_vc(link, node);
			if (temp_buffer != buffer)
			{
				net_debug("msg "
					"a=\"arbitrator stall\" "
					"net=\"%s\" "
					"msg=%lld "
					"why=\"sched\"\n",
					net->name,
					msg->id);
				esim_schedule_event(event, stack, 1);
				return;
			}
		}

		/* If destination input buffer is busy, wait */
		assert(buffer == link->src_buffer);
		input_buffer = link->dst_buffer;
		if (input_buffer->write_busy >= esim_cycle)
		{
			esim_schedule_event(event, stack, input_buffer->write_busy - esim_cycle + 1);
			return;
		}

		/* If destination input buffer is full, wait */
		if (msg->size > input_buffer->size)
			fatal("%s: message does not fit in buffer.\n%s",
				net->name, net_err_large_message);
		if (input_buffer->count + msg->size > input_buffer->size)
		{
			net_buffer_wait(input_buffer, event, stack);
			return;
		}

		/* Calculate latency and occupy resources */
		lat = (msg->size - 1) / link->bandwidth + 1;
		assert(lat > 0);
		buffer->read_busy = esim_cycle + lat - 1;
		link->busy = esim_cycle + lat - 1;
		input_buffer->write_busy = esim_cycle + lat - 1;

		/* Transfer message to next input buffer */
		assert(msg->busy < esim_cycle);
		net_buffer_extract(buffer, msg);
		net_buffer_insert(input_buffer, msg);
		msg->node = input_buffer->node;
		msg->buffer = input_buffer;
		msg->busy = esim_cycle + lat - 1;

		/* Stats */
		link->busy_cycles += lat;
		link->transferred_bytes += msg->size;
		link->transferred_msgs++;
		node->bytes_sent += msg->size;
		node->msgs_sent++;
		input_buffer->node->bytes_received += msg->size;
		input_buffer->node->msgs_received++;

		/* Schedule next event */
		esim_schedule_event(EV_NET_INPUT_BUFFER, stack, lat);
	}

	else if (event == EV_NET_INPUT_BUFFER)
	{
		struct net_routing_table_entry_t *entry;
		struct net_buffer_t *output_buffer;
		int lat;

		/* Debug */
		net_debug("msg "
			"a=\"ibuf\" "
			"net=\"%s\" "
			"msg=%lld "
			"node=\"%s\" "
			"buf=\"%s\"\n",
			net->name,
			msg->id,
			node->name,
			buffer->name);

		/* If message is not at buffer head, process later */
		assert(list_count(buffer->msg_list));
		if (list_get(buffer->msg_list, 0) != msg)
		{
			net_debug("msg "
				"a=\"stall\" "
				"net=\"%s\" "
				"msg=%lld "
				"why=\"not-head\"\n",
				net->name,
				msg->id);
			net_buffer_wait(buffer, event, stack);
			return;
		}
		
		/* If this is the destination node, finish */
		if (node == msg->dst_node)
		{
			esim_schedule_event(EV_NET_RECEIVE, stack, 0);
			return;
		}
		
		/* If source input buffer is busy, wait */
		if (buffer->read_busy >= esim_cycle)
		{
			net_debug("msg "
				"a=\"stall\" "
				"net=\"%s\" "
				"msg=%lld "
				"why=\"src-busy\"\n",
				net->name,
				msg->id);
			esim_schedule_event(event, stack, buffer->read_busy - esim_cycle + 1);
			return;
		}
		
		/* Get output buffer */
		entry = net_routing_table_lookup(routing_table, node, dst_node);
		output_buffer = entry->output_buffer;
		if (!output_buffer)
			fatal("%s: no route from %s to %s.\n%s", net->name,
				node->name, dst_node->name, net_err_no_route);
		
		/* If destination output buffer is busy, wait */
		if (output_buffer->write_busy >= esim_cycle)
		{
			net_debug("msg "
				"a=\"stall\" "
				"net=\"%s\" "
				"msg=%lld "
				"why=\"dst-busy\"\n",
				net->name,
				msg->id);
			esim_schedule_event(event, stack, output_buffer->write_busy - esim_cycle + 1);
			return;
		}

		/* If destination output buffer is full, wait */
		if (msg->size > output_buffer->size)
			fatal("%s: message does not fit in buffer.\n%s",
				net->name, net_err_large_message);
		if (output_buffer->count + msg->size > output_buffer->size)
		{
			net_debug("msg "
				"a=\"stall\" "
				"net=\"%s\" "
				"msg=%lld "
				"why=\"dst-full\"\n",
				net->name,
				msg->id);
			net_buffer_wait(output_buffer, event, stack);
			return;
		}

		/* If scheduler says that it is not our turn, try later */
		if (net_node_schedule(node, output_buffer) != buffer)
		{
			net_debug("msg "
				"a=\"stall\" "
				"net=\"%s\" "
				"msg=%lld "
				"why=\"sched\"\n",
				net->name,
				msg->id);
			esim_schedule_event(event, stack, 1);
			return;
		}

		/* Calculate latency and occupy resources */
		assert(node->kind != net_node_end);
		assert(node->bandwidth > 0);
		lat = (msg->size - 1) / node->bandwidth + 1;
		assert(lat > 0);
		buffer->read_busy = esim_cycle + lat - 1;
		output_buffer->write_busy = esim_cycle + lat - 1;

		/* Transfer message to next output buffer */
		assert(msg->busy < esim_cycle);
		net_buffer_extract(buffer, msg);
		net_buffer_insert(output_buffer, msg);
		msg->buffer = output_buffer;
		msg->busy = esim_cycle + lat - 1;

		/* Schedule next event */
		esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, lat);
	}

	else if (event == EV_NET_RECEIVE)
	{
		/* Debug */
		net_debug("msg "
			"a=\"receive\" "
			"net=\"%s\" "
			"msg=%lld "
			"node=\"%s\"\n",
			net->name,
			msg->id,
			dst_node->name);

		/* Stats */
		net->transfers++;
		net->lat_acc += esim_cycle - msg->send_cycle;
		net->msg_size_acc += msg->size;

		/* If not return event was specified, free message here */
		if (stack->ret_event == ESIM_EV_NONE)
			net_receive(net, node, msg);

		/* Finish */
		net_stack_return(stack);
	}

	else
	{
		panic("%s: unknown event", __FUNCTION__);
	}
}