[bwm-tools-devel] COMMIT - r55 - in trunk: bwmd include lib
Brought to you by:
nkukard
From: SVN C. <sv...@li...> - 2005-01-21 06:47:16
|
Author: nkukard Date: 2005-01-21 08:46:58 +0200 (Fri, 21 Jan 2005) New Revision: 55 Modified: trunk/bwmd/autoclass.c trunk/bwmd/ipq.c trunk/include/autoclass.h trunk/include/flow.h trunk/lib/xmlConf.c Log: * Misc optimizations and pre-tos work Modified: trunk/bwmd/autoclass.c =================================================================== --- trunk/bwmd/autoclass.c 2005-01-21 06:45:35 UTC (rev 54) +++ trunk/bwmd/autoclass.c 2005-01-21 06:46:58 UTC (rev 55) @@ -22,86 +22,204 @@ */ #include "autoclass.h" +#include "flow.h" -// Band calculation functions, tcp -long int tcpPortToBand(long int bandNum, u_int16_t port) + +// Auto classify by port +static unsigned char autoClassify_port(struct ip_packet_t *ip_packet, unsigned char prioClassifier) { - long int ret = bandNum; + unsigned char prio = 0; + + + // Priority calculation functions, tcp + static unsigned char tcpPortToPrio(u_int16_t port) + { + unsigned char ret = 0; + + + // Decide band to pump packet into + switch (port) + { + // AUTH + case 113: + ret = 20; + break; + // SSH + case 22: + // TELNET + case 23: + ret = 25; + break; + // HTTP + case 80: + // PROXY? + case 8080: + case 3128: + case 3130: + // HTTPS + case 443: + ret = 65; + break; + // CVS + case 2401: + ret = 70; + break; + // POP3 + case 110: + // IMAP + case 143: + ret = 75; + break; + // FTP + case 20: + case 21: + ret = 80; + break; + }; + + return ret; + } + + + // Priority calculation functions, udp + static unsigned char udpPortToPrio(u_int16_t port) + { + unsigned char ret = 0; - // Decide band to pump packet into - switch (port) + // Decide band to pump packet into + switch (port) + { + // DNS + case 53: + ret = 10; + break; + // NTP + case 123: + ret = 15; + break; + // RADIUS + case 1645: + case 1646: + case 1812: + case 1813: + ret = 30; + break; + default: + // Traceroute + if (port >= 33434 && port <= 33465) + ret = 5; + break; + }; + + return ret; + } + + + // Process a TCP packet + if (ip_packet->protocol == IPPROTO_TCP) { - // AUTH - case 113: - ret = 20; - break; - // SSH - case 22: - // TELNET - case 23: - ret = 25; - break; - // HTTP - case 80: - // PROXY? - case 8080: - case 3128: - case 3130: - // HTTPS - case 443: - ret = 65; - break; - // CVS - case 2401: - ret = 70; - break; - // POP3 - case 110: - // IMAP - case 143: - ret = 75; - break; - // FTP - case 20: - case 21: - ret = 80; - break; - }; + struct tcphdr *tcph = (struct tcphdr *) (ip_packet + (ip_packet->ihl * 4)); +/* + fprintf(stderr," tcp -> sport = %i, dport = %i, prec = 0x%x\n", ntohs(tcph->source), + ntohs(tcph->dest), IPTOS_PREC(ip_packet->tos)); +*/ + if (!(prio = tcpPortToPrio(ntohs(tcph->dest)))) + prio = tcpPortToPrio(ntohs(tcph->source)); + } - return ret; + // Process a ICMP packet + else if (ip_packet->protocol == IPPROTO_ICMP) + { +// struct icmphdr *icmph = (struct icmphdr *) (ip_packet + (ip_packet->ihl * 4)); + +/* + fprintf(stderr,"something: icmp = %i, type = %i\n", icmph->code, icmph->type); +*/ + prio = 5; + } + + // Process a UDP packet + else if (ip_packet->protocol == IPPROTO_UDP) + { + struct udphdr *udph = (struct udphdr *) (ip_packet + (ip_packet->ihl * 4)); +/* + fprintf(stderr," udp -> sport = %i, dport = %i\n", ntohs(udph->source), + ntohs(udph->dest)); +*/ + if (!(prio = udpPortToPrio(ntohs(udph->dest)))) + prio = udpPortToPrio(ntohs(udph->source)); + } + + return prio; } + -// Band calculation functions, udp -long int udpPortToBand(long int bandNum, u_int16_t port) +// Auto classify by ip header TOS value +static unsigned char autoClassify_tos(struct ip_packet_t *ip_packet, unsigned char prioClassifier) { - long int ret = bandNum; - - - // Decide band to pump packet into - switch (port) + unsigned char prio = 0; + // Get type of service + unsigned char tos = IPTOS_TOS(ip_packet->tos); + + + // Decide what we doing... + if (tos == IPTOS_LOWDELAY) { - // DNS - case 53: - ret = 10; - break; - // NTP - case 123: - ret = 15; - break; - // RADIUS - case 1645: - case 1646: - case 1812: - case 1813: - ret = 30; - break; - }; - - if (port >= 33434 && port <= 33465) - ret = 5; - - return ret; +/* + * 1. LOW DELAY + * - PRIO 10 + * - high drop probability + */ + } + else if (tos == IPTOS_THROUGHPUT) + { +/* + * 2. THROUGHPUT + * - long queue? + * - low drop probability + */ + } + else if (tos == IPTOS_RELIABILITY) + { +/* + * 3. RELIABILITY + * - low drop probability + */ + } + else if (tos == IPTOS_MINCOST) + { +/* + * 4. MIN COST + * - PRIO 90 + * - high drop probability + */ + } + + return prio; } + +// Auto classify packet and return priority (1 - best, 100 - worst) +unsigned char autoClassify(struct ip_packet_t *ip_packet, unsigned char prioClassifier) +{ + unsigned char prio; + + + // Classify by port + if (prioClassifier == AUTOCLASS_PORT) + prio = autoClassify_port(ip_packet,prioClassifier); + // Classify by TOS + else if (prioClassifier == AUTOCLASS_TOS) + prio = autoClassify_tos(ip_packet,prioClassifier); + // Default - this will basically match if we have AUTOCLASS_NONE + else + prio = 50; + + return prio; +} + + + + Modified: trunk/bwmd/ipq.c =================================================================== --- trunk/bwmd/ipq.c 2005-01-21 06:45:35 UTC (rev 54) +++ trunk/bwmd/ipq.c 2005-01-21 06:46:58 UTC (rev 55) @@ -22,6 +22,7 @@ */ +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -31,7 +32,10 @@ #include "libipq.h" +#define QUEUE_HEAD 1 +#define QUEUE_TAIL 2 + // Destroy the ipq handle static void destroyIPQHandle(struct ipq_handle *h) { @@ -91,6 +95,8 @@ int status; int result; int drop = 0; + // Default to inserting at queue tail + unsigned char queuePos = QUEUE_TAIL; // Our find functions @@ -138,94 +144,171 @@ if (!foundQueue) { struct ip_packet_t *ip_packet = (struct ip_packet_t *) packet->payload->payload; - long int bandNum = -1; - + unsigned char prio = 0; + /* fprintf(stderr,"auto packet queue -> protocol = %i, src = %i.%i.%i.%i, dest = %i.%i.%i.%i, tos = 0x%x\n", ip_packet->protocol, ip_packet->u_saddr.addr.a, ip_packet->u_saddr.addr.b, ip_packet->u_saddr.addr.c, ip_packet->u_saddr.addr.d, ip_packet->u_daddr.addr.a, ip_packet->u_daddr.addr.b, ip_packet->u_daddr.addr.c, ip_packet->u_daddr.addr.d, IPTOS_PREC(ip_packet->tos)); -*/ - // Process a TCP packet - if (ip_packet->protocol == IPPROTO_TCP) - { - struct tcphdr *tcph = (struct tcphdr *) (packet->payload->payload + (ip_packet->ihl * 4)); -/* - fprintf(stderr," tcp -> sport = %i, dport = %i, prec = 0x%x\n", ntohs(tcph->source), - ntohs(tcph->dest), IPTOS_PREC(ip_packet->tos)); */ - bandNum = tcpPortToBand(bandNum,ntohs(tcph->dest)); - if (bandNum == -1) - bandNum = tcpPortToBand(bandNum,ntohs(tcph->source)); + + prio = autoClassify(ip_packet,foundFlow->prioClassifier); + + // If we didn't get anything set band number to 50, 50/50 + if (prio == 0) + prio = 50; + foundQueue = foundFlow->pktQueues[prio]; + } + + + // Lock flow before we fuck with it + g_mutex_lock(foundQueue->lock); + g_mutex_lock(P_FLOW(foundQueue,lock)); + + +/* This is my current work on implementing RED - nk...@lb... */ +#if 0 + { + /* Saved variables */ + unsigned int avg; // Average queue size + unsigned long int q_time; // Last time a packet was received + unsigned int count; // Packets since last one marked + /* Fixed params */ + Wq; // Weight of queue + min_th; // Min threshold of queue + max_th; // Max threshold of queue + max_p; // Max value for Pb + /* Other */ + float Pa; // Current packet marking probability + q; // Current queue size + time; // Current time + float Pb; + + + avg = 0; + count = -1; + + + LOOP WITH PACKETS + + calculate new average + + if queue is non empty + { + // Exponential weighted moving average (EWMA) + avg = (1 - Wq) * avg + Wq * q; } + else + { + } - // Process a ICMP packet - if (ip_packet->protocol == IPPROTO_ICMP) + if (min_th <= avg && avg < max_th) { -/* - struct icmphdr *icmph = (struct icmphdr *) (packet->payload->payload + (ip_packet->ihl * 4)); + count++; - fprintf(stderr,"something: icmp = %i, type = %i\n", icmph->code, icmph->type); -*/ - bandNum = 5; + Pb = max_p * (avg - min_p) / (max_th - min_th); + // Favour small packets + Pb = Pb * (packet_size / max_packet_size); + + Pa = Pb / (1 - count & Pb); + + // FIXME - mark packet with Pa + mark packet + count = 0; } - - // Process a UDP packet - if (ip_packet->protocol == IPPROTO_UDP) + else if (max_th <= avg) { - struct udphdr *udph = (struct udphdr *) (packet->payload->payload + (ip_packet->ihl * 4)); -/* - fprintf(stderr," udp -> sport = %i, dport = %i\n", ntohs(udph->source), - ntohs(udph->dest)); -*/ - bandNum = udpPortToBand(bandNum,ntohs(udph->dest)); - if (bandNum == -1) - bandNum = udpPortToBand(bandNum,ntohs(udph->source)); + // FIXME - mark packet; + count = 0; } - - // If we didn't get anything set band number to 50, 50/50 - if (bandNum == -1) - bandNum = 50; + else + count = -1; - foundQueue = foundFlow->pktQueues[bandNum]; + if queue is empty + q_time = time(); + + CONTINUE LOOP + + + } +#endif + + + + + + - - // Lock flow before we fuck with it - g_mutex_lock(foundQueue->lock); - g_mutex_lock(P_FLOW(foundQueue,lock)); - // Check first of all if we fucked over our one of our queue limits if (will_exceed_pkt_queue(foundQueue,PKT_SIZE(packet)) || will_exceed_flow_queue(foundQueue->parentFlow,PKT_SIZE(packet))) drop = 1; + // Or checkif we fell over our soft curve, slow start algo + else + { + long int maxQueueSize, curQueueSize, avgQueueSize; + /* Check if we must use our queue's size or parent flow queue size */ #if 0 - // Check second of all if we fucked our min threshold over - else if (TH_EXCEEDED(foundQueue,min_th)) - { - int j = 1 + (int) (10.0 * rand() / (RAND_MAX + 1.0)); - - if (TH_EXCEEDED(foundQueue,max_th)) + if (foundQueue->maxSize) { - if (j > 5) - drop = 1; + maxQueueSize = foundQueue->maxSize; + curQueueSize = foundQueue->curSize; } else { - if (j < 3) - drop = 1; +#endif + maxQueueSize = P_FLOW(foundQueue,maxQueueSize); + curQueueSize = P_FLOW(foundQueue,curQueueSize); + avgQueueSize = P_FLOW(foundQueue,avgQueueSize); +#if 0 } - } #endif + + // Check if we have limits to exceed + if (maxQueueSize && curQueueSize > 0 && avgQueueSize > 0) + { + float avgProb = 0, curProb = 0, prob = 0; + int min_th = 10; + double drand = drand48(); + + // nice soft curve flow based on average queue size, starts slow, increases fast will hit 100% probability at 75% + // FIXME - this is based on the flow's queue size, it should be configurable to the queue's queue size + //avgProb = powf((P_FLOW(foundQueue,avgQueueSize) / maxQueueSize * 1.25),3); + avgProb = powf((((float) avgQueueSize / (float) maxQueueSize) * 1.25),3); + // current queue size & threshold curve... sort of flatish, but starting slowish + curProb = powf(((float) curQueueSize / (float) maxQueueSize) + powf(((float) min_th / (float) 150),3),2) / 2; + prob = avgProb + curProb; + // Check if we should drop packet + drop = drand < prob; +/* + logMessage(LOG_DEBUG, "%s: Packet Drop Probability: %f (%li:%li) %f (%li:%li)\t%f\t%i\n", + P_FLOW(foundQueue,flowName), + avgProb,avgQueueSize,maxQueueSize, + curProb,curQueueSize,maxQueueSize, + avgProb + curProb, + drop); +*/ + } + + } + // Check if we must pass the packet if (!drop) { // Lock, queue... adjust stats - foundQueue->packets = g_list_append(foundQueue->packets,packet); + if (queuePos == QUEUE_TAIL) + foundQueue->packets = g_list_append(foundQueue->packets,packet); + else if (queuePos == QUEUE_HEAD) + { + // FIXME - APPEND TO LAST QUEUE + } + foundQueue->curSize += PKT_SIZE(packet); P_FLOW(foundQueue,curQueueSize) += PKT_SIZE(packet); foundQueue->curLen++; @@ -327,7 +410,6 @@ break; case IPQM_PACKET: - // Get packet details... g_mutex_lock(runnerData->IPQLock); m = ipq_get_packet(buf); Modified: trunk/include/autoclass.h =================================================================== --- trunk/include/autoclass.h 2005-01-21 06:45:35 UTC (rev 54) +++ trunk/include/autoclass.h 2005-01-21 06:46:58 UTC (rev 55) @@ -26,12 +26,17 @@ #include <stdlib.h> +#include "flow.h" -// Band calculation functions, tcp -long int tcpPortToBand(long int bandNum, u_int16_t port); -// Band calculation functions, udp -long int udpPortToBand(long int bandNum, u_int16_t port); +// Classificaiton types... +#define AUTOCLASS_NONE 0 +#define AUTOCLASS_PORT 1 +#define AUTOCLASS_TOS 2 +// Auto classify packet and return priority (1 - best, 100 - worst) +unsigned char autoClassify(struct ip_packet_t *ip_packet, unsigned char prioClassifier); + + #endif Modified: trunk/include/flow.h =================================================================== --- trunk/include/flow.h 2005-01-21 06:45:35 UTC (rev 54) +++ trunk/include/flow.h 2005-01-21 06:46:58 UTC (rev 55) @@ -90,7 +90,7 @@ // Shaping struct flow_t *parent; // STATIC, not specified, determined - pointer to parent - int prio; // STATIC - Flow priority + unsigned char prioClassifier; // STATIC - Flow priority auto classifier unsigned long int nfmark; // STATIC - nfmark value i must match auto to queues long int maxQueueSize; // STATIC - max length in bytes of queue long int maxQueueLen; // STATIC - and/or length in items @@ -118,6 +118,7 @@ float curThroughput; // Current throughput unsigned int curThroughputAge; // How many microseconds since last throughput update + unsigned int avgQueueSize; // Average queue size struct timeval lastThroughputUpdate; // Last time the throughput was updated unsigned int accumMs; // Accumulated number of microseconds Modified: trunk/lib/xmlConf.c =================================================================== --- trunk/lib/xmlConf.c 2005-01-21 06:45:35 UTC (rev 54) +++ trunk/lib/xmlConf.c 2005-01-21 06:46:58 UTC (rev 55) @@ -29,6 +29,7 @@ #include <time.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> +#include "autoclass.h" #include "common.h" #include "flow.h" #include "xmlConf.h" @@ -415,6 +416,8 @@ done = 1; if (!done && !xmlStrcmp(key,"report-timeout")) done = 1; + if (!done && !xmlStrcmp(key,"prio-classifier")) + done = 1; if (!done && !xmlStrcmp(key,"burst-rate")) done = 1; if (!done && !xmlStrcmp(key,"max-rate")) @@ -645,6 +648,7 @@ long int maxRate, long int burstRate, unsigned long int nfmark, + unsigned char prioClassifier, float parent_th, int reportTimeout) { @@ -676,6 +680,9 @@ flow->burstRate = burstRate; flow->nfmark = nfmark; + // Set the priority classifier + flow->prioClassifier = prioClassifier; + flow->parent_th = parent_th; flow->counterTimeout = reportTimeout; @@ -720,6 +727,7 @@ gettimeofday(&flow->lastThroughputUpdate,NULL); flow->curThroughputAge = 0; flow->curThroughput = 0; + flow->avgQueueSize = 0; // Set last time we calculated credit and the rest... flow->accumMs = 0; gettimeofday(&flow->lastCreditCalc,NULL); @@ -746,22 +754,18 @@ if (flow->maxQueueLen == -1) { if (flow->maxRate != 0) - flow->maxQueueLen = 5; // Seems an OK value for normal use? + flow->maxQueueLen = ((flow->burstRate + flow->maxRate) / 2 / 750) * 2; // Seems an OK value for normal use? else flow->maxQueueLen = 0; } if (flow->maxQueueSize == -1) { if (flow->maxRate != 0) - flow->maxQueueSize = 4096; // Let us queue at least 2 big packets and some small ones + flow->maxQueueSize = (flow->burstRate + flow->maxRate); // Normal use, this should be ok? else flow->maxQueueSize = 0; } - // Calculate our thresholds - //flow->min_th = (flow->maxRate / 750); - //flow->max_th = (flow->maxRate / 750) * 4; - // Blank all queues for (i = 0; i < NUM_PRIO_BANDS; i++) { @@ -928,6 +932,7 @@ char *p; long int statsLen, maxQueueSize, maxQueueLen, maxRate, burstRate, reportTimeout; unsigned long int nfmark; + unsigned char prioClassifier = AUTOCLASS_PORT; float parent_th; @@ -968,9 +973,24 @@ reportTimeout = 30; } + // Work out automatic classifier to use + if ((p = g_hash_table_lookup(tagProperties,"prio-classifier")) != NULL) + { + if (strcasecmp(p,"tos") == 0) + prioClassifier = AUTOCLASS_TOS; + else if (strcasecmp(p,"port") == 0) + prioClassifier = AUTOCLASS_PORT; + else if (strcasecmp(p,"none") == 0) + prioClassifier = AUTOCLASS_NONE; + else + fprintf(stderr,"ERROR: %s - Tag value for \"prio-classifier\" is invalid, please read manual\n",flowName); + } + else + prioClassifier = AUTOCLASS_NONE; + // Create our flow newFlow = createFlow(flowName,parentFlow,statsLen,maxQueueSize,maxQueueLen,maxRate,burstRate,nfmark, - parent_th,reportTimeout); + prioClassifier,parent_th,reportTimeout); flows = g_list_append(flows,newFlow); } |