package org.batfish.z3; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.batfish.common.BatfishException; import org.batfish.datamodel.ForwardingAction; import org.batfish.datamodel.HeaderSpace; import org.batfish.z3.node.AcceptExpr; import org.batfish.z3.node.AndExpr; import org.batfish.z3.node.BooleanExpr; import org.batfish.z3.node.DebugExpr; import org.batfish.z3.node.DropAclExpr; import org.batfish.z3.node.DropAclInExpr; import org.batfish.z3.node.DropAclOutExpr; import org.batfish.z3.node.DropExpr; import org.batfish.z3.node.DropNoRouteExpr; import org.batfish.z3.node.DropNullRouteExpr; import org.batfish.z3.node.NodeAcceptExpr; import org.batfish.z3.node.NodeDropAclExpr; import org.batfish.z3.node.NodeDropAclInExpr; import org.batfish.z3.node.NodeDropAclOutExpr; import org.batfish.z3.node.NodeDropExpr; import org.batfish.z3.node.NodeDropNoRouteExpr; import org.batfish.z3.node.NodeDropNullRouteExpr; import org.batfish.z3.node.OrExpr; import org.batfish.z3.node.OriginateVrfExpr; import org.batfish.z3.node.QueryExpr; import org.batfish.z3.node.QueryRelationExpr; import org.batfish.z3.node.RuleExpr; import org.batfish.z3.node.SaneExpr; import com.microsoft.z3.BoolExpr; import com.microsoft.z3.Z3Exception; public class ReachabilityQuerySynthesizer extends BaseQuerySynthesizer { private Set<ForwardingAction> _actions; private Set<String> _finalNodes; private HeaderSpace _headerSpace; private Map<String, Set<String>> _ingressNodeVrfs; public ReachabilityQuerySynthesizer(Set<ForwardingAction> actions, HeaderSpace headerSpace, Set<String> finalNodes, Map<String, Set<String>> ingressNodeVrfs) { _actions = actions; _finalNodes = finalNodes; _headerSpace = headerSpace; _ingressNodeVrfs = ingressNodeVrfs; } @Override public NodProgram getNodProgram(NodProgram baseProgram) throws Z3Exception { NodProgram program = new NodProgram(baseProgram.getContext()); // create rules for injecting symbolic packets into ingress node(s) List<RuleExpr> originateRules = new ArrayList<>(); for (String ingressNode : _ingressNodeVrfs.keySet()) { for (String ingressVrf : _ingressNodeVrfs.get(ingressNode)) { OriginateVrfExpr originate = new OriginateVrfExpr(ingressNode, ingressVrf); RuleExpr originateRule = new RuleExpr(originate); originateRules.add(originateRule); } } AndExpr queryConditions = new AndExpr(); // create query condition for action at final node(s) OrExpr finalActions = new OrExpr(); for (ForwardingAction action : _actions) { switch (action) { case ACCEPT: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeAcceptExpr accept = new NodeAcceptExpr(finalNode); finalActions.addDisjunct(accept); } } else { finalActions.addDisjunct(AcceptExpr.INSTANCE); } break; case DEBUG: finalActions.addDisjunct(DebugExpr.INSTANCE); break; case DROP: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeDropExpr drop = new NodeDropExpr(finalNode); finalActions.addDisjunct(drop); } } else { finalActions.addDisjunct(DropExpr.INSTANCE); } break; case DROP_ACL: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeDropAclExpr drop = new NodeDropAclExpr(finalNode); finalActions.addDisjunct(drop); } } else { finalActions.addDisjunct(DropAclExpr.INSTANCE); } break; case DROP_ACL_IN: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeDropAclInExpr drop = new NodeDropAclInExpr(finalNode); finalActions.addDisjunct(drop); } } else { finalActions.addDisjunct(DropAclInExpr.INSTANCE); } break; case DROP_ACL_OUT: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeDropAclOutExpr drop = new NodeDropAclOutExpr(finalNode); finalActions.addDisjunct(drop); } } else { finalActions.addDisjunct(DropAclOutExpr.INSTANCE); } break; case DROP_NO_ROUTE: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeDropNoRouteExpr drop = new NodeDropNoRouteExpr(finalNode); finalActions.addDisjunct(drop); } } else { finalActions.addDisjunct(DropNoRouteExpr.INSTANCE); } break; case DROP_NULL_ROUTE: if (_finalNodes.size() > 0) { for (String finalNode : _finalNodes) { NodeDropNullRouteExpr drop = new NodeDropNullRouteExpr( finalNode); finalActions.addDisjunct(drop); } } else { finalActions.addDisjunct(DropNullRouteExpr.INSTANCE); } break; case FORWARD: default: throw new BatfishException("unsupported action"); } } queryConditions.addConjunct(finalActions); queryConditions.addConjunct(SaneExpr.INSTANCE); // add headerSpace constraints BooleanExpr matchHeaderSpace = Synthesizer.matchHeaderSpace(_headerSpace); queryConditions.addConjunct(matchHeaderSpace); RuleExpr queryRule = new RuleExpr(queryConditions, QueryRelationExpr.INSTANCE); List<BoolExpr> rules = program.getRules(); for (RuleExpr originateRule : originateRules) { BoolExpr originateBoolExpr = originateRule.toBoolExpr(baseProgram); rules.add(originateBoolExpr); } rules.add(queryRule.toBoolExpr(baseProgram)); QueryExpr query = new QueryExpr(QueryRelationExpr.INSTANCE); BoolExpr queryBoolExpr = query.toBoolExpr(baseProgram); program.getQueries().add(queryBoolExpr); return program; } }