Skip to content

Instantly share code, notes, and snippets.

@upa
Created January 24, 2015 17:36
Show Gist options
  • Save upa/68f097cb83f29b16fe4e to your computer and use it in GitHub Desktop.
Save upa/68f097cb83f29b16fe4e to your computer and use it in GitHub Desktop.
"""
Water Fall NFV
"""
import types
import logging
import struct
from ryu.base import app_manager
from ryu.controller import mac_to_port
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.controller import dpset
from ryu.ofproto import ofproto_v1_0
from ryu.ofproto import ether
from ryu.lib import addrconv
from ryu.lib.mac import haddr_to_bin, haddr_to_str
from ryu.lib.ip import ipv4_to_bin, ipv4_to_str
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ipv4
def mac_text_to_int(mac_text):
if mac_text == 0:
return mac_text
assert isinstance(mac_text, str)
return struct.unpack('!I', haddr_to_bin (mac_text))[0]
def ipv4_text_to_int(ip_text):
if ip_text == 0:
return ip_text
assert isinstance(ip_text, str)
return struct.unpack('!I', addrconv.ipv4.text_to_bin(ip_text))[0]
class VnfPort () :
def __init__ (self) :
self.portlist = {}
self.portindex = {}
self.index = 0
""" { port : [mac1, mac2, mac3...], } """
""" { port : index, port : index } """
return
def addportmac (self, port, mac) :
if not port in self.portlist.keys () :
self.portlist[port] = []
if mac in self.portlist[port] :
# already exist
return
if not self.portindex.has_key (port) :
self.portindex[port] = 0
self.portlist[port].append (mac)
return
def delportmac (self, port, mac) :
if port in self.portlist.keys () :
if mac in self.portlist[port] :
self.portlist[port].remove (mac)
if len (self.portlist[port]) == 0 :
del (self.portlist[port])
del (self.portindex[port])
return
def selectportmac (self) :
if len (self.portlist.keys ()) == 0 :
return None
idx = self.index % len (self.portlist.keys ())
port = self.portlist.keys ()[idx]
maclist = self.portlist[port]
if len (maclist) == 0 :
del (self.portlist[port])
idx = self.portindex[port] % len (maclist)
self.portindex[port] += 1
return [ port, maclist[idx] ]
def selectportmac_key (self, key) :
golden_ratio_prime = int ("0x9e370001", 0)
if len (self.portlist.keys ()) == 0 :
return None
key *= golden_ratio_prime
idx = key % len (self.portlist.keys ())
port = self.portlist.keys ()[idx]
maclist = self.portlist[port]
if len (maclist) == 0 :
del (self.portlist[port])
idx = key % len (maclist)
self.portindex[port] += 1
return [ port, maclist[idx] ]
class WaterFall (app_manager.RyuApp) :
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]
_CONTEXTS = { 'dpset' : dpset.DPSet, }
def __init__ (self, *args, **kwargs) :
super (WaterFall, self).__init__ (*args, **kwargs)
print "WaterFall is now starting"
self.vnfports = VnfPort () # ports connected to VNF
# add vnf port and its mac address
self.vnfports.addportmac (1, haddr_to_bin ("c8:1f:66:de:15:d0"))
self.vnfports.addportmac (1, haddr_to_bin ("c8:1f:66:de:15:d1"))
self.vnfports.addportmac (1, haddr_to_bin ("c8:1f:66:de:15:d2"))
self.vnfports.addportmac (1, haddr_to_bin ("c8:1f:66:de:15:d3"))
return
@set_ev_cls (dpset.EventDP)
def dp_handler (self, ev) :
if ev.enter :
print "New DPID %s [ %s ]" \
% (ev.dp.id, " ".join (map (str, ev.dp.ports)))
else :
print "DPID %s leaved" % (ev.dp.id)
return
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler (self, ev) :
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
pkt = packet.Packet (msg.data)
inport = msg.in_port
eth = pkt.get_protocol (ethernet.ethernet)
if not eth :
# not ethernet packet
print "not ethernet packet"
return
if eth.ethertype != ether.ETH_TYPE_IP :
return
ip = pkt.get_protocol (ipv4.ipv4)
ing_port = inport
ing_mac = haddr_to_bin (eth.src)
ing_ip = ip.src
key = ipv4_text_to_int (ing_ip)
[eng_port, eng_mac] = self.vnfports.selectportmac_key (key)
print "PacktIn %s, ing %s, %s, eng, %d, %s" % (ing_ip,
ing_port, haddr_to_str (ing_mac),
eng_port, haddr_to_str (eng_mac))
# set a flow entry to ingress port
# Match client ip address as a destination, and vnf port as inport
match = datapath.ofproto_parser.OFPMatch (
in_port = eng_port, dl_type=ether.ETH_TYPE_IP,
nw_dst = ipv4_text_to_int (ing_ip))
actions = [datapath.ofproto_parser.OFPActionSetDlDst(ing_mac),
datapath.ofproto_parser.OFPActionOutput(ing_port),]
mod = datapath.ofproto_parser.OFPFlowMod (
datapath = datapath, match = match, cookie = 0,
command = ofproto.OFPFC_ADD, idle_timeout = 0, hard_timeout = 0,
priority = ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions = actions)
datapath.send_msg (mod)
# set a flow entry to vnf port
# Match client ip address as a source, and ingress port as inport
match = datapath.ofproto_parser.OFPMatch (
in_port = ing_port, dl_type=ether.ETH_TYPE_IP,
nw_src = ipv4_text_to_int (ing_ip))
actions = [ datapath.ofproto_parser.OFPActionSetDlDst(eng_mac),
datapath.ofproto_parser.OFPActionOutput(eng_port)]
mod = datapath.ofproto_parser.OFPFlowMod (
datapath = datapath, match = match, cookie = 0,
command = ofproto.OFPFC_ADD, idle_timeout = 0, hard_timeout = 0,
priority = ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions = actions)
datapath.send_msg (mod)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment