vrrp: add statistics support

Supports statistics that Commercial routers provides.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
FUJITA Tomonori 2013-11-27 06:59:49 +09:00
parent 8ad764f193
commit aab020d0a0
4 changed files with 91 additions and 10 deletions

View File

@ -118,7 +118,8 @@ class VRRPConfig(object):
admin_state=None,
priority=vrrp.VRRP_PRIORITY_BACKUP_DEFAULT, ip_addresses=None,
advertisement_interval=vrrp.VRRP_MAX_ADVER_INT_DEFAULT_IN_SEC,
preempt_mode=True, preempt_delay=0, accept_mode=False):
preempt_mode=True, preempt_delay=0, accept_mode=False,
statistics_interval=None, resource_id=None):
# To allow version and priority default
assert vrid is not None
assert ip_addresses is not None
@ -133,8 +134,9 @@ class VRRPConfig(object):
self.preempt_mode = preempt_mode
self.preempt_delay = preempt_delay
self.accept_mode = accept_mode
self.is_ipv6 = vrrp.is_ipv6(ip_addresses[0])
self.statistics_interval = statistics_interval
self.resource_id = resource_id
@property
def address_owner(self):

View File

@ -25,6 +25,8 @@ PYTHONPATH=. ./bin/ryu-manager --verbose \
ryu.services.protocols.vrrp.dumper
"""
import time
from ryu.base import app_manager
from ryu.controller import handler
from ryu.lib import hub
@ -75,11 +77,13 @@ class VRRPManager(app_manager.RyuApp):
self.reply_to_request(ev, rep)
return
statistics = VRRPStatistics(name, config.resource_id,
config.statistics_interval)
monitor = vrrp_monitor.VRRPInterfaceMonitor.factory(
interface, config, name, *self._args, **self._kwargs)
router = vrrp_router.VRRPRouter.factory(
name, monitor.name, interface, config, *self._args, **self._kwargs)
interface, config, name, statistics, *self._args, **self._kwargs)
router = vrrp_router.VRRPRouter.factory(name, monitor.name, interface,
config, statistics,
*self._args, **self._kwargs)
# Event piping
# vrrp_router -> vrrp_manager
# EventVRRPStateChanged to vrrp_manager is handled by framework
@ -155,3 +159,38 @@ class VRRPManager(app_manager.RyuApp):
vrrp_list = vrrp_event.EventVRRPListReply(instance_list)
self.reply_to_request(ev, vrrp_list)
class VRRPStatistics(object):
def __init__(self, name, resource_id, statistics_interval):
self.name = name
self.resource_id = resource_id
self.statistics_interval = statistics_interval
self.tx_vrrp_packets = 0
self.rx_vrrp_packets = 0
self.rx_vrrp_zero_prio_packets = 0
self.tx_vrrp_zero_prio_packets = 0
self.rx_vrrp_invalid_packets = 0
self.rx_vrrp_bad_auth = 0
self.idle_to_master_transitions = 0
self.idle_to_backup_transitions = 0
self.backup_to_master_transitions = 0
self.master_to_backup_transitions = 0
def get_stats(self):
ts = time.strftime("%Y-%m-%dT%H:%M:%S")
stats_dict = dict(
timestamp=ts,
resource_id=self.resource_id,
tx_vrrp_packets=self.tx_vrrp_packets,
rx_vrrp_packets=self.rx_vrrp_packets,
rx_vrrp_zero_prio_packets=self.rx_vrrp_zero_prio_packets,
tx_vrrp_zero_prio_packets=self.tx_vrrp_zero_prio_packets,
rx_vrrp_invalid_packets=self.rx_vrrp_invalid_packets,
rx_vrrp_bad_auth=self.rx_vrrp_bad_auth,
idle_to_master_transitions=self.idle_to_master_transitions,
idle_to_backup_transitions=self.idle_to_backup_transitions,
backup_to_master_transitions=self.backup_to_master_transitions,
master_to_backup_transitions=self.master_to_backup_transitions
)
return stats_dict

View File

@ -40,7 +40,7 @@ class VRRPInterfaceMonitor(app_manager.RyuApp):
return _register
@staticmethod
def factory(interface, config, router_name, *args, **kwargs):
def factory(interface, config, router_name, statistics, *args, **kwargs):
cls = VRRPInterfaceMonitor._CONSTRUCTORS[interface.__class__]
app_mgr = app_manager.AppManager.get_instance()
@ -48,6 +48,7 @@ class VRRPInterfaceMonitor(app_manager.RyuApp):
kwargs['router_name'] = router_name
kwargs['vrrp_config'] = config
kwargs['vrrp_interface'] = interface
kwargs['vrrp_statistics'] = statistics
app = app_mgr.instantiate(cls, *args, **kwargs)
return app
@ -60,9 +61,10 @@ class VRRPInterfaceMonitor(app_manager.RyuApp):
self.config = kwargs['vrrp_config']
self.interface = kwargs['vrrp_interface']
self.router_name = kwargs['router_name']
self.statistics = kwargs['vrrp_statistics']
self.name = self.instance_name(self.interface, self.config.vrid)
def _send_vrrp_packet_received(self, packet_data):
def _parse_received_packet(self, packet_data):
# OF doesn't support VRRP packet matching, so we have to parse
# it ourselvs.
packet_ = packet.Packet(packet_data)
@ -120,9 +122,19 @@ class VRRPInterfaceMonitor(app_manager.RyuApp):
# TODO: Optional check rfc5798 7.1
# may_vrrp.ip_addresses equals to self.config.ip_addresses
if may_vrrp.priority == 0:
self.statistics.rx_vrrp_zero_prio_packets += 1
vrrp_received = vrrp_event.EventVRRPReceived(self.interface, packet_)
self.send_event(self.router_name, vrrp_received)
return True
def _send_vrrp_packet_received(self, packet_data):
valid = self._parse_received_packet(packet_data)
if valid is True:
self.statistics.rx_vrrp_packets += 1
else:
self.statistics.rx_vrrp_invalid_packets += 1
@handler.set_ev_handler(vrrp_event.EventVRRPTransmitRequest)
def vrrp_transmit_request_handler(self, ev):
@ -146,6 +158,15 @@ class VRRPInterfaceMonitor(app_manager.RyuApp):
self._initialize()
elif ev.new_state in [vrrp_event.VRRP_STATE_BACKUP,
vrrp_event.VRRP_STATE_MASTER]:
pass
if ev.old_state == vrrp_event.VRRP_STATE_INITIALIZE:
if ev.new_state == vrrp_event.VRRP_STATE_MASTER:
self.statistics.idle_to_master_transitions += 1
else:
self.statistics.idle_to_backup_transitions += 1
elif ev.old_state == vrrp_event.VRRP_STATE_MASTER:
self.statistics.master_to_backup_transitions += 1
else:
self.statistics.backup_to_master_transitions += 1
else:
raise RuntimeError('unknown vrrp state %s' % ev.new_state)

View File

@ -148,7 +148,8 @@ class VRRPRouter(app_manager.RyuApp):
return _register
@staticmethod
def factory(name, monitor_name, interface, config, *args, **kwargs):
def factory(name, monitor_name, interface, config, statistics, *args,
**kwargs):
cls = VRRPRouter._CONSTRUCTORS[config.version]
app_mgr = app_manager.AppManager.get_instance()
kwargs = kwargs.copy()
@ -156,6 +157,7 @@ class VRRPRouter(app_manager.RyuApp):
kwargs['monitor_name'] = monitor_name
kwargs['vrrp_interface'] = interface
kwargs['vrrp_config'] = config
kwargs['vrrp_statistics'] = statistics
return app_mgr.instantiate(cls, *args, **kwargs)
class _EventMasterDown(event.EventBase):
@ -167,12 +169,16 @@ class VRRPRouter(app_manager.RyuApp):
class _EventPreemptDelay(event.EventBase):
pass
class _EventStatisticsOut(event.EventBase):
pass
def __init__(self, *args, **kwargs):
super(VRRPRouter, self).__init__(*args, **kwargs)
self.name = kwargs['name']
self.monitor_name = kwargs['monitor_name']
self.interface = kwargs['vrrp_interface']
self.config = kwargs['vrrp_config']
self.statistics = kwargs['vrrp_statistics']
self.params = VRRPParams(self.config)
self.state = None
self.state_impl = None
@ -185,6 +191,10 @@ class VRRPRouter(app_manager.RyuApp):
self.register_observer(self._EventMasterDown, self.name)
self.register_observer(self._EventAdver, self.name)
self.stats_out_timer = TimerEventSender(self,
self._EventStatisticsOut)
self.register_observer(self._EventStatisticsOut, self.name)
def send_advertisement(self, release=False):
if self.vrrp is None:
config = self.config
@ -200,12 +210,15 @@ class VRRPRouter(app_manager.RyuApp):
vrrp.VRRP_PRIORITY_RELEASE_RESPONSIBILITY,
vrrp_.max_adver_int, vrrp_.ip_addresses)
if self.vrrp.priority == 0:
self.statistics.tx_vrrp_zero_prio_packets += 1
# create packet frame each time to generate new ip identity
interface = self.interface
packet_ = vrrp_.create_packet(interface.primary_ip_address,
interface.vlan_id)
packet_.serialize()
vrrp_api.vrrp_transmit(self, self.monitor_name, packet_.data)
self.statistics.tx_vrrp_packets += 1
def state_change(self, new_state):
old_state = self.state
@ -256,6 +269,11 @@ class VRRPRouter(app_manager.RyuApp):
self.state_impl.vrrp_config_change_request(ev)
@handler.set_ev_handler(_EventStatisticsOut)
def statistics_handler(self, ev):
# sends stats to somewhere here
# print self.statistics.get_stats()
self.stats_out_timer.start(self.statistics.statistics_interval)
# RFC defines that start timer, then change the state.
# This causes the race between state change and event dispatching.
@ -686,4 +704,5 @@ class VRRPRouterV3(VRRPRouter):
self.state_change(vrrp_event.VRRP_STATE_BACKUP)
self.master_down_timer.start(params.master_down_interval)
self.stats_out_timer.start(self.statistics.statistics_interval)
super(VRRPRouterV3, self).start()