105 lines
3.8 KiB
Python
105 lines
3.8 KiB
Python
# Copyright (c) 2014 Openstack Foundation
|
|
#
|
|
# 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.
|
|
|
|
from neutron.agent.linux import ip_lib
|
|
from neutron.agent.linux import iptables_manager
|
|
from neutron.common import utils as common_utils
|
|
from neutron.openstack.common import log as logging
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class RouterInfo(object):
|
|
|
|
def __init__(self,
|
|
router_id,
|
|
router,
|
|
agent_conf,
|
|
interface_driver,
|
|
use_ipv6=False,
|
|
ns_name=None):
|
|
self.router_id = router_id
|
|
self.ex_gw_port = None
|
|
self._snat_enabled = None
|
|
self._snat_action = None
|
|
self.internal_ports = []
|
|
self.floating_ips = set()
|
|
# Invoke the setter for establishing initial SNAT action
|
|
self.router = router
|
|
self.ns_name = ns_name
|
|
self.iptables_manager = iptables_manager.IptablesManager(
|
|
use_ipv6=use_ipv6,
|
|
namespace=self.ns_name)
|
|
self.routes = []
|
|
self.agent_conf = agent_conf
|
|
self.driver = interface_driver
|
|
# radvd is a neutron.agent.linux.ra.DaemonMonitor
|
|
self.radvd = None
|
|
|
|
@property
|
|
def router(self):
|
|
return self._router
|
|
|
|
@router.setter
|
|
def router(self, value):
|
|
self._router = value
|
|
if not self._router:
|
|
return
|
|
# enable_snat by default if it wasn't specified by plugin
|
|
self._snat_enabled = self._router.get('enable_snat', True)
|
|
# Set a SNAT action for the router
|
|
if self._router.get('gw_port'):
|
|
self._snat_action = ('add_rules' if self._snat_enabled
|
|
else 'remove_rules')
|
|
elif self.ex_gw_port:
|
|
# Gateway port was removed, remove rules
|
|
self._snat_action = 'remove_rules'
|
|
|
|
@property
|
|
def is_ha(self):
|
|
# TODO(Carl) Refactoring should render this obsolete. Remove it.
|
|
return False
|
|
|
|
def perform_snat_action(self, snat_callback, *args):
|
|
# Process SNAT rules for attached subnets
|
|
if self._snat_action:
|
|
snat_callback(self, self._router.get('gw_port'),
|
|
*args, action=self._snat_action)
|
|
self._snat_action = None
|
|
|
|
def _update_routing_table(self, operation, route):
|
|
cmd = ['ip', 'route', operation, 'to', route['destination'],
|
|
'via', route['nexthop']]
|
|
ip_wrapper = ip_lib.IPWrapper(namespace=self.ns_name)
|
|
ip_wrapper.netns.execute(cmd, check_exit_code=False)
|
|
|
|
def routes_updated(self):
|
|
new_routes = self.router['routes']
|
|
|
|
old_routes = self.routes
|
|
adds, removes = common_utils.diff_list_of_dict(old_routes,
|
|
new_routes)
|
|
for route in adds:
|
|
LOG.debug("Added route entry is '%s'", route)
|
|
# remove replaced route from deleted route
|
|
for del_route in removes:
|
|
if route['destination'] == del_route['destination']:
|
|
removes.remove(del_route)
|
|
#replace success even if there is no existing route
|
|
self._update_routing_table('replace', route)
|
|
for route in removes:
|
|
LOG.debug("Removed route entry is '%s'", route)
|
|
self._update_routing_table('delete', route)
|
|
self.routes = new_routes
|