3 # pcepdump - Display messages from PCCs
5 # Copyright (c) 2012,2013 Cisco Systems, Inc. and others. All rights reserved.
7 # This program and the accompanying materials are made available under the
8 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
9 # and is available at http://www.eclipse.org/legal/epl-v10.html
20 import pcepy.peer as _P
21 import pcepy.session as _S
22 import pcepy.message as _M
23 from pcepy.message import object as _O
25 _LOGGER = logging.getLogger('pcepy.peer')
27 DEFAULT_IP = '0.0.0.0'
30 class PcepDumper(_P.Context):
31 """A manager for a PCEP connection.
33 PcepDumper can be PCC or PCE and it main function it to listen in and
34 print incoming messages. It aslo provide interface for sending messages.
35 This class should not be used directly, use one of subclasses instead.
38 def __init__(self, config, loglevel):
39 super(PcepDumper, self).__init__(config)
40 self.logger = logging.getLogger()
41 handler = logging.StreamHandler()
44 "%(asctime)s: %(levelname)s;%(message)s",
48 self.logger.addHandler(handler)
49 self.loglevel = loglevel
54 return self.logger.getEffectiveLevel()
57 def loglevel(self, level):
58 "Set the log level of root logger"
59 self.logger.setLevel(level)
62 self.logger.info("Bringing PCE down")
72 self.logger.info('Waiting on bus stop')
75 self.logger.info("All connections are down.")
77 except Exception as err:
78 self.logger.exception("Clean shutdown failed: %s" % err)
81 def on_message(self, session, eventargs):
83 dt = datetime.datetime.now()
84 # Dont print KeepAlive messages in quiet mode
85 if self.loglevel == logging.WARN and \
86 isinstance(eventargs['message'], _M.Keepalive):
90 print("=======\n%s: Message on %s:\n%s\n=======" % (
91 dt.strftime("%Y-%m-%d %H:%M:%S"), eventargs['session'],
92 eventargs['message'].show(
94 'msg_sep':'\n', 'obj_sep':'\n',
95 'item_sep':'\n', 'data':'\n'
101 class ManualOpener(_P.base.Opener):
102 def on_connect(self, peer, eventargs):
103 # Copy paste from peer.base.Opener, only difference is that we don't
105 session = eventargs['session']
106 if session.is_server():
109 # TODO: duplicate sessions -> send err 9 close
110 session[_P.base.Opener.STATE_STATE] = _P.base.Opener.OS_OPENWAIT
111 session[_P.base.Opener.STATE_PCEPTYPE] = \
112 self._get_pceptype(peer, session)
113 session[_P.base.Opener.STATE_SESSIONID] = \
114 self._get_sessionid(peer, session)
115 session[_P.base.Keeper.STATE_KEEPALIVE] = self._get_keepalive(peer, session)
116 session[_P.base.Keeper.STATE_DEADTIMER] = self._get_deadtimer(peer, session)
117 session[_P.base.Opener.STATE_OPENWAIT] = \
118 _P.base.resolve_timeout(_P.base.Opener.OPENWAIT)
120 def on_message(self, peer, eventargs):
121 session = eventargs['session']
122 message = eventargs['message']
123 state = session[_P.base.Opener.STATE_STATE]
125 is_open = isinstance(message, _M.Open)
128 open = message.get(_O.Open)
129 if state == _P.base.Opener.OS_OPENWAIT:
131 _LOGGER.error('Open message without Open object received')
134 session[_P.base.Opener.STATE_REMOTE_OPEN] = open
135 accept_open = self._accept_open(peer, session, open)
137 if accept_open is True:
138 del session[_P.base.Opener.STATE_OPENWAIT]
139 session[_P.base.Opener.STATE_REMOTE_OK] = True
140 session[_P.base.Opener.STATE_STATE] = \
141 _P.base.Opener.OS_KEEPWAIT
144 _LOGGER.error('Open message received in %s state' % state)
146 elif isinstance(message, _M.Keepalive):
147 if state == _P.base.Opener.OS_KEEPWAIT:
148 del session[_P.base.Opener.STATE_KEEPWAIT]
150 elif state != _P.base.Opener.OS_UP:
151 _LOGGER.error('Keepalive message received in %s state' % state)
154 def send_open(self, keepalive, deadtimer, session_id):
155 send(_M.Open(_O.Open(
157 deaedtimer=deadtimer,
158 session_id=session_id
160 self.open_sended = True
162 def send_keepalive(self, peer, session):
164 self._session_open(peer, session)
165 session[_P.base.Opener.STATE_STATE] = _P.base.Opener.OS_UP
168 class PccDumper(PcepDumper):
169 """ PCC manager. See PcepDumper for more info. """
170 def __init__(self, config, loglevel, manual_open):
171 super(PccDumper, self).__init__(config, loglevel)
172 self.peer = _P.Pcc('PDE', self)
173 self.peer.add_handler(self)
174 self.role = _S.Node.ROLE_PCC
177 self.peer.remove_handler(_P.base.Opener)
178 self.opener = ManualOpener()
179 self.peer.add_handler(self.opener)
181 def send_open(keepalive=30, deadtimer=120, session_id=1):
182 self.opener.send_open(keepalive, deadtimer, session_id)
184 def send_keepalive():
185 self.opener.send_keepalive(self.peer, self.peer.sessions[0])
187 self.send_open = send_open
188 self.send_keepalive = send_keepalive
190 def start(self, address, port):
191 self.logger.info("Starting dumper on %s:%s" % (address, port))
192 address = self.address_from(address)
194 local = '::' if self.address_is_ipv6(address) else '0.0.0.0'
195 self.peer_node = self.get_node(self.role, 'DumpNode',
196 self.address_from(local)
198 self.mark_node = self.get_node(self.role, 'MarkNode',
199 self.address_from(address), port
201 self.peer.create_session(self.peer_node, self.mark_node)
203 if not self.bus.is_alive():
206 def send_open(self, keepalive=30, deadtimer=120, session_id=1):
207 send(_M.Open(_O.Open(
210 session_id=session_id
214 def send_keepalive(self):
217 class PceDumper(PcepDumper):
218 """ PCE manager. See PcepDumper for more info. """
219 def __init__(self, config, loglevel):
220 super(PceDumper, self).__init__(config, loglevel)
221 self.peer = _P.Pce('PDE', self)
222 self.peer.add_handler(self)
223 self.role = _S.Node.ROLE_PCE
225 def start(self, address, port):
226 self.logger.info("Starting dumper on %s:%s" % (address, port))
227 address = self.address_from(address)
229 self.peer_node = self.get_node(self.role, 'DumpNode', address, port)
230 self.peer.create_server(self.peer_node)
232 if not self.bus.is_alive():
235 def ipaddr_port_type(data):
237 ip, port = data.split('@')
243 ip = _P.Context.address_from(ip)
245 raise argparse.ArgumentTypeError('Invalid IP address: %s' % ip)
250 raise argparse.ArgumentTypeError('Invalid port: %s' % port)
255 sys.exit(dumper.exit())
257 def process_arguments(arguments):
258 """ Initialize command line arguments parser. """
260 parser = argparse.ArgumentParser(
261 description='Command line utility for running PCE or PCC and printing \
263 version='%(prog)s 0.1 Copyright (c) 2012,2013 Cisco Systems, Inc. and others. All rights reserved.',
264 usage='%(prog)s [OPTION]...',
267 group_type = parser.add_argument_group()
269 group_type.add_argument(
271 action='store_const',
275 help='Enable PCC mode (PCE is default)',
278 group_parameters = parser.add_argument_group()
280 group_parameters.add_argument(
283 type=ipaddr_port_type,
285 default=(_P.Context.address_from(DEFAULT_IP), _S.PCEP_PORT),
287 help='the ip address and port to which is this server bound'
290 group_parameters.add_argument(
294 dest=_P.base.Opener.CONFIG_NODE_ID,
296 help='the node ID for PCE',
299 group_parameters.add_argument(
300 '-k', '-ka', '--keepalive',
303 dest=_P.base.Keeper.CONFIG_KEEPALIVE,
306 help='in seconds, value of the desired KeepAlive timer'
309 group_parameters.add_argument(
313 dest=_P.base.Keeper.CONFIG_DEADTIMER,
316 help='in seconds, value of the desired deadtimer'
319 group_open = parser.add_argument_group()
321 group_open.add_argument(
323 action='store_const',
327 help='Force manual session opening (pcc only)'
330 group_mode = parser.add_argument_group()
332 # TODO: Maybe raise error when specified more of these?
333 # Now, last one specified is used.
334 group_mode.add_argument(
336 action='store_const',
337 const=_P.base.Opener.PCEPTYPE_STATEFUL,
338 dest=_P.base.Opener.CONFIG_PCEPTYPE,
339 default=_P.base.Opener.PCEPTYPE_STATELESS,
340 help='passive stateful'
343 group_mode.add_argument(
345 action='store_const',
346 const=_P.base.Opener.PCEPTYPE_STATEFULA,
347 dest=_P.base.Opener.CONFIG_PCEPTYPE,
348 default=_P.base.Opener.PCEPTYPE_STATELESS,
349 help='active stateful'
352 group_mode.add_argument(
355 dest=_P.base.Opener.CONFIG_DB_VERSION,
359 help='version number for versioned stateful'
362 group_output = parser.add_argument_group()
364 group_output.add_argument(
366 action='store_const',
369 default=logging.INFO,
370 help='Suppres WARN log level (INFO is default)',
373 group_output.add_argument(
375 action='store_const',
378 default=logging.INFO,
379 help='Suppres DEBUG log level (INFO is default)',
382 # Parse arguments and create dict
383 parsed_args = vars(parser.parse_args(arguments))
385 # If keepalive timer was set and deadtimer was not, reset it to
386 # 4 times keepalive (max value is 255)
387 parsed_args[_P.base.Keeper.CONFIG_DEADTIMER] = \
388 parsed_args[_P.base.Keeper.CONFIG_DEADTIMER]or \
389 parsed_args[_P.base.Keeper.CONFIG_KEEPALIVE] * 4 if \
390 parsed_args[_P.base.Keeper.CONFIG_KEEPALIVE] * 4 < 255 else \
393 # Print warning, if user forces deadtimer other than keepalive * 4
394 if parsed_args[_P.base.Keeper.CONFIG_DEADTIMER] != \
395 parsed_args[_P.base.Keeper.CONFIG_KEEPALIVE] * 4:
396 sys.stderr.write('Warrning: deadtimer (%s) should be 4 times bigger '\
397 'than keepalive (%s)\n' \
398 % (parsed_args[_P.base.Keeper.CONFIG_DEADTIMER],
399 parsed_args[_P.base.Keeper.CONFIG_KEEPALIVE]))
401 # Set stateful type if versioned and stateless
402 if parsed_args[_P.base.Opener.CONFIG_DB_VERSION] and \
403 parsed_args[_P.base.Opener.CONFIG_PCEPTYPE] == \
404 _P.base.Opener.PCEPTYPE_STATELESS:
406 parsed_args[_P.base.Opener.CONFIG_PCEPTYPE] = \
407 _P.base.Opener.PCEPTYPE_STATEFUL
411 def send(msg, session=0):
412 """ UI function for messages sending. """
414 dumper.peer.sessions[session].send(msg)
416 sys.stderr.write('Could not send message, ' + \
417 'sessions %s doesn\'t exists\n' % session)
422 if __name__ == '__main__':
423 args = process_arguments(sys.argv[1:])
425 # Determine role (PCE or PCC)
426 role = _S.Node.ROLE_PCC if args['pcc'] else _S.Node.ROLE_PCE
430 log_level = args['loglevel']
433 manual_open = args['open']
436 # Additional arguments are used for config construction
437 config_session = _P.pce.Pce.CONFIG_SESSION_CONFIG if \
438 role == _S.Node.ROLE_PCE else _P.pcc.Pcc.CONFIG_SESSION_CONFIG
442 { key : value for key, value in args.iteritems() if \
446 # Create and start dumper
447 if role == _S.Node.ROLE_PCC:
448 dumper = PccDumper(config, log_level, manual_open)
450 dumper = PceDumper(config, log_level)
452 dumper.start(args['ip_port'][0], args['ip_port'][1])
454 code.interact(banner=None, local=globals())
455 sys.exit(dumper.exit())