Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
18 changes: 18 additions & 0 deletions lab0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Warmm up Exercise

## Analyzing h1 and h3

Run iperf h1 - h3 tcp for 20 seconds and analyzing the latency

```sh
iperf -c 10.0.0.3 -p 5566 -t 20 -P 20
```
We have th following results
![mtr tcp report 20](images/latency.png)

The throughput using Iperf `-P` option
![Throughput result tcp](images/throughput.png)

The average throughput h1 = 32.5/20 = `1.67 Mb/s`
The average throughput h3 = 14.4/20 = `0.7 Mb/s`

Binary file added lab0/images/latency.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added lab0/images/throughput.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion lab0/network_topo.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#!/usr/bin/python

from mininet.topo import Topo
from mininet.link import TCLink

class BridgeTopo(Topo):
"Creat a bridge-like customized network topology according to Figure 1 in the lab0 description."
Expand All @@ -25,6 +26,21 @@ def __init__(self):

Topo.__init__(self)

# TODO: add nodes and links to construct the topology; remember to specify the link properties
# Add the hosts and Switches
h1 = self.addHost('h1')
h2 = self.addHost('h2')
h3 = self.addHost('h3')
h4 = self.addHost('h4')

# Add the switches
s1 = self.addSwitch('s1')
s2 = self.addSwitch('s2')

# Do the linking
self.addLink(h1, s1, cls=TCLink, bw=15, delay=10) # e1
self.addLink(h2, s1, cls=TCLink, bw=15, delay=10) # e2
self.addLink(s1, s2, cls=TCLink, bw=20, delay=45) # e5
self.addLink(s2, h3, cls=TCLink, bw=15, delay=10) # e3
self.addLink(s2, h4, cls=TCLink, bw=15, delay=10) # e4

topos = {'bridge': (lambda: BridgeTopo())}
208 changes: 196 additions & 12 deletions lab1/ans_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3

from ryu.lib.packet import packet, ethernet, arp, ipv4, ether_types, icmp
from ryu.ofproto import ether

class LearningSwitch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
Expand All @@ -28,37 +30,219 @@ def __init__(self, *args, **kwargs):
super(LearningSwitch, self).__init__(*args, **kwargs)

# Here you can initialize the data structures you want to keep at the controller

self.mac_to_port = {}

# Router specific info
self.port_to_own_mac = {
1: "00:00:00:00:01:01",
2: "00:00:00:00:01:02",
3: "00:00:00:00:01:03"
}
# Router port (gateways) IP addresses assumed by the controller
self.port_to_own_ip = {
1: "10.0.1.1",
2: "10.0.2.1",
3: "192.168.1.1"
}

# ARP table ip_mac & ip port
self.ip_to_mac = {}
self.ip_to_port = {}

@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):

datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
of_proto = datapath.ofproto
of_parser = datapath.ofproto_parser

# Initial flow entry for matching misses
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
match = of_parser.OFPMatch()
actions = [of_parser.OFPActionOutput(of_proto.OFPP_CONTROLLER,
of_proto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)

# Add a flow entry to the flow-table
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
of_proto = datapath.ofproto
of_parser = datapath.ofproto_parser

# Construct flow_mod message and send it
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
inst = [of_parser.OFPInstructionActions(of_proto.OFPIT_APPLY_ACTIONS, actions)]
mod = of_parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)

# Handle the packet_in event
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):

msg = ev.msg
datapath = msg.datapath
of_proto = datapath.ofproto
of_parser = datapath.ofproto_parser

# create packet from message data
pkt = packet.Packet(msg.data)

# icmp generated when host ping its own gateway
icmp_pkt = pkt.get_protocol(icmp.icmp)
self.logger.info('icmp: %s', pkt)

# extract the src
# dest mac addresses from the ethernet protocol layer
eth = pkt.get_protocol(ethernet.ethernet)
dst = eth.dst
src = eth.src

dpid = datapath.id
in_port = msg.match['in_port']

# If it's a switch (s1 or s2): act as learning switch
# Use datapath 1 and 2
if dpid in [1, 2]:
self.mac_to_port.setdefault(dpid, {})
self.mac_to_port[dpid][src] = in_port

# Case: dst mac is in mac_to_port
# we get the outport
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]

# Else we flood
else:
out_port = of_proto.OFPP_FLOOD

# we then add a flow
actions = [of_parser.OFPActionOutput(out_port)]
match = of_parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)
self.add_flow(datapath, 1, match, actions)


# Case: Router (s3): act as IP router
elif dpid == 3:

# Check if its an Adress resolution (ARP)
if eth.ethertype == ether_types.ETH_TYPE_ARP:
arp_pkt = pkt.get_protocol(arp.arp)

# ARP - REQUEST
if arp_pkt.opcode == arp.ARP_REQUEST:
self.handle_arp_request(datapath, in_port, eth, arp_pkt)
return

# ARP - REPLY
# Keep track of IP and MAC for ARP REPLY
elif arp_pkt.opcode == arp.ARP_REPLY:
self.ip_to_mac[arp_pkt.src_ip] = arp_pkt.src_mac
self.ip_to_port[arp_pkt.src_ip] = in_port
return

# Packet is an IP packet
elif eth.ethertype == ether_types.ETH_TYPE_IP:
ip_pkt = pkt.get_protocol(ipv4.ipv4)
src_ip = ip_pkt.src
dst_ip = ip_pkt.dst
self.ip_to_mac[src_ip] = src
self.ip_to_port[src_ip] = in_port

