Beispiel #1
0
def equivalent(policy1, policy2):
    """Determine if policy1 is equivalent to policy2 under equality.

    Note that this is unidirectional, it only asks if the packets that can go
    into policy1 behave the same under policy1 as they do under policy2.
    """
    p1_in, p1_out = Consts("p1_in p1_out", Packet)
    p2_in, p2_out1, p2_out2 = Consts("p2_in p2_out1 p2_out2", Packet)
    s = Solver()
    # There are two components to this.  First, we want to ensure that if p1
    # forwards a packet, p2 also forwards it
    constraint = Implies(forwards(policy1, p1_in, p1_out), forwards(policy2, p1_in, p1_out))
    # Second, we want to ensure that if p2 forwards a packet, and it's a packet
    # that p1 can forward, that p2 only forwards it in ways that p1 does.
    constraint = And(
        constraint,
        Implies(
            And(forwards(policy2, p2_in, p2_out1), forwards(policy1, p2_in, p2_out2)), forwards(policy1, p2_in, p2_out1)
        ),
    )
    # We want to check for emptiness, so our model gives us a packet back
    s.add(Not(constraint))

    if s.check() == unsat:
        return None
    else:
        return (s.model(), (p1_in, p1_out, p2_in, p2_out1, p2_out2), HEADER_INDEX)
Beispiel #2
0
def compile_smt(model_filename, hypers_filename, data_filename, train_batch,
                out_dir):
    (parsed_model, data, hypers,
     out_name) = u.read_inputs(model_filename, hypers_filename, data_filename,
                               train_batch)

    print("Unrolling execution model.")
    parsed_model = u.replace_hypers(parsed_model, hypers)
    unrolled_parsed_model = unroller.unroll_and_flatten(parsed_model,
                                                        do_checks=False,
                                                        print_info=False)
    input_dependents = tptv1.get_input_dependent_vars(unrolled_parsed_model)

    idx = 1
    constraints = []
    z3compilers = []
    for i in data['instances']:
        print("Generating SMT constraint for I/O example %i." % idx)
        z3compiler = ToZ3ConstraintsVisitor(tag="__ex%i" % idx,
                                            variables_to_tag=input_dependents)
        constraints.extend(z3compiler.visit(unrolled_parsed_model))
        for var_name, vals in i.iteritems():
            if vals is None:
                pass
            elif isinstance(vals, list):
                for i, val in enumerate(vals):
                    if val is not None:
                        var_name_item = "%s_%s" % (var_name, i)
                        constraints.append(
                            z3compiler.get_expr(var_name_item) == IntVal(val))
            else:
                constraints.append(
                    z3compiler.get_expr(var_name) == IntVal(vals))
        z3compilers.append(z3compiler)
        idx = idx + 1

    # Unify things:
    z3compiler = z3compilers[0]
    for i in xrange(1, len(z3compilers)):
        z3compilerP = z3compilers[i]
        for param in z3compiler.get_params():
            constraints.append(
                z3compiler.get_expr(param) == z3compilerP.get_expr(param))

    out_file_name = os.path.join(out_dir, out_name + ".smt2")
    print "Writing SMTLIB2 benchmark info to '%s'." % out_file_name
    if not os.path.isdir(out_dir):
        os.makedirs(out_dir)

    solver = Solver()
    idx = 0
    for c in constraints:
        # Debugging helper if things unexpectedly end up UNSAT:
        # solver.assert_and_track(c, "c%i" % idx)
        solver.add(c)
        idx = idx + 1
    with open(out_file_name, 'w') as f:
        f.write(solver.to_smt2())
        f.write("(get-model)")
Beispiel #3
0
def compile_smt(model_filename, hypers_filename, data_filename,
                train_batch, out_dir):
    (parsed_model, data, hypers, out_name) = u.read_inputs(model_filename,
                                                           hypers_filename,
                                                           data_filename,
                                                           train_batch)

    print ("Unrolling execution model.")
    parsed_model = u.replace_hypers(parsed_model, hypers)
    unrolled_parsed_model = unroller.unroll_and_flatten(parsed_model,
                                                        do_checks=False,
                                                        print_info=False)
    input_dependents = tptv1.get_input_dependent_vars(unrolled_parsed_model)

    idx = 1
    constraints = []
    z3compilers = []
    for i in data['instances']:
        print ("Generating SMT constraint for I/O example %i." % idx)
        z3compiler = ToZ3ConstraintsVisitor(tag="__ex%i" % idx, variables_to_tag=input_dependents)
        constraints.extend(z3compiler.visit(unrolled_parsed_model))
        for var_name, vals in i.iteritems():
            if isinstance(vals, list):
                for i, val in enumerate(vals):
                    var_name_item = "%s_%s" % (var_name, i)
                    constraints.append(
                        z3compiler.get_expr(var_name_item) == IntVal(val))
            else:
                constraints.append(
                    z3compiler.get_expr(var_name) == IntVal(vals))
        z3compilers.append(z3compiler)
        idx = idx + 1

    # Unify things:
    z3compiler = z3compilers[0]
    for i in xrange(1, len(z3compilers)):
        z3compilerP = z3compilers[i]
        for param in z3compiler.get_params():
            constraints.append(
                z3compiler.get_expr(param) == z3compilerP.get_expr(param))

    out_file_name = os.path.join(out_dir, out_name + ".smt2")
    print "Writing SMTLIB2 benchmark info to '%s'." % out_file_name
    solver = Solver()
    idx = 0
    for c in constraints:
        # Debugging helper if things unexpectedly end up UNSAT:
        # solver.assert_and_track(c, "c%i" % idx)
        solver.add(c)
        idx = idx + 1
    with open(out_file_name, 'w') as f:
        f.write(solver.to_smt2())
        f.write("(get-model)")
Beispiel #4
0
def shared_outputs(policy1, policy2):
    """Try to find packet in output of policy1 and egress of slice2."""
    p, q, pp = Consts("p q pp", Packet)

    solv = Solver()
    solv.add(output(policy1, p, pp))
    solv.add(egress(policy2, q, pp))

    if solv.check() == unsat:
        return None
    else:
        return solv.model(), (p, pp), HEADER_INDEX
Beispiel #5
0
    def __init__(self, s: z3.Solver, g: Graph):
        (G, G_nodes) = z3.EnumSort(g.name_, tuple(g.nodes()))
        # Function that returns true if there is an edge between two nodes, 
        # and false otherwise
        edges_f = z3.Function('G_%s_edges' % (g.name_,), G, G, z3.BoolSort())
        for (n1,n2) in itertools.product(iter(G_nodes), iter(G_nodes)):
            n1_str = repr(n1)
            n2_str = repr(n2)
            s.add(edges_f(n1,n2) == g.has_edge(n1_str,n2_str))

        self.nodes_s = G       # Nodes Sort
        self.nodes   = G_nodes
        self.edges_f = edges_f
Beispiel #6
0
def not_empty(policy):
    """Determine if there are any packets that the policy forwards.

    RETURNS:
        None if not forwardable.
        (model, (p_in, p_out), HEADERS) if forwardable.
    """
    p_in, p_out = Consts("p_in p_out", Packet)
    s = Solver()
    s.add(forwards(policy, p_in, p_out))
    if s.check() == unsat:
        return None
    else:
        return (s.model(), (p_in, p_out), HEADER_INDEX)
Beispiel #7
0
def shared_io(topo, policy1, policy2):
    """Try to find output of policy1 in the inputs of policy2."""
    p, pp, q, qq = Consts("p pp q qq", Packet)
    o = Int("o")

    solv = Solver()
    solv.add(output(policy1, p, pp))
    solv.add(transfer(topo, pp, q))
    solv.add(input(policy2, q, qq, o))

    if solv.check() == unsat:
        return None
    else:
        return solv.model(), (p, pp, q, qq), HEADER_INDEX
Beispiel #8
0
def simulates_forwards(topo, a, b, field="vlan", edge_policy={}):
    """Determine if b simulates a up to field on one hop."""
    p, pp = Consts("p pp", Packet)
    v, vv = Ints("v vv")
    # Z3 emits a warning about not finding a pattern for our quantification.
    # This is fine, so ignore it.
    set_option("WARNING", False)

    solv = Solver()
    solv.add(on_valid_port(topo, p))

    # b doesn't need to forward packets on external links that don't satisfy the
    # ingress predicate
    edge_option = And(external_link(edge_policy, p), Not(edges_ingress(edge_policy, p)))

    solv.add(
        And(
            forwards(a, p, pp),
            ForAll([v, vv], Not(Or(forwards_with(b, p, {field: v}, pp, {field: vv}), edge_option)), patterns=[]),
        )
    )
    if solv.check() == unsat:
        set_option("WARNING", True)
        return None
    else:
        set_option("WARNING", True)
        return solv.model(), (p, pp), HEADER_INDEX
Beispiel #9
0
def z3_graph_mapping(s: z3.Solver, g1: GraphZ3, g2: GraphZ3):
    map_f = z3.Function('Map', g1.nodes_s, g2.nodes_s)
    x = z3.Const('x', g1.nodes_s)
    y = z3.Const('y', g1.nodes_s)
    s.add([
        z3.ForAll([x,y], g1.edges_f(x,y) == g2.edges_f(map_f(x), map_f(y)))
    ])

    # Check if can satisfy the specified constraints
    if s.check():
        # If can, get the model (i.e., a solution that satisfies the
        # constrains) for the Map function and return it
        m = s.model()
        for d in m.decls():
            if d.name() == 'Map':
                    iso_m = m[d]
                    return iso_m
        raise RuntimeError("Isomorphism function not found in model")
    return None
Beispiel #10
0
def shared_transit(topo, policy1, policy2):
    """Try to find packet in the border of policy1 and the border of policy2.
    
    Note that this is symmetric.
    """
    p, pp, ppp, qq, qqq = Consts("p pp ppp qq qqq", Packet)
    o, n = Ints("o n")

    solv = Solver()
    # Predicates are focused on a packet p, all other packets are fodder for
    # that one.  We want an input packet p or an output packet after a hop p in
    # each case.
    solv.add(Or(ingress(policy1, p, pp, o), And(egress(policy1, pp, ppp), transfer(topo, ppp, p))))
    solv.add(Or(ingress(policy2, p, qq, n), And(egress(policy2, qq, qqq), transfer(topo, qqq, p))))

    if solv.check() == unsat:
        return None
    else:
        return solv.model(), (p,), HEADER_INDEX
Beispiel #11
0
def shared_inputs(policy1, policy2):
    """Try to find packet in input of policy1 and ingress of policy2."""
    p, pp, qq = Consts("p pp qq", Packet)
    o, n = Ints("o n")

    solv = Solver()
    solv.add(input(policy1, p, pp, o))
    solv.add(ingress(policy2, p, qq, n))

    if solv.check() == unsat:
        return None
    else:
        return solv.model(), (p, pp, qq), HEADER_INDEX
Beispiel #12
0
def simulates_forwards2(topo, a, b, field="vlan", edge_policy={}):
    """Determine if b simulates a up to field on two hop on topo."""
    p, pp, q, qq = Consts("p pp q qq", Packet)
    v, vv, vvv = Ints("v vv, vvv")
    # Z3 emits a warning about not finding a pattern for our quantification.
    # This is fine, so ignore it.
    set_option("WARNING", False)

    solv = Solver()

    solv.add(on_valid_port(topo, p))

    # b doesn't need to forward packets on external links that don't satisfy the
    # ingress predicate, but we only care about the first hop
    edge_option = And(external_link(edge_policy, p), Not(edges_ingress(edge_policy, p)))

    # This case breaks the And inside the ForAll because they're both False and
    # z3 can't handle that.
    # However, it does mean that they simulate each other, because neither
    # forwards packets, so just short-circuit.
    if forwards(b, p, pp) is False and forwards(b, q, qq) is False:
        return None
    c = And(
        forwards(a, p, pp),
        transfer(topo, pp, q),
        forwards(a, q, qq),
        ForAll(
            [v, vv, vvv],
            Not(
                Or(
                    And(
                        forwards_with(b, p, {field: v}, pp, {field: vv}),
                        forwards_with(b, q, {field: vv}, qq, {field: vvv}),
                    ),
                    edge_option,
                )
            ),
        ),
    )

    solv.add(c)
    if solv.check() == unsat:
        set_option("WARNING", True)
        return None
    else:
        set_option("WARNING", True)
        return solv.model(), (p, pp), HEADER_INDEX
Beispiel #13
0
def simulates_observes(topo, a, b, field="vlan", edge_policy={}):
    p = Const("p", Packet)
    o, v = Ints("o v")
    # Z3 emits a warning about not finding a pattern for our quantification.
    # This is fine, so ignore it.
    set_option("WARNING", False)

    solv = Solver()

    solv.add(on_valid_port(topo, p))

    # b doesn't need to observe packets on external links that don't satisfy the
    # ingress predicate
    edge_option = And(external_link(edge_policy, p), Not(edges_ingress(edge_policy, p)))

    solv.add(And(observes(a, p, o), ForAll([v], Not(Or(observes_with(b, p, {field: v}, o), edge_option)), patterns=[])))

    if solv.check() == unsat:
        set_option("WARNING", True)
        return None
    else:
        set_option("WARNING", True)
        return solv.model(), (p), HEADER_INDEX
Beispiel #14
0
def one_per_edge(topo, pol, field="vlan"):
    """Determine if pol only uses one value of field on each internal edge.
    
    We don't care about external edges because they never have the problem of
    preventing tiling of two-node connectivity since this slice never reads
    packets sent to them.
    """

    p, pp, q, qq = Consts("p pp q qq", Packet)
    r, rr, s, ss = Consts("r rr s ss", Packet)

    solv = Solver()
    solv.add(forwards(pol, p, pp))
    solv.add(transfer(topo, pp, r))
    solv.add(forwards(pol, r, rr))
    solv.add(forwards(pol, q, qq))
    solv.add(switch(pp) == switch(qq))
    solv.add(port(pp) == port(qq))
    solv.add(HEADER_INDEX[field](pp) != HEADER_INDEX[field](qq))
    if solv.check() == unsat:
        return None
    else:
        return solv.model(), (p, pp), HEADER_INDEX