Simulating a ring network - python

I'm trying to simulate a token ring, but having some troubles so far. I modified the one the simpy examples to get this:
import random
import simpy
import math
SIM_TIME = 1000 # Simulation time in minutes
TOTAL_BYTES = 0
class Ring(object):
"""
Hosts have to request the token. When they get the token, they
can be served.
"""
def __init__(self, env):
self.env = env
self.token = simpy.Resource(env)
def serve(self, host):
global TOTAL_BYTES
bytes = random.randint(64, 1518)
TOTAL_BYTES += bytes
yield self.env.timeout(bytes / 10e8 * 60)
print("Ring served %s." % (host))
def host(env, name, ring):
"""The host process (each host has a ``name``) arrives at the ring
(``ring``) and waits for a token.
"""
print('%s enters the ring at %.2f.' % (name, env.now))
with ring.token.request() as request:
yield request
print('%s is handed a token at %.2f.' % (name, env.now))
yield env.process(ring.serve(name))
def setup(env, numberOfHosts, lmda):
"""Create a ring, a number of initial hosts."""
# Create the ring
ring = Ring(env)
# Create n hosts
for i in range(numberOfHosts):
env.process(host(env, 'Host %d' % i, ring))
# Create more packets for the hosts
while True:
yield env.timeout(nedTime(lmda))
print("A new process has arrived at %s" % (i))
# Return a random number (negativeExponentiallyDistributedTime)
def nedTime(rate):
u = random.random()
return (-1 / rate) * math.log(1 - u)
# Create an environment and start the setup process
env = simpy.Environment()
env.process(setup(env, numberOfHosts=10, lmda=0.01))
# Execute!
env.run(until=SIM_TIME)
My question is: how can I get it so that packets are always incoming to a host at all times while the simulation is running.
I've tried the while True in setup, but I don't think that's the correct place to put it.
Also, how can the host function hold a buffer of packets? I've tried converting the host() function to a Host class, but having compiling issues now.
Thank you.

Related

Simpy preempt interrupt isn't handled at very start of simulation

