Append 3 more punt path protection TCs
[integration/test.git] / tools / fastbgp / play.py
index dfc4f0ef98af5b17ecd6520a326f68885d9131a0..d04e2e75e7687127198bd4b07b656f5f846f9fed 100755 (executable)
@@ -11,17 +11,19 @@ EXABGP in this type of scenario."""
 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
 # and is available at http://www.eclipse.org/legal/epl-v10.html
 
+from copy import deepcopy
+from SimpleXMLRPCServer import SimpleXMLRPCServer
 import argparse
 import binascii
 import ipaddr
+import logging
+import Queue
 import select
 import socket
-import time
-import logging
 import struct
-
 import thread
-from copy import deepcopy
+import threading
+import time
 
 
 __author__ = "Vratko Polak"
@@ -30,6 +32,25 @@ __license__ = "Eclipse Public License v1.0"
 __email__ = "vrpolak@cisco.com"
 
 
+class SafeDict(dict):
+    '''Thread safe dictionary
+
+    The object will serve as thread safe data storage.
+    It should be used with "with" statement.
+    '''
+
+    def __init__(self, * p_arg, ** n_arg):
+        super(SafeDict, self).__init__()
+        self._lock = threading.Lock()
+
+    def __enter__(self):
+        self._lock.acquire()
+        return self
+
+    def __exit__(self, type, value, traceback):
+        self._lock.release()
+
+
 def parse_arguments():
     """Use argparse to get arguments,
 
@@ -44,6 +65,8 @@ def parse_arguments():
     # we should mirror AS number from peer's open message.
     str_help = "Amount of IP prefixes to generate. (negative means ""infinite"")."
     parser.add_argument("--amount", default="1", type=int, help=str_help)
+    str_help = "Rpc server port."
+    parser.add_argument("--port", default="8000", type=int, help=str_help)
     str_help = "Maximum number of IP prefixes to be announced in one iteration"
     parser.add_argument("--insert", default="1", type=int, help=str_help)
     str_help = "Maximum number of IP prefixes to be withdrawn in one iteration"
@@ -105,6 +128,8 @@ def parse_arguments():
     parser.add_argument("--threshold", default="1000", type=int, help=str_help)
     str_help = "RFC 4760 Multiprotocol Extensions for BGP-4 supported"
     parser.add_argument("--rfc4760", default=True, type=bool, help=str_help)
+    str_help = "Using peerip instead of myip for xmlrpc server"
+    parser.add_argument("--usepeerip", default=False, action="store_true", help=str_help)
     str_help = "Link-State NLRI supported"
     parser.add_argument("--bgpls", default=False, type=bool, help=str_help)
     str_help = "Link-State NLRI: Identifier"
@@ -131,6 +156,34 @@ def parse_arguments():
     parser.add_argument("-lsteaddrstep", default="1", type=int, help=str_help)
     str_help = "How many play utilities are to be started."
     parser.add_argument("--multiplicity", default="1", type=int, help=str_help)
+    str_help = "Open message includes multiprotocol extension capability l2vpn-evpn.\
+    Enabling this flag makes the script not decoding the update mesage, because of not\
+    supported decoding for these elements."
+    parser.add_argument("--evpn", default=False, action="store_true", help=str_help)
+    str_help = "Open message includes Multicast in MPLS/BGP IP VPNs arguments.\
+    Enabling this flag makes the script not decoding the update mesage, because of not\
+    supported decoding for these elements."
+    parser.add_argument("--grace", default="8", type=int, help=str_help)
+    str_help = "Open message includes Graceful-restart capability, containing AFI/SAFIS:\
+    IPV4-Unicast, IPV6-Unicast, BGP-LS\
+    Enabling this flag makes the script not decoding the update mesage, because of not\
+    supported decoding for these elements."
+    parser.add_argument("--mvpn", default=False, action="store_true", help=str_help)
+    str_help = "Open message includes L3VPN-MULTICAST arguments.\
+    Enabling this flag makes the script not decoding the update mesage, because of not\
+    supported decoding for these elements."
+    parser.add_argument("--l3vpn_mcast", default=False, action="store_true", help=str_help)
+    str_help = "Open message includes L3VPN-UNICAST arguments, without message decoding."
+    parser.add_argument("--l3vpn", default=False, action="store_true", help=str_help)
+    str_help = "Open message includes ROUTE-TARGET-CONSTRAIN arguments, without message decoding."
+    parser.add_argument("--rt_constrain", default=False, action="store_true", help=str_help)
+    str_help = "Open message includes ipv6-unicast family, without message decoding."
+    parser.add_argument("--ipv6", default=False, action="store_true", help=str_help)
+    str_help = "Add all supported families without message decoding."
+    parser.add_argument("--allf", default=False, action="store_true", help=str_help)
+    parser.add_argument("--wfr", default=10, type=int, help="Wait for read timeout")
+    str_help = "Skipping well known attributes for update message"
+    parser.add_argument("--skipattr", default=False, action="store_true", help=str_help)
     arguments = parser.parse_args()
     if arguments.multiplicity < 1:
         print "Multiplicity", arguments.multiplicity, "is not positive."
