diff -r b412ae0aa701 -r 353323c7bdc1 components/openstack/neutron/files/agent/evs_l3_agent.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/openstack/neutron/files/agent/evs_l3_agent.py Mon Mar 17 09:51:44 2014 -0600 @@ -0,0 +1,211 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Nicira Networks, Inc. All rights reserved. +# +# Copyright (c) 2014, Oracle and/or its affiliates. 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. +# +# @author: Dan Wendlandt, Nicira, Inc +# @author: Girish Moodalbail, Oracle, Inc. +# + +""" +Based off generic l3_agent (quantum/agent/l3_agent) code +""" + +from oslo.config import cfg + +from quantum.agent import l3_agent +from quantum.agent.solaris import interface +from quantum.agent.solaris import ipfilters_manager +from quantum.agent.solaris import net_lib +from quantum.common import constants as l3_constants +from quantum.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) +INTERNAL_DEV_PREFIX = 'l3i' +EXTERNAL_DEV_PREFIX = 'l3e' + + +class RouterInfo(object): + + def __init__(self, router_id, root_helper, use_namespaces, router): + self.router_id = router_id + self.ex_gw_port = None + self.internal_ports = [] + self.floating_ips = [] + self.router = router + self.ipfilters_manager = ipfilters_manager.IpfiltersManager() + self.routes = [] + + +class EVSL3NATAgent(l3_agent.L3NATAgent): + + RouterInfo = RouterInfo + + OPTS = [ + cfg.StrOpt('external_network_bridge', default='', + help=_("Name of bridge used for external network " + "traffic.")), + cfg.StrOpt('interface_driver', + help=_("The driver used to manage the virtual " + "interface.")), + cfg.BoolOpt('use_namespaces', default=False, + help=_("Allow overlapping IP.")), + cfg.StrOpt('router_id', + help=_("If namespaces is disabled, the l3 agent can only" + " configure a router that has the matching router " + "ID.")), + cfg.BoolOpt('handle_internal_only_routers', default=True, + help=_("Agent should implement routers with no gateway")), + cfg.StrOpt('gateway_external_network_id', default='', + help=_("UUID of external network for routers implemented " + "by the agents.")), + cfg.StrOpt('external_network_datalink', default='net0', + help=_("Name of the datalink that connects to " + "an external network.")), + cfg.BoolOpt('allow_forwarding_between_networks', default=False, + help=_("Allow forwarding of packets between tenant's " + "networks")), + ] + + def __init__(self, host, conf=None): + cfg.CONF.register_opts(self.OPTS) + cfg.CONF.register_opts(interface.OPTS) + if not cfg.CONF.router_id: + raise SystemExit(_("router_id option needs to be set")) + + super(EVSL3NATAgent, self).__init__(host=host, conf=conf) + + def _router_added(self, router_id, router): + ri = RouterInfo(router_id, self.root_helper, + self.conf.use_namespaces, router) + self.router_info[router_id] = ri + + def _router_removed(self, router_id): + ri = self.router_info[router_id] + ri.router['gw_port'] = None + ri.router[l3_constants.INTERFACE_KEY] = [] + ri.router[l3_constants.FLOATINGIP_KEY] = [] + self.process_router(ri) + del self.router_info[router_id] + + def get_internal_device_name(self, port_id): + # Because of the way how dnsmasq works on Solaris, the length + # of datalink name cannot exceed 16 (includes terminating nul + # character). So, the linkname can only have 15 characters and + # the last two characters are set aside for '_0'. So, we only + # have 13 characters left. + dname = (INTERNAL_DEV_PREFIX + port_id)[:13] + dname += '_0' + return dname.replace('-', '_') + + def get_external_device_name(self, port_id): + dname = (EXTERNAL_DEV_PREFIX + port_id)[:13] + dname += '_0' + return dname.replace('-', '_') + + def external_gateway_added(self, ri, ex_gw_port, internal_cidrs): + pass + + def external_gateway_removed(self, ri, ex_gw_port, internal_cidrs): + pass + + def _get_ippool_name(self, mac_address): + # generate a unique-name for ippool(1m) from that last 3 + # bytes of mac-address + mac_suffix = mac_address.split(':')[3:] + return int("".join(mac_suffix), 16) + + def internal_network_added(self, ri, ex_gw_port, port): + + internal_dlname = self.get_internal_device_name(port['id']) + if not net_lib.Datalink.datalink_exists(internal_dlname): + self.driver.plug(port['tenant_id'], port['network_id'], port['id'], + internal_dlname) + self.driver.init_l3(internal_dlname, [port['ip_cidr']]) + + # add ippool(1m) for the new internal port + new_ippool_name = self._get_ippool_name(port['mac_address']) + ri.ipfilters_manager.add_ippool(new_ippool_name, None) + + # walk through the other internal ports and retrieve their + # cidrs and at the same time add the new internal port's + # cidr to them + subnet_cidr = port['subnet']['cidr'] + other_subnet_cidrs = [] + for oip in ri.internal_ports: + if oip['mac_address'] != port['mac_address']: + if (self.conf.allow_forwarding_between_networks and + oip['tenant_id'] == port['tenant_id']): + continue + other_subnet_cidrs.append(oip['subnet']['cidr']) + ippool_name = self._get_ippool_name(oip['mac_address']) + ri.ipfilters_manager.add_ippool(ippool_name, [subnet_cidr]) + # update the new port's pool with other port's cidrs + ri.ipfilters_manager.add_ippool(new_ippool_name, other_subnet_cidrs) + + # now setup the IPF rule + rules = ['block in quick on %s from %s to pool/%d' % + (internal_dlname, subnet_cidr, new_ippool_name)] + ri.ipfilters_manager.add_ipf_rules(rules) + + def internal_network_removed(self, ri, ex_gw_port, port): + internal_dlname = self.get_internal_device_name(port['id']) + if net_lib.Datalink.datalink_exists(internal_dlname): + self.driver.fini_l3(internal_dlname) + self.driver.unplug(internal_dlname) + + # remove all the IP filter rules that we added during addition. + ippool_name = self._get_ippool_name(port['mac_address']) + rules = ['block in quick on %s from %s to pool/%d' % + (internal_dlname, port['subnet']['cidr'], ippool_name)] + ri.ipfilters_manager.remove_ipf_rules(rules) + # remove the ippool + ri.ipfilters_manager.remove_ippool(ippool_name, None) + for internal_port in ri.internal_ports: + if (self.conf.allow_forwarding_between_networks and + internal_port['tenant_id'] == port['tenant_id']): + continue + ippool_name = \ + self._get_ippool_name(internal_port['mac_address']) + ri.ipfilters_manager.remove_ippool(ippool_name, + internal_port['subnet']['cidr']) + + def floating_ip_added(self, ri, ex_gw_port, floating_ip, fixed_ip): + floating_ipcidr = str(floating_ip) + '/32' + fixed_ipcidr = str(fixed_ip) + '/32' + #ifname = self.get_external_device_name(ex_gw_port['id']) + ifname = self.conf.external_network_datalink + ipif = net_lib.IPInterface(ifname) + ipif.create_address(floating_ipcidr) + + nat_rules = ['bimap %s %s -> %s' % + (ifname, fixed_ipcidr, floating_ipcidr)] + ri.ipfilters_manager.add_nat_rules(nat_rules) + + def floating_ip_removed(self, ri, ex_gw_port, floating_ip, fixed_ip): + floating_ipcidr = str(floating_ip) + '/32' + fixed_ipcidr = str(fixed_ip) + '/32' + ifname = self.conf.external_network_datalink + ipif = net_lib.IPInterface(ifname) + ipif.delete_address(floating_ipcidr) + + nat_rules = ['bimap %s %s -> %s' % + (ifname, fixed_ipcidr, floating_ipcidr)] + ri.ipfilters_manager.remove_nat_rules(nat_rules) + + def routes_updated(self, ri): + pass