Currently picking up Simpy and trying to build a simulation which has a series of events to complete which need personnel, supplies, etc.
To emulate the personnel, I have a Container with the number of people and to handle the availability (like a shift pattern for when the people are able to work) I have a PreemptiveResource which events can grab when the shift is available but are all removed with a priority request at the end of a shift, leaving the events to wait.
All works well except for one circumstance when the priority request occurs at the start of the simulation (e.g. the simulation starts at midnight and first shift begins at 6am, so there's an immediate request to pull the shifts away from the events).
Here's the code:
import itertools
import random
import simpy
import simpy.util
import bisect
class PriorityFilterStore(simpy.FilterStore):
def _do_put(self, event):
if len(self.items) < self._capacity:
bisect.insort(self.items, event.item)
event.succeed()
def _do_get(self, event):
for i in range(len(self.items)):
item = self.items[i]
if event.filter(item):
del self.items[i]
event.succeed(item)
break
return True
RANDOM_SEED = 42
CONS_MAX = [100, 100, 100]
RESUPPLY_TIME = 24
def incident_1(name, env, schedule, manpool, manhours):
print('%s is created at %.1f' % (name, env.now))
done_in = manhours
while done_in > 0:
with schedule.request(priority=2) as req:
yield req
try:
mans = manpool.get(1)
yield mans
start = env.now
print('%s is being pre-planned starting at %.1f hours.' % (name, start))
yield env.timeout(done_in)
print('%s finished pre-planning at %.1f hours.' % (name, env.now))
manpool.put(1)
done_in = 0
except simpy.Interrupt:
done_in -= env.now - start
print('%s interrupted at %.1f, with %.1f hours left' % (name, env.now, done_in))
manpool.put(1)
def cons_control(env, cons_list):
"""Periodically check the level of the *fuel_pump* and call the tank
truck if the level falls below a threshold."""
while True:
resups = [0,0,0]
res_flag = False
for i in range(len(cons_list)):
if cons_list[i].capacity > cons_list[i].level:
# We need to call the tank truck now!
print('Calling resupply for cons %d at %d' % (i, env.now))
# Wait for the tank truck to arrive and refuel the station
res_flag = True
resups[i] = cons_list[i].capacity - cons_list[i].level
if res_flag:
yield env.process(resup_truck(env, cons_list, resups))
yield env.timeout(12)
def resup_truck(env, cons_list, resups):
"""Arrives at the gas station after a certain delay and refuels it."""
yield env.timeout(RESUPPLY_TIME)
print('Resupply arriving at time %d' % env.now)
for i in range(len(cons_list)):
if resups[i] > 0:
print('Resupplying cons %d with %d items.' % (i, resups[i]))
yield cons_list[i].put(resups[i])
def scheduler(env, shift_a, schedule_a):
#env.timeout(1)
env.process(shift_off(env, schedule_a, shift_a[0]))
simpy.util.start_delayed(env,shift_off(env, schedule_a, shift_a[2]-shift_a[1]),shift_a[1])
simpy.util.start_delayed(env,shift_off(env, schedule_a, 6), shift_a[3])
yield env.timeout(0)
def shift_off(env, this_schedule, time):
with this_schedule.request(priority=1) as req:
yield req
try:
print('Shift is stopping at %.1f until %.1f' % (env.now, env.now + time))
yield env.timeout(time)
print('Shift is starting at %.1f' % env.now)
except simpy.Interrupt:
print('Shift is somehow pulled back in play...')
def monitoring(env, time, man_a, man_b, man_c):
while True:
print('At time = %d: '% env.now)
print('%d of %d are allocated.' % (man_a.count, man_a.capacity))
print('%d of %d are allocated.' % (man_b.count, man_b.capacity))
print('%d of %d are allocated.' % (man_c.count, man_c.capacity))
yield env.timeout(0)
# Setup and start the simulation
print('Incident processing')
random.seed(RANDOM_SEED)
# Create environment and start processes
env = simpy.Environment()
schedule_a = simpy.PreemptiveResource(env, capacity=1)
man_a = simpy.Container(env, capacity=5, init=5)
shift_a = [6, 12, 13, 18]
man_b = simpy.Resource(env, capacity=1)
man_c = simpy.Resource(env, capacity=1)
cons_x = simpy.Container(env, CONS_MAX[0], init=CONS_MAX[0])
cons_y = simpy.Container(env, CONS_MAX[1], init=CONS_MAX[1])
cons_z = simpy.Container(env, CONS_MAX[2], init=CONS_MAX[2])
#env.process(monitoring(env,3,man_a,man_b,man_c))
env.process(scheduler(env,shift_a,schedule_a))
env.process(cons_control(env, [cons_x,cons_y,cons_z]))
env.process(incident_1('Incident 1', env, schedule_a, man_a, 24))
# Execute!
env.run(until=240)
If you comment out the line env.process(shift_off(env, schedule_a, shift_a[0])), then it works. Otherwise there is an "Exception Unhandled" error, which appears to happen within def shift_off at the line yield env.timeout(time)
Can anyone explain why this interrupt isn't being handled and how to correct this?
TIA
Edit 1:
I've got this working, but don't understand why.
Trying to follow some working examples, I managed to get the behaviour to work if I created a Scheduler object and had it initialise with the processes to stop/start the shifts (e.g. request the resource):
class Scheduler (object):
def __init__(self, env, this_shift, this_sched):
self.env = env
self.shift = this_shift
self.sched = this_sched
self.process = env.process(self.shift_off(env, self.sched, self.shift[0]))
def shift_off(self, env, this_schedule, time):
with this_schedule.request(priority=1) as req:
yield req
try:
print('Shift is stopping at %.1f until %.1f' % (env.now, env.now + time))
yield env.timeout(time)
print('Shift is starting at %.1f' % env.now)
except simpy.Interrupt:
print('Shift is somehow pulled back in play...')
I'm assuming this has something to do with removing the process from env to this object, but do not follow how or why this works.
Anyone explain the subtleties here?
Edit 2: This is still confusing me... Making further changes can still cause this error.
My current work-around is to create the activities to be worked on, then create the scheduler that blocks the shifts. The preemptive request goes in, kicks the activities out and it continues fine. If I init the scheduler before the activities then I get the interrupt error as before - but surely it's not interrupting anything if the resource is free and available at this point...

Simpy queue simulation

I'm trying to simulate a queue with limited buffer where no packet is dropped but kept in waiting . Bear with me since I'm just a student with basic coding skills.
The packet arrive exponentially distributed and each hold a packet size with mean 1250 bytes. I managed to get the code working for packet arrival + processing time but i couldn't make the packet 'depart' and also simulating the queue (so far, it is with unlimited buffer) Is there anything I could do to simulate the packet departure and the queue limit?
code:
import random
import simpy
RANDOM_SEED = 42
NEW_CUSTOMERS = 100 # Total number of customers
INTERVAL_CUSTOMERS = 1 # Generate new customers roughly every x seconds
SIZE = 1250
def source(env, number, interval, port):
"""Source generates packet randomly"""
for i in range(number):
size = int(random.expovariate(0.0008))
packet = Packet(env, '%d' % i, size, port, time_in_port=1)
env.process(packet)
t = random.expovariate(1 / interval)
yield env.timeout(t)
def Packet(env, id, size, port, time_in_port):
arrive = env.now
yield Queue.buffer.put(size)
print('packet%s %s arriving at %lf' % (id, size, arrive))
with port.request() as req:
yield req
tip = random.expovariate(1/time_in_port)
yield env.timeout(tip)
amount = size
yield Queue.buffer.get(amount)
print('packet%s %s finished processing at %lf' % (id, size, env.now))
class queue: #THIS PART WON'T WORK
def __init__(self, env):
self.port = simpy.Resource(env, capacity=1)
self.buffer = simpy.Container(env, init = 0, capacity=12500)
self.mon_proc = env.process(self.monitor_tank(env))
def monitor_tank(self, env):
while True:
if self.buffer.level > 12500:
print('Full at %d' % env.now)
random.seed(RANDOM_SEED)
env = simpy.Environment()
Queue = queue(env)
port = simpy.Resource(env, capacity=1)
env.process(source(env, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, port))
env.run()
The queue class didn't work (The program won't run at all). It will run if only I remove the queue class and simulate packet arrival and processing time. Would appreciate any help to make me simulate the packet departure(using a sink) and the queue limit. Thanks.
Not familiar with the details, but your call to self.monitor_tank(env) in the queue constructor is going to go into a tight infinite loop - it isn't a generator, just an unending loop, so python is going to get stuck at that point in the execution.
I think this code from your code is a infinite loop and is blocking your code from running
def monitor_tank(self, env):
while True:
if self.buffer.level > 12500:
print('Full at %d' % env.now)
Try commenting This piece out, or adding a env.timeout so it "sleeps" for a bit on every loop pass
Hello I think the code will solve your problem or at least give you a direction. As in your original code all the packages have the same size, I modelled in this packages, but to change to bytes is straight forward.
I used a buffer (container) and a server (resource).
;)
import simpy
import random
def arrival(env, buffer):
#Arrival of the Package
while True:
print('Package ARRIVED at %.1f \n\t Buffer: %i'
% (env.now, buffer.level))
yield buffer.put(1) # Put the package in the buffer
yield env.timeout(random.expovariate(1.0)) # time between arrivals
env.process(processDeparture(env, buffer, server))
def processDeparture(env, buffer, server):
#Processing and Departure of the Package
while True:
# request a Server to process thge package
request = server.request()
yield request
yield buffer.get(1) # GET a package from the buffer
# Processing time of the package
processingTime = 2
print('Package begin processing at %.1f'
% (env.now))
yield env.timeout(processingTime)
print('Package end processing at %.1f'
% (env.now))
# release the server
yield server.release(request)
random.seed(150)
env = simpy.Environment()
buffer = simpy.Container(env, capacity=3, init=0) # Create the Buffer
server = simpy.Resource(env, capacity=1) # Create the servers (resources)
env.process(arrival(env, buffer))
env.run(until=30) # Execute the Model

Access a variable that has been created in a different class. Python

I am not familiar with python classes. I need to pass the variable servicetime (which is located in the class simulation, under the function service) to the function customer and more specifically to the line which says priority=servicetime. Of course both servicetime's have to be equal and also equal to the specific instance of the class. How can this be done?
import simpy
import numpy as np
import random
import itertools
global meanqtime # average queue time
global meanstime # average server time
meanqtime=[]
meanstime=[]
class simulation(object):
"""
"""
def __init__(self,env,num_machines,servicerate):
self.env=env
self.machine=simpy.PriorityResource(env,num_machines)
self.servicerate=servicerate
def service (self,customer):
servicetime=random.expovariate(servicerate) #this
yield self.env.timeout(servicetime)
def customer(env, name, server):
"""The customer process arrives at the server
and requests to be serviced
"""
artime=env.now
#print('%s arrives at the desk at %.2f.' % (name, env.now))
with server.machine.request(priority=servicetime) as request: #to be here
yield request
#print('%s starts servicing at %.2f.' % (name, env.now))
qtime=env.now
meanqtime.append(qtime-artime)
yield env.process(server.service(name))
#print('%s leaves the desk at %.2f.' % (name, env.now))
stime=env.now
meanstime.append(stime-artime)
def setup(env, num_servers, servicerate, arrivalrate):
desk = simulation(env, num_servers, servicerate)
while True:
for i in itertools.count():
#t=np.random.poisson(arrivalrate)
t=random.expovariate(arrivalrate)
yield env.timeout(t)
env.process(customer(env, 'Person %d' % i, desk))
#yield env.timeout(t)
num_servers = 1 #number of servers
arrivalrate=0.1 #per hour
servicerate=0.125#hours
T=100
env = simpy.Environment()
env.process(setup(env, num_servers, servicerate, arrivalrate))
# Execute!
env.run(until=T)

How to count size or number of tweets?

I'm using this wonderful resource to grab tweets from twitter.
Twitter streams the tweets, and this script grabs them and displays them in the terminal.
I apologize for the beginners question, but how would I limit the number of tweets or the total size of all tweets that are received using this script?
I understand that I can write these to a file and watch the size of the file, but is there a way to do count the bytes received or number of tweets received?
The script is below as well as in the link above.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (C) 2012 Gustav ArngÄrden
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
import pycurl
import urllib
import json
import oauth2 as oauth
API_ENDPOINT_URL = 'https://stream.twitter.com/1.1/statuses/filter.json'
USER_AGENT = 'TwitterStream 1.0' # This can be anything really
# You need to replace these with your own values
OAUTH_KEYS = {'consumer_key': <Consumer key>,
'consumer_secret': <Consumer secret>,
'access_token_key': <Token key>,
'access_token_secret': <Token secret>}
# These values are posted when setting up the connection
POST_PARAMS = {'include_entities': 0,
'stall_warning': 'true',
'track': 'iphone,ipad,ipod'}
class TwitterStream:
def __init__(self, timeout=False):
self.oauth_token = oauth.Token(key=OAUTH_KEYS['access_token_key'], secret=OAUTH_KEYS['access_token_secret'])
self.oauth_consumer = oauth.Consumer(key=OAUTH_KEYS['consumer_key'], secret=OAUTH_KEYS['consumer_secret'])
self.conn = None
self.buffer = ''
self.timeout = timeout
self.setup_connection()
def setup_connection(self):
""" Create persistant HTTP connection to Streaming API endpoint using cURL.
"""
if self.conn:
self.conn.close()
self.buffer = ''
self.conn = pycurl.Curl()
# Restart connection if less than 1 byte/s is received during "timeout" seconds
if isinstance(self.timeout, int):
self.conn.setopt(pycurl.LOW_SPEED_LIMIT, 1)
self.conn.setopt(pycurl.LOW_SPEED_TIME, self.timeout)
self.conn.setopt(pycurl.URL, API_ENDPOINT_URL)
self.conn.setopt(pycurl.USERAGENT, USER_AGENT)
# Using gzip is optional but saves us bandwidth.
self.conn.setopt(pycurl.ENCODING, 'deflate, gzip')
self.conn.setopt(pycurl.POST, 1)
self.conn.setopt(pycurl.POSTFIELDS, urllib.urlencode(POST_PARAMS))
self.conn.setopt(pycurl.HTTPHEADER, ['Host: stream.twitter.com',
'Authorization: %s' % self.get_oauth_header()])
# self.handle_tweet is the method that are called when new tweets arrive
self.conn.setopt(pycurl.WRITEFUNCTION, self.handle_tweet)
def get_oauth_header(self):
""" Create and return OAuth header.
"""
params = {'oauth_version': '1.0',
'oauth_nonce': oauth.generate_nonce(),
'oauth_timestamp': int(time.time())}
req = oauth.Request(method='POST', parameters=params, url='%s?%s' % (API_ENDPOINT_URL,
urllib.urlencode(POST_PARAMS)))
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), self.oauth_consumer, self.oauth_token)
return req.to_header()['Authorization'].encode('utf-8')
def start(self):
""" Start listening to Streaming endpoint.
Handle exceptions according to Twitter's recommendations.
"""
backoff_network_error = 0.25
backoff_http_error = 5
backoff_rate_limit = 60
while True:
self.setup_connection()
try:
self.conn.perform()
except:
# Network error, use linear back off up to 16 seconds
print 'Network error: %s' % self.conn.errstr()
print 'Waiting %s seconds before trying again' % backoff_network_error
time.sleep(backoff_network_error)
backoff_network_error = min(backoff_network_error + 1, 16)
continue
# HTTP Error
sc = self.conn.getinfo(pycurl.HTTP_CODE)
if sc == 420:
# Rate limit, use exponential back off starting with 1 minute and double each attempt
print 'Rate limit, waiting %s seconds' % backoff_rate_limit
time.sleep(backoff_rate_limit)
backoff_rate_limit *= 2
else:
# HTTP error, use exponential back off up to 320 seconds
print 'HTTP error %s, %s' % (sc, self.conn.errstr())
print 'Waiting %s seconds' % backoff_http_error
time.sleep(backoff_http_error)
backoff_http_error = min(backoff_http_error * 2, 320)
def handle_tweet(self, data):
""" This method is called when data is received through Streaming endpoint.
"""
self.buffer += data
if data.endswith('\r\n') and self.buffer.strip():
# complete message received
message = json.loads(self.buffer)
self.buffer = ''
msg = ''
if message.get('limit'):
print 'Rate limiting caused us to miss %s tweets' % (message['limit'].get('track'))
elif message.get('disconnect'):
raise Exception('Got disconnect: %s' % message['disconnect'].get('reason'))
elif message.get('warning'):
print 'Got warning: %s' % message['warning'].get('message')
else:
print 'Got tweet with text: %s' % message.get('text')
if __name__ == '__main__':
ts = TwitterStream()
ts.setup_connection()
ts.start()
Why not a counter in your __init__:
def __init__(self, timeout=False):
...
self.tweetsSoFar = 0
def handleTweet(self, data):
...
else:
self.tweetsSoFar += 1 # we've seen another tweet!
print 'Got tweet with text: %s' % message.get('text')
def start(self):
...
while self.tweetsSoFar < 50: # stop at 50 tweets
...
Hope this helps
I'm not too familiar with the API, but assuming each complete message represents a tweet, then what you can do is to first add a counter in the class:
self.tweets = 0
Then increment it in handle_tweet after a full message is received:
if data.endswith('\r\n') and self.buffer.strip():
# complete message received
message = json.loads(self.buffer)
...
...
else:
print 'Got tweet with text: %s' % message.get('text')
self.tweets += 1
if self.tweets == SOME_LIMIT:
self.conn.close() # or exit()

Alternative to tuntap

I'm trying to transmit TCP/IP over a radio that is connected to my computer (specifically, the USRP). Right now, it's done very simply using Tun/Tap to set up a new network interface. Here's the code:
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
(Anyone familiar with GNU Radio will recognize this as tunnel.py)
My question is, is there a better way to move packets to and from the kernel than tun/tap? I've been looking at ipip or maybe using sockets, but I'm pretty sure those won't be very fast. Speed is what I'm most concerned with.
Remember that tunnel.py is a really, really rough example, and hasn't been updated in a while. It's not really meant to be a basis for other code, so be careful of how much you rely on the code.
Also, remember that TCP over unreliable radio links has significant issues:
http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_over_wireless_networks

Categories