Esempio n. 1
0
    def messages(self, negotiated, include_withdraw=True):
        # sort the nlris

        nlris = []
        mp_nlris = {}

        for nlri in sorted(self.nlris):
            if nlri.family() in negotiated.families:
                if nlri.afi == AFI.ipv4 and nlri.safi in [
                        SAFI.unicast, SAFI.multicast
                ] and nlri.nexthop.afi == AFI.ipv4:
                    nlris.append(nlri)
                else:
                    mp_nlris.setdefault(nlri.family(),
                                        {}).setdefault(nlri.action,
                                                       []).append(nlri)

        if not nlris and not mp_nlris:
            return

        # If all we have is MP_UNREACH_NLRI, we do not need the default
        # attributes. See RFC4760 that states the following:
        #
        #	An UPDATE message that contains the MP_UNREACH_NLRI is not required
        #	to carry any other path attributes.
        #
        include_defaults = True

        if mp_nlris and not nlris:

            for family, actions in mp_nlris.items():
                afi, safi = family

                if safi not in (SAFI.unicast, SAFI.multicast):
                    break

                if set(actions.keys()) != {OUT.WITHDRAW}:
                    break
            else:
                include_defaults = False

        attr = self.attributes.pack(negotiated, include_defaults)

        # Withdraws/NLRIS (IPv4 unicast and multicast)
        msg_size = negotiated.msg_size - 19 - 2 - 2 - len(
            attr)  # 2 bytes for each of the two prefix() header

        if msg_size < 0:
            # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
            Logger().critical(
                'attributes size is so large we can not even pack one NLRI',
                'parser')
            return

        if msg_size == 0 and (nlris or mp_nlris):
            # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
            Logger().critical(
                'attributes size is so large we can not even pack one NLRI',
                'parser')
            return

        withdraws = b''
        announced = b''
        for nlri in nlris:
            packed = nlri.pack(negotiated)
            if len(announced + withdraws + packed) <= msg_size:
                if nlri.action == OUT.ANNOUNCE:
                    announced += packed
                elif include_withdraw:
                    withdraws += packed
                continue

            if not withdraws and not announced:
                # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
                Logger().critical(
                    'attributes size is so large we can not even pack one NLRI',
                    'parser')
                return

            if announced:
                yield self._message(
                    Update.prefix(withdraws) + Update.prefix(attr) + announced)
            else:
                yield self._message(
                    Update.prefix(withdraws) + Update.prefix(b'') + announced)

            if nlri.action == OUT.ANNOUNCE:
                announced = packed
                withdraws = b''
            elif include_withdraw:
                withdraws = packed
                announced = b''
            else:
                withdraws = b''
                announced = b''

        if announced or withdraws:
            if announced:
                yield self._message(
                    Update.prefix(withdraws) + Update.prefix(attr) + announced)
            else:
                yield self._message(
                    Update.prefix(withdraws) + Update.prefix(b'') + announced)

        for family in mp_nlris.keys():
            afi, safi = family
            mp_reach = b''
            mp_unreach = b''
            mp_announce = MPRNLRI(afi, safi,
                                  mp_nlris[family].get(OUT.ANNOUNCE, []))
            mp_withdraw = MPURNLRI(afi, safi,
                                   mp_nlris[family].get(OUT.WITHDRAW, []))

            for mprnlri in mp_announce.packed_attributes(
                    negotiated, msg_size - len(withdraws + announced)):
                if mp_reach:
                    yield self._message(
                        Update.prefix(withdraws) +
                        Update.prefix(attr + mp_reach) + announced)
                    announced = b''
                    withdraws = b''
                mp_reach = mprnlri

            if include_withdraw:
                for mpurnlri in mp_withdraw.packed_attributes(
                        negotiated,
                        msg_size - len(withdraws + announced + mp_reach)):
                    if mp_unreach:
                        yield self._message(
                            Update.prefix(withdraws) +
                            Update.prefix(attr + mp_unreach + mp_reach) +
                            announced)
                        mp_reach = b''
                        announced = b''
                        withdraws = b''
                    mp_unreach = mpurnlri

            yield self._message(
                Update.prefix(withdraws) +
                Update.prefix(attr + mp_unreach + mp_reach) +
                announced)  # yield mpr/mpur per family
            withdraws = b''
            announced = b''
