Firewall

This section describes how to use Firewall, which can be set using REST.

Example of operation of a single tenant (IPv4)

The following shows an example of creating a topology such as the following and adding or deleting a route or address for switch s1.

_images/fig13.png

Environment Building

First, build an environment on Mininet. The commands to be entered are the same as “Switching Hub

$ sudo mn --topo single,3 --mac --switch ovsk --controller remote -x
*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6633
*** Adding hosts:
h1 h2 h3
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1)
*** Configuring hosts
h1 h2 h3
*** Running terms on localhost:10.0
*** Starting controller
*** Starting 1 switches
s1

*** Starting CLI:
mininet>

Also, start another xterm for the controller.

mininet> xterm c0
mininet>

Next, set the version of OpenFlow to be used in each router to 1.3.

switch: s1 (root):

# ovs-vsctl set Bridge s1 protocols=OpenFlow13

Finally, start rest_firewall on xterm of the controller.

controller: c0 (root):

# ryu-manager ryu.app.rest_firewall
loading app ryu.app.rest_firewall
loading app ryu.controller.ofp_handler
instantiating app None of DPSet
creating context dpset
creating context wsgi
instantiating app ryu.app.rest_firewall of RestFirewallAPI
instantiating app ryu.controller.ofp_handler of OFPHandler
(2210) wsgi starting up on http://0.0.0.0:8080/

After a successful connection between the router and Ryu, the following message appears.

controller: c0 (root):

[FW][INFO] switch_id=0000000000000001: Join as firewall

Changing in the initial state

Immediately after starting the firewall, it was set to disable status to cut off all communication. Enable it with the following command.

Note

For details of REST API used in the following description, please see “REST API List” at the end of the section.

Node: c0 (root):

# curl -X PUT http://localhost:8080/firewall/module/enable/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": {
        "result": "success",
        "details": "firewall running."
      }
    }
  ]

# curl http://localhost:8080/firewall/module/status
  [
    {
      "status": "enable",
      "switch_id": "0000000000000001"
    }
  ]

Note

The result of the REST command is formatted for easy viewing.

Check ping communication from h1 to h2. Since access permission rules are not set, communication will be blocked.

host: h1:

# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
^C
--- 10.0.0.2 ping statistics ---
20 packets transmitted, 0 received, 100% packet loss, time 19003ms

Packets that are blocked are output to the log.

controller: c0 (root):

[FW][INFO] dpid=0000000000000001: Blocked packet = ethernet(dst='00:00:00:00:00:02',ethertype=2048,src='00:00:00:00:00:01'), ipv4(csum=9895,dst='10.0.0.2',flags=2,header_length=5,identification=0,offset=0,option=None,proto=1,src='10.0.0.1',tos=0,total_length=84,ttl=64,version=4), icmp(code=0,csum=55644,data=echo(data='K\x8e\xaeR\x00\x00\x00\x00=\xc6\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567',id=6952,seq=1),type=8)
...

Adding a Rule

Add a rule to permit pinging between h1 and h2. You need to add the rule for both ways.

Let’s add the following rules. Rule ID is assigned automatically.

Source Destination Protocol Permission (Rule ID)
10.0.0.1/32 10.0.0.2/32 ICMP Allow 1
10.0.0.2/32 10.0.0.1/32 ICMP Allow 2

Node: c0 (root):

# curl -X POST -d '{"nw_src": "10.0.0.1/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=1"
        }
      ]
    }
  ]

# curl -X POST -d '{"nw_src": "10.0.0.2/32", "nw_dst": "10.0.0.1/32", "nw_proto": "ICMP"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=2"
        }
      ]
    }
  ]

Added rules are registered in the switch as flow entries.

switch: s1 (root):

# ovs-ofctl -O openflow13 dump-flows s1
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=823.705s, table=0, n_packets=10, n_bytes=420, priority=65534,arp actions=NORMAL
 cookie=0x0, duration=542.472s, table=0, n_packets=20, n_bytes=1960, priority=0 actions=CONTROLLER:128
 cookie=0x1, duration=145.05s, table=0, n_packets=0, n_bytes=0, priority=1,icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2 actions=NORMAL
 cookie=0x2, duration=118.265s, table=0, n_packets=0, n_bytes=0, priority=1,icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1 actions=NORMAL

In addition, add a rule to allow all IPv4 packets, including ping, between h3 and h2.

Source Destination Protocol Permission (Rule ID)
10.0.0.2/32 10.0.0.3/32 any Allow 3
10.0.0.3/32 10.0.0.2/32 any Allow 4

Node: c0 (root):

