Remove controller_1_3 and replace it with controller_1_3_1
This commit is contained in:
@@ -1,153 +0,0 @@
|
|||||||
{
|
|
||||||
"application": {
|
|
||||||
"dpctl": "",
|
|
||||||
"ipBase": "10.0.0.0/8",
|
|
||||||
"netflow": {
|
|
||||||
"nflowAddId": "0",
|
|
||||||
"nflowTarget": "",
|
|
||||||
"nflowTimeout": "600"
|
|
||||||
},
|
|
||||||
"openFlowVersions": {
|
|
||||||
"ovsOf10": "0",
|
|
||||||
"ovsOf11": "0",
|
|
||||||
"ovsOf12": "0",
|
|
||||||
"ovsOf13": "1"
|
|
||||||
},
|
|
||||||
"sflow": {
|
|
||||||
"sflowHeader": "128",
|
|
||||||
"sflowPolling": "30",
|
|
||||||
"sflowSampling": "400",
|
|
||||||
"sflowTarget": ""
|
|
||||||
},
|
|
||||||
"startCLI": "1",
|
|
||||||
"switchType": "ovs",
|
|
||||||
"terminalType": "xterm"
|
|
||||||
},
|
|
||||||
"controllers": [
|
|
||||||
{
|
|
||||||
"opts": {
|
|
||||||
"controllerProtocol": "tcp",
|
|
||||||
"controllerType": "remote",
|
|
||||||
"hostname": "c0",
|
|
||||||
"remoteIP": "127.0.0.1",
|
|
||||||
"remotePort": 6633
|
|
||||||
},
|
|
||||||
"x": "791.0",
|
|
||||||
"y": "340.0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"hosts": [
|
|
||||||
{
|
|
||||||
"number": "3",
|
|
||||||
"opts": {
|
|
||||||
"defaultRoute": "10.0.3.62",
|
|
||||||
"hostname": "h3",
|
|
||||||
"ip": "10.0.3.1/26",
|
|
||||||
"nodeNum": 3,
|
|
||||||
"sched": "host"
|
|
||||||
},
|
|
||||||
"x": "754.0",
|
|
||||||
"y": "143.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": "4",
|
|
||||||
"opts": {
|
|
||||||
"defaultRoute": "10.0.4.2",
|
|
||||||
"hostname": "h4",
|
|
||||||
"ip": "10.0.4.1/30",
|
|
||||||
"nodeNum": 4,
|
|
||||||
"sched": "host"
|
|
||||||
},
|
|
||||||
"x": "355.0",
|
|
||||||
"y": "444.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": "2",
|
|
||||||
"opts": {
|
|
||||||
"defaultRoute": "10.0.2.254",
|
|
||||||
"hostname": "h2",
|
|
||||||
"ip": "10.0.2.1/24",
|
|
||||||
"nodeNum": 2,
|
|
||||||
"sched": "host"
|
|
||||||
},
|
|
||||||
"x": "300.0",
|
|
||||||
"y": "145.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": "1",
|
|
||||||
"opts": {
|
|
||||||
"defaultRoute": "10.0.1.14",
|
|
||||||
"hostname": "h1",
|
|
||||||
"ip": "10.0.1.1/28",
|
|
||||||
"nodeNum": 1,
|
|
||||||
"sched": "host"
|
|
||||||
},
|
|
||||||
"x": "452.0",
|
|
||||||
"y": "66.0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"dest": "h4",
|
|
||||||
"opts": {},
|
|
||||||
"src": "s2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dest": "s2",
|
|
||||||
"opts": {},
|
|
||||||
"src": "s1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dest": "s1",
|
|
||||||
"opts": {},
|
|
||||||
"src": "h2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dest": "s1",
|
|
||||||
"opts": {},
|
|
||||||
"src": "h1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dest": "h3",
|
|
||||||
"opts": {},
|
|
||||||
"src": "s1"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"switches": [
|
|
||||||
{
|
|
||||||
"number": "1",
|
|
||||||
"opts": {
|
|
||||||
"controllers": [
|
|
||||||
"c0"
|
|
||||||
],
|
|
||||||
"dpid": "1",
|
|
||||||
"hostname": "s1",
|
|
||||||
"netflow": "0",
|
|
||||||
"nodeNum": 1,
|
|
||||||
"sflow": "0",
|
|
||||||
"switchIP": "",
|
|
||||||
"switchType": "default"
|
|
||||||
},
|
|
||||||
"x": "576.0",
|
|
||||||
"y": "181.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": "2",
|
|
||||||
"opts": {
|
|
||||||
"controllers": [
|
|
||||||
"c0"
|
|
||||||
],
|
|
||||||
"dpid": "2",
|
|
||||||
"hostname": "s2",
|
|
||||||
"netflow": "0",
|
|
||||||
"nodeNum": 2,
|
|
||||||
"sflow": "0",
|
|
||||||
"switchIP": "",
|
|
||||||
"switchType": "default"
|
|
||||||
},
|
|
||||||
"x": "357.0",
|
|
||||||
"y": "300.0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2"
|
|
||||||
}
|
|
@@ -1,3 +1,6 @@
|
|||||||
|
# Abgabe von:
|
||||||
|
# Jutta Seth, Janek Schoffit, Eva Hoegner
|
||||||
|
# Problem 1.3 (IP Router for IPv4)
|
||||||
from ryu.base import app_manager
|
from ryu.base import app_manager
|
||||||
from ryu.controller import ofp_event
|
from ryu.controller import ofp_event
|
||||||
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
|
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
|
||||||
@@ -11,10 +14,14 @@ from ryu.lib.packet import icmp
|
|||||||
from ryu.lib.packet.arp import arp
|
from ryu.lib.packet.arp import arp
|
||||||
from ryu.lib.packet.packet import Packet
|
from ryu.lib.packet.packet import Packet
|
||||||
|
|
||||||
|
# For IP address subnet matching
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
|
|
||||||
class L3Switch(app_manager.RyuApp):
|
class L3Switch(app_manager.RyuApp):
|
||||||
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
|
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
|
||||||
|
|
||||||
IP_ADDR = ["10.0.1.14", "10.0.2.254", "10.0.2.252", "10.0.3.62", "10.0.4.2"]
|
IP_ADDR = ["10.0.2.254", "10.0.2.252", "10.0.1.14", "10.0.3.62", "10.0.4.2"]
|
||||||
MAC_ADDR = ["52:00:00:00:00:01", "52:00:00:00:00:02"]
|
MAC_ADDR = ["52:00:00:00:00:01", "52:00:00:00:00:02"]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -40,30 +47,6 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
ofproto.OFPCML_NO_BUFFER)]
|
ofproto.OFPCML_NO_BUFFER)]
|
||||||
self.add_flow(datapath, 0, match, actions)
|
self.add_flow(datapath, 0, match, actions)
|
||||||
|
|
||||||
self.logger.info("Add new action for: ")
|
|
||||||
self.logger.info(datapath.id)
|
|
||||||
# Routing Switch 2 to 1
|
|
||||||
if datapath.id == 2:
|
|
||||||
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
|
||||||
parser.OFPActionSetField(eth_src=self.MAC_ADDR[1]), # set own mac as source
|
|
||||||
parser.OFPActionSetField(eth_dst=self.MAC_ADDR[0]), # set dst switch
|
|
||||||
parser.OFPActionOutput(1)]
|
|
||||||
|
|
||||||
match = parser.OFPMatch(ipv4_src=("10.0.4.1", "255.255.255.252"), ipv4_dst=("10.0.1.1", "255.255.255.240"), eth_type=0x0800)
|
|
||||||
#match = parser.OFPMatch(ipv4_src="10.0.4.1", ipv4_dst="10.0.1.1", eth_type=0x0800)
|
|
||||||
self.add_flow(datapath, 0, match, actions)
|
|
||||||
|
|
||||||
# Routing Switch 1 to 2
|
|
||||||
if datapath.id == 1:
|
|
||||||
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
|
||||||
parser.OFPActionSetField(eth_src=self.MAC_ADDR[0]), # set own mac as source
|
|
||||||
parser.OFPActionSetField(eth_dst=self.MAC_ADDR[1]), # set dst switch
|
|
||||||
parser.OFPActionOutput(4)]
|
|
||||||
|
|
||||||
match = parser.OFPMatch(ipv4_dst=("10.0.4.1", "255.255.255.252"), eth_type=0x0800)
|
|
||||||
self.add_flow(datapath, 0, match, actions)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_flow(self, datapath, priority, match, actions, buffer_id=None):
|
def add_flow(self, datapath, priority, match, actions, buffer_id=None):
|
||||||
ofproto = datapath.ofproto
|
ofproto = datapath.ofproto
|
||||||
@@ -109,16 +92,17 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
dpid = datapath.id
|
dpid = datapath.id
|
||||||
ofproto = datapath.ofproto
|
ofproto = datapath.ofproto
|
||||||
parser = datapath.ofproto_parser
|
parser = datapath.ofproto_parser
|
||||||
|
macaddr = self.MAC_ADDR[dpid-1]
|
||||||
|
|
||||||
arpPacket = packet.get_protocol(arp)
|
arpPacket = packet.get_protocol(arp)
|
||||||
if arpPacket.opcode == 1 :
|
if arpPacket.opcode == 1 :
|
||||||
# arp request
|
# arp request
|
||||||
arp_dstIp = arpPacket.dst_ip
|
arp_dstIp = arpPacket.dst_ip
|
||||||
self.logger.info('received ARP Request %s => %s (port%d)'%(frame.src, frame.dst, inPort))
|
self.logger.info('received ARP Request %s => %s (port%d, ip: %s)'%(frame.src, frame.dst, inPort, arp_dstIp))
|
||||||
if arp_dstIp in self.IP_ADDR:
|
if arp_dstIp in self.IP_ADDR:
|
||||||
# this switch was requested
|
# this switch was requested
|
||||||
opcode = 2
|
opcode = 2
|
||||||
srcMAC = self.MAC_ADDR[dpid-1]
|
srcMAC = macaddr
|
||||||
srcIP = arp_dstIp
|
srcIP = arp_dstIp
|
||||||
dstMAC = frame.src
|
dstMAC = frame.src
|
||||||
dstIP = arpPacket.src_ip
|
dstIP = arpPacket.src_ip
|
||||||
@@ -191,13 +175,14 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
self.send_packet(datapath, outPort, p)
|
self.send_packet(datapath, outPort, p)
|
||||||
|
|
||||||
def do_icmp(self, datapath, port, pkt_ethernet, pkt_ipv4, pkt_icmp):
|
def do_icmp(self, datapath, port, pkt_ethernet, pkt_ipv4, pkt_icmp):
|
||||||
dpid = datapath.id
|
self.logger.info(pkt_icmp.type)
|
||||||
|
self.logger.info(icmp.ICMP_ECHO_REQUEST)
|
||||||
if pkt_icmp.type != icmp.ICMP_ECHO_REQUEST:
|
if pkt_icmp.type != icmp.ICMP_ECHO_REQUEST:
|
||||||
return
|
return
|
||||||
pkt = packet.Packet()
|
pkt = packet.Packet()
|
||||||
pkt.add_protocol(ethernet.ethernet(ethertype=pkt_ethernet.ethertype,
|
pkt.add_protocol(ethernet.ethernet(ethertype=pkt_ethernet.ethertype,
|
||||||
dst=pkt_ethernet.src,
|
dst=pkt_ethernet.src,
|
||||||
src=self.MAC_ADDR[dpid]))
|
src=self.MAC_ADDR[datapath.id-1]))
|
||||||
pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src,
|
pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src,
|
||||||
src=pkt_ipv4.dst,
|
src=pkt_ipv4.dst,
|
||||||
proto=pkt_ipv4.proto))
|
proto=pkt_ipv4.proto))
|
||||||
@@ -205,7 +190,8 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
code=icmp.ICMP_ECHO_REPLY_CODE,
|
code=icmp.ICMP_ECHO_REPLY_CODE,
|
||||||
csum=0,
|
csum=0,
|
||||||
data=pkt_icmp.data))
|
data=pkt_icmp.data))
|
||||||
self.logger.info("do icmp: %s" %(pkt))
|
self.logger.info("do icmp: %s" %(pkt,))
|
||||||
|
self.logger.info("port: %s" %(port))
|
||||||
self.send_packet(datapath, port, pkt)
|
self.send_packet(datapath, port, pkt)
|
||||||
|
|
||||||
def do_l2_switch(self, datapath, dpid, packet, frame, in_port, buffer_id=None):
|
def do_l2_switch(self, datapath, dpid, packet, frame, in_port, buffer_id=None):
|
||||||
@@ -242,21 +228,59 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
parser = datapath.ofproto_parser
|
parser = datapath.ofproto_parser
|
||||||
|
|
||||||
if ipv4_pkt.dst in self.ip_to_mac[dpid]:
|
if ipv4_pkt.dst in self.ip_to_mac[dpid]:
|
||||||
# GEt mac and port of the given destination
|
# Get mac and port of the given destination
|
||||||
dstMac = self.ip_to_mac[dpid][ipv4_pkt.dst]
|
dstMac = self.ip_to_mac[dpid][ipv4_pkt.dst]
|
||||||
out_port = self.mac_to_port[dpid][dstMac]
|
out_port = self.mac_to_port[dpid][dstMac]
|
||||||
else:
|
else:
|
||||||
|
# This flow is for the second switch if the address is in range 10.0.0.0-10.0.3.255
|
||||||
|
# The ipaddress module assumes an IP adress as a unicode string (python 2.7 default for a string is ascii encoding)
|
||||||
|
if datapath.id == 2 and ipaddress.ip_address(unicode(ipv4_pkt.dst)) in ipaddress.ip_network(unicode("10.0.0.0/22")):
|
||||||
|
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
||||||
|
parser.OFPActionSetField(eth_src=self.MAC_ADDR[1]), # set own mac as source
|
||||||
|
parser.OFPActionSetField(eth_dst=self.MAC_ADDR[0]), # set dst switch
|
||||||
|
parser.OFPActionOutput(2)]
|
||||||
|
|
||||||
|
match = parser.OFPMatch(ipv4_dst=("10.0.0.0", "255.255.252.0"), eth_dst=self.MAC_ADDR[1], eth_type=0x0800)
|
||||||
|
self.add_flow(datapath, 1, match, actions)
|
||||||
|
|
||||||
|
data = None
|
||||||
|
if buffer_id == ofproto.OFP_NO_BUFFER:
|
||||||
|
data = packet.data
|
||||||
|
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
|
||||||
|
in_port=in_port, actions=actions, data=data)
|
||||||
|
datapath.send_msg(out)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add a flow for the first switch if the ipadress matches network 4.
|
||||||
|
if datapath.id == 1 and ipaddress.ip_address(unicode(ipv4_pkt.dst)) in ipaddress.ip_network(unicode("10.0.4.0/30")):
|
||||||
|
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
||||||
|
parser.OFPActionSetField(eth_src=self.MAC_ADDR[0]), # set own mac as source
|
||||||
|
parser.OFPActionSetField(eth_dst=self.MAC_ADDR[1]), # set dst switch
|
||||||
|
parser.OFPActionOutput(1)]
|
||||||
|
|
||||||
|
match = parser.OFPMatch(ipv4_dst=("10.0.4.0", "255.255.255.252"), eth_dst=self.MAC_ADDR[0], eth_type=0x0800)
|
||||||
|
self.add_flow(datapath, 1, match, actions)
|
||||||
|
|
||||||
|
data = None
|
||||||
|
if buffer_id == ofproto.OFP_NO_BUFFER:
|
||||||
|
data = packet.data
|
||||||
|
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
|
||||||
|
in_port=in_port, actions=actions, data=data)
|
||||||
|
datapath.send_msg(out)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# Send an arp request and define mac and port
|
# Send an arp request and define mac and port
|
||||||
# so we're able to apply the following actions
|
# so we're able to apply the following actions
|
||||||
# on the packet.
|
# on the packet.
|
||||||
out_port = ofproto.OFPP_FLOOD
|
out_port = ofproto.OFPP_FLOOD
|
||||||
dstMac = "FF:FF:FF:FF:FF:FF"
|
dstMac = "FF:FF:FF:FF:FF:FF"
|
||||||
self.send_arp(datapath, 1, self.MAC_ADDR[dpid-1], ipv4_pkt.src, dstMac, ipv4_pkt.dst, out_port)
|
self.send_arp(datapath, 1, self.MAC_ADDR[datapath.id-1], ipv4_pkt.src, dstMac, ipv4_pkt.dst, out_port)
|
||||||
|
|
||||||
# Actions are applied in the same order as defined in the list.
|
# Actions are applied in the same order as defined in the list.
|
||||||
# OFPActionOutput terminates the chain. So this call should be the last action.
|
# OFPActionOutput terminates the chain. So this call should be the last action.
|
||||||
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
||||||
parser.OFPActionSetField(eth_src=self.MAC_ADDR[1]), # set own mac as source
|
parser.OFPActionSetField(eth_src=self.MAC_ADDR[datapath.id-1]), # set own mac as source
|
||||||
parser.OFPActionSetField(eth_dst=dstMac), # set dst from arp request
|
parser.OFPActionSetField(eth_dst=dstMac), # set dst from arp request
|
||||||
parser.OFPActionOutput(out_port)] # forward packet through out_port
|
parser.OFPActionOutput(out_port)] # forward packet through out_port
|
||||||
|
|
||||||
@@ -313,17 +337,18 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
|
|
||||||
|
|
||||||
self.logger.info("packet in dpid: %s, src: %s, dest: %s, in_port: %s", dpid, src, dst, in_port)
|
self.logger.info("packet in dpid: %s, src: %s, dest: %s, in_port: %s", dpid, src, dst, in_port)
|
||||||
self.logger.info(pkt)
|
#self.logger.info(pkt)
|
||||||
#learn mac to port mapping
|
#learn mac to port mapping
|
||||||
if src not in self.mac_to_port[dpid]:
|
if src not in self.mac_to_port[dpid]:
|
||||||
self.mac_to_port[dpid][src] = in_port
|
self.mac_to_port[dpid][src] = in_port
|
||||||
|
|
||||||
if eth.ethertype == ether_types.ETH_TYPE_ARP:
|
if eth.ethertype == ether_types.ETH_TYPE_ARP and src not in self.MAC_ADDR:
|
||||||
self.do_arp(datapath, pkt, eth, in_port)
|
self.do_arp(datapath, pkt, eth, in_port)
|
||||||
return
|
return
|
||||||
|
|
||||||
if eth.ethertype == ether_types.ETH_TYPE_IP:
|
if eth.ethertype == ether_types.ETH_TYPE_IP:
|
||||||
ipv4_pkt = pkt.get_protocol(ipv4.ipv4)
|
ipv4_pkt = pkt.get_protocol(ipv4.ipv4)
|
||||||
|
self.logger.info("IP src: %s, dst: %s", ipv4_pkt.src, ipv4_pkt.dst)
|
||||||
|
|
||||||
#check if packet is for this switch
|
#check if packet is for this switch
|
||||||
if ipv4_pkt.dst in self.IP_ADDR:
|
if ipv4_pkt.dst in self.IP_ADDR:
|
||||||
@@ -333,11 +358,10 @@ class L3Switch(app_manager.RyuApp):
|
|||||||
else:
|
else:
|
||||||
# forward the package into a different subnet
|
# forward the package into a different subnet
|
||||||
self.do_l3_switch(datapath, dpid, pkt, eth, ipv4_pkt, in_port, msg.buffer_id)
|
self.do_l3_switch(datapath, dpid, pkt, eth, ipv4_pkt, in_port, msg.buffer_id)
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# packet is not for this switch, so do l2 switching
|
# packet is not for this switch, so do l2 switching
|
||||||
if dst != self.MAC_ADDR[dpid - 1]:
|
if dst != self.MAC_ADDR[dpid-1]:
|
||||||
self.do_l2_switch(datapath, dpid, pkt, eth, in_port, msg.buffer_id)
|
self.do_l2_switch(datapath, dpid, pkt, eth, in_port, msg.buffer_id)
|
||||||
return
|
return
|
||||||
return
|
return
|
||||||
|
@@ -1,367 +0,0 @@
|
|||||||
# Abgabe von:
|
|
||||||
# Jutta Seth, Janek Schoffit, Eva Hoegner
|
|
||||||
# Problem 1.3 (IP Router for IPv4)
|
|
||||||
from ryu.base import app_manager
|
|
||||||
from ryu.controller import ofp_event
|
|
||||||
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
|
|
||||||
from ryu.controller.handler import set_ev_cls
|
|
||||||
from ryu.ofproto import ofproto_v1_3
|
|
||||||
from ryu.lib.packet import packet
|
|
||||||
from ryu.lib.packet import ethernet
|
|
||||||
from ryu.lib.packet import ether_types
|
|
||||||
from ryu.lib.packet import ipv4
|
|
||||||
from ryu.lib.packet import icmp
|
|
||||||
from ryu.lib.packet.arp import arp
|
|
||||||
from ryu.lib.packet.packet import Packet
|
|
||||||
|
|
||||||
# For IP address subnet matching
|
|
||||||
import ipaddress
|
|
||||||
|
|
||||||
|
|
||||||
class L3Switch(app_manager.RyuApp):
|
|
||||||
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
|
|
||||||
|
|
||||||
IP_ADDR = ["10.0.2.254", "10.0.2.252", "10.0.1.14", "10.0.3.62", "10.0.4.2"]
|
|
||||||
MAC_ADDR = ["52:00:00:00:00:01", "52:00:00:00:00:02"]
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(L3Switch, self).__init__(*args, **kwargs)
|
|
||||||
self.mac_to_port = {}
|
|
||||||
self.ip_to_mac = {}
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
# install table-miss flow entry
|
|
||||||
#
|
|
||||||
# We specify NO BUFFER to max_len of the output action due to
|
|
||||||
# OVS bug. At this moment, if we specify a lesser number, e.g.,
|
|
||||||
# 128, OVS will send Packet-In with invalid buffer_id and
|
|
||||||
# truncated packet data. In that case, we cannot output packets
|
|
||||||
# correctly. The bug has been fixed in OVS v2.1.0.
|
|
||||||
match = parser.OFPMatch()
|
|
||||||
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
|
|
||||||
ofproto.OFPCML_NO_BUFFER)]
|
|
||||||
self.add_flow(datapath, 0, match, actions)
|
|
||||||
|
|
||||||
|
|
||||||
def add_flow(self, datapath, priority, match, actions, buffer_id=None):
|
|
||||||
ofproto = datapath.ofproto
|
|
||||||
parser = datapath.ofproto_parser
|
|
||||||
|
|
||||||
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
|
|
||||||
actions)]
|
|
||||||
if buffer_id:
|
|
||||||
mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
|
|
||||||
priority=priority, match=match,
|
|
||||||
instructions=inst)
|
|
||||||
else:
|
|
||||||
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
|
|
||||||
match=match, instructions=inst)
|
|
||||||
datapath.send_msg(mod)
|
|
||||||
|
|
||||||
def send_packet(self, datapath, port, pkt, buffer_id=None):
|
|
||||||
ofproto = datapath.ofproto
|
|
||||||
parser = datapath.ofproto_parser
|
|
||||||
|
|
||||||
pkt.serialize()
|
|
||||||
self.logger.info("packet-out %s" % (pkt,))
|
|
||||||
data = pkt.data
|
|
||||||
|
|
||||||
actions = [parser.OFPActionOutput(port=port)]
|
|
||||||
|
|
||||||
if buffer_id:
|
|
||||||
out = parser.OFPPacketOut(datapath=datapath,
|
|
||||||
buffer_id=buffer_id,
|
|
||||||
in_port=ofproto.OFPP_CONTROLLER,
|
|
||||||
actions=actions,
|
|
||||||
data=data)
|
|
||||||
else:
|
|
||||||
out = parser.OFPPacketOut(datapath=datapath,
|
|
||||||
buffer_id=ofproto.OFP_NO_BUFFER,
|
|
||||||
in_port=ofproto.OFPP_CONTROLLER,
|
|
||||||
actions=actions,
|
|
||||||
data=data)
|
|
||||||
|
|
||||||
datapath.send_msg(out)
|
|
||||||
|
|
||||||
def do_arp(self, datapath, packet, frame, inPort):
|
|
||||||
dpid = datapath.id
|
|
||||||
ofproto = datapath.ofproto
|
|
||||||
parser = datapath.ofproto_parser
|
|
||||||
macaddr = self.MAC_ADDR[dpid-1]
|
|
||||||
|
|
||||||
arpPacket = packet.get_protocol(arp)
|
|
||||||
if arpPacket.opcode == 1 :
|
|
||||||
# arp request
|
|
||||||
arp_dstIp = arpPacket.dst_ip
|
|
||||||
self.logger.info('received ARP Request %s => %s (port%d, ip: %s)'%(frame.src, frame.dst, inPort, arp_dstIp))
|
|
||||||
if arp_dstIp in self.IP_ADDR:
|
|
||||||
# this switch was requested
|
|
||||||
opcode = 2
|
|
||||||
srcMAC = macaddr
|
|
||||||
srcIP = arp_dstIp
|
|
||||||
dstMAC = frame.src
|
|
||||||
dstIP = arpPacket.src_ip
|
|
||||||
outPort = inPort
|
|
||||||
# learn mac 2 port mapping
|
|
||||||
self.mac_to_port[dpid][dstMAC] = inPort
|
|
||||||
# learn ip 2 mac mapping
|
|
||||||
self.ip_to_mac[dpid][dstIP] = dstMAC
|
|
||||||
self.logger.info("send ARP reply %s => %s (port%d)" %(srcMAC, dstMAC, outPort))
|
|
||||||
else:
|
|
||||||
if arpPacket.dst_ip in self.ip_to_mac[dpid]:
|
|
||||||
# optimization: the switch already knows the mapping and can answer the request
|
|
||||||
opcode = 2
|
|
||||||
srcMAC = self.ip_to_mac[dpid][arpPacket.dst_ip]
|
|
||||||
srcIP = arpPacket.dst_ip
|
|
||||||
dstMAC = frame.src
|
|
||||||
dstIP = arpPacket.src_ip
|
|
||||||
outPort = self.mac_to_port[dpid][dstMAC]
|
|
||||||
self.logger.info("optimization: answer ARP request %s => %s (port%d)" %(srcMAC, dstMAC, outPort))
|
|
||||||
else:
|
|
||||||
# forward arp request
|
|
||||||
opcode = 1
|
|
||||||
srcMAC = frame.src
|
|
||||||
srcIP = arpPacket.src_ip
|
|
||||||
dstMAC = frame.dst
|
|
||||||
dstIP = arpPacket.dst_ip
|
|
||||||
outPort = ofproto.OFPP_FLOOD
|
|
||||||
# learn mac 2 port mapping
|
|
||||||
self.mac_to_port[dpid][srcMAC] = inPort
|
|
||||||
# learn ip 2 mac mapping
|
|
||||||
self.ip_to_mac[dpid][srcIP] = srcMAC
|
|
||||||
self.logger.info("froward ARP request %s => %s (port%d)" %(srcMAC, dstMAC, outPort))
|
|
||||||
elif arpPacket.opcode == 2 :
|
|
||||||
self.logger.info(arpPacket)
|
|
||||||
if arpPacket.dst_mac in self.MAC_ADDR:
|
|
||||||
# learn mac 2 port mapping
|
|
||||||
self.mac_to_port[dpid][arpPacket.src_mac] = inPort
|
|
||||||
# learn ip 2 mac mapping
|
|
||||||
self.ip_to_mac[dpid][arpPacket.src_ip] = arpPacket.src_mac
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
opcode = 2
|
|
||||||
#arp reply
|
|
||||||
# forward arp reply
|
|
||||||
srcMAC = frame.src
|
|
||||||
srcIP = arpPacket.src_ip
|
|
||||||
dstMAC = frame.dst
|
|
||||||
dstIP = arpPacket.dst_ip
|
|
||||||
outPort = self.mac_to_port[dpid][dstMAC]
|
|
||||||
# learn mac 2 port mapping
|
|
||||||
self.mac_to_port[dpid][srcMAC] = inPort
|
|
||||||
# learn ip 2 mac mapping
|
|
||||||
self.ip_to_mac[dpid][srcIP] = srcMAC
|
|
||||||
self.logger.debug('forward ARP reply %s => %s (port%d)'%(frame.src ,frame.dst, inPort))
|
|
||||||
self.send_arp(datapath, opcode, srcMAC, srcIP, dstMAC, dstIP, outPort)
|
|
||||||
|
|
||||||
def send_arp(self, datapath, opcode, srcMac, srcIp, dstMac, dstIp, outPort):
|
|
||||||
if opcode == 1:
|
|
||||||
targetMac = "FF:FF:FF:FF:FF:FF"
|
|
||||||
targetIp = dstIp
|
|
||||||
elif opcode == 2:
|
|
||||||
targetMac = dstMac
|
|
||||||
targetIp = dstIp
|
|
||||||
e = ethernet.ethernet(dstMac, srcMac, ether_types.ETH_TYPE_ARP)
|
|
||||||
a = arp(1, 0x0800, 6, 4, opcode, srcMac, srcIp, targetMac, targetIp)
|
|
||||||
p = Packet()
|
|
||||||
p.add_protocol(e)
|
|
||||||
p.add_protocol(a)
|
|
||||||
|
|
||||||
self.send_packet(datapath, outPort, p)
|
|
||||||
|
|
||||||
def do_icmp(self, datapath, port, pkt_ethernet, pkt_ipv4, pkt_icmp):
|
|
||||||
self.logger.info(pkt_icmp.type)
|
|
||||||
self.logger.info(icmp.ICMP_ECHO_REQUEST)
|
|
||||||
if pkt_icmp.type != icmp.ICMP_ECHO_REQUEST:
|
|
||||||
return
|
|
||||||
pkt = packet.Packet()
|
|
||||||
pkt.add_protocol(ethernet.ethernet(ethertype=pkt_ethernet.ethertype,
|
|
||||||
dst=pkt_ethernet.src,
|
|
||||||
src=self.MAC_ADDR[datapath.id-1]))
|
|
||||||
pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src,
|
|
||||||
src=pkt_ipv4.dst,
|
|
||||||
proto=pkt_ipv4.proto))
|
|
||||||
pkt.add_protocol(icmp.icmp(type_=icmp.ICMP_ECHO_REPLY,
|
|
||||||
code=icmp.ICMP_ECHO_REPLY_CODE,
|
|
||||||
csum=0,
|
|
||||||
data=pkt_icmp.data))
|
|
||||||
self.logger.info("do icmp: %s" %(pkt,))
|
|
||||||
self.logger.info("port: %s" %(port))
|
|
||||||
self.send_packet(datapath, port, pkt)
|
|
||||||
|
|
||||||
def do_l2_switch(self, datapath, dpid, packet, frame, in_port, buffer_id=None):
|
|
||||||
ofproto = datapath.ofproto
|
|
||||||
parser = datapath.ofproto_parser
|
|
||||||
|
|
||||||
if frame.dst in self.mac_to_port[dpid]:
|
|
||||||
out_port = self.mac_to_port[dpid][frame.dst]
|
|
||||||
else:
|
|
||||||
out_port = ofproto.OFPP_FLOOD
|
|
||||||
|
|
||||||
actions = [parser.OFPActionOutput(out_port)]
|
|
||||||
|
|
||||||
# install a flow to avoid packet_in next time
|
|
||||||
if out_port != ofproto.OFPP_FLOOD:
|
|
||||||
match = parser.OFPMatch(in_port=in_port, eth_dst=frame.dst)
|
|
||||||
# verify if we have a valid buffer_id, if yes avoid to send both
|
|
||||||
# flow_mod & packet_out
|
|
||||||
if buffer_id != ofproto.OFP_NO_BUFFER:
|
|
||||||
self.add_flow(datapath, 1, match, actions, buffer_id)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.add_flow(datapath, 1, match, actions)
|
|
||||||
data = None
|
|
||||||
if buffer_id == ofproto.OFP_NO_BUFFER:
|
|
||||||
data = packet.data
|
|
||||||
|
|
||||||
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
|
|
||||||
in_port=in_port, actions=actions, data=data)
|
|
||||||
datapath.send_msg(out)
|
|
||||||
|
|
||||||
def do_l3_switch(self, datapath, dpid, packet, frame, ipv4_pkt, in_port, buffer_id=None):
|
|
||||||
ofproto = datapath.ofproto
|
|
||||||
parser = datapath.ofproto_parser
|
|
||||||
|
|
||||||
if ipv4_pkt.dst in self.ip_to_mac[dpid]:
|
|
||||||
# Get mac and port of the given destination
|
|
||||||
dstMac = self.ip_to_mac[dpid][ipv4_pkt.dst]
|
|
||||||
out_port = self.mac_to_port[dpid][dstMac]
|
|
||||||
else:
|
|
||||||
# This flow is for the second switch if the address is in range 10.0.0.0-10.0.3.255
|
|
||||||
# The ipaddress module assumes an IP adress as a unicode string (python 2.7 default for a string is ascii encoding)
|
|
||||||
if datapath.id == 2 and ipaddress.ip_address(unicode(ipv4_pkt.dst)) in ipaddress.ip_network(unicode("10.0.0.0/22")):
|
|
||||||
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
|
||||||
parser.OFPActionSetField(eth_src=self.MAC_ADDR[1]), # set own mac as source
|
|
||||||
parser.OFPActionSetField(eth_dst=self.MAC_ADDR[0]), # set dst switch
|
|
||||||
parser.OFPActionOutput(2)]
|
|
||||||
|
|
||||||
match = parser.OFPMatch(ipv4_dst=("10.0.0.0", "255.255.252.0"), eth_dst=self.MAC_ADDR[1], eth_type=0x0800)
|
|
||||||
self.add_flow(datapath, 1, match, actions)
|
|
||||||
|
|
||||||
data = None
|
|
||||||
if buffer_id == ofproto.OFP_NO_BUFFER:
|
|
||||||
data = packet.data
|
|
||||||
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
|
|
||||||
in_port=in_port, actions=actions, data=data)
|
|
||||||
datapath.send_msg(out)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Add a flow for the first switch if the ipadress matches network 4.
|
|
||||||
if datapath.id == 1 and ipaddress.ip_address(unicode(ipv4_pkt.dst)) in ipaddress.ip_network(unicode("10.0.4.0/30")):
|
|
||||||
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
|
||||||
parser.OFPActionSetField(eth_src=self.MAC_ADDR[0]), # set own mac as source
|
|
||||||
parser.OFPActionSetField(eth_dst=self.MAC_ADDR[1]), # set dst switch
|
|
||||||
parser.OFPActionOutput(1)]
|
|
||||||
|
|
||||||
match = parser.OFPMatch(ipv4_dst=("10.0.4.0", "255.255.255.252"), eth_dst=self.MAC_ADDR[0], eth_type=0x0800)
|
|
||||||
self.add_flow(datapath, 1, match, actions)
|
|
||||||
|
|
||||||
data = None
|
|
||||||
if buffer_id == ofproto.OFP_NO_BUFFER:
|
|
||||||
data = packet.data
|
|
||||||
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
|
|
||||||
in_port=in_port, actions=actions, data=data)
|
|
||||||
datapath.send_msg(out)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# Send an arp request and define mac and port
|
|
||||||
# so we're able to apply the following actions
|
|
||||||
# on the packet.
|
|
||||||
out_port = ofproto.OFPP_FLOOD
|
|
||||||
dstMac = "FF:FF:FF:FF:FF:FF"
|
|
||||||
self.send_arp(datapath, 1, self.MAC_ADDR[datapath.id-1], ipv4_pkt.src, dstMac, ipv4_pkt.dst, out_port)
|
|
||||||
|
|
||||||
# Actions are applied in the same order as defined in the list.
|
|
||||||
# OFPActionOutput terminates the chain. So this call should be the last action.
|
|
||||||
actions = [parser.OFPActionDecNwTtl(), #decrease TTL count
|
|
||||||
parser.OFPActionSetField(eth_src=self.MAC_ADDR[datapath.id-1]), # set own mac as source
|
|
||||||
parser.OFPActionSetField(eth_dst=dstMac), # set dst from arp request
|
|
||||||
parser.OFPActionOutput(out_port)] # forward packet through out_port
|
|
||||||
|
|
||||||
# Only install a flow if we#re in the first case (specific mac and out_port)
|
|
||||||
if ipv4_pkt.dst in self.ip_to_mac[dpid]:
|
|
||||||
# install a flow to avoid packet_in next time
|
|
||||||
match = parser.OFPMatch(in_port=in_port, ipv4_dst=ipv4_pkt.dst, eth_type=0x0800) #onlz match ipv4 packets
|
|
||||||
|
|
||||||
# verify if we have a valid buffer_id, if yes avoid to send both
|
|
||||||
# flow_mod & packet_out
|
|
||||||
if buffer_id != ofproto.OFP_NO_BUFFER:
|
|
||||||
self.add_flow(datapath, 1, match, actions, buffer_id)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.add_flow(datapath, 1, match, actions)
|
|
||||||
|
|
||||||
data = None
|
|
||||||
if buffer_id == ofproto.OFP_NO_BUFFER:
|
|
||||||
data = packet.data
|
|
||||||
|
|
||||||
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
|
|
||||||
in_port=in_port, actions=actions, data=data)
|
|
||||||
datapath.send_msg(out)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
|
|
||||||
def _packet_in_handler(self, ev):
|
|
||||||
# If you hit this you might want to increase
|
|
||||||
# the "miss_send_length" of your switch
|
|
||||||
if ev.msg.msg_len < ev.msg.total_len:
|
|
||||||
self.logger.debug("packet truncated: only %s of %s bytes",
|
|
||||||
ev.msg.msg_len, ev.msg.total_len)
|
|
||||||
|
|
||||||
msg = ev.msg
|
|
||||||
datapath = msg.datapath
|
|
||||||
ofproto = datapath.ofproto
|
|
||||||
parser = datapath.ofproto_parser
|
|
||||||
in_port = msg.match['in_port']
|
|
||||||
|
|
||||||
pkt = packet.Packet(msg.data)
|
|
||||||
eth = pkt.get_protocols(ethernet.ethernet)[0]
|
|
||||||
|
|
||||||
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
|
|
||||||
# ignore lldp packet
|
|
||||||
return
|
|
||||||
|
|
||||||
dst = eth.dst
|
|
||||||
src = eth.src
|
|
||||||
|
|
||||||
dpid = datapath.id
|
|
||||||
self.mac_to_port.setdefault(dpid, {})
|
|
||||||
self.ip_to_mac.setdefault(dpid, {})
|
|
||||||
|
|
||||||
|
|
||||||
self.logger.info("packet in dpid: %s, src: %s, dest: %s, in_port: %s", dpid, src, dst, in_port)
|
|
||||||
#self.logger.info(pkt)
|
|
||||||
#learn mac to port mapping
|
|
||||||
if src not in self.mac_to_port[dpid]:
|
|
||||||
self.mac_to_port[dpid][src] = in_port
|
|
||||||
|
|
||||||
if eth.ethertype == ether_types.ETH_TYPE_ARP and src not in self.MAC_ADDR:
|
|
||||||
self.do_arp(datapath, pkt, eth, in_port)
|
|
||||||
return
|
|
||||||
|
|
||||||
if eth.ethertype == ether_types.ETH_TYPE_IP:
|
|
||||||
ipv4_pkt = pkt.get_protocol(ipv4.ipv4)
|
|
||||||
self.logger.info("IP src: %s, dst: %s", ipv4_pkt.src, ipv4_pkt.dst)
|
|
||||||
|
|
||||||
#check if packet is for this switch
|
|
||||||
if ipv4_pkt.dst in self.IP_ADDR:
|
|
||||||
icmp_pkt = pkt.get_protocol(icmp.icmp)
|
|
||||||
if icmp_pkt:
|
|
||||||
self.do_icmp(datapath, in_port, eth, ipv4_pkt, icmp_pkt)
|
|
||||||
else:
|
|
||||||
# forward the package into a different subnet
|
|
||||||
self.do_l3_switch(datapath, dpid, pkt, eth, ipv4_pkt, in_port, msg.buffer_id)
|
|
||||||
|
|
||||||
|
|
||||||
# packet is not for this switch, so do l2 switching
|
|
||||||
if dst != self.MAC_ADDR[dpid-1]:
|
|
||||||
self.do_l2_switch(datapath, dpid, pkt, eth, in_port, msg.buffer_id)
|
|
||||||
return
|
|
||||||
return
|
|
Reference in New Issue
Block a user