¡@

Home 

OpenStack Study: varmour_router.py

OpenStack Index

**** CubicPower OpenStack Study ****

# vim: tabstop=4 shiftwidth=4 softtabstop=4

#

# Copyright 2013 vArmour Networks Inc.

# 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: Gary Duan, vArmour Networks Inc.

#

import eventlet

import netaddr

from oslo.config import cfg

from neutron.agent.common import config

from neutron.agent import l3_agent

from neutron.agent.linux import external_process

from neutron.agent.linux import interface

from neutron.agent.linux import ip_lib

from neutron.common import constants as l3_constants

from neutron.common import legacy

from neutron.common import topics

from neutron.openstack.common import log as logging

from neutron.openstack.common import service

from neutron import service as neutron_service

from neutron.services.firewall.agents.l3reference import firewall_l3_agent

from neutron.services.firewall.agents.varmour import varmour_api

from neutron.services.firewall.agents.varmour import varmour_utils as va_utils

LOG = logging.getLogger(__name__)

**** CubicPower OpenStack Study ****

class vArmourL3NATAgent(l3_agent.L3NATAgent, firewall_l3_agent.FWaaSL3AgentRpcCallback):

**** CubicPower OpenStack Study ****

    def __init__(self, host, conf=None):

        LOG.debug(_('vArmourL3NATAgent: __init__'))

        self.rest = varmour_api.vArmourRestAPI()

        super(vArmourL3NATAgent, self).__init__(host, conf)

**** CubicPower OpenStack Study ****

    def _destroy_router_namespaces(self, only_router_id=None):

        return

**** CubicPower OpenStack Study ****

    def _destroy_router_namespace(self, namespace):

        return

**** CubicPower OpenStack Study ****

    def _create_router_namespace(self, ri):

        return

**** CubicPower OpenStack Study ****

    def _router_added(self, router_id, router):

        LOG.debug(_("_router_added: %s"), router_id)

        ri = l3_agent.RouterInfo(router_id, self.root_helper,

                                 self.conf.use_namespaces, router)

        self.router_info[router_id] = ri

        super(vArmourL3NATAgent, self).process_router_add(ri)

**** CubicPower OpenStack Study ****

    def _router_removed(self, router_id):

        LOG.debug(_("_router_removed: %s"), router_id)

        ri = self.router_info[router_id]

        if ri:

            ri.router['gw_port'] = None

            ri.router[l3_constants.INTERFACE_KEY] = []

            ri.router[l3_constants.FLOATINGIP_KEY] = []

            self.process_router(ri)

            name = va_utils.get_snat_rule_name(ri)

            self.rest.del_cfg_objs(va_utils.REST_URL_CONF_NAT_RULE, name)

            name = va_utils.get_dnat_rule_name(ri)

            self.rest.del_cfg_objs(va_utils.REST_URL_CONF_NAT_RULE, name)

            name = va_utils.get_trusted_zone_name(ri)

            self._va_unset_zone_interfaces(name, True)

            name = va_utils.get_untrusted_zone_name(ri)

            self._va_unset_zone_interfaces(name, True)

            del self.router_info[router_id]

**** CubicPower OpenStack Study ****

    def _spawn_metadata_proxy(self, router_id, ns_name):

        return

**** CubicPower OpenStack Study ****

    def _destroy_metadata_proxy(self, router_id, ns_name):

        return

**** CubicPower OpenStack Study ****

    def _set_subnet_info(self, port):

        ips = port['fixed_ips']

        if not ips:

            raise Exception(_("Router port %s has no IP address") % port['id'])

            return

        if len(ips) > 1:

            LOG.warn(_("Ignoring multiple IPs on router port %s"), port['id'])

        prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen

        port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen)

**** CubicPower OpenStack Study ****

    def _va_unset_zone_interfaces(self, zone_name, remove_zone=False):

        # return True if zone exists; otherwise, return False

        LOG.debug(_("_va_unset_zone_interfaces: %s"), zone_name)

        resp = self.rest.rest_api('GET', va_utils.REST_URL_CONF_ZONE)

        if resp and resp['status'] == 200:

            zlist = resp['body']['response']

            for zn in zlist:

                if zn == zone_name:

                    commit = False

                    if 'interface' in zlist[zn]:

                        for intf in zlist[zn]['interface']:

                            self.rest.rest_api('DELETE',

                                               va_utils.REST_URL_CONF +

                                               va_utils.REST_ZONE_NAME % zn +

                                               va_utils.REST_INTF_NAME % intf)

                            commit = True

                    if remove_zone:

                        self.rest.rest_api('DELETE',

                                           va_utils.REST_URL_CONF +

                                           va_utils.REST_ZONE_NAME % zn)

                        commit = True

                    if commit:

                        self.rest.commit()

                    return True

        return False

**** CubicPower OpenStack Study ****

    def _va_pif_2_lif(self, pif):

        return pif + '.0'

**** CubicPower OpenStack Study ****

    def _va_set_interface_ip(self, pif, cidr):

        LOG.debug(_("_va_set_interface_ip: %(pif)s %(cidr)s"),

                  {'pif': pif, 'cidr': cidr})

        lif = self._va_pif_2_lif(pif)

        obj = va_utils.REST_INTF_NAME % pif + va_utils.REST_LOGIC_NAME % lif

        body = {

            'name': lif,

            'family': 'ipv4',

            'address': cidr

        }

        self.rest.rest_api('PUT', va_utils.REST_URL_CONF + obj, body)

**** CubicPower OpenStack Study ****

    def _va_get_port_name(self, port_list, name):

        if name:

            for p in port_list:

                if p['VM name'] == name:

                    return p['name']

**** CubicPower OpenStack Study ****

    def _va_config_trusted_zone(self, ri, plist):

        zone = va_utils.get_trusted_zone_name(ri)

        LOG.debug(_("_va_config_trusted_zone: %s"), zone)

        body = {

            'name': zone,

            'type': 'L3',

            'interface': []

        }

        if not self._va_unset_zone_interfaces(zone):

            # if zone doesn't exist, create it

            self.rest.rest_api('POST', va_utils.REST_URL_CONF_ZONE, body)

            self.rest.commit()

        # add new internal ports to trusted zone

        for p in ri.internal_ports:

            if p['admin_state_up']:

                dev = self.get_internal_device_name(p['id'])

                pif = self._va_get_port_name(plist, dev)

                if pif:

                    lif = self._va_pif_2_lif(pif)

                    if lif not in body['interface']:

                        body['interface'].append(lif)

                        self._va_set_interface_ip(pif, p['ip_cidr'])

        if body['interface']:

            self.rest.rest_api('PUT', va_utils.REST_URL_CONF_ZONE, body)

            self.rest.commit()

**** CubicPower OpenStack Study ****

    def _va_config_untrusted_zone(self, ri, plist):

        zone = va_utils.get_untrusted_zone_name(ri)

        LOG.debug(_("_va_config_untrusted_zone: %s"), zone)

        body = {

            'name': zone,

            'type': 'L3',

            'interface': []

        }

        if not self._va_unset_zone_interfaces(zone):

            # if zone doesn't exist, create it

            self.rest.rest_api('POST', va_utils.REST_URL_CONF_ZONE, body)

            self.rest.commit()

        # add new gateway ports to untrusted zone

        if ri.ex_gw_port:

            LOG.debug(_("_va_config_untrusted_zone: gw=%r"), ri.ex_gw_port)

            dev = self.get_external_device_name(ri.ex_gw_port['id'])

            pif = self._va_get_port_name(plist, dev)

            if pif:

                lif = self._va_pif_2_lif(pif)

                self._va_set_interface_ip(pif, ri.ex_gw_port['ip_cidr'])

                body['interface'].append(lif)

                self.rest.rest_api('PUT', va_utils.REST_URL_CONF_ZONE, body)

                self.rest.commit()

**** CubicPower OpenStack Study ****

    def _va_config_router_snat_rules(self, ri, plist):

        LOG.debug(_('_va_config_router_snat_rules: %s'), ri.router['id'])

        prefix = va_utils.get_snat_rule_name(ri)

        self.rest.del_cfg_objs(va_utils.REST_URL_CONF_NAT_RULE, prefix)

        if not ri.enable_snat:

            return

        for idx, p in enumerate(ri.internal_ports):

            if p['admin_state_up']:

                dev = self.get_internal_device_name(p['id'])

                pif = self._va_get_port_name(plist, dev)

                if pif:

                    net = netaddr.IPNetwork(p['ip_cidr'])

                    body = {

                        'name': '%s_%d' % (prefix, idx),

                        'ingress-context-type': 'interface',

                        'ingress-index': self._va_pif_2_lif(pif),

                        'source-address': [

                            [str(netaddr.IPAddress(net.first + 2)),

                             str(netaddr.IPAddress(net.last - 1))]

                        ],

                        'flag': 'interface translate-source'

                    }

                    self.rest.rest_api('POST',

                                       va_utils.REST_URL_CONF_NAT_RULE,

                                       body)

        if ri.internal_ports:

            self.rest.commit()

**** CubicPower OpenStack Study ****

    def _va_config_floating_ips(self, ri):

        LOG.debug(_('_va_config_floating_ips: %s'), ri.router['id'])

        prefix = va_utils.get_dnat_rule_name(ri)

        self.rest.del_cfg_objs(va_utils.REST_URL_CONF_NAT_RULE, prefix)

        # add new dnat rules

        for idx, fip in enumerate(ri.floating_ips):

            body = {

                'name': '%s_%d' % (prefix, idx),

                'ingress-context-type': 'zone',

                'ingress-index': va_utils.get_untrusted_zone_name(ri),

                'destination-address': [[fip['floating_ip_address'],

                                         fip['floating_ip_address']]],

                'static': [fip['fixed_ip_address'], fip['fixed_ip_address']],

                'flag': 'translate-destination'

            }

            self.rest.rest_api('POST', va_utils.REST_URL_CONF_NAT_RULE, body)

        if ri.floating_ips:

            self.rest.commit()

**** CubicPower OpenStack Study ****

    def process_router(self, ri):

        LOG.debug(_("process_router: %s"), ri.router['id'])

        super(vArmourL3NATAgent, self).process_router(ri)

        self.rest.auth()

        # read internal port name and configuration port name map

        resp = self.rest.rest_api('GET', va_utils.REST_URL_INTF_MAP)

        if resp and resp['status'] == 200:

            try:

                plist = resp['body']['response']

            except ValueError:

                LOG.warn(_("Unable to parse interface mapping."))

                return

        else:

            LOG.warn(_("Unable to read interface mapping."))

            return

        if ri.ex_gw_port:

            self._set_subnet_info(ri.ex_gw_port)

        self._va_config_trusted_zone(ri, plist)

        self._va_config_untrusted_zone(ri, plist)

        self._va_config_router_snat_rules(ri, plist)

        self._va_config_floating_ips(ri)

**** CubicPower OpenStack Study ****

    def _handle_router_snat_rules(self, ri, ex_gw_port, internal_cidrs,

                                  interface_name, action):

        return

**** CubicPower OpenStack Study ****

    def _send_gratuitous_arp_packet(self, ri, interface_name, ip_address):

        return

**** CubicPower OpenStack Study ****

    def external_gateway_added(self, ri, ex_gw_port,

                               interface_name, internal_cidrs):

        LOG.debug(_("external_gateway_added: %s"), ri.router['id'])

        if not ip_lib.device_exists(interface_name,

                                    root_helper=self.root_helper,

                                    namespace=ri.ns_name):

            self.driver.plug(ex_gw_port['network_id'],

                             ex_gw_port['id'], interface_name,

                             ex_gw_port['mac_address'],

                             bridge=self.conf.external_network_bridge,

                             namespace=ri.ns_name,

                             prefix=l3_agent.EXTERNAL_DEV_PREFIX)

        self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']],

                            namespace=ri.ns_name)

**** CubicPower OpenStack Study ****

    def _update_routing_table(self, ri, operation, route):

        return

**** CubicPower OpenStack Study ****

class vArmourL3NATAgentWithStateReport(vArmourL3NATAgent, l3_agent.L3NATAgentWithStateReport):

pass

**** CubicPower OpenStack Study ****

def main():

    eventlet.monkey_patch()

    conf = cfg.CONF

    conf.register_opts(vArmourL3NATAgent.OPTS)

    config.register_interface_driver_opts_helper(conf)

    config.register_use_namespaces_opts_helper(conf)

    config.register_agent_state_opts_helper(conf)

    config.register_root_helper(conf)

    conf.register_opts(interface.OPTS)

    conf.register_opts(external_process.OPTS)

    conf(project='neutron')

    config.setup_logging(conf)

    legacy.modernize_quantum_config(conf)

    server = neutron_service.Service.create(

        binary='neutron-l3-agent',

        topic=topics.L3_AGENT,

        report_interval=cfg.CONF.AGENT.report_interval,

        manager='neutron.services.firewall.agents.varmour.varmour_router.'

                'vArmourL3NATAgentWithStateReport')

    service.launch(server).wait()