def test_setup_expert(self): """ This UnitTest executes the wca_setup_expert-function with the given config-file. It sets the values of all the from WebInterface of the Router. """ print("Test if the 'wca_setup_wizard'-function is working") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) try: # Config config = ConfigManager.get_web_interface_list()[router.id] self.assertEqual(len(config), 30, "Wrong size of the Config-Directory") print("Set the following configuration: \n" + str(config)) router_web_config = RouterWebConfiguration(router, config, wizard=True) router_web_config.start() router_web_config.join() except Exception as e: nv_assist.close() raise e assert router.mode == Mode.normal nv_assist.close()
def single(self, ns): self.signal() netns.setns(ns) k = ns + '_' + self.check while True: self.results[k] = { 'check': self.check, 'type': self.type, 'ns': ns, 'state': 'RUN' } res = self.results[k] try: r = pyping.ping(self.host, count=self.count, packet_size=self.length) res['max_rtt'] = r.max_rtt res['avg_rtt'] = r.avg_rtt res['min_rtt'] = r.min_rtt res['packet_lost'] = r.packet_lost res['state'] = 'OK' logging.info("[PING:%s] host = %s, max time = %s, avg time = %s, min time = %s, lost packets = %d" % (ns, self.host, r.max_rtt, r.avg_rtt, r.min_rtt, r.packet_lost)) except: res['state'] = 'FAIL' logging.info("[PING:%s] Cannot ping host %s" % (ns, self.host)) self.results[k] = res time.sleep(float(self.delay))
def __init__(self, nsp_name: str, ipdb: IPDB): """ Creats a namespace for a specific vlan_iface :param nsp_name: :param vlan_iface_name: :param ipdb: IPDB is a transactional database, containing records, representing network stack objects. Any change in the database is not reflected immidiately in OS, but waits until commit() is called. """ Logger().debug("Create Namespace ...", 2) self.nsp_name = nsp_name self.id = id self.vlan_iface_name = "" self.vlan_iface_ip = "0.0.0.0" self.ipdb = ipdb self.ipdb_netns = None try: self.ipdb_netns = IPDB(nl=NetNS(nsp_name)) netns.setns(nsp_name) self.ipdb_netns.interfaces['lo'].up().commit() Logger().debug("[+] Namespace(" + nsp_name + ") successfully created", 3) # self.encapsulate_interface() except Exception as e: Logger().debug("[-] Couldn't create Namespace(" + nsp_name + ")", 3) for tb in traceback.format_tb(sys.exc_info()[2]): Logger().error(tb, 3) Logger().error(str(e), 3) self.remove()
def test_flash_firmware(self): print("Test Router_Flash_Firmware") router = self._create_router() print("Download/Import firmware-image from UpdateServer/PI ...") # Download firmare-image from UpdateServer sysupdate = Sysupdate(router) sysupdate.start() sysupdate.join() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # The IP where the Router can download the firmware image (should be the frameworks IP) web_server_ip = nv_assist.get_ip_address(router.namespace_name, router.vlan_iface_name)[0] try: # Copy firmware-image to the Router (/tmp/image) print("Copy firmware-image to Router ...") sysupgrade = Sysupgrade(router, n=True, web_server_ip=web_server_ip, debug=True) sysupgrade.start() sysupgrade.join() except Exception: raise finally: nv_assist.close()
def setUpClass(cls): cls.router = cls._create_router() # NVAssisten cls.nv_assist = NVAssistent("eth0") cls.nv_assist.create_namespace_vlan(cls.router) # Set netns for the current process netns.setns(cls.router.namespace_name) # Create NetworkCrtl cls.network_ctrl = NetworkCtrl(cls.router) assert isinstance(cls.network_ctrl, NetworkCtrl)
def __setns(cls, remote_sys: RemoteSystem) -> None: """ Set Namespace and VLAN for the current process. :param remote_sys: The RemoteSystem which you want to connect over VLAN """ if cls.VLAN: logging.debug("%sSet Namespace and VLAN for the current process(" + str(os.getpid()) + ")", LoggerSetup.get_log_deep(2)) netns.setns(remote_sys.namespace_name)
def NSPopenServer(nsname, flags, channel_in, channel_out, argv, kwarg): # set netns try: setns(nsname, flags=flags) except Exception as e: channel_out.put(e) return # create the Popen object child = subprocess.Popen(*argv, **kwarg) for fname in ['stdout', 'stderr', 'stdin']: obj = getattr(child, fname) if obj is not None: fproxy = NSPopenFile(obj) setattr(child, fname, fproxy) # send the API map channel_out.put(None) while True: # synchronous mode # 1. get the command from the API try: call = channel_in.get() except: (et, ev, tb) = sys.exc_info() try: channel_out.put({'code': 500, 'data': ev}) except: pass break # 2. stop? if call['name'] == 'release': break # 3. run the call try: # get the object namespace ns = call.get('namespace') obj = child if ns: for step in ns.split('.'): obj = getattr(obj, step) attr = getattr(obj, call['name']) if isinstance(attr, (types.MethodType, types.FunctionType, types.BuiltinMethodType)): result = attr(*call['argv'], **call['kwarg']) else: result = attr channel_out.put({'code': 200, 'data': result}) except: (et, ev, tb) = sys.exc_info() channel_out.put({'code': 500, 'data': ev}) child.wait()
def single(self, ns): self.signal() netns.setns(ns) self.results[ns + '_torrent_state'] = "RUN" session = libtorrent.session() session.listen_on(6881, 6891) info = libtorrent.torrent_info(self.file) resource = session.add_torrent({'ti' : info, 'save_path' : '/var/tmp/' + ns}) download_rates_sum = 0 download_rates_avg = 0.0 upload_rates_sum = 0 upload_rates_avg = 0.0 download_count = 0 upload_count = 0 start = time.time() while (not resource.is_seed()): status = resource.status() download_rate = status.download_rate upload_rate = status.upload_rate if download_rate != 0: download_rates_sum += download_rate download_count += 1 if upload_rate != 0: upload_rates_sum += upload_rate upload_count += 1 time.sleep(1) end = time.time() if download_count == 0: download_count = 1 if upload_count == 0: upload_count = 1 download_rates_avg = float(download_rates_sum) / download_count upload_rates_avg = float(upload_rates_sum) / upload_count shutil.rmtree('/var/tmp/' + ns, ignore_errors=True) self.results[ns + "_torrent_downspeed"] = download_rates_avg self.results[ns + "_torrent_upspeed"] = upload_rates_avg self.results[ns + "_torrent_time"] = end - start self.results[ns + '_torrent_state'] = "OK" logging.info("[TORRENT:%s] download speed = %.2f b/s, upload speed = %.2f b/s, time = %.2f sec" % (ns, download_rates_avg, upload_rates_avg, (end - start)))
def single(self, ns): self.signal() netns.setns(ns) k = ns + '_' + self.check recursor = dns.resolver.Resolver() while True: self.results[k] = { 'check': self.check, 'type': self.type, 'ns': ns, 'state': 'RUN' } res = self.results[k] recursor.nameservers = [self.server] error = "" # Если резолвим IP адрес, приводим его к правильному виду if re.search("^\d+\.\d+\.\d+\.\d+$", self.host): self.host = dns.reversename.from_address(self.host) # Замеряем время выполнения запроса start = time.time() # Выполняем запрос try: answers = recursor.query (self.host, self.query_type) except dns.exception.DNSException as e: if isinstance(e, dns.resolver.NXDOMAIN): error = "No such domain " + str(self.host) elif isinstance(e, dns.resolver.Timeout): error = "Timed out while resolving " + str(self.host) elif isinstance(e, dns.resolver.NoAnswer): error = "No answer while resolving " + str(self.host) elif isinstance(e, dns.resolver.NoNameservers): error = "Nameserver " + str(self.server) + " not available" else: error = "Unhandled DNS exception" # Замеряем время выполнения запроса end = time.time() if error != "": res['qtime'] = (end - start) * 1000 res['state'] = 'FAIL' logging.info("[DNS:%s] host = %s, query time = %.2f msec, return message = %s" % (ns, self.host, (end - start) * 1000, error)) else: res['qtime'] = (end - start) * 1000 res['state'] = 'OK' logging.info("[DNS:%s] host = %s, query time = %.2f msec, return message = Success" % (ns, self.host, (end - start) * 1000)) self.results[k] = res time.sleep(float(self.delay))
def _power_off(self, ps: Ubnt, q: Queue, port: int): nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(ps) netns.setns(ps.namespace_name) power_on = PowerStripControl(self.router, ps, False, port) power_on.start() power_on.join() nv_assist.close() q.put(ps)
def _reboot_into_normal(self, router: Router, q: Queue): print("Reboot Router back into normalmode ...") nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) router_reboot = RouterReboot(router, configmode=False) router_reboot.start() router_reboot.join() assert router.mode == Mode.normal nv_assist.close() q.put(router)
def single(self, ns): self.signal() netns.setns(ns) logger_rzs = logging.getLogger('RZS') logger_rzs.propagate = False log_handler_rzs = logging.FileHandler('/var/log/sensors_rzs_' + ns + '.log') logger_rzs.addHandler(log_handler_rzs) logging.getLogger("urllib3").propagate = False k = ns + '_' + self.check headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'} while True: self.results[k] = { 'check': self.check, 'type': self.type, 'ns': ns, 'state': 'RUN' } res = self.results[k] available_hosts_count = 0 unavailable_hosts_count = 0 total_hosts_count = 0 try: f = open(self.blockfile, 'r') blocked_urls = f.read() f.close() for url in blocked_urls.splitlines(): total_hosts_count += 1 try: response = requests.get(url, headers=headers, timeout=0.5) available_hosts_count += 1 logger_rzs.info("[RZS:%s] %s Available host: %s" % (ns, time.strftime("%H:%M:%S %d/%m/%Y", time.localtime(time.time())), url)) except Exception as e: unavailable_hosts_count += 1 res['rzs_total'] = total_hosts_count res['rzs_available'] = available_hosts_count res['rzs_unavailable'] = unavailable_hosts_count res['state'] = 'OK' logging.info("[RZS:%s] Total hosts count = %d, available hosts count = %d, unavailable hosts count = %d" % (ns, total_hosts_count, available_hosts_count, unavailable_hosts_count)) except: res['state'] = 'FAIL' logging.info("[RZS:%s] Cannot open block file %s" % (ns, self.blockfile)) self.results[k] = res time.sleep(float(self.delay))
def __createNetns(self, phyIfaceIndex): netnsName = self.__getNetnsName() (pvdIfaceName, pvdIfaceIndex) = self.__getPvdIfaceParams() netns.create(netnsName) LOG.debug('network namespace {0} created'.format(netnsName)) # create a virtual interface where PvD parameters are going to be configured, then move the interface to the new network namespace self.ipRoot.link_create(ifname=pvdIfaceName, index=pvdIfaceIndex, kind=self.__PVD_IFACE_TYPE, link=phyIfaceIndex) LOG.debug('macvlan {0} created in default network namespace'.format(pvdIfaceName)) pvdIfaceIndex = self.ipRoot.link_lookup(ifname=pvdIfaceName) self.ipRoot.link('set', index=pvdIfaceIndex[0], net_ns_fd=netnsName) LOG.debug('macvlan {0} moved to network namespace {1}'.format(pvdIfaceName, netnsName)) # change the namespace and get new NETLINK handles to operate in new namespace netns.setns(netnsName) LOG.debug('network namespace switched to {0}'.format(netnsName)) ip = IPRoute() ipdb = IPDB() ipdb.register_callback(self.__onIfaceStateChange) # disable kernel to auto-configure the interface associated with the PvD, let the pvdman to solely control interface configuration acceptRaConfFile = self.__ACCEPT_RA_CONF_FILE.replace(self.__IFACENAME_REPLACE_PATTERN, pvdIfaceName) acceptRaConfFile = open(acceptRaConfFile, 'w') acceptRaConfFile.write('0') LOG.debug('processing of RAs by kernel disabled in {0}'.format(acceptRaConfFile.name)) # return to a default network namespace to not cause a colision with other modules # ip and ipdb handles continue to work in the target network namespace netns.setns(self.__NETNS_DEFAULT_NAME) LOG.debug('network namespace switched to default') # get new index since interface has been moved to a different namespace loIfaceIndex = ip.link_lookup(ifname=self.__LOOPBACK_IFACE_NAME) if (len(loIfaceIndex) > 0): loIfaceIndex = loIfaceIndex[0] pvdIfaceIndex = ip.link_lookup(ifname=pvdIfaceName) if (len(pvdIfaceIndex) > 0): pvdIfaceIndex = pvdIfaceIndex[0] # start interfaces ip.link_up(loIfaceIndex) ip.link_up(pvdIfaceIndex) # clear network configuration if exists ip.flush_addr(index=pvdIfaceIndex) ip.flush_routes(index=pvdIfaceIndex) ip.flush_rules(index=pvdIfaceIndex) LOG.debug('macvlan {0} in network namespace {1} initialized'.format(pvdIfaceName, netnsName)) return (netnsName, pvdIfaceName, ip)
def _reboot_into_config(self, router: Router, q: Queue): print("Reboot Router into configmode ...") # Create NVAssistent nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # Reboot Router into configmode router_reboot = RouterReboot(router, configmode=True) router_reboot.start() router_reboot.join() assert router.mode == Mode.configuration nv_assist.close() q.put(router)
def NetNServer(netns, cmdch, brdch, flags=os.O_CREAT): ''' The netns server supposed to be started automatically by NetNS. It has two communication channels: one simplex to forward incoming netlink packets, `rcvch`, and other synchronous duplex to get commands and send back responses, `cmdch`. Channels should support standard socket API, should be compatible with poll/select and should be able to transparently pickle objects. NetNS uses `multiprocessing.Pipe` for this purpose, but it can be any other implementation with compatible API. The first parameter, `netns`, is a netns name. Depending on the `flags`, the netns can be created automatically. The `flags` semantics is exactly the same as for `open(2)` system call. ... The server workflow is simple. The startup sequence:: 1. Create or open a netns. 2. Start `IPRoute` instance. It will be used only on the low level, the `IPRoute` will not parse any packet. 3. Start poll/select loop on `cmdch` and `IPRoute`. On the startup, the server sends via `cmdch` the status packet. It can be `None` if all is OK, or some exception. Further data handling, depending on the channel, server side:: 1. `IPRoute`: read an incoming netlink packet and send it unmodified to the peer via `rcvch`. The peer, polling `rcvch`, can handle the packet on its side. 2. `cmdch`: read tuple (cmd, argv, kwarg). If the `cmd` starts with "send", then take `argv[0]` as a packet buffer, treat it as one netlink packet and substitute PID field (offset 12, uint32) with its own. Strictly speaking, it is not mandatory for modern netlink implementations, but it is required by the protocol standard. ''' signal.signal(signal.SIGINT, signal.SIG_IGN) try: nsfd = setns(netns, flags) except OSError as e: cmdch.send({'stage': 'init', 'error': e}) return e.errno except Exception as e: cmdch.send({'stage': 'init', 'error': OSError(errno.ECOMM, str(e), netns)}) return 255 Server(cmdch, brdch) os.close(nsfd)
def test_router_info(self): print("Test Router_Info") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) print("Get informations via ssh-commands ...") router_info = RouterInfo(router) router_info.start() router_info.join() print(str(router)) # Close Namespaces and VLANs nv_assist.close()
def _reboot_into_config(self, router: Router, q: Queue): print("Reboot Router into configmode ...") # Create NVAssistent nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # Reboot Router into configmode try: router_reboot = RouterReboot(router, configmode=True) router_reboot.start() router_reboot.join() except Exception as e: nv_assist.close() raise e assert router.mode == Mode.configuration nv_assist.close() q.put(router)
def test_there_and_back(self): require_user('root') fd = open('/proc/self/ns/net', 'r') foo = str(uuid4()) # # please notice, that IPRoute / IPDB, started in a netns, will continue # to work in a given netns even if the process changes to another netns # with IPRoute() as ip: links_main1 = set([x.get('index', None) for x in ip.get_links()]) netnsmod.setns(foo) with IPRoute() as ip: links_foo = set([x.get('index', None) for x in ip.get_links()]) netnsmod.setns(fd) with IPRoute() as ip: links_main2 = set([x.get('index', None) for x in ip.get_links()]) assert links_main1 == links_main2 assert links_main1 != links_foo netnsmod.remove(foo) fd.close()
def in_cgroup(): try: pid = os.getpid() cg = Cgroup(name) for env in env_vars: #log.info('Setting ENV %s' % env) os.putenv(*env.split('=', 1)) # Set network namespace netns.setns(netns_name) # add process to cgroup cg.add(pid) os.chroot(layer_dir) if working_dir != '': #log.info("Setting working directory to %s" % working_dir) os.chdir(working_dir) except Exception as e: traceback.print_exc()
def NSPopenServer(nsname, flags, channel_in, channel_out, argv, kwarg): # set netns try: setns(nsname, flags=flags) except Exception as e: channel_out.put(e) return # create the Popen object child = subprocess.Popen(*argv, **kwarg) # send the API map channel_out.put(None) while True: # synchronous mode # 1. get the command from the API try: call = channel_in.get() except: (et, ev, tb) = sys.exc_info() try: channel_out.put({'code': 500, 'data': ev}) except: pass break # 2. stop? if call['name'] == 'release': break # 3. run the call try: attr = getattr(child, call['name']) if isinstance(attr, types.MethodType): result = attr(*call['argv'], **call['kwarg']) else: result = attr channel_out.put({'code': 200, 'data': result}) except: (et, ev, tb) = sys.exc_info() channel_out.put({'code': 500, 'data': ev}) child.wait()
def __init__(self, netns, flags=os.O_CREAT): self.netns = netns self.flags = flags trnsp_in, self.remote_trnsp_out = [Transport(FD(x)) for x in os.pipe()] self.remote_trnsp_in, trnsp_out = [Transport(FD(x)) for x in os.pipe()] self.child = os.fork() if self.child == 0: # child process trnsp_in.close() trnsp_out.close() try: setns(self.netns, self.flags) except OSError as e: (self .remote_trnsp_out .send({'stage': 'init', 'error': e})) os._exit(e.errno) except Exception as e: (self. remote_trnsp_out .send({'stage': 'init', 'error': OSError(errno.ECOMM, str(e), self.netns)})) os._exit(255) try: Server(self.remote_trnsp_in, self.remote_trnsp_out) finally: os._exit(0) try: super(NetNS, self).__init__(trnsp_in, trnsp_out) except Exception: self.close() raise atexit.register(self.close) self.marshal = MarshalRtnl()
def test_router_online(self): print("Test if the Router is reachable") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) print("Send a Ping to the two static IP-addresses ...") router_online = RouterOnline(router) router_online.start() router_online.join() print("Router is online with IP " + router.ip + "/" + str(router.ip_mask)) self.assertEqual(router.mode, Mode.configuration, "The Configuration Mode is not correct") # Close Namespaces and VLANs nv_assist.close()
def in_cgroup(): try: pid = os.getpid() cg = Cgroup(name) for env in env_vars: log.info('Setting ENV %s' % env) os.putenv(*env.split('=', 1)) # Set network namespace netns.setns(netns_name) # add process to cgroup cg.add(pid) os.chroot(layer_dir) if working_dir != '': log.info("Setting working directory to %s" % working_dir) os.chdir(working_dir) except Exception as e: traceback.print_exc() log.error("Failed to preexecute function") log.error(e)
def __init__(self, netns, flags=os.O_CREAT): self.netns = netns self.flags = flags trnsp_in, self.remote_trnsp_out = [Transport(FD(x)) for x in os.pipe()] self.remote_trnsp_in, trnsp_out = [Transport(FD(x)) for x in os.pipe()] self.child = os.fork() if self.child == 0: # child process trnsp_in.close() trnsp_out.close() try: setns(self.netns, self.flags) except OSError as e: (self.remote_trnsp_out.send({'stage': 'init', 'error': e})) os._exit(e.errno) except Exception as e: (self.remote_trnsp_out.send({ 'stage': 'init', 'error': OSError(errno.ECOMM, str(e), self.netns) })) os._exit(255) try: Server(self.remote_trnsp_in, self.remote_trnsp_out) finally: os._exit(0) try: self.remote_trnsp_in.close() self.remote_trnsp_out.close() super(NetNS, self).__init__(trnsp_in, trnsp_out) except Exception: self.close() raise atexit.register(self.close) self.marshal = MarshalRtnl()
def single(self, ns): self.signal() netns.setns(ns) k = ns + '_' + self.check c = pycurl.Curl() c.setopt(pycurl.WRITEFUNCTION, lambda x: None) c.setopt(c.FOLLOWLOCATION, 1) c.setopt(c.MAXREDIRS, 5) c.setopt(c.OPT_FILETIME, 1) c.setopt(pycurl.CONNECTTIMEOUT, 15) c.setopt(pycurl.TIMEOUT, 30) c.setopt(pycurl.NOSIGNAL, 1) while True: self.results[k] = { 'check': self.check, 'type': self.type, 'ns': ns, 'state': 'RUN' } res = self.results[k] try: c.setopt(c.URL, self.host) c.perform() res['code'] = c.getinfo(c.HTTP_CODE) res['time'] = c.getinfo(c.TOTAL_TIME) res['speed'] = c.getinfo(c.SPEED_DOWNLOAD) res['size'] = c.getinfo(c.SIZE_DOWNLOAD) res['state'] = 'OK' logging.info("[HTTP:%s] host = %s, return code = %d, total time = %.2f sec, download speed = %.2f b/sec, download size = %d Kb" % (ns, self.host, c.getinfo(c.HTTP_CODE), c.getinfo(c.TOTAL_TIME), c.getinfo(c.SPEED_DOWNLOAD), c.getinfo(c.SIZE_DOWNLOAD) / 1024)) except: res['state'] = 'FAIL' logging.info("[HTTP:%s] Cannot get %s" % (ns, self.host)) self.results[k] = res time.sleep(float(self.delay))
def test_there_and_back(self): require_user('root') # wait until the previous test's side effects are gone time.sleep(2) # fd = open('/proc/self/ns/net', 'r') foo = str(uuid4()) # # please notice, that IPRoute / IPDB, started in a netns, will continue # to work in a given netns even if the process changes to another netns # with IPRoute() as ip: links_main1 = set([x.get('index', None) for x in ip.get_links()]) netnsmod.setns(foo) with IPRoute() as ip: links_foo = set([x.get('index', None) for x in ip.get_links()]) netnsmod.setns(fd) with IPRoute() as ip: links_main2 = set([x.get('index', None) for x in ip.get_links()]) assert links_main1 == links_main2 assert links_main1 != links_foo netnsmod.remove(foo) fd.close()
def __updatePvd(self, phyIfaceName, pvdInfo): pvd = self.pvds.get((phyIfaceName, pvdInfo.pvdId)) if (pvd): if (pvd.pvdInfo == pvdInfo): # if PvD parameters did not change, just update the timestamp in the PvD manager's log pvd.updateTimestamp() LOG.info('PvD {0} received through {1} UNCHANGED, timestamp UPDATED, type {2}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.pvdInfo.pvdType)) else: # if any of the PvD parameters has changed, reconfigure the PvD netns.setns(pvd.netnsName) ip = IPRoute() # return to a default network namespace to not cause a colision with other modules # ip handle continues to work in the target network namespace netns.setns(self.__NETNS_DEFAULT_NAME) self.__configureNetwork(pvd.pvdIfaceName, pvdInfo, ip) self.__configureDns(pvdInfo, pvd.netnsName) # update the PvD record in the PvD manager's log pvd.pvdInfo = pvdInfo pvd.updateTimestamp() LOG.info('PvD {0} received through {1} RECONFIGURED in network namespace {2} on macvlan {3}, type {4}'.format(pvd.pvdId, pvd.phyIfaceName, pvd.netnsName, pvd.pvdIfaceName, pvd.pvdInfo.pvdType)) self.pvdserver.stateChanged ("updated", pvdInfo.pvdId) else: raise Exception('There is no PvD {0} configured on {1}'.format(pvdInfo.pvdId, phyIfaceName))
def in_namespace(namespace): """Move current process in a specific namespace. This contextmanager moves current process in a specific namespace and ensures to move it back in original namespace or kills it if we fail to move back in original namespace. """ if not namespace: yield return org_netns_fd = os.open(PROCESS_NETNS, os.O_RDONLY) pynetns.setns(namespace) try: yield finally: try: # NOTE(cby): this code is not executed only if we fail to # move in target namespace pynetns.setns(org_netns_fd) except Exception as e: msg = _('Failed to move back in original netns: %s') % e LOG.critical(msg) raise BackInNamespaceExit(msg)
def NetNServer(netns, rcvch, cmdch, flags=os.O_CREAT): ''' The netns server supposed to be started automatically by NetNS. It has two communication channels: one simplex to forward incoming netlink packets, `rcvch`, and other synchronous duplex to get commands and send back responses, `cmdch`. Channels should support standard socket API, should be compatible with poll/select and should be able to transparently pickle objects. NetNS uses `multiprocessing.Pipe` for this purpose, but it can be any other implementation with compatible API. The first parameter, `netns`, is a netns name. Depending on the `flags`, the netns can be created automatically. The `flags` semantics is exactly the same as for `open(2)` system call. ... The server workflow is simple. The startup sequence:: 1. Create or open a netns. 2. Start `IPRoute` instance. It will be used only on the low level, the `IPRoute` will not parse any packet. 3. Start poll/select loop on `cmdch` and `IPRoute`. On the startup, the server sends via `cmdch` the status packet. It can be `None` if all is OK, or some exception. Further data handling, depending on the channel, server side:: 1. `IPRoute`: read an incoming netlink packet and send it unmodified to the peer via `rcvch`. The peer, polling `rcvch`, can handle the packet on its side. 2. `cmdch`: read tuple (cmd, argv, kwarg). If the `cmd` starts with "send", then take `argv[0]` as a packet buffer, treat it as one netlink packet and substitute PID field (offset 12, uint32) with its own. Strictly speaking, it is not mandatory for modern netlink implementations, but it is required by the protocol standard. ''' try: nsfd = setns(netns, flags) except OSError as e: cmdch.send(e) return e.errno except Exception as e: cmdch.send(OSError(errno.ECOMM, str(e), netns)) return 255 # try: ipr = IPRoute() rcvch_lock = ipr._sproxy.lock ipr._s_channel = rcvch poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(cmdch, select.POLLIN | select.POLLPRI) except Exception as e: cmdch.send(e) return 255 # all is OK so far cmdch.send(None) # 8<------------------------------------------------------------- while True: events = poll.poll() for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with rcvch_lock: rcvch.send(ipr.recv(bufsize)) elif fd == cmdch.fileno(): try: cmdline = cmdch.recv() if cmdline is None: poll.unregister(ipr) poll.unregister(cmdch) ipr.close() os.close(nsfd) return (cmd, argv, kwarg) = cmdline if cmd[:4] == 'send': # Achtung # # It's a hack, but we just have to do it: one # must use actual pid in netlink messages # # FIXME: there can be several messages in one # call buffer; but right now we can ignore it msg = argv[0][:12] msg += struct.pack("I", os.getpid()) msg += argv[0][16:] argv = list(argv) argv[0] = msg cmdch.send(getattr(ipr, cmd)(*argv, **kwarg)) except Exception as e: e.tb = traceback.format_exc() cmdch.send(e)
def exec_ns(ns_name, cmd): netns.setns(ns_name) subprocess.Popen(cmd)
def main(argv): if (len(argv) != 2): print('Usage: python pvdtest_veth.py PVD_ID') print('PVD_ID := name of the interface that contains PvD-related network configuration') sys.exit() # Get user-entered PVD ID pvdId = sys.argv[1] # Create IPRoute object for manipulation with a default network namespace ipMain = IPRoute() # Create a PvD-related network namespace pvdNetnsName = getPvdNetnsName(pvdId); if (pvdNetnsName in netns.listnetns()): netns.remove(pvdNetnsName) netns.create(pvdNetnsName) # Create IPRoute object for manipulation with a PvD-related network namespace netns.setns(pvdNetnsName) ipPvd = IPRoute() # Activate loopback interface in a PvD-related network namespace loIndex = ipPvd.link_lookup(ifname='lo')[0] ipPvd.link_up(loIndex) # Get addresses from a PvD-related network interface pvdIfIndex = ipMain.link_lookup(ifname=getPvdIfName(pvdId))[0] pvdAddresses = ipMain.get_addr(index=pvdIfIndex) # Get current routes pvdRoutes = ipMain.get_routes() # Create bridge bridge = getPvdBridgeName(pvdId) ipMain.link_create(ifname=bridge, kind='bridge') # Create veth interface (veth0, veth1) = getPvdVethNames(pvdId) ipMain.link_create(ifname=veth0, kind='veth', peer=veth1) # Move one end of the veth interafce to a PvD-related network namespace veth1Index = ipMain.link_lookup(ifname=veth1)[0] ipMain.link('set', index=veth1Index, net_ns_fd=pvdNetnsName) # Shut down and remove addresses from the PvD interface before adding it to the bridge ipMain.link_down(pvdIfIndex) ipMain.flush_addr(pvdIfIndex) # Make a bridge between PvD interface and one end of veth interface veth0Index = ipMain.link_lookup(ifname=veth0)[0] bridgeIndex = ipMain.link_lookup(ifname=bridge)[0] ipMain.link('set', index=veth0Index, master=bridgeIndex) ipMain.link('set', index=pvdIfIndex, master=bridgeIndex) # Activate bridge and connected interfaces ipMain.link_up(pvdIfIndex) ipMain.link_up(veth0Index) ipMain.link_up(bridgeIndex) ipPvd.link_up(veth1Index) # Configure bridge and another end of the veth interface with PvD-related network parameters + add routes ipMain.flush_routes() ipPvd.flush_routes() for address in pvdAddresses: ipAddress = broadcastAddress = netmask = addrFamily = None for attr in address['attrs']: if attr[0] == 'IFA_ADDRESS': ipAddress = attr[1] if attr[0] == 'IFA_BROADCAST': broadcastAddress = attr[1] netmask = address['prefixlen'] addrFamily = address['family'] # Configure bridge try: ipMain.addr('add', index=bridgeIndex, family=addrFamily, address=ipAddress, broadcast=broadcastAddress, mask=netmask) except: pass # Configure veth try: ipPvd.addr('add', index=veth1Index, family=addrFamily, address=ipAddress, broadcast=broadcastAddress, mask=netmask) except: pass # Configure routes # Some routes are added during interface IP address/netmask configuration, skip them if already there ipNetwork = IPNetwork(ipAddress + '/' + str(netmask)) try: ipMain.route('add', dst=str(ipNetwork.network), mask=netmask, oif=bridgeIndex, src=ipAddress, rtproto='RTPROT_STATIC', rtscope='RT_SCOPE_LINK') except: pass try: ipPvd.route('add', dst=str(ipNetwork.network), mask=netmask, oif=veth1Index, src=ipAddress, rtproto='RTPROT_STATIC', rtscope='RT_SCOPE_LINK') except: pass # Fing gateway(s) and add default routes defGateways = [] for route in pvdRoutes: for attr in route['attrs']: if (attr[0] == 'RTA_GATEWAY' and attr[1] not in defGateways): defGateways.append(attr[1]) if (len(defGateways) > 0): ipMain.route('add', dst='0.0.0.0', oif=bridgeIndex, gateway=defGateways[0], rtproto='RTPROT_STATIC') ipPvd.route('add', dst='0.0.0.0', oif=veth1Index, gateway=defGateways[0], rtproto='RTPROT_STATIC')
def NetNServer(netns, rcvch, cmdch, flags=os.O_CREAT): ''' The netns server supposed to be started automatically by NetNS. It has two communication channels: one simplex to forward incoming netlink packets, `rcvch`, and other synchronous duplex to get commands and send back responses, `cmdch`. Channels should support standard socket API, should be compatible with poll/select and should be able to transparently pickle objects. NetNS uses `multiprocessing.Pipe` for this purpose, but it can be any other implementation with compatible API. The first parameter, `netns`, is a netns name. Depending on the `flags`, the netns can be created automatically. The `flags` semantics is exactly the same as for `open(2)` system call. ... The server workflow is simple. The startup sequence:: 1. Create or open a netns. 2. Start `IPRoute` instance. It will be used only on the low level, the `IPRoute` will not parse any packet. 3. Start poll/select loop on `cmdch` and `IPRoute`. On the startup, the server sends via `cmdch` the status packet. It can be `None` if all is OK, or some exception. Further data handling, depending on the channel, server side:: 1. `IPRoute`: read an incoming netlink packet and send it unmodified to the peer via `rcvch`. The peer, polling `rcvch`, can handle the packet on its side. 2. `cmdch`: read tuple (cmd, argv, kwarg). If the `cmd` starts with "send", then take `argv[0]` as a packet buffer, treat it as one netlink packet and substitute PID field (offset 12, uint32) with its own. Strictly speaking, it is not mandatory for modern netlink implementations, but it is required by the protocol standard. ''' signal.signal(signal.SIGINT, signal.SIG_IGN) try: nsfd = setns(netns, flags) except OSError as e: cmdch.send(e) return e.errno except Exception as e: cmdch.send(OSError(errno.ECOMM, str(e), netns)) return 255 # try: ipr = IPRoute() rcvch_lock = ipr._sproxy.lock ipr._s_channel = rcvch poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(cmdch, select.POLLIN | select.POLLPRI) except Exception as e: cmdch.send(e) return 255 # all is OK so far cmdch.send(None) # 8<------------------------------------------------------------- while True: events = poll.poll() for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with rcvch_lock: rcvch.send(ipr.recv(bufsize)) elif fd == cmdch.fileno(): try: cmdline = cmdch.recv() if cmdline is None: poll.unregister(ipr) poll.unregister(cmdch) ipr.close() os.close(nsfd) return (cmd, argv, kwarg) = cmdline if cmd[:4] == 'send': # Achtung # # It's a hack, but we just have to do it: one # must use actual pid in netlink messages # # FIXME: there can be several messages in one # call buffer; but right now we can ignore it msg = argv[0][:12] msg += struct.pack("I", os.getpid()) msg += argv[0][16:] argv = list(argv) argv[0] = msg cmdch.send(getattr(ipr, cmd)(*argv, **kwarg)) except Exception as e: e.tb = traceback.format_exc() cmdch.send(e)
def preexec(): cgroup.add(os.getpid()) netns.setns(netns_names.netns)
def Server(trnsp_in, trnsp_out, netns=None, target='localhost'): def stop_server(signum, frame): Server.run = False Server.run = True signal.signal(signal.SIGTERM, stop_server) try: if netns is not None: netnsmod.setns(netns) ipr = IPRoute(target=target) lock = ipr._sproxy.lock ipr._s_channel = ProxyChannel(trnsp_out, 'broadcast') except Exception as e: trnsp_out.send({'stage': 'init', 'error': e}) return 255 inputs = [ipr.fileno(), trnsp_in.fileno()] broadcasts = {ipr.fileno(): ipr} outputs = [] # all is OK so far trnsp_out.send({'stage': 'init', 'uname': config.uname, 'error': None}) # 8<------------------------------------------------------------- while Server.run: try: events, _, _ = select.select(inputs, outputs, inputs) except: continue for fd in events: if fd in broadcasts: sock = broadcasts[fd] bufsize = sock.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with lock: error = None data = None try: data = sock.recv(bufsize) except Exception as e: error = e error.tb = traceback.format_exc() trnsp_out.send({ 'stage': 'broadcast', 'data': data, 'error': error }) elif fd == trnsp_in.fileno(): cmd = trnsp_in.recv_cmd() if cmd['stage'] == 'shutdown': ipr.close() data = struct.pack('IHHQIQQ', 28, 2, 0, 0, 104, 0, 0) trnsp_out.send({ 'stage': 'broadcast', 'data': data, 'error': None }) return elif cmd['stage'] == 'reconstruct': error = None try: msg = cmd['argv'][0]() msg.load(pickle.loads(cmd['argv'][1])) ipr.sendto_gate(msg, cmd['argv'][2]) except Exception as e: error = e error.tb = traceback.format_exc() trnsp_out.send({ 'stage': 'reconstruct', 'error': error, 'return': None, 'cookie': cmd['cookie'] }) elif cmd['stage'] == 'command': error = None try: ret = getattr(ipr, cmd['name'])(*cmd['argv'], **cmd['kwarg']) if cmd['name'] == 'bind' and \ ipr._brd_socket is not None: inputs.append(ipr._brd_socket.fileno()) broadcasts[ipr._brd_socket.fileno()] = \ ipr._brd_socket except Exception as e: ret = None error = e error.tb = traceback.format_exc() trnsp_out.send({ 'stage': 'command', 'error': error, 'return': ret, 'cookie': cmd['cookie'] })