blob: 967ca0237c60b6b2d43c79fe528dcda5c65432c0 [file] [log] [blame]
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Hyunsun Moond0e932a2015-09-15 22:39:16 -07003 *
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 */
Hyunsun Moon7f4ed9d2016-04-14 16:13:42 -070016package org.onosproject.cordvtn.impl;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070017
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 Moon7f4ed9d2016-04-14 16:13:42 -070032import org.onosproject.cordvtn.api.CordService;
33import org.onosproject.cordvtn.api.CordServiceId;
34import org.onosproject.cordvtn.api.CordVtnConfig;
35import org.onosproject.cordvtn.api.CordVtnNode;
36import org.onosproject.cordvtn.api.CordVtnService;
Hyunsun Moon1f145552015-10-08 22:25:30 -070037import org.onosproject.core.ApplicationId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070038import org.onosproject.core.CoreService;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080039import org.onosproject.dhcp.DhcpService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080040import org.onosproject.mastership.MastershipService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080041import org.onosproject.net.ConnectPoint;
Hyunsun Moond772f342015-10-28 20:28:16 -070042import org.onosproject.net.DefaultAnnotations;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070043import org.onosproject.net.Host;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080044import org.onosproject.net.HostId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080045import org.onosproject.net.HostLocation;
Hyunsun Moon8539b042015-11-07 22:08:43 -080046import org.onosproject.net.Port;
Hyunsun Moon746956f2016-01-24 21:47:06 -080047import org.onosproject.net.config.ConfigFactory;
48import org.onosproject.net.config.NetworkConfigEvent;
49import org.onosproject.net.config.NetworkConfigListener;
50import org.onosproject.net.config.NetworkConfigRegistry;
51import org.onosproject.net.config.NetworkConfigService;
52import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070053import org.onosproject.net.device.DeviceService;
Hyunsun Moond772f342015-10-28 20:28:16 -070054import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080055import org.onosproject.net.flow.FlowRuleService;
56import org.onosproject.net.group.GroupService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080057import org.onosproject.net.host.DefaultHostDescription;
58import org.onosproject.net.host.HostDescription;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070059import org.onosproject.net.host.HostEvent;
60import org.onosproject.net.host.HostListener;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080061import org.onosproject.net.host.HostProvider;
62import org.onosproject.net.host.HostProviderRegistry;
63import org.onosproject.net.host.HostProviderService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070064import org.onosproject.net.host.HostService;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080065import org.onosproject.net.packet.PacketContext;
66import org.onosproject.net.packet.PacketProcessor;
67import org.onosproject.net.packet.PacketService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080068import org.onosproject.net.provider.AbstractProvider;
69import org.onosproject.net.provider.ProviderId;
sangho93447f12016-02-24 00:33:22 +090070import org.onosproject.openstackinterface.OpenstackInterfaceService;
71import org.onosproject.openstackinterface.OpenstackNetwork;
72import org.onosproject.openstackinterface.OpenstackPort;
73import org.onosproject.openstackinterface.OpenstackSubnet;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070074import org.slf4j.Logger;
75
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080076import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070077import java.util.Map;
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -080078import java.util.Objects;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080079import java.util.Set;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070080import java.util.concurrent.ExecutorService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080081import java.util.stream.Collectors;
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -080082import java.util.stream.StreamSupport;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070083
Hyunsun Moon1f145552015-10-08 22:25:30 -070084import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon746956f2016-01-24 21:47:06 -080085import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070086import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070087import static org.slf4j.LoggerFactory.getLogger;
88
89/**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080090 * Provisions virtual tenant networks with service chaining capability
91 * in OpenStack environment.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070092 */
93@Component(immediate = true)
94@Service
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080095public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider {
Hyunsun Moond0e932a2015-09-15 22:39:16 -070096
97 protected final Logger log = getLogger(getClass());
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected CoreService coreService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon746956f2016-01-24 21:47:06 -0800103 protected NetworkConfigRegistry configRegistry;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected NetworkConfigService configService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800109 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700112 protected DeviceService deviceService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected HostService hostService;
116
Hyunsun Moon1f145552015-10-08 22:25:30 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700118 protected DriverService driverService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800121 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800124 protected PacketService packetService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800127 protected MastershipService mastershipService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected GroupService groupService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +0900133 protected OpenstackInterfaceService openstackService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800134
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected DhcpService dhcpService;
137
Hyunsun Moon746956f2016-01-24 21:47:06 -0800138 private final ConfigFactory configFactory =
139 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
140 @Override
141 public CordVtnConfig createConfig() {
142 return new CordVtnConfig();
143 }
144 };
145
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800146 private static final String DEFAULT_TUNNEL = "vxlan";
147 private static final String SERVICE_ID = "serviceId";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800148 private static final String OPENSTACK_PORT_ID = "openstackPortId";
149 private static final String DATA_PLANE_IP = "dataPlaneIp";
150 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
151 private static final String S_TAG = "stag";
Hyunsun Moon98025542016-03-08 04:36:02 -0800152 private static final String VSG_HOST_ID = "vsgHostId";
Hyunsun Moond35420f2016-03-08 21:59:13 -0800153 private static final String CREATED_TIME = "createdTime";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800154
155 private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800156
Hyunsun Moon746956f2016-01-24 21:47:06 -0800157 private final ExecutorService eventExecutor =
158 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700159
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800160 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800161 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800162 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700163
Hyunsun Moon746956f2016-01-24 21:47:06 -0800164 private ApplicationId appId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800165 private HostProviderService hostProvider;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800166 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800167 private CordVtnArpProxy arpProxy;
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800168 private volatile MacAddress privateGatewayMac = MacAddress.NONE;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800169
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800170 /**
171 * Creates an cordvtn host location provider.
172 */
173 public CordVtn() {
174 super(new ProviderId("host", CORDVTN_APP_ID));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800175 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700176
177 @Activate
178 protected void activate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800179 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800180 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
181 deviceService,
182 driverService,
183 groupService,
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800184 configRegistry,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800185 DEFAULT_TUNNEL);
186
Hyunsun Moon9cf43db2016-02-12 15:59:53 -0800187 arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800188 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
189 arpProxy.requestPacket();
190
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700191 hostService.addListener(hostListener);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800192 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700193
Hyunsun Moon746956f2016-01-24 21:47:06 -0800194 configRegistry.registerConfigFactory(configFactory);
195 configService.addListener(configListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800196
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700197 log.info("Started");
198 }
199
200 @Deactivate
201 protected void deactivate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800202 hostProviderRegistry.unregister(this);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700203 hostService.removeListener(hostListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800204
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800205 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700206
Hyunsun Moon746956f2016-01-24 21:47:06 -0800207 configRegistry.unregisterConfigFactory(configFactory);
208 configService.removeListener(configListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700209
Hyunsun Moon746956f2016-01-24 21:47:06 -0800210 eventExecutor.shutdown();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700211 log.info("Stopped");
212 }
213
214 @Override
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800215 public void triggerProbe(Host host) {
216 /*
217 * Note: In CORD deployment, we assume that all hosts are configured.
218 * Therefore no probe is required.
219 */
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800220 }
221
222 @Override
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800223 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId,
224 boolean isBidirectional) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800225 CordService tService = getCordService(tServiceId);
226 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800227
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800228 if (tService == null || pService == null) {
229 log.error("Failed to create CordService for {}", tServiceId.id());
230 return;
231 }
232
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800233 log.info("Service dependency from {} to {} created.", tService.id().id(), pService.id().id());
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800234 ruleInstaller.populateServiceDependencyRules(tService, pService, isBidirectional);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800235 }
236
237 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800238 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
239 CordService tService = getCordService(tServiceId);
240 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800241
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800242 if (tService == null || pService == null) {
243 log.error("Failed to create CordService for {}", tServiceId.id());
244 return;
245 }
246
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800247 log.info("Service dependency from {} to {} removed.", tService.id().id(), pService.id().id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800248 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800249 }
250
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800251 @Override
252 public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
253 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
254 OpenstackPort vPort = openstackService.port(port);
255 if (vPort == null) {
256 log.warn("Failed to get OpenstackPort for {}", getPortName(port));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800257 return;
258 }
259
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800260 MacAddress mac = vPort.macAddress();
261 HostId hostId = HostId.hostId(mac);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800262
Hyunsun Moond35420f2016-03-08 21:59:13 -0800263 Host existingHost = hostService.getHost(hostId);
264 if (existingHost != null) {
265 String serviceId = existingHost.annotations().value(SERVICE_ID);
266 if (serviceId == null || !serviceId.equals(vPort.networkId())) {
267 // this host is not injected by cordvtn or a stale host, remove it
268 hostProvider.hostVanished(existingHost.id());
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800269 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800270 }
271
Hyunsun Moond35420f2016-03-08 21:59:13 -0800272 // Included CREATED_TIME to annotation intentionally to trigger HOST_UPDATED
273 // event so that the flow rule population for this host can happen.
274 // This ensures refreshing data plane by pushing network config always make
275 // the data plane synced.
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800276 Set<IpAddress> fixedIp = Sets.newHashSet(vPort.fixedIps().values());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800277 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800278 .set(SERVICE_ID, vPort.networkId())
Hyunsun Moon6d247342016-02-12 12:48:47 -0800279 .set(OPENSTACK_PORT_ID, vPort.id())
280 .set(DATA_PLANE_IP, node.dpIp().ip().toString())
Hyunsun Moond35420f2016-03-08 21:59:13 -0800281 .set(DATA_PLANE_INTF, node.dpIntf())
282 .set(CREATED_TIME, String.valueOf(System.currentTimeMillis()));
Hyunsun Moon6d247342016-02-12 12:48:47 -0800283
284 String serviceVlan = getServiceVlan(vPort);
285 if (serviceVlan != null) {
286 annotations.set(S_TAG, serviceVlan);
287 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800288
289 HostDescription hostDesc = new DefaultHostDescription(
290 mac,
291 VlanId.NONE,
292 new HostLocation(connectPoint, System.currentTimeMillis()),
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800293 fixedIp,
Hyunsun Moon6d247342016-02-12 12:48:47 -0800294 annotations.build());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800295
296 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800297 }
298
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800299 @Override
300 public void removeServiceVm(ConnectPoint connectPoint) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800301 hostService.getConnectedHosts(connectPoint)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800302 .stream()
Hyunsun Moon2a225162016-02-17 19:00:50 -0800303 .forEach(host -> hostProvider.hostVanished(host.id()));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800304 }
305
Hyunsun Moon6d247342016-02-12 12:48:47 -0800306 @Override
307 public void updateVirtualSubscriberGateways(HostId vSgHostId, String serviceVlan,
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800308 Map<IpAddress, MacAddress> vSgs) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800309 Host vSgHost = hostService.getHost(vSgHostId);
310 if (vSgHost == null || !vSgHost.annotations().value(S_TAG).equals(serviceVlan)) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800311 log.debug("Invalid vSG updates for {}", serviceVlan);
312 return;
313 }
314
Hyunsun Moon98025542016-03-08 04:36:02 -0800315 log.info("Updates vSGs in {} with {}", vSgHost.id(), vSgs.toString());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800316 vSgs.entrySet().stream()
Hyunsun Moon98025542016-03-08 04:36:02 -0800317 .filter(entry -> hostService.getHostsByMac(entry.getValue()).isEmpty())
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800318 .forEach(entry -> addVirtualSubscriberGateway(
Hyunsun Moon98025542016-03-08 04:36:02 -0800319 vSgHost,
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800320 entry.getKey(),
321 entry.getValue(),
322 serviceVlan));
323
Hyunsun Moon98025542016-03-08 04:36:02 -0800324 hostService.getConnectedHosts(vSgHost.location()).stream()
325 .filter(host -> !host.mac().equals(vSgHost.mac()))
Hyunsun Moon2a225162016-02-17 19:00:50 -0800326 .filter(host -> !vSgs.values().contains(host.mac()))
327 .forEach(host -> {
328 log.info("Removed vSG {}", host.toString());
329 hostProvider.hostVanished(host.id());
330 });
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800331 }
332
333 /**
334 * Adds virtual subscriber gateway to the system.
335 *
336 * @param vSgHost host virtual machine of this vSG
337 * @param vSgIp vSG ip address
338 * @param vSgMac vSG mac address
339 * @param serviceVlan service vlan
340 */
Hyunsun Moon2a225162016-02-17 19:00:50 -0800341 private void addVirtualSubscriberGateway(Host vSgHost, IpAddress vSgIp, MacAddress vSgMac,
342 String serviceVlan) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800343 log.info("vSG with IP({}) MAC({}) added", vSgIp.toString(), vSgMac.toString());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800344
Hyunsun Moon98025542016-03-08 04:36:02 -0800345 HostId hostId = HostId.hostId(vSgMac);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800346 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moon98025542016-03-08 04:36:02 -0800347 .set(S_TAG, serviceVlan)
Hyunsun Moond35420f2016-03-08 21:59:13 -0800348 .set(VSG_HOST_ID, vSgHost.id().toString())
349 .set(CREATED_TIME, String.valueOf(System.currentTimeMillis()));
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800350
351 HostDescription hostDesc = new DefaultHostDescription(
352 vSgMac,
353 VlanId.NONE,
354 vSgHost.location(),
355 Sets.newHashSet(vSgIp),
356 annotations.build());
357
358 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800359 }
360
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800361 /**
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800362 * Returns public ip addresses of vSGs running inside a give vSG host.
363 *
364 * @param vSgHost vSG host
365 * @return map of ip and mac address, or empty map
366 */
367 private Map<IpAddress, MacAddress> getSubscriberGateways(Host vSgHost) {
368 String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
369 String serviceVlan = vSgHost.annotations().value(S_TAG);
370
371 OpenstackPort vPort = openstackService.port(vPortId);
372 if (vPort == null) {
373 log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
374 return Maps.newHashMap();
375 }
376
377 if (!serviceVlan.equals(getServiceVlan(vPort))) {
378 log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
379 return Maps.newHashMap();
380 }
381
382 return vPort.allowedAddressPairs();
383 }
384
385 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800386 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800387 *
388 * @param serviceId service id
389 * @return cord service, or null if it fails to get network from OpenStack
390 */
391 private CordService getCordService(CordServiceId serviceId) {
392 OpenstackNetwork vNet = openstackService.network(serviceId.id());
393 if (vNet == null) {
394 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
395 return null;
396 }
397
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800398 OpenstackSubnet subnet = vNet.subnets().stream()
399 .findFirst()
400 .orElse(null);
401 if (subnet == null) {
402 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
403 return null;
404 }
405
406 Set<CordServiceId> tServices = Sets.newHashSet();
407 // TODO get tenant services from XOS
408
409 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
410 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800411 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800412
413 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800414 }
415
416 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800417 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800418 *
419 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800420 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800421 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800422 private CordService getCordService(OpenstackNetwork vNet) {
423 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800424
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800425 CordServiceId serviceId = CordServiceId.of(vNet.id());
426 OpenstackSubnet subnet = vNet.subnets().stream()
427 .findFirst()
428 .orElse(null);
429 if (subnet == null) {
430 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
431 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800432 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800433
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800434 Set<CordServiceId> tServices = Sets.newHashSet();
435 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800436
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800437 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
438 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800439 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800440
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800441 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800442 }
443
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800444 /**
445 * Returns IP address for tunneling for a given host.
446 *
447 * @param host host
Hyunsun Moon6d247342016-02-12 12:48:47 -0800448 * @return ip address, or null
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800449 */
450 private IpAddress getTunnelIp(Host host) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800451 String ip = host.annotations().value(DATA_PLANE_IP);
452 return ip == null ? null : IpAddress.valueOf(ip);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800453 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700454
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800455 /**
456 * Returns port name.
457 *
458 * @param port port
459 * @return port name
460 */
461 private String getPortName(Port port) {
462 return port.annotations().value("portName");
463 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800464
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800465 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800466 * Returns s-tag from a given OpenStack port.
467 *
468 * @param vPort openstack port
469 * @return s-tag string
470 */
471 private String getServiceVlan(OpenstackPort vPort) {
472 checkNotNull(vPort);
473
474 if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
475 return vPort.name().split("-")[1];
476 } else {
477 return null;
478 }
479 }
480
481 /**
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800482 * Returns service ID of this host.
483 *
484 * @param host host
485 * @return service id, or null if not found
486 */
487 private String getServiceId(Host host) {
488 return host.annotations().value(SERVICE_ID);
489 }
490
491 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800492 * Returns hosts associated with a given OpenStack network.
493 *
494 * @param vNet openstack network
495 * @return set of hosts
496 */
497 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
498 checkNotNull(vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700499
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800500 String vNetId = vNet.id();
501 return StreamSupport.stream(hostService.getHosts().spliterator(), false)
502 .filter(host -> Objects.equals(vNetId, getServiceId(host)))
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800503 .collect(Collectors.toSet());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800504 }
505
506 /**
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800507 * Registers static DHCP lease for a given host.
508 *
509 * @param host host
510 * @param service cord service
511 */
512 private void registerDhcpLease(Host host, CordService service) {
513 List<Ip4Address> options = Lists.newArrayList();
514 options.add(Ip4Address.makeMaskPrefix(service.serviceIpRange().prefixLength()));
515 options.add(service.serviceIp().getIp4Address());
516 options.add(service.serviceIp().getIp4Address());
517 options.add(DEFAULT_DNS);
518
519 log.debug("Set static DHCP mapping for {}", host.mac());
520 dhcpService.setStaticMapping(host.mac(),
521 host.ipAddresses().stream().findFirst().get().getIp4Address(),
522 true,
523 options);
524 }
525
526 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800527 * Handles VM detected situation.
528 *
529 * @param host host
530 */
531 private void serviceVmAdded(Host host) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800532 String serviceVlan = host.annotations().value(S_TAG);
533 if (serviceVlan != null) {
534 virtualSubscriberGatewayAdded(host, serviceVlan);
535 }
536
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800537 String vNetId = host.annotations().value(SERVICE_ID);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800538 if (vNetId == null) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800539 // ignore this host, it is not the service VM, or it's a vSG
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800540 return;
541 }
542
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800543 OpenstackNetwork vNet = openstackService.network(vNetId);
544 if (vNet == null) {
Hyunsun Moond35420f2016-03-08 21:59:13 -0800545 log.warn("Failed to get OpenStack network {} for VM {}.",
546 vNetId, host.id());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800547 return;
548 }
549
Hyunsun Moond35420f2016-03-08 21:59:13 -0800550 log.info("VM is detected, MAC: {} IP: {}",
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800551 host.mac(),
552 host.ipAddresses().stream().findFirst().get());
553
554 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800555 if (service == null) {
556 return;
557 }
558
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800559 switch (service.serviceType()) {
560 case MANAGEMENT:
561 ruleInstaller.populateManagementNetworkRules(host, service);
562 break;
563 case PRIVATE:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800564 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
Hyunsun Moon098cda82016-03-03 13:27:44 -0800565 case PUBLIC:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800566 default:
567 // TODO check if the service needs an update on its group buckets after done CORD-433
568 ruleInstaller.updateServiceGroup(service);
569 // sends gratuitous ARP here for the case of adding existing VMs
570 // when ONOS or cordvtn app is restarted
571 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), Sets.newHashSet(host));
572 break;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800573 }
574
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800575 registerDhcpLease(host, service);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800576 ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800577 }
578
579 /**
580 * Handles VM removed situation.
581 *
582 * @param host host
583 */
584 private void serviceVmRemoved(Host host) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800585 String serviceVlan = host.annotations().value(S_TAG);
586 if (serviceVlan != null) {
587 virtualSubscriberGatewayRemoved(host);
588 }
589
Hyunsun Moon2a225162016-02-17 19:00:50 -0800590 String vNetId = host.annotations().value(SERVICE_ID);
591 if (vNetId == null) {
592 // ignore it, it's not the service VM or it's a vSG
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800593 return;
594 }
595
Hyunsun Moon6d247342016-02-12 12:48:47 -0800596 OpenstackNetwork vNet = openstackService.network(vNetId);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800597 if (vNet == null) {
Hyunsun Moond35420f2016-03-08 21:59:13 -0800598 log.warn("Failed to get OpenStack network {} for VM {}",
599 vNetId, host.id());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800600 return;
601 }
602
Hyunsun Moond35420f2016-03-08 21:59:13 -0800603 log.info("VM is vanished, MAC: {} IP: {}",
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800604 host.mac(),
605 host.ipAddresses().stream().findFirst().get());
606
607 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moonfb631b42016-02-03 14:44:06 -0800608 dhcpService.removeStaticMapping(host.mac());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800609
610 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800611 if (service == null) {
612 return;
613 }
614
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800615 switch (service.serviceType()) {
616 case MANAGEMENT:
617 ruleInstaller.removeManagementNetworkRules(host, service);
618 break;
619 case PRIVATE:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800620 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
621 arpProxy.removeGateway(service.serviceIp());
622 }
Hyunsun Moon098cda82016-03-03 13:27:44 -0800623 case PUBLIC:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800624 default:
625 // TODO check if the service needs an update on its group buckets after done CORD-433
626 ruleInstaller.updateServiceGroup(service);
627 break;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700628 }
629 }
630
Hyunsun Moon98025542016-03-08 04:36:02 -0800631
632 /**
633 * Handles virtual subscriber gateway VM or container.
634 *
635 * @param host new host with stag, it can be vsg VM or vsg
636 * @param serviceVlan service vlan
637 */
638 private void virtualSubscriberGatewayAdded(Host host, String serviceVlan) {
639 Map<IpAddress, MacAddress> vSgs;
640 Host vSgHost;
641
642 String vSgHostId = host.annotations().value(VSG_HOST_ID);
643 if (vSgHostId == null) {
644 log.debug("vSG VM detected {}", host.id());
645
646 vSgHost = host;
647 vSgs = getSubscriberGateways(vSgHost);
648 vSgs.entrySet().stream().forEach(entry -> addVirtualSubscriberGateway(
649 vSgHost,
650 entry.getKey(),
651 entry.getValue(),
652 serviceVlan));
653 } else {
654 vSgHost = hostService.getHost(HostId.hostId(vSgHostId));
655 if (vSgHost == null) {
656 return;
657 }
658
659 log.debug("vSG detected {}", host.id());
660 vSgs = getSubscriberGateways(vSgHost);
661 }
662
663 ruleInstaller.populateSubscriberGatewayRules(vSgHost, vSgs.keySet());
664 }
665
666 /**
667 * Handles virtual subscriber gateway removed.
668 *
669 * @param vSg vsg host to remove
670 */
671 private void virtualSubscriberGatewayRemoved(Host vSg) {
672 String vSgHostId = vSg.annotations().value(VSG_HOST_ID);
673 if (vSgHostId == null) {
674 return;
675 }
676
677 Host vSgHost = hostService.getHost(HostId.hostId(vSgHostId));
678 if (vSgHost == null) {
679 return;
680 }
681
682 log.info("vSG removed {}", vSg.id());
683 Map<IpAddress, MacAddress> vSgs = getSubscriberGateways(vSgHost);
684 ruleInstaller.populateSubscriberGatewayRules(vSgHost, vSgs.keySet());
685 }
686
Hyunsun Moon746956f2016-01-24 21:47:06 -0800687 /**
688 * Sets service network gateway MAC address and sends out gratuitous ARP to all
689 * VMs to update the gateway MAC address.
690 *
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800691 * @param newMac mac address to update
Hyunsun Moon746956f2016-01-24 21:47:06 -0800692 */
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800693 private void setPrivateGatewayMac(MacAddress newMac) {
694 if (newMac == null || newMac.equals(privateGatewayMac)) {
695 // no updates, do nothing
696 return;
Hyunsun Moon746956f2016-01-24 21:47:06 -0800697 }
698
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800699 privateGatewayMac = newMac;
700 log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
701
Hyunsun Moon746956f2016-01-24 21:47:06 -0800702 // TODO get existing service list from XOS and replace the loop below
703 Set<String> vNets = Sets.newHashSet();
704 hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
705 vNets.remove(null);
706
707 vNets.stream().forEach(vNet -> {
708 CordService service = getCordService(CordServiceId.of(vNet));
709 if (service != null) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800710 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
711 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), service.hosts().keySet());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800712 }
713 });
714 }
715
716 /**
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800717 * Sets public gateway MAC address.
718 *
719 * @param publicGateways gateway ip and mac address pairs
720 */
721 private void setPublicGatewayMac(Map<IpAddress, MacAddress> publicGateways) {
722 publicGateways.entrySet()
723 .stream()
724 .forEach(entry -> {
725 arpProxy.addGateway(entry.getKey(), entry.getValue());
Hyunsun Moon80b03872016-03-10 12:40:16 -0800726 log.info("Added public gateway IP {}, MAC {}",
Hyunsun Moon7f4ed9d2016-04-14 16:13:42 -0700727 entry.getKey().toString(), entry.getValue().toString());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800728 });
729 // TODO notice gateway MAC change to VMs holds this gateway IP
730 }
731
732 /**
Hyunsun Moon746956f2016-01-24 21:47:06 -0800733 * Updates configurations.
734 */
735 private void readConfiguration() {
736 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
737 if (config == null) {
738 log.debug("No configuration found");
739 return;
740 }
741
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800742 setPrivateGatewayMac(config.privateGatewayMac());
743 setPublicGatewayMac(config.publicGateways());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800744 }
745
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700746 private class InternalHostListener implements HostListener {
747
748 @Override
749 public void event(HostEvent event) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800750 Host host = event.subject();
Hyunsun Moond35420f2016-03-08 21:59:13 -0800751 if (!mastershipService.isLocalMaster(host.location().deviceId())) {
752 // do not allow to proceed without mastership
753 return;
754 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700755
756 switch (event.type()) {
Hyunsun Moond35420f2016-03-08 21:59:13 -0800757 case HOST_UPDATED:
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700758 case HOST_ADDED:
Hyunsun Moond35420f2016-03-08 21:59:13 -0800759 eventExecutor.submit(() -> serviceVmAdded(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700760 break;
761 case HOST_REMOVED:
Hyunsun Moond35420f2016-03-08 21:59:13 -0800762 eventExecutor.submit(() -> serviceVmRemoved(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700763 break;
764 default:
765 break;
766 }
767 }
768 }
769
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800770 private class InternalPacketProcessor implements PacketProcessor {
771
772 @Override
773 public void process(PacketContext context) {
774 if (context.isHandled()) {
775 return;
776 }
777
778 Ethernet ethPacket = context.inPacket().parsed();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800779 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800780 return;
781 }
782
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800783 arpProxy.processArpPacket(context, ethPacket);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800784 }
785 }
786
787 private class InternalConfigListener implements NetworkConfigListener {
788
789 @Override
790 public void event(NetworkConfigEvent event) {
791 if (!event.configClass().equals(CordVtnConfig.class)) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800792 return;
793 }
794
Hyunsun Moon746956f2016-01-24 21:47:06 -0800795 switch (event.type()) {
796 case CONFIG_ADDED:
797 case CONFIG_UPDATED:
798 log.info("Network configuration changed");
799 eventExecutor.execute(CordVtn.this::readConfiguration);
800 break;
801 default:
802 break;
803 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800804 }
805 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700806}