def test_compiled_badly(self): o = Header({'switch': 2, 'port': 1}) |then| Action(2, [1]) r = BottomPolicy() self.assertFalse(sat.compiled_correctly(topo, o, r)) o = Header({'switch': 2, 'port': 1}) |then| Action(2, [1]) r = Header({'switch': 1, 'port': 1}) |then| Action(2, [1]) self.assertFalse(sat.compiled_correctly(topo, o, r))
def testHostsCompile(self): topo, combined = linear_hosts((0, 1, 2, 3), (0, 1, 2, 3)) policies = [p for _, p in combined] compiled = ec.compile_slices(topo, combined) self.assertIsNotNone(sat.shared_io(topo, policies[0], policies[1])) self.assertIsNone(sat.shared_io(topo, compiled[0], compiled[1])) self.assertTrue(sat.compiled_correctly(topo, policies[0], compiled[0])) self.assertTrue(sat.compiled_correctly(topo, policies[1], compiled[1]))
def testBasicCompile(self): topo, policies = linear((0, 1, 2, 3), (0, 1, 2, 3)) slices = [slicing.ident_map_slice(topo, {}) for p in policies] combined = zip(slices, policies) compiled = cp.compile_slices(combined) self.assertIsNotNone(sat.shared_io(topo, policies[0], policies[1])) self.assertIsNone(sat.shared_io(topo, compiled[0], compiled[1])) self.assertTrue(sat.compiled_correctly(topo, policies[0], compiled[0])) self.assertTrue(sat.compiled_correctly(topo, policies[1], compiled[1]))
def test_input_restriction(self): edge_policy = {(1, 1): Header({'dstip': 80}), (3, 2): Header({'dstip': 80})} o = (Header({'switch': 1, 'port': 1}) |then| Action(1, [2], obs=[1])) r = Header({'switch': 1, 'port': 1, 'dstip': 80})\ |then| Action(1, [2], obs=[1]) self.assertTrue(sat.compiled_correctly(topo_host, o, r, edge_policy=edge_policy)) o = (Header({'switch': 1, 'port': 1}) |then| Action(1, [2], obs=[1])) +\ (Header({'switch': 3, 'port': 1}) |then| Action(3, [2], obs=[2])) r = (Header({'switch': 1, 'port': 1, 'dstip': 80}) |then| Action(1, [2], {'vlan': 1}, obs=[1])) +\ (Header({'switch': 3, 'port': 1, 'vlan': 1}) |then| Action(3, [2], {'vlan': 0}, obs=[2])) self.assertTrue(sat.compiled_correctly(topo_host, o, r, edge_policy=edge_policy))
def test_simulates_forwards2(self): o = (Header({'switch': 2, 'port': 1}) |then| forward(2, 2))+\ (Header({'switch': 3, 'port': 1}) |then| forward(3, 2)) r = (Header({'switch': 2, 'port': 1, 'vlan': 2}) |then| forward(2, 2))+\ (Header({'switch': 3, 'port': 1, 'vlan': 2}) |then| forward(3, 2)) self.assertIsNone(sat.simulates_forwards2(topo, o, r)) self.assertIsNotNone(sat.simulates_forwards2(topo, o, r, field='srcmac')) o = (Header({'switch': 2, 'port': 1, 'vlan': 1}) |then| forward(2, 2))+\ (Header({'switch': 3, 'port': 1, 'vlan': 1}) |then| forward(3, 2)) r = (Header({'switch': 2, 'port': 1, 'vlan': 2}) |then| forward(2, 2))+\ (Header({'switch': 3, 'port': 1, 'vlan': 2}) |then| forward(3, 2)) self.assertIsNone(sat.simulates_forwards2(topo, o, r)) self.assertIsNotNone(sat.simulates_forwards2(topo, o, r, field='srcmac')) # This is the corner case that demonstrates that we need to restrict # compiled policies to only one vlan per slice. o = (Header({'switch': 2, 'port': 1}) |then| forward(2, 2))+\ (Header({'switch': 3, 'port': 1}) |then| forward(3, 2))+\ (Header({'switch': 4, 'port': 1}) |then| forward(4, 2)) r = (Header({'switch': 2, 'port': 1, 'vlan': 1}) |then| forward(2, 2))+\ (Header({'switch': 3, 'port': 1, 'vlan': 1}) |then| forward(3, 2))+\ (Header({'switch': 3, 'port': 1, 'vlan': 2}) |then| forward(3, 2))+\ (Header({'switch': 4, 'port': 1, 'vlan': 2}) |then| forward(4, 2)) self.assertIsNone(sat.simulates_forwards(topo, o, r)) # NOTE: We would really like this to be a failure, but it isn't. # Therefore, for compiler correctness, we also need one vlan per edge. self.assertIsNone(sat.simulates_forwards2(topo, o, r)) self.assertIsNotNone(sat.simulates_forwards2(topo, o, r, field='srcmac')) # And verify that the compilation test finds this failure self.assertFalse(sat.compiled_correctly(topo, o, r))
def edgeCompile(self, nodes, topo, combined): compiled = ec.compile_slices(topo, combined, verbose=verbose) for i in range(len(compiled)): self.assertTrue(sat.compiled_correctly(topo, combined[i][1], compiled[i])) self.assertIsNotNone(sat.shared_io(topo, compiled[i], compiled[i])) for j in range(len(compiled)): if verbose: print "testing edge compiled %d:%s with %d:%s."\ % (i, nodes[i], j, nodes[j]) if i != j: self.assertFalse(sat.compiled_correctly(topo, combined[i][1], compiled[j])) self.assertIsNone(sat.shared_io(topo, compiled[i], compiled[j]))
def sliceCompile(self, nodes, topo, combined): compiled = cp.compile_slices(combined) for i in range(len(compiled)): self.assertTrue(sat.compiled_correctly(topo, combined[i][1], compiled[i])) for j in range(len(compiled)): if verbose: print "testing compiled %s with %s."\ % (nodes[i], nodes[j]) result = sat.shared_io(topo, compiled[i], compiled[j]) if i == j: self.assertIsNotNone(result) else: cc = sat.compiled_correctly(topo, combined[i][1], compiled[j]) self.assertIsNotNone(cc) self.assertIsNone(result)
def testHostsCompileSmall(self): topo, combined = linear_hosts((0, 1, 2, 3), (0, 1, 2, 3)) slices = [s for s, _ in combined] policy = ((nc.inport(3, 3) |then| nc.forward(3, 1)) + (nc.inport(3, 3) |then| nc.forward(3, 2)) + (nc.inport(2, 3) |then| nc.forward(2, 2))) combined = [(slices[0], policy), (slices[1], nc.BottomPolicy())] compiled, _ = ec.compile_slices(topo, combined) self.assertIsNone(sat.one_per_edge(topo, compiled)) self.assertTrue(sat.compiled_correctly(topo, policy, compiled))
def test_compiled_correctly(self): o = Header({'switch': 2, 'port': 2, 'vlan': 2}) |then| Action(2, [1]) r = Header({'switch': 2, 'port': 2, 'vlan': 2}) |then| Action(2, [1]) self.assertTrue(sat.compiled_correctly(topo, o, r)) o = Header({'switch': 2, 'port': 2}) |then| Action(2, [1]) r = Header({'switch': 2, 'port': 2, 'vlan': 2}) |then| Action(2, [1]) self.assertTrue(sat.compiled_correctly(topo, o, r)) o = Header({'switch': 2, 'port': 2}) |then| forward(2, 1) r = Header({'switch': 2, 'port': 2, 'vlan': 2})\ |then| Action(2, [1], {'vlan': 2}) self.assertTrue(sat.compiled_correctly(topo, o, r)) o = Header({'switch': 1, 'port': 1}) |then| Action(1, [1]) r = Header({'switch': 1, 'port': 1, 'vlan': 1}) |then|\ Action(1, [1], {'vlan': 1}) self.assertTrue(sat.compiled_correctly(topo, o, r)) o = Header({'switch': 1, 'port': 1, 'srcmac': 33, 'dstmac': 32})\ |then| Action(1, [1]) r = Header({'switch': 1, 'port': 1, 'srcmac': 33, 'dstmac': 32, 'vlan': 1})\ |then| Action(1, [1], {'vlan': 1}) self.assertTrue(sat.compiled_correctly(topo, o, r))
def main(): parser = argparse.ArgumentParser(description='Compile netcore programs.') parser.add_argument('--waxman', action='store_const', const=waxman, dest='topo_gen', help='Generate a waxman topology') parser.add_argument('--smallworld', action='store_const', const=smallworld, dest='topo_gen', help='Generate a smallworld topology') parser.add_argument('--fattree', action='store_const', const=fattree, dest='topo_gen', help='Generate a fattree topology') parser.add_argument('--flood', action='store_const', const=flood, dest='policy_gen', help='Use a flood routing policy') parser.add_argument('--flood_observe', action='store_const', const=flood_observe, dest='policy_gen', help='Use a flood and observe routing policy') parser.add_argument('--shortest_path', action='store_const', const=shortest_path, dest='policy_gen', help='Use a shortest path routing policy') parser.add_argument('--multicast', action='store_const', const=multicast, dest='policy_gen', help='Use a multicast routing policy') parser.add_argument('-e', '--edge', action='store_true', default=False, help='Use the per-edge compiler.') parser.add_argument('--hosts', action='store', type=int, default=20, help='Number of hosts on network (approximate for ' 'fattree).') parser.add_argument('--ast', action='store_true', default=False, help= 'Print out AST size statistics.') parser.add_argument('--ctime', action='store_true', default=False, help= 'Print out compilation timing information.') parser.add_argument('--vtime', action='store_true', default=False, help= 'Print out validation timing information.') args = parser.parse_args() init = time.time() topo = args.topo_gen(args.hosts) topo_time = time.time() policy = args.policy_gen(topo) policy_time = time.time() combined = build_slices(topo, policy) slice_time = time.time() compiled = do_compile(topo, combined, edge=args.edge) compile_time = time.time() if args.ast: ast_orig = policy.size() ast_final = compiled[0].size() print 'AST Nodes: %5d -> %5d' % (ast_orig, ast_final) if args.ctime: t = topo_time - init p = policy_time - topo_time s = slice_time - policy_time c = compile_time - slice_time print '\n'.join([ 'Time to compile: %f' % c, ]) if args.vtime: policy1 = compiled[0] policy2 = compiled[1] init = time.time() assert sat.shared_io(topo, policy1, policy2) is None assert sat.shared_io(topo, policy2, policy1) is None assert sat.shared_inputs(policy1, policy2) is None assert sat.shared_inputs(policy2, policy1) is None # Not None because we're not doing output restrictions assert sat.shared_outputs(policy1, policy2) is not None assert sat.shared_outputs(policy2, policy1) is not None assert verification.disjoint_observations(policy1, policy2) # Not None because we're not doing output restrictions assert sat.shared_transit(topo, policy1, policy2) is not None iso_t = time.time() print 'Time to check isolation: %f' % (iso_t - init) init = time.time() assert sat.compiled_correctly(topo, policy, compiled[0], edge_policy=combined[0][0].edge_policy) comp_t = time.time() print 'Time to check compilation: %f' % (comp_t - init)