-
Notifications
You must be signed in to change notification settings - Fork 14
/
driver.py
206 lines (172 loc) · 9.43 KB
/
driver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from os_ken.services.protocols.bgp import bgpspeaker
from os_ken.services.protocols.bgp.rtconf.neighbors import CONNECT_MODE_ACTIVE
from oslo_log import log as logging
from oslo_utils import encodeutils
from neutron_dynamic_routing._i18n import _LE, _LI
from neutron_dynamic_routing.services.bgp.agent.driver import base
from neutron_dynamic_routing.services.bgp.agent.driver import exceptions as bgp_driver_exc # noqa
from neutron_dynamic_routing.services.bgp.agent.driver import utils
LOG = logging.getLogger(__name__)
# Function for logging BGP peer and path changes.
def bgp_peer_down_cb(remote_ip, remote_as):
LOG.info(_LI('BGP Peer %(peer_ip)s for remote_as=%(peer_as)d went DOWN.'),
{'peer_ip': remote_ip, 'peer_as': remote_as})
def bgp_peer_up_cb(remote_ip, remote_as):
LOG.info(_LI('BGP Peer %(peer_ip)s for remote_as=%(peer_as)d is UP.'),
{'peer_ip': remote_ip, 'peer_as': remote_as})
def best_path_change_cb(event):
LOG.info(_LI("Best path change observed. cidr=%(prefix)s, "
"nexthop=%(nexthop)s, remote_as=%(remote_as)d, "
"is_withdraw=%(is_withdraw)s"),
{'prefix': event.prefix, 'nexthop': event.nexthop,
'remote_as': event.remote_as,
'is_withdraw': event.is_withdraw})
class OsKenBgpDriver(base.BgpDriverBase):
"""BGP speaker implementation via os-ken."""
def __init__(self, cfg):
LOG.info(_LI('Initializing os-ken driver for BGP functionality.'))
self._read_config(cfg)
# Note: Even though os-ken can only support one BGP speaker as of now,
# we have tried making the framework generic for the future purposes.
self.cache = utils.BgpMultiSpeakerCache()
def _read_config(self, cfg):
if cfg is None or cfg.bgp_router_id is None:
# If either cfg or router_id is not specified, raise voice
LOG.error(_LE('BGP router-id MUST be specified for the correct '
'functional working.'))
else:
self.routerid = cfg.bgp_router_id
LOG.info(_LI('Initialized os-ken BGP Speaker driver interface '
'with bgp_router_id=%s'), self.routerid)
def add_bgp_speaker(self, speaker_as):
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if curr_speaker is not None:
raise bgp_driver_exc.BgpSpeakerAlreadyScheduled(
current_as=speaker_as,
rtid=self.routerid)
# os-ken can only support One speaker
if self.cache.get_hosted_bgp_speakers_count() == 1:
raise bgp_driver_exc.BgpSpeakerMaxScheduled(count=1)
# Validate input parameters.
# speaker_as must be an integer in the allowed range.
utils.validate_as_num('local_as', speaker_as)
# Notify os-ken about BGP Speaker addition.
# Please note: Since, only the route-advertisement support is
# implemented we are explicitly setting the bgp_server_port
# attribute to 0 which disables listening on port 179.
curr_speaker = bgpspeaker.BGPSpeaker(as_number=speaker_as,
router_id=self.routerid, bgp_server_port=0,
best_path_change_handler=best_path_change_cb,
peer_down_handler=bgp_peer_down_cb,
peer_up_handler=bgp_peer_up_cb)
LOG.info(_LI('Added BGP Speaker for local_as=%(as)d with '
'router_id= %(rtid)s.'),
{'as': speaker_as, 'rtid': self.routerid})
self.cache.put_bgp_speaker(speaker_as, curr_speaker)
def delete_bgp_speaker(self, speaker_as):
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# Notify os-ken about BGP Speaker deletion
curr_speaker.shutdown()
LOG.info(_LI('Removed BGP Speaker for local_as=%(as)d with '
'router_id=%(rtid)s.'),
{'as': speaker_as, 'rtid': self.routerid})
self.cache.remove_bgp_speaker(speaker_as)
def add_bgp_peer(self, speaker_as, peer_ip, peer_as,
auth_type='none', password=None):
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# Validate peer_ip and peer_as.
utils.validate_as_num('remote_as', peer_as)
utils.validate_ip_addr(peer_ip)
utils.validate_auth(auth_type, password)
if password is not None:
password = encodeutils.to_utf8(password)
curr_speaker.neighbor_add(address=peer_ip,
remote_as=peer_as,
enable_ipv4=True,
enable_ipv6=True,
password=password,
connect_mode=CONNECT_MODE_ACTIVE)
LOG.info(_LI('Added BGP Peer %(peer)s for remote_as=%(as)d to '
'BGP Speaker running for local_as=%(local_as)d.'),
{'peer': peer_ip, 'as': peer_as, 'local_as': speaker_as})
def delete_bgp_peer(self, speaker_as, peer_ip):
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# Validate peer_ip. It must be a string.
utils.validate_ip_addr(peer_ip)
# Notify os-ken about BGP Peer removal
curr_speaker.neighbor_del(address=peer_ip)
LOG.info(_LI('Removed BGP Peer %(peer)s from BGP Speaker '
'running for local_as=%(local_as)d.'),
{'peer': peer_ip, 'local_as': speaker_as})
def advertise_route(self, speaker_as, cidr, nexthop):
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# Validate cidr and nexthop. Both must be strings.
utils.validate_string(cidr)
utils.validate_string(nexthop)
# Notify os-ken about route advertisement
curr_speaker.prefix_add(prefix=cidr, next_hop=nexthop)
LOG.info(_LI('Route cidr=%(prefix)s, nexthop=%(nexthop)s is '
'advertised for BGP Speaker running for '
'local_as=%(local_as)d.'),
{'prefix': cidr, 'nexthop': nexthop, 'local_as': speaker_as})
def withdraw_route(self, speaker_as, cidr, nexthop=None):
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# Validate cidr. It must be a string.
utils.validate_string(cidr)
# Notify os-ken about route withdrawal
curr_speaker.prefix_del(prefix=cidr)
LOG.info(_LI('Route cidr=%(prefix)s is withdrawn from BGP Speaker '
'running for local_as=%(local_as)d.'),
{'prefix': cidr, 'local_as': speaker_as})
def get_bgp_speaker_statistics(self, speaker_as):
LOG.info(_LI('Collecting BGP Speaker statistics for local_as=%d.'),
speaker_as)
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# TODO(vikram): Filter and return the necessary information.
# Will be done as part of new RFE requirement
# https://bugs.launchpad.net/neutron/+bug/1527993
return curr_speaker.neighbor_state_get()
def get_bgp_peer_statistics(self, speaker_as, peer_ip):
LOG.info(_LI('Collecting BGP Peer statistics for peer_ip=%(peer)s, '
'running in speaker_as=%(speaker_as)d '),
{'peer': peer_ip, 'speaker_as': speaker_as})
curr_speaker = self.cache.get_bgp_speaker(speaker_as)
if not curr_speaker:
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
rtid=self.routerid)
# TODO(vikram): Filter and return the necessary information.
# Will be done as part of new RFE requirement
# https://bugs.launchpad.net/neutron/+bug/1527993
return curr_speaker.neighbor_state_get(address=peer_ip)