blob: f1b41bc07db390e3acc7b36a1d8433f8b18673d5 [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 Parkcc8e7462021-03-09 13:37:42 +090039import org.onosproject.kubevirtnetworking.api.KubevirtPort;
40import org.onosproject.kubevirtnetworking.api.KubevirtPortEvent;
41import org.onosproject.kubevirtnetworking.api.KubevirtPortListener;
42import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
Daniel Parkb9a22022021-03-04 18:58:47 +090043import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
44import org.onosproject.kubevirtnetworking.api.KubevirtRouterAdminService;
45import org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent;
46import org.onosproject.kubevirtnetworking.api.KubevirtRouterListener;
Jian Lib5ab63c2021-02-03 17:54:28 +090047import org.onosproject.kubevirtnode.api.KubevirtApiConfigService;
48import org.onosproject.kubevirtnode.api.KubevirtNode;
49import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
50import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
51import org.onosproject.kubevirtnode.api.KubevirtNodeService;
52import org.onosproject.net.Device;
53import org.onosproject.net.DeviceId;
54import org.onosproject.net.PortNumber;
55import org.onosproject.net.behaviour.BridgeConfig;
56import org.onosproject.net.behaviour.BridgeDescription;
57import org.onosproject.net.behaviour.BridgeName;
58import org.onosproject.net.behaviour.ControllerInfo;
59import org.onosproject.net.behaviour.DefaultBridgeDescription;
60import org.onosproject.net.behaviour.DefaultPatchDescription;
61import org.onosproject.net.behaviour.InterfaceConfig;
62import org.onosproject.net.behaviour.PatchDescription;
63import org.onosproject.net.device.DeviceAdminService;
Daniel Park4063f402021-02-25 09:14:22 +090064import org.onosproject.net.driver.DriverService;
Jian Lib5ab63c2021-02-03 17:54:28 +090065import org.onosproject.net.flow.DefaultTrafficSelector;
66import org.onosproject.net.flow.DefaultTrafficTreatment;
67import org.onosproject.net.flow.TrafficSelector;
68import org.onosproject.net.flow.TrafficTreatment;
69import org.osgi.service.component.annotations.Activate;
70import org.osgi.service.component.annotations.Component;
71import org.osgi.service.component.annotations.Deactivate;
72import org.osgi.service.component.annotations.Reference;
73import org.osgi.service.component.annotations.ReferenceCardinality;
74import org.slf4j.Logger;
75
76import java.util.List;
77import java.util.Objects;
Daniel Parkb9a22022021-03-04 18:58:47 +090078import java.util.Set;
Jian Lib5ab63c2021-02-03 17:54:28 +090079import java.util.concurrent.ExecutorService;
80
81import static java.lang.Thread.sleep;
82import static java.util.concurrent.Executors.newSingleThreadExecutor;
Jian Li543fe852021-02-04 17:25:01 +090083import static org.onlab.packet.ICMP.CODE_ECHO_REQEUST;
84import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
85import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Jian Lib5ab63c2021-02-03 17:54:28 +090086import static org.onlab.util.Tools.groupedThreads;
Daniel Parkcc8e7462021-03-09 13:37:42 +090087import static org.onosproject.kubevirtnetworking.api.Constants.FLAT_TABLE;
88import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090089import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Daniel Park4063f402021-02-25 09:14:22 +090090import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090091import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Lib5ab63c2021-02-03 17:54:28 +090092import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_DHCP_RULE;
Jian Li543fe852021-02-04 17:25:01 +090093import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
94import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ICMP_RULE;
Daniel Parkcc8e7462021-03-09 13:37:42 +090095import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +090096import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_TUNNEL_RULE;
Jian Li543fe852021-02-04 17:25:01 +090097import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ARP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090098import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_DHCP_TABLE;
99import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Li543fe852021-02-04 17:25:01 +0900100import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ICMP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +0900101import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_INBOUND_TABLE;
Jian Li543fe852021-02-04 17:25:01 +0900102import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_TO_TUNNEL_PREFIX;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900103import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
Jian Li543fe852021-02-04 17:25:01 +0900104import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Daniel Parkb9a22022021-03-04 18:58:47 +0900105import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
Daniel Parkcc8e7462021-03-09 13:37:42 +0900106import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtNetwork;
107import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtPort;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900108import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
109import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.portNumber;
Jian Lib5ab63c2021-02-03 17:54:28 +0900110import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.segmentIdHex;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900111import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
112import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelToTenantPort;
Jian Li543fe852021-02-04 17:25:01 +0900113import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_NX_IP_TTL;
114import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_OF_ICMP_TYPE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900115import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
Jian Li543fe852021-02-04 17:25:01 +0900116import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildLoadExtension;
117import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
118import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
119import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
120import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveIpSrcToDstExtension;
Jian Lib5ab63c2021-02-03 17:54:28 +0900121import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_BRIDGE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900122import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_TO_INTEGRATION;
Daniel Park4063f402021-02-25 09:14:22 +0900123import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
124import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
Jian Lib5ab63c2021-02-03 17:54:28 +0900125import static org.slf4j.LoggerFactory.getLogger;
126
127/**
128 * Handles kubevirt network events.
129 */
130@Component(immediate = true)
131public class KubevirtNetworkHandler {
132 protected final Logger log = getLogger(getClass());
133 private static final String DEFAULT_OF_PROTO = "tcp";
134 private static final int DEFAULT_OFPORT = 6653;
135 private static final int DPID_BEGIN = 3;
136 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li543fe852021-02-04 17:25:01 +0900137 private static final int DEFAULT_TTL = 0xff;
Jian Lib5ab63c2021-02-03 17:54:28 +0900138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
140 protected CoreService coreService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
143 protected ClusterService clusterService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
146 protected LeadershipService leadershipService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
149 protected DeviceAdminService deviceService;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
152 protected KubevirtApiConfigService apiConfigService;
153
154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
155 protected KubevirtNodeService nodeService;
156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY)
158 protected KubevirtNetworkService networkService;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
161 protected KubevirtFlowRuleService flowService;
162
Daniel Park4063f402021-02-25 09:14:22 +0900163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
164 protected DriverService driverService;
165
Daniel Parkb9a22022021-03-04 18:58:47 +0900166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
167 protected KubevirtRouterAdminService kubevirtRouterService;
168
Daniel Parkcc8e7462021-03-09 13:37:42 +0900169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
170 protected KubevirtPortService kubevirtPortService;
171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY)
173 protected KubevirtNetworkService kubevirtNetworkService;
174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY)
176 protected KubevirtNodeService kubevirtNodeService;
177
Jian Lib5ab63c2021-02-03 17:54:28 +0900178 private final KubevirtNetworkListener networkListener = new InternalNetworkEventListener();
179 private final KubevirtNodeListener nodeListener = new InternalNodeEventListener();
Daniel Parkcc8e7462021-03-09 13:37:42 +0900180 private final KubevirtPortListener portListener = new InternalKubevirtPortListener();
Jian Lib5ab63c2021-02-03 17:54:28 +0900181
Daniel Parkb9a22022021-03-04 18:58:47 +0900182 private final InternalRouterEventListener kubevirtRouterlistener =
183 new InternalRouterEventListener();
184
Jian Lib5ab63c2021-02-03 17:54:28 +0900185 private final ExecutorService eventExecutor = newSingleThreadExecutor(
186 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
187
188 private ApplicationId appId;
189 private NodeId localNodeId;
190
191 @Activate
192 protected void activate() {
193 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
194 localNodeId = clusterService.getLocalNode().id();
Jian Lib5ab63c2021-02-03 17:54:28 +0900195 leadershipService.runForLeadership(appId.name());
196
Daniel Parkcc8e7462021-03-09 13:37:42 +0900197 networkService.addListener(networkListener);
198 nodeService.addListener(nodeListener);
199 kubevirtPortService.addListener(portListener);
Daniel Parkb9a22022021-03-04 18:58:47 +0900200 kubevirtRouterService.addListener(kubevirtRouterlistener);
201
Jian Lib5ab63c2021-02-03 17:54:28 +0900202 log.info("Started");
203 }
204
205 @Deactivate
206 protected void deactivate() {
207 networkService.removeListener(networkListener);
208 nodeService.removeListener(nodeListener);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900209 kubevirtPortService.removeListener(portListener);
Daniel Parkb9a22022021-03-04 18:58:47 +0900210 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900211 leadershipService.withdraw(appId.name());
Jian Lib5ab63c2021-02-03 17:54:28 +0900212 eventExecutor.shutdown();
213
214 log.info("Stopped");
215 }
216
217 private void createBridge(KubevirtNode node, KubevirtNetwork network) {
218
219 Device tunBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
220 if (tunBridge != null) {
221 log.warn("The tunnel bridge {} already exists at node {}",
222 network.tenantBridgeName(), node.hostname());
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900223 setDefaultRulesForTenantNetwork(node, network);
Jian Lib5ab63c2021-02-03 17:54:28 +0900224 return;
225 }
226
227 Device device = deviceService.getDevice(node.ovsdb());
228
229 IpAddress serverIp = apiConfigService.apiConfig().ipAddress();
230 ControllerInfo controlInfo =
231 new ControllerInfo(serverIp, DEFAULT_OFPORT, DEFAULT_OF_PROTO);
232 List<ControllerInfo> controllers = Lists.newArrayList(controlInfo);
233
234 String dpid = network.tenantDeviceId(
235 node.hostname()).toString().substring(DPID_BEGIN);
236
237 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
238 .name(network.tenantBridgeName())
239 .failMode(BridgeDescription.FailMode.SECURE)
240 .datapathId(dpid)
241 .disableInBand()
242 .controllers(controllers);
243
244 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
245 bridgeConfig.addBridge(builder.build());
246 }
247
248 private void removeBridge(KubevirtNode node, KubevirtNetwork network) {
249 Device device = deviceService.getDevice(node.ovsdb());
250
251 BridgeName bridgeName = BridgeName.bridgeName(network.tenantBridgeName());
252
253 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
254 bridgeConfig.deleteBridge(bridgeName);
255 deviceService.removeDevice(network.tenantDeviceId(node.hostname()));
256 }
257
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900258 private void createPatchTenantInterface(KubevirtNode node, KubevirtNetwork network) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900259 Device device = deviceService.getDevice(node.ovsdb());
260
261 if (device == null || !device.is(InterfaceConfig.class)) {
262 log.error("Failed to create patch interface on {}", node.ovsdb());
263 return;
264 }
265
266 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
267
Jian Li543fe852021-02-04 17:25:01 +0900268 String tenantToTunIntf =
269 TENANT_TO_TUNNEL_PREFIX + segmentIdHex(network.segmentId());
270 String tunToTenantIntf =
271 TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900272
Jian Li543fe852021-02-04 17:25:01 +0900273 // tenant bridge -> tunnel bridge
274 PatchDescription brTenantTunPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900275 DefaultPatchDescription.builder()
276 .deviceId(network.tenantBridgeName())
Jian Li543fe852021-02-04 17:25:01 +0900277 .ifaceName(tenantToTunIntf)
278 .peer(tunToTenantIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900279 .build();
280
Jian Li543fe852021-02-04 17:25:01 +0900281 ifaceConfig.addPatchMode(tenantToTunIntf, brTenantTunPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900282
Jian Li543fe852021-02-04 17:25:01 +0900283 // tunnel bridge -> tenant bridge
284 PatchDescription brTunTenantPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900285 DefaultPatchDescription.builder()
286 .deviceId(TUNNEL_BRIDGE)
Jian Li543fe852021-02-04 17:25:01 +0900287 .ifaceName(tunToTenantIntf)
288 .peer(tenantToTunIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900289 .build();
Jian Li543fe852021-02-04 17:25:01 +0900290 ifaceConfig.addPatchMode(tunToTenantIntf, brTunTenantPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900291 }
292
293 private void removePatchInterface(KubevirtNode node, KubevirtNetwork network) {
294 Device device = deviceService.getDevice(node.ovsdb());
295
296 if (device == null || !device.is(InterfaceConfig.class)) {
297 log.error("Failed to create patch interface on {}", node.ovsdb());
298 return;
299 }
300
301 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
302
Jian Li543fe852021-02-04 17:25:01 +0900303 String tunToIntIntf = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900304
305 ifaceConfig.removePatchMode(tunToIntIntf);
306 }
307
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900308 private void setArpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900309
310 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
311 if (router == null) {
312 return;
313 }
314
315 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
316 if (electedGw == null) {
317 return;
318 }
319
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900320 setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE, electedGw.intgBridge(),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900321 network.tenantDeviceId(node.hostname()), true);
322 }
323
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900324 private void setIcmpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900325 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
326 if (router == null) {
327 return;
328 }
329
330 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
331 if (electedGw == null) {
332 return;
333 }
334
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900335 setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE, electedGw.intgBridge(),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900336 network.tenantDeviceId(node.hostname()), true);
337 }
338
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900339 private void setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(KubevirtNode node, KubevirtNetwork network) {
340 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
341 if (router == null) {
342 return;
343 }
Daniel Parkcc8e7462021-03-09 13:37:42 +0900344
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900345 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
346 if (electedGw == null) {
347 return;
348 }
349
350 setDefaulGatewayRuleToWorkerNodeTunBridge(router, network, electedGw.intgBridge(), node, true);
351 }
352
353 private void setDefaultRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900354 DeviceId deviceId = network.tenantDeviceId(node.hostname());
355
356 while (!deviceService.isAvailable(deviceId)) {
357 log.warn("Device {} is not ready for installing rules", deviceId);
358
359 try {
360 sleep(SLEEP_MS);
361 } catch (InterruptedException e) {
362 log.error("Failed to check device availability", e);
363 }
364 }
365
366 flowService.connectTables(deviceId, TENANT_INBOUND_TABLE, TENANT_DHCP_TABLE);
Jian Li543fe852021-02-04 17:25:01 +0900367 flowService.connectTables(deviceId, TENANT_DHCP_TABLE, TENANT_ARP_TABLE);
368 flowService.connectTables(deviceId, TENANT_ARP_TABLE, TENANT_ICMP_TABLE);
369 flowService.connectTables(deviceId, TENANT_ICMP_TABLE, TENANT_FORWARDING_TABLE);
Jian Lib5ab63c2021-02-03 17:54:28 +0900370
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900371 setDhcpRuleForTenantNetwork(deviceId, true);
Jian Lib5ab63c2021-02-03 17:54:28 +0900372 setForwardingRule(deviceId, true);
373
374 log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
375 }
376
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900377 private void setDhcpRuleForTenantNetwork(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900378 TrafficSelector selector = DefaultTrafficSelector.builder()
379 .matchEthType(Ethernet.TYPE_IPV4)
380 .matchIPProtocol(IPv4.PROTOCOL_UDP)
381 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
382 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
383 .build();
384
385 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
386 .punt()
387 .build();
388
389 flowService.setRule(
390 appId,
391 deviceId,
392 selector,
393 treatment,
394 PRIORITY_DHCP_RULE,
395 TENANT_DHCP_TABLE,
396 install);
397 }
398
Jian Li543fe852021-02-04 17:25:01 +0900399 private void setForwardingRule(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900400 TrafficSelector selector = DefaultTrafficSelector.builder().build();
401 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
402 .setOutput(PortNumber.NORMAL)
403 .build();
404
405 flowService.setRule(
406 appId,
407 deviceId,
408 selector,
409 treatment,
Jian Li543fe852021-02-04 17:25:01 +0900410 PRIORITY_FORWARDING_RULE,
Jian Lib5ab63c2021-02-03 17:54:28 +0900411 TENANT_FORWARDING_TABLE,
412 install);
413 }
414
Daniel Parkb9a22022021-03-04 18:58:47 +0900415 private void initGatewayNodeForInternalNetwork(KubevirtNetwork network,
416 KubevirtRouter router,
417 KubevirtNode electedGateway,
418 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900419 switch (network.type()) {
420 case VXLAN:
421 case GRE:
422 case GENEVE:
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900423 setDefaultEgressRuleToGatewayNode(router, network, electedGateway.intgBridge(), install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900424 kubevirtNodeService.completeNodes(WORKER).forEach(node -> {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900425 setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900426 electedGateway.intgBridge(),
427 network.tenantDeviceId(node.hostname()), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900428 setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900429 electedGateway.intgBridge(),
430 network.tenantDeviceId(node.hostname()), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900431 setDefaulGatewayRuleToWorkerNodeTunBridge(router, network,
432 electedGateway.intgBridge(), node, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900433 });
434 break;
435 case FLAT:
436 case VLAN:
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900437 setGatewayArpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900438 electedGateway.intgBridge(), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900439 setGatewayIcmpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900440 electedGateway.intgBridge(), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900441 setGatewayProviderInterNetworkRoutingWithinSameRouter(network, router, electedGateway, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900442 break;
443 default:
444 // do nothing
445 break;
446 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900447 }
448
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900449 private void setDefaulGatewayRuleToWorkerNodeTunBridge(KubevirtRouter router,
450 KubevirtNetwork network,
451 DeviceId gwDeviceId,
452 KubevirtNode workerNode,
453 boolean install) {
454 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900455
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900456 if (routerMacAddress == null) {
457 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
458 "there's no br-int port for device {}", gwDeviceId);
459 return;
460 }
461
462 KubevirtNode gwNode = kubevirtNodeService.node(gwDeviceId);
463
464 if (gwNode == null) {
465 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
466 "there's no gateway node for device {}", gwDeviceId);
467 return;
468 }
469
470
471 PortNumber patchPortNumber = tunnelToTenantPort(workerNode, network);
472 if (patchPortNumber == null) {
473 return;
474 }
475
476 PortNumber tunnelPortNumber = tunnelPort(workerNode, network);
477 if (tunnelPortNumber == null) {
478 return;
479 }
480
481 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
482 .matchInPort(patchPortNumber)
483 .matchEthType(Ethernet.TYPE_IPV4)
484 .matchEthDst((routerMacAddress));
485
486 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
487 .setTunnelId(Long.parseLong(network.segmentId()))
488 .extension(buildExtension(
489 deviceService,
490 workerNode.tunBridge(),
491 gwNode.dataIp().getIp4Address()),
492 workerNode.tunBridge())
493 .setOutput(tunnelPortNumber);
494
495 flowService.setRule(
496 appId,
497 workerNode.tunBridge(),
498 sBuilder.build(),
499 tBuilder.build(),
500 PRIORITY_FORWARDING_RULE,
501 TUNNEL_DEFAULT_TABLE,
502 install);
503 }
504
505 private void setDefaultEgressRuleToGatewayNode(KubevirtRouter router,
506 KubevirtNetwork network,
507 DeviceId gwDeviceId,
508 boolean install) {
509 MacAddress routerMacAddress = getRouterMacAddress(router);
510
511 if (routerMacAddress == null) {
512 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
513 "there's no br-int port for device {}", gwDeviceId);
514 return;
515 }
516
517 KubevirtNode gwNode = kubevirtNodeService.node(gwDeviceId);
518
519 if (gwNode == null) {
520 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
521 "there's no gateway node for device {}", gwDeviceId);
522 return;
523 }
524
525 PortNumber tunToIntPortNum = portNumber(gwNode.tunBridge(), TUNNEL_TO_INTEGRATION);
526
527 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
528 .matchTunnelId(Long.parseLong(network.segmentId()));
529
530 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
531 .setOutput(tunToIntPortNum);
532
533 flowService.setRule(
534 appId,
535 gwNode.tunBridge(),
536 sBuilder.build(),
537 tBuilder.build(),
538 PRIORITY_TUNNEL_RULE,
539 TUNNEL_DEFAULT_TABLE,
540 install);
541 }
542
543
544 private void setGatewayIcmpRuleForTenantInternalNetwork(KubevirtRouter router,
545 KubevirtNetwork network,
546 int tableNum,
547 DeviceId gwDeviceId,
548 DeviceId tenantDeviceId,
549 boolean install) {
550 MacAddress routerMacAddress = getRouterMacAddress(router);
551
552 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900553 log.warn("Setting gateway ICMP rule for internal network because " +
554 "there's no br-int port for device {}", gwDeviceId);
555 return;
556 }
557
558 Device device = deviceService.getDevice(tenantDeviceId);
559
560 if (device == null) {
561 log.warn("Setting gateway icmp rule for internal network because " +
562 "there's no tenant device for {} to install gateway arp rule",
563 tenantDeviceId);
564 return;
565 }
566
567
568 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
569 .matchEthType(Ethernet.TYPE_IPV4)
570 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
571 .matchIcmpType(TYPE_ECHO_REQUEST)
572 .matchIcmpCode(CODE_ECHO_REQEUST)
573 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
574
575 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
576 .extension(buildMoveEthSrcToDstExtension(device), device.id())
577 .extension(buildMoveIpSrcToDstExtension(device), device.id())
578 .extension(buildLoadExtension(device,
579 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
580 .extension(buildLoadExtension(device,
581 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
582 .setIpSrc(network.gatewayIp())
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900583 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900584 .setOutput(PortNumber.IN_PORT);
585
586 flowService.setRule(
587 appId,
588 tenantDeviceId,
589 sBuilder.build(),
590 tBuilder.build(),
591 PRIORITY_ICMP_RULE,
592 tableNum,
593 install);
594 }
595
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900596 private void setGatewayArpRuleForTenantInternalNetwork(KubevirtRouter router,
597 KubevirtNetwork network,
598 int tableNum,
599 DeviceId gwDeviceId,
600 DeviceId tenantDeviceId,
601 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900602
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900603 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900604
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900605 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900606 log.warn("Setting gateway arp rule for internal network because " +
607 "there's no br-int port for device {}", gwDeviceId);
608 return;
609 }
610
611 Device device = deviceService.getDevice(tenantDeviceId);
612
613 if (device == null) {
614 log.warn("Setting gateway arp rule for internal network because " +
615 "there's no tenant device for {} to install gateway arp rule",
616 tenantDeviceId);
617 return;
618 }
619
620
621 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
622 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
623 .matchArpOp(ARP.OP_REQUEST)
624 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
625
626 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
627 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
628 .extension(buildMoveArpShaToThaExtension(device), device.id())
629 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
630 .setArpOp(ARP.OP_REPLY)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900631 .setArpSha(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900632 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900633 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900634 .setOutput(PortNumber.IN_PORT);
635
636 flowService.setRule(
637 appId,
638 device.id(),
639 sBuilder.build(),
640 tBuilder.build(),
641 PRIORITY_ARP_GATEWAY_RULE,
642 tableNum,
643 install
644 );
645 }
646
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900647 private void setGatewayProviderInterNetworkRoutingWithinSameRouter(
Daniel Parkcc8e7462021-03-09 13:37:42 +0900648 KubevirtNetwork network, KubevirtRouter router, KubevirtNode gatewayNode, boolean install) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900649 router.internal().forEach(srcNetwork -> {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900650 if (srcNetwork.equals(network.networkId())
651 || kubevirtNetworkService.network(srcNetwork) == null) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900652 return;
653 }
654
Daniel Parkcc8e7462021-03-09 13:37:42 +0900655 kubevirtPortService.ports(network.networkId()).forEach(port -> {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900656 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900657 port, gatewayNode, install);
658 });
Daniel Parkb9a22022021-03-04 18:58:47 +0900659 });
660 }
661
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900662 private void setGatewayInterNetworkRoutingFromNetworkToPort(KubevirtRouter router,
663 KubevirtNetwork srcNetwork,
664 KubevirtPort dstPort,
665 KubevirtNode gatewayNode,
666 boolean install) {
Jian Li543fe852021-02-04 17:25:01 +0900667
Daniel Parkcc8e7462021-03-09 13:37:42 +0900668 Device gwDevice = deviceService.getDevice(gatewayNode.intgBridge());
669
670 if (gwDevice == null) {
671 log.warn("Failed to set internal network routing rule because " +
672 "there's no device Id for device {}", gatewayNode.intgBridge());
673 return;
674 }
675
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900676 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900677
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900678 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900679 log.warn("Failed to set internal network routing rule because " +
680 "there's no br-int port for device {}", gatewayNode.intgBridge());
681 return;
682 }
683
684 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
685 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900686 .matchEthDst(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900687 .matchIPSrc(IpPrefix.valueOf(srcNetwork.cidr()))
688 .matchIPDst(IpPrefix.valueOf(dstPort.ipAddress(), 32));
689
690 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900691 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900692 .setEthDst(dstPort.macAddress())
693 .transition(FORWARDING_TABLE)
694 .build();
695
696 flowService.setRule(
697 appId,
698 gwDevice.id(),
699 sBuilder.build(),
700 treatment,
701 PRIORITY_INTERNAL_ROUTING_RULE,
702 FLAT_TABLE,
703 install
704 );
705 }
706
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900707 private void setGatewayArpRuleForProviderInternalNetwork(KubevirtRouter router, KubevirtNetwork network,
708 int tableNum, DeviceId gwDeviceId, boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900709
710
711 Device device = deviceService.getDevice(gwDeviceId);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900712 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900713
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900714 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900715 log.warn("Setting gateway arp rule for internal network because " +
716 "there's no br-int port for device {}", gwDeviceId);
Daniel Parkb9a22022021-03-04 18:58:47 +0900717 return;
718 }
719
Jian Li543fe852021-02-04 17:25:01 +0900720 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
721 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
722 .matchArpOp(ARP.OP_REQUEST)
723 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
724
725 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
726 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
727 .extension(buildMoveArpShaToThaExtension(device), device.id())
728 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
729 .setArpOp(ARP.OP_REPLY)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900730 .setArpSha(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900731 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900732 .setEthSrc(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900733 .setOutput(PortNumber.IN_PORT);
734
735 flowService.setRule(
736 appId,
737 device.id(),
738 sBuilder.build(),
739 tBuilder.build(),
740 PRIORITY_ARP_GATEWAY_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900741 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900742 install
743 );
744 }
745
Daniel Parkb9a22022021-03-04 18:58:47 +0900746 /**
747 * Sends ICMP echo reply for the ICMP echo request from the kubevirt VM.
748 *
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900749 * @param router kubevirt router
Daniel Parkb9a22022021-03-04 18:58:47 +0900750 * @param network kubevirt network
751 * @param tableNum flow table number
752 * @param deviceId device id of the selected gateway for the network
753 * @param install install if true, remove otherwise
754 */
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900755 private void setGatewayIcmpRuleForProviderInternalNetwork(KubevirtRouter router, KubevirtNetwork network,
756 int tableNum, DeviceId deviceId, boolean install) {
757 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900758
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900759 if (routerMacAddress == null) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900760 log.error("Setting gateway ICMP rule for internal network because " +
761 "there's no br-int port for device {}", deviceId);
762 return;
763 }
764
Jian Li543fe852021-02-04 17:25:01 +0900765 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
766 .matchEthType(Ethernet.TYPE_IPV4)
767 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
768 .matchIcmpType(TYPE_ECHO_REQUEST)
769 .matchIcmpCode(CODE_ECHO_REQEUST)
770 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
771
772 Device device = deviceService.getDevice(deviceId);
773 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
774 .extension(buildMoveEthSrcToDstExtension(device), device.id())
775 .extension(buildMoveIpSrcToDstExtension(device), device.id())
776 .extension(buildLoadExtension(device,
777 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
778 .extension(buildLoadExtension(device,
779 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
780 .setIpSrc(network.gatewayIp())
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900781 .setEthSrc(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900782 .setOutput(PortNumber.IN_PORT);
783
784 flowService.setRule(
785 appId,
786 deviceId,
787 sBuilder.build(),
788 tBuilder.build(),
789 PRIORITY_ICMP_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900790 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900791 install);
792 }
793
Daniel Parkb9a22022021-03-04 18:58:47 +0900794 private class InternalRouterEventListener implements KubevirtRouterListener {
795 private boolean isRelevantHelper() {
796 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park4063f402021-02-25 09:14:22 +0900797 }
798
Daniel Parkb9a22022021-03-04 18:58:47 +0900799 @Override
800 public void event(KubevirtRouterEvent event) {
801 switch (event.type()) {
802 case KUBEVIRT_ROUTER_CREATED:
803 eventExecutor.execute(() -> processRouterCreation(event.subject()));
804 break;
805 case KUBEVIRT_ROUTER_REMOVED:
806 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
807 break;
808 case KUBEVIRT_ROUTER_UPDATED:
809 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
810 break;
811 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
812 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
813 event.internal()));
814 break;
815 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
816 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
817 event.internal()));
818 break;
819 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
820 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
821 event.gateway()));
822 break;
823 case KUBEVIRT_GATEWAY_NODE_DETACHED:
824 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
825 event.gateway()));
826 break;
827 case KUBEVIRT_GATEWAY_NODE_CHANGED:
828 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
829 event.gateway()));
830 break;
Daniel Park4063f402021-02-25 09:14:22 +0900831
Daniel Parkb9a22022021-03-04 18:58:47 +0900832 default:
833 //do nothing
834 break;
835 }
836 }
837
838 private void processRouterCreation(KubevirtRouter router) {
839 // When a router is created, we performs the election process to associate the router
840 // to the specific gateway. After the election, KubevirtNetwork handler installs bunch of rules
841 // to elected gateway node so that VMs associated to the router can ping to their gateway IP.
842 // SNAT and floating ip rule setup is out of this handler's scope and would be done with the other handlers
843 if (!isRelevantHelper()) {
844 return;
845 }
846 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
847 if (electedGw == null) {
848 return;
849 }
850
851 router.internal().forEach(networkName -> {
852 KubevirtNetwork network = networkService.network(networkName);
853
854 if (network != null) {
855 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
856 }
857 });
858 kubevirtRouterService.updateRouter(router.updatedElectedGateway(electedGw.hostname()));
859 }
860
861 private void processRouterDeletion(KubevirtRouter router) {
862 if (!isRelevantHelper()) {
863 return;
864 }
865 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
866 if (electedGw == null) {
867 return;
868 }
869
870 router.internal().forEach(networkName -> {
871 KubevirtNetwork network = networkService.network(networkName);
872
873 if (network != null) {
874 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
875 }
876 });
877 }
878
879 private void processRouterUpdate(KubevirtRouter router) {
880 if (!isRelevantHelper()) {
881 return;
882 }
883 if (router.electedGateway() == null) {
884 return;
885 }
886
887 KubevirtNode electedGw = nodeService.node(router.electedGateway());
888
889 router.internal().forEach(networkName -> {
890 KubevirtNetwork network = networkService.network(networkName);
891
892 if (network != null) {
893 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
894 }
895 });
896 }
897
898 private void processRouterInternalNetworksAttached(KubevirtRouter router,
899 Set<String> attachedInternalNetworks) {
900 if (!isRelevantHelper()) {
901 return;
902 }
903 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
904 if (electedGw == null) {
905 return;
906 }
907
908 attachedInternalNetworks.forEach(networkName -> {
909 KubevirtNetwork network = networkService.network(networkName);
910
911 if (network != null) {
912 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
913 }
914 });
915 }
916
917 private void processRouterInternalNetworksDetached(KubevirtRouter router,
918 Set<String> detachedInternalNetworks) {
919 if (!isRelevantHelper()) {
920 return;
921 }
922 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
923 if (electedGw == null) {
924 return;
925 }
926
927 detachedInternalNetworks.forEach(networkName -> {
928 KubevirtNetwork network = networkService.network(networkName);
929
930 if (network != null) {
931 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
932 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900933
Daniel Parkcc8e7462021-03-09 13:37:42 +0900934 removeDetachedInternalNetworkRules(network, router, electedGw);
935 });
936 }
937
938 private void removeDetachedInternalNetworkRules(KubevirtNetwork removedNetwork, KubevirtRouter router,
939 KubevirtNode electedGw) {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900940 router.internal().stream().filter(networkId -> kubevirtNetworkService.network(networkId) != null)
941 .forEach(networkId -> {
942 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
943 setGatewayInterNetworkRoutingFromNetworkToPort(
944 router, removedNetwork, kubevirtPort, electedGw, false);
945 });
Daniel Parkcc8e7462021-03-09 13:37:42 +0900946 });
Daniel Parkb9a22022021-03-04 18:58:47 +0900947 }
948
949 private void processRouterGatewayNodeAttached(KubevirtRouter router,
950 String associatedGateway) {
951 if (!isRelevantHelper()) {
952 return;
953 }
954
955 KubevirtNode gatewayNode = nodeService.node(associatedGateway);
956 if (gatewayNode == null) {
957 return;
958 }
959
960 router.internal().forEach(networkName -> {
961 KubevirtNetwork network = networkService.network(networkName);
962
963 if (network != null) {
964 initGatewayNodeForInternalNetwork(network, router, gatewayNode, true);
965 }
966 });
967 }
968
969 private void processRouterGatewayNodeDetached(KubevirtRouter router,
970 String disAssociatedGateway) {
971 if (!isRelevantHelper()) {
972 return;
973 }
974
975 KubevirtNode gatewayNode = nodeService.node(disAssociatedGateway);
976 if (gatewayNode == null) {
977 return;
978 }
979
980 router.internal().forEach(networkName -> {
981 KubevirtNetwork network = networkService.network(networkName);
982
983 if (network != null) {
984 initGatewayNodeForInternalNetwork(network, router, gatewayNode, false);
985 }
986 });
987 }
988
989 private void processRouterGatewayNodeChanged(KubevirtRouter router,
990 String disAssociatedGateway) {
991 if (!isRelevantHelper()) {
992 return;
993 }
994
995 KubevirtNode oldGatewayNode = nodeService.node(disAssociatedGateway);
996 if (oldGatewayNode == null) {
997 return;
998 }
999
1000 router.internal().forEach(networkName -> {
1001 KubevirtNetwork network = networkService.network(networkName);
1002
1003 if (network != null) {
1004 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, false);
1005 }
1006 });
1007
1008 KubevirtNode newGatewayNode = nodeService.node(router.electedGateway());
1009 if (newGatewayNode == null) {
1010 return;
1011 }
1012
1013 router.internal().forEach(networkName -> {
1014 KubevirtNetwork network = networkService.network(networkName);
1015
1016 if (network != null) {
1017 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, true);
1018 }
1019 });
1020 }
Daniel Park4063f402021-02-25 09:14:22 +09001021 }
1022
Jian Lib5ab63c2021-02-03 17:54:28 +09001023 private class InternalNetworkEventListener implements KubevirtNetworkListener {
1024
1025 private boolean isRelevantHelper() {
1026 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1027 }
1028
1029 @Override
1030 public void event(KubevirtNetworkEvent event) {
1031 switch (event.type()) {
1032 case KUBEVIRT_NETWORK_CREATED:
1033 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
1034 break;
1035 case KUBEVIRT_NETWORK_REMOVED:
1036 eventExecutor.execute(() -> processNetworkRemoval(event.subject()));
1037 break;
1038 case KUBEVIRT_NETWORK_UPDATED:
1039 default:
1040 // do nothing
1041 break;
1042 }
1043 }
1044
1045 private void processNetworkCreation(KubevirtNetwork network) {
1046 if (!isRelevantHelper()) {
1047 return;
1048 }
1049
1050 switch (network.type()) {
1051 case VXLAN:
1052 case GRE:
1053 case GENEVE:
1054 initIntegrationTunnelBridge(network);
1055 break;
1056 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +09001057 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001058 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001059 default:
1060 // do nothing
1061 break;
1062 }
1063 }
1064
1065 private void processNetworkRemoval(KubevirtNetwork network) {
1066 if (!isRelevantHelper()) {
1067 return;
1068 }
1069
1070 switch (network.type()) {
1071 case VXLAN:
1072 case GRE:
1073 case GENEVE:
1074 purgeIntegrationTunnelBridge(network);
1075 break;
1076 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +09001077 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001078 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001079 default:
1080 // do nothing
1081 break;
1082 }
1083 }
1084
1085 private void initIntegrationTunnelBridge(KubevirtNetwork network) {
1086 if (network.segmentId() == null) {
1087 return;
1088 }
1089
1090 nodeService.completeNodes().forEach(n -> {
1091 createBridge(n, network);
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001092 createPatchTenantInterface(n, network);
1093 setDefaultRulesForTenantNetwork(n, network);
Jian Lib5ab63c2021-02-03 17:54:28 +09001094 });
1095 }
1096
1097 private void purgeIntegrationTunnelBridge(KubevirtNetwork network) {
1098 if (network.segmentId() == null) {
1099 return;
1100 }
1101
1102 nodeService.completeNodes().forEach(n -> {
1103 removePatchInterface(n, network);
1104 removeBridge(n, network);
1105 });
1106 }
1107 }
1108
1109 private class InternalNodeEventListener implements KubevirtNodeListener {
1110
1111 private boolean isRelevantHelper() {
1112 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1113 }
1114
1115 @Override
1116 public void event(KubevirtNodeEvent event) {
1117 switch (event.type()) {
1118 case KUBEVIRT_NODE_COMPLETE:
1119 eventExecutor.execute(() -> processNodeCompletion(event.subject()));
1120 break;
Daniel Parkb9a22022021-03-04 18:58:47 +09001121 case KUBEVIRT_NODE_REMOVED:
1122 eventExecutor.execute(() -> processNodeDeletion(event.subject()));
1123 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001124 case KUBEVIRT_NODE_INCOMPLETE:
1125 case KUBEVIRT_NODE_UPDATED:
1126 default:
1127 // do nothing
1128 break;
1129 }
1130 }
1131
1132 private void processNodeCompletion(KubevirtNode node) {
1133 if (!isRelevantHelper()) {
1134 return;
1135 }
1136
Daniel Park4063f402021-02-25 09:14:22 +09001137 if (node.type().equals(WORKER)) {
1138 for (KubevirtNetwork network : networkService.networks()) {
1139 switch (network.type()) {
1140 case VXLAN:
1141 case GRE:
1142 case GENEVE:
1143 if (network.segmentId() == null) {
1144 continue;
1145 }
1146 createBridge(node, network);
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001147 createPatchTenantInterface(node, network);
1148 setDefaultRulesForTenantNetwork(node, network);
1149 setArpRulesForTenantNetwork(node, network);
1150 setIcmpRulesForTenantNetwork(node, network);
1151 setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(node, network);
Daniel Park4063f402021-02-25 09:14:22 +09001152 break;
1153 case FLAT:
1154 case VLAN:
1155 default:
1156 // do nothing
1157 break;
1158 }
1159 }
1160 } else if (node.type().equals(GATEWAY)) {
Daniel Parkb9a22022021-03-04 18:58:47 +09001161 updateGatewayNodeForRouter();
Daniel Park4063f402021-02-25 09:14:22 +09001162 for (KubevirtNetwork network : networkService.networks()) {
1163 switch (network.type()) {
1164 case FLAT:
1165 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001166 break;
1167 case VXLAN:
1168 case GRE:
1169 case GENEVE:
1170 default:
1171 // do nothing
1172 break;
1173 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001174 }
1175 }
1176 }
Daniel Parkb9a22022021-03-04 18:58:47 +09001177
1178 private void processNodeDeletion(KubevirtNode node) {
1179 if (!isRelevantHelper()) {
1180 return;
1181 }
1182
1183 if (node.type().equals(GATEWAY)) {
1184 updateGatewayNodeForRouter();
1185 for (KubevirtNetwork network : networkService.networks()) {
1186 switch (network.type()) {
1187 case FLAT:
1188 case VLAN:
1189 break;
1190 case VXLAN:
1191 case GRE:
1192 case GENEVE:
1193 default:
1194 // do nothing
1195 break;
1196 }
1197 }
1198 }
1199 }
1200
1201 private void updateGatewayNodeForRouter() {
1202 kubevirtRouterService.routers().forEach(router -> {
1203 KubevirtNode newGwNode = gatewayNodeForSpecifiedRouter(nodeService, router);
1204
1205 if (newGwNode == null) {
1206 return;
1207 }
1208 kubevirtRouterService.updateRouter(router.updatedElectedGateway(newGwNode.hostname()));
1209 });
1210 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001211 }
Daniel Parkcc8e7462021-03-09 13:37:42 +09001212
1213 private class InternalKubevirtPortListener implements KubevirtPortListener {
1214
1215 private boolean isRelevantHelper() {
1216 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1217 }
1218
1219 @Override
1220 public void event(KubevirtPortEvent event) {
1221 switch (event.type()) {
1222 case KUBEVIRT_PORT_CREATED:
1223 eventExecutor.execute(() -> processPortCreation(event.subject()));
1224 break;
1225 case KUBEVIRT_PORT_UPDATED:
1226 eventExecutor.execute(() -> processPortUpdate(event.subject()));
1227 break;
1228 case KUBEVIRT_PORT_REMOVED:
1229 eventExecutor.execute(() -> processPortDeletion(event.subject()));
1230 break;
1231 default:
1232 //do nothing
1233 break;
1234 }
1235 }
1236
1237 private void processPortCreation(KubevirtPort kubevirtPort) {
1238 if (!isRelevantHelper()) {
1239 return;
1240 }
1241
1242 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1243 if (router == null) {
1244 return;
1245 }
1246
1247 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1248
1249 if (gwNode != null) {
1250
1251 router.internal().forEach(srcNetwork -> {
1252 if (srcNetwork.equals(kubevirtPort.networkId())
1253 || kubevirtNetworkService.network(srcNetwork) == null) {
1254 return;
1255 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001256 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001257 kubevirtPort, gwNode, true);
1258 });
1259 }
1260 }
1261
1262 private void processPortUpdate(KubevirtPort kubevirtPort) {
1263 if (!isRelevantHelper()) {
1264 return;
1265 }
1266
1267 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1268 if (router == null) {
1269 return;
1270 }
1271
1272 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1273
1274 if (gwNode != null) {
1275
1276 router.internal().forEach(srcNetwork -> {
1277 if (srcNetwork.equals(kubevirtPort.networkId())
1278 || kubevirtNetworkService.network(srcNetwork) == null) {
1279 return;
1280 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001281 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001282 kubevirtPort, gwNode, true);
1283 });
1284 }
1285 }
1286
1287 private void processPortDeletion(KubevirtPort kubevirtPort) {
1288 if (!isRelevantHelper()) {
1289 return;
1290 }
1291
1292 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1293 if (router == null) {
1294 return;
1295 }
1296
1297 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1298
1299 if (gwNode != null) {
1300
1301 router.internal().forEach(srcNetwork -> {
1302 if (srcNetwork.equals(kubevirtPort.networkId())
1303 || kubevirtNetworkService.network(srcNetwork) == null) {
1304 return;
1305 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001306 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001307 kubevirtPort, gwNode, false);
1308 });
1309 }
1310
1311 }
1312 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001313}