Example #1
0
 def test_diff_list_of_dict(self):
     old_list = [{"key1": "value1"},
                 {"key2": "value2"},
                 {"key3": "value3"}]
     new_list = [{"key1": "value1"},
                 {"key2": "value2"},
                 {"key4": "value4"}]
     added, removed = helpers.diff_list_of_dict(old_list, new_list)
     self.assertEqual(added, [dict(key4="value4")])
     self.assertEqual(removed, [dict(key3="value3")])
Example #2
0
    def update_router(self, context, id, router):
        original_router = self.get_router(context, id)
        result = super(OVNL3RouterPlugin,
                       self).update_router(context, id, router)

        update = {}
        added = []
        removed = []
        router_name = utils.ovn_name(id)
        if 'admin_state_up' in router['router']:
            enabled = router['router']['admin_state_up']
            if enabled != original_router['admin_state_up']:
                update['enabled'] = enabled

        if 'name' in router['router']:
            if router['router']['name'] != original_router['name']:
                external_ids = {
                    ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
                    router['router']['name']
                }
                update['external_ids'] = external_ids
        """Update static routes"""
        if 'routes' in router['router']:
            routes = router['router']['routes']
            added, removed = helpers.diff_list_of_dict(
                original_router['routes'], routes)

        if update or added or removed:
            try:
                with self._ovn.transaction(check_error=True) as txn:
                    if update:
                        txn.add(self._ovn.update_lrouter(
                            router_name, **update))

                    for route in added:
                        txn.add(
                            self._ovn.add_static_route(
                                router_name,
                                ip_prefix=route['destination'],
                                nexthop=route['nexthop']))

                    for route in removed:
                        txn.add(
                            self._ovn.delete_static_route(
                                router_name,
                                ip_prefix=route['destination'],
                                nexthop=route['nexthop']))
            except Exception:
                LOG.exception(_LE('Unable to update lrouter for %s'), id)
                super(OVNL3RouterPlugin,
                      self).update_router(context, id, original_router)
                raise n_exc.ServiceUnavailable()

        return result
Example #3
0
 def routes_updated(self, old_routes, new_routes):
     adds, removes = helpers.diff_list_of_dict(old_routes, new_routes)
     for route in adds:
         LOG.debug("Added route entry is '%s'", route)
         # remove replaced route from deleted route
         for del_route in removes:
             if route['destination'] == del_route['destination']:
                 removes.remove(del_route)
         #replace success even if there is no existing route
         self.update_routing_table('replace', route)
     for route in removes:
         LOG.debug("Removed route entry is '%s'", route)
         self.update_routing_table('delete', route)
Example #4
0
 def routes_updated(self, old_routes, new_routes):
     adds, removes = helpers.diff_list_of_dict(old_routes,
                                               new_routes)
     for route in adds:
         LOG.debug("Added route entry is '%s'", route)
         # remove replaced route from deleted route
         for del_route in removes:
             if route['destination'] == del_route['destination']:
                 removes.remove(del_route)
         #replace success even if there is no existing route
         self.update_routing_table('replace', route)
     for route in removes:
         LOG.debug("Removed route entry is '%s'", route)
         self.update_routing_table('delete', route)
Example #5
0
    def _update_extra_routes(self, context, router, routes):
        self._validate_routes(context, router['id'], routes)
        old_routes, routes_dict = self._get_extra_routes_dict_by_router_id(
            context, router['id'])
        added, removed = helpers.diff_list_of_dict(old_routes, routes)
        LOG.debug('Added routes are %s', added)
        for route in added:
            router_routes = l3_models.RouterRoute(
                router_id=router['id'],
                destination=route['destination'],
                nexthop=route['nexthop'])
            context.session.add(router_routes)

        LOG.debug('Removed routes are %s', removed)
        for route in removed:
            context.session.delete(routes_dict[(route['destination'],
                                                route['nexthop'])])
Example #6
0
    def _update_extra_routes(self, context, router, routes):
        self._validate_routes(context, router['id'], routes)
        old_routes = self._get_extra_routes_by_router_id(context, router['id'])
        added, removed = helpers.diff_list_of_dict(old_routes, routes)
        LOG.debug('Added routes are %s', added)
        for route in added:
            l3_obj.RouterRoute(
                context,
                router_id=router['id'],
                destination=utils.AuthenticIPNetwork(route['destination']),
                nexthop=netaddr.IPAddress(route['nexthop'])).create()

        LOG.debug('Removed routes are %s', removed)
        for route in removed:
            l3_obj.RouterRoute.get_object(context,
                                          router_id=router['id'],
                                          destination=route['destination'],
                                          nexthop=route['nexthop']).delete()
