Static Flow Pusher API (New)

Skip to end of metadata
Go to start of metadata
This guide is for Floodlight v1.0. If you are using Floodlight v0.9 or earlier or are using a master copy downloaded prior to December 30, 2014, please consider upgrading to the latest release. Please refer to these instructions for help using the Static Flow Pusher for pre-v1.0 releases.

What is the Static Flow Pusher?

The Static Flow Pusher is a Floodlight module, exposed via a REST API, that allows a user to manually insert flows into an OpenFlow network.

Proactive vs Reactive flow insertion

OpenFlow supports two methods of flow insertion: proactive and reactive. Reactive flow insertion occurs when a packet reaches an OpenFlow switch without a matching flow. The packet is sent to the controller, which evaluates it, adds the appropriate flows, and lets the switch continue its forwarding. Alternatively, flows can be inserted proactively by the controller in switches before packets arrive. In the case of proactive flow insertion, the arriving packet will never be sent to the controller for evaluation since it matches the proactively-inserted flow.

Floodlight supports both mechanisms of flow insertion. The Static Flow Pusher is generally useful for proactive flow insertion.

Note that by default, Floodlight loads the Forwarding module which does reactive flow pushing. If you would like to exclusively use static flows, you must remove Forwarding from the floodlight.properties file.

How is the Static Flow Pusher used?

API Summary

URI 
Description 
Arguments 
/wm/staticflowpusher/json Add/Delete static flow HTTP POST data (add flow), HTTP DELETE (for deletion)
/wm/staticflowpusher/list/<switch>/json List static flows for a switch or all switches switch: Valid Switch DPID (XX:XX:XX:XX:XX:XX:XX:XX) or "all"
/wm/staticflowpusher/clear/<switch>/json Clear static flows for a switch or all switches switch: Valid Switch DPID (XX:XX:XX:XX:XX:XX:XX:XX) or "all"

Adding a static flow

The Static Flow Pusher is accessible via a REST API. To add a static flow, the user needs to define the flow in JSON format. For example, to insert a flow on switch 1 that takes packets from port 1 and outputs them on port 2, you can compose the JSON string and simply use a curl command to send the HTTP POST to the controller. The second command will dump the flow so you can see it set.

curl -d '{"switch": "00:00:00:00:00:00:00:01", "name":"flow-mod-1", "cookie":"0", "priority":"32768", "ingress-port":"1","active":"true", "actions":"output=2"}' http://<controller_ip>:8080/wm/staticflowpusher/json

Listing static flows

To get a list of all static flows, the Static Flow Pusher REST API accepts an HTTP GET to the path specified in API Summary above. You can query for static flows on a per-switch basis or ask the controller for all static flows across all switches.

curl http://<controller_ip>:8080/wm/staticflowpusher/list/00:00:00:00:00:00:00:01/jsoncurl http://<controller_ip>:8080/wm/staticflowpusher/list/all/json

Deleting a static flow

To delete a static flow you send an HTTP DELETE that includes the name of the flow used during insertion.

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

Required properties of a flow entry:

Key Value Notes
name <string> Name of the flow entry.
This is used as the primary key for the flow.
The name must be globally unique.
switch <switch DPID> DPID of the switch to which this flow should be added.
xx:xx:xx:xx:xx:xx:xx:xx

Optional properties of a flow entry:

Key Value Notes
priority <number> Default is 32767.
Max is 32767.
active <boolean> "true" or "false"
table <number> Default flow table is used if omitted.
idle_timeout <number> Default of zero, which is no-timeout.
hard_timeout <number> Default of zero, which is no-timeout.
cookie <number> Can be hexadecimal (with leading 0x) or decimal.
cookie_mask <number> Can be hexadecimal (with leading 0x) or decimal.

Optional match fields of a flow entry:

