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 Watching packet received on this interface and parse VRRP packet.
20 VRRPManager creates/deletes instances of interface monitor dynamically.
23 from ryu.base import app_manager
24 from ryu.controller import handler
25 from ryu.lib.packet import packet
26 from ryu.lib.packet import vlan
27 from ryu.lib.packet import vrrp
28 from ryu.services.protocols.vrrp import event as vrrp_event
31 class VRRPInterfaceMonitor(app_manager.RyuApp):
32 # subclass of VRRPInterfaceBase -> subclass of VRRPInterfaceMonitor
36 def register(interface_cls):
38 VRRPInterfaceMonitor._CONSTRUCTORS[interface_cls] = cls
43 def factory(interface, config, router_name, statistics, *args, **kwargs):
44 cls = VRRPInterfaceMonitor._CONSTRUCTORS[interface.__class__]
45 app_mgr = app_manager.AppManager.get_instance()
47 kwargs = kwargs.copy()
48 kwargs['router_name'] = router_name
49 kwargs['vrrp_config'] = config
50 kwargs['vrrp_interface'] = interface
51 kwargs['vrrp_statistics'] = statistics
52 app = app_mgr.instantiate(cls, *args, **kwargs)
56 def instance_name(cls, interface, vrid):
57 return '%s-%s-%d' % (cls.__name__, str(interface), vrid)
59 def __init__(self, *args, **kwargs):
60 super(VRRPInterfaceMonitor, self).__init__(*args, **kwargs)
61 self.config = kwargs['vrrp_config']
62 self.interface = kwargs['vrrp_interface']
63 self.router_name = kwargs['router_name']
64 self.statistics = kwargs['vrrp_statistics']
65 self.name = self.instance_name(self.interface, self.config.vrid)
67 def _parse_received_packet(self, packet_data):
68 # OF doesn't support VRRP packet matching, so we have to parse
70 packet_ = packet.Packet(packet_data)
71 protocols = packet_.protocols
74 # [ether, vlan, ip, vrrp{, padding}]
76 # [ether, ip, vrrp{, padding}]
78 if len(protocols) < 2:
79 self.logger.debug('len(protocols) %d', len(protocols))
82 vlan_vid = self.interface.vlan_id
83 may_vlan = protocols[1]
84 if (vlan_vid is not None) != isinstance(may_vlan, vlan.vlan):
85 self.logger.debug('vlan_vid: %s %s', vlan_vid, type(may_vlan))
87 if vlan_vid is not None and vlan_vid != may_vlan.vid:
88 self.logger.debug('vlan_vid: %s vlan %s', vlan_vid, type(may_vlan))
91 # self.logger.debug('%s %s', packet_, packet_.protocols)
92 may_ip, may_vrrp = vrrp.vrrp.get_payload(packet_)
93 if not may_ip or not may_vrrp:
94 # self.logger.debug('may_ip %s may_vrrp %s', may_ip, may_vrrp)
96 if not vrrp.vrrp.is_valid_ttl(may_ip):
97 self.logger.debug('valid_ttl')
99 if may_vrrp.version != self.config.version:
100 self.logger.debug('vrrp version %d %d',
101 may_vrrp.version, self.config.version)
103 if not may_vrrp.is_valid():
104 self.logger.debug('valid vrrp')
107 for proto in packet_.protocols:
108 if proto == may_vrrp:
111 if not may_vrrp.checksum_ok(
112 may_ip, packet_.data[offset:offset + len(may_vrrp)]):
113 self.logger.debug('bad checksum')
115 if may_vrrp.vrid != self.config.vrid:
116 self.logger.debug('vrid %d %d', may_vrrp.vrid, self.config.vrid)
118 if may_vrrp.is_ipv6 != self.config.is_ipv6:
119 self.logger.debug('is_ipv6 %s %s',
120 may_vrrp.is_ipv6, self.config.is_ipv6)
123 # TODO: Optional check rfc5798 7.1
124 # may_vrrp.ip_addresses equals to self.config.ip_addresses
125 if may_vrrp.priority == 0:
126 self.statistics.rx_vrrp_zero_prio_packets += 1
128 vrrp_received = vrrp_event.EventVRRPReceived(self.interface, packet_)
129 self.send_event(self.router_name, vrrp_received)
132 def _send_vrrp_packet_received(self, packet_data):
133 valid = self._parse_received_packet(packet_data)
135 self.statistics.rx_vrrp_packets += 1
137 self.statistics.rx_vrrp_invalid_packets += 1
139 @handler.set_ev_handler(vrrp_event.EventVRRPTransmitRequest)
140 def vrrp_transmit_request_handler(self, ev):
141 raise NotImplementedError()
143 def _initialize(self):
144 raise NotImplementedError()
147 raise NotImplementedError()
149 @handler.set_ev_handler(vrrp_event.EventVRRPStateChanged)
150 def vrrp_state_changed_handler(self, ev):
151 assert ev.interface == self.interface
153 if ev.new_state == vrrp_event.VRRP_STATE_INITIALIZE:
154 # add/del packet in rule
159 elif ev.new_state in [vrrp_event.VRRP_STATE_BACKUP,
160 vrrp_event.VRRP_STATE_MASTER]:
162 if ev.old_state == vrrp_event.VRRP_STATE_INITIALIZE:
163 if ev.new_state == vrrp_event.VRRP_STATE_MASTER:
164 self.statistics.idle_to_master_transitions += 1
166 self.statistics.idle_to_backup_transitions += 1
167 elif ev.old_state == vrrp_event.VRRP_STATE_MASTER:
168 self.statistics.master_to_backup_transitions += 1
170 self.statistics.backup_to_master_transitions += 1
172 raise RuntimeError('unknown vrrp state %s' % ev.new_state)