Merged overlay_payload and overlay_frame structures to just overlay_frame

which is now used for both encapsulation and decapsulation.
Improved payload length encoding scheme to be shorter for most payload
lengths.
selfannouncement frames now get directed to stub functions for
implementation.
This commit is contained in:
gardners 2011-08-17 10:52:17 +09:30
parent 62a7a65fd6
commit b075b51c43
8 changed files with 269 additions and 106 deletions

123
mphlr.h
View File

@ -373,6 +373,43 @@ int packetSendRequest(int method,unsigned char *packet,int packet_len,int batchP
struct response_set *responses);
typedef struct overlay_frame {
struct overlay_frame *prev;
struct overlay_frame *next;
unsigned int type;
unsigned int modifiers;
unsigned char ttl;
unsigned char nexthop[32];
int nexthop_address_status;
unsigned char destination[32];
int destination_address_status;
unsigned char source[32];
int source_address_status;
/* Frame content from destination address onwards */
unsigned int bytecount;
unsigned char *bytes;
/* Actual payload */
unsigned int payloadlength;
unsigned char *payload;
int payloadFreeP; /* Set if this needs to be freed on disposal
of the frame */
int rfs; /* remainder of frame size */
long long enqueued_at;
} overlay_frame;
int overlay_frame_process(int interface,overlay_frame *f);
int overlay_frame_resolve_addresses(int interface,overlay_frame *f);
#define CRYPT_CIPHERED 1
#define CRYPT_SIGNED 2
@ -503,46 +540,16 @@ typedef struct overlay_buffer {
int allocSize;
int checkpointLength;
int sizeLimit;
int var_length_offset;
int var_length_bytes;
} overlay_buffer;
int ob_unlimitsize(overlay_buffer *b);
typedef struct overlay_payload {
struct overlay_payload *prev;
struct overlay_payload *next;
/* We allows 256 bit addresses and 32bit port numbers */
unsigned char src[SIDDIDFIELD_LEN];
unsigned char dst[SIDDIDFIELD_LEN];
int srcPort;
int dstPort;
/* Hops before packet is dropped */
unsigned char ttl;
unsigned char trafficClass;
unsigned char srcAddrType;
unsigned char dstAddrType;
/* Method of encryption if any employed */
unsigned char cipher;
/* Payload flags */
unsigned char flags;
/* Size and Pointer to the payload itself */
int payloadLength;
/* make the payload pointer be at the end, so that we can conveniently have the data follow this structure if necessary.
(this lets us change the char * to a char payload[1] down the track to simplify this) */
unsigned char *payload;
/* time this frame was enqueued */
long long enqueued_at;
} overlay_payload;
typedef struct overlay_txqueue {
overlay_payload *first;
overlay_payload *last;
struct overlay_frame *first;
struct overlay_frame *last;
int length;
int maxLength;
/* Latency target in ms for this traffic class.
@ -578,8 +585,11 @@ int ob_makespace(overlay_buffer *b,int bytes);
int ob_append_bytes(overlay_buffer *b,unsigned char *bytes,int count);
int ob_append_short(overlay_buffer *b,unsigned short v);
int ob_append_int(overlay_buffer *b,unsigned int v);
int ob_patch_rfs(overlay_buffer *b,int l);
int ob_indel_space(overlay_buffer *b,int offset,int shift);
int ob_append_rfs(overlay_buffer *b,int l);
int op_free(overlay_payload *p);
int op_free(overlay_frame *p);
long long parse_quantity(char *q);
@ -593,7 +603,7 @@ long long overlay_time_until_next_tick();
int overlay_rx_messages();
int overlay_check_ticks();
int overlay_add_selfannouncement();
int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b);
int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b);
int overlay_interface_args(char *arg);
int overlay_get_nexthop(unsigned char *final_destination,unsigned char *nexthop,int *nexthoplen);
@ -627,7 +637,7 @@ extern int overlay_interface_count;
#define OF_TYPE_FLAG_BITS 0xf0000000
#define OF_TYPE_FLAG_NORMAL 0x0
#define OF_TYPE_FLAG_E12 0x10000000
#define OF_TYPE_FLAG_E20 0x00000000
#define OF_TYPE_FLAG_E20 0x20000000
/* Modifiers that indicate the disposition of the frame */
#define OF_MODIFIER_BITS 0x0f
@ -648,6 +658,8 @@ extern int overlay_interface_count;
#define OVERLAY_ADDRESS_CACHE_SIZE 1024
int overlay_abbreviate_address(unsigned char *in,char *out,int *ofs);
int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a);
int overlay_abbreviate_expand_address(int interface,unsigned char *in,int *inofs,unsigned char *out,int *ofs);
int overlay_abbreviate_cache_address(unsigned char *sid);
int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *ofs,
@ -682,32 +694,13 @@ int overlay_abbreviate_set_most_recent_address(unsigned char *in);
/* The TTL field in a frame is used to differentiate between link-local and wide-area broadcasts */
#define OA_CODE_BROADCAST 0x0f
typedef struct overlay_frame {
unsigned int type;
unsigned int modifiers;
#define RFS_PLUS250 0xfa
#define RFS_PLUS456 0xfb
#define RFS_PLUS762 0xfc
#define RFS_PLUS1018 0xfd
#define RFS_PLUS1274 0xfe
#define RFS_3BYTE 0xff
int rfs_length(int l);
int rfs_encode(int l,unsigned char *b);
int rfs_decode(unsigned char *b,int *offset);
unsigned char ttl;
unsigned char nexthop[32];
int nexthop_address_status;
unsigned char destination[32];
int destination_address_status;
unsigned char source[32];
int source_address_status;
/* Frame content from destination address onwards */
unsigned int bytecount;
unsigned char *bytes;
/* Actual payload */
unsigned int payloadlength;
unsigned char *payload;
int rfs; /* remainder of frame size */
} overlay_frame;
int overlay_frame_process(int interface,overlay_frame *f);
int overlay_frame_resolve_addresses(int interface,overlay_frame *f);

