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)))
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_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 _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 _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 _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
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 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)
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
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(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)
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 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 (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 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 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 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 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_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 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 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_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 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 messages(self, negotitated): # pylint: disable=W0613 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
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 add(self, rule): ID = rule.ID if ID in (FlowDestination.ID, FlowSource.ID): if ID in self.rules: return False if ID == FlowDestination.ID: pair = self.rules.get(FlowSource.ID, []) else: pair = self.rules.get(FlowDestination.ID, []) if pair: if rule.afi != pair[0].afi: return False if rule.NAME.endswith('ipv6'): # better way to check this ? self.afi = AFI(AFI.ipv6) self.rules.setdefault(ID, []).append(rule) return True
class OperationalFamily(Operational): has_family = True def __init__(self, what, afi, safi, data=b''): Operational.__init__(self, what) self.afi = AFI(afi) self.safi = SAFI(safi) self.data = data def family(self): return (self.afi, self.safi) def _message(self, data): return Operational._message( self, concat_bytes(self.afi.pack(), self.safi.pack(), data)) def message(self, negotiated): return self._message(self.data)
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)
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 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 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)
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, what, afi, safi, data=b''): Operational.__init__(self,what) self.afi = AFI.create(afi) self.safi = SAFI.create(safi) self.data = data
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_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 all (self,tokeniser): for afi_name in ('ipv4','ipv6','l2vpn'): for safi_name in AFI.implemented_safi(afi_name): self._add(tokeniser,afi_name,safi_name)
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, afi, safi, reserved=0): self.afi = AFI(afi) self.safi = SAFI(safi) self.reserved = Reserved(reserved)
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 __init__ (self,what,afi,safi,data=''): Operational.__init__(self,what) self.afi = AFI(afi) self.safi = SAFI(afi) self.data = data