def __init__ (self,what,afi,safi,data=''): self.afi = AFI(afi) self.safi = SAFI(afi) Operational.__init__( self,what, '%s%s%s' % (self.afi.pack(),self.safi.pack(),data) )
def unpack_nlri (cls, afi, safi, data, action, addpath): if not cls.logger: cls.logger = Logger() cls.logger.parser(LazyNLRI(afi,safi,data)) key = '%s/%s' % (AFI(afi),SAFI(safi)) if key in cls.registered_nlri: return cls.registered_nlri[key].unpack_nlri(afi,safi,data,action,addpath) raise Notify(3,0,'trying to decode unknown family %s/%s' % (AFI(afi),SAFI(safi)))
class Inet(Address): _UNICAST = SAFI(SAFI.unicast) _MULTICAST = SAFI(SAFI.multicast) _multicast_range = set(range(224, 240)) # 239 is last """An IP in the 4 bytes format""" # README: yep, we should surely change this _ name here _af = { AFI.ipv4: socket.AF_INET, AFI.ipv6: socket.AF_INET6, } _afi = { socket.AF_INET: AFI.ipv4, socket.AF_INET6: AFI.ipv6, } length = { AFI.ipv4: 4, AFI.ipv6: 16, } def __init__(self, afi, safi, packed): if safi: # XXX: FIXME: we use a constant which is zero - reference it explicitly Address.__init__(self, afi, safi) elif ord(packed[0]) in self._multicast_range: Address.__init__(self, afi, self._MULTICAST) else: Address.__init__(self, afi, self._UNICAST) self.packed = packed self.ip = socket.inet_ntop(self._af[self.afi], self.packed) def pack(self): return self.packed def __len__(self): return len(self.packed) def inet(self): return self.ip def __str__(self): return self.inet() def __cmp__(self, other): if self.packed == other.packed: return 0 if self.packed < other.packed: return -1 return 1 def __repr__(self): return "<%s value %s>" % (str( self.__class__).split("'")[1].split('.')[-1], str(self))
def _nlri(afi, safi, bgp, action, addpath): labels = [] rd = '' if addpath: path_identifier = bgp[:4] bgp = bgp[4:] else: path_identifier = None mask = ord(bgp[0]) bgp = bgp[1:] if SAFI(safi).has_label(): 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 if SAFI(safi).has_rd(): mask -= 8 * 8 # the 8 bytes of the route distinguisher rd = bgp[:8] bgp = bgp[8:] 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) prefix = network + padding return labels, rd, path_identifier, mask, size, prefix, bgp
def _add (self, tokeniser, afi_name, safi_names): self._check_duplicate(tokeniser,RaisedFamily) known = self.content.setdefault(AFI(AFI.value(afi_name)),[]) for (idx_line,idx_column,line,safi_name) in safi_names: if safi_name not in AFI.implemented_safi(afi_name): raise RaisedFamily(Location(idx_line,idx_column,line),'the family pair afi/safi %s/%s is unimplemented' % (afi_name,safi_name)) safi = SAFI(SAFI.value(safi_name)) if safi in known: raise RaisedFamily(Location(idx_line,idx_column,line),'afi/safi pair already defined in this family') known.append(safi)
def _nlrifactory(afi, safi, bgp, action): labels = [] rd = '' mask = ord(bgp[0]) bgp = bgp[1:] if SAFI(safi).has_label(): 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 if SAFI(safi).has_rd(): mask -= 8 * 8 # the 8 bytes of the route distinguisher rd = bgp[:8] bgp = bgp[8:] 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 = mask_to_bytes.get(mask, None) if size is None: raise Notify(3, 10, 'invalid netmask found when decoding NLRI') 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' * (NLRI.length[afi] - size) prefix = network + padding return labels, rd, mask, size, prefix, bgp
class EVPN(object): registered_evpn = dict() # CODE : NEED to be defined in the subclasses NAME = 'unknown' SHORT_NAME = 'unknown' # lower case to match the class Address API afi = AFI(AFI.l2vpn) safi = SAFI(SAFI.evpn) def __init__(self, packed): self.packed = packed def _prefix(self): return "evpn:%s:" % (self._name.get(self.CODE, 'unknown').lower()) def __str__(self): return "evpn:%s:%s" % (self._name.get(self.CODE, 'unknown').lower(), '0x' + ''.join('%02x' % ord(_) for _ in self.packed)) def __repr__(self): return str(self) def pack(self): return pack('!BB', self.CODE, len(self.packed)) + self.packed def __len__(self): return len(self.packed) + 2 # For subtype 2 (MAC/IP advertisement route), # we will have to ignore a part of the route, so this method will be overridden def __cmp__(self, other): if not isinstance(other, EVPN): return -1 if self.CODE != other.CODE: return -1 if self.packed != other.packed: return -1 return 0 def __hash__(self): return hash("%s:%s:%s:%s" % (self.afi, self.safi, self.CODE, self.packed)) @classmethod def register_evpn(cls): cls.registered_evpn[cls.CODE] = cls @classmethod def unpack(cls, data): code = ord(data[0]) length = ord(data[1]) if code in cls.registered_evpn: return cls.registered_evpn[code].unpack(data[length + 1:]) klass = cls(data[length + 1:]) klass.CODE = code return klass
def ipv6(self, tokeniser): self._check_conflict() safi = tokeniser() if safi == 'unicast': self.content.append((AFI(AFI.ipv6), SAFI(SAFI.unicast))) elif safi == 'mpls-vpn': self.content.append((AFI(AFI.ipv6), SAFI(SAFI.mpls_vpn))) elif safi in ('flow'): self.content.append((AFI(AFI.ipv6), SAFI(SAFI.flow_ip))) elif safi == 'flow-vpn': self.content.append((AFI(AFI.ipv6), SAFI(SAFI.flow_vpn))) else: raise Raised('unknow family safi %s' % safi) self._drop_colon(tokeniser)
def register_nlri(klass): cls.registered_nlri['%d/%d' % (afi, safi)] = klass new = (AFI(afi), SAFI(safi)) if new in cls.registered_nlri: raise RuntimeError('Tried to register %s/%s twice' % new) cls.registered_families.append(new) return klass
def post(self): # self._family() self._split() # self.scope.to_context() routes = self.scope.pop(self.name) if routes: for route in routes: # if route.nlri.has_rd(): if route.nlri.rd is not RouteDistinguisher.NORD: route.nlri.safi = SAFI(SAFI.mpls_vpn) # elif route.nlri.has_label(): elif route.nlri.labels is not Labels.NOLABEL: route.nlri.safi = SAFI(SAFI.nlri_mpls) self.scope.extend('routes', routes) return True
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, direction, negotiated): nlris = [] # -- Reading AFI/SAFI afi, safi = unpack('!HB', data[:3]) offset = 3 data = data[offset:] if negotiated and (afi, safi) not in negotiated.families: raise Notify( 3, 0, 'presented a non-negotiated family %s %s' % (AFI.create(afi), SAFI.create(safi))) # Do we need to handle Path Information with the route (AddPath) if direction == Direction.IN: addpath = negotiated.addpath.receive(afi, safi) else: addpath = negotiated.addpath.send(afi, safi) while data: nlri, data = NLRI.unpack_nlri(afi, safi, data, IN.WITHDRAWN, addpath) # allow unpack_nlri to return none for "treat as withdraw" controlled by NLRI.unpack_nlri if nlri: nlris.append(nlri) return cls(afi, safi, nlris)
class RouteRefresh(Message): TYPE = chr(Message.Type.ROUTE_REFRESH) request = 0 start = 1 end = 2 def __init__(self, afi, safi, reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved) def messages(self, negotitated): return [ self._message( '%s%s%s' % (self.afi.pack(), chr(self.reserved), self.safi.pack())), ] def __str__(self): return "REFRESH" def extensive(self): return 'route refresh %s/%d/%s' % (self.afi, self.reserved, self.safi) def families(self): return self._families[:]
class RouteRefresh (Message): ID = Message.ID.ROUTE_REFRESH TYPE = chr(Message.ID.ROUTE_REFRESH) request = 0 start = 1 end = 2 def __init__ (self,afi,safi,reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved) def messages (self,negotitated): return [self._message('%s%s%s' % (self.afi.pack(),chr(self.reserved),self.safi.pack())),] def __str__ (self): return "REFRESH" def extensive (self): return 'route refresh %s/%d/%s' % (self.afi,self.reserved,self.safi) def families (self): return self._families[:] @classmethod def unpack_message (cls,data,negotitated): try: afi,reserved,safi = unpack('!HBB',data) except error: raise Notify(7,1,'invalid route-refresh message') if reserved not in (0,1,2): raise Notify(7,2,'invalid route-refresh message subtype') return RouteRefresh(afi,safi,reserved)
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_nlri(cls, afi, safi, data, action, addpath): a, s = AFI.create(afi), SAFI.create(safi) log.debug(LazyNLRI(a, s, addpath, data), 'parser') key = '%s/%s' % (a, s) if key in cls.registered_nlri: return cls.registered_nlri[key].unpack_nlri(a, s, data, action, addpath) raise Notify(3, 0, 'trying to decode unknown family %s/%s' % (a, s))
def unpack(capability, instance, data): # XXX: FIXME: should check that we have not yet seen the capability while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) sr = ord(data[3]) instance.add_path(afi, safi, sr) data = data[4:] return instance
def parse_api_refresh (self,command): tokens = formated(command).split(' ')[2:] if len(tokens) != 2: return False afi = AFI.value(tokens.pop(0)) safi = SAFI.value(tokens.pop(0)) if afi is None or safi is None: return False return RouteRefresh(afi,safi)
def api_refresh(self, command): tokens = formated(command).split(' ')[2:] if len(tokens) != 2: return False afi = AFI.value(tokens.pop(0)) safi = SAFI.value(tokens.pop(0)) if afi is None or safi is None: return False return RouteRefresh(afi, safi)
def unpack_capability (instance, data, capability=None): # pylint: disable=W0613 # XXX: FIXME: should check that we have not yet seen the capability while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) sr = ord(data[3]) instance.add_path(afi,safi,sr) data = data[4:] return instance
def unpack_capability (instance, data, capability=None): # pylint: disable=W0613 # XXX: FIXME: should check that we have not yet seen the capability while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) sr = ord_(data[3]) instance.add_path(afi,safi,sr) data = data[4:] return instance
def unpack (capability,instance,data): # XXX: FIXME: should check that we have not yet seen the capability while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) sr = ord(data[3]) instance.add_path(afi,safi,sr) data = data[4:] return instance
def unpack (cls,afi,safi,data,addpath,nexthop,action): if not cls.logger: cls.logger = Logger() cls.logger.parser(LazyFormat("parsing %s/%s nlri payload " % (afi,safi),data)) key = '%d/%d' % (afi,safi) if key in cls.registered_nlri: return cls.registered_nlri[key].unpack(afi,safi,data,addpath,nexthop,action) raise Notify(3,0,'trying to decode unknown family %s/%s' % (AFI(afi),SAFI(safi)))
def new(self, neighbor, restarted): graceful = neighbor.graceful_restart families = neighbor.families() mp = MultiProtocol() mp.extend(families) self[Capability.ID.MULTIPROTOCOL_EXTENSIONS] = mp if neighbor.asn4: self[Capability.ID.FOUR_BYTES_ASN] = ASN4(neighbor.local_as) if neighbor.add_path: ap_families = [] if (AFI(AFI.ipv4), SAFI(SAFI.unicast)) in families: ap_families.append((AFI(AFI.ipv4), SAFI(SAFI.unicast))) if (AFI(AFI.ipv6), SAFI(SAFI.unicast)) in families: ap_families.append((AFI(AFI.ipv6), SAFI(SAFI.unicast))) # if (AFI(AFI.ipv4),SAFI(SAFI.nlri_mpls)) in families: # ap_families.append((AFI(AFI.ipv4),SAFI(SAFI.nlri_mpls))) #if (AFI(AFI.ipv6),SAFI(SAFI.unicast)) in families: # ap_families.append((AFI(AFI.ipv6),SAFI(SAFI.unicast))) self[Capability.ID.ADD_PATH] = AddPath(ap_families, neighbor.add_path) if graceful: if restarted: self[Capability.ID.GRACEFUL_RESTART] = Graceful().set( Graceful.RESTART_STATE, graceful, [(afi, safi, Graceful.FORWARDING_STATE) for (afi, safi) in families]) else: self[Capability.ID.GRACEFUL_RESTART] = Graceful().set( 0x0, graceful, [(afi, safi, Graceful.FORWARDING_STATE) for (afi, safi) in families]) if neighbor.route_refresh: self[Capability.ID.ROUTE_REFRESH] = RouteRefresh() self[Capability.ID.ENHANCED_ROUTE_REFRESH] = EnhancedRouteRefresh() # MUST be the last key added if neighbor.multisession: self[Capability.ID.MULTISESSION_BGP] = MultiSession().set( [Capability.ID.MULTIPROTOCOL_EXTENSIONS]) return self
def post (self): route = self.scope.pop(self.name) # if route.nlri.has_rd(): # ??? if route.nlri.rd is not RouteDistinguisher.NORD: route.nlri.safi = SAFI(SAFI.flow_vpn) if route: self.scope.append('routes',route) return True
def unpack_capability (instance, data, capability=None): # pylint: disable=W0613 # XXX: FIXME: we should complain if we have twice the same AFI/SAFI # XXX: FIXME: should check that we have not yet seen the capability while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[3]) nexthop = AFI.unpack(data[4:6]) instance.add_nexthop(afi, safi, nexthop) data = data[6:] return instance
def l2vpn(self, tokeniser): self._check_conflict() safi = tokeniser() if safi == 'vpls': self.content.append((AFI(AFI.l2vpn), SAFI(SAFI.vpls))) else: raise Raised('unknow family safi %s' % safi) self._drop_colon(tokeniser)
def unpack_capability(instance, data, capability=None): # pylint: disable=W0613 # XXX: FIXME: we should complain if we have twice the same AFI/SAFI # XXX: FIXME: should check that we have not yet seen the capability while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[3]) nexthop = AFI.unpack(data[4:6]) instance.add_nexthop(afi, safi, nexthop) data = data[6:] return instance
def unpack_nlri (cls, afi, safi, data, action, addpath): if not cls.logger: cls.logger = Logger() a,s = AFI.create(afi),SAFI.create(safi) cls.logger.debug(LazyNLRI(a,s,addpath,data),'parser') key = '%s/%s' % (a, s) if key in cls.registered_nlri: return cls.registered_nlri[key].unpack_nlri(a,s,data,action,addpath) raise Notify(3,0,'trying to decode unknown family %s/%s' % (a,s))
class OperationalFamily (Operational): def __init__ (self,what,afi,safi,data=''): self.afi = AFI(afi) self.safi = SAFI(afi) Operational.__init__( self,what, '%s%s%s' % (self.afi.pack(),self.safi.pack(),data) ) def family (self): return (self.afi,self.safi)
def register_nlri(klass): new = (AFI(afi), SAFI(safi)) if new in cls.registered_nlri: if force: cls.registered_nlri['%d/%d' % new] = klass else: raise RuntimeError('Tried to register %s/%s twice' % new) else: cls.registered_nlri['%d/%d' % new] = klass cls.registered_families.append(new) return klass
def _family(self, tokeniser, afi, safis, nhafis): safi = tokeniser().lower() if safi not in safis: raise ValueError('invalid afi/safi pair %s/%s' % (afi, safi)) nhafi = tokeniser().lower() if nhafi not in nhafis: raise ValueError('invalid nexthop afi %s' % nhafi) seen = (AFI.fromString(afi), SAFI.fromString(safi), AFI.fromString(nhafi)) self._seen.append(seen) return seen
def _family (self, tokeniser, afi, safis, nhafis): safi = tokeniser().lower() if safi not in safis: raise ValueError('invalid afi/safi pair %s/%s' % (afi, safi)) nhafi = tokeniser().lower() if nhafi not in nhafis: raise ValueError('invalid nexthop afi %s' % nhafi) seen = (AFI.fromString(afi), SAFI.fromString(safi), AFI.fromString(nhafi)) self._seen.append(seen) return seen
def _add (self,tokeniser,afi_name,safi_names): self._check_duplicate(tokeniser,RaisedFamily) known = self.content.setdefault(AFI(AFI.value(afi_name)),[]) for (idx_line,idx_column,line,safi_name) in safi_names: if safi_name not in AFI.implemented_safi(afi_name): raise RaisedFamily(Location(idx_line,idx_column,line),'the family pair afi/safi %s/%s is unimplemented' % (afi_name,safi_name)) safi = SAFI(SAFI.value(safi_name)) if safi in known: raise RaisedFamily(Location(idx_line,idx_column,line),'afi/safi pair already defined in this family') known.append(safi)
def register_nlri (klass): new = (AFI(afi),SAFI(safi)) if new in cls.registered_nlri: if force: # python has a bug and does not allow %ld/%ld (pypy does) cls.registered_nlri['%s/%s' % new] = klass else: raise RuntimeError('Tried to register %s/%s twice' % new) else: # python has a bug and does not allow %ld/%ld (pypy does) cls.registered_nlri['%s/%s' % new] = klass cls.registered_families.append(new) return klass
def register_nlri (klass): new = (AFI.create(afi),SAFI.create(safi)) if new in cls.registered_nlri: if force: # python has a bug and does not allow %ld/%ld (pypy does) cls.registered_nlri['%s/%s' % new] = klass else: raise RuntimeError('Tried to register %s/%s twice' % new) else: # python has a bug and does not allow %ld/%ld (pypy does) cls.registered_nlri['%s/%s' % new] = klass cls.registered_families.append(new) return klass
class RouteRefresh(Message): ID = Message.CODE.ROUTE_REFRESH TYPE = character(Message.CODE.ROUTE_REFRESH) request = 0 start = 1 end = 2 def __init__(self, afi, safi, reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved) def message(self, negotiated=None): return self._message( concat_bytes(self.afi.pack(), character(self.reserved), self.safi.pack())) def __str__(self): return "REFRESH" def extensive(self): return 'route refresh %s/%d/%s' % (self.afi, self.reserved, self.safi) # XXX: Check how we get this data into the RR def families(self): return self._families[:] @classmethod def unpack_message(cls, data, _): try: afi, reserved, safi = unpack('!HBB', data) except error: raise Notify(7, 1, 'invalid route-refresh message') if reserved not in (0, 1, 2): raise Notify(7, 2, 'invalid route-refresh message subtype') return RouteRefresh(afi, safi, reserved) def __eq__(self, other): if not isinstance(other, RouteRefresh): return False if self.afi != other.afi: return False if self.safi != other.safi: return False if self.reserved != other.reserved: return False return True def __ne__(self, other): return not self.__eq__(other)
def _addpath (self, neighbor): if not neighbor.add_path: return families = neighbor.families() ap_families = [] if (AFI(AFI.ipv4),SAFI(SAFI.unicast)) in families: ap_families.append((AFI(AFI.ipv4),SAFI(SAFI.unicast))) if (AFI(AFI.ipv6),SAFI(SAFI.unicast)) in families: ap_families.append((AFI(AFI.ipv6),SAFI(SAFI.unicast))) if (AFI(AFI.ipv4),SAFI(SAFI.nlri_mpls)) in families: ap_families.append((AFI(AFI.ipv4),SAFI(SAFI.nlri_mpls))) if (AFI(AFI.ipv6),SAFI(SAFI.unicast)) in families: ap_families.append((AFI(AFI.ipv6),SAFI(SAFI.unicast))) self[Capability.CODE.ADD_PATH] = AddPath(ap_families,neighbor.add_path)
def unpack (what,instance,data): # XXX: FIXME: should raise if instance was already setup restart = unpack('!H',data[:2])[0] restart_flag = restart >> 12 restart_time = restart & Graceful.TIME_MASK data = data[2:] families = [] while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) flag_family = ord(data[0]) families.append((afi,safi,flag_family)) data = data[4:] return instance.set(restart_flag,restart_time,families)
def unpack_capability (instance, data, capability=None): # pylint: disable=W0613 # XXX: FIXME: should raise if instance was already setup restart = unpack('!H',data[:2])[0] restart_flag = restart >> 12 restart_time = restart & Graceful.TIME_MASK data = data[2:] families = [] while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) flag_family = ord(data[3]) families.append((afi,safi,flag_family)) data = data[4:] return instance.set(restart_flag,restart_time,families)
def unpack_capability(instance, data, _=None): # XXX: FIXME: should raise if instance was already setup restart = unpack('!H', data[:2])[0] restart_flag = restart >> 12 restart_time = restart & Graceful.TIME_MASK data = data[2:] families = [] while data: afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[2]) flag_family = ord(data[0]) families.append((afi, safi, flag_family)) data = data[4:] return instance.set(restart_flag, restart_time, families)
class RouteRefresh (Message): ID = Message.CODE.ROUTE_REFRESH TYPE = chr(Message.CODE.ROUTE_REFRESH) request = 0 start = 1 end = 2 def __init__ (self, afi, safi, reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved) def message (self,negotiated=None): return self._message('%s%s%s' % (self.afi.pack(),chr(self.reserved),self.safi.pack())) def __str__ (self): return "REFRESH" def extensive (self): return 'route refresh %s/%d/%s' % (self.afi,self.reserved,self.safi) def families (self): return self._families[:] @classmethod def unpack_message (cls, data, _): try: afi,reserved,safi = unpack('!HBB',data) except error: raise Notify(7,1,'invalid route-refresh message') if reserved not in (0,1,2): raise Notify(7,2,'invalid route-refresh message subtype') return RouteRefresh(afi,safi,reserved) def __eq__ (self, other): if not isinstance(other, RouteRefresh): return False if self.afi != other.afi: return False if self.safi != other.safi: return False if self.reserved != other.reserved: return False return True def __ne__ (self, other): return not self.__eq__(other)
def parse_api_eor (self,command): tokens = formated(command).split(' ')[2:] lt = len(tokens) if not lt: return Family(1,1) if lt !=2: return False afi = AFI.fromString(tokens[0]) if afi == AFI.undefined: return False safi = SAFI.fromString(tokens[1]) if safi == SAFI.undefined: return False return Family(afi,safi)
def api_eor (self, command): tokens = formated(command).split(' ')[2:] number = len(tokens) if not number: return Family(1,1) if number != 2: return False afi = AFI.fromString(tokens[0]) if afi == AFI.undefined: return False safi = SAFI.fromString(tokens[1]) if safi == SAFI.undefined: return False return Family(afi,safi)
def unpack (cls, data, negotiated): nlris = [] # -- Reading AFI/SAFI afi,safi = unpack('!HB',data[:3]) offset = 3 data = data[offset:] if negotiated and (afi,safi) not in negotiated.families: raise Notify(3,0,'presented a non-negotiated family %s %s' % (AFI.create(afi),SAFI.create(safi))) # Is the peer going to send us some Path Information with the route (AddPath) addpath = negotiated.addpath.receive(afi,safi) while data: nlri,data = NLRI.unpack_nlri(afi,safi,data,IN.WITHDRAWN,addpath) nlris.append(nlri) return cls(afi,safi,nlris)
class OperationalFamily (Operational): has_family = True def __init__ (self,what,afi,safi,data=''): Operational.__init__(self,what) self.afi = AFI(afi) self.safi = SAFI(afi) self.data = data def family (self): return (self.afi,self.safi) def _message (self,data): return Operational._message(self,"%s%s%s" % ( self.afi.pack(), self.safi.pack(), data )) def message (self,negotiated): return self._message(self.data)
class RouteRefresh (Message): TYPE = chr(Message.Type.ROUTE_REFRESH) request = 0 start = 1 end = 2 def __init__ (self,afi,safi,reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved) def messages (self,negotitated): return [self._message('%s%s%s' % (self.afi.pack(),chr(self.reserved),self.safi.pack())),] def __str__ (self): return "REFRESH" def extensive (self): return 'route refresh %s/%d/%s' % (self.afi,self.reserved,self.safi) def families (self): return self._families[:]
def __init__ (self, afi, safi, reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved)
def unpack_capability (instance, data, capability=None): # pylint: disable=W0613 # XXX: FIXME: we should raise if we have twice the same AFI/SAFI afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[3]) instance.append((afi,safi)) return instance
def unpack_message (cls, data, negotiated): header_length = len(EOR.NLRI.PREFIX) return cls(AFI.unpack(data[header_length:header_length+2]),SAFI.unpack(data[header_length+2]))
def unpack (what,instance,data): # XXX: FIXME: we should raise if we have twice the same AFI/SAFI afi = AFI.unpack(data[:2]) safi = SAFI.unpack(data[3]) instance.append((afi,safi)) return instance
def unpack (cls, data, negotiated): nlris = [] # -- Reading AFI/SAFI _afi,_safi = unpack('!HB',data[:3]) afi,safi = AFI.create(_afi),SAFI.create(_safi) offset = 3 # we do not want to accept unknown families if negotiated and (afi,safi) not in negotiated.families: raise Notify(3,0,'presented a non-negotiated family %s/%s' % (afi,safi)) # -- Reading length of next-hop len_nh = ordinal(data[offset]) offset += 1 if (afi,safi) not in Family.size: raise Notify(3,0,'unsupported %s %s' % (afi,safi)) length,rd = Family.size[(afi,safi)] if len_nh not in length: raise Notify(3,0,'invalid %s %s next-hop length %d expected %s' % (afi,safi,len_nh,' or '.join(str(_) for _ in length))) size = len_nh - rd # XXX: FIXME: GET IT FROM CACHE HERE ? nhs = data[offset+rd:offset+rd+size] nexthops = [nhs[pos:pos+16] for pos in range(0,len(nhs),16)] # chech the RD is well zero if rd and sum([int(ordinal(_)) for _ in data[offset:8]]) != 0: raise Notify(3,0,"MP_REACH_NLRI next-hop's route-distinguisher must be zero") offset += len_nh # Skip a reserved bit as somone had to bug us ! reserved = ordinal(data[offset]) offset += 1 if reserved != 0: raise Notify(3,0,'the reserved bit of MP_REACH_NLRI is not zero') # Is the peer going to send us some Path Information with the route (AddPath) addpath = negotiated.addpath.receive(afi,safi) # Reading the NLRIs data = data[offset:] if not data: raise Notify(3,0,'No data to decode in an MPREACHNLRI but it is not an EOR %d/%d' % (afi,safi)) while data: if nexthops: for nexthop in nexthops: nlri,left = NLRI.unpack_nlri(afi,safi,data,IN.ANNOUNCED,addpath) nlri.nexthop = NextHop.unpack(nexthop) nlris.append(nlri) else: nlri,left = NLRI.unpack_nlri(afi,safi,data,IN.ANNOUNCED,addpath) nlris.append(nlri) if left == data: raise RuntimeError("sub-calls should consume data") data = left return cls(afi,safi,nlris)
def __init__ (self, what, afi, safi, data=b''): Operational.__init__(self,what) self.afi = AFI.create(afi) self.safi = SAFI.create(safi) self.data = data
def __init__ (self,what,afi,safi,data=''): Operational.__init__(self,what) self.afi = AFI(afi) self.safi = SAFI(afi) self.data = data