View File

@ -200,16 +200,26 @@ int overlay_frame_process(int interface,overlay_frame *f)
return WHY("Could not find next hop for host - dropping frame");
f->ttl--;
/* Queue frame for dispatch */
/* XXX We currently have separate overlay_payload structures for sending and
overlay_frame for receiving. Need to harmonise this. Multiple conversions
are wasteful. We really should be able to cope with a single structure. */
return WHY("forwarding of frame not implemented");
WHY("forwarding of frame not implemented");
/* If the frame was a broadcast frame, then we need to hang around
so that we can process it, since we are one of the recipients.
Otherwise, return triumphant. */
if (!broadcast) return 0;
}
switch(f->type)
{
case OF_TYPE_SELFANNOUNCE:
overlay_route_saw_selfannounce(f);
break;
case OF_TYPE_SELFANNOUNCE_ACK:
overlay_route_saw_selfannounce_ack(f);
break;
default:
return WHY("Support for that f->type not yet implemented");

View File

@ -203,6 +203,16 @@ int overlay_abbreviate_try_byindex(unsigned char *in,char *out,int *ofs,int inde
return 1;
}
int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a)
{
int count=0;
ob_makespace(b,SID_SIZE+3);
int r=overlay_abbreviate_address(a,&b->bytes[b->length],&count);
if (r) return r;
b->length+=count;
return 0;
}
int overlay_abbreviate_address(unsigned char *in,char *out,int *ofs)
{
int i;

View File

@ -1,6 +1,5 @@
#include "mphlr.h"
overlay_buffer *ob_new(int size)
{
overlay_buffer *ret=calloc(sizeof(overlay_buffer),1);
@ -99,3 +98,91 @@ int ob_append_int(overlay_buffer *b,unsigned int v)
unsigned int s=htonl(v);
return ob_append_bytes(b,(unsigned char *)&s,sizeof(unsigned int));
}
int ob_append_rfs(overlay_buffer *b,int l)
{
/* Encode the specified length and append it to the buffer */
if (l<0||l>0xffff) return -1;
/* First work out how long the field needs to be, then write dummy bytes
and use ob_patch_length to set the value. That way we have only one
lot of code that does the encoding. */
b->var_length_offset=b->length;
b->var_length_bytes=rfs_length(l);
unsigned char c[3]={0,0,0};
if (ob_append_bytes(b,c,b->var_length_bytes)) {
b->var_length_offset=0;
return -1;
}
return ob_patch_rfs(b,l);
}
int rfs_length(int l)
{
if (l<0) return -1;
if (l<250) return 1;
else if (l<(255+250+(256*4))) return 2;
else if (l<=0xffff) return 3;
else return -1;
}
int rfs_encode(int l, unsigned char *b)
{
if (l<250) { b[0]=l; }
else if (l<(255+250+(256*4))) {
b[0]=RFS_PLUS250+(l-250)/256;
b[1]=l-((l-250)/256);
} else {
b[0]=RFS_3BYTE;
b[1]=l>>8;
b[2]=l&0xff;
}
return 0;
}
int rfs_decode(unsigned char *b,int *ofs)
{
int rfs=b[*ofs];
switch(rfs) {
case RFS_PLUS250: case RFS_PLUS456: case RFS_PLUS762: case RFS_PLUS1018: case RFS_PLUS1274:
rfs=250+256*(rfs-RFS_PLUS250)+b[++(*ofs)];
break;
case RFS_3BYTE: rfs=(b[(*ofs)+1]<<8)+b[(*ofs)+2]; (*ofs)+=2;
default: /* Length is natural value of field, so nothing to do */
break;
}
(*ofs)++;
return rfs;
}
int ob_indel_space(overlay_buffer *b,int offset,int shift)
{
if (shift>0) { /* make space */
if (ob_makespace(b,-shift)) return -1;
bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->length-(offset+shift));
} else if (shift<0) { /* free up space */
bcopy(&b->bytes[offset],&b->bytes[offset-shift],b->length-(offset-shift));
}
b->length+=shift;
return 0;
}
int ob_patch_rfs(overlay_buffer *b,int l)
{
if (l<0||l>0xffff) return -1;
/* Adjust size of field */
int new_size=rfs_length(l);
int shift=new_size-b->var_length_bytes;
if (ob_indel_space(b,b->var_length_offset,shift)) return -1;
if (rfs_encode(l,&b->bytes[b->var_length_offset])) return -1;
return 0;
}

