def connect(self, timeout=-1): """ Connect to the switch @param timeout Block for up to timeout seconds. Pass -1 for the default. @return Boolean, True if connected """ if not self.passive: # Do active connection now self.logger.info("Attempting to connect to %s on port %s" % (self.switch, str(self.port))) soc = self.active_connect() if soc: self.logger.info("Connected to %s", self.switch) self.dbg_state = "running" self.switch_socket = soc self.wakeup() with self.connect_cv: if self.initial_hello: self.message_send(cfg_ofp.message.hello()) self.connect_cv.notify() # Notify anyone waiting else: self.logger.error("Could not actively connect to switch %s", self.switch) self.active = False else: with self.connect_cv: ofutils.timed_wait(self.connect_cv, lambda: self.switch_socket, timeout=timeout) return self.switch_socket is not None
def wait_disconnected(self, timeout=-1): """ @param timeout Block for up to timeout seconds. Pass -1 for the default. @return Boolean, True if disconnected """ with self.connect_cv: ofutils.timed_wait(self.connect_cv, lambda: True if not self.switch_socket else None, timeout=timeout) return self.switch_socket is None
def poll(self, exp_msg=None, timeout=-1): """ Wait for the next OF message received from the switch. @param exp_msg If set, return only when this type of message is received (unless timeout occurs). @param timeout Maximum number of seconds to wait for the message. Pass -1 for the default timeout. @retval A pair (msg, pkt) where msg is a message object and pkt the string representing the packet as received from the socket. This allows additional parsing by the receiver if necessary. The data members in the message are in host endian order. If an error occurs, (None, None) is returned """ exp_msg_str = "unspecified" if exp_msg is not None: exp_msg_str = ofp.ofp_type_map.get(exp_msg, "unknown (%d)" % exp_msg) if exp_msg is not None: self.logger.debug("Poll for %s", exp_msg_str) else: self.logger.debug("Poll for any OF message") # Take the packet from the queue def grab(): if len(self.packets) > 0: if exp_msg is None: self.logger.debug("Looking for any packet") (msg, pkt) = self.packets.pop(0) return (msg, pkt) else: self.logger.debug("Looking for %s", exp_msg_str) for i in range(len(self.packets)): msg = self.packets[i][0] msg_str = ofp.ofp_type_map.get( msg.type, "unknown (%d)" % msg.type) self.logger.debug( "Checking packets[%d] %s) against %s", i, msg_str, exp_msg_str) if msg.type == exp_msg: (msg, pkt) = self.packets.pop(i) return (msg, pkt) # Not found self.logger.debug("Packet not in queue") return None with self.packets_cv: ret = ofutils.timed_wait(self.packets_cv, grab, timeout=timeout) if ret != None: (msg, pkt) = ret self.logger.debug("Got message %s" % str(msg)) return (msg, pkt) else: return (None, None)
def poll(self, port_number=None, timeout=-1, exp_pkt=None): """ Poll one or all dataplane ports for a packet If port_number is given, get the oldest packet from that port. Otherwise, find the port with the oldest packet and return that packet. If exp_pkt is true, discard all packets until that one is found @param port_number If set, get packet from this port @param timeout If positive and no packet is available, block until a packet is received or for this many seconds @param exp_pkt If not None, look for this packet and ignore any others received. Note that if port_number is None, all packets from all ports will be discarded until the exp_pkt is found @return The triple port_number, packet, pkt_time where packet is received from port_number at time pkt_time. If a timeout occurs, return None, None, None """ if exp_pkt and not port_number: self.logger.warn("Dataplane poll with exp_pkt but no port number") FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) def hex_dump_buffer(src, length=16): result = ["\n"] for i in xrange(0, len(src), length): chars = src[i:i+length] hex = ' '.join(["%02x" % ord(x) for x in chars]) printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars]) result.append("%04x %-*s %s\n" % (i, length*3, hex, printable)) return ''.join(result) def format_packet(pkt): return "Packet length %d \n%s" % (len(str(pkt)), hex_dump_buffer(str(pkt))) # Retrieve the packet. Returns (port number, packet, time). def grab(): self.logger.debug("Grabbing packet") for (rcv_port_number, pkt, time) in self.packets(port_number): print "packet received at "+str(time) self.logger.debug("Checking packet from port %d", rcv_port_number) if not exp_pkt or match_exp_pkt(exp_pkt, pkt): self.logger.debug("matched %s",format_packet(exp_pkt)) return (rcv_port_number, pkt, time) self.logger.debug("Did not find packet") return None with self.cvar: ret = ofutils.timed_wait(self.cvar, grab, timeout=timeout) if ret != None: return ret else: self.logger.debug("Poll time out, no packet from " + str(port_number)) return (None, None, None)
def poll(self, exp_msg=None, timeout=-1): """ Wait for the next OF message received from the switch. @param exp_msg If set, return only when this type of message is received (unless timeout occurs). @param timeout Maximum number of seconds to wait for the message. Pass -1 for the default timeout. @retval A pair (msg, pkt) where msg is a message object and pkt the string representing the packet as received from the socket. This allows additional parsing by the receiver if necessary. The data members in the message are in host endian order. If an error occurs, (None, None) is returned """ exp_msg_str = "unspecified" if exp_msg is not None: exp_msg_str = ofp.ofp_type_map.get(exp_msg, "unknown (%d)" % exp_msg) if exp_msg is not None: self.logger.debug("Poll for %s", exp_msg_str) else: self.logger.debug("Poll for any OF message") # Take the packet from the queue def grab(): if len(self.packets) > 0: if exp_msg is None: self.logger.debug("Looking for any packet") (msg, pkt) = self.packets.pop(0) return (msg, pkt) else: self.logger.debug("Looking for %s", exp_msg_str) for i in range(len(self.packets)): msg = self.packets[i][0] msg_str = ofp.ofp_type_map.get(msg.type, "unknown (%d)" % msg.type) self.logger.debug("Checking packets[%d] %s) against %s", i, msg_str, exp_msg_str) if msg.type == exp_msg: (msg, pkt) = self.packets.pop(i) return (msg, pkt) # Not found self.logger.debug("Packet not in queue") return None with self.packets_cv: ret = ofutils.timed_wait(self.packets_cv, grab, timeout=timeout) if ret != None: (msg, pkt) = ret self.logger.debug("Got message %s" % str(msg)) return (msg, pkt) else: return (None, None)
def transact(self, msg, timeout=-1, zero_xid=False): """ Run a message transaction with the switch Send the message in msg and wait for a reply with a matching transaction id. Transactions have the highest priority in received message handling. @param msg The message object to send; must not be a string @param timeout The timeout in seconds; if -1 use default. @param zero_xid Normally, if the XID is 0 an XID will be generated for the message. Set zero_xid to override this behavior @return The matching message object or None if unsuccessful """ if not zero_xid and msg.header.xid == 0: msg.header.xid = ofutils.gen_xid() self.logger.debug("Running transaction %d" % msg.header.xid) with self.xid_cv: if self.xid: self.logger.error("Can only run one transaction at a time") return (None, None) self.xid = msg.header.xid self.xid_response = None self.message_send(msg.pack()) self.logger.debug("Waiting for transaction %d" % msg.header.xid) ofutils.timed_wait(self.xid_cv, lambda: self.xid_response, timeout=timeout) if self.xid_response: (resp, pkt) = self.xid_response self.xid_response = None else: (resp, pkt) = (None, None) if resp is None: self.logger.warning("No response for xid " + str(self.xid)) return (resp, pkt)
def transact(self, msg, timeout=-1): """ Run a message transaction with the switch Send the message in msg and wait for a reply with a matching transaction id. Transactions have the highest priority in received message handling. @param msg The message object to send; must not be a string @param timeout The timeout in seconds; if -1 use default. """ if msg.xid == None: msg.xid = ofutils.gen_xid() self.logger.debug("Running transaction %d" % msg.xid) with self.xid_cv: if self.xid: self.logger.error("Can only run one transaction at a time") return (None, None) self.xid = msg.xid self.xid_response = None self.message_send(msg) self.logger.debug("Waiting for transaction %d" % msg.xid) ofutils.timed_wait(self.xid_cv, lambda: self.xid_response, timeout=timeout) if self.xid_response: (resp, pkt) = self.xid_response self.xid_response = None else: (resp, pkt) = (None, None) if resp is None: self.logger.warning("No response for xid " + str(self.xid)) return (resp, pkt)
def transact( self, msg, timeout=-1 ): """ Run a message transaction with the switch Send the message in msg and wait for a reply with a matching transaction id. Transactions have the highest priority in received message handling. @param msg The message object to send; must not be a string @param timeout The timeout in seconds; if -1 use default. """ if msg.xid == None: msg.xid = ofutils.gen_xid( ) self.logger.debug( "Running transaction %d" % msg.xid ) with self.xid_cv: if self.xid: self.logger.error( "Can only run one transaction at a time" ) return (None, None) self.xid = msg.xid self.xid_response = None self.message_send( msg ) self.logger.debug( "Waiting for transaction %d" % msg.xid ) ofutils.timed_wait( self.xid_cv, lambda: self.xid_response, timeout=timeout ) if self.xid_response: (resp, pkt) = self.xid_response self.xid_response = None else: (resp, pkt) = (None, None) if resp is None: self.logger.warning( "No response for xid " + str( self.xid ) ) return (resp, pkt)
def poll( self, exp_msg=None, timeout=-1 ): """ Wait for the next OF message received from the switch. @param exp_msg If set, return only when this type of message is received (unless timeout occurs). @param timeout Maximum number of seconds to wait for the message. Pass -1 for the default timeout. @retval A pair (msg, pkt) where msg is a message object and pkt the string representing the packet as received from the socket. This allows additional parsing by the receiver if necessary. The data members in the message are in host endian order. If an error occurs, (None, None) is returned """ if exp_msg is None: self.logger.warn( "DEPRECATED polling for any message class" ) klass = None elif isinstance( exp_msg, int ): klass = cfg_ofp.message.message.subtypes[ exp_msg ] elif issubclass( exp_msg, loxi.OFObject ): klass = exp_msg else: raise ValueError( "Unexpected exp_msg argument %r" % exp_msg ) self.logger.debug( "Polling for %s", klass.__name__ ) # Take the packet from the queue def grab( ): for i, (msg, pkt) in enumerate( self.packets ): if klass is None or isinstance( msg, klass ): self.logger.debug( "Got %s message", msg.__class__.__name__ ) return self.packets.pop( i ) # Not found self.logger.debug( "%s message not in queue", klass.__name__ ) return None with self.packets_cv: ret = ofutils.timed_wait( self.packets_cv, grab, timeout=timeout ) if ret != None: (msg, pkt) = ret return (msg, pkt) else: return (None, None)
def poll(self, exp_msg=None, timeout=-1): """ Wait for the next OF message received from the switch. @param exp_msg If set, return only when this type of message is received (unless timeout occurs). @param timeout Maximum number of seconds to wait for the message. Pass -1 for the default timeout. @retval A pair (msg, pkt) where msg is a message object and pkt the string representing the packet as received from the socket. This allows additional parsing by the receiver if necessary. The data members in the message are in host endian order. If an error occurs, (None, None) is returned """ if exp_msg is None: self.logger.warn("DEPRECATED polling for any message class") klass = None elif isinstance(exp_msg, int): klass = cfg_ofp.message.message.subtypes[exp_msg] elif issubclass(exp_msg, loxi.OFObject): klass = exp_msg else: raise ValueError("Unexpected exp_msg argument %r" % exp_msg) if klass is not None: self.logger.debug("Polling for %s", klass.__name__) # Take the packet from the queue def grab(): for i, (msg, pkt) in enumerate(self.packets): if klass is None or isinstance(msg, klass): self.logger.debug("Got %s message", msg.__class__.__name__) return self.packets.pop(i) # Not found self.logger.debug("%s message not in queue", klass.__name__) return None with self.packets_cv: ret = ofutils.timed_wait(self.packets_cv, grab, timeout=timeout) if ret != None: (msg, pkt) = ret return (msg, pkt) else: return (None, None)
def poll(self, port_number=None, timeout=-1, exp_pkt=None): """ Poll one or all dataplane ports for a packet If port_number is given, get the oldest packet from that port. Otherwise, find the port with the oldest packet and return that packet. If exp_pkt is true, discard all packets until that one is found @param port_number If set, get packet from this port @param timeout If positive and no packet is available, block until a packet is received or for this many seconds @param exp_pkt If not None, look for this packet and ignore any others received. Note that if port_number is None, all packets from all ports will be discarded until the exp_pkt is found @return The triple port_number, packet, pkt_time where packet is received from port_number at time pkt_time. If a timeout occurs, return None, None, None """ if exp_pkt and (port_number is None): self.logger.warn("Dataplane poll with exp_pkt but no port number") # Retrieve the packet. Returns (port number, packet, time). def grab(): self.logger.debug("Grabbing packet") for (rcv_port_number, pkt, time) in self.packets(port_number): self.logger.debug("Checking packet from port %d", rcv_port_number) if not exp_pkt or match_exp_pkt(exp_pkt, pkt): return (rcv_port_number, pkt, time) self.logger.debug("Did not find packet") return None with self.cvar: ret = ofutils.timed_wait(self.cvar, grab, timeout=timeout) if ret != None: return ret else: self.logger.debug("Poll time out, no packet from " + str(port_number)) return (None, None, None)