Key 
Value 
Prerequisite Matches OpenFlow Versions Notes 
in_port <number>   all Switch port on which the packet is received.
eth_type <number>   all Can be hexadecimal (with leading 0x) or decimal.
eth_src <MAC address>   all xx:xx:xx:xx:xx:xx
eth_dst <MAC address>   all xx:xx:xx:xx:xx:xx
eth_vlan_vid <number>   all Can be hexadecimal (with leading 0x) or decimal.
eth_vlan_pcp <number> eth_vlan_vid = something all Can be hexadecimal (with leading 0x) or decimal.
ip_proto <number> eth_type = 0x0800 || 0x86dd all Can be hexadecimal (with leading 0x) or decimal.
ipv4_src <IPv4 address[/mask]> eth_type = 0x0800 all xx.xx.xx.xx[/xx]
ipv4_dst <IPv4 address[/mask]> eth_type = 0x0800 all xx.xx.xx.xx[/xx]
ipv6_src <IPv6 address[/mask]> eth_type = 0x86dd
OpenFlow 1.2+ xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx[/xx]
ipv6_dst <IPv6 address[/mask]> eth_type = 0x86dd
OpenFlow 1.2+
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx[/xx]
ipv6_label <number> eth_type = 0x86dd OpenFlow 1.2+
Can be hexadecimal (with leading 0x) or decimal.
ip_tos <number> eth_type = 0x0800 || 0x86dd
all Can be hexadecimal (with leading 0x) or decimal.
ip_ecn <number> eth_type = 0x0800 || 0x86dd
all Can be hexadecimal (with leading 0x) or decimal.
ip_dscp <number> eth_type = 0x0800 || 0x86dd
all Can be hexadecimal (with leading 0x) or decimal. 
tp_src <number> ip_proto = 0x06 || 0x11 || 0x84 all UDP, TCP, and SCTP supported.
tp_dst <number> ip_proto = 0x06 || 0x11 || 0x84 all UDP, TCP, and SCTP supported.
udp_src <number> ip_proto = 0x11
all UDP only.
udp_dst <number> ip_proto = 0x11 all UDP only.
tcp_src <number> ip_proto = 0x06 all TCP only.
tcp_dst <number> ip_proto = 0x06 all TCP only.
sctp_src <number> ip_proto = 0x84 all SCTP only.
sctp_dst <number> ip_proto = 0x84 all SCTP only.
icmpv4_type <number> ip_proto = 0x01 OpenFlow 1.2+ Can be hexadecimal (with leading 0x) or decimal.
icmpv4_code <number> ip_proto = 0x01 OpenFlow 1.2+ Can be hexadecimal (with leading 0x) or decimal.
icmpv6_type <number> ip_proto = 0x3a OpenFlow 1.2+ Can be hexadecimal (with leading 0x) or decimal.
icmpv6_code <number> ip_proto = 0x3a
OpenFlow 1.2+ Can be hexadecimal (with leading 0x) or decimal.
ipv6_nd_ssl <MAC address> icmpv6_type = 0x87 OpenFlow 1.2+
xx:xx:xx:xx:xx:xx
ipv6_nd_ttl <MAC address> icmpv6_type = 0x88 OpenFlow 1.2+
xx:xx:xx:xx:xx:xx
ipv6_nd_target <IPv6 address> icmpv6_type = 0x87 || 0x88 OpenFlow 1.2+
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
arp_opcode <number> eth_type = 0x0806 OpenFlow 1.2+ Can be hexadecimal (with leading 0x) or decimal.
arp_sha <MAC address> eth_type = 0x0806
OpenFlow 1.2+
xx:xx:xx:xx:xx:xx
arp_tha <MAC address> eth_type = 0x0806
OpenFlow 1.2+
xx:xx:xx:xx:xx:xx
arp_spa <IPv4 address> eth_type = 0x0806 OpenFlow 1.2+
xx.xx.xx.xx
arp_tpa <IPv4 address> eth_type = 0x0806
OpenFlow 1.2+
xx.xx.xx.xx
mpls_label <number> eth_type = 0x8847 || 0x8848 OpenFlow 1.2+
Can be hexadecimal (with leading 0x) or decimal.
mpls_tc <number> eth_type = 0x8847 || 0x8848
OpenFlow 1.2+
Can be hexadecimal (with leading 0x) or decimal.
mpls_bos <boolean> eth_type = 0x8847 || 0x8848
OpenFlow 1.3+ "true" or "false"
tunnel_id <number>   OpenFlow 1.3+ Can be hexadecimal (with leading 0x) or decimal.
metadata <number>   OpenFlow 1.2+
Can be hexadecimal (with leading 0x) or decimal.