# curl -X POST -d '{"nw_src": "10.0.0.2/32", "nw_dst": "10.0.0.3/32"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=3"
        }
      ]
    }
  ]

# curl -X POST -d '{"nw_src": "10.0.0.3/32", "nw_dst": "10.0.0.2/32"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=4"
        }
      ]
    }
  ]

Added rules are registered in the switch as flow entries.

switch: s1 (root):

OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x3, duration=12.724s, table=0, n_packets=0, n_bytes=0, priority=1,ip,nw_src=10.0.0.2,nw_dst=10.0.0.3 actions=NORMAL
 cookie=0x4, duration=3.668s, table=0, n_packets=0, n_bytes=0, priority=1,ip,nw_src=10.0.0.3,nw_dst=10.0.0.2 actions=NORMAL
 cookie=0x0, duration=1040.802s, table=0, n_packets=10, n_bytes=420, priority=65534,arp actions=NORMAL
 cookie=0x0, duration=759.569s, table=0, n_packets=20, n_bytes=1960, priority=0 actions=CONTROLLER:128
 cookie=0x1, duration=362.147s, table=0, n_packets=0, n_bytes=0, priority=1,icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2 actions=NORMAL
 cookie=0x2, duration=335.362s, table=0, n_packets=0, n_bytes=0, priority=1,icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1 actions=NORMAL

Priority can be set to rules.

Try to add a rule to block pings (ICMP) between h3 and h2. Set a value greater than 1, which is default value of priority.

(Priority) Source Destination Protocol Permission (Rule ID)
10 10.0.0.2/32 10.0.0.3/32 ICMP Block 5
10 10.0.0.3/32 10.0.0.2/32 ICMP Block 6

Node: c0 (root):

# curl -X POST -d  '{"nw_src": "10.0.0.2/32", "nw_dst": "10.0.0.3/32", "nw_proto": "ICMP", "actions": "DENY", "priority": "10"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=5"
        }
      ]
    }
  ]

# curl -X POST -d  '{"nw_src": "10.0.0.3/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP", "actions": "DENY", "priority": "10"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=6"
        }
      ]
    }
  ]

Added rules are registered in the switch as flow entries.

switch: s1 (root):

# ovs-ofctl -O openflow13 dump-flows s1
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x3, duration=242.155s, table=0, n_packets=0, n_bytes=0, priority=1,ip,nw_src=10.0.0.2,nw_dst=10.0.0.3 actions=NORMAL
 cookie=0x4, duration=233.099s, table=0, n_packets=0, n_bytes=0, priority=1,ip,nw_src=10.0.0.3,nw_dst=10.0.0.2 actions=NORMAL
 cookie=0x0, duration=1270.233s, table=0, n_packets=10, n_bytes=420, priority=65534,arp actions=NORMAL
 cookie=0x0, duration=989s, table=0, n_packets=20, n_bytes=1960, priority=0 actions=CONTROLLER:128
 cookie=0x5, duration=26.984s, table=0, n_packets=0, n_bytes=0, priority=10,icmp,nw_src=10.0.0.2,nw_dst=10.0.0.3 actions=CONTROLLER:128
 cookie=0x1, duration=591.578s, table=0, n_packets=0, n_bytes=0, priority=1,icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2 actions=NORMAL
 cookie=0x6, duration=14.523s, table=0, n_packets=0, n_bytes=0, priority=10,icmp,nw_src=10.0.0.3,nw_dst=10.0.0.2 actions=CONTROLLER:128
 cookie=0x2, duration=564.793s, table=0, n_packets=0, n_bytes=0, priority=1,icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1 actions=NORMAL

Confirming Rules

Confirm the rules that have been set.

Node: c0 (root):

# curl http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "access_control_list": [
        {
          "rules": [
            {
              "priority": 1,
              "dl_type": "IPv4",
              "nw_dst": "10.0.0.3",
              "nw_src": "10.0.0.2",
              "rule_id": 3,
              "actions": "ALLOW"
            },
            {
              "priority": 1,
              "dl_type": "IPv4",
              "nw_dst": "10.0.0.2",
              "nw_src": "10.0.0.3",
              "rule_id": 4,
              "actions": "ALLOW"
            },
            {
              "priority": 10,
              "dl_type": "IPv4",
              "nw_proto": "ICMP",
              "nw_dst": "10.0.0.3",
              "nw_src": "10.0.0.2",
              "rule_id": 5,
              "actions": "DENY"
            },
            {
              "priority": 1,
              "dl_type": "IPv4",
              "nw_proto": "ICMP",
              "nw_dst": "10.0.0.2",
              "nw_src": "10.0.0.1",
              "rule_id": 1,
              "actions": "ALLOW"
            },
            {
              "priority": 10,
              "dl_type": "IPv4",
              "nw_proto": "ICMP",
              "nw_dst": "10.0.0.2",
              "nw_src": "10.0.0.3",
              "rule_id": 6,
              "actions": "DENY"
            },
            {
              "priority": 1,
              "dl_type": "IPv4",
              "nw_proto": "ICMP",
              "nw_dst": "10.0.0.1",
              "nw_src": "10.0.0.2",
              "rule_id": 2,
              "actions": "ALLOW"
            }
          ]
        }
      ],
      "switch_id": "0000000000000001"
    }
  ]