Example #7
0
    def _update_extra_routes(self, context, router, routes):
        self._validate_routes(context, router['id'],
                              routes)
        old_routes, routes_dict = self._get_extra_routes_dict_by_router_id(
            context, router['id'])
        added, removed = helpers.diff_list_of_dict(old_routes,
                                                   routes)
        LOG.debug('Added routes are %s', added)
        for route in added:
            router_routes = l3_models.RouterRoute(
                router_id=router['id'],
                destination=route['destination'],
                nexthop=route['nexthop'])
            context.session.add(router_routes)

        LOG.debug('Removed routes are %s', removed)
        for route in removed:
            context.session.delete(
                routes_dict[(route['destination'], route['nexthop'])])
Example #8
0
    def _update_extra_routes(self, context, router, routes):
        self._validate_routes(context, router['id'], routes)
        old_routes = self._get_extra_routes_by_router_id(context, router['id'])
        added, removed = helpers.diff_list_of_dict(old_routes, routes)
        LOG.debug('Added routes are %s', added)
        for route in added:
            l3_obj.RouterRoute(
                context,
                router_id=router['id'],
                destination=utils.AuthenticIPNetwork(route['destination']),
                nexthop=netaddr.IPAddress(route['nexthop'])).create()

        LOG.debug('Removed routes are %s', removed)
        for route in removed:
            l3_obj.RouterRoute.get_object(
                context,
                router_id=router['id'],
                destination=route['destination'],
                nexthop=route['nexthop']).delete()
Example #9
0
    def update_router(self, context, id, router):
        original_router = self.get_router(context, id)
        result = super(OVNL3RouterPlugin,
                       self).update_router(context, id, router)
        gateway_new = result.get(l3.EXTERNAL_GW_INFO)
        gateway_old = original_router.get(l3.EXTERNAL_GW_INFO)
        revert_router = {'router': original_router}
        try:
            if gateway_new and not gateway_old:
                # Route gateway is set
                self._add_router_ext_gw(context, result)
            elif gateway_old and not gateway_new:
                # router gateway is removed
                self._delete_router_ext_gw(context, id, original_router)
            elif gateway_new and gateway_old:
                # Check if external gateway has changed, if yes, delete the old
                # gateway and add the new gateway
                if (gateway_old['network_id'] != gateway_new['network_id']
                        or set([
                            str(fixed_ip)
                            for fixed_ip in gateway_old['external_fixed_ips']
                        ]) != set([
                            str(fixed_ip)
                            for fixed_ip in gateway_new['external_fixed_ips']
                        ])):
                    self._delete_router_ext_gw(context, id, original_router)
                    self._add_router_ext_gw(context, result)
                else:
                    # Check if snat has been enabled/disabled and update
                    old_snat_state = gateway_old.get('enable_snat', True)
                    new_snat_state = gateway_new.get('enable_snat', True)
                    if old_snat_state != new_snat_state:
                        networks = self._get_v4_network_of_all_router_ports(
                            context, id)
                        self._update_snat_for_networks(
                            context,
                            result,
                            networks,
                            enable_snat=new_snat_state)
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE('Unable to update lrouter for %s'), id)
                super(OVNL3RouterPlugin,
                      self).update_router(context, id, revert_router)

        # Check for change in admin_state_up
        update = {}
        router_name = utils.ovn_name(id)
        if 'admin_state_up' in router['router']:
            enabled = router['router']['admin_state_up']
            if enabled != original_router['admin_state_up']:
                update['enabled'] = enabled

        # Check for change in name
        if 'name' in router['router']:
            if router['router']['name'] != original_router['name']:
                external_ids = {
                    ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
                    router['router']['name']
                }
                update['external_ids'] = external_ids

        if update:
            try:
                self._ovn.update_lrouter(router_name,
                                         **update).execute(check_error=True)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.error(_LE('Unable to update lrouter for %s'), id)
                    super(OVNL3RouterPlugin,
                          self).update_router(context, id, revert_router)

        # Check for route updates
        added = []
        removed = []
        if 'routes' in router['router']:
            routes = router['router']['routes']
            added, removed = helpers.diff_list_of_dict(
                original_router['routes'], routes)

        if added or removed:
            try:
                self._update_lrouter_routes(context, id, added, removed)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _LE('Unable to update static routes in lrouter '
                            '%s'), id)
                    super(OVNL3RouterPlugin,
                          self).update_router(context, id, revert_router)

        return result
Example #10
0
    def sync_routers_and_rports(self, ctx):
        """Sync Routers between neutron and NB.

        @param ctx: neutron context
        @type  ctx: object of type neutron.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

        # TODO(chandrav): Add sync support for NAT, bug #1629076.
        LOG.debug('OVN-NB Sync Routers and Router ports started')
        db_routers = {}
        db_router_ports = {}
        for router in self.l3_plugin.get_routers(ctx):
            db_routers[router['id']] = router

        interfaces = self.l3_plugin._get_sync_interfaces(ctx,
                                                         db_routers.keys())
        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 = []
        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 = []
                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})
                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': []})
                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']))
        LOG.debug('OVN-NB Sync routers and router ports finished')
Example #11
0
 def test_diff_list_of_dict(self):
     old_list = [{"key1": "value1"}, {"key2": "value2"}, {"key3": "value3"}]
     new_list = [{"key1": "value1"}, {"key2": "value2"}, {"key4": "value4"}]
     added, removed = helpers.diff_list_of_dict(old_list, new_list)
     self.assertEqual(added, [dict(key4="value4")])
     self.assertEqual(removed, [dict(key3="value3")])
Example #12
0
def diff_list_of_dict(old_list, new_list):
    return helpers.diff_list_of_dict(old_list, new_list)
Example #13
0
    def sync_routers_and_rports(self, ctx):
        """Sync Routers between neutron and NB.

        @param ctx: neutron context
        @type  ctx: object of type neutron.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')
        db_routers = {}
        db_router_ports = {}
        for router in self.l3_plugin.get_routers(ctx):
            db_routers[router['id']] = router

        interfaces = self.l3_plugin._get_sync_interfaces(
            ctx, db_routers.keys())
        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 = []
        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 = []
                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
                })
                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': []
                        })
                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']))
        LOG.debug('OVN-NB Sync routers and router ports finished')
Example #14
0
    def scan_encaps(self, previous, sync):
        """Scan encap rules and check which rules is new/changed/removed

        Args:
            previous(dict): previous encap information
                           {"targets": list
                            "targets_updated": list
                            "targets_removed": list
                           }
            sync(Bool): If this is true, all current encap rules as new
        Return:
            encap_info(dict): same format as previous(dict)
        """
        encap_info = {
            'targets': [],
            'targets_updated': [],
            'targets_removed': []
        }

        updated_encaps = self.rpc_callbacks.get_and_clear_updated_encaps()
        all_encaps = self.mgr.get_all_encap_rules()

        if previous is None:
            previous = {
                'targets': [],
                'targets_updated': [],
                'targets_removed': []
            }

        if sync:
            LOG.info("Sync all encap rules")
            encap_nets = self.resource_rpc.bulk_pull(
                self.context, objects.SRv6EncapNetwork.obj_name())
            # NOTE: Fails to get encap_nets.encap_rules so gets encap_rules
            bulk_encap_rules = self.resource_rpc.bulk_pull(
                self.context, objects.SRv6EncapRule.obj_name())
            current_encaps = []
            for encap_net in encap_nets:
                net_id = encap_net['network_id']
                project_id = encap_net['project_id']
                network_type = self.network_type_map.get(net_id)
                if network_type is None:
                    network_info = self.dhcp_rpc.get_network_info(net_id)
                    network_type = network_info["provider:network_type"]
                    self.network_type_map[net_id] = network_type
                vrf = vrf_utils.get_vrf_name(network_type, project_id, net_id)
                encap_rules = []
                for rule in bulk_encap_rules:
                    if rule.srv6_encap_network_id != encap_net['id']:
                        continue
                    encap_rules.append({
                        "destination": rule['destination'],
                        "nexthop": rule['nexthop']
                    })
                current_encaps.append({
                    'id': encap_net['id'],
                    'rules': encap_rules,
                    'vrf': vrf
                })
            for encap in current_encaps:
                for pre_encap in all_encaps:
                    if encap['id'] == pre_encap['id']:
                        added, removed = helpers.diff_list_of_dict(
                            pre_encap['rules'], encap['rules'])
                        encap_info['targets_updated'].append({
                            'id':
                            encap['id'],
                            'rules':
                            added,
                            'vrf':
                            encap['vrf']
                        })
                        encap_info['targets_removed'].append({
                            'id':
                            encap['id'],
                            'rules':
                            removed,
                            'vrf':
                            encap['vrf']
                        })
                        break
                else:
                    encap_info['targets_updated'].append({
                        'id':
                        encap['id'],
                        'rules':
                        encap['rules'],
                        'vrf':
                        encap['vrf']
                    })
            encap_info['targets'] = current_encaps
        else:
            for encap in updated_encaps:
                for pre_encap in previous['targets']:
                    if encap['id'] == pre_encap['id']:
                        added, removed = helpers.diff_list_of_dict(
                            pre_encap['rules'], encap['rules'])
                        encap_info['targets_updated'].append({
                            'id':
                            encap['id'],
                            'rules':
                            added,
                            'vrf':
                            encap['vrf']
                        })
                        encap_info['targets_removed'].append({
                            'id':
                            encap['id'],
                            'rules':
                            removed,
                            'vrf':
                            encap['vrf']
                        })
                        if (len(removed) != len(pre_encap['rules'])) or added:
                            encap_info['targets'].append(encap)
                        previous['targets'].remove(pre_encap)
                        break
                else:
                    encap_info['targets_updated'].append({
                        'id':
                        encap['id'],
                        'rules':
                        encap['rules'],
                        'vrf':
                        encap['vrf']
                    })
                    encap_info['targets'].append(encap)
            encap_info['targets'] += previous['targets']
        return encap_info
