Completed
Push — master ( 25ce4f...b9bc4f )
by Thomas
11:58
created

SectionAnnounce.__init__()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 5
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
# encoding: utf-8
2
"""
3
announce/__init__.py
4
5
Created by Thomas Mangin on 2015-06-04.
6
Copyright (c) 2009-2017 Exa Networks. All rights reserved.
7
"""
8
9
from exabgp.util import ordinal
10
from exabgp.util import character
11
from exabgp.util import concat_bytes_i
12
13
from exabgp.protocol.ip import IP
14
15
from exabgp.bgp.message import OUT
16
from exabgp.rib.change import Change
17
18
from exabgp.protocol.family import AFI
19
from exabgp.configuration.core import Section
20
21
from exabgp.bgp.message.update.nlri.cidr import CIDR
22
from exabgp.bgp.message.update.attribute import Attribute
23
24
25
# Take an integer an created it networked packed representation for the right family (ipv4/ipv6)
26
def pack_int (afi, integer):
27
	return concat_bytes_i(character((integer >> (offset * 8)) & 0xff) for offset in range(IP.length(afi)-1,-1,-1))
28
29
30
class ParseAnnounce (Section):
31
	syntax = ''
32
	afi = None
33
34
	def post (self):
35
		self._split()
36
		routes = self.scope.pop(self.name)
37
		if routes:
38
			self.scope.extend_routes(routes)
39
		return True
40
41
	@staticmethod
42
	def split (last):
43
		if Attribute.CODE.INTERNAL_SPLIT not in last.attributes:
44
			yield last
45
			return
46
47
		# ignore if the request is for an aggregate, or the same size
48
		mask = last.nlri.cidr.mask
49
		cut = last.attributes[Attribute.CODE.INTERNAL_SPLIT]
50
		if mask >= cut:
51
			yield last
52
			return
53
54
		# calculate the number of IP in the /<size> of the new route
55
		increment = pow(2,last.nlri.afi.mask() - cut)
56
		# how many new routes are we going to create from the initial one
57
		number = pow(2,cut - last.nlri.cidr.mask)
58
59
		# convert the IP into a integer/long
60
		ip = 0
61
		for c in last.nlri.cidr.ton():
62
			ip <<= 8
63
			ip += ordinal(c)
64
65
		afi = last.nlri.afi
66
		safi = last.nlri.safi
67
68
		# Really ugly
69
		klass = last.nlri.__class__
70
		path_info = last.nlri.path_info
71
		nexthop = last.nlri.nexthop
72
73
		# XXX: Looks weird to set and then set to None, check
74
		last.nlri.cidr.mask = cut
75
		last.nlri = None
76
77
		# generate the new routes
78
		for _ in range(number):
79
			# update ip to the next route, this recalculate the "ip" field of the Inet class
80
			nlri = klass(afi,safi,OUT.ANNOUNCE)
81
			nlri.cidr = CIDR(pack_int(afi,ip),cut)
82
			nlri.nexthop = nexthop  # nexthop can be NextHopSelf
83
			nlri.path_info = path_info
84
			# next ip
85
			ip += increment
86
			yield Change(nlri,last.attributes)
87
88
	def _split (self):
89
		for route in self.scope.pop_routes():
90
			for splat in self.split(route):
91
				self.scope.append_route(splat)
92
93
	def _check(self):
94
		if not self.check(self.scope.get(self.name), self.afi):
95
			return self.error.set(self.syntax)
96
		return True
97
98
	@staticmethod
99
	def check (change,afi):
100
		raise RuntimeError('need to be implemented by subclasses')
101
102
103
class SectionAnnounce (ParseAnnounce):
104
	name = 'announce'
105
106
	def __init__ (self, tokeniser, scope, error, logger):
107
		Section.__init__(self,tokeniser,scope,error,logger)
108
109
	def clear (self):
110
		return True
111
112
	def pre (self):
113
		return True
114
115
	def post (self):
116
		routes = self.scope.pop('routes',[])
117
		self.scope.pop()
118
		if routes:
119
			self.scope.extend('routes',routes)
120
		self.scope.pop(self.name)
121
		return True
122
123
124
class AnnounceIPv4 (ParseAnnounce):
125
	name = 'ipv4'
126
	afi = AFI.ipv4
127
128
	def clear (self):
129
		return True
130
131
132
class AnnounceIPv6 (ParseAnnounce):
133
	name = 'ipv6'
134
	afi = AFI.ipv6
135
136
	def clear (self):
137
		return True
138
139
140
class AnnounceL2VPN (ParseAnnounce):
141
	name = 'l2vpn'
142
	afi = AFI.l2vpn
143
144
	def clear (self):
145
		return True
146