Create a formal interface between the RIB and FIB.
* IntentSynchronizer implements a more generalized FibListener interface
* Updates to the FIB are signalled with FibUpdate to any FibListeners
* generateRouteIntent logic has been pushed down into the IntentSynchronizer
Change-Id: I6f0ccfd52ee4e16ce9974af5ee549d4ede6c2d0e
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibEntry.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibEntry.java
new file mode 100644
index 0000000..988b49a
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibEntry.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 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;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+/**
+ * An entry in the Forwarding Information Base (FIB).
+ */
+public class FibEntry {
+
+ private final IpPrefix prefix;
+ private final IpAddress nextHopIp;
+ private final MacAddress nextHopMac;
+
+ /**
+ * Creates a new FIB entry.
+ *
+ * @param prefix IP prefix of the FIB entry
+ * @param nextHopIp IP address of the next hop
+ * @param nextHopMac MAC address of the next hop
+ */
+ public FibEntry(IpPrefix prefix, IpAddress nextHopIp, MacAddress nextHopMac) {
+ this.prefix = prefix;
+ this.nextHopIp = nextHopIp;
+ this.nextHopMac = nextHopMac;
+ }
+
+ /**
+ * Returns the IP prefix of the FIB entry.
+ *
+ * @return the IP prefix
+ */
+ public IpPrefix prefix() {
+ return prefix;
+ }
+
+ /**
+ * Returns the IP address of the next hop.
+ *
+ * @return the IP address
+ */
+ public IpAddress nextHopIp() {
+ return nextHopIp;
+ }
+
+ /**
+ * Returns the MAC address of the next hop.
+ *
+ * @return the MAC address
+ */
+ public MacAddress nextHopMac() {
+ return nextHopMac;
+ }
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibListener.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibListener.java
new file mode 100644
index 0000000..13674e3
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibListener.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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;
+
+import java.util.Collection;
+
+/**
+ * A component that is able to process Forwarding Information Base (FIB) updates.
+ */
+public interface FibListener {
+
+ /**
+ * Signals the FIB component of changes to the FIB.
+ *
+ * @param updates FIB updates of the UDPATE type
+ * @param withdraws FIB updates of the WITHDRAW type
+ */
+ // TODO this interface should use only one collection when we have the new
+ // intent key API
+ void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws);
+
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibUpdate.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibUpdate.java
new file mode 100644
index 0000000..a3d8c3c
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibUpdate.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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;
+
+/**
+ * Represents a change to the Forwarding Information Base (FIB).
+ */
+public class FibUpdate {
+
+ /**
+ * Specifies the type of the FIB update.
+ */
+ public enum Type {
+ /**
+ * The update contains a new or updated FIB entry for a prefix.
+ */
+ UPDATE,
+
+ /**
+ * The update signals that a prefix should be removed from the FIB.
+ */
+ DELETE
+ }
+
+ private final Type type;
+ private final FibEntry entry;
+
+ /**
+ * Creates a new FIB update.
+ *
+ * @param type type of the update
+ * @param entry FIB entry describing the update
+ */
+ public FibUpdate(Type type, FibEntry entry) {
+ this.type = type;
+ this.entry = entry;
+ }
+
+ /**
+ * Returns the type of the update.
+ *
+ * @return update type
+ */
+ public Type type() {
+ return type;
+ }
+
+ /**
+ * Returns the FIB entry which contains update information.
+ *
+ * @return the FIB entry
+ */
+ public FibEntry entry() {
+ return entry;
+ }
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
index 0a0e569..9f3c872 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
@@ -15,22 +15,19 @@
*/
package org.onosproject.sdnip;
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Semaphore;
-
-import org.apache.commons.lang3.tuple.Pair;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria.IPCriterion;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.intent.Intent;
@@ -39,16 +36,32 @@
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.sdnip.config.BgpPeer;
+import org.onosproject.sdnip.config.Interface;
+import org.onosproject.sdnip.config.SdnIpConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+
+import static com.google.common.base.Preconditions.checkArgument;
/**
* Synchronizes intents between the in-memory intent store and the
* IntentService.
*/
-public class IntentSynchronizer {
+public class IntentSynchronizer implements FibListener {
private static final Logger log =
LoggerFactory.getLogger(IntentSynchronizer.class);
@@ -65,18 +78,28 @@
private volatile boolean isElectedLeader = false;
private volatile boolean isActivatedLeader = false;
+ private final SdnIpConfigurationService configService;
+ private final InterfaceService interfaceService;
+
/**
* Class constructor.
*
* @param appId the Application ID
* @param intentService the intent service
+ * @param configService the SDN-IP configuration service
+ * @param interfaceService the interface service
*/
- IntentSynchronizer(ApplicationId appId, IntentService intentService) {
+ IntentSynchronizer(ApplicationId appId, IntentService intentService,
+ SdnIpConfigurationService configService,
+ InterfaceService interfaceService) {
this.appId = appId;
this.intentService = intentService;
peerIntents = new ConcurrentHashMap<>();
routeIntents = new ConcurrentHashMap<>();
+ this.configService = configService;
+ this.interfaceService = interfaceService;
+
bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder()
.setNameFormat("sdnip-intents-synchronizer-%d").build());
@@ -244,16 +267,85 @@
}
/**
- * Updates multi-point-to-single-point route intents.
+ * Generates a route intent for a prefix, the next hop IP address, and
+ * the next hop MAC address.
+ * <p/>
+ * This method will find the egress interface for the intent.
+ * Intent will match dst IP prefix and rewrite dst MAC address at all other
+ * border switches, then forward packets according to dst MAC address.
*
- * @param submitIntents the intents to submit
- * @param withdrawPrefixes the IPv4 or IPv6 matching prefixes for the
- * intents to withdraw
+ * @param prefix IP prefix of the route to add
+ * @param nextHopIpAddress IP address of the next hop
+ * @param nextHopMacAddress MAC address of the next hop
+ * @return the generated intent, or null if no intent should be submitted
*/
- void updateRouteIntents(
- Collection<Pair<IpPrefix, MultiPointToSinglePointIntent>> submitIntents,
- Collection<IpPrefix> withdrawPrefixes) {
+ private MultiPointToSinglePointIntent generateRouteIntent(
+ IpPrefix prefix,
+ IpAddress nextHopIpAddress,
+ MacAddress nextHopMacAddress) {
+ // Find the attachment point (egress interface) of the next hop
+ Interface egressInterface;
+ if (configService.getBgpPeers().containsKey(nextHopIpAddress)) {
+ // Route to a peer
+ log.debug("Route to peer {}", nextHopIpAddress);
+ BgpPeer peer =
+ configService.getBgpPeers().get(nextHopIpAddress);
+ egressInterface =
+ interfaceService.getInterface(peer.connectPoint());
+ } else {
+ // Route to non-peer
+ log.debug("Route to non-peer {}", nextHopIpAddress);
+ egressInterface =
+ interfaceService.getMatchingInterface(nextHopIpAddress);
+ if (egressInterface == null) {
+ log.warn("No outgoing interface found for {}",
+ nextHopIpAddress);
+ return null;
+ }
+ }
+
+ //
+ // Generate the intent itself
+ //
+ Set<ConnectPoint> ingressPorts = new HashSet<>();
+ ConnectPoint egressPort = egressInterface.connectPoint();
+ log.debug("Generating intent for prefix {}, next hop mac {}",
+ prefix, nextHopMacAddress);
+
+ for (Interface intf : interfaceService.getInterfaces()) {
+ if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
+ ConnectPoint srcPort = intf.connectPoint();
+ ingressPorts.add(srcPort);
+ }
+ }
+
+ // Match the destination IP prefix at the first hop
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ if (prefix.version() == Ip4Address.VERSION) {
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ } else {
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ }
+ selector.matchIPDst(prefix);
+
+ // Rewrite the destination MAC address
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(nextHopMacAddress);
+ if (!egressInterface.vlan().equals(VlanId.NONE)) {
+ treatment.setVlanId(egressInterface.vlan());
+ // If we set VLAN ID, we have to make sure a VLAN tag exists.
+ // TODO support no VLAN -> VLAN routing
+ selector.matchVlanId(VlanId.ANY);
+ }
+
+ return new MultiPointToSinglePointIntent(appId, selector.build(),
+ treatment.build(),
+ ingressPorts, egressPort);
+ }
+
+ @Override
+ public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) {
//
// NOTE: Semantically, we MUST withdraw existing intents before
// submitting new intents.
@@ -262,14 +354,19 @@
MultiPointToSinglePointIntent intent;
log.debug("SDN-IP submitting intents = {} withdrawing = {}",
- submitIntents.size(), withdrawPrefixes.size());
+ updates.size(), withdraws.size());
//
// Prepare the Intent batch operations for the intents to withdraw
//
IntentOperations.Builder withdrawBuilder =
IntentOperations.builder(appId);
- for (IpPrefix prefix : withdrawPrefixes) {
+ for (FibUpdate withdraw : withdraws) {
+ checkArgument(withdraw.type() == FibUpdate.Type.DELETE,
+ "FibUpdate with wrong type in withdraws list");
+
+ IpPrefix prefix = withdraw.entry().prefix();
+
intent = routeIntents.remove(prefix);
if (intent == null) {
log.trace("SDN-IP No intent in routeIntents to delete " +
@@ -287,10 +384,21 @@
//
IntentOperations.Builder submitBuilder =
IntentOperations.builder(appId);
- for (Pair<IpPrefix, MultiPointToSinglePointIntent> pair :
- submitIntents) {
- IpPrefix prefix = pair.getLeft();
- intent = pair.getRight();
+ for (FibUpdate update : updates) {
+ checkArgument(update.type() == FibUpdate.Type.UPDATE,
+ "FibUpdate with wrong type in updates list");
+
+ IpPrefix prefix = update.entry().prefix();
+ intent = generateRouteIntent(prefix, update.entry().nextHopIp(),
+ update.entry().nextHopMac());
+
+ if (intent == null) {
+ // This preserves the old semantics - if an intent can't be
+ // generated, we don't do anything with that prefix. But
+ // perhaps we should withdraw the old intent anyway?
+ continue;
+ }
+
MultiPointToSinglePointIntent oldIntent =
routeIntents.put(prefix, intent);
if (isElectedLeader && isActivatedLeader) {
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
index 2b2213a..d19f298 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
@@ -15,8 +15,27 @@
*/
package org.onosproject.sdnip;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.googlecode.concurrenttrees.common.KeyValuePair;
+import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
+import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
+import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.Host;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -28,48 +47,16 @@
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
-import org.apache.commons.lang3.tuple.Pair;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Host;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.sdnip.config.BgpPeer;
-import org.onosproject.sdnip.config.Interface;
-import org.onosproject.sdnip.config.SdnIpConfigurationService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.googlecode.concurrenttrees.common.KeyValuePair;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
-
/**
- * This class processes BGP route update, translates each update into a intent
- * and submits the intent.
+ * This class processes route updates and maintains a Routing Information Base
+ * (RIB). After route updates have been processed and next hops have been
+ * resolved, FIB updates are sent to any listening FIB components.
*/
public class Router implements RouteListener {
private static final Logger log = LoggerFactory.getLogger(Router.class);
- // Store all route updates in a radix tree.
+ // Route entries are stored in a radix tree.
// The key in this tree is the binary string of prefix of the route.
private InvertedRadixTree<RouteEntry> ribTable4;
private InvertedRadixTree<RouteEntry> ribTable6;
@@ -77,37 +64,26 @@
// Stores all incoming route updates in a queue.
private final BlockingQueue<Collection<RouteUpdate>> routeUpdatesQueue;
- // The IpAddress is the next hop address of each route update.
+ // Next-hop IP address to route entry mapping for next hops pending MAC resolution
private final SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
// The IPv4 address to MAC address mapping
private final Map<IpAddress, MacAddress> ip2Mac;
- private final ApplicationId appId;
- private final IntentSynchronizer intentSynchronizer;
+ private final FibListener fibComponent;
private final HostService hostService;
- private final SdnIpConfigurationService configService;
- private final InterfaceService interfaceService;
private final ExecutorService bgpUpdatesExecutor;
private final HostListener hostListener;
/**
* Class constructor.
*
- * @param appId the application ID
- * @param intentSynchronizer the intent synchronizer
- * @param configService the configuration service
- * @param interfaceService the interface service
+ * @param fibComponent the intent synchronizer
* @param hostService the host service
*/
- public Router(ApplicationId appId, IntentSynchronizer intentSynchronizer,
- SdnIpConfigurationService configService,
- InterfaceService interfaceService,
- HostService hostService) {
- this.appId = appId;
- this.intentSynchronizer = intentSynchronizer;
- this.configService = configService;
- this.interfaceService = interfaceService;
+ public Router(FibListener fibComponent, HostService hostService) {
+ // TODO move to a listener model for adding fib listeners
+ this.fibComponent = fibComponent;
this.hostService = hostService;
this.hostListener = new InternalHostListener();
@@ -291,23 +267,23 @@
*/
void processRouteUpdates(Collection<RouteUpdate> routeUpdates) {
synchronized (this) {
- Collection<Pair<IpPrefix, MultiPointToSinglePointIntent>>
- submitIntents = new LinkedList<>();
Collection<IpPrefix> withdrawPrefixes = new LinkedList<>();
- MultiPointToSinglePointIntent intent;
+ Collection<FibUpdate> fibUpdates = new LinkedList<>();
+ Collection<FibUpdate> fibWithdraws = new LinkedList<>();
for (RouteUpdate update : routeUpdates) {
switch (update.type()) {
case UPDATE:
- intent = processRouteAdd(update.routeEntry(),
- withdrawPrefixes);
- if (intent != null) {
- submitIntents.add(Pair.of(update.routeEntry().prefix(),
- intent));
+ FibEntry fib = processRouteAdd(update.routeEntry(),
+ withdrawPrefixes);
+ if (fib != null) {
+ fibUpdates.add(new FibUpdate(FibUpdate.Type.UPDATE, fib));
}
+
break;
case DELETE:
processRouteDelete(update.routeEntry(), withdrawPrefixes);
+
break;
default:
log.error("Unknown update Type: {}", update.type());
@@ -315,8 +291,10 @@
}
}
- intentSynchronizer.updateRouteIntents(submitIntents,
- withdrawPrefixes);
+ withdrawPrefixes.forEach(p -> fibWithdraws.add(new FibUpdate(
+ FibUpdate.Type.DELETE, new FibEntry(p, null, null))));
+
+ fibComponent.update(fibUpdates, fibWithdraws);
}
}
@@ -335,9 +313,9 @@
* @param routeEntry the route entry to add
* @param withdrawPrefixes the collection of accumulated prefixes whose
* intents will be withdrawn
- * @return the corresponding intent that should be submitted, or null
+ * @return the corresponding FIB entry change, or null
*/
- private MultiPointToSinglePointIntent processRouteAdd(
+ private FibEntry processRouteAdd(
RouteEntry routeEntry,
Collection<IpPrefix> withdrawPrefixes) {
log.debug("Processing route add: {}", routeEntry);
@@ -397,86 +375,8 @@
routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
return null;
}
- return generateRouteIntent(routeEntry.prefix(), routeEntry.nextHop(),
- nextHopMacAddress);
- }
-
- /**
- * Generates a route intent for a prefix, the next hop IP address, and
- * the next hop MAC address.
- * <p/>
- * This method will find the egress interface for the intent.
- * Intent will match dst IP prefix and rewrite dst MAC address at all other
- * border switches, then forward packets according to dst MAC address.
- *
- * @param prefix IP prefix of the route to add
- * @param nextHopIpAddress IP address of the next hop
- * @param nextHopMacAddress MAC address of the next hop
- * @return the generated intent, or null if no intent should be submitted
- */
- private MultiPointToSinglePointIntent generateRouteIntent(
- IpPrefix prefix,
- IpAddress nextHopIpAddress,
- MacAddress nextHopMacAddress) {
-
- // Find the attachment point (egress interface) of the next hop
- Interface egressInterface;
- if (configService.getBgpPeers().containsKey(nextHopIpAddress)) {
- // Route to a peer
- log.debug("Route to peer {}", nextHopIpAddress);
- BgpPeer peer =
- configService.getBgpPeers().get(nextHopIpAddress);
- egressInterface =
- interfaceService.getInterface(peer.connectPoint());
- } else {
- // Route to non-peer
- log.debug("Route to non-peer {}", nextHopIpAddress);
- egressInterface =
- interfaceService.getMatchingInterface(nextHopIpAddress);
- if (egressInterface == null) {
- log.warn("No outgoing interface found for {}",
- nextHopIpAddress);
- return null;
- }
- }
-
- //
- // Generate the intent itself
- //
- Set<ConnectPoint> ingressPorts = new HashSet<>();
- ConnectPoint egressPort = egressInterface.connectPoint();
- log.debug("Generating intent for prefix {}, next hop mac {}",
- prefix, nextHopMacAddress);
-
- for (Interface intf : interfaceService.getInterfaces()) {
- if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
- ConnectPoint srcPort = intf.connectPoint();
- ingressPorts.add(srcPort);
- }
- }
-
- // Match the destination IP prefix at the first hop
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- if (prefix.version() == Ip4Address.VERSION) {
- selector.matchEthType(Ethernet.TYPE_IPV4);
- } else {
- selector.matchEthType(Ethernet.TYPE_IPV6);
- }
- selector.matchIPDst(prefix);
-
- // Rewrite the destination MAC address
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
- .setEthDst(nextHopMacAddress);
- if (!egressInterface.vlan().equals(VlanId.NONE)) {
- treatment.setVlanId(egressInterface.vlan());
- // If we set VLAN ID, we have to make sure a VLAN tag exists.
- // TODO support no VLAN -> VLAN routing
- selector.matchVlanId(VlanId.ANY);
- }
-
- return new MultiPointToSinglePointIntent(appId, selector.build(),
- treatment.build(),
- ingressPorts, egressPort);
+ return new FibEntry(routeEntry.prefix(), routeEntry.nextHop(),
+ nextHopMacAddress);
}
/**
@@ -528,9 +428,7 @@
// tree and the intents could get out of sync.
//
synchronized (this) {
- Collection<Pair<IpPrefix, MultiPointToSinglePointIntent>>
- submitIntents = new LinkedList<>();
- MultiPointToSinglePointIntent intent;
+ Collection<FibUpdate> submitFibEntries = new LinkedList<>();
Set<RouteEntry> routesToPush =
routesWaitingOnArp.removeAll(ipAddress);
@@ -540,27 +438,21 @@
RouteEntry foundRouteEntry = findRibRoute(routeEntry.prefix());
if (foundRouteEntry != null &&
foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
- // We only push prefix flows if the prefix is still in the
- // radix tree and the next hop is the same as our
- // update.
+ // We only push FIB updates if the prefix is still in the
+ // radix tree and the next hop is the same as our entry.
// The prefix could have been removed while we were waiting
// for the ARP, or the next hop could have changed.
- intent = generateRouteIntent(routeEntry.prefix(),
- ipAddress, macAddress);
- if (intent != null) {
- submitIntents.add(Pair.of(routeEntry.prefix(),
- intent));
- }
+ submitFibEntries.add(new FibUpdate(FibUpdate.Type.UPDATE,
+ new FibEntry(routeEntry.prefix(),
+ ipAddress, macAddress)));
} else {
log.debug("{} has been revoked before the MAC was resolved",
routeEntry);
}
}
- if (!submitIntents.isEmpty()) {
- Collection<IpPrefix> withdrawPrefixes = new LinkedList<>();
- intentSynchronizer.updateRouteIntents(submitIntents,
- withdrawPrefixes);
+ if (!submitFibEntries.isEmpty()) {
+ fibComponent.update(submitFibEntries, Collections.emptyList());
}
ip2Mac.put(ipAddress, macAddress);
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
index a910950..0b921ff 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
@@ -15,11 +15,6 @@
*/
package org.onosproject.sdnip;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Collection;
-import java.util.Dictionary;
-
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -44,6 +39,11 @@
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
+import java.util.Collection;
+import java.util.Dictionary;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
/**
* Component for the SDN-IP peering application.
*/
@@ -104,7 +104,8 @@
InterfaceService interfaceService =
new HostToInterfaceAdaptor(hostService);
- intentSynchronizer = new IntentSynchronizer(appId, intentService);
+ intentSynchronizer = new IntentSynchronizer(appId, intentService,
+ config, interfaceService);
intentSynchronizer.start();
peerConnectivity = new PeerConnectivityManager(appId,
@@ -113,8 +114,7 @@
interfaceService);
peerConnectivity.start();
- router = new Router(appId, intentSynchronizer, config,
- interfaceService, hostService);
+ router = new Router(intentSynchronizer, hostService);
router.start();
leadershipService.addListener(leadershipEventListener);
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
index 9960481..e4808f7 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
@@ -15,23 +15,10 @@
*/
package org.onosproject.sdnip;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
+import com.google.common.collect.Sets;
+import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
+import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
+import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
@@ -67,10 +54,16 @@
import org.onosproject.net.provider.ProviderId;
import org.onosproject.sdnip.config.Interface;
-import com.google.common.collect.Sets;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
/**
* This class tests the intent synchronization function in the
@@ -116,9 +109,9 @@
setUpHostService();
intentService = createMock(IntentService.class);
- intentSynchronizer = new IntentSynchronizer(APPID, intentService);
- router = new Router(APPID, intentSynchronizer, null, interfaceService,
- hostService);
+ intentSynchronizer = new IntentSynchronizer(APPID, intentService,
+ null, interfaceService);
+ router = new Router(intentSynchronizer, hostService);
}
/**
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
index e542eb0..5311a72 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
@@ -15,19 +15,7 @@
*/
package org.onosproject.sdnip;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
+import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -60,7 +48,14 @@
import org.onosproject.sdnip.config.InterfaceAddress;
import org.onosproject.sdnip.config.SdnIpConfigurationService;
-import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
/**
* Unit tests for PeerConnectivityManager.
@@ -552,7 +547,9 @@
intentService = createMock(IntentService.class);
replay(intentService);
- intentSynchronizer = new IntentSynchronizer(APPID, intentService);
+ intentSynchronizer = new IntentSynchronizer(APPID, intentService,
+ configInfoService,
+ interfaceService);
intentSynchronizer.leaderChanged(true);
TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java
index 80fb578..4d14228 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java
@@ -15,22 +15,10 @@
*/
package org.onosproject.sdnip;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
+import com.google.common.collect.Sets;
+import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
+import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
+import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
@@ -69,10 +57,16 @@
import org.onosproject.sdnip.config.Interface;
import org.onosproject.sdnip.config.SdnIpConfigurationService;
-import com.google.common.collect.Sets;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
/**
* This class tests adding a route, updating a route, deleting a route, and
@@ -122,9 +116,10 @@
hostService = createMock(HostService.class);
intentService = createMock(IntentService.class);
- intentSynchronizer = new IntentSynchronizer(APPID, intentService);
- router = new Router(APPID, intentSynchronizer,
- sdnIpConfigService, interfaceService, hostService);
+ intentSynchronizer = new IntentSynchronizer(APPID, intentService,
+ sdnIpConfigService,
+ interfaceService);
+ router = new Router(intentSynchronizer, hostService);
internalHostListener = router.new InternalHostListener();
}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java
index 6c98efb..a7b4cce 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java
@@ -15,22 +15,7 @@
*/
package org.onosproject.sdnip;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
@@ -68,7 +53,15 @@
import org.onosproject.sdnip.config.Interface;
import org.onosproject.sdnip.config.SdnIpConfigurationService;
-import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
/**
* This class tests adding a route, updating a route, deleting a route,
@@ -125,9 +118,10 @@
intentService = createMock(IntentService.class);
- intentSynchronizer = new IntentSynchronizer(APPID, intentService);
- router = new Router(APPID, intentSynchronizer, sdnIpConfigService,
- interfaceService, hostService);
+ intentSynchronizer = new IntentSynchronizer(APPID, intentService,
+ sdnIpConfigService,
+ interfaceService);
+ router = new Router(intentSynchronizer, hostService);
}
/**
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java
index 36bd3b7..157c73f 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java
@@ -15,26 +15,7 @@
*/
package org.onosproject.sdnip;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
+import com.google.common.collect.Sets;
import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;
@@ -66,7 +47,20 @@
import org.onosproject.sdnip.config.Interface;
import org.onosproject.sdnip.config.SdnIpConfigurationService;
-import com.google.common.collect.Sets;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
/**
* Integration tests for the SDN-IP application.
@@ -130,9 +124,10 @@
intentService = createMock(IntentService.class);
random = new Random();
- intentSynchronizer = new IntentSynchronizer(APPID, intentService);
- router = new Router(APPID, intentSynchronizer, sdnIpConfigService,
- interfaceService, hostService);
+ intentSynchronizer = new IntentSynchronizer(APPID, intentService,
+ sdnIpConfigService,
+ interfaceService);
+ router = new Router(intentSynchronizer, hostService);
}
/**