blob: e27aa74805d4e344705f97734506ec0b42cccc8b [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 Moonb77b60f2016-01-15 20:03:18 -080041import org.onosproject.net.SparseAnnotations;
Hyunsun Moon746956f2016-01-24 21:47:06 -080042import org.onosproject.net.config.ConfigFactory;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigRegistry;
46import org.onosproject.net.config.NetworkConfigService;
47import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070048import org.onosproject.net.device.DeviceService;
Hyunsun Moond772f342015-10-28 20:28:16 -070049import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080050import org.onosproject.net.flow.FlowRuleService;
51import org.onosproject.net.group.GroupService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080052import org.onosproject.net.host.DefaultHostDescription;
53import org.onosproject.net.host.HostDescription;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070054import org.onosproject.net.host.HostEvent;
55import org.onosproject.net.host.HostListener;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080056import org.onosproject.net.host.HostProvider;
57import org.onosproject.net.host.HostProviderRegistry;
58import org.onosproject.net.host.HostProviderService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070059import org.onosproject.net.host.HostService;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080060import org.onosproject.net.packet.PacketContext;
61import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080063import org.onosproject.net.provider.AbstractProvider;
64import org.onosproject.net.provider.ProviderId;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080065import org.onosproject.openstackswitching.OpenstackNetwork;
66import org.onosproject.openstackswitching.OpenstackPort;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080067import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080068import org.onosproject.openstackswitching.OpenstackSwitchingService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070069import org.slf4j.Logger;
70
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080071import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070072import java.util.Map;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080073import java.util.Set;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070074import java.util.concurrent.ExecutorService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080075import java.util.stream.Collectors;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070076
Hyunsun Moon1f145552015-10-08 22:25:30 -070077import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon746956f2016-01-24 21:47:06 -080078import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070079import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070080import static org.slf4j.LoggerFactory.getLogger;
81
82/**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080083 * Provisions virtual tenant networks with service chaining capability
84 * in OpenStack environment.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070085 */
86@Component(immediate = true)
87@Service
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080088public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider {
Hyunsun Moond0e932a2015-09-15 22:39:16 -070089
90 protected final Logger log = getLogger(getClass());
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon746956f2016-01-24 21:47:06 -080096 protected NetworkConfigRegistry configRegistry;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected NetworkConfigService configService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800102 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700105 protected DeviceService deviceService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected HostService hostService;
109
Hyunsun Moon1f145552015-10-08 22:25:30 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700111 protected DriverService driverService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800114 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800117 protected PacketService packetService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800120 protected MastershipService mastershipService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected GroupService groupService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800126 protected OpenstackSwitchingService openstackService;
127
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected DhcpService dhcpService;
130
Hyunsun Moon746956f2016-01-24 21:47:06 -0800131 private final ConfigFactory configFactory =
132 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
133 @Override
134 public CordVtnConfig createConfig() {
135 return new CordVtnConfig();
136 }
137 };
138
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800139 private static final String DEFAULT_TUNNEL = "vxlan";
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800140 private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800141 private static final String SERVICE_ID = "serviceId";
142 private static final String LOCATION_IP = "locationIp";
143 private static final String OPENSTACK_VM_ID = "openstackVmId";
144
Hyunsun Moon746956f2016-01-24 21:47:06 -0800145 private final ExecutorService eventExecutor =
146 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700147
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800148 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800149 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800150 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700151
Hyunsun Moon746956f2016-01-24 21:47:06 -0800152 private ApplicationId appId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800153 private HostProviderService hostProvider;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800154 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800155 private CordVtnArpProxy arpProxy;
Hyunsun Moon746956f2016-01-24 21:47:06 -0800156 private volatile MacAddress gatewayMac = MacAddress.NONE;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800157
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800158 /**
159 * Creates an cordvtn host location provider.
160 */
161 public CordVtn() {
162 super(new ProviderId("host", CORDVTN_APP_ID));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800163 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700164
165 @Activate
166 protected void activate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800167 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800168 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
169 deviceService,
170 driverService,
171 groupService,
172 mastershipService,
173 DEFAULT_TUNNEL);
174
Hyunsun Moon9cf43db2016-02-12 15:59:53 -0800175 arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800176 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
177 arpProxy.requestPacket();
178
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700179 hostService.addListener(hostListener);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800180 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700181
Hyunsun Moon746956f2016-01-24 21:47:06 -0800182 configRegistry.registerConfigFactory(configFactory);
183 configService.addListener(configListener);
184 readConfiguration();
185
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700186 log.info("Started");
187 }
188
189 @Deactivate
190 protected void deactivate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800191 hostProviderRegistry.unregister(this);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700192 hostService.removeListener(hostListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800193
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800194 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700195
Hyunsun Moon746956f2016-01-24 21:47:06 -0800196 configRegistry.unregisterConfigFactory(configFactory);
197 configService.removeListener(configListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700198
Hyunsun Moon746956f2016-01-24 21:47:06 -0800199 eventExecutor.shutdown();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700200 log.info("Stopped");
201 }
202
203 @Override
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800204 public void triggerProbe(Host host) {
205 /*
206 * Note: In CORD deployment, we assume that all hosts are configured.
207 * Therefore no probe is required.
208 */
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800209 }
210
211 @Override
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800212 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId,
213 boolean isBidirectional) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800214 CordService tService = getCordService(tServiceId);
215 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800216
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800217 if (tService == null || pService == null) {
218 log.error("Failed to create CordService for {}", tServiceId.id());
219 return;
220 }
221
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800222 log.info("Service dependency from {} to {} created.", tService.id().id(), pService.id().id());
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800223 ruleInstaller.populateServiceDependencyRules(tService, pService, isBidirectional);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800224 }
225
226 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800227 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
228 CordService tService = getCordService(tServiceId);
229 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800230
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800231 if (tService == null || pService == null) {
232 log.error("Failed to create CordService for {}", tServiceId.id());
233 return;
234 }
235
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800236 log.info("Service dependency from {} to {} removed.", tService.id().id(), pService.id().id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800237 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800238 }
239
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800240 @Override
241 public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
242 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
243 OpenstackPort vPort = openstackService.port(port);
244 if (vPort == null) {
245 log.warn("Failed to get OpenstackPort for {}", getPortName(port));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800246 return;
247 }
248
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800249 MacAddress mac = vPort.macAddress();
250 HostId hostId = HostId.hostId(mac);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800251
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800252 Host host = hostService.getHost(hostId);
253 if (host != null) {
254 // Host is already known to the system, no HOST_ADDED event is triggered in this case.
255 // It happens when the application is restarted.
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800256 String vmId = host.annotations().value(OPENSTACK_VM_ID);
257 if (vmId != null && vmId.equals(vPort.deviceId())) {
258 serviceVmAdded(host);
259 return;
260 } else {
261 hostProvider.hostVanished(host.id());
262 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800263 }
264
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800265 Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values());
266 SparseAnnotations annotations = DefaultAnnotations.builder()
267 .set(OPENSTACK_VM_ID, vPort.deviceId())
268 .set(SERVICE_ID, vPort.networkId())
Hyunsun Moon133fd792016-02-09 01:55:48 -0800269 .set(LOCATION_IP, node.dpIp().ip().toString())
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800270 .build();
271
272 HostDescription hostDesc = new DefaultHostDescription(
273 mac,
274 VlanId.NONE,
275 new HostLocation(connectPoint, System.currentTimeMillis()),
276 ip,
277 annotations);
278
279 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800280 }
281
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800282 @Override
283 public void removeServiceVm(ConnectPoint connectPoint) {
284 Host host = hostService.getConnectedHosts(connectPoint)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800285 .stream()
286 .findFirst()
287 .orElse(null);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800288
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800289 if (host == null) {
290 log.debug("No host is connected on {}", connectPoint.toString());
291 return;
292 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800293
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800294 hostProvider.hostVanished(host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800295 }
296
297 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800298 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800299 *
300 * @param serviceId service id
301 * @return cord service, or null if it fails to get network from OpenStack
302 */
303 private CordService getCordService(CordServiceId serviceId) {
304 OpenstackNetwork vNet = openstackService.network(serviceId.id());
305 if (vNet == null) {
306 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
307 return null;
308 }
309
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800310 OpenstackSubnet subnet = vNet.subnets().stream()
311 .findFirst()
312 .orElse(null);
313 if (subnet == null) {
314 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
315 return null;
316 }
317
318 Set<CordServiceId> tServices = Sets.newHashSet();
319 // TODO get tenant services from XOS
320
321 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
322 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800323 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800324
325 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800326 }
327
328 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800329 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800330 *
331 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800332 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800333 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800334 private CordService getCordService(OpenstackNetwork vNet) {
335 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800336
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800337 CordServiceId serviceId = CordServiceId.of(vNet.id());
338 OpenstackSubnet subnet = vNet.subnets().stream()
339 .findFirst()
340 .orElse(null);
341 if (subnet == null) {
342 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
343 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800344 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800345
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800346 Set<CordServiceId> tServices = Sets.newHashSet();
347 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800348
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800349 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
350 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800351 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800352
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800353 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800354 }
355
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800356 /**
357 * Returns IP address for tunneling for a given host.
358 *
359 * @param host host
360 * @return ip address
361 */
362 private IpAddress getTunnelIp(Host host) {
363 return IpAddress.valueOf(host.annotations().value(LOCATION_IP));
364 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700365
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800366 /**
367 * Returns port name.
368 *
369 * @param port port
370 * @return port name
371 */
372 private String getPortName(Port port) {
373 return port.annotations().value("portName");
374 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800375
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800376 /**
377 * Returns hosts associated with a given OpenStack network.
378 *
379 * @param vNet openstack network
380 * @return set of hosts
381 */
382 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
383 checkNotNull(vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700384
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800385 Set<Host> hosts = openstackService.ports(vNet.id()).stream()
386 .filter(port -> port.deviceOwner().contains("compute"))
387 .map(port -> hostService.getHostsByMac(port.macAddress())
388 .stream()
389 .findFirst()
390 .orElse(null))
391 .collect(Collectors.toSet());
392
393 hosts.remove(null);
394 return hosts;
395 }
396
397 /**
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800398 * Registers static DHCP lease for a given host.
399 *
400 * @param host host
401 * @param service cord service
402 */
403 private void registerDhcpLease(Host host, CordService service) {
404 List<Ip4Address> options = Lists.newArrayList();
405 options.add(Ip4Address.makeMaskPrefix(service.serviceIpRange().prefixLength()));
406 options.add(service.serviceIp().getIp4Address());
407 options.add(service.serviceIp().getIp4Address());
408 options.add(DEFAULT_DNS);
409
410 log.debug("Set static DHCP mapping for {}", host.mac());
411 dhcpService.setStaticMapping(host.mac(),
412 host.ipAddresses().stream().findFirst().get().getIp4Address(),
413 true,
414 options);
415 }
416
417 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800418 * Handles VM detected situation.
419 *
420 * @param host host
421 */
422 private void serviceVmAdded(Host host) {
423 String vNetId = host.annotations().value(SERVICE_ID);
424 OpenstackNetwork vNet = openstackService.network(vNetId);
425 if (vNet == null) {
426 log.warn("Failed to get OpenStack network {} for VM {}({}).",
427 vNetId,
428 host.id(),
429 host.annotations().value(OPENSTACK_VM_ID));
430 return;
431 }
432
433 log.info("VM {} is detected, MAC: {} IP: {}",
434 host.annotations().value(OPENSTACK_VM_ID),
435 host.mac(),
436 host.ipAddresses().stream().findFirst().get());
437
438 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800439 if (service == null) {
440 return;
441 }
442
443 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
444 ruleInstaller.populateManagementNetworkRules(host, service);
445 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800446 // TODO check if the service needs an update on its group buckets after done CORD-433
447 ruleInstaller.updateServiceGroup(service);
448 arpProxy.addServiceIp(service.serviceIp());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800449
450 // sends gratuitous ARP here for the case of adding existing VMs
451 // when ONOS or cordvtn app is restarted
452 arpProxy.sendGratuitousArp(service.serviceIp(), gatewayMac, Sets.newHashSet(host));
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800453 }
454
455 ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800456 registerDhcpLease(host, service);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800457 }
458
459 /**
460 * Handles VM removed situation.
461 *
462 * @param host host
463 */
464 private void serviceVmRemoved(Host host) {
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800465 if (host.annotations().value(OPENSTACK_VM_ID) == null) {
466 // this host was not injected from CordVtn, just return
467 return;
468 }
469
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800470 String vNetId = host.annotations().value(SERVICE_ID);
471 OpenstackNetwork vNet = openstackService.network(host.annotations().value(SERVICE_ID));
472 if (vNet == null) {
473 log.warn("Failed to get OpenStack network {} for VM {}({}).",
474 vNetId,
475 host.id(),
476 host.annotations().value(OPENSTACK_VM_ID));
477 return;
478 }
479
480 log.info("VM {} is vanished, MAC: {} IP: {}",
481 host.annotations().value(OPENSTACK_VM_ID),
482 host.mac(),
483 host.ipAddresses().stream().findFirst().get());
484
485 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moonfb631b42016-02-03 14:44:06 -0800486 dhcpService.removeStaticMapping(host.mac());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800487
488 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800489 if (service == null) {
490 return;
491 }
492
493 if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
494 ruleInstaller.removeManagementNetworkRules(host, service);
495 } else {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800496 // TODO check if the service needs an update on its group buckets after done CORD-433
497 ruleInstaller.updateServiceGroup(service);
498
499 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
500 arpProxy.removeServiceIp(service.serviceIp());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700501 }
502 }
503 }
504
Hyunsun Moon746956f2016-01-24 21:47:06 -0800505 /**
506 * Sets service network gateway MAC address and sends out gratuitous ARP to all
507 * VMs to update the gateway MAC address.
508 *
509 * @param mac mac address
510 */
511 private void setServiceGatewayMac(MacAddress mac) {
512 if (mac != null && !mac.equals(gatewayMac)) {
513 gatewayMac = mac;
514 log.debug("Set service gateway MAC address to {}", gatewayMac.toString());
515 }
516
517 // TODO get existing service list from XOS and replace the loop below
518 Set<String> vNets = Sets.newHashSet();
519 hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
520 vNets.remove(null);
521
522 vNets.stream().forEach(vNet -> {
523 CordService service = getCordService(CordServiceId.of(vNet));
524 if (service != null) {
525 arpProxy.sendGratuitousArp(
526 service.serviceIp(),
527 gatewayMac,
528 service.hosts().keySet());
529 }
530 });
531 }
532
533 /**
534 * Updates configurations.
535 */
536 private void readConfiguration() {
537 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
538 if (config == null) {
539 log.debug("No configuration found");
540 return;
541 }
542
543 setServiceGatewayMac(config.gatewayMac());
544 }
545
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700546 private class InternalHostListener implements HostListener {
547
548 @Override
549 public void event(HostEvent event) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800550 Host host = event.subject();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700551
552 switch (event.type()) {
553 case HOST_ADDED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800554 eventExecutor.submit(() -> serviceVmAdded(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700555 break;
556 case HOST_REMOVED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800557 eventExecutor.submit(() -> serviceVmRemoved(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700558 break;
559 default:
560 break;
561 }
562 }
563 }
564
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800565 private class InternalPacketProcessor implements PacketProcessor {
566
567 @Override
568 public void process(PacketContext context) {
569 if (context.isHandled()) {
570 return;
571 }
572
573 Ethernet ethPacket = context.inPacket().parsed();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800574 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800575 return;
576 }
577
Hyunsun Moon746956f2016-01-24 21:47:06 -0800578 arpProxy.processArpPacket(context, ethPacket, gatewayMac);
579 }
580 }
581
582 private class InternalConfigListener implements NetworkConfigListener {
583
584 @Override
585 public void event(NetworkConfigEvent event) {
586 if (!event.configClass().equals(CordVtnConfig.class)) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800587 return;
588 }
589
Hyunsun Moon746956f2016-01-24 21:47:06 -0800590 switch (event.type()) {
591 case CONFIG_ADDED:
592 case CONFIG_UPDATED:
593 log.info("Network configuration changed");
594 eventExecutor.execute(CordVtn.this::readConfiguration);
595 break;
596 default:
597 break;
598 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800599 }
600 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700601}