def unpack (cls, data): datalen = len(data) rd = RouteDistinguisher.unpack(data[:8]) esi = ESI.unpack(data[8:18]) etag = EthernetTag.unpack(data[18:22]) maclength = ord(data[22]) if (maclength > 48 or maclength < 0): raise Notify(3,5,'invalid MAC Address length in %s' % cls.NAME) end = 23 + 6 # MAC length MUST be 6 mac = MACQUAL.unpack(data[23:end]) length = ord(data[end]) iplen = length / 8 if datalen in [33,36]: # No IP information (1 or 2 labels) iplenUnpack = 0 if iplen != 0: raise Notify(3,5,"IP length is given as %d, but current MAC route has no IP information" % iplen) elif datalen in [37, 40]: # Using IPv4 addresses (1 or 2 labels) iplenUnpack = 4 if (iplen > 32 or iplen < 0): raise Notify(3,5,"IP field length is given as %d, but current MAC route is IPv4 and valus is out of range" % iplen) elif datalen in [49, 52]: # Using IPv6 addresses (1 or 2 labels) iplenUnpack = 16 if (iplen > 128 or iplen < 0): raise Notify(3,5,"IP field length is given as %d, but current MAC route is IPv6 and valus is out of range" % iplen) else: raise Notify(3,5,"Data field length is given as %d, but does not match one of the expected lengths" % datalen) ip = IP.unpack(data[end+1:end+1+iplenUnpack]) label = Labels.unpack(data[end+1+iplenUnpack:end+1+iplenUnpack+3]) return cls(rd,esi,etag,mac,maclength,label,ip,data)
def unpack (cls, exdata): data = exdata # Get the data length to understand if addresses are IPv4 or IPv6 datalen = len(data) rd = RouteDistinguisher.unpack(data[:8]) data = data[8:] esi = ESI.unpack(data[:10]) data = data[10:] etag = EthernetTag.unpack(data[:4]) data = data[4:] iplen = ord(data[0]) data = data[1:] if datalen == (26 + 8): # Using IPv4 addresses ip = IP.unpack(data[:4]) data = data[4:] gwip = IP.unpack(data[:4]) data = data[4:] elif datalen == (26 + 32): # Using IPv6 addresses ip = IP.unpack(data[:16]) data = data[16:] gwip = IP.unpack(data[:16]) data = data[16:] else: raise Notify(3,5,"Data field length is given as %d, but EVPN route currently support only IPv4 or IPv6(34 or 58)" % iplen) label = Labels.unpack(data[:3]) return cls(rd,esi,etag,label,ip,iplen,gwip,exdata)
def rd(self, scope, name, command, tokens, safi): try: try: data = tokens.pop(0) except IndexError: return self.error.set(self.syntax) separator = data.find(':') if separator > 0: prefix = data[:separator] suffix = int(data[separator + 1:]) if '.' in prefix: data = [chr(0), chr(1)] data.extend([chr(int(_)) for _ in prefix.split('.')]) data.extend([chr(suffix >> 8), chr(suffix & 0xFF)]) rd = ''.join(data) else: number = int(prefix) if number < pow(2, 16) and suffix < pow(2, 32): rd = chr(0) + chr(0) + pack('!H', number) + pack( '!L', suffix) elif number < pow(2, 32) and suffix < pow(2, 16): rd = chr(0) + chr(2) + pack('!L', number) + pack( '!H', suffix) else: raise ValueError('invalid route-distinguisher %s' % data) nlri = scope[-1]['announce'][-1].nlri # overwrite nlri-mpls nlri.safi = SAFI(safi) nlri.rd = RouteDistinguisher(rd) return True except ValueError: return self.error.set(self.syntax)
def unpack (cls, data): rd = RouteDistinguisher.unpack(data[:8]) esi = ESI.unpack(data[8:18]) etag = EthernetTag.unpack(data[18:22]) label = Labels.unpack(data[22:25]) return cls(rd,esi,etag,label,data)
def unpack_nlri(cls, afi, safi, bgp, action, addpath): length, bgp = ord(bgp[0]), bgp[1:] if length & 0xF0 == 0xF0: # bigger than 240 extra, bgp = ord(bgp[0]), bgp[1:] length = ((length & 0x0F) << 16) + extra if length > len(bgp): raise Notify(3, 10, 'invalid length at the start of the the flow') over = bgp[length:] bgp = bgp[:length] nlri = Flow(afi, safi, action) if safi == SAFI.flow_vpn: nlri.rd = RouteDistinguisher(bgp[:8]) bgp = bgp[8:] seen = [] while bgp: what, bgp = ord(bgp[0]), bgp[1:] if what not in decode.get(afi, {}): raise Notify( 3, 10, 'unknown flowspec component received for address family %d' % what) seen.append(what) if sorted(seen) != seen: raise Notify( 3, 10, 'components are not sent in the right order %s' % seen) decoded = decode[afi][what] klass = factory[afi][what] if decoded == 'prefix': adding, bgp = klass.make(bgp) if not nlri.add(adding): raise Notify( 3, 10, 'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s' % seen) # logger.parser(LazyFormat("added flow %s (%s) payload " % (klass.NAME,adding),bgp[:-len(left)])) else: end = False while not end: byte, bgp = ord(bgp[0]), bgp[1:] end = CommonOperator.eol(byte) operator = CommonOperator.operator(byte) length = CommonOperator.length(byte) value, bgp = bgp[:length], bgp[length:] adding = klass.decoder(value) nlri.add(klass(operator, adding)) # logger.parser(LazyFormat("added flow %s (%s) operator %d len %d payload " % (klass.NAME,adding,byte,length),value)) return nlri, bgp + over
def route_distinguisher(tokeniser): data = tokeniser() separator = data.find(':') if separator > 0: prefix = data[:separator] suffix = int(data[separator + 1:]) if '.' in prefix: data = [character(0), character(1)] data.extend([character(int(_)) for _ in prefix.split('.')]) data.extend([character(suffix >> 8), character(suffix & 0xFF)]) rtd = concat_bytes_i(data) else: number = int(prefix) if number < pow(2, 16) and suffix < pow(2, 32): rtd = character(0) + character(0) + pack('!H', number) + pack( '!L', suffix) elif number < pow(2, 32) and suffix < pow(2, 16): rtd = character(0) + character(2) + pack('!L', number) + pack( '!H', suffix) else: raise ValueError('invalid route-distinguisher %s' % data) return RouteDistinguisher(rtd)
def rd (tokeniser): try: value = tokeniser() separator = value.find(':') if separator > 0: prefix = value[:separator] suffix = int(value[separator+1:]) # XXX: FIXME: we need much more checks here instead that the blank try/except... if '.' in prefix: data = [chr(0),chr(1)] data.extend([chr(int(_)) for _ in prefix.split('.')]) data.extend([chr(suffix >> 8),chr(suffix & 0xFF)]) distinguisher = ''.join(data) else: number = int(prefix) if number < pow(2,16) and suffix < pow(2,32): distinguisher = chr(0) + chr(0) + pack('!H',number) + pack('!L',suffix) elif number < pow(2,32) and suffix < pow(2,16): distinguisher = chr(0) + chr(2) + pack('!L',number) + pack('!H',suffix) else: raise ValueError('invalid route-distinguisher %s' % value) except ValueError: raise ValueError('invalid route-distinguisher %s' % value) return RouteDistinguisher(distinguisher)
def unpack(cls, data): rd = RouteDistinguisher.unpack(data[:8]) esi = ESI.unpack(data[8:18]) etag = EthernetTag.unpack(data[18:22]) label = Labels.unpack(data[22:25]) return cls(rd, esi, etag, label, data)
def unpack_nlri(cls, afi, safi, bgp, action, addpath): nlri = cls(afi, safi, action) if addpath: nlri.path_info = PathInfo(bgp[:4]) bgp = bgp[4:] mask = bgp[0] bgp = bgp[1:] _, rd_size = Family.size.get((afi, safi), (0, 0)) rd_mask = rd_size * 8 if safi.has_label(): labels = [] while mask - rd_mask >= 24: label = int(unpack('!L', bytes([0]) + bgp[:3])[0]) bgp = bgp[3:] mask -= 24 # 3 bytes # The last 4 bits are the bottom of Stack # The last bit is set for the last label labels.append(label >> 4) # This is a route withdrawal if label == 0x800000 and action == IN.WITHDRAWN: break # This is a next-hop if label == 0x000000: break if label & 1: break nlri.labels = Labels(labels) if rd_size: mask -= rd_mask # the route distinguisher rd = bgp[:rd_size] bgp = bgp[rd_size:] nlri.rd = RouteDistinguisher(rd) if mask < 0: raise Notify(3, 10, 'invalid length in NLRI prefix') if not bgp and mask: raise Notify( 3, 10, 'not enough data for the mask provided to decode the NLRI') size = CIDR.size(mask) if len(bgp) < size: raise Notify( 3, 10, 'could not decode route with family %s (AFI %d) %s (SAFI %d)' % (AFI(afi), int(afi), SAFI(safi), int(safi))) network, bgp = bgp[:size], bgp[size:] nlri.cidr = CIDR(network + bytes(IP.length(afi) - size), mask) return nlri, bgp
def unpack (cls, data): rd = RouteDistinguisher.unpack(data[:8]) etag = EthernetTag.unpack(data[8:12]) iplen = ord_(data[12]) if iplen not in (4*8,16*8): raise Exception("IP len is %d, but EVPN route currently support only IPv4" % iplen) ip = IP.unpack(data[13:13+iplen//8]) return cls(rd,etag,ip,data)
def unpack(cls, data): datalen = len(data) rd = RouteDistinguisher.unpack(data[:8]) esi = ESI.unpack(data[8:18]) etag = EthernetTag.unpack(data[18:22]) maclength = data[22] if maclength > 48 or maclength < 0: raise Notify(3, 5, 'invalid MAC Address length in %s' % cls.NAME) end = 23 + 6 # MAC length MUST be 6 mac = MACQUAL.unpack(data[23:end]) length = data[end] iplen = length / 8 if datalen in [33, 36]: # No IP information (1 or 2 labels) iplenUnpack = 0 if iplen != 0: raise Notify( 3, 5, "IP length is given as %d, but current MAC route has no IP information" % iplen) elif datalen in [37, 40]: # Using IPv4 addresses (1 or 2 labels) iplenUnpack = 4 if iplen > 32 or iplen < 0: raise Notify( 3, 5, "IP field length is given as %d, but current MAC route is IPv4 and valus is out of range" % iplen, ) elif datalen in [49, 52]: # Using IPv6 addresses (1 or 2 labels) iplenUnpack = 16 if iplen > 128 or iplen < 0: raise Notify( 3, 5, "IP field length is given as %d, but current MAC route is IPv6 and valus is out of range" % iplen, ) else: raise Notify( 3, 5, "Data field length is given as %d, but does not match one of the expected lengths" % datalen) payload = data[end + 1:end + 1 + iplenUnpack] if payload: ip = IP.unpack(data[end + 1:end + 1 + iplenUnpack]) else: ip = None label = Labels.unpack(data[end + 1 + iplenUnpack:end + 1 + iplenUnpack + 3]) return cls(rd, esi, etag, mac, maclength, label, ip, data)
def unpack_nlri(cls, afi, safi, bgp, action, addpath): nlri = cls(afi, safi, action) if addpath: nlri.path_info = PathInfo(bgp[:4]) bgp = bgp[4:] mask = ord(bgp[0]) bgp = bgp[1:] if cls.has_label(): labels = [] while bgp and mask >= 8: label = int(unpack('!L', chr(0) + bgp[:3])[0]) bgp = bgp[3:] mask -= 24 # 3 bytes # The last 4 bits are the bottom of Stack # The last bit is set for the last label labels.append(label >> 4) # This is a route withdrawal if label == 0x800000 and action == IN.WITHDRAWN: break # This is a next-hop if label == 0x000000: break if label & 1: break nlri.labels = Labels(labels) if cls.has_rd(): mask -= 8 * 8 # the 8 bytes of the route distinguisher rd = bgp[:8] bgp = bgp[8:] nlri.rd = RouteDistinguisher(rd) if mask < 0: raise Notify(3, 10, 'invalid length in NLRI prefix') if not bgp and mask: raise Notify( 3, 10, 'not enough data for the mask provided to decode the NLRI') size = CIDR.size(mask) if len(bgp) < size: raise Notify( 3, 10, 'could not decode route with AFI %d sand SAFI %d' % (afi, safi)) network, bgp = bgp[:size], bgp[size:] padding = '\0' * (IP.length(afi) - size) nlri.cidr = CIDR(network + padding, mask) return nlri, bgp
def generate_rd (rd): """only ip:num is supported atm.code from configure.file""" separator = rd.find(':') prefix = rd[:separator] suffix = int(rd[separator+1:]) data = [chr(0),chr(1)] data.extend([chr(int(_)) for _ in prefix.split('.')]) data.extend([chr(suffix >> 8),chr(suffix & 0xFF)]) bin_rd = ''.join(data) return RouteDistinguisher(bin_rd)
def unpack (cls, data): rd = RouteDistinguisher.unpack(data[:8]) esi = ESI.unpack(data[8:18]) iplen = ordinal(data[18]) if iplen not in (32,128): raise Notify(3,5,"IP length field is given as %d in current Segment, expecting 32 (IPv4) or 128 (IPv6) bits" % iplen) ip = IP.unpack(data[19:19+(iplen//8)]) return cls(rd,esi,ip,data)
def unpack_nlri (cls, afi, safi, bgp, action, addpath): # label is 20bits, stored using 3 bytes, 24 bits length, = unpack('!H',bgp[0:2]) if len(bgp) != length+2: raise Notify(3,10,'l2vpn vpls message length is not consistent with encoded bgp') rd = RouteDistinguisher(bgp[2:10]) endpoint,offset,size = unpack('!HHH',bgp[10:16]) base = unpack('!L','\x00'+bgp[16:19])[0] >> 4 nlri = cls(rd,endpoint,base,offset,size) nlri.action = action # nlri.nexthop = IP.unpack(nexthop) return nlri, bgp[19:]
def unpack(cls, afi, safi, bgp, addpath, nexthop, action): labels, rd, path_identifier, mask, size, prefix, left = NLRI._nlri( afi, safi, bgp, action, addpath) nlri = cls(afi, safi, prefix, mask, nexthop, action) if labels: nlri.labels = Labels(labels) if rd: nlri.rd = RouteDistinguisher(rd) if path_identifier: nlri.path_info = PathInfo(None, None, path_identifier) return len(bgp) - len(left), nlri
def unpack(cls, data): rd = RouteDistinguisher.unpack(data[:8]) esi = ESI.unpack(data[8:18]) iplen = ord_(data[18]) if iplen not in (32, 128): raise Notify( 3, 5, "IP field length is given as %d in current Segment, expecting 32 (IPv4) or 128 (IPv6) bits" % iplen) ip = IP.unpack(data[19:19 + (iplen / 8)]) return cls(rd, esi, ip, data)
def unpack(cls, afi, safi, data, addpath, nexthop, action): # label is 20bits, stored using 3 bytes, 24 bits length, = unpack('!H', data[0:2]) if len(data) != length + 2: raise Notify( 3, 10, 'l2vpn vpls message length is not consistent with encoded data' ) rd = RouteDistinguisher(data[2:10]) ve, offset, size = unpack('!HHH', data[10:16]) base = unpack('!L', '\x00' + data[16:19])[0] >> 4 nlri = cls(rd, ve, base, offset, size) nlri.action = action nlri.nexthop = IP.unpack(nexthop) return len(data), nlri
def unpack_nlri(cls, afi, safi, bgp, action, addpath): code, length = unpack('!HH', bgp[:4]) if code in cls.registered_bgpls: if safi == SAFI.bgp_ls_vpn: # Extract Route Distinguisher rd = RouteDistinguisher.unpack(bgp[4:12]) klass = cls.registered_bgpls[code].unpack_nlri(bgp[12 : length + 4], rd) else: rd = None klass = cls.registered_bgpls[code].unpack_nlri(bgp[4 : length + 4], rd) else: klass = GenericBGPLS(code, bgp[4 : length + 4]) klass.CODE = code klass.action = action klass.addpath = addpath return klass, bgp[length + 4 :]
def unpack_nlri(cls, afi, safi, bgp, action, addpath): code, length = unpack('!HH',bgp[:4]) if code in cls.registered_bgpls: if safi == SAFI.bgp_ls_vpn: # Extract Route Distinguisher rd = RouteDistinguisher.unpack(bgp[4:12]) klass = cls.registered_bgpls[code].unpack_nlri(bgp[12:length+4],rd) else: rd = None klass = cls.registered_bgpls[code].unpack_nlri(bgp[4:length+4],rd) else: klass = GenericBGPLS(code,bgp[4:length+4]) klass.CODE = code klass.action = action klass.addpath = addpath return klass,bgp[length+4:]
def route_distinguisher(tokeniser): data = tokeniser() separator = data.find(':') if separator > 0: prefix = data[:separator] suffix = int(data[separator + 1:]) if '.' in prefix: data = [bytes([0, 1])] data.extend([bytes([int(_)]) for _ in prefix.split('.')]) data.extend([bytes([suffix >> 8]), bytes([suffix & 0xFF])]) rtd = b''.join(data) else: number = int(prefix) if number < pow(2, 16) and suffix < pow(2, 32): rtd = bytes([0, 0]) + pack('!H', number) + pack('!L', suffix) elif number < pow(2, 32) and suffix < pow(2, 16): rtd = bytes([0, 2]) + pack('!L', number) + pack('!H', suffix) else: raise ValueError('invalid route-distinguisher %s' % data) return RouteDistinguisher(rtd)