blob: 4672912501acd64c3e6ce73514a577595fba9244 [file] [log] [blame]
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001/*
2 * Copyright 2014-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.cordvtn;
17
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080018import com.google.common.collect.Lists;
Hyunsun Moonae39ae82016-02-17 15:02:06 -080019import com.google.common.collect.Maps;
Hyunsun Moon1f145552015-10-08 22:25:30 -070020import com.google.common.collect.Sets;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080027import org.onlab.packet.Ethernet;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080028import org.onlab.packet.Ip4Address;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080029import org.onlab.packet.IpAddress;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080030import org.onlab.packet.MacAddress;
31import org.onlab.packet.VlanId;
Hyunsun Moon1f145552015-10-08 22:25:30 -070032import org.onosproject.core.ApplicationId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070033import org.onosproject.core.CoreService;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080034import org.onosproject.dhcp.DhcpService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080035import org.onosproject.mastership.MastershipService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080036import org.onosproject.net.ConnectPoint;
Hyunsun Moond772f342015-10-28 20:28:16 -070037import org.onosproject.net.DefaultAnnotations;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070038import org.onosproject.net.Host;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080039import org.onosproject.net.HostId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080040import org.onosproject.net.HostLocation;
Hyunsun Moon8539b042015-11-07 22:08:43 -080041import org.onosproject.net.Port;
Hyunsun Moon746956f2016-01-24 21:47:06 -080042import org.onosproject.net.config.ConfigFactory;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigRegistry;
46import org.onosproject.net.config.NetworkConfigService;
47import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070048import org.onosproject.net.device.DeviceService;
Hyunsun Moond772f342015-10-28 20:28:16 -070049import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080050import org.onosproject.net.flow.FlowRuleService;
51import org.onosproject.net.group.GroupService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080052import org.onosproject.net.host.DefaultHostDescription;
53import org.onosproject.net.host.HostDescription;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070054import org.onosproject.net.host.HostEvent;
55import org.onosproject.net.host.HostListener;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080056import org.onosproject.net.host.HostProvider;
57import org.onosproject.net.host.HostProviderRegistry;
58import org.onosproject.net.host.HostProviderService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070059import org.onosproject.net.host.HostService;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080060import org.onosproject.net.packet.PacketContext;
61import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080063import org.onosproject.net.provider.AbstractProvider;
64import org.onosproject.net.provider.ProviderId;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080065import org.onosproject.openstackswitching.OpenstackNetwork;
66import org.onosproject.openstackswitching.OpenstackPort;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080067import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080068import org.onosproject.openstackswitching.OpenstackSwitchingService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070069import org.slf4j.Logger;
70
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080071import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070072import java.util.Map;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080073import java.util.Set;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070074import java.util.concurrent.ExecutorService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080075import java.util.stream.Collectors;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070076
Hyunsun Moon1f145552015-10-08 22:25:30 -070077import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon746956f2016-01-24 21:47:06 -080078import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070079import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070080import static org.slf4j.LoggerFactory.getLogger;
81
82/**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080083 * Provisions virtual tenant networks with service chaining capability
84 * in OpenStack environment.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070085 */
86@Component(immediate = true)
87@Service
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080088public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider {
Hyunsun Moond0e932a2015-09-15 22:39:16 -070089
90 protected final Logger log = getLogger(getClass());
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon746956f2016-01-24 21:47:06 -080096 protected NetworkConfigRegistry configRegistry;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected NetworkConfigService configService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800102 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700105 protected DeviceService deviceService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected HostService hostService;
109
Hyunsun Moon1f145552015-10-08 22:25:30 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700111 protected DriverService driverService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800114 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800117 protected PacketService packetService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800120 protected MastershipService mastershipService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected GroupService groupService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800126 protected OpenstackSwitchingService openstackService;
127
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected DhcpService dhcpService;
130
Hyunsun Moon746956f2016-01-24 21:47:06 -0800131 private final ConfigFactory configFactory =
132 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
133 @Override
134 public CordVtnConfig createConfig() {
135 return new CordVtnConfig();
136 }
137 };
138
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800139 private static final String DEFAULT_TUNNEL = "vxlan";
140 private static final String SERVICE_ID = "serviceId";
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800141 private static final String OPENSTACK_VM_ID = "openstackVmId";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800142 private static final String OPENSTACK_PORT_ID = "openstackPortId";
143 private static final String DATA_PLANE_IP = "dataPlaneIp";
144 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
145 private static final String S_TAG = "stag";
146
147 private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800148
Hyunsun Moon746956f2016-01-24 21:47:06 -0800149 private final ExecutorService eventExecutor =
150 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700151
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800152 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800153 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800154 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700155
Hyunsun Moon746956f2016-01-24 21:47:06 -0800156 private ApplicationId appId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800157 private HostProviderService hostProvider;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800158 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800159 private CordVtnArpProxy arpProxy;
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800160 private volatile MacAddress privateGatewayMac = MacAddress.NONE;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800161
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800162 /**
163 * Creates an cordvtn host location provider.
164 */
165 public CordVtn() {
166 super(new ProviderId("host", CORDVTN_APP_ID));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800167 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700168
169 @Activate
170 protected void activate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800171 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800172 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
173 deviceService,
174 driverService,
175 groupService,
176 mastershipService,
177 DEFAULT_TUNNEL);
178
Hyunsun Moon9cf43db2016-02-12 15:59:53 -0800179 arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800180 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
181 arpProxy.requestPacket();
182
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700183 hostService.addListener(hostListener);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800184 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700185
Hyunsun Moon746956f2016-01-24 21:47:06 -0800186 configRegistry.registerConfigFactory(configFactory);
187 configService.addListener(configListener);
188 readConfiguration();
189
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700190 log.info("Started");
191 }
192
193 @Deactivate
194 protected void deactivate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800195 hostProviderRegistry.unregister(this);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700196 hostService.removeListener(hostListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800197
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800198 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700199
Hyunsun Moon746956f2016-01-24 21:47:06 -0800200 configRegistry.unregisterConfigFactory(configFactory);
201 configService.removeListener(configListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700202
Hyunsun Moon746956f2016-01-24 21:47:06 -0800203 eventExecutor.shutdown();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700204 log.info("Stopped");
205 }
206
207 @Override
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800208 public void triggerProbe(Host host) {
209 /*
210 * Note: In CORD deployment, we assume that all hosts are configured.
211 * Therefore no probe is required.
212 */
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800213 }
214
215 @Override
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800216 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId,
217 boolean isBidirectional) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800218 CordService tService = getCordService(tServiceId);
219 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800220
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800221 if (tService == null || pService == null) {
222 log.error("Failed to create CordService for {}", tServiceId.id());
223 return;
224 }
225
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800226 log.info("Service dependency from {} to {} created.", tService.id().id(), pService.id().id());
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800227 ruleInstaller.populateServiceDependencyRules(tService, pService, isBidirectional);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800228 }
229
230 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800231 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
232 CordService tService = getCordService(tServiceId);
233 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800234
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800235 if (tService == null || pService == null) {
236 log.error("Failed to create CordService for {}", tServiceId.id());
237 return;
238 }
239
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800240 log.info("Service dependency from {} to {} removed.", tService.id().id(), pService.id().id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800241 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800242 }
243
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800244 @Override
245 public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
246 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
247 OpenstackPort vPort = openstackService.port(port);
248 if (vPort == null) {
249 log.warn("Failed to get OpenstackPort for {}", getPortName(port));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800250 return;
251 }
252
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800253 MacAddress mac = vPort.macAddress();
254 HostId hostId = HostId.hostId(mac);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800255
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800256 Host host = hostService.getHost(hostId);
257 if (host != null) {
258 // Host is already known to the system, no HOST_ADDED event is triggered in this case.
259 // It happens when the application is restarted.
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800260 String vmId = host.annotations().value(OPENSTACK_VM_ID);
261 if (vmId != null && vmId.equals(vPort.deviceId())) {
262 serviceVmAdded(host);
263 return;
264 } else {
265 hostProvider.hostVanished(host.id());
266 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800267 }
268
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800269 Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800270 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800271 .set(SERVICE_ID, vPort.networkId())
Hyunsun Moon6d247342016-02-12 12:48:47 -0800272 .set(OPENSTACK_VM_ID, vPort.deviceId())
273 .set(OPENSTACK_PORT_ID, vPort.id())
274 .set(DATA_PLANE_IP, node.dpIp().ip().toString())
275 .set(DATA_PLANE_INTF, node.dpIntf());
276
277 String serviceVlan = getServiceVlan(vPort);
278 if (serviceVlan != null) {
279 annotations.set(S_TAG, serviceVlan);
280 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800281
282 HostDescription hostDesc = new DefaultHostDescription(
283 mac,
284 VlanId.NONE,
285 new HostLocation(connectPoint, System.currentTimeMillis()),
286 ip,
Hyunsun Moon6d247342016-02-12 12:48:47 -0800287 annotations.build());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800288
289 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800290 }
291
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800292 @Override
293 public void removeServiceVm(ConnectPoint connectPoint) {
294 Host host = hostService.getConnectedHosts(connectPoint)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800295 .stream()
296 .findFirst()
297 .orElse(null);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800298
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800299 if (host == null) {
300 log.debug("No host is connected on {}", connectPoint.toString());
301 return;
302 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800303
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800304 hostProvider.hostVanished(host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800305 }
306
Hyunsun Moon6d247342016-02-12 12:48:47 -0800307 @Override
308 public void updateVirtualSubscriberGateways(HostId vSgHostId, String serviceVlan,
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800309 Map<IpAddress, MacAddress> vSgs) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800310 Host vSgVm = hostService.getHost(vSgHostId);
311
312 if (vSgVm == null || !vSgVm.annotations().value(S_TAG).equals(serviceVlan)) {
313 log.debug("Invalid vSG updates for {}", serviceVlan);
314 return;
315 }
316
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800317 log.info("Updates vSGs in {} with {}", vSgVm.id(), vSgs.toString());
318 vSgs.entrySet().stream()
319 .forEach(entry -> addVirtualSubscriberGateway(
320 vSgVm,
321 entry.getKey(),
322 entry.getValue(),
323 serviceVlan));
324
325 ruleInstaller.populateSubscriberGatewayRules(vSgVm, vSgs.keySet());
326 }
327
328 /**
329 * Adds virtual subscriber gateway to the system.
330 *
331 * @param vSgHost host virtual machine of this vSG
332 * @param vSgIp vSG ip address
333 * @param vSgMac vSG mac address
334 * @param serviceVlan service vlan
335 */
336 public void addVirtualSubscriberGateway(Host vSgHost, IpAddress vSgIp, MacAddress vSgMac, String serviceVlan) {
337 HostId hostId = HostId.hostId(vSgMac);
338 Host host = hostService.getHost(hostId);
339 if (host != null) {
340 log.debug("vSG with {} already exists", vSgMac.toString());
341 return;
342 }
343
344 log.info("vSG with IP({}) MAC({}) detected", vSgIp.toString(), vSgMac.toString());
345 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
346 .set(S_TAG, serviceVlan);
347
348 HostDescription hostDesc = new DefaultHostDescription(
349 vSgMac,
350 VlanId.NONE,
351 vSgHost.location(),
352 Sets.newHashSet(vSgIp),
353 annotations.build());
354
355 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800356 }
357
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800358 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800359 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800360 *
361 * @param serviceId service id
362 * @return cord service, or null if it fails to get network from OpenStack
363 */
364 private CordService getCordService(CordServiceId serviceId) {
365 OpenstackNetwork vNet = openstackService.network(serviceId.id());
366 if (vNet == null) {
367 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
368 return null;
369 }
370
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800371 OpenstackSubnet subnet = vNet.subnets().stream()
372 .findFirst()
373 .orElse(null);
374 if (subnet == null) {
375 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
376 return null;
377 }
378
379 Set<CordServiceId> tServices = Sets.newHashSet();
380 // TODO get tenant services from XOS
381
382 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
383 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800384 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800385
386 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800387 }
388
389 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800390 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800391 *
392 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800393 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800394 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800395 private CordService getCordService(OpenstackNetwork vNet) {
396 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800397
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800398 CordServiceId serviceId = CordServiceId.of(vNet.id());
399 OpenstackSubnet subnet = vNet.subnets().stream()
400 .findFirst()
401 .orElse(null);
402 if (subnet == null) {
403 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
404 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800405 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800406
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800407 Set<CordServiceId> tServices = Sets.newHashSet();
408 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800409
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800410 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
411 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800412 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800413
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800414 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800415 }
416
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800417 /**
418 * Returns IP address for tunneling for a given host.
419 *
420 * @param host host
Hyunsun Moon6d247342016-02-12 12:48:47 -0800421 * @return ip address, or null
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800422 */
423 private IpAddress getTunnelIp(Host host) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800424 String ip = host.annotations().value(DATA_PLANE_IP);
425 return ip == null ? null : IpAddress.valueOf(ip);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800426 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700427
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800428 /**
429 * Returns port name.
430 *
431 * @param port port
432 * @return port name
433 */
434 private String getPortName(Port port) {
435 return port.annotations().value("portName");
436 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800437
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800438 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800439 * Returns s-tag from a given OpenStack port.
440 *
441 * @param vPort openstack port
442 * @return s-tag string
443 */
444 private String getServiceVlan(OpenstackPort vPort) {
445 checkNotNull(vPort);
446
447 if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
448 return vPort.name().split("-")[1];
449 } else {
450 return null;
451 }
452 }
453
454 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800455 * Returns hosts associated with a given OpenStack network.
456 *
457 * @param vNet openstack network
458 * @return set of hosts
459 */
460 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
461 checkNotNull(vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700462
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800463 Set<Host> hosts = openstackService.ports(vNet.id()).stream()
464 .filter(port -> port.deviceOwner().contains("compute"))
465 .map(port -> hostService.getHostsByMac(port.macAddress())
466 .stream()
467 .findFirst()
468 .orElse(null))
469 .collect(Collectors.toSet());
470
471 hosts.remove(null);
472 return hosts;
473 }
474
475 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800476 * Returns public ip addresses of vSGs running inside a give vSG host.
477 *
478 * @param vSgHost vSG host
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800479 * @return map of ip and mac address, or empty map
Hyunsun Moon6d247342016-02-12 12:48:47 -0800480 */
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800481 private Map<IpAddress, MacAddress> getSubscriberGateways(Host vSgHost) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800482 String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
483 String serviceVlan = vSgHost.annotations().value(S_TAG);
484
485 OpenstackPort vPort = openstackService.port(vPortId);
486 if (vPort == null) {
487 log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800488 return Maps.newHashMap();
Hyunsun Moon6d247342016-02-12 12:48:47 -0800489 }
490
491 if (!serviceVlan.equals(getServiceVlan(vPort))) {
492 log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800493 return Maps.newHashMap();
Hyunsun Moon6d247342016-02-12 12:48:47 -0800494 }
495
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800496 return vPort.allowedAddressPairs();
Hyunsun Moon6d247342016-02-12 12:48:47 -0800497 }
498
499 /**
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800500 * Registers static DHCP lease for a given host.
501 *
502 * @param host host
503 * @param service cord service
504 */
505 private void registerDhcpLease(Host host, CordService service) {
506 List<Ip4Address> options = Lists.newArrayList();
507 options.add(Ip4Address.makeMaskPrefix(service.serviceIpRange().prefixLength()));
508 options.add(service.serviceIp().getIp4Address());
509 options.add(service.serviceIp().getIp4Address());
510 options.add(DEFAULT_DNS);
511
512 log.debug("Set static DHCP mapping for {}", host.mac());
513 dhcpService.setStaticMapping(host.mac(),
514 host.ipAddresses().stream().findFirst().get().getIp4Address(),
515 true,
516 options);
517 }
518
519 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800520 * Handles VM detected situation.
521 *
522 * @param host host
523 */
524 private void serviceVmAdded(Host host) {
525 String vNetId = host.annotations().value(SERVICE_ID);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800526 if (vNetId == null) {
527 // ignore this host, it not a VM we injected or a vSG
528 return;
529 }
530
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800531 OpenstackNetwork vNet = openstackService.network(vNetId);
532 if (vNet == null) {
533 log.warn("Failed to get OpenStack network {} for VM {}({}).",
534 vNetId,
535 host.id(),
536 host.annotations().value(OPENSTACK_VM_ID));
537 return;
538 }
539
540 log.info("VM {} is detected, MAC: {} IP: {}",
541 host.annotations().value(OPENSTACK_VM_ID),
542 host.mac(),
543 host.ipAddresses().stream().findFirst().get());
544
545 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800546 if (service == null) {
547 return;
548 }
549
550 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
551 ruleInstaller.populateManagementNetworkRules(host, service);
552 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800553 // TODO check if the service needs an update on its group buckets after done CORD-433
554 ruleInstaller.updateServiceGroup(service);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800555 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800556
557 // sends gratuitous ARP here for the case of adding existing VMs
558 // when ONOS or cordvtn app is restarted
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800559 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), Sets.newHashSet(host));
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800560 }
561
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800562 registerDhcpLease(host, service);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800563 ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
564
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800565 String serviceVlan = host.annotations().value(S_TAG);
566 if (serviceVlan != null) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800567 log.debug("vSG VM detected {}", host.id());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800568 Map<IpAddress, MacAddress> vSgs = getSubscriberGateways(host);
569 vSgs.entrySet().stream()
570 .forEach(entry -> addVirtualSubscriberGateway(
571 host,
572 entry.getKey(),
573 entry.getValue(),
574 serviceVlan));
575
576 ruleInstaller.populateSubscriberGatewayRules(host, vSgs.keySet());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800577 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800578 }
579
580 /**
581 * Handles VM removed situation.
582 *
583 * @param host host
584 */
585 private void serviceVmRemoved(Host host) {
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800586 if (host.annotations().value(OPENSTACK_VM_ID) == null) {
587 // this host was not injected from CordVtn, just return
588 return;
589 }
590
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800591 String vNetId = host.annotations().value(SERVICE_ID);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800592 OpenstackNetwork vNet = openstackService.network(vNetId);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800593 if (vNet == null) {
594 log.warn("Failed to get OpenStack network {} for VM {}({}).",
595 vNetId,
596 host.id(),
597 host.annotations().value(OPENSTACK_VM_ID));
598 return;
599 }
600
601 log.info("VM {} is vanished, MAC: {} IP: {}",
602 host.annotations().value(OPENSTACK_VM_ID),
603 host.mac(),
604 host.ipAddresses().stream().findFirst().get());
605
606 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moonfb631b42016-02-03 14:44:06 -0800607 dhcpService.removeStaticMapping(host.mac());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800608
609 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800610 if (service == null) {
611 return;
612 }
613
614 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
615 ruleInstaller.removeManagementNetworkRules(host, service);
616 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800617 // TODO check if the service needs an update on its group buckets after done CORD-433
618 ruleInstaller.updateServiceGroup(service);
619
620 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800621 arpProxy.removeGateway(service.serviceIp());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700622 }
623 }
624 }
625
Hyunsun Moon746956f2016-01-24 21:47:06 -0800626 /**
627 * Sets service network gateway MAC address and sends out gratuitous ARP to all
628 * VMs to update the gateway MAC address.
629 *
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800630 * @param newMac mac address to update
Hyunsun Moon746956f2016-01-24 21:47:06 -0800631 */
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800632 private void setPrivateGatewayMac(MacAddress newMac) {
633 if (newMac == null || newMac.equals(privateGatewayMac)) {
634 // no updates, do nothing
635 return;
Hyunsun Moon746956f2016-01-24 21:47:06 -0800636 }
637
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800638 privateGatewayMac = newMac;
639 log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
640
Hyunsun Moon746956f2016-01-24 21:47:06 -0800641 // TODO get existing service list from XOS and replace the loop below
642 Set<String> vNets = Sets.newHashSet();
643 hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
644 vNets.remove(null);
645
646 vNets.stream().forEach(vNet -> {
647 CordService service = getCordService(CordServiceId.of(vNet));
648 if (service != null) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800649 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
650 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), service.hosts().keySet());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800651 }
652 });
653 }
654
655 /**
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800656 * Sets public gateway MAC address.
657 *
658 * @param publicGateways gateway ip and mac address pairs
659 */
660 private void setPublicGatewayMac(Map<IpAddress, MacAddress> publicGateways) {
661 publicGateways.entrySet()
662 .stream()
663 .forEach(entry -> {
664 arpProxy.addGateway(entry.getKey(), entry.getValue());
665 log.debug("Added public gateway IP {}, MAC {}",
666 entry.getKey().toString(), entry.getValue().toString());
667 });
668 // TODO notice gateway MAC change to VMs holds this gateway IP
669 }
670
671 /**
Hyunsun Moon746956f2016-01-24 21:47:06 -0800672 * Updates configurations.
673 */
674 private void readConfiguration() {
675 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
676 if (config == null) {
677 log.debug("No configuration found");
678 return;
679 }
680
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800681 setPrivateGatewayMac(config.privateGatewayMac());
682 setPublicGatewayMac(config.publicGateways());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800683 }
684
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700685 private class InternalHostListener implements HostListener {
686
687 @Override
688 public void event(HostEvent event) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800689 Host host = event.subject();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700690
691 switch (event.type()) {
692 case HOST_ADDED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800693 eventExecutor.submit(() -> serviceVmAdded(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700694 break;
695 case HOST_REMOVED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800696 eventExecutor.submit(() -> serviceVmRemoved(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700697 break;
698 default:
699 break;
700 }
701 }
702 }
703
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800704 private class InternalPacketProcessor implements PacketProcessor {
705
706 @Override
707 public void process(PacketContext context) {
708 if (context.isHandled()) {
709 return;
710 }
711
712 Ethernet ethPacket = context.inPacket().parsed();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800713 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800714 return;
715 }
716
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800717 arpProxy.processArpPacket(context, ethPacket);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800718 }
719 }
720
721 private class InternalConfigListener implements NetworkConfigListener {
722
723 @Override
724 public void event(NetworkConfigEvent event) {
725 if (!event.configClass().equals(CordVtnConfig.class)) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800726 return;
727 }
728
Hyunsun Moon746956f2016-01-24 21:47:06 -0800729 switch (event.type()) {
730 case CONFIG_ADDED:
731 case CONFIG_UPDATED:
732 log.info("Network configuration changed");
733 eventExecutor.execute(CordVtn.this::readConfiguration);
734 break;
735 default:
736 break;
737 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800738 }
739 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700740}