@@ -143,7 +196,7 @@ def establish_connection(arguments):
     """Establish connection to BGP peer.
 
     Arguments:
-        :arguments: following command-line argumets are used
+        :arguments: following command-line arguments are used
             - arguments.myip: local IP address
             - arguments.myport: local port
             - arguments.peerip: remote IP address
@@ -292,13 +345,14 @@ class MessageGenerator(object):
                 options for MesageGenerator initialisation
         Notes:
             Calculates and stores default values used later on for
-            message geeration.
+            message generation.
         """
         self.total_prefix_amount = args.amount
         # Number of update messages left to be sent.
         self.remaining_prefixes = self.total_prefix_amount
 
         # New parameters initialisation
+        self.port = args.port
         self.iteration = 0
         self.prefix_base_default = args.firstprefix
         self.prefix_length_default = args.prefixlen
@@ -326,6 +380,15 @@ class MessageGenerator(object):
         self.performance_threshold_default = args.threshold
         self.rfc4760 = args.rfc4760
         self.bgpls = args.bgpls
+        self.evpn = args.evpn
+        self.mvpn = args.mvpn
+        self.l3vpn_mcast = args.l3vpn_mcast
+        self.l3vpn = args.l3vpn
+        self.rt_constrain = args.rt_constrain
+        self.ipv6 = args.ipv6
+        self.allf = args.allf
+        self.skipattr = args.skipattr
+        self.grace = args.grace
         # Default values when BGP-LS Attributes are used
         if self.bgpls:
             self.prefix_count_to_add_default = 1
@@ -346,7 +409,7 @@ class MessageGenerator(object):
                     self.prefix_count_to_add_default + 1)
         s2_slots = ((self.remaining_prefixes_threshold - 1) /
                     (self.prefix_count_to_add_default -
-                    self.prefix_count_to_del_default) + 1)
+                     self.prefix_count_to_del_default) + 1)
         # S1_First_Index = 0
         # S1_Last_Index = s1_slots * self.prefix_count_to_add_default - 1
         s2_first_index = s1_slots * self.prefix_count_to_add_default
@@ -755,7 +818,7 @@ class MessageGenerator(object):
 
         # Optional Parameters
         optional_parameters_hex = ""
-        if self.rfc4760:
+        if self.rfc4760 or self.allf:
             optional_parameter_hex = (
                 "\x02"  # Param type ("Capability Ad")
                 "\x06"  # Length (6 bytes)
@@ -768,7 +831,19 @@ class MessageGenerator(object):
             )
             optional_parameters_hex += optional_parameter_hex
 
-        if self.bgpls:
+        if self.ipv6 or self.allf:
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x02"  # AFI (IPV6)
+                "\x00"  # (reserved)
+                "\x01"  # SAFI (UNICAST)
+            )
+            optional_parameters_hex += optional_parameter_hex
+
+        if self.bgpls or self.allf:
             optional_parameter_hex = (
                 "\x02"  # Param type ("Capability Ad")
                 "\x06"  # Length (6 bytes)
@@ -781,6 +856,96 @@ class MessageGenerator(object):
             )
             optional_parameters_hex += optional_parameter_hex
 
