def parse(self, data, negotiated): if not data: return self # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(ord(data[0])) aid = Attribute.CODE(ord(data[1])) if flag & Attribute.Flag.EXTENDED_LENGTH: length = unpack('!H', data[2:4])[0] offset = 4 else: length = ord(data[2]) offset = 3 data = data[offset:] left = data[length:] attribute = data[:length] logger = Logger() logger.parser( LazyFormat( "parsing flag %x type %02x (%s) len %02x %s" % (flag, int(aid), aid, length, 'payload ' if length else ''), data[:length])) # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: aid &= Attribute.Flag.MASK_PARTIAL & 0xFF # aid &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) # handle the attribute if we know it if Attribute.registered(aid, flag): self.add(Attribute.unpack(aid, flag, attribute, negotiated)) return self.parse(left, negotiated) # XXX: FIXME: we could use a fallback function here like capability # if we know the attribute but the flag is not what the RFC says. ignore it. if aid in Attribute.attributes_known: logger.parser( 'invalid flag for attribute %s (flag 0x%02X, aid 0x%02X)' % (Attribute.CODE.names.get(aid, 'unset'), flag, aid)) return self.parse(left, negotiated) # it is an unknown transitive attribute we need to pass on if flag & Attribute.Flag.TRANSITIVE: logger.parser( 'unknown transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag, aid)) self.add( GenericAttribute(aid, flag | Attribute.Flag.PARTIAL, attribute), attribute) return self.parse(left, negotiated) # it is an unknown non-transitive attribute we can ignore. logger.parser( 'ignoring unknown non-transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag, aid)) return self.parse(left, negotiated)
def flag_attribute_content(data): flag = Attribute.Flag(ord(data[0])) attr = Attribute.CODE(ord(data[1])) if flag & Attribute.Flag.EXTENDED_LENGTH: length = unpack('!H', data[2:4])[0] return flag, attr, data[4:length + 4] else: length = ord(data[2]) return flag, attr, data[3:length + 3]
def add(self, attribute, _=None): # we return None as attribute if the unpack code must not generate them if attribute is None: return self._str = '' self._json = '' # XXX: FIXME: I am not sure anymore that more than one of each is possible if attribute.ID in Attributes.MULTIPLE: # deadcode: setdefault does not seem to exist anywhere ? (TM) self.setdefault(attribute.ID, []).append(attribute) # elif attribute.ID in (Attribute.CODE.COMMUNITY, Attribute.CODE.EXTENDED_COMMUNITY): # if attribute.ID not in self: # self[attribute.ID] = Attribute.klass(attribute.ID,attribute.FLAG)() # self[attribute.ID].add(attribute) elif attribute.ID in self: # For flows we can add extended-communities using special keywords and extended-community # This allows this trick if attribute.ID != Attribute.CODE.EXTENDED_COMMUNITY: raise Notify( 3, 0, 'multiple attribute for %s' % str(Attribute.CODE(attribute.ID))) for community in attribute.communities: self[attribute.ID].add(community) else: self[attribute.ID] = attribute
def parse (self, data, negotiated): if not data: return self # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(ord(data[0])) aid = Attribute.CODE(ord(data[1])) if flag & Attribute.Flag.EXTENDED_LENGTH: length = unpack('!H',data[2:4])[0] offset = 4 else: length = ord(data[2]) offset = 3 data = data[offset:] left = data[length:] attribute = data[:length] logger = Logger() logger.parser(LazyFormat("parsing flag %x type %02x (%s) len %02x %s" % (flag,int(aid),aid,length,'payload ' if length else ''),data[:length])) # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: flag &= Attribute.Flag.MASK_PARTIAL & 0xFF # flag &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) # handle the attribute if we know it if Attribute.registered(aid,flag): self.add(Attribute.unpack(aid,flag,attribute,negotiated)) return self.parse(left,negotiated) # XXX: FIXME: we could use a fallback function here like capability # if we know the attribute but the flag is not what the RFC says. ignore it. if aid in Attribute.attributes_known: logger.parser('invalid flag for attribute %s (flag 0x%02X, aid 0x%02X)' % (Attribute.CODE.names.get(aid,'unset'),flag,aid)) return self.parse(left,negotiated) # it is an unknown transitive attribute we need to pass on if flag & Attribute.Flag.TRANSITIVE: logger.parser('unknown transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag,aid)) self.add(GenericAttribute(aid,flag | Attribute.Flag.PARTIAL,attribute),attribute) return self.parse(left,negotiated) # it is an unknown non-transitive attribute we can ignore. logger.parser('ignoring unknown non-transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag,aid)) return self.parse(left,negotiated)
def add(self, attribute, _=None): # we return None as attribute if the unpack code must not generate them if attribute is None: return self._str = '' self._json = '' # XXX: FIXME: I am not sure anymore that more than one of each is possible if attribute.ID in Attributes.MULTIPLE: self.setdefault(attribute.ID, []).append(attribute) elif attribute.ID in self: raise Notify( 3, 0, 'multiple attribute for %s' % str(Attribute.CODE(attribute.ID))) else: self[attribute.ID] = attribute
def add(self, attribute, data=None): # we return None as attribute if the unpack code must not generate them if attribute is None: return self._str = '' self._json = '' if attribute.MULTIPLE: if self.has(attribute.ID): self[attribute.ID].append(attribute) else: self[attribute.ID] = MultiAttributes(attribute) else: if attribute.ID in self: raise Notify( 3, 0, 'multiple attribute for %s' % str(Attribute.ID(attribute.ID))) self[attribute.ID] = attribute
def parse(self, data, negotiated): if not data: return self try: # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(ord(data[0])) aid = Attribute.CODE(ord(data[1])) except IndexError: self.add(TreatAsWithdraw()) return self try: offset = 3 length = ord(data[2]) if flag & Attribute.Flag.EXTENDED_LENGTH: offset = 4 length = (length << 8) + ord(data[3]) except IndexError: self.add(TreatAsWithdraw(aid)) return self data = data[offset:] left = data[length:] attribute = data[:length] logger = Logger() logger.parser(LazyAttribute(flag, aid, length, data[:length])) # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: flag &= Attribute.Flag.MASK_PARTIAL & 0xFF # flag &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) if aid in self: if aid in self.NO_DUPLICATE: raise Notify( 3, 1, 'multiple attribute for %s' % str(Attribute.CODE(attribute.ID))) logger.parser( 'duplicate attribute %s (flag 0x%02X, aid 0x%02X) skipping' % (Attribute.CODE.names.get(aid, 'unset'), flag, aid)) return self.parse(left, negotiated) # handle the attribute if we know it if Attribute.registered(aid, flag): if length == 0 and aid not in self.VALID_ZERO: self.add(TreatAsWithdraw(aid)) return self.parse(left, negotiated) try: decoded = Attribute.unpack(aid, flag, attribute, negotiated) except IndexError, exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw(aid) else: raise exc except Notify, exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw() elif aid in self.DISCARD: decoded = Discard() else: raise exc
def parse(self, data, direction, negotiated): if not data: return self try: # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(data[0]) aid = Attribute.CODE(data[1]) except IndexError: self.add(TreatAsWithdraw()) return self try: offset = 3 length = data[2] if flag & Attribute.Flag.EXTENDED_LENGTH: offset = 4 length = (length << 8) + data[3] except IndexError: self.add(TreatAsWithdraw(aid)) return self data = data[offset:] left = data[length:] attribute = data[:length] logfunc.debug(lazyattribute(flag, aid, length, data[:length]), 'parser') # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: flag &= Attribute.Flag.MASK_PARTIAL & 0xFF # flag &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) if aid in self: if aid in self.NO_DUPLICATE: raise Notify(3, 1, 'multiple attribute for %s' % str(Attribute.CODE(attribute.ID))) log.debug( 'duplicate attribute %s (flag 0x%02X, aid 0x%02X) skipping' % (Attribute.CODE.names.get(aid, 'unset'), flag, aid), 'parser', ) return self.parse(left, direction, negotiated) # handle the attribute if we know it if Attribute.registered(aid, flag): if length == 0 and aid not in self.VALID_ZERO: self.add(TreatAsWithdraw(aid)) return self.parse(left, direction, negotiated) try: decoded = Attribute.unpack(aid, flag, attribute, direction, negotiated) except IndexError as exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw(aid) else: raise exc except Notify as exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw() elif aid in self.DISCARD: decoded = Discard() else: raise exc self.add(decoded) return self.parse(left, direction, negotiated) # XXX: FIXME: we could use a fallback function here like capability # if we know the attribute but the flag is not what the RFC says. if aid in Attribute.attributes_known: if aid in self.TREAT_AS_WITHDRAW: log.debug( 'invalid flag for attribute %s (flag 0x%02X, aid 0x%02X) treat as withdraw' % (Attribute.CODE.names.get(aid, 'unset'), flag, aid), 'parser', ) self.add(TreatAsWithdraw()) if aid in self.DISCARD: log.debug( 'invalid flag for attribute %s (flag 0x%02X, aid 0x%02X) discard' % (Attribute.CODE.names.get(aid, 'unset'), flag, aid), 'parser', ) return self.parse(left, direction, negotiated) # XXX: Check if we are missing any log.debug( 'invalid flag for attribute %s (flag 0x%02X, aid 0x%02X) unspecified (should not happen)' % (Attribute.CODE.names.get(aid, 'unset'), flag, aid), 'parser', ) return self.parse(left, direction, negotiated) # it is an unknown transitive attribute we need to pass on if flag & Attribute.Flag.TRANSITIVE: log.debug('unknown transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag, aid), 'parser') try: decoded = GenericAttribute(aid, flag | Attribute.Flag.PARTIAL, attribute) except IndexError: decoded = TreatAsWithdraw(aid) self.add(decoded, attribute) return self.parse(left, direction, negotiated) # it is an unknown non-transitive attribute we can ignore. log.debug('ignoring unknown non-transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag, aid), 'parser') return self.parse(left, direction, negotiated)
from exabgp.bgp.message.update.attribute.med import MED from exabgp.bgp.message.update.attribute.localpref import LocalPreference from exabgp.bgp.message.update.attribute.atomicaggregate import AtomicAggregate from exabgp.bgp.message.update.attribute.aggregator import Aggregator from exabgp.bgp.message.update.attribute.aggregator import Aggregator4 from exabgp.bgp.message.update.attribute.community.communities import Communities from exabgp.bgp.message.update.attribute.community.extended.communities import ExtendedCommunities from exabgp.bgp.message.update.attribute.originatorid import OriginatorID from exabgp.bgp.message.update.attribute.clusterlist import ClusterList from exabgp.bgp.message.update.attribute.mprnlri import MPRNLRI from exabgp.bgp.message.update.attribute.mpurnlri import MPURNLRI from exabgp.bgp.message.update.attribute.pmsi import PMSI from exabgp.bgp.message.update.attribute.aigp import AIGP from exabgp.bgp.message.update.attribute.bgpsec import BGPSEC Attribute.register_attribute(Origin) Attribute.register_attribute(ASPath) Attribute.register_attribute(AS4Path) Attribute.register_attribute(NextHop) Attribute.register_attribute(MED) Attribute.register_attribute(LocalPreference) Attribute.register_attribute(AtomicAggregate) Attribute.register_attribute(Aggregator) Attribute.register_attribute(Aggregator4) Attribute.register_attribute(Communities) Attribute.register_attribute(ExtendedCommunities) Attribute.register_attribute(OriginatorID) Attribute.register_attribute(ClusterList) Attribute.register_attribute(MPRNLRI) Attribute.register_attribute(MPURNLRI) Attribute.register_attribute(PMSI)
from exabgp.bgp.message.update.attribute.med import MED from exabgp.bgp.message.update.attribute.localpref import LocalPreference from exabgp.bgp.message.update.attribute.atomicaggregate import AtomicAggregate from exabgp.bgp.message.update.attribute.aggregator import Aggregator from exabgp.bgp.message.update.attribute.aggregator import Aggregator4 from exabgp.bgp.message.update.attribute.community.communities import Communities from exabgp.bgp.message.update.attribute.community.extended.communities import ExtendedCommunities from exabgp.bgp.message.update.attribute.originatorid import OriginatorID from exabgp.bgp.message.update.attribute.clusterlist import ClusterList from exabgp.bgp.message.update.attribute.mprnlri import MPRNLRI from exabgp.bgp.message.update.attribute.mpurnlri import MPURNLRI from exabgp.bgp.message.update.attribute.pmsi import PMSI from exabgp.bgp.message.update.attribute.aigp import AIGP Attribute.register_attribute(Origin) Attribute.register_attribute(ASPath) Attribute.register_attribute(AS4Path) Attribute.register_attribute(NextHop) Attribute.register_attribute(MED) Attribute.register_attribute(LocalPreference) Attribute.register_attribute(AtomicAggregate) Attribute.register_attribute(Aggregator) Attribute.register_attribute(Aggregator4) Attribute.register_attribute(Communities) Attribute.register_attribute(ExtendedCommunities) Attribute.register_attribute(OriginatorID) Attribute.register_attribute(ClusterList) Attribute.register_attribute(MPRNLRI) Attribute.register_attribute(MPURNLRI) Attribute.register_attribute(PMSI)
def parse (self, data, negotiated): if not data: return self try: # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(ordinal(data[0])) aid = Attribute.CODE(ordinal(data[1])) except IndexError: self.add(TreatAsWithdraw()) return self try: offset = 3 length = ordinal(data[2]) if flag & Attribute.Flag.EXTENDED_LENGTH: offset = 4 length = (length << 8) + ordinal(data[3]) except IndexError: self.add(TreatAsWithdraw(aid)) return self data = data[offset:] left = data[length:] attribute = data[:length] logger = Logger() logger.debug(LazyAttribute(flag,aid,length,data[:length]),'parser') # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: flag &= Attribute.Flag.MASK_PARTIAL & 0xFF # flag &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) if aid in self: if aid in self.NO_DUPLICATE: raise Notify(3,1,'multiple attribute for %s' % str(Attribute.CODE(attribute.ID))) logger.debug('duplicate attribute %s (flag 0x%02X, aid 0x%02X) skipping' % (Attribute.CODE.names.get(aid,'unset'),flag,aid),'parser') return self.parse(left,negotiated) # handle the attribute if we know it if Attribute.registered(aid,flag): if length == 0 and aid not in self.VALID_ZERO: self.add(TreatAsWithdraw(aid)) return self.parse(left,negotiated) try: decoded = Attribute.unpack(aid,flag,attribute,negotiated) except IndexError as exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw(aid) else: raise exc except Notify as exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw() elif aid in self.DISCARD: decoded = Discard() else: raise exc self.add(decoded) return self.parse(left,negotiated) # XXX: FIXME: we could use a fallback function here like capability # if we know the attribute but the flag is not what the RFC says. if aid in Attribute.attributes_known: if aid in self.TREAT_AS_WITHDRAW: logger.debug('invalid flag for attribute %s (flag 0x%02X, aid 0x%02X) treat as withdraw' % (Attribute.CODE.names.get(aid,'unset'),flag,aid),'parser') self.add(TreatAsWithdraw()) if aid in self.DISCARD: logger.debug('invalid flag for attribute %s (flag 0x%02X, aid 0x%02X) discard' % (Attribute.CODE.names.get(aid,'unset'),flag,aid),'parser') return self.parse(left,negotiated) # XXX: Check if we are missing any logger.debug('invalid flag for attribute %s (flag 0x%02X, aid 0x%02X) unspecified (should not happen)' % (Attribute.CODE.names.get(aid,'unset'),flag,aid),'parser') return self.parse(left,negotiated) # it is an unknown transitive attribute we need to pass on if flag & Attribute.Flag.TRANSITIVE: logger.debug('unknown transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag,aid),'parser') try: decoded = GenericAttribute(aid,flag | Attribute.Flag.PARTIAL,attribute) except IndexError: decoded = TreatAsWithdraw(aid) self.add(decoded,attribute) return self.parse(left,negotiated) # it is an unknown non-transitive attribute we can ignore. logger.debug('ignoring unknown non-transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag,aid),'parser') return self.parse(left,negotiated)
def parse (self, data, negotiated): if not data: return self try: # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(ord(data[0])) aid = Attribute.CODE(ord(data[1])) except IndexError: self.add(TreatAsWithdraw()) return self try: offset = 3 length = ord(data[2]) if flag & Attribute.Flag.EXTENDED_LENGTH: offset = 4 length = (length << 8) + ord(data[3]) except IndexError: self.add(TreatAsWithdraw(aid)) return self data = data[offset:] left = data[length:] attribute = data[:length] logger = Logger() logger.parser(LazyAttribute(flag,aid,length,data[:length])) # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: flag &= Attribute.Flag.MASK_PARTIAL & 0xFF # flag &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) if aid in self: if aid in self.NO_DUPLICATE: raise Notify(3,1,'multiple attribute for %s' % str(Attribute.CODE(attribute.ID))) logger.parser('duplicate attribute %s (flag 0x%02X, aid 0x%02X) skipping' % (Attribute.CODE.names.get(aid,'unset'),flag,aid)) return self.parse(left,negotiated) # handle the attribute if we know it if Attribute.registered(aid,flag): if length == 0 and aid not in self.VALID_ZERO: self.add(TreatAsWithdraw(aid)) return self.parse(left,negotiated) try: decoded = Attribute.unpack(aid,flag,attribute,negotiated) except IndexError, exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw(aid) else: raise exc except Notify, exc: if aid in self.TREAT_AS_WITHDRAW: decoded = TreatAsWithdraw() elif aid in self.DISCARD: decoded = Discard() else: raise exc