void cubic_congestionAvoidance(Cubic* cubic, gint inFlight, gint packetsAcked, gint ack) { MAGIC_ASSERT(cubic); TCPCongestion* congestion = (TCPCongestion*)cubic; gint32 now = worker_getCurrentTime() / SIMTIME_ONE_MILLISECOND; if(now - cubic->hystart.lastReset >= congestion->rttSmoothed) { _cubic_hystartReset(cubic, inFlight); } _cubic_hystartUpdate(cubic); if(congestion->window <= congestion->threshold) { congestion->state = TCP_CCS_SLOWSTART; congestion->window++; } else { congestion->state = TCP_CCS_AVOIDANCE; _cubic_update(cubic); if(cubic->windowCount > cubic->count) { congestion->window += 1; cubic->windowCount = 0; } else { cubic->windowCount += 1; } } }
static void _cubic_hystartReset(Cubic* cubic, gint ack) { MAGIC_ASSERT(cubic); TCPCongestion* congestion = (TCPCongestion*)cubic; SimulationTime now = worker_getCurrentTime() / SIMTIME_ONE_MILLISECOND; cubic->hystart.roundStart = now; cubic->hystart.lastReset = now; cubic->hystart.lastTime = now; cubic->hystart.lastRTT = congestion->rttSmoothed; cubic->hystart.currRTT = 0; cubic->hystart.samplingCount = cubic->hystart.nSampling; cubic->hystart.endSequence = ack; }
void tracker_heartbeat(Tracker* tracker) { MAGIC_ASSERT(tracker); TrackerFlags flags = _tracker_getFlags(tracker); GLogLevelFlags level = _tracker_getLogLevel(tracker); SimulationTime interval = _tracker_getLogInterval(tracker); /* check to see if node info is being logged */ if(flags & TRACKER_FLAGS_NODE) { _tracker_logNode(tracker, level, interval); } /* check to see if socket buffer info is being logged */ if(flags & TRACKER_FLAGS_SOCKET) { _tracker_logSocket(tracker, level, interval); } /* check to see if ram info is being logged */ if(flags & TRACKER_FLAGS_RAM) { _tracker_logRAM(tracker, level, interval); } /* make sure we have the latest global configured flags */ tracker->globalFlags = _tracker_parseGlobalFlags(); /* clear interval stats */ tracker->processingTimeLastInterval = 0; tracker->delayTimeLastInterval = 0; tracker->numDelayedLastInterval = 0; tracker->allocatedBytesLastInterval = 0; tracker->deallocatedBytesLastInterval = 0; /* clear the counters */ memset(&tracker->local, 0, sizeof(IFaceCounters)); memset(&tracker->remote, 0, sizeof(IFaceCounters)); SocketStats* ss = NULL; GHashTableIter socketIterator; g_hash_table_iter_init(&socketIterator, tracker->socketStats); while (g_hash_table_iter_next(&socketIterator, NULL, (gpointer*)&ss)) { if(ss) { memset(&ss->local, 0, sizeof(IFaceCounters)); memset(&ss->remote, 0, sizeof(IFaceCounters)); } } /* schedule the next heartbeat */ tracker->lastHeartbeat = worker_getCurrentTime(); HeartbeatEvent* heartbeat = heartbeat_new(tracker); worker_scheduleEvent((Event*)heartbeat, interval, 0); }
static void _cubic_hystartUpdate(Cubic* cubic) { MAGIC_ASSERT(cubic); TCPCongestion* congestion = (TCPCongestion*)cubic; SimulationTime now = worker_getCurrentTime() / SIMTIME_ONE_MILLISECOND; gint rtt = congestion->rttSmoothed; if(!rtt) { rtt = 100; } gint delayMin = MIN(cubic->hystart.delayMin, rtt); if(!cubic->hystart.delayMin) { delayMin = rtt; cubic->hystart.delayMin = delayMin; } if(!cubic->hystart.found && congestion->window <= congestion->threshold) { if(now - cubic->hystart.lastTime <= 2) { cubic->hystart.lastTime = now; if(now - cubic->hystart.roundStart >= delayMin / 2) { cubic->hystart.found = 1; } } if(cubic->hystart.samplingCount) { cubic->hystart.currRTT = MIN(cubic->hystart.currRTT, rtt); if(!cubic->hystart.currRTT) { cubic->hystart.currRTT = rtt; } cubic->hystart.samplingCount--; } gint n = MAX(2, ceil(cubic->hystart.lastRTT / 16.0)); if(!cubic->hystart.samplingCount && cubic->hystart.currRTT >= cubic->hystart.lastRTT + n) { cubic->hystart.found = 2; } if(cubic->hystart.found && congestion->window >= cubic->hystart.lowThreshold) { congestion->threshold = congestion->window; } } }
void networkinterface_sent(NetworkInterface* interface) { MAGIC_ASSERT(interface); /* we just finished sending some packets */ interface->flags &= ~NIF_SENDING; /* decide how much delay we get to absorb based on the passed time */ SimulationTime now = worker_getCurrentTime(); SimulationTime absorbInterval = now - interface->lastTimeSent; if(absorbInterval > 0) { gdouble newConsumed = interface->sendNanosecondsConsumed - absorbInterval; interface->sendNanosecondsConsumed = MAX(0, newConsumed); } interface->lastTimeSent = now; /* now try to send the next ones */ _networkinterface_scheduleNextSend(interface); }
void networkinterface_received(NetworkInterface* interface) { MAGIC_ASSERT(interface); /* we just finished receiving some packets */ interface->flags &= ~NIF_RECEIVING; /* decide how much delay we get to absorb based on the passed time */ SimulationTime now = worker_getCurrentTime(); SimulationTime absorbInterval = now - interface->lastTimeReceived; if(absorbInterval > 0) { /* decide how much delay we get to absorb based on the passed time */ gdouble newConsumed = interface->receiveNanosecondsConsumed - absorbInterval; interface->receiveNanosecondsConsumed = MAX(0, newConsumed); } interface->lastTimeReceived = now; /* now try to receive the next ones */ _networkinterface_scheduleNextReceive(interface); }
void pcapwriter_writePacket(PCapWriter* pcap, Packet* packet) { if(!pcap || !pcap->pcapFile || !packet) { return; } guint32 ts_sec; /* timestamp seconds */ guint32 ts_usec; /* timestamp microseconds */ guint32 incl_len; /* number of octets of packet saved in file */ guint32 orig_len; /* actual length of packet */ /* get the current time that the packet is being sent/received */ SimulationTime now = worker_getCurrentTime(); ts_sec = now / SIMTIME_ONE_SECOND; ts_usec = (now % SIMTIME_ONE_SECOND) / SIMTIME_ONE_MICROSECOND; /* get the header and payload lengths */ guint headerSize = packet_getHeaderSize(packet); guint payloadLength = packet_getPayloadLength(packet); incl_len = headerSize + payloadLength; orig_len = headerSize + payloadLength; /* get the TCP header and the payload */ PacketTCPHeader tcpHeader; guchar *payload = g_new0(guchar, payloadLength); packet_getTCPHeader(packet, &tcpHeader); packet_copyPayload(packet, 0, payload, payloadLength); /* write the PCAP packet header to the pcap file */ fwrite(&ts_sec, sizeof(ts_sec), 1, pcap->pcapFile); fwrite(&ts_usec, sizeof(ts_usec), 1, pcap->pcapFile); fwrite(&incl_len, sizeof(incl_len), 1, pcap->pcapFile); fwrite(&orig_len, sizeof(orig_len), 1, pcap->pcapFile); /* write the ethernet header */ guint8 destinationMAC[6] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}; guint8 sourceMAC[6] = {0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6}; guint16 type = htons(0x0800); fwrite(destinationMAC, 1, sizeof(destinationMAC), pcap->pcapFile); fwrite(sourceMAC, 1, sizeof(sourceMAC), pcap->pcapFile); fwrite(&type, 1, sizeof(type), pcap->pcapFile); /* write the IP header */ guint8 versionAndHeaderLength = 0x45; guint8 fields = 0x00; guint16 totalLength = htons(orig_len - 14); guint16 identification = 0x0000; guint16 flagsAndFragment = 0x0040; guint8 timeToLive = 64; guint8 protocol = 6; /* TCP */ guint16 headerChecksum = 0x0000; guint32 sourceIP = tcpHeader.sourceIP; guint32 destinationIP = tcpHeader.destinationIP; fwrite(&versionAndHeaderLength, 1, sizeof(versionAndHeaderLength), pcap->pcapFile); fwrite(&fields, 1, sizeof(fields), pcap->pcapFile); fwrite(&totalLength, 1, sizeof(totalLength), pcap->pcapFile); fwrite(&identification, 1, sizeof(identification), pcap->pcapFile); fwrite(&flagsAndFragment, 1, sizeof(flagsAndFragment), pcap->pcapFile); fwrite(&timeToLive, 1, sizeof(timeToLive), pcap->pcapFile); fwrite(&protocol, 1, sizeof(protocol), pcap->pcapFile); fwrite(&headerChecksum, 1, sizeof(headerChecksum), pcap->pcapFile); fwrite(&sourceIP, 1, sizeof(sourceIP), pcap->pcapFile); fwrite(&destinationIP, 1, sizeof(destinationIP), pcap->pcapFile); /* write the TCP header */ guint16 sourcePort = tcpHeader.sourcePort; guint16 destinationPort = tcpHeader.destinationPort; guint32 sequence = tcpHeader.sequence; guint32 acknowledgement = 0; if(tcpHeader.flags & PTCP_ACK) { acknowledgement = htonl(tcpHeader.acknowledgment); } guint8 headerLength = 0x80; guint8 tcpFlags = 0; if(tcpHeader.flags & PTCP_RST) tcpFlags |= 0x04; if(tcpHeader.flags & PTCP_SYN) tcpFlags |= 0x02; if(tcpHeader.flags & PTCP_ACK) tcpFlags |= 0x10; if(tcpHeader.flags & PTCP_FIN) tcpFlags |= 0x01; guint16 window = tcpHeader.window; guint16 tcpChecksum = 0x0000; guint8 options[14] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; fwrite(&sourcePort, 1, sizeof(sourcePort), pcap->pcapFile); fwrite(&destinationPort, 1, sizeof(destinationPort), pcap->pcapFile); fwrite(&sequence, 1, sizeof(sequence), pcap->pcapFile); fwrite(&acknowledgement, 1, sizeof(acknowledgement), pcap->pcapFile); fwrite(&headerLength, 1, sizeof(headerLength), pcap->pcapFile); fwrite(&tcpFlags, 1, sizeof(tcpFlags), pcap->pcapFile); fwrite(&window, 1, sizeof(window), pcap->pcapFile); fwrite(&tcpChecksum, 1, sizeof(tcpChecksum), pcap->pcapFile); fwrite(options, 1, sizeof(options), pcap->pcapFile); /* write payload data */ if(payloadLength > 0) { fwrite(payload, 1, payloadLength, pcap->pcapFile); } g_free(payload); }
static void _cubic_update(Cubic* cubic) { MAGIC_ASSERT(cubic); TCPCongestion* congestion = (TCPCongestion*)cubic; gint now = (gint)(worker_getCurrentTime() / SIMTIME_ONE_MILLISECOND); gint rtt = congestion->rttSmoothed; if(cubic->delayMin) { cubic->delayMin = MIN(cubic->delayMin, rtt); } else { cubic->delayMin = rtt; } cubic->ackCount += 1; if(now - cubic->lastTime <= HZ / 32) { return; } cubic->lastTime = now; if(!cubic->epochStart) { cubic->epochStart = now; if(congestion->window < cubic->lastMaxWindow) { cubic->k = cbrt(cubic->cubeFactor * (cubic->lastMaxWindow - congestion->window)); cubic->originPoint = cubic->lastMaxWindow; } else { cubic->k = 0; cubic->originPoint = congestion->window; } cubic->ackCount = 1; cubic->tcpWindowEst = congestion->window; } gint t = now + cubic->delayMin - cubic->epochStart; gint64 offset = 0; if(t < cubic->k) { offset = cubic->k - t; } else { offset = t - cubic->k; } gint originDelta = (gint)((cubic->rttScale * offset * offset * offset) >> 40); gint target = 0; if(t < cubic->k) { target = cubic->originPoint - originDelta; } else { target = cubic->originPoint + originDelta; } if(target > congestion->window) { cubic->count = congestion->window / (target - congestion->window); } else { cubic->count = congestion->window * 100; } if(cubic->delayMin > 0) { gint minCount = (congestion->window * 1000 * 8) / (10 * 16 * cubic->delayMin); if(cubic->count < minCount && t >= cubic->k) { cubic->count = minCount; } } /* cubic_tcp_friendliness() */ gint32 delta = (congestion->window * cubic->betaScale) >> 3; while (cubic->ackCount > delta) { /* update tcp window */ cubic->ackCount -= delta; cubic->tcpWindowEst++; } cubic->ackCount = 0; if(cubic->tcpWindowEst > congestion->window) { guint maxCount = congestion->window / (cubic->tcpWindowEst - congestion->window); if(cubic->count > maxCount) { cubic->count = maxCount; } } cubic->count /= 2; if(cubic->count == 0) { cubic->count = 1; } }
void logging_logv(const gchar *msgLogDomain, GLogLevelFlags msgLogLevel, const gchar* fileName, const gchar* functionName, const gint lineNumber, const gchar *format, va_list vargs) { /* this is called by worker threads, so we have access to worker */ /* see if we can avoid some work because the message is filtered anyway */ const gchar* logDomainStr = msgLogDomain ? msgLogDomain : "shadow"; if(worker_isFiltered(msgLogLevel)) { return; } gchar* logFileStr = fileName ? g_path_get_basename(fileName) : g_strdup("n/a"); const gchar* logFunctionStr = functionName ? functionName : "n/a"; const gchar* formatStr = format ? format : "n/a"; const gchar* logLevelStr = _logging_getNewLogLevelString(msgLogLevel); SimulationTime currentTime = worker_isAlive() ? worker_getCurrentTime() : SIMTIME_INVALID; Host* currentHost = worker_isAlive() ? worker_getCurrentHost() : NULL; gint workerThreadID = worker_isAlive() ? worker_getThreadID() : 0; /* format the simulation time if we are running an event */ GString* clockStringBuffer = g_string_new(""); if(currentTime != SIMTIME_INVALID) { SimulationTime hours, minutes, seconds, remainder; remainder = currentTime; hours = remainder / SIMTIME_ONE_HOUR; remainder %= SIMTIME_ONE_HOUR; minutes = remainder / SIMTIME_ONE_MINUTE; remainder %= SIMTIME_ONE_MINUTE; seconds = remainder / SIMTIME_ONE_SECOND; remainder %= SIMTIME_ONE_SECOND; g_string_printf(clockStringBuffer, "%02"G_GUINT64_FORMAT":%02"G_GUINT64_FORMAT":%02"G_GUINT64_FORMAT".%09"G_GUINT64_FORMAT"", hours, minutes, seconds, remainder); } else { g_string_printf(clockStringBuffer, "n/a"); } /* we'll need to free clockString later */ gchar* clockString = g_string_free(clockStringBuffer, FALSE); /* node identifier, if we are running a node * dont free this since we dont own the ip address string */ GString* nodeStringBuffer = g_string_new(""); if(currentHost) { g_string_printf(nodeStringBuffer, "%s~%s", host_getName(currentHost), host_getDefaultIPName(currentHost)); } else { g_string_printf(nodeStringBuffer, "n/a"); } gchar* nodeString = g_string_free(nodeStringBuffer, FALSE); /* the function name - no need to free this */ GString* newLogFormatBuffer = g_string_new(NULL); g_string_printf(newLogFormatBuffer, "[thread-%i] %s [%s-%s] [%s] [%s:%i] [%s] %s", workerThreadID, clockString, logDomainStr, logLevelStr, nodeString, logFileStr, lineNumber, logFunctionStr, formatStr); /* get the new format out of our string buffer and log it */ gchar* newLogFormat = g_string_free(newLogFormatBuffer, FALSE); g_logv(logDomainStr, msgLogLevel, newLogFormat, vargs); /* cleanup */ g_free(logFileStr); g_free(newLogFormat); g_free(clockString); g_free(nodeString); }