The following shows the rules set.

_images/fig21.png

Try to send a ping from h1 to h2. Since rules to allow communication are set, the ping will go through.

host: h1:

# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=0.419 ms
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.047 ms
64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=0.060 ms
64 bytes from 10.0.0.2: icmp_req=4 ttl=64 time=0.033 ms
...

Packets from h1 to h2 other than ping are blocked by the firewall. For example, if you execute wget from h1 to h2, a log is output that packets were blocked.

host: h1:

# wget http://10.0.0.2
--2013-12-16 15:00:38--  http://10.0.0.2/
Connecting to 10.0.0.2:80... ^C

controller: c0 (root):

[FW][INFO] dpid=0000000000000001: Blocked packet = ethernet(dst='00:00:00:00:00:02',ethertype=2048,src='00:00:00:00:00:01'), ipv4(csum=4812,dst='10.0.0.2',flags=2,header_length=5,identification=5102,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=60,ttl=64,version=4), tcp(ack=0,bits=2,csum=45753,dst_port=80,offset=10,option='\x02\x04\x05\xb4\x04\x02\x08\n\x00H:\x99\x00\x00\x00\x00\x01\x03\x03\t',seq=1021913463,src_port=42664,urgent=0,window_size=14600)
...

Between h2 and 3h, packets other than ping can communicate. For example, if you execute ssh from h2 to h3, it will not output a log that packets were blocked. (Since sshd is not operating in h3, communication by ssh will fail.)

host: h2:

# ssh 10.0.0.3
ssh: connect to host 10.0.0.3 port 22: Connection refused

If you execute ping from h2 to h3, a log is output that packets were blocked by the firewall.

host: h2:

# ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
^C
--- 10.0.0.3 ping statistics ---
8 packets transmitted, 0 received, 100% packet loss, time 7055ms

controller: c0 (root):

[FW][INFO] dpid=0000000000000001: Blocked packet = ethernet(dst='00:00:00:00:00:03',ethertype=2048,src='00:00:00:00:00:02'), ipv4(csum=9893,dst='10.0.0.3',flags=2,header_length=5,identification=0,offset=0,option=None,proto=1,src='10.0.0.2',tos=0,total_length=84,ttl=64,version=4), icmp(code=0,csum=35642,data=echo(data='\r\x12\xcaR\x00\x00\x00\x00\xab\x8b\t\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567',id=8705,seq=1),type=8)
...

Deleting a Rule

Delete the “rule_id:5” and “rule_id:6” rules.

Node: c0 (root):

# curl -X DELETE -d '{"rule_id": "5"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule deleted. : ruleID=5"
        }
      ]
    }
  ]

# curl -X DELETE -d '{"rule_id": "6"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule deleted. : ruleID=6"
        }
      ]
    }
  ]

The following shows the current rules.

_images/fig31.png

Let’s confirm them. Since the rule to block pings (ICMP) between h2 and h3 is deleted, you can see that ping can now communicate.

host: h2:

# ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_req=1 ttl=64 time=0.841 ms
64 bytes from 10.0.0.3: icmp_req=2 ttl=64 time=0.036 ms
64 bytes from 10.0.0.3: icmp_req=3 ttl=64 time=0.026 ms
64 bytes from 10.0.0.3: icmp_req=4 ttl=64 time=0.033 ms
...

Example of the Operation of a Multi-tenant (IPv4)

The following shows an example of creating a topology where tenants are divided by VLAN such as the following and routes or addresses for each switch s1 are added or deleted and communication availability between each host is verified.

_images/fig4.png

Building an Environment

As with the example of Single-tenant, build an environment on Mininet and start another xterm for controller. Note that there is one more host to be used than before.

$ sudo mn --topo single,4 --mac --switch ovsk --controller remote -x
*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6633
*** Adding hosts:
h1 h2 h3 h4
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1) (h4, s1)
*** Configuring hosts
h1 h2 h3 h4
*** Running terms on localhost:10.0
*** Starting controller
*** Starting 1 switches
s1

