Thursday, March 19, 2015

Accessing Floodlight with cURL and Python

I wanted to access a Floodlight OpenFlow Controller from RHEL 6.4. This can be done with cURL http://curl.haxx.se/ or Python.

Some cURL commands that worked in my environment are below.

Get features of switch:
$ curl http://9.23.13.143:8080/wm/core/switch/00:01:XX:XX:XX:XX:XX:XX/features/json | python -m json.tool
$ curl http://9.23.13.143:8080/wm/core/switch/all/features/json | python -m json.tool
$ curl http://9.23.13.143:8080/wm/core/switch/all/port/json | python -m json.tool

Push a flow:
$ curl -d '{"switch": "00:01:XX:XX:XX:XX:XX:XX", "name":"flow-mod-1", "cookie":"0", "priority":"32768", "ingress-port":"50","active":"true", "actions":"output=51"}'

Get flows:
$ curl http://9.23.13.143:8080/wm/staticflowpusher/list/00:01:XX:XX:XX:XX:XX:XX/json | python -m json.tool

Delete a flow:
$ curl -X DELETE -d '{"name":"flow-mod-1"}' http://<controller_ip>:8080/wm/staticflowpusher/json

The switch can also be managed using Python without cURL. The following script is cobbled together from various others I found, including https://raw.githubusercontent.com/xsited/sdn/master/python/staticflowpusher.py. My version of the script contains changes from the ones I found around the internet so that it works in my environment.

#!/usr/bin/env python

import httplib
import json

class StaticFlowPusher(object):

    def __init__(self, server):
        self.server = server

    def get(self, path, data):
        ret = self.rest_call(path, {}, 'GET')
        return json.loads(ret[2])

    def set(self, path, data):
        ret = self.rest_call(path, data, 'POST')
#       return ret[0] == 200

    def remove(self, path, data):
        ret = self.rest_call(path, data, 'DELETE')
#       return ret[0] == 200

    def rest_call(self, path, data, action):
        headers = {
            'Content-type': 'application/json',
            'Accept': 'application/json',
            }
        body = json.dumps(data)
        conn = httplib.HTTPConnection(self.server, 8080)
        conn.request(action, path, body, headers)
        response = conn.getresponse()
        ret = (response.status, response.reason, response.read())
        print ret
        conn.close()
        return ret


flow1 = {
    'switch':"00:01:XX:XX:XX:XX:XX:XX",
    "name":"flow-mod-1",
    "cookie":"0",
    "priority":"32750",
    "in_port":"51",
    "active":"true"
}


flow3 = {
    'switch':"00:01:XX:XX:XX:XX:XX:XX",
    "name":"flow-mod-3",
    "cookie":"0",
    "priority":"32751",
    "actions":"output=51",
#   "instruction_write_actions":"
#   "table":"0x27",
#   "ingress-port":"51",
    "in_port":"50",
#   "eth_vlan_vid":"0x1002",
#   "ip_proto":"0x06",
#   "output":"51",
#   "eth_dst":"00:01:FF:DD:EE:AA:CC:F3",
#   "eth_src":"00:01:AA:BB:CC:DD:EE:F1",
#   "tp_src":"0x0CBD",
#   "tp_dst":"0x0CBE",
#   "ipv4_src":"9.1.2.3/24",
#   "eth_type":"0x8100",
#   "eth-vlan-pcp":"0x3",
#   "eth_type":"0x810",
#   "eth_vlan_pcp":"0x3",
#   "set_vlan_vid":"1002",
#   "set_vlan_pcp":"0x4",
#   "set_eth_src":"00:01:22:33:44:55:66:F4",
    "active":"true"
}

flow4 = {
    'switch':"00:01:XX:XX:XX:XX:XX:XX",
    "name":"flow-mod-4",
    "cookie":"0",
    "priority":"32751",
    "actions":"output=51",
    "in_port":"50",
    "active":"true"
}

flow5 = {
    'switch':"00:01:XX:XX:XX:XX:XX:XX",
    "name":"flow-mod-5",
    "cookie":"0",
    "priority":"32751",
    "actions":"output=50",
    "in_port":"51",
    "active":"true"
}

switch01 = {
   'switch':"00:01:XX:XX:XX:XX:XX:XX"
}


switchpath = '00:01:XX:XX:XX:XX:XX:XX'
pushflowpath = '/wm/staticflowpusher/json'
#getflowpath = '/wm/staticflowpusher/list/00:01:XX:XX:XX:XX:XX:XX/json'
getflowpath = '/wm/staticflowpusher/list/'+switchpath+'/json'
getallflowpath = '/wm/staticflowpusher/list/all/json'
pusher = StaticFlowPusher('127.0.0.1')
print 'pushing flowpath 4'
pusher.set(pushflowpath, flow4)
print 'pushing flowpath 5'
pusher.set(pushflowpath, flow5)
#print 'pushing flowpath 1'
#pusher.set(pushflowpath, flow1)
print 'getting flowpath'
pusher.get(getflowpath, switch01)
print 'getting all flowpaths'
pusher.get(getallflowpath, switch01)
#print 'removing flowpath'
#pusher.remove(pushflowpath, {"name": "flow-mod-3"})
print 'getting flowpath'
pusher.get(getflowpath, switch01)



Links to related information:

Floodlight and Python documentation.


Versions:
Python 2.6.6
Linux 2.6.39-400.17.1.el6uek.x86_64
Floodlight v1.0.
OpenFlow 1.0 switch.

No comments:

Post a Comment