blob: 3222714219fa6e7bb96492e36c50cfe1107e12bb [file] [log] [blame]
Brian Stanke11f6d532016-07-05 16:17:59 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Brian Stanke11f6d532016-07-05 16:17:59 -04003 *
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
17package org.onosproject.net.intent.impl.compiler;
18
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import org.osgi.service.component.annotations.Activate;
20import org.osgi.service.component.annotations.Component;
21import org.osgi.service.component.annotations.Deactivate;
22import org.osgi.service.component.annotations.Reference;
23import org.osgi.service.component.annotations.ReferenceCardinality;
Brian Stanke11f6d532016-07-05 16:17:59 -040024import org.onlab.osgi.DefaultServiceDirectory;
25import org.onlab.osgi.ServiceDirectory;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.incubator.net.tunnel.TunnelId;
28import org.onosproject.incubator.net.virtual.NetworkId;
29import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
30import org.onosproject.incubator.net.virtual.VirtualNetworkService;
31import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
32import org.onosproject.incubator.net.virtual.VirtualPort;
33import org.onosproject.net.ConnectPoint;
Ray Milkeya2cf3a12018-02-15 16:13:56 -080034import org.onosproject.net.FilteredConnectPoint;
Brian Stanke11f6d532016-07-05 16:17:59 -040035import org.onosproject.net.Link;
36import org.onosproject.net.Path;
Brian Stanke11f6d532016-07-05 16:17:59 -040037import org.onosproject.net.intent.Intent;
Yuta HIGUCHId95d5902016-06-27 00:18:45 -070038import org.onosproject.net.intent.IntentCompilationException;
Brian Stanke11f6d532016-07-05 16:17:59 -040039import org.onosproject.net.intent.IntentService;
40import org.onosproject.net.intent.Key;
41import org.onosproject.net.intent.PointToPointIntent;
Brian Stanke11f6d532016-07-05 16:17:59 -040042import org.onosproject.net.topology.TopologyService;
43import org.slf4j.Logger;
44
45import java.util.ArrayList;
46import java.util.List;
47import java.util.Optional;
48import java.util.Set;
49
50import static org.slf4j.LoggerFactory.getLogger;
51
52/**
53 * An intent compiler for {@link org.onosproject.incubator.net.virtual.VirtualNetworkIntent}.
54 */
55@Component(immediate = true)
56public class VirtualNetworkIntentCompiler
57 extends ConnectivityIntentCompiler<VirtualNetworkIntent> {
58
59 private final Logger log = getLogger(getClass());
60
61 private static final String NETWORK_ID = "networkId=";
62 protected static final String KEY_FORMAT = "{" + NETWORK_ID + "%s, src=%s, dst=%s}";
63
64 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
65
Ray Milkeyd84f89b2018-08-17 14:54:17 -070066 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Brian Stanke11f6d532016-07-05 16:17:59 -040067 protected VirtualNetworkService manager;
68
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Brian Stanke11f6d532016-07-05 16:17:59 -040070 protected IntentService intentService;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Brian Stanke11f6d532016-07-05 16:17:59 -040073 protected VirtualNetworkStore store;
74
75
76 @Activate
77 public void activate() {
78 intentManager.registerCompiler(VirtualNetworkIntent.class, this);
79 }
80
81 @Deactivate
82 public void deactivate() {
83 intentManager.unregisterCompiler(VirtualNetworkIntent.class);
84 }
85
86 @Override
87 public List<Intent> compile(VirtualNetworkIntent intent, List<Intent> installable) {
88
89 log.debug("Compiling intent: " + intent);
90 List<Intent> intents = new ArrayList<>();
91 Optional<Path> path = getPaths(intent).stream()
92 .findFirst();
93 if (path != null && path.isPresent()) {
Brian Stankefb61df42016-07-25 11:47:51 -040094 List<Link> links = path.get().links();
Brian Stanke11f6d532016-07-05 16:17:59 -040095
Brian Stankefb61df42016-07-25 11:47:51 -040096 // First create an intent between the intent ingress CP and the first link source CP,
97 // only if the two CPs are not the same.
98 Link firstLink = links.get(0);
99 if (!intent.ingressPoint().equals(firstLink.src())) {
100 intents.add(createPtPtIntent(intent, intent.ingressPoint(), firstLink.src()));
101 }
102
103 // Next create an intent between the intent egress CP and the last link destination CP,
104 // only if the two CPs are not the same.
105 Link lastLink = links.get(links.size() - 1);
106 if (!intent.egressPoint().equals(lastLink.dst())) {
107 intents.add(createPtPtIntent(intent, lastLink.dst(), intent.egressPoint()));
108 }
109
110 // Now loop through all of the virtual links in the path and create an intent.
111 // An intent is also created connecting two virtual links.
112 final int[] index = {0};
113 links.forEach(link -> {
114 intents.add(createPtPtIntent(intent, link.src(), link.dst()));
115 if (index[0] > 0) {
116 Link previousLink = links.get(index[0] - 1);
117 intents.add(createPtPtIntent(intent, previousLink.dst(), link.src()));
118 }
119 index[0]++;
Brian Stanke11f6d532016-07-05 16:17:59 -0400120 });
121 } else {
122 throw new IntentCompilationException("Unable to find a path for intent " + intent);
123 }
124
125 return intents;
126 }
127
128 /**
129 * Returns the paths for the virtual network intent.
130 *
131 * @param intent virtual network intent
132 * @return set of paths
133 */
134 private Set<Path> getPaths(VirtualNetworkIntent intent) {
135
136 TopologyService topologyService = manager.get(intent.networkId(), TopologyService.class);
137 if (topologyService == null) {
138 throw new IntentCompilationException("topologyService is null");
139 }
140 return topologyService.getPaths(topologyService.currentTopology(),
141 intent.ingressPoint().deviceId(), intent.egressPoint().deviceId());
142 }
143
144 /**
Brian Stankefb61df42016-07-25 11:47:51 -0400145 * Encodes the key using the network identifier, application identifier, source and destination
Brian Stanke11f6d532016-07-05 16:17:59 -0400146 * connect points.
147 *
148 * @param networkId virtual network identifier
149 * @param applicationId application identifier
150 * @param src source connect point
151 * @param dst destination connect point
152 * @return encoded key
153 */
Brian Stankefb61df42016-07-25 11:47:51 -0400154
Brian Stanke11f6d532016-07-05 16:17:59 -0400155 private static Key encodeKey(NetworkId networkId, ApplicationId applicationId, ConnectPoint src, ConnectPoint dst) {
156 String key = String.format(KEY_FORMAT, networkId, src, dst);
157 return Key.of(key, applicationId);
158 }
159
160 /**
Brian Stankefb61df42016-07-25 11:47:51 -0400161 * Creates a point-to-point intent using the virtual network intent between the source and destination
162 * connect point.
Brian Stanke11f6d532016-07-05 16:17:59 -0400163 *
164 * @param intent virtual network intent
Brian Stankefb61df42016-07-25 11:47:51 -0400165 * @param src source connect point
166 * @param dst destination connect point
Brian Stanke11f6d532016-07-05 16:17:59 -0400167 * @return point to point intent
168 */
Brian Stankefb61df42016-07-25 11:47:51 -0400169 private Intent createPtPtIntent(VirtualNetworkIntent intent, ConnectPoint src, ConnectPoint dst) {
170 ConnectPoint ingressPoint = mapVirtualToPhysicalPort(intent.networkId(), src);
171 ConnectPoint egressPoint = mapVirtualToPhysicalPort(intent.networkId(), dst);
Brian Stanke11f6d532016-07-05 16:17:59 -0400172 Key intentKey = encodeKey(intent.networkId(), intent.appId(), ingressPoint, egressPoint);
173
Brian Stanke11f6d532016-07-05 16:17:59 -0400174 // TODO Currently there can only be one intent between the ingress and egress across
175 // all virtual networks. We may want to support multiple intents between the same src/dst pairs.
176 PointToPointIntent physicalIntent = PointToPointIntent.builder()
177 .key(intentKey)
178 .appId(intent.appId())
Ray Milkeya2cf3a12018-02-15 16:13:56 -0800179 .filteredIngressPoint(new FilteredConnectPoint(ingressPoint))
180 .filteredEgressPoint(new FilteredConnectPoint(egressPoint))
Brian Stankefb61df42016-07-25 11:47:51 -0400181 .constraints(intent.constraints())
182 .selector(intent.selector())
183 .treatment(intent.treatment())
Luca Prete670ac5d2017-02-03 15:55:43 -0800184 .resourceGroup(intent.resourceGroup())
Brian Stanke11f6d532016-07-05 16:17:59 -0400185 .build();
186 log.debug("Submitting physical intent: " + physicalIntent);
187 intentService.submit(physicalIntent);
188
Brian Stankefb61df42016-07-25 11:47:51 -0400189 // Store the physical intent against this virtual intent.
190 store.addTunnelId(intent, TunnelId.valueOf(physicalIntent.key().toString()));
191
Brian Stanke11f6d532016-07-05 16:17:59 -0400192 return physicalIntent;
193 }
194
195 /**
196 * Maps the virtual connect point to a physical connect point.
197 *
198 * @param networkId virtual network identifier
199 * @param virtualCp virtual connect point
200 * @return physical connect point
201 */
202 private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId, ConnectPoint virtualCp) {
203 Set<VirtualPort> ports = manager.getVirtualPorts(networkId, virtualCp.deviceId());
204 for (VirtualPort port : ports) {
205 if (port.element().id().equals(virtualCp.elementId()) &&
206 port.number().equals(virtualCp.port())) {
Yoonseon Han6c603892016-09-01 11:52:21 -0700207 return new ConnectPoint(port.realizedBy().deviceId(), port.realizedBy().port());
Brian Stanke11f6d532016-07-05 16:17:59 -0400208 }
209 }
210 return null;
211 }
212}
213