param -> path_to_xml (default None)
"""
testloader = unittest.TestLoader()
- testnames = testloader.getTestCaseNames(clazz)
+ testnames = testloader.getTestCaseNames(clazz)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(clazz(name, path_to_xml=path_to_xml))
--- /dev/null
+import unittest
+import os
+import re
+import sys
+import logging
+import time
+import argparse
+import itertools
+import requests
+import xml.dom.minidom as md
+from xml.etree import ElementTree as ET
+
+from odl_tests_new import MininetTools, FileLoaderTools, ParseTools
+
+class TestRestartMininet(unittest.TestCase):
+
+ log = logging.getLogger('TestRestartMininet')
+
+ def setUp(self):
+ TestRestartMininet.log.info('setUp')
+ self.switch_flows_stored = 0
+ self.table_id = 2
+
+ self.__start_MN()
+
+ xmls = self.__load_xmls()
+ for xml in xmls:
+ self.__add_flows(xml)
+
+ def tearDown(self):
+ TestRestartMininet.log.info('tearDown')
+ self.net.stop()
+
+ def __start_MN(self):
+ wait_time = 15
+
+ self.net = MininetTools.create_network(self.host, self.mn_port)
+ self.net.start()
+ TestRestartMininet.log.info('mininet stared')
+ TestRestartMininet.log.info('waiting {} seconds...'.format(wait_time))
+ time.sleep(wait_time)
+
+ def __get_flows_string(self, net=None):
+ if net is None:
+ net = self.net
+ switch = net.switches[0]
+ output = switch.cmdPrint(
+ 'ovs-ofctl -O OpenFlow13 dump-flows %s' % switch.name)
+
+ TestRestartMininet.log.debug('switch flow table: {}'.format(output))
+
+ return output.splitlines()[1:]
+
+ def __load_xmls(self, path='xmls'):
+ TestRestartMininet.log.info('loading xmls')
+ xmls = None
+ suite = unittest.TestSuite()
+ if args.xmls is not None:
+ xmls = map(int, args.xmls.split(','))
+
+ xmlfiles = None
+ if xmls is not None:
+ xmlfiles = (path + '/f%d.xml' % fid for fid in xmls)
+ else:
+ xmlfiles = (path + '/' + xml for xml in os.listdir(path) if xml.endswith('.xml'))
+
+ return xmlfiles
+
+ def __add_flows(self, path_to_xml):
+ TestRestartMininet.log.info('adding flow from xml: {}'.format(path_to_xml))
+ xml_string = FileLoaderTools.load_file_to_string(path_to_xml)
+ #TestRestartMininet.log.info('loaded xml: {}'.format(''.join(xml_string.split())))
+ tree = md.parseString(xml_string)
+
+ ids = ParseTools.get_values(tree.documentElement, 'table_id', 'id')
+
+ data = (self.host, self.port, ids['table_id'], ids['id'])
+
+ url = 'http://%s:%d/restconf/config/opendaylight-inventory:nodes' \
+ '/node/openflow:1/table/%s/flow/%s' % data
+ # send request via RESTCONF
+ headers = {
+ 'Content-Type': 'application/xml',
+ 'Accept': 'application/xml',
+ }
+ TestRestartMininet.log.info('sending request to url: {}'.format(url))
+ rsp = requests.put(url, auth=('admin', 'admin'), data=xml_string,
+ headers=headers)
+ TestRestartMininet.log.info('received status code: {}'.format(rsp.status_code))
+ TestRestartMininet.log.debug('received content: {}'.format(rsp.text))
+ try:
+ assert rsp.status_code == 204 or rsp.status_code == 200, 'Status' \
+ ' code returned %d' % rsp.status_code
+
+ # check request content against restconf's datastore
+ response = requests.get(url, auth=('admin', 'admin'),
+ headers={'Accept': 'application/xml'})
+ assert response.status_code == 200
+
+ switch_flows = self.__get_flows_string(self.net)
+ assert len(switch_flows) > 0
+
+ # store last used table id which got flows for later checkup
+ self.table_id = ids['table_id']
+ self.switch_flows_stored = len(switch_flows)
+ TestRestartMininet.log.info('stored: {} flows'.format(self.switch_flows_stored))
+
+
+ except AssertionError as e:
+ TestRestartMininet.log.error('error adding flow, assert: {}'.format(str(e)))
+ except StandardError as e:
+ TestRestartMininet.log.error('error adding flow: {}'.format(str(e)))
+
+ def test(self):
+
+ switch_flows = 0
+
+ TestRestartMininet.log.info('---------- preparation finished, running test ----------\n\n')
+ assert self.switch_flows_stored > 0, 'don\'t have any stored flows'
+ TestRestartMininet.log.info('got {} stored flows'.format(self.switch_flows_stored))
+
+ #STOP mininet and start it again - then check flows
+ TestRestartMininet.log.info('restaring mininet...')
+ self.net.stop()
+ TestRestartMininet.log.info('mininet stopped')
+ self.__start_MN()
+
+ url = 'http://%s:%d/restconf/config/opendaylight-inventory:nodes' \
+ '/node/openflow:1/table/%s/' % (self.host, self.port, self.table_id)
+ TestRestartMininet.log.info('checking flows in controller - sending request to url: {}'.format(url))
+ response = requests.get(url, auth=('admin', 'admin'),
+ headers={'Accept': 'application/xml'})
+ assert response.status_code == 200
+
+ tree = ET.ElementTree(ET.fromstring(response.text))
+ flows_on_controller = len(tree.getroot())
+ TestRestartMininet.log.info('{} flows are stored in switch config datastore'.format(flows_on_controller))
+
+ current_try = 1
+
+ while current_try <= self.retry and switch_flows != self.switch_flows_stored:
+ TestRestartMininet.log.info('trying to get flows from mininet switch: {}/{}...'.format(current_try, self.retry))
+ TestRestartMininet.log.info('waiting {} more seconds...'.format(self.wait))
+ time.sleep(self.wait)
+ switch_flows = len(self.__get_flows_string(self.net))
+ TestRestartMininet.log.info('got {} flows...'.format(switch_flows))
+ current_try = current_try + 1
+
+ assert self.switch_flows_stored == switch_flows, 'Stored amount of flows on switch should be equal to stored flows on controller'\
+ ' %d <> %d' % (switch_flows,self.switch_flows_stored)
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.INFO)
+
+ # parse cmdline arguments
+ parser = argparse.ArgumentParser(description='Test for flow addition to'
+ ' switch after the switch has been restarted')
+ parser.add_argument('--odlhost', default='127.0.0.1', help='host where '
+ 'odl controller is running')
+ parser.add_argument('--odlport', type=int, default=8080, help='port on '
+ 'which odl\'s RESTCONF is listening')
+ parser.add_argument('--mnport', type=int, default=6653, help='port on '
+ 'which odl\'s controller is listening')
+ parser.add_argument('--xmls', default=None, help='generete tests only '
+ 'from some xmls (i.e. 1,3,34) ')
+ parser.add_argument('--wait', default=60, help='number of second that '
+ 'should test wait before trying to get flows from '
+ 'restared mininet switch')
+ parser.add_argument('--retry', default=2, help='number of tries to get'
+ 'flows from restarted mininet')
+ args = parser.parse_args()
+
+ # set host and port of ODL controller for test cases
+ TestRestartMininet.port = args.odlport
+ TestRestartMininet.host = args.odlhost
+ TestRestartMininet.mn_port = args.mnport
+ TestRestartMininet.wait = args.wait
+ TestRestartMininet.retry = args.retry
+
+ del sys.argv[1:]
+ unittest.main()
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf101</flow-name>
+ <id>256</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>101</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>TABLE</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf102</flow-name>
+ <id>257</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>102</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>INPORT</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>17.1.2.3/8</ipv4-source>
+ <ipv4-destination>172.168.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>2</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>25364</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf103</flow-name>
+ <id>258</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>103</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>1</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>17.1.2.3/8</ipv4-source>
+ <ipv4-destination>172.168.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>2</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>25364</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf104</flow-name>
+ <id>259</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>104</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>LOCAL</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf105</flow-name>
+ <id>260</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>105</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>NORMAL</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/84</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/90</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>45</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>20345</tcp-source-port>
+ <tcp-destination-port>80</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf106</flow-name>
+ <id>261</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>106</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>FLOOD</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/100</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/67</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>45</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>20345</tcp-source-port>
+ <tcp-destination-port>80</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf107</flow-name>
+ <id>262</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>107</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>ALL</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf108</flow-name>
+ <id>263</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>108</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>CONTROLLER</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf109</flow-name>
+ <id>264</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>109</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>ANY</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf101</flow-name>
+ <id>256</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>101</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <set-nw-ttl-action>
+ <nw-ttl>1</nw-ttl>
+ </set-nw-ttl-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+</flow>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>set-field-tcp-src</flow-name>
+ <id>256</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>101</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <set-field>
+ <tcp-source-port>2059</tcp-source-port>
+ </set-field>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+</flow>
+