// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2009 XORP, Inc. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License, Version // 2.1, June 1999 as published by the Free Software Foundation. // Redistribution and/or modification of this program under the terms of // any other version of the GNU Lesser General Public License is not // permitted. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details, // see the GNU Lesser General Public License, Version 2.1, a copy of // which can be found in the XORP LICENSE.lgpl file. // // XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA; // http://xorp.net // $XORP: xorp/libxorp/asnum.hh,v 1.21 2009/01/05 18:30:57 jtc Exp $ #ifndef __LIBXORP_ASNUM_HH__ #define __LIBXORP_ASNUM_HH__ #include "libxorp/xorp.h" #include "libxorp/exceptions.hh" #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #include "c_format.hh" /** * @short A class for storing an AS number used by protocols such as BGP * * This class can be used to store an AS number that can be either 16 * or 32 bits. Originally, the AS numbers were defined as 16-bit * unsigned numbers. Later the "extended" AS numbers were introduced, * which are unsigned 32-bit numbers. Conventional terminology refers * to the 32-bit version as 4-byte AS numbers rather than 32-bit AS * numbers, so we'll try and stick with that where it makes sense. * * 2-byte numbers are expanded to 32-bits by extending them with 0's in front. * 4-byte numbers are represented in a 2-byte AS path, by a special * 16-bit value, AS_TRAN, which will be allocated by IANA. * Together with any AsPath containing AS_TRAN, we will always see a * AS4_PATH attribute which contains the full 32-bit representation * of the path. So there is no loss of information. * * IANA refers to NEW_AS_PATH, but the latest internet drafts refer to * AS4_PATH. They're the same thing, but I the latter is preferred so * we'll use that. * * The internal representation of an AsNum is 32-bit in host order. * * The canonical string form of a 4-byte AS number is <high>.<low>, so * decimal 65536 ends up being printed as "1.0". * * An AsNum must always be initialized, so the default constructor * is never called. */ class AsNum { public: static const uint16_t AS_INVALID = 0; // XXX IANA-reserved static const uint16_t AS_TRAN = 23456; // IANA /** * Constructor. * @param value the value to assign to this AS number. */ explicit AsNum(const uint32_t value) : _as(value) { } explicit AsNum(const uint16_t value) : _as(value) {} explicit AsNum(int value) { assert(value >= 0 && value <= 0xffff); _as = value; } /** * construct from a 2-byte buffer in memory */ explicit AsNum(const uint8_t *d) { _as = (d[0] << 8) + d[1]; } /** * construct from a 2-byte buffer in memory or a 4 byte buffer (in * net byte order). * * The 4byte parameter is mostly to distinguish this from the * 2-byte constructor above. */ explicit AsNum(const uint8_t *d, bool fourbyte) { if (fourbyte) { // 4 byte version memcpy(&_as, d, 4); _as = htonl(_as); } else { // 2 byte version _as = (d[0] << 8) + d[1]; } } /** * construct from a string, either as a decimal number in the * range 1-65535, or as two decimal numbers x.y, where x and y are * in the range 0-65535 */ explicit AsNum(const string& as_str) throw(InvalidString) { bool four_byte = false; bool seen_digit = false; for (uint32_t i = 0; i < as_str.size(); i++) { if (as_str[i] == '.') { if (four_byte || seen_digit == false) { // more than one dot, or no number before the first dot. xorp_throw(InvalidString, c_format("Bad AS number \"%s\"", as_str.c_str())); } else { four_byte = true; seen_digit = false; } } else if (!isdigit(as_str[i])) { // got some disallowed character xorp_throw(InvalidString, c_format("Bad AS number \"%s\"", as_str.c_str())); } else { seen_digit = true; } } if (seen_digit == false) { // either no digit here, or no digit after the dot xorp_throw(InvalidString, c_format("Bad AS number \"%s\"", as_str.c_str())); } // got here, so the text is in the right format if (!four_byte) { _as = atoi(as_str.c_str()); if (_as < 1 || _as > 65535) { // out of range xorp_throw(InvalidString, c_format("Bad AS number \"%s\"", as_str.c_str())); } } else { uint32_t upper = strtoul(as_str.c_str(), NULL, 10); uint32_t lower = strtoul(strchr(as_str.c_str(), '.') + 1, NULL, 10); if (upper > 65535 || lower > 65535) { // out of range xorp_throw(InvalidString, c_format("Bad AS number \"%s\"", as_str.c_str())); } _as = (upper << 16) | lower; } } /** * Get the non-extended AS number value. * * @return the non-extended AS number value. */ uint16_t as() const { return extended() ? AS_TRAN : _as; } /** * Get the extended AS number value. * * @return the extended AS number value. */ uint32_t as4() const { return _as; } /** * copy the 16-bit value into a 2-byte memory buffer */ void copy_out(uint8_t *d) const { uint16_t x = as(); d[0] = (x >> 8) & 0xff; d[1] = x & 0xff; } /** * copy the 32-bit value into a 4-byte network byte order memory buffer */ void copy_out4(uint8_t *d) const { // note - buffer may be unaligned, so use memcpy uint32_t x = htonl(_as); memcpy(d, &x, 4); } /** * Test if this is an extended AS number. * * @return true if this is an extended AS number. */ bool extended() const { return _as>0xffff;}; /** * Equality Operator * * @param other the right-hand operand to compare against. * @return true if the left-hand operand is numerically same as the * right-hand operand. */ bool operator==(const AsNum& x) const { return _as == x._as; } /** * Less-Than Operator * @return true if the left-hand operand is numerically smaller than the * right-hand operand. */ bool operator<(const AsNum& x) const { return _as < x._as; } /** * Convert this AS number from binary form to presentation format. * * @return C++ string with the human-readable ASCII representation * of the AS number. */ string str() const { if (extended()) return c_format("AS/%u.%u", (_as >> 16)&0xffff, _as&0xffff); else return c_format("AS/%u", XORP_UINT_CAST(_as)); } string short_str() const { if (extended()) return c_format("%u.%u", (_as >> 16)&0xffff, _as&0xffff); else return c_format("%u", XORP_UINT_CAST(_as)); } string fourbyte_str() const { // this version forces the long canonical format return c_format("%u.%u", (_as >> 16)&0xffff, _as&0xffff); } private: uint32_t _as; // The value of the AS number AsNum(); // forbidden }; #endif // __LIBXORP_ASNUM_HH__