def test_index_slice_len(self): # These all have dependencies and cannot be interlaced action_list = self.action_list_nonreorderable actions = ActionList(action_list) self.assertEqual(len(action_list), len(actions)) self.assertEqual(0, len(ActionList())) self.assertFalse(ActionList()) self.assertTrue(actions) for i, orig_action in enumerate(action_list): # Check the correct item is returned self.assertEqual(orig_action, actions[i]) # Check the correct index is returned self.assertEqual(i, actions.index(actions[i])) # Now lets check we can do some slicing - note length # Note slicing returns normal lists not Actions back self.assertListEqual(action_list[:], actions[:]) self.assertListEqual(action_list[::-1], actions[::-1]) self.assertListEqual(action_list[2:], actions[2:]) self.assertListEqual(action_list[3::2], actions[3::2]) self.assertListEqual(action_list[1:-1], actions[1:-1]) self.assertListEqual(action_list[1:len(actions) - 1], actions[1:len(actions) - 1])
def setUp(self): self.f = Rule() self.fg1 = Group() self.fg1.type_ = 'INDIRECT' self.fg1.buckets = [ActionList([("OUTPUT", 7)])] self.fg2 = Group() self.fg2.type_ = 'INDIRECT' self.fg2.buckets = [ActionList( [("POP_MPLS", 0x800), ("OUTPUT", 8)])] self.act_apply1 = ActionList( [('GROUP', self.fg1), ("SET_FIELD", ("ETH_DST", 0x1002)), ("OUTPUT", 1)]) self.act_apply2 = ActionList( [("SET_FIELD", ("ETH_DST", 0x1002)), ("OUTPUT", 4), ('GROUP', self.fg2)]) self.act_set1 = ActionSet( [("SET_FIELD", ("IPV4_SRC", 123)), ("OUTPUT", 5)]) self.act_set2 = ActionSet( [("SET_FIELD", ("IPV4_SRC", 321)), ("POP_VLAN", None), ("OUTPUT", 6)]) self.inst1 = Instructions() self.inst1.apply_actions = self.act_apply1 self.inst1.write_actions = self.act_set1 self.inst2 = Instructions() self.inst2.apply_actions = self.act_apply2 self.inst2.write_actions = self.act_set2
def test_adding_lists(self): # Tests the '+', '+=' and copy(add=) operations for Action Lists actions1 = ActionList(self.action_list_complex) actions2 = ActionList(self.action_list_nonreorderable) # This should be the same as adding the two original lists together expected = ActionList(self.action_list_complex + self.action_list_nonreorderable) expected_rev = ActionList(self.action_list_nonreorderable + self.action_list_complex) self._test_add(actions1, actions2, expected, expected_rev)
def test_simple_fully_dep_reverse(self): """ Reversed to ensure it was not fluke sorting """ action_list1 = [("SET_FIELD", ("ETH_DST", 1)), ("SET_FIELD", ("ETH_DST", 45))] action_list2 = [("SET_FIELD", ("VLAN_VID", 0x1015)), ("PUSH_VLAN", 0x88a8), ("SET_FIELD", ("VLAN_VID", 0x100F))] self.assertEqual(action_list1, list(ActionList(action_list1))) self.assertEqual(action_list2, list(ActionList(action_list2)))
def test_action_set_ordering(self): # Test adding sets together and set and list combos actlista = [('OUTPUT', 1), ('SET_FIELD', ('VLAN_VID', 0x1003)), ('SET_FIELD', ('VLAN_PCP', 0x1)), ('PUSH_VLAN', None)] actlista_ordered = [('PUSH_VLAN', None), ('SET_FIELD', ('VLAN_VID', 0x1003)), ('SET_FIELD', ('VLAN_PCP', 0x1)), ('OUTPUT', 1)] actlistb = [('SET_QUEUE', 5), ('SET_FIELD', ('IPV4_SRC', 12))] actlistc = [('SET_FIELD', ('VLAN_PCP', 0x2)), ('PUSH_VLAN', None), ('OUTPUT', 2)] actlistc_ordered = [('PUSH_VLAN', None), ('SET_FIELD', ('VLAN_PCP', 0x2)), ('OUTPUT', 2)] actlistd = [('OUTPUT', 7)] actliste = [('GROUP', 8)] actlistf = [('GROUP', 9)] seta = ActionSet(actlista) setb = ActionSet(actlistb) setc = ActionSet(actlistc) setd = ActionSet(actlistd) sete = ActionSet(actliste) setf = ActionSet(actlistf) # Sanity check, check ordering is correct self.assertEqual(seta, ActionList(actlista_ordered)) self.assertEqual(setc, ActionList(actlistc_ordered)) # Now lets add some sets together! # Set a and b dont overlap, both orders should be equal expected = [('PUSH_VLAN', None), ('SET_FIELD', ('IPV4_SRC', 12)), ('SET_FIELD', ('VLAN_VID', 0x1003)), ('SET_FIELD', ('VLAN_PCP', 0x1)), ('SET_QUEUE', 5), ('OUTPUT', 1)] expected = ActionList(expected) self._test_add(seta, setb, expected, expected) # Set a and c entirely overlap, OUTPUT, VLAN_PCP and QUEUE expected = [('PUSH_VLAN', None), ('SET_FIELD', ('VLAN_VID', 0x1003)), ('SET_FIELD', ('VLAN_PCP', 0x2)), ('OUTPUT', 2)] expected = ActionList(expected) self._test_add(seta, setc, expected, ActionList(actlista_ordered)) # Check special case with 'GROUP', groups overwrite 'OUTPUT' in the # result yet they both can be added expected = ActionSet([('GROUP', 8)]) self._test_add(setd, sete, expected, expected) expectedb = ActionSet([('GROUP', 9)]) self._test_add(sete, setf, expectedb, expected)
def test_simple_unordered(self): """ Test on a couple of sets where order does not matter """ import itertools action_list1 = [("SET_FIELD", ("ETH_DST", 1)), ("SET_FIELD", ("VLAN_VID", 45)), ("SET_QUEUE", 1), ("PUSH_MPLS", 0x8847)] expected = ActionList(action_list1) for permuation in itertools.permutations(action_list1): res = ActionList(permuation) self.assertEqual(expected, res)
def test_simple_fully_dep(self): """ Tests some simple cases in which the order matters and as the such the same result should be expected """ action_list1 = [("SET_FIELD", ("ETH_DST", 45)), ("SET_FIELD", ("ETH_DST", 1))] action_list2 = [("SET_FIELD", ("VLAN_VID", 0x100F)), ("PUSH_VLAN", 0x88a8), ("SET_FIELD", ("VLAN_VID", 0x1015))] self.assertEqual(action_list1, list(ActionList(action_list1))) self.assertEqual(action_list2, list(ActionList(action_list2)))
def test_removal(self): # Check that removing an object works and that lists are # correctly reordered. In the case a something is removed # it may require other items to be placed into a higher level action_list = self.action_list_complex actions = ActionList(action_list) # Constant seed used here :) random = Random(143) # We will remove a random item until the list is empty # Checking each time the result matches a new list. while actions: random_item = actions[random.randint(0, len(actions) - 1)] actions.remove(random_item) action_list.remove(random_item) self.assertEqual(actions, ActionList(action_list))
def test_contains(self): actions = ActionList(self.action_list_complex) self.assertEqual(len(self.action_list_complex), len(actions)) for action in self.action_list_complex: self.assertIn(action, actions) self.assertNotIn(("PUSH_MPLS", 0x8847), actions) self.assertNotIn(("POP_MPLS", 0x0800), actions) self.assertNotIn(("POP_MPLS", 0x0800), actions) self.assertNotIn(("OUTPUT", 20), actions)
def test_list_add_set(self): # Test that adding a set to a list works and a list to a set actlista = [('OUTPUT', 1), ('SET_FIELD', ('VLAN_VID', 0x1003)), ('SET_FIELD', ('VLAN_PCP', 0x1)), ('PUSH_VLAN', None)] actlista_ordered = [('PUSH_VLAN', None), ('SET_FIELD', ('VLAN_VID', 0x1003)), ('SET_FIELD', ('VLAN_PCP', 0x1)), ('OUTPUT', 1)] act_list = self.action_list_nonreorderable lista = ActionList(act_list) seta = ActionSet(actlista) set_add_list = ActionList([("PUSH_VLAN", 0x88a8), ("SET_FIELD", ("ETH_DST", 1)), ("SET_FIELD", ("VLAN_VID", 0x1015)), ('SET_FIELD', ('VLAN_PCP', 0x1)), ("OUTPUT", 5)]) list_add_set = ActionList(act_list + actlista_ordered) self._test_add(seta, lista, set_add_list, list_add_set)
def build_inst(apply_actions=None, write_actions=None, goto_table=None, clear_actions=None): inst = Instructions() if clear_actions: inst.clear_actions = True if apply_actions: inst.apply_actions = ActionList(apply_actions) if write_actions: inst.write_actions = ActionSet(write_actions) if goto_table: inst.goto_table = goto_table return inst
def test_equal_matches(self): matcha = Match([("VLAN_VID", 0x1001, None)]) matchb = Match([("VLAN_VID", 0x1001, None)]) f1 = Rule(priority=100, match=matcha, instructions=self.inst1, table=1) f2 = Rule(priority=100, match=matcha, instructions=self.inst2, table=2) res = simulate_actions(f1, f2) self.assertEqual(res[0], None) # act_apply1 + act_apply2 + merge(act_set1, act_set2) self.assertEqual(res[1], ActionList(self.act_apply1+self.act_apply2+(self.act_set1+self.act_set2))) self.assertEqual(res[2], None) print(self.act_set1) print(self.act_set2) print(self.act_set1 + self.act_set2)
def test_convert_instructions(self): """ Test converting instructions from ovs """ inst = Instructions() inst.write_metadata = (0x56, 0xff) self.assertEqual(instructions_from_ovs("write_metadata:0x56/0xff", {}), inst) inst = Instructions() inst.goto_table = 6 self.assertEqual(instructions_from_ovs("goto_table:6", {}), inst) inst = Instructions() inst.apply_actions = ActionList([('OUTPUT', 1)]) self.assertEqual(instructions_from_ovs("output:1", {}), inst) inst = Instructions() inst.write_actions = ActionSet([('OUTPUT', 2)]) self.assertEqual(instructions_from_ovs("write_actions(output:2)", {}), inst)
def test_convert_instructions(self): """ Test converting instructions from ryu """ ryu_inst = [OFPInstructionWriteMetadata(0x56, 0xff)] inst = Instructions() inst.write_metadata = (0x56, 0xff) self.assertEqual(instructions_from_ryu(ryu_inst), inst) ryu_inst = [OFPInstructionGotoTable(6)] inst = Instructions() inst.goto_table = 6 self.assertEqual(instructions_from_ryu(ryu_inst), inst) output = OFPActionOutput(1) ryu_inst = [OFPInstructionActions(OFPIT_APPLY_ACTIONS, [output])] inst = Instructions() inst.apply_actions = ActionList([('OUTPUT', 1)]) self.assertEqual(instructions_from_ryu(ryu_inst), inst) output = OFPActionOutput(2) ryu_inst = [OFPInstructionActions(OFPIT_WRITE_ACTIONS, [output])] inst = Instructions() inst.write_actions = ActionSet([('OUTPUT', 2)]) self.assertEqual(instructions_from_ryu(ryu_inst), inst)
def test_complex_actions(self): """ Test a huge dependency mess of rules """ action_list1 = self.action_list_complex result = ActionList(action_list1) # The first 3 can be reordered amongst themselves self.assertSetEqual(set(action_list1[0:3]), set(result[0:3])) # And the next 4 self.assertSetEqual(set(action_list1[3:7]), set(result[3:7])) # And the next 5 self.assertSetEqual(set(action_list1[7:12]), set(result[7:12])) # However within that the push vlan must become the set vlan self.assertIsBefore(("PUSH_VLAN", 0x8100), ("SET_FIELD", ("VLAN_VID", 45)), result) self.assertIsBefore(("PUSH_VLAN", 0x8100), ("SET_FIELD", ("VLAN_PCP", 2)), result) # The next two can be reordered self.assertSetEqual(set(action_list1[12:14]), set(result[12:14])) # The SET_QUEUE must be before the final two outputs self.assertSetEqual(set(action_list1[14]), set(result[14])) # The final 2 can be reordered self.assertSetEqual(set(action_list1[15:17]), set(result[15:17]))
def test_convert_actions(self): """ Test all action conversions work correctly """ # First check set returns a set self.assertIs(type(actions_from_ryu([OFPActionOutput(6)], 'set')), ActionSet) # And list a list self.assertIs(type(actions_from_ryu([OFPActionOutput(6)], 'list')), ActionList) # Now check all the action types, OUTPUT etc self.assertEqual(actions_from_ryu([OFPActionOutput(6)], 'list'), ActionList([('OUTPUT', 6)])) self.assertEqual(actions_from_ryu([OFPActionGroup(7)], 'list'), ActionList([('GROUP', 7)])) self.assertEqual(actions_from_ryu([OFPActionSetQueue(8)], 'list'), ActionList([('SET_QUEUE', 8)])) # Push/Pop self.assertEqual(actions_from_ryu([OFPActionPushVlan(0x8100)], 'list'), ActionList([('PUSH_VLAN', 0x8100)])) self.assertEqual(actions_from_ryu([OFPActionPushVlan(0x88a8)], 'list'), ActionList([('PUSH_VLAN', 0x88a8)])) self.assertEqual(actions_from_ryu([OFPActionPopVlan()], 'list'), ActionList([('POP_VLAN', None)])) self.assertEqual(actions_from_ryu([OFPActionPushMpls(0x8847)], 'list'), ActionList([('PUSH_MPLS', 0x8847)])) self.assertEqual(actions_from_ryu([OFPActionPushMpls(0x8848)], 'list'), ActionList([('PUSH_MPLS', 0x8848)])) self.assertEqual(actions_from_ryu([OFPActionPopMpls(0x0800)], 'list'), ActionList([('POP_MPLS', 0x0800)])) self.assertEqual(actions_from_ryu([OFPActionPushPbb(0x88e7)], 'list'), ActionList([('PUSH_PBB', 0x88e7)])) self.assertEqual(actions_from_ryu([OFPActionPopPbb()], 'list'), ActionList([('POP_PBB', None)])) # SET_FIELD, take this chance to check we can do MAC, IPv4/6 conversion # as ryu might be using those. set_field = OFPActionSetField(vlan_vid=100) self.assertEqual(actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('VLAN_VID', 100))])) set_field = OFPActionSetField(eth_dst="10:11:12:13:14:15") self.assertEqual( actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('ETH_DST', 0x101112131415))])) set_field = OFPActionSetField(eth_src="10-11-12-13-14-15") self.assertEqual( actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('ETH_SRC', 0x101112131415))])) set_field = OFPActionSetField(ipv4_dst="192.168.2.1") self.assertEqual(actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('IPV4_DST', 0xc0a80201))])) set_field = OFPActionSetField(ipv4_src="192.168.2.2") self.assertEqual(actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('IPV4_SRC', 0xc0a80202))])) set_field = OFPActionSetField(ipv6_src="::") self.assertEqual(actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('IPV6_SRC', 0x0))])) set_field = OFPActionSetField( ipv6_src="2001:DB8:0123:4567:89ab:cdef:a:a") ipv6_num = 0x20010DB80123456789abcdef000a000a self.assertEqual(actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('IPV6_SRC', ipv6_num))])) set_field = OFPActionSetField(ipv6_dst="2001:DB8::") ipv6_num = 0x20010DB8000000000000000000000000 self.assertEqual(actions_from_ryu([set_field], 'list'), ActionList([("SET_FIELD", ('IPV6_DST', ipv6_num))])) # TTL self.assertEqual(actions_from_ryu([OFPActionCopyTtlOut()], 'list'), ActionList([('COPY_TTL_OUT', None)])) self.assertEqual(actions_from_ryu([OFPActionCopyTtlIn()], 'list'), ActionList([('COPY_TTL_IN', None)])) self.assertEqual(actions_from_ryu([OFPActionSetMplsTtl(24)], 'list'), ActionList([('SET_MPLS_TTL', 24)])) self.assertEqual(actions_from_ryu([OFPActionDecMplsTtl()], 'list'), ActionList([('DEC_MPLS_TTL', None)])) self.assertEqual(actions_from_ryu([OFPActionSetNwTtl(0xff)], 'list'), ActionList([('SET_NW_TTL', 0xff)])) self.assertEqual(actions_from_ryu([OFPActionDecNwTtl()], 'list'), ActionList([('DEC_NW_TTL', None)]))
def inst_from_acts(actions): inst = Instructions() inst.apply_actions = ActionList(actions) return inst
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from ofequivalence.rule import (Match, Rule, Instructions, ActionList) from ofequivalence.ruleset import (to_single_table,) output1 = Instructions() output1.apply_actions = ActionList([('OUTPUT', 6)]) goto1 = Instructions() goto1.goto_table = 1 goto2 = Instructions() goto2.goto_table = 2 """ arp -> drop ip=1 -> output:1 * -> drop """ data1 = [ Rule(priority=10, match=Match([('ETH_TYPE', 60, None)])), Rule(priority=9, match=Match([('IPV4_DST', 1, None)]),
def test_convert_actions(self): """ Test all action conversions work correctly """ # Now check all the action types, OUTPUT etc self.assertEqual(actions_from_ovs("output:6", {}), ActionList([('OUTPUT', 6)])) self.assertEqual(actions_from_ovs('group:7', {7: 7}), ActionList([('GROUP', 7)])) self.assertEqual(actions_from_ovs("set_queue:8", {}), ActionList([('SET_QUEUE', 8)])) # Push/Pop self.assertEqual(actions_from_ovs('push_vlan:0x8100', {}), ActionList([('PUSH_VLAN', 0x8100)])) self.assertEqual(actions_from_ovs('push_vlan:0x88a8', {}), ActionList([('PUSH_VLAN', 0x88a8)])) self.assertEqual(actions_from_ovs('pop_vlan', {}), ActionList([('POP_VLAN', None)])) self.assertEqual(actions_from_ovs('strip_vlan', {}), ActionList([('POP_VLAN', None)])) self.assertEqual(actions_from_ovs('push_mpls:0x8847', {}), ActionList([('PUSH_MPLS', 0x8847)])) self.assertEqual(actions_from_ovs('push_mpls:0x8848', {}), ActionList([('PUSH_MPLS', 0x8848)])) self.assertEqual(actions_from_ovs('pop_mpls:0x0800', {}), ActionList([('POP_MPLS', 0x0800)])) # PBB not supported by ovs #self.assertEqual(actions_from_ovs([OFPActionPushPbb(0x88e7)], 'list'), # ActionList([('PUSH_PBB', 0x88e7)])) #self.assertEqual(actions_from_ovs([OFPActionPopPbb()], 'list'), # ActionList([('POP_PBB', None)])) # SET_FIELD, take this chance to check we can do MAC, IPv4/6 conversion # as ovs stores these in their respective format self.assertEqual(actions_from_ovs('set_field:100->vlan_vid', {}), ActionList([("SET_FIELD", ('VLAN_VID', 100))])) self.assertEqual(actions_from_ovs('set_field:4196->vlan_vid', {}), ActionList([("SET_FIELD", ('VLAN_VID', 100))])) self.assertEqual( actions_from_ovs('set_field:10:11:12:13:14:15->eth_dst', {}), ActionList([("SET_FIELD", ('ETH_DST', 0x101112131415))])) self.assertEqual( actions_from_ovs('set_field:10:11:12:13:14:15->eth_src', {}), ActionList([("SET_FIELD", ('ETH_SRC', 0x101112131415))])) self.assertEqual(actions_from_ovs("set_field:192.168.2.1->ip_dst", {}), ActionList([("SET_FIELD", ('IPV4_DST', 0xc0a80201))])) self.assertEqual(actions_from_ovs("set_field:192.168.2.2->ip_src", {}), ActionList([("SET_FIELD", ('IPV4_SRC', 0xc0a80202))])) self.assertEqual(actions_from_ovs('set_field:::->ipv6_src', {}), ActionList([("SET_FIELD", ('IPV6_SRC', 0x0))])) ipv6_num = 0x20010DB80123456789abcdef000a000a self.assertEqual( actions_from_ovs( 'set_field:2001:db8:123:4567:89ab:cdef:a:a->ipv6_src', {}), ActionList([("SET_FIELD", ('IPV6_SRC', ipv6_num))])) ipv6_num = 0x20010DB8000000000000000000000000 self.assertEqual( actions_from_ovs('set_field:2001:db8::->ipv6_dst', {}), ActionList([("SET_FIELD", ('IPV6_DST', ipv6_num))])) # TTL #self.assertEqual(actions_from_ovs([OFPActionCopyTtlOut()], 'list'), # ActionList([('COPY_TTL_OUT', None)])) #self.assertEqual(actions_from_ovs([OFPActionCopyTtlIn()], 'list'), # ActionList([('COPY_TTL_IN', None)])) self.assertEqual( actions_from_ovs('set_field:12->mpls_ttl', {}), # documented as :24 but uses (24) ActionList([('SET_MPLS_TTL', 12)])) self.assertEqual( actions_from_ovs('set_mpls_ttl(24)', {}), # documented as :24 but uses (24) ActionList([('SET_MPLS_TTL', 24)])) self.assertEqual(actions_from_ovs('set_mpls_ttl:23', {}), ActionList([('SET_MPLS_TTL', 23)])) self.assertEqual(actions_from_ovs('dec_mpls_ttl', {}), ActionList([('DEC_MPLS_TTL', None)])) self.assertEqual(actions_from_ovs('mod_nw_ttl:255', {}), ActionList([('SET_NW_TTL', 0xff)])) self.assertEqual(actions_from_ovs('set_nw_ttl:255', {}), ActionList([('SET_NW_TTL', 0xff)])) self.assertEqual(actions_from_ovs('set_field:255->nw_ttl', {}), ActionList([('SET_NW_TTL', 0xff)])) self.assertEqual(actions_from_ovs('dec_ttl', {}), ActionList([('DEC_NW_TTL', None)]))