blob: b73422665d17e7d7295505a03e00d5d1f405ee71 [file] [log] [blame]
Jian Lib5ab63c2021-02-03 17:54:28 +09001/*
2 * Copyright 2021-present Open Networking Foundation
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.kubevirtnetworking.impl;
17
18import com.google.common.collect.Lists;
Jian Li543fe852021-02-04 17:25:01 +090019import org.onlab.packet.ARP;
20import org.onlab.packet.EthType;
Jian Lib5ab63c2021-02-03 17:54:28 +090021import org.onlab.packet.Ethernet;
22import org.onlab.packet.IPv4;
Jian Li543fe852021-02-04 17:25:01 +090023import org.onlab.packet.Ip4Address;
Jian Lib5ab63c2021-02-03 17:54:28 +090024import org.onlab.packet.IpAddress;
Jian Li543fe852021-02-04 17:25:01 +090025import org.onlab.packet.IpPrefix;
Daniel Parkb9a22022021-03-04 18:58:47 +090026import org.onlab.packet.MacAddress;
Jian Lib5ab63c2021-02-03 17:54:28 +090027import org.onlab.packet.TpPort;
28import org.onlab.packet.UDP;
29import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
35import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
36import org.onosproject.kubevirtnetworking.api.KubevirtNetworkEvent;
37import org.onosproject.kubevirtnetworking.api.KubevirtNetworkListener;
38import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
Daniel Parkb9a22022021-03-04 18:58:47 +090039import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
40import org.onosproject.kubevirtnetworking.api.KubevirtRouterAdminService;
41import org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent;
42import org.onosproject.kubevirtnetworking.api.KubevirtRouterListener;
Jian Lib5ab63c2021-02-03 17:54:28 +090043import org.onosproject.kubevirtnode.api.KubevirtApiConfigService;
44import org.onosproject.kubevirtnode.api.KubevirtNode;
45import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
46import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
47import org.onosproject.kubevirtnode.api.KubevirtNodeService;
48import org.onosproject.net.Device;
49import org.onosproject.net.DeviceId;
50import org.onosproject.net.PortNumber;
51import org.onosproject.net.behaviour.BridgeConfig;
52import org.onosproject.net.behaviour.BridgeDescription;
53import org.onosproject.net.behaviour.BridgeName;
54import org.onosproject.net.behaviour.ControllerInfo;
55import org.onosproject.net.behaviour.DefaultBridgeDescription;
56import org.onosproject.net.behaviour.DefaultPatchDescription;
57import org.onosproject.net.behaviour.InterfaceConfig;
58import org.onosproject.net.behaviour.PatchDescription;
59import org.onosproject.net.device.DeviceAdminService;
Daniel Park4063f402021-02-25 09:14:22 +090060import org.onosproject.net.driver.DriverService;
Jian Lib5ab63c2021-02-03 17:54:28 +090061import org.onosproject.net.flow.DefaultTrafficSelector;
62import org.onosproject.net.flow.DefaultTrafficTreatment;
63import org.onosproject.net.flow.TrafficSelector;
64import org.onosproject.net.flow.TrafficTreatment;
65import org.osgi.service.component.annotations.Activate;
66import org.osgi.service.component.annotations.Component;
67import org.osgi.service.component.annotations.Deactivate;
68import org.osgi.service.component.annotations.Reference;
69import org.osgi.service.component.annotations.ReferenceCardinality;
70import org.slf4j.Logger;
71
72import java.util.List;
73import java.util.Objects;
Daniel Parkb9a22022021-03-04 18:58:47 +090074import java.util.Set;
Jian Lib5ab63c2021-02-03 17:54:28 +090075import java.util.concurrent.ExecutorService;
76
77import static java.lang.Thread.sleep;
78import static java.util.concurrent.Executors.newSingleThreadExecutor;
Jian Li543fe852021-02-04 17:25:01 +090079import static org.onlab.packet.ICMP.CODE_ECHO_REQEUST;
80import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
81import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Jian Lib5ab63c2021-02-03 17:54:28 +090082import static org.onlab.util.Tools.groupedThreads;
83import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Daniel Park4063f402021-02-25 09:14:22 +090084import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090085import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Lib5ab63c2021-02-03 17:54:28 +090086import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_DHCP_RULE;
Jian Li543fe852021-02-04 17:25:01 +090087import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
88import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ICMP_RULE;
89import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ARP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090090import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_DHCP_TABLE;
91import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090092import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ICMP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090093import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_INBOUND_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090094import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_TO_TUNNEL_PREFIX;
95import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Daniel Parkb9a22022021-03-04 18:58:47 +090096import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
97import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getbrIntMacAddress;
Jian Lib5ab63c2021-02-03 17:54:28 +090098import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.segmentIdHex;
Jian Li543fe852021-02-04 17:25:01 +090099import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_NX_IP_TTL;
100import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_OF_ICMP_TYPE;
101import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildLoadExtension;
102import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
103import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
104import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
105import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveIpSrcToDstExtension;
Jian Lib5ab63c2021-02-03 17:54:28 +0900106import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_BRIDGE;
Daniel Park4063f402021-02-25 09:14:22 +0900107import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
108import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
Jian Lib5ab63c2021-02-03 17:54:28 +0900109import static org.slf4j.LoggerFactory.getLogger;
110
111/**
112 * Handles kubevirt network events.
113 */
114@Component(immediate = true)
115public class KubevirtNetworkHandler {
116 protected final Logger log = getLogger(getClass());
117 private static final String DEFAULT_OF_PROTO = "tcp";
118 private static final int DEFAULT_OFPORT = 6653;
119 private static final int DPID_BEGIN = 3;
120 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li543fe852021-02-04 17:25:01 +0900121 private static final int DEFAULT_TTL = 0xff;
Jian Lib5ab63c2021-02-03 17:54:28 +0900122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
124 protected CoreService coreService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
127 protected ClusterService clusterService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
130 protected LeadershipService leadershipService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
133 protected DeviceAdminService deviceService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
136 protected KubevirtApiConfigService apiConfigService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
139 protected KubevirtNodeService nodeService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
142 protected KubevirtNetworkService networkService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
145 protected KubevirtFlowRuleService flowService;
146
Daniel Park4063f402021-02-25 09:14:22 +0900147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
148 protected DriverService driverService;
149
Daniel Parkb9a22022021-03-04 18:58:47 +0900150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
151 protected KubevirtRouterAdminService kubevirtRouterService;
152
Jian Lib5ab63c2021-02-03 17:54:28 +0900153 private final KubevirtNetworkListener networkListener = new InternalNetworkEventListener();
154 private final KubevirtNodeListener nodeListener = new InternalNodeEventListener();
155
Daniel Parkb9a22022021-03-04 18:58:47 +0900156 private final InternalRouterEventListener kubevirtRouterlistener =
157 new InternalRouterEventListener();
158
Jian Lib5ab63c2021-02-03 17:54:28 +0900159 private final ExecutorService eventExecutor = newSingleThreadExecutor(
160 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
161
162 private ApplicationId appId;
163 private NodeId localNodeId;
164
165 @Activate
166 protected void activate() {
167 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
168 localNodeId = clusterService.getLocalNode().id();
169 networkService.addListener(networkListener);
170 nodeService.addListener(nodeListener);
171 leadershipService.runForLeadership(appId.name());
172
Daniel Parkb9a22022021-03-04 18:58:47 +0900173 kubevirtRouterService.addListener(kubevirtRouterlistener);
174
Jian Lib5ab63c2021-02-03 17:54:28 +0900175 log.info("Started");
176 }
177
178 @Deactivate
179 protected void deactivate() {
180 networkService.removeListener(networkListener);
181 nodeService.removeListener(nodeListener);
182 leadershipService.withdraw(appId.name());
Daniel Parkb9a22022021-03-04 18:58:47 +0900183
184 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Jian Lib5ab63c2021-02-03 17:54:28 +0900185 eventExecutor.shutdown();
186
187 log.info("Stopped");
188 }
189
190 private void createBridge(KubevirtNode node, KubevirtNetwork network) {
191
192 Device tunBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
193 if (tunBridge != null) {
194 log.warn("The tunnel bridge {} already exists at node {}",
195 network.tenantBridgeName(), node.hostname());
196 setDefaultRules(node, network);
197 return;
198 }
199
200 Device device = deviceService.getDevice(node.ovsdb());
201
202 IpAddress serverIp = apiConfigService.apiConfig().ipAddress();
203 ControllerInfo controlInfo =
204 new ControllerInfo(serverIp, DEFAULT_OFPORT, DEFAULT_OF_PROTO);
205 List<ControllerInfo> controllers = Lists.newArrayList(controlInfo);
206
207 String dpid = network.tenantDeviceId(
208 node.hostname()).toString().substring(DPID_BEGIN);
209
210 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
211 .name(network.tenantBridgeName())
212 .failMode(BridgeDescription.FailMode.SECURE)
213 .datapathId(dpid)
214 .disableInBand()
215 .controllers(controllers);
216
217 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
218 bridgeConfig.addBridge(builder.build());
219 }
220
221 private void removeBridge(KubevirtNode node, KubevirtNetwork network) {
222 Device device = deviceService.getDevice(node.ovsdb());
223
224 BridgeName bridgeName = BridgeName.bridgeName(network.tenantBridgeName());
225
226 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
227 bridgeConfig.deleteBridge(bridgeName);
228 deviceService.removeDevice(network.tenantDeviceId(node.hostname()));
229 }
230
231 private void createPatchInterface(KubevirtNode node, KubevirtNetwork network) {
232 Device device = deviceService.getDevice(node.ovsdb());
233
234 if (device == null || !device.is(InterfaceConfig.class)) {
235 log.error("Failed to create patch interface on {}", node.ovsdb());
236 return;
237 }
238
239 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
240
Jian Li543fe852021-02-04 17:25:01 +0900241 String tenantToTunIntf =
242 TENANT_TO_TUNNEL_PREFIX + segmentIdHex(network.segmentId());
243 String tunToTenantIntf =
244 TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900245
Jian Li543fe852021-02-04 17:25:01 +0900246 // tenant bridge -> tunnel bridge
247 PatchDescription brTenantTunPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900248 DefaultPatchDescription.builder()
249 .deviceId(network.tenantBridgeName())
Jian Li543fe852021-02-04 17:25:01 +0900250 .ifaceName(tenantToTunIntf)
251 .peer(tunToTenantIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900252 .build();
253
Jian Li543fe852021-02-04 17:25:01 +0900254 ifaceConfig.addPatchMode(tenantToTunIntf, brTenantTunPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900255
Jian Li543fe852021-02-04 17:25:01 +0900256 // tunnel bridge -> tenant bridge
257 PatchDescription brTunTenantPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900258 DefaultPatchDescription.builder()
259 .deviceId(TUNNEL_BRIDGE)
Jian Li543fe852021-02-04 17:25:01 +0900260 .ifaceName(tunToTenantIntf)
261 .peer(tenantToTunIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900262 .build();
Jian Li543fe852021-02-04 17:25:01 +0900263 ifaceConfig.addPatchMode(tunToTenantIntf, brTunTenantPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900264 }
265
266 private void removePatchInterface(KubevirtNode node, KubevirtNetwork network) {
267 Device device = deviceService.getDevice(node.ovsdb());
268
269 if (device == null || !device.is(InterfaceConfig.class)) {
270 log.error("Failed to create patch interface on {}", node.ovsdb());
271 return;
272 }
273
274 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
275
Jian Li543fe852021-02-04 17:25:01 +0900276 String tunToIntIntf = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900277
278 ifaceConfig.removePatchMode(tunToIntIntf);
279 }
280
281 private void setDefaultRules(KubevirtNode node, KubevirtNetwork network) {
282 DeviceId deviceId = network.tenantDeviceId(node.hostname());
283
284 while (!deviceService.isAvailable(deviceId)) {
285 log.warn("Device {} is not ready for installing rules", deviceId);
286
287 try {
288 sleep(SLEEP_MS);
289 } catch (InterruptedException e) {
290 log.error("Failed to check device availability", e);
291 }
292 }
293
294 flowService.connectTables(deviceId, TENANT_INBOUND_TABLE, TENANT_DHCP_TABLE);
Jian Li543fe852021-02-04 17:25:01 +0900295 flowService.connectTables(deviceId, TENANT_DHCP_TABLE, TENANT_ARP_TABLE);
296 flowService.connectTables(deviceId, TENANT_ARP_TABLE, TENANT_ICMP_TABLE);
297 flowService.connectTables(deviceId, TENANT_ICMP_TABLE, TENANT_FORWARDING_TABLE);
Jian Lib5ab63c2021-02-03 17:54:28 +0900298
299 setDhcpRule(deviceId, true);
300 setForwardingRule(deviceId, true);
Daniel Parkb9a22022021-03-04 18:58:47 +0900301 setGatewayArpRuleForInternalNetwork(network, TENANT_ARP_TABLE,
Daniel Park4063f402021-02-25 09:14:22 +0900302 network.tenantDeviceId(node.hostname()), true);
Daniel Parkb9a22022021-03-04 18:58:47 +0900303 setGatewayIcmpRuleForInternalNetwork(network, TENANT_ICMP_TABLE,
Daniel Park4063f402021-02-25 09:14:22 +0900304 network.tenantDeviceId(node.hostname()), true);
Jian Lib5ab63c2021-02-03 17:54:28 +0900305
306 log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
307 }
308
309 private void setDhcpRule(DeviceId deviceId, boolean install) {
310 TrafficSelector selector = DefaultTrafficSelector.builder()
311 .matchEthType(Ethernet.TYPE_IPV4)
312 .matchIPProtocol(IPv4.PROTOCOL_UDP)
313 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
314 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
315 .build();
316
317 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
318 .punt()
319 .build();
320
321 flowService.setRule(
322 appId,
323 deviceId,
324 selector,
325 treatment,
326 PRIORITY_DHCP_RULE,
327 TENANT_DHCP_TABLE,
328 install);
329 }
330
Jian Li543fe852021-02-04 17:25:01 +0900331 private void setForwardingRule(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900332 TrafficSelector selector = DefaultTrafficSelector.builder().build();
333 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
334 .setOutput(PortNumber.NORMAL)
335 .build();
336
337 flowService.setRule(
338 appId,
339 deviceId,
340 selector,
341 treatment,
Jian Li543fe852021-02-04 17:25:01 +0900342 PRIORITY_FORWARDING_RULE,
Jian Lib5ab63c2021-02-03 17:54:28 +0900343 TENANT_FORWARDING_TABLE,
344 install);
345 }
346
Daniel Parkb9a22022021-03-04 18:58:47 +0900347 private void initGatewayNodeForInternalNetwork(KubevirtNetwork network,
348 KubevirtRouter router,
349 KubevirtNode electedGateway,
350 boolean install) {
351 setGatewayArpRuleForInternalNetwork(network, PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
352 setGatewayIcmpRuleForInternalNetwork(network, PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
353 }
354
355
356 private void setGatewayInterNetworkRouting(KubevirtNetwork network, KubevirtRouter router, boolean install) {
357 router.internal().forEach(srcNetwork -> {
358 if (srcNetwork.equals(network.networkId())) {
359 return;
360 }
361
362 });
363 }
364
365 private void setGatewayArpRuleForInternalNetwork(KubevirtNetwork network,
366 int tableNum, DeviceId deviceId, boolean install) {
Daniel Park4063f402021-02-25 09:14:22 +0900367 Device device = deviceService.getDevice(deviceId);
Jian Li543fe852021-02-04 17:25:01 +0900368
Daniel Parkb9a22022021-03-04 18:58:47 +0900369 MacAddress brIntMacAddress = getbrIntMacAddress(deviceService, deviceId);
370
371 if (brIntMacAddress == null) {
372 log.error("Setting gateway arp rule for internal network because " +
373 "there's no br-int port for device {}", deviceId);
374 return;
375 }
376
Jian Li543fe852021-02-04 17:25:01 +0900377 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
378 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
379 .matchArpOp(ARP.OP_REQUEST)
380 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
381
382 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
383 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
384 .extension(buildMoveArpShaToThaExtension(device), device.id())
385 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
386 .setArpOp(ARP.OP_REPLY)
Daniel Parkb9a22022021-03-04 18:58:47 +0900387 .setArpSha(brIntMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900388 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parkb9a22022021-03-04 18:58:47 +0900389 .setEthSrc(brIntMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900390 .setOutput(PortNumber.IN_PORT);
391
392 flowService.setRule(
393 appId,
394 device.id(),
395 sBuilder.build(),
396 tBuilder.build(),
397 PRIORITY_ARP_GATEWAY_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900398 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900399 install
400 );
401 }
402
Daniel Parkb9a22022021-03-04 18:58:47 +0900403 /**
404 * Sends ICMP echo reply for the ICMP echo request from the kubevirt VM.
405 *
406 * @param network kubevirt network
407 * @param tableNum flow table number
408 * @param deviceId device id of the selected gateway for the network
409 * @param install install if true, remove otherwise
410 */
411 private void setGatewayIcmpRuleForInternalNetwork(KubevirtNetwork network,
412 int tableNum, DeviceId deviceId, boolean install) {
413 MacAddress brIntMacAddress = getbrIntMacAddress(deviceService, deviceId);
414
415 if (brIntMacAddress == null) {
416 log.error("Setting gateway ICMP rule for internal network because " +
417 "there's no br-int port for device {}", deviceId);
418 return;
419 }
420
Jian Li543fe852021-02-04 17:25:01 +0900421 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
422 .matchEthType(Ethernet.TYPE_IPV4)
423 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
424 .matchIcmpType(TYPE_ECHO_REQUEST)
425 .matchIcmpCode(CODE_ECHO_REQEUST)
426 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
427
428 Device device = deviceService.getDevice(deviceId);
429 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
430 .extension(buildMoveEthSrcToDstExtension(device), device.id())
431 .extension(buildMoveIpSrcToDstExtension(device), device.id())
432 .extension(buildLoadExtension(device,
433 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
434 .extension(buildLoadExtension(device,
435 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
436 .setIpSrc(network.gatewayIp())
Daniel Parkb9a22022021-03-04 18:58:47 +0900437 .setEthSrc(brIntMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900438 .setOutput(PortNumber.IN_PORT);
439
440 flowService.setRule(
441 appId,
442 deviceId,
443 sBuilder.build(),
444 tBuilder.build(),
445 PRIORITY_ICMP_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900446 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900447 install);
448 }
449
Daniel Parkb9a22022021-03-04 18:58:47 +0900450 private class InternalRouterEventListener implements KubevirtRouterListener {
451 private boolean isRelevantHelper() {
452 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park4063f402021-02-25 09:14:22 +0900453 }
454
Daniel Parkb9a22022021-03-04 18:58:47 +0900455 @Override
456 public void event(KubevirtRouterEvent event) {
457 switch (event.type()) {
458 case KUBEVIRT_ROUTER_CREATED:
459 eventExecutor.execute(() -> processRouterCreation(event.subject()));
460 break;
461 case KUBEVIRT_ROUTER_REMOVED:
462 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
463 break;
464 case KUBEVIRT_ROUTER_UPDATED:
465 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
466 break;
467 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
468 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
469 event.internal()));
470 break;
471 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
472 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
473 event.internal()));
474 break;
475 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
476 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
477 event.gateway()));
478 break;
479 case KUBEVIRT_GATEWAY_NODE_DETACHED:
480 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
481 event.gateway()));
482 break;
483 case KUBEVIRT_GATEWAY_NODE_CHANGED:
484 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
485 event.gateway()));
486 break;
Daniel Park4063f402021-02-25 09:14:22 +0900487
Daniel Parkb9a22022021-03-04 18:58:47 +0900488 default:
489 //do nothing
490 break;
491 }
492 }
493
494 private void processRouterCreation(KubevirtRouter router) {
495 // When a router is created, we performs the election process to associate the router
496 // to the specific gateway. After the election, KubevirtNetwork handler installs bunch of rules
497 // to elected gateway node so that VMs associated to the router can ping to their gateway IP.
498 // SNAT and floating ip rule setup is out of this handler's scope and would be done with the other handlers
499 if (!isRelevantHelper()) {
500 return;
501 }
502 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
503 if (electedGw == null) {
504 return;
505 }
506
507 router.internal().forEach(networkName -> {
508 KubevirtNetwork network = networkService.network(networkName);
509
510 if (network != null) {
511 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
512 }
513 });
514 kubevirtRouterService.updateRouter(router.updatedElectedGateway(electedGw.hostname()));
515 }
516
517 private void processRouterDeletion(KubevirtRouter router) {
518 if (!isRelevantHelper()) {
519 return;
520 }
521 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
522 if (electedGw == null) {
523 return;
524 }
525
526 router.internal().forEach(networkName -> {
527 KubevirtNetwork network = networkService.network(networkName);
528
529 if (network != null) {
530 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
531 }
532 });
533 }
534
535 private void processRouterUpdate(KubevirtRouter router) {
536 if (!isRelevantHelper()) {
537 return;
538 }
539 if (router.electedGateway() == null) {
540 return;
541 }
542
543 KubevirtNode electedGw = nodeService.node(router.electedGateway());
544
545 router.internal().forEach(networkName -> {
546 KubevirtNetwork network = networkService.network(networkName);
547
548 if (network != null) {
549 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
550 }
551 });
552 }
553
554 private void processRouterInternalNetworksAttached(KubevirtRouter router,
555 Set<String> attachedInternalNetworks) {
556 if (!isRelevantHelper()) {
557 return;
558 }
559 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
560 if (electedGw == null) {
561 return;
562 }
563
564 attachedInternalNetworks.forEach(networkName -> {
565 KubevirtNetwork network = networkService.network(networkName);
566
567 if (network != null) {
568 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
569 }
570 });
571 }
572
573 private void processRouterInternalNetworksDetached(KubevirtRouter router,
574 Set<String> detachedInternalNetworks) {
575 if (!isRelevantHelper()) {
576 return;
577 }
578 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
579 if (electedGw == null) {
580 return;
581 }
582
583 detachedInternalNetworks.forEach(networkName -> {
584 KubevirtNetwork network = networkService.network(networkName);
585
586 if (network != null) {
587 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
588 }
589 });
590
591 }
592
593 private void processRouterGatewayNodeAttached(KubevirtRouter router,
594 String associatedGateway) {
595 if (!isRelevantHelper()) {
596 return;
597 }
598
599 KubevirtNode gatewayNode = nodeService.node(associatedGateway);
600 if (gatewayNode == null) {
601 return;
602 }
603
604 router.internal().forEach(networkName -> {
605 KubevirtNetwork network = networkService.network(networkName);
606
607 if (network != null) {
608 initGatewayNodeForInternalNetwork(network, router, gatewayNode, true);
609 }
610 });
611 }
612
613 private void processRouterGatewayNodeDetached(KubevirtRouter router,
614 String disAssociatedGateway) {
615 if (!isRelevantHelper()) {
616 return;
617 }
618
619 KubevirtNode gatewayNode = nodeService.node(disAssociatedGateway);
620 if (gatewayNode == null) {
621 return;
622 }
623
624 router.internal().forEach(networkName -> {
625 KubevirtNetwork network = networkService.network(networkName);
626
627 if (network != null) {
628 initGatewayNodeForInternalNetwork(network, router, gatewayNode, false);
629 }
630 });
631 }
632
633 private void processRouterGatewayNodeChanged(KubevirtRouter router,
634 String disAssociatedGateway) {
635 if (!isRelevantHelper()) {
636 return;
637 }
638
639 KubevirtNode oldGatewayNode = nodeService.node(disAssociatedGateway);
640 if (oldGatewayNode == null) {
641 return;
642 }
643
644 router.internal().forEach(networkName -> {
645 KubevirtNetwork network = networkService.network(networkName);
646
647 if (network != null) {
648 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, false);
649 }
650 });
651
652 KubevirtNode newGatewayNode = nodeService.node(router.electedGateway());
653 if (newGatewayNode == null) {
654 return;
655 }
656
657 router.internal().forEach(networkName -> {
658 KubevirtNetwork network = networkService.network(networkName);
659
660 if (network != null) {
661 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, true);
662 }
663 });
664 }
Daniel Park4063f402021-02-25 09:14:22 +0900665 }
666
Jian Lib5ab63c2021-02-03 17:54:28 +0900667 private class InternalNetworkEventListener implements KubevirtNetworkListener {
668
669 private boolean isRelevantHelper() {
670 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
671 }
672
673 @Override
674 public void event(KubevirtNetworkEvent event) {
675 switch (event.type()) {
676 case KUBEVIRT_NETWORK_CREATED:
677 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
678 break;
679 case KUBEVIRT_NETWORK_REMOVED:
680 eventExecutor.execute(() -> processNetworkRemoval(event.subject()));
681 break;
682 case KUBEVIRT_NETWORK_UPDATED:
683 default:
684 // do nothing
685 break;
686 }
687 }
688
689 private void processNetworkCreation(KubevirtNetwork network) {
690 if (!isRelevantHelper()) {
691 return;
692 }
693
694 switch (network.type()) {
695 case VXLAN:
696 case GRE:
697 case GENEVE:
698 initIntegrationTunnelBridge(network);
699 break;
700 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +0900701 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +0900702 break;
Jian Lib5ab63c2021-02-03 17:54:28 +0900703 default:
704 // do nothing
705 break;
706 }
707 }
708
709 private void processNetworkRemoval(KubevirtNetwork network) {
710 if (!isRelevantHelper()) {
711 return;
712 }
713
714 switch (network.type()) {
715 case VXLAN:
716 case GRE:
717 case GENEVE:
718 purgeIntegrationTunnelBridge(network);
719 break;
720 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +0900721 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +0900722 break;
Jian Lib5ab63c2021-02-03 17:54:28 +0900723 default:
724 // do nothing
725 break;
726 }
727 }
728
729 private void initIntegrationTunnelBridge(KubevirtNetwork network) {
730 if (network.segmentId() == null) {
731 return;
732 }
733
734 nodeService.completeNodes().forEach(n -> {
735 createBridge(n, network);
736 createPatchInterface(n, network);
737 setDefaultRules(n, network);
738 });
739 }
740
741 private void purgeIntegrationTunnelBridge(KubevirtNetwork network) {
742 if (network.segmentId() == null) {
743 return;
744 }
745
746 nodeService.completeNodes().forEach(n -> {
747 removePatchInterface(n, network);
748 removeBridge(n, network);
749 });
750 }
751 }
752
753 private class InternalNodeEventListener implements KubevirtNodeListener {
754
755 private boolean isRelevantHelper() {
756 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
757 }
758
759 @Override
760 public void event(KubevirtNodeEvent event) {
761 switch (event.type()) {
762 case KUBEVIRT_NODE_COMPLETE:
763 eventExecutor.execute(() -> processNodeCompletion(event.subject()));
764 break;
Daniel Parkb9a22022021-03-04 18:58:47 +0900765 case KUBEVIRT_NODE_REMOVED:
766 eventExecutor.execute(() -> processNodeDeletion(event.subject()));
767 break;
Jian Lib5ab63c2021-02-03 17:54:28 +0900768 case KUBEVIRT_NODE_INCOMPLETE:
769 case KUBEVIRT_NODE_UPDATED:
770 default:
771 // do nothing
772 break;
773 }
774 }
775
776 private void processNodeCompletion(KubevirtNode node) {
777 if (!isRelevantHelper()) {
778 return;
779 }
780
Daniel Park4063f402021-02-25 09:14:22 +0900781 if (node.type().equals(WORKER)) {
782 for (KubevirtNetwork network : networkService.networks()) {
783 switch (network.type()) {
784 case VXLAN:
785 case GRE:
786 case GENEVE:
787 if (network.segmentId() == null) {
788 continue;
789 }
790 createBridge(node, network);
791 createPatchInterface(node, network);
792 setDefaultRules(node, network);
793 break;
794 case FLAT:
795 case VLAN:
796 default:
797 // do nothing
798 break;
799 }
800 }
801 } else if (node.type().equals(GATEWAY)) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900802 updateGatewayNodeForRouter();
Daniel Park4063f402021-02-25 09:14:22 +0900803 for (KubevirtNetwork network : networkService.networks()) {
804 switch (network.type()) {
805 case FLAT:
806 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +0900807 break;
808 case VXLAN:
809 case GRE:
810 case GENEVE:
811 default:
812 // do nothing
813 break;
814 }
Jian Lib5ab63c2021-02-03 17:54:28 +0900815 }
816 }
817 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900818
819 private void processNodeDeletion(KubevirtNode node) {
820 if (!isRelevantHelper()) {
821 return;
822 }
823
824 if (node.type().equals(GATEWAY)) {
825 updateGatewayNodeForRouter();
826 for (KubevirtNetwork network : networkService.networks()) {
827 switch (network.type()) {
828 case FLAT:
829 case VLAN:
830 break;
831 case VXLAN:
832 case GRE:
833 case GENEVE:
834 default:
835 // do nothing
836 break;
837 }
838 }
839 }
840 }
841
842 private void updateGatewayNodeForRouter() {
843 kubevirtRouterService.routers().forEach(router -> {
844 KubevirtNode newGwNode = gatewayNodeForSpecifiedRouter(nodeService, router);
845
846 if (newGwNode == null) {
847 return;
848 }
849 kubevirtRouterService.updateRouter(router.updatedElectedGateway(newGwNode.hostname()));
850 });
851 }
Jian Lib5ab63c2021-02-03 17:54:28 +0900852 }
853}