1. Basic requirements
1. Write a Python program and call the northbound interface of OpenDaylight to achieve the following functions
(1) Use the Mininet platform to build the network topology shown in the figure below, and connect;
-
Build topology
sudo mn --topo=single,3 --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow13 -
Beryllium Version Connect OpenDaylight
./distribution-karaf-0.4.4-Beryllium-SR4/bin/karaf feature:install odl-restconf odl-l2switch-switch-ui odl-openflowplugin-all odl-mdsal-apidocs odl-dlux-core odl-dlux-node odl-dlux-yangui
(2) Issue an instruction to delete the flow table data on s1.
- Create and write delete.py file
#!/usr/bin/python import requests from requests.auth import HTTPBasicAuth if __name__ == "__main__": url = 'http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/' headers = {'Content-Type': 'application/json'} res = requests.delete(url, headers=headers, auth=HTTPBasicAuth('admin', 'admin')) print (res.content)
- Command line input python3 delete.py
(3) Distribute the hard timeout flow table to realize the network interruption of hosts h1 and h3 in the topology for 20s.
- Create and write timeout.py file
#!/usr/bin/python import requests from requests.auth import HTTPBasicAuth if __name__ == "__main__": url = 'http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/1' with open("./timeout.json") as file: str = file.read() headers = {'Content-Type': 'application/json'} res = requests.put(url, str, headers=headers, auth=HTTPBasicAuth('admin', 'admin')) print (res.content)
- Create and write timeout.json file
{ "flow": [ { "id": "1", "match": { "in-port": "1", "ethernet-match": { "ethernet-type": { "type": "0x0800" } }, "ipv4-destination": "10.0.0.3/32" }, "instructions": { "instruction": [ { "order": "0", "apply-actions": { "action": [ { "order": "0", "drop-action": {} } ] } } ] }, "flow-name": "flow", "priority": "65535", "hard-timeout": "20", "cookie": "2", "table_id": "0" } ] }
(4) Get the number of active flow tables on s1.
- Create and write the getflow.py file
#!/usr/bin/python import requests from requests.auth import HTTPBasicAuth if __name__ == "__main__": url = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/opendaylight-flow-table-statistics:flow-table-statistics' headers = {'Content-Type': 'application/json'} res = requests.get(url,headers=headers, auth=HTTPBasicAuth('admin', 'admin')) print (res.content)
2. Write a Python program and call the northbound interface of Ryu to achieve the following functions
(1) Implement the same hard timeout flow table delivery on the OpenDaylight experimental topology above.
- Create and write ryu_timeout.py file
# ryu_timeout.py import requests if __name__ == "__main__": url = 'http://127.0.0.1:8080/stats/flowentry/add' with open("./ryu_timeout.json") as file: str = file.read() headers = {'Content-Type': 'application/json'} res = requests.post(url, str, headers=headers) print (res.content)
- Create and write ryu_timeout.json file
# ryu_timeout.json { "dpid": 1, "cookie": 1, "cookie_mask": 1, "table_id": 0, "hard_timeout": 20, "priority": 65535, "flags": 1, "match":{ "in_port":1 }, "actions":[ ] }
- Shut down ODL controller, close last topology and clear topology sudo mn -c
- Start ryu controller ryu-manager ryu.app.simple_switch_13 ryu.app.ofctl_rest
- Create topology sudo mn --topo=single,3 --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow13
- h1 ping h3 , run python3 ryu_timeout.py
(2) Refer to the documentation of Ryu REST API, based on the network topology of the VLAN experiment, program the same VLAN configuration.
- Create and write the ryu_topo.py file
#topo.py from mininet.topo import Topo class MyTopo(Topo): def __init__(self): # initilaize topology Topo.__init__(self) self.addSwitch("s1") self.addSwitch("s2") self.addHost("h1") self.addHost("h2") self.addHost("h3") self.addHost("h4") self.addLink("s1", "h1") self.addLink("s1", "h2") self.addLink("s2", "h3") self.addLink("s2", "h4") self.addLink("s1", "s2") topos = {'mytopo': (lambda: MyTopo())}
- Create and write the ryu_vlan.py file
import json import requests if __name__ == "__main__": url = 'http://127.0.0.1:8080/stats/flowentry/add' headers = {'Content-Type': 'application/json'} flow1 = { "dpid": 1, "priority": 1, "match":{ "in_port": 1 }, "actions":[ { "type": "PUSH_VLAN", "ethertype": 33024 }, { "type": "SET_FIELD", "field": "vlan_vid", "value": 4096 }, { "type": "OUTPUT", "port": 3 } ] } flow2 = { "dpid": 1, "priority": 1, "match":{ "in_port": 2 }, "actions":[ { "type": "PUSH_VLAN", "ethertype": 33024 }, { "type": "SET_FIELD", "field": "vlan_vid", "value": 4097 }, { "type": "OUTPUT", "port": 3 } ] } flow3 = { "dpid": 1, "priority": 1, "match":{ "vlan_vid": 0 }, "actions":[ { "type": "POP_VLAN", "ethertype": 33024 }, { "type": "OUTPUT", "port": 1 } ] } flow4 = { "dpid": 1, "priority": 1, "match": { "vlan_vid": 1 }, "actions": [ { "type": "POP_VLAN", "ethertype": 33024 }, { "type": "OUTPUT", "port": 2 } ] } flow5 = { "dpid": 2, "priority": 1, "match": { "in_port": 1 }, "actions": [ { "type": "PUSH_VLAN", "ethertype": 33024 }, { "type": "SET_FIELD", "field": "vlan_vid", "value": 4096 }, { "type": "OUTPUT", "port": 3 } ] } flow6 = { "dpid": 2, "priority": 1, "match": { "in_port": 2 }, "actions": [ { "type": "PUSH_VLAN", "ethertype": 33024 }, { "type": "SET_FIELD", "field": "vlan_vid", "value": 4097 }, { "type": "OUTPUT", "port": 3 } ] } flow7 = { "dpid": 2, "priority": 1, "match": { "vlan_vid": 0 }, "actions": [ { "type": "POP_VLAN", "ethertype": 33024 }, { "type": "OUTPUT", "port": 1 } ] } flow8 = { "dpid": 2, "priority": 1, "match": { "vlan_vid": 1 }, "actions": [ { "type": "POP_VLAN", "ethertype": 33024 }, { "type": "OUTPUT", "port": 2 } ] } res1 = requests.post(url, json.dumps(flow1), headers=headers) res2 = requests.post(url, json.dumps(flow2), headers=headers) res3 = requests.post(url, json.dumps(flow3), headers=headers) res4 = requests.post(url, json.dumps(flow4), headers=headers) res5 = requests.post(url, json.dumps(flow5), headers=headers) res6 = requests.post(url, json.dumps(flow6), headers=headers) res7 = requests.post(url, json.dumps(flow7), headers=headers) res8 = requests.post(url, json.dumps(flow8), headers=headers)
-
Shut down the controller, close the topology of the last experiment and clear sudo mn -c
-
Start Ryu controller ryu-manager ryu.app.simple_switch_13 ryu.app.ofctl_rest
-
Create topology sudo sudo mn --custom ryu_topo.py --topo mytopo --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow13
-
Install curl sudo apt install curl
-
delete flow table
curl -X DELETE http://127.0.0.1:8080/stats/flowentry/clear/1
curl -X DELETE http://127.0.0.1:8080/stats/flowentry/clear/2 -
run python3 ryu_vlan.py
Advanced requirements
1. Choose either OpenDaylight or Ryu to programmatically view the names of all nodes (including switches and hosts) in the pre-order VLAN experimental topology, and display all flow entries of each switch.
- Create and write the getall.py file
#getall.py import requests import time import re class GetNodes: def __init__(self, ip): self.ip = ip def get_switch_id(self): url = 'http://' + self.ip + '/stats/switches' re_switch_id = requests.get(url=url).json() switch_id_hex = [] for i in re_switch_id: switch_id_hex.append(hex(i)) return switch_id_hex def getflow(self): url = 'http://' + self.ip + '/stats/flow/%d' switch_list = self.get_switch_id() ret_flow = [] for switch in switch_list: new_url = format(url % int(switch, 16)) re_switch_flow = requests.get(url=new_url).json() ret_flow.append(re_switch_flow) return ret_flow def show(self): flow_list = self.getflow() for flow in flow_list: for dpid in flow.keys(): dp_id = dpid switchnum= '{1}'.format(hex(int(dp_id)), int(dp_id)) print('s'+switchnum,end = " ") switchnum = int(switchnum) for list_table in flow.values(): for table in list_table: string1 = str(table) if re.search("'dl_vlan': '(.*?)'", string1) is not None: num = re.search("'dl_vlan': '(.*?)'", string1).group(1); if num == '0' and switchnum == 1: print('h1',end = " ") if num == '1' and switchnum == 1: print('h2',end = " ") if num == '0' and switchnum == 2: print('h3',end = " ") if num == '1' and switchnum == 2: print('h4',end = " ") print("") flow_list = self.getflow() for flow in flow_list: for dpid in flow.keys(): dp_id = dpid print('switch_name:s{1}'.format(hex(int(dp_id)), int(dp_id))) for list_table in flow.values(): for table in list_table: print(table) s1 = GetNodes("127.0.0.1:8080") s1.show()
- run python3 getall.py
Personal summary
- This experiment is relatively comprehensive, using the previous knowledge of OpenDaylight and Ryu, and it was successfully completed after review. After this experiment, I roughly wrote a program to call OpenDaylight REST API and Ryu REST API to implement specific network functions. Although small problems occurred frequently during the experiment, fortunately, the reference materials were relatively abundant. By reading the relevant documents and the help of classmates, the experiment was successfully completed by referring to the relevant routines.
There are mainly two types of problems encountered. First, when deleting the flow table, the curl library was not installed and an error was reported. After installation, Ryu did not run and could not be deleted. The second problem is that you forget to use sudo mn -c to clear the topology, resulting in incorrect experimental results.