package org.batfish.question;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
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.Configuration;
import org.batfish.datamodel.Interface;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.answers.AnswerElement;
import org.batfish.datamodel.collections.MultiSet;
import org.batfish.datamodel.collections.NodeInterfacePair;
import org.batfish.datamodel.collections.TreeMultiSet;
import org.batfish.datamodel.questions.Question;
import com.fasterxml.jackson.annotation.JsonProperty;
public class UniqueIpAssignmentsQuestionPlugin extends QuestionPlugin {
public static class UniqueIpAssignmentsAnswerElement
implements AnswerElement {
private SortedMap<Ip, SortedSet<NodeInterfacePair>> _allIps;
private SortedMap<Ip, SortedSet<NodeInterfacePair>> _enabledIps;
public UniqueIpAssignmentsAnswerElement() {
_allIps = new TreeMap<>();
_enabledIps = new TreeMap<>();
}
public void add(SortedMap<Ip, SortedSet<NodeInterfacePair>> map, Ip ip,
String hostname, String interfaceName) {
SortedSet<NodeInterfacePair> interfaces = map.get(ip);
if (interfaces == null) {
interfaces = new TreeSet<>();
map.put(ip, interfaces);
}
interfaces.add(new NodeInterfacePair(hostname, interfaceName));
}
public SortedMap<Ip, SortedSet<NodeInterfacePair>> getAllIps() {
return _allIps;
}
public SortedMap<Ip, SortedSet<NodeInterfacePair>> getEnabledIps() {
return _enabledIps;
}
private Object ipsToString(String indent, String header,
SortedMap<Ip, SortedSet<NodeInterfacePair>> ips) {
StringBuilder sb = new StringBuilder(indent + header + "\n");
for (Ip ip : ips.keySet()) {
sb.append(indent + indent + ip.toString() + "\n");
for (NodeInterfacePair nip : ips.get(ip)) {
sb.append(indent + indent + indent + nip.toString() + "\n");
}
}
return sb.toString();
}
@Override
public String prettyPrint() {
StringBuilder sb = new StringBuilder(
"Results for unique IP assignment check\n");
if (_allIps != null) {
sb.append(ipsToString(" ", "All IPs", _allIps));
}
if (_enabledIps != null) {
sb.append(ipsToString(" ", "Enabled IPs", _enabledIps));
}
return sb.toString();
}
public void setAllIps(
SortedMap<Ip, SortedSet<NodeInterfacePair>> allIps) {
_allIps = allIps;
}
public void setEnabledIps(
SortedMap<Ip, SortedSet<NodeInterfacePair>> enabledIps) {
_enabledIps = enabledIps;
}
}
public static class UniqueIpAssignmentsAnswerer extends Answerer {
// private final Batfish _batfish;
// private final UniqueIpAssignmentsQuestion _question;
//
// public UniqueIpAssignmentsReplier(Batfish batfish,
// UniqueIpAssignmentsQuestion question) {
// _batfish = batfish;
// _question = question;
// _batfish.checkConfigurations();
//
// if (question.getDifferential()) {
// _batfish.checkEnvironmentExists(_batfish.getBaseTestrigSettings());
// _batfish.checkEnvironmentExists(_batfish.getDeltaTestrigSettings());
// UniqueIpAssignmentsAnswerElement before = initAnswerElement(batfish
// .getBaseTestrigSettings());
// UniqueIpAssignmentsAnswerElement after = initAnswerElement(batfish
// .getDeltaTestrigSettings());
// ObjectMapper mapper = new BatfishObjectMapper();
// try {
// String beforeJsonStr = mapper.writeValueAsString(before);
// String afterJsonStr = mapper.writeValueAsString(after);
// JSONObject beforeJson = new JSONObject(beforeJsonStr);
// JSONObject afterJson = new JSONObject(afterJsonStr);
// JsonDiff diff = new JsonDiff(beforeJson, afterJson);
// addAnswerElement(new JsonDiffAnswerElement(diff));
// }
// catch (JsonProcessingException | JSONException e) {
// throw new BatfishException(
// "Could not convert diff element to json string", e);
// }
// }
// else {
// UniqueIpAssignmentsAnswerElement answerElement =
// initAnswerElement(batfish
// .getTestrigSettings());
// addAnswerElement(answerElement);
// }
//
// }
public UniqueIpAssignmentsAnswerer(Question question, IBatfish batfish) {
super(question, batfish);
}
@Override
public AnswerElement answer() {
UniqueIpAssignmentsQuestion question = (UniqueIpAssignmentsQuestion) _question;
_batfish.checkConfigurations();
Pattern nodeRegex;
try {
nodeRegex = Pattern.compile(question.getNodeRegex());
}
catch (PatternSyntaxException e) {
throw new BatfishException(
"Supplied regex for nodes is not a valid java regex: \""
+ question.getNodeRegex() + "\"",
e);
}
UniqueIpAssignmentsAnswerElement answerElement = new UniqueIpAssignmentsAnswerElement();
Map<String, Configuration> configurations = _batfish
.loadConfigurations();
MultiSet<Ip> allIps = new TreeMultiSet<>();
MultiSet<Ip> enabledIps = new TreeMultiSet<>();
for (Entry<String, Configuration> e : configurations.entrySet()) {
String hostname = e.getKey();
if (!nodeRegex.matcher(hostname).matches()) {
continue;
}
Configuration c = e.getValue();
for (Interface iface : c.getInterfaces().values()) {
for (Prefix prefix : iface.getAllPrefixes()) {
Ip ip = prefix.getAddress();
allIps.add(ip);
if (iface.getActive()) {
enabledIps.add(ip);
}
}
}
}
for (Entry<String, Configuration> e : configurations.entrySet()) {
String hostname = e.getKey();
if (!nodeRegex.matcher(hostname).matches()) {
continue;
}
Configuration c = e.getValue();
for (Entry<String, Interface> e2 : c.getInterfaces().entrySet()) {
String interfaceName = e2.getKey();
Interface iface = e2.getValue();
for (Prefix prefix : iface.getAllPrefixes()) {
Ip ip = prefix.getAddress();
if (allIps.count(ip) != 1) {
answerElement.add(answerElement.getAllIps(), ip, hostname,
interfaceName);
}
if (iface.getActive()) {
if (enabledIps.count(ip) != 1) {
answerElement.add(answerElement.getEnabledIps(), ip,
hostname, interfaceName);
}
}
}
}
}
return answerElement;
}
}
// <question_page_comment>
/**
* Lists IP addresses that are assigned to multiple interfaces.
* <p>
* Except in cases of anycast, an IP address should be assigned to only one
* interface. This question produces the list of IP addresses for which this
* condition does not hold.
*
* @type UniqueIpAssignments multifile
*
* @param nodeRegex
* Regular expression for names of nodes to include. Default value
* is '.*' (all nodes).
* @param verbose
* Details coming
*
* @example bf_answer("UniqueIpAssignments", nodeRegex='as2.*') Answers the
* question only for nodes whose names start with 'as2'.
*/
public static class UniqueIpAssignmentsQuestion extends Question {
private static final String NODE_REGEX_VAR = "nodeRegex";
private static final String VERBOSE_VAR = "verbose";
private String _nodeRegex;
private boolean _verbose;
public UniqueIpAssignmentsQuestion() {
_nodeRegex = ".*";
}
@Override
public boolean getDataPlane() {
return false;
}
@Override
public String getName() {
return "uniqueipassignments";
}
@JsonProperty(NODE_REGEX_VAR)
public String getNodeRegex() {
return _nodeRegex;
}
@Override
public boolean getTraffic() {
return false;
}
@JsonProperty(VERBOSE_VAR)
public boolean getVerbose() {
return _verbose;
}
@Override
public String prettyPrint() {
String retString = String.format(
"uniqueipassignments %snodeRegex=\"%s\" | verbose=%s",
prettyPrintBase(), _nodeRegex, _verbose);
return retString;
}
@JsonProperty(NODE_REGEX_VAR)
public void setNodeRegex(String nodeRegex) {
_nodeRegex = nodeRegex;
}
@JsonProperty(VERBOSE_VAR)
public void setVerbose(boolean verbose) {
_verbose = verbose;
}
}
@Override
protected Answerer createAnswerer(Question question, IBatfish batfish) {
return new UniqueIpAssignmentsAnswerer(question, batfish);
}
@Override
protected Question createQuestion() {
return new UniqueIpAssignmentsQuestion();
}
}