ONOS-5629: Enable encapsulation in SDN-IP

Change-Id: I4c3dbe877fd009302938b228fc9af40225d75329
diff --git a/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java b/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
index 9e0d04e..c24d90b 100644
--- a/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
+++ b/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
@@ -74,15 +74,17 @@
             VlanId vlan = getVlan(jsonNode);
 
             speakers.add(new BgpSpeakerConfig(name,
-                    vlan,
-                    ConnectPoint.deviceConnectPoint(jsonNode.path(CONNECT_POINT).asText()),
-                    listenAddresses));
+                                              vlan,
+                                              ConnectPoint.deviceConnectPoint(jsonNode.path(CONNECT_POINT).asText()),
+                                              listenAddresses));
         });
 
         return speakers;
     }
 
-    // If configured, it retreives a VLAN Id from a BGP speaker node
+    /*
+     * If configured, it retrieves a VLAN Id from a BGP speaker node
+     */
     private VlanId getVlan(JsonNode node) {
         VlanId vlan = VlanId.NONE;
         if (!node.path(VLAN).isMissingNode()) {
@@ -94,8 +96,8 @@
     /**
      * Examines whether a name of BGP speaker exists in configuration.
      *
-     * @param name name of BGP speaker being search
-     * @return speaker
+     * @param name the name of BGP speaker being search
+     * @return the BGP speaker
      */
     public BgpSpeakerConfig getSpeakerWithName(String name) {
         for (BgpConfig.BgpSpeakerConfig speaker : bgpSpeakers()) {
@@ -107,17 +109,15 @@
     }
 
     /**
-     * Adds BGP speaker to configuration.
+     * Adds a BGP speaker to the configuration.
      *
-     * @param speaker BGP speaker configuration entry
+     * @param speaker the BGP speaker configuration entry
      */
     public void addSpeaker(BgpSpeakerConfig speaker) {
+        // Create the new speaker node and set the parameters
         ObjectNode speakerNode = JsonNodeFactory.instance.objectNode();
-
         speakerNode.put(NAME, speaker.name().get());
-
         speakerNode.put(VLAN, speaker.vlan().toString());
-
         speakerNode.put(CONNECT_POINT, speaker.connectPoint().elementId().toString()
                 + "/" + speaker.connectPoint().port().toString());
 
@@ -126,8 +126,9 @@
             peersNode.add(peerAddress.toString());
         }
 
+        // Add the new BGP speaker to the existing node array
         ArrayNode speakersArray = bgpSpeakers().isEmpty() ?
-                initBgpConfiguration() : (ArrayNode) object.get(SPEAKERS);
+                initBgpSpeakersConfiguration() : (ArrayNode) object.get(SPEAKERS);
         speakersArray.add(speakerNode);
     }
 
@@ -212,11 +213,10 @@
      *
      * @return empty array of BGP speakers
      */
-    private ArrayNode initBgpConfiguration() {
+    private ArrayNode initBgpSpeakersConfiguration() {
         return object.putArray(SPEAKERS);
     }
 
-
     /**
      * Configuration for a BGP speaker.
      */
@@ -227,8 +227,10 @@
         private ConnectPoint connectPoint;
         private Set<IpAddress> peers;
 
-        public BgpSpeakerConfig(Optional<String> name, VlanId vlanId,
-                                ConnectPoint connectPoint, Set<IpAddress> peers) {
+        public BgpSpeakerConfig(Optional<String> name,
+                                VlanId vlanId,
+                                ConnectPoint connectPoint,
+                                Set<IpAddress> peers) {
             this.name = checkNotNull(name);
             this.vlanId = checkNotNull(vlanId);
             this.connectPoint = checkNotNull(connectPoint);
diff --git a/apps/sdnip/BUCK b/apps/sdnip/BUCK
index d934d74..2a3166f 100644
--- a/apps/sdnip/BUCK
+++ b/apps/sdnip/BUCK
@@ -2,6 +2,8 @@
     '//lib:CORE_DEPS',
     '//incubator/api:onos-incubator-api',
     '//apps/routing-api:onos-apps-routing-api',
+    '//lib:org.apache.karaf.shell.console',
+    '//cli:onos-cli'
 ]
 
 BUNDLES = [
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
index 6b35a55..64046fe 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.sdnip;
 
+import com.google.common.collect.ImmutableList;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IPv6;
@@ -28,6 +29,8 @@
 import org.onosproject.incubator.net.intf.InterfaceListener;
 import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigService;
@@ -36,12 +39,15 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.net.intent.ConnectivityIntent;
 import org.onosproject.net.intent.IntentUtils;
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
 import org.onosproject.routing.IntentSynchronizationService;
 import org.onosproject.routing.RoutingService;
 import org.onosproject.routing.config.BgpConfig;
+import org.onosproject.sdnip.config.SdnIpConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,6 +60,7 @@
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.EncapsulationType.NONE;
 
 /**
  * Manages the connectivity requirements between peers.
@@ -130,15 +137,24 @@
      * BGP speakers and external BGP peers.
      */
     private void setUpConnectivity() {
-        BgpConfig config = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
+        BgpConfig bgpConfig = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
+        SdnIpConfig sdnIpConfig = configService.getConfig(appId, SdnIpConfig.class);
 
         Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers;
+        EncapsulationType encap;
 
-        if (config == null) {
-            log.warn("No BGP config available");
+        if (bgpConfig == null) {
+            log.debug("No BGP config available");
             bgpSpeakers = Collections.emptySet();
         } else {
-            bgpSpeakers = config.bgpSpeakers();
+            bgpSpeakers = bgpConfig.bgpSpeakers();
+        }
+
+        if (sdnIpConfig == null) {
+            log.debug("No SDN-IP config available");
+            encap = EncapsulationType.NONE;
+        } else {
+            encap = sdnIpConfig.encap();
         }
 
         Map<Key, PointToPointIntent> existingIntents = new HashMap<>(peerIntents);
@@ -147,7 +163,7 @@
             log.debug("Start to set up BGP paths for BGP speaker: {}",
                     bgpSpeaker);
 
-            buildSpeakerIntents(bgpSpeaker).forEach(i -> {
+            buildSpeakerIntents(bgpSpeaker, encap).forEach(i -> {
                 PointToPointIntent intent = existingIntents.remove(i.key());
                 if (intent == null || !IntentUtils.intentsAreEqual(i, intent)) {
                     peerIntents.put(i.key(), i);
@@ -164,7 +180,8 @@
         });
     }
 
-    private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
+    private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker,
+                                                               EncapsulationType encap) {
         List<PointToPointIntent> intents = new ArrayList<>();
 
         // Get the BGP Speaker VLAN Id
@@ -195,7 +212,8 @@
                                         bgpSpeakerAddress,
                                         peeringInterface.connectPoint(),
                                         peerVlanId,
-                                        peerAddress));
+                                        peerAddress,
+                                        encap));
         }
 
         return intents;
@@ -210,6 +228,7 @@
      * @param portTwo the external BGP peer connect point
      * @param vlanTwo the external BGP peer VLAN
      * @param ipTwo the external BGP peer IP address
+     * @param encap the encapsulation type
      * @return the intents to install
      */
     private Collection<PointToPointIntent> buildIntents(ConnectPoint portOne,
@@ -217,13 +236,16 @@
                                                         IpAddress ipOne,
                                                         ConnectPoint portTwo,
                                                         VlanId vlanTwo,
-                                                        IpAddress ipTwo) {
+                                                        IpAddress ipTwo,
+                                                        EncapsulationType encap) {
 
         List<PointToPointIntent> intents = new ArrayList<>();
 
         TrafficTreatment.Builder treatmentToPeer = DefaultTrafficTreatment.builder();
         TrafficTreatment.Builder treatmentToSpeaker = DefaultTrafficTreatment.builder();
 
+        PointToPointIntent.Builder intentBuilder;
+
         TrafficSelector selector;
         Key key;
 
@@ -251,15 +273,18 @@
 
         key = buildKey(ipOne, ipTwo, SUFFIX_DST);
 
-        intents.add(PointToPointIntent.builder()
+        intentBuilder = PointToPointIntent.builder()
                 .appId(appId)
                 .key(key)
+                .filteredIngressPoint(new FilteredConnectPoint(portOne))
+                .filteredEgressPoint(new FilteredConnectPoint(portTwo))
                 .selector(selector)
                 .treatment(treatmentToPeer.build())
-                .ingressPoint(portOne)
-                .egressPoint(portTwo)
-                .priority(PRIORITY_OFFSET)
-                .build());
+                .priority(PRIORITY_OFFSET);
+
+        encap(intentBuilder, encap);
+
+        intents.add(intentBuilder.build());
 
         // Path from BGP speaker to BGP peer matching source TCP port 179
         selector = buildSelector(tcpProtocol,
@@ -271,15 +296,18 @@
 
         key = buildKey(ipOne, ipTwo, SUFFIX_SRC);
 
-        intents.add(PointToPointIntent.builder()
+        intentBuilder = PointToPointIntent.builder()
                 .appId(appId)
                 .key(key)
+                .filteredIngressPoint(new FilteredConnectPoint(portOne))
+                .filteredEgressPoint(new FilteredConnectPoint(portTwo))
                 .selector(selector)
                 .treatment(treatmentToPeer.build())
-                .ingressPoint(portOne)
-                .egressPoint(portTwo)
-                .priority(PRIORITY_OFFSET)
-                .build());
+                .priority(PRIORITY_OFFSET);
+
+        encap(intentBuilder, encap);
+
+        intents.add(intentBuilder.build());
 
         // ICMP path from BGP speaker to BGP peer
         selector = buildSelector(icmpProtocol,
@@ -291,15 +319,18 @@
 
         key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
 
-        intents.add(PointToPointIntent.builder()
+        intentBuilder = PointToPointIntent.builder()
                             .appId(appId)
                             .key(key)
+                            .filteredIngressPoint(new FilteredConnectPoint(portOne))
+                            .filteredEgressPoint(new FilteredConnectPoint(portTwo))
                             .selector(selector)
                             .treatment(treatmentToPeer.build())
-                            .ingressPoint(portOne)
-                            .egressPoint(portTwo)
-                            .priority(PRIORITY_OFFSET)
-                            .build());
+                            .priority(PRIORITY_OFFSET);
+
+        encap(intentBuilder, encap);
+
+        intents.add(intentBuilder.build());
 
         // Add VLAN treatment for traffic going from BGP peer to BGP speaker
         treatmentToSpeaker = applyVlanTreatment(vlanTwo, vlanOne, treatmentToSpeaker);
@@ -314,15 +345,18 @@
 
         key = buildKey(ipTwo, ipOne, SUFFIX_DST);
 
-        intents.add(PointToPointIntent.builder()
+        intentBuilder = PointToPointIntent.builder()
                 .appId(appId)
                 .key(key)
+                .filteredIngressPoint(new FilteredConnectPoint(portTwo))
+                .filteredEgressPoint(new FilteredConnectPoint(portOne))
                 .selector(selector)
                 .treatment(treatmentToSpeaker.build())
-                .ingressPoint(portTwo)
-                .egressPoint(portOne)
-                .priority(PRIORITY_OFFSET)
-                .build());
+                .priority(PRIORITY_OFFSET);
+
+        encap(intentBuilder, encap);
+
+        intents.add(intentBuilder.build());
 
         // Path from BGP peer to BGP speaker matching source TCP port 179
         selector = buildSelector(tcpProtocol,
@@ -334,15 +368,18 @@
 
         key = buildKey(ipTwo, ipOne, SUFFIX_SRC);
 
-        intents.add(PointToPointIntent.builder()
+        intentBuilder = PointToPointIntent.builder()
                 .appId(appId)
                 .key(key)
+                .filteredIngressPoint(new FilteredConnectPoint(portTwo))
+                .filteredEgressPoint(new FilteredConnectPoint(portOne))
                 .selector(selector)
                 .treatment(treatmentToSpeaker.build())
-                .ingressPoint(portTwo)
-                .egressPoint(portOne)
-                .priority(PRIORITY_OFFSET)
-                .build());
+                .priority(PRIORITY_OFFSET);
+
+        encap(intentBuilder, encap);
+
+        intents.add(intentBuilder.build());
 
         // ICMP path from BGP peer to BGP speaker
         selector = buildSelector(icmpProtocol,
@@ -354,15 +391,18 @@
 
         key = buildKey(ipTwo, ipOne, SUFFIX_ICMP);
 
-        intents.add(PointToPointIntent.builder()
+        intentBuilder = PointToPointIntent.builder()
                 .appId(appId)
                 .key(key)
+                .filteredIngressPoint(new FilteredConnectPoint(portTwo))
+                .filteredEgressPoint(new FilteredConnectPoint(portOne))
                 .selector(selector)
                 .treatment(treatmentToSpeaker.build())
-                .ingressPoint(portTwo)
-                .egressPoint(portOne)
-                .priority(PRIORITY_OFFSET)
-                .build());
+                .priority(PRIORITY_OFFSET);
+
+        encap(intentBuilder, encap);
+
+        intents.add(intentBuilder.build());
 
         return intents;
     }
@@ -390,12 +430,12 @@
 
         if (dstIp.isIp4()) {
             builder.matchEthType(Ethernet.TYPE_IPV4)
-                    .matchIPSrc(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET_MASK_LENGTH))
-                    .matchIPDst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET_MASK_LENGTH));
+                   .matchIPSrc(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET_MASK_LENGTH))
+                   .matchIPDst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET_MASK_LENGTH));
         } else {
             builder.matchEthType(Ethernet.TYPE_IPV6)
-                    .matchIPv6Src(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET6_MASK_LENGTH))
-                    .matchIPv6Dst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET6_MASK_LENGTH));
+                   .matchIPv6Src(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET6_MASK_LENGTH))
+                   .matchIPv6Dst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET6_MASK_LENGTH));
         }
 
         if (srcTcpPort != null) {
@@ -457,6 +497,21 @@
         return Key.of(keyString, appId);
     }
 
