2012-07-12 15 views
3

我試圖通過連接到我的電腦(特別是USRP)的無線電傳輸TCP/IP。現在,使用Tun/Tap來設置新的網絡接口非常簡單。下面的代碼:替代tuntap

from gnuradio import gr, gru, modulation_utils 
from gnuradio import usrp 
from gnuradio import eng_notation 
from gnuradio.eng_option import eng_option 
from optparse import OptionParser 

import random 
import time 
import struct 
import sys 
import os 

# from current dir 
from transmit_path import transmit_path 
from receive_path import receive_path 
import fusb_options 

#print os.getpid() 
#raw_input('Attach and press enter') 

# Linux specific... 
# TUNSETIFF ifr flags from <linux/tun_if.h> 

IFF_TUN  = 0x0001 # tunnel IP packets 
IFF_TAP  = 0x0002 # tunnel ethernet frames 
IFF_NO_PI = 0x1000 # don't pass extra packet info 
IFF_ONE_QUEUE = 0x2000 # beats me ;) 

def open_tun_interface(tun_device_filename): 
    from fcntl import ioctl 

    mode = IFF_TAP | IFF_NO_PI 
    TUNSETIFF = 0x400454ca 

    tun = os.open(tun_device_filename, os.O_RDWR) 
    ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode)) 
    ifname = ifs[:16].strip("\x00") 
    return (tun, ifname) 


# ///////////////////////////////////////////////////////////////////////////// 
#        the flow graph 
# ///////////////////////////////////////////////////////////////////////////// 

class my_top_block(gr.top_block): 

    def __init__(self, mod_class, demod_class, 
       rx_callback, options): 

     gr.top_block.__init__(self) 
     self.txpath = transmit_path(mod_class, options) 
     self.rxpath = receive_path(demod_class, rx_callback, options) 
    self.connect(self.txpath); 
    self.connect(self.rxpath); 

    def send_pkt(self, payload='', eof=False): 
     return self.txpath.send_pkt(payload, eof) 

    def carrier_sensed(self): 
     """ 
     Return True if the receive path thinks there's carrier 
     """ 
     return self.rxpath.carrier_sensed() 


# ///////////////////////////////////////////////////////////////////////////// 
#       Carrier Sense MAC 
# ///////////////////////////////////////////////////////////////////////////// 

class cs_mac(object): 
    """ 
    Prototype carrier sense MAC 

    Reads packets from the TUN/TAP interface, and sends them to the PHY. 
    Receives packets from the PHY via phy_rx_callback, and sends them 
    into the TUN/TAP interface. 

    Of course, we're not restricted to getting packets via TUN/TAP, this 
    is just an example. 
    """ 
    def __init__(self, tun_fd, verbose=False): 
     self.tun_fd = tun_fd  # file descriptor for TUN/TAP interface 
     self.verbose = verbose 
     self.tb = None    # top block (access to PHY) 

    def set_top_block(self, tb): 
     self.tb = tb 

    def phy_rx_callback(self, ok, payload): 
     """ 
     Invoked by thread associated with PHY to pass received packet up. 

     @param ok: bool indicating whether payload CRC was OK 
     @param payload: contents of the packet (string) 
     """ 
     if self.verbose: 
      print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload)) 
     if ok: 
      os.write(self.tun_fd, payload) 

    def main_loop(self): 
     """ 
     Main loop for MAC. 
     Only returns if we get an error reading from TUN. 

     FIXME: may want to check for EINTR and EAGAIN and reissue read 
     """ 
     min_delay = 0.001    # seconds 

     while 1: 
      payload = os.read(self.tun_fd, 10*1024) 
      if not payload: 
       self.tb.send_pkt(eof=True) 
       break 

      if self.verbose: 
       print "Tx: len(payload) = %4d" % (len(payload),) 

      delay = min_delay 
      while self.tb.carrier_sensed(): 
       sys.stderr.write('B') 
       time.sleep(delay) 
       if delay < 0.050: 
        delay = delay * 2  # exponential back-off 

      self.tb.send_pkt(payload) 


# ///////////////////////////////////////////////////////////////////////////// 
#         main 
# ///////////////////////////////////////////////////////////////////////////// 

