blob: 04f42e54f63e905afa26530030ceaf9ce4ab0c5f [file] [log] [blame]
Brian Stanke11f6d532016-07-05 16:17:59 -04001/*
2 * Copyright 2016-present 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
17package org.onosproject.net.intent.impl.compiler;
18
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import 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;
34import org.onosproject.net.EncapsulationType;
35import org.onosproject.net.Link;
36import org.onosproject.net.Path;
37import org.onosproject.net.intent.Constraint;
38import org.onosproject.net.intent.Intent;
39import org.onosproject.net.intent.IntentService;
40import org.onosproject.net.intent.Key;
41import org.onosproject.net.intent.PointToPointIntent;
42import org.onosproject.net.intent.constraint.EncapsulationConstraint;
43import org.onosproject.net.intent.impl.IntentCompilationException;
44import org.onosproject.net.topology.TopologyService;
45import org.slf4j.Logger;
46
47import java.util.ArrayList;
48import java.util.List;
49import java.util.Optional;
50import java.util.Set;
51
52import static org.slf4j.LoggerFactory.getLogger;
53
54/**
55 * An intent compiler for {@link org.onosproject.incubator.net.virtual.VirtualNetworkIntent}.
56 */
57@Component(immediate = true)
58public class VirtualNetworkIntentCompiler
59 extends ConnectivityIntentCompiler<VirtualNetworkIntent> {
60
61 private final Logger log = getLogger(getClass());
62
63 private static final String NETWORK_ID = "networkId=";
64 protected static final String KEY_FORMAT = "{" + NETWORK_ID + "%s, src=%s, dst=%s}";
65
66 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected VirtualNetworkService manager;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected IntentService intentService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected VirtualNetworkStore store;
76
77
78 @Activate
79 public void activate() {
80 intentManager.registerCompiler(VirtualNetworkIntent.class, this);
81 }
82
83 @Deactivate
84 public void deactivate() {
85 intentManager.unregisterCompiler(VirtualNetworkIntent.class);
86 }
87
88 @Override
89 public List<Intent> compile(VirtualNetworkIntent intent, List<Intent> installable) {
90
91 log.debug("Compiling intent: " + intent);
92 List<Intent> intents = new ArrayList<>();
93 Optional<Path> path = getPaths(intent).stream()
94 .findFirst();
95 if (path != null && path.isPresent()) {
96 path.get().links().forEach(link -> {
97 Intent physicalIntent = createPtPtIntent(intent, link);
98 intents.add(physicalIntent);
99
100 // store the virtual intent to physical intent tunnelId mapping
101 store.addTunnelId(intent, TunnelId.valueOf(physicalIntent.key().toString()));
102 });
103 } else {
104 throw new IntentCompilationException("Unable to find a path for intent " + intent);
105 }
106
107 return intents;
108 }
109
110 /**
111 * Returns the paths for the virtual network intent.
112 *
113 * @param intent virtual network intent
114 * @return set of paths
115 */
116 private Set<Path> getPaths(VirtualNetworkIntent intent) {
117
118 TopologyService topologyService = manager.get(intent.networkId(), TopologyService.class);
119 if (topologyService == null) {
120 throw new IntentCompilationException("topologyService is null");
121 }
122 return topologyService.getPaths(topologyService.currentTopology(),
123 intent.ingressPoint().deviceId(), intent.egressPoint().deviceId());
124 }
125
126 /**
127 * Encodes the key using the network identifier, application identifer, source and destination
128 * connect points.
129 *
130 * @param networkId virtual network identifier
131 * @param applicationId application identifier
132 * @param src source connect point
133 * @param dst destination connect point
134 * @return encoded key
135 */
136 private static Key encodeKey(NetworkId networkId, ApplicationId applicationId, ConnectPoint src, ConnectPoint dst) {
137 String key = String.format(KEY_FORMAT, networkId, src, dst);
138 return Key.of(key, applicationId);
139 }
140
141 /**
142 * Creates a point-to-point intent from the virtual network intent and virtual link.
143 *
144 * @param intent virtual network intent
145 * @param link virtual link
146 * @return point to point intent
147 */
148 private Intent createPtPtIntent(VirtualNetworkIntent intent, Link link) {
149 ConnectPoint ingressPoint = mapVirtualToPhysicalPort(intent.networkId(), link.src());
150 ConnectPoint egressPoint = mapVirtualToPhysicalPort(intent.networkId(), link.dst());
151 Key intentKey = encodeKey(intent.networkId(), intent.appId(), ingressPoint, egressPoint);
152
153 List<Constraint> constraints = new ArrayList<>();
154 constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
155
156 // TODO Currently there can only be one intent between the ingress and egress across
157 // all virtual networks. We may want to support multiple intents between the same src/dst pairs.
158 PointToPointIntent physicalIntent = PointToPointIntent.builder()
159 .key(intentKey)
160 .appId(intent.appId())
161 .ingressPoint(ingressPoint)
162 .egressPoint(egressPoint)
163 .constraints(constraints)
164 .build();
165 log.debug("Submitting physical intent: " + physicalIntent);
166 intentService.submit(physicalIntent);
167
168 return physicalIntent;
169 }
170
171 /**
172 * Maps the virtual connect point to a physical connect point.
173 *
174 * @param networkId virtual network identifier
175 * @param virtualCp virtual connect point
176 * @return physical connect point
177 */
178 private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId, ConnectPoint virtualCp) {
179 Set<VirtualPort> ports = manager.getVirtualPorts(networkId, virtualCp.deviceId());
180 for (VirtualPort port : ports) {
181 if (port.element().id().equals(virtualCp.elementId()) &&
182 port.number().equals(virtualCp.port())) {
183 return new ConnectPoint(port.realizedBy().element().id(), port.realizedBy().number());
184 }
185 }
186 return null;
187 }
188}
189