1 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2013 Isaku Yamahata <yamahata at private email ne jp>
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 VRRP manager that manages VRRP router instances
19 VRRPManager creates/deletes VRRPRouter, VRRPInterfaceMonitor
20 dynamically as requested.
23 PYTHONPATH=. ./bin/ryu-manager --verbose \
24 ryu.services.protocols.vrrp.manager \
25 ryu.services.protocols.vrrp.dumper
30 from ryu.base import app_manager
31 from ryu.controller import handler
32 from ryu.lib import hub
33 from ryu.services.protocols.vrrp import event as vrrp_event
34 from ryu.services.protocols.vrrp import monitor as vrrp_monitor
35 from ryu.services.protocols.vrrp import router as vrrp_router
38 class VRRPInstance(object):
39 def __init__(self, name, monitor_name, config, interface):
40 super(VRRPInstance, self).__init__()
41 self.name = name # vrrp_router.name
42 self.monitor_name = monitor_name # interface_monitor.name
44 self.interface = interface
47 def state_changed(self, new_state):
48 self.state = new_state
51 class VRRPManager(app_manager.RyuApp):
53 def _instance_name(interface, vrid, is_ipv6):
54 ip_version = 'ipv6' if is_ipv6 else 'ipv4'
55 return 'VRRP-Router-%s-%d-%s' % (str(interface), vrid, ip_version)
57 def __init__(self, *args, **kwargs):
58 super(VRRPManager, self).__init__(*args, **kwargs)
61 self.name = vrrp_event.VRRP_MANAGER_NAME
62 self._instances = {} # name -> VRRPInstance
63 self.shutdown = hub.Queue()
66 t = hub.spawn(self._shutdown_loop)
67 super(VRRPManager, self).start()
70 @handler.set_ev_cls(vrrp_event.EventVRRPConfigRequest)
71 def config_request_handler(self, ev):
73 interface = ev.interface
74 name = self._instance_name(interface, config.vrid, config.is_ipv6)
75 if name in self._instances:
76 rep = vrrp_event.EventVRRPConfigReply(None, interface, config)
77 self.reply_to_request(ev, rep)
80 statistics = VRRPStatistics(name, config.resource_id,
81 config.statistics_interval)
82 monitor = vrrp_monitor.VRRPInterfaceMonitor.factory(
83 interface, config, name, statistics, *self._args, **self._kwargs)
84 router = vrrp_router.VRRPRouter.factory(name, monitor.name, interface,
86 *self._args, **self._kwargs)
88 # vrrp_router -> vrrp_manager
89 # EventVRRPStateChanged to vrrp_manager is handled by framework
90 # vrrp_manager -> vrrp_rouer
91 self.register_observer(vrrp_event.EventVRRPShutdownRequest,
93 # vrrp_router -> vrrp_monitor
94 router.register_observer(vrrp_event.EventVRRPStateChanged,
96 router.register_observer(vrrp_event.EventVRRPTransmitRequest,
98 # vrrp_interface_monitor -> vrrp_router
99 monitor.register_observer(vrrp_event.EventVRRPReceived, router.name)
101 instance = VRRPInstance(name, monitor.name, config, interface)
102 self._instances[name] = instance
103 # self.logger.debug('report_bricks')
104 # app_manager.AppManager.get_instance().report_bricks() # debug
108 rep = vrrp_event.EventVRRPConfigReply(instance.name, interface, config)
109 self.reply_to_request(ev, rep)
111 def _proxy_event(self, ev):
112 name = ev.instance_name
113 instance = self._instances.get(name, None)
115 self.logger.info('unknown vrrp router %s', name)
117 self.send_event(instance.name, ev)
119 @handler.set_ev_cls(vrrp_event.EventVRRPShutdownRequest)
120 def shutdown_request_handler(self, ev):
121 self._proxy_event(ev)
123 @handler.set_ev_cls(vrrp_event.EventVRRPConfigChangeRequest)
124 def config_change_request_handler(self, ev):
125 self._proxy_event(ev)
127 @handler.set_ev_cls(vrrp_event.EventVRRPStateChanged)
128 def state_change_handler(self, ev):
129 instance = self._instances.get(ev.instance_name, None)
130 assert instance is not None
131 instance.state_changed(ev.new_state)
132 if ev.old_state and ev.new_state == vrrp_event.VRRP_STATE_INITIALIZE:
133 self.shutdown.put(instance)
135 def _shutdown_loop(self):
136 app_mgr = app_manager.AppManager.get_instance()
137 while self.is_active or not self.shutdown.empty():
138 instance = self.shutdown.get()
139 app_mgr.uninstantiate(instance.name)
140 app_mgr.uninstantiate(instance.monitor_name)
141 del self._instances[instance.name]
143 @handler.set_ev_cls(vrrp_event.EventVRRPListRequest)
144 def list_request_handler(self, ev):
145 instance_name = ev.instance_name
146 if instance_name is None:
147 instance_list = [vrrp_event.VRRPInstance(
148 instance.name, instance.monitor_name,
149 instance.config, instance.interface, instance.state)
150 for instance in self._instances.values()]
152 instance = self._instances.get(instance_name, None)
156 instance_list = [vrrp_event.VRRPInstance(
157 instance_name, instance.monitor_name,
158 instance.config, instance.interface, instance.state)]
160 vrrp_list = vrrp_event.EventVRRPListReply(instance_list)
161 self.reply_to_request(ev, vrrp_list)
164 class VRRPStatistics(object):
165 def __init__(self, name, resource_id, statistics_interval):
167 self.resource_id = resource_id
168 self.statistics_interval = statistics_interval
169 self.tx_vrrp_packets = 0
170 self.rx_vrrp_packets = 0
171 self.rx_vrrp_zero_prio_packets = 0
172 self.tx_vrrp_zero_prio_packets = 0
173 self.rx_vrrp_invalid_packets = 0
174 self.rx_vrrp_bad_auth = 0
175 self.idle_to_master_transitions = 0
176 self.idle_to_backup_transitions = 0
177 self.backup_to_master_transitions = 0
178 self.master_to_backup_transitions = 0
181 ts = time.strftime("%Y-%m-%dT%H:%M:%S")
184 resource_id=self.resource_id,
185 tx_vrrp_packets=self.tx_vrrp_packets,
186 rx_vrrp_packets=self.rx_vrrp_packets,
187 rx_vrrp_zero_prio_packets=self.rx_vrrp_zero_prio_packets,
188 tx_vrrp_zero_prio_packets=self.tx_vrrp_zero_prio_packets,
189 rx_vrrp_invalid_packets=self.rx_vrrp_invalid_packets,
190 rx_vrrp_bad_auth=self.rx_vrrp_bad_auth,
191 idle_to_master_transitions=self.idle_to_master_transitions,
192 idle_to_backup_transitions=self.idle_to_backup_transitions,
193 backup_to_master_transitions=self.backup_to_master_transitions,
194 master_to_backup_transitions=self.master_to_backup_transitions