Beispiel #1
0
 def _update_floating_ip_in_ovn(self, context, router_id, update,
                                associate=True):
     fip_apis = {}
     fip_apis['nat'] = self._ovn.add_nat_rule_in_lrouter if \
         associate else self._ovn.delete_nat_rule_in_lrouter
     fip_apis['garp'] = self._ovn.add_nat_ip_to_lrport_peer_options if \
         associate else self._ovn.delete_nat_ip_from_lrport_peer_options
     gw_lrouter_name = utils.ovn_gateway_router_name(router_id)
     try:
         with self._ovn.transaction(check_error=True) as txn:
             if associate:
                 # TODO(chandrav): Since the floating ip port is not
                 # bound to any chassis, packets destined to floating ip
                 # will be dropped. To overcome this, delete the floating
                 # ip port. Proper fix for this would be to redirect packets
                 # destined to floating ip to the router port. This would
                 # require changes in ovn-northd.
                 txn.add(self._ovn.delete_lswitch_port(
                     update['fip_port_id'],
                     utils.ovn_name(update['fip_net_id'])))
             txn.add(fip_apis['nat'](gw_lrouter_name, type='dnat_and_snat',
                                     logical_ip=update['logical_ip'],
                                     external_ip=update['external_ip']))
             txn.add(fip_apis['garp'](update['gw_port_id'],
                                      nat_ip=update['external_ip']))
     except Exception:
         with excutils.save_and_reraise_exception():
             LOG.error(_LE('Unable to update NAT rule in gateway router'))
Beispiel #2
0
 def _delete_lrouter_in_ovn(self, id, is_gateway_router=False):
     if is_gateway_router:
         lrouter_name = utils.ovn_gateway_router_name(id)
     else:
         lrouter_name = utils.ovn_name(id)
     with self._ovn.transaction(check_error=True) as txn:
         txn.add(self._ovn.delete_lrouter(lrouter_name))
Beispiel #3
0
    def create_lrouter_in_ovn(self, router, is_gateway_router=None):
        """Create lrouter in OVN

        @param router: Router to be created in OVN
        @param is_gateway_router: Is router ovn gateway router
        @param nexthop: Nexthop for router
        @return: Nothing
        """

        external_ids = {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
                        router.get('name', 'no_router_name')}
        enabled = router.get('admin_state_up')
        options = {}

        if is_gateway_router:
            lrouter_name = utils.ovn_gateway_router_name(router['id'])
            chassis = self.scheduler.select(self._ovn, self._sb_ovn,
                                            lrouter_name)
            options = {'chassis': chassis}
        else:
            lrouter_name = utils.ovn_name(router['id'])

        with self._ovn.transaction(check_error=True) as txn:
            txn.add(self._ovn.create_lrouter(lrouter_name,
                                             external_ids=external_ids,
                                             enabled=enabled,
                                             options=options))
Beispiel #4
0
    def _update_snat_and_static_routes_for_networks(
            self, context, router, networks, nexthop, enable_snat=True,
            update_static_routes=True):
        apis = {}
        apis['nat'] = self._ovn.add_nat_rule_in_lrouter \
            if enable_snat else self._ovn.delete_nat_rule_in_lrouter
        apis['garp'] = self._ovn.add_nat_ip_to_lrport_peer_options if \
            enable_snat else self._ovn.delete_nat_ip_from_lrport_peer_options
        apis['route'] = self._ovn.add_static_route \
            if enable_snat else self._ovn.delete_static_route

        gw_port_id = router['gw_port_id']
        gw_lrouter_name = utils.ovn_gateway_router_name(router['id'])
        router_ip = self._get_router_ip(context, router)

        with self._ovn.transaction(check_error=True) as txn:
            for network in networks:
                txn.add(apis['nat'](gw_lrouter_name, type='snat',
                                    logical_ip=network,
                                    external_ip=router_ip))
                if update_static_routes:
                    txn.add(apis['route'](gw_lrouter_name, ip_prefix=network,
                                          nexthop=nexthop))
            if networks:
                txn.add(apis['garp'](gw_port_id, nat_ip=router_ip))
