FANDOM


Dynamic Firewall (based on Quota) on SDNEdit

Welcome to the Group 9 ProjectEdit

A group of 4 from UNSW TELE4642 is runing this wiki. Group member: Kong,Youwei; Tang,Zhongtian; Wang,Xinning; Xu,Yuanfang.

BackgroundEdit

This mini project aims to provide a way to manage bandwidth usage in a software defined network. The project is based on a hotel situation. POX is used to interface with a network switch and provide the logic for the network.The scenario is that the user should buy quota to connect the Internet, and if there is no quota left, the connection between Internet will be blocked. The amount of quota is stored in a csv file. Once user buys data, pox will read the data again from csv file.
QQ截图20150603155001
This is a sample topology of an SDN controlled switch, which is a simple linear topo and emulated in Mininet below. The internet is represented by host5 in this network, and packets entering the switch that originated from this host is inspected by the switch for its destination host (using its destination MAC address), and that host's quota will be subtracted by the size of the packet in bytes. This emulates real life requests for data from the Internet, with the switch and the hosts being computers. In this case, POX is being managed by the service provider, and you give your quota division to your service provider for them to implement onto their controller.

Code & Explaination Edit

This part covers the code in our project and will clearly explain the principle behind it. Basiclly, our project has 5 functions which are read (), sendout(), quota_manager() and launch().

FIrstly, initialize some global viables and read the csv data file.

log = core.getLogger()
policyFile = "%s/pox/pox/misc/quotablock-policies.csv" % os.environ[ 'HOME' ]  
host={}                                # To store hosts mac addresses
quota={}                               # To store hosts quotas

k = 0                                  # To store the number of hosts
with open(policyFile, 'rb') as f:      # Initialize hosts addresses and quotas
  reader = csv.DictReader(f)
  for row in reader:
    if row['id'] == 'proxy':
      proxy = row['mac']
    elif row['id'] == 'admin':
      admin = row['mac']
    else:
      k = k + 1
      host[k]=row['mac']
      b=row['quota']
      quota[k]=int(b)
	
for i in irange(1, k): 
  print "Host", i, "'s quota is", quota[i], "bytes"
print ""
for i in irange(1, k):
  print "Host", i, "is at", host[i]
print ""


Quota count & BlockEdit

Using PacketIn EventEdit

So, before sending the packet from controller to host, controller will detect the quota first. Therefore, we set a priority level for detecting quota as 1. Every time the controller detect quota first then to judge where to send the data to host. Once the controller has detected a coming packet, the program will go into the quota_manager function which shows below.

def quota_manager (event):              # packet_handler handling computation of downlink data usage from Internet

  global quota    
  global host
  global k
  global policyFile
   
  packet = event.parsed                     
  size = len(event.data)                  # size of packet in bytes
	
  pktSrc = packet.src                     # in_packet source MAC address
  pktDst = packet.dst                     # in_packet destination MAC address  
  
  if pktSrc == EthAddr(proxy):
    if pktDst == EthAddr(admin):
	  return
    for i in irange(1, k):
      if pktDst == EthAddr(host[i]):                    # if packet is coming from the internet
        if quota[i] > 0:                                # subtract their quota
          quota[i] = quota[i] - size
          with open(policyFile, 'w') as f:               
            wr=csv.DictWriter(f,fieldnames=['id','mac','quota'])
            wr.writeheader()
            wr.writerow({'id':'admin','mac':admin,'quota':0})
            for a in irange(1,k):
              h='host%s'%a
              wr.writerow({'id':h,'mac':host[a],'quota':quota[a]})
            wr.writerow({'id':'proxy','mac':proxy,'quota':0})		  
          print "Host",i,"'s quota is",quota[i],"bytes"
          print " "     
          sendout (event)
        else:
          print "Host",i,"is now out of quota"
          print "packet being blocked"                    # block outgoing packet if quota
          print " "                                       # is less than or equal to zero
    return EventHalt
  elif pktDst == EthAddr(proxy):
    if pktSrc == EthAddr(admin):
      return 
    for i in irange(1, k):
      if  (pktSrc == EthAddr(host[i])) and (quota[i] <= 0) : # check the source host's quota
        print "Host",i,"is out of quota"  
        print " "
    sendout (event)
    return EventHalt

The method for blocking is a downlink block, there will be data send to proxy, but proxy will not send to host. 

It calculates the size of data first. Afterwards, for each host in the network, if there is a packet coming, it will reduce the size of packet from quota. If quota is bigger than 0, it will keep transmitting the packet which means the packet will go to the sendout function. Otherwise, it will stop the event and return EventHalt. 


Using FlowStatsReceived EventEdit

