Beispiel #1
0
    def messages(self, negotiated):
        # sort the nlris

        add_nlri = []
        del_nlri = []
        add_mp = {}
        del_mp = {}

        for nlri in self.nlris:
            if nlri.family() in negotiated.families:
                if nlri.afi == AFI.ipv4 and nlri.safi in [
                        SAFI.unicast, SAFI.multicast
                ]:
                    if nlri.action == OUT.announce:
                        add_nlri.append(nlri)
                    else:
                        del_nlri.append(nlri)
                else:
                    if nlri.action == OUT.announce:
                        add_mp.setdefault(nlri.family(), []).append(nlri)
                    else:
                        del_mp.setdefault(nlri.family(), []).append(nlri)

        if not add_nlri and not del_nlri and not add_mp and not del_mp:
            return

        if add_nlri or add_mp:
            attr = self.attributes.pack(negotiated, True)
        else:
            attr = ''

        # withdrawn IPv4

        packed_del = ''
        msg_size = negotiated.msg_size - 19 - 2 - 2  # 2 bytes for each of the two prefix() header
        addpath = negotiated.addpath.send(AFI.ipv4, SAFI.unicast)

        while del_nlri:
            nlri = del_nlri.pop()
            packed = nlri.pack(addpath)
            if len(packed_del + packed) >= msg_size:
                if not packed_del:
                    raise Notify(
                        6, 0,
                        'attributes size is so large we can not even pack one NLRI'
                    )
                yield self._message(prefix(packed_del) + prefix(''))
                packed_del = packed
            else:
                packed_del += packed

        # withdrawn MP

        packed_mp_del = ''

        families = del_mp.keys()
        while families:
            family = families.pop()
            mps = del_mp[family]
            addpath = negotiated.addpath.send(*family)
            mp_packed_generator = MPURNLRI(mps).packed_attributes(addpath)
            try:
                while True:
                    packed = mp_packed_generator.next()
                    if len(packed_del + packed_mp_del + packed) >= msg_size:
                        if not packed_mp_del and not packed_del:
                            raise Notify(
                                6, 0,
                                'attributes size is so large we can not even pack one MPURNLRI'
                            )
                        yield self._message(
                            prefix(packed_del) + prefix(packed_mp_del))
                        packed_del = ''
                        packed_mp_del = packed
                    else:
                        packed_mp_del += packed
            except StopIteration:
                pass

        # add MP

        # we have some MPRNLRI so we need to add the attributes, recalculate
        # and make sure we do not overflow

        packed_mp_add = ''

        if add_mp:
            msg_size = negotiated.msg_size - 19 - 2 - 2 - len(
                attr)  # 2 bytes for each of the two prefix() header
        if len(packed_del + packed_mp_del) >= msg_size:
            yield self._message(prefix(packed_del) + prefix(packed_mp_del))
            packed_del = ''
            packed_mp_del = ''

        families = add_mp.keys()
        while families:
            family = families.pop()
            mps = add_mp[family]
            addpath = negotiated.addpath.send(*family)
            mp_packed_generator = MPRNLRI(mps).packed_attributes(addpath)
            try:
                while True:
                    packed = mp_packed_generator.next()
                    if len(packed_del + packed_mp_del + packed_mp_add +
                           packed) >= msg_size:
                        if not packed_mp_add and not packed_mp_del and not packed_del:
                            raise Notify(
                                6, 0,
                                'attributes size is so large we can not even pack on MPURNLRI'
                            )
                        yield self._message(
                            prefix(packed_del) +
                            prefix(attr + packed_mp_del + packed_mp_add))
                        packed_del = ''
                        packed_mp_del = ''
                        packed_mp_add = packed
                    else:
                        packed_mp_add += packed
            except StopIteration:
                pass

        # ADD Ipv4

        packed_add = ''

        if add_nlri:
            msg_size = negotiated.msg_size - 19 - 2 - 2 - len(
                attr)  # 2 bytes for each of the two prefix() header
        if len(packed_del + packed_mp_del + packed_mp_add) >= msg_size:
            yield self._message(prefix(packed_del) + prefix(packed_mp_del))
            packed_del = ''
            packed_mp_del = ''

        addpath = negotiated.addpath.send(AFI.ipv4, SAFI.unicast)

        while add_nlri:
            nlri = add_nlri.pop()
            packed = nlri.pack(addpath)
            if len(packed_del + packed_mp_del + packed_mp_add + packed_add +
                   packed) >= msg_size:
                if not packed_add and not packed_mp_add and not packed_mp_del and not packed_del:
                    raise Notify(
                        6, 0,
                        'attributes size is so large we can not even pack one NLRI'
                    )
                if packed_mp_add:
                    yield self._message(
                        prefix(packed_del) +
                        prefix(attr + packed_mp_del + packed_mp_add) +
                        packed_add)
                    msg_size = negotiated.msg_size - 19 - 2 - 2  # 2 bytes for each of the two prefix() header
                else:
                    yield self._message(
                        prefix(packed_del) + prefix(attr + packed_mp_del) +
                        packed_add)
                packed_del = ''
                packed_mp_del = ''
                packed_mp_add = ''
                packed_add = packed
            else:
                packed_add += packed

        yield self._message(
            prefix(packed_del) + prefix(attr + packed_mp_del + packed_mp_add) +
            packed_add)
