#include <config.h>
#endif
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "event_analysis.h"
#include "sync_chain.h"
#include "event_matching_tcp.h"
-#ifndef g_info
-#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
-#endif
-
-
// Functions common to all matching modules
static void initMatchingTCP(SyncState* const syncState);
static void destroyMatchingTCP(SyncState* const syncState);
-static void matchEventTCP(SyncState* const syncState, NetEvent* const event,
- EventType eventType);
+static void matchEventTCP(SyncState* const syncState, Event* const event);
static GArray* finalizeMatchingTCP(SyncState* const syncState);
static void printMatchingStatsTCP(SyncState* const syncState);
+static void writeMatchingGraphsPlotsTCPMessages(SyncState* const syncState,
+ const unsigned int i, const unsigned int j);
// Functions specific to this module
static void registerMatchingTCP() __attribute__((constructor (101)));
-static void matchEvents(SyncState* const syncState, NetEvent* const event,
+static void matchEvents(SyncState* const syncState, Event* const event,
GHashTable* const unMatchedList, GHashTable* const
unMatchedOppositeList, const size_t fieldOffset, const size_t
oppositeFieldOffset);
static void partialDestroyMatchingTCP(SyncState* const syncState);
-static bool isAck(const Packet* const packet);
-static bool needsAck(const Packet* const packet);
+static bool isAck(const Message* const message);
+static bool needsAck(const Message* const message);
static void buildReversedConnectionKey(ConnectionKey* const
reversedConnectionKey, const ConnectionKey* const connectionKey);
+static void openGraphDataFiles(SyncState* const syncState);
+static void closeGraphDataFiles(SyncState* const syncState);
+static void writeMessagePoint(FILE* stream, const Message* const message);
+
static MatchingModule matchingModuleTCP = {
.name= "TCP",
+ .canMatch[TCP]= true,
+ .canMatch[UDP]= false,
.initMatching= &initMatchingTCP,
.destroyMatching= &destroyMatchingTCP,
.matchEvent= &matchEventTCP,
.finalizeMatching= &finalizeMatchingTCP,
.printMatchingStats= &printMatchingStatsTCP,
+ .graphFunctions= {
+ .writeTraceTraceForePlots= &writeMatchingGraphsPlotsTCPMessages,
+ }
};
matchingData= malloc(sizeof(MatchingDataTCP));
syncState->matchingData= matchingData;
- matchingData->unMatchedInE= g_hash_table_new_full(&ghfPacketKeyHash,
- &gefPacketKeyEqual, NULL, &gdnDestroyNetEvent);
- matchingData->unMatchedOutE= g_hash_table_new_full(&ghfPacketKeyHash,
- &gefPacketKeyEqual, NULL, &gdnDestroyNetEvent);
+ matchingData->unMatchedInE= g_hash_table_new_full(&ghfSegmentKeyHash,
+ &gefSegmentKeyEqual, NULL, &gdnDestroyEvent);
+ matchingData->unMatchedOutE= g_hash_table_new_full(&ghfSegmentKeyHash,
+ &gefSegmentKeyEqual, NULL, &gdnDestroyEvent);
matchingData->unAcked= g_hash_table_new_full(&ghfConnectionKeyHash,
&gefConnectionKeyEqual, &gdnConnectionKeyDestroy,
- &gdnPacketListDestroy);
+ &gdnTCPSegmentListDestroy);
if (syncState->stats)
{
+ unsigned int i;
+
matchingData->stats= calloc(1, sizeof(MatchingStatsTCP));
+ matchingData->stats->totMessageArray= malloc(syncState->traceNb *
+ sizeof(unsigned int*));
+ for (i= 0; i < syncState->traceNb; i++)
+ {
+ matchingData->stats->totMessageArray[i]=
+ calloc(syncState->traceNb, sizeof(unsigned int));
+ }
}
else
{
matchingData->stats= NULL;
}
+
+ if (syncState->graphsStream)
+ {
+ openGraphDataFiles(syncState);
+ }
+ else
+ {
+ matchingData->messagePoints= NULL;
+ }
}
if (syncState->stats)
{
+ unsigned int i;
+
+ for (i= 0; i < syncState->traceNb; i++)
+ {
+ free(matchingData->stats->totMessageArray[i]);
+ }
+ free(matchingData->stats->totMessageArray);
free(matchingData->stats);
}
return;
}
- g_debug("Cleaning up unMatchedInE list\n");
g_hash_table_destroy(matchingData->unMatchedInE);
matchingData->unMatchedInE= NULL;
- g_debug("Cleaning up unMatchedOutE list\n");
g_hash_table_destroy(matchingData->unMatchedOutE);
- g_debug("Cleaning up unAcked list\n");
g_hash_table_destroy(matchingData->unAcked);
+
+ if (syncState->graphsStream && matchingData->messagePoints)
+ {
+ closeGraphDataFiles(syncState);
+ }
}
* Args:
* syncState container for synchronization data.
* event new event to match
- * eventType type of event to match
*/
-static void matchEventTCP(SyncState* const syncState, NetEvent* const event, EventType eventType)
+static void matchEventTCP(SyncState* const syncState, Event* const event)
{
MatchingDataTCP* matchingData;
+ g_assert(event->type == TCP);
+
matchingData= (MatchingDataTCP*) syncState->matchingData;
- if (eventType == IN)
+ if (event->event.tcpEvent->direction == IN)
{
matchEvents(syncState, event, matchingData->unMatchedInE,
- matchingData->unMatchedOutE, offsetof(Packet, inE),
- offsetof(Packet, outE));
+ matchingData->unMatchedOutE, offsetof(Message, inE),
+ offsetof(Message, outE));
}
else
{
matchEvents(syncState, event, matchingData->unMatchedOutE,
- matchingData->unMatchedInE, offsetof(Packet, outE),
- offsetof(Packet, inE));
+ matchingData->unMatchedInE, offsetof(Message, outE),
+ offsetof(Message, inE));
}
}
/*
- * Print statistics related to matching and downstream modules. Must be
- * called after finalizeMatching.
+ * Print statistics related to matching. Must be called after
+ * finalizeMatching.
*
* Args:
* syncState container for synchronization data.
*/
static void printMatchingStatsTCP(SyncState* const syncState)
{
+ unsigned int i, j;
MatchingDataTCP* matchingData;
if (!syncState->stats)
matchingData= (MatchingDataTCP*) syncState->matchingData;
printf("TCP matching stats:\n");
- printf("\ttotal input and output events matched together to form a packet: %d\n",
+ printf("\ttotal input and output events matched together to form a packet: %u\n",
matchingData->stats->totPacket);
- printf("\ttotal packets identified needing an acknowledge: %d\n",
- matchingData->stats->totPacketNeedAck);
- printf("\ttotal exchanges (four events matched together): %d\n",
- matchingData->stats->totExchangeEffective);
- printf("\ttotal synchronization exchanges: %d\n",
- matchingData->stats->totExchangeSync);
-
- if (syncState->analysisModule->printAnalysisStats != NULL)
+
+ printf("\tMessage traffic:\n");
+
+ for (i= 0; i < syncState->traceNb; i++)
{
- syncState->analysisModule->printAnalysisStats(syncState);
+ for (j= i + 1; j < syncState->traceNb; j++)
+ {
+ printf("\t\t%3d - %-3d: sent %-10u received %-10u\n", i, j,
+ matchingData->stats->totMessageArray[j][i],
+ matchingData->stats->totMessageArray[i][j]);
+ }
+ }
+
+ if (syncState->analysisModule->analyzeExchange != NULL)
+ {
+ printf("\ttotal packets identified needing an acknowledge: %u\n",
+ matchingData->stats->totPacketNeedAck);
+ printf("\ttotal exchanges (four events matched together): %u\n",
+ matchingData->stats->totExchangeEffective);
+ printf("\ttotal synchronization exchanges: %u\n",
+ matchingData->stats->totExchangeSync);
}
}
* Implementation of a packet matching algorithm for TCP
*
* Args:
- * netEvent: new event to match
+ * event: new event to match
* unMatchedList: list of unmatched events of the same type (send or
- * receive) as netEvent
+ * receive) as event
* unMatchedOppositeList: list of unmatched events of the opposite type of
- * netEvent
- * fieldOffset: offset of the NetEvent field in the Packet struct for the
- * field of the type of netEvent
- * oppositeFieldOffset: offset of the NetEvent field in the Packet struct
- * for the field of the opposite type of netEvent
+ * event
+ * fieldOffset: offset of the Event field in the Message struct for the
+ * field of the type of event
+ * oppositeFieldOffset: offset of the Event field in the Message struct
+ * for the field of the opposite type of event
*/
-static void matchEvents(SyncState* const syncState, NetEvent* const event,
+static void matchEvents(SyncState* const syncState, Event* const event,
GHashTable* const unMatchedList, GHashTable* const unMatchedOppositeList,
const size_t fieldOffset, const size_t oppositeFieldOffset)
{
- NetEvent* companionEvent;
- Packet* packet;
+ Event* companionEvent;
+ Message* packet;
MatchingDataTCP* matchingData;
GQueue* conUnAcked;
matchingData= (MatchingDataTCP*) syncState->matchingData;
- companionEvent= g_hash_table_lookup(unMatchedOppositeList, event->packetKey);
+ companionEvent= g_hash_table_lookup(unMatchedOppositeList, event->event.tcpEvent->segmentKey);
if (companionEvent != NULL)
{
g_debug("Found matching companion event, ");
+ // If it's there, remove it and create a Message
+ g_hash_table_steal(unMatchedOppositeList, event->event.tcpEvent->segmentKey);
+ packet= malloc(sizeof(Message));
+ *((Event**) ((void*) packet + fieldOffset))= event;
+ *((Event**) ((void*) packet + oppositeFieldOffset))= companionEvent;
+ packet->print= &printTCPSegment;
+ // Both events can now share the same segmentKey
+ free(packet->outE->event.tcpEvent->segmentKey);
+ packet->outE->event.tcpEvent->segmentKey= packet->inE->event.tcpEvent->segmentKey;
+
if (syncState->stats)
{
matchingData->stats->totPacket++;
+ matchingData->stats->totMessageArray[packet->inE->traceNum][packet->outE->traceNum]++;
}
- // If it's there, remove it and create a Packet
- g_hash_table_steal(unMatchedOppositeList, event->packetKey);
- packet= malloc(sizeof(Packet));
- *((NetEvent**) ((void*) packet + fieldOffset))= event;
- *((NetEvent**) ((void*) packet + oppositeFieldOffset))= companionEvent;
- // Both events can now share the same packetKey
- free(packet->outE->packetKey);
- packet->outE->packetKey= packet->inE->packetKey;
- packet->acks= NULL;
-
// Discard loopback traffic
if (packet->inE->traceNum == packet->outE->traceNum)
{
- destroyPacket(packet);
+ destroyTCPSegment(packet);
return;
}
- if (syncState->analysisModule->analyzePacket)
+ if (syncState->graphsStream)
+ {
+ writeMessagePoint(matchingData->messagePoints[packet->inE->traceNum][packet->outE->traceNum],
+ packet);
+ }
+
+ if (syncState->analysisModule->analyzeMessage != NULL)
{
- syncState->analysisModule->analyzePacket(syncState, packet);
+ syncState->analysisModule->analyzeMessage(syncState, packet);
}
// We can skip the rest of the algorithm if the analysis module is not
// interested in exchanges
- if (!syncState->analysisModule->analyzeExchange)
+ if (syncState->analysisModule->analyzeExchange == NULL)
{
- destroyPacket(packet);
+ destroyTCPSegment(packet);
return;
}
ConnectionKey oppositeConnectionKey;
buildReversedConnectionKey(&oppositeConnectionKey,
- &event->packetKey->connectionKey);
+ &event->event.tcpEvent->segmentKey->connectionKey);
conUnAcked= g_hash_table_lookup(matchingData->unAcked,
&oppositeConnectionKey);
if (conUnAcked != NULL)
{
- Packet* ackedPacket;
+ Message* ackedPacket;
GList* result;
+ Exchange* exchange;
- result= g_queue_find_custom(conUnAcked, packet, &gcfPacketAckCompare);
+ exchange= NULL;
+
+ result= g_queue_find_custom(conUnAcked, packet, &gcfTCPSegmentAckCompare);
while (result != NULL)
{
// and keep it for later offset calculations
g_debug("Found matching unAcked packet, ");
- ackedPacket= (Packet*) result->data;
+ ackedPacket= (Message*) result->data;
g_queue_delete_link(conUnAcked, result);
if (syncState->stats)
matchingData->stats->totExchangeEffective++;
}
- if (packet->acks == NULL)
+ if (exchange == NULL)
{
- packet->acks= g_queue_new();
+ exchange= malloc(sizeof(Exchange));
+ exchange->message= packet;
+ exchange->acks= g_queue_new();
}
- g_queue_push_tail(packet->acks, ackedPacket);
+ g_queue_push_tail(exchange->acks, ackedPacket);
result= g_queue_find_custom(conUnAcked, packet,
- &gcfPacketAckCompare);
+ &gcfTCPSegmentAckCompare);
}
// It might be possible to do an offset calculation
- if (packet->acks != NULL)
+ if (exchange != NULL)
{
- ackedPacket= g_queue_peek_tail(packet->acks);
+ ackedPacket= g_queue_peek_tail(exchange->acks);
if (ackedPacket->outE->traceNum != packet->inE->traceNum
|| ackedPacket->inE->traceNum !=
packet->outE->traceNum || packet->inE->traceNum ==
packet->outE->traceNum)
{
- printPacket(ackedPacket);
- printPacket(packet);
+ ackedPacket->print(ackedPacket);
+ packet->print(packet);
g_error("Disorganized exchange encountered during "
"synchronization");
}
}
syncState->analysisModule->analyzeExchange(syncState,
- packet);
+ exchange);
}
+
+ exchange->message= NULL;
+ destroyTCPExchange(exchange);
}
}
}
// If this packet will generate an ack, add it to the unAcked list
g_debug("Adding to unAcked, ");
conUnAcked= g_hash_table_lookup(matchingData->unAcked,
- &event->packetKey->connectionKey);
+ &event->event.tcpEvent->segmentKey->connectionKey);
if (conUnAcked == NULL)
{
ConnectionKey* connectionKey;
connectionKey= malloc(sizeof(ConnectionKey));
- memcpy(connectionKey, &event->packetKey->connectionKey,
+ memcpy(connectionKey, &event->event.tcpEvent->segmentKey->connectionKey,
sizeof(ConnectionKey));
g_hash_table_insert(matchingData->unAcked, connectionKey,
conUnAcked= g_queue_new());
}
else
{
- destroyPacket(packet);
+ destroyTCPSegment(packet);
}
}
else
// If there's no corresponding event, add the event to the unmatched
// list for this type of event
g_debug("Adding to unmatched event list, ");
- g_hash_table_replace(unMatchedList, event->packetKey, event);
+ g_hash_table_replace(unMatchedList, event->event.tcpEvent->segmentKey, event);
}
}
/*
* Check if a packet is an acknowledge
*
+ * Args:
+ * packet TCP Message
+ *
* Returns:
* true if it is,
* false otherwise
*/
-static bool isAck(const Packet* const packet)
+static bool isAck(const Message* const packet)
{
- if (packet->inE->packetKey->ack == 1)
+ if (packet->inE->event.tcpEvent->segmentKey->ack == 1)
{
return true;
}
* Check if a packet will increment the sequence number, thus needing an
* acknowledge
*
+ * Args:
+ * packet TCP Message
+ *
* Returns:
* true if the packet will need an acknowledge
* false otherwise
*/
-static bool needsAck(const Packet* const packet)
+static bool needsAck(const Message* const packet)
{
- if (packet->inE->packetKey->syn || packet->inE->packetKey->fin ||
- packet->inE->packetKey->tot_len - packet->inE->packetKey->ihl * 4 -
- packet->inE->packetKey->doff * 4 > 0)
+ if (packet->inE->event.tcpEvent->segmentKey->syn || packet->inE->event.tcpEvent->segmentKey->fin ||
+ packet->inE->event.tcpEvent->segmentKey->tot_len - packet->inE->event.tcpEvent->segmentKey->ihl * 4 -
+ packet->inE->event.tcpEvent->segmentKey->doff * 4 > 0)
{
return true;
}
reversedConnectionKey->source= connectionKey->dest;
reversedConnectionKey->dest= connectionKey->source;
}
+
+
+/*
+ * Create and open files used to store message points to genereate
+ * graphs. Allocate and populate array to store file pointers.
+ *
+ * Args:
+ * syncState: container for synchronization data
+ */
+static void openGraphDataFiles(SyncState* const syncState)
+{
+ unsigned int i, j;
+ int retval;
+ char* cwd;
+ char name[29];
+ MatchingDataTCP* matchingData;
+
+ matchingData= (MatchingDataTCP*) syncState->matchingData;
+
+ cwd= changeToGraphDir(syncState->graphsDir);
+
+ matchingData->messagePoints= malloc(syncState->traceNb * sizeof(FILE**));
+ for (i= 0; i < syncState->traceNb; i++)
+ {
+ matchingData->messagePoints[i]= malloc(syncState->traceNb *
+ sizeof(FILE*));
+ for (j= 0; j < syncState->traceNb; j++)
+ {
+ if (i != j)
+ {
+ retval= snprintf(name, sizeof(name),
+ "matching_tcp-%03u_to_%03u.data", j, i);
+ if (retval > sizeof(name) - 1)
+ {
+ name[sizeof(name) - 1]= '\0';
+ }
+ if ((matchingData->messagePoints[i][j]= fopen(name, "w")) ==
+ NULL)
+ {
+ g_error(strerror(errno));
+ }
+ }
+ }
+ }
+
+ retval= chdir(cwd);
+ if (retval == -1)
+ {
+ g_error(strerror(errno));
+ }
+ free(cwd);
+}
+
+
+/*
+ * Write a message point to a file used to generate graphs
+ *
+ * Args:
+ * stream: FILE*, file pointer where to write the point
+ * message: message for which to write the point
+ */
+static void writeMessagePoint(FILE* stream, const Message* const message)
+{
+ uint64_t x, y;
+
+ if (message->inE->traceNum < message->outE->traceNum)
+ {
+ // CA is inE->traceNum
+ x= message->inE->cpuTime;
+ y= message->outE->cpuTime;
+ }
+ else
+ {
+ // CA is outE->traceNum
+ x= message->outE->cpuTime;
+ y= message->inE->cpuTime;
+ }
+
+ fprintf(stream, "%20llu %20llu\n", x, y);
+}
+
+
+/*
+ * Close files used to store convex hull points to genereate graphs.
+ * Deallocate array to store file pointers.
+ *
+ * Args:
+ * syncState: container for synchronization data
+ */
+static void closeGraphDataFiles(SyncState* const syncState)
+{
+ unsigned int i, j;
+ MatchingDataTCP* matchingData;
+ int retval;
+
+ matchingData= (MatchingDataTCP*) syncState->matchingData;
+
+ if (matchingData->messagePoints == NULL)
+ {
+ return;
+ }
+
+ for (i= 0; i < syncState->traceNb; i++)
+ {
+ for (j= 0; j < syncState->traceNb; j++)
+ {
+ if (i != j)
+ {
+ retval= fclose(matchingData->messagePoints[i][j]);
+ if (retval != 0)
+ {
+ g_error(strerror(errno));
+ }
+ }
+ }
+ free(matchingData->messagePoints[i]);
+ }
+ free(matchingData->messagePoints);
+
+ matchingData->messagePoints= NULL;
+}
+
+
+/*
+ * Write the matching-specific graph lines in the gnuplot script.
+ *
+ * Args:
+ * syncState: container for synchronization data
+ * i: first trace number
+ * j: second trace number, garanteed to be larger than i
+ */
+static void writeMatchingGraphsPlotsTCPMessages(SyncState* const syncState,
+ const unsigned int i, const unsigned int j)
+{
+ fprintf(syncState->graphsStream,
+ "\t\"matching_tcp-%1$03d_to_%2$03d.data\" "
+ "title \"Sent messages\" with points linetype 4 "
+ "linecolor rgb \"#98fc66\" pointtype 9 pointsize 2, \\\n"
+ "\t\"matching_tcp-%2$03d_to_%1$03d.data\" "
+ "title \"Received messages\" with points linetype 4 "
+ "linecolor rgb \"#6699cc\" pointtype 11 pointsize 2, \\\n", i, j);
+}