backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / services / protocols / bgp / bmp.py
1 # Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 from ryu.services.protocols.bgp.base import Activity
17 from ryu.lib import hub
18 from ryu.lib.packet import bmp
19 from ryu.lib.packet import bgp
20 import socket
21 import logging
22 from calendar import timegm
23 from ryu.services.protocols.bgp.signals.emit import BgpSignalBus
24 from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path
25 from ryu.lib.packet.bgp import BGPUpdate
26 from ryu.lib.packet.bgp import BGPPathAttributeMpUnreachNLRI
27
28 LOG = logging.getLogger('bgpspeaker.bmp')
29
30
31 class BMPClient(Activity):
32     """A BMP client.
33
34     Try to establish BMP session between a configured BMP server.
35     If BMP session is established, transfer information about peers
36     (e.g. received and sent open msgs, contents of adj-rib-in, other stats)
37
38     """
39
40     def __init__(self, core_service, host, port):
41         super(BMPClient, self).__init__(name='BMPClient(%s:%s)' % (host, port))
42         self._core_service = core_service
43         self._core_service.signal_bus.register_listener(
44             BgpSignalBus.BGP_ADJ_RIB_IN_CHANGED,
45             lambda _, data: self.on_adj_rib_in_changed(data)
46         )
47         self._core_service.signal_bus.register_listener(
48             BgpSignalBus.BGP_ADJ_UP,
49             lambda _, data: self.on_adj_up(data)
50         )
51         self._core_service.signal_bus.register_listener(
52             BgpSignalBus.BGP_ADJ_DOWN,
53             lambda _, data: self.on_adj_down(data)
54         )
55         self._socket = None
56         self.server_address = (host, port)
57         self._connect_retry_event = hub.Event()
58         self._connect_retry_time = 5
59
60     def _run(self):
61         self._connect_retry_event.set()
62
63         while True:
64             self._connect_retry_event.wait()
65
66             try:
67                 self._connect_retry_event.clear()
68                 self._connect_tcp(self.server_address,
69                                   self._handle_bmp_session)
70             except socket.error:
71                 self._connect_retry_event.set()
72                 LOG.info('Will try to reconnect to %s after %s secs: %s',
73                          self.server_address, self._connect_retry_time,
74                          self._connect_retry_event.is_set())
75
76             self.pause(self._connect_retry_time)
77
78     def _send(self, msg):
79         if not self._socket:
80             return
81         assert isinstance(msg, bmp.BMPMessage)
82         self._socket.send(msg.serialize())
83
84     def on_adj_rib_in_changed(self, data):
85         peer = data['peer']
86         path = data['received_route']
87         msg = self._construct_route_monitoring(peer, path)
88         self._send(msg)
89
90     def on_adj_up(self, data):
91         peer = data['peer']
92         msg = self._construct_peer_up_notification(peer)
93         self._send(msg)
94
95     def on_adj_down(self, data):
96         peer = data['peer']
97         msg = self._construct_peer_down_notification(peer)
98         self._send(msg)
99
100     def _construct_peer_up_notification(self, peer):
101         if peer.is_mpbgp_cap_valid(bgp.RF_IPv4_VPN) or \
102                 peer.is_mpbgp_cap_valid(bgp.RF_IPv6_VPN):
103             peer_type = bmp.BMP_PEER_TYPE_L3VPN
104         else:
105             peer_type = bmp.BMP_PEER_TYPE_GLOBAL
106
107         peer_distinguisher = 0
108         peer_as = peer._neigh_conf.remote_as
109         peer_bgp_id = peer.protocol.recv_open_msg.bgp_identifier
110         timestamp = peer.state._established_time
111
112         local_address = peer.host_bind_ip
113         local_port = int(peer.host_bind_port)
114         peer_address, remote_port = peer.protocol._remotename
115         remote_port = int(remote_port)
116
117         sent_open_msg = peer.protocol.sent_open_msg
118         recv_open_msg = peer.protocol.recv_open_msg
119
120         msg = bmp.BMPPeerUpNotification(local_address=local_address,
121                                         local_port=local_port,
122                                         remote_port=remote_port,
123                                         sent_open_message=sent_open_msg,
124                                         received_open_message=recv_open_msg,
125                                         peer_type=peer_type,
126                                         is_post_policy=False,
127                                         peer_distinguisher=peer_distinguisher,
128                                         peer_address=peer_address,
129                                         peer_as=peer_as,
130                                         peer_bgp_id=peer_bgp_id,
131                                         timestamp=timestamp)
132
133         return msg
134
135     def _construct_peer_down_notification(self, peer):
136         if peer.is_mpbgp_cap_valid(bgp.RF_IPv4_VPN) or \
137                 peer.is_mpbgp_cap_valid(bgp.RF_IPv6_VPN):
138             peer_type = bmp.BMP_PEER_TYPE_L3VPN
139         else:
140             peer_type = bmp.BMP_PEER_TYPE_GLOBAL
141
142         peer_as = peer._neigh_conf.remote_as
143         peer_bgp_id = peer.protocol.recv_open_msg.bgp_identifier
144         peer_address, _ = peer.protocol._remotename
145
146         return bmp.BMPPeerDownNotification(bmp.BMP_PEER_DOWN_REASON_UNKNOWN,
147                                            data=None,
148                                            peer_type=peer_type,
149                                            is_post_policy=False,
150                                            peer_distinguisher=0,
151                                            peer_address=peer_address,
152                                            peer_as=peer_as,
153                                            peer_bgp_id=peer_bgp_id,
154                                            timestamp=0)
155
156     def _construct_update(self, path):
157         # Get copy of path's path attributes.
158         new_pathattr = [attr for attr in path.pathattr_map.values()]
159
160         if path.is_withdraw:
161             if isinstance(path, Ipv4Path):
162                 return BGPUpdate(withdrawn_routes=[path.nlri],
163                                  path_attributes=new_pathattr)
164             else:
165                 mpunreach_attr = BGPPathAttributeMpUnreachNLRI(
166                     path.route_family.afi, path.route_family.safi, [path.nlri]
167                 )
168                 new_pathattr.append(mpunreach_attr)
169         else:
170             if isinstance(path, Ipv4Path):
171                 return BGPUpdate(nlri=[path.nlri],
172                                  path_attributes=new_pathattr)
173
174         return BGPUpdate(path_attributes=new_pathattr)
175
176     def _construct_route_monitoring(self, peer, route):
177         if peer.is_mpbgp_cap_valid(bgp.RF_IPv4_VPN) or \
178                 peer.is_mpbgp_cap_valid(bgp.RF_IPv6_VPN):
179             peer_type = bmp.BMP_PEER_TYPE_L3VPN
180         else:
181             peer_type = bmp.BMP_PEER_TYPE_GLOBAL
182
183         peer_distinguisher = 0
184         peer_as = peer._neigh_conf.remote_as
185         peer_bgp_id = peer.protocol.recv_open_msg.bgp_identifier
186         peer_address, _ = peer.protocol._remotename
187
188         bgp_update = self._construct_update(route.path)
189         is_post_policy = not route.filtered
190         timestamp = timegm(route.timestamp)
191
192         msg = bmp.BMPRouteMonitoring(bgp_update=bgp_update,
193                                      peer_type=peer_type,
194                                      is_post_policy=is_post_policy,
195                                      peer_distinguisher=peer_distinguisher,
196                                      peer_address=peer_address,
197                                      peer_as=peer_as, peer_bgp_id=peer_bgp_id,
198                                      timestamp=timestamp)
199
200         return msg
201
202     def _handle_bmp_session(self, socket):
203
204         self._socket = socket
205         # send init message
206         init_info = {'type': bmp.BMP_INIT_TYPE_STRING,
207                      'value': u'This is Ryu BGP BMP message'}
208         init_msg = bmp.BMPInitiation([init_info])
209         self._send(init_msg)
210
211         # send peer-up message for each peers
212         peer_manager = self._core_service.peer_manager
213
214         for peer in (p for p in peer_manager.iterpeers if p.in_established()):
215             msg = self._construct_peer_up_notification(peer)
216             self._send(msg)
217
218             for path in peer._adj_rib_in.values():
219                 msg = self._construct_route_monitoring(peer, path)
220                 self._send(msg)
221
222         # TODO periodically send stats to bmpstation
223
224         while True:
225             # bmpstation shouldn't send any packet to bmpclient.
226             # this recv() is only meant to detect socket closed
227             ret = self._socket.recv(1)
228             if len(ret) == 0:
229                 LOG.debug('BMP socket is closed. retry connecting..')
230                 self._socket = None
231                 self._connect_retry_event.set()
232                 break
233
234             # silently ignore packets from the bmpstation