Vous êtes sur la page 1sur 6

jdsla opda# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.

#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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 License for the specific language governing permissions and
# limitations under the License.
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,ipv4, icmp
#from datetime import time
class SimpleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
A = '10.0.0.1'
B = '10.0.0.2'
C = '10.0.0.3'
policy = {A : (B,C), B : (C), C : (B)}
# firewall policy rules
#### interpretation is : A can talk to B and C. B can talk to C. C can talk
to B.
def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
"""Called whenever a switch connects.
Verifies that swich runs OpenFlow 1.3.
Initialized switch.
Paramteres: sw - the switch"""
def switch_connected(self, sw,datapath):
#this part is done now
print "switch %s connected" %sw.datapath_id
#time.sleep(5)
self.reset_switch(datapath)

"""Called whenever a switch disconnects."""
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, DEAD_DISPATCHER) #TODO not sur
e
def switch_disconnected(self, sw):
# this part is yet to be implemented.
print "switch %s disconnected" % sw.datapath_id
@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

self.switch_connected(ev.msg,datapath)
# 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.
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath = datapath, priority=0, actions = actions)

"""Reset the switch. Flush all flow table entries, set up default behaviour"
""
def reset_switch(self, datapath):
#this part is done now
#drop all flow table entries
#initialize switch such that all packets which have no matching flow tab
le entry
#are send to the controller. Simulates OpenFlow 1.0 behavior by installi
ng a
#table-miss flow entry.

ofproto = datapath.ofproto
flow_mod = datapath.ofproto_parser.OFPFlowMod(datapath,0,0,0,
ofproto.OFPFC_DELETE,
0,0,1,
ofproto.OFPCML_NO_BUFFER,
ofproto.OFPP_ANY,
ofproto.OFPG_ANY,
)
print "deleting all flow table entries in the tables :"
datapath.send_msg(flow_mod)
#pass

def __add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst, idle_timeout=180
0)
datapath.send_msg(mod)


"""Returns an OpenFlow 1.3 match.
The default value of all parameters is don't-care-match-all wildcard.