*** Starting CLI:
mininet> xterm c0
mininet>

Next, set the VLAN ID to the interface of each host.

host: h1:

# ip addr del 10.0.0.1/8 dev h1-eth0
# ip link add link h1-eth0 name h1-eth0.2 type vlan id 2
# ip addr add 10.0.0.1/8 dev h1-eth0.2
# ip link set dev h1-eth0.2 up

host: h2:

# ip addr del 10.0.0.2/8 dev h2-eth0
# ip link add link h2-eth0 name h2-eth0.2 type vlan id 2
# ip addr add 10.0.0.2/8 dev h2-eth0.2
# ip link set dev h2-eth0.2 up

host: h3:

# ip addr del 10.0.0.3/8 dev h3-eth0
# ip link add link h3-eth0 name h3-eth0.110 type vlan id 110
# ip addr add 10.0.0.3/8 dev h3-eth0.110
# ip link set dev h3-eth0.110 up

host: h4:

# ip addr del 10.0.0.4/8 dev h4-eth0
# ip link add link h4-eth0 name h4-eth0.110 type vlan id 110
# ip addr add 10.0.0.4/8 dev h4-eth0.110
# ip link set dev h4-eth0.110 up

Then, set the version of OpenFlow to be used in each router to 1.3.

switch: s1 (root):

# ovs-vsctl set Bridge s1 protocols=OpenFlow13

Finally, start rest_firewall on an xterm of the controller.

controller: c0 (root):

# ryu-manager ryu.app.rest_firewall
loading app ryu.app.rest_firewall
loading app ryu.controller.ofp_handler
instantiating app None of DPSet
creating context dpset
creating context wsgi
instantiating app ryu.app.rest_firewall of RestFirewallAPI
instantiating app ryu.controller.ofp_handler of OFPHandler
(13419) wsgi starting up on http://0.0.0.0:8080/

After a successful connection between the router and Ryu, the following message appears.

controller: c0 (root):

[FW][INFO] switch_id=0000000000000001: Join as firewall

Changing the Initial State

Enable the firewall.

Node: c0 (root):

# curl -X PUT http://localhost:8080/firewall/module/enable/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": {
        "result": "success",
        "details": "firewall running."
      }
    }
  ]

# curl http://localhost:8080/firewall/module/status
  [
    {
      "status": "enable",
      "switch_id": "0000000000000001"
    }
  ]

Adding Rules

Add a rule to vlan_id = 2 that allows pings (ICMP packets) to be sent and received to 10.0.0.0/8. Since there is a need to set rules in both directions, add two rules.

(Priority) VLAN ID Source Destination Protocol Permission (Rule ID)
1 2 10.0.0.0/8 any ICMP Allow 1
1 2 any 10.0.0.0/8 ICMP Allow 2

Node: c0 (root):

# curl -X POST -d '{"nw_src": "10.0.0.0/8", "nw_proto": "ICMP"}' http://localhost:8080/firewall/rules/0000000000000001/2
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "vlan_id": 2,
          "details": "Rule added. : rule_id=1"
        }
      ]
    }
  ]

# curl -X POST -d '{"nw_dst": "10.0.0.0/8", "nw_proto": "ICMP"}' http://localhost:8080/firewall/rules/0000000000000001/2
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "vlan_id": 2,
          "details": "Rule added. : rule_id=2"
        }
      ]
    }
  ]

Confirming Rules

Confirm the rules that have been set.

Node: c0 (root):

# curl http://localhost:8080/firewall/rules/0000000000000001/all
  [
    {
      "access_control_list": [
        {
          "rules": [
            {
              "priority": 1,
              "dl_type": "IPv4",
              "nw_proto": "ICMP",
              "dl_vlan": 2,
              "nw_src": "10.0.0.0/8",
              "rule_id": 1,
              "actions": "ALLOW"
            },
            {
              "priority": 1,
              "dl_type": "IPv4",
              "nw_proto": "ICMP",
              "nw_dst": "10.0.0.0/8",
              "dl_vlan": 2,
              "rule_id": 2,
              "actions": "ALLOW"
            }
          ],
          "vlan_id": 2
        }
      ],
      "switch_id": "0000000000000001"
    }
  ]

Let’s confirm them. When you execute ping from h1, which is vlan_id=2, to h2 which is also vlan_id=2, you can see that it can communicate per the rules that were added.

host: h1:

# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=0.893 ms
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.098 ms
64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=0.122 ms
64 bytes from 10.0.0.2: icmp_req=4 ttl=64 time=0.047 ms
...

Since there is no rule between h3 and h4, which are both vlan_id=110, packets are blocked.

host: h3:

# ping 10.0.0.4
PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data.
^C
--- 10.0.0.4 ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 4999ms

Since packets are blocked, a log is output.

controller: c0 (root):

[FW][INFO] dpid=0000000000000001: Blocked packet = ethernet(dst='00:00:00:00:00:04',ethertype=33024,src='00:00:00:00:00:03'), vlan(cfi=0,ethertype=2048,pcp=0,vid=110), ipv4(csum=9891,dst='10.0.0.4',flags=2,header_length=5,identification=0,offset=0,option=None,proto=1,src='10.0.0.3',tos=0,total_length=84,ttl=64,version=4), icmp(code=0,csum=58104,data=echo(data='\xb8\xa9\xaeR\x00\x00\x00\x00\xce\xe3\x02\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567',id=7760,seq=4),type=8)
...

Example of operation of a single tenant (IPv6)

The following shows an example of creating a topology where hosts are assigned with IPv6 address such as the following and routes or addresses for each switch s1 are added or deleted and communication availability between each host is verified.

_images/fig5.png

Environment Building

First, build an environment on Mininet. The commands to be entered are the same as “Example of operation of a single tenant (IPv4)”.

$ sudo mn --topo single,3 --mac --switch ovsk --controller remote -x
*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6633
*** Adding hosts:
h1 h2 h3
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1)
*** Configuring hosts
h1 h2 h3
*** Running terms on localhost:10.0
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet>

Also, start another xterm for the controller.

mininet> xterm c0
mininet>

Next, set the version of OpenFlow to be used in each router to 1.3.

switch: s1 (root):

# ovs-vsctl set Bridge s1 protocols=OpenFlow13

Finally, start rest_firewall on xterm of the controller.

controller: c0 (root):

# ryu-manager ryu.app.rest_firewall
loading app ryu.app.rest_firewall
loading app ryu.controller.ofp_handler
instantiating app None of DPSet
creating context dpset
creating context wsgi
instantiating app ryu.app.rest_firewall of RestFirewallAPI
instantiating app ryu.controller.ofp_handler of OFPHandler
(2210) wsgi starting up on http://0.0.0.0:8080/

After a successful connection between the router and Ryu, the following message appears.

controller: c0 (root):

[FW][INFO] switch_id=0000000000000001: Join as firewall

Changing the Initial State

Enable the firewall.

Node: c0 (root):

# curl -X PUT http://localhost:8080/firewall/module/enable/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": {
        "result": "success",
        "details": "firewall running."
      }
    }
  ]

# curl http://localhost:8080/firewall/module/status
  [
    {
      "status": "enable",
      "switch_id": "0000000000000001"
    }
  ]

Adding Rules

Add rules to permit pinging between h1 and h2. You need to add rules for both ways.

Source Destination Protocol Permission (Rule ID) (Note)
fe80::200:ff:fe00:1 fe80::200:ff:fe00:2 ICMPv6 Allow 1 Unicast message (Echo)
fe80::200:ff:fe00:2 fe80::200:ff:fe00:1 ICMPv6 Allow 2 Unicast message (Echo)
fe80::200:ff:fe00:1 ff02::1:ff00:2 ICMPv6 Allow 3 Multicast message (Neighbor Discovery)
fe80::200:ff:fe00:2 ff02::1:ff00:1 ICMPv6 Allow 4 Multicast message (Neighbor Discovery)

Node: c0 (root):

# curl -X POST -d '{"ipv6_src": "fe80::200:ff:fe00:1", "ipv6_dst": "fe80::200:ff:fe00:2", "nw_proto": "ICMPv6"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=1"
        }
      ]
    }
  ]

# curl -X POST -d '{"ipv6_src": "fe80::200:ff:fe00:2", "ipv6_dst": "fe80::200:ff:fe00:1", "nw_proto": "ICMPv6"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=2"
        }
      ]
    }
  ]

# curl -X POST -d '{"ipv6_src": "fe80::200:ff:fe00:1", "ipv6_dst": "ff02::1:ff00:2", "nw_proto": "ICMPv6"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=3"
        }
      ]
    }
  ]

# curl -X POST -d '{"ipv6_src": "fe80::200:ff:fe00:2", "ipv6_dst": "ff02::1:ff00:1", "nw_proto": "ICMPv6"}' http://localhost:8080/firewall/rules/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": [
        {
          "result": "success",
          "details": "Rule added. : rule_id=4"
        }
      ]
    }
  ]