Example #15
0
    def update_router(self, context, id, router):
        original_router = self.get_router(context, id)
        result = super(OVNL3RouterPlugin, self).update_router(context, id,
                                                              router)
        gateway_new = result.get(l3.EXTERNAL_GW_INFO)
        gateway_old = original_router.get(l3.EXTERNAL_GW_INFO)

        try:
            if gateway_new and not gateway_old:
                # Route gateway is set
                self._add_router_ext_gw(context, result)
            elif gateway_old and not gateway_new:
                # router gateway is removed
                self._delete_router_ext_gw(context, id, original_router)
            elif gateway_new and gateway_old:
                # Check if external gateway has changed, if yes, delete the old
                # gateway and add the new gateway
                if gateway_old['network_id'] != gateway_new['network_id']:
                    self._delete_router_ext_gw(context, id, original_router)
                    self._add_router_ext_gw(context, result)

                # Check if snat has been enabled/disabled and update
                old_snat_state = gateway_old.get('enable_snat', 'True')
                new_snat_state = gateway_new.get('enable_snat', 'True')
                if old_snat_state != new_snat_state:
                    networks = self._get_v4_network_of_all_router_ports(
                        context, id)
                    self._update_snat_and_static_routes_for_networks(
                        context, result, networks, nexthop=None,
                        enable_snat=new_snat_state, update_static_routes=False)
        except Exception:
            with excutils.save_and_reraise_exception():
                revert_router = {}
                LOG.error(_LE('Unable to update lrouter for %s'), id)
                revert_router['router'] = original_router
                super(OVNL3RouterPlugin, self).update_router(context, id,
                                                             revert_router)

        # Check for change in admin_state_up
        update = {}
        router_name = utils.ovn_name(id)
        if 'admin_state_up' in router['router']:
            enabled = router['router']['admin_state_up']
            if enabled != original_router['admin_state_up']:
                update['enabled'] = enabled

        # Check for change in name
        if 'name' in router['router']:
            if router['router']['name'] != original_router['name']:
                external_ids = {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
                                router['router']['name']}
                update['external_ids'] = external_ids

        if update:
            try:
                self._ovn.update_lrouter(router_name, **update).execute(
                    check_error=True)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.error(_LE('Unable to update lrouter for %s'), id)
                    router['router'] = original_router
                    super(OVNL3RouterPlugin, self).update_router(context, id,
                                                                 router)

        # Check for route updates
        added = []
        removed = []
        if 'routes' in router['router']:
            routes = router['router']['routes']
            added, removed = helpers.diff_list_of_dict(
                original_router['routes'], routes)

        if added or removed:
            try:
                self._update_lrouter_routes(context, id, added, removed)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.error(_LE('Unable to update static routes in lrouter '
                                  '%s'), id)
                    router['router'] = original_router
                    super(OVNL3RouterPlugin, self).update_router(context, id,
                                                                 router)

        return result
Example #16
0
def diff_list_of_dict(old_list, new_list):
    return helpers.diff_list_of_dict(old_list, new_list)
Example #17
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()))