Anther method to count quota is using "FlowStatsReceived" event to get the individual flow statistics from switch. We use _time_func() to send the individual flow statistics request to the switch and execute the function every 5 seconds. Function handle_flow_stats() is used to handle the event, counting quota and making the block. 


def _timer_func ():
	for connection in core.openflow._connections.values():
		connection.send(of.ofp_stats_request(body=of.ofp_flow_stats_request()))
		break
	log.debug("Sent %i flow/port stats request(s)", len(core.openflow._connections))


def handle_flow_stats (event):
	global quota
	global host
	global i
	global lastrecord
	global policyFile
	
	for q in event.stats:
		if q.match.dl_src==EthAddr(proxy):
			for j in range(1,i):
				if (q.match.dl_dst==EthAddr(host[j])):
					if ((q.duration_sec<5) and (quota[j]>0)):
						quota[j]=quota[j]-lastrecord[j]
						with open(policyFile, 'w') as f:
							wr=csv.DictWriter(f,fieldnames=['id','mac','quota'])
							wr.writeheader()
							wr.writerow({'id':'admin','mac':admin,'quota':0})
							for k in range(1,i):
								h='host%s'%k
								wr.writerow({'id':h,'mac':host[k],'quota':quota[k]})
							wr.writerow({'id':'proxy','mac':proxy,'quota':0})
						print "Host",j,"is remaining",quota[j],"bytes quota.(wrote in csv)"
						if quota[j]<=0:
							print "Host",j,"is out of quota."
							msg=of.ofp_flow_mod()
							msg.priority=50
							msg.hard_timeout=60
							msg.match.dl_src=EthAddr(proxy)
							msg.match.dl_dst=EthAddr(host[j])
							for con in core.openflow.connections:
								con.send(msg)
							msg.match.dl_src=EthAddr(host[j])
							msg.match.dl_dst=EthAddr(proxy)
							for con in core.openflow.connections:
								con.send(msg)
							print "It is being blocked from/to the proxy now."
					lastrecord[j]=q.byte_count
					print "From Proxy to Host",j
					print q.byte_count,"bytes"
					print q.packet_count,"packets"
					print q.duration_sec,"duration"
					print "----------"


For New user add-in & Quota top-upEdit

Once the quota of a host is minus-counted, it will be updated in data file instantly, so the data file will not miss any count. 

Here we define a function read() to read the data file to update the global quota{} , host{}(mac)  and k (the total number of user hosts) in the controller. In the launch() function, we use timer to execute read() function every 30 seconds. 

Administrators can edit data file manully or use other processes to add new users' mac addresses and change quota in the data file which is read by controller periodically, so that the controller can count quotas for new users or reconnect users whose quotas have been topped up or refreshed without restart.

  def read ():             # Updating hosts quotas every X seconds 
  global policyFile       
  global quota
  global host
  global k
  i = 0
  with open(policyFile, 'rb') as fl:
    reader = csv.DictReader(fl)
    for row in reader:
      if row['id'] == 'proxy':
        proxy = row['mac']
      elif row['id'] == 'admin':
        admin = row['mac']
      else:
	    i = i + 1
        quota[i] = int(row['quota'])
        host[i] =  row['mac']        
  k = i
  print "All hosts quota have been updated"
  for i in irange(1, k):
    print "Host", i, "'s quota is", quota[i], "bytes"
  print ""


Other FunctionsEdit

The function sendout() is for packet sending which is as same as what we have done in lab2.

def sendout (event):                       # flood packet 
  msg = of.ofp_packet_out()
  msg.in_port = event.port
  msg.data = event.ofp
  msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
  event.connection.send(msg)

In the launch() function, the controller add listener for 'PacketIn' event for quota_manager() function and read the data file periodically.

def launch ():                 
  core.openflow.addListenerByName("PacketIn", quota_manager, priority = 1)    #Monitor PacketIn Event
  Timer(30, read, recurring = True)                                           #Timer for activating read function


Code TestEdit

Testing


FilesEdit

quota.py -- controller (based on PacketIn event)

quotablock.py -- controller (based on FlowStatsReceived event)

quotablock-policies.csv -- data file

Division of work Edit

First we discussed this project together and come up with some ideas. We had two plans in the beginning and decided one later.

Wang Xinning and Tang Zhongtian mainly write the code, and run the test.

Kong Youwei and Xu Yuanfang help doing research online, such as finding code examples.

Background is written by Xu Yuanfang.

Code part of this wiki is written and explained by Youwei Kong, inder to show how the quota and block function works.

Latest activityEdit

Photos and videos are a great way to add visuals to your wiki. Find videos about your topic by exploring Wikia's Video Library.

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.