def create_ipsec_site_connection(self, context, conn_info): """Creates an IPSec site-to-site connection on CSR. Create the PSK, IKE policy, IPSec policy, connection, static route, and (future) DPD. """ # Get all the IDs conn_id = conn_info['id'] psk_id = conn_id site_conn_id = conn_info['cisco']['site_conn_id'] ike_policy_id = conn_info['cisco']['ike_policy_id'] ipsec_policy_id = conn_info['cisco']['ipsec_policy_id'] LOG.debug('Creating IPSec connection %s', conn_id) # Get all the attributes needed to create try: psk_info = self.create_psk_info(psk_id, conn_info) ike_policy_info = self.create_ike_policy_info(ike_policy_id, conn_info) ipsec_policy_info = self.create_ipsec_policy_info(ipsec_policy_id, conn_info) connection_info = self.create_site_connection_info(site_conn_id, ipsec_policy_id, conn_info) routes_info = self.create_routes_info(site_conn_id, conn_info) except (CsrUnknownMappingError, CsrDriverMismatchError) as e: LOG.exception(e) return try: self.do_create_action('pre_shared_key', psk_info, conn_id, 'Pre-Shared Key') self.do_create_action('ike_policy', ike_policy_info, ike_policy_id, 'IKE Policy') self.do_create_action('ipsec_policy', ipsec_policy_info, ipsec_policy_id, 'IPSec Policy') self.do_create_action('ipsec_connection', connection_info, site_conn_id, 'IPSec Connection') # TODO(pcm): FUTURE - Do DPD for v1 and handle if >1 connection # and different DPD settings for route_id, route_info in routes_info: self.do_create_action('static_route', route_info, route_id, 'Static Route') except CsrResourceCreateFailure: self.do_rollback() LOG.info(_LI("FAILED: Create of IPSec site-to-site connection %s"), conn_id) else: LOG.info(_LI("SUCCESS: Created IPSec site-to-site connection %s"), conn_id)
def create_ipsec_site_connection(self, context, conn_info): """Creates an IPSec site-to-site connection on CSR. Create the PSK, IKE policy, IPSec policy, connection, static route, and (future) DPD. """ # Get all the IDs conn_id = conn_info['id'] psk_id = conn_id site_conn_id = conn_info['cisco']['site_conn_id'] ike_policy_id = conn_info['cisco']['ike_policy_id'] ipsec_policy_id = conn_info['cisco']['ipsec_policy_id'] LOG.debug('Creating IPSec connection %s', conn_id) # Get all the attributes needed to create try: psk_info = self.create_psk_info(psk_id, conn_info) ike_policy_info = self.create_ike_policy_info( ike_policy_id, conn_info) ipsec_policy_info = self.create_ipsec_policy_info( ipsec_policy_id, conn_info) connection_info = self.create_site_connection_info( site_conn_id, ipsec_policy_id, conn_info) routes_info = self.create_routes_info(site_conn_id, conn_info) except (CsrUnknownMappingError, CsrDriverMismatchError) as e: LOG.exception(e) return try: self.do_create_action('pre_shared_key', psk_info, conn_id, 'Pre-Shared Key') self.do_create_action('ike_policy', ike_policy_info, ike_policy_id, 'IKE Policy') self.do_create_action('ipsec_policy', ipsec_policy_info, ipsec_policy_id, 'IPSec Policy') self.do_create_action('ipsec_connection', connection_info, site_conn_id, 'IPSec Connection') # TODO(pcm): FUTURE - Do DPD for v1 and handle if >1 connection # and different DPD settings for route_id, route_info in routes_info: self.do_create_action('static_route', route_info, route_id, 'Static Route') except CsrResourceCreateFailure: self.do_rollback() LOG.info(_LI("FAILED: Create of IPSec site-to-site connection %s"), conn_id) else: LOG.info(_LI("SUCCESS: Created IPSec site-to-site connection %s"), conn_id)
def multitenants_vpn_test(self, **kwargs): """Test VPN connectivity under two different tenants. 1. Create 2 private networks with 2 different tenants, subnets, routers 2. Create public network, subnets and GW IPs on routers, if not present 3. Execute ip netns command and get the snat and qrouter namespaces (assuming we use DVR) 4. Verify that there is a route between the router gateways by pinging each other from their snat namespaces 5. Add security group rules for SSH and ICMP 6. Start a nova instance in each of the private networks 7. Create IKE and IPSEC policies 8. Create VPN service at each of the routers 9. Create IPSEC site connections at both endpoints 10. Verify that the vpn-service and ipsec-site-connection are ACTIVE 11. Cleanup the resources that are setup for this test """ try: self.setup(**kwargs) self.create_tenants() self.create_networks(**kwargs) self.check_route() self.ike_policy = self._create_ike_policy(**kwargs) self.ipsec_policy = self._create_ipsec_policy(**kwargs) self.create_vpn_services() self.create_ipsec_site_connections(**kwargs) self.assert_statuses(final_status='ACTIVE', **kwargs) LOG.info(_LI("VPN TENANT TEST PASSED!")) finally: self.cleanup()
def create_tunnel_mapping(context, conn_info): """Create Cisco CSR IDs, using mapping table and OpenStack UUIDs.""" conn_id = conn_info['id'] ike_policy_id = conn_info['ikepolicy_id'] ipsec_policy_id = conn_info['ipsecpolicy_id'] tenant_id = conn_info['tenant_id'] with context.session.begin(): csr_tunnel_id = get_next_available_tunnel_id(context.session) csr_ike_id = determine_csr_ike_policy_id(ike_policy_id, conn_id, context.session) csr_ipsec_id = determine_csr_ipsec_policy_id(ipsec_policy_id, conn_id, context.session) map_entry = IdentifierMap(tenant_id=tenant_id, ipsec_site_conn_id=conn_id, csr_tunnel_id=csr_tunnel_id, csr_ike_policy_id=csr_ike_id, csr_ipsec_policy_id=csr_ipsec_id) try: context.session.add(map_entry) # Force committing to database context.session.flush() except db_exc.DBDuplicateEntry: msg = _("Attempt to create duplicate entry in Cisco CSR " "mapping table for connection %s") % conn_id raise CsrInternalError(reason=msg) LOG.info( _LI("Mapped connection %(conn_id)s to Tunnel%(tunnel_id)d " "using IKE policy ID %(ike_id)d and IPSec policy " "ID %(ipsec_id)d"), { 'conn_id': conn_id, 'tunnel_id': csr_tunnel_id, 'ike_id': csr_ike_id, 'ipsec_id': csr_ipsec_id })
def create_tunnel_mapping(context, conn_info): """Create Cisco CSR IDs, using mapping table and OpenStack UUIDs.""" conn_id = conn_info['id'] ike_policy_id = conn_info['ikepolicy_id'] ipsec_policy_id = conn_info['ipsecpolicy_id'] tenant_id = conn_info['tenant_id'] with context.session.begin(): csr_tunnel_id = get_next_available_tunnel_id(context.session) csr_ike_id = determine_csr_ike_policy_id(ike_policy_id, conn_id, context.session) csr_ipsec_id = determine_csr_ipsec_policy_id(ipsec_policy_id, conn_id, context.session) map_entry = IdentifierMap(tenant_id=tenant_id, ipsec_site_conn_id=conn_id, csr_tunnel_id=csr_tunnel_id, csr_ike_policy_id=csr_ike_id, csr_ipsec_policy_id=csr_ipsec_id) try: context.session.add(map_entry) # Force committing to database context.session.flush() except db_exc.DBDuplicateEntry: msg = _("Attempt to create duplicate entry in Cisco CSR " "mapping table for connection %s") % conn_id raise CsrInternalError(reason=msg) LOG.info(_LI("Mapped connection %(conn_id)s to Tunnel%(tunnel_id)d " "using IKE policy ID %(ike_id)d and IPSec policy " "ID %(ipsec_id)d"), {'conn_id': conn_id, 'tunnel_id': csr_tunnel_id, 'ike_id': csr_ike_id, 'ipsec_id': csr_ipsec_id})
def __init__(self): super(VPNDriverPlugin, self).__init__() self.service_type_manager = st_db.ServiceTypeManager.get_instance() add_provider_configuration(self.service_type_manager, constants.VPN) # Load the service driver from neutron.conf. drivers, default_provider = service_base.load_drivers(constants.VPN, self) LOG.info(_LI("VPN plugin using service driver: %s"), default_provider) self.ipsec_driver = drivers[default_provider] vpn_db.subscribe()
def __init__(self): super(VPNDriverPlugin, self).__init__() self.service_type_manager = st_db.ServiceTypeManager.get_instance() add_provider_configuration(self.service_type_manager, constants.VPN) # Load the service driver from neutron.conf. drivers, default_provider = service_base.load_drivers( constants.VPN, self) LOG.info(_LI("VPN plugin using service driver: %s"), default_provider) self.ipsec_driver = drivers[default_provider] vpn_db.subscribe()
def delete_ipsec_site_connection(self, context, conn_id): """Delete the site-to-site IPSec connection. This will be best effort and will continue, if there are any failures. """ LOG.debug('Deleting IPSec connection %s', conn_id) if not self.steps: LOG.warning(_LW('Unable to find connection %s'), conn_id) else: self.do_rollback() LOG.info(_LI("SUCCESS: Deleted IPSec site-to-site connection %s"), conn_id)
def execute_with_mount(): conf = setup_conf() conf() config.setup_logging() if not conf.cmd: LOG.error(_LE('No command provided, exiting')) return errno.EINVAL if not conf.mount_paths: LOG.error(_LE('No mount path provided, exiting')) return errno.EINVAL # Both sudoers and rootwrap.conf will not exist in the directory /etc # after bind-mount, so we can't use utils.execute(conf.cmd, # run_as_root=True). That's why we have to check here if cmd matches # CommandFilter filter_command(conf.cmd, conf.rootwrap_config) # Make sure the process is running in net namespace invoked by ip # netns exec(/proc/[pid]/ns/net) which is since Linux 3.0, # as we can't check mount namespace(/proc/[pid]/ns/mnt) # which is since Linux 3.8. For more detail please refer the link # http://man7.org/linux/man-pages/man7/namespaces.7.html if os.path.samefile(os.path.join('/proc/1/ns/net'), os.path.join('/proc', str(os.getpid()), 'ns/net')): LOG.error(_LE('Cannot run without netns, exiting')) return errno.EINVAL for path, new_path in conf.mount_paths.items(): if not os.path.isdir(new_path): # Sometimes all directories are not ready LOG.debug('%s is not directory', new_path) continue if os.path.isdir(path) and os.path.isabs(path): return_code = execute(['mount', '--bind', new_path, path]) if return_code == 0: LOG.info( _LI('%(new_path)s has been ' 'bind-mounted in %(path)s'), { 'new_path': new_path, 'path': path }) else: LOG.error( _LE('Failed to bind-mount ' '%(new_path)s in %(path)s'), { 'new_path': new_path, 'path': path }) return execute(conf.cmd)
def report_status_internal(self, context): """Generate report and send to plugin, if anything changed.""" service_report = [] LOG.debug("Report: Starting status report processing") for vpn_service_id, vpn_service in self.service_state.items(): LOG.debug("Report: Collecting status for VPN service %s", vpn_service_id) report = self.build_report_for_service(vpn_service) if report: service_report.append(report) if service_report: LOG.info(_LI("Sending status report update to plugin")) self.agent_rpc.update_status(context, service_report) LOG.debug("Report: Completed status report processing") return service_report
def execute_with_mount(): conf = setup_conf() conf() config.setup_logging() if not conf.cmd: LOG.error(_LE('No command provided, exiting')) return errno.EINVAL if not conf.mount_paths: LOG.error(_LE('No mount path provided, exiting')) return errno.EINVAL # Both sudoers and rootwrap.conf will not exist in the directory /etc # after bind-mount, so we can't use utils.execute(conf.cmd, # run_as_root=True). That's why we have to check here if cmd matches # CommandFilter filter_command(conf.cmd, conf.rootwrap_config) # Make sure the process is running in net namespace invoked by ip # netns exec(/proc/[pid]/ns/net) which is since Linux 3.0, # as we can't check mount namespace(/proc/[pid]/ns/mnt) # which is since Linux 3.8. For more detail please refer the link # http://man7.org/linux/man-pages/man7/namespaces.7.html if os.path.samefile(os.path.join('/proc/1/ns/net'), os.path.join('/proc', str(os.getpid()), 'ns/net')): LOG.error(_LE('Cannot run without netns, exiting')) return errno.EINVAL for path, new_path in six.iteritems(conf.mount_paths): if not os.path.isdir(new_path): # Sometimes all directories are not ready LOG.debug('%s is not directory', new_path) continue if os.path.isdir(path) and os.path.isabs(path): return_code = execute(['mount', '--bind', new_path, path]) if return_code == 0: LOG.info(_LI('%(new_path)s has been ' 'bind-mounted in %(path)s'), {'new_path': new_path, 'path': path}) else: LOG.error(_LE('Failed to bind-mount ' '%(new_path)s in %(path)s'), {'new_path': new_path, 'path': path}) return execute(conf.cmd)
def _process_running(self): """Checks if process is still running.""" # If no PID file, we assume the process is not running. if not os.path.exists(self.pid_file): return False try: # We take an ask-forgiveness-not-permission approach and rely # on throwing to tell us something. If the pid file exists, # delve into the process information and check if it matches # our expected command line. with open(self.pid_file, 'r') as f: pid = f.readline().strip() with open('/proc/%s/cmdline' % pid) as cmd_line_file: cmd_line = cmd_line_file.readline() if self.pid_path in cmd_line and 'pluto' in cmd_line: # Okay the process is probably a pluto process # and it contains the pid_path in the command # line... could be a race. Log to error and return # that it is *NOT* okay to clean up files. We are # logging to error instead of debug because it # indicates something bad has happened and this is # valuable information for figuring it out. LOG.error( _LE('Process %(pid)s exists with command ' 'line %(cmd_line)s.') % { 'pid': pid, 'cmd_line': cmd_line }) return True except IOError as e: # This is logged as "info" instead of error because it simply # means that we couldn't find the files to check on them. LOG.info( _LI('Unable to find control files on startup for ' 'router %(router)s: %(msg)s'), { 'router': self.id, 'msg': e }) return False
def check_vpn_status(self, **kwargs): """Test VPN's status correctly after bringing router's status to DOWN and back to ACTIVE state 1. Create 2 private networks, subnets and routers 2. Create public network, subnets and GW IPs on routers, if not present 3. Execute ip netns command and get the snat and qrouter namespaces (assuming we use DVR) 4. Verify that there is a route between the router gateways by pinging each other from their snat namespaces 5. Add security group rules for SSH and ICMP 6. Start a nova instance in each of the private networks 7. Create IKE and IPSEC policies 8. Create VPN service at each of the routers 9. Create IPSEC site connections at both endpoints 10. Bring both the private router's status to DOWN state 11. Verify that vpn-service and ipsec-site-connection is DOWN 12. Bring back the router's status to ACTIVE state 13. Verify the vpn-service and ipsec-site-connection is back to ACTIVE 14. Perform resource cleanup """ try: self.setup(**kwargs) self.create_networks(**kwargs) self.check_route() self.ike_policy = self._create_ike_policy(**kwargs) self.ipsec_policy = self._create_ipsec_policy(**kwargs) self.create_vpn_services() self.create_ipsec_site_connections(**kwargs) self.assert_statuses(final_status='ACTIVE', **kwargs) self.update_router(self.router_ids[0], admin_state_up=False) self.update_router(self.router_ids[1], admin_state_up=False) self.assert_statuses(final_status='DOWN', **kwargs) self.update_router(self.router_ids[0], admin_state_up=True) self.update_router(self.router_ids[1], admin_state_up=True) self.assert_statuses(final_status='ACTIVE', **kwargs) LOG.info(_LI("VPN STATUS TEST PASSED!")) finally: self.cleanup()
def create_and_delete_vpn_connection( self, **kwargs): """Basic VPN connectivity scenario. 1. Create 2 private networks, subnets and routers 2. Create public network, subnets and GW IPs on routers, if not present 3. Execute ip netns command and get the snat and qrouter namespaces (assuming we use DVR) 4. Verify that there is a route between the router gateways by pinging each other from their snat namespaces 5. Add security group rules for SSH and ICMP 6. Start a nova instance in each of the private networks 7. Create IKE and IPSEC policies 8. Create VPN service at each of the routers 9. Create IPSEC site connections at both endpoints 10. Verify that the ipsec-site-connection is ACTIVE (takes upto 30secs) 11. To verify the vpn connectivity, get into the first snat namespace and start a tcpdump at the qg-xxxx interface 12. SSH into the second instance from the second qrouter namespace and try to ping the first instance 14. Verify that the captured packets are encapsulated and encrypted. 15. Verify the connectivity in the reverse direction following the steps 11 through 13 16. Submit a request to delete all the resources """ try: self.setup() self.create_networks_and_servers(**kwargs) self.check_route() self.ike_policy = self._create_ike_policy(**kwargs) self.ipsec_policy = self._create_ipsec_policy(**kwargs) self.create_vpn_services() self.create_ipsec_site_connections(**kwargs) self.assert_statuses(final_status='ACTIVE', **kwargs) self.assert_vpn_connectivity() LOG.info(_LI("VPN CONNECTIVITY TEST PASSED!!")) finally: self.cleanup()
def create_and_delete_vpn_connection(self, **kwargs): """Basic VPN connectivity scenario. 1. Create 2 private networks, subnets and routers 2. Create public network, subnets and GW IPs on routers, if not present 3. Execute ip netns command and get the snat and qrouter namespaces (assuming we use DVR) 4. Verify that there is a route between the router gateways by pinging each other from their snat namespaces 5. Add security group rules for SSH and ICMP 6. Start a nova instance in each of the private networks 7. Create IKE and IPSEC policies 8. Create VPN service at each of the routers 9. Create IPSEC site connections at both endpoints 10. Verify that the ipsec-site-connection is ACTIVE (takes upto 30secs) 11. To verify the vpn connectivity, get into the peer router's snat namespace and start a tcpdump at the qg-xxxx interface 12. SSH into the nova instance from the local qrouter namespace and try to ping the nova instance on the peer network. 14. Verify that the captured packets are encapsulated and encrypted. 15. Verify the connectivity in the reverse direction following the steps 11 through 13 16. Submit a request to delete all the resources """ try: self.setup(**kwargs) self.create_networks(**kwargs) self.create_servers(**kwargs) self.check_route() self.ike_policy = self._create_ike_policy(**kwargs) self.ipsec_policy = self._create_ipsec_policy(**kwargs) self.create_vpn_services() self.create_ipsec_site_connections(**kwargs) self.assert_statuses(final_status='ACTIVE', **kwargs) self.verify_vpn_connectivity(**kwargs) LOG.info(_LI("VPN CONNECTIVITY TEST PASSED!")) finally: self.cleanup()
def _process_running(self): """Checks if process is still running.""" # If no PID file, we assume the process is not running. if not os.path.exists(self.pid_file): return False try: # We take an ask-forgiveness-not-permission approach and rely # on throwing to tell us something. If the pid file exists, # delve into the process information and check if it matches # our expected command line. with open(self.pid_file, 'r') as f: pid = f.readline().strip() with open('/proc/%s/cmdline' % pid) as cmd_line_file: cmd_line = cmd_line_file.readline() if self.pid_path in cmd_line and 'pluto' in cmd_line: # Okay the process is probably a pluto process # and it contains the pid_path in the command # line... could be a race. Log to error and return # that it is *NOT* okay to clean up files. We are # logging to error instead of debug because it # indicates something bad has happened and this is # valuable information for figuring it out. LOG.error(_LE('Process %(pid)s exists with command ' 'line %(cmd_line)s.') % {'pid': pid, 'cmd_line': cmd_line}) return True except IOError as e: # This is logged as "info" instead of error because it simply # means that we couldn't find the files to check on them. LOG.info(_LI('Unable to find control files on startup for ' 'router %(router)s: %(msg)s'), {'router': self.id, 'msg': e}) return False
def delete_tunnel_mapping(context, conn_info): conn_id = conn_info['id'] with context.session.begin(): sess_qry = context.session.query(IdentifierMap) sess_qry.filter_by(ipsec_site_conn_id=conn_id).delete() LOG.info(_LI("Removed mapping for connection %s"), conn_id)