# 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, root_helper, 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() self.root_helper = root_helper # 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(self.root_helper, 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