blob: a84e3e1201840624b29f53ed31ee74257d833582 [file] [log] [blame]
Pingping Linffa27d32015-04-30 14:41:03 -07001/*
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 */
16package org.onosproject.virtualbng;
17
18import static com.google.common.base.Preconditions.checkNotNull;
19
20import java.util.Map;
21import java.util.concurrent.ConcurrentHashMap;
22
23import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import org.onlab.packet.Ethernet;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
32import org.onlab.packet.MacAddress;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.Host;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.host.HostService;
42import org.onosproject.net.intent.IntentService;
43import org.onosproject.net.intent.Key;
44import org.onosproject.net.intent.PointToPointIntent;
45import org.slf4j.Logger;
46import org.slf4j.LoggerFactory;
47
48/**
49 * This is a virtual Broadband Network Gateway (BNG) application. It mainly
50 * has 3 functions:
51 * (1) assigns and replies a public IP address to a REST request with a private
52 * IP address
53 * (2) maintains the mapping from the private IP address to the public IP address
54 * (3) installs point to point intents for the host configured with private IP
55 * address to access Internet
56 */
57@Component(immediate = true)
58@Service
59public class VbngManager implements VbngService {
60
61 private static final String APP_NAME = "org.onosproject.virtualbng";
62
63 private final Logger log = LoggerFactory.getLogger(getClass());
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected CoreService coreService;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected HostService hostService;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected IntentService intentService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected VbngConfigurationService vbngConfigurationService;
76
77 private ApplicationId appId;
78 private Map<IpAddress, PointToPointIntent> p2pIntentsFromHost;
79 private Map<IpAddress, PointToPointIntent> p2pIntentsToHost;
80
81 @Activate
82 public void activate() {
83 appId = coreService.registerApplication(APP_NAME);
84 p2pIntentsFromHost = new ConcurrentHashMap<>();
85 p2pIntentsToHost = new ConcurrentHashMap<>();
86 log.info("vBNG Started");
87 }
88
89 @Deactivate
90 public void deactivate() {
91 log.info("vBNG Stopped");
92 }
93
94 @Override
95 public IpAddress createVbng(IpAddress privateIpAddress) {
96
97 IpAddress nextHopIpAddress =
98 vbngConfigurationService.getNextHopIpAddress();
99 if (nextHopIpAddress == null) {
100 log.info("Did not find next hop IP address");
101 return null;
102 }
103
104 IpAddress publicIpAddress =
105 vbngConfigurationService.getAvailablePublicIpAddress(
106 privateIpAddress);
107 if (publicIpAddress == null) {
108 log.info("Did not find an available public IP address to use.");
109 return null;
110 }
111 log.info("Private IP to Public IP mapping: {} --> {}",
112 privateIpAddress, publicIpAddress);
113
114 // Setup paths between the host configured with private IP and
115 // next hop
116 setupForwardingPaths(privateIpAddress, publicIpAddress,
117 nextHopIpAddress);
118 return publicIpAddress;
119 }
120
121 /**
122 * Sets up forwarding paths in both two directions between host configured
123 * with private IP and next hop.
124 *
125 * @param privateIp the private IP address of a local host
126 * @param publicIp the public IP address assigned for the private IP address
127 * @param nextHopIpAddress the next hop IP address outside local SDN network
128 */
129 private void setupForwardingPaths(IpAddress privateIp, IpAddress publicIp,
130 IpAddress nextHopIpAddress) {
131 checkNotNull(privateIp);
132 checkNotNull(publicIp);
133 checkNotNull(nextHopIpAddress);
134
135 // If there are already intents for private IP address in the system,
136 // we will do nothing and directly return.
137 if (p2pIntentsFromHost.containsKey(privateIp)
138 && p2pIntentsToHost.containsKey(privateIp)) {
139 return;
140 }
141
142 Host localHost = null;
143 Host nextHopHost = null;
144 if (!hostService.getHostsByIp(nextHopIpAddress).isEmpty()) {
145 nextHopHost = hostService.getHostsByIp(nextHopIpAddress)
146 .iterator().next();
147 } else {
148 // TODO to write a new thread to install intents after ONOS
149 // discovers the next hop host
150 hostService.startMonitoringIp(nextHopIpAddress);
151 if (hostService.getHostsByIp(privateIp).isEmpty()) {
152 hostService.startMonitoringIp(privateIp);
153 }
154 return;
155 }
156
157 if (!hostService.getHostsByIp(privateIp).isEmpty()) {
158 localHost =
159 hostService.getHostsByIp(privateIp).iterator().next();
160 } else {
161 // TODO to write a new thread to install intents after ONOS
162 // discovers the next hop host
163 hostService.startMonitoringIp(privateIp);
164 return;
165 }
166
167 ConnectPoint nextHopConnectPoint =
168 new ConnectPoint(nextHopHost.location().elementId(),
169 nextHopHost.location().port());
170 ConnectPoint localHostConnectPoint =
171 new ConnectPoint(localHost.location().elementId(),
172 localHost.location().port());
173
174 // Generate and install intent for traffic from host configured with
175 // private IP
176 if (!p2pIntentsFromHost.containsKey(privateIp)) {
177 PointToPointIntent toNextHopIntent
178 = srcMatchIntentGenerator(privateIp,
179 publicIp,
180 nextHopHost.mac(),
181 nextHopConnectPoint,
182 localHostConnectPoint
183 );
184 p2pIntentsFromHost.put(privateIp, toNextHopIntent);
185 intentService.submit(toNextHopIntent);
186 }
187
188 // Generate and install intent for traffic to host configured with
189 // private IP
190 if (!p2pIntentsToHost.containsKey(privateIp)) {
191 PointToPointIntent toLocalHostIntent
192 = dstMatchIntentGenerator(publicIp,
193 privateIp,
194 localHost.mac(),
195 localHostConnectPoint,
196 nextHopConnectPoint);
197 p2pIntentsToHost.put(nextHopIpAddress, toLocalHostIntent);
198 intentService.submit(toLocalHostIntent);
199 }
200
201 return;
202 }
203
204 /**
205 * PointToPointIntent Generator.
206 * <p>
207 * The intent will match the source IP address in packet, rewrite the
208 * source IP address, and rewrite the destination MAC address.
209 * </p>
210 *
211 * @param srcIpAddress the source IP address in packet to match
212 * @param newSrcIpAddress the new source IP address to set
213 * @param dstMacAddress the destination MAC address to set
214 * @param dstConnectPoint the egress point
215 * @param srcConnectPoint the ingress point
216 * @return a PointToPointIntent
217 */
218 private PointToPointIntent srcMatchIntentGenerator(
219 IpAddress srcIpAddress,
220 IpAddress newSrcIpAddress,
221 MacAddress dstMacAddress,
222 ConnectPoint dstConnectPoint,
223 ConnectPoint srcConnectPoint) {
224 checkNotNull(srcIpAddress);
225 checkNotNull(newSrcIpAddress);
226 checkNotNull(dstMacAddress);
227 checkNotNull(dstConnectPoint);
228 checkNotNull(srcConnectPoint);
229
230 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
231 selector.matchEthType(Ethernet.TYPE_IPV4);
232 selector.matchIPSrc(IpPrefix.valueOf(srcIpAddress,
233 IpPrefix.MAX_INET_MASK_LENGTH));
234
235 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
236 treatment.setEthDst(dstMacAddress);
237 treatment.setIpSrc(newSrcIpAddress);
238
239 Key key = Key.of(srcIpAddress.toString() + "MatchSrc", appId);
240 PointToPointIntent intent = PointToPointIntent.builder()
241 .appId(appId)
242 .key(key)
243 .selector(selector.build())
244 .treatment(treatment.build())
245 .egressPoint(dstConnectPoint)
246 .ingressPoint(srcConnectPoint)
247 .build();
248
249 log.info("Generated a PointToPointIntent for traffic from local host "
250 + ": {}", intent);
251 return intent;
252 }
253
254 /**
255 * PointToPointIntent Generator.
256 * <p>
257 * The intent will match the destination IP address in packet, rewrite the
258 * destination IP address, and rewrite the destination MAC address.
259 * </p>
260 *
261 * @param dstIpAddress the destination IP address in packet to match
262 * @param newDstIpAddress the new destination IP address to set
263 * @param dstMacAddress the destination MAC address to set
264 * @param dstConnectPoint the egress point
265 * @param srcConnectPoint the ingress point
266 * @return a PointToPointIntent
267 */
268 private PointToPointIntent dstMatchIntentGenerator(
269 IpAddress dstIpAddress,
270 IpAddress newDstIpAddress,
271 MacAddress dstMacAddress,
272 ConnectPoint dstConnectPoint,
273 ConnectPoint srcConnectPoint) {
274 checkNotNull(dstIpAddress);
275 checkNotNull(newDstIpAddress);
276 checkNotNull(dstMacAddress);
277 checkNotNull(dstConnectPoint);
278 checkNotNull(srcConnectPoint);
279
280 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
281 selector.matchEthType(Ethernet.TYPE_IPV4);
282 selector.matchIPDst(IpPrefix.valueOf(dstIpAddress,
283 IpPrefix.MAX_INET_MASK_LENGTH));
284
285 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
286 treatment.setEthDst(dstMacAddress);
287 treatment.setIpDst(newDstIpAddress);
288
289 Key key = Key.of(newDstIpAddress.toString() + "MatchDst", appId);
290 PointToPointIntent intent = PointToPointIntent.builder()
291 .appId(appId)
292 .key(key)
293 .selector(selector.build())
294 .treatment(treatment.build())
295 .egressPoint(dstConnectPoint)
296 .ingressPoint(srcConnectPoint)
297 .build();
298 log.info("Generated a PointToPointIntent for traffic to local host "
299 + ": {}", intent);
300
301 return intent;
302 }
303
304
305}