Commit 6e97ec8a authored by Nigel Kukard's avatar Nigel Kukard
Browse files

* Misc optimizations and pre-tos work

parent 2456ca5a
......@@ -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;
};
return ret;
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));
}
// 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;
}
......@@ -22,6 +22,7 @@
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -31,6 +32,9 @@
#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 @@ static int queuePacket(struct runnerData_t *runnerData, unsigned long int nfmark
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 @@ static int queuePacket(struct runnerData_t *runnerData, unsigned long int nfmark
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 - nkukard@lbsd.net */
#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
}
// Lock flow before we fuck with it
g_mutex_lock(foundQueue->lock);
g_mutex_lock(P_FLOW(foundQueue,lock));
#endif
// 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 @@ void *IPQRunner(void *data)
break;
case IPQM_PACKET:
// Get packet details...
g_mutex_lock(runnerData->IPQLock);
m = ipq_get_packet(buf);
......
......@@ -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
......@@ -90,7 +90,7 @@ struct flow_t
// 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 @@ struct flow_t
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
......
......@@ -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 @@ static char *createTrafficRuleset(GHashTable *properties)
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 @@ static struct flow_t* createFlow(
long int maxRate,
long int burstRate,
unsigned long int nfmark,
unsigned char prioClassifier,
float parent_th,
int reportTimeout)
{
......@@ -676,6 +680,9 @@ static struct flow_t* createFlow(
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 @@ static struct flow_t* createFlow(
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 @@ static struct flow_t* createFlow(
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 @@ struct flowData_t createFlowData(char *filename)
char *p;
long int statsLen, maxQueueSize, maxQueueLen, maxRate, burstRate, reportTimeout;
unsigned long int nfmark;