backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / services / protocols / vrrp / router.py
diff --git a/ryu/build/lib.linux-armv7l-2.7/ryu/services/protocols/vrrp/router.py b/ryu/build/lib.linux-armv7l-2.7/ryu/services/protocols/vrrp/router.py
new file mode 100644 (file)
index 0000000..8278831
--- /dev/null
@@ -0,0 +1,713 @@
+# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2013 Isaku Yamahata <yamahata at private email ne jp>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+VRRP state machine implementation
+
+VRRPManager creates/deletes VRRPRounter instances dynamically.
+"""
+
+import abc
+import six
+
+from ryu.base import app_manager
+from ryu.controller import event
+from ryu.controller import handler
+from ryu.lib import hub
+from ryu.lib.packet import vrrp
+from ryu.services.protocols.vrrp import event as vrrp_event
+from ryu.services.protocols.vrrp import api as vrrp_api
+
+
+# TODO: improve Timer service and move it into framework
+class Timer(object):
+    def __init__(self, handler_):
+        assert callable(handler_)
+
+        super(Timer, self).__init__()
+        self._handler = handler_
+        self._event = hub.Event()
+        self._thread = None
+
+    def start(self, interval):
+        """interval is in seconds"""
+        if self._thread:
+            self.cancel()
+        self._event.clear()
+        self._thread = hub.spawn(self._timer, interval)
+
+    def cancel(self):
+        if self._thread is None:
+            return
+        self._event.set()
+        hub.joinall([self._thread])
+        self._thread = None
+
+    def is_running(self):
+        return self._thread is not None
+
+    def _timer(self, interval):
+        # Avoid cancellation during execution of self._callable()
+        cancel = self._event.wait(interval)
+        if cancel:
+            return
+
+        self._handler()
+
+
+class TimerEventSender(Timer):
+    # timeout handler is called by timer thread context.
+    # So in order to actual execution context to application's event thread,
+    # post the event to the application
+    def __init__(self, app, ev_cls):
+        super(TimerEventSender, self).__init__(self._timeout)
+        self._app = app
+        self._ev_cls = ev_cls
+
+    def _timeout(self):
+        self._app.send_event(self._app.name, self._ev_cls())
+
+
+class VRRPParams(object):
+    def __init__(self, config):
+        self.config = config
+        self.master_adver_interval = None       # In seconds
+
+    @property
+    def skew_time(self):
+        # In seconds
+        config = self.config
+        version = config.version
+        priority = config.priority
+        if config.version == vrrp.VRRP_VERSION_V2:
+            return (256.0 - priority) / 256.0
+        if config.version == vrrp.VRRP_VERSION_V3:
+            return (((256.0 - priority) * self.master_adver_interval) / 256.0)
+        raise ValueError('unknown vrrp version %d' % version)
+
+    @property
+    def master_down_interval(self):
+        # In seconds
+        return (3.0 * self.master_adver_interval) + self.skew_time
+
+
+@six.add_metaclass(abc.ABCMeta)
+class VRRPState(object):
+    def __init__(self, vrrp_router):
+        super(VRRPState, self).__init__()
+        self.vrrp_router = vrrp_router
+
+    @abc.abstractmethod
+    def master_down(self, ev):
+        pass
+
+    @abc.abstractmethod
+    def adver(self, ev):
+        pass
+
+    @abc.abstractmethod
+    def preempt_delay(self, ev):
+        pass
+
+    @abc.abstractmethod
+    def vrrp_received(self, ev):
+        pass
+
+    @abc.abstractmethod
+    def vrrp_shutdown_request(self, ev):
+        pass
+
+    @abc.abstractmethod
+    def vrrp_config_change_request(self, ev):
+        pass
+
+
+class VRRPRouter(app_manager.RyuApp):
+    _EVENTS = [vrrp_event.EventVRRPStateChanged]
+    _CONSTRUCTORS = {}
+    _STATE_MAP = {}     # should be overrided by concrete class
+
+    @staticmethod
+    def register(version):
+        def _register(cls):
+            VRRPRouter._CONSTRUCTORS[version] = cls
+            return cls
+        return _register
+
+    @staticmethod
+    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()
+        kwargs['name'] = name
+        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):
+        pass
+
+    class _EventAdver(event.EventBase):
+        pass
+
+    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
+        self.vrrp = None
+
+        self.master_down_timer = TimerEventSender(self, self._EventMasterDown)
+        self.adver_timer = TimerEventSender(self, self._EventAdver)
+        self.preempt_delay_timer = TimerEventSender(self,
+                                                    self._EventPreemptDelay)
+        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
+            max_adver_int = vrrp.vrrp.sec_to_max_adver_int(
+                config.version, config.advertisement_interval)
+            self.vrrp = vrrp.vrrp.create_version(
+                config.version, vrrp.VRRP_TYPE_ADVERTISEMENT, config.vrid,
+                config.priority, max_adver_int, config.ip_addresses)
+
+        vrrp_ = self.vrrp
+        if release:
+            vrrp_ = vrrp_.create(vrrp_.type, vrrp_.vrid,
+                                 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
+        self.state = new_state
+        self.state_impl = self._STATE_MAP[new_state](self)
+        state_changed = vrrp_event.EventVRRPStateChanged(
+            self.name, self.monitor_name, self.interface, self.config,
+            old_state, new_state)
+        self.send_event_to_observers(state_changed)
+
+    @handler.set_ev_handler(_EventMasterDown)
+    def master_down_handler(self, ev):
+        self.state_impl.master_down(ev)
+
+    @handler.set_ev_handler(_EventAdver)
+    def adver_handler(self, ev):
+        self.state_impl.adver(ev)
+
+    @handler.set_ev_handler(_EventPreemptDelay)
+    def preempt_delay_handler(self, ev):
+        self.state_impl.preempt_delay(ev)
+
+    @handler.set_ev_handler(vrrp_event.EventVRRPReceived)
+    def vrrp_received_handler(self, ev):
+        self.state_impl.vrrp_received(ev)
+
+    @handler.set_ev_handler(vrrp_event.EventVRRPShutdownRequest)
+    def vrrp_shutdown_request_handler(self, ev):
+        assert ev.instance_name == self.name
+        self.state_impl.vrrp_shutdown_request(ev)
+
+    @handler.set_ev_handler(vrrp_event.EventVRRPConfigChangeRequest)
+    def vrrp_config_change_request_handler(self, ev):
+        config = self.config
+        if ev.priority is not None:
+            config.priority = ev.priority
+        if ev.advertisement_interval is not None:
+            config.advertisement_interval = ev.advertisement_interval
+        if ev.preempt_mode is not None:
+            config.preempt_mode = ev.preempt_mode
+        if ev.preempt_delay is not None:
+            config.preempt_delay = ev.preempt_delay
+        if ev.accept_mode is not None:
+            config.accept_mode = ev.accept_mode
+
+        # force to recreate cached vrrp packet
+        self.vrrp = None
+
+        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.
+# So our implementation does, state change, then start timer
+
+
+class VRRPV2StateInitialize(VRRPState):
+    # In theory this shouldn't be called.
+    def master_down(self, ev):
+        self.vrrp_router.logger.warning('%s master_down',
+                                        self.__class__.__name__)
+
+    def adver(self, ev):
+        self.vrrp_router.logger.warning('%s adver', self.__class__.__name__)
+
+    def preempt_delay(self, ev):
+        self.vrrp_router.logger.warning('%s preempt_delay',
+                                        self.__class__.__name__)
+
+    def vrrp_received(self, ev):
+        self.vrrp_router.logger.warning('%s vrrp_received',
+                                        self.__class__.__name__)
+
+    def vrrp_shutdown_request(self, ev):
+        self.vrrp_router.logger.warning('%s vrrp_shutdown_request',
+                                        self.__class__.__name__)
+
+    def vrrp_config_change_request(self, ev):
+        self.vrrp_router.logger.warning('%s vrrp_config_change_request',
+                                        self.__class__.__name__)
+
+
+class VRRPV2StateMaster(VRRPState):
+    def master_down(self, ev):
+        # should not reach here.
+        # In fact this can be happned due to event scheduling
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s master_down %s %s',
+                                 self.__class__.__name__,
+                                 ev.__class__.__name__, vrrp_router.state)
+
+    def _adver(self):
+        vrrp_router = self.vrrp_router
+        vrrp_router.send_advertisement()
+        vrrp_router.adver_timer.start(
+            vrrp_router.config.advertisement_interval)
+
+    def adver(self, ev):
+        self.vrrp_router.logger.debug('%s adver', self.__class__.__name__)
+        self._adver()
+
+    def preempt_delay(self, ev):
+        self.vrrp_router.logger.warning('%s preempt_delay',
+                                        self.__class__.__name__)
+
+    def vrrp_received(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_received', self.__class__.__name__)
+
+        ip, vrrp_ = vrrp.vrrp.get_payload(ev.packet)
+        config = vrrp_router.config
+        if vrrp_.priority == 0:
+            vrrp_router.send_advertisement()
+            vrrp_router.adver_timer.start(config.advertisement_interval)
+        else:
+            params = vrrp_router.params
+            if (config.priority < vrrp_.priority or
+                (config.priority == vrrp_.priority and
+                 vrrp.ip_address_lt(vrrp_router.interface.primary_ip_address,
+                                    ip.src))):
+                vrrp_router.adver_timer.cancel()
+
+                vrrp_router.state_change(vrrp_event.VRRP_STATE_BACKUP)
+                vrrp_router.master_down_timer.start(
+                    params.master_down_interval)
+
+    def vrrp_shutdown_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_shutdown_request',
+                                 self.__class__.__name__)
+
+        vrrp_router.adver_timer.cancel()
+        vrrp_router.send_advertisement(True)
+        vrrp_router.state_change(vrrp_event.VRRP_STATE_INITIALIZE)
+
+    def vrrp_config_change_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.warning('%s vrrp_config_change_request',
+                                   self.__class__.__name__)
+        if ev.priority is not None or ev.advertisement_interval is not None:
+            vrrp_router.adver_timer.cancel()
+            self._adver()
+
+
+class VRRPV2StateBackup(VRRPState):
+    def _master_down(self):
+        vrrp_router = self.vrrp_router
+        vrrp_router.send_advertisement()
+
+        # This action should be done router on
+        # EventVRRPStateChanged(VRRP_STATE_BACKUP->VRRP_STATE_MASTER)
+        #
+        # RFC3768 6.4.2 Backup
+        # o  Broadcast a gratuitous ARP request containing the virtual
+        #    router MAC address for each IP address associated with the
+        #    virtual router
+
+        # RACE: actual router has the responsiblity to send garp.
+        #       so due to thread scheduling there is a race between
+        #       actual router sending GARP and VRRPRouter becoming
+        #       master/backup
+
+        vrrp_router.preempt_delay_timer.cancel()
+        vrrp_router.state_change(vrrp_event.VRRP_STATE_MASTER)
+        vrrp_router.adver_timer.start(
+            vrrp_router.config.advertisement_interval)
+
+    def master_down(self, ev):
+        self.vrrp_router.logger.debug('%s master_down',
+                                      self.__class__.__name__)
+        self._master_down()
+
+    def adver(self, ev):
+        # should not reach here
+        # In fact this can be happned due to event scheduling
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s adver %s %s',
+                                 self.__class__.__name__,
+                                 ev.__class__.__name__, vrrp_router.state)
+
+    def preempt_delay(self, ev):
+        self.vrrp_router.logger.warning('%s preempt_delay',
+                                        self.__class__.__name__)
+        self._master_down()
+
+    def vrrp_received(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_received', self.__class__.__name__)
+
+        _ip, vrrp_ = vrrp.vrrp.get_payload(ev.packet)
+        if vrrp_.priority == 0:
+            vrrp_router.master_down_timer.start(vrrp_router.params.skew_time)
+        else:
+            config = vrrp_router.config
+            params = vrrp_router.params
+            if (not config.preempt_mode or config.priority <= vrrp_.priority):
+                vrrp_router.preempt_delay_timer.cancel()
+                vrrp_router.master_down_timer.start(
+                    params.master_down_interval)
+            elif (config.preempt_mode and config.preempt_delay > 0 and
+                  config.priority > vrrp_.priority):
+                if not vrrp_router.preempt_delay_timer.is_running():
+                    vrrp_router.preempt_delay_timer.start(config.preempt_delay)
+                vrrp_router.master_down_timer.start(
+                    params.master_down_interval)
+
+    def vrrp_shutdown_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_shutdown_request',
+                                 self.__class__.__name__)
+
+        vrrp_router.master_down_timer.cancel()
+        vrrp_router.preempt_delay_timer.cancel()
+        vrrp_router.state_change(vrrp_event.VRRP_STATE_INITIALIZE)
+
+    def vrrp_config_change_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.warning('%s vrrp_config_change_request',
+                                   self.__class__.__name__)
+        if ev.priority is not None and vrrp_router.config.address_owner:
+            vrrp_router.master_down_timer.cancel()
+            self._master_down()
+        if ev.preempt_mode is not None or ev.preempt_delay is not None:
+            vrrp_router.preempt_delay_timer.cancel()
+
+
+@VRRPRouter.register(vrrp.VRRP_VERSION_V2)
+class VRRPRouterV2(VRRPRouter):
+    _STATE_MAP = {
+        vrrp_event.VRRP_STATE_INITIALIZE: VRRPV2StateInitialize,
+        vrrp_event.VRRP_STATE_MASTER: VRRPV2StateMaster,
+        vrrp_event.VRRP_STATE_BACKUP: VRRPV2StateBackup,
+    }
+
+    def __init__(self, *args, **kwargs):
+        super(VRRPRouterV2, self).__init__(*args, **kwargs)
+
+    def start(self):
+        params = self.params
+        params.master_adver_interval = self.config.advertisement_interval
+        self.state_change(vrrp_event.VRRP_STATE_INITIALIZE)
+        if self.config.address_owner:
+            self.send_advertisement()
+
+            # This action should be done router on
+            # EventVRRPStateChanged(None->VRRP_STATE_MASTER)
+            #
+            # RFC3768 6.4.1
+            # o  Broadcast a gratuitous ARP request containing the virtual
+            # router MAC address for each IP address associated with the
+            # virtual router.
+
+            self.state_change(vrrp_event.VRRP_STATE_MASTER)
+            self.adver_timer.start(self.config.advertisement_interval)
+        else:
+            self.state_change(vrrp_event.VRRP_STATE_BACKUP)
+            self.master_down_timer.start(params.master_down_interval)
+
+        super(VRRPRouterV2, self).start()
+
+
+class VRRPV3StateInitialize(VRRPState):
+    # In theory this shouldn't be called.
+    def master_down(self, ev):
+        self.vrrp_router.logger.debug('%s master_down',
+                                      self.__class__.__name__)
+
+    def adver(self, ev):
+        self.vrrp_router.logger.debug('%s adver', self.__class__.__name__)
+
+    def preempt_delay(self, ev):
+        self.vrrp_router.logger.warning('%s preempt_delay',
+                                        self.__class__.__name__)
+
+    def vrrp_received(self, ev):
+        self.vrrp_router.logger.debug('%s vrrp_received',
+                                      self.__class__.__name__)
+
+    def vrrp_shutdown_request(self, ev):
+        self.vrrp_router.logger.debug('%s vrrp_shutdown_request',
+                                      self.__class__.__name__)
+
+    def vrrp_config_change_request(self, ev):
+        self.vrrp_router.logger.warning('%s vrrp_config_change_request',
+                                        self.__class__.__name__)
+
+
+class VRRPV3StateMaster(VRRPState):
+    def master_down(self, ev):
+        # should not reach here
+        # In fact this can be happned due to event scheduling
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s master_down %s %s',
+                                 self.__class__.__name__,
+                                 ev.__class__.__name__, vrrp_router.state)
+
+    def _adver(self):
+        vrrp_router = self.vrrp_router
+        vrrp_router.send_advertisement()
+        vrrp_router.adver_timer.start(
+            vrrp_router.config.advertisement_interval)
+
+    def adver(self, ev):
+        self.vrrp_router.logger.debug('%s adver', self.__class__.__name__)
+        self._adver()
+
+    def preempt_delay(self, ev):
+        self.vrrp_router.logger.warning('%s preempt_delay',
+                                        self.__class__.__name__)
+
+    def vrrp_received(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_received', self.__class__.__name__)
+
+        ip, vrrp_ = vrrp.vrrp.get_payload(ev.packet)
+        config = vrrp_router.config
+        if vrrp_.priority == 0:
+            vrrp_router.send_advertisement()
+            vrrp_router.adver_timer.start(config.advertisement_interval)
+        else:
+            params = vrrp_router.params
+            if (config.priority < vrrp_.priority or
+                (config.priority == vrrp_.priority and
+                 vrrp.ip_address_lt(vrrp_router.interface.primary_ip_address,
+                                    ip.src))):
+                vrrp_router.adver_timer.cancel()
+                params.master_adver_interval = vrrp_.max_adver_int_in_sec
+
+                vrrp_router.state_change(vrrp_event.VRRP_STATE_BACKUP)
+                vrrp_router.master_down_timer.start(
+                    params.master_down_interval)
+
+    def vrrp_shutdown_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_shutdown_request',
+                                 self.__class__.__name__)
+
+        vrrp_router.adver_timer.cancel()
+        vrrp_router.send_advertisement(True)
+        vrrp_router.state_change(vrrp_event.VRRP_STATE_INITIALIZE)
+
+    def vrrp_config_change_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.warning('%s vrrp_config_change_request',
+                                   self.__class__.__name__)
+        if ev.priority is not None or ev.advertisement_interval is not None:
+            vrrp_router.adver_timer.cancel()
+            self._adver()
+
+
+class VRRPV3StateBackup(VRRPState):
+    def _master_down(self):
+        vrrp_router = self.vrrp_router
+        vrrp_router.send_advertisement()
+
+        # This action should be done by router on
+        # EventStateChange(VRRP_SATE_BACKUP -> VRRP_STATE_MASTER)
+        #
+        # RFC 5795 6.4.2
+        # (375) + If the protected IPvX address is an IPv4 address, then:
+        #   (380) * Broadcast a gratuitous ARP request on that interface
+        #   containing the virtual router MAC address for each IPv4
+        #   address associated with the virtual router.
+        # (385) + else // ipv6
+        #   (390) * Compute and join the Solicited-Node multicast
+        #   address [RFC4291] for the IPv6 address(es) associated with
+        #   the virtual router.
+        #   (395) * For each IPv6 address associated with the virtual
+        #   router, send an unsolicited ND Neighbor Advertisement with
+        #   the Router Flag (R) set, the Solicited Flag (S) unset, the
+        #   Override flag (O) set, the target address set to the IPv6
+        #   address of the virtual router, and the target link-layer
+        #   address set to the virtual router MAC address.
+
+        # RACE: actual router has the responsiblity to send garp.
+        #       so due to thread scheduling there is a race between
+        #       actual router sending GARP and VRRPRouter becoming
+        #       master/backup
+
+        vrrp_router.preempt_delay_timer.cancel()
+        vrrp_router.state_change(vrrp_event.VRRP_STATE_MASTER)
+        vrrp_router.adver_timer.start(
+            vrrp_router.config.advertisement_interval)
+
+    def master_down(self, ev):
+        self.vrrp_router.logger.debug('%s master_down',
+                                      self.__class__.__name__)
+        self._master_down()
+
+    def adver(self, ev):
+        # should not reach here
+        # In fact this can be happned due to event scheduling
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('adver %s %s %s',
+                                 self.__class__.__name__,
+                                 ev.__class__.__name__, vrrp_router.state)
+
+    def preempt_delay(self, ev):
+        self.vrrp_router.logger.warning('%s preempt_delay',
+                                        self.__class__.__name__)
+        self._master_down()
+
+    def vrrp_received(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_received', self.__class__.__name__)
+
+        _ip, vrrp_ = vrrp.vrrp.get_payload(ev.packet)
+        if vrrp_.priority == 0:
+            vrrp_router.master_down_timer.start(vrrp_router.params.skew_time)
+        else:
+            params = vrrp_router.params
+            config = vrrp_router.config
+            if (not config.preempt_mode or config.priority <= vrrp_.priority):
+                params.master_adver_interval = vrrp_.max_adver_int_in_sec
+                vrrp_router.master_down_timer.start(
+                    params.master_down_interval)
+            elif (config.preempt_mode and config.preempt_delay > 0 and
+                  config.priority > vrrp_.priority):
+                if not vrrp_router.preempt_delay_timer.is_running():
+                    vrrp_router.preempt_delay_timer.start(config.preempt_delay)
+                vrrp_router.master_down_timer.start(
+                    params.master_down_interval)
+
+    def vrrp_shutdown_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.debug('%s vrrp_shutdown_request',
+                                 self.__class__.__name__)
+
+        vrrp_router.preempt_delay_timer.cancel()
+        vrrp_router.master_down_timer.cancel()
+        vrrp_router.state_change(vrrp_event.VRRP_STATE_INITIALIZE)
+
+    def vrrp_config_change_request(self, ev):
+        vrrp_router = self.vrrp_router
+        vrrp_router.logger.warning('%s vrrp_config_change_request',
+                                   self.__class__.__name__)
+        if ev.priority is not None and vrrp_router.config.address_owner:
+            vrrp_router.master_down_timer.cancel()
+            self._master_down()
+        if ev.preempt_mode is not None or ev.preempt_delay is not None:
+            vrrp_router.preempt_delay_timer.cancel()
+
+
+@VRRPRouter.register(vrrp.VRRP_VERSION_V3)
+class VRRPRouterV3(VRRPRouter):
+    _STATE_MAP = {
+        vrrp_event.VRRP_STATE_INITIALIZE: VRRPV3StateInitialize,
+        vrrp_event.VRRP_STATE_MASTER: VRRPV3StateMaster,
+        vrrp_event.VRRP_STATE_BACKUP: VRRPV3StateBackup,
+    }
+
+    def __init__(self, *args, **kwargs):
+        super(VRRPRouterV3, self).__init__(*args, **kwargs)
+
+    def start(self):
+        self.state_change(vrrp_event.VRRP_STATE_INITIALIZE)
+        # Check role here and change accordingly
+        # Check config.admin_state
+        if self.config.address_owner or self.config.admin_state == 'master':
+            self.send_advertisement()
+
+            # This action should be done router on
+            # EventVRRPStateChanged(None->VRRP_STATE_MASTER)
+            #
+            # RFC 5795 6.4.1
+            # (115) + If the protected IPvX address is an IPv4 address, then:
+            #   (120) * Broadcast a gratuitous ARP request containing the
+            #   virtual router MAC address for each IP address associated
+            #   with the virtual router.
+            # (125) + else // IPv6
+            #   (130) * For each IPv6 address associated with the virtual
+            #   router, send an unsolicited ND Neighbor Advertisement with
+            #   the Router Flag (R) set, the Solicited Flag (S) unset, the
+            #   Override flag (O) set, the target address set to the IPv6
+            #   address of the virtual router, and the target link-layer
+            #   address set to the virtual router MAC address.
+
+            self.state_change(vrrp_event.VRRP_STATE_MASTER)
+            self.adver_timer.start(self.config.advertisement_interval)
+        else:
+            params = self.params
+            params.master_adver_interval = self.config.advertisement_interval
+            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()