dragonflow/dragonflow/controller/apps/aging.py

100 lines
3.6 KiB
Python

# Copyright (c) 2015 OpenStack Foundation.
# All Rights Reserved.
#
# 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.
import eventlet
from oslo_log import log
from dragonflow.controller.common import constants as const
from dragonflow.controller.common import cookies
from dragonflow.controller import df_base_app
LOG = log.getLogger(__name__)
AGING_COOKIE_NAME = 'aging'
class AgingApp(df_base_app.DFlowApp):
def __init__(self, *args, **kwargs):
super(AgingApp, self).__init__(*args, **kwargs)
self.do_aging = True
self._aging_cookie = 0
cookies.add_global_cookie_modifier(AGING_COOKIE_NAME, 1,
lambda x: self._aging_cookie)
"""
check_aging_needed()
-> get_canary_flow()
-> canary flow exist, get canary cookie
-> no canary flow, i.e., first boot or ovs restart, no need to do
aging
-> renew_aging_cookie()
-> add canary flows with new cookie
after all apps flushed flows with new cookie, switch_sync_finished() will
be called
"""
def switch_sync_started(self):
LOG.info("start aging")
canary_flow = self._get_canary_flow()
if not canary_flow:
self.do_aging = False
self._aging_cookie = 1
LOG.info("no canary table, don't do aging")
else:
self.do_aging = True
canary_cookie = canary_flow.cookie
old_cookie = cookies.extract_value_from_cookie(AGING_COOKIE_NAME,
canary_cookie)
self._aging_cookie = self._invert_cookie(old_cookie)
LOG.info("renew cookie, old: %(old)x new: %(new)x",
{'old': canary_cookie, 'new': self._aging_cookie})
# NOTE(oanson) cookie will be set automatically with _aging_cookie
self.mod_flow(table_id=const.CANARY_TABLE)
"""
now all apps had flushed flows with new cookie
delete flows with old cookie
"""
def switch_sync_finished(self):
if self.do_aging:
# Give apps a few more seconds to finish their magic
eventlet.spawn_after(5, self._start_aging)
LOG.info("Scheduled aged flows deletion")
def _invert_cookie(self, cookie):
return 1 ^ cookie
def _start_aging(self):
inverted_cookie = self._invert_cookie(self._aging_cookie)
old_cookie, old_mask = cookies.get_cookie(AGING_COOKIE_NAME,
inverted_cookie)
self._cleanup_flows(old_cookie, old_mask)
LOG.info("Scheduled aged flows deletion completed!")
def _cleanup_flows(self, cookie, cookie_mask):
self.mod_flow(cookie=cookie,
cookie_mask=cookie_mask,
table_id=self.ofproto.OFPTT_ALL,
match=self.parser.OFPMatch(),
command=self.ofproto.OFPFC_DELETE,
priority=0)
def _get_canary_flow(self):
canary_flow = self.get_flows(table_id=const.CANARY_TABLE)
if not canary_flow:
return None
return canary_flow[0]