Possible Action and Instruction Lists

Key Value OpenFlow Versions Notes
actions <list of actions>
<action1=value1,action2=value2,...>
OpenFlow 1.0 (technically) Can be used in place of instruction_apply_actions for OpenFlow 1.1+.
instruction_apply_actions <list of actions>
<action1=value1,action2=value2,...>
OpenFlow 1.1+ OpenFlow 1.2+ uses OXM (match) syntax to specify set_field actions.
instruction_write_actions <list of actions>
<action1=value1,action2=value2,...>
OpenFlow 1.1+ OpenFlow 1.2+ uses OXM (match) syntax to specify set_field actions.
instruction_clear_actions   OpenFlow 1.1+  
instruction_write_metadata <number> OpenFlow 1.1+  
instruction_goto_table <number> OpenFlow 1.1+
instruction_goto_meter <number> OpenFlow 1.3+  

Possible Actions within the Action and Instruction fields:

Key 
Value Prerequisite Matches OpenFlow Versions Notes
output <number> 
all 
controller 
local 
ingress-port 
normal 
flood
  all No "drop" option.
(Instead, specify no action to drop packets.)
Can be hexadecimal (with leading 0x) or decimal.
table <number>   OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
group <number>   OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
enqueue <number>:<number>   OpenFlow 1.0 First number is port number, second is queue ID.  
Can be hexadecimal (with leading 0x) or decimal.
set_queue <number>   OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
strip_vlan   eth_vlan_vid = something
OpenFlow 1.0  
set_vlan_vid <number> eth_vlan_vid = something 
all Can be hexadecimal (with leading 0x) or decimal.
set_vlan_pcp <number> eth_vlan_vid = something all Can be hexadecimal (with leading 0x) or decimal.
push_vlan <number>     Can be hexadecimal (with leading 0x) or decimal.
pop_vlan   eth_vlan_vid = something    
set_eth_src <MAC address>   OpenFlow 1.0 - 1.1 xx:xx:xx:xx:xx:xx
set_eth_dst <MAC address>   OpenFlow 1.0 - 1.1
xx:xx:xx:xx:xx:xx
set_ip_tos <number> eth_type = 0x0800 || 0x86dd
OpenFlow 1.0
Can be hexadecimal (with leading 0x) or decimal.
set_ip_ecn <number> eth_type = 0x0800 || 0x86dd
OpenFlow 1.1 Can be hexadecimal (with leading 0x) or decimal.
set_ipv4_src <IPv4 address> eth_type = 0x0800
OpenFlow 1.0 - 1.1
xx.xx.xx.xx
set_ipv4_dst <IPv4 address> eth_type = 0x0800
OpenFlow 1.0 - 1.1
xx.xx.xx.xx
set_ip_ttl <number> eth_type = 0x0800 || 0x86dd OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
dec_ip_ttl   eth_type = 0x0800 || 0x86dd
OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
copy_ip_ttl_in   eth_type = 0x0800 || 0x86dd
OpenFlow 1.1+  
copy_ip_ttl_out   eth_type = 0x0800 || 0x86dd
OpenFlow 1.1+  
set_mpls_label <number> eth_type = 0x8847 || 0x8848 OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
set_mpls_tc <number> eth_type = 0x8847 || 0x8848 OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
set_mpls_ttl <number> eth_type = 0x8847 || 0x8848
OpenFlow 1.1+ Can be hexadecimal (with leading 0x) or decimal.
dec_mpls_ttl   eth_type = 0x8847 || 0x8848
OpenFlow 1.1+  
push_mpls <number>   OpenFlow 1.1+
Can be hexadecimal (with leading 0x) or decimal.
pop_mpls <number> eth_type = 0x8847 || 0x8848
OpenFlow 1.1+
Can be hexadecimal (with leading 0x) or decimal.
push_pbb <number>   OpenFlow 1.1+
Can be hexadecimal (with leading 0x) or decimal.
pop_pbb   eth_type = 0x88e7 OpenFlow 1.1+
 