Beispiel #5
0
    def _disjoin_lrouter_and_gw_lrouter(self, router, transit_net_ports):
        router_id = router['id']
        lrouter_name = utils.ovn_name(router_id)
        gw_lrouter_name = utils.ovn_gateway_router_name(router_id)

        gtrp_ip = transit_net_ports['gtsp']['ip']
        gtrp_name = utils.ovn_lrouter_port_name(utils.ovn_gtsp_name(router_id))
        dtrp_name = utils.ovn_lrouter_port_name(utils.ovn_dtsp_name(router_id))

        lswitch_name = utils.ovn_transit_ls_name(router_id)
        dtsp_name = utils.ovn_dtsp_name(router_id)
        gtsp_name = utils.ovn_gtsp_name(router_id)

        with self._ovn.transaction(check_error=True) as txn:
            # 1. Delete default static route in gateway router
            txn.add(self._ovn.delete_static_route(
                lrouter_name, ip_prefix="0.0.0.0/0", nexthop=gtrp_ip))
            # 2. Delete gtrp port
            txn.add(self._ovn.delete_lrouter_port(gtrp_name, gw_lrouter_name))
            # 3. Delete dtrp port
            txn.add(self._ovn.delete_lrouter_port(dtrp_name, lrouter_name))
            # 4. Delete gtsp port
            txn.add(self._ovn.delete_lswitch_port(gtsp_name, lswitch_name))
            # 5. Delete dtsp port
            txn.add(self._ovn.delete_lswitch_port(dtsp_name, lswitch_name))
            # 6. Delete transit logical switch
            txn.add(self._ovn.delete_lswitch(lswitch_name))
Beispiel #6
0
    def _get_lrouter_connected_to_nexthop(self, context, router_id,
                                          router_ports, nexthop):
        """Find lrouter connected to nexthop

        @param router_id: router id
        @param router_ports: router ports in router
        @param nexthop: nexthop
        @return: distributed logical router name or gateway router name or None
        """

        lrouter_name = None
        for port in router_ports:
            found_nexthop = False
            for fixed_ip in port.get('fixed_ips', []):
                subnet_id = fixed_ip['subnet_id']
                subnet = self._plugin.get_subnet(context.elevated(), subnet_id)
                network = netaddr.IPNetwork(subnet['cidr'])
                if netaddr.IPAddress(nexthop) in network:
                    if port['device_owner'] == n_const.DEVICE_OWNER_ROUTER_GW:
                        # Nexthop is in external network
                        lrouter_name = utils.ovn_gateway_router_name(router_id)
                    else:
                        # Next hop is in tenant network
                        lrouter_name = utils.ovn_name(router_id)
                    found_nexthop = True
                    break
            if found_nexthop:
                break
        if not lrouter_name:
            raise exc.L3RouterPluginStaticRouteError(nexthop=nexthop,
                                                     router=router_id)

        return lrouter_name
Beispiel #7
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:
            transit_net_ports = self._get_transit_network_ports()
            nexthop = transit_net_ports['dtsp']['ip']
            gw_lrouter_name = utils.ovn_gateway_router_name(router_id)
            if self._is_snat_enabled(router):
                self._update_snat_and_static_routes_for_networks(
                    context, router, networks=[cidr], nexthop=nexthop,
                    enable_snat=True, update_static_routes=True)
            else:
                route = {'destination': cidr, 'nexthop': nexthop}
                self._update_lrouter_routes(
                    context, router_id, add=[route], remove=[],
                    lrouter_name=gw_lrouter_name)
        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
