Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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)