blob: f20a085db139e1ca6961080f70ab58929cde441f [file] [log] [blame]
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001/*
2 * Copyright 2014-2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.cordvtn;
17
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080018import com.google.common.collect.Lists;
Hyunsun Moonae39ae82016-02-17 15:02:06 -080019import com.google.common.collect.Maps;
Hyunsun Moon1f145552015-10-08 22:25:30 -070020import com.google.common.collect.Sets;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080027import org.onlab.packet.Ethernet;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080028import org.onlab.packet.Ip4Address;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080029import org.onlab.packet.IpAddress;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080030import org.onlab.packet.MacAddress;
31import org.onlab.packet.VlanId;
Hyunsun Moon1f145552015-10-08 22:25:30 -070032import org.onosproject.core.ApplicationId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070033import org.onosproject.core.CoreService;
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080034import org.onosproject.dhcp.DhcpService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080035import org.onosproject.mastership.MastershipService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080036import org.onosproject.net.ConnectPoint;
Hyunsun Moond772f342015-10-28 20:28:16 -070037import org.onosproject.net.DefaultAnnotations;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070038import org.onosproject.net.Host;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080039import org.onosproject.net.HostId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080040import org.onosproject.net.HostLocation;
Hyunsun Moon8539b042015-11-07 22:08:43 -080041import org.onosproject.net.Port;
Hyunsun Moon746956f2016-01-24 21:47:06 -080042import org.onosproject.net.config.ConfigFactory;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigRegistry;
46import org.onosproject.net.config.NetworkConfigService;
47import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070048import org.onosproject.net.device.DeviceService;
Hyunsun Moond772f342015-10-28 20:28:16 -070049import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080050import org.onosproject.net.flow.FlowRuleService;
51import org.onosproject.net.group.GroupService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080052import org.onosproject.net.host.DefaultHostDescription;
53import org.onosproject.net.host.HostDescription;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070054import org.onosproject.net.host.HostEvent;
55import org.onosproject.net.host.HostListener;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080056import org.onosproject.net.host.HostProvider;
57import org.onosproject.net.host.HostProviderRegistry;
58import org.onosproject.net.host.HostProviderService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070059import org.onosproject.net.host.HostService;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080060import org.onosproject.net.packet.PacketContext;
61import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080063import org.onosproject.net.provider.AbstractProvider;
64import org.onosproject.net.provider.ProviderId;
sangho93447f12016-02-24 00:33:22 +090065import org.onosproject.openstackinterface.OpenstackInterfaceService;
66import org.onosproject.openstackinterface.OpenstackNetwork;
67import org.onosproject.openstackinterface.OpenstackPort;
68import org.onosproject.openstackinterface.OpenstackSubnet;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070069import org.slf4j.Logger;
70
Hyunsun Moon1d3eac92016-02-03 00:11:11 -080071import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070072import java.util.Map;
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -080073import java.util.Objects;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080074import java.util.Set;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070075import java.util.concurrent.ExecutorService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080076import java.util.stream.Collectors;
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -080077import java.util.stream.StreamSupport;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070078
Hyunsun Moon1f145552015-10-08 22:25:30 -070079import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon746956f2016-01-24 21:47:06 -080080import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070081import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070082import static org.slf4j.LoggerFactory.getLogger;
83
84/**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080085 * Provisions virtual tenant networks with service chaining capability
86 * in OpenStack environment.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070087 */
88@Component(immediate = true)
89@Service
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080090public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider {
Hyunsun Moond0e932a2015-09-15 22:39:16 -070091
92 protected final Logger log = getLogger(getClass());
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected CoreService coreService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon746956f2016-01-24 21:47:06 -080098 protected NetworkConfigRegistry configRegistry;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected NetworkConfigService configService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800104 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700107 protected DeviceService deviceService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected HostService hostService;
111
Hyunsun Moon1f145552015-10-08 22:25:30 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700113 protected DriverService driverService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800116 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800119 protected PacketService packetService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800122 protected MastershipService mastershipService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected GroupService groupService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +0900128 protected OpenstackInterfaceService openstackService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800129
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected DhcpService dhcpService;
132
Hyunsun Moon746956f2016-01-24 21:47:06 -0800133 private final ConfigFactory configFactory =
134 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
135 @Override
136 public CordVtnConfig createConfig() {
137 return new CordVtnConfig();
138 }
139 };
140
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800141 private static final String DEFAULT_TUNNEL = "vxlan";
142 private static final String SERVICE_ID = "serviceId";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800143 private static final String OPENSTACK_PORT_ID = "openstackPortId";
144 private static final String DATA_PLANE_IP = "dataPlaneIp";
145 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
146 private static final String S_TAG = "stag";
Hyunsun Moon98025542016-03-08 04:36:02 -0800147 private static final String VSG_HOST_ID = "vsgHostId";
Hyunsun Moond35420f2016-03-08 21:59:13 -0800148 private static final String CREATED_TIME = "createdTime";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800149
150 private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800151
Hyunsun Moon746956f2016-01-24 21:47:06 -0800152 private final ExecutorService eventExecutor =
153 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700154
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800155 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800156 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800157 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700158
Hyunsun Moon746956f2016-01-24 21:47:06 -0800159 private ApplicationId appId;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800160 private HostProviderService hostProvider;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800161 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800162 private CordVtnArpProxy arpProxy;
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800163 private volatile MacAddress privateGatewayMac = MacAddress.NONE;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800164
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800165 /**
166 * Creates an cordvtn host location provider.
167 */
168 public CordVtn() {
169 super(new ProviderId("host", CORDVTN_APP_ID));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800170 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700171
172 @Activate
173 protected void activate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800174 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800175 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
176 deviceService,
177 driverService,
178 groupService,
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800179 configRegistry,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800180 DEFAULT_TUNNEL);
181
Hyunsun Moon9cf43db2016-02-12 15:59:53 -0800182 arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800183 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
184 arpProxy.requestPacket();
185
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700186 hostService.addListener(hostListener);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800187 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700188
Hyunsun Moon746956f2016-01-24 21:47:06 -0800189 configRegistry.registerConfigFactory(configFactory);
190 configService.addListener(configListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800191
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700192 log.info("Started");
193 }
194
195 @Deactivate
196 protected void deactivate() {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800197 hostProviderRegistry.unregister(this);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700198 hostService.removeListener(hostListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800199
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800200 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700201
Hyunsun Moon746956f2016-01-24 21:47:06 -0800202 configRegistry.unregisterConfigFactory(configFactory);
203 configService.removeListener(configListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700204
Hyunsun Moon746956f2016-01-24 21:47:06 -0800205 eventExecutor.shutdown();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700206 log.info("Stopped");
207 }
208
209 @Override
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800210 public void triggerProbe(Host host) {
211 /*
212 * Note: In CORD deployment, we assume that all hosts are configured.
213 * Therefore no probe is required.
214 */
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800215 }
216
217 @Override
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800218 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId,
219 boolean isBidirectional) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800220 CordService tService = getCordService(tServiceId);
221 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800222
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800223 if (tService == null || pService == null) {
224 log.error("Failed to create CordService for {}", tServiceId.id());
225 return;
226 }
227
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800228 log.info("Service dependency from {} to {} created.", tService.id().id(), pService.id().id());
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800229 ruleInstaller.populateServiceDependencyRules(tService, pService, isBidirectional);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800230 }
231
232 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800233 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
234 CordService tService = getCordService(tServiceId);
235 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800236
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800237 if (tService == null || pService == null) {
238 log.error("Failed to create CordService for {}", tServiceId.id());
239 return;
240 }
241
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800242 log.info("Service dependency from {} to {} removed.", tService.id().id(), pService.id().id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800243 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800244 }
245
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800246 @Override
247 public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
248 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
249 OpenstackPort vPort = openstackService.port(port);
250 if (vPort == null) {
251 log.warn("Failed to get OpenstackPort for {}", getPortName(port));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800252 return;
253 }
254
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800255 MacAddress mac = vPort.macAddress();
256 HostId hostId = HostId.hostId(mac);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800257
Hyunsun Moond35420f2016-03-08 21:59:13 -0800258 Host existingHost = hostService.getHost(hostId);
259 if (existingHost != null) {
260 String serviceId = existingHost.annotations().value(SERVICE_ID);
261 if (serviceId == null || !serviceId.equals(vPort.networkId())) {
262 // this host is not injected by cordvtn or a stale host, remove it
263 hostProvider.hostVanished(existingHost.id());
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800264 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800265 }
266
Hyunsun Moond35420f2016-03-08 21:59:13 -0800267 // Included CREATED_TIME to annotation intentionally to trigger HOST_UPDATED
268 // event so that the flow rule population for this host can happen.
269 // This ensures refreshing data plane by pushing network config always make
270 // the data plane synced.
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800271 Set<IpAddress> fixedIp = Sets.newHashSet(vPort.fixedIps().values());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800272 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800273 .set(SERVICE_ID, vPort.networkId())
Hyunsun Moon6d247342016-02-12 12:48:47 -0800274 .set(OPENSTACK_PORT_ID, vPort.id())
275 .set(DATA_PLANE_IP, node.dpIp().ip().toString())
Hyunsun Moond35420f2016-03-08 21:59:13 -0800276 .set(DATA_PLANE_INTF, node.dpIntf())
277 .set(CREATED_TIME, String.valueOf(System.currentTimeMillis()));
Hyunsun Moon6d247342016-02-12 12:48:47 -0800278
279 String serviceVlan = getServiceVlan(vPort);
280 if (serviceVlan != null) {
281 annotations.set(S_TAG, serviceVlan);
282 }
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800283
284 HostDescription hostDesc = new DefaultHostDescription(
285 mac,
286 VlanId.NONE,
287 new HostLocation(connectPoint, System.currentTimeMillis()),
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800288 fixedIp,
Hyunsun Moon6d247342016-02-12 12:48:47 -0800289 annotations.build());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800290
291 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800292 }
293
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800294 @Override
295 public void removeServiceVm(ConnectPoint connectPoint) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800296 hostService.getConnectedHosts(connectPoint)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800297 .stream()
Hyunsun Moon2a225162016-02-17 19:00:50 -0800298 .forEach(host -> hostProvider.hostVanished(host.id()));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800299 }
300
Hyunsun Moon6d247342016-02-12 12:48:47 -0800301 @Override
302 public void updateVirtualSubscriberGateways(HostId vSgHostId, String serviceVlan,
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800303 Map<IpAddress, MacAddress> vSgs) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800304 Host vSgHost = hostService.getHost(vSgHostId);
305 if (vSgHost == null || !vSgHost.annotations().value(S_TAG).equals(serviceVlan)) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800306 log.debug("Invalid vSG updates for {}", serviceVlan);
307 return;
308 }
309
Hyunsun Moon98025542016-03-08 04:36:02 -0800310 log.info("Updates vSGs in {} with {}", vSgHost.id(), vSgs.toString());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800311 vSgs.entrySet().stream()
Hyunsun Moon98025542016-03-08 04:36:02 -0800312 .filter(entry -> hostService.getHostsByMac(entry.getValue()).isEmpty())
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800313 .forEach(entry -> addVirtualSubscriberGateway(
Hyunsun Moon98025542016-03-08 04:36:02 -0800314 vSgHost,
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800315 entry.getKey(),
316 entry.getValue(),
317 serviceVlan));
318
Hyunsun Moon98025542016-03-08 04:36:02 -0800319 hostService.getConnectedHosts(vSgHost.location()).stream()
320 .filter(host -> !host.mac().equals(vSgHost.mac()))
Hyunsun Moon2a225162016-02-17 19:00:50 -0800321 .filter(host -> !vSgs.values().contains(host.mac()))
322 .forEach(host -> {
323 log.info("Removed vSG {}", host.toString());
324 hostProvider.hostVanished(host.id());
325 });
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800326 }
327
328 /**
329 * Adds virtual subscriber gateway to the system.
330 *
331 * @param vSgHost host virtual machine of this vSG
332 * @param vSgIp vSG ip address
333 * @param vSgMac vSG mac address
334 * @param serviceVlan service vlan
335 */
Hyunsun Moon2a225162016-02-17 19:00:50 -0800336 private void addVirtualSubscriberGateway(Host vSgHost, IpAddress vSgIp, MacAddress vSgMac,
337 String serviceVlan) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800338 log.info("vSG with IP({}) MAC({}) added", vSgIp.toString(), vSgMac.toString());
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800339
Hyunsun Moon98025542016-03-08 04:36:02 -0800340 HostId hostId = HostId.hostId(vSgMac);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800341 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moon98025542016-03-08 04:36:02 -0800342 .set(S_TAG, serviceVlan)
Hyunsun Moond35420f2016-03-08 21:59:13 -0800343 .set(VSG_HOST_ID, vSgHost.id().toString())
344 .set(CREATED_TIME, String.valueOf(System.currentTimeMillis()));
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800345
346 HostDescription hostDesc = new DefaultHostDescription(
347 vSgMac,
348 VlanId.NONE,
349 vSgHost.location(),
350 Sets.newHashSet(vSgIp),
351 annotations.build());
352
353 hostProvider.hostDetected(hostId, hostDesc, false);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800354 }
355
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800356 /**
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800357 * Returns public ip addresses of vSGs running inside a give vSG host.
358 *
359 * @param vSgHost vSG host
360 * @return map of ip and mac address, or empty map
361 */
362 private Map<IpAddress, MacAddress> getSubscriberGateways(Host vSgHost) {
363 String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
364 String serviceVlan = vSgHost.annotations().value(S_TAG);
365
366 OpenstackPort vPort = openstackService.port(vPortId);
367 if (vPort == null) {
368 log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
369 return Maps.newHashMap();
370 }
371
372 if (!serviceVlan.equals(getServiceVlan(vPort))) {
373 log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
374 return Maps.newHashMap();
375 }
376
377 return vPort.allowedAddressPairs();
378 }
379
380 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800381 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800382 *
383 * @param serviceId service id
384 * @return cord service, or null if it fails to get network from OpenStack
385 */
386 private CordService getCordService(CordServiceId serviceId) {
387 OpenstackNetwork vNet = openstackService.network(serviceId.id());
388 if (vNet == null) {
389 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
390 return null;
391 }
392
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800393 OpenstackSubnet subnet = vNet.subnets().stream()
394 .findFirst()
395 .orElse(null);
396 if (subnet == null) {
397 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
398 return null;
399 }
400
401 Set<CordServiceId> tServices = Sets.newHashSet();
402 // TODO get tenant services from XOS
403
404 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
405 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800406 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800407
408 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800409 }
410
411 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800412 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800413 *
414 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800415 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800416 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800417 private CordService getCordService(OpenstackNetwork vNet) {
418 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800419
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800420 CordServiceId serviceId = CordServiceId.of(vNet.id());
421 OpenstackSubnet subnet = vNet.subnets().stream()
422 .findFirst()
423 .orElse(null);
424 if (subnet == null) {
425 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
426 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800427 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800428
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800429 Set<CordServiceId> tServices = Sets.newHashSet();
430 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800431
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800432 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
433 .stream()
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800434 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800435
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800436 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800437 }
438
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800439 /**
440 * Returns IP address for tunneling for a given host.
441 *
442 * @param host host
Hyunsun Moon6d247342016-02-12 12:48:47 -0800443 * @return ip address, or null
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800444 */
445 private IpAddress getTunnelIp(Host host) {
Hyunsun Moon6d247342016-02-12 12:48:47 -0800446 String ip = host.annotations().value(DATA_PLANE_IP);
447 return ip == null ? null : IpAddress.valueOf(ip);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800448 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700449
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800450 /**
451 * Returns port name.
452 *
453 * @param port port
454 * @return port name
455 */
456 private String getPortName(Port port) {
457 return port.annotations().value("portName");
458 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800459
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800460 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800461 * Returns s-tag from a given OpenStack port.
462 *
463 * @param vPort openstack port
464 * @return s-tag string
465 */
466 private String getServiceVlan(OpenstackPort vPort) {
467 checkNotNull(vPort);
468
469 if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
470 return vPort.name().split("-")[1];
471 } else {
472 return null;
473 }
474 }
475
476 /**
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800477 * Returns service ID of this host.
478 *
479 * @param host host
480 * @return service id, or null if not found
481 */
482 private String getServiceId(Host host) {
483 return host.annotations().value(SERVICE_ID);
484 }
485
486 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800487 * Returns hosts associated with a given OpenStack network.
488 *
489 * @param vNet openstack network
490 * @return set of hosts
491 */
492 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
493 checkNotNull(vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700494
Hyunsun Moon32f3b8e2016-03-02 19:27:26 -0800495 String vNetId = vNet.id();
496 return StreamSupport.stream(hostService.getHosts().spliterator(), false)
497 .filter(host -> Objects.equals(vNetId, getServiceId(host)))
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800498 .collect(Collectors.toSet());
Hyunsun Moon6d247342016-02-12 12:48:47 -0800499 }
500
501 /**
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800502 * Registers static DHCP lease for a given host.
503 *
504 * @param host host
505 * @param service cord service
506 */
507 private void registerDhcpLease(Host host, CordService service) {
508 List<Ip4Address> options = Lists.newArrayList();
509 options.add(Ip4Address.makeMaskPrefix(service.serviceIpRange().prefixLength()));
510 options.add(service.serviceIp().getIp4Address());
511 options.add(service.serviceIp().getIp4Address());
512 options.add(DEFAULT_DNS);
513
514 log.debug("Set static DHCP mapping for {}", host.mac());
515 dhcpService.setStaticMapping(host.mac(),
516 host.ipAddresses().stream().findFirst().get().getIp4Address(),
517 true,
518 options);
519 }
520
521 /**
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800522 * Handles VM detected situation.
523 *
524 * @param host host
525 */
526 private void serviceVmAdded(Host host) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800527 String serviceVlan = host.annotations().value(S_TAG);
528 if (serviceVlan != null) {
529 virtualSubscriberGatewayAdded(host, serviceVlan);
530 }
531
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800532 String vNetId = host.annotations().value(SERVICE_ID);
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800533 if (vNetId == null) {
Hyunsun Moon2a225162016-02-17 19:00:50 -0800534 // ignore this host, it is not the service VM, or it's a vSG
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800535 return;
536 }
537
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800538 OpenstackNetwork vNet = openstackService.network(vNetId);
539 if (vNet == null) {
Hyunsun Moond35420f2016-03-08 21:59:13 -0800540 log.warn("Failed to get OpenStack network {} for VM {}.",
541 vNetId, host.id());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800542 return;
543 }
544
Hyunsun Moond35420f2016-03-08 21:59:13 -0800545 log.info("VM is detected, MAC: {} IP: {}",
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800546 host.mac(),
547 host.ipAddresses().stream().findFirst().get());
548
549 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800550 if (service == null) {
551 return;
552 }
553
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800554 switch (service.serviceType()) {
555 case MANAGEMENT:
556 ruleInstaller.populateManagementNetworkRules(host, service);
557 break;
558 case PRIVATE:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800559 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
Hyunsun Moon098cda82016-03-03 13:27:44 -0800560 case PUBLIC:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800561 default:
562 // TODO check if the service needs an update on its group buckets after done CORD-433
563 ruleInstaller.updateServiceGroup(service);
564 // sends gratuitous ARP here for the case of adding existing VMs
565 // when ONOS or cordvtn app is restarted
566 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), Sets.newHashSet(host));
567 break;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800568 }
569
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800570 registerDhcpLease(host, service);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800571 ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800572 }
573
574 /**
575 * Handles VM removed situation.
576 *
577 * @param host host
578 */
579 private void serviceVmRemoved(Host host) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800580 String serviceVlan = host.annotations().value(S_TAG);
581 if (serviceVlan != null) {
582 virtualSubscriberGatewayRemoved(host);
583 }
584
Hyunsun Moon2a225162016-02-17 19:00:50 -0800585 String vNetId = host.annotations().value(SERVICE_ID);
586 if (vNetId == null) {
587 // ignore it, it's not the service VM or it's a vSG
Hyunsun Moon1d3eac92016-02-03 00:11:11 -0800588 return;
589 }
590
Hyunsun Moon6d247342016-02-12 12:48:47 -0800591 OpenstackNetwork vNet = openstackService.network(vNetId);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800592 if (vNet == null) {
Hyunsun Moond35420f2016-03-08 21:59:13 -0800593 log.warn("Failed to get OpenStack network {} for VM {}",
594 vNetId, host.id());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800595 return;
596 }
597
Hyunsun Moond35420f2016-03-08 21:59:13 -0800598 log.info("VM is vanished, MAC: {} IP: {}",
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800599 host.mac(),
600 host.ipAddresses().stream().findFirst().get());
601
602 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moonfb631b42016-02-03 14:44:06 -0800603 dhcpService.removeStaticMapping(host.mac());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800604
605 CordService service = getCordService(vNet);
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800606 if (service == null) {
607 return;
608 }
609
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800610 switch (service.serviceType()) {
611 case MANAGEMENT:
612 ruleInstaller.removeManagementNetworkRules(host, service);
613 break;
614 case PRIVATE:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800615 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
616 arpProxy.removeGateway(service.serviceIp());
617 }
Hyunsun Moon098cda82016-03-03 13:27:44 -0800618 case PUBLIC:
Hyunsun Moon1e5caeb2016-03-01 16:36:23 -0800619 default:
620 // TODO check if the service needs an update on its group buckets after done CORD-433
621 ruleInstaller.updateServiceGroup(service);
622 break;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700623 }
624 }
625
Hyunsun Moon98025542016-03-08 04:36:02 -0800626
627 /**
628 * Handles virtual subscriber gateway VM or container.
629 *
630 * @param host new host with stag, it can be vsg VM or vsg
631 * @param serviceVlan service vlan
632 */
633 private void virtualSubscriberGatewayAdded(Host host, String serviceVlan) {
634 Map<IpAddress, MacAddress> vSgs;
635 Host vSgHost;
636
637 String vSgHostId = host.annotations().value(VSG_HOST_ID);
638 if (vSgHostId == null) {
639 log.debug("vSG VM detected {}", host.id());
640
641 vSgHost = host;
642 vSgs = getSubscriberGateways(vSgHost);
643 vSgs.entrySet().stream().forEach(entry -> addVirtualSubscriberGateway(
644 vSgHost,
645 entry.getKey(),
646 entry.getValue(),
647 serviceVlan));
648 } else {
649 vSgHost = hostService.getHost(HostId.hostId(vSgHostId));
650 if (vSgHost == null) {
651 return;
652 }
653
654 log.debug("vSG detected {}", host.id());
655 vSgs = getSubscriberGateways(vSgHost);
656 }
657
658 ruleInstaller.populateSubscriberGatewayRules(vSgHost, vSgs.keySet());
659 }
660
661 /**
662 * Handles virtual subscriber gateway removed.
663 *
664 * @param vSg vsg host to remove
665 */
666 private void virtualSubscriberGatewayRemoved(Host vSg) {
667 String vSgHostId = vSg.annotations().value(VSG_HOST_ID);
668 if (vSgHostId == null) {
669 return;
670 }
671
672 Host vSgHost = hostService.getHost(HostId.hostId(vSgHostId));
673 if (vSgHost == null) {
674 return;
675 }
676
677 log.info("vSG removed {}", vSg.id());
678 Map<IpAddress, MacAddress> vSgs = getSubscriberGateways(vSgHost);
679 ruleInstaller.populateSubscriberGatewayRules(vSgHost, vSgs.keySet());
680 }
681
Hyunsun Moon746956f2016-01-24 21:47:06 -0800682 /**
683 * Sets service network gateway MAC address and sends out gratuitous ARP to all
684 * VMs to update the gateway MAC address.
685 *
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800686 * @param newMac mac address to update
Hyunsun Moon746956f2016-01-24 21:47:06 -0800687 */
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800688 private void setPrivateGatewayMac(MacAddress newMac) {
689 if (newMac == null || newMac.equals(privateGatewayMac)) {
690 // no updates, do nothing
691 return;
Hyunsun Moon746956f2016-01-24 21:47:06 -0800692 }
693
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800694 privateGatewayMac = newMac;
695 log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
696
Hyunsun Moon746956f2016-01-24 21:47:06 -0800697 // TODO get existing service list from XOS and replace the loop below
698 Set<String> vNets = Sets.newHashSet();
699 hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
700 vNets.remove(null);
701
702 vNets.stream().forEach(vNet -> {
703 CordService service = getCordService(CordServiceId.of(vNet));
704 if (service != null) {
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800705 arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
706 arpProxy.sendGratuitousArpForGateway(service.serviceIp(), service.hosts().keySet());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800707 }
708 });
709 }
710
711 /**
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800712 * Sets public gateway MAC address.
713 *
714 * @param publicGateways gateway ip and mac address pairs
715 */
716 private void setPublicGatewayMac(Map<IpAddress, MacAddress> publicGateways) {
717 publicGateways.entrySet()
718 .stream()
719 .forEach(entry -> {
720 arpProxy.addGateway(entry.getKey(), entry.getValue());
Hyunsun Moon80b03872016-03-10 12:40:16 -0800721 log.info("Added public gateway IP {}, MAC {}",
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800722 entry.getKey().toString(), entry.getValue().toString());
723 });
724 // TODO notice gateway MAC change to VMs holds this gateway IP
725 }
726
727 /**
Hyunsun Moon746956f2016-01-24 21:47:06 -0800728 * Updates configurations.
729 */
730 private void readConfiguration() {
731 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
732 if (config == null) {
733 log.debug("No configuration found");
734 return;
735 }
736
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800737 setPrivateGatewayMac(config.privateGatewayMac());
738 setPublicGatewayMac(config.publicGateways());
Hyunsun Moon746956f2016-01-24 21:47:06 -0800739 }
740
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700741 private class InternalHostListener implements HostListener {
742
743 @Override
744 public void event(HostEvent event) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800745 Host host = event.subject();
Hyunsun Moond35420f2016-03-08 21:59:13 -0800746 if (!mastershipService.isLocalMaster(host.location().deviceId())) {
747 // do not allow to proceed without mastership
748 return;
749 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700750
751 switch (event.type()) {
Hyunsun Moond35420f2016-03-08 21:59:13 -0800752 case HOST_UPDATED:
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700753 case HOST_ADDED:
Hyunsun Moond35420f2016-03-08 21:59:13 -0800754 eventExecutor.submit(() -> serviceVmAdded(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700755 break;
756 case HOST_REMOVED:
Hyunsun Moond35420f2016-03-08 21:59:13 -0800757 eventExecutor.submit(() -> serviceVmRemoved(host));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700758 break;
759 default:
760 break;
761 }
762 }
763 }
764
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800765 private class InternalPacketProcessor implements PacketProcessor {
766
767 @Override
768 public void process(PacketContext context) {
769 if (context.isHandled()) {
770 return;
771 }
772
773 Ethernet ethPacket = context.inPacket().parsed();
Hyunsun Moon746956f2016-01-24 21:47:06 -0800774 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800775 return;
776 }
777
Hyunsun Moonae39ae82016-02-17 15:02:06 -0800778 arpProxy.processArpPacket(context, ethPacket);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800779 }
780 }
781
782 private class InternalConfigListener implements NetworkConfigListener {
783
784 @Override
785 public void event(NetworkConfigEvent event) {
786 if (!event.configClass().equals(CordVtnConfig.class)) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800787 return;
788 }
789
Hyunsun Moon746956f2016-01-24 21:47:06 -0800790 switch (event.type()) {
791 case CONFIG_ADDED:
792 case CONFIG_UPDATED:
793 log.info("Network configuration changed");
794 eventExecutor.execute(CordVtn.this::readConfiguration);
795 break;
796 default:
797 break;
798 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800799 }
800 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700801}