components/openstack/neutron/files/agent/evs_l3_agent.py
branchs11-update
changeset 3028 5e73a3a3f66a
child 1944 56ac2df1785b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/neutron/files/agent/evs_l3_agent.py	Mon Mar 31 16:44:02 2014 -0700
@@ -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