blob: e0715504224b1d95a6de0e5be2822da367f1c030 [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 Moon1f145552015-10-08 22:25:30 -070019import com.google.common.collect.Sets;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080026import org.onlab.packet.Ethernet;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080027import org.onlab.packet.Ip4Address;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080028import org.onlab.packet.IpAddress;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080029import org.onlab.packet.MacAddress;
30import org.onlab.packet.VlanId;
Hyunsun Moon1f145552015-10-08 22:25:30 -070031import org.onosproject.core.ApplicationId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070032import org.onosproject.core.CoreService;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080033import org.onosproject.dhcp.DhcpService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080034import org.onosproject.mastership.MastershipService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080035import org.onosproject.net.ConnectPoint;
Hyunsun Moond772f342015-10-28 20:28:16 -070036import org.onosproject.net.DefaultAnnotations;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070037import org.onosproject.net.Host;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080038import org.onosproject.net.HostId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080039import org.onosproject.net.HostLocation;
Hyunsun Moon8539b042015-11-07 22:08:43 -080040import org.onosproject.net.Port;
Hyunsun Moon746956f2016-01-24 21:47:06 -080041import org.onosproject.net.config.ConfigFactory;
42import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
44import org.onosproject.net.config.NetworkConfigRegistry;
45import org.onosproject.net.config.NetworkConfigService;
46import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070047import org.onosproject.net.device.DeviceService;
Hyunsun Moond772f342015-10-28 20:28:16 -070048import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080049import org.onosproject.net.flow.FlowRuleService;
50import org.onosproject.net.group.GroupService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080051import org.onosproject.net.host.DefaultHostDescription;
52import org.onosproject.net.host.HostDescription;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070053import org.onosproject.net.host.HostEvent;
54import org.onosproject.net.host.HostListener;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080055import org.onosproject.net.host.HostProvider;
56import org.onosproject.net.host.HostProviderRegistry;
57import org.onosproject.net.host.HostProviderService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070058import org.onosproject.net.host.HostService;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080059import org.onosproject.net.packet.PacketContext;
60import org.onosproject.net.packet.PacketProcessor;
61import org.onosproject.net.packet.PacketService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080062import org.onosproject.net.provider.AbstractProvider;
63import org.onosproject.net.provider.ProviderId;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080064import org.onosproject.openstackswitching.OpenstackNetwork;
65import org.onosproject.openstackswitching.OpenstackPort;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080066import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080067import org.onosproject.openstackswitching.OpenstackSwitchingService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070068import org.slf4j.Logger;
69
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080070import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070071import java.util.Map;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080072import java.util.Set;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070073import java.util.concurrent.ExecutorService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080074import java.util.stream.Collectors;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070075
Hyunsun Moon1f145552015-10-08 22:25:30 -070076import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon746956f2016-01-24 21:47:06 -080077import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070078import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070079import static org.slf4j.LoggerFactory.getLogger;
80
81/**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080082 * Provisions virtual tenant networks with service chaining capability
83 * in OpenStack environment.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070084 */
85@Component(immediate = true)
86@Service
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080087public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider {
Hyunsun Moond0e932a2015-09-15 22:39:16 -070088
89 protected final Logger log = getLogger(getClass());
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon746956f2016-01-24 21:47:06 -080095 protected NetworkConfigRegistry configRegistry;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected NetworkConfigService configService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800101 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700104 protected DeviceService deviceService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected HostService hostService;
108
Hyunsun Moon1f145552015-10-08 22:25:30 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700110 protected DriverService driverService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800113 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800116 protected PacketService packetService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800119 protected MastershipService mastershipService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected GroupService groupService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800125 protected OpenstackSwitchingService openstackService;
126
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected DhcpService dhcpService;
129
Hyunsun Moon746956f2016-01-24 21:47:06 -0800130 private final ConfigFactory configFactory =
131 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
132 @Override
133 public CordVtnConfig createConfig() {
134 return new CordVtnConfig();
135 }
136 };
137
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800138 private static final String DEFAULT_TUNNEL = "vxlan";
139 private static final String SERVICE_ID = "serviceId";
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800140 private static final String OPENSTACK_VM_ID = "openstackVmId";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800141 private static final String OPENSTACK_PORT_ID = "openstackPortId";
142 private static final String DATA_PLANE_IP = "dataPlaneIp";
143 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
144 private static final String S_TAG = "stag";
145
146 private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800147
Hyunsun Moon746956f2016-01-24 21:47:06 -0800148 private final ExecutorService eventExecutor =
149 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700150
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800151 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800152 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800153 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700154
Hyunsun Moon746956f2016-01-24 21:47:06 -0800155 private ApplicationId appId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800156 private HostProviderService hostProvider;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800157 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800158 private CordVtnArpProxy arpProxy;
Hyunsun Moon746956f2016-01-24 21:47:06 -0800159 private volatile MacAddress gatewayMac = MacAddress.NONE;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800160
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800161 /**
162 * Creates an cordvtn host location provider.
163 */
164 public CordVtn() {
165 super(new ProviderId("host", CORDVTN_APP_ID));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800166 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700167
168 @Activate
169 protected void activate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800170 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800171 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
172 deviceService,
173 driverService,
174 groupService,
175 mastershipService,
176 DEFAULT_TUNNEL);
177
Hyunsun Moon9cf43db2016-02-12 15:59:53 -0800178 arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800179 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
180 arpProxy.requestPacket();
181
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700182 hostService.addListener(hostListener);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800183 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700184
Hyunsun Moon746956f2016-01-24 21:47:06 -0800185 configRegistry.registerConfigFactory(configFactory);
186 configService.addListener(configListener);
187 readConfiguration();
188
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700189 log.info("Started");
190 }
191
192 @Deactivate
193 protected void deactivate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800194 hostProviderRegistry.unregister(this);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700195 hostService.removeListener(hostListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800196
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800197 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700198
Hyunsun Moon746956f2016-01-24 21:47:06 -0800199 configRegistry.unregisterConfigFactory(configFactory);
200 configService.removeListener(configListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700201
Hyunsun Moon746956f2016-01-24 21:47:06 -0800202 eventExecutor.shutdown();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700203 log.info("Stopped");
204 }
205
206 @Override
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800207 public void triggerProbe(Host host) {
208 /*
209 * Note: In CORD deployment, we assume that all hosts are configured.
210 * Therefore no probe is required.
211 */
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800212 }
213
214 @Override
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800215 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId,
216 boolean isBidirectional) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800217 CordService tService = getCordService(tServiceId);
218 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800219
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800220 if (tService == null || pService == null) {
221 log.error("Failed to create CordService for {}", tServiceId.id());
222 return;
223 }
224
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800225 log.info("Service dependency from {} to {} created.", tService.id().id(), pService.id().id());
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800226 ruleInstaller.populateServiceDependencyRules(tService, pService, isBidirectional);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800227 }
228
229 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800230 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
231 CordService tService = getCordService(tServiceId);
232 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800233
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800234 if (tService == null || pService == null) {
235 log.error("Failed to create CordService for {}", tServiceId.id());
236 return;
237 }
238
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800239 log.info("Service dependency from {} to {} removed.", tService.id().id(), pService.id().id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800240 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800241 }
242
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800243 @Override
244 public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
245 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
246 OpenstackPort vPort = openstackService.port(port);
247 if (vPort == null) {
248 log.warn("Failed to get OpenstackPort for {}", getPortName(port));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800249 return;
250 }
251
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800252 MacAddress mac = vPort.macAddress();
253 HostId hostId = HostId.hostId(mac);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800254
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800255 Host host = hostService.getHost(hostId);
256 if (host != null) {
257 // Host is already known to the system, no HOST_ADDED event is triggered in this case.
258 // It happens when the application is restarted.
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800259 String vmId = host.annotations().value(OPENSTACK_VM_ID);
260 if (vmId != null && vmId.equals(vPort.deviceId())) {
261 serviceVmAdded(host);
262 return;
263 } else {
264 hostProvider.hostVanished(host.id());
265 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800266 }
267
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800268 Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800269 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800270 .set(SERVICE_ID, vPort.networkId())
Hyunsun Moon6d247342016-02-12 12:48:47 -0800271 .set(OPENSTACK_VM_ID, vPort.deviceId())
272 .set(OPENSTACK_PORT_ID, vPort.id())
273 .set(DATA_PLANE_IP, node.dpIp().ip().toString())
274 .set(DATA_PLANE_INTF, node.dpIntf());
275
276 String serviceVlan = getServiceVlan(vPort);
277 if (serviceVlan != null) {
278 annotations.set(S_TAG, serviceVlan);
279 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800280
281 HostDescription hostDesc = new DefaultHostDescription(
282 mac,
283 VlanId.NONE,
284 new HostLocation(connectPoint, System.currentTimeMillis()),
285 ip,
Hyunsun Moon6d247342016-02-12 12:48:47 -0800286 annotations.build());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800287
288 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800289 }
290
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800291 @Override
292 public void removeServiceVm(ConnectPoint connectPoint) {
293 Host host = hostService.getConnectedHosts(connectPoint)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800294 .stream()
295 .findFirst()
296 .orElse(null);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800297
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800298 if (host == null) {
299 log.debug("No host is connected on {}", connectPoint.toString());
300 return;
301 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800302
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800303 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,
308 Set<IpAddress> vSgIps) {
309 Host vSgVm = hostService.getHost(vSgHostId);
310
311 if (vSgVm == null || !vSgVm.annotations().value(S_TAG).equals(serviceVlan)) {
312 log.debug("Invalid vSG updates for {}", serviceVlan);
313 return;
314 }
315
316 log.info("Updates vSGs in {} with {}", vSgVm.id(), vSgIps.toString());
317 ruleInstaller.populateSubscriberGatewayRules(vSgVm, vSgIps);
318 }
319
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800320 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800321 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800322 *
323 * @param serviceId service id
324 * @return cord service, or null if it fails to get network from OpenStack
325 */
326 private CordService getCordService(CordServiceId serviceId) {
327 OpenstackNetwork vNet = openstackService.network(serviceId.id());
328 if (vNet == null) {
329 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
330 return null;
331 }
332
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800333 OpenstackSubnet subnet = vNet.subnets().stream()
334 .findFirst()
335 .orElse(null);
336 if (subnet == null) {
337 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
338 return null;
339 }
340
341 Set<CordServiceId> tServices = Sets.newHashSet();
342 // TODO get tenant services from XOS
343
344 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
345 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800346 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800347
348 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800349 }
350
351 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800352 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800353 *
354 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800355 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800356 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800357 private CordService getCordService(OpenstackNetwork vNet) {
358 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800359
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800360 CordServiceId serviceId = CordServiceId.of(vNet.id());
361 OpenstackSubnet subnet = vNet.subnets().stream()
362 .findFirst()
363 .orElse(null);
364 if (subnet == null) {
365 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
366 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800367 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800368
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800369 Set<CordServiceId> tServices = Sets.newHashSet();
370 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800371
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800372 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
373 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800374 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800375
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800376 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800377 }
378
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800379 /**
380 * Returns IP address for tunneling for a given host.
381 *
382 * @param host host
Hyunsun Moon6d247342016-02-12 12:48:47 -0800383 * @return ip address, or null
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800384 */
385 private IpAddress getTunnelIp(Host host) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800386 String ip = host.annotations().value(DATA_PLANE_IP);
387 return ip == null ? null : IpAddress.valueOf(ip);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800388 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700389
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800390 /**
391 * Returns port name.
392 *
393 * @param port port
394 * @return port name
395 */
396 private String getPortName(Port port) {
397 return port.annotations().value("portName");
398 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800399
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800400 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800401 * Returns s-tag from a given OpenStack port.
402 *
403 * @param vPort openstack port
404 * @return s-tag string
405 */
406 private String getServiceVlan(OpenstackPort vPort) {
407 checkNotNull(vPort);
408
409 if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
410 return vPort.name().split("-")[1];
411 } else {
412 return null;
413 }
414 }
415
416 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800417 * Returns hosts associated with a given OpenStack network.
418 *
419 * @param vNet openstack network
420 * @return set of hosts
421 */
422 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
423 checkNotNull(vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700424
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800425 Set<Host> hosts = openstackService.ports(vNet.id()).stream()
426 .filter(port -> port.deviceOwner().contains("compute"))
427 .map(port -> hostService.getHostsByMac(port.macAddress())
428 .stream()
429 .findFirst()
430 .orElse(null))
431 .collect(Collectors.toSet());
432
433 hosts.remove(null);
434 return hosts;
435 }
436
437 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800438 * Returns public ip addresses of vSGs running inside a give vSG host.
439 *
440 * @param vSgHost vSG host
441 * @return set of ip address, or empty set
442 */
443 private Set<IpAddress> getSubscriberGatewayIps(Host vSgHost) {
444 String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
445 String serviceVlan = vSgHost.annotations().value(S_TAG);
446
447 OpenstackPort vPort = openstackService.port(vPortId);
448 if (vPort == null) {
449 log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
450 return Sets.newHashSet();
451 }
452
453 if (!serviceVlan.equals(getServiceVlan(vPort))) {
454 log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
455 return Sets.newHashSet();
456 }
457
458 return vPort.allowedAddressPairs().keySet();
459 }
460
461 /**
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800462 * Registers static DHCP lease for a given host.
463 *
464 * @param host host
465 * @param service cord service
466 */
467 private void registerDhcpLease(Host host, CordService service) {
468 List<Ip4Address> options = Lists.newArrayList();
469 options.add(Ip4Address.makeMaskPrefix(service.serviceIpRange().prefixLength()));
470 options.add(service.serviceIp().getIp4Address());
471 options.add(service.serviceIp().getIp4Address());
472 options.add(DEFAULT_DNS);
473
474 log.debug("Set static DHCP mapping for {}", host.mac());
475 dhcpService.setStaticMapping(host.mac(),
476 host.ipAddresses().stream().findFirst().get().getIp4Address(),
477 true,
478 options);
479 }
480
481 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800482 * Handles VM detected situation.
483 *
484 * @param host host
485 */
486 private void serviceVmAdded(Host host) {
487 String vNetId = host.annotations().value(SERVICE_ID);
488 OpenstackNetwork vNet = openstackService.network(vNetId);
489 if (vNet == null) {
490 log.warn("Failed to get OpenStack network {} for VM {}({}).",
491 vNetId,
492 host.id(),
493 host.annotations().value(OPENSTACK_VM_ID));
494 return;
495 }
496
497 log.info("VM {} is detected, MAC: {} IP: {}",
498 host.annotations().value(OPENSTACK_VM_ID),
499 host.mac(),
500 host.ipAddresses().stream().findFirst().get());
501
502 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800503 if (service == null) {
504 return;
505 }
506
507 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
508 ruleInstaller.populateManagementNetworkRules(host, service);
509 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800510 // TODO check if the service needs an update on its group buckets after done CORD-433
511 ruleInstaller.updateServiceGroup(service);
512 arpProxy.addServiceIp(service.serviceIp());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800513
514 // sends gratuitous ARP here for the case of adding existing VMs
515 // when ONOS or cordvtn app is restarted
516 arpProxy.sendGratuitousArp(service.serviceIp(), gatewayMac, Sets.newHashSet(host));
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800517 }
518
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800519 registerDhcpLease(host, service);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800520 ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
521
522 if (host.annotations().value(S_TAG) != null) {
523 log.debug("vSG VM detected {}", host.id());
524 ruleInstaller.populateSubscriberGatewayRules(host, getSubscriberGatewayIps(host));
525 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800526 }
527
528 /**
529 * Handles VM removed situation.
530 *
531 * @param host host
532 */
533 private void serviceVmRemoved(Host host) {
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800534 if (host.annotations().value(OPENSTACK_VM_ID) == null) {
535 // this host was not injected from CordVtn, just return
536 return;
537 }
538
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800539 String vNetId = host.annotations().value(SERVICE_ID);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800540 OpenstackNetwork vNet = openstackService.network(vNetId);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800541 if (vNet == null) {
542 log.warn("Failed to get OpenStack network {} for VM {}({}).",
543 vNetId,
544 host.id(),
545 host.annotations().value(OPENSTACK_VM_ID));
546 return;
547 }
548
549 log.info("VM {} is vanished, MAC: {} IP: {}",
550 host.annotations().value(OPENSTACK_VM_ID),
551 host.mac(),
552 host.ipAddresses().stream().findFirst().get());
553
554 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moonfb631b42016-02-03 14:44:06 -0800555 dhcpService.removeStaticMapping(host.mac());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800556
557 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800558 if (service == null) {
559 return;
560 }
561
562 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
563 ruleInstaller.removeManagementNetworkRules(host, service);
564 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800565 // TODO check if the service needs an update on its group buckets after done CORD-433
566 ruleInstaller.updateServiceGroup(service);
567
568 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
569 arpProxy.removeServiceIp(service.serviceIp());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700570 }
571 }
572 }
573
Hyunsun Moon746956f2016-01-24 21:47:06 -0800574 /**
575 * Sets service network gateway MAC address and sends out gratuitous ARP to all
576 * VMs to update the gateway MAC address.
577 *
578 * @param mac mac address
579 */
580 private void setServiceGatewayMac(MacAddress mac) {
581 if (mac != null && !mac.equals(gatewayMac)) {
582 gatewayMac = mac;
583 log.debug("Set service gateway MAC address to {}", gatewayMac.toString());
584 }
585
586 // TODO get existing service list from XOS and replace the loop below
587 Set<String> vNets = Sets.newHashSet();
588 hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
589 vNets.remove(null);
590
591 vNets.stream().forEach(vNet -> {
592 CordService service = getCordService(CordServiceId.of(vNet));
593 if (service != null) {
594 arpProxy.sendGratuitousArp(
595 service.serviceIp(),
596 gatewayMac,
597 service.hosts().keySet());
598 }
599 });
600 }
601
602 /**
603 * Updates configurations.
604 */
605 private void readConfiguration() {
606 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
607 if (config == null) {
608 log.debug("No configuration found");
609 return;
610 }
611
612 setServiceGatewayMac(config.gatewayMac());
613 }
614
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700615 private class InternalHostListener implements HostListener {
616
617 @Override
618 public void event(HostEvent event) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800619 Host host = event.subject();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700620
621 switch (event.type()) {
622 case HOST_ADDED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800623 eventExecutor.submit(() -> serviceVmAdded(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700624 break;
625 case HOST_REMOVED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800626 eventExecutor.submit(() -> serviceVmRemoved(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700627 break;
628 default:
629 break;
630 }
631 }
632 }
633
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800634 private class InternalPacketProcessor implements PacketProcessor {
635
636 @Override
637 public void process(PacketContext context) {
638 if (context.isHandled()) {
639 return;
640 }
641
642 Ethernet ethPacket = context.inPacket().parsed();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800643 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800644 return;
645 }
646
Hyunsun Moon746956f2016-01-24 21:47:06 -0800647 arpProxy.processArpPacket(context, ethPacket, gatewayMac);
648 }
649 }
650
651 private class InternalConfigListener implements NetworkConfigListener {
652
653 @Override
654 public void event(NetworkConfigEvent event) {
655 if (!event.configClass().equals(CordVtnConfig.class)) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800656 return;
657 }
658
Hyunsun Moon746956f2016-01-24 21:47:06 -0800659 switch (event.type()) {
660 case CONFIG_ADDED:
661 case CONFIG_UPDATED:
662 log.info("Network configuration changed");
663 eventExecutor.execute(CordVtn.this::readConfiguration);
664 break;
665 default:
666 break;
667 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800668 }
669 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700670}