def main(): 

    mods = modulation_utils.type_1_mods() 
    demods = modulation_utils.type_1_demods() 

    parser = OptionParser (option_class=eng_option, conflict_handler="resolve") 
    expert_grp = parser.add_option_group("Expert") 

    parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), 
         default='gmsk', 
         help="Select modulation from: %s [default=%%default]" 
          % (', '.join(mods.keys()),)) 

    parser.add_option("-v","--verbose", action="store_true", default=False) 
    expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30, 
          help="set carrier detect threshold (dB) [default=%default]") 
    expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun", 
          help="path to tun device file [default=%default]") 

    transmit_path.add_options(parser, expert_grp) 
    receive_path.add_options(parser, expert_grp) 

    for mod in mods.values(): 
     mod.add_options(expert_grp) 

    for demod in demods.values(): 
     demod.add_options(expert_grp) 

    fusb_options.add_options(expert_grp) 

    (options, args) = parser.parse_args() 
    if len(args) != 0: 
     parser.print_help(sys.stderr) 
     sys.exit(1) 

    if options.rx_freq is None or options.tx_freq is None: 
     sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") 
     parser.print_help(sys.stderr) 
     sys.exit(1) 

    # open the TUN/TAP interface 
    (tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename) 

    # Attempt to enable realtime scheduling 
    r = gr.enable_realtime_scheduling() 
    if r == gr.RT_OK: 
     realtime = True 
    else: 
     realtime = False 
     print "Note: failed to enable realtime scheduling" 


    # If the user hasn't set the fusb_* parameters on the command line, 
    # pick some values that will reduce latency. 

    if options.fusb_block_size == 0 and options.fusb_nblocks == 0: 
     if realtime:      # be more aggressive 
      options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024) 
      options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16) 
     else: 
      options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096) 
      options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16) 

    #print "fusb_block_size =", options.fusb_block_size 
    #print "fusb_nblocks =", options.fusb_nblocks 

    # instantiate the MAC 
    mac = cs_mac(tun_fd, verbose=True) 


    # build the graph (PHY) 
    tb = my_top_block(mods[options.modulation], 
         demods[options.modulation], 
         mac.phy_rx_callback, 
         options) 

    mac.set_top_block(tb) # give the MAC a handle for the PHY 

    if tb.txpath.bitrate() != tb.rxpath.bitrate(): 
     print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % (
      eng_notation.num_to_str(tb.txpath.bitrate()), 
      eng_notation.num_to_str(tb.rxpath.bitrate())) 

    print "modulation:  %s" % (options.modulation,) 
    print "freq:   %s"  % (eng_notation.num_to_str(options.tx_freq)) 
    print "bitrate:  %sb/sec" % (eng_notation.num_to_str(tb.txpath.bitrate()),) 
    print "samples/symbol: %3d" % (tb.txpath.samples_per_symbol(),) 
    #print "interp:   %3d" % (tb.txpath.interp(),) 
    #print "decim:   %3d" % (tb.rxpath.decim(),) 

    tb.rxpath.set_carrier_threshold(options.carrier_threshold) 
    print "Carrier sense threshold:", options.carrier_threshold, "dB" 

    print 
    print "Allocated virtual ethernet interface: %s" % (tun_ifname,) 
    print "You must now use ifconfig to set its IP address. E.g.," 
    print 
    print " $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,) 
    print 
    print "Be sure to use a different address in the same subnet for each machine." 
    print 


    tb.start() # Start executing the flow graph (runs in separate threads) 

    mac.main_loop() # don't expect this to return... 

    tb.stop()  # but if it does, tell flow graph to stop. 
    tb.wait()  # wait for it to finish 


if __name__ == '__main__': 
    try: 
     main() 
    except KeyboardInterrupt: 
     pass 

(任何熟悉GNU電臺就知道這是tunnel.py) 我的問題是,有沒有數據包移入和移出內核比TUN/TAP更好的辦法?我一直在看ipip或者使用套接字,但我很確定那些速度不會很快。速度是我最關心的。

+1

更多的研究後,我想我已經確定TUN/TAP是最好的一段路要走,但我仍然不知道如果它在該代碼中以最佳方式實施。 – blueintegral 2012-07-12 19:04:06

回答