View File

@ -452,7 +452,7 @@ int overlay_tick_interface(int i, long long now)
{
int frame_pax=0;
#define MAX_FRAME_PAX 1024
overlay_payload *pax[MAX_FRAME_PAX];
overlay_frame *pax[MAX_FRAME_PAX];
if (overlay_interfaces[i].bits_per_second<1) {
/* An interface with no speed budget is for listening only, so doesn't get ticked */
@ -481,11 +481,11 @@ int overlay_tick_interface(int i, long long now)
overlay_add_selfannouncement(i,e);
/* 2. Add any queued high-priority isochronous data (i.e. voice) to the frame. */
overlay_payload **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first;
overlay_frame **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first;
while(p)
{
/* Throw away any stale frames */
overlay_payload *pp=*p;
overlay_frame *pp=*p;
if (!pp) break;
@ -505,7 +505,7 @@ int overlay_tick_interface(int i, long long now)
bad. The only hard limit is the maximum number of payloads we allow in a frame, which is
set so high as to be irrelevant, even on loopback or gigabit ethernet interface */
if (frame_pax>=MAX_FRAME_PAX) break;
if (!overlay_payload_package_fmt1(*p,e))
if (!overlay_frame_package_fmt1(*p,e))
{
/* Add payload to list of payloads we are sending with this frame so that we can dequeue them
if we send them. */
@ -533,7 +533,7 @@ int overlay_tick_interface(int i, long long now)
overlay_interfaces[i].sequence_number,i,e->length);
/* De-queue the passengers who were aboard. */
int j;
overlay_payload **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first;
overlay_frame **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first;
for(j=0;j<frame_pax;j++)
{
/* Skip any frames that didn't get queued */

View File

@ -22,9 +22,9 @@ int packetOkOverlay(int interface,unsigned char *packet,int len,unsigned char *t
All frames have the following fields:
Frame type (8bits)
Frame type (8-24bits)
TTL (8bits)
Remaining frame size (RFS) (8bits for <256 bytes, 16bits for <510 bytes etc)
Remaining frame size (RFS) (see overlay_payload.c or overlay_buffer.c for explanation of format)
Next hop (variable length due to address abbreviation)
Destination (variable length due to address abbreviation)*
Source (variable length due to address abbreviation)*
@ -119,10 +119,8 @@ int packetOkOverlay(int interface,unsigned char *packet,int len,unsigned char *t
/* Get time to live */
f.ttl=packet[ofs++];
/* Get length of remainder of frame */
f.rfs=packet[ofs];
while (packet[ofs]==0xff&&(ofs<len)&&(f.rfs<16384)) f.rfs+=packet[++ofs];
ofs++;
/* Decode length of remainder of frame */
f.rfs=rfs_decode(packet,&ofs);
if (!f.rfs) {
/* Zero length -- assume we fell off the end of the packet */

View File

@ -1,6 +1,6 @@
#include "mphlr.h"
int overlay_payload_verify(overlay_payload *p)
int overlay_payload_verify(overlay_frame *p)
{
/* Make sure that an incoming payload has a valid signature from the sender.
This is used to prevent spoofing */
@ -8,12 +8,43 @@ int overlay_payload_verify(overlay_payload *p)
return WHY("function not implemented");
}
int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b)
int op_append_type(overlay_buffer *headers,overlay_frame *p)
{
/* Convert a payload structure into a series of bytes.
Also select next-hop address to help payload get to its' destination */
unsigned char c[3];
switch(p->type&OF_TYPE_FLAG_BITS)
{
case OF_TYPE_FLAG_NORMAL:
c[0]=p->type|p->modifiers;
if (ob_append_bytes(headers,c,1)) return -1;
break;
case OF_TYPE_FLAG_E12:
c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED12;
c[1]=(p->type>>4)&0xff;
if (ob_append_bytes(headers,c,2)) return -1;
break;
case OF_TYPE_FLAG_E20:
c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED20;
c[1]=(p->type>>4)&0xff;
c[2]=(p->type>>12)&0xff;
if (ob_append_bytes(headers,c,3)) return -1;
break;
default:
/* Don't know this type of frame */
WHY("Asked for format frame with unknown TYPE_FLAG bits");
return -1;
}
return 0;
}
unsigned char nexthop[SIDDIDFIELD_LEN+1];
int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b)
{
/* Convert a payload (frame) structure into a series of bytes.
Assumes that any encryption etc has already been done.
Will pick a next hop if one has not been chosen.
*/
unsigned char c[64];
int nexthoplen=0;
overlay_buffer *headers=ob_new(256);
@ -25,31 +56,55 @@ int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b)
/* Build header */
int fail=0;
if (overlay_get_nexthop((unsigned char *)p->dst,nexthop,&nexthoplen)) fail++;
if (ob_append_bytes(headers,nexthop,nexthoplen)) fail++;
if (p->nexthop_address_status!=OA_RESOLVED) {
if (overlay_get_nexthop((unsigned char *)p->destination,p->nexthop,&nexthoplen)) fail++;
else p->nexthop_address_status=OA_RESOLVED;
}
/* XXX Can use shorter fields for different address types, and if we know that the next hop
knows a short-hand for the address.
XXX Need a prefix byte for the type of address being used.
BETTER - We just insist that the first byte of Curve25519 addresses be >0x0f, and use
the low numbers for special cases:
*/
if (p->src[0]<0x10||p->dst[0]<0x10) {
if (p->source[0]<0x10||p->destination[0]<0x10||p->nexthop[0]<0x10) {
// Make sure that addresses do not overload the special address spaces of 0x00*-0x0f*
fail++;
return WHY("address begins with reserved value 0x00-0x0f");
return WHY("one or more packet addresses begins with reserved value 0x00-0x0f");
}
if (ob_append_bytes(headers,(unsigned char *)p->src,SIDDIDFIELD_LEN)) fail++;
if (ob_append_bytes(headers,(unsigned char *)p->dst,SIDDIDFIELD_LEN)) fail++;
/* XXX Write fields in correct order */
/* Write out type field byte(s) */
if (op_append_type(headers,p)) fail++;
/* Write out TTL */
c[0]=p->ttl; if (ob_append_bytes(headers,c,1)) fail++;
/* Length. This is the fun part, because we cannot calculate how many bytes we need until
we have abbreviated the addresses, and the length encoding we use varies according to the
length encoded. The simple option of running the abbreviations twice won't work because
we rely on context for abbreviating the addresses. So we write it initially and then patch it
after.
*/
int max_len=((SID_SIZE+3)*3+headers->length+p->payloadlength);
ob_append_rfs(b,max_len);
int addrs_len=b->length;
/* Write out addresses as abbreviated as possible */
overlay_abbreviate_append_address(b,p->nexthop);
overlay_abbreviate_set_most_recent_address(p->nexthop);
overlay_abbreviate_append_address(b,p->destination);
overlay_abbreviate_set_most_recent_address(p->destination);
overlay_abbreviate_append_address(b,p->source);
overlay_abbreviate_set_most_recent_address(p->source);
addrs_len=b->length-addrs_len;
int actual_len=addrs_len+p->payloadlength;
ob_patch_rfs(b,actual_len);
if (fail) {
ob_free(headers);
return WHY("failure count was non-zero");
}
/* Write payload format plus total length of header bits */
if (ob_makespace(b,2+headers->length+p->payloadLength)) {
if (ob_makespace(b,2+headers->length+p->payloadlength)) {
/* Not enough space free in output buffer */
ob_free(headers);
return WHY("Could not make enough space free in output buffer");
@ -57,11 +112,11 @@ int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b)
/* Package up headers and payload */
ob_checkpoint(b);
if (ob_append_short(b,0x1000|(p->payloadLength+headers->length)))
if (ob_append_short(b,0x1000|(p->payloadlength+headers->length)))
{ fail++; WHY("could not append version and length bytes"); }
if (ob_append_bytes(b,headers->bytes,headers->length))
{ fail++; WHY("could not append header"); }
if (ob_append_bytes(b,p->payload,p->payloadLength))
if (ob_append_bytes(b,p->payload,p->payloadlength))
{ fail++; WHY("could not append payload"); }
/* XXX SIGN &/or ENCRYPT */
@ -71,14 +126,14 @@ int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b)
if (fail) { ob_rewind(b); return WHY("failure count was non-zero"); } else return 0;
}
overlay_payload *overlay_payload_unpackage(overlay_buffer *b) {
overlay_buffer *overlay_payload_unpackage(overlay_frame *b) {
/* Extract the payload at the current location in the buffer. */
WHY("not implemented");
return NULL;
}
int overlay_payload_enqueue(int q,overlay_payload *p)
int overlay_payload_enqueue(int q,overlay_frame *p)
{
/* Add payload p to queue q.
*/
@ -86,7 +141,7 @@ int overlay_payload_enqueue(int q,overlay_payload *p)
return WHY("not implemented");
}
int op_free(overlay_payload *p)
int op_free(overlay_frame *p)
{
if (!p) return WHY("Asked to free NULL");
if (p->prev&&p->prev->next==p) return WHY("p->prev->next still points here");

View File

@ -4,3 +4,13 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *nexthoplen)
{
return WHY("Not implemented");
}
int overlay_route_saw_selfannounce(overlay_frame *f)
{
return WHY("Not implemented");
}
int overlay_route_saw_selfannounce_ack(overlay_frame *f)
{
return WHY("Not implemented");
}