+        if self.evpn or self.allf:
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x19"  # AFI (L2-VPN)
+                "\x00"  # (reserved)
+                "\x46"  # SAFI (EVPN)
+            )
+            optional_parameters_hex += optional_parameter_hex
+
+        if self.mvpn or self.allf:
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x01"  # AFI (IPV4)
+                "\x00"  # (reserved)
+                "\x05"  # SAFI (MCAST-VPN)
+            )
+            optional_parameters_hex += optional_parameter_hex
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x02"  # AFI (IPV6)
+                "\x00"  # (reserved)
+                "\x05"  # SAFI (MCAST-VPN)
+            )
+            optional_parameters_hex += optional_parameter_hex
+
+        if self.l3vpn_mcast or self.allf:
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x01"  # AFI (IPV4)
+                "\x00"  # (reserved)
+                "\x81"  # SAFI (L3VPN-MCAST)
+            )
+            optional_parameters_hex += optional_parameter_hex
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x02"  # AFI (IPV6)
+                "\x00"  # (reserved)
+                "\x81"  # SAFI (L3VPN-MCAST)
+            )
+            optional_parameters_hex += optional_parameter_hex
+
+        if self.l3vpn or self.allf:
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x01"  # AFI (IPV4)
+                "\x00"  # (reserved)
+                "\x80"  # SAFI (L3VPN-UNICAST)
+            )
+            optional_parameters_hex += optional_parameter_hex
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x02"  # AFI (IPV6)
+                "\x00"  # (reserved)
+                "\x80"  # SAFI (L3VPN-UNICAST)
+            )
+            optional_parameters_hex += optional_parameter_hex
+
+        if self.rt_constrain or self.allf:
+            optional_parameter_hex = (
+                "\x02"  # Param type ("Capability Ad")
+                "\x06"  # Length (6 bytes)
+                "\x01"  # Multiprotocol extetension capability,
+                "\x04"  # Capability value length
+                "\x00\x01"  # AFI (IPV4)
+                "\x00"  # (reserved)
+                "\x84"  # SAFI (ROUTE-TARGET-CONSTRAIN)
+            )
+            optional_parameters_hex += optional_parameter_hex
+
         optional_parameter_hex = (
             "\x02"  # Param type ("Capability Ad")
             "\x06"  # Length (6 bytes)
@@ -793,6 +958,39 @@ class MessageGenerator(object):
         )
         optional_parameters_hex += optional_parameter_hex
 
+        if self.grace != 8:
+            b = list(bin(self.grace)[2:])
+            b = b + [0] * (3 - len(b))
+            length = "\x08"
+            if b[1] == '1':
+                restart_flag = "\x80\x05"
+            else:
+                restart_flag = "\x00\x05"
+            if b[2] == '1':
+                ipv4_flag = "\x80"
+            else:
+                ipv4_flag = "\x00"
+            if b[0] == '1':
+                ll_gr = "\x47\x07\x00\x01\x01\x00\x00\x00\x1e"
+                length = "\x11"
+            else:
+                ll_gr = ""
+            logger.debug("Grace parameters list: {}".format(b))
+            # "\x02" Param type ("Capability Ad")
+            # :param length: Length of whole message
+            # "\x40" Graceful-restart capability
+            # "\x06" Length (6 bytes)
+            # "\x00" Restart Flag (customizable - turned on when grace == 2,3,6,7)
+            # "\x05" Restart timer (5sec)
+            # "\x00\x01" AFI (IPV4)
+            # "\x01"  SAFI (Unicast)
+            # "\x00"  Ipv4 Flag (customizable - turned on when grace == 1,3,5,7)
+            # "\x47\x07\x00\x01\x01\x00\x00\x00\x1e" ipv4 ll-graceful-restart capability, timer 30sec
+            # ll-gr turned on when grace is between 4-7
+            optional_parameter_hex = "\x02{}\x40\x06{}\x00\x01\x01{}{}".format(
+                length, restart_flag, ipv4_flag, ll_gr)
+            optional_parameters_hex += optional_parameter_hex
+
         # Optional Parameters Length
         optional_parameters_length = len(optional_parameters_hex)
         optional_parameters_length_hex = struct.pack("B",
@@ -911,7 +1109,7 @@ class MessageGenerator(object):
         # TODO: to replace hardcoded string by encoding?
         # Path Attributes
         path_attributes_hex = ""
-        if nlri_prefixes != []:
+        if not self.skipattr:
             path_attributes_hex += (
                 "\x40"  # Flags ("Well-Known")
                 "\x01"  # Type (ORIGIN)
@@ -927,6 +1125,13 @@ class MessageGenerator(object):
             )
             my_as_hex = struct.pack(">I", my_autonomous_system)
             path_attributes_hex += my_as_hex  # AS segment (4 bytes)
+            path_attributes_hex += (
+                "\x40"  # Flags ("Well-Known")
+                "\x05"  # Type (LOCAL_PREF)
+                "\x04"  # Length (4)
+                "\x00\x00\x00\x64"  # (100)
+            )
+        if nlri_prefixes != []:
             path_attributes_hex += (
                 "\x40"  # Flags ("Well-Known")
                 "\x03"  # Type (NEXT_HOP)
@@ -946,7 +1151,7 @@ class MessageGenerator(object):
             if cluster_list_item is not None:
                 path_attributes_hex += (
                     "\x80"  # Flags ("Optional, non-transitive")
-                    "\x09"  # Type (CLUSTER_LIST)
+                    "\x0a"  # Type (CLUSTER_LIST)
                     "\x04"  # Length (4)
                 )           # one CLUSTER_LIST item (4 bytes)
                 path_attributes_hex += struct.pack(">I", int(cluster_list_item))
@@ -1006,6 +1211,9 @@ class MessageGenerator(object):
             nlri_hex
         )
 
+        if self.grace != 8 and self.grace != 0 and end_of_rib:
+            message_hex = (marker_hex + binascii.unhexlify("00170200000000"))
+
         if self.log_debug:
             logger.debug("UPDATE message encoding")
             logger.debug("  Marker=0x" + binascii.hexlify(marker_hex))
@@ -1229,12 +1437,22 @@ class ReadTracker(object):
     for idle waiting.
     """
 
-    def __init__(self, bgp_socket, timer):
+    def __init__(self, bgp_socket, timer, storage, evpn=False, mvpn=False,
+                 l3vpn_mcast=False, allf=False, l3vpn=False, rt_constrain=False,
+                 ipv6=False, grace=8, wait_for_read=10):
         """The reader initialisation.
 
         Arguments:
             bgp_socket: socket to be used for sending
             timer: timer to be used for scheduling
+            storage: thread safe dict
+            evpn: flag that evpn functionality is tested
+            mvpn: flag that mvpn functionality is tested
+            grace: flag that grace-restart functionality is tested
+            l3vpn_mcast: flag that l3vpn_mcast functionality is tested
+            l3vpn: flag that l3vpn unicast functionality is tested
+            rt_constrain: flag that rt-constrain functionality is tested
+            allf: flag for all family testing.
         """
         # References to outside objects.
         self.socket = bgp_socket
@@ -1255,6 +1473,16 @@ class ReadTracker(object):
         self.prefixes_withdrawn = 0
         self.rx_idle_time = 0
         self.rx_activity_detected = True
+        self.storage = storage
+        self.evpn = evpn
+        self.mvpn = mvpn
+        self.l3vpn_mcast = l3vpn_mcast
+        self.l3vpn = l3vpn
+        self.rt_constrain = rt_constrain
+        self.ipv6 = ipv6
+        self.allf = allf
+        self.wfr = wait_for_read
+        self.grace = grace
 
     def read_message_chunk(self):
         """Read up to one message
@@ -1452,6 +1680,51 @@ class ReadTracker(object):
         # message header - message type
         msg_type_hex = msg[18:19]
         msg_type = int(binascii.b2a_hex(msg_type_hex), 16)
+
+        with self.storage as stor:
+            # this will replace the previously stored message
+            stor['update'] = binascii.hexlify(msg)
+
+        logger.debug("Evpn {}".format(self.evpn))
+        if self.evpn:
+            logger.debug("Skipping update decoding due to evpn data expected")
+            return
+
+        logger.debug("Graceful-restart {}".format(self.grace))
+        if self.grace != 8:
+            logger.debug("Skipping update decoding due to graceful-restart data expected")
+            return
+
+        logger.debug("Mvpn {}".format(self.mvpn))
+        if self.mvpn:
+            logger.debug("Skipping update decoding due to mvpn data expected")
+            return
+
+        logger.debug("L3vpn-mcast {}".format(self.l3vpn_mcast))
+        if self.l3vpn_mcast:
+            logger.debug("Skipping update decoding due to l3vpn_mcast data expected")
+            return
+
+        logger.debug("L3vpn-unicast {}".format(self.l3vpn))
+        if self.l3vpn_mcast:
+            logger.debug("Skipping update decoding due to l3vpn-unicast data expected")
+            return
+
+        logger.debug("Route-Target-Constrain {}".format(self.rt_constrain))
+        if self.rt_constrain:
+            logger.debug("Skipping update decoding due to Route-Target-Constrain data expected")
+            return
+
+        logger.debug("Ipv6-Unicast {}".format(self.ipv6))
+        if self.ipv6:
+            logger.debug("Skipping update decoding due to Ipv6 data expected")
+            return
+
+        logger.debug("Allf {}".format(self.allf))
+        if self.allf:
+            logger.debug("Skipping update decoding")
+            return
+
         if msg_type == 2:
             logger.debug("Message type: 0x%s (update)",
                          binascii.b2a_hex(msg_type_hex))
@@ -1509,7 +1782,7 @@ class ReadTracker(object):
         # Compute time to the first predictable state change
         event_time = self.timer.get_next_event_time()
         # snapshot_time would be imprecise
-        wait_timedelta = min(event_time - time.time(), 10)
+        wait_timedelta = min(event_time - time.time(), self.wfr)
         if wait_timedelta < 0:
             # The program got around to waiting to an event in "very near
             # future" so late that it became a "past" event, thus tell
@@ -1600,20 +1873,26 @@ class WriteTracker(object):
 class StateTracker(object):
     """Main loop has state so complex it warrants this separate class."""
 
-    def __init__(self, bgp_socket, generator, timer):
+    def __init__(self, bgp_socket, generator, timer, inqueue, storage, cliargs):
         """The state tracker initialisation.
 
         Arguments:
             bgp_socket: socket to be used for sending / receiving
             generator: generator to be used for message generation
             timer: timer to be used for scheduling
+            inqueue: user initiated messages queue
+            storage: thread safe dict to store data for the rpc server
+            cliargs: cli args from the user
         """
         # References to outside objects.
         self.socket = bgp_socket
         self.generator = generator
         self.timer = timer
         # Sub-trackers.
-        self.reader = ReadTracker(bgp_socket, timer)
+        self.reader = ReadTracker(bgp_socket, timer, storage, evpn=cliargs.evpn, mvpn=cliargs.mvpn,
+                                  l3vpn_mcast=cliargs.l3vpn_mcast, l3vpn=cliargs.l3vpn, allf=cliargs.allf,
+                                  rt_constrain=cliargs.rt_constrain, ipv6=cliargs.ipv6, grace=cliargs.grace,
+                                  wait_for_read=cliargs.wfr)
         self.writer = WriteTracker(bgp_socket, generator, timer)
         # Prioritization state.
         self.prioritize_writing = False
@@ -1626,6 +1905,7 @@ class StateTracker(object):
         # TODO: Alternative is to switch fairly between reading and
         # writing (called round robin from now on).
         # Message counting is done in generator.
+        self.inqueue = inqueue
 
     def perform_one_loop_iteration(self):
         """ The main loop iteration
@@ -1643,6 +1923,14 @@ class StateTracker(object):
                     logger.info("KEEP ALIVE is sent.")
                 # We are sending a message now, so let's prioritize it.
                 self.prioritize_writing = True
+
+        try:
+            msg = self.inqueue.get_nowait()
+            logger.info("Received message: {}".format(msg))
+            msgbin = binascii.unhexlify(msg)
+            self.writer.enqueue_message_for_sending(msgbin)
+        except Queue.Empty:
+            pass
         # Now we know what our priorities are, we have to check
         # which actions are available.
         # socket.socket() returns three lists,
@@ -1730,13 +2018,15 @@ def create_logger(loglevel, logfile):
     return logger
 
 
-def job(arguments):
+def job(arguments, inqueue, storage):
     """One time initialisation and iterations looping.
     Notes:
         Establish BGP connection and run iterations.
 
     Arguments:
         :arguments: Command line arguments
+        :inqueue: Data to be sent from play.py
+        :storage: Shared dict for rpc server
     Returns:
         :return: None
     """
@@ -1746,6 +2036,8 @@ def job(arguments):
     # FIXME: Add parameter to send default open message first,
     # to work with "you first" peers.
     msg_in = read_open_message(bgp_socket)
+    logger.info(binascii.hexlify(msg_in))
+    storage['open'] = binascii.hexlify(msg_in)
     timer = TimeTracker(msg_in)
     generator = MessageGenerator(arguments)
     msg_out = generator.open_message()
@@ -1769,11 +2061,57 @@ def job(arguments):
     # Use the remembered time.
     timer.reset_my_keepalive_time(timer.snapshot_time)
     # End of initial handshake phase.
-    state = StateTracker(bgp_socket, generator, timer)
+    state = StateTracker(bgp_socket, generator, timer, inqueue, storage, arguments)
     while True:  # main reactor loop
         state.perform_one_loop_iteration()
 
 
+class Rpcs:
+    '''Handler for SimpleXMLRPCServer'''
+
+    def __init__(self, sendqueue, storage):
+        '''Init method
+
+        Arguments:
+            :sendqueue: queue for data to be sent towards odl
+            :storage: thread safe dict
+        '''
+        self.queue = sendqueue
+        self.storage = storage
+
+    def send(self, text):
+        '''Data to be sent
+
+        Arguments:
+            :text: hes string of the data to be sent
+        '''
+        self.queue.put(text)
+
+    def get(self, text=''):
+        '''Reads data form the storage
+
+        - returns stored data or an empty string, at the moment only
+          'update' is stored
+
+        Arguments:
+            :text: a key to the storage to get the data
+        Returns:
+            :data: stored data
+        '''
+        with self.storage as stor:
+            return stor.get(text, '')
+
+    def clean(self, text=''):
+        '''Cleans data form the storage
+
+        Arguments:
+            :text: a key to the storage to clean the data
+        '''
+        with self.storage as stor:
+            if text in stor:
+                del stor[text]
+
+
 def threaded_job(arguments):
     """Run the job threaded
 
@@ -1786,7 +2124,10 @@ def threaded_job(arguments):
     utils_left = arguments.multiplicity
     prefix_current = arguments.firstprefix
     myip_current = arguments.myip
+    port = arguments.port
     thread_args = []
+    rpcqueue = Queue.Queue()
+    storage = SafeDict()
 
     while 1:
         amount_per_util = (amount_left - 1) / utils_left + 1  # round up
@@ -1807,14 +2148,18 @@ def threaded_job(arguments):
     try:
         # Create threads
         for t in thread_args:
-            thread.start_new_thread(job, (t,))
+            thread.start_new_thread(job, (t, rpcqueue, storage))
     except Exception:
         print "Error: unable to start thread."
         raise SystemExit(2)
 
-    # Work remains forever
-    while 1:
-        time.sleep(5)
+    if arguments.usepeerip:
+        ip = arguments.peerip
+    else:
+        ip = arguments.myip
+    rpcserver = SimpleXMLRPCServer((ip.compressed, port), allow_none=True)
+    rpcserver.register_instance(Rpcs(rpcqueue, storage))
+    rpcserver.serve_forever()
 
 
 if __name__ == "__main__":