def test_find_metadata_conflicting_paths(self): """ Metadata rewrite conflicting paths test As metadata can be set bitwise it uses a slightly different code path to a standard set field. * MD=0x10 GT=1 0x10 MD=0x1/0x1 GT=2 0x11 output1 * * vs. single table, note all traffic is different no set * drop """ inst_a = Instructions() inst_a.goto_table = 1 inst_a.write_metadata = (0x12, None) inst_b = Instructions() inst_b.goto_table = 2 inst_b.write_metadata = (0x1, 0x3) # Note: Set VLAN applies the present bit mask so must included it ruleset_a = [ Rule(priority=10, table=0, instructions=inst_a), Rule(priority=10, table=1, match=Match([('METADATA', 0x12, None)]), instructions=inst_b), Rule(priority=0, table=1), Rule(priority=10, table=2, match=Match([('METADATA', 0x11, None)]), instructions=Instructions(dup=output1)), Rule(priority=0, table=2), ] ruleset_b = [ Rule(priority=0, table=0) ] single_a = to_single_table(ruleset_a) single_b = to_single_table(ruleset_b) norm_a = normalise(single_a) norm_b = normalise(single_b) # Make sure the frozensets are made after to_single_table which changes # priorities which changes the Rule's hash in the frozenset result_ab = { (ruleset_a[0], ruleset_a[1], ruleset_a[3]): frozenset([(ruleset_b[0],)]), } result_ba = { (ruleset_b[0],): frozenset([(ruleset_a[0], ruleset_a[1], ruleset_a[3],)]) } equal_ab, diff_ab = check_equal(norm_a, norm_b, diff=True) self.assertFalse(equal_ab) paths_ab = find_conflicting_paths(diff_ab, single_a, single_b) paths_ba = find_conflicting_paths(diff_ab, single_b, single_a) self.assertEqual(paths_ab, result_ab) self.assertNotEqual(paths_ab, result_ba) # Sanity check self.assertEqual(paths_ba, result_ba)
def test_find_rewrite_conflicting_paths(self): """ Rewritten conflicting paths test VLAN_VID=0 SetVLAN(1), goto1 VLAN_VID=0 output:1 * VLAN_VID=1 drop * vs. single table, note all traffic is different no set * output1 """ inst_a = Instructions() inst_a.goto_table = 1 inst_a.apply_actions.append("SET_FIELD", ("VLAN_VID", 1)) # Note: Set VLAN applies the present bit mask so must included it ruleset_a = [ Rule(priority=10, table=0, match=Match([('VLAN_VID', 0x1000 | 0, None)]), instructions=Instructions(dup=inst_a)), Rule(priority=0, table=0), Rule(priority=20, table=1, match=Match([('VLAN_VID', 0x1000 | 0, None)]), instructions=Instructions(dup=output1)), Rule(priority=20, table=1, match=Match([('VLAN_VID', 0x1000 | 1, None)])), Rule(priority=0, table=1) ] ruleset_b = [ Rule(priority=0, table=0, instructions=Instructions(dup=output1)) ] single_a = to_single_table(ruleset_a) single_b = to_single_table(ruleset_b) norm_a = normalise(single_a) norm_b = normalise(single_b) # Make sure the frozensets are made after to_single_table which changes # priorities which changes the Rule's hash in the frozenset result_ab = { (ruleset_a[0], ruleset_a[3]): frozenset([(ruleset_b[0],)]), (ruleset_a[1],): frozenset([(ruleset_b[0],)]) } result_ba = { (ruleset_b[0],): frozenset([(ruleset_a[0], ruleset_a[3]), (ruleset_a[1],)]) } equal_ab, diff_ab = check_equal(norm_a, norm_b, diff=True) self.assertFalse(equal_ab) paths_ab = find_conflicting_paths(diff_ab, single_a, single_b) paths_ba = find_conflicting_paths(diff_ab, single_b, single_a) self.assertEqual(paths_ab, result_ab) self.assertNotEqual(paths_ab, result_ba) # Sanity check self.assertEqual(paths_ba, result_ba)
def test_to_single_table(self): ruleset1 = to_single_table(FORWARD_DROP) self.assertListEqual(ruleset1, FORWARD_DROP_SINGLE) ruleset2 = to_single_table(DROP_FORWARD) self.assertListEqual(ruleset2, DROP_FORWARD_SINGLE) # Already in normalise test, but we can do it again here # with the examples from the paper norm1 = normalise(ruleset1) norm2 = normalise(ruleset2) check_equal(norm1, norm2) check_equal(norm2, norm1)
def test_find_vlans_conflicting_paths(self): """ VLAN rewrite paths test, check push/pop combinations Also due to internals of how this can be structured IN_PORT:1,VLAN:1 TCP:80: drop VLAN:1 output:10 IN_PORT:2 pushVLAN:2 * -> VLAN:2 pop output:11 IN_PORT:3 pushVLAN:1 IN_PORT:4,VLAN:2 * drop vs. A vlan can do things: IN_PORT:1,VLAN:1 VLAN:1 pop output:11 IN_PORT:2 pushVLAN:2 VLAN:2 output:10 IN_PORT:3 pushVLAN:1 IN_PORT:4,VLAN:2 * drop vs. single table, note all traffic is different no set * drop """ push_vlan2 = Instructions() push_vlan2.goto_table = 1 push_vlan2.apply_actions.append("PUSH_VLAN", 0x8100) push_vlan2.apply_actions.append("SET_FIELD", ("VLAN_VID", 2)) push_vlan1 = Instructions() push_vlan1.goto_table = 1 push_vlan1.apply_actions.append("PUSH_VLAN", 0x8100) push_vlan1.apply_actions.append("SET_FIELD", ("VLAN_VID", 1)) trunk10 = Instructions() trunk10.write_actions.append("OUTPUT", 11) access11 = Instructions() access11.write_actions.append("POP_VLAN", None) access11.write_actions.append("OUTPUT", 11) # Note: Set VLAN applies the present bit mask so must included it ruleset_a = [ Rule(priority=10, table=0, match=Match([('IN_PORT', 1, None), ('VLAN_VID', 0x1001, None)]), instructions=goto1), Rule(priority=10, table=0, match=Match([('IN_PORT', 2, None)]), instructions=push_vlan2), Rule(priority=10, table=0, match=Match([('IN_PORT', 3, None)]), instructions=push_vlan1), Rule(priority=10, table=0, match=Match([('IN_PORT', 4, None), ('VLAN_VID', 0x1002, None)]), instructions=goto1), Rule(priority=0, table=0), Rule(priority=10, table=1, match=Match([('TCP_SRC', 80, None)])), Rule(priority=0, table=1, instructions=goto2), Rule(priority=10, table=2, match=Match([('VLAN_VID', 0x1001, None)]), instructions=Instructions(dup=trunk10)), Rule(priority=10, table=2, match=Match([('VLAN_VID', 0x1002, None)]), instructions=Instructions(dup=access11)), Rule(priority=0, table=2), ] ruleset_b = [ Rule(priority=10, table=0, match=Match([('IN_PORT', 1, None), ('VLAN_VID', 0x1001, None)]), instructions=goto1), Rule(priority=10, table=0, match=Match([('IN_PORT', 2, None)]), instructions=push_vlan2), Rule(priority=10, table=0, match=Match([('IN_PORT', 3, None)]), instructions=push_vlan1), Rule(priority=10, table=0, match=Match([('IN_PORT', 4, None), ('VLAN_VID', 0x1002, None)]), instructions=goto1), Rule(priority=0, table=0), Rule(priority=10, table=1, match=Match([('VLAN_VID', 0x1001, None)]), instructions=Instructions(dup=access11)), Rule(priority=10, table=1, match=Match([('VLAN_VID', 0x1002, None)]), instructions=Instructions(dup=trunk10)), Rule(priority=0, table=1)] ruleset_c = [ Rule(priority=0, table=0) ] single_a = to_single_table(ruleset_a) single_b = to_single_table(ruleset_b) single_c = to_single_table(ruleset_c) norm_a = normalise(single_a) norm_b = normalise(single_b) norm_c = normalise(single_c) # Make sure the frozensets are made after to_single_table which changes # priorities which changes the Rule's hash in the frozenset result_ab = { (ruleset_a[0], ruleset_a[5]): frozenset([(ruleset_b[0], ruleset_b[5])]), (ruleset_a[0], ruleset_a[6], ruleset_a[7]): frozenset([(ruleset_b[0], ruleset_b[5])]), (ruleset_a[1], ruleset_a[5]): frozenset([(ruleset_b[1], ruleset_b[6])]), (ruleset_a[1], ruleset_a[6], ruleset_a[8]): frozenset([(ruleset_b[1], ruleset_b[6])]), (ruleset_a[2], ruleset_a[5]): frozenset([(ruleset_b[2], ruleset_b[5])]), (ruleset_a[2], ruleset_a[6], ruleset_a[7]): frozenset([(ruleset_b[2], ruleset_b[5])]), (ruleset_a[3], ruleset_a[5]): frozenset([(ruleset_b[3], ruleset_b[6])]), (ruleset_a[3], ruleset_a[6], ruleset_a[8]): frozenset([(ruleset_b[3], ruleset_b[6])]), } result_ba = { (ruleset_b[0], ruleset_b[5]): frozenset([(ruleset_a[0], ruleset_a[5]), (ruleset_a[0], ruleset_a[6], ruleset_a[7])]), (ruleset_b[1], ruleset_b[6]): frozenset([(ruleset_a[1], ruleset_a[5]), (ruleset_a[1], ruleset_a[6], ruleset_a[8])]), (ruleset_b[2], ruleset_b[5]): frozenset([(ruleset_a[2], ruleset_a[5]), (ruleset_a[2], ruleset_a[6], ruleset_a[7])]), (ruleset_b[3], ruleset_b[6]): frozenset([(ruleset_a[3], ruleset_a[5]), (ruleset_a[3], ruleset_a[6], ruleset_a[8])]), } result_ca = { (ruleset_c[0],): frozenset([(ruleset_a[0], ruleset_a[6], ruleset_a[7]), (ruleset_a[1], ruleset_a[6], ruleset_a[8]), (ruleset_a[2], ruleset_a[6], ruleset_a[7]), (ruleset_a[3], ruleset_a[6], ruleset_a[8])]) } equal_ab, diff_ab = check_equal(norm_a, norm_b, diff=True) equal_ca, diff_ca = check_equal(norm_c, norm_a, diff=True) self.assertFalse(equal_ab) self.assertFalse(equal_ca) paths_ab = find_conflicting_paths(diff_ab, single_a, single_b) paths_ba = find_conflicting_paths(diff_ab, single_b, single_a) paths_ca = find_conflicting_paths(diff_ca, single_c, single_a) self.assertEqual(paths_ab, result_ab) self.assertNotEqual(paths_ab, result_ba) # Sanity check self.assertEqual(paths_ba, result_ba) self.assertEqual(paths_ca, result_ca)
def test_find_multitable_conflicting_paths(self): """ Multitable conflicting paths test vlan:1 GT(1) ip:0/0xFFFFFFFE output1 ip:0 vlan:2 GT(2) ip:0 output1 (shadowed) ip:1 * * * === As single table === vlan:1,ip:0 output1 vlan:1,ip:1 output1 vlan:2,ip:0 vlan:2,ip:1 * vs. vlan:1,ip:0 vlan:1,ip:1 output1 vlan:2,ip:0 output1 vlan:2,ip:1 * """ ruleset_a = [ Rule(priority=10, table=0, match=Match([('VLAN_VID', 1, None)]), instructions=Instructions(dup=goto1)), Rule(priority=10, table=0, match=Match([('VLAN_VID', 2, None)]), instructions=Instructions(dup=goto2)), Rule(priority=0, table=0), Rule(priority=20, table=1, match=Match([('IPV4_DST', 0, 0xFFFFFFFE)]), instructions=Instructions(dup=output1)), Rule(priority=19, table=1, match=Match([('IPV4_DST', 0, None)]), instructions=Instructions(dup=output1)), Rule(priority=0, table=1), Rule(priority=30, table=2, match=Match([('IPV4_DST', 0, None)]), instructions=Instructions()), Rule(priority=30, table=2, match=Match([('IPV4_DST', 1, None)]), instructions=Instructions()), Rule(priority=0, table=2) ] ruleset_b = [ Rule(priority=14, table=0, match=Match([('VLAN_VID', 1, None), ('IPV4_DST', 0, None)])), Rule(priority=14, table=0, match=Match([('VLAN_VID', 1, None), ('IPV4_DST', 1, None)]), instructions=Instructions(dup=output1)), Rule(priority=14, table=0, match=Match([('VLAN_VID', 2, None), ('IPV4_DST', 0, None)]), instructions=Instructions(dup=output1)), Rule(priority=14, table=0, match=Match([('VLAN_VID', 2, None), ('IPV4_DST', 1, None)])), Rule(priority=0, table=0) ] single_a = to_single_table(ruleset_a) single_b = to_single_table(ruleset_b) norm_a = normalise(single_a) norm_b = normalise(single_b) result_ab = { (ruleset_a[0], ruleset_a[3]): frozenset([(ruleset_b[0],)]), (ruleset_a[1], ruleset_a[6]): frozenset([(ruleset_b[2],)]) } result_ba = { (ruleset_b[0],): frozenset([(ruleset_a[0], ruleset_a[3])]), (ruleset_b[2],): frozenset([(ruleset_a[1], ruleset_a[6])]) } equal_ab, diff_ab = check_equal(norm_a, norm_b, diff=True) self.assertFalse(equal_ab) equal_ba, diff_ba = check_equal(norm_b, norm_a, diff=True) self.assertFalse(equal_ba) paths_ab = find_conflicting_paths(diff_ab, single_a, single_b) paths_ba = find_conflicting_paths(diff_ab, single_b, single_a) self.assertEqual(paths_ab, result_ab) self.assertNotEqual(paths_ab, result_ba) # Sanity self.assertEqual(paths_ba, result_ba)
def test_find_simple_conflicting_paths(self): """ Simple single table conflicting paths test Difference test ip=1 -> output:1 * -> drop vs. ip=1 -> drop * -> drop vs. * -> drop """ ruleset_a = [ Rule(priority=9, table=0, match=Match([('IPV4_DST', 1, None)]), instructions=Instructions(dup=output1)), Rule(priority=0, table=0) ] ruleset_b = [ Rule(priority=9, table=0, match=Match([('IPV4_DST', 1, None)])), Rule(priority=0, table=0) ] ruleset_c = [ Rule(priority=0, table=0) ] # Expected results result_ab = { (ruleset_a[0],): frozenset([(ruleset_b[0],)]) } result_ba = { (ruleset_b[0],): frozenset([(ruleset_a[0],)]) } result_ac = { (ruleset_a[0],): frozenset([(ruleset_c[0],)]) } result_ca = { (ruleset_c[0],): frozenset([(ruleset_a[0],)]) } single_a = to_single_table(ruleset_a) single_b = to_single_table(ruleset_b) single_c = to_single_table(ruleset_c) norm_a = normalise(single_a) norm_b = normalise(single_b) norm_c = normalise(single_c) equal_ab, diff_ab = check_equal(norm_a, norm_b, diff=True) self.assertFalse(equal_ab) equal_ac, diff_ac = check_equal(norm_a, norm_b, diff=True) self.assertFalse(equal_ac) self.assertTrue(check_equal(norm_b, norm_c)) paths_ab = find_conflicting_paths(diff_ab, single_a, single_b) self.assertEqual(paths_ab, result_ab) self.assertNotEqual(paths_ab, result_ba) # Sanity check paths_ba = find_conflicting_paths(diff_ab, single_b, single_a) self.assertEqual(paths_ba, result_ba) self.assertNotEqual(paths_ba, result_ab) # Sanity check paths_ca = find_conflicting_paths(diff_ac, single_c, single_a) self.assertEqual(paths_ca, result_ca) paths_ac = find_conflicting_paths(diff_ac, single_a, single_c) self.assertEqual(paths_ac, result_ac)