+    /**
+     * Adds an encapsulation constraint to the builder given, if encap is not
+     * equal to NONE.
+     *
+     * @param builder the intent builder
+     * @param encap the encapsulation type
+     */
+    private static void encap(ConnectivityIntent.Builder builder,
+                              EncapsulationType encap) {
+        if (!encap.equals(NONE)) {
+            builder.constraints(ImmutableList.of(
+                    new EncapsulationConstraint(encap)));
+        }
+    }
+
     private class InternalNetworkConfigListener implements NetworkConfigListener {
 
         @Override
@@ -469,7 +524,8 @@
             case CONFIG_ADDED:
             case CONFIG_UPDATED:
             case CONFIG_REMOVED:
-                if (event.configClass() == RoutingService.CONFIG_CLASS) {
+                if (event.configClass() == RoutingService.CONFIG_CLASS ||
+                    event.configClass() == SdnIpConfig.class) {
                     setUpConnectivity();
                 }
                 break;
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 643bb2b..249a2da 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
@@ -26,9 +26,13 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.component.ComponentService;
 import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.SubjectFactories;
 import org.onosproject.routing.IntentSynchronizationService;
 import org.onosproject.routing.RoutingService;
+import org.onosproject.sdnip.config.SdnIpConfig;
 import org.slf4j.Logger;
 
 import java.util.List;
@@ -60,6 +64,9 @@
     protected IntentSynchronizationService intentSynchronizer;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry cfgRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentService componentService;
 
     private PeerConnectivityManager peerConnectivity;
@@ -72,12 +79,23 @@
             org.onosproject.sdnip.SdnIpFib.class.getName()
     );
 
+    private final List<ConfigFactory<?, ?>> factories = ImmutableList.of(
+            new ConfigFactory<ApplicationId, SdnIpConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
+                                                          SdnIpConfig.class, SdnIpConfig.CONFIG_KEY) {
+                @Override
+                public SdnIpConfig createConfig() {
+                    return new SdnIpConfig();
+                }
+            });
+
     @Activate
     protected void activate() {
-        components.forEach(name -> componentService.activate(appId, name));
-
         appId = coreService.registerApplication(SDN_IP_APP);
 
+        factories.forEach(cfgRegistry::registerConfigFactory);
+
+        components.forEach(name -> componentService.activate(appId, name));
+
         peerConnectivity = new PeerConnectivityManager(appId,
                                                        intentSynchronizer,
                                                        networkConfigService,
@@ -95,6 +113,8 @@
     protected void deactivate() {
         components.forEach(name -> componentService.deactivate(appId, name));
 
+        factories.forEach(cfgRegistry::unregisterConfigFactory);
+
         peerConnectivity.stop();
 
         log.info("Stopped");
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java
index aa646ba..1275bd2 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java
@@ -39,23 +39,34 @@
 import org.onosproject.incubator.net.routing.RouteListener;
 import org.onosproject.incubator.net.routing.RouteService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
 import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
 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.intent.ConnectivityIntent;
 import org.onosproject.net.intent.Constraint;
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
 import org.onosproject.net.intent.constraint.PartialFailureConstraint;
 import org.onosproject.routing.IntentSynchronizationService;
+import org.onosproject.sdnip.config.SdnIpConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import static org.onosproject.net.EncapsulationType.NONE;
+
 /**
  * FIB component of SDN-IP.
  */
@@ -73,10 +84,15 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected RouteService routeService;
 
     private final InternalRouteListener routeListener = new InternalRouteListener();
     private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
+    private final InternalNetworkConfigListener networkConfigListener =
+            new InternalNetworkConfigListener();
 
     private static final int PRIORITY_OFFSET = 100;
     private static final int PRIORITY_MULTIPLIER = 5;
@@ -91,9 +107,8 @@
     @Activate
     public void activate() {
         appId = coreService.getAppId(SdnIp.SDN_IP_APP);
-
         interfaceService.addListener(interfaceListener);
-
+        networkConfigService.addListener(networkConfigListener);
         routeService.addListener(routeListener);
     }
 
@@ -106,11 +121,15 @@
     private void update(ResolvedRoute route) {
         synchronized (this) {
             IpPrefix prefix = route.prefix();
+            EncapsulationType encap = encap();
             MultiPointToSinglePointIntent intent =
-                    generateRouteIntent(prefix, route.nextHop(), route.nextHopMac());
+                    generateRouteIntent(prefix,
+                                        route.nextHop(),
+                                        route.nextHopMac(),
+                                        encap);
 
             if (intent == null) {
-                log.debug("SDN-IP no interface found for route {}", route);
+                log.debug("No interface found for route {}", route);
                 return;
             }
 
@@ -124,8 +143,8 @@
             IpPrefix prefix = route.prefix();
             MultiPointToSinglePointIntent intent = routeIntents.remove(prefix);
             if (intent == null) {
-                log.trace("SDN-IP no intent in routeIntents to delete " +
-                        "for prefix: {}", prefix);
+                log.trace("No intent in routeIntents to delete for prefix: {}",
+                          prefix);
                 return;
             }
             intentSynchronizer.withdraw(intent);
@@ -140,15 +159,17 @@
      * 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
+     * @param prefix            the IP prefix of the route to add
+     * @param nextHopIpAddress  the IP address of the next hop
+     * @param nextHopMacAddress the MAC address of the next hop
+     * @param encap             the encapsulation type in use
      * @return the generated intent, or null if no intent should be submitted
      */
     private MultiPointToSinglePointIntent generateRouteIntent(
             IpPrefix prefix,
             IpAddress nextHopIpAddress,
-            MacAddress nextHopMacAddress) {
+            MacAddress nextHopMacAddress,
+            EncapsulationType encap) {
 
         // Find the attachment point (egress interface) of the next hop
         Interface egressInterface =
@@ -194,15 +215,19 @@
         // Set key
         Key key = Key.of(prefix.toString(), appId);
 
-        return MultiPointToSinglePointIntent.builder()
-                .appId(appId)
-                .key(key)
-                .filteredIngressPoints(ingressFilteredCPs)
-                .filteredEgressPoint(egressFilteredCP)
-                .treatment(treatment.build())
-                .priority(priority)
-                .constraints(CONSTRAINTS)
-                .build();
+        MultiPointToSinglePointIntent.Builder intentBuilder =
+                MultiPointToSinglePointIntent.builder()
+                                             .appId(appId)
+                                             .key(key)
+                                             .filteredIngressPoints(ingressFilteredCPs)
+                                             .filteredEgressPoint(egressFilteredCP)
+                                             .treatment(treatment.build())
+                                             .priority(priority)
+                                             .constraints(CONSTRAINTS);
+
+        setEncap(intentBuilder, CONSTRAINTS, encap);
+
+        return intentBuilder.build();
     }
 
     private void addInterface(Interface intf) {
@@ -350,6 +375,87 @@
         return false;
     }
 
+    /*
+     * Triggered when the network configuration configuration is modified.
+     * It checks if the encapsulation type has changed from last time, and in
+     * case modifies all intents.
+     */
+    private void encapUpdate() {
+        synchronized (this) {
+            // Get the encapsulation type just set from the configuration
+            EncapsulationType encap = encap();
+
+
+            for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry : routeIntents.entrySet()) {
+                // Get each intent currently registered by SDN-IP
+                MultiPointToSinglePointIntent intent = entry.getValue();
+
+                // Make sure the same constraint is not already part of the
+                // intent constraints
+                List<Constraint> constraints = intent.constraints();
+                if (!constraints.stream()
+                                .filter(c -> c instanceof EncapsulationConstraint &&
+                                        new EncapsulationConstraint(encap).equals(c))
+                                .findAny()
+                                .isPresent()) {
+                    MultiPointToSinglePointIntent.Builder intentBuilder =
+                            MultiPointToSinglePointIntent.builder(intent);
+
+                    // Set the new encapsulation constraint
+                    setEncap(intentBuilder, constraints, encap);
+
+                    // Build and submit the new intent
+                    MultiPointToSinglePointIntent newIntent =
+                            intentBuilder.build();
+
+                    routeIntents.put(entry.getKey(), newIntent);
+                    intentSynchronizer.submit(newIntent);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets an encapsulation constraint to the intent builder given.
+     *
+     * @param builder the intent builder
+     * @param constraints the existing intent constraints
+     * @param encap the encapsulation type to be set
+     */
+    private static void setEncap(ConnectivityIntent.Builder builder,
+                                 List<Constraint> constraints,
+                                 EncapsulationType encap) {
+        // Constraints might be an immutable list, so a new modifiable list
+        // is created
+        List<Constraint> newConstraints = new ArrayList<>(constraints);
+
+        // Remove any encapsulation constraint if already in the list
+        constraints.stream()
+                .filter(c -> c instanceof EncapsulationConstraint)
+                .forEach(c -> newConstraints.remove(c));
+
+        // if the new encapsulation is different from NONE, a new encapsulation
+        // constraint should be added to the list
+        if (!encap.equals(NONE)) {
+            newConstraints.add(new EncapsulationConstraint(encap));
+        }
+
+        // Submit new constraint list as immutable list
+        builder.constraints(ImmutableList.copyOf(newConstraints));
+    }
+
+    private EncapsulationType encap() {
+        SdnIpConfig sdnIpConfig =
+                networkConfigService.getConfig(appId, SdnIpConfig.class);
+
+        if (sdnIpConfig == null) {
+            log.debug("No SDN-IP config available");
+            return EncapsulationType.NONE;
+        } else {
+            return sdnIpConfig.encap();
+        }
+    }
+
     private class InternalRouteListener implements RouteListener {
         @Override
         public void event(RouteEvent event) {
@@ -367,8 +473,28 @@
         }
     }
 
-    private class InternalInterfaceListener implements InterfaceListener {
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+        @Override
+        public void event(NetworkConfigEvent event) {
+            switch (event.type()) {
+                case CONFIG_REGISTERED:
+                    break;
+                case CONFIG_UNREGISTERED:
+                    break;
+                case CONFIG_ADDED:
+                case CONFIG_UPDATED:
+                case CONFIG_REMOVED:
+                    if (event.configClass() == SdnIpConfig.class) {
+                        encapUpdate();
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
 
+    private class InternalInterfaceListener implements InterfaceListener {
         @Override
         public void event(InterfaceEvent event) {
             switch (event.type()) {
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/SdnIpCommand.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/SdnIpCommand.java
new file mode 100644
index 0000000..47b50d5
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/SdnIpCommand.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015-present 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.EncapsulationType;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.sdnip.SdnIp;
+import org.onosproject.sdnip.config.SdnIpConfig;
+
+/**
+ * CLI to interact with the SDN-IP application.
+ */
+@Command(scope = "onos", name = "sdnip",
+        description = "Manages the SDN-IP application")
+public class SdnIpCommand extends AbstractShellCommand {
+
+    // Color codes and style
+    private static final String BOLD = "\u001B[1m";
+    private static final String COLOR_ERROR = "\u001B[31m";
+    private static final String RESET = "\u001B[0m";
+
+    // Messages and string formatter
+    private static final String ENCAP_NOT_FOUND =
+            COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET +
+                    COLOR_ERROR + " not found" + RESET;
+
+    private static final String SDNIP_COMMAND_NOT_FOUND =
+            COLOR_ERROR + "SDN-IP command " + BOLD + "%s" + RESET + COLOR_ERROR +
+                    " not found" + RESET;
+
+    @Argument(index = 0, name = "command", description = "Command name" +
+            " {set-encap}",
+            required = true, multiValued = false)
+    String command = null;
+
+    @Argument(index = 1, name = "encapType", description = "The encapsulation" +
+            " type {NONE | VLAN | MPLS}",
+            required = true, multiValued = false)
+    String encapType = null;
+
+    @Override
+    protected void execute() {
+        if (command != null) {
+            switch (command) {
+                case "set-encap":
+                    setEncap(encapType);
+                    break;
+                default:
+                    print(SDNIP_COMMAND_NOT_FOUND, command);
+            }
+        }
+    }
+
+    /**
+     * Sets the encapsulation type for SDN-IP.
+     *
+     * @param encap the encapsulation type
+     */
+    private void setEncap(String encap) {
+        EncapsulationType encapType = EncapsulationType.enumFromString(encap);
+        if (encapType.equals(EncapsulationType.NONE) &&
+                !encapType.toString().equals(encap)) {
+            print(ENCAP_NOT_FOUND, encap);
+            return;
+        }
+
+        NetworkConfigService configService = get(NetworkConfigService.class);
+        CoreService coreService = get(CoreService.class);
+        ApplicationId appId = coreService.getAppId(SdnIp.SDN_IP_APP);
+
+        SdnIpConfig config = configService.addConfig(appId, SdnIpConfig.class);
+
+        config.setEncap(encapType);
+        config.apply();
+
+        //configService.applyConfig(appId, SdnIpConfig.class, config.node());
+    }
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/SdnIpCommandCompleter.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/SdnIpCommandCompleter.java
new file mode 100644
index 0000000..593522f
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/SdnIpCommandCompleter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015-present 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.completer;
+
+import com.google.common.collect.Lists;
+import org.onosproject.cli.AbstractChoicesCompleter;
+
+import java.util.List;
+
+/**
+ * SDN-IP command completer.
+ */
+public class SdnIpCommandCompleter extends AbstractChoicesCompleter {
+
+    @Override
+    public List<String> choices() {
+        return Lists.newArrayList("set-encap");
+    }
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/SdnIpEncapCompleter.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/SdnIpEncapCompleter.java
new file mode 100644
index 0000000..bd3a49c
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/SdnIpEncapCompleter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015-present 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.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.net.EncapsulationType;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * SDN-IP encapsulation type completer.
+ */
+public class SdnIpEncapCompleter extends AbstractChoicesCompleter {
+
+    @Override
+    public List<String> choices() {
+        return Arrays.stream(EncapsulationType.values())
+                .map(Enum::toString)
+                .collect(Collectors.toList());
+    }
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/package-info.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/package-info.java
new file mode 100644
index 0000000..382b96c
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/completer/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present 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.
+ */
+
+/**
+ * Completers implementation for the SDN-IP CLI.
+ */
+package org.onosproject.sdnip.cli.completer;
\ No newline at end of file
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/package-info.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/package-info.java
new file mode 100644
index 0000000..621bcc8
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present 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.
+ */
+
+/**
+ * CLI implementation for SDN-IP services.
+ */
+package org.onosproject.sdnip.cli;
\ No newline at end of file
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/config/SdnIpConfig.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/config/SdnIpConfig.java
new file mode 100644
index 0000000..3ae134b
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/config/SdnIpConfig.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015-present 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.config;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.config.Config;
+
+/**
+ * Configuration object for SDN-IP config.
+ */
+public class SdnIpConfig extends Config<ApplicationId> {
+
+    public static final String CONFIG_KEY = "sdnip";
+
+    public static final String ENCAPSULTATION = "encap";
+
+    /**
+     * Retrieves the encapsulation type set.
+     *
+     * @return the encapsulation type configured
+     */
+    public EncapsulationType encap() {
+        EncapsulationType encapType = EncapsulationType.NONE;
+        if (object.hasNonNull(ENCAPSULTATION)) {
+            String encap = object.get(ENCAPSULTATION).asText();
+            encapType = EncapsulationType.enumFromString(encap);
+        }
+
+        return encapType;
+    }
+
+    /**
+     * Sets the encapsulation type used by SDN-IP.
+     *
+     * @param encap the encapsulation type
+     */
+    public void setEncap(EncapsulationType encap) {
+        object.put(ENCAPSULTATION, encap.toString());
+    }
+}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/config/package-info.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/config/package-info.java
new file mode 100644
index 0000000..1b4a3a0
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/config/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014-present 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.
+ */
+
+/**
+ * SDN-IP peering application configuration.
+ */
+package org.onosproject.sdnip.config;
diff --git a/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 0000000..d8fca7b
--- /dev/null
+++ b/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright 2014-present 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.
+  -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.sdnip.cli.SdnIpCommand"/>
+            <completers>
+                <ref component-id="sdnIpCommandCompleter"/>
+                <ref component-id="sdnIpEncapCompleter"/>
+                <null/>
+            </completers>
+        </command>
+    </command-bundle>
+
+    <bean id="sdnIpCommandCompleter" class="org.onosproject.sdnip.cli.completer.SdnIpCommandCompleter"/>
+    <bean id="sdnIpEncapCompleter" class="org.onosproject.sdnip.cli.completer.SdnIpEncapCompleter"/>
+</blueprint>
\ No newline at end of file
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 b8e4e1b..c261f15 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
@@ -33,6 +33,7 @@
 import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.EncapsulationType;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigService;
@@ -47,6 +48,7 @@
 import org.onosproject.net.intent.PointToPointIntent;
 import org.onosproject.routing.IntentSynchronizationService;
 import org.onosproject.routing.config.BgpConfig;
+import org.onosproject.sdnip.config.SdnIpConfig;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -84,6 +86,8 @@
 
     private BgpConfig bgpConfig;
 
+    private SdnIpConfig sdnIpConfig;
+
     private List<PointToPointIntent> intentList;
 
     private final DeviceId deviceId1 =
@@ -125,6 +129,7 @@
         networkConfigService.addListener(anyObject(NetworkConfigListener.class));
         expectLastCall().anyTimes();
         bgpConfig = createMock(BgpConfig.class);
+        sdnIpConfig = createMock(SdnIpConfig.class);
 
         // These will set expectations on routingConfig and interfaceService
         bgpSpeakers = setUpBgpSpeakers();
@@ -168,7 +173,7 @@
 
     /**
      * Sets up logical interfaces, which emulate the configured interfaces
-     * in SDN-IP application.
+     * in the SDN-IP application.
      *
      * @return configured interfaces as a map from interface name to Interface
      */
@@ -581,6 +586,12 @@
         replay(bgpConfig);
         expect(networkConfigService.getConfig(APPID, BgpConfig.class))
                 .andReturn(bgpConfig).anyTimes();
+
+        expect(sdnIpConfig.encap()).andReturn(EncapsulationType.NONE).anyTimes();
+        replay(sdnIpConfig);
+        expect(networkConfigService.getConfig(APPID, SdnIpConfig.class))
+                .andReturn(sdnIpConfig).anyTimes();
+
         replay(networkConfigService);
         replay(interfaceService);
 
@@ -670,6 +681,10 @@
         expect(bgpConfig.bgpSpeakers()).andReturn(Collections.emptySet()).anyTimes();
         replay(bgpConfig);
 
+        reset(sdnIpConfig);
+        expect(sdnIpConfig.encap()).andReturn(EncapsulationType.NONE).anyTimes();
+        replay(sdnIpConfig);
+
         // We don't expect any intents in this case
         reset(intentSynchronizer);
         replay(intentSynchronizer);
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java
index 31e1cde..9af9c76 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java
@@ -16,6 +16,8 @@
 
 package org.onosproject.sdnip;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import org.junit.Before;
@@ -41,8 +43,13 @@
 import org.onosproject.incubator.net.routing.RouteServiceAdapter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.EncapsulationType;
 import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
@@ -52,6 +59,9 @@
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.routing.IntentSynchronizationService;
+import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpConfig;
+import org.onosproject.sdnip.config.SdnIpConfig;
 
 import java.util.Collections;
 import java.util.List;
@@ -142,6 +152,7 @@
         sdnipFib = new SdnIpFib();
         sdnipFib.routeService = new TestRouteService();
         sdnipFib.coreService = new TestCoreService();
+        sdnipFib.networkConfigService = new TestNetworkConfigService();
         sdnipFib.interfaceService = interfaceService;
         sdnipFib.intentSynchronizer = intentSynchronizer;
 
@@ -636,10 +647,41 @@
         }
     }
 
+    private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+        /**
+         * Returns an empty BGP network configuration to be able to correctly
+         * return the encapsulation parameter when needed.
+         *
+         * @return an empty BGP network configuration object
+         */
+        @Override
+        public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
+            ApplicationId appId =
+                    new TestApplicationId(SdnIp.SDN_IP_APP);
+
+            ObjectMapper mapper = new ObjectMapper();
+            ConfigApplyDelegate delegate = new MockCfgDelegate();
+            JsonNode emptyTree = new ObjectMapper().createObjectNode();
+
+            SdnIpConfig sdnIpConfig = new SdnIpConfig();
+
+            sdnIpConfig.init(appId, "sdnip-test", emptyTree, mapper, delegate);
+
+            return (C) sdnIpConfig;
+        }
+    }
+
     private class InterfaceServiceDelegate extends InterfaceServiceAdapter {
         @Override
         public void addListener(InterfaceListener listener) {
             SdnIpFibTest.this.interfaceListener = listener;
         }
     }
+
+    private class MockCfgDelegate implements ConfigApplyDelegate {
+        @Override
+        public void onApply(@SuppressWarnings("rawtypes") Config config) {
+            config.apply();
+        }
+    }
 }