Beispiel #2
0
    def messages(self, negotiated):
        attributes = ''

        asn4 = negotiated.asn4
        local_as = negotiated.local_as
        peer_as = negotiated.peer_as

        msg_size = negotiated.msg_size - 2 - 2  # 2 bytes for each of the two prefix() header

        # sort the nlris

        add_nlri = []
        del_nlri = []
        add_mp = {}
        del_mp = {}

        for nlri in self.nlris:
            if nlri.family() in negotiated.families:
                if nlri.afi == AFI.ipv4 and nlri.safi in [
                        SAFI.unicast, SAFI.multicast
                ]:
                    if nlri.action == OUT.announce:
                        add_nlri.append(nlri)
                    else:
                        del_nlri.append(nlri)
                else:
                    if nlri.action == OUT.announce:
                        add_mp.setdefault(nlri.family(), []).append(nlri)
                    else:
                        del_mp.setdefault(nlri.family(), []).append(nlri)

        if not add_nlri and not del_nlri and not add_mp and not del_mp:
            return

        if add_nlri:
            attr = self.attributes.pack(asn4, local_as, peer_as, True)
        elif add_mp:
            add_default = False
            for afi, safi in add_mp:
                if safi not in (SAFI.flow_ip, SAFI.flow_vpn):
                    add_default = True
            attr = self.attributes.pack(asn4, local_as, peer_as, add_default)
        else:
            attr = ''

        # generate the message

        packed_del = ''
        packed_mp_del = ''
        packed_mp_add = ''
        packed_add = ''

        # withdrawn IPv4

        addpath = negotiated.addpath.send(AFI.ipv4, SAFI.unicast)

        while del_nlri:
            nlri = del_nlri.pop()
            packed = nlri.pack(addpath)
            if len(packed_del + packed) > msg_size:
                if not packed_del:
                    raise Notify(
                        6, 0,
                        'attributes size is so large we can not even pack one NLRI'
                    )
                yield self._message(prefix(packed_del))
                packed_del = packed
            else:
                packed_del += packed

        # withdrawn MP

        families = del_mp.keys()
        while families:
            family = families.pop()
            mps = del_mp[family]
            addpath = negotiated.addpath.send(*family)
            mp_packed_generator = MPURNLRI(mps).packed_attributes(addpath)
            try:
                while True:
                    packed = mp_packed_generator.next()
                    if len(packed_del + packed_mp_del + packed) > msg_size:
                        if not packed_mp_del and not packed_del:
                            raise Notify(
                                6, 0,
                                'attributes size is so large we can not even pack one MPURNLRI'
                            )
                        yield self._message(
                            prefix(packed_del) + prefix(packed_mp_del))
                        packed_del = ''
                        packed_mp_del = packed
                    else:
                        packed_mp_del += packed
            except StopIteration:
                pass

        # we have some MPRNLRI so we need to add the attributes, recalculate
        # and make sure we do not overflow

        if add_mp:
            msg_size = negotiated.msg_size - 2 - 2 - len(
                attr)  # 2 bytes for each of the two prefix() header
        if len(packed_del + packed_mp_del) > msg_size:
            yield self._message(prefix(packed_del) + prefix(packed_mp_del))
            packed_del = ''
            packed_mp_del = ''

        # add MP

        families = add_mp.keys()
        while families:
            family = families.pop()
            mps = add_mp[family]
            addpath = negotiated.addpath.send(*family)
            mp_packed_generator = MPRNLRI(mps).packed_attributes(addpath)
            try:
                while True:
                    packed = mp_packed_generator.next()
                    if len(packed_del + packed_mp_del + packed_mp_add +
                           packed) > msg_size:
                        if not packed_mp_add and not packed_mp_del and not packed_del:
                            raise Notify(
                                6, 0,
                                'attributes size is so large we can not even pack on MPURNLRI'
                            )
                        yield self._message(
                            prefix(packed_del) +
                            prefix(attributes + packed_mp_del + packed_mp_add))
                        packed_del = ''
                        packed_mp_del = ''
                        packed_mp_add = packed
                        if family not in ((AFI.ipv4, SAFI.flow_ip),
                                          (AFI.ipv4, SAFI.flow_vpn)):
                            attributes = attr
                        else:
                            attributes = ''
                    else:
                        packed_mp_add += packed
                        attributes = attr
            except StopIteration:
                pass

        # recalculate size if we do not have any more attributes to send

        if not packed_mp_add:
            msg_size = negotiated.msg_size - 2 - 2  # 2 bytes for each of the two prefix() header

        # ADD Ipv4

        addpath = negotiated.addpath.send(AFI.ipv4, SAFI.unicast)
        while add_nlri:
            nlri = add_nlri.pop()
            packed = nlri.pack(addpath)
            if len(packed_del + packed_mp_del + packed_mp_add + packed_add +
                   packed) > msg_size:
                if not packed_add and not packed_mp_add and not packed_mp_del and not packed_del:
                    raise Notify(
                        6, 0,
                        'attributes size is so large we can not even pack one NLRI'
                    )
                if packed_mp_add:
                    yield self._message(
                        prefix(packed_del) +
                        prefix(attributes + packed_mp_del + packed_mp_add) +
                        packed_add)
                    msg_size = negotiated.msg_size - 2 - 2  # 2 bytes for each of the two prefix() header
                else:
                    yield self._message(
                        prefix(packed_del) + prefix(packed_mp_del) +
                        packed_add)
                packed_del = ''
                packed_mp_del = ''
                packed_mp_add = ''
                packed_add = packed
                attributes = attr
            else:
                packed_add += packed
                attributes = attr

        yield self._message(
            prefix(packed_del) +
            prefix(attributes + packed_mp_del + packed_mp_add) + packed_add)