If no parameters are given, the returned match matches everything.
##### this one is done by so far except making different
. #### functions for each case like with or w/o eth addresses
#### or with or without ip addresses.
"""
def add_flow(self, datapath, actions, priority = 1000 ,in_port=None, in_phy_
port=None, metadata=None, eth_dst=None, eth_src=None, eth_type=None,
vlan_vid=None, vlan_pcp=None, ip_dscp=None, ip_ecn=None, ip_proto=N
one, ipv4_src=None, ipv4_dst=None,
tcp_src=None, tcp_dst=None, udp_src=None, udp_dst=None, sctp_src=No
ne, sctp_dst=None, icmpv4_type=None,
icmpv4_code=None, arp_op=None, arp_spa=None, arp_tpa=None, arp_sha=
None, arp_tha=None,
ipv6_src=None, ipv6_dst=None, ipv6_flabel=None, icmpv6_type=None, i
cmpv6_code=None,
ipv6_nd_target=None, ipv6_nd_sll=None, ipv6_nd_tll=None, mpls_label
=None, mpls_tc=None, mpls_bos=None,
pbb_isid=None, tunnel_id=None, ipv6_exthdr=None):

assert(datapath is not None)
assert(actions is not None)

parser = datapath.ofproto_parser

## pseudocode
assert(parser is openflow 1.3) #TODO pseudocode
or
assert(datapath is a openflow 1.3 switch)
## pseudocode

""" please check for actions that where it fits and what is it's advanta
ge """
match = parser.OFPMatch()

#TODO
# please test if you need the in_port. If not, remove the check!
#TODO
if (in_port is not None):
print "In_Port is set"
#match = parser.OFPMatch(in_port = in_port)
if (eth_type is not None):
# here you can set eth src and eth dst if they are not set to no
ne.
print "Eth_Type is set"
# check what is ethertype set to.
if (eth_type == 0x800):
print "IP Object is set"
#match = parser.OFPMatch(in_port = in_port, eth_type = eth_t
ype,eth_src=eth_src,eth_dst=eth_dst)
if (ip_proto is not None):
# here you can set ip src and ip dst if they are not set
to none.
print "IP_Proto is set"
# based on tcp/udp or icmp, you can set the addresses an
d type/codes
# for icmp
if (ip_proto == 1):
print "ICMP object type is set"
#you can set type and code here
if (ipv4_src is not None) & (ipv4_dst is not None):
if(icmpv4_type is not None) & (icmpv4_code is no
t None):
match = parser.OFPMatch(in_port = in_port,
eth_type = eth_type,
eth_src = eth_src,
eth_dst = eth_dst,
ip_proto= ip_proto,
icmpv4_type = icmpv4
_type,
icmpv4_code = icmpv4
_code,
ipv4_src = ipv4_src,
ipv4_dst= ipv4_dst)
elif (icmpv4_code is not None):
match = parser.OFPMatch(in_port = in_port,
eth_type = eth_type,
eth_src = eth_src,
eth_dst = eth_dst,
ip_proto = ip_proto,
icmpv4_code = icmpv4
_code,
ipv4_src = ipv4_src,
ipv4_dst= ipv4_dst)
elif (icmpv4_type is not None):
match = parser.OFPMatch(in_port = in_port,
eth_type = eth_type,
eth_src = eth_src,
eth_dst = eth_dst,
ip_proto = ip_proto,
icmpv4_type = icmpv4
_type,
ipv4_src = ipv4_src,
ipv4_dst = ipv4_dst)
else:
match = parser.OFPMatch(in_port = in_port, e
th_type = eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto, ipv4_src
= ipv4_src, ipv4_dst= ipv4_dst)
else:
if(icmpv4_type is not None) & (icmpv4_code is no
t None):
match = parser.OFPMatch(in_port = in_port, e
th_type = eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto, icmpv4_t
ype = icmpv4_type,icmpv4_code = icmpv4_code)
elif (icmpv4_code is not None):
match = parser.OFPMatch(in_port = in_port, e
th_type = eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto, icmpv4_c
ode = icmpv4_code)
elif (icmpv4_type is not None):
match = parser.OFPMatch(in_port = in_port, e
th_type = eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto, icmpv4_t
ype = icmpv4_type)
else:
match = parser.OFPMatch(in_port = in_port, e
th_type = eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto)

elif(ip_proto == 6):
print "TCP object is set"
match = parser.OFPMatch(in_port = in_port, eth_type
= eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto)
elif(ip_proto == 17):
print "UDP object is set"
match = parser.OFPMatch(in_port = in_port, eth_type
= eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto)
elif (ip_proto == 132):
print "SCTP object is set"
match = parser.OFPMatch(in_port = in_port, eth_type
= eth_type,eth_src=eth_src,eth_dst=eth_dst, ip_proto= ip_proto)
else:
# default case
print "Please check OFPMatch--> ip_proto parameter i
n order to continue."

else:
print "Please set OFPMatch--> ip_proto parameter in orde
r to continue."
elif (eth_type == 0x0806):
print "ARP object is set"
match = parser.OFPMatch(in_port = in_port, eth_type = eth_ty
pe,eth_src=eth_src,eth_dst=eth_dst)
# you can set here the values of ARP src , dst and ARP Op Co
de. But remember, if you can set ARP IPv4 addresses or not.
elif (eth_type == 0x86DD):
print "IPv6 object is set"
match = parser.OFPMatch(in_port = in_port, eth_type = eth_ty
pe,eth_src=eth_src,eth_dst=eth_dst)
# you can set IPV6 SRC DST and Flow Label. Also you can set
ICMPv6 here with its code and types.
elif (eth_type == 0x8847):
print "MPLS object is set"
match = parser.OFPMatch(in_port = in_port, eth_type = eth_ty
pe,eth_src=eth_src,eth_dst=eth_dst)
# you can set MPLS label and TC and Bottom of Stack bit here
.
else:
print "Please set OFPMatch--> eth_type parameter in order to con
tinue."
else:
print "Please Set the OFPMatch--> in_port parameter in order to cont
inue."
if match is not None:
self.__add_flow(datapath, priority, match, actions)
else:
print "Sorry, no matching rule found or added."

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
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]
dst = eth.dst
src = eth.src
ethtype = eth.ethertype
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port

if (ethtype == 2048) | (ethtype == 2054):
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
action_fwd_to_out_port = [parser.OFPActionOutput(out_port)]
action_fwd_to_in_port = [parser.OFPActionOutput(in_port)]
# set this IPO.PROTO to 1 so that i am checking if this is ICMP rule or
not
if(out_port != ofproto.OFPP_FLOOD) & (ethtype == 2048):
ipo = pkt.get_protocols(ipv4.ipv4)[0]

# check if policy contains this guy or not
if (self.policy.has_key(ipo.src)):
# if A can ping B then allow controller to add A's echo request
and B's echo reply Matches to FLOW TABLE ENTRY. This way we can reduce packet ex
changes between controller and switch
if ipo.dst in self.policy.get(ipo.src):
self.add_flow(datapath=datapath, actions=action_fwd_to_out_p
ort, priority=100, in_port=in_port, eth_type = 0x800, eth_src= src, eth_dst = ds
t, ip_proto = 1, icmpv4_type= 8, ipv4_src = ipo.src, ipv4_dst= ipo.dst)

self.add_flow(datapath=datapath, actions=_fwd_to_in_port, pr
iority=100, in_port = out_port, eth_type = 0x800, eth_src= dst, eth_dst = src, i
p_proto = 1, icmpv4_type= 0, ipv4_src = ipo.dst, ipv4_dst= ipo.src)

# otherwise, it means that you are adding the DROP rule here.
else:
action_drop = [parser.OFPActionOutput(ofproto.OFPPC_NO_FWD)]
self.add_flow(datapath=datapath, actions=action_drop, priori
ty=100,in_port = in_port, eth_type = 0x800, eth_src= src, eth_dst = dst, ip_prot
o = 1, icmpv4_type= 8, ipv4_src = ipo.src, ipv4_dst= ipo.dst)
else:
print "please check the firewall policy. it is not correct."

# let us add ARP rules here.
elif(out_port != ofproto.OFPP_FLOOD) & (ethtype == 2054):
self.add_flow(datapath=datapath, actions=action_fwd_to_out_port, pri
ority=1000, in_port = in_port, eth_type= 0x0806, eth_src= src, eth_dst = dst)

data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=action_fwd_to_out_por
t, data=data)
datapath.send_msg(out)

Vous aimerez peut-être aussi