Beispiel #8
0
    def _join_lrouter_and_gw_lrouter(self, router, transit_net_ports):
        router_id = router['id']
        lswitch_name = utils.ovn_transit_ls_name(router_id)

        dtsp_name = utils.ovn_dtsp_name(router_id)
        dtsp_addresses = transit_net_ports['dtsp']['addresses']

        gtsp_name = utils.ovn_gtsp_name(router_id)
        gtsp_addresses = transit_net_ports['gtsp']['addresses']

        gw_lrouter_name = utils.ovn_gateway_router_name(router_id)
        lrouter_name = utils.ovn_name(router_id)

        gtrp_name = utils.ovn_lrouter_port_name(utils.ovn_gtsp_name(router_id))
        gtrp_mac = transit_net_ports['gtsp']['mac_address']
        gtrp_ip = transit_net_ports['gtsp']['ip']
        cidr = netaddr.IPNetwork(self._l3_admin_net_cidr)
        gtrp_network = "%s/%s" % (gtrp_ip, str(cidr.prefixlen))

        dtrp_name = utils.ovn_lrouter_port_name(utils.ovn_dtsp_name(router_id))
        dtrp_mac = transit_net_ports['dtsp']['mac_address']
        dtrp_ip = transit_net_ports['dtsp']['ip']
        dtrp_network = "%s/%s" % (dtrp_ip, str(cidr.prefixlen))

        with self._ovn.transaction(check_error=True) as txn:
            # 1. Create a transit logical switch
            txn.add(self._ovn.create_lswitch(lswitch_name=lswitch_name))
            # 2. Add dtsp port
            txn.add(self._ovn.create_lswitch_port(lport_name=dtsp_name,
                                                  lswitch_name=lswitch_name,
                                                  addresses=dtsp_addresses,
                                                  enabled='True'))
            # 3. Add gtsp port
            txn.add(self._ovn.create_lswitch_port(lport_name=gtsp_name,
                                                  lswitch_name=lswitch_name,
                                                  addresses=gtsp_addresses,
                                                  enabled='True'))
            # 4. Add dtrp port in logical router
            txn.add(self._ovn.add_lrouter_port(name=dtrp_name,
                                               lrouter=lrouter_name,
                                               mac=dtrp_mac,
                                               networks=dtrp_network))
            txn.add(self._ovn.set_lrouter_port_in_lswitch_port(
                utils.ovn_dtsp_name(router_id), dtrp_name))

            # 5. Add gtrp port in gateway router
            txn.add(self._ovn.add_lrouter_port(name=gtrp_name,
                                               lrouter=gw_lrouter_name,
                                               mac=gtrp_mac,
                                               networks=gtrp_network))
            txn.add(self._ovn.set_lrouter_port_in_lswitch_port(
                utils.ovn_gtsp_name(router_id), gtrp_name))
            # 6. Add default static route in gateway router with nexthop as
            # gtrp ip
            txn.add(self._ovn.add_static_route(lrouter_name,
                                               ip_prefix='0.0.0.0/0',
                                               nexthop=gtrp_ip))
Beispiel #9
0
 def _delete_router_ext_gw(self, context, router_id, router,
                           transit_net_ports=None, cleanup=None):
     transit_net_ports = transit_net_ports or \
         self._get_transit_network_ports()
     cleanup = cleanup or []
     gw_port_id = router['gw_port_id']
     gw_lrouter_name = utils.ovn_gateway_router_name(router_id)
     ext_gw_ip = self._get_external_gateway_ip(context, router)
     if 'join' in cleanup or not cleanup:
         self._disjoin_lrouter_and_gw_lrouter(router, transit_net_ports)
     with self._ovn.transaction(check_error=True) as txn:
         if 'ext_gw_ip_nexthop' in cleanup or not cleanup:
             txn.add(self._ovn.delete_static_route(gw_lrouter_name,
                                                   ip_prefix='0.0.0.0/0',
                                                   nexthop=ext_gw_ip))
         if 'ext_gw_port' in cleanup or not cleanup:
             txn.add(self._ovn.delete_lrouter_port(
                 utils.ovn_lrouter_port_name(gw_port_id),
                 gw_lrouter_name))
     if 'gw_router' in cleanup or not cleanup:
         self._delete_lrouter_in_ovn(router_id, is_gateway_router=True)
     self._check_and_delete_l3_admin_net(context)
Beispiel #10
0
    def create_lrouter_port_in_ovn(self, context, router_id, port,
                                   is_lrouter_gateway_router=False):
        """Create lrouter port in OVN

         @param router_id : LRouter ID for the port that needs to be created
         @param port : LRouter port that needs to be created
         @param is_lrouter_gateway_router : Is gateway router
         @return: Nothing
         """
        lrouter = utils.ovn_name(router_id) if not is_lrouter_gateway_router \
            else utils.ovn_gateway_router_name(router_id)
        networks = self.get_networks_for_lrouter_port(context,
                                                      port['fixed_ips'])

        lrouter_port_name = utils.ovn_lrouter_port_name(port['id'])
        with self._ovn.transaction(check_error=True) as txn:
            txn.add(self._ovn.add_lrouter_port(name=lrouter_port_name,
                                               lrouter=lrouter,
                                               mac=port['mac_address'],
                                               networks=networks))

            txn.add(self._ovn.set_lrouter_port_in_lswitch_port(
                port['id'], lrouter_port_name))
Beispiel #11
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

            router_name = utils.ovn_gateway_router_name(router_id)
            transit_net_ports = self._get_transit_network_ports()
            nexthop = transit_net_ports['dtsp']['ip']

            if self._is_snat_enabled(router):
                self._update_snat_and_static_routes_for_networks(
                    context, router, networks=[cidr], nexthop=nexthop,
                    enable_snat=False, update_static_routes=True)
            else:
                route = {'destination': cidr, 'nexthop': nexthop}
                self._update_lrouter_routes(
                    context, router_id, add=[route], remove=[],
                    lrouter_name=router_name)
        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
Beispiel #12
0
    def _add_router_ext_gw(self, context, router):
        # TODO(chandrav): Add sync support, bug #1629076 to track this.
        transit_net_ports = self._get_transit_network_ports(create=True)
        router_id = router['id']
        gw_lrouter_name = utils.ovn_gateway_router_name(router['id'])
        cleanup = []

        # 1. Create gateway router
        try:
            self.create_lrouter_in_ovn(router, is_gateway_router=True)
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE('Unable to create gateway router %s'),
                          gw_lrouter_name)
        cleanup.append('gw_router')

        # 2. Add the external gateway router port to gateway router.
        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,
                                            is_lrouter_gateway_router=True)
        except Exception:
            with excutils.save_and_reraise_exception():
                self._delete_router_ext_gw(context, router_id, router,
                                           transit_net_ports, cleanup)
                LOG.error(_LE('Unable to add external router port %(id)s to'
                              'gateway_router %(name)s'),
                          {'id': port['id'], 'name': gw_lrouter_name})
        cleanup.append('ext_gw_port')

        # 3. Add default route in gateway router 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, [],
                                        gw_lrouter_name)
        except Exception:
            with excutils.save_and_reraise_exception():
                self._delete_router_ext_gw(context, router_id, router,
                                           transit_net_ports, cleanup)
                LOG.error(_LE('Error updating routes %(route)s in lrouter '
                              '%(name)s'), {'route': route,
                                            'name': gw_lrouter_name})
        cleanup.append('ext_gw_ip_nexthop')

        # 4. Join the logical router and gateway router
        try:
            self._join_lrouter_and_gw_lrouter(router, transit_net_ports)
        except Exception:
            with excutils.save_and_reraise_exception():
                self._delete_router_ext_gw(context, router_id, router,
                                           transit_net_ports, cleanup)
                LOG.error(_LE('Error in connecting lrouter and gateway router '
                              'for router %s'), router_id)
        cleanup.append('join')

        # 5. Check if tenant router ports are already configured.
        # If snat is enabled, add snat rules and static routes for tenant
        # networks in gateway router
        # If snat is disabled, add only static routes for tenant networks in
        # gateway router (For traffic destined to floating ips)
        # Static routes are added with a nexthop of gtsp port ip in logical
        # router.
        try:
            networks = self._get_v4_network_of_all_router_ports(context,
                                                                router_id)
            if not networks:
                return
            nexthop = transit_net_ports['dtsp']['ip']
            if self._is_snat_enabled(router):
                self._update_snat_and_static_routes_for_networks(
                    context, router, networks, nexthop, enable_snat=True,
                    update_static_routes=True)
            else:
                routes = []
                for network in networks:
                    routes.append({'destination': network, 'nexthop': nexthop})
                self._update_lrouter_routes(
                    context, router_id, routes, remove=[],
                    lrouter_name=gw_lrouter_name)
        except Exception:
            with excutils.save_and_reraise_exception():
                self._delete_router_ext_gw(context, router_id, router,
                                           transit_net_ports, cleanup)
                LOG.error(_LE('Error in updating SNAT for router %s'),
                          router_id)