Merge into master from pull request #401:
Add 512-bit variation of OFPortBigMap (https://github.com/floodlight/loxigen/pull/401)
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 64794cf..ac6a3e0 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -705,6 +705,15 @@
'of_oxm_bsn_l2_cache_hit' : { 'value' : boolean_value },
'of_oxm_bsn_l2_cache_hit_masked' : { 'value' : boolean_value, 'value_mask' : boolean_value },
+ 'of_oxm_bsn_vxlan_network_id' : { 'value' : u32obj },
+ 'of_oxm_bsn_vxlan_network_id_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
+
+ 'of_oxm_bsn_inner_eth_dst' : { 'value' : mac_addr },
+ 'of_oxm_bsn_inner_eth_dst_masked' : { 'value' : mac_addr, 'value_mask' : mac_addr },
+
+ 'of_oxm_bsn_inner_eth_src' : { 'value' : mac_addr },
+ 'of_oxm_bsn_inner_eth_src_masked' : { 'value' : mac_addr, 'value_mask' : mac_addr },
+
'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
'of_match_v1': { 'vlan_vid' : vlan_vid_match, 'vlan_pcp': vlan_pcp,
'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
index faae773..e36cb59 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
@@ -263,6 +263,15 @@
public final static MatchField<OFBooleanValue> BSN_L2_CACHE_HIT =
new MatchField<OFBooleanValue>("bsn_l2_cache_hit", MatchFields.BSN_L2_CACHE_HIT);
+ public final static MatchField<U32> BSN_VXLAN_NETWORK_ID =
+ new MatchField<U32>("bsn_vxlan_network_id", MatchFields.BSN_VXLAN_NETWORK_ID);
+
+ public final static MatchField<MacAddress> BSN_INNER_ETH_DST =
+ new MatchField<MacAddress>("bsn_inner_eth_dst", MatchFields.BSN_INNER_ETH_DST);
+
+ public final static MatchField<MacAddress> BSN_INNER_ETH_SRC =
+ new MatchField<MacAddress>("bsn_inner_eth_src", MatchFields.BSN_INNER_ETH_SRC);
+
public String getName() {
return name;
}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
index 2cefa53..76671bd 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
@@ -65,4 +65,7 @@
BSN_VLAN_XLATE_PORT_GROUP_ID,
BSN_L2_CACHE_HIT,
BSN_INGRESS_PORT_GROUP_ID,
+ BSN_VXLAN_NETWORK_ID,
+ BSN_INNER_ETH_DST,
+ BSN_INNER_ETH_SRC,
}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
index e1f739d..ad21e06 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
@@ -40,6 +40,13 @@
*/
public abstract boolean isBroadcast();
+
+ /**
+ * Checks if the IPAddress is the multicast address
+ * @return boolean true or false
+ */
+ public abstract boolean isMulticast();
+
/**
* Perform a low level AND operation on the bits of two IPAddress objects
* @param other IPAddress
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
index 1530629..53e8071 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -90,6 +90,14 @@
return this.equals(NO_MASK);
}
+ /**
+ * IPv4 multicast addresses are defined by the leading address bits of 1110
+ */
+ @Override
+ public boolean isMulticast() {
+ return ((rawValue >>> 24) & 0xF0) == 0xE0;
+ }
+
@Override
public IPv4Address and(IPv4Address other) {
Preconditions.checkNotNull(other, "other must not be null");
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index 4660fc5..fee04ac 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -115,6 +115,14 @@
return this.equals(NO_MASK);
}
+ /**
+ * IPv6 multicast addresses are defined by the prefix ff00::/8
+ */
+ @Override
+ public boolean isMulticast() {
+ return (raw1 >>> 56) == 0xFFL;
+ }
+
@Override
public IPv6Address and(IPv6Address other) {
Preconditions.checkNotNull(other, "other must not be null");
@@ -166,13 +174,13 @@
(address[0] & 0xFFL) << 56 | (address[1] & 0xFFL) << 48
| (address[2] & 0xFFL) << 40 | (address[3] & 0xFFL) << 32
| (address[4] & 0xFFL) << 24 | (address[5] & 0xFFL) << 16
- | (address[6] & 0xFFL) << 8 | (address[7]);
+ | (address[6] & 0xFFL) << 8 | (address[7] & 0xFFL);
long raw2 =
(address[8] & 0xFFL) << 56 | (address[9] & 0xFFL) << 48
| (address[10] & 0xFFL) << 40 | (address[11] & 0xFFL) << 32
| (address[12] & 0xFFL) << 24 | (address[13] & 0xFFL) << 16
- | (address[14] & 0xFFL) << 8 | (address[15]);
+ | (address[14] & 0xFFL) << 8 | (address[15] & 0xFFL);
return IPv6Address.of(raw1, raw2);
}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
index 32e9bcc..9c571ea 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
@@ -38,7 +38,7 @@
public final static OFGroup ANY = new NamedGroup(ANY_VAL, "any");
/** group 0 in case we need it */
- public static final OFGroup ZERO = OFGroup.of(ZERO_VAL);
+ public static final OFGroup ZERO = new OFGroup(ZERO_VAL);
public static final OFGroup NO_MASK = ANY;
public static final OFGroup FULL_MASK = ZERO;
@@ -62,7 +62,7 @@
public static OFGroup of(final int groupNumber) {
switch(groupNumber) {
case ZERO_VAL:
- return MAX;
+ return ZERO;
case MAX_VAL:
return MAX;
case ALL_VAL:
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
index 2ba4528..6e9d047 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
@@ -130,4 +130,17 @@
}
}
+ @Test
+ public void testMulticastIp() {
+ IPAddress<?> ip0 = IPAddress.of("240.2.3.4");
+ IPAddress<?> ip1 = IPAddress.of("224.0.1.1");
+ IPAddress<?> ip2 = IPAddress.of("239.0.0.0");
+ IPAddress<?> ip3 = IPAddress.of("feff::1");
+ IPAddress<?> ip4 = IPAddress.of("ff00::1");
+ assertTrue(!ip0.isMulticast());
+ assertTrue(ip1.isMulticast());
+ assertTrue(ip2.isMulticast());
+ assertTrue(!ip3.isMulticast());
+ assertTrue(ip4.isMulticast());
+ }
}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
index 52f2487..a94f443 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
@@ -20,7 +20,8 @@
"::",
"::1",
"ffe0::",
- "1:2:3:4:5:6:7:8"
+ "1:2:3:4:5:6:7:8",
+ "8091:a2b3:c4d5:e6f7:8495:a6b7:c1d2:e3d4",
};
diff --git a/openflow_input/bsn_inner_eth_dst b/openflow_input/bsn_inner_eth_dst
new file mode 100644
index 0000000..d3e9fa9
--- /dev/null
+++ b/openflow_input/bsn_inner_eth_dst
@@ -0,0 +1,47 @@
+// Copyright 2015, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+#version 5
+
+/*
+ * Inner ethernet destination MAC
+ */
+
+struct of_oxm_bsn_inner_eth_dst : of_oxm {
+ uint32_t type_len == 0x00032c06;
+ of_mac_addr_t value;
+};
+
+struct of_oxm_bsn_inner_eth_dst_masked : of_oxm {
+ uint32_t type_len == 0x00032d0c;
+ of_mac_addr_t value;
+ of_mac_addr_t value_mask;
+};
diff --git a/openflow_input/bsn_inner_eth_src b/openflow_input/bsn_inner_eth_src
new file mode 100644
index 0000000..36e0e35
--- /dev/null
+++ b/openflow_input/bsn_inner_eth_src
@@ -0,0 +1,47 @@
+// Copyright 2015, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+#version 5
+
+/*
+ * Inner ethernet source MAC
+ */
+
+struct of_oxm_bsn_inner_eth_src : of_oxm {
+ uint32_t type_len == 0x00032e06;
+ of_mac_addr_t value;
+};
+
+struct of_oxm_bsn_inner_eth_src_masked : of_oxm {
+ uint32_t type_len == 0x00032f0c;
+ of_mac_addr_t value;
+ of_mac_addr_t value_mask;
+};
diff --git a/openflow_input/bsn_vxlan b/openflow_input/bsn_vxlan
new file mode 100644
index 0000000..4171a51
--- /dev/null
+++ b/openflow_input/bsn_vxlan
@@ -0,0 +1,47 @@
+// Copyright 2015, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+#version 5
+
+/*
+ * VXLAN Virtual Network Identifier
+ */
+
+struct of_oxm_bsn_vxlan_network_id : of_oxm {
+ uint32_t type_len == 0x00032a04;
+ uint32_t value;
+};
+
+struct of_oxm_bsn_vxlan_network_id_masked : of_oxm {
+ uint32_t type_len == 0x00032b08;
+ uint32_t value;
+ uint32_t value_mask;
+};
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index 9c741d2..aa7141a 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -88,6 +88,7 @@
render('__init__.py', template_name='toplevel_init.py')
render('pp.py')
render('generic_util.py')
+ render('connection.py')
for version in loxi_globals.OFVersions.all_supported:
subdir = 'of' + version.version.replace('.', '')
diff --git a/py_gen/templates/connection.py b/py_gen/templates/connection.py
new file mode 100644
index 0000000..f0648be
--- /dev/null
+++ b/py_gen/templates/connection.py
@@ -0,0 +1,264 @@
+:: # Copyright 2015, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+# Copyright 2015, Big Switch Networks, Inc.
+
+"""
+OpenFlow connection class
+
+This class creates a thread which continually parses OpenFlow messages off the
+supplied socket and places them in a queue. The class has methods for reading messages
+from the RX queue, sending messages, and higher level operations like request-response
+and multipart transactions.
+"""
+
+import loxi
+import loxi.of14
+import logging
+import time
+import socket
+import errno
+import os
+import select
+from threading import Condition, Lock, Thread
+
+DEFAULT_TIMEOUT = 1
+
+class TransactionError(Exception):
+ def __str__(self):
+ return self.args[0]
+
+ @property
+ def msg(self):
+ return self.args[1]
+
+class Connection(Thread):
+ def __init__(self, sock):
+ Thread.__init__(self)
+ self.sock = sock
+ self.logger = logging.getLogger("connection")
+ self.rx = []
+ self.rx_cv = Condition()
+ self.tx_lock = Lock()
+ self.next_xid = 1
+ self.wakeup_rd, self.wakeup_wr = os.pipe()
+ self.finished = False
+ self.read_buffer = None
+
+ def run(self):
+ while not self.finished:
+ rd, wr, err = select.select([self.sock, self.wakeup_rd], [], [])
+ if self.sock in rd:
+ self.process_read()
+ if self.wakeup_rd in rd:
+ os.read(self.wakeup_rd, 1)
+ self.logger.debug("Exited event loop")
+
+ def process_read(self):
+ recvd = self.sock.recv(4096)
+
+ self.logger.debug("Received %d bytes", len(recvd))
+
+ buf = self.read_buffer
+ if buf:
+ buf += recvd
+ else:
+ buf = recvd
+
+ offset = 0
+ while offset < len(buf):
+ if offset + 8 > len(buf):
+ # Not enough data for the OpenFlow header
+ break
+
+ # Parse the header to get type
+ hdr_version, hdr_type, hdr_msglen, hdr_xid = loxi.of14.message.parse_header(buf[offset:])
+
+ # Use loxi to resolve ofp of matching version
+ ofp = loxi.protocol(hdr_version)
+
+ # Extract the raw message bytes
+ if (offset + hdr_msglen) > len(buf):
+ # Not enough data for the body
+ break
+ rawmsg = buf[offset : offset + hdr_msglen]
+ offset += hdr_msglen
+
+ msg = ofp.message.parse_message(rawmsg)
+ if not msg:
+ self.logger.warn("Could not parse message")
+ continue
+
+ self.logger.debug("Received message %s.%s xid %d length %d",
+ type(msg).__module__, type(msg).__name__, hdr_xid, hdr_msglen)
+
+ with self.rx_cv:
+ self.rx.append(msg)
+ self.rx_cv.notify_all()
+
+ if offset == len(buf):
+ self.read_buffer = None
+ else:
+ self.read_buffer = buf[offset:]
+ self.logger.debug("%d bytes remaining", len(self.read_buffer))
+
+ def recv(self, predicate, timeout=DEFAULT_TIMEOUT):
+ """
+ Remove and return the first message in the RX queue for
+ which 'predicate' returns true
+ """
+ assert self.is_alive()
+
+ deadline = time.time() + timeout
+ while True:
+ with self.rx_cv:
+ for i, msg in enumerate(self.rx):
+ if predicate(msg):
+ return self.rx.pop(i)
+
+ now = time.time()
+ if now > deadline:
+ return None
+ else:
+ self.rx_cv.wait(deadline - now)
+
+ def recv_any(self, timeout=DEFAULT_TIMEOUT):
+ """
+ Return the first message in the RX queue
+ """
+ return self.recv(lambda msg: True, timeout)
+
+ def recv_xid(self, xid, timeout=DEFAULT_TIMEOUT):
+ """
+ Return the first message in the RX queue with XID 'xid'
+ """
+ return self.recv(lambda msg: msg.xid == xid, timeout)
+
+ def recv_class(self, klass, timeout=DEFAULT_TIMEOUT):
+ """
+ Return the first message in the RX queue which is an instance of 'klass'
+ """
+ return self.recv(lambda msg: isinstance(msg, klass), timeout)
+
+ def send_raw(self, buf):
+ """
+ Send raw bytes on the socket
+ """
+ assert self.is_alive()
+ self.logger.debug("Sending raw message length %d", len(buf))
+ with self.tx_lock:
+ if self.sock.sendall(buf) is not None:
+ raise RuntimeError("failed to send message to switch")
+
+ def send(self, msg):
+ """
+ Send a message
+ """
+ assert self.is_alive()
+
+ if msg.xid is None:
+ msg.xid = self._gen_xid()
+ buf = msg.pack()
+ self.logger.debug("Sending message %s.%s xid %d length %d",
+ type(msg).__module__, type(msg).__name__, msg.xid, len(buf))
+ with self.tx_lock:
+ if self.sock.sendall(buf) is not None:
+ raise RuntimeError("failed to send message to switch")
+
+ def transact(self, msg, timeout=DEFAULT_TIMEOUT):
+ """
+ Send a message and return the reply
+ """
+ self.send(msg)
+ reply = self.recv_xid(msg.xid, timeout)
+ if reply is None:
+ raise TransactionError("no reply for %s" % type(msg).__name__, None)
+ elif isinstance(reply, loxi.protocol(reply.version).message.error_msg):
+ raise TransactionError("received %s in response to %s" % (type(reply).__name__, type(msg).__name__), reply)
+ return reply
+
+ def transact_multipart_generator(self, msg, timeout=DEFAULT_TIMEOUT):
+ """
+ Send a multipart request and yield each entry from the replies
+ """
+ self.send(msg)
+ finished = False
+ while not finished:
+ reply = self.recv_xid(msg.xid, timeout)
+ if reply is None:
+ raise TransactionError("no reply for %s" % type(msg).__name__, None)
+ elif not isinstance(reply, loxi.protocol(reply.version).message.stats_reply):
+ raise TransactionError("received %s in response to %s" % (type(reply).__name__, type(msg).__name__), reply)
+ for entry in reply.entries:
+ yield entry
+ finished = reply.flags & loxi.protocol(reply.version).OFPSF_REPLY_MORE == 0
+
+ def transact_multipart(self, msg, timeout=DEFAULT_TIMEOUT):
+ """
+ Send a multipart request and return all entries from the replies
+ """
+ entries = []
+ for entry in self.transact_multipart_generator(msg, timeout):
+ entries.append(entry)
+ return entries
+
+ def stop(self):
+ """
+ Signal the thread to exit and wait for it
+ """
+ assert not self.finished
+ self.logger.debug("Stopping connection")
+ self.finished = True
+ os.write(self.wakeup_wr, "x")
+ self.join()
+ self.sock.close()
+ os.close(self.wakeup_rd)
+ os.close(self.wakeup_wr)
+ self.logger.debug("Stopped connection")
+
+ def _gen_xid(self):
+ xid = self.next_xid
+ self.next_xid += 1
+ return xid
+
+def connect(ip, port=6653, daemon=True, ofp=loxi.of14):
+ """
+ Actively connect to a switch
+ """
+ soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ soc.connect((ip, port))
+ soc.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
+ cxn = Connection(soc)
+ cxn.daemon = daemon
+ cxn.logger.debug("Connected to %s:%d", ip, port)
+ cxn.start()
+
+ cxn.send(ofp.message.hello())
+ if not cxn.recv(lambda msg: msg.type == ofp.OFPT_HELLO):
+ raise Exception("Did not receive HELLO")
+
+ return cxn