Beispiel #1
0
void connectnetwork_run(ConnectNetworkAction* action) {
    MAGIC_ASSERT(action);

    internetwork_connectNetworks(worker_getInternet(),
                                 action->sourceClusterID, action->destinationClusterID,
                                 action->latency, action->jitter, action->packetloss,
                                 action->latencymin, action->latencyQ1, action->latencymean,
                                 action->latencyQ3, action->latencymax);

}
Beispiel #2
0
void worker_scheduleEvent(Event* event, SimulationTime nano_delay, GQuark receiver_node_id) {
	/* TODO create accessors, or better yet refactor the work to event class */
	MAGIC_ASSERT(event);
	MAGIC_ASSERT((&(event->super)));

	/* get our thread-private worker */
	Worker* worker = worker_getPrivate();
	Engine* engine = worker->cached_engine;

	/* when the event will execute */
	event->time = worker->clock_now + nano_delay;

	/* parties involved. sender may be NULL, receiver may not! */
	Node* sender = worker->cached_node;

	/* we MAY NOT OWN the receiver, so do not write to it! */
	Node* receiver = receiver_node_id == 0 ? sender : internetwork_getNode(worker_getInternet(), receiver_node_id);
	g_assert(receiver);

	/* the NodeEvent needs a pointer to the correct node */
	event->node = receiver;

	/* if we are not going to execute any more events, free it and return */
	if(engine_isKilled(engine)) {
		shadowevent_free(event);
		return;
	}

	/* engine is not killed, assert accurate worker clock */
	g_assert(worker->clock_now != SIMTIME_INVALID);

	/* non-local events must be properly delayed */
	SimulationTime jump = engine_getMinTimeJump(engine);
	if(!node_isEqual(receiver, sender)) {
		SimulationTime minTime = worker->clock_now + jump;

		/* warn and adjust time if needed */
		if(event->time < minTime) {
			debug("Inter-node event time %lu changed to %lu due to minimum delay %lu",
					event->time, minTime, jump);
			event->time = minTime;
		}
	}

	/* figure out where to push the event */
	if(engine_getNumThreads(engine) > 1) {
		/* multi-threaded, push event to receiver node */
		EventQueue* eventq = node_getEvents(receiver);
		eventqueue_push(eventq, event);
	} else {
		/* single-threaded, push to master queue */
		engine_pushEvent(engine, (Event*)event);
	}
}
Beispiel #3
0
int system_getnameinfo(const struct sockaddr *sa, socklen_t salen,
		char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
	/* FIXME this is not fully implemented */
	if(!sa) {
		return EAI_FAIL;
	}

	gint retval = 0;
	Node* node = _system_switchInShadowContext();

	GQuark convertedIP = (GQuark) (((struct sockaddr_in*)sa)->sin_addr.s_addr);
	const gchar* hostname = internetwork_resolveID(worker_getInternet(), convertedIP);

	if(hostname) {
		g_utf8_strncpy(host, hostname, hostlen);
	} else {
		retval = EAI_NONAME;
	}

	_system_switchOutShadowContext(node);
	return retval;
}
Beispiel #4
0
void createnetwork_run(CreateNetworkAction* action) {
	MAGIC_ASSERT(action);

	internetwork_createNetwork(worker_getInternet(), action->id,
			action->bandwidthdown, action->bandwidthup, action->packetloss);
}
Beispiel #5
0
gint system_getAddrInfo(gchar *name, const gchar *service,
		const struct addrinfo *hgints, struct addrinfo **res) {
	Node* node = _system_switchInShadowContext();

	gint result = 0;

	*res = NULL;
	if(name != NULL && node != NULL) {

		/* node may be a number-and-dots address, or a hostname. lets hope for hostname
		 * and try that first, o/w convert to the in_addr_t and do a second lookup. */
		in_addr_t address = (in_addr_t) internetwork_resolveName(worker_getInternet(), name);

		if(address == 0) {
			/* name was not in hostname format. convert to IP format and try again */
			struct in_addr inaddr;
			gint r = inet_pton(AF_INET, name, &inaddr);

			if(r == 1) {
				/* successful conversion to IP format, now find the real hostname */
				GQuark convertedIP = (GQuark) inaddr.s_addr;
				const gchar* hostname = internetwork_resolveID(worker_getInternet(), convertedIP);

				if(hostname != NULL) {
					/* got it, so convertedIP is a valid IP */
					address = (in_addr_t) convertedIP;
				} else {
					/* name not mapped by resolver... */
					result = EAI_FAIL;
					goto done;
				}
			} else if(r == 0) {
				/* not in correct form... hmmm, too bad i guess */
				result = EAI_NONAME;
				goto done;
			} else {
				/* error occured */
				result = EAI_SYSTEM;
				goto done;
			}
		}

		/* should have address now */
		struct sockaddr_in* sa = g_malloc(sizeof(struct sockaddr_in));
		/* application will expect it in network order */
		// sa->sin_addr.s_addr = (in_addr_t) htonl((guint32)(*addr));
		sa->sin_addr.s_addr = address;
		sa->sin_family = AF_INET; /* libcurl expects this to be set */

		struct addrinfo* ai_out = g_malloc(sizeof(struct addrinfo));
		ai_out->ai_addr = (struct sockaddr*) sa;
		ai_out->ai_addrlen =  sizeof(struct sockaddr_in);
		ai_out->ai_canonname = NULL;
		ai_out->ai_family = AF_INET;
		ai_out->ai_flags = 0;
		ai_out->ai_next = NULL;
		ai_out->ai_protocol = 0;
		ai_out->ai_socktype = SOCK_STREAM;

		*res = ai_out;
		result = 0;
		goto done;
	}

	errno = EINVAL;
	result = EAI_SYSTEM;

	done:
	_system_switchOutShadowContext(node);
	return result;
}
Beispiel #6
0
static void _tcp_autotune(TCP* tcp) {
	MAGIC_ASSERT(tcp);

	if(!CONFIG_TCPAUTOTUNE) {
		return;
	}

	/* our buffers need to be large enough to send and receive
	 * a full delay*bandwidth worth of bytes to keep the pipe full.
	 * but not too large that we'll just buffer everything. autotuning
	 * is meant to tune it to an optimal rate. estimate that by taking
	 * the 80th percentile.
	 */
	Internetwork* internet = worker_getInternet();

	GQuark sourceID = (GQuark) tcp_getIP(tcp);
	GQuark destinationID = (GQuark) tcp_getPeerIP(tcp);

	if(sourceID == destinationID) {
		/* 16 MiB as max */
		g_assert(16777216 > tcp->super.inputBufferSize);
		g_assert(16777216 > tcp->super.outputBufferSize);
		tcp->super.inputBufferSize = 16777216;
		tcp->super.outputBufferSize = 16777216;
		debug("set loopback buffer sizes to 16777216");
		return;
	}

	/* get latency in milliseconds */
	guint32 send_latency = (guint32) internetwork_getLatency(internet, sourceID, destinationID, 0.8);
	guint32 receive_latency = (guint32) internetwork_getLatency(internet, destinationID, sourceID, 0.8);
	g_assert(send_latency > 0 && receive_latency > 0);

	guint32 rtt_milliseconds = send_latency + receive_latency;

	/* i got delay, now i need values for my send and receive buffer
	 * sizes based on bandwidth in both directions. do my send size first. */
	guint32 my_send_bw = internetwork_getNodeBandwidthUp(internet, sourceID);
	guint32 their_receive_bw = internetwork_getNodeBandwidthDown(internet, destinationID);

	/* KiBps is the same as Bpms, which works with our RTT calculation. */
	guint32 send_bottleneck_bw = my_send_bw < their_receive_bw ? my_send_bw : their_receive_bw;

	/* the delay bandwidth product is how many bytes I can send at once to keep the pipe full */
	guint64 sendbuf_size = (guint64) (rtt_milliseconds * send_bottleneck_bw * 1.25f);

	/* now the same thing for my receive buf */
	guint32 my_receive_bw = internetwork_getNodeBandwidthDown(internet, sourceID);
	guint32 their_send_bw = internetwork_getNodeBandwidthUp(internet, destinationID);

	/* KiBps is the same as Bpms, which works with our RTT calculation. */
	guint32 receive_bottleneck_bw = my_receive_bw < their_send_bw ? my_receive_bw : their_send_bw;

	/* the delay bandwidth product is how many bytes I can receive at once to keep the pipe full */
	guint64 receivebuf_size = (guint64) (rtt_milliseconds * receive_bottleneck_bw * 1.25);

    /* keep minimum buffer size bounds */
    if(sendbuf_size < CONFIG_SEND_BUFFER_MIN_SIZE) {
    	sendbuf_size = CONFIG_SEND_BUFFER_MIN_SIZE;
    }
    if(receivebuf_size < CONFIG_RECV_BUFFER_MIN_SIZE) {
        receivebuf_size = CONFIG_RECV_BUFFER_MIN_SIZE;
    }

	/* make sure the user hasnt already written to the buffer, because if we
	 * shrink it, our buffer math would overflow the size variable
	 */
	g_assert(tcp->super.inputBufferLength == 0);
	g_assert(tcp->super.outputBufferLength == 0);

	/* its ok to change buffer sizes since the user hasn't written anything yet */
	tcp->super.inputBufferSize = receivebuf_size;
	tcp->super.outputBufferSize = sendbuf_size;

	debug("set network buffer sizes: send %lu receive %lu", sendbuf_size, receivebuf_size);
}