components/openstack/neutron/files/agent/evs_l3_agent.py
changeset 1760 353323c7bdc1
child 1944 56ac2df1785b
equal deleted inserted replaced
1759:b412ae0aa701 1760:353323c7bdc1
       
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
       
     2 
       
     3 # Copyright 2012 Nicira Networks, Inc.  All rights reserved.
       
     4 #
       
     5 # Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
       
     6 #
       
     7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
       
     8 #    not use this file except in compliance with the License. You may obtain
       
     9 #    a copy of the License at
       
    10 #
       
    11 #         http://www.apache.org/licenses/LICENSE-2.0
       
    12 #
       
    13 #    Unless required by applicable law or agreed to in writing, software
       
    14 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
       
    15 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
       
    16 #    License for the specific language governing permissions and limitations
       
    17 #    under the License.
       
    18 #
       
    19 # @author: Dan Wendlandt, Nicira, Inc
       
    20 # @author: Girish Moodalbail, Oracle, Inc.
       
    21 #
       
    22 
       
    23 """
       
    24 Based off generic l3_agent (quantum/agent/l3_agent) code
       
    25 """
       
    26 
       
    27 from oslo.config import cfg
       
    28 
       
    29 from quantum.agent import l3_agent
       
    30 from quantum.agent.solaris import interface
       
    31 from quantum.agent.solaris import ipfilters_manager
       
    32 from quantum.agent.solaris import net_lib
       
    33 from quantum.common import constants as l3_constants
       
    34 from quantum.openstack.common import log as logging
       
    35 
       
    36 
       
    37 LOG = logging.getLogger(__name__)
       
    38 INTERNAL_DEV_PREFIX = 'l3i'
       
    39 EXTERNAL_DEV_PREFIX = 'l3e'
       
    40 
       
    41 
       
    42 class RouterInfo(object):
       
    43 
       
    44     def __init__(self, router_id, root_helper, use_namespaces, router):
       
    45         self.router_id = router_id
       
    46         self.ex_gw_port = None
       
    47         self.internal_ports = []
       
    48         self.floating_ips = []
       
    49         self.router = router
       
    50         self.ipfilters_manager = ipfilters_manager.IpfiltersManager()
       
    51         self.routes = []
       
    52 
       
    53 
       
    54 class EVSL3NATAgent(l3_agent.L3NATAgent):
       
    55 
       
    56     RouterInfo = RouterInfo
       
    57 
       
    58     OPTS = [
       
    59         cfg.StrOpt('external_network_bridge', default='',
       
    60                    help=_("Name of bridge used for external network "
       
    61                           "traffic.")),
       
    62         cfg.StrOpt('interface_driver',
       
    63                    help=_("The driver used to manage the virtual "
       
    64                           "interface.")),
       
    65         cfg.BoolOpt('use_namespaces', default=False,
       
    66                     help=_("Allow overlapping IP.")),
       
    67         cfg.StrOpt('router_id',
       
    68                    help=_("If namespaces is disabled, the l3 agent can only"
       
    69                           " configure a router that has the matching router "
       
    70                           "ID.")),
       
    71         cfg.BoolOpt('handle_internal_only_routers', default=True,
       
    72                     help=_("Agent should implement routers with no gateway")),
       
    73         cfg.StrOpt('gateway_external_network_id', default='',
       
    74                    help=_("UUID of external network for routers implemented "
       
    75                           "by the agents.")),
       
    76         cfg.StrOpt('external_network_datalink', default='net0',
       
    77                    help=_("Name of the datalink that connects to "
       
    78                           "an external network.")),
       
    79         cfg.BoolOpt('allow_forwarding_between_networks', default=False,
       
    80                     help=_("Allow forwarding of packets between tenant's "
       
    81                            "networks")),
       
    82     ]
       
    83 
       
    84     def __init__(self, host, conf=None):
       
    85         cfg.CONF.register_opts(self.OPTS)
       
    86         cfg.CONF.register_opts(interface.OPTS)
       
    87         if not cfg.CONF.router_id:
       
    88             raise SystemExit(_("router_id option needs to be set"))
       
    89 
       
    90         super(EVSL3NATAgent, self).__init__(host=host, conf=conf)
       
    91 
       
    92     def _router_added(self, router_id, router):
       
    93         ri = RouterInfo(router_id, self.root_helper,
       
    94                         self.conf.use_namespaces, router)
       
    95         self.router_info[router_id] = ri
       
    96 
       
    97     def _router_removed(self, router_id):
       
    98         ri = self.router_info[router_id]
       
    99         ri.router['gw_port'] = None
       
   100         ri.router[l3_constants.INTERFACE_KEY] = []
       
   101         ri.router[l3_constants.FLOATINGIP_KEY] = []
       
   102         self.process_router(ri)
       
   103         del self.router_info[router_id]
       
   104 
       
   105     def get_internal_device_name(self, port_id):
       
   106         # Because of the way how dnsmasq works on Solaris, the length
       
   107         # of datalink name cannot exceed 16 (includes terminating nul
       
   108         # character). So, the linkname can only have 15 characters and
       
   109         # the last two characters are set aside for '_0'. So, we only
       
   110         # have 13 characters left.
       
   111         dname = (INTERNAL_DEV_PREFIX + port_id)[:13]
       
   112         dname += '_0'
       
   113         return dname.replace('-', '_')
       
   114 
       
   115     def get_external_device_name(self, port_id):
       
   116         dname = (EXTERNAL_DEV_PREFIX + port_id)[:13]
       
   117         dname += '_0'
       
   118         return dname.replace('-', '_')
       
   119 
       
   120     def external_gateway_added(self, ri, ex_gw_port, internal_cidrs):
       
   121         pass
       
   122 
       
   123     def external_gateway_removed(self, ri, ex_gw_port, internal_cidrs):
       
   124         pass
       
   125 
       
   126     def _get_ippool_name(self, mac_address):
       
   127         # generate a unique-name for ippool(1m) from that last 3
       
   128         # bytes of mac-address
       
   129         mac_suffix = mac_address.split(':')[3:]
       
   130         return int("".join(mac_suffix), 16)
       
   131 
       
   132     def internal_network_added(self, ri, ex_gw_port, port):
       
   133 
       
   134         internal_dlname = self.get_internal_device_name(port['id'])
       
   135         if not net_lib.Datalink.datalink_exists(internal_dlname):
       
   136             self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
       
   137                              internal_dlname)
       
   138         self.driver.init_l3(internal_dlname, [port['ip_cidr']])
       
   139 
       
   140         # add ippool(1m) for the new internal port
       
   141         new_ippool_name = self._get_ippool_name(port['mac_address'])
       
   142         ri.ipfilters_manager.add_ippool(new_ippool_name, None)
       
   143 
       
   144         # walk through the other internal ports and retrieve their
       
   145         # cidrs and at the same time add the new internal port's
       
   146         # cidr to them
       
   147         subnet_cidr = port['subnet']['cidr']
       
   148         other_subnet_cidrs = []
       
   149         for oip in ri.internal_ports:
       
   150             if oip['mac_address'] != port['mac_address']:
       
   151                 if (self.conf.allow_forwarding_between_networks and
       
   152                     oip['tenant_id'] == port['tenant_id']):
       
   153                     continue
       
   154                 other_subnet_cidrs.append(oip['subnet']['cidr'])
       
   155                 ippool_name = self._get_ippool_name(oip['mac_address'])
       
   156                 ri.ipfilters_manager.add_ippool(ippool_name, [subnet_cidr])
       
   157         # update the new port's pool with other port's cidrs
       
   158         ri.ipfilters_manager.add_ippool(new_ippool_name, other_subnet_cidrs)
       
   159 
       
   160         # now setup the IPF rule
       
   161         rules = ['block in quick on %s from %s to pool/%d' %
       
   162                  (internal_dlname, subnet_cidr, new_ippool_name)]
       
   163         ri.ipfilters_manager.add_ipf_rules(rules)
       
   164 
       
   165     def internal_network_removed(self, ri, ex_gw_port, port):
       
   166         internal_dlname = self.get_internal_device_name(port['id'])
       
   167         if net_lib.Datalink.datalink_exists(internal_dlname):
       
   168             self.driver.fini_l3(internal_dlname)
       
   169             self.driver.unplug(internal_dlname)
       
   170 
       
   171         # remove all the IP filter rules that we added during addition.
       
   172         ippool_name = self._get_ippool_name(port['mac_address'])
       
   173         rules = ['block in quick on %s from %s to pool/%d' %
       
   174                  (internal_dlname, port['subnet']['cidr'], ippool_name)]
       
   175         ri.ipfilters_manager.remove_ipf_rules(rules)
       
   176         # remove the ippool
       
   177         ri.ipfilters_manager.remove_ippool(ippool_name, None)
       
   178         for internal_port in ri.internal_ports:
       
   179             if (self.conf.allow_forwarding_between_networks and
       
   180                 internal_port['tenant_id'] == port['tenant_id']):
       
   181                 continue
       
   182             ippool_name = \
       
   183                 self._get_ippool_name(internal_port['mac_address'])
       
   184             ri.ipfilters_manager.remove_ippool(ippool_name,
       
   185                                                internal_port['subnet']['cidr'])
       
   186 
       
   187     def floating_ip_added(self, ri, ex_gw_port, floating_ip, fixed_ip):
       
   188         floating_ipcidr = str(floating_ip) + '/32'
       
   189         fixed_ipcidr = str(fixed_ip) + '/32'
       
   190         #ifname = self.get_external_device_name(ex_gw_port['id'])
       
   191         ifname = self.conf.external_network_datalink
       
   192         ipif = net_lib.IPInterface(ifname)
       
   193         ipif.create_address(floating_ipcidr)
       
   194 
       
   195         nat_rules = ['bimap %s %s -> %s' %
       
   196                      (ifname, fixed_ipcidr, floating_ipcidr)]
       
   197         ri.ipfilters_manager.add_nat_rules(nat_rules)
       
   198 
       
   199     def floating_ip_removed(self, ri, ex_gw_port, floating_ip, fixed_ip):
       
   200         floating_ipcidr = str(floating_ip) + '/32'
       
   201         fixed_ipcidr = str(fixed_ip) + '/32'
       
   202         ifname = self.conf.external_network_datalink
       
   203         ipif = net_lib.IPInterface(ifname)
       
   204         ipif.delete_address(floating_ipcidr)
       
   205 
       
   206         nat_rules = ['bimap %s %s -> %s' %
       
   207                      (ifname, fixed_ipcidr, floating_ipcidr)]
       
   208         ri.ipfilters_manager.remove_nat_rules(nat_rules)
       
   209 
       
   210     def routes_updated(self, ri):
       
   211         pass