blob: 400c6ce9a236de0948d96c0d477d103e535fbdc8 [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;
sangho0c2a3da2016-02-16 13:39:07 +090065import org.onosproject.openstacknetworking.OpenstackNetworkingService;
66import org.onosproject.openstacknetworking.OpenstackNetwork;
67import org.onosproject.openstacknetworking.OpenstackPort;
68import org.onosproject.openstacknetworking.OpenstackSubnet;
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)
sangho0c2a3da2016-02-16 13:39:07 +0900126 protected OpenstackNetworkingService openstackService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800127
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) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800294 hostService.getConnectedHosts(connectPoint)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800295 .stream()
Hyunsun Moon2a225162016-02-17 19:00:50 -0800296 .forEach(host -> hostProvider.hostVanished(host.id()));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800297 }
298
Hyunsun Moon6d247342016-02-12 12:48:47 -0800299 @Override
300 public void updateVirtualSubscriberGateways(HostId vSgHostId, String serviceVlan,
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800301 Map<IpAddress, MacAddress> vSgs) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800302 Host vSgVm = hostService.getHost(vSgHostId);
303
304 if (vSgVm == null || !vSgVm.annotations().value(S_TAG).equals(serviceVlan)) {
305 log.debug("Invalid vSG updates for {}", serviceVlan);
306 return;
307 }
308
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800309 log.info("Updates vSGs in {} with {}", vSgVm.id(), vSgs.toString());
310 vSgs.entrySet().stream()
311 .forEach(entry -> addVirtualSubscriberGateway(
312 vSgVm,
313 entry.getKey(),
314 entry.getValue(),
315 serviceVlan));
316
Hyunsun Moon2a225162016-02-17 19:00:50 -0800317 hostService.getConnectedHosts(vSgVm.location()).stream()
318 .filter(host -> !host.mac().equals(vSgVm.mac()))
319 .filter(host -> !vSgs.values().contains(host.mac()))
320 .forEach(host -> {
321 log.info("Removed vSG {}", host.toString());
322 hostProvider.hostVanished(host.id());
323 });
324
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800325 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 */
Hyunsun Moon2a225162016-02-17 19:00:50 -0800336 private void addVirtualSubscriberGateway(Host vSgHost, IpAddress vSgIp, MacAddress vSgMac,
337 String serviceVlan) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800338 HostId hostId = HostId.hostId(vSgMac);
339 Host host = hostService.getHost(hostId);
340 if (host != null) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800341 log.trace("vSG with {} already exists", vSgMac.toString());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800342 return;
343 }
344
345 log.info("vSG with IP({}) MAC({}) detected", vSgIp.toString(), vSgMac.toString());
346 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
347 .set(S_TAG, serviceVlan);
348
349 HostDescription hostDesc = new DefaultHostDescription(
350 vSgMac,
351 VlanId.NONE,
352 vSgHost.location(),
353 Sets.newHashSet(vSgIp),
354 annotations.build());
355
356 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800357 }
358
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800359 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800360 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800361 *
362 * @param serviceId service id
363 * @return cord service, or null if it fails to get network from OpenStack
364 */
365 private CordService getCordService(CordServiceId serviceId) {
366 OpenstackNetwork vNet = openstackService.network(serviceId.id());
367 if (vNet == null) {
368 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
369 return null;
370 }
371
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800372 OpenstackSubnet subnet = vNet.subnets().stream()
373 .findFirst()
374 .orElse(null);
375 if (subnet == null) {
376 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
377 return null;
378 }
379
380 Set<CordServiceId> tServices = Sets.newHashSet();
381 // TODO get tenant services from XOS
382
383 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
384 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800385 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800386
387 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800388 }
389
390 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800391 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800392 *
393 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800394 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800395 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800396 private CordService getCordService(OpenstackNetwork vNet) {
397 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800398
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800399 CordServiceId serviceId = CordServiceId.of(vNet.id());
400 OpenstackSubnet subnet = vNet.subnets().stream()
401 .findFirst()
402 .orElse(null);
403 if (subnet == null) {
404 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
405 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800406 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800407
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800408 Set<CordServiceId> tServices = Sets.newHashSet();
409 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800410
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800411 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
412 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800413 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800414
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800415 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800416 }
417
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800418 /**
419 * Returns IP address for tunneling for a given host.
420 *
421 * @param host host
Hyunsun Moon6d247342016-02-12 12:48:47 -0800422 * @return ip address, or null
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800423 */
424 private IpAddress getTunnelIp(Host host) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800425 String ip = host.annotations().value(DATA_PLANE_IP);
426 return ip == null ? null : IpAddress.valueOf(ip);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800427 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700428
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800429 /**
430 * Returns port name.
431 *
432 * @param port port
433 * @return port name
434 */
435 private String getPortName(Port port) {
436 return port.annotations().value("portName");
437 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800438
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800439 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800440 * Returns s-tag from a given OpenStack port.
441 *
442 * @param vPort openstack port
443 * @return s-tag string
444 */
445 private String getServiceVlan(OpenstackPort vPort) {
446 checkNotNull(vPort);
447
448 if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
449 return vPort.name().split("-")[1];
450 } else {
451 return null;
452 }
453 }
454
455 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800456 * Returns hosts associated with a given OpenStack network.
457 *
458 * @param vNet openstack network
459 * @return set of hosts
460 */
461 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
462 checkNotNull(vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700463
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800464 Set<Host> hosts = openstackService.ports(vNet.id()).stream()
465 .filter(port -> port.deviceOwner().contains("compute"))
466 .map(port -> hostService.getHostsByMac(port.macAddress())
467 .stream()
468 .findFirst()
469 .orElse(null))
470 .collect(Collectors.toSet());
471
472 hosts.remove(null);
473 return hosts;
474 }
475
476 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800477 * Returns public ip addresses of vSGs running inside a give vSG host.
478 *
479 * @param vSgHost vSG host
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800480 * @return map of ip and mac address, or empty map
Hyunsun Moon6d247342016-02-12 12:48:47 -0800481 */
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800482 private Map<IpAddress, MacAddress> getSubscriberGateways(Host vSgHost) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800483 String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
484 String serviceVlan = vSgHost.annotations().value(S_TAG);
485
486 OpenstackPort vPort = openstackService.port(vPortId);
487 if (vPort == null) {
488 log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800489 return Maps.newHashMap();
Hyunsun Moon6d247342016-02-12 12:48:47 -0800490 }
491
492 if (!serviceVlan.equals(getServiceVlan(vPort))) {
493 log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800494 return Maps.newHashMap();
Hyunsun Moon6d247342016-02-12 12:48:47 -0800495 }
496
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800497 return vPort.allowedAddressPairs();
Hyunsun Moon6d247342016-02-12 12:48:47 -0800498 }
499
500 /**
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800501 * Registers static DHCP lease for a given host.
502 *
503 * @param host host
504 * @param service cord service
505 */
506 private void registerDhcpLease(Host host, CordService service) {
507 List<Ip4Address> options = Lists.newArrayList();
508 options.add(Ip4Address.makeMaskPrefix(service.serviceIpRange().prefixLength()));
509 options.add(service.serviceIp().getIp4Address());
510 options.add(service.serviceIp().getIp4Address());
511 options.add(DEFAULT_DNS);
512
513 log.debug("Set static DHCP mapping for {}", host.mac());
514 dhcpService.setStaticMapping(host.mac(),
515 host.ipAddresses().stream().findFirst().get().getIp4Address(),
516 true,
517 options);
518 }
519
520 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800521 * Handles VM detected situation.
522 *
523 * @param host host
524 */
525 private void serviceVmAdded(Host host) {
526 String vNetId = host.annotations().value(SERVICE_ID);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800527 if (vNetId == null) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800528 // ignore this host, it is not the service VM, or it's a vSG
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800529 return;
530 }
531
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800532 OpenstackNetwork vNet = openstackService.network(vNetId);
533 if (vNet == null) {
534 log.warn("Failed to get OpenStack network {} for VM {}({}).",
535 vNetId,
536 host.id(),
537 host.annotations().value(OPENSTACK_VM_ID));
538 return;
539 }
540
541 log.info("VM {} is detected, MAC: {} IP: {}",
542 host.annotations().value(OPENSTACK_VM_ID),
543 host.mac(),
544 host.ipAddresses().stream().findFirst().get());
545
546 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800547 if (service == null) {
548 return;
549 }
550
551 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
552 ruleInstaller.populateManagementNetworkRules(host, service);
553 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800554 // TODO check if the service needs an update on its group buckets after done CORD-433
555 ruleInstaller.updateServiceGroup(service);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800556 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800557
558 // sends gratuitous ARP here for the case of adding existing VMs
559 // when ONOS or cordvtn app is restarted
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800560 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), Sets.newHashSet(host));
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800561 }
562
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800563 registerDhcpLease(host, service);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800564 ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
565
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800566 String serviceVlan = host.annotations().value(S_TAG);
567 if (serviceVlan != null) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800568 log.debug("vSG VM detected {}", host.id());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800569 Map<IpAddress, MacAddress> vSgs = getSubscriberGateways(host);
570 vSgs.entrySet().stream()
571 .forEach(entry -> addVirtualSubscriberGateway(
572 host,
573 entry.getKey(),
574 entry.getValue(),
575 serviceVlan));
576
577 ruleInstaller.populateSubscriberGatewayRules(host, vSgs.keySet());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800578 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800579 }
580
581 /**
582 * Handles VM removed situation.
583 *
584 * @param host host
585 */
586 private void serviceVmRemoved(Host host) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800587 String vNetId = host.annotations().value(SERVICE_ID);
588 if (vNetId == null) {
589 // ignore it, it's not the service VM or it's a vSG
590 String serviceVlan = host.annotations().value(S_TAG);
591 if (serviceVlan != null) {
592 log.info("vSG {} removed", host.id());
593 }
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800594 return;
595 }
596
Hyunsun Moon6d247342016-02-12 12:48:47 -0800597 OpenstackNetwork vNet = openstackService.network(vNetId);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800598 if (vNet == null) {
599 log.warn("Failed to get OpenStack network {} for VM {}({}).",
600 vNetId,
601 host.id(),
602 host.annotations().value(OPENSTACK_VM_ID));
603 return;
604 }
605
606 log.info("VM {} is vanished, MAC: {} IP: {}",
607 host.annotations().value(OPENSTACK_VM_ID),
608 host.mac(),
609 host.ipAddresses().stream().findFirst().get());
610
611 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moonfb631b42016-02-03 14:44:06 -0800612 dhcpService.removeStaticMapping(host.mac());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800613
614 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800615 if (service == null) {
616 return;
617 }
618
619 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
620 ruleInstaller.removeManagementNetworkRules(host, service);
621 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800622 // TODO check if the service needs an update on its group buckets after done CORD-433
623 ruleInstaller.updateServiceGroup(service);
624
625 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800626 arpProxy.removeGateway(service.serviceIp());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700627 }
628 }
629 }
630
Hyunsun Moon746956f2016-01-24 21:47:06 -0800631 /**
632 * Sets service network gateway MAC address and sends out gratuitous ARP to all
633 * VMs to update the gateway MAC address.
634 *
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800635 * @param newMac mac address to update
Hyunsun Moon746956f2016-01-24 21:47:06 -0800636 */
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800637 private void setPrivateGatewayMac(MacAddress newMac) {
638 if (newMac == null || newMac.equals(privateGatewayMac)) {
639 // no updates, do nothing
640 return;
Hyunsun Moon746956f2016-01-24 21:47:06 -0800641 }
642
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800643 privateGatewayMac = newMac;
644 log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
645
Hyunsun Moon746956f2016-01-24 21:47:06 -0800646 // TODO get existing service list from XOS and replace the loop below
647 Set<String> vNets = Sets.newHashSet();
648 hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
649 vNets.remove(null);
650
651 vNets.stream().forEach(vNet -> {
652 CordService service = getCordService(CordServiceId.of(vNet));
653 if (service != null) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800654 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
655 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), service.hosts().keySet());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800656 }
657 });
658 }
659
660 /**
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800661 * Sets public gateway MAC address.
662 *
663 * @param publicGateways gateway ip and mac address pairs
664 */
665 private void setPublicGatewayMac(Map<IpAddress, MacAddress> publicGateways) {
666 publicGateways.entrySet()
667 .stream()
668 .forEach(entry -> {
669 arpProxy.addGateway(entry.getKey(), entry.getValue());
670 log.debug("Added public gateway IP {}, MAC {}",
671 entry.getKey().toString(), entry.getValue().toString());
672 });
673 // TODO notice gateway MAC change to VMs holds this gateway IP
674 }
675
676 /**
Hyunsun Moon746956f2016-01-24 21:47:06 -0800677 * Updates configurations.
678 */
679 private void readConfiguration() {
680 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
681 if (config == null) {
682 log.debug("No configuration found");
683 return;
684 }
685
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800686 setPrivateGatewayMac(config.privateGatewayMac());
687 setPublicGatewayMac(config.publicGateways());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800688 }
689
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700690 private class InternalHostListener implements HostListener {
691
692 @Override
693 public void event(HostEvent event) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800694 Host host = event.subject();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700695
696 switch (event.type()) {
697 case HOST_ADDED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800698 eventExecutor.submit(() -> serviceVmAdded(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700699 break;
700 case HOST_REMOVED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800701 eventExecutor.submit(() -> serviceVmRemoved(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700702 break;
703 default:
704 break;
705 }
706 }
707 }
708
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800709 private class InternalPacketProcessor implements PacketProcessor {
710
711 @Override
712 public void process(PacketContext context) {
713 if (context.isHandled()) {
714 return;
715 }
716
717 Ethernet ethPacket = context.inPacket().parsed();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800718 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800719 return;
720 }
721
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800722 arpProxy.processArpPacket(context, ethPacket);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800723 }
724 }
725
726 private class InternalConfigListener implements NetworkConfigListener {
727
728 @Override
729 public void event(NetworkConfigEvent event) {
730 if (!event.configClass().equals(CordVtnConfig.class)) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800731 return;
732 }
733
Hyunsun Moon746956f2016-01-24 21:47:06 -0800734 switch (event.type()) {
735 case CONFIG_ADDED:
736 case CONFIG_UPDATED:
737 log.info("Network configuration changed");
738 eventExecutor.execute(CordVtn.this::readConfiguration);
739 break;
740 default:
741 break;
742 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800743 }
744 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700745}