Esempio n. 2
0
	def messages (self, negotiated, include_withdraw=True):
		# 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)
					elif include_withdraw:
						del_nlri.append(nlri)
				else:
					if nlri.action == OUT.ANNOUNCE:
						add_mp.setdefault(nlri.family(),[]).append(nlri)
					elif include_withdraw:
						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

		while del_nlri:
			nlri = del_nlri.pop()
			packed = nlri.pack(negotiated)
			seen_size = len(packed_del + packed)
			if seen_size > 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(Update.prefix(packed_del) + Update.prefix(''))
				packed_del = packed
			else:
				packed_del += packed

		# withdrawn MP

		packed_mp_del = ''

		families = del_mp.keys()
		while families:
			family = families.pop()
			afi,safi = family
			mps = del_mp[family]
			seen_size = len(packed_del + packed_mp_del)
			mp_packed_generator = MPURNLRI(afi,safi,mps).packed_attributes(negotiated)
			try:
				while True:
					packed = mp_packed_generator.next()
					seen_size = len(packed_del + packed_mp_del + packed)
					if seen_size > 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(Update.prefix(packed_del) + Update.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
		seen_size = len(packed_del + packed_mp_del)
		if seen_size > msg_size:
			yield self._message(Update.prefix(packed_del) + Update.prefix(packed_mp_del))
			packed_del = ''
			packed_mp_del = ''

		families = add_mp.keys()
		while families:
			family = families.pop()
			afi,safi = family
			mps = add_mp[family]
			seen_size = len(packed_del + packed_mp_del + packed_mp_add)
			mp_packed_generator = MPRNLRI(afi,safi,mps).packed_attributes(negotiated)
			try:
				while True:
					packed = mp_packed_generator.next()
					seen_size = len(packed_del + packed_mp_del + packed_mp_add + packed)
					if seen_size > 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(Update.prefix(packed_del) + Update.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
		seen_size = len(packed_del + packed_mp_del + packed_mp_add)
		if seen_size > msg_size:
			yield self._message(Update.prefix(packed_del) + Update.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(negotiated)
			seen_size = len(packed_del + packed_mp_del + packed_mp_add + packed_add + packed)
			if seen_size > 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(Update.prefix(packed_del) + Update.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(Update.prefix(packed_del) + Update.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(Update.prefix(packed_del) + Update.prefix(attr + packed_mp_del + packed_mp_add) + packed_add)
Esempio n. 3
0
    def messages(self, negotiated, include_withdraw=True):
        # sort the nlris

        nlris = []
        mp_nlris = {}

        for nlri in self.nlris:
            if nlri.family() in negotiated.families:
                if nlri.afi == AFI.ipv4 and nlri.safi in [
                        SAFI.unicast, SAFI.multicast
                ]:
                    nlris.append(nlri)
                else:
                    mp_nlris.setdefault(nlri.family(),
                                        {}).setdefault(nlri.action,
                                                       []).append(nlri)

        if not nlris and not mp_nlris:
            return

        attr = self.attributes.pack(negotiated, True)

        # Withdraws/NLRIS (IPv4 unicast and multicast)
        msg_size = negotiated.msg_size - 19 - 2 - 2 - len(
            attr)  # 2 bytes for each of the two prefix() header
        withdraws = b''
        announced = b''
        for nlri in nlris:
            packed = nlri.pack(negotiated)
            if len(announced + withdraws + packed) > msg_size:
                if not withdraws and not announced:
                    raise Notify(
                        6, 0,
                        'attributes size is so large we can not even pack one NLRI'
                    )
                yield self._message(
                    Update.prefix(withdraws) + Update.prefix(attr) + announced)
                if nlri.action == OUT.ANNOUNCE:
                    announced = packed
                    withdraws = b''
                elif include_withdraw:
                    withdraws = packed
                    announced = b''
            else:
                if nlri.action == OUT.ANNOUNCE:
                    announced += packed
                elif include_withdraw:
                    withdraws += packed

        if mp_nlris:
            for family in mp_nlris.keys():
                afi, safi = family
                mp_reach = b''
                mp_unreach = b''
                mp_announce = MPRNLRI(afi, safi,
                                      mp_nlris[family].get(OUT.ANNOUNCE, []))
                mp_withdraw = MPURNLRI(afi, safi,
                                       mp_nlris[family].get(OUT.WITHDRAW, []))

                for mprnlri in mp_announce.packed_attributes(
                        negotiated, msg_size - len(withdraws + announced)):
                    if mp_reach:
                        yield self._message(
                            Update.prefix(withdraws) +
                            Update.prefix(attr + mp_reach) + announced)
                        announced = b''
                        withdraws = b''
                    mp_reach = mprnlri

                if include_withdraw:
                    for mpurnlri in mp_withdraw.packed_attributes(
                            negotiated,
                            msg_size - len(withdraws + announced + mp_reach)):
                        if mp_unreach:
                            yield self._message(
                                Update.prefix(withdraws) +
                                Update.prefix(attr + mp_unreach + mp_reach) +
                                announced)
                            mp_reach = b''
                            announced = b''
                            withdraws = b''
                        mp_unreach = mpurnlri

                yield self._message(
                    Update.prefix(withdraws) +
                    Update.prefix(attr + mp_unreach + mp_reach) +
                    announced)  # yield mpr/mpur per family
                withdraws = b''
                announced = b''
        else:
            yield self._message(
                Update.prefix(withdraws) + Update.prefix(attr) + announced)
Esempio n. 4
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

		while del_nlri:
			nlri = del_nlri.pop()
			packed = nlri.pack(negotiated)
			seen_size = len(packed_del + packed)
			if seen_size > 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(Update.prefix(packed_del) + Update.prefix(''))
				packed_del = packed
			else:
				packed_del += packed

		# withdrawn MP

		packed_mp_del = ''

		families = del_mp.keys()
		while families:
			family = families.pop()
			afi,safi = family
			mps = del_mp[family]
			seen_size = len(packed_del + packed_mp_del)
			mp_packed_generator = MPURNLRI(afi,safi,mps).packed_attributes(negotiated)
			try:
				while True:
					packed = mp_packed_generator.next()
					seen_size = len(packed_del + packed_mp_del + packed)
					if seen_size > 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(Update.prefix(packed_del) + Update.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
		seen_size = len(packed_del + packed_mp_del)
		if seen_size > msg_size:
			yield self._message(Update.prefix(packed_del) + Update.prefix(packed_mp_del))
			packed_del = ''
			packed_mp_del = ''

		families = add_mp.keys()
		while families:
			family = families.pop()
			afi,safi = family
			mps = add_mp[family]
			seen_size = len(packed_del + packed_mp_del + packed_mp_add)
			mp_packed_generator = MPRNLRI(afi,safi,mps).packed_attributes(negotiated)
			try:
				while True:
					packed = mp_packed_generator.next()
					seen_size = len(packed_del + packed_mp_del + packed_mp_add + packed)
					if seen_size > 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(Update.prefix(packed_del) + Update.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
		seen_size = len(packed_del + packed_mp_del + packed_mp_add)
		if seen_size > msg_size:
			yield self._message(Update.prefix(packed_del) + Update.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(negotiated)
			seen_size = len(packed_del + packed_mp_del + packed_mp_add + packed_add + packed)
			if seen_size > 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(Update.prefix(packed_del) + Update.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(Update.prefix(packed_del) + Update.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(Update.prefix(packed_del) + Update.prefix(attr + packed_mp_del + packed_mp_add) + packed_add)
Esempio n. 5
0
	def messages (self, negotiated, include_withdraw=True):
		# sort the nlris

		nlris = []
		mp_nlris = {}

		for nlri in self.nlris:
			if nlri.family() in negotiated.families:
				if nlri.afi == AFI.ipv4 and nlri.safi in [SAFI.unicast, SAFI.multicast]:
					nlris.append(nlri)
				else:
					mp_nlris.setdefault(nlri.family(), {}).setdefault(nlri.action, []).append(nlri)

		if not nlris and not mp_nlris:
			return

		attr = self.attributes.pack(negotiated, True)

		# Withdraws/NLRIS (IPv4 unicast and multicast)
		msg_size = negotiated.msg_size - 19 - 2 - 2 - len(attr) # 2 bytes for each of the two prefix() header
		withdraws = b''
		announced = b''
		for nlri in nlris:
			packed = nlri.pack(negotiated)
			if len(announced + withdraws + packed) > msg_size:
				if not withdraws and not announced:
					raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
				yield self._message(Update.prefix(withdraws) + Update.prefix(attr) + announced)
				if nlri.action == OUT.ANNOUNCE:
					announced = packed
					withdraws = b''
				elif include_withdraw:
					withdraws = packed
					announced = b''
			else:
				if nlri.action == OUT.ANNOUNCE:
					announced += packed
				elif include_withdraw:
					withdraws += packed

		if mp_nlris:
			for family in mp_nlris.keys():
				afi, safi = family
				mp_reach = b''
				mp_unreach = b''
				mp_announce = MPRNLRI(afi, safi, mp_nlris[family].get(OUT.ANNOUNCE, []))
				mp_withdraw = MPURNLRI(afi, safi, mp_nlris[family].get(OUT.WITHDRAW, []))

				for mprnlri in mp_announce.packed_attributes(negotiated, msg_size - len(withdraws + announced)):
					if mp_reach:
						yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_reach) + announced)
						announced = b''
						withdraws = b''
					mp_reach = mprnlri

				if include_withdraw:
					for mpurnlri in mp_withdraw.packed_attributes(negotiated, msg_size - len(withdraws + announced + mp_reach)):
						if mp_unreach:
							yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_unreach + mp_reach) + announced)
							mp_reach = b''
							announced = b''
							withdraws = b''
						mp_unreach = mpurnlri

				yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_unreach + mp_reach) + announced) # yield mpr/mpur per family
				withdraws = b''
				announced = b''
		else:
			yield self._message(Update.prefix(withdraws) + Update.prefix(attr) + announced)
Esempio n. 6
0
    def messages (self, negotiated, include_withdraw=True):
        # sort the nlris

        nlris = []
        mp_nlris = {}

        for nlri in sorted(self.nlris):
            if nlri.family() in negotiated.families:
                if nlri.afi == AFI.ipv4 and nlri.safi in [SAFI.unicast, SAFI.multicast] and nlri.nexthop.afi == AFI.ipv4 and not hasattr(negotiated.neighbor,'bgpsec'):
                    nlris.append(nlri)
                else:
                    mp_nlris.setdefault(nlri.family(), {}).setdefault(nlri.action, []).append(nlri)

        if not nlris and not mp_nlris:
            return

        if hasattr(negotiated.neighbor,'bgpsec') and negotiated.neighbor.bgpsec :
            mp_nlris_values = mp_nlris.values()
            for mp_nlri in list(mp_nlris_values)[0].get(OUT.ANNOUNCE, []) :
                attr = self.attributes.pack(negotiated, True, mp_nlri)

                # Withdraws/NLRIS (IPv4 unicast and multicast)
                msg_size = negotiated.msg_size - 19 - 2 - 2 - len(attr)  # 2 bytes for each of the two prefix() header

                if msg_size < 0:
                    # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
                    Logger().critical('attributes size is so large we can not even pack one NLRI','parser')
                    return

                if msg_size == 0 and (nlris or mp_nlris):
                    # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
                    Logger().critical('attributes size is so large we can not even pack one NLRI','parser')
                    return

                withdraws = b''
                announced = b''

                for family in mp_nlris.keys():
                    afi, safi = family
                    mp_reach = b''
                    mp_unreach = b''
                    mp_announce = MPRNLRI(afi, safi, [mp_nlri])
                    mp_withdraw = MPURNLRI(afi, safi, mp_nlris[family].get(OUT.WITHDRAW, []))

                    for mprnlri in mp_announce.packed_attributes(negotiated, msg_size - len(withdraws + announced)):
                        if mp_reach:
                            yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_reach) + announced)
                            announced = b''
                            withdraws = b''
                        mp_reach = mprnlri

                    if include_withdraw:
                        for mpurnlri in mp_withdraw.packed_attributes(negotiated, msg_size - len(withdraws + announced + mp_reach)):
                            if mp_unreach:
                                yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_unreach + mp_reach) + announced)
                                mp_reach = b''
                                announced = b''
                                withdraws = b''
                            mp_unreach = mpurnlri

                    yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_unreach + mp_reach) + announced)  # yield mpr/mpur per family
                    withdraws = b''
                    announced = b''

        else :
            attr = self.attributes.pack(negotiated, True)
            # Withdraws/NLRIS (IPv4 unicast and multicast)
            msg_size = negotiated.msg_size - 19 - 2 - 2 - len(attr)  # 2 bytes for each of the two prefix() header

            if msg_size < 0:
                # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
                Logger().critical('attributes size is so large we can not even pack one NLRI','parser')
                return

            if msg_size == 0 and (nlris or mp_nlris):
                # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
                Logger().critical('attributes size is so large we can not even pack one NLRI','parser')
                return

            withdraws = b''
            announced = b''
            for nlri in nlris:
                packed = nlri.pack(negotiated)
                if len(announced + withdraws + packed) <= msg_size:
                    if nlri.action == OUT.ANNOUNCE:
                        announced += packed
                    elif include_withdraw:
                        withdraws += packed
                    continue

                if not withdraws and not announced:
                    # raise Notify(6,0,'attributes size is so large we can not even pack one NLRI')
                    Logger().critical('attributes size is so large we can not even pack one NLRI','parser')
                    return

                if announced:
                    yield self._message(Update.prefix(withdraws) + Update.prefix(attr) + announced)
                else:
                    yield self._message(Update.prefix(withdraws) + Update.prefix(b'') + announced)

                if nlri.action == OUT.ANNOUNCE:
                    announced = packed
                    withdraws = b''
                elif include_withdraw:
                    withdraws = packed
                    announced = b''
                else:
                    withdraws = b''
                    announced = b''

            if announced or withdraws:
                if announced:
                    yield self._message(Update.prefix(withdraws) + Update.prefix(attr) + announced)
                else:
                    yield self._message(Update.prefix(withdraws) + Update.prefix(b'') + announced)

            for family in mp_nlris.keys():
                afi, safi = family
                mp_reach = b''
                mp_unreach = b''
                mp_announce = MPRNLRI(afi, safi, mp_nlris[family].get(OUT.ANNOUNCE, []))
                mp_withdraw = MPURNLRI(afi, safi, mp_nlris[family].get(OUT.WITHDRAW, []))

                for mprnlri in mp_announce.packed_attributes(negotiated, msg_size - len(withdraws + announced)):
                    if mp_reach:
                        yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_reach) + announced)
                        announced = b''
                        withdraws = b''
                    mp_reach = mprnlri

                if include_withdraw:
                    for mpurnlri in mp_withdraw.packed_attributes(negotiated, msg_size - len(withdraws + announced + mp_reach)):
                        if mp_unreach:
                            yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_unreach + mp_reach) + announced)
                            mp_reach = b''
                            announced = b''
                            withdraws = b''
                        mp_unreach = mpurnlri

                yield self._message(Update.prefix(withdraws) + Update.prefix(attr + mp_unreach + mp_reach) + announced)  # yield mpr/mpur per family
                withdraws = b''
                announced = b''