set_tp_src <number> ip_proto = 0x06 || 0x11 || 0x84
OpenFlow 1.0 Can be hexadecimal (with leading 0x) or decimal.
set_tp_dst <number> ip_proto = 0x06 || 0x11 || 0x84
OpenFlow 1.0 Can be hexadecimal (with leading 0x) or decimal.
set_field <OXM->value> See match table above. OpenFlow 1.2+ e.g. "set_field=eth_src->00:11:22:33:44:55"

Using Static Flow Pusher in practice

The Static Flow Pusher can be scripted using simple python code to control a network. As an example, set up a simple network in a mininet VM after starting the Floodlight controller. The default topology is one switch (s1) and two hosts connected to it (h2 and h3).

 sudo mn --controller=remote,ip=<controller ip>,port=6653
 sudo mn --controller=remote,ip=<controller ip>,port=6653 --switch ovsk,protocols=OpenFlow13

The code below will insert a flow from h2 to h3 and one from h3 to h2:

import httplib
import json

class StaticFlowPusher(object):

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

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

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

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

    def rest_call(self, data, action):
        path = '/wm/staticflowpusher/json'
        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

pusher = StaticFlowPusher('<insert_controller_ip')

flow1 = {
    'switch':"00:00:00:00:00:00:00:01",
    "name":"flow_mod_1",
    "cookie":"0",
    "priority":"32768",
    "in_port":"1",
    "active":"true",
    "actions":"output=flood"
    }

flow2 =	{
    'switch':"00:00:00:00:00:00:00:01",
    "name":"flow_mod_2",
    "cookie":"0",
    "priority":"32768",
    "in_port":"2",
    "active":"true",
    "actions":"output=flood"
    }

pusher.set(flow1)
pusher.set(flow2)

To test this out, run a pingtest in the mininet vm (note: you may want to disable the learning switch and other routing code in advance to make sure your static flows are taken).

mininet> h2 ping h3

As an example unrelated to the one above, the following demonstrates how to use the Static Flow Pusher to insert flows that modify header fields in OpenFlow 1.3:

flow3 = {
    'switch':"00:00:00:00:00:00:00:01",
    "name":"flow_mod_3",
    "cookie":"0",
    "priority":"32768",
    "in_port":"1",
    "eth_type":"0x0806"
    "active":"true",
    "instruction_apply_actions":"set_field=arp_tpa->10.0.0.2,output=2"
    }
flow4 = {
    'switch':"00:00:00:00:00:00:00:01",
    "name":"flow_mod_4",
    "cookie":"0",
    "priority":"32768",
    "in_port":"1",
    "eth_type":"0x0806"
    "active":"true",
    "actions":"set_field=arp_tpa->10.0.0.2,output=2"
    }

flow3 and flow4 are equivalent. The former uses the proper instruction to apply the actions immediately in an OpenFlow 1.1+ sense. The latter also works; the "actions" key is interpreted as "instruction_apply_actions" if supplied for an OpenFlow 1.1+ switch. Note the use of "set_field" to set the target protocol address of matching ARP packets to 10.0.0.2.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.