def off(self, target, component): # Kill tcpdump, if it was started pidfile = os.path.join(target.state_dir, "tcpdump.pid") commonl.process_terminate(pidfile, tag="tcpdump", path="/usr/sbin/tcpdump") # remove the top level device mode = self._get_mode(target) if mode == 'physical': # bring down the lower device ifname = commonl.if_find_by_mac(target.tags['mac_addr']) subprocess.check_call( # flush the IP addresses, bring it down "/usr/sbin/ip add flush dev %s; " "/usr/sbin/ip link set dev %s down promisc off" % (ifname, ifname), shell=True) elif mode == 'vlan': commonl.if_remove_maybe("b%(id)s" % target.kws) # nothing; we killed the upper and on the lwoer, a # physical device we do nothing, as others might be using it pass elif mode == 'virtual': commonl.if_remove_maybe("b%(id)s" % target.kws) # remove the lower we created commonl.if_remove_maybe("_b%(id)s" % target.kws) else: raise AssertionError("Unknown mode %s" % mode) target.fsdb.set('power_state', 'off')
def _if_rename(target): if 'mac_addr' in target.tags: # We do have a physical device, so we are going to first, # rename it to match the IC's name (so it allows targets # to find it to run IP commands to attach to it) ifname = commonl.if_find_by_mac(target.tags['mac_addr']) if ifname == None: raise ValueError("Cannot find network interface with MAC '%s'" % target.tags['mac_addr']) if ifname != target.id: subprocess.check_call("ip link set %s down" % ifname, shell = True) subprocess.check_call("ip link set %s name b%s" % (ifname, target.id), shell = True)
def on(self, target, _component): # Bring up the lower network interface; lower is called # whatever (if it is a physical device) or _bNAME; bring it # up, make it promiscuous mode = self._get_mode(target) if mode == 'vlan': # our lower is a physical device, our upper is a device # which till tag for eth vlan %(vlan) ifname = commonl.if_find_by_mac(target.tags['mac_addr'], physical=True) commonl.if_remove_maybe("b%(id)s" % target.kws) kws = dict(target.kws) kws['ifname'] = ifname subprocess.check_call( "/usr/sbin/ip link add" " link %(ifname)s name b%(id)s" " type vlan id %(vlan)s" #" protocol VLAN_PROTO" #" reorder_hdr on|off" #" gvrp on|off mvrp on|off loose_binding on|off" % kws, shell=True) subprocess.check_call( # bring lower up "/usr/sbin/ip link set dev %s up promisc on" % ifname, shell=True) elif mode == 'physical': ifname = commonl.if_find_by_mac(target.tags['mac_addr']) subprocess.check_call( # bring lower up "/usr/sbin/ip link set dev %s up promisc on" % ifname, shell=True) self._if_rename(target) elif mode == 'virtual': # We do not have a physical device, a bridge, to serve as # lower commonl.if_remove_maybe("_b%(id)s" % target.kws) subprocess.check_call("/usr/sbin/ip link add" " name _b%(id)s" " type bridge" % target.kws, shell=True) subprocess.check_call("/usr/sbin/ip link add" " link _b%(id)s name b%(id)s" " type macvlan mode bridge; " % target.kws, shell=True) subprocess.check_call( # bring lower up "/usr/sbin/ip link set" " dev _b%(id)s" " up promisc on" % target.kws, shell=True) else: raise AssertionError("Unknown mode %s" % mode) # Configure the IP addresses for the top interface subprocess.check_call( # clean up existing address "/usr/sbin/ip add flush dev b%(id)s " % target.kws, shell=True) subprocess.check_call( # add IPv6 # if this fails, check Network Manager hasn't disabled ipv6 # sysctl -a | grep disable_ipv6 must show all to 0 "/usr/sbin/ip addr add" " %(ipv6_addr)s/%(ipv6_prefix_len)s dev b%(id)s " % target.kws, shell=True) subprocess.check_call( # add IPv4 "/usr/sbin/ip addr add" " %(ipv4_addr)s/%(ipv4_prefix_len)d" " dev b%(id)s" % target.kws, shell=True) # Bring up the top interface, which sets up ther outing subprocess.check_call( "/usr/sbin/ip link set dev b%(id)s up promisc on" % target.kws, shell=True) target.fsdb.set('power_state', 'on') # Start tcpdump on the network? # # The value of the tcpdump property, if not None, is the # filename we'll capture to. tcpdump = target.fsdb.get('tcpdump') if tcpdump: assert not os.path.sep in tcpdump \ and tcpdump != "" \ and tcpdump != os.path.pardir \ and tcpdump != os.path.curdir, \ "Bad filename for TCP dump capture '%s' specified as " \ " value to property *tcpdump*: must not include" % tcpdump # per ttbd:make_ticket(), colon splits the real username # from the ticket owner = target.owner_get().split(":")[0] assert owner, "BUG? target not owned on power on?" capfile = os.path.join(target.files_path, owner, tcpdump) # Because it is in the user's area, # we assume the user knows what he is doing to overwrite it, # so we'll remove any first commonl.rm_f(capfile) pidfile = os.path.join(target.state_dir, "tcpdump.pid") logfile = os.path.join(target.state_dir, "tcpdump.log") cmdline = [ "/usr/sbin/tcpdump", "-U", "-i", "_b%(id)s" % target.kws, "-w", capfile ] try: logf = open(logfile, "a") target.log.info("Starting tcpdump with: %s", " ".join(cmdline)) p = subprocess.Popen(cmdline, shell=False, cwd=target.state_dir, close_fds=True, stdout=logf, stderr=subprocess.STDOUT) except OSError as e: raise RuntimeError("tcpdump failed to start: %s" % e) ttbl.daemon_pid_add(p.pid) # FIXME: race condition if it died? with open(pidfile, "w") as pidfilef: pidfilef.write("%d" % p.pid) pid = commonl.process_started( # Verify it started pidfile, "/usr/sbin/tcpdump", verification_f=os.path.exists, verification_f_args=(capfile, ), timeout=20, tag="tcpdump", log=target.log) if pid == None: raise RuntimeError("tcpdump failed to start after 5s")