Pingping Lin

sdn-ip reactive routing

   This module can handle 3 cases:
   (1) one host wants to talk to another host, both two hosts are in SDN network.
   (2) one host in SDN network wants to talk to another host in Internet.
   (3) one host from Internet wants to talk to another host in SDN network.
   In all cases, we use MultiPointToSinglePointIntent.

Change-Id: I80dd954bd608e52b45b993f3c27e67636a7105d9
Showing 23 changed files with 1245 additions and 43 deletions
...@@ -172,7 +172,8 @@ public class BgpRouter { ...@@ -172,7 +172,8 @@ public class BgpRouter {
172 172
173 icmpHandler = new IcmpHandler(configService, packetService); 173 icmpHandler = new IcmpHandler(configService, packetService);
174 174
175 - routingService.start(new InternalFibListener()); 175 + routingService.addFibListener(new InternalFibListener());
176 + routingService.start();
176 177
177 connectivityManager.start(); 178 connectivityManager.start();
178 179
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
42 <module>oecfg</module> 42 <module>oecfg</module>
43 <module>routing</module> 43 <module>routing</module>
44 <module>routing-api</module> 44 <module>routing-api</module>
45 + <module>reactive-routing</module>
45 <module>bgprouter</module> 46 <module>bgprouter</module>
46 <module>test</module> 47 <module>test</module>
47 </modules> 48 </modules>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<app name="org.onosproject.reactive.routing" origin="ON.Lab" version="1.2.0"
18 + features="onos-app-reactive-routing">
19 + <description> ONOS SDN/IP reactive routing </description>
20 +</app>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
19 + <modelVersion>4.0.0</modelVersion>
20 +
21 + <artifactId>onos-app-reactive-routing</artifactId>
22 + <packaging>bundle</packaging>
23 + <description> SDN-IP reactive routing </description>
24 +
25 + <parent>
26 + <groupId>org.onosproject</groupId>
27 + <artifactId>onos-apps</artifactId>
28 + <version>1.2.0-SNAPSHOT</version>
29 + <relativePath>../pom.xml</relativePath>
30 + </parent>
31 +
32 + <dependencies>
33 + <dependency>
34 + <groupId>org.onosproject</groupId>
35 + <artifactId>onos-app-routing-api</artifactId>
36 + <version>${project.version}</version>
37 + </dependency>
38 +
39 + <dependency>
40 + <groupId>org.onosproject</groupId>
41 + <artifactId>onos-app-routing</artifactId>
42 + <version>${project.version}</version>
43 + </dependency>
44 + </dependencies>
45 +
46 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.reactive.routing;
17 +import static org.slf4j.LoggerFactory.getLogger;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onlab.packet.Ethernet;
25 +import org.onlab.packet.IPv4;
26 +import org.onlab.packet.IpAddress;
27 +import org.onlab.packet.MacAddress;
28 +import org.onosproject.core.ApplicationId;
29 +import org.onosproject.core.CoreService;
30 +import org.onosproject.net.ConnectPoint;
31 +import org.onosproject.net.flow.DefaultTrafficSelector;
32 +import org.onosproject.net.flow.DefaultTrafficTreatment;
33 +import org.onosproject.net.flow.TrafficSelector;
34 +import org.onosproject.net.flow.TrafficTreatment;
35 +import org.onosproject.net.packet.DefaultOutboundPacket;
36 +import org.onosproject.net.packet.InboundPacket;
37 +import org.onosproject.net.packet.OutboundPacket;
38 +import org.onosproject.net.packet.PacketContext;
39 +import org.onosproject.net.packet.PacketPriority;
40 +import org.onosproject.net.packet.PacketProcessor;
41 +import org.onosproject.net.packet.PacketService;
42 +import org.onosproject.routing.RoutingService;
43 +import org.slf4j.Logger;
44 +
45 +/**
46 + * This is reactive routing to handle 3 cases:
47 + * (1) one host wants to talk to another host, both two hosts are in
48 + * SDN network.
49 + * (2) one host in SDN network wants to talk to another host in Internet.
50 + * (3) one host from Internet wants to talk to another host in SDN network.
51 + */
52 +@Component(immediate = true)
53 +public class SdnIpReactiveRouting {
54 +
55 + private static final String APP_NAME = "org.onosproject.reactive.routing";
56 + private final Logger log = getLogger(getClass());
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + protected CoreService coreService;
60 +
61 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 + protected PacketService packetService;
63 +
64 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 + protected RoutingService routingService;
66 +
67 + private ApplicationId appId;
68 +
69 + private ReactiveRoutingProcessor processor =
70 + new ReactiveRoutingProcessor();
71 +
72 + @Activate
73 + public void activate() {
74 + appId = coreService.registerApplication(APP_NAME);
75 + packetService.addProcessor(processor,
76 + PacketProcessor.ADVISOR_MAX + 2);
77 +
78 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
79 + // TODO: to support IPv6 later
80 + selector.matchEthType(Ethernet.TYPE_IPV4);
81 + packetService.requestPackets(selector.build(),
82 + PacketPriority.REACTIVE, appId);
83 +
84 + log.info("SDN-IP Reactive Routing Started");
85 + }
86 +
87 + @Deactivate
88 + public void deactivate() {
89 + packetService.removeProcessor(processor);
90 + processor = null;
91 + log.info("SDN-IP Reactive Routing Stopped");
92 + }
93 +
94 + private class ReactiveRoutingProcessor implements PacketProcessor {
95 + @Override
96 + public void process(PacketContext context) {
97 +
98 + InboundPacket pkt = context.inPacket();
99 + Ethernet ethPkt = pkt.parsed();
100 + if (ethPkt == null) {
101 + return;
102 + }
103 +
104 + // In theory, we do not need to check whether it is Ethernet
105 + // TYPE_IPV4. However, due to the current implementation of the
106 + // packetService, we will receive all packets from all subscribers.
107 + // Hence, we have to check the Ethernet type again here.
108 + if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
109 + return;
110 + }
111 +
112 + // Parse packet
113 + IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
114 + IpAddress dstIp =
115 + IpAddress.valueOf(ipv4Packet.getDestinationAddress());
116 + IpAddress srcIp =
117 + IpAddress.valueOf(ipv4Packet.getSourceAddress());
118 + ConnectPoint srcConnectPoint = pkt.receivedFrom();
119 + MacAddress srcMac = ethPkt.getSourceMAC();
120 + routingService.packetReactiveProcessor(dstIp, srcIp,
121 + srcConnectPoint, srcMac);
122 +
123 + // TODO emit packet first or packetReactiveProcessor first
124 + ConnectPoint egressConnectPoint = null;
125 + egressConnectPoint = routingService.getEgressConnectPoint(dstIp);
126 + if (egressConnectPoint != null) {
127 + forwardPacketToDst(context, egressConnectPoint);
128 + }
129 + }
130 + }
131 +
132 + /**
133 + * Emits the specified packet onto the network.
134 + *
135 + * @param context the packet context
136 + * @param connectPoint the connect point where the packet should be
137 + * sent out
138 + */
139 + private void forwardPacketToDst(PacketContext context,
140 + ConnectPoint connectPoint) {
141 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
142 + .setOutput(connectPoint.port()).build();
143 + OutboundPacket packet =
144 + new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
145 + context.inPacket().unparsed());
146 + packetService.emit(packet);
147 + log.trace("sending packet: {}", packet);
148 + }
149 +
150 +}
151 +
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Application to enable (1) hosts in local SDN network to talk to other hosts
19 + * in Internet, and (2) hosts in local SDN network to talk to each other.
20 + */
21 +package org.onosproject.reactive.routing;
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.routing;
17 +
18 +import org.onlab.packet.IpAddress;
19 +import org.onlab.packet.IpPrefix;
20 +import org.onlab.packet.MacAddress;
21 +import org.onosproject.net.ConnectPoint;
22 +
23 +/**
24 + * An interface to process intent requests.
25 + */
26 +public interface IntentRequestListener {
27 +
28 + /**
29 + * Sets up connectivity for packet from Internet to a host in local
30 + * SDN network.
31 + *
32 + * @param dstIpAddress IP address of destination host in local SDN network
33 + */
34 + void setUpConnectivityInternetToHost(IpAddress dstIpAddress);
35 +
36 + /**
37 + * Sets up the connectivity for two hosts in local SDN network.
38 + *
39 + * @param dstIpAddress the destination IP address
40 + * @param srcIpAddress the source IP address
41 + * @param srcMacAddress the source MAC address
42 + * @param srcConnectPoint the connectPoint of the source host
43 + */
44 + void setUpConnectivityHostToHost(IpAddress dstIpAddress,
45 + IpAddress srcIpAddress,
46 + MacAddress srcMacAddress,
47 + ConnectPoint srcConnectPoint);
48 +
49 + /**
50 + * Adds one new ingress connect point into ingress points of an existing
51 + * intent and resubmits the new intent.
52 + * <p>
53 + * If there is already an intent for an IP prefix in the system, we do not
54 + * need to create a new one, we only need to update this existing intent by
55 + * adding more ingress points.
56 + * </p>
57 + *
58 + * @param ipPrefix the IP prefix used to search the existing
59 + * MultiPointToSinglePointIntent
60 + * @param ingressConnectPoint the ingress connect point to be added into
61 + * the exiting intent
62 + */
63 + void updateExistingMp2pIntent(IpPrefix ipPrefix,
64 + ConnectPoint ingressConnectPoint);
65 +
66 + /**
67 + * Checks whether there is a MultiPointToSinglePointIntent in memory for a
68 + * given IP prefix.
69 + *
70 + * @param ipPrefix the IP prefix used to search the existing
71 + * MultiPointToSinglePointIntent
72 + * @return true if there is a MultiPointToSinglePointIntent, otherwise false
73 + */
74 + boolean mp2pIntentExists(IpPrefix ipPrefix);
75 +
76 +}
...@@ -17,17 +17,92 @@ package org.onosproject.routing; ...@@ -17,17 +17,92 @@ package org.onosproject.routing;
17 17
18 import java.util.Collection; 18 import java.util.Collection;
19 19
20 +import org.onlab.packet.IpAddress;
21 +import org.onlab.packet.MacAddress;
22 +import org.onosproject.net.ConnectPoint;
23 +
20 /** 24 /**
21 * Provides a way of interacting with the RIB management component. 25 * Provides a way of interacting with the RIB management component.
22 */ 26 */
23 public interface RoutingService { 27 public interface RoutingService {
24 28
25 /** 29 /**
30 + * Specifies the type of an IP address or an IP prefix location.
31 + */
32 + public static enum LocationType {
33 + /**
34 + * The location of an IP address or an IP prefix is in local SDN network.
35 + */
36 + LOCAL,
37 + /**
38 + * The location of an IP address or an IP prefix is outside local SDN network.
39 + */
40 + INTERNET,
41 + /**
42 + * There is no route for this IP address or IP prefix.
43 + */
44 + NO_ROUTE
45 + }
46 +
47 + /**
48 + * Specifies the type of traffic.
49 + * <p>
50 + * We classify traffic by the first packet of each traffic.
51 + * </p>
52 + */
53 + public enum TrafficType {
54 + /**
55 + * Traffic from a host located in local SDN network wants to
56 + * communicate with destination host located in Internet (outside
57 + * local SDN network).
58 + */
59 + HOST_TO_INTERNET,
60 + /**
61 + * Traffic from Internet wants to communicate with a host located
62 + * in local SDN network.
63 + */
64 + INTERNET_TO_HOST,
65 + /**
66 + * Both the source host and destination host of a traffic are in
67 + * local SDN network.
68 + */
69 + HOST_TO_HOST,
70 + /**
71 + * Traffic from Internet wants to traverse local SDN network.
72 + */
73 + INTERNET_TO_INTERNET,
74 + /**
75 + * Any traffic wants to communicate with a destination which has
76 + * no route, or traffic from Internet wants to access a local private
77 + * IP address.
78 + */
79 + DROP,
80 + /**
81 + * Traffic does not belong to the types above.
82 + */
83 + UNKNOWN
84 + }
85 +
86 + /**
26 * Starts the routing service. 87 * Starts the routing service.
88 + */
89 + public void start();
90 +
91 + /**
92 + * Adds FIB listener.
27 * 93 *
28 - * @param listener listener to send FIB updates to 94 + * @param fibListener listener to send FIB updates to
29 */ 95 */
30 - public void start(FibListener listener); 96 + public void addFibListener(FibListener fibListener);
97 +
98 + /**
99 + * Adds intent creation and submission listener.
100 + *
101 + * @param intentRequestListener listener to send intent creation and
102 + * submission request to
103 + */
104 + public void addIntentRequestListener(IntentRequestListener
105 + intentRequestListener);
31 106
32 /** 107 /**
33 * Stops the routing service. 108 * Stops the routing service.
...@@ -47,4 +122,43 @@ public interface RoutingService { ...@@ -47,4 +122,43 @@ public interface RoutingService {
47 * @return the SDN-IP IPv6 routes 122 * @return the SDN-IP IPv6 routes
48 */ 123 */
49 public Collection<RouteEntry> getRoutes6(); 124 public Collection<RouteEntry> getRoutes6();
125 +
126 + /**
127 + * Evaluates the location of an IP address and returns the location type.
128 + *
129 + * @param ipAddress the IP address to evaluate
130 + * @return the IP address location type
131 + */
132 + public LocationType getLocationType(IpAddress ipAddress);
133 +
134 + /**
135 + * Finds out the route entry which has the longest matchable IP prefix.
136 + *
137 + * @param ipAddress IP address used to find out longest matchable IP prefix
138 + * @return a route entry which has the longest matchable IP prefix if
139 + * found, otherwise null
140 + */
141 + public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress);
142 +
143 + /**
144 + * Finds out the egress connect point where to emit the first packet
145 + * based on destination IP address.
146 + *
147 + * @param dstIpAddress the destination IP address
148 + * @return the egress connect point if found, otherwise null
149 + */
150 + public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress);
151 +
152 + /**
153 + * Routes packet reactively.
154 + *
155 + * @param dstIpAddress the destination IP address of a packet
156 + * @param srcIpAddress the source IP address of a packet
157 + * @param srcConnectPoint the connect point where a packet comes from
158 + * @param srcMacAddress the source MAC address of a packet
159 + */
160 + public void packetReactiveProcessor(IpAddress dstIpAddress,
161 + IpAddress srcIpAddress,
162 + ConnectPoint srcConnectPoint,
163 + MacAddress srcMacAddress);
50 } 164 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.routing.config;
17 +
18 +import com.fasterxml.jackson.annotation.JsonProperty;
19 +import com.google.common.base.MoreObjects;
20 +
21 +import java.util.Objects;
22 +
23 +import org.onlab.packet.IpPrefix;
24 +
25 +/**
26 + * Configuration details for an IP prefix entry.
27 + */
28 +public class LocalIpPrefixEntry {
29 + private final IpPrefix ipPrefix;
30 + private final IpPrefixType type;
31 +
32 + /**
33 + * Specifies the type of local IP prefix.
34 + */
35 + public enum IpPrefixType {
36 + /**
37 + * Public IP prefixes should be exchanged by eBGP.
38 + */
39 + PUBLIC,
40 + /**
41 + * Private IP prefixes should be used only locally and not exchanged
42 + * by eBGP.
43 + */
44 + PRIVATE,
45 + /**
46 + * For IP prefixes in blacklist.
47 + */
48 + BLACK_LIST
49 + }
50 +
51 + /**
52 + * Creates a new IP prefix entry.
53 + *
54 + * @param ipPrefix an IP prefix as a String
55 + * @param type an IP prefix type as an IpPrefixType
56 + */
57 + public LocalIpPrefixEntry(@JsonProperty("ipPrefix") String ipPrefix,
58 + @JsonProperty("type") IpPrefixType type) {
59 + this.ipPrefix = IpPrefix.valueOf(ipPrefix);
60 + this.type = type;
61 + }
62 +
63 + /**
64 + * Gets the IP prefix of the IP prefix entry.
65 + *
66 + * @return the IP prefix
67 + */
68 + public IpPrefix ipPrefix() {
69 + return ipPrefix;
70 + }
71 +
72 + /**
73 + * Gets the IP prefix type of the IP prefix entry.
74 + *
75 + * @return the IP prefix type
76 + */
77 + public IpPrefixType ipPrefixType() {
78 + return type;
79 + }
80 +
81 + /**
82 + * Tests whether the IP version of this entry is IPv4.
83 + *
84 + * @return true if the IP version of this entry is IPv4, otherwise false.
85 + */
86 + public boolean isIp4() {
87 + return ipPrefix.isIp4();
88 + }
89 +
90 + /**
91 + * Tests whether the IP version of this entry is IPv6.
92 + *
93 + * @return true if the IP version of this entry is IPv6, otherwise false.
94 + */
95 + public boolean isIp6() {
96 + return ipPrefix.isIp6();
97 + }
98 +
99 + @Override
100 + public int hashCode() {
101 + return Objects.hash(ipPrefix, type);
102 + }
103 +
104 + @Override
105 + public boolean equals(Object obj) {
106 + if (obj == this) {
107 + return true;
108 + }
109 +
110 + if (!(obj instanceof LocalIpPrefixEntry)) {
111 + return false;
112 + }
113 +
114 + LocalIpPrefixEntry that = (LocalIpPrefixEntry) obj;
115 + return Objects.equals(this.ipPrefix, that.ipPrefix)
116 + && Objects.equals(this.type, that.type);
117 + }
118 +
119 + @Override
120 + public String toString() {
121 + return MoreObjects.toStringHelper(getClass())
122 + .add("ipPrefix", ipPrefix)
123 + .add("ipPrefixType", type)
124 + .toString();
125 + }
126 +}
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.routing.config; 16 package org.onosproject.routing.config;
17 17
18 import org.onlab.packet.IpAddress; 18 import org.onlab.packet.IpAddress;
19 +import org.onlab.packet.IpPrefix;
19 import org.onosproject.net.ConnectPoint; 20 import org.onosproject.net.ConnectPoint;
20 21
21 import java.util.Map; 22 import java.util.Map;
...@@ -41,6 +42,22 @@ public interface RoutingConfigurationService { ...@@ -41,6 +42,22 @@ public interface RoutingConfigurationService {
41 public Map<IpAddress, BgpPeer> getBgpPeers(); 42 public Map<IpAddress, BgpPeer> getBgpPeers();
42 43
43 /** 44 /**
45 + * Evaluates whether an IP address belongs to local SDN network.
46 + *
47 + * @param ipAddress the IP address to evaluate
48 + * @return true if the IP address belongs to local SDN network, otherwise false
49 + */
50 + public boolean isIpAddressLocal(IpAddress ipAddress);
51 +
52 + /**
53 + * Evaluates whether an IP prefix belongs to local SDN network.
54 + *
55 + * @param ipPrefix the IP prefix to evaluate
56 + * @return true if the IP prefix belongs to local SDN network, otherwise false
57 + */
58 + public boolean isIpPrefixLocal(IpPrefix ipPrefix);
59 +
60 + /**
44 * Retrieves the entire set of interfaces in the network. 61 * Retrieves the entire set of interfaces in the network.
45 * 62 *
46 * @return the set of interfaces 63 * @return the set of interfaces
......
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
16 package org.onosproject.routing.config.impl; 16 package org.onosproject.routing.config.impl;
17 17
18 import com.fasterxml.jackson.annotation.JsonProperty; 18 import com.fasterxml.jackson.annotation.JsonProperty;
19 +
19 import org.onosproject.routing.config.BgpPeer; 20 import org.onosproject.routing.config.BgpPeer;
20 import org.onosproject.routing.config.BgpSpeaker; 21 import org.onosproject.routing.config.BgpSpeaker;
22 +import org.onosproject.routing.config.LocalIpPrefixEntry;
21 23
22 import java.util.Collections; 24 import java.util.Collections;
23 import java.util.List; 25 import java.util.List;
...@@ -32,6 +34,12 @@ public class Configuration { ...@@ -32,6 +34,12 @@ public class Configuration {
32 private List<BgpSpeaker> bgpSpeakers; 34 private List<BgpSpeaker> bgpSpeakers;
33 private List<BgpPeer> peers; 35 private List<BgpPeer> peers;
34 36
37 + // All IP prefixes from the configuration are local
38 + private List<LocalIpPrefixEntry> localIp4PrefixEntries =
39 + Collections.emptyList();
40 + private List<LocalIpPrefixEntry> localIp6PrefixEntries =
41 + Collections.emptyList();
42 +
35 /** 43 /**
36 * Default constructor. 44 * Default constructor.
37 */ 45 */
...@@ -78,4 +86,51 @@ public class Configuration { ...@@ -78,4 +86,51 @@ public class Configuration {
78 this.peers = peers; 86 this.peers = peers;
79 } 87 }
80 88
89 + /**
90 + * Gets a list of local IPv4 prefix entries configured for local
91 + * SDN network.
92 + * <p>
93 + * IP prefix entries are represented by {@link LocalIpPrefixEntry}
94 + * objects.
95 + * </p>
96 + *
97 + * @return the list of local IPv4 prefix entries
98 + */
99 + public List<LocalIpPrefixEntry> getLocalIp4PrefixEntries() {
100 + return Collections.unmodifiableList(localIp4PrefixEntries);
101 + }
102 +
103 + /**
104 + * Sets a list of IPv4 prefix entries configured for local SDN network.
105 + *
106 + * @param ip4PrefixEntries the list of Ipv4 prefix entries
107 + */
108 + @JsonProperty("ip4LocalPrefixes")
109 + public void setLocalIp4PrefixEntries(List<LocalIpPrefixEntry> ip4PrefixEntries) {
110 + this.localIp4PrefixEntries = ip4PrefixEntries;
111 + }
112 +
113 + /**
114 + * Gets a list of IPv6 prefix entries configured for local SDN network.
115 + * <p>
116 + * IP prefix entries are represented by {@link LocalIpPrefixEntry}
117 + * objects.
118 + * </p>
119 + *
120 + * @return the list of IPv6 prefix entries
121 + */
122 + public List<LocalIpPrefixEntry> getLocalIp6PrefixEntries() {
123 + return Collections.unmodifiableList(localIp6PrefixEntries);
124 + }
125 +
126 + /**
127 + * Sets a list of IPv6 prefix entries configured for local SDN network.
128 + *
129 + * @param ip6PrefixEntries the list of Ipv6 prefix entries
130 + */
131 + @JsonProperty("ip6LocalPrefixes")
132 + public void setLocalIp6PrefixEntries(List<LocalIpPrefixEntry> ip6PrefixEntries) {
133 + this.localIp6PrefixEntries = ip6PrefixEntries;
134 + }
135 +
81 } 136 }
......
...@@ -16,17 +16,25 @@ ...@@ -16,17 +16,25 @@
16 package org.onosproject.routing.config.impl; 16 package org.onosproject.routing.config.impl;
17 17
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 +import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
20 +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
21 +import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
22 +
19 import org.apache.felix.scr.annotations.Activate; 23 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 24 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Reference; 25 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality; 26 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service; 27 import org.apache.felix.scr.annotations.Service;
28 +import org.onlab.packet.Ip4Address;
29 +import org.onlab.packet.Ip6Address;
24 import org.onlab.packet.IpAddress; 30 import org.onlab.packet.IpAddress;
31 +import org.onlab.packet.IpPrefix;
25 import org.onosproject.net.ConnectPoint; 32 import org.onosproject.net.ConnectPoint;
26 import org.onosproject.net.host.HostService; 33 import org.onosproject.net.host.HostService;
27 import org.onosproject.routing.config.BgpPeer; 34 import org.onosproject.routing.config.BgpPeer;
28 import org.onosproject.routing.config.BgpSpeaker; 35 import org.onosproject.routing.config.BgpSpeaker;
29 import org.onosproject.routing.config.Interface; 36 import org.onosproject.routing.config.Interface;
37 +import org.onosproject.routing.config.LocalIpPrefixEntry;
30 import org.onosproject.routing.config.RoutingConfigurationService; 38 import org.onosproject.routing.config.RoutingConfigurationService;
31 import org.slf4j.Logger; 39 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory; 40 import org.slf4j.LoggerFactory;
...@@ -39,6 +47,8 @@ import java.util.Map; ...@@ -39,6 +47,8 @@ import java.util.Map;
39 import java.util.Set; 47 import java.util.Set;
40 import java.util.concurrent.ConcurrentHashMap; 48 import java.util.concurrent.ConcurrentHashMap;
41 49
50 +import static org.onosproject.routing.RouteEntry.createBinaryString;
51 +
42 /** 52 /**
43 * Implementation of RoutingConfigurationService which reads routing 53 * Implementation of RoutingConfigurationService which reads routing
44 * configuration from a file. 54 * configuration from a file.
...@@ -59,6 +69,13 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService { ...@@ -59,6 +69,13 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
59 private Map<String, BgpSpeaker> bgpSpeakers = new ConcurrentHashMap<>(); 69 private Map<String, BgpSpeaker> bgpSpeakers = new ConcurrentHashMap<>();
60 private Map<IpAddress, BgpPeer> bgpPeers = new ConcurrentHashMap<>(); 70 private Map<IpAddress, BgpPeer> bgpPeers = new ConcurrentHashMap<>();
61 71
72 + private InvertedRadixTree<LocalIpPrefixEntry>
73 + localPrefixTable4 = new ConcurrentInvertedRadixTree<>(
74 + new DefaultByteArrayNodeFactory());
75 + private InvertedRadixTree<LocalIpPrefixEntry>
76 + localPrefixTable6 = new ConcurrentInvertedRadixTree<>(
77 + new DefaultByteArrayNodeFactory());
78 +
62 private HostToInterfaceAdaptor hostAdaptor; 79 private HostToInterfaceAdaptor hostAdaptor;
63 80
64 @Activate 81 @Activate
...@@ -88,6 +105,16 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService { ...@@ -88,6 +105,16 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
88 for (BgpPeer peer : config.getPeers()) { 105 for (BgpPeer peer : config.getPeers()) {
89 bgpPeers.put(peer.ipAddress(), peer); 106 bgpPeers.put(peer.ipAddress(), peer);
90 } 107 }
108 +
109 + for (LocalIpPrefixEntry entry : config.getLocalIp4PrefixEntries()) {
110 + localPrefixTable4.put(createBinaryString(entry.ipPrefix()),
111 + entry);
112 + }
113 + for (LocalIpPrefixEntry entry : config.getLocalIp6PrefixEntries()) {
114 + localPrefixTable6.put(createBinaryString(entry.ipPrefix()),
115 + entry);
116 + }
117 +
91 } catch (FileNotFoundException e) { 118 } catch (FileNotFoundException e) {
92 log.warn("Configuration file not found: {}", configFileName); 119 log.warn("Configuration file not found: {}", configFileName);
93 } catch (IOException e) { 120 } catch (IOException e) {
...@@ -96,7 +123,8 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService { ...@@ -96,7 +123,8 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
96 } 123 }
97 124
98 /** 125 /**
99 - * Instructs the configuration reader to read the configuration from the file. 126 + * Instructs the configuration reader to read the configuration from the
127 + * file.
100 */ 128 */
101 public void readConfiguration() { 129 public void readConfiguration() {
102 readConfiguration(configFileName); 130 readConfiguration(configFileName);
...@@ -127,4 +155,27 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService { ...@@ -127,4 +155,27 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
127 return hostAdaptor.getMatchingInterface(ipAddress); 155 return hostAdaptor.getMatchingInterface(ipAddress);
128 } 156 }
129 157
158 + @Override
159 + public boolean isIpAddressLocal(IpAddress ipAddress) {
160 + if (ipAddress.isIp4()) {
161 + return localPrefixTable4.getValuesForKeysPrefixing(
162 + createBinaryString(
163 + IpPrefix.valueOf(ipAddress, Ip4Address.BIT_LENGTH)))
164 + .iterator().hasNext();
165 + } else {
166 + return localPrefixTable6.getValuesForKeysPrefixing(
167 + createBinaryString(
168 + IpPrefix.valueOf(ipAddress, Ip6Address.BIT_LENGTH)))
169 + .iterator().hasNext();
170 + }
171 + }
172 +
173 + @Override
174 + public boolean isIpPrefixLocal(IpPrefix ipPrefix) {
175 + return (localPrefixTable4.getValueForExactKey(
176 + createBinaryString(ipPrefix)) != null ||
177 + localPrefixTable6.getValueForExactKey(
178 + createBinaryString(ipPrefix)) != null);
179 + }
180 +
130 } 181 }
......
...@@ -36,9 +36,12 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -36,9 +36,12 @@ import org.apache.felix.scr.annotations.Deactivate;
36 import org.apache.felix.scr.annotations.Reference; 36 import org.apache.felix.scr.annotations.Reference;
37 import org.apache.felix.scr.annotations.ReferenceCardinality; 37 import org.apache.felix.scr.annotations.ReferenceCardinality;
38 import org.apache.felix.scr.annotations.Service; 38 import org.apache.felix.scr.annotations.Service;
39 +import org.onlab.packet.Ip4Address;
40 +import org.onlab.packet.Ip6Address;
39 import org.onlab.packet.IpAddress; 41 import org.onlab.packet.IpAddress;
40 import org.onlab.packet.IpPrefix; 42 import org.onlab.packet.IpPrefix;
41 import org.onlab.packet.MacAddress; 43 import org.onlab.packet.MacAddress;
44 +import org.onosproject.net.ConnectPoint;
42 import org.onosproject.net.Host; 45 import org.onosproject.net.Host;
43 import org.onosproject.net.host.HostEvent; 46 import org.onosproject.net.host.HostEvent;
44 import org.onosproject.net.host.HostListener; 47 import org.onosproject.net.host.HostListener;
...@@ -47,10 +50,13 @@ import org.onosproject.routing.BgpService; ...@@ -47,10 +50,13 @@ import org.onosproject.routing.BgpService;
47 import org.onosproject.routing.FibEntry; 50 import org.onosproject.routing.FibEntry;
48 import org.onosproject.routing.FibListener; 51 import org.onosproject.routing.FibListener;
49 import org.onosproject.routing.FibUpdate; 52 import org.onosproject.routing.FibUpdate;
53 +import org.onosproject.routing.IntentRequestListener;
50 import org.onosproject.routing.RouteEntry; 54 import org.onosproject.routing.RouteEntry;
51 import org.onosproject.routing.RouteListener; 55 import org.onosproject.routing.RouteListener;
52 import org.onosproject.routing.RouteUpdate; 56 import org.onosproject.routing.RouteUpdate;
53 import org.onosproject.routing.RoutingService; 57 import org.onosproject.routing.RoutingService;
58 +import org.onosproject.routing.config.Interface;
59 +import org.onosproject.routing.config.RoutingConfigurationService;
54 import org.slf4j.Logger; 60 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory; 61 import org.slf4j.LoggerFactory;
56 62
...@@ -63,6 +69,8 @@ import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFa ...@@ -63,6 +69,8 @@ import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFa
63 import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; 69 import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
64 import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; 70 import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
65 71
72 +import static org.onosproject.routing.RouteEntry.createBinaryString;
73 +
66 /** 74 /**
67 * This class processes route updates and maintains a Routing Information Base 75 * This class processes route updates and maintains a Routing Information Base
68 * (RIB). After route updates have been processed and next hops have been 76 * (RIB). After route updates have been processed and next hops have been
...@@ -80,16 +88,18 @@ public class Router implements RoutingService { ...@@ -80,16 +88,18 @@ public class Router implements RoutingService {
80 private InvertedRadixTree<RouteEntry> ribTable6; 88 private InvertedRadixTree<RouteEntry> ribTable6;
81 89
82 // Stores all incoming route updates in a queue. 90 // Stores all incoming route updates in a queue.
83 - private final BlockingQueue<Collection<RouteUpdate>> routeUpdatesQueue 91 + private final BlockingQueue<Collection<RouteUpdate>> routeUpdatesQueue =
84 - = new LinkedBlockingQueue<>(); 92 + new LinkedBlockingQueue<>();
85 93
86 - // Next-hop IP address to route entry mapping for next hops pending MAC resolution 94 + // Next-hop IP address to route entry mapping for next hops pending MAC
95 + // resolution
87 private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp; 96 private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
88 97
89 // The IPv4 address to MAC address mapping 98 // The IPv4 address to MAC address mapping
90 private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>(); 99 private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>();
91 100
92 private FibListener fibComponent; 101 private FibListener fibComponent;
102 + private IntentRequestListener intentRequestListener;
93 103
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected HostService hostService; 105 protected HostService hostService;
...@@ -97,6 +107,9 @@ public class Router implements RoutingService { ...@@ -97,6 +107,9 @@ public class Router implements RoutingService {
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected BgpService bgpService; 108 protected BgpService bgpService;
99 109
110 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 + protected RoutingConfigurationService routingConfigurationService;
112 +
100 private ExecutorService bgpUpdatesExecutor; 113 private ExecutorService bgpUpdatesExecutor;
101 private final HostListener hostListener = new InternalHostListener(); 114 private final HostListener hostListener = new InternalHostListener();
102 115
...@@ -106,6 +119,7 @@ public class Router implements RoutingService { ...@@ -106,6 +119,7 @@ public class Router implements RoutingService {
106 new DefaultByteArrayNodeFactory()); 119 new DefaultByteArrayNodeFactory());
107 ribTable6 = new ConcurrentInvertedRadixTree<>( 120 ribTable6 = new ConcurrentInvertedRadixTree<>(
108 new DefaultByteArrayNodeFactory()); 121 new DefaultByteArrayNodeFactory());
122 +
109 routesWaitingOnArp = Multimaps.synchronizedSetMultimap( 123 routesWaitingOnArp = Multimaps.synchronizedSetMultimap(
110 HashMultimap.<IpAddress, RouteEntry>create()); 124 HashMultimap.<IpAddress, RouteEntry>create());
111 125
...@@ -120,8 +134,18 @@ public class Router implements RoutingService { ...@@ -120,8 +134,18 @@ public class Router implements RoutingService {
120 } 134 }
121 135
122 @Override 136 @Override
123 - public void start(FibListener listener) { 137 + public void addFibListener(FibListener fibListener) {
124 - this.fibComponent = checkNotNull(listener); 138 + this.fibComponent = checkNotNull(fibListener);
139 +
140 + }
141 +
142 + @Override
143 + public void addIntentRequestListener(IntentRequestListener intentRequestListener) {
144 + this.intentRequestListener = checkNotNull(intentRequestListener);
145 + }
146 +
147 + @Override
148 + public void start() {
125 this.hostService.addListener(hostListener); 149 this.hostService.addListener(hostListener);
126 150
127 bgpService.start(new InternalRouteListener()); 151 bgpService.start(new InternalRouteListener());
...@@ -146,9 +170,9 @@ public class Router implements RoutingService { ...@@ -146,9 +170,9 @@ public class Router implements RoutingService {
146 synchronized (this) { 170 synchronized (this) {
147 // Cleanup all local state 171 // Cleanup all local state
148 ribTable4 = new ConcurrentInvertedRadixTree<>( 172 ribTable4 = new ConcurrentInvertedRadixTree<>(
149 - new DefaultByteArrayNodeFactory()); 173 + new DefaultByteArrayNodeFactory());
150 ribTable6 = new ConcurrentInvertedRadixTree<>( 174 ribTable6 = new ConcurrentInvertedRadixTree<>(
151 - new DefaultByteArrayNodeFactory()); 175 + new DefaultByteArrayNodeFactory());
152 routeUpdatesQueue.clear(); 176 routeUpdatesQueue.clear();
153 routesWaitingOnArp.clear(); 177 routesWaitingOnArp.clear();
154 ip2Mac.clear(); 178 ip2Mac.clear();
...@@ -178,7 +202,7 @@ public class Router implements RoutingService { ...@@ -178,7 +202,7 @@ public class Router implements RoutingService {
178 while (!interrupted) { 202 while (!interrupted) {
179 try { 203 try {
180 Collection<RouteUpdate> routeUpdates = 204 Collection<RouteUpdate> routeUpdates =
181 - routeUpdatesQueue.take(); 205 + routeUpdatesQueue.take();
182 processRouteUpdates(routeUpdates); 206 processRouteUpdates(routeUpdates);
183 } catch (InterruptedException e) { 207 } catch (InterruptedException e) {
184 log.error("Interrupted while taking from updates queue", e); 208 log.error("Interrupted while taking from updates queue", e);
...@@ -202,7 +226,7 @@ public class Router implements RoutingService { ...@@ -202,7 +226,7 @@ public class Router implements RoutingService {
202 @Override 226 @Override
203 public Collection<RouteEntry> getRoutes4() { 227 public Collection<RouteEntry> getRoutes4() {
204 Iterator<KeyValuePair<RouteEntry>> it = 228 Iterator<KeyValuePair<RouteEntry>> it =
205 - ribTable4.getKeyValuePairsForKeysStartingWith("").iterator(); 229 + ribTable4.getKeyValuePairsForKeysStartingWith("").iterator();
206 230
207 List<RouteEntry> routes = new LinkedList<>(); 231 List<RouteEntry> routes = new LinkedList<>();
208 232
...@@ -222,7 +246,7 @@ public class Router implements RoutingService { ...@@ -222,7 +246,7 @@ public class Router implements RoutingService {
222 @Override 246 @Override
223 public Collection<RouteEntry> getRoutes6() { 247 public Collection<RouteEntry> getRoutes6() {
224 Iterator<KeyValuePair<RouteEntry>> it = 248 Iterator<KeyValuePair<RouteEntry>> it =
225 - ribTable6.getKeyValuePairsForKeysStartingWith("").iterator(); 249 + ribTable6.getKeyValuePairsForKeysStartingWith("").iterator();
226 250
227 List<RouteEntry> routes = new LinkedList<>(); 251 List<RouteEntry> routes = new LinkedList<>();
228 252
...@@ -242,7 +266,7 @@ public class Router implements RoutingService { ...@@ -242,7 +266,7 @@ public class Router implements RoutingService {
242 * @return the route if found, otherwise null 266 * @return the route if found, otherwise null
243 */ 267 */
244 RouteEntry findRibRoute(IpPrefix prefix) { 268 RouteEntry findRibRoute(IpPrefix prefix) {
245 - String binaryString = RouteEntry.createBinaryString(prefix); 269 + String binaryString = createBinaryString(prefix);
246 if (prefix.isIp4()) { 270 if (prefix.isIp4()) {
247 // IPv4 271 // IPv4
248 return ribTable4.getValueForExactKey(binaryString); 272 return ribTable4.getValueForExactKey(binaryString);
...@@ -259,12 +283,12 @@ public class Router implements RoutingService { ...@@ -259,12 +283,12 @@ public class Router implements RoutingService {
259 void addRibRoute(RouteEntry routeEntry) { 283 void addRibRoute(RouteEntry routeEntry) {
260 if (routeEntry.isIp4()) { 284 if (routeEntry.isIp4()) {
261 // IPv4 285 // IPv4
262 - ribTable4.put(RouteEntry.createBinaryString(routeEntry.prefix()), 286 + ribTable4.put(createBinaryString(routeEntry.prefix()),
263 - routeEntry); 287 + routeEntry);
264 } else { 288 } else {
265 // IPv6 289 // IPv6
266 - ribTable6.put(RouteEntry.createBinaryString(routeEntry.prefix()), 290 + ribTable6.put(createBinaryString(routeEntry.prefix()),
267 - routeEntry); 291 + routeEntry);
268 } 292 }
269 } 293 }
270 294
...@@ -278,10 +302,10 @@ public class Router implements RoutingService { ...@@ -278,10 +302,10 @@ public class Router implements RoutingService {
278 boolean removeRibRoute(IpPrefix prefix) { 302 boolean removeRibRoute(IpPrefix prefix) {
279 if (prefix.isIp4()) { 303 if (prefix.isIp4()) {
280 // IPv4 304 // IPv4
281 - return ribTable4.remove(RouteEntry.createBinaryString(prefix)); 305 + return ribTable4.remove(createBinaryString(prefix));
282 } 306 }
283 // IPv6 307 // IPv6
284 - return ribTable6.remove(RouteEntry.createBinaryString(prefix)); 308 + return ribTable6.remove(createBinaryString(prefix));
285 } 309 }
286 310
287 /** 311 /**
...@@ -298,8 +322,9 @@ public class Router implements RoutingService { ...@@ -298,8 +322,9 @@ public class Router implements RoutingService {
298 for (RouteUpdate update : routeUpdates) { 322 for (RouteUpdate update : routeUpdates) {
299 switch (update.type()) { 323 switch (update.type()) {
300 case UPDATE: 324 case UPDATE:
325 +
301 FibEntry fib = processRouteAdd(update.routeEntry(), 326 FibEntry fib = processRouteAdd(update.routeEntry(),
302 - withdrawPrefixes); 327 + withdrawPrefixes);
303 if (fib != null) { 328 if (fib != null) {
304 fibUpdates.add(new FibUpdate(FibUpdate.Type.UPDATE, fib)); 329 fibUpdates.add(new FibUpdate(FibUpdate.Type.UPDATE, fib));
305 } 330 }
...@@ -341,9 +366,8 @@ public class Router implements RoutingService { ...@@ -341,9 +366,8 @@ public class Router implements RoutingService {
341 * intents will be withdrawn 366 * intents will be withdrawn
342 * @return the corresponding FIB entry change, or null 367 * @return the corresponding FIB entry change, or null
343 */ 368 */
344 - private FibEntry processRouteAdd( 369 + private FibEntry processRouteAdd(RouteEntry routeEntry,
345 - RouteEntry routeEntry, 370 + Collection<IpPrefix> withdrawPrefixes) {
346 - Collection<IpPrefix> withdrawPrefixes) {
347 log.debug("Processing route add: {}", routeEntry); 371 log.debug("Processing route add: {}", routeEntry);
348 372
349 // Find the old next-hop if we are updating an old route entry 373 // Find the old next-hop if we are updating an old route entry
...@@ -368,11 +392,12 @@ public class Router implements RoutingService { ...@@ -368,11 +392,12 @@ public class Router implements RoutingService {
368 withdrawPrefixes.add(routeEntry.prefix()); 392 withdrawPrefixes.add(routeEntry.prefix());
369 } 393 }
370 394
371 - if (routeEntry.nextHop().isZero()) { 395 + if (routingConfigurationService.isIpPrefixLocal(routeEntry.prefix())) {
372 - // Route originated by SDN domain 396 + // Route originated by local SDN domain
373 - // We don't handle these at the moment 397 + // We don't handle these here, reactive routing APP will handle
398 + // these
374 log.debug("Own route {} to {}", 399 log.debug("Own route {} to {}",
375 - routeEntry.prefix(), routeEntry.nextHop()); 400 + routeEntry.prefix(), routeEntry.nextHop());
376 return null; 401 return null;
377 } 402 }
378 403
...@@ -402,7 +427,7 @@ public class Router implements RoutingService { ...@@ -402,7 +427,7 @@ public class Router implements RoutingService {
402 return null; 427 return null;
403 } 428 }
404 return new FibEntry(routeEntry.prefix(), routeEntry.nextHop(), 429 return new FibEntry(routeEntry.prefix(), routeEntry.nextHop(),
405 - nextHopMacAddress); 430 + nextHopMacAddress);
406 } 431 }
407 432
408 /** 433 /**
...@@ -446,7 +471,7 @@ public class Router implements RoutingService { ...@@ -446,7 +471,7 @@ public class Router implements RoutingService {
446 */ 471 */
447 private void updateMac(IpAddress ipAddress, MacAddress macAddress) { 472 private void updateMac(IpAddress ipAddress, MacAddress macAddress) {
448 log.debug("Received updated MAC info: {} => {}", ipAddress, 473 log.debug("Received updated MAC info: {} => {}", ipAddress,
449 - macAddress); 474 + macAddress);
450 475
451 // 476 //
452 // We synchronize on "this" to prevent changes to the Radix tree 477 // We synchronize on "this" to prevent changes to the Radix tree
...@@ -457,23 +482,23 @@ public class Router implements RoutingService { ...@@ -457,23 +482,23 @@ public class Router implements RoutingService {
457 Collection<FibUpdate> submitFibEntries = new LinkedList<>(); 482 Collection<FibUpdate> submitFibEntries = new LinkedList<>();
458 483
459 Set<RouteEntry> routesToPush = 484 Set<RouteEntry> routesToPush =
460 - routesWaitingOnArp.removeAll(ipAddress); 485 + routesWaitingOnArp.removeAll(ipAddress);
461 486
462 for (RouteEntry routeEntry : routesToPush) { 487 for (RouteEntry routeEntry : routesToPush) {
463 // These will always be adds 488 // These will always be adds
464 RouteEntry foundRouteEntry = findRibRoute(routeEntry.prefix()); 489 RouteEntry foundRouteEntry = findRibRoute(routeEntry.prefix());
465 if (foundRouteEntry != null && 490 if (foundRouteEntry != null &&
466 - foundRouteEntry.nextHop().equals(routeEntry.nextHop())) { 491 + foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
467 // We only push FIB updates if the prefix is still in the 492 // We only push FIB updates if the prefix is still in the
468 // radix tree and the next hop is the same as our entry. 493 // radix tree and the next hop is the same as our entry.
469 // The prefix could have been removed while we were waiting 494 // The prefix could have been removed while we were waiting
470 // for the ARP, or the next hop could have changed. 495 // for the ARP, or the next hop could have changed.
471 submitFibEntries.add(new FibUpdate(FibUpdate.Type.UPDATE, 496 submitFibEntries.add(new FibUpdate(FibUpdate.Type.UPDATE,
472 - new FibEntry(routeEntry.prefix(), 497 + new FibEntry(routeEntry.prefix(),
473 - ipAddress, macAddress))); 498 + ipAddress, macAddress)));
474 } else { 499 } else {
475 log.debug("{} has been revoked before the MAC was resolved", 500 log.debug("{} has been revoked before the MAC was resolved",
476 - routeEntry); 501 + routeEntry);
477 } 502 }
478 } 503 }
479 504
...@@ -522,4 +547,179 @@ public class Router implements RoutingService { ...@@ -522,4 +547,179 @@ public class Router implements RoutingService {
522 Router.this.update(routeUpdates); 547 Router.this.update(routeUpdates);
523 } 548 }
524 } 549 }
550 +
551 + @Override
552 + public LocationType getLocationType(IpAddress ipAddress) {
553 + if (routingConfigurationService.isIpAddressLocal(ipAddress)) {
554 + return LocationType.LOCAL;
555 + } else if (getLongestMatchableRouteEntry(ipAddress) != null) {
556 + return LocationType.INTERNET;
557 + } else {
558 + return LocationType.NO_ROUTE;
559 + }
560 + }
561 +
562 + @Override
563 + public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) {
564 + RouteEntry routeEntry = null;
565 + Iterable<RouteEntry> routeEntries;
566 +
567 + if (ipAddress.isIp4()) {
568 + routeEntries = ribTable4.getValuesForKeysPrefixing(
569 + createBinaryString(
570 + IpPrefix.valueOf(ipAddress, Ip4Address.BIT_LENGTH)));
571 + } else {
572 + routeEntries = ribTable6.getValuesForKeysPrefixing(
573 + createBinaryString(
574 + IpPrefix.valueOf(ipAddress, Ip6Address.BIT_LENGTH)));
575 + }
576 + if (routeEntries == null) {
577 + return null;
578 + }
579 + Iterator<RouteEntry> it = routeEntries.iterator();
580 + while (it.hasNext()) {
581 + routeEntry = it.next();
582 + }
583 + return routeEntry;
584 + }
585 +
586 + @Override
587 + public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) {
588 + LocationType type = getLocationType(dstIpAddress);
589 + if (type == LocationType.LOCAL) {
590 + Set<Host> hosts = hostService.getHostsByIp(dstIpAddress);
591 + if (!hosts.isEmpty()) {
592 + return hosts.iterator().next().location();
593 + } else {
594 + hostService.startMonitoringIp(dstIpAddress);
595 + return null;
596 + }
597 + } else if (type == LocationType.INTERNET) {
598 + IpAddress nextHopIpAddress = null;
599 + RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress);
600 + if (routeEntry != null) {
601 + nextHopIpAddress = routeEntry.nextHop();
602 + Interface it = routingConfigurationService
603 + .getMatchingInterface(nextHopIpAddress);
604 + if (it != null) {
605 + return it.connectPoint();
606 + } else {
607 + return null;
608 + }
609 + } else {
610 + return null;
611 + }
612 + } else {
613 + return null;
614 + }
615 + }
616 +
617 + @Override
618 + public void packetReactiveProcessor(IpAddress dstIpAddress,
619 + IpAddress srcIpAddress,
620 + ConnectPoint srcConnectPoint,
621 + MacAddress srcMacAddress) {
622 + checkNotNull(dstIpAddress);
623 + checkNotNull(srcIpAddress);
624 + checkNotNull(srcConnectPoint);
625 + checkNotNull(srcMacAddress);
626 +
627 + //
628 + // Step1: Try to update the existing intent first if it exists.
629 + //
630 + IpPrefix ipPrefix = null;
631 + if (routingConfigurationService.isIpAddressLocal(dstIpAddress)) {
632 + if (dstIpAddress.isIp4()) {
633 + ipPrefix = IpPrefix.valueOf(dstIpAddress,
634 + Ip4Address.BIT_LENGTH);
635 + } else {
636 + ipPrefix = IpPrefix.valueOf(dstIpAddress,
637 + Ip6Address.BIT_LENGTH);
638 + }
639 + } else {
640 + // Get IP prefix from BGP route table
641 + RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress);
642 + if (routeEntry != null) {
643 + ipPrefix = routeEntry.prefix();
644 + }
645 + }
646 + if (ipPrefix != null
647 + && intentRequestListener.mp2pIntentExists(ipPrefix)) {
648 + intentRequestListener.updateExistingMp2pIntent(ipPrefix,
649 + srcConnectPoint);
650 + return;
651 + }
652 +
653 + //
654 + // Step2: There is no existing intent for the destination IP address.
655 + // Check whether it is necessary to create a new one. If necessary then
656 + // create a new one.
657 + //
658 + TrafficType trafficType =
659 + trafficTypeClassifier(srcConnectPoint, dstIpAddress);
660 +
661 + switch (trafficType) {
662 + case HOST_TO_INTERNET:
663 + // If the destination IP address is outside the local SDN network.
664 + // The Step 1 has already handled it. We do not need to do anything here.
665 + break;
666 + case INTERNET_TO_HOST:
667 + intentRequestListener.setUpConnectivityInternetToHost(dstIpAddress);
668 + break;
669 + case HOST_TO_HOST:
670 + intentRequestListener.setUpConnectivityHostToHost(dstIpAddress,
671 + srcIpAddress, srcMacAddress, srcConnectPoint);
672 + break;
673 + case INTERNET_TO_INTERNET:
674 + log.trace("This is transit traffic, "
675 + + "the intent should be preinstalled already");
676 + break;
677 + case DROP:
678 + // TODO here should setUpDropPaccketIntent(...);
679 + // We need a new type of intent here.
680 + break;
681 + case UNKNOWN:
682 + log.trace("This is unknown traffic, so we do nothing");
683 + break;
684 + default:
685 + break;
686 + }
687 + }
688 +
689 + /**
690 + * Classifies the traffic and return the traffic type.
691 + *
692 + * @param srcConnectPoint the connect point where the packet comes from
693 + * @param dstIp the destination IP address in packet
694 + * @return the traffic type which this packet belongs to
695 + */
696 + private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint,
697 + IpAddress dstIp) {
698 + LocationType dstIpLocationType = getLocationType(dstIp);
699 + Interface srcInterface =
700 + routingConfigurationService.getInterface(srcConnectPoint);
701 +
702 + switch (dstIpLocationType) {
703 + case INTERNET:
704 + if (srcInterface == null) {
705 + return TrafficType.HOST_TO_INTERNET;
706 + } else {
707 + return TrafficType.INTERNET_TO_INTERNET;
708 + }
709 + case LOCAL:
710 + if (srcInterface == null) {
711 + return TrafficType.HOST_TO_HOST;
712 + } else {
713 + // TODO Currently we only consider local public prefixes.
714 + // In the future, we will consider the local private prefixes.
715 + // If dstIpLocationType is a local private, we should return
716 + // TrafficType.DROP.
717 + return TrafficType.INTERNET_TO_HOST;
718 + }
719 + case NO_ROUTE:
720 + return TrafficType.DROP;
721 + default:
722 + return TrafficType.UNKNOWN;
723 + }
724 + }
525 } 725 }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.routing.impl; 16 package org.onosproject.routing.impl;
17 17
18 import com.google.common.collect.Sets; 18 import com.google.common.collect.Sets;
19 +
19 import org.junit.After; 20 import org.junit.After;
20 import org.junit.Before; 21 import org.junit.Before;
21 import org.junit.Test; 22 import org.junit.Test;
...@@ -36,6 +37,7 @@ import org.onosproject.net.host.HostEvent; ...@@ -36,6 +37,7 @@ import org.onosproject.net.host.HostEvent;
36 import org.onosproject.net.host.HostListener; 37 import org.onosproject.net.host.HostListener;
37 import org.onosproject.net.host.HostService; 38 import org.onosproject.net.host.HostService;
38 import org.onosproject.net.provider.ProviderId; 39 import org.onosproject.net.provider.ProviderId;
40 +import org.onosproject.routing.config.RoutingConfigurationService;
39 import org.onosproject.routing.impl.Router.InternalHostListener; 41 import org.onosproject.routing.impl.Router.InternalHostListener;
40 import org.onosproject.routing.BgpService; 42 import org.onosproject.routing.BgpService;
41 import org.onosproject.routing.FibEntry; 43 import org.onosproject.routing.FibEntry;
...@@ -57,6 +59,7 @@ public class RouterAsyncArpTest { ...@@ -57,6 +59,7 @@ public class RouterAsyncArpTest {
57 59
58 private HostService hostService; 60 private HostService hostService;
59 private FibListener fibListener; 61 private FibListener fibListener;
62 + private RoutingConfigurationService routingConfigurationService;
60 63
61 private static final ConnectPoint SW1_ETH1 = new ConnectPoint( 64 private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
62 DeviceId.deviceId("of:0000000000000001"), 65 DeviceId.deviceId("of:0000000000000001"),
...@@ -76,6 +79,8 @@ public class RouterAsyncArpTest { ...@@ -76,6 +79,8 @@ public class RouterAsyncArpTest {
76 @Before 79 @Before
77 public void setUp() throws Exception { 80 public void setUp() throws Exception {
78 hostService = createMock(HostService.class); 81 hostService = createMock(HostService.class);
82 + routingConfigurationService =
83 + createMock(RoutingConfigurationService.class);
79 84
80 BgpService bgpService = createMock(BgpService.class); 85 BgpService bgpService = createMock(BgpService.class);
81 bgpService.start(anyObject(RouteListener.class)); 86 bgpService.start(anyObject(RouteListener.class));
...@@ -86,10 +91,12 @@ public class RouterAsyncArpTest { ...@@ -86,10 +91,12 @@ public class RouterAsyncArpTest {
86 91
87 router = new Router(); 92 router = new Router();
88 router.hostService = hostService; 93 router.hostService = hostService;
94 + router.routingConfigurationService = routingConfigurationService;
89 router.bgpService = bgpService; 95 router.bgpService = bgpService;
90 router.activate(); 96 router.activate();
91 97
92 - router.start(fibListener); 98 + router.addFibListener(fibListener);
99 + router.start();
93 100
94 internalHostListener = router.new InternalHostListener(); 101 internalHostListener = router.new InternalHostListener();
95 } 102 }
...@@ -121,6 +128,10 @@ public class RouterAsyncArpTest { ...@@ -121,6 +128,10 @@ public class RouterAsyncArpTest {
121 hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1")); 128 hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1"));
122 replay(hostService); 129 replay(hostService);
123 130
131 + reset(routingConfigurationService);
132 + expect(routingConfigurationService.isIpPrefixLocal(
133 + anyObject(IpPrefix.class))).andReturn(false);
134 + replay(routingConfigurationService);
124 135
125 // Initially when we add the route, no FIB update will be sent 136 // Initially when we add the route, no FIB update will be sent
126 replay(fibListener); 137 replay(fibListener);
...@@ -175,6 +186,10 @@ public class RouterAsyncArpTest { ...@@ -175,6 +186,10 @@ public class RouterAsyncArpTest {
175 hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1")); 186 hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1"));
176 replay(hostService); 187 replay(hostService);
177 188
189 + reset(routingConfigurationService);
190 + expect(routingConfigurationService.isIpPrefixLocal(
191 + anyObject(IpPrefix.class))).andReturn(false);
192 + replay(routingConfigurationService);
178 193
179 // Initially when we add the route, the DELETE FIB update will be sent 194 // Initially when we add the route, the DELETE FIB update will be sent
180 // but the UPDATE FIB update will come later when the MAC is resolved 195 // but the UPDATE FIB update will come later when the MAC is resolved
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.routing.impl; 16 package org.onosproject.routing.impl;
17 17
18 import com.google.common.collect.Sets; 18 import com.google.common.collect.Sets;
19 +
19 import org.junit.After; 20 import org.junit.After;
20 import org.junit.Before; 21 import org.junit.Before;
21 import org.junit.Test; 22 import org.junit.Test;
...@@ -42,6 +43,7 @@ import org.onosproject.routing.FibUpdate; ...@@ -42,6 +43,7 @@ import org.onosproject.routing.FibUpdate;
42 import org.onosproject.routing.RouteEntry; 43 import org.onosproject.routing.RouteEntry;
43 import org.onosproject.routing.RouteListener; 44 import org.onosproject.routing.RouteListener;
44 import org.onosproject.routing.RouteUpdate; 45 import org.onosproject.routing.RouteUpdate;
46 +import org.onosproject.routing.config.RoutingConfigurationService;
45 47
46 import java.util.Collections; 48 import java.util.Collections;
47 49
...@@ -58,6 +60,7 @@ import static org.junit.Assert.assertTrue; ...@@ -58,6 +60,7 @@ import static org.junit.Assert.assertTrue;
58 public class RouterTest { 60 public class RouterTest {
59 61
60 private HostService hostService; 62 private HostService hostService;
63 + private RoutingConfigurationService routingConfigurationService;
61 64
62 private FibListener fibListener; 65 private FibListener fibListener;
63 66
...@@ -82,6 +85,8 @@ public class RouterTest { ...@@ -82,6 +85,8 @@ public class RouterTest {
82 @Before 85 @Before
83 public void setUp() throws Exception { 86 public void setUp() throws Exception {
84 setUpHostService(); 87 setUpHostService();
88 + routingConfigurationService =
89 + createMock(RoutingConfigurationService.class);
85 90
86 BgpService bgpService = createMock(BgpService.class); 91 BgpService bgpService = createMock(BgpService.class);
87 bgpService.start(anyObject(RouteListener.class)); 92 bgpService.start(anyObject(RouteListener.class));
...@@ -92,10 +97,12 @@ public class RouterTest { ...@@ -92,10 +97,12 @@ public class RouterTest {
92 97
93 router = new Router(); 98 router = new Router();
94 router.hostService = hostService; 99 router.hostService = hostService;
100 + router.routingConfigurationService = routingConfigurationService;
95 router.bgpService = bgpService; 101 router.bgpService = bgpService;
96 router.activate(); 102 router.activate();
97 103
98 - router.start(fibListener); 104 + router.addFibListener(fibListener);
105 + router.start();
99 } 106 }
100 107
101 @After 108 @After
...@@ -207,9 +214,13 @@ public class RouterTest { ...@@ -207,9 +214,13 @@ public class RouterTest {
207 FibUpdate.Type.UPDATE, updateFibEntry)), 214 FibUpdate.Type.UPDATE, updateFibEntry)),
208 Collections.singletonList(new FibUpdate( 215 Collections.singletonList(new FibUpdate(
209 FibUpdate.Type.DELETE, withdrawFibEntry))); 216 FibUpdate.Type.DELETE, withdrawFibEntry)));
210 -
211 replay(fibListener); 217 replay(fibListener);
212 218
219 + reset(routingConfigurationService);
220 + expect(routingConfigurationService.isIpPrefixLocal(
221 + anyObject(IpPrefix.class))).andReturn(false);
222 + replay(routingConfigurationService);
223 +
213 router.processRouteUpdates(Collections.singletonList(new RouteUpdate( 224 router.processRouteUpdates(Collections.singletonList(new RouteUpdate(
214 RouteUpdate.Type.UPDATE, routeEntryUpdate))); 225 RouteUpdate.Type.UPDATE, routeEntryUpdate)));
215 226
...@@ -256,6 +267,11 @@ public class RouterTest { ...@@ -256,6 +267,11 @@ public class RouterTest {
256 // No methods on the FIB listener should be called 267 // No methods on the FIB listener should be called
257 replay(fibListener); 268 replay(fibListener);
258 269
270 + reset(routingConfigurationService);
271 + expect(routingConfigurationService.isIpPrefixLocal(
272 + anyObject(IpPrefix.class))).andReturn(true);
273 + replay(routingConfigurationService);
274 +
259 // Call the processRouteUpdates() method in Router class 275 // Call the processRouteUpdates() method in Router class
260 RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE, 276 RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
261 routeEntry); 277 routeEntry);
......
...@@ -35,12 +35,14 @@ import org.onlab.packet.MacAddress; ...@@ -35,12 +35,14 @@ import org.onlab.packet.MacAddress;
35 import org.onlab.packet.VlanId; 35 import org.onlab.packet.VlanId;
36 import org.onosproject.core.ApplicationId; 36 import org.onosproject.core.ApplicationId;
37 import org.onosproject.net.ConnectPoint; 37 import org.onosproject.net.ConnectPoint;
38 +import org.onosproject.net.Host;
38 import org.onosproject.net.flow.DefaultTrafficSelector; 39 import org.onosproject.net.flow.DefaultTrafficSelector;
39 import org.onosproject.net.flow.DefaultTrafficTreatment; 40 import org.onosproject.net.flow.DefaultTrafficTreatment;
40 import org.onosproject.net.flow.TrafficSelector; 41 import org.onosproject.net.flow.TrafficSelector;
41 import org.onosproject.net.flow.TrafficTreatment; 42 import org.onosproject.net.flow.TrafficTreatment;
42 import org.onosproject.net.flow.criteria.Criteria.IPCriterion; 43 import org.onosproject.net.flow.criteria.Criteria.IPCriterion;
43 import org.onosproject.net.flow.criteria.Criterion; 44 import org.onosproject.net.flow.criteria.Criterion;
45 +import org.onosproject.net.host.HostService;
44 import org.onosproject.net.intent.Intent; 46 import org.onosproject.net.intent.Intent;
45 import org.onosproject.net.intent.IntentService; 47 import org.onosproject.net.intent.IntentService;
46 import org.onosproject.net.intent.IntentState; 48 import org.onosproject.net.intent.IntentState;
...@@ -49,6 +51,7 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent; ...@@ -49,6 +51,7 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent;
49 import org.onosproject.net.intent.PointToPointIntent; 51 import org.onosproject.net.intent.PointToPointIntent;
50 import org.onosproject.routing.FibListener; 52 import org.onosproject.routing.FibListener;
51 import org.onosproject.routing.FibUpdate; 53 import org.onosproject.routing.FibUpdate;
54 +import org.onosproject.routing.IntentRequestListener;
52 import org.onosproject.routing.config.BgpPeer; 55 import org.onosproject.routing.config.BgpPeer;
53 import org.onosproject.routing.config.Interface; 56 import org.onosproject.routing.config.Interface;
54 import org.onosproject.routing.config.RoutingConfigurationService; 57 import org.onosproject.routing.config.RoutingConfigurationService;
...@@ -58,12 +61,13 @@ import org.slf4j.LoggerFactory; ...@@ -58,12 +61,13 @@ import org.slf4j.LoggerFactory;
58 import com.google.common.util.concurrent.ThreadFactoryBuilder; 61 import com.google.common.util.concurrent.ThreadFactoryBuilder;
59 62
60 import static com.google.common.base.Preconditions.checkArgument; 63 import static com.google.common.base.Preconditions.checkArgument;
64 +import static com.google.common.base.Preconditions.checkNotNull;
61 65
62 /** 66 /**
63 * Synchronizes intents between the in-memory intent store and the 67 * Synchronizes intents between the in-memory intent store and the
64 * IntentService. 68 * IntentService.
65 */ 69 */
66 -public class IntentSynchronizer implements FibListener { 70 +public class IntentSynchronizer implements FibListener, IntentRequestListener {
67 private static final int PRIORITY_OFFSET = 100; 71 private static final int PRIORITY_OFFSET = 100;
68 private static final int PRIORITY_MULTIPLIER = 5; 72 private static final int PRIORITY_MULTIPLIER = 5;
69 73
...@@ -72,6 +76,7 @@ public class IntentSynchronizer implements FibListener { ...@@ -72,6 +76,7 @@ public class IntentSynchronizer implements FibListener {
72 76
73 private final ApplicationId appId; 77 private final ApplicationId appId;
74 private final IntentService intentService; 78 private final IntentService intentService;
79 + private final HostService hostService;
75 private final Map<IntentKey, PointToPointIntent> peerIntents; 80 private final Map<IntentKey, PointToPointIntent> peerIntents;
76 private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents; 81 private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents;
77 82
...@@ -90,12 +95,15 @@ public class IntentSynchronizer implements FibListener { ...@@ -90,12 +95,15 @@ public class IntentSynchronizer implements FibListener {
90 * 95 *
91 * @param appId the Application ID 96 * @param appId the Application ID
92 * @param intentService the intent service 97 * @param intentService the intent service
98 + * @param hostService the host service
93 * @param configService the SDN-IP configuration service 99 * @param configService the SDN-IP configuration service
94 */ 100 */
95 IntentSynchronizer(ApplicationId appId, IntentService intentService, 101 IntentSynchronizer(ApplicationId appId, IntentService intentService,
102 + HostService hostService,
96 RoutingConfigurationService configService) { 103 RoutingConfigurationService configService) {
97 this.appId = appId; 104 this.appId = appId;
98 this.intentService = intentService; 105 this.intentService = intentService;
106 + this.hostService = hostService;
99 peerIntents = new ConcurrentHashMap<>(); 107 peerIntents = new ConcurrentHashMap<>();
100 routeIntents = new ConcurrentHashMap<>(); 108 routeIntents = new ConcurrentHashMap<>();
101 109
...@@ -264,6 +272,25 @@ public class IntentSynchronizer implements FibListener { ...@@ -264,6 +272,25 @@ public class IntentSynchronizer implements FibListener {
264 } 272 }
265 273
266 /** 274 /**
275 + * Submits a MultiPointToSinglePointIntent for reactive routing.
276 + *
277 + * @param ipPrefix the IP prefix to match in a MultiPointToSinglePointIntent
278 + * @param intent the intent to submit
279 + */
280 + void submitReactiveIntent(IpPrefix ipPrefix, MultiPointToSinglePointIntent intent) {
281 + synchronized (this) {
282 + // Store the intent in memory
283 + routeIntents.put(ipPrefix, intent);
284 +
285 + // Push the intent
286 + if (isElectedLeader && isActivatedLeader) {
287 + log.trace("SDN-IP submitting reactive routing intent: {}", intent);
288 + intentService.submit(intent);
289 + }
290 + }
291 + }
292 +
293 + /**
267 * Generates a route intent for a prefix, the next hop IP address, and 294 * Generates a route intent for a prefix, the next hop IP address, and
268 * the next hop MAC address. 295 * the next hop MAC address.
269 * <p/> 296 * <p/>
...@@ -352,6 +379,62 @@ public class IntentSynchronizer implements FibListener { ...@@ -352,6 +379,62 @@ public class IntentSynchronizer implements FibListener {
352 } 379 }
353 380
354 @Override 381 @Override
382 + public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) {
383 + checkNotNull(hostIpAddress);
384 + Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
385 + for (Interface intf : configService.getInterfaces()) {
386 + ConnectPoint srcPoint = intf.connectPoint();
387 + ingressPoints.add(srcPoint);
388 + }
389 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
390 +
391 + if (hostIpAddress.isIp4()) {
392 + selector.matchEthType(Ethernet.TYPE_IPV4);
393 + } else {
394 + selector.matchEthType(Ethernet.TYPE_IPV6);
395 + }
396 +
397 + // Match the destination IP prefix at the first hop
398 + IpPrefix ipPrefix = hostIpAddress.toIpPrefix();
399 + selector.matchIPDst(ipPrefix);
400 +
401 + // Rewrite the destination MAC address
402 + MacAddress hostMac = null;
403 + ConnectPoint egressPoint = null;
404 + for (Host host : hostService.getHostsByIp(hostIpAddress)) {
405 + if (host.mac() != null) {
406 + hostMac = host.mac();
407 + egressPoint = host.location();
408 + break;
409 + }
410 + }
411 + if (hostMac == null) {
412 + hostService.startMonitoringIp(hostIpAddress);
413 + return;
414 + }
415 +
416 + TrafficTreatment.Builder treatment =
417 + DefaultTrafficTreatment.builder().setEthDst(hostMac);
418 + Key key = Key.of(ipPrefix.toString(), appId);
419 + int priority = ipPrefix.prefixLength() * PRIORITY_MULTIPLIER
420 + + PRIORITY_OFFSET;
421 + MultiPointToSinglePointIntent intent =
422 + MultiPointToSinglePointIntent.builder()
423 + .appId(appId)
424 + .key(key)
425 + .selector(selector.build())
426 + .treatment(treatment.build())
427 + .ingressPoints(ingressPoints)
428 + .egressPoint(egressPoint)
429 + .priority(priority)
430 + .build();
431 +
432 + log.trace("Generates ConnectivityInternetToHost intent {}", intent);
433 + submitReactiveIntent(ipPrefix, intent);
434 + }
435 +
436 +
437 + @Override
355 public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) { 438 public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) {
356 // 439 //
357 // NOTE: Semantically, we MUST withdraw existing intents before 440 // NOTE: Semantically, we MUST withdraw existing intents before
...@@ -738,4 +821,167 @@ public class IntentSynchronizer implements FibListener { ...@@ -738,4 +821,167 @@ public class IntentSynchronizer implements FibListener {
738 return false; 821 return false;
739 } 822 }
740 } 823 }
824 +
825 + @Override
826 + public void setUpConnectivityHostToHost(IpAddress dstIpAddress,
827 + IpAddress srcIpAddress,
828 + MacAddress srcMacAddress,
829 + ConnectPoint srcConnectPoint) {
830 + checkNotNull(dstIpAddress);
831 + checkNotNull(srcIpAddress);
832 + checkNotNull(srcMacAddress);
833 + checkNotNull(srcConnectPoint);
834 +
835 + IpPrefix srcIpPrefix = srcIpAddress.toIpPrefix();
836 + IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
837 + ConnectPoint dstConnectPoint = null;
838 + MacAddress dstMacAddress = null;
839 +
840 + for (Host host : hostService.getHostsByIp(dstIpAddress)) {
841 + if (host.mac() != null) {
842 + dstMacAddress = host.mac();
843 + dstConnectPoint = host.location();
844 + break;
845 + }
846 + }
847 + if (dstMacAddress == null) {
848 + hostService.startMonitoringIp(dstIpAddress);
849 + return;
850 + }
851 +
852 + //
853 + // Handle intent from source host to destination host
854 + //
855 + MultiPointToSinglePointIntent srcToDstIntent =
856 + hostToHostIntentGenerator(dstIpAddress, dstConnectPoint,
857 + dstMacAddress, srcConnectPoint);
858 + submitReactiveIntent(dstIpPrefix, srcToDstIntent);
859 +
860 + //
861 + // Handle intent from destination host to source host
862 + //
863 +
864 + // Since we proactively handle the intent from destination host to
865 + // source host, we should check whether there is an exiting intent
866 + // first.
867 + if (mp2pIntentExists(srcIpPrefix)) {
868 + updateExistingMp2pIntent(srcIpPrefix, dstConnectPoint);
869 + return;
870 + } else {
871 + // There is no existing intent, create a new one.
872 + MultiPointToSinglePointIntent dstToSrcIntent =
873 + hostToHostIntentGenerator(srcIpAddress, srcConnectPoint,
874 + srcMacAddress, dstConnectPoint);
875 + submitReactiveIntent(srcIpPrefix, dstToSrcIntent);
876 + }
877 + }
878 +
879 + /**
880 + * Generates MultiPointToSinglePointIntent for both source host and
881 + * destination host located in local SDN network.
882 + *
883 + * @param dstIpAddress the destination IP address
884 + * @param dstConnectPoint the destination host connect point
885 + * @param dstMacAddress the MAC address of destination host
886 + * @param srcConnectPoint the connect point where packet-in from
887 + * @return the generated MultiPointToSinglePointIntent
888 + */
889 + private MultiPointToSinglePointIntent hostToHostIntentGenerator(
890 + IpAddress dstIpAddress,
891 + ConnectPoint dstConnectPoint,
892 + MacAddress dstMacAddress,
893 + ConnectPoint srcConnectPoint) {
894 + checkNotNull(dstIpAddress);
895 + checkNotNull(dstConnectPoint);
896 + checkNotNull(dstMacAddress);
897 + checkNotNull(srcConnectPoint);
898 +
899 + Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
900 + ingressPoints.add(srcConnectPoint);
901 + IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
902 +
903 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
904 + if (dstIpAddress.isIp4()) {
905 + selector.matchEthType(Ethernet.TYPE_IPV4);
906 + selector.matchIPDst(dstIpPrefix);
907 + } else {
908 + selector.matchEthType(Ethernet.TYPE_IPV6);
909 + selector.matchIPv6Dst(dstIpPrefix);
910 + }
911 +
912 + // Rewrite the destination MAC address
913 + TrafficTreatment.Builder treatment =
914 + DefaultTrafficTreatment.builder().setEthDst(dstMacAddress);
915 +
916 + Key key = Key.of(dstIpPrefix.toString(), appId);
917 + int priority = dstIpPrefix.prefixLength() * PRIORITY_MULTIPLIER
918 + + PRIORITY_OFFSET;
919 + MultiPointToSinglePointIntent intent =
920 + MultiPointToSinglePointIntent.builder()
921 + .appId(appId)
922 + .key(key)
923 + .selector(selector.build())
924 + .treatment(treatment.build())
925 + .ingressPoints(ingressPoints)
926 + .egressPoint(dstConnectPoint)
927 + .priority(priority)
928 + .build();
929 +
930 + log.trace("Generates ConnectivityHostToHost = {} ", intent);
931 + return intent;
932 + }
933 +
934 + @Override
935 + public void updateExistingMp2pIntent(IpPrefix ipPrefix,
936 + ConnectPoint ingressConnectPoint) {
937 + checkNotNull(ipPrefix);
938 + checkNotNull(ingressConnectPoint);
939 +
940 + MultiPointToSinglePointIntent existingIntent =
941 + getExistingMp2pIntent(ipPrefix);
942 + if (existingIntent != null) {
943 + Set<ConnectPoint> ingressPoints = existingIntent.ingressPoints();
944 + // Add host connect point into ingressPoints of the existing intent
945 + if (ingressPoints.add(ingressConnectPoint)) {
946 + MultiPointToSinglePointIntent updatedMp2pIntent =
947 + MultiPointToSinglePointIntent.builder()
948 + .appId(appId)
949 + .key(existingIntent.key())
950 + .selector(existingIntent.selector())
951 + .treatment(existingIntent.treatment())
952 + .ingressPoints(ingressPoints)
953 + .egressPoint(existingIntent.egressPoint())
954 + .priority(existingIntent.priority())
955 + .build();
956 +
957 + log.trace("Update an existing MultiPointToSinglePointIntent "
958 + + "to new intent = {} ", updatedMp2pIntent);
959 + submitReactiveIntent(ipPrefix, updatedMp2pIntent);
960 + }
961 + // If adding ingressConnectPoint to ingressPoints failed, it
962 + // because between the time interval from checking existing intent
963 + // to generating new intent, onos updated this intent due to other
964 + // packet-in and the new intent also includes the
965 + // ingressConnectPoint. This will not affect reactive routing.
966 + }
967 + }
968 +
969 + @Override
970 + public boolean mp2pIntentExists(IpPrefix ipPrefix) {
971 + checkNotNull(ipPrefix);
972 + return routeIntents.get(ipPrefix) == null ? false : true;
973 + }
974 +
975 + /**
976 + * Gets the existing MultiPointToSinglePointIntent from memory for a given
977 + * IP prefix.
978 + *
979 + * @param ipPrefix the IP prefix used to find MultiPointToSinglePointIntent
980 + * @return the MultiPointToSinglePointIntent if found, otherwise null
981 + */
982 + private MultiPointToSinglePointIntent getExistingMp2pIntent(IpPrefix
983 + ipPrefix) {
984 + checkNotNull(ipPrefix);
985 + return routeIntents.get(ipPrefix);
986 + }
741 } 987 }
......
...@@ -29,6 +29,7 @@ import org.onosproject.cluster.LeadershipService; ...@@ -29,6 +29,7 @@ import org.onosproject.cluster.LeadershipService;
29 import org.onosproject.config.NetworkConfigService; 29 import org.onosproject.config.NetworkConfigService;
30 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
31 import org.onosproject.core.CoreService; 31 import org.onosproject.core.CoreService;
32 +import org.onosproject.net.host.HostService;
32 import org.onosproject.net.intent.IntentService; 33 import org.onosproject.net.intent.IntentService;
33 import org.onosproject.routing.RoutingService; 34 import org.onosproject.routing.RoutingService;
34 import org.onosproject.routing.config.RoutingConfigurationService; 35 import org.onosproject.routing.config.RoutingConfigurationService;
...@@ -53,6 +54,9 @@ public class SdnIp implements SdnIpService { ...@@ -53,6 +54,9 @@ public class SdnIp implements SdnIpService {
53 protected IntentService intentService; 54 protected IntentService intentService;
54 55
55 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 56 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
57 + protected HostService hostService;
58 +
59 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected ClusterService clusterService; 60 protected ClusterService clusterService;
57 61
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -89,6 +93,7 @@ public class SdnIp implements SdnIpService { ...@@ -89,6 +93,7 @@ public class SdnIp implements SdnIpService {
89 localControllerNode = clusterService.getLocalNode(); 93 localControllerNode = clusterService.getLocalNode();
90 94
91 intentSynchronizer = new IntentSynchronizer(appId, intentService, 95 intentSynchronizer = new IntentSynchronizer(appId, intentService,
96 + hostService,
92 config); 97 config);
93 intentSynchronizer.start(); 98 intentSynchronizer.start();
94 99
...@@ -97,7 +102,9 @@ public class SdnIp implements SdnIpService { ...@@ -97,7 +102,9 @@ public class SdnIp implements SdnIpService {
97 config); 102 config);
98 peerConnectivity.start(); 103 peerConnectivity.start();
99 104
100 - routingService.start(intentSynchronizer); 105 + routingService.addFibListener(intentSynchronizer);
106 + routingService.addIntentRequestListener(intentSynchronizer);
107 + routingService.start();
101 108
102 leadershipService.addListener(leadershipEventListener); 109 leadershipService.addListener(leadershipEventListener);
103 leadershipService.runForLeadership(appId.name()); 110 leadershipService.runForLeadership(appId.name());
......
...@@ -27,4 +27,5 @@ public interface SdnIpService { ...@@ -27,4 +27,5 @@ public interface SdnIpService {
27 * @param isPrimary true if the instance is primary, false if it is not 27 * @param isPrimary true if the instance is primary, false if it is not
28 */ 28 */
29 public void modifyPrimary(boolean isPrimary); 29 public void modifyPrimary(boolean isPrimary);
30 +
30 } 31 }
......
...@@ -62,5 +62,21 @@ ...@@ -62,5 +62,21 @@
62 ] 62 ]
63 63
64 } 64 }
65 + ],
66 + "ip4LocalPrefixes" : [
67 + {
68 + "ipPrefix" : "100.0.0.0/24",
69 + "type" : "PUBLIC"
70 + },
71 + {
72 + "ipPrefix" : "200.0.0.0/8",
73 + "type" : "PUBLIC"
74 + },
75 + {
76 + "ipPrefix" : "192.0.0.0/24",
77 + "type" : "PRIVATE"
78 + }
79 + ],
80 + "ip6LocalPrefixes" : [
65 ] 81 ]
66 } 82 }
......
...@@ -118,7 +118,7 @@ public class IntentSyncTest extends AbstractIntentTest { ...@@ -118,7 +118,7 @@ public class IntentSyncTest extends AbstractIntentTest {
118 intentService = createMock(IntentService.class); 118 intentService = createMock(IntentService.class);
119 119
120 intentSynchronizer = new IntentSynchronizer(APPID, intentService, 120 intentSynchronizer = new IntentSynchronizer(APPID, intentService,
121 - routingConfig); 121 + null, routingConfig);
122 } 122 }
123 123
124 /** 124 /**
......
...@@ -555,7 +555,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { ...@@ -555,7 +555,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
555 replay(intentService); 555 replay(intentService);
556 556
557 intentSynchronizer = new IntentSynchronizer(APPID, intentService, 557 intentSynchronizer = new IntentSynchronizer(APPID, intentService,
558 - routingConfig); 558 + null, routingConfig);
559 intentSynchronizer.leaderChanged(true); 559 intentSynchronizer.leaderChanged(true);
560 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); 560 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
561 561
......
...@@ -188,6 +188,12 @@ ...@@ -188,6 +188,12 @@
188 <bundle>mvn:org.onosproject/onos-app-optical/@ONOS-VERSION</bundle> 188 <bundle>mvn:org.onosproject/onos-app-optical/@ONOS-VERSION</bundle>
189 </feature> 189 </feature>
190 190
191 + <feature name="onos-app-reactive-routing" version="@FEATURE-VERSION"
192 + description="ONOS SDN/IP reactive routing">
193 + <feature>onos-app-sdnip</feature>
194 + <bundle>mvn:org.onosproject/onos-app-reactive-routing/@ONOS-VERSION</bundle>
195 + </feature>
196 +
191 <feature name="onos-app-sdnip" version="@FEATURE-VERSION" 197 <feature name="onos-app-sdnip" version="@FEATURE-VERSION"
192 description="SDN-IP peering application"> 198 description="SDN-IP peering application">
193 <feature>onos-api</feature> 199 <feature>onos-api</feature>
......
...@@ -371,6 +371,22 @@ public class IpAddress implements Comparable<IpAddress> { ...@@ -371,6 +371,22 @@ public class IpAddress implements Comparable<IpAddress> {
371 } 371 }
372 372
373 /** 373 /**
374 + * Generates an IP prefix.
375 + *
376 + * @return the IP prefix of the IP address
377 + */
378 + public IpPrefix toIpPrefix() {
379 +
380 + if (isIp4()) {
381 + return IpPrefix.valueOf(new IpAddress(Version.INET, octets),
382 + Ip4Address.BIT_LENGTH);
383 + } else {
384 + return IpPrefix.valueOf(new IpAddress(Version.INET6, octets),
385 + Ip6Address.BIT_LENGTH);
386 + }
387 + }
388 +
389 + /**
374 * Gets the IP address name for the IP address version. 390 * Gets the IP address name for the IP address version.
375 * 391 *
376 * @param version the IP address version 392 * @param version the IP address version
......