blob: 47bf5ccc55bf0decc01ea77f3ecf898747972985 [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.FORWARDING_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090088import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Daniel Park4063f402021-02-25 09:14:22 +090089import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090090import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Lib5ab63c2021-02-03 17:54:28 +090091import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_DHCP_RULE;
Jian Li543fe852021-02-04 17:25:01 +090092import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
93import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ICMP_RULE;
Daniel Parkcc8e7462021-03-09 13:37:42 +090094import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +090095import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_TUNNEL_RULE;
Jian Li543fe852021-02-04 17:25:01 +090096import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ARP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090097import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_DHCP_TABLE;
98import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090099import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ICMP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +0900100import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_INBOUND_TABLE;
Jian Li543fe852021-02-04 17:25:01 +0900101import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_TO_TUNNEL_PREFIX;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900102import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
Jian Li543fe852021-02-04 17:25:01 +0900103import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Daniel Parkb9a22022021-03-04 18:58:47 +0900104import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
Daniel Parkcc8e7462021-03-09 13:37:42 +0900105import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtNetwork;
106import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtPort;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900107import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
108import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.portNumber;
Jian Lib5ab63c2021-02-03 17:54:28 +0900109import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.segmentIdHex;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900110import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
111import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelToTenantPort;
Jian Li543fe852021-02-04 17:25:01 +0900112import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_NX_IP_TTL;
113import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_OF_ICMP_TYPE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900114import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
Jian Li543fe852021-02-04 17:25:01 +0900115import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildLoadExtension;
116import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
117import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
118import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
119import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveIpSrcToDstExtension;
Jian Lib5ab63c2021-02-03 17:54:28 +0900120import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_BRIDGE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900121import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_TO_INTEGRATION;
Daniel Park4063f402021-02-25 09:14:22 +0900122import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
123import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
Jian Lib5ab63c2021-02-03 17:54:28 +0900124import static org.slf4j.LoggerFactory.getLogger;
125
126/**
127 * Handles kubevirt network events.
128 */
129@Component(immediate = true)
130public class KubevirtNetworkHandler {
131 protected final Logger log = getLogger(getClass());
132 private static final String DEFAULT_OF_PROTO = "tcp";
133 private static final int DEFAULT_OFPORT = 6653;
134 private static final int DPID_BEGIN = 3;
135 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li543fe852021-02-04 17:25:01 +0900136 private static final int DEFAULT_TTL = 0xff;
Jian Lib5ab63c2021-02-03 17:54:28 +0900137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
139 protected CoreService coreService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
142 protected ClusterService clusterService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
145 protected LeadershipService leadershipService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
148 protected DeviceAdminService deviceService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
151 protected KubevirtApiConfigService apiConfigService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
154 protected KubevirtNodeService nodeService;
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
157 protected KubevirtNetworkService networkService;
158
159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
160 protected KubevirtFlowRuleService flowService;
161
Daniel Park4063f402021-02-25 09:14:22 +0900162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
163 protected DriverService driverService;
164
Daniel Parkb9a22022021-03-04 18:58:47 +0900165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
166 protected KubevirtRouterAdminService kubevirtRouterService;
167
Daniel Parkcc8e7462021-03-09 13:37:42 +0900168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
169 protected KubevirtPortService kubevirtPortService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
172 protected KubevirtNetworkService kubevirtNetworkService;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
175 protected KubevirtNodeService kubevirtNodeService;
176
Jian Lib5ab63c2021-02-03 17:54:28 +0900177 private final KubevirtNetworkListener networkListener = new InternalNetworkEventListener();
178 private final KubevirtNodeListener nodeListener = new InternalNodeEventListener();
Daniel Parkcc8e7462021-03-09 13:37:42 +0900179 private final KubevirtPortListener portListener = new InternalKubevirtPortListener();
Jian Lib5ab63c2021-02-03 17:54:28 +0900180
Daniel Parkb9a22022021-03-04 18:58:47 +0900181 private final InternalRouterEventListener kubevirtRouterlistener =
182 new InternalRouterEventListener();
183
Jian Lib5ab63c2021-02-03 17:54:28 +0900184 private final ExecutorService eventExecutor = newSingleThreadExecutor(
185 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
186
187 private ApplicationId appId;
188 private NodeId localNodeId;
189
190 @Activate
191 protected void activate() {
192 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
193 localNodeId = clusterService.getLocalNode().id();
Jian Lib5ab63c2021-02-03 17:54:28 +0900194 leadershipService.runForLeadership(appId.name());
195
Daniel Parkcc8e7462021-03-09 13:37:42 +0900196 networkService.addListener(networkListener);
197 nodeService.addListener(nodeListener);
198 kubevirtPortService.addListener(portListener);
Daniel Parkb9a22022021-03-04 18:58:47 +0900199 kubevirtRouterService.addListener(kubevirtRouterlistener);
200
Jian Lib5ab63c2021-02-03 17:54:28 +0900201 log.info("Started");
202 }
203
204 @Deactivate
205 protected void deactivate() {
206 networkService.removeListener(networkListener);
207 nodeService.removeListener(nodeListener);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900208 kubevirtPortService.removeListener(portListener);
Daniel Parkb9a22022021-03-04 18:58:47 +0900209 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900210 leadershipService.withdraw(appId.name());
Jian Lib5ab63c2021-02-03 17:54:28 +0900211 eventExecutor.shutdown();
212
213 log.info("Stopped");
214 }
215
216 private void createBridge(KubevirtNode node, KubevirtNetwork network) {
217
218 Device tunBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
219 if (tunBridge != null) {
220 log.warn("The tunnel bridge {} already exists at node {}",
221 network.tenantBridgeName(), node.hostname());
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900222 setDefaultRulesForTenantNetwork(node, network);
Jian Lib5ab63c2021-02-03 17:54:28 +0900223 return;
224 }
225
226 Device device = deviceService.getDevice(node.ovsdb());
227
228 IpAddress serverIp = apiConfigService.apiConfig().ipAddress();
229 ControllerInfo controlInfo =
230 new ControllerInfo(serverIp, DEFAULT_OFPORT, DEFAULT_OF_PROTO);
231 List<ControllerInfo> controllers = Lists.newArrayList(controlInfo);
232
233 String dpid = network.tenantDeviceId(
234 node.hostname()).toString().substring(DPID_BEGIN);
235
236 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
237 .name(network.tenantBridgeName())
238 .failMode(BridgeDescription.FailMode.SECURE)
239 .datapathId(dpid)
240 .disableInBand()
241 .controllers(controllers);
242
243 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
244 bridgeConfig.addBridge(builder.build());
245 }
246
247 private void removeBridge(KubevirtNode node, KubevirtNetwork network) {
248 Device device = deviceService.getDevice(node.ovsdb());
249
250 BridgeName bridgeName = BridgeName.bridgeName(network.tenantBridgeName());
251
252 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
253 bridgeConfig.deleteBridge(bridgeName);
254 deviceService.removeDevice(network.tenantDeviceId(node.hostname()));
255 }
256
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900257 private void createPatchTenantInterface(KubevirtNode node, KubevirtNetwork network) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900258 Device device = deviceService.getDevice(node.ovsdb());
259
260 if (device == null || !device.is(InterfaceConfig.class)) {
261 log.error("Failed to create patch interface on {}", node.ovsdb());
262 return;
263 }
264
265 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
266
Jian Li543fe852021-02-04 17:25:01 +0900267 String tenantToTunIntf =
268 TENANT_TO_TUNNEL_PREFIX + segmentIdHex(network.segmentId());
269 String tunToTenantIntf =
270 TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900271
Jian Li543fe852021-02-04 17:25:01 +0900272 // tenant bridge -> tunnel bridge
273 PatchDescription brTenantTunPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900274 DefaultPatchDescription.builder()
275 .deviceId(network.tenantBridgeName())
Jian Li543fe852021-02-04 17:25:01 +0900276 .ifaceName(tenantToTunIntf)
277 .peer(tunToTenantIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900278 .build();
279
Jian Li543fe852021-02-04 17:25:01 +0900280 ifaceConfig.addPatchMode(tenantToTunIntf, brTenantTunPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900281
Jian Li543fe852021-02-04 17:25:01 +0900282 // tunnel bridge -> tenant bridge
283 PatchDescription brTunTenantPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900284 DefaultPatchDescription.builder()
285 .deviceId(TUNNEL_BRIDGE)
Jian Li543fe852021-02-04 17:25:01 +0900286 .ifaceName(tunToTenantIntf)
287 .peer(tenantToTunIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900288 .build();
Jian Li543fe852021-02-04 17:25:01 +0900289 ifaceConfig.addPatchMode(tunToTenantIntf, brTunTenantPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900290 }
291
292 private void removePatchInterface(KubevirtNode node, KubevirtNetwork network) {
293 Device device = deviceService.getDevice(node.ovsdb());
294
295 if (device == null || !device.is(InterfaceConfig.class)) {
296 log.error("Failed to create patch interface on {}", node.ovsdb());
297 return;
298 }
299
300 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
301
Jian Li543fe852021-02-04 17:25:01 +0900302 String tunToIntIntf = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900303
304 ifaceConfig.removePatchMode(tunToIntIntf);
305 }
306
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900307 private void setArpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900308
309 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
310 if (router == null) {
311 return;
312 }
313
314 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
315 if (electedGw == null) {
316 return;
317 }
318
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900319 setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE, electedGw.intgBridge(),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900320 network.tenantDeviceId(node.hostname()), true);
321 }
322
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900323 private void setIcmpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900324 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
325 if (router == null) {
326 return;
327 }
328
329 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
330 if (electedGw == null) {
331 return;
332 }
333
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900334 setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE, electedGw.intgBridge(),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900335 network.tenantDeviceId(node.hostname()), true);
336 }
337
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900338 private void setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(KubevirtNode node, KubevirtNetwork network) {
339 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
340 if (router == null) {
341 return;
342 }
Daniel Parkcc8e7462021-03-09 13:37:42 +0900343
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900344 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
345 if (electedGw == null) {
346 return;
347 }
348
Jian Li91358d62021-03-22 11:04:52 +0900349 setDefaultGatewayRuleToWorkerNodeTunBridge(router, network, electedGw.intgBridge(), node, true);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900350 }
351
352 private void setDefaultRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900353 DeviceId deviceId = network.tenantDeviceId(node.hostname());
354
355 while (!deviceService.isAvailable(deviceId)) {
356 log.warn("Device {} is not ready for installing rules", deviceId);
357
358 try {
359 sleep(SLEEP_MS);
360 } catch (InterruptedException e) {
361 log.error("Failed to check device availability", e);
362 }
363 }
364
365 flowService.connectTables(deviceId, TENANT_INBOUND_TABLE, TENANT_DHCP_TABLE);
Jian Li543fe852021-02-04 17:25:01 +0900366 flowService.connectTables(deviceId, TENANT_DHCP_TABLE, TENANT_ARP_TABLE);
367 flowService.connectTables(deviceId, TENANT_ARP_TABLE, TENANT_ICMP_TABLE);
368 flowService.connectTables(deviceId, TENANT_ICMP_TABLE, TENANT_FORWARDING_TABLE);
Jian Lib5ab63c2021-02-03 17:54:28 +0900369
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900370 setDhcpRuleForTenantNetwork(deviceId, true);
Jian Lib5ab63c2021-02-03 17:54:28 +0900371 setForwardingRule(deviceId, true);
372
373 log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
374 }
375
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900376 private void setDhcpRuleForTenantNetwork(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900377 TrafficSelector selector = DefaultTrafficSelector.builder()
378 .matchEthType(Ethernet.TYPE_IPV4)
379 .matchIPProtocol(IPv4.PROTOCOL_UDP)
380 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
381 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
382 .build();
383
384 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
385 .punt()
386 .build();
387
388 flowService.setRule(
389 appId,
390 deviceId,
391 selector,
392 treatment,
393 PRIORITY_DHCP_RULE,
394 TENANT_DHCP_TABLE,
395 install);
396 }
397
Jian Li543fe852021-02-04 17:25:01 +0900398 private void setForwardingRule(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900399 TrafficSelector selector = DefaultTrafficSelector.builder().build();
400 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
401 .setOutput(PortNumber.NORMAL)
402 .build();
403
404 flowService.setRule(
405 appId,
406 deviceId,
407 selector,
408 treatment,
Jian Li543fe852021-02-04 17:25:01 +0900409 PRIORITY_FORWARDING_RULE,
Jian Lib5ab63c2021-02-03 17:54:28 +0900410 TENANT_FORWARDING_TABLE,
411 install);
412 }
413
Daniel Parkb9a22022021-03-04 18:58:47 +0900414 private void initGatewayNodeForInternalNetwork(KubevirtNetwork network,
415 KubevirtRouter router,
416 KubevirtNode electedGateway,
417 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900418 switch (network.type()) {
419 case VXLAN:
420 case GRE:
421 case GENEVE:
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900422 setDefaultEgressRuleToGatewayNode(router, network, electedGateway.intgBridge(), install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900423 kubevirtNodeService.completeNodes(WORKER).forEach(node -> {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900424 setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900425 electedGateway.intgBridge(),
426 network.tenantDeviceId(node.hostname()), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900427 setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900428 electedGateway.intgBridge(),
429 network.tenantDeviceId(node.hostname()), install);
Jian Li91358d62021-03-22 11:04:52 +0900430 setDefaultGatewayRuleToWorkerNodeTunBridge(router, network,
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900431 electedGateway.intgBridge(), node, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900432 });
433 break;
434 case FLAT:
435 case VLAN:
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900436 setGatewayArpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900437 electedGateway.intgBridge(), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900438 setGatewayIcmpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900439 electedGateway.intgBridge(), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900440 setGatewayProviderInterNetworkRoutingWithinSameRouter(network, router, electedGateway, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900441 break;
442 default:
443 // do nothing
444 break;
445 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900446 }
447
Jian Li91358d62021-03-22 11:04:52 +0900448 private void setDefaultGatewayRuleToWorkerNodeTunBridge(KubevirtRouter router,
449 KubevirtNetwork network,
450 DeviceId gwDeviceId,
451 KubevirtNode workerNode,
452 boolean install) {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900453 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900454
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900455 if (routerMacAddress == null) {
456 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
457 "there's no br-int port for device {}", gwDeviceId);
458 return;
459 }
460
461 KubevirtNode gwNode = kubevirtNodeService.node(gwDeviceId);
462
463 if (gwNode == null) {
464 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
465 "there's no gateway node for device {}", gwDeviceId);
466 return;
467 }
468
469
470 PortNumber patchPortNumber = tunnelToTenantPort(workerNode, network);
471 if (patchPortNumber == null) {
472 return;
473 }
474
475 PortNumber tunnelPortNumber = tunnelPort(workerNode, network);
476 if (tunnelPortNumber == null) {
477 return;
478 }
479
480 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
481 .matchInPort(patchPortNumber)
482 .matchEthType(Ethernet.TYPE_IPV4)
483 .matchEthDst((routerMacAddress));
484
485 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
486 .setTunnelId(Long.parseLong(network.segmentId()))
487 .extension(buildExtension(
488 deviceService,
489 workerNode.tunBridge(),
490 gwNode.dataIp().getIp4Address()),
491 workerNode.tunBridge())
492 .setOutput(tunnelPortNumber);
493
494 flowService.setRule(
495 appId,
496 workerNode.tunBridge(),
497 sBuilder.build(),
498 tBuilder.build(),
499 PRIORITY_FORWARDING_RULE,
500 TUNNEL_DEFAULT_TABLE,
501 install);
502 }
503
504 private void setDefaultEgressRuleToGatewayNode(KubevirtRouter router,
505 KubevirtNetwork network,
506 DeviceId gwDeviceId,
507 boolean install) {
508 MacAddress routerMacAddress = getRouterMacAddress(router);
509
510 if (routerMacAddress == null) {
511 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
512 "there's no br-int port for device {}", gwDeviceId);
513 return;
514 }
515
516 KubevirtNode gwNode = kubevirtNodeService.node(gwDeviceId);
517
518 if (gwNode == null) {
519 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
520 "there's no gateway node for device {}", gwDeviceId);
521 return;
522 }
523
524 PortNumber tunToIntPortNum = portNumber(gwNode.tunBridge(), TUNNEL_TO_INTEGRATION);
525
526 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
527 .matchTunnelId(Long.parseLong(network.segmentId()));
528
529 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
530 .setOutput(tunToIntPortNum);
531
532 flowService.setRule(
533 appId,
534 gwNode.tunBridge(),
535 sBuilder.build(),
536 tBuilder.build(),
537 PRIORITY_TUNNEL_RULE,
538 TUNNEL_DEFAULT_TABLE,
539 install);
540 }
541
542
543 private void setGatewayIcmpRuleForTenantInternalNetwork(KubevirtRouter router,
544 KubevirtNetwork network,
545 int tableNum,
546 DeviceId gwDeviceId,
547 DeviceId tenantDeviceId,
548 boolean install) {
549 MacAddress routerMacAddress = getRouterMacAddress(router);
550
551 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900552 log.warn("Setting gateway ICMP rule for internal network because " +
553 "there's no br-int port for device {}", gwDeviceId);
554 return;
555 }
556
557 Device device = deviceService.getDevice(tenantDeviceId);
558
559 if (device == null) {
560 log.warn("Setting gateway icmp rule for internal network because " +
561 "there's no tenant device for {} to install gateway arp rule",
562 tenantDeviceId);
563 return;
564 }
565
566
567 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
568 .matchEthType(Ethernet.TYPE_IPV4)
569 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
570 .matchIcmpType(TYPE_ECHO_REQUEST)
571 .matchIcmpCode(CODE_ECHO_REQEUST)
572 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
573
574 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
575 .extension(buildMoveEthSrcToDstExtension(device), device.id())
576 .extension(buildMoveIpSrcToDstExtension(device), device.id())
577 .extension(buildLoadExtension(device,
578 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
579 .extension(buildLoadExtension(device,
580 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
581 .setIpSrc(network.gatewayIp())
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900582 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900583 .setOutput(PortNumber.IN_PORT);
584
585 flowService.setRule(
586 appId,
587 tenantDeviceId,
588 sBuilder.build(),
589 tBuilder.build(),
590 PRIORITY_ICMP_RULE,
591 tableNum,
592 install);
593 }
594
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900595 private void setGatewayArpRuleForTenantInternalNetwork(KubevirtRouter router,
596 KubevirtNetwork network,
597 int tableNum,
598 DeviceId gwDeviceId,
599 DeviceId tenantDeviceId,
600 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900601
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900602 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900603
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900604 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900605 log.warn("Setting gateway arp rule for internal network because " +
606 "there's no br-int port for device {}", gwDeviceId);
607 return;
608 }
609
610 Device device = deviceService.getDevice(tenantDeviceId);
611
612 if (device == null) {
613 log.warn("Setting gateway arp rule for internal network because " +
614 "there's no tenant device for {} to install gateway arp rule",
615 tenantDeviceId);
616 return;
617 }
618
619
620 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
621 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
622 .matchArpOp(ARP.OP_REQUEST)
623 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
624
625 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
626 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
627 .extension(buildMoveArpShaToThaExtension(device), device.id())
628 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
629 .setArpOp(ARP.OP_REPLY)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900630 .setArpSha(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900631 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900632 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900633 .setOutput(PortNumber.IN_PORT);
634
635 flowService.setRule(
636 appId,
637 device.id(),
638 sBuilder.build(),
639 tBuilder.build(),
640 PRIORITY_ARP_GATEWAY_RULE,
641 tableNum,
642 install
643 );
644 }
645
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900646 private void setGatewayProviderInterNetworkRoutingWithinSameRouter(
Daniel Parkcc8e7462021-03-09 13:37:42 +0900647 KubevirtNetwork network, KubevirtRouter router, KubevirtNode gatewayNode, boolean install) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900648 router.internal().forEach(srcNetwork -> {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900649 if (srcNetwork.equals(network.networkId())
650 || kubevirtNetworkService.network(srcNetwork) == null) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900651 return;
652 }
653
Daniel Parkcc8e7462021-03-09 13:37:42 +0900654 kubevirtPortService.ports(network.networkId()).forEach(port -> {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900655 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900656 port, gatewayNode, install);
657 });
Daniel Parkb9a22022021-03-04 18:58:47 +0900658 });
659 }
660
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900661 private void setGatewayInterNetworkRoutingFromNetworkToPort(KubevirtRouter router,
662 KubevirtNetwork srcNetwork,
663 KubevirtPort dstPort,
664 KubevirtNode gatewayNode,
665 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900666 Device gwDevice = deviceService.getDevice(gatewayNode.intgBridge());
667
668 if (gwDevice == null) {
669 log.warn("Failed to set internal network routing rule because " +
670 "there's no device Id for device {}", gatewayNode.intgBridge());
671 return;
672 }
673
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900674 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900675
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900676 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900677 log.warn("Failed to set internal network routing rule because " +
678 "there's no br-int port for device {}", gatewayNode.intgBridge());
679 return;
680 }
681
682 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
683 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900684 .matchEthDst(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900685 .matchIPSrc(IpPrefix.valueOf(srcNetwork.cidr()))
686 .matchIPDst(IpPrefix.valueOf(dstPort.ipAddress(), 32));
687
688 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900689 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900690 .setEthDst(dstPort.macAddress())
691 .transition(FORWARDING_TABLE)
692 .build();
693
694 flowService.setRule(
695 appId,
696 gwDevice.id(),
697 sBuilder.build(),
698 treatment,
699 PRIORITY_INTERNAL_ROUTING_RULE,
Daniel Park54205272021-03-23 08:00:00 +0900700 PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900701 install
702 );
703 }
704
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900705 private void setGatewayArpRuleForProviderInternalNetwork(KubevirtRouter router, KubevirtNetwork network,
706 int tableNum, DeviceId gwDeviceId, boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900707
708
709 Device device = deviceService.getDevice(gwDeviceId);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900710 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900711
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900712 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900713 log.warn("Setting gateway arp rule for internal network because " +
714 "there's no br-int port for device {}", gwDeviceId);
Daniel Parkb9a22022021-03-04 18:58:47 +0900715 return;
716 }
717
Jian Li543fe852021-02-04 17:25:01 +0900718 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
719 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
720 .matchArpOp(ARP.OP_REQUEST)
721 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
722
723 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
724 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
725 .extension(buildMoveArpShaToThaExtension(device), device.id())
726 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
727 .setArpOp(ARP.OP_REPLY)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900728 .setArpSha(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900729 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900730 .setEthSrc(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900731 .setOutput(PortNumber.IN_PORT);
732
733 flowService.setRule(
734 appId,
735 device.id(),
736 sBuilder.build(),
737 tBuilder.build(),
738 PRIORITY_ARP_GATEWAY_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900739 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900740 install
741 );
742 }
743
Daniel Parkb9a22022021-03-04 18:58:47 +0900744 /**
745 * Sends ICMP echo reply for the ICMP echo request from the kubevirt VM.
746 *
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900747 * @param router kubevirt router
Daniel Parkb9a22022021-03-04 18:58:47 +0900748 * @param network kubevirt network
749 * @param tableNum flow table number
750 * @param deviceId device id of the selected gateway for the network
751 * @param install install if true, remove otherwise
752 */
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900753 private void setGatewayIcmpRuleForProviderInternalNetwork(KubevirtRouter router, KubevirtNetwork network,
754 int tableNum, DeviceId deviceId, boolean install) {
755 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900756
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900757 if (routerMacAddress == null) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900758 log.error("Setting gateway ICMP rule for internal network because " +
759 "there's no br-int port for device {}", deviceId);
760 return;
761 }
762
Jian Li543fe852021-02-04 17:25:01 +0900763 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
764 .matchEthType(Ethernet.TYPE_IPV4)
765 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
766 .matchIcmpType(TYPE_ECHO_REQUEST)
767 .matchIcmpCode(CODE_ECHO_REQEUST)
768 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
769
770 Device device = deviceService.getDevice(deviceId);
771 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
772 .extension(buildMoveEthSrcToDstExtension(device), device.id())
773 .extension(buildMoveIpSrcToDstExtension(device), device.id())
774 .extension(buildLoadExtension(device,
775 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
776 .extension(buildLoadExtension(device,
777 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
778 .setIpSrc(network.gatewayIp())
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900779 .setEthSrc(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900780 .setOutput(PortNumber.IN_PORT);
781
782 flowService.setRule(
783 appId,
784 deviceId,
785 sBuilder.build(),
786 tBuilder.build(),
787 PRIORITY_ICMP_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900788 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900789 install);
790 }
791
Daniel Parkb9a22022021-03-04 18:58:47 +0900792 private class InternalRouterEventListener implements KubevirtRouterListener {
793 private boolean isRelevantHelper() {
794 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park4063f402021-02-25 09:14:22 +0900795 }
796
Daniel Parkb9a22022021-03-04 18:58:47 +0900797 @Override
798 public void event(KubevirtRouterEvent event) {
799 switch (event.type()) {
800 case KUBEVIRT_ROUTER_CREATED:
801 eventExecutor.execute(() -> processRouterCreation(event.subject()));
802 break;
803 case KUBEVIRT_ROUTER_REMOVED:
804 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
805 break;
806 case KUBEVIRT_ROUTER_UPDATED:
807 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
808 break;
809 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
810 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
811 event.internal()));
812 break;
813 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
814 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
815 event.internal()));
816 break;
817 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
818 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
819 event.gateway()));
820 break;
821 case KUBEVIRT_GATEWAY_NODE_DETACHED:
822 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
823 event.gateway()));
824 break;
825 case KUBEVIRT_GATEWAY_NODE_CHANGED:
826 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
827 event.gateway()));
828 break;
Daniel Park4063f402021-02-25 09:14:22 +0900829
Daniel Parkb9a22022021-03-04 18:58:47 +0900830 default:
831 //do nothing
832 break;
833 }
834 }
835
836 private void processRouterCreation(KubevirtRouter router) {
837 // When a router is created, we performs the election process to associate the router
838 // to the specific gateway. After the election, KubevirtNetwork handler installs bunch of rules
839 // to elected gateway node so that VMs associated to the router can ping to their gateway IP.
840 // SNAT and floating ip rule setup is out of this handler's scope and would be done with the other handlers
841 if (!isRelevantHelper()) {
842 return;
843 }
844 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
845 if (electedGw == null) {
846 return;
847 }
848
849 router.internal().forEach(networkName -> {
850 KubevirtNetwork network = networkService.network(networkName);
851
852 if (network != null) {
853 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
854 }
855 });
856 kubevirtRouterService.updateRouter(router.updatedElectedGateway(electedGw.hostname()));
857 }
858
859 private void processRouterDeletion(KubevirtRouter router) {
860 if (!isRelevantHelper()) {
861 return;
862 }
863 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
864 if (electedGw == null) {
865 return;
866 }
867
868 router.internal().forEach(networkName -> {
869 KubevirtNetwork network = networkService.network(networkName);
870
871 if (network != null) {
872 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
873 }
874 });
875 }
876
877 private void processRouterUpdate(KubevirtRouter router) {
878 if (!isRelevantHelper()) {
879 return;
880 }
881 if (router.electedGateway() == null) {
882 return;
883 }
884
885 KubevirtNode electedGw = nodeService.node(router.electedGateway());
886
887 router.internal().forEach(networkName -> {
888 KubevirtNetwork network = networkService.network(networkName);
889
890 if (network != null) {
891 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
892 }
893 });
894 }
895
896 private void processRouterInternalNetworksAttached(KubevirtRouter router,
897 Set<String> attachedInternalNetworks) {
898 if (!isRelevantHelper()) {
899 return;
900 }
901 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
902 if (electedGw == null) {
903 return;
904 }
905
906 attachedInternalNetworks.forEach(networkName -> {
907 KubevirtNetwork network = networkService.network(networkName);
908
909 if (network != null) {
910 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
911 }
912 });
913 }
914
915 private void processRouterInternalNetworksDetached(KubevirtRouter router,
916 Set<String> detachedInternalNetworks) {
917 if (!isRelevantHelper()) {
918 return;
919 }
920 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
921 if (electedGw == null) {
922 return;
923 }
924
925 detachedInternalNetworks.forEach(networkName -> {
926 KubevirtNetwork network = networkService.network(networkName);
927
928 if (network != null) {
929 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
930 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900931
Daniel Parkcc8e7462021-03-09 13:37:42 +0900932 removeDetachedInternalNetworkRules(network, router, electedGw);
933 });
934 }
935
936 private void removeDetachedInternalNetworkRules(KubevirtNetwork removedNetwork, KubevirtRouter router,
937 KubevirtNode electedGw) {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900938 router.internal().stream().filter(networkId -> kubevirtNetworkService.network(networkId) != null)
939 .forEach(networkId -> {
940 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
941 setGatewayInterNetworkRoutingFromNetworkToPort(
942 router, removedNetwork, kubevirtPort, electedGw, false);
943 });
Daniel Parkcc8e7462021-03-09 13:37:42 +0900944 });
Daniel Parkb9a22022021-03-04 18:58:47 +0900945 }
946
947 private void processRouterGatewayNodeAttached(KubevirtRouter router,
948 String associatedGateway) {
949 if (!isRelevantHelper()) {
950 return;
951 }
952
953 KubevirtNode gatewayNode = nodeService.node(associatedGateway);
954 if (gatewayNode == null) {
955 return;
956 }
957
958 router.internal().forEach(networkName -> {
959 KubevirtNetwork network = networkService.network(networkName);
960
961 if (network != null) {
962 initGatewayNodeForInternalNetwork(network, router, gatewayNode, true);
963 }
964 });
965 }
966
967 private void processRouterGatewayNodeDetached(KubevirtRouter router,
968 String disAssociatedGateway) {
969 if (!isRelevantHelper()) {
970 return;
971 }
972
973 KubevirtNode gatewayNode = nodeService.node(disAssociatedGateway);
974 if (gatewayNode == null) {
975 return;
976 }
977
978 router.internal().forEach(networkName -> {
979 KubevirtNetwork network = networkService.network(networkName);
980
981 if (network != null) {
982 initGatewayNodeForInternalNetwork(network, router, gatewayNode, false);
983 }
984 });
985 }
986
987 private void processRouterGatewayNodeChanged(KubevirtRouter router,
988 String disAssociatedGateway) {
989 if (!isRelevantHelper()) {
990 return;
991 }
992
993 KubevirtNode oldGatewayNode = nodeService.node(disAssociatedGateway);
994 if (oldGatewayNode == null) {
995 return;
996 }
997
998 router.internal().forEach(networkName -> {
999 KubevirtNetwork network = networkService.network(networkName);
1000
1001 if (network != null) {
1002 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, false);
1003 }
1004 });
1005
1006 KubevirtNode newGatewayNode = nodeService.node(router.electedGateway());
1007 if (newGatewayNode == null) {
1008 return;
1009 }
1010
1011 router.internal().forEach(networkName -> {
1012 KubevirtNetwork network = networkService.network(networkName);
1013
1014 if (network != null) {
1015 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, true);
1016 }
1017 });
1018 }
Daniel Park4063f402021-02-25 09:14:22 +09001019 }
1020
Jian Lib5ab63c2021-02-03 17:54:28 +09001021 private class InternalNetworkEventListener implements KubevirtNetworkListener {
1022
1023 private boolean isRelevantHelper() {
1024 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1025 }
1026
1027 @Override
1028 public void event(KubevirtNetworkEvent event) {
1029 switch (event.type()) {
1030 case KUBEVIRT_NETWORK_CREATED:
1031 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
1032 break;
1033 case KUBEVIRT_NETWORK_REMOVED:
1034 eventExecutor.execute(() -> processNetworkRemoval(event.subject()));
1035 break;
1036 case KUBEVIRT_NETWORK_UPDATED:
1037 default:
1038 // do nothing
1039 break;
1040 }
1041 }
1042
1043 private void processNetworkCreation(KubevirtNetwork network) {
1044 if (!isRelevantHelper()) {
1045 return;
1046 }
1047
1048 switch (network.type()) {
1049 case VXLAN:
1050 case GRE:
1051 case GENEVE:
1052 initIntegrationTunnelBridge(network);
1053 break;
1054 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +09001055 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001056 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001057 default:
1058 // do nothing
1059 break;
1060 }
1061 }
1062
1063 private void processNetworkRemoval(KubevirtNetwork network) {
1064 if (!isRelevantHelper()) {
1065 return;
1066 }
1067
1068 switch (network.type()) {
1069 case VXLAN:
1070 case GRE:
1071 case GENEVE:
1072 purgeIntegrationTunnelBridge(network);
1073 break;
1074 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +09001075 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001076 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001077 default:
1078 // do nothing
1079 break;
1080 }
1081 }
1082
1083 private void initIntegrationTunnelBridge(KubevirtNetwork network) {
1084 if (network.segmentId() == null) {
1085 return;
1086 }
1087
1088 nodeService.completeNodes().forEach(n -> {
1089 createBridge(n, network);
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001090 createPatchTenantInterface(n, network);
1091 setDefaultRulesForTenantNetwork(n, network);
Jian Lib5ab63c2021-02-03 17:54:28 +09001092 });
1093 }
1094
1095 private void purgeIntegrationTunnelBridge(KubevirtNetwork network) {
1096 if (network.segmentId() == null) {
1097 return;
1098 }
1099
1100 nodeService.completeNodes().forEach(n -> {
1101 removePatchInterface(n, network);
1102 removeBridge(n, network);
1103 });
1104 }
1105 }
1106
1107 private class InternalNodeEventListener implements KubevirtNodeListener {
1108
1109 private boolean isRelevantHelper() {
1110 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1111 }
1112
1113 @Override
1114 public void event(KubevirtNodeEvent event) {
1115 switch (event.type()) {
1116 case KUBEVIRT_NODE_COMPLETE:
1117 eventExecutor.execute(() -> processNodeCompletion(event.subject()));
1118 break;
Daniel Parkb9a22022021-03-04 18:58:47 +09001119 case KUBEVIRT_NODE_REMOVED:
1120 eventExecutor.execute(() -> processNodeDeletion(event.subject()));
1121 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001122 case KUBEVIRT_NODE_INCOMPLETE:
1123 case KUBEVIRT_NODE_UPDATED:
1124 default:
1125 // do nothing
1126 break;
1127 }
1128 }
1129
1130 private void processNodeCompletion(KubevirtNode node) {
1131 if (!isRelevantHelper()) {
1132 return;
1133 }
1134
Daniel Park4063f402021-02-25 09:14:22 +09001135 if (node.type().equals(WORKER)) {
1136 for (KubevirtNetwork network : networkService.networks()) {
1137 switch (network.type()) {
1138 case VXLAN:
1139 case GRE:
1140 case GENEVE:
1141 if (network.segmentId() == null) {
1142 continue;
1143 }
1144 createBridge(node, network);
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001145 createPatchTenantInterface(node, network);
1146 setDefaultRulesForTenantNetwork(node, network);
1147 setArpRulesForTenantNetwork(node, network);
1148 setIcmpRulesForTenantNetwork(node, network);
1149 setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(node, network);
Daniel Park4063f402021-02-25 09:14:22 +09001150 break;
1151 case FLAT:
1152 case VLAN:
1153 default:
1154 // do nothing
1155 break;
1156 }
1157 }
1158 } else if (node.type().equals(GATEWAY)) {
Daniel Parkb9a22022021-03-04 18:58:47 +09001159 updateGatewayNodeForRouter();
Daniel Park4063f402021-02-25 09:14:22 +09001160 for (KubevirtNetwork network : networkService.networks()) {
1161 switch (network.type()) {
1162 case FLAT:
1163 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001164 break;
1165 case VXLAN:
1166 case GRE:
1167 case GENEVE:
1168 default:
1169 // do nothing
1170 break;
1171 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001172 }
1173 }
1174 }
Daniel Parkb9a22022021-03-04 18:58:47 +09001175
1176 private void processNodeDeletion(KubevirtNode node) {
1177 if (!isRelevantHelper()) {
1178 return;
1179 }
1180
1181 if (node.type().equals(GATEWAY)) {
1182 updateGatewayNodeForRouter();
1183 for (KubevirtNetwork network : networkService.networks()) {
1184 switch (network.type()) {
1185 case FLAT:
1186 case VLAN:
1187 break;
1188 case VXLAN:
1189 case GRE:
1190 case GENEVE:
1191 default:
1192 // do nothing
1193 break;
1194 }
1195 }
1196 }
1197 }
1198
1199 private void updateGatewayNodeForRouter() {
1200 kubevirtRouterService.routers().forEach(router -> {
1201 KubevirtNode newGwNode = gatewayNodeForSpecifiedRouter(nodeService, router);
1202
1203 if (newGwNode == null) {
1204 return;
1205 }
1206 kubevirtRouterService.updateRouter(router.updatedElectedGateway(newGwNode.hostname()));
1207 });
1208 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001209 }
Daniel Parkcc8e7462021-03-09 13:37:42 +09001210
1211 private class InternalKubevirtPortListener implements KubevirtPortListener {
1212
1213 private boolean isRelevantHelper() {
1214 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1215 }
1216
1217 @Override
1218 public void event(KubevirtPortEvent event) {
1219 switch (event.type()) {
1220 case KUBEVIRT_PORT_CREATED:
1221 eventExecutor.execute(() -> processPortCreation(event.subject()));
1222 break;
1223 case KUBEVIRT_PORT_UPDATED:
1224 eventExecutor.execute(() -> processPortUpdate(event.subject()));
1225 break;
1226 case KUBEVIRT_PORT_REMOVED:
1227 eventExecutor.execute(() -> processPortDeletion(event.subject()));
1228 break;
1229 default:
1230 //do nothing
1231 break;
1232 }
1233 }
1234
1235 private void processPortCreation(KubevirtPort kubevirtPort) {
1236 if (!isRelevantHelper()) {
1237 return;
1238 }
1239
1240 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1241 if (router == null) {
1242 return;
1243 }
1244
1245 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1246
1247 if (gwNode != null) {
1248
1249 router.internal().forEach(srcNetwork -> {
1250 if (srcNetwork.equals(kubevirtPort.networkId())
1251 || kubevirtNetworkService.network(srcNetwork) == null) {
1252 return;
1253 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001254 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001255 kubevirtPort, gwNode, true);
1256 });
1257 }
1258 }
1259
1260 private void processPortUpdate(KubevirtPort kubevirtPort) {
1261 if (!isRelevantHelper()) {
1262 return;
1263 }
1264
1265 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1266 if (router == null) {
1267 return;
1268 }
1269
1270 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1271
1272 if (gwNode != null) {
1273
1274 router.internal().forEach(srcNetwork -> {
1275 if (srcNetwork.equals(kubevirtPort.networkId())
1276 || kubevirtNetworkService.network(srcNetwork) == null) {
1277 return;
1278 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001279 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001280 kubevirtPort, gwNode, true);
1281 });
1282 }
1283 }
1284
1285 private void processPortDeletion(KubevirtPort kubevirtPort) {
1286 if (!isRelevantHelper()) {
1287 return;
1288 }
1289
1290 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1291 if (router == null) {
1292 return;
1293 }
1294
1295 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1296
1297 if (gwNode != null) {
1298
1299 router.internal().forEach(srcNetwork -> {
1300 if (srcNetwork.equals(kubevirtPort.networkId())
1301 || kubevirtNetworkService.network(srcNetwork) == null) {
1302 return;
1303 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001304 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001305 kubevirtPort, gwNode, false);
1306 });
1307 }
1308
1309 }
1310 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001311}