Confirming Rules

Confirm the rules that have been set.

Node: c0 (root):

# curl http://localhost:8080/firewall/rules/0000000000000001/all
  [
    {
      "switch_id": "0000000000000001",
      "access_control_list": [
        {
          "rules": [
            {
              "ipv6_dst": "fe80::200:ff:fe00:2",
              "actions": "ALLOW",
              "rule_id": 1,
              "ipv6_src": "fe80::200:ff:fe00:1",
              "nw_proto": "ICMPv6",
              "dl_type": "IPv6",
              "priority": 1
            },
            {
              "ipv6_dst": "fe80::200:ff:fe00:1",
              "actions": "ALLOW",
              "rule_id": 2,
              "ipv6_src": "fe80::200:ff:fe00:2",
              "nw_proto": "ICMPv6",
              "dl_type": "IPv6",
              "priority": 1
            },
            {
              "ipv6_dst": "ff02::1:ff00:2",
              "actions": "ALLOW",
              "rule_id": 3,
              "ipv6_src": "fe80::200:ff:fe00:1",
              "nw_proto": "ICMPv6",
              "dl_type": "IPv6",
              "priority": 1
            },
            {
              "ipv6_dst": "ff02::1:ff00:1",
              "actions": "ALLOW",
              "rule_id": 4,
              "ipv6_src": "fe80::200:ff:fe00:2",
              "nw_proto": "ICMPv6",
              "dl_type": "IPv6",
              "priority": 1
            }
          ]
        }
      ]
    }
  ]

Let’s confirm them. When you execute ping from h1 to h2, you can see that it can communicate per the rules that were added.

host: h1:

# ping6 -I h1-eth0 fe80::200:ff:fe00:2
PING fe80::200:ff:fe00:2(fe80::200:ff:fe00:2) from fe80::200:ff:fe00:1 h1-eth0: 56 data bytes
64 bytes from fe80::200:ff:fe00:2: icmp_seq=1 ttl=64 time=0.954 ms
64 bytes from fe80::200:ff:fe00:2: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from fe80::200:ff:fe00:2: icmp_seq=3 ttl=64 time=0.055 ms
64 bytes from fe80::200:ff:fe00:2: icmp_seq=4 ttl=64 time=0.027 ms
...

Since there is no rule between h1 and h3, packets are blocked.

host: h1:

# ping6 -I h1-eth0 fe80::200:ff:fe00:3
PING fe80::200:ff:fe00:3(fe80::200:ff:fe00:3) from fe80::200:ff:fe00:1 h1-eth0: 56 data bytes
From fe80::200:ff:fe00:1 icmp_seq=1 Destination unreachable: Address unreachable
From fe80::200:ff:fe00:1 icmp_seq=2 Destination unreachable: Address unreachable
From fe80::200:ff:fe00:1 icmp_seq=3 Destination unreachable: Address unreachable
^C
--- fe80::200:ff:fe00:3 ping statistics ---
4 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2999ms

Since packets are blocked, a log is output.

controller: c0 (root):

[FW][INFO] dpid=0000000000000001: Blocked packet = ethernet(dst='33:33:ff:00:00:03',ethertype=34525,src='00:00:00:00:00:01'), ipv6(dst='ff02::1:ff00:3',ext_hdrs=[],flow_label=0,hop_limit=255,nxt=58,payload_length=32,src='fe80::200:ff:fe00:1',traffic_class=0,version=6), icmpv6(code=0,csum=31381,data=nd_neighbor(dst='fe80::200:ff:fe00:3',option=nd_option_sla(data=None,hw_src='00:00:00:00:00:01',length=1),res=0),type_=135)
...

Example of the Operation of a Multi-tenant (IPv6)

The following shows an example of creating a topology where tenants are divided by VLAN and assigned with IPv6 address such as the following, routes or addresses for each switch s1 are added or deleted and communication availability between each host is verified.

_images/fig6.png

Building an Environment

As with “Example of the Operation of a Multi-tenant (IPv4)”, build an environment on Mininet and start another xterm for controller.

$ sudo mn --topo single,4 --mac --switch ovsk --controller remote -x
*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6633
*** Adding hosts:
h1 h2 h3 h4
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1) (h4, s1)
*** Configuring hosts
h1 h2 h3 h4
*** Running terms on localhost:10.0
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet> xterm c0
mininet>

Next, set the VLAN ID to the interface of each host.

host: h1:

# ip addr del fe80::200:ff:fe00:1/64 dev h1-eth0
# ip link add link h1-eth0 name h1-eth0.2 type vlan id 2
# ip addr add fe80::200:ff:fe00:1/64 dev h1-eth0.2
# ip link set dev h1-eth0.2 up

host: h2:

# ip addr del fe80::200:ff:fe00:2/64 dev h2-eth0
# ip link add link h2-eth0 name h2-eth0.2 type vlan id 2
# ip addr add fe80::200:ff:fe00:2/64 dev h2-eth0.2
# ip link set dev h2-eth0.2 up

host: h3:

# ip addr del fe80::200:ff:fe00:3/64 dev h3-eth0
# ip link add link h3-eth0 name h3-eth0.110 type vlan id 110
# ip addr add fe80::200:ff:fe00:3/64 dev h3-eth0.110
# ip link set dev h3-eth0.110 up

host: h4:

# ip addr del fe80::200:ff:fe00:4/64 dev h4-eth0
# ip link add link h4-eth0 name h4-eth0.110 type vlan id 110
# ip addr add fe80::200:ff:fe00:4/64 dev h4-eth0.110
# ip link set dev h4-eth0.110 up

Then, set the version of OpenFlow to be used in each router to 1.3.

switch: s1 (root):

# ovs-vsctl set Bridge s1 protocols=OpenFlow13

Finally, start rest_firewall on an xterm of the controller.

controller: c0 (root):

# ryu-manager ryu.app.rest_firewall
loading app ryu.app.rest_firewall
loading app ryu.controller.ofp_handler
instantiating app None of DPSet
creating context dpset
creating context wsgi
instantiating app ryu.app.rest_firewall of RestFirewallAPI
instantiating app ryu.controller.ofp_handler of OFPHandler
(13419) wsgi starting up on http://0.0.0.0:8080/

After a successful connection between the router and Ryu, the following message appears.

controller: c0 (root):

[FW][INFO] switch_id=0000000000000001: Join as firewall

Changing the Initial State

Enable the firewall.

Node: c0 (root):

# curl -X PUT http://localhost:8080/firewall/module/enable/0000000000000001
  [
    {
      "switch_id": "0000000000000001",
      "command_result": {
        "result": "success",
        "details": "firewall running."
      }
    }
  ]

# curl http://localhost:8080/firewall/module/status
  [
    {
      "status": "enable",
      "switch_id": "0000000000000001"
    }
  ]

Adding Rules

Add a rule to vlan_id = 2 that allows pings (ICMPv6 packets) to be sent and received to fe80::/64. Since there is a need to set rules in both directions, add two rules.

(Priority) VLAN ID Source Destination Protocol Permission (Rule ID)
1 2 fe80::200:ff:fe00:1 any ICMPv6 Allow 1
1 2 fe80::200:ff:fe00:2 any ICMPv6 Allow 2

Node: c0 (root):

# curl -X POST -d '{"ipv6_src": "fe80::200:ff:fe00:1", "nw_proto": "ICMPv6"}' http://localhost:8080/firewall/rules/0000000000000001/2
  [
    {
      "command_result": [
        {
          "details": "Rule added. : rule_id=1",
          "vlan_id": 2,
          "result": "success"
        }
      ],
      "switch_id": "0000000000000001"
    }
  ]

# curl -X POST -d '{"ipv6_src": "fe80::200:ff:fe00:2", "nw_proto": "ICMPv6"}' http://localhost:8080/firewall/rules/0000000000000001/2
  [
    {
      "command_result": [
        {
          "details": "Rule added. : rule_id=2",
          "vlan_id": 2,
          "result": "success"
        }
      ],
      "switch_id": "0000000000000001"
    }
  ]

Confirming Rules

Confirm the rules that have been set.

Node: c0 (root):

# curl http://localhost:8080/firewall/rules/0000000000000001/all
  [
    {
      "switch_id": "0000000000000001",
      "access_control_list": [
        {
          "vlan_id": "2",
          "rules": [
            {
              "actions": "ALLOW",
              "rule_id": 1,
              "dl_vlan": "2",
              "ipv6_src": "fe80::200:ff:fe00:1",
              "nw_proto": "ICMPv6",
              "dl_type": "IPv6",
              "priority": 1
            },
            {
              "actions": "ALLOW",
              "rule_id": 2,
              "dl_vlan": "2",
              "ipv6_src": "fe80::200:ff:fe00:2",
              "nw_proto": "ICMPv6",
              "dl_type": "IPv6",
              "priority": 1
            }
          ]
        }
      ]
    }
  ]

Let’s confirm them. When you execute ping from h1, which is vlan_id=2, to h2 which is also vlan_id=2, you can see that it can communicate per the rules that were added.

host: h1:

# ping6 -I h1-eth0.2 fe80::200:ff:fe00:2
PING fe80::200:ff:fe00:2(fe80::200:ff:fe00:2) from fe80::200:ff:fe00:1 h1-eth0.2: 56 data bytes
64 bytes from fe80::200:ff:fe00:2: icmp_seq=1 ttl=64 time=0.609 ms
64 bytes from fe80::200:ff:fe00:2: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from fe80::200:ff:fe00:2: icmp_seq=3 ttl=64 time=0.046 ms
64 bytes from fe80::200:ff:fe00:2: icmp_seq=4 ttl=64 time=0.057 ms
...

Since there is no rule between h3 and h4, which are both vlan_id=110, packets are blocked.

host: h3:

# ping6 -I h3-eth0.110 fe80::200:ff:fe00:4
PING fe80::200:ff:fe00:4(fe80::200:ff:fe00:4) from fe80::200:ff:fe00:3 h3-eth0.110: 56 data bytes
From fe80::200:ff:fe00:3 icmp_seq=1 Destination unreachable: Address unreachable
From fe80::200:ff:fe00:3 icmp_seq=2 Destination unreachable: Address unreachable
From fe80::200:ff:fe00:3 icmp_seq=3 Destination unreachable: Address unreachable
^C
--- fe80::200:ff:fe00:4 ping statistics ---
4 packets transmitted, 0 received, +3 errors, 100% packet loss, time 3014ms

Since packets are blocked, a log is output.

controller: c0 (root):

[FW][INFO] dpid=0000000000000001: Blocked packet = ethernet(dst='33:33:ff:00:00:04',ethertype=33024,src='00:00:00:00:00:03'), vlan(cfi=0,ethertype=34525,pcp=0,vid=110), ipv6(dst='ff02::1:ff00:4',ext_hdrs=[],flow_label=0,hop_limit=255,nxt=58,payload_length=32,src='fe80::200:ff:fe00:3',traffic_class=0,version=6), icmpv6(code=0,csum=31375,data=nd_neighbor(dst='fe80::200:ff:fe00:4',option=nd_option_sla(data=None,hw_src='00:00:00:00:00:03',length=1),res=0),type_=135)
...

In this section, you learned how to use the firewall with specific examples.

REST API List

List of REST API of rest_firewall, which is introduced in this section.

Acquiring Enable/Disable State of All Switches

Method GET
URL /firewall/module/status

Changing Enable/Disable State of All Switches

Method PUT
URL

/firewall/module/{op}/{switch}

op: [ “enable” | “disable” ]

switch: [ “all” | Switch ID ]

Remarks Initial state of each switch is “disable”

Acquiring All Rules

Method GET
URL

/firewall/rules/{switch}[/{vlan}]

switch: [ “all” | Switch ID ]

vlan: [ “all” | VLAN ID ]

Remarks Specification of VLAN ID is optional.

Adding Rules

Method POST
URL

/firewall/rules/{switch}[/{vlan}]

switch: [ “all” | Switch ID ]

vlan: [ “all” | VLAN ID ]

Data

priority:[ 0 - 65535 ]

in_port:[ 0 - 65535 ]

dl_src:”<xx:xx:xx:xx:xx:xx>”

dl_dst:”<xx:xx:xx:xx:xx:xx>”

dl_type:[ “ARP” | “IPv4” | “IPv6” ]

nw_src:”<xxx.xxx.xxx.xxx/xx>”

nw_dst:”<xxx.xxx.xxx.xxx/xx>”

ipv6_src:”<xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xx>”

ipv6_dst:”<xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xx>”

nw_proto”:[ “TCP” | “UDP” | “ICMP” | “ICMPv6” ]

tp_src:[ 0 - 65535 ]

tp_dst:[ 0 - 65535 ]

actions: [ “ALLOW” | “DENY” ]

Remarks

When it is successfully registered, Rule ID is generated and is noted in the response.

Specification of VLAN ID is optional.

Deleting Rules

Method DELETE
URL

/firewall/rules/{switch}[/{vlan}]

switch: [ “all” | Switch ID ]

vlan: [ “all” | VLAN ID ]

Data rule_id:[ “all” | 1 - ... ]
Remarks Specification of VLAN ID is optional.

Acquiring Log Output State of All Switches

Method GET
URL /firewall/log/status

Changing Log Output State of All Switches

Method PUT
URL

/firewall/log/{op}/{switch}

op: [ “enable” | “disable” ]

switch: [ “all” | Switch ID ]

Remarks Initial state of each switch is “enable”