Mininet Assignment 3: Moving a TCP connection in multitrunk.py
Due: Friday, August 11
In this assignment we will use the following multitrunk.py configuration
(N=1, K=2):
s1--------------------s3
/
\
h1----s5
s6---h2
\
/
s2--------------------s4
In this configuration there are two paths from h1 to h2. The existing code
will set up a TCP path for a single connection from h1 to h2 via s1--s3. You
are to change that connection so that it follows the
s2--s4 trunk, without changing any other connections.
You will use the mininet python file trunk12.py
(N=1, K=2). The corresponding controller file is multitrunkpox12.py.
To start the latter, you need a relatively complex command line: in the
top-level pox directory enter (perhaps by pasting) the following:
./pox.py
openflow.discovery openflow.nicira --convert-packet-in log.level
--WARNING forwarding.multitrunkpox12
What I do is put this into a file, such as mt12.sh,
and make it executable, and run it.
A bit of notation: a Flow
object represents a one-way TCP flow (so a TCP connection from h1 to h2 will
involve two Flow objects: one
for the h1→h2 flow and one for the return h2→h1 flow. You are only moving
the first flow; the return path will be unchanged. Each Flow
has an assigned path; paths are Python lists such as [h1,s5,s1,s3,s6,h2] or
[h1,s5,s2,s4,s6,h2]. Those are the only two paths from h1 to h2, in fact.
For a path p from h1 to h2, p[0] = h1, p[1]=s5, p[2] is the entry trunk
switch s1 or s2, and so on.
It is possible to create TCP connections originating at h2 and connecting to
h1, but we will ignore that. That way, we can assume all TCP connections
start at h1. Typically these will be ssh connections: at the mininet prompt
you will type xterm h1 (which
you can do more than once), and then in the h1 xterm window you will type slogin 10.0.0.2. This creates one
TCP connection. You can also use netcat to create continuous data-flow
connections, but we'll get to those later.
Whenever a new TCP connection is created, the Pox controller assigns a path
for each of the two unidirectional Flow
objects, and creates appropriate flow entries at each switch along the path.
Given a flow f, you can look
up its path as flow_to_path[f].
The first TCP flow from h1 to h2 is assigned a path through s1, the second
is assigned a path through s2, the third is assigned a path through s1
again, and back and forth. The choice of the first trunk switch -- and thus
of the path-- is made by picktrunk().
All flows from h2 to h1 -- the reverse direction -- are assigned a path
through s1 by picktrunk().
Each TCP flow from h1 to h2 is added to the list TCPflows.
The first connection is thus TCPflows[0].
Some code has been added to multitrunkpox12.py's _handle_PacketIn() to help
decide what connection to move. There is a call to moveTCPflow(),
which is triggered by the second TCP connection. It calls moveTCPflow()
on the first connection's h1→h2 flow. The first TCP connection's
reverse (h2→h1) flow is left unchanged. The first h1→h2 flow always goes
through s1, by assignment, and so the goal is to move it so as to be through
s2 (switchmap[2]). Hence, the
call is, in full, moveTCPflow(TCPflows[0],
switchmap[2]).
Here is what moveTCPflow(flow,ts)
has to do:
- use findpath() to create
the new path (newpath)
- use create_path_entries()
to enable newpath
- update the dictionary flow_to_path
- delete old entries (that is, in the two trunk switches on the original
path. These switches are oldpath[2]
and oldpath[3]. This step
is optional, in that if you omit it the new connection still works.
To delete flow entries, create a match object, match on all six flow
attributes plus IPv4 and TCP (shown below), and set the command to of.OFPFC_DELETE. Then send it via
the switch's connection()
object.
msg =
nx.nx_flow_mod()
msg.match = nx.nx_match() # pld: see pox
dox "Using nx_match"
msg.table_id = 0
msg.match.append(nx.NXM_OF_ETH_SRC(flow.ethsrc))
msg.match.append(nx.NXM_OF_ETH_DST(flow.ethdst))
msg.match.append(nx.NXM_OF_ETH_TYPE(pkt.ethernet.IP_TYPE))
# match that this is an IPv4 packet
msg.match.append(nx.NXM_OF_IP_PROTO(pkt.ipv4.TCP_PROTOCOL))
# match that this is a TCP packet
msg.match.append(nx.NXM_OF_IP_SRC(flow.srcip))
msg.match.append(nx.NXM_OF_IP_DST(flow.dstip))
msg.match.append(nx.NXM_OF_TCP_SRC(flow.srcport))
msg.match.append(nx.NXM_OF_TCP_DST(flow.dstport))
msg.command = of.OFPFC_DELETE
s.connection().send(msg)
After the first connection, you should see the following with ovs-ofctl
(consider ovs-ofctl dump-flows s |
grep -i tcp)
- ovs-ofctl dump-flows s5
should show two TCP flows (for one TCP connection). Make a note of the
ports. If you used slogin, one port should be 22; the other port
determines the TCP connection.
- ovs-ofctl dump-flows s1
should show two TCP flows (the same two!)
- ovs-ofctl dump-flows s2
should show no TCP flows
After this first connection's h1→h2 flow has been moved, we should see the
following:
- ovs-ofctl dump-flows s5
should show the h1→h2 flow having a different actions=output:port,
because this flow is now being routed differently by s5.
- ovs-ofctl dump-flows s2
should show the h1→h2 flow from above (identify it by its TCP port
numbers)
Verify this.
If you want to use a continuous TCP flow, instead of ssh which is
fundamentally intermittent, consider the following, where FILENAME is a
text file of modest size:
while cat FILENAME; do : ; done | netcat
10.0.0.2 5432
Be careful with the punctuation. This continuously sends the named file
over a netcat connection.
Getting ssh/slogin to work
It turns out that ssh is not set up by default (this is one of the
things that got lost when we moved from 64-bit to 32-bit at the start of the
semester). The ssh command itself works, but you need to configure things so
that the root user is authorized without a password. Here is what to do.
First, run the following command, as root:
ssh-keygen
Answer y to all the questions (or just Enter for the default). Then do the
following:
cd
/root/.ssh
cp id_rsa.pub authorized_keys
The file id_rsa.pub is root's
public key; by putting this in authorized_keys
you're saying that root is authorized to log in.
You will probably get warning messages the first time you connect,
like
The authenticity of host 10.0.0.2 can’t be
established.
RSA key fingerprint is
da:2e:e3:94:84:6b:bf:6d:2f:e4:c3:76:68:72:a5:a0.
Are you sure you want to continue connecting
(yes/no)?
Choose yes. This just means that, because this is the first time the public
key has been seen, you have to agree to trust it.