# block ext (192.168.1.x) from pinging internal hosts
if src_ip.startswith("192.168.1.") and dst_ip.startswith("10.0."):
return

# block ext <-> ser for TCP/UDP
if ("192.168.1." in src_ip and dst_ip == "10.0.2.2") or ("192.168.1." in dst_ip and src_ip == "10.0.2.2"):
return

# Find out port, src and dst mac to send ip packet
if dst_ip in self.ip_to_mac and dst_ip in self.ip_to_port:
out_port = self.ip_to_port[dst_ip]
dst_mac = self.ip_to_mac[dst_ip]
src_mac = self.port_to_own_mac[out_port]

actions = [
of_parser.OFPActionSetField(eth_src=src_mac),
of_parser.OFPActionSetField(eth_dst=dst_mac),
of_parser.OFPActionOutput(out_port)
]
match = of_parser.OFPMatch(
eth_type=ether_types.ETH_TYPE_IP,
ipv4_dst=dst_ip,
ipv4_src=src_ip
)
self.add_flow(datapath, 10, match, actions)


# Host trying to test its own gateway with ICMP
if icmp_pkt:
self.logger.info('checking %s ', self.port_to_own_ip.items())
ip_pkt = pkt.get_protocol(ipv4.ipv4)
src_mac = None
if ip_pkt and ip_pkt.dst in self.port_to_own_ip.values():
for p, ip in self.port_to_own_ip.items():
if ip == ip_pkt.dst:
src_mac = self.port_to_own_mac[p]
self.logger.info('Mac port found %s, %s', src_mac, p)

eth_p = ethernet.ethernet(dst=eth.src, src=src_mac, ethertype=eth.ethertype)
ip = ipv4.ipv4(dst=ip_pkt.src, src=ip_pkt.dst, proto=ip_pkt.proto)
icmp_reply = icmp.icmp(type_=0, code=0, csum=0, data=icmp_pkt.data)
pkt = packet.Packet()
pkt.add_protocol(eth_p)
pkt.add_protocol(ip)
pkt.add_protocol(icmp_reply)
pkt.serialize()

actions = [of_parser.OFPActionOutput(p)]
out = of_parser.OFPPacketOut(
datapath=datapath,
buffer_id=0xffffffff,
in_port=datapath.ofproto.OFPP_CONTROLLER,
actions=actions,
data=pkt.data
)
datapath.send_msg(out)

self.logger.info('switch Learnt Mac and ports %s', self.mac_to_port)
self.logger.info('Learnt gateway Ips port match %s', self.ip_to_mac)
self.logger.info('Learnt IP -> MAC %s', self.ip_to_mac)

def handle_arp_request(self, datapath, port, eth, arp_pkt):
"""

"""
of_proto = datapath.ofproto
of_parser = datapath.ofproto_parser

target_ip = arp_pkt.dst_ip
if target_ip not in self.port_to_own_ip.values():
return

for p, ip in self.port_to_own_ip.items():
if ip == target_ip:
target_mac = self.port_to_own_mac[p]

# Create a new packet to be used as reply
arp_reply = packet.Packet()
arp_reply.add_protocol(ethernet.ethernet(
ethertype=ether.ETH_TYPE_ARP,
src=target_mac,
dst=eth.src
))
arp_reply.add_protocol(arp.arp(
opcode=arp.ARP_REPLY,
src_mac=target_mac,
src_ip=target_ip,
dst_mac=eth.src,
dst_ip=arp_pkt.src_ip
))
arp_reply.serialize()

actions = [of_parser.OFPActionOutput(port)]

# Your controller implementation should start here
# We will send the packet to the original requester
out = of_parser.OFPPacketOut(datapath=datapath,
buffer_id=of_proto.OFP_NO_BUFFER,
in_port=of_proto.OFPP_CONTROLLER,
actions=actions,
data=arp_reply.data)
datapath.send_msg(out)
27 changes: 26 additions & 1 deletion lab1/run_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,32 @@ def __init__(self):

Topo.__init__(self)

# Build the specified network topology here
# Internal hosts
h1 = self.addHost('h1', ip='10.0.1.2/24', defaultRoute='via 10.0.1.1')
h2 = self.addHost('h2', ip='10.0.1.3/24', defaultRoute='via 10.0.1.1')

# Internal server
ser = self.addHost('ser', ip='10.0.2.2/24', defaultRoute='via 10.0.2.1')

# External host
ext= self.addHost('ext', ip='192.168.1.123/24', defaultRoute='via 192.169.1.1')

# Add switches
s3 = self.addSwitch('s3') # router
s1 = self.addSwitch('s1')
s2 = self.addSwitch('s2')


# Add host links
self.addLink(h1, s1, cls=TCLink, bw=15, delay=10)
self.addLink(h2, s1, cls=TCLink, bw=15, delay=10)
self.addLink(ser, s2, cls=TCLink, bw=15, delay=10)
self.addLink(ext, s3, cls=TCLink, bw=15, delay=10)

# Add switch links
self.addLink(s2, s3, cls=TCLink, bw=15, delay=10)
self.addLink(s1, s3, cls=TCLink, bw=15, delay=10)


def run():
topo = NetworkTopo()
Expand Down