Esempio n. 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)
Esempio n. 2
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
Esempio n. 3
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
Esempio n. 4
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
Esempio n. 5
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)