示例#1
0
    def remove_router_interface(self, context, router_id, interface_info):
        router_interface_info = \
            super(OVNL3RouterPlugin, self).remove_router_interface(
                context, router_id, interface_info)
        router = self.get_router(context, router_id)
        port_id = router_interface_info['port_id']
        multi_prefix = False
        port_removed = False
        try:
            port = self._plugin.get_port(context, port_id)
            # The router interface port still exists, call ovn to update it.
            self._ovn_client.update_router_port(port, bump_db_rev=False)
            multi_prefix = True
        except n_exc.PortNotFound:
            # The router interface port doesn't exist any more,
            # we will call ovn to delete it once we remove the snat
            # rules in the router itself if we have to
            port_removed = True

        if not router.get(l3.EXTERNAL_GW_INFO):
            if port_removed:
                self._ovn_client.delete_router_port(port_id, router_id)
            return router_interface_info

        try:
            cidr = None
            if multi_prefix:
                subnet = self._plugin.get_subnet(context,
                                                 interface_info['subnet_id'])
                if subnet['ip_version'] == 4:
                    cidr = subnet['cidr']
            else:
                subnet_ids = router_interface_info.get('subnet_ids')
                for subnet_id in subnet_ids:
                    subnet = self._plugin.get_subnet(context, subnet_id)
                    if subnet['ip_version'] == 4:
                        cidr = subnet['cidr']
                        break

            if utils.is_snat_enabled(router) and cidr:
                self._ovn_client.update_nat_rules(router,
                                                  networks=[cidr],
                                                  enable_snat=False)
        except Exception:
            with excutils.save_and_reraise_exception():
                super(OVNL3RouterPlugin,
                      self).add_router_interface(context, router_id,
                                                 interface_info)
                LOG.error('Error is deleting snat')

        # NOTE(mangelajo): If the port doesn't exist anymore, we delete the
        # router port as the last operation and update the revision database
        # to ensure consistency
        if port_removed:
            self._ovn_client.delete_router_port(port_id, router_id)
        else:
            # otherwise, we just update the revision database
            db_rev.bump_revision(port, ovn_const.TYPE_ROUTER_PORTS)

        return router_interface_info
示例#2
0
    def add_router_interface(self, context, router_id, interface_info):
        router_interface_info = \
            super(OVNL3RouterPlugin, self).add_router_interface(
                context, router_id, interface_info)
        port = self._plugin.get_port(context, router_interface_info['port_id'])

        multi_prefix = False
        if (len(router_interface_info['subnet_ids']) == 1
                and len(port['fixed_ips']) > 1):
            # NOTE(lizk) It's adding a subnet onto an already existing router
            # interface port, try to update lrouter port 'networks' column.
            self.update_lrouter_port_in_ovn(context, router_id, port)
            multi_prefix = True
        else:
            self.create_lrouter_port_in_ovn(context, router_id, port)

        router = self.get_router(context, router_id)
        if not router.get(l3.EXTERNAL_GW_INFO):
            return router_interface_info

        cidr = None
        for fixed_ip in port['fixed_ips']:
            subnet = self._plugin.get_subnet(context, fixed_ip['subnet_id'])
            if multi_prefix:
                if 'subnet_id' in interface_info:
                    if subnet['id'] is not interface_info['subnet_id']:
                        continue
            if subnet['ip_version'] == 4:
                cidr = subnet['cidr']

        if not cidr:
            return router_interface_info

        try:
            if utils.is_snat_enabled(router):
                self._update_snat_for_networks(context,
                                               router,
                                               networks=[cidr],
                                               enable_snat=True)
        except Exception:
            with excutils.save_and_reraise_exception():
                self._ovn.delete_lrouter_port(
                    utils.ovn_lrouter_port_name(port['id']),
                    utils.ovn_name(router_id)).execute(check_error=True)
                super(OVNL3RouterPlugin,
                      self).remove_router_interface(context, router_id,
                                                    router_interface_info)
                LOG.error(
                    _LE('Error updating snat for subnet %(subnet)s in '
                        'router %(router)s'), {
                            'subnet': router_interface_info['subnet_id'],
                            'router': router_id
                        })

        return router_interface_info
示例#3
0
    def remove_router_interface(self, context, router_id, interface_info):
        router_interface_info = \
            super(OVNL3RouterPlugin, self).remove_router_interface(
                context, router_id, interface_info)
        router = self.get_router(context, router_id)
        port_id = router_interface_info['port_id']
        multi_prefix = False
        try:
            port = self._plugin.get_port(context, port_id)
            # The router interface port still exists, call ovn to update it.
            self.update_lrouter_port_in_ovn(context, router_id, port)
            multi_prefix = True
        except n_exc.PortNotFound:
            # The router interface port doesn't exist any more, call ovn to
            # delete it.
            self._ovn.delete_lrouter_port(
                utils.ovn_lrouter_port_name(port_id),
                utils.ovn_name(router_id),
                if_exists=False).execute(check_error=True)

        if not router.get(l3.EXTERNAL_GW_INFO):
            return router_interface_info

        try:
            cidr = None
            if multi_prefix:
                subnet = self._plugin.get_subnet(context,
                                                 interface_info['subnet_id'])
                if subnet['ip_version'] == 4:
                    cidr = subnet['cidr']
            else:
                subnet_ids = router_interface_info.get('subnet_ids')
                for subnet_id in subnet_ids:
                    subnet = self._plugin.get_subnet(context, subnet_id)
                    if subnet['ip_version'] == 4:
                        cidr = subnet['cidr']
                        break

            if not cidr:
                return router_interface_info

            if utils.is_snat_enabled(router):
                self._update_snat_for_networks(context,
                                               router,
                                               networks=[cidr],
                                               enable_snat=False)
        except Exception:
            with excutils.save_and_reraise_exception():
                super(OVNL3RouterPlugin,
                      self).add_router_interface(context, router_id,
                                                 interface_info)
                LOG.error(_LE('Error is deleting snat'))

        return router_interface_info
示例#4
0
    def _add_router_ext_gw(self, context, router):
        router_id = router['id']
        lrouter_name = utils.ovn_name(router['id'])

        # 1. Add the external gateway router port.
        ext_gw_ip = self._get_external_gateway_ip(context, router)
        gw_port_id = router['gw_port_id']
        port = self._plugin.get_port(context.elevated(), gw_port_id)
        try:
            self.create_lrouter_port_in_ovn(context.elevated(), router_id,
                                            port)
        except Exception:
            with excutils.save_and_reraise_exception():
                self._delete_router_ext_gw(context, router_id, router)
                LOG.error(
                    _LE('Unable to add external router port %(id)s to'
                        'lrouter %(name)s'), {
                            'id': port['id'],
                            'name': lrouter_name
                        })

        # 2. Add default route with nexthop as ext_gw_ip
        route = [{'destination': '0.0.0.0/0', 'nexthop': ext_gw_ip}]
        try:
            self._update_lrouter_routes(context, router_id, route, [])
        except Exception:
            with excutils.save_and_reraise_exception():
                self._delete_router_ext_gw(context, router_id, router)
                LOG.error(
                    _LE('Error updating routes %(route)s in lrouter '
                        '%(name)s'), {
                            'route': route,
                            'name': lrouter_name
                        })

        # 3. Add snat rules for tenant networks in lrouter if snat is enabled
        if utils.is_snat_enabled(router):
            try:
                networks = self._get_v4_network_of_all_router_ports(
                    context, router_id)
                if networks:
                    self._update_snat_for_networks(context,
                                                   router,
                                                   networks,
                                                   enable_snat=True)
            except Exception:
                with excutils.save_and_reraise_exception():
                    self._delete_router_ext_gw(context, router_id, router)
                    LOG.error(_LE('Error in updating SNAT for lrouter %s'),
                              lrouter_name)
示例#5
0
    def sync_routers_and_rports(self, ctx):
        """Sync Routers between neutron and NB.

        @param ctx: neutron_lib.context
        @type  ctx: object of type neutron_lib.context.Context
        @var   db_routers: List of Routers from neutron DB
        @var   db_router_ports: List of Router ports from neutron DB
        @var   lrouters: NB dictionary of logical routers and
               the corresponding logical router ports.
               vs list-of-acls
        @var   del_lrouters_list: List of Routers that need to be
               deleted from NB
        @var   del_lrouter_ports_list: List of Router ports that need to be
               deleted from NB
        @return: Nothing
        """
        if not config.is_ovn_l3():
            LOG.debug("OVN L3 mode is disabled, skipping "
                      "sync routers and router ports")
            return

        LOG.debug('OVN-NB Sync Routers and Router ports started @ %s' %
                  str(datetime.now()))

        db_routers = {}
        db_extends = {}
        db_router_ports = {}
        for router in self.l3_plugin.get_routers(ctx):
            db_routers[router['id']] = router
            db_extends[router['id']] = {}
            db_extends[router['id']]['routes'] = []
            db_extends[router['id']]['snats'] = []
            db_extends[router['id']]['fips'] = []
            if not router.get(l3.EXTERNAL_GW_INFO):
                continue
            r_ip, gw_ip = self.l3_plugin.get_external_router_and_gateway_ip(
                ctx, router)
            if gw_ip:
                db_extends[router['id']]['routes'].append({
                    'destination': '0.0.0.0/0',
                    'nexthop': gw_ip
                })
            if r_ip and utils.is_snat_enabled(router):
                networks = self.l3_plugin._get_v4_network_of_all_router_ports(
                    ctx, router['id'])
                for network in networks:
                    db_extends[router['id']]['snats'].append({
                        'logical_ip': network,
                        'external_ip': r_ip,
                        'type': 'snat'
                    })

        fips = self.l3_plugin.get_floatingips(
            ctx, {'router_id': list(db_routers.keys())})
        for fip in fips:
            db_extends[fip['router_id']]['fips'].append({
                'external_ip':
                fip['floating_ip_address'],
                'logical_ip':
                fip['fixed_ip_address'],
                'type':
                'dnat_and_snat'
            })
        interfaces = self.l3_plugin._get_sync_interfaces(
            ctx, db_routers.keys(), [
                constants.DEVICE_OWNER_ROUTER_INTF,
                constants.DEVICE_OWNER_ROUTER_GW
            ])
        for interface in interfaces:
            db_router_ports[interface['id']] = interface
            db_router_ports[interface['id']]['networks'] = sorted(
                self.l3_plugin.get_networks_for_lrouter_port(
                    ctx, interface['fixed_ips']))
        lrouters = self.ovn_api.get_all_logical_routers_with_rports()

        del_lrouters_list = []
        del_lrouter_ports_list = []
        update_sroutes_list = []
        update_lrport_list = []
        update_snats_list = []
        update_fips_list = []
        for lrouter in lrouters:
            if lrouter['name'] in db_routers:
                for lrport, lrport_nets in lrouter['ports'].items():
                    if lrport in db_router_ports:
                        db_lrport_nets = db_router_ports[lrport]['networks']
                        if db_lrport_nets != sorted(lrport_nets):
                            update_lrport_list.append(
                                (lrouter['name'], db_router_ports[lrport]))
                        del db_router_ports[lrport]
                    else:
                        del_lrouter_ports_list.append({
                            'port':
                            lrport,
                            'lrouter':
                            lrouter['name']
                        })
                if 'routes' in db_routers[lrouter['name']]:
                    db_routes = db_routers[lrouter['name']]['routes']
                else:
                    db_routes = []
                if 'routes' in db_extends[lrouter['name']]:
                    db_routes.extend(db_extends[lrouter['name']]['routes'])

                ovn_routes = lrouter['static_routes']
                add_routes, del_routes = helpers.diff_list_of_dict(
                    ovn_routes, db_routes)
                update_sroutes_list.append({
                    'id': lrouter['name'],
                    'add': add_routes,
                    'del': del_routes
                })
                ovn_fips = lrouter['dnat_and_snats']
                db_fips = db_extends[lrouter['name']]['fips']
                add_fips, del_fips = helpers.diff_list_of_dict(
                    ovn_fips, db_fips)
                update_fips_list.append({
                    'id': lrouter['name'],
                    'add': add_fips,
                    'del': del_fips
                })
                ovn_nats = lrouter['snats']
                db_snats = db_extends[lrouter['name']]['snats']
                add_snats, del_snats = helpers.diff_list_of_dict(
                    ovn_nats, db_snats)
                update_snats_list.append({
                    'id': lrouter['name'],
                    'add': add_snats,
                    'del': del_snats
                })
                del db_routers[lrouter['name']]
            else:
                del_lrouters_list.append(lrouter)

        for r_id, router in db_routers.items():
            LOG.warning(
                _LW("Router found in Neutron but not in "
                    "OVN DB, router id=%s"), router['id'])
            if self.mode == SYNC_MODE_REPAIR:
                try:
                    LOG.warning(_LW("Creating the router %s in OVN NB DB"),
                                router['id'])
                    self.l3_plugin.create_lrouter_in_ovn(router)
                    if 'routes' in router:
                        update_sroutes_list.append({
                            'id': router['id'],
                            'add': router['routes'],
                            'del': []
                        })
                    if 'routes' in db_extends[router['id']]:
                        update_sroutes_list.append({
                            'id':
                            router['id'],
                            'add':
                            db_extends[router['id']]['routes'],
                            'del': []
                        })
                    if 'snats' in db_extends[router['id']]:
                        update_snats_list.append({
                            'id':
                            router['id'],
                            'add':
                            db_extends[router['id']]['snats'],
                            'del': []
                        })
                    if 'fips' in db_extends[router['id']]:
                        update_fips_list.append({
                            'id':
                            router['id'],
                            'add':
                            db_extends[router['id']]['fips'],
                            'del': []
                        })
                except RuntimeError:
                    LOG.warning(
                        _LW("Create router in OVN NB failed for"
                            " router %s"), router['id'])

        for rp_id, rrport in db_router_ports.items():
            LOG.warning(
                _LW("Router Port found in Neutron but not in OVN "
                    "DB, router port_id=%s"), rrport['id'])
            if self.mode == SYNC_MODE_REPAIR:
                try:
                    LOG.warning(
                        _LW("Creating the router port %s in "
                            "OVN NB DB"), rrport['id'])
                    self.l3_plugin.create_lrouter_port_in_ovn(
                        ctx, rrport['device_id'], rrport)
                except RuntimeError:
                    LOG.warning(
                        _LW("Create router port in OVN "
                            "NB failed for"
                            " router port %s"), rrport['id'])

        for router_id, rport in update_lrport_list:
            LOG.warning(
                _LW("Router Port port_id=%s needs to be updated"
                    " for networks changed"), rport['id'])
            if self.mode == SYNC_MODE_REPAIR:
                try:
                    LOG.warning(
                        _LW("Updating networks on router port %s in "
                            "OVN NB DB"), rport['id'])
                    self.l3_plugin.update_lrouter_port_in_ovn(
                        ctx, router_id, rport, rport['networks'])
                except RuntimeError:
                    LOG.warning(
                        _LW("Update router port networks in OVN "
                            "NB failed for"
                            " router port %s"), rport['id'])

        with self.ovn_api.transaction(check_error=True) as txn:
            for lrouter in del_lrouters_list:
                LOG.warning(
                    _LW("Router found in OVN but not in "
                        "Neutron, router id=%s"), lrouter['name'])
                if self.mode == SYNC_MODE_REPAIR:
                    LOG.warning(_LW("Deleting the router %s from OVN NB DB"),
                                lrouter['name'])
                    txn.add(
                        self.ovn_api.delete_lrouter(
                            utils.ovn_name(lrouter['name'])))

            for lrport_info in del_lrouter_ports_list:
                LOG.warning(
                    _LW("Router Port found in OVN but not in "
                        "Neutron, port_id=%s"), lrport_info['port'])
                if self.mode == SYNC_MODE_REPAIR:
                    LOG.warning(_LW("Deleting the port %s from OVN NB DB"),
                                lrport_info['port'])
                    txn.add(
                        self.ovn_api.delete_lrouter_port(
                            utils.ovn_lrouter_port_name(lrport_info['port']),
                            utils.ovn_name(lrport_info['lrouter']),
                            if_exists=False))
            for sroute in update_sroutes_list:
                if sroute['add']:
                    LOG.warning(
                        _LW("Router %(id)s static routes %(route)s "
                            "found in Neutron but not in OVN"), {
                                'id': sroute['id'],
                                'route': sroute['add']
                            })
                    if self.mode == SYNC_MODE_REPAIR:
                        LOG.warning(_LW("Add static routes %s to OVN NB DB"),
                                    sroute['add'])
                        for route in sroute['add']:
                            txn.add(
                                self.ovn_api.add_static_route(
                                    utils.ovn_name(sroute['id']),
                                    ip_prefix=route['destination'],
                                    nexthop=route['nexthop']))
                if sroute['del']:
                    LOG.warning(
                        _LW("Router %(id)s static routes %(route)s "
                            "found in OVN but not in Neutron"), {
                                'id': sroute['id'],
                                'route': sroute['del']
                            })
                    if self.mode == SYNC_MODE_REPAIR:
                        LOG.warning(
                            _LW("Delete static routes %s from OVN "
                                "NB DB"), sroute['del'])
                        for route in sroute['del']:
                            txn.add(
                                self.ovn_api.delete_static_route(
                                    utils.ovn_name(sroute['id']),
                                    ip_prefix=route['destination'],
                                    nexthop=route['nexthop']))
            for fip in update_fips_list:
                if fip['del']:
                    LOG.warning(
                        _LW("Router %(id)s floating ips %(fip)s "
                            "found in OVN but not in Neutron"), {
                                'id': fip['id'],
                                'fip': fip['del']
                            })
                    if self.mode == SYNC_MODE_REPAIR:
                        LOG.warning(
                            _LW("Delete floating ips %s from OVN NB DB"),
                            fip['del'])
                        for nat in fip['del']:
                            txn.add(
                                self.ovn_api.delete_nat_rule_in_lrouter(
                                    utils.ovn_name(fip['id']),
                                    logical_ip=nat['logical_ip'],
                                    external_ip=nat['external_ip'],
                                    type='dnat_and_snat'))
                if fip['add']:
                    LOG.warning(
                        _LW("Router %(id)s floating ips %(fip)s "
                            "found in Neutron but not in OVN"), {
                                'id': fip['id'],
                                'fip': fip['add']
                            })
                    if self.mode == SYNC_MODE_REPAIR:
                        LOG.warning(_LW("Add floating ips %s to OVN NB DB"),
                                    fip['add'])
                        for nat in fip['add']:
                            txn.add(
                                self.ovn_api.add_nat_rule_in_lrouter(
                                    utils.ovn_name(fip['id']),
                                    logical_ip=nat['logical_ip'],
                                    external_ip=nat['external_ip'],
                                    type='dnat_and_snat'))
            for snat in update_snats_list:
                if snat['del']:
                    LOG.warning(
                        _LW("Router %(id)s snat %(snat)s "
                            "found in OVN but not in Neutron"), {
                                'id': snat['id'],
                                'snat': snat['del']
                            })
                    if self.mode == SYNC_MODE_REPAIR:
                        LOG.warning(_LW("Delete snats %s from OVN NB DB"),
                                    snat['del'])
                        for nat in snat['del']:
                            txn.add(
                                self.ovn_api.delete_nat_rule_in_lrouter(
                                    utils.ovn_name(snat['id']),
                                    logical_ip=nat['logical_ip'],
                                    external_ip=nat['external_ip'],
                                    type='snat'))
                if snat['add']:
                    LOG.warning(
                        _LW("Router %(id)s snat %(snat)s "
                            "found in Neutron but not in OVN"), {
                                'id': snat['id'],
                                'snat': snat['add']
                            })
                    if self.mode == SYNC_MODE_REPAIR:
                        LOG.warning(_LW("Add snats %s to OVN NB DB"),
                                    snat['add'])
                        for nat in snat['add']:
                            txn.add(
                                self.ovn_api.add_nat_rule_in_lrouter(
                                    utils.ovn_name(snat['id']),
                                    logical_ip=nat['logical_ip'],
                                    external_ip=nat['external_ip'],
                                    type='snat'))
        LOG.debug('OVN-NB Sync routers and router ports finished %s' %
                  str(datetime.now()))