/* TEST: int BGP_addPathAttributeToUpdate(BGPMessage* msg, uint16_t type, uint16_t length, const uint8_t *value); * */ void testBGP_addPathAttributeToUpdate() { uint8_t flags1 = 0x40; uint8_t code1 = 0xFF; uint8_t flags2 = 0x50; uint8_t code2 = 0xF0; uint16_t length = 1; uint8_t value = 0xFF; BGPUpdate *update = (BGPUpdate*)bgpMessage->typeSpecific; CU_ASSERT(0 == BGP_addPathAttributeToUpdate(bgpMessage,flags1,code1,0,NULL)); CU_ASSERT(-1 == BGP_addPathAttributeToUpdate(bgpMessage,flags1,code1,length,NULL)); CU_ASSERT(0 == BGP_addPathAttributeToUpdate(bgpMessage,flags1,code1,length,&value)); CU_ASSERT(NULL != update->pathAtts); if(NULL == update->pathAtts) { return; } CU_ASSERT(1 == update->totalPathAttsCount); CU_ASSERT(0x40 == update->pathAtts[0]->flags); CU_ASSERT(0xFF == update->pathAtts[0]->code); CU_ASSERT(1 == update->pathAtts[0]->length); CU_ASSERT(value == update->pathAtts[0]->value[0]); CU_ASSERT(1 == (BGP_PAL_LEN(update->pathAtts[0]->flags))); CU_ASSERT(0 == BGP_addPathAttributeToUpdate(bgpMessage,flags2,code2,length,&value)); CU_ASSERT(2 == update->totalPathAttsCount); CU_ASSERT(0x50 == update->pathAtts[0]->flags); CU_ASSERT(0xF0 == update->pathAtts[0]->code); CU_ASSERT(1 == update->pathAtts[0]->length); CU_ASSERT(value == update->pathAtts[0]->value[0]); CU_ASSERT(2 == (BGP_PAL_LEN(update->pathAtts[0]->flags))); CU_ASSERT(0x40 == update->pathAtts[1]->flags); CU_ASSERT(0xFF == update->pathAtts[1]->code); CU_ASSERT(1 == update->pathAtts[1]->length); CU_ASSERT(value == update->pathAtts[1]->value[0]); CU_ASSERT(1 == (BGP_PAL_LEN(update->pathAtts[1]->flags))); return; }
/****************************************************************************** Name: BGP_calculateLength Input: A pointer to the BGPMessage Output: The number of bytes anticipated in the message Author: Catherine Olschanowsky ******************************************************************************/ int BGP_calculateLength(BGPMessage* msg, int asnLen) { int i; // the first task should be too allocate enough space to hold the message, // but we don't know what that is. // so, the first thing we need to do is calculate how long the message // is going to turn out to be. int length_in_bytes = BGP_HEADER_LENGTH; if(msg->type == BGP_UPDATE){ BGPUpdate *update = (BGPUpdate*)msg->typeSpecific; // withdrawn routes length_in_bytes += 2; // space for the length for(i=0;i<update->withdrawnRoutesCount;i++){ length_in_bytes += 1; // for the length of this prefix length_in_bytes += update->withdrawnRoutes[i]->length/8; if(update->withdrawnRoutes[i]->length%8 != 0){ length_in_bytes++; } } // path attributes length_in_bytes += 2; // space for the length for(i=0;i<update->totalPathAttsCount;i++){ length_in_bytes += 2; // type length_in_bytes += BGP_PAL_LEN(update->pathAtts[i]->flags); length_in_bytes += update->pathAtts[i]->length; // value // one special case due to ASN4 versus ASN2 if(update->pathAtts[i]->code == BGP_PATTR_AS_PATH){ // AS_PATH is a well-known mandatory attribute that is composed // of a sequence of AS path segments. Each AS path segment is // represented by a triple <path segment type, path segment // length, path segment value>. // The path segment type is a 1-octet length field with the // following values defined: // Value Segment Type // 1 AS_SET: unordered set of ASes a route in the // UPDATE message has traversed // 2 AS_SEQUENCE: ordered set of ASes a route in // the UPDATE message has traversed // The path segment length is a 1-octet length field, // containing the number of ASes (not the number of octets) in // the path segment value field. // The path segment value field contains one or more AS // numbers, each encoded as a 2-octet length field. // the above text is taken from RFC 4271, however, this code must handle // AS_PATHs created by MRT and therefore, the ASes might be 4 bytes // this code is used to calculate the length of an AS_PATH assuming that // it is to be truncated from 4 bytes to 2 bytes -- I believe this is // only useful from the MRT module // we can calculate the length by looking at the path segment length // multiplying that value by 2 and subtracting it from the length in the // path attribute header if(asnLen == 2){ // this has to be done for each segment int idz; for(idz = 1; idz < update->pathAtts[i]->length; ){ length_in_bytes -= (update->pathAtts[i]->value[idz]*2); idz += update->pathAtts[i]->value[idz]*4 + 1; } } } } // nlri for(i=0;i<update->nlriCount;i++){ length_in_bytes += 1; length_in_bytes += update->nlris[i]->length/8; if((update->nlris[i]->length%8) != 0){ length_in_bytes += 1; } } msg->length = length_in_bytes; }else{ // only updates are supported at this point return 0; } return length_in_bytes; }
/****************************************************************************** Name: BGP_serialize Input: A pointer to the BGPMessage, 1 to translate asns to 2 bytes, 0 to leave them as 4 byte ASNs Output: A pointer to the binary message (note that msg->length is changed to reflect the number of bytes. (not including the header) Author: Catherine Olschanowsky ******************************************************************************/ int BGP_serialize(uint8_t* bits,BGPMessage* msg, int asnLen) { // currently only support update if(msg->type != BGP_UPDATE){ return -1; } BGPUpdate *update = (BGPUpdate*)msg->typeSpecific; // i will keep our place in the message as we populate int i; // l will be used to hold the place of a length field // this way we can add the bits for that section // before we know the length and then go back int lm,l; // lm is the main length for the whole message // idx is for loops that don't move us along inthe msg int idx,idy; // add in the BGP header for(i=0;i<16;i++){ bits[i] = 0xFF; } lm = i; i+=2; bits[i]=msg->type; i+=1; // Add the withdrawn routes // skip the length for now l=i; i+=2; for(idx=0;idx<update->withdrawnRoutesCount;idx++){ bits[i]=update->withdrawnRoutes[idx]->length; i+=1; for(idy=0;idy<update->withdrawnRoutes[idx]->length/8;idy++){ bits[i]=update->withdrawnRoutes[idx]->prefix[idy]; i+=1; } if(update->withdrawnRoutes[idx]->length%8 != 0){ bits[i]=update->withdrawnRoutes[idx]->prefix[idy]; i+=1; } } // Add the length back in: the 2 is here because of the length of the length field BGP_ASSIGN_2BYTES(&bits[l],(uint16_t)(i-l-2)); // Add in the path attributes l = i; // l marks the spot for the length i+=2; // i is incremented to leave the length spot alone for(idx=0;idx<update->totalPathAttsCount;idx++){ bits[i] = update->pathAtts[idx]->flags; i+=1; bits[i] = update->pathAtts[idx]->code; i+=1; // this is the base case. // For all attributes other than AS_PATH we don't mess with them // we are looking at // <type, length, value> // type is flags+code which we took care of above // this logic is to determine if we have a length of one or two if(update->pathAtts[idx]->code != BGP_PATTR_AS_PATH){ // Path Attribute Length (PAL) length is 1 if(1 == (BGP_PAL_LEN(update->pathAtts[idx]->flags))){ bits[i] = (uint8_t)update->pathAtts[idx]->length; i+=1; }else{ // Path Attribute Length (PAL) length is 2 BGP_ASSIGN_2BYTES(&bits[i],update->pathAtts[idx]->length); i+=2; } // now that we have the length we just copy the value over // byte at a time for(idy=0;idy<update->pathAtts[idx]->length;idy++){ bits[i] = update->pathAtts[idx]->value[idy]; i+=1; } }else{ // AS_PATH is a well-known mandatory attribute that is composed // of a sequence of AS path segments. Each AS path segment is // represented by a triple <path segment type, path segment // length, path segment value>. // The path segment type is a 1-octet length field with the // following values defined: // Value Segment Type // 1 AS_SET: unordered set of ASes a route in the // UPDATE message has traversed // 2 AS_SEQUENCE: ordered set of ASes a route in // the UPDATE message has traversed // The path segment length is a 1-octet length field, // containing the number of ASes (not the number of octets) in // the path segment value field. // The path segment value field contains one or more AS // numbers, each encoded as a 2-octet length field. // the above text is taken from RFC 4271, however, this code must handle // AS_PATHs created by MRT and therefore, the ASes might be 4 bytes // this code is used to calculate the length of an AS_PATH assuming that // it is to be truncated from 4 bytes to 2 bytes -- I believe this is // only useful from the MRT module // http://tools.ietf.org/html/rfc4893 describes how to properly handle // 4 byte ASNs that cannot be reduced to 2 bytes, however, this is not // really needed as we have a simplified case. Either, we have 2 byte // ASNs that have been promoted to 4 byte ASNs within MRT (and can therefore, // be truncated) or we have a router that can handle 4 byte ASNs in which // case we leave them be // we can calculate the length by looking at the path segment length // multiplying that value by 2 and subtracting it from the length in the // path attribute header // <type, length, value> // type is flags+code which we took care of above // this logic is to determine if we have a length of one or two // if the Path attribute length (PAL) length is 1 int l2 = i; // hold the place for the length (l is already in use) if((BGP_PAL_LEN(update->pathAtts[idx]->flags)) == 1){ i+=1; }else{ i+=2; } // now we look into creating the value // <path segment type, path segment length, path segment value> for(idy = 0; idy < update->pathAtts[idx]->length; ){ bits[i] = update->pathAtts[idx]->value[idy]; // path segment type i++; idy++; int psl = bits[i] = update->pathAtts[idx]->value[idy]; // path segment length i++; idy++; // need to translate to 2 byte asns if(asnLen == 2){ int idz; for(idz = 0; (idz/4) < psl; ){ uint32_t tmp; BGP_READ_4BYTES(tmp,update->pathAtts[idx]->value[idy+idz]); BGP_ASSIGN_2BYTES(&bits[i],(uint16_t)tmp); i+=2; idz+=4; } idy+=idz; // can keep asns at 4 bytes (just copy) }else{ int idz; for(idz = 0; idz < psl; idz++){ bits[i] = update->pathAtts[idx]->value[idy+idz]; i+=1; } idy+=idz; } } // go back and add in the length of this path attribute if((BGP_PAL_LEN(update->pathAtts[idx]->flags)) == 1){ bits[l2] = (uint8_t)(i-l2-1); }else{ BGP_ASSIGN_2BYTES(&bits[l2],(uint16_t)(i-l2-2)); } } } // Add the length back in: the 2 is here because of the length of the length field BGP_ASSIGN_2BYTES(&bits[l],(uint16_t)(i-l-2)); // Add in the NLRI information for(idx=0; idx<update->nlriCount;idx++){ bits[i] = update->nlris[idx]->length; i+=1; for(idy=0;idy<(update->nlris[idx]->length/8);idy++){ bits[i] = update->nlris[idx]->prefix[idy]; i+=1; } if(update->nlris[idx]->length%8 > 0){ bits[i] = update->nlris[idx]->prefix[idy]; i+=1; } } BGP_ASSIGN_2BYTES(&bits[lm],i); msg->length = i; return 0; }