aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--framework/src/onos/apps/dhcp/pom.xml3
-rw-r--r--framework/src/onos/apps/routing-api/pom.xml15
-rw-r--r--framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java167
-rw-r--r--framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java244
-rw-r--r--framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java6
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddPeerCommand.java96
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddSpeakerCommand.java90
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemovePeerCommand.java81
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemoveSpeakerCommand.java87
-rw-r--r--framework/src/onos/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml12
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java29
-rw-r--r--framework/src/onos/tools/test/cells/aaron_local_cell10
12 files changed, 835 insertions, 5 deletions
diff --git a/framework/src/onos/apps/dhcp/pom.xml b/framework/src/onos/apps/dhcp/pom.xml
index 7a10776e..473caea6 100644
--- a/framework/src/onos/apps/dhcp/pom.xml
+++ b/framework/src/onos/apps/dhcp/pom.xml
@@ -36,7 +36,4 @@
<module>app</module>
</modules>
- <dependencies>
- </dependencies>
-
</project>
diff --git a/framework/src/onos/apps/routing-api/pom.xml b/framework/src/onos/apps/routing-api/pom.xml
index 48fc2920..4c2d7d37 100644
--- a/framework/src/onos/apps/routing-api/pom.xml
+++ b/framework/src/onos/apps/routing-api/pom.xml
@@ -53,6 +53,21 @@
<dependency>
<groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
<artifactId>onlab-junit</artifactId>
<scope>test</scope>
</dependency>
diff --git a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
index 2f1ede79..6085c60a 100644
--- a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
+++ b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
@@ -17,12 +17,16 @@
package org.onosproject.routing.config;
import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.Config;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -49,6 +53,11 @@ public class BgpConfig extends Config<ApplicationId> {
Set<BgpSpeakerConfig> speakers = Sets.newHashSet();
JsonNode speakersNode = object.get(SPEAKERS);
+
+ if (speakersNode == null) {
+ return speakers;
+ }
+
speakersNode.forEach(jsonNode -> {
Set<IpAddress> listenAddresses = Sets.newHashSet();
jsonNode.path(PEERS).forEach(addressNode ->
@@ -71,6 +80,130 @@ public class BgpConfig extends Config<ApplicationId> {
}
/**
+ * Examines whether a name of BGP speaker exists in configuration.
+ *
+ * @param name name of BGP speaker being search
+ * @return speaker
+ */
+ public BgpSpeakerConfig getSpeakerWithName(String name) {
+ for (BgpConfig.BgpSpeakerConfig speaker : bgpSpeakers()) {
+ if (speaker.name().isPresent() && speaker.name().get().equals(name)) {
+ return speaker;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds BGP speaker to configuration.
+ *
+ * @param speaker BGP speaker configuration entry
+ */
+ public void addSpeaker(BgpSpeakerConfig speaker) {
+ ObjectNode speakerNode = JsonNodeFactory.instance.objectNode();
+
+ speakerNode.put(NAME, speaker.name().get());
+
+ speakerNode.put(CONNECT_POINT, speaker.connectPoint().elementId().toString()
+ + "/" + speaker.connectPoint().port().toString());
+
+ ArrayNode peersNode = speakerNode.putArray(PEERS);
+ for (IpAddress peerAddress: speaker.peers()) {
+ peersNode.add(peerAddress.toString());
+ }
+
+ ArrayNode speakersArray = bgpSpeakers().isEmpty() ?
+ initBgpConfiguration() : (ArrayNode) object.get(SPEAKERS);
+ speakersArray.add(speakerNode);
+ }
+
+ /**
+ * Removes BGP speaker from configuration.
+ *
+ * @param speakerName BGP speaker name
+ */
+ public void removeSpeaker(String speakerName) {
+ ArrayNode speakersArray = (ArrayNode) object.get(SPEAKERS);
+
+ for (int i = 0; i < speakersArray.size(); i++) {
+ if (speakersArray.get(i).hasNonNull(NAME) &&
+ speakersArray.get(i).get(NAME).asText().equals(speakerName)) {
+ speakersArray.remove(i);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Adds peering address to BGP speaker.
+ *
+ * @param speakerName name of BGP speaker
+ * @param peerAddress peering address to be added
+ */
+ public void addPeerToSpeaker(String speakerName, IpAddress peerAddress) {
+ JsonNode speakersNode = object.get(SPEAKERS);
+ speakersNode.forEach(jsonNode -> {
+ if (jsonNode.hasNonNull(NAME) &&
+ jsonNode.get(NAME).asText().equals(speakerName)) {
+ ArrayNode peersNode = (ArrayNode) jsonNode.get(PEERS);
+ for (int i = 0; i < peersNode.size(); i++) {
+ if (peersNode.get(i).asText().equals(peerAddress.toString())) {
+ return; // Peer already exists.
+ }
+ }
+ peersNode.add(peerAddress.toString());
+ }
+ });
+ }
+
+ /**
+ * Finds BGP speaker peering with a given external peer.
+ *
+ * @param peerAddress peering address to be removed
+ * @return speaker
+ */
+ public BgpSpeakerConfig getSpeakerFromPeer(IpAddress peerAddress) {
+ for (BgpConfig.BgpSpeakerConfig speaker : bgpSpeakers()) {
+ if (speaker.peers().contains(peerAddress)) {
+ return speaker;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes peering address from BGP speaker.
+ *
+ * @param speaker BGP speaker configuration entries
+ * @param peerAddress peering address to be removed
+ */
+ public void removePeerFromSpeaker(BgpSpeakerConfig speaker, IpAddress peerAddress) {
+ JsonNode speakersNode = object.get(SPEAKERS);
+ speakersNode.forEach(jsonNode -> {
+ if (jsonNode.hasNonNull(NAME) &&
+ jsonNode.get(NAME).asText().equals(speaker.name().get())) {
+ ArrayNode peersNode = (ArrayNode) jsonNode.get(PEERS);
+ for (int i = 0; i < peersNode.size(); i++) {
+ if (peersNode.get(i).asText().equals(peerAddress.toString())) {
+ peersNode.remove(i);
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Creates empty configuration for BGP speakers.
+ *
+ * @return empty array of BGP speakers
+ */
+ private ArrayNode initBgpConfiguration() {
+ return object.putArray(SPEAKERS);
+ }
+
+
+ /**
* Configuration for a BGP speaker.
*/
public static class BgpSpeakerConfig {
@@ -97,5 +230,39 @@ public class BgpConfig extends Config<ApplicationId> {
public Set<IpAddress> peers() {
return peers;
}
+
+ /**
+ * Examines if BGP peer is connected.
+ *
+ * @param peer IP address of peer
+ * @return result of search
+ */
+ public boolean isConnectedToPeer(IpAddress peer) {
+ for (final IpAddress entry : peers()) {
+ if (entry.equals(peer)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof BgpSpeakerConfig) {
+ final BgpSpeakerConfig that = (BgpSpeakerConfig) obj;
+ return Objects.equals(this.name, that.name) &&
+ Objects.equals(this.connectPoint, that.connectPoint) &&
+ Objects.equals(this.peers, that.peers);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, connectPoint, peers);
+ }
}
}
diff --git a/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java b/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java
new file mode 100644
index 00000000..28f52b79
--- /dev/null
+++ b/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.routing.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.routing.RoutingService;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class BgpConfigTest {
+
+ private static final ApplicationId APP_ID =
+ new TestApplicationId(RoutingService.ROUTER_APP_ID);
+
+ private static final IpAddress IP1 = IpAddress.valueOf("10.0.1.1");
+ private static final IpAddress IP2 = IpAddress.valueOf("10.0.2.1");
+ private static final IpAddress IP3 = IpAddress.valueOf("10.0.3.1");
+ private static final IpAddress IP4 = IpAddress.valueOf("10.0.101.1");
+ private static final IpAddress IP5 = IpAddress.valueOf("10.0.201.1");
+ public static final IpAddress IP_NON_EXIST = IpAddress.valueOf("10.101.1.1");
+
+ public static final ConnectPoint CONNECT_POINT1 = ConnectPoint.
+ deviceConnectPoint("of:0000000000000001/1");
+ public static final ConnectPoint CONNECT_POINT2 = ConnectPoint.
+ deviceConnectPoint("of:00000000000000a3/1");
+
+ private static final String JSON_TREE = "{\"" + BgpConfig.SPEAKERS +
+ "\" : [{\"" + BgpConfig.NAME + "\" : \"bgp1\"," +
+ "\"" + BgpConfig.CONNECT_POINT +
+ "\" : \"of:0000000000000001/1\"," +
+ "\"" + BgpConfig.PEERS + "\" : [" +
+ "\"10.0.1.1\",\"10.0.2.1\",\"10.0.3.1\"]}]}";
+ private static final String EMPTY_JSON_TREE = "{}";
+
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final ConfigApplyDelegate delegate = new MockCfgDelegate();
+ private final BgpConfig.BgpSpeakerConfig initialSpeaker = createInitialSpeaker();
+
+ private Set<BgpConfig.BgpSpeakerConfig> speakers = new HashSet<>();
+ private BgpConfig bgpConfig = new BgpConfig();
+ private BgpConfig emptyBgpConfig = new BgpConfig();
+
+ @Before
+ public void setUp() throws Exception {
+ JsonNode tree = new ObjectMapper().readTree(JSON_TREE);
+ bgpConfig.init(APP_ID, "bgp-test", tree, mapper, delegate);
+ JsonNode emptyTree = new ObjectMapper().readTree(EMPTY_JSON_TREE);
+ emptyBgpConfig.init(APP_ID, "bgp-test", emptyTree, mapper, delegate);
+ speakers.add(initialSpeaker);
+ }
+
+ /**
+ * Tests if speakers can be retrieved from JSON.
+ */
+ @Test
+ public void testBgpSpeakers() throws Exception {
+ assertEquals(speakers, bgpConfig.bgpSpeakers());
+ }
+
+ /**
+ * Tests if speakers can be retrieved from empty JSON.
+ */
+ @Test
+ public void testEmptyBgpSpeakers() throws Exception {
+ assertTrue(emptyBgpConfig.bgpSpeakers().isEmpty());
+ }
+
+ /**
+ * Tests if speaker can be found by name.
+ */
+ @Test
+ public void testGetSpeakerWithName() throws Exception {
+ assertNotNull(bgpConfig.getSpeakerWithName("bgp1"));
+ assertNull(bgpConfig.getSpeakerWithName("bgp2"));
+ }
+
+ /**
+ * Tests addition of new speaker.
+ */
+ @Test
+ public void testAddSpeaker() throws Exception {
+ int initialSize = bgpConfig.bgpSpeakers().size();
+ BgpConfig.BgpSpeakerConfig newSpeaker = createNewSpeaker();
+ bgpConfig.addSpeaker(newSpeaker);
+ assertEquals(initialSize + 1, bgpConfig.bgpSpeakers().size());
+ speakers.add(newSpeaker);
+ assertEquals(speakers, bgpConfig.bgpSpeakers());
+ }
+
+ /**
+ * Tests addition of new speaker to empty configuration.
+ */
+ @Test
+ public void testAddSpeakerToEmpty() throws Exception {
+ BgpConfig.BgpSpeakerConfig newSpeaker = createNewSpeaker();
+ emptyBgpConfig.addSpeaker(newSpeaker);
+
+ assertFalse(emptyBgpConfig.bgpSpeakers().isEmpty());
+ }
+
+ /**
+ * Tests removal of existing speaker.
+ */
+ @Test
+ public void testRemoveExistingSpeaker() throws Exception {
+ int initialSize = bgpConfig.bgpSpeakers().size();
+ bgpConfig.removeSpeaker("bgp1");
+
+ assertEquals(initialSize - 1, bgpConfig.bgpSpeakers().size());
+ }
+
+ /**
+ * Tests removal of non-existing speaker.
+ */
+ @Test
+ public void testRemoveInexistingSpeaker() throws Exception {
+ int initialSize = bgpConfig.bgpSpeakers().size();
+ bgpConfig.removeSpeaker("bgp2");
+
+ assertEquals(initialSize, bgpConfig.bgpSpeakers().size());
+ }
+
+ /**
+ * Tests addition of new speaker.
+ */
+ @Test
+ public void testAddPeerToSpeaker() throws Exception {
+ int initialSize = bgpConfig.getSpeakerWithName("bgp1").peers().size();
+ bgpConfig.addPeerToSpeaker("bgp1", IP4);
+
+ assertEquals(initialSize + 1, bgpConfig.getSpeakerWithName("bgp1").peers().size());
+ }
+
+ /**
+ * Tests addition of new speaker when peer already exists.
+ */
+ @Test
+ public void testAddExistingPeerToSpeaker() throws Exception {
+ int initialSize = bgpConfig.getSpeakerWithName("bgp1").peers().size();
+ bgpConfig.addPeerToSpeaker("bgp1", IP1);
+
+ assertEquals(initialSize, bgpConfig.getSpeakerWithName("bgp1").peers().size());
+ }
+
+ /**
+ * Tests retrieval of speaker based on peering address.
+ */
+ @Test
+ public void testGetSpeakerFromPeer() throws Exception {
+ assertNotNull(bgpConfig.getSpeakerFromPeer(IP1));
+ assertNull(bgpConfig.getSpeakerFromPeer(IP_NON_EXIST));
+ }
+
+ /**
+ * Tests removal of peer.
+ */
+ @Test
+ public void testRemoveExistingPeerFromSpeaker() throws Exception {
+ int initialSize = bgpConfig.getSpeakerWithName("bgp1").peers().size();
+ bgpConfig.removePeerFromSpeaker(initialSpeaker, IP1);
+
+ assertEquals(initialSize - 1, bgpConfig.getSpeakerWithName("bgp1").peers().size());
+ }
+
+ /**
+ * Tests peer removal when peer does not exist.
+ */
+ @Test
+ public void testRemoveNonExistingPeerFromSpeaker() throws Exception {
+ int initialSize = bgpConfig.getSpeakerWithName("bgp1").peers().size();
+ bgpConfig.removePeerFromSpeaker(initialSpeaker, IP_NON_EXIST);
+
+ assertEquals(initialSize, bgpConfig.getSpeakerWithName("bgp1").peers().size());
+ }
+
+ /**
+ * Tests if connections to peers are found.
+ */
+ @Test
+ public void testIsConnectedToPeer() {
+ BgpConfig.BgpSpeakerConfig speaker = createNewSpeaker();
+
+ assertTrue(speaker.isConnectedToPeer(IP4));
+ assertFalse(speaker.isConnectedToPeer(IP_NON_EXIST));
+ }
+
+ private class MockCfgDelegate implements ConfigApplyDelegate {
+
+ @Override
+ public void onApply(@SuppressWarnings("rawtypes") Config config) {
+ config.apply();
+ }
+
+ }
+
+ private BgpConfig.BgpSpeakerConfig createInitialSpeaker() {
+ Optional<String> speakerName = Optional.of("bgp1");
+ ConnectPoint connectPoint = CONNECT_POINT1;
+ Set<IpAddress> connectedPeers = new HashSet<>(Arrays.asList(IP1, IP2, IP3));
+
+ return new BgpConfig.BgpSpeakerConfig(speakerName, connectPoint, connectedPeers);
+ }
+
+ private BgpConfig.BgpSpeakerConfig createNewSpeaker() {
+ Optional<String> speakerName = Optional.of("newSpeaker");
+ ConnectPoint connectPoint = CONNECT_POINT2;
+ Set<IpAddress> connectedPeers = new HashSet<>(
+ Arrays.asList(IP4, IP5));
+
+ return new BgpConfig.BgpSpeakerConfig(speakerName, connectPoint, connectedPeers);
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java
index 23d7086c..064080fd 100644
--- a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java
+++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java
@@ -50,13 +50,17 @@ public class BgpSpeakersListCommand extends AbstractShellCommand {
ApplicationId appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
BgpConfig config = configService.getConfig(appId, BgpConfig.class);
+ if (config == null) {
+ print("No speakers configured");
+ return;
+ }
List<BgpConfig.BgpSpeakerConfig> bgpSpeakers =
Lists.newArrayList(config.bgpSpeakers());
Collections.sort(bgpSpeakers, SPEAKERS_COMPARATOR);
- if (config == null || config.bgpSpeakers().isEmpty()) {
+ if (config.bgpSpeakers().isEmpty()) {
print("No speakers configured");
} else {
bgpSpeakers.forEach(
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddPeerCommand.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddPeerCommand.java
new file mode 100644
index 00000000..81231ab9
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddPeerCommand.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdnip.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpConfig;
+
+/**
+ * Command to add new BGP peer to existing internal speaker.
+ */
+@Command(scope = "onos", name = "add-bgp-peer",
+ description = "Adds an external BGP router as peer to an existing BGP speaker")
+public class AddPeerCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "name",
+ description = "Name of the internal BGP speaker",
+ required = true, multiValued = false)
+ String name = null;
+
+ @Argument(index = 1, name = "ip",
+ description = "IP address of the BGP peer",
+ required = true, multiValued = false)
+ String ip = null;
+
+ private static final String PEER_ADD_SUCCESS = "Peer Successfully Added.";
+ private static final String NO_CONFIGURATION = "No speakers configured";
+ private static final String SPEAKER_NOT_FOUND =
+ "Speaker with name \'%s\' not found";
+ private static final String NO_INTERFACE =
+ "No matching interface found for IP \'%s\'";
+
+ private IpAddress peerAddress = null;
+
+ @Override
+ protected void execute() {
+ peerAddress = IpAddress.valueOf(ip);
+
+ NetworkConfigService configService = get(NetworkConfigService.class);
+ CoreService coreService = get(CoreService.class);
+ ApplicationId appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
+
+ BgpConfig config = configService.getConfig(appId, BgpConfig.class);
+ if (config == null || config.bgpSpeakers().isEmpty()) {
+ print(NO_CONFIGURATION);
+ return;
+ }
+
+ BgpConfig.BgpSpeakerConfig speaker = config.getSpeakerWithName(name);
+ if (speaker == null) {
+ print(SPEAKER_NOT_FOUND, name);
+ return;
+ } else {
+ if (speaker.isConnectedToPeer(peerAddress)) {
+ return; // Peering already exists.
+ }
+ }
+
+ InterfaceService interfaceService = get(InterfaceService.class);
+ if (interfaceService.getMatchingInterface(peerAddress) == null) {
+ print(NO_INTERFACE, ip);
+ return;
+ }
+
+ addPeerToSpeakerConf(config);
+ configService.applyConfig(appId, BgpConfig.class, config.node());
+
+ print(PEER_ADD_SUCCESS);
+ }
+
+ private void addPeerToSpeakerConf(BgpConfig config) {
+ log.debug("Creating BGP configuration for new peer: {}", ip);
+ config.addPeerToSpeaker(name, peerAddress);
+ }
+}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddSpeakerCommand.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddSpeakerCommand.java
new file mode 100644
index 00000000..84353852
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/AddSpeakerCommand.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdnip.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpConfig;
+
+import java.util.HashSet;
+import java.util.Optional;
+
+/**
+ * Command to add a new internal BGP speaker.
+ */
+@Command(scope = "onos", name = "add-bgp-speaker",
+ description = "Adds an internal BGP speaker")
+public class AddSpeakerCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "name",
+ description = "Name of the internal BGP speaker",
+ required = true, multiValued = false)
+ String name = null;
+
+ @Argument(index = 1, name = "connectionPoint",
+ description = "Interface to the BGP speaker",
+ required = true, multiValued = false)
+ String connectionPoint = null;
+
+ private static final String SPEAKER_ADD_SUCCESS = "Speaker Successfully Added.";
+
+ @Override
+ protected void execute() {
+ NetworkConfigService configService = get(NetworkConfigService.class);
+ CoreService coreService = get(CoreService.class);
+ ApplicationId appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
+
+ BgpConfig config = configService.addConfig(appId, BgpConfig.class);
+
+ BgpConfig.BgpSpeakerConfig speaker = config.getSpeakerWithName(name);
+ if (speaker != null) {
+ log.debug("Speaker already exists: {}", name);
+ return;
+ }
+
+ addSpeakerToConf(config);
+ configService.applyConfig(appId, BgpConfig.class, config.node());
+
+ print(SPEAKER_ADD_SUCCESS);
+ }
+
+ /**
+ * Adds the speaker to the BgpConfig service.
+ *
+ * @param config the BGP configuration
+ */
+ private void addSpeakerToConf(BgpConfig config) {
+ log.debug("Adding new speaker to configuration: {}", name);
+ BgpConfig.BgpSpeakerConfig speaker = getSpeaker();
+
+ config.addSpeaker(speaker);
+ }
+
+ private BgpConfig.BgpSpeakerConfig getSpeaker() {
+ ConnectPoint connectPoint = ConnectPoint.
+ deviceConnectPoint(connectionPoint);
+ return new BgpConfig.BgpSpeakerConfig(Optional.ofNullable(name),
+ connectPoint, new HashSet<IpAddress>());
+ }
+}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemovePeerCommand.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemovePeerCommand.java
new file mode 100644
index 00000000..bfc6fb7b
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemovePeerCommand.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdnip.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpConfig;
+
+/**
+ * Command to remove existing BGP peer.
+ */
+@Command(scope = "onos", name = "remove-bgp-peer",
+ description = "Removes a BGP peer")
+public class RemovePeerCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "ip",
+ description = "IP address of the BGP peer",
+ required = true, multiValued = false)
+ String ip = null;
+
+ private static final String PEER_REMOVE_SUCCESS = "Peer Successfully Removed.";
+ private static final String NO_CONFIGURATION = "No speakers configured";
+ private static final String PEER_NOT_FOUND =
+ "Peer with IP \'%s\' not found";
+
+ private IpAddress peerAddress = null;
+
+ @Override
+ protected void execute() {
+ peerAddress = IpAddress.valueOf(ip);
+
+ NetworkConfigService configService = get(NetworkConfigService.class);
+ CoreService coreService = get(CoreService.class);
+ ApplicationId appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
+
+ BgpConfig config = configService.getConfig(appId, BgpConfig.class);
+ if (config == null || config.bgpSpeakers().isEmpty()) {
+ print(NO_CONFIGURATION);
+ return;
+ }
+
+ peerAddress = IpAddress.valueOf(ip);
+
+ BgpConfig.BgpSpeakerConfig speaker = config.getSpeakerFromPeer(peerAddress);
+ if (speaker == null) {
+ print(PEER_NOT_FOUND, ip);
+ return;
+ }
+
+ removePeerFromSpeakerConf(speaker, config);
+ configService.applyConfig(appId, BgpConfig.class, config.node());
+
+ print(PEER_REMOVE_SUCCESS);
+ }
+
+ private void removePeerFromSpeakerConf(BgpConfig.BgpSpeakerConfig speaker,
+ BgpConfig config) {
+ log.debug("Removing BGP configuration for peer: {}", ip);
+ config.removePeerFromSpeaker(speaker, peerAddress);
+ }
+}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemoveSpeakerCommand.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemoveSpeakerCommand.java
new file mode 100644
index 00000000..6a51b42f
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RemoveSpeakerCommand.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdnip.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpConfig;
+
+/**
+ * Command to remove a internal BGP speaker.
+ */
+@Command(scope = "onos", name = "remove-bgp-speaker",
+ description = "Removes an internal BGP speaker")
+public class RemoveSpeakerCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "name",
+ description = "Name of the internal BGP speaker",
+ required = true, multiValued = false)
+ String name = null;
+
+ private static final String SPEAKER_REMOVE_SUCCESS = "Speaker Successfully Removed.";
+ private static final String NO_CONFIGURATION = "No speakers configured";
+ private static final String PEERS_EXIST =
+ "Speaker with name \'%s\' has peer connections";
+ private static final String SPEAKER_NOT_FOUND =
+ "Speaker with name \'%s\' not found";
+
+ @Override
+ protected void execute() {
+ NetworkConfigService configService = get(NetworkConfigService.class);
+ CoreService coreService = get(CoreService.class);
+ ApplicationId appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
+
+ BgpConfig config = configService.getConfig(appId, BgpConfig.class);
+ if (config == null || config.bgpSpeakers().isEmpty()) {
+ print(NO_CONFIGURATION);
+ return;
+ }
+
+ BgpConfig.BgpSpeakerConfig speaker = config.getSpeakerWithName(name);
+ if (speaker == null) {
+ print(SPEAKER_NOT_FOUND, name);
+ return;
+ } else {
+ if (!speaker.peers().isEmpty()) {
+ // Removal not allowed when peer connections exist.
+ print(PEERS_EXIST, name);
+ return;
+ }
+ }
+
+ removeSpeakerFromConf(config);
+ configService.applyConfig(appId, BgpConfig.class, config.node());
+
+ print(SPEAKER_REMOVE_SUCCESS);
+ }
+
+ /**
+ * Removes the speaker from the BgpConfig service.
+ *
+ * @param bgpConfig the BGP configuration
+ */
+ private void removeSpeakerFromConf(BgpConfig bgpConfig) {
+ log.debug("Removing speaker from configuration: {}", name);
+
+ bgpConfig.removeSpeaker(name);
+ }
+}
diff --git a/framework/src/onos/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 3be1c79a..97b2f09f 100644
--- a/framework/src/onos/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/framework/src/onos/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -19,5 +19,17 @@
<command>
<action class="org.onosproject.sdnip.cli.PrimaryChangeCommand"/>
</command>
+ <command>
+ <action class="org.onosproject.sdnip.cli.AddSpeakerCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.sdnip.cli.RemoveSpeakerCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.sdnip.cli.AddPeerCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.sdnip.cli.RemovePeerCommand"/>
+ </command>
</command-bundle>
</blueprint>
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java
index 8cd63e7d..1695e5ff 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java
@@ -59,6 +59,7 @@ import org.onosproject.net.flow.FlowRuleStore;
import org.onosproject.net.flow.FlowRuleStoreDelegate;
import org.onosproject.net.flow.StoredFlowEntry;
import org.onosproject.net.flow.TableStatisticsEntry;
+import org.onosproject.persistence.PersistenceService;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
import org.onosproject.store.cluster.messaging.ClusterMessage;
@@ -74,6 +75,7 @@ import org.onosproject.store.serializers.custom.DistributedStoreSerializers;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.WallClockTimestamp;
import org.osgi.service.component.ComponentContext;
@@ -113,6 +115,7 @@ public class NewDistributedFlowRuleStore
private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 8;
private static final boolean DEFAULT_BACKUP_ENABLED = true;
+ private static final boolean DEFAULT_PERSISTENCE_ENABLED = false;
private static final int DEFAULT_BACKUP_PERIOD_MILLIS = 2000;
private static final long FLOW_RULE_STORE_TIMEOUT_MILLIS = 5000;
// number of devices whose flow entries will be backed up in one communication round
@@ -129,6 +132,9 @@ public class NewDistributedFlowRuleStore
@Property(name = "backupPeriod", intValue = DEFAULT_BACKUP_PERIOD_MILLIS,
label = "Delay in ms between successive backup runs")
private int backupPeriod = DEFAULT_BACKUP_PERIOD_MILLIS;
+ @Property(name = "persistenceEnabled", boolValue = false,
+ label = "Indicates whether or not changes in the flow table should be persisted to disk.")
+ private boolean persistenceEnabled = DEFAULT_PERSISTENCE_ENABLED;
private InternalFlowTable flowTable = new InternalFlowTable();
@@ -153,6 +159,9 @@ public class NewDistributedFlowRuleStore
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PersistenceService persistenceService;
+
private Map<Long, NodeId> pendingResponses = Maps.newConcurrentMap();
private ExecutorService messageHandlingExecutor;
@@ -716,7 +725,25 @@ public class NewDistributedFlowRuleStore
* @return Map representing Flow Table of given device.
*/
private Map<FlowId, Set<StoredFlowEntry>> getFlowTable(DeviceId deviceId) {
- return flowEntries.computeIfAbsent(deviceId, id -> Maps.newConcurrentMap());
+ if (persistenceEnabled) {
+ return flowEntries.computeIfAbsent(deviceId, id -> persistenceService
+ .<FlowId, Set<StoredFlowEntry>>persistentMapBuilder()
+ .withName("FlowTable:" + deviceId.toString())
+ .withSerializer(new Serializer() {
+ @Override
+ public <T> byte[] encode(T object) {
+ return SERIALIZER.encode(object);
+ }
+
+ @Override
+ public <T> T decode(byte[] bytes) {
+ return SERIALIZER.decode(bytes);
+ }
+ })
+ .build());
+ } else {
+ return flowEntries.computeIfAbsent(deviceId, id -> Maps.newConcurrentMap());
+ }
}
private Set<StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId, FlowId flowId) {
diff --git a/framework/src/onos/tools/test/cells/aaron_local_cell b/framework/src/onos/tools/test/cells/aaron_local_cell
new file mode 100644
index 00000000..e3b5f734
--- /dev/null
+++ b/framework/src/onos/tools/test/cells/aaron_local_cell
@@ -0,0 +1,10 @@
+# Local VirtualBox-based ONOS instances 1,2 & ONOS mininet box
+
+export ONOS_NIC=192.168.56.*
+export OC1="192.168.56.101"
+export OC2="192.168.56.102"
+export OC3="192.168.56.103"
+export OCN="192.168.56.100"
+
+export ONOS_USE_SSH=true
+export ONOS_APPS="drivers,openflow,fwd,proxyarp,mobility"