diff --git a/Makefile.am b/Makefile.am index 23fdd956..da46cb6e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ fpm -s dir -t rpm -n core \ -v $(PACKAGE_VERSION) \ --rpm-init scripts/core-daemon \ --config-files "/etc/core" \ + -d "ethtool" \ -d "tcl" \ -d "tk" \ -d "procps-ng" \ @@ -89,6 +90,7 @@ fpm -s dir -t deb -n core \ --deb-systemd scripts/core-daemon.service \ --deb-no-default-config-files \ --config-files "/etc/core" \ + -d "ethtool" \ -d "tcl" \ -d "tk" \ -d "libtk-img" \ diff --git a/corefx/pom.xml b/corefx/pom.xml index 149d4ac1..af957aa2 100644 --- a/corefx/pom.xml +++ b/corefx/pom.xml @@ -13,8 +13,9 @@ 1.8 1.8 2.1.1 - 2.9.6 + 2.9.9 1.20.0 + 2.9.0 @@ -58,25 +59,15 @@ jackson-annotations ${jackson.version} - - com.squareup.okhttp3 - okhttp - 3.11.0 - org.apache.logging.log4j log4j-api - 2.9.0 + ${log4j.version} org.apache.logging.log4j log4j-core - 2.9.0 - - - io.socket - socket.io-client - 0.8.3 + ${log4j.version} org.projectlombok @@ -84,11 +75,6 @@ 1.18.0 provided - - commons-net - commons-net - 3.6 - com.jfoenix jfoenix @@ -114,6 +100,11 @@ guava 20.0 + + com.github.seancfoley + ipaddress + 5.0.2 + @@ -153,4 +144,4 @@ - \ No newline at end of file + diff --git a/corefx/src/main/java/com/core/client/ICoreClient.java b/corefx/src/main/java/com/core/client/ICoreClient.java index 7e0350aa..d5c5c8fe 100644 --- a/corefx/src/main/java/com/core/client/ICoreClient.java +++ b/corefx/src/main/java/com/core/client/ICoreClient.java @@ -1,8 +1,8 @@ package com.core.client; import com.core.Controller; -import com.core.client.rest.ServiceFile; -import com.core.client.rest.WlanConfig; +import com.core.data.ServiceFile; +import com.core.data.WlanConfig; import com.core.data.*; import java.io.File; diff --git a/corefx/src/main/java/com/core/client/grpc/CoreGrpcClient.java b/corefx/src/main/java/com/core/client/grpc/CoreGrpcClient.java index 972c30be..2c626b73 100644 --- a/corefx/src/main/java/com/core/client/grpc/CoreGrpcClient.java +++ b/corefx/src/main/java/com/core/client/grpc/CoreGrpcClient.java @@ -2,10 +2,10 @@ package com.core.client.grpc; import com.core.Controller; import com.core.client.ICoreClient; -import com.core.client.rest.ServiceFile; -import com.core.client.rest.WlanConfig; import com.core.data.*; import com.core.ui.dialogs.MobilityPlayerDialog; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; import io.grpc.Context; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; @@ -123,6 +123,9 @@ public class CoreGrpcClient implements ICoreClient { private CoreProto.Interface interfaceToProto(CoreInterface coreInterface) { CoreProto.Interface.Builder builder = CoreProto.Interface.newBuilder(); + if (coreInterface.getId() != null) { + builder.setId(coreInterface.getId()); + } if (coreInterface.getName() != null) { builder.setName(coreInterface.getName()); } @@ -130,16 +133,16 @@ public class CoreGrpcClient implements ICoreClient { builder.setMac(coreInterface.getMac()); } if (coreInterface.getIp4() != null) { - builder.setIp4(coreInterface.getIp4()); + builder.setIp4(coreInterface.getIp4().toAddressString().getHostAddress().toString()); } - if (coreInterface.getIp4Mask() != null) { - builder.setIp4Mask(coreInterface.getIp4Mask()); + if (coreInterface.getIp4() != null) { + builder.setIp4Mask(coreInterface.getIp4().getPrefixLength()); } if (coreInterface.getIp6() != null) { - builder.setIp6(coreInterface.getIp6()); + builder.setIp6(coreInterface.getIp6().toAddressString().getHostAddress().toString()); } - if (coreInterface.getIp6Mask() != null) { - builder.setIp6Mask(Integer.parseInt(coreInterface.getIp6Mask())); + if (coreInterface.getIp6() != null) { + builder.setIp6Mask(coreInterface.getIp6().getPrefixLength()); } return builder.build(); } @@ -170,10 +173,12 @@ public class CoreGrpcClient implements ICoreClient { coreInterface.setId(protoInterface.getId()); coreInterface.setName(protoInterface.getName()); coreInterface.setMac(protoInterface.getMac()); - coreInterface.setIp4(protoInterface.getIp4()); - coreInterface.setIp4Mask(protoInterface.getIp4Mask()); - coreInterface.setIp6(protoInterface.getIp6()); - coreInterface.setIp6Mask(Integer.toString(protoInterface.getIp6Mask())); + String ip4String = String.format("%s/%s", protoInterface.getIp4(), protoInterface.getIp4Mask()); + IPAddress ip4 = new IPAddressString(ip4String).getAddress(); + coreInterface.setIp4(ip4); + String ip6String = String.format("%s/%s", protoInterface.getIp6(), protoInterface.getIp6Mask()); + IPAddress ip6 = new IPAddressString(ip6String).getAddress(); + coreInterface.setIp6(ip6); return coreInterface; } diff --git a/corefx/src/main/java/com/core/client/rest/CoreRestClient.java b/corefx/src/main/java/com/core/client/rest/CoreRestClient.java deleted file mode 100644 index cecc5bf9..00000000 --- a/corefx/src/main/java/com/core/client/rest/CoreRestClient.java +++ /dev/null @@ -1,430 +0,0 @@ -package com.core.client.rest; - -import com.core.Controller; -import com.core.client.ICoreClient; -import com.core.data.*; -import com.core.utils.WebUtils; -import com.core.websocket.CoreWebSocket; -import lombok.Data; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.*; - -@Data -public class CoreRestClient implements ICoreClient { - private static final Logger logger = LogManager.getLogger(); - private String address; - private int port; - private Integer sessionId; - private SessionState sessionState; - private CoreWebSocket coreWebSocket; - - @Override - public void setConnection(String address, int port) { - this.address = address; - this.port = port; - } - - @Override - public boolean isLocalConnection() { - return address.equals("127.0.0.1") || address.equals("localhost"); - } - - @Override - public Integer currentSession() { - return sessionId; - } - - @Override - public void updateState(SessionState state) { - sessionState = state; - } - - @Override - public void updateSession(Integer sessionId) { - this.sessionId = sessionId; - } - - private String getUrl(String path) { - return String.format("http://%s:%s/%s", address, port, path); - } - - @Override - public SessionOverview createSession() throws IOException { - String url = getUrl("sessions"); - return WebUtils.post(url, SessionOverview.class); - } - - @Override - public boolean deleteSession(Integer sessionId) throws IOException { - String path = String.format("sessions/%s", sessionId); - String url = getUrl(path); - return WebUtils.delete(url); - } - - public Map> getServices() throws IOException { - String url = getUrl("services"); - GetServices getServices = WebUtils.getJson(url, GetServices.class); - return getServices.getGroups(); - } - - @Override - public Session getSession(Integer sessionId) throws IOException { - String path = String.format("sessions/%s", sessionId); - String url = getUrl(path); - return WebUtils.getJson(url, Session.class); - } - - @Override - public List getSessions() throws IOException { - String url = getUrl("sessions"); - GetSessions getSessions = WebUtils.getJson(url, GetSessions.class); - return getSessions.getSessions(); - } - - @Override - public boolean start(Collection nodes, Collection links, List hooks) throws IOException { - boolean result = setState(SessionState.DEFINITION); - if (!result) { - return false; - } - - result = setState(SessionState.CONFIGURATION); - if (!result) { - return false; - } - - for (Hook hook : hooks) { - if (!createHook(hook)) { - return false; - } - } - - for (CoreNode node : nodes) { - // must pre-configure wlan nodes, if not already - if (node.getNodeType().getValue() == NodeType.WLAN) { - WlanConfig config = getWlanConfig(node); - setWlanConfig(node, config); - } - - if (!createNode(node)) { - return false; - } - } - - for (CoreLink link : links) { - if (!createLink(link)) { - return false; - } - } - - return setState(SessionState.INSTANTIATION); - } - - @Override - public boolean stop() throws IOException { - return setState(SessionState.SHUTDOWN); - } - - @Override - public boolean setState(SessionState state) throws IOException { - String url = getUrl(String.format("sessions/%s/state", sessionId)); - Map data = new HashMap<>(); - data.put("state", state.getValue()); - boolean result = WebUtils.putJson(url, data); - - if (result) { - sessionState = state; - } - return result; - } - - private boolean uploadFile(File file) throws IOException { - String url = getUrl("upload"); - return WebUtils.postFile(url, file); - } - - @Override - public boolean startThroughput(Controller controller) throws IOException { - String url = getUrl("throughput/start"); - return WebUtils.putJson(url); - } - - @Override - public boolean stopThroughput() throws IOException { - String url = getUrl("throughput/stop"); - return WebUtils.putJson(url); - } - - @Override - public Map> getDefaultServices() throws IOException { - String url = getUrl(String.format("sessions/%s/services/default", sessionId)); - GetDefaultServices getDefaultServices = WebUtils.getJson(url, GetDefaultServices.class); - return getDefaultServices.getDefaults(); - } - - @Override - public boolean setDefaultServices(Map> defaults) throws IOException { - String url = getUrl(String.format("sessions/%s/services/default", sessionId)); - return WebUtils.postJson(url, defaults); - } - - @Override - public CoreService getService(CoreNode node, String serviceName) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s", sessionId, node.getId(), serviceName)); - return WebUtils.getJson(url, CoreService.class); - } - - @Override - public boolean setService(CoreNode node, String serviceName, CoreService service) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s", sessionId, node.getId(), serviceName)); - return WebUtils.putJson(url, service); - } - - @Override - public String getServiceFile(CoreNode node, String serviceName, String fileName) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/file", sessionId, node.getId(), - serviceName)); - Map args = new HashMap<>(); - args.put("file", fileName); - return WebUtils.getJson(url, String.class, args); - } - - @Override - public boolean startService(CoreNode node, String serviceName) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/start", sessionId, node.getId(), - serviceName)); - return WebUtils.putJson(url); - } - - @Override - public boolean stopService(CoreNode node, String serviceName) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/stop", sessionId, node.getId(), - serviceName)); - return WebUtils.putJson(url); - } - - @Override - public boolean restartService(CoreNode node, String serviceName) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/restart", sessionId, node.getId(), - serviceName)); - return WebUtils.putJson(url); - } - - @Override - public boolean validateService(CoreNode node, String serviceName) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/validate", sessionId, node.getId(), - serviceName)); - return WebUtils.putJson(url); - } - - @Override - public boolean setServiceFile(CoreNode node, String serviceName, ServiceFile serviceFile) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/file", sessionId, node.getId(), - serviceName)); - return WebUtils.putJson(url, serviceFile); - } - - @Override - public List getEmaneModels() throws IOException { - String url = getUrl(String.format("sessions/%s/emane/models", sessionId)); - GetEmaneModels getEmaneModels = WebUtils.getJson(url, GetEmaneModels.class); - return getEmaneModels.getModels(); - } - - @Override - public List getEmaneModelConfig(Integer id, String model) throws IOException { - String url = getUrl(String.format("sessions/%s/emane/model/config", sessionId)); - Map args = new HashMap<>(); - args.put("node", id.toString()); - args.put("name", model); - GetConfig getConfig = WebUtils.getJson(url, GetConfig.class, args); - return getConfig.getGroups(); - } - - @Override - public List getEmaneConfig(CoreNode node) throws IOException { - String url = getUrl(String.format("sessions/%s/emane/config", sessionId)); - Map args = new HashMap<>(); - args.put("node", node.getId().toString()); - GetConfig getConfig = WebUtils.getJson(url, GetConfig.class, args); - return getConfig.getGroups(); - } - - @Override - public boolean setEmaneConfig(CoreNode node, List options) throws IOException { - String url = getUrl(String.format("sessions/%s/emane/config", sessionId)); - SetEmaneConfig setEmaneConfig = new SetEmaneConfig(); - setEmaneConfig.setNode(node.getId()); - setEmaneConfig.setValues(options); - return WebUtils.putJson(url, setEmaneConfig); - } - - @Override - public boolean setEmaneModelConfig(Integer id, String model, List options) throws IOException { - String url = getUrl(String.format("sessions/%s/emane/model/config", sessionId)); - SetEmaneModelConfig setEmaneModelConfig = new SetEmaneModelConfig(); - setEmaneModelConfig.setNode(id); - setEmaneModelConfig.setName(model); - setEmaneModelConfig.setValues(options); - return WebUtils.putJson(url, setEmaneModelConfig); - } - - @Override - public boolean isRunning() { - return sessionState == SessionState.RUNTIME; - } - - @Override - public void saveSession(File file) throws IOException { - String path = String.format("sessions/%s/xml", sessionId); - String url = getUrl(path); - WebUtils.getFile(url, file); - } - - @Override - public SessionOverview openSession(File file) throws IOException { - String url = getUrl("sessions/xml"); - return WebUtils.postFile(url, file, SessionOverview.class); - } - - @Override - public List getSessionConfig() throws IOException { - String url = getUrl(String.format("sessions/%s/options", sessionId)); - GetConfig getConfig = WebUtils.getJson(url, GetConfig.class); - return getConfig.getGroups(); - } - - @Override - public boolean setSessionConfig(List configOptions) throws IOException { - String url = getUrl(String.format("sessions/%s/options", sessionId)); - SetConfig setConfig = new SetConfig(configOptions); - return WebUtils.putJson(url, setConfig); - } - - @Override - public LocationConfig getLocationConfig() throws IOException { - String url = getUrl(String.format("sessions/%s/location", sessionId)); - return WebUtils.getJson(url, LocationConfig.class); - } - - @Override - public boolean setLocationConfig(LocationConfig config) throws IOException { - String url = getUrl(String.format("sessions/%s/location", sessionId)); - return WebUtils.putJson(url, config); - } - - @Override - public String nodeCommand(CoreNode node, String command) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/command", sessionId, node.getId())); - return WebUtils.putJson(url, command, String.class); - } - - @Override - public boolean createNode(CoreNode node) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes", sessionId)); - return WebUtils.postJson(url, node); - } - - - @Override - public boolean editNode(CoreNode node) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s", sessionId, node.getId())); - return WebUtils.putJson(url, node); - } - - @Override - public boolean deleteNode(CoreNode node) throws IOException { - String url = getUrl(String.format("/sessions/%s/nodes/%s", sessionId, node.getId())); - return WebUtils.delete(url); - } - - @Override - public boolean createLink(CoreLink link) throws IOException { - String url = getUrl(String.format("sessions/%s/links", sessionId)); - return WebUtils.postJson(url, link); - } - - @Override - public boolean editLink(CoreLink link) throws IOException { - String url = getUrl(String.format("sessions/%s/links", sessionId)); - return WebUtils.putJson(url, link); - } - - @Override - public boolean createHook(Hook hook) throws IOException { - String url = getUrl(String.format("sessions/%s/hooks", sessionId)); - return WebUtils.postJson(url, hook); - } - - @Override - public List getHooks() throws IOException { - String url = getUrl(String.format("sessions/%s/hooks", sessionId)); - GetHooks getHooks = WebUtils.getJson(url, GetHooks.class); - return getHooks.getHooks(); - } - - @Override - public WlanConfig getWlanConfig(CoreNode node) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/wlan", sessionId, node.getId())); - return WebUtils.getJson(url, WlanConfig.class); - } - - @Override - public boolean setWlanConfig(CoreNode node, WlanConfig config) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/wlan", sessionId, node.getId())); - return WebUtils.putJson(url, config); - } - - @Override - public String getTerminalCommand(CoreNode node) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/terminal", sessionId, node.getId())); - return WebUtils.getJson(url, String.class); - } - - @Override - public boolean setMobilityConfig(CoreNode node, MobilityConfig config) throws IOException { - boolean uploaded = uploadFile(config.getScriptFile()); - if (!uploaded) { - throw new IOException("failed to upload mobility script"); - } - - String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", sessionId, node.getId())); - config.setFile(config.getScriptFile().getName()); - return WebUtils.postJson(url, config); - } - - @Override - public Map getMobilityConfigs() throws IOException { - String url = getUrl(String.format("sessions/%s/mobility/configs", sessionId)); - GetMobilityConfigs getMobilityConfigs = WebUtils.getJson(url, GetMobilityConfigs.class); - return getMobilityConfigs.getConfigurations(); - } - - @Override - public MobilityConfig getMobilityConfig(CoreNode node) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", sessionId, node.getId())); - return WebUtils.getJson(url, MobilityConfig.class); - } - - @Override - public boolean mobilityAction(CoreNode node, String action) throws IOException { - String url = getUrl(String.format("sessions/%s/nodes/%s/mobility/%s", sessionId, node.getId(), action)); - return WebUtils.putJson(url); - } - - @Override - public void setupEventHandlers(Controller controller) throws IOException { - coreWebSocket.stop(); - coreWebSocket = new CoreWebSocket(controller); - try { - coreWebSocket.start(address, port); - } catch (URISyntaxException ex) { - throw new IOException("error starting web socket", ex); - } - } -} diff --git a/corefx/src/main/java/com/core/client/rest/GetConfig.java b/corefx/src/main/java/com/core/client/rest/GetConfig.java deleted file mode 100644 index 61a843b6..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.core.client.rest; - -import com.core.data.ConfigGroup; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -@Data -public class GetConfig { - private List groups = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/GetDefaultServices.java b/corefx/src/main/java/com/core/client/rest/GetDefaultServices.java deleted file mode 100644 index b134cbc0..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetDefaultServices.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.core.client.rest; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class GetDefaultServices { - private Map> defaults = new HashMap<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/GetEmaneModels.java b/corefx/src/main/java/com/core/client/rest/GetEmaneModels.java deleted file mode 100644 index 43cef1c6..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetEmaneModels.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.core.client.rest; - -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -@Data -public class GetEmaneModels { - private List models = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/GetHooks.java b/corefx/src/main/java/com/core/client/rest/GetHooks.java deleted file mode 100644 index fe26e828..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetHooks.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.core.client.rest; - -import com.core.data.Hook; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -@Data -public class GetHooks { - private List hooks = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/GetMobilityConfigs.java b/corefx/src/main/java/com/core/client/rest/GetMobilityConfigs.java deleted file mode 100644 index e5905b7e..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetMobilityConfigs.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.core.client.rest; - -import com.core.data.MobilityConfig; -import lombok.Data; - -import java.util.HashMap; -import java.util.Map; - -@Data -public class GetMobilityConfigs { - private Map configurations = new HashMap<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/GetServices.java b/corefx/src/main/java/com/core/client/rest/GetServices.java deleted file mode 100644 index 17e04ddc..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetServices.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.core.client.rest; - -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -@Data -@NoArgsConstructor -public class GetServices { - private Map> groups; -} diff --git a/corefx/src/main/java/com/core/client/rest/GetSessions.java b/corefx/src/main/java/com/core/client/rest/GetSessions.java deleted file mode 100644 index 674fc83a..00000000 --- a/corefx/src/main/java/com/core/client/rest/GetSessions.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.core.client.rest; - -import com.core.data.SessionOverview; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - -@Data -@NoArgsConstructor -public class GetSessions { - private List sessions = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/SetConfig.java b/corefx/src/main/java/com/core/client/rest/SetConfig.java deleted file mode 100644 index 0d3f11ea..00000000 --- a/corefx/src/main/java/com/core/client/rest/SetConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.core.client.rest; - -import com.core.data.ConfigOption; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class SetConfig { - private List values = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/SetEmaneConfig.java b/corefx/src/main/java/com/core/client/rest/SetEmaneConfig.java deleted file mode 100644 index ee947c51..00000000 --- a/corefx/src/main/java/com/core/client/rest/SetEmaneConfig.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.core.client.rest; - -import com.core.data.ConfigOption; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -@Data -public class SetEmaneConfig { - private Integer node; - private List values = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/client/rest/SetEmaneModelConfig.java b/corefx/src/main/java/com/core/client/rest/SetEmaneModelConfig.java deleted file mode 100644 index e5c37092..00000000 --- a/corefx/src/main/java/com/core/client/rest/SetEmaneModelConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.core.client.rest; - -import com.core.data.ConfigOption; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -@Data -public class SetEmaneModelConfig { - private Integer node; - private String name; - private List values = new ArrayList<>(); -} diff --git a/corefx/src/main/java/com/core/data/CoreEvent.java b/corefx/src/main/java/com/core/data/CoreEvent.java index 9ac8ed03..718097d8 100644 --- a/corefx/src/main/java/com/core/data/CoreEvent.java +++ b/corefx/src/main/java/com/core/data/CoreEvent.java @@ -1,6 +1,5 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonSetter; import lombok.Data; @Data @@ -11,9 +10,4 @@ public class CoreEvent { private Double time; private EventType eventType; private String data; - - @JsonSetter("event_type") - public void setEventType(int value) { - eventType = EventType.get(value); - } } diff --git a/corefx/src/main/java/com/core/data/CoreInterface.java b/corefx/src/main/java/com/core/data/CoreInterface.java index f159f10e..200aeabd 100644 --- a/corefx/src/main/java/com/core/data/CoreInterface.java +++ b/corefx/src/main/java/com/core/data/CoreInterface.java @@ -1,6 +1,6 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonProperty; +import inet.ipaddr.IPAddress; import lombok.Data; import lombok.NoArgsConstructor; @@ -10,10 +10,6 @@ public class CoreInterface { private Integer id; private String name; private String mac; - private String ip4; - @JsonProperty("ip4mask") - private Integer ip4Mask; - private String ip6; - @JsonProperty("ip6mask") - private String ip6Mask; + private IPAddress ip4; + private IPAddress ip6; } diff --git a/corefx/src/main/java/com/core/data/CoreLink.java b/corefx/src/main/java/com/core/data/CoreLink.java index f3d4a215..88c6ff30 100644 --- a/corefx/src/main/java/com/core/data/CoreLink.java +++ b/corefx/src/main/java/com/core/data/CoreLink.java @@ -1,7 +1,5 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -12,36 +10,16 @@ import lombok.NoArgsConstructor; public class CoreLink { @EqualsAndHashCode.Include private Integer id; - - @JsonIgnore private Float weight = 1.0f; - - @JsonIgnore private boolean loaded = true; - - @JsonIgnore private double throughput; - - @JsonIgnore private boolean visible = true; - - @JsonProperty("message_type") private Integer messageType; - private Integer type = 1; - - @JsonProperty("node_one") private Integer nodeOne; - - @JsonProperty("node_two") private Integer nodeTwo; - - @JsonProperty("interface_one") private CoreInterface interfaceOne; - - @JsonProperty("interface_two") private CoreInterface interfaceTwo; - private CoreLinkOptions options = new CoreLinkOptions(); public CoreLink(Integer id) { diff --git a/corefx/src/main/java/com/core/data/CoreNode.java b/corefx/src/main/java/com/core/data/CoreNode.java index f441bd69..ab5240a8 100644 --- a/corefx/src/main/java/com/core/data/CoreNode.java +++ b/corefx/src/main/java/com/core/data/CoreNode.java @@ -2,7 +2,6 @@ package com.core.data; import com.core.graph.RadioIcon; import com.core.utils.IconUtils; -import com.fasterxml.jackson.annotation.JsonIgnore; import edu.uci.ics.jung.visualization.LayeredIcon; import lombok.Data; import lombok.EqualsAndHashCode; @@ -27,15 +26,10 @@ public class CoreNode { private Set services = new HashSet<>(); private String emane; private String url; - @JsonIgnore private NodeType nodeType; - @JsonIgnore private String icon; - @JsonIgnore private boolean loaded = true; - @JsonIgnore private LayeredIcon graphIcon; - @JsonIgnore private RadioIcon radioIcon = new RadioIcon(); public CoreNode(Integer id) { diff --git a/corefx/src/main/java/com/core/data/CoreService.java b/corefx/src/main/java/com/core/data/CoreService.java index ed9dd230..c33aebed 100644 --- a/corefx/src/main/java/com/core/data/CoreService.java +++ b/corefx/src/main/java/com/core/data/CoreService.java @@ -1,6 +1,5 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.ArrayList; @@ -14,9 +13,7 @@ public class CoreService { private List configs = new ArrayList<>(); private List startup = new ArrayList<>(); private List validate = new ArrayList<>(); - @JsonProperty("validation_mode") private String validationMode; - @JsonProperty("validation_timer") private String validationTimer; private List shutdown = new ArrayList<>(); private String meta; diff --git a/corefx/src/main/java/com/core/data/Hook.java b/corefx/src/main/java/com/core/data/Hook.java index 35b1a934..652976b0 100644 --- a/corefx/src/main/java/com/core/data/Hook.java +++ b/corefx/src/main/java/com/core/data/Hook.java @@ -1,13 +1,11 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; @Data public class Hook { private String file; private Integer state; - @JsonIgnore private String stateDisplay; private String data; } diff --git a/corefx/src/main/java/com/core/data/InterfaceThroughput.java b/corefx/src/main/java/com/core/data/InterfaceThroughput.java index 1c6303e0..8df86501 100644 --- a/corefx/src/main/java/com/core/data/InterfaceThroughput.java +++ b/corefx/src/main/java/com/core/data/InterfaceThroughput.java @@ -1,12 +1,10 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data public class InterfaceThroughput { private int node; - @JsonProperty("interface") private int nodeInterface; private double throughput; } diff --git a/corefx/src/main/java/com/core/data/MobilityConfig.java b/corefx/src/main/java/com/core/data/MobilityConfig.java index 67b5d769..f16de6ff 100644 --- a/corefx/src/main/java/com/core/data/MobilityConfig.java +++ b/corefx/src/main/java/com/core/data/MobilityConfig.java @@ -1,7 +1,5 @@ package com.core.data; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.io.File; @@ -9,17 +7,12 @@ import java.io.File; @Data public class MobilityConfig { private String file; - @JsonIgnore private File scriptFile; - @JsonProperty("refresh_ms") private Integer refresh; private String loop; private String autostart; private String map; - @JsonProperty("script_start") private String startScript; - @JsonProperty("script_pause") private String pauseScript; - @JsonProperty("script_stop") private String stopScript; } diff --git a/corefx/src/main/java/com/core/data/NodeType.java b/corefx/src/main/java/com/core/data/NodeType.java index 4af7dc3d..3b070799 100644 --- a/corefx/src/main/java/com/core/data/NodeType.java +++ b/corefx/src/main/java/com/core/data/NodeType.java @@ -73,11 +73,9 @@ public class NodeType { return ID_LOOKUP.values().stream() .filter(nodeType -> { boolean sameType = nodeType.getValue() == type; - boolean sameModel; - if (model != null) { + boolean sameModel = true; + if (!model.isEmpty()) { sameModel = model.equals(nodeType.getModel()); - } else { - sameModel = nodeType.getModel() == null; } return sameType && sameModel; }) diff --git a/corefx/src/main/java/com/core/client/rest/ServiceFile.java b/corefx/src/main/java/com/core/data/ServiceFile.java similarity index 87% rename from corefx/src/main/java/com/core/client/rest/ServiceFile.java rename to corefx/src/main/java/com/core/data/ServiceFile.java index 977ed984..f30efcd0 100644 --- a/corefx/src/main/java/com/core/client/rest/ServiceFile.java +++ b/corefx/src/main/java/com/core/data/ServiceFile.java @@ -1,4 +1,4 @@ -package com.core.client.rest; +package com.core.data; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/corefx/src/main/java/com/core/client/rest/WlanConfig.java b/corefx/src/main/java/com/core/data/WlanConfig.java similarity index 86% rename from corefx/src/main/java/com/core/client/rest/WlanConfig.java rename to corefx/src/main/java/com/core/data/WlanConfig.java index 45b9805f..26048d73 100644 --- a/corefx/src/main/java/com/core/client/rest/WlanConfig.java +++ b/corefx/src/main/java/com/core/data/WlanConfig.java @@ -1,4 +1,4 @@ -package com.core.client.rest; +package com.core.data; import lombok.Data; diff --git a/corefx/src/main/java/com/core/graph/CoreAddresses.java b/corefx/src/main/java/com/core/graph/CoreAddresses.java index 5db724b6..70ab5e06 100644 --- a/corefx/src/main/java/com/core/graph/CoreAddresses.java +++ b/corefx/src/main/java/com/core/graph/CoreAddresses.java @@ -1,41 +1,79 @@ package com.core.graph; import com.core.data.CoreInterface; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.Collection; +import java.beans.IndexedPropertyDescriptor; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicBoolean; public class CoreAddresses { private static final Logger logger = LogManager.getLogger(); - public static final int IP4_MASK = 24; - public static final int IP4_INDEX = (IP4_MASK / 8) - 1; + private IPAddress currentSubnet = new IPAddressString("10.0.0.0/24").getAddress().toPrefixBlock(); + private Queue deleted = new LinkedBlockingQueue<>(); + private Set usedSubnets = new HashSet<>(); - private String ip4Base; - - public CoreAddresses(String ip4Base) { - this.ip4Base = ip4Base; + public void usedAddress(IPAddress address) { + logger.info("adding used address: {} - {}", address, address.toPrefixBlock()); + usedSubnets.add(address.toPrefixBlock()); + logger.info("used subnets: {}", usedSubnets); } - public int getSubnet(Collection nodeOneInterfaces, Collection nodeTwoInterfaces) { - int subOne = getMaxSubnet(nodeOneInterfaces); - int subTwo = getMaxSubnet(nodeTwoInterfaces); - logger.info("next subnet: {} - {}", subOne, subTwo); - return Math.max(subOne, subTwo) + 1; + public void reuseSubnet(IPAddress subnet) { + deleted.add(subnet); } - private int getMaxSubnet(Collection coreInterfaces) { - int sub = 0; - for (CoreInterface coreInterface : coreInterfaces) { - String[] values = coreInterface.getIp4().split("\\."); - int currentSub = Integer.parseInt(values[IP4_INDEX]); - logger.info("checking {} value {}", coreInterface.getIp4(), currentSub); - sub = Math.max(currentSub, sub); + public IPAddress nextSubnet() { + logger.info("getting next subnet: {}", currentSubnet); + // skip existing subnets, when loaded from file + while (usedSubnets.contains(currentSubnet)) { + currentSubnet = currentSubnet.incrementBoundary(1).toPrefixBlock(); } - return sub; + + // re-use any deleted subnets + IPAddress next = deleted.poll(); + if (next == null) { + next = currentSubnet; + currentSubnet = currentSubnet.incrementBoundary(1).toPrefixBlock(); + } + return next; } - public String getIp4Address(int sub, int id) { - return String.format("%s.%s.%s", ip4Base, sub, id); + public IPAddress findSubnet(Set interfaces) { + IPAddress subnet; + logger.info("finding subnet from interfaces: {}", interfaces); + if (interfaces.isEmpty()) { + subnet = nextSubnet(); + } else { + IPAddress maxAddress = getMaxAddress(interfaces); + subnet = maxAddress.toPrefixBlock(); + } + return subnet; + } + + private IPAddress getMaxAddress(Set interfaces) { + return interfaces.stream() + .map(CoreInterface::getIp4) + .max(Comparator.comparingInt(x -> x.toIPv4().intValue())) + .orElseGet(() -> currentSubnet); + } + + public void reset() { + deleted.clear(); + usedSubnets.clear(); + currentSubnet = new IPAddressString("10.0.0.0/24").getAddress().toPrefixBlock(); + } + + public static void main(String... args) { + IPAddress addresses = new IPAddressString("10.0.0.0/16").getAddress(); + System.out.println(String.format("address: %s", addresses.increment(257))); } } diff --git a/corefx/src/main/java/com/core/graph/NetworkGraph.java b/corefx/src/main/java/com/core/graph/NetworkGraph.java index 7d55cdb2..da3389ef 100644 --- a/corefx/src/main/java/com/core/graph/NetworkGraph.java +++ b/corefx/src/main/java/com/core/graph/NetworkGraph.java @@ -20,9 +20,9 @@ import edu.uci.ics.jung.visualization.control.GraphMouseListener; import edu.uci.ics.jung.visualization.control.ModalGraphMouse; import edu.uci.ics.jung.visualization.decorators.EdgeShape; import edu.uci.ics.jung.visualization.renderers.Renderer; +import inet.ipaddr.IPAddress; import javafx.application.Platform; import lombok.Data; -import org.apache.commons.net.util.SubnetUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -32,7 +32,6 @@ import java.awt.event.MouseEvent; import java.awt.geom.Ellipse2D; import java.io.IOException; import java.util.*; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -50,8 +49,7 @@ public class NetworkGraph { private EditingModalGraphMouse graphMouse; private AnnotationControls annotationControls; - private SubnetUtils subnetUtils = new SubnetUtils("10.0.0.0/24"); - private CoreAddresses coreAddresses = new CoreAddresses("10.0"); + private CoreAddresses coreAddresses = new CoreAddresses(); private NodeType nodeType; private Map nodeMap = new ConcurrentHashMap<>(); private int vertexId = 1; @@ -77,9 +75,8 @@ public class NetworkGraph { graphViewer.setBackground(Color.WHITE); graphViewer.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.S); - RenderContext renderContext = graphViewer.getRenderContext(); - // node render properties + RenderContext renderContext = graphViewer.getRenderContext(); renderContext.setVertexLabelTransformer(CoreNode::getName); renderContext.setVertexLabelRenderer(nodeLabelRenderer); renderContext.setVertexShapeTransformer(node -> { @@ -251,6 +248,7 @@ public class NetworkGraph { } nodeMap.clear(); graphViewer.repaint(); + coreAddresses.reset(); } public void updatePositions() { @@ -287,40 +285,93 @@ public class NetworkGraph { private void handleEdgeAdded(GraphEvent.Edge edgeEvent) { CoreLink link = edgeEvent.getEdge(); - if (!link.isLoaded()) { - Pair endpoints = graph.getEndpoints(link); - - CoreNode nodeOne = endpoints.getFirst(); - CoreNode nodeTwo = endpoints.getSecond(); - - // create interfaces for nodes - int sub = coreAddresses.getSubnet( - getInterfaces(nodeOne), - getInterfaces(nodeTwo) - ); - - link.setNodeOne(nodeOne.getId()); - if (isNode(nodeOne)) { - int interfaceOneId = nextInterfaceId(nodeOne); - CoreInterface interfaceOne = createInterface(nodeOne, sub, interfaceOneId); - link.setInterfaceOne(interfaceOne); + if (link.isLoaded()) { + // load addresses to avoid duplication + if (link.getInterfaceOne().getIp4() != null) { + coreAddresses.usedAddress(link.getInterfaceOne().getIp4()); } - - link.setNodeTwo(nodeTwo.getId()); - if (isNode(nodeTwo)) { - int interfaceTwoId = nextInterfaceId(nodeTwo); - CoreInterface interfaceTwo = createInterface(nodeTwo, sub, interfaceTwoId); - link.setInterfaceTwo(interfaceTwo); + if (link.getInterfaceTwo().getIp4() != null) { + coreAddresses.usedAddress(link.getInterfaceTwo().getIp4()); } - - boolean isVisible = !checkForWirelessNode(nodeOne, nodeTwo); - link.setVisible(isVisible); - - logger.info("adding user created edge: {}", link); + return; } + Pair endpoints = graph.getEndpoints(link); + CoreNode nodeOne = endpoints.getFirst(); + CoreNode nodeTwo = endpoints.getSecond(); + boolean nodeOneIsDefault = isNode(nodeOne); + boolean nodeTwoIsDefault = isNode(nodeTwo); + + // check what we are linking together + IPAddress subnet = null; + Set interfaces; + if (nodeOneIsDefault && nodeTwoIsDefault) { + subnet = coreAddresses.nextSubnet(); + logger.info("linking node to node using subnet: {}", subnet); + } else if (nodeOneIsDefault) { + interfaces = getNetworkInterfaces(nodeTwo, new HashSet<>()); + subnet = coreAddresses.findSubnet(interfaces); + logger.info("linking node one to network using subnet: {}", subnet); + } else if (nodeTwoIsDefault) { + interfaces = getNetworkInterfaces(nodeOne, new HashSet<>()); + subnet = coreAddresses.findSubnet(interfaces); + logger.info("linking node two to network using subnet: {}", subnet); + } else { + logger.info("subnet not needed for linking networks together"); + } + + link.setNodeOne(nodeOne.getId()); + if (nodeOneIsDefault) { + int interfaceOneId = nextInterfaceId(nodeOne); + CoreInterface interfaceOne = createInterface(nodeOne, interfaceOneId, subnet); + link.setInterfaceOne(interfaceOne); + } + + link.setNodeTwo(nodeTwo.getId()); + if (nodeTwoIsDefault) { + int interfaceTwoId = nextInterfaceId(nodeTwo); + CoreInterface interfaceTwo = createInterface(nodeTwo, interfaceTwoId, subnet); + link.setInterfaceTwo(interfaceTwo); + } + + boolean isVisible = !checkForWirelessNode(nodeOne, nodeTwo); + link.setVisible(isVisible); + logger.info("adding user created edge: {}", link); } - public List getInterfaces(CoreNode node) { + public Set getNetworkInterfaces(CoreNode node, Set visited) { + Set interfaces = new HashSet<>(); + if (visited.contains(node)) { + return interfaces; + } + visited.add(node); + + logger.info("checking network node links: {}", node); + for (CoreLink link : graph.getIncidentEdges(node)) { + logger.info("checking link: {}", link); + if (link.getNodeOne() == null && link.getNodeTwo() == null) { + continue; + } + + // ignore oneself + CoreNode currentNode = getVertex(link.getNodeOne()); + CoreInterface currentInterface = link.getInterfaceOne(); + if (node.getId().equals(link.getNodeOne())) { + currentNode = getVertex(link.getNodeTwo()); + currentInterface = link.getInterfaceTwo(); + } + + if (isNode(currentNode)) { + interfaces.add(currentInterface); + } else { + Set nextInterfaces = getNetworkInterfaces(currentNode, visited); + interfaces.addAll(nextInterfaces); + } + } + + return interfaces; + } + + public Set getNodeInterfaces(CoreNode node) { return graph.getIncidentEdges(node).stream() .map(link -> { if (node.getId().equals(link.getNodeOne())) { @@ -330,7 +381,7 @@ public class NetworkGraph { } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .collect(Collectors.toSet()); } private int nextInterfaceId(CoreNode node) { @@ -360,19 +411,52 @@ public class NetworkGraph { return node.getType() == NodeType.DEFAULT; } - private CoreInterface createInterface(CoreNode node, int sub, int interfaceId) { + private CoreInterface createInterface(CoreNode node, int interfaceId, IPAddress subnet) { CoreInterface coreInterface = new CoreInterface(); coreInterface.setId(interfaceId); coreInterface.setName(String.format("eth%s", interfaceId)); - String nodeOneIp4 = coreAddresses.getIp4Address(sub, node.getId()); - coreInterface.setIp4(nodeOneIp4); - coreInterface.setIp4Mask(CoreAddresses.IP4_MASK); + IPAddress address = subnet.increment(node.getId()); + logger.info("creating interface for node({}): {}", node.getId(), address); + coreInterface.setIp4(address); + coreInterface.setIp6(address.toIPv6()); return coreInterface; } private void handleEdgeRemoved(GraphEvent.Edge edgeEvent) { CoreLink link = edgeEvent.getEdge(); logger.info("removed edge: {}", link); + CoreNode nodeOne = getVertex(link.getNodeOne()); + CoreInterface interfaceOne = link.getInterfaceOne(); + CoreNode nodeTwo = getVertex(link.getNodeTwo()); + CoreInterface interfaceTwo = link.getInterfaceTwo(); + boolean nodeOneIsDefault = isNode(nodeOne); + boolean nodeTwoIsDefault = isNode(nodeTwo); + + // check what we are unlinking + Set interfaces; + IPAddress subnet = null; + if (nodeOneIsDefault && nodeTwoIsDefault) { + subnet = interfaceOne.getIp4().toPrefixBlock(); + logger.info("unlinking node to node reuse subnet: {}", subnet); + } else if (nodeOneIsDefault) { + interfaces = getNetworkInterfaces(nodeTwo, new HashSet<>()); + if (interfaces.isEmpty()) { + subnet = interfaceOne.getIp4().toPrefixBlock(); + logger.info("unlinking node one from network reuse subnet: {}", subnet); + } + } else if (nodeTwoIsDefault) { + interfaces = getNetworkInterfaces(nodeOne, new HashSet<>()); + if (interfaces.isEmpty()) { + subnet = interfaceTwo.getIp4().toPrefixBlock(); + logger.info("unlinking node two from network reuse subnet: {}", subnet); + } + } else { + logger.info("nothing to do when unlinking networks"); + } + + if (subnet != null) { + coreAddresses.reuseSubnet(subnet); + } } private void handleVertexAdded(GraphEvent.Vertex vertexEvent) { @@ -431,7 +515,7 @@ public class NetworkGraph { } private boolean isWirelessNode(CoreNode node) { - return node.getType() == NodeType.EMANE || node.getType() == NodeType.WLAN; + return node != null && (node.getType() == NodeType.EMANE || node.getType() == NodeType.WLAN); } private boolean checkForWirelessNode(CoreNode nodeOne, CoreNode nodeTwo) { diff --git a/corefx/src/main/java/com/core/ui/LinkDetails.java b/corefx/src/main/java/com/core/ui/LinkDetails.java index 5a0c78d0..b01c5e40 100644 --- a/corefx/src/main/java/com/core/ui/LinkDetails.java +++ b/corefx/src/main/java/com/core/ui/LinkDetails.java @@ -11,6 +11,7 @@ import com.core.ui.textfields.DoubleFilter; import com.core.utils.FxmlUtils; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXTextField; +import inet.ipaddr.IPAddress; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; @@ -129,8 +130,8 @@ public class LinkDetails extends ScrollPane { if (coreInterface.getMac() != null) { addRow("MAC", coreInterface.getMac(), true); } - addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask()); - addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask()); + addIp4Address(coreInterface.getIp4()); + addIp6Address(coreInterface.getIp6()); } private void addRow(String labelText, String value, boolean disabled) { @@ -155,18 +156,18 @@ public class LinkDetails extends ScrollPane { return textField; } - private void addIp4Address(String ip, Integer mask) { + private void addIp4Address(IPAddress ip) { if (ip == null) { return; } - addRow("IP4", String.format("%s/%s", ip, mask), true); + addRow("IP4", ip.toString(), true); } - private void addIp6Address(String ip, String mask) { + private void addIp6Address(IPAddress ip) { if (ip == null) { return; } - addRow("IP6", String.format("%s/%s", ip, mask), true); + addRow("IP6", ip.toString(), true); } private void clear() { diff --git a/corefx/src/main/java/com/core/ui/NodeDetails.java b/corefx/src/main/java/com/core/ui/NodeDetails.java index c1e9751c..0fca8a95 100644 --- a/corefx/src/main/java/com/core/ui/NodeDetails.java +++ b/corefx/src/main/java/com/core/ui/NodeDetails.java @@ -10,6 +10,7 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXListView; import com.jfoenix.controls.JFXScrollPane; import com.jfoenix.controls.JFXTextField; +import inet.ipaddr.IPAddress; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; @@ -147,8 +148,8 @@ public class NodeDetails extends ScrollPane { if (coreInterface.getMac() != null) { addRow("MAC", coreInterface.getMac(), true); } - addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask()); - addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask()); + addIp4Address(coreInterface.getIp4()); + addIp6Address(coreInterface.getIp6()); } private void addRow(String labelText, String value, boolean disabled) { @@ -158,18 +159,18 @@ public class NodeDetails extends ScrollPane { gridPane.addRow(index++, label, textField); } - private void addIp4Address(String ip, Integer mask) { + private void addIp4Address(IPAddress ip) { if (ip == null) { return; } - addRow("IP4", String.format("%s/%s", ip, mask), true); + addRow("IP4", ip.toString(), true); } - private void addIp6Address(String ip, String mask) { + private void addIp6Address(IPAddress ip) { if (ip == null) { return; } - addRow("IP6", String.format("%s/%s", ip, mask), true); + addRow("IP6", ip.toString(), true); } private void clear() { diff --git a/corefx/src/main/java/com/core/ui/dialogs/NodeWlanDialog.java b/corefx/src/main/java/com/core/ui/dialogs/NodeWlanDialog.java index 8cbc7868..e11a498f 100644 --- a/corefx/src/main/java/com/core/ui/dialogs/NodeWlanDialog.java +++ b/corefx/src/main/java/com/core/ui/dialogs/NodeWlanDialog.java @@ -1,7 +1,7 @@ package com.core.ui.dialogs; import com.core.Controller; -import com.core.client.rest.WlanConfig; +import com.core.data.WlanConfig; import com.core.data.CoreNode; import com.core.ui.Toast; import com.jfoenix.controls.JFXButton; diff --git a/corefx/src/main/java/com/core/ui/dialogs/ServiceDialog.java b/corefx/src/main/java/com/core/ui/dialogs/ServiceDialog.java index ab526fc6..635997e8 100644 --- a/corefx/src/main/java/com/core/ui/dialogs/ServiceDialog.java +++ b/corefx/src/main/java/com/core/ui/dialogs/ServiceDialog.java @@ -1,7 +1,7 @@ package com.core.ui.dialogs; import com.core.Controller; -import com.core.client.rest.ServiceFile; +import com.core.data.ServiceFile; import com.core.data.CoreNode; import com.core.data.CoreService; import com.jfoenix.controls.JFXButton; diff --git a/corefx/src/main/java/com/core/utils/WebUtils.java b/corefx/src/main/java/com/core/utils/WebUtils.java deleted file mode 100644 index fec69313..00000000 --- a/corefx/src/main/java/com/core/utils/WebUtils.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.core.utils; - -import com.fasterxml.jackson.core.type.TypeReference; -import okhttp3.*; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.*; -import java.util.Collections; -import java.util.Map; - -public final class WebUtils { - private static final Logger logger = LogManager.getLogger(); - private static final OkHttpClient client = new OkHttpClient(); - private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - - private WebUtils() { - } - - public static T getJson(String url, Class clazz) throws IOException { - return getJson(url, clazz, Collections.emptyMap()); - } - - public static T getJson(String url, Class clazz, Map args) throws IOException { - logger.debug("get json: {}", url); - HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); - args.forEach(urlBuilder::addQueryParameter); - HttpUrl httpUrl = urlBuilder.build(); - - Request request = new Request.Builder() - .url(httpUrl) - .build(); - String response = readResponse(request); - return JsonUtils.read(response, clazz); - } - - public static void getFile(String url, File file) throws IOException { - logger.debug("get file: {}", url); - Request request = new Request.Builder() - .url(url) - .build(); - try (Response response = client.newCall(request).execute()) { - InputStream input = response.body().byteStream(); - try (OutputStream output = new FileOutputStream(file)) { - int count; - byte[] data = new byte[1024]; - while ((count = input.read(data)) != -1) { - output.write(data, 0, count); - } - } - } - } - - public static boolean postFile(String url, File file) throws IOException { - MediaType mediaType = MediaType.parse("File/*"); - RequestBody requestBody = new MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file)) - .build(); - - Request request = new Request.Builder() - .url(url) - .post(requestBody) - .build(); - - try (Response response = client.newCall(request).execute()) { - return response.isSuccessful(); - } - } - - public static T postFile(String url, File file, Class clazz) throws IOException { - MediaType mediaType = MediaType.parse("File/*"); - RequestBody requestBody = new MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file)) - .build(); - - Request request = new Request.Builder() - .url(url) - .post(requestBody) - .build(); - - String response = readResponse(request); - return JsonUtils.read(response, clazz); - } - - public static T getJson(String url, TypeReference reference) throws IOException { - Request request = new Request.Builder() - .url(url) - .build(); - String response = readResponse(request); - return JsonUtils.getMapper().readValue(response, reference); - } - - private static String readResponse(Request request) throws IOException { - try (Response response = client.newCall(request).execute()) { - ResponseBody body = response.body(); - if (body == null) { - throw new IOException("failed to received body"); - } else { - return body.string(); - } - } - } - - public static boolean postJson(String url, Object json) throws IOException { - logger.debug("post json: {} - {}", url, json); - RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json)); - Request request = new Request.Builder() - .url(url) - .post(body) - .build(); - try (Response response = client.newCall(request).execute()) { - return response.isSuccessful(); - } - } - - public static boolean putJson(String url) throws IOException { - logger.debug("put json: {}", url); - RequestBody body = new FormBody.Builder().build(); - Request request = new Request.Builder() - .url(url) - .put(body) - .build(); - try (Response response = client.newCall(request).execute()) { - return response.isSuccessful(); - } - } - - public static boolean putJson(String url, Object json) throws IOException { - logger.debug("put json: {} - {}", url, json); - RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json)); - Request request = new Request.Builder() - .url(url) - .put(body) - .build(); - try (Response response = client.newCall(request).execute()) { - return response.isSuccessful(); - } - } - - public static T putJson(String url, Object json, Class clazz) throws IOException { - logger.debug("put json: {} - {}", url, json); - RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json)); - Request request = new Request.Builder() - .url(url) - .put(body) - .build(); - String response = readResponse(request); - return JsonUtils.read(response, clazz); - } - - public static T post(String url, Class clazz) throws IOException { - logger.debug("post: {}", url); - RequestBody body = new FormBody.Builder().build(); - Request request = new Request.Builder() - .url(url) - .post(body) - .build(); - String response = readResponse(request); - return JsonUtils.read(response, clazz); - } - - public static boolean delete(String url) throws IOException { - logger.debug("delete: {}", url); - Request request = new Request.Builder() - .url(url) - .delete() - .build(); - try (Response response = client.newCall(request).execute()) { - return response.isSuccessful(); - } - } -} diff --git a/corefx/src/main/java/com/core/websocket/CoreWebSocket.java b/corefx/src/main/java/com/core/websocket/CoreWebSocket.java deleted file mode 100644 index 3019c622..00000000 --- a/corefx/src/main/java/com/core/websocket/CoreWebSocket.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.core.websocket; - -import com.core.Controller; -import com.core.data.*; -import com.core.ui.dialogs.MobilityPlayerDialog; -import com.core.utils.JsonUtils; -import io.socket.client.IO; -import io.socket.client.Socket; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.IOException; -import java.net.URISyntaxException; - -public class CoreWebSocket { - private static final Logger logger = LogManager.getLogger(); - private final Controller controller; - private Thread socketThread; - private Socket socket; - - public CoreWebSocket(Controller controller) { - this.controller = controller; - } - - public void start(String address, int port) throws URISyntaxException { - socket = IO.socket(String.format("http://%s:%s", address, port)); - socket.on(Socket.EVENT_CONNECT, args -> logger.info("connected to web socket")); - socket.on("node", this::handleNodes); - socket.on("event", this::handleEvents); - socket.on("config", this::handleConfigs); - socket.on("link", this::handleLinks); - socket.on("throughput", this::handleThroughputs); - socket.on(Socket.EVENT_DISCONNECT, args -> logger.info("disconnected from web socket")); - - logger.info("attempting to connect to web socket!"); - socketThread = new Thread(socket::connect); - socketThread.setDaemon(true); - socketThread.start(); - } - - public void stop() { - if (socketThread != null) { - socket.close(); - socketThread.interrupt(); - } - } - - private void handleThroughputs(Object... args) { - for (Object arg : args) { - logger.info("throughput update: {}", arg); - try { - Throughputs throughputs = JsonUtils.read(arg.toString(), Throughputs.class); - controller.handleThroughputs(throughputs); - } catch (IOException ex) { - logger.error("error getting throughputs", ex); - } - } - } - - private void handleNodes(Object... args) { - for (Object arg : args) { - try { - CoreNode node = JsonUtils.read(arg.toString(), CoreNode.class); - logger.info("core node update: {}", node); - controller.getNetworkGraph().setNodeLocation(node); - } catch (IOException ex) { - logger.error("error getting core node", ex); - } - } - } - - private void handleEvents(Object... args) { - for (Object arg : args) { - try { - CoreEvent event = JsonUtils.read(arg.toString(), CoreEvent.class); - logger.info("handling broadcast event: {}", event); - SessionState state = SessionState.get(event.getEventType().getValue()); - if (state == null) { - logger.warn("unknown event type: {}", event.getEventType().getValue()); - return; - } - - // session state event - if (state.getValue() <= 6) { - logger.info("event updating session state: {}", state); - controller.getCoreClient().updateState(state); - // mobility script event - } else if (state.getValue() <= 9) { - Integer nodeId = event.getNode(); - String[] values = event.getData().split("\\s+"); - Integer start = Integer.parseInt(values[0].split("=")[1]); - Integer end = Integer.parseInt(values[1].split("=")[1]); - logger.info(String.format("node(%s) mobility event (%s) - start(%s) stop(%s)", - nodeId, state, start, end)); - logger.info("all dialogs: {}", controller.getMobilityPlayerDialogs().keySet()); - MobilityPlayerDialog mobilityPlayerDialog = controller.getMobilityPlayerDialogs().get(nodeId); - mobilityPlayerDialog.event(state, start, end); - } - } catch (IOException ex) { - logger.error("error getting core event", ex); - } - } - } - - private void handleLinks(Object... args) { - for (Object arg : args) { - try { - CoreLink link = JsonUtils.read(arg.toString(), CoreLink.class); - logger.info("handling broadcast link: {}", link); - MessageFlags flag = MessageFlags.get(link.getMessageType()); - if (MessageFlags.DELETE == flag) { - logger.info("delete"); - controller.getNetworkGraph().removeWirelessLink(link); - } else if (MessageFlags.ADD == flag) { - link.setLoaded(true); - controller.getNetworkGraph().addLink(link); - } - controller.getNetworkGraph().getGraphViewer().repaint(); - } catch (IOException ex) { - logger.error("error handling broadcast link", ex); - } - } - } - - private void handleConfigs(Object... args) { - for (Object arg : args) { - logger.info("handling broadcast config: {}", arg); - } - } -} diff --git a/corefx/src/main/proto/core.proto b/corefx/src/main/proto/core.proto index a00ebb81..cec58963 120000 --- a/corefx/src/main/proto/core.proto +++ b/corefx/src/main/proto/core.proto @@ -1 +1 @@ -../../../../daemon/proto/core.proto \ No newline at end of file +../../../../daemon/proto/core/api/grpc/core.proto \ No newline at end of file diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 120eb98e..b2c26f42 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -17,6 +17,7 @@ from core.emulator.emudata import NodeOptions, InterfaceData, LinkOptions from core.emulator.enumerations import NodeTypes, EventTypes, LinkTypes from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.nodes import nodeutils +from core.nodes.base import CoreNetworkBase from core.nodes.ipaddress import MacAddress from core.services.coreservices import ServiceManager @@ -73,18 +74,24 @@ def convert_link(session, link_data): interface_one = None if link_data.interface1_id is not None: node = session.get_node(link_data.node1_id) - interface = node.netif(link_data.interface1_id) + interface_name = None + if not isinstance(node, CoreNetworkBase): + interface = node.netif(link_data.interface1_id) + interface_name = interface.name interface_one = core_pb2.Interface( - id=link_data.interface1_id, name=interface.name, mac=convert_value(link_data.interface1_mac), + id=link_data.interface1_id, name=interface_name, mac=convert_value(link_data.interface1_mac), ip4=convert_value(link_data.interface1_ip4), ip4mask=link_data.interface1_ip4_mask, ip6=convert_value(link_data.interface1_ip6), ip6mask=link_data.interface1_ip6_mask) interface_two = None if link_data.interface2_id is not None: node = session.get_node(link_data.node2_id) - interface = node.netif(link_data.interface2_id) + interface_name = None + if not isinstance(node, CoreNetworkBase): + interface = node.netif(link_data.interface2_id) + interface_name = interface.name interface_two = core_pb2.Interface( - id=link_data.interface2_id, name=interface.name, mac=convert_value(link_data.interface2_mac), + id=link_data.interface2_id, name=interface_name, mac=convert_value(link_data.interface2_mac), ip4=convert_value(link_data.interface2_ip4), ip4mask=link_data.interface2_ip4_mask, ip6=convert_value(link_data.interface2_ip6), ip6mask=link_data.interface2_ip6_mask) @@ -855,6 +862,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): logging.debug("set wlan config: %s", request) session = self.get_session(request.session_id, context) session.mobility.set_model_config(request.node_id, BasicRangeModel.name, request.config) + if session.state == EventTypes.RUNTIME_STATE.value: + node = self.get_node(session, request.node_id, context) + node.updatemodel(request.config) return core_pb2.SetWlanConfigResponse(result=True) def GetEmaneConfig(self, request, context): diff --git a/daemon/core/api/tlv/corehandlers.py b/daemon/core/api/tlv/corehandlers.py index efb2a6bc..40ac9e94 100644 --- a/daemon/core/api/tlv/corehandlers.py +++ b/daemon/core/api/tlv/corehandlers.py @@ -40,6 +40,7 @@ from core.emulator.enumerations import NodeTlvs from core.emulator.enumerations import NodeTypes from core.emulator.enumerations import RegisterTlvs from core.emulator.enumerations import SessionTlvs +from core.location.mobility import BasicRangeModel from core.nodes import nodeutils from core.services.coreservices import ServiceManager from core.services.coreservices import ServiceShim @@ -1268,6 +1269,13 @@ class CoreHandler(socketserver.BaseRequestHandler): parsed_config = ConfigShim.str_to_dict(values_str) self.session.mobility.set_model_config(node_id, object_name, parsed_config) + if self.session.state == EventTypes.RUNTIME_STATE.value: + try: + node = self.session.get_node(node_id) + if object_name == BasicRangeModel.name: + node.updatemodel(parsed_config) + except KeyError: + logging.error("skipping mobility configuration for unknown node: %s", node_id) return replies diff --git a/daemon/core/constants.py.in b/daemon/core/constants.py.in index 0cb3750e..a84a375a 100644 --- a/daemon/core/constants.py.in +++ b/daemon/core/constants.py.in @@ -20,6 +20,7 @@ VCMD_BIN = which("vcmd") BRCTL_BIN = which("brctl") SYSCTL_BIN = which("sysctl") IP_BIN = which("ip") +ETHTOOL_BIN = which("ethtool") TC_BIN = which("tc") EBTABLES_BIN = which("ebtables") MOUNT_BIN = which("mount") diff --git a/daemon/core/location/mobility.py b/daemon/core/location/mobility.py index 4c74447a..a63dce65 100644 --- a/daemon/core/location/mobility.py +++ b/daemon/core/location/mobility.py @@ -9,7 +9,7 @@ import os import threading import time from builtins import int -from past.builtins import cmp +from functools import total_ordering from core import utils from core.config import ConfigGroup @@ -358,7 +358,7 @@ class BasicRangeModel(WirelessModel): :param dict config: values to convert :return: nothing """ - self.range = int(config["range"]) + self.range = int(float(config["range"])) logging.info("basic range model configured for WLAN %d using range %d", self.wlan.id, self.range) self.bw = int(config["bandwidth"]) if self.bw == 0: @@ -561,6 +561,7 @@ class BasicRangeModel(WirelessModel): return all_links +@total_ordering class WayPoint(object): """ Maintains information regarding waypoints. @@ -580,18 +581,17 @@ class WayPoint(object): self.coords = coords self.speed = speed - def __cmp__(self, other): - """ - Custom comparison method for waypoints. + def __eq__(self, other): + return (self.time, self.nodenum) == (other.time, other.nodedum) - :param WayPoint other: waypoint to compare to - :return: the comparison result against the other waypoint - :rtype: int - """ - tmp = cmp(self.time, other.time) - if tmp == 0: - tmp = cmp(self.nodenum, other.nodenum) - return tmp + def __ne__(self, other): + return not self == other + + def __lt__(self, other): + result = self.time < other.time + if result: + result = self.nodenum < other.nodenum + return result class WayPointMobility(WirelessModel): @@ -836,7 +836,12 @@ class WayPointMobility(WirelessModel): :param z: z position :return: nothing """ - # this would cause PyCoreNetIf.poshook() callback (range calculation) + if x is not None: + x = int(x) + if y is not None: + y = int(y) + if z is not None: + z = int(z) node.position.set(x, y, z) node_data = node.data(message_type=0) self.session.broadcast_node(node_data) diff --git a/daemon/core/nodes/base.py b/daemon/core/nodes/base.py index 05b45b4c..555eda78 100644 --- a/daemon/core/nodes/base.py +++ b/daemon/core/nodes/base.py @@ -668,6 +668,7 @@ class CoreNode(CoreNodeBase): if self.up: utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)]) self.check_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname]) + self.check_cmd([constants.ETHTOOL_BIN, "-K", ifname, "rx", "off", "tx", "off"]) veth.name = ifname diff --git a/daemon/core/nodes/client.py b/daemon/core/nodes/client.py index 8530804b..d2d6cc4d 100644 --- a/daemon/core/nodes/client.py +++ b/daemon/core/nodes/client.py @@ -73,7 +73,7 @@ class VnodeClient(object): # run command, return process when not waiting cmd = self._cmd_args() + args - logging.info("cmd wait(%s): %s", wait, cmd) + logging.debug("cmd wait(%s): %s", wait, cmd) p = Popen(cmd, stdout=PIPE, stderr=PIPE) if not wait: return 0 @@ -124,7 +124,7 @@ class VnodeClient(object): self._verify_connection() args = utils.split_args(args) cmd = self._cmd_args() + args - logging.info("popen: %s", cmd) + logging.debug("popen: %s", cmd) p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE) return p, p.stdin, p.stdout, p.stderr @@ -157,7 +157,7 @@ class VnodeClient(object): # run command, return process when not waiting args = utils.split_args(args) cmd = self._cmd_args() + args - logging.info("redircmd: %s", cmd) + logging.debug("redircmd: %s", cmd) p = Popen(cmd, stdin=infd, stdout=outfd, stderr=errfd) if not wait: diff --git a/daemon/core/nodes/network.py b/daemon/core/nodes/network.py index dd4cbed7..bb5b269d 100644 --- a/daemon/core/nodes/network.py +++ b/daemon/core/nodes/network.py @@ -1018,14 +1018,7 @@ class WlanNode(CoreNetwork): logging.info("adding model: %s", model.name) if model.config_type == RegisterTlvs.WIRELESS.value: self.model = model(session=self.session, _id=self.id) - self.model.update_config(config) - if self.model.position_callback: - for netif in self.netifs(): - netif.poshook = self.model.position_callback - if netif.node is not None: - x, y, z = netif.node.position.get() - netif.poshook(netif, x, y, z) - self.model.setlinkparams() + self.updatemodel(config) elif model.config_type == RegisterTlvs.MOBILITY.value: self.mobility = model(session=self.session, _id=self.id) self.mobility.update_config(config) @@ -1033,20 +1026,19 @@ class WlanNode(CoreNetwork): def update_mobility(self, config): if not self.mobility: raise ValueError("no mobility set to update for node(%s)", self.id) - self.mobility.set_configs(config, node_id=self.id) + self.mobility.update_config(config) def updatemodel(self, config): if not self.model: raise ValueError("no model set to update for node(%s)", self.id) logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config) - self.model.set_configs(config, node_id=self.id) + self.model.update_config(config) if self.model.position_callback: for netif in self.netifs(): netif.poshook = self.model.position_callback if netif.node is not None: x, y, z = netif.node.position.get() netif.poshook(netif, x, y, z) - self.model.updateconfig() def all_link_data(self, flags): """ diff --git a/daemon/core/utils.py b/daemon/core/utils.py index 5b18f230..ac76e693 100644 --- a/daemon/core/utils.py +++ b/daemon/core/utils.py @@ -148,9 +148,7 @@ def split_args(args): :return: shell-like syntax list :rtype: list """ - logging.info("split args: %s - %s", args, type(args)) if isinstance(args, basestring): - logging.info("splitting args") args = shlex.split(args) return args diff --git a/daemon/data/logging.conf b/daemon/data/logging.conf index 46de6e92..7f3d496f 100644 --- a/daemon/data/logging.conf +++ b/daemon/data/logging.conf @@ -14,7 +14,7 @@ } }, "root": { - "level": "DEBUG", + "level": "INFO", "handlers": ["console"] } } diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py index 416147d7..990f80cb 100644 --- a/daemon/tests/test_grpc.py +++ b/daemon/tests/test_grpc.py @@ -458,18 +458,29 @@ class TestGrpc: # given client = CoreGrpcClient() session = grpc_server.coreemu.create_session() + session.set_state(EventTypes.CONFIGURATION_STATE) wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN) + wlan.setmodel(BasicRangeModel, BasicRangeModel.default_values()) + session.instantiate() range_key = "range" - range_value = "300" + range_value = "50" # then with client.context_connect(): - response = client.set_wlan_config(session.id, wlan.id, {range_key: range_value}) + response = client.set_wlan_config(session.id, wlan.id, { + range_key: range_value, + "delay": "0", + "loss": "0", + "bandwidth": "50000", + "error": "0", + "jitter": "0" + }) # then assert response.result is True config = session.mobility.get_model_config(wlan.id, BasicRangeModel.name) assert config[range_key] == range_value + assert wlan.model.range == int(range_value) def test_get_emane_config(self, grpc_server): # given