package org.batfish.question; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.batfish.common.Answerer; import org.batfish.common.BatfishException; import org.batfish.common.plugin.IBatfish; import org.batfish.datamodel.BgpNeighbor; import org.batfish.datamodel.BgpProcess; import org.batfish.datamodel.Configuration; import org.batfish.datamodel.Edge; import org.batfish.datamodel.Ip; import org.batfish.datamodel.NeighborType; import org.batfish.datamodel.OspfNeighbor; import org.batfish.datamodel.OspfProcess; import org.batfish.datamodel.Topology; import org.batfish.datamodel.Vrf; import org.batfish.datamodel.answers.AnswerElement; import org.batfish.datamodel.collections.IpEdge; import org.batfish.datamodel.questions.Question; import com.fasterxml.jackson.annotation.JsonProperty; public class NeighborsQuestionPlugin extends QuestionPlugin { public static class NeighborsAnswerElement implements AnswerElement { private static final String EBGP_NEIGHBORS_VAR = "ebgpNeighbors"; private static final String IBGP_NEIGHBORS_VAR = "ibgpNeighbors"; private final static String LAN_NEIGHBORS_VAR = "lanNeighbors"; private final static String OSPF_NEIGHBORS_VAR = "ospfNeighbors"; private SortedSet<IpEdge> _ebgpNeighbors; private SortedSet<IpEdge> _ibgpNeighbors; private SortedSet<Edge> _lanNeighbors; private SortedSet<IpEdge> _ospfNeighbors; public void addLanEdge(Edge edge) { _lanNeighbors.add(edge); } @JsonProperty(EBGP_NEIGHBORS_VAR) public SortedSet<IpEdge> getEbgpNeighbors() { return _ebgpNeighbors; } @JsonProperty(IBGP_NEIGHBORS_VAR) public SortedSet<IpEdge> getIbgpNeighbors() { return _ibgpNeighbors; } @JsonProperty(LAN_NEIGHBORS_VAR) public SortedSet<Edge> getLanNeighbors() { return _lanNeighbors; } @JsonProperty(OSPF_NEIGHBORS_VAR) public SortedSet<IpEdge> getOspfNeighbors() { return _ospfNeighbors; } public void initEbgpNeighbors() { _ebgpNeighbors = new TreeSet<>(); } public void initIbgpNeighbors() { _ibgpNeighbors = new TreeSet<>(); } public void initLanNeighbors() { _lanNeighbors = new TreeSet<>(); } public void initOspfNeighbors() { _ospfNeighbors = new TreeSet<>(); } @Override public String prettyPrint() { StringBuilder sb = new StringBuilder("Results for neighbors\n"); if (_lanNeighbors != null) { sb.append(" LAN neighbors\n"); for (Edge edge : _lanNeighbors) { sb.append(" " + edge.toString() + "\n"); } } if (_ebgpNeighbors != null) { sb.append(" eBGP Neighbors\n"); for (IpEdge ipEdge : _ebgpNeighbors) { sb.append(" " + ipEdge.toString() + "\n"); } } if (_ibgpNeighbors != null) { sb.append(" iBGP Neighbors\n"); for (IpEdge ipEdge : _ibgpNeighbors) { sb.append(" " + ipEdge.toString() + "\n"); } } if (_ospfNeighbors != null) { sb.append(" OSPF Neighbors\n"); for (IpEdge ipEdge : _ospfNeighbors) { sb.append(" " + ipEdge.toString() + "\n"); } } return sb.toString(); } @JsonProperty(EBGP_NEIGHBORS_VAR) public void setEbgpNeighbors(SortedSet<IpEdge> ebgpNeighbors) { _ebgpNeighbors = ebgpNeighbors; } @JsonProperty(IBGP_NEIGHBORS_VAR) public void setIbgpNeighbors(SortedSet<IpEdge> ibgpNeighbors) { _ibgpNeighbors = ibgpNeighbors; } @JsonProperty(LAN_NEIGHBORS_VAR) public void setLanNeighbors(SortedSet<Edge> lanNeighbors) { _lanNeighbors = lanNeighbors; } @JsonProperty(OSPF_NEIGHBORS_VAR) public void setOspfNeighbors(SortedSet<IpEdge> ospfNeighbors) { _ospfNeighbors = ospfNeighbors; } } public static class NeighborsAnswerer extends Answerer { private boolean _remoteBgpNeighborsInitialized; private boolean _remoteOspfNeighborsInitialized; Topology _topology; public NeighborsAnswerer(Question question, IBatfish batfish) { super(question, batfish); } @Override public AnswerElement answer() { NeighborsQuestion question = (NeighborsQuestion) _question; Pattern node1Regex; Pattern node2Regex; try { node1Regex = Pattern.compile(question.getNode1Regex()); node2Regex = Pattern.compile(question.getNode2Regex()); } catch (PatternSyntaxException e) { throw new BatfishException(String.format( "One of the supplied regexes (%s OR %s) is not a valid java regex.", question.getNode1Regex(), question.getNode2Regex()), e); } NeighborsAnswerElement answerElement = new NeighborsAnswerElement(); Map<String, Configuration> configurations = _batfish .loadConfigurations(); // for (NeighborType nType : question.getNeighborTypes()) { // switch (nType) { // case EBGP: // answerElement.initEbgpNeighbors(); // initRemoteBgpNeighbors(_batfish, configurations); // break; // case IBGP: // answerElement.initIbgpNeighbors(); // initRemoteBgpNeighbors(_batfish, configurations); // break; // case LAN: // answerElement.initLanNeighbors(); // break; // default: // throw new BatfishException("Unsupported NeighborType: " // + nType.toString()); // // } // } if (question.getNeighborTypes().contains(NeighborType.OSPF)) { answerElement.initOspfNeighbors(); initTopology(configurations); initRemoteOspfNeighbors(_batfish, configurations, _topology); for (Configuration c : configurations.values()) { String hostname = c.getHostname(); for (Vrf vrf : c.getVrfs().values()) { OspfProcess proc = vrf.getOspfProcess(); if (proc != null) { for (OspfNeighbor ospfNeighbor : proc.getOspfNeighbors() .values()) { OspfNeighbor remoteOspfNeighbor = ospfNeighbor .getRemoteOspfNeighbor(); if (remoteOspfNeighbor != null) { Configuration remoteHost = remoteOspfNeighbor .getOwner(); String remoteHostname = remoteHost.getHostname(); Matcher node1Matcher = node1Regex.matcher(hostname); Matcher node2Matcher = node2Regex .matcher(remoteHostname); if (node1Matcher.matches() && node2Matcher.matches()) { Ip localIp = ospfNeighbor.getLocalIp(); Ip remoteIp = remoteOspfNeighbor.getLocalIp(); answerElement.getOspfNeighbors() .add(new IpEdge(hostname, localIp, remoteHostname, remoteIp)); } } } } } } } if (question.getNeighborTypes().contains(NeighborType.EBGP)) { answerElement.initEbgpNeighbors(); initRemoteBgpNeighbors(_batfish, configurations); for (Configuration c : configurations.values()) { String hostname = c.getHostname(); for (Vrf vrf : c.getVrfs().values()) { BgpProcess proc = vrf.getBgpProcess(); if (proc != null) { for (BgpNeighbor bgpNeighbor : proc.getNeighbors() .values()) { BgpNeighbor remoteBgpNeighbor = bgpNeighbor .getRemoteBgpNeighbor(); if (remoteBgpNeighbor != null) { boolean ebgp = !bgpNeighbor.getRemoteAs() .equals(bgpNeighbor.getLocalAs()); if (ebgp) { Configuration remoteHost = remoteBgpNeighbor .getOwner(); String remoteHostname = remoteHost.getHostname(); Matcher node1Matcher = node1Regex .matcher(hostname); Matcher node2Matcher = node2Regex .matcher(remoteHostname); if (node1Matcher.matches() && node2Matcher.matches()) { Ip localIp = bgpNeighbor.getLocalIp(); Ip remoteIp = remoteBgpNeighbor.getLocalIp(); answerElement.getEbgpNeighbors() .add(new IpEdge(hostname, localIp, remoteHostname, remoteIp)); } } } } } } } } if (question.getNeighborTypes().contains(NeighborType.IBGP)) { answerElement.initIbgpNeighbors(); initRemoteBgpNeighbors(_batfish, configurations); for (Configuration c : configurations.values()) { String hostname = c.getHostname(); for (Vrf vrf : c.getVrfs().values()) { BgpProcess proc = vrf.getBgpProcess(); if (proc != null) { for (BgpNeighbor bgpNeighbor : proc.getNeighbors() .values()) { BgpNeighbor remoteBgpNeighbor = bgpNeighbor .getRemoteBgpNeighbor(); if (remoteBgpNeighbor != null) { boolean ibgp = bgpNeighbor.getRemoteAs() .equals(bgpNeighbor.getLocalAs()); if (ibgp) { Configuration remoteHost = remoteBgpNeighbor .getOwner(); String remoteHostname = remoteHost.getHostname(); Matcher node1Matcher = node1Regex .matcher(hostname); Matcher node2Matcher = node2Regex .matcher(remoteHostname); if (node1Matcher.matches() && node2Matcher.matches()) { Ip localIp = bgpNeighbor.getLocalIp(); Ip remoteIp = remoteBgpNeighbor.getLocalIp(); answerElement.getIbgpNeighbors() .add(new IpEdge(hostname, localIp, remoteHostname, remoteIp)); } } } } } } } } if (question.getNeighborTypes().isEmpty() || question.getNeighborTypes().contains(NeighborType.LAN)) { answerElement.initLanNeighbors(); initTopology(configurations); for (Edge edge : _topology.getEdges()) { Matcher node1Matcher = node1Regex.matcher(edge.getNode1()); Matcher node2Matcher = node2Regex.matcher(edge.getNode2()); if (node1Matcher.matches() && node2Matcher.matches()) { answerElement.addLanEdge(edge); } } } return answerElement; } private void initRemoteBgpNeighbors(IBatfish batfish, Map<String, Configuration> configurations) { if (!_remoteBgpNeighborsInitialized) { Map<Ip, Set<String>> ipOwners = _batfish .computeIpOwners(configurations, true); batfish.initRemoteBgpNeighbors(configurations, ipOwners); _remoteBgpNeighborsInitialized = true; } } private void initRemoteOspfNeighbors(IBatfish batfish, Map<String, Configuration> configurations, Topology topology) { if (!_remoteOspfNeighborsInitialized) { Map<Ip, Set<String>> ipOwners = _batfish .computeIpOwners(configurations, true); batfish.initRemoteOspfNeighbors(configurations, ipOwners, topology); _remoteOspfNeighborsInitialized = true; } } private void initTopology(Map<String, Configuration> configurations) { if (_topology == null) { _topology = _batfish.computeTopology(configurations); } } } // <question_page_comment> /** * Lists neighbor relationships in the testrig. * <p> * Details coming * * @type Neighbors multifile * * @param neighborType * The type(s) of neighbor relationships to focus on among (eBGP, * iBGP, IP). Default is IP. * @param node1Regex * Regular expression to match the nodes names for one end of pair. * Default is '.*' (all nodes). * @param node2Regex * Regular expression to match the nodes names for the other end of * the pair. Default is '.*' (all nodes). * * @example bf_answer("Neighbors", neighborType=["ebgp", "ibgp"] * node1Regex="as1.*", node2Regex="as2.*") Shows all eBGP and iBGP * neighbor relationships between nodes that start with as1 and * those that start with as2. * */ public static class NeighborsQuestion extends Question { private static final String NEIGHBOR_TYPES_VAR = "neighborTypes"; private static final String NODE1_REGEX_VAR = "node1Regex"; private static final String NODE2_REGEX_VAR = "node2Regex"; private SortedSet<NeighborType> _neighborTypes; private String _node1Regex; private String _node2Regex; public NeighborsQuestion() { _node1Regex = ".*"; _node2Regex = ".*"; _neighborTypes = new TreeSet<>(); } @Override public boolean getDataPlane() { return false; } @Override public String getName() { return "neighbors"; } @JsonProperty(NEIGHBOR_TYPES_VAR) public SortedSet<NeighborType> getNeighborTypes() { return _neighborTypes; } @JsonProperty(NODE1_REGEX_VAR) public String getNode1Regex() { return _node1Regex; } @JsonProperty(NODE2_REGEX_VAR) public String getNode2Regex() { return _node2Regex; } @Override public boolean getTraffic() { return false; } @Override public String prettyPrint() { try { String retString = String.format( "neighbors %s%s=%s | %s=%s | %s=%s", prettyPrintBase(), NODE1_REGEX_VAR, _node1Regex, NODE2_REGEX_VAR, _node2Regex, NEIGHBOR_TYPES_VAR, _neighborTypes.toString()); return retString; } catch (Exception e) { try { return "Pretty printing failed. Printing Json\n" + toJsonString(); } catch (BatfishException e1) { throw new BatfishException( "Both pretty and json printing failed\n"); } } } @JsonProperty(NEIGHBOR_TYPES_VAR) public void setNeighborTypes(SortedSet<NeighborType> neighborTypes) { _neighborTypes = neighborTypes; } @JsonProperty(NODE1_REGEX_VAR) public void setNode1Regex(String regex) { _node1Regex = regex; } @JsonProperty(NODE2_REGEX_VAR) public void setNode2Regex(String regex) { _node2Regex = regex; } } @Override protected Answerer createAnswerer(Question question, IBatfish batfish) { return new NeighborsAnswerer(question, batfish); } @Override protected Question createQuestion() { return new NeighborsQuestion(); } }