blob: d88520a7716fb0865b9294ba7c7f65991ac60d76 [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 Park150b9622021-03-24 12:30:50 +0900104import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
105import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
Daniel Parkb9a22022021-03-04 18:58:47 +0900106import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
Daniel Parkcc8e7462021-03-09 13:37:42 +0900107import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtNetwork;
108import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtPort;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900109import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
110import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.portNumber;
Jian Lib5ab63c2021-02-03 17:54:28 +0900111import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.segmentIdHex;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900112import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
113import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelToTenantPort;
Jian Li543fe852021-02-04 17:25:01 +0900114import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_NX_IP_TTL;
115import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_OF_ICMP_TYPE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900116import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
Jian Li543fe852021-02-04 17:25:01 +0900117import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildLoadExtension;
118import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
119import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
120import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
121import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveIpSrcToDstExtension;
Jian Lib5ab63c2021-02-03 17:54:28 +0900122import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_BRIDGE;
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900123import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_TO_INTEGRATION;
Daniel Park4063f402021-02-25 09:14:22 +0900124import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
125import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
Jian Lib5ab63c2021-02-03 17:54:28 +0900126import static org.slf4j.LoggerFactory.getLogger;
127
128/**
129 * Handles kubevirt network events.
130 */
131@Component(immediate = true)
132public class KubevirtNetworkHandler {
133 protected final Logger log = getLogger(getClass());
134 private static final String DEFAULT_OF_PROTO = "tcp";
135 private static final int DEFAULT_OFPORT = 6653;
136 private static final int DPID_BEGIN = 3;
137 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li543fe852021-02-04 17:25:01 +0900138 private static final int DEFAULT_TTL = 0xff;
Jian Lib5ab63c2021-02-03 17:54:28 +0900139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
141 protected CoreService coreService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
144 protected ClusterService clusterService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
147 protected LeadershipService leadershipService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
150 protected DeviceAdminService deviceService;
151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
153 protected KubevirtApiConfigService apiConfigService;
154
155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
156 protected KubevirtNodeService nodeService;
157
158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
159 protected KubevirtNetworkService networkService;
160
161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
162 protected KubevirtFlowRuleService flowService;
163
Daniel Park4063f402021-02-25 09:14:22 +0900164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
165 protected DriverService driverService;
166
Daniel Parkb9a22022021-03-04 18:58:47 +0900167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
168 protected KubevirtRouterAdminService kubevirtRouterService;
169
Daniel Parkcc8e7462021-03-09 13:37:42 +0900170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
171 protected KubevirtPortService kubevirtPortService;
172
173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
174 protected KubevirtNetworkService kubevirtNetworkService;
175
176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
177 protected KubevirtNodeService kubevirtNodeService;
178
Jian Lib5ab63c2021-02-03 17:54:28 +0900179 private final KubevirtNetworkListener networkListener = new InternalNetworkEventListener();
180 private final KubevirtNodeListener nodeListener = new InternalNodeEventListener();
Daniel Parkcc8e7462021-03-09 13:37:42 +0900181 private final KubevirtPortListener portListener = new InternalKubevirtPortListener();
Jian Lib5ab63c2021-02-03 17:54:28 +0900182
Daniel Parkb9a22022021-03-04 18:58:47 +0900183 private final InternalRouterEventListener kubevirtRouterlistener =
184 new InternalRouterEventListener();
185
Jian Lib5ab63c2021-02-03 17:54:28 +0900186 private final ExecutorService eventExecutor = newSingleThreadExecutor(
187 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
188
189 private ApplicationId appId;
190 private NodeId localNodeId;
191
192 @Activate
193 protected void activate() {
194 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
195 localNodeId = clusterService.getLocalNode().id();
Jian Lib5ab63c2021-02-03 17:54:28 +0900196 leadershipService.runForLeadership(appId.name());
197
Daniel Parkcc8e7462021-03-09 13:37:42 +0900198 networkService.addListener(networkListener);
199 nodeService.addListener(nodeListener);
200 kubevirtPortService.addListener(portListener);
Daniel Parkb9a22022021-03-04 18:58:47 +0900201 kubevirtRouterService.addListener(kubevirtRouterlistener);
202
Jian Lib5ab63c2021-02-03 17:54:28 +0900203 log.info("Started");
204 }
205
206 @Deactivate
207 protected void deactivate() {
208 networkService.removeListener(networkListener);
209 nodeService.removeListener(nodeListener);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900210 kubevirtPortService.removeListener(portListener);
Daniel Parkb9a22022021-03-04 18:58:47 +0900211 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900212 leadershipService.withdraw(appId.name());
Jian Lib5ab63c2021-02-03 17:54:28 +0900213 eventExecutor.shutdown();
214
215 log.info("Stopped");
216 }
217
218 private void createBridge(KubevirtNode node, KubevirtNetwork network) {
219
220 Device tunBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
221 if (tunBridge != null) {
222 log.warn("The tunnel bridge {} already exists at node {}",
223 network.tenantBridgeName(), node.hostname());
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900224 setDefaultRulesForTenantNetwork(node, network);
Jian Lib5ab63c2021-02-03 17:54:28 +0900225 return;
226 }
227
228 Device device = deviceService.getDevice(node.ovsdb());
229
230 IpAddress serverIp = apiConfigService.apiConfig().ipAddress();
231 ControllerInfo controlInfo =
232 new ControllerInfo(serverIp, DEFAULT_OFPORT, DEFAULT_OF_PROTO);
233 List<ControllerInfo> controllers = Lists.newArrayList(controlInfo);
234
235 String dpid = network.tenantDeviceId(
236 node.hostname()).toString().substring(DPID_BEGIN);
237
238 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
239 .name(network.tenantBridgeName())
240 .failMode(BridgeDescription.FailMode.SECURE)
241 .datapathId(dpid)
242 .disableInBand()
243 .controllers(controllers);
244
245 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
246 bridgeConfig.addBridge(builder.build());
247 }
248
249 private void removeBridge(KubevirtNode node, KubevirtNetwork network) {
250 Device device = deviceService.getDevice(node.ovsdb());
251
252 BridgeName bridgeName = BridgeName.bridgeName(network.tenantBridgeName());
253
254 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
255 bridgeConfig.deleteBridge(bridgeName);
256 deviceService.removeDevice(network.tenantDeviceId(node.hostname()));
257 }
258
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900259 private void createPatchTenantInterface(KubevirtNode node, KubevirtNetwork network) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900260 Device device = deviceService.getDevice(node.ovsdb());
261
262 if (device == null || !device.is(InterfaceConfig.class)) {
263 log.error("Failed to create patch interface on {}", node.ovsdb());
264 return;
265 }
266
267 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
268
Jian Li543fe852021-02-04 17:25:01 +0900269 String tenantToTunIntf =
270 TENANT_TO_TUNNEL_PREFIX + segmentIdHex(network.segmentId());
271 String tunToTenantIntf =
272 TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900273
Jian Li543fe852021-02-04 17:25:01 +0900274 // tenant bridge -> tunnel bridge
275 PatchDescription brTenantTunPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900276 DefaultPatchDescription.builder()
277 .deviceId(network.tenantBridgeName())
Jian Li543fe852021-02-04 17:25:01 +0900278 .ifaceName(tenantToTunIntf)
279 .peer(tunToTenantIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900280 .build();
281
Jian Li543fe852021-02-04 17:25:01 +0900282 ifaceConfig.addPatchMode(tenantToTunIntf, brTenantTunPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900283
Jian Li543fe852021-02-04 17:25:01 +0900284 // tunnel bridge -> tenant bridge
285 PatchDescription brTunTenantPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900286 DefaultPatchDescription.builder()
287 .deviceId(TUNNEL_BRIDGE)
Jian Li543fe852021-02-04 17:25:01 +0900288 .ifaceName(tunToTenantIntf)
289 .peer(tenantToTunIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900290 .build();
Jian Li543fe852021-02-04 17:25:01 +0900291 ifaceConfig.addPatchMode(tunToTenantIntf, brTunTenantPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900292 }
293
294 private void removePatchInterface(KubevirtNode node, KubevirtNetwork network) {
295 Device device = deviceService.getDevice(node.ovsdb());
296
297 if (device == null || !device.is(InterfaceConfig.class)) {
298 log.error("Failed to create patch interface on {}", node.ovsdb());
299 return;
300 }
301
302 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
303
Jian Li543fe852021-02-04 17:25:01 +0900304 String tunToIntIntf = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900305
306 ifaceConfig.removePatchMode(tunToIntIntf);
307 }
308
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900309 private void setArpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900310
311 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
312 if (router == null) {
313 return;
314 }
315
316 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
317 if (electedGw == null) {
318 return;
319 }
320
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900321 setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE, electedGw.intgBridge(),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900322 network.tenantDeviceId(node.hostname()), true);
323 }
324
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900325 private void setIcmpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900326 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
327 if (router == null) {
328 return;
329 }
330
331 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
332 if (electedGw == null) {
333 return;
334 }
335
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900336 setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE, electedGw.intgBridge(),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900337 network.tenantDeviceId(node.hostname()), true);
338 }
339
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900340 private void setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(KubevirtNode node, KubevirtNetwork network) {
341 KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
342 if (router == null) {
343 return;
344 }
Daniel Parkcc8e7462021-03-09 13:37:42 +0900345
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900346 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
347 if (electedGw == null) {
348 return;
349 }
350
Jian Li91358d62021-03-22 11:04:52 +0900351 setDefaultGatewayRuleToWorkerNodeTunBridge(router, network, electedGw.intgBridge(), node, true);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900352 }
353
354 private void setDefaultRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900355 DeviceId deviceId = network.tenantDeviceId(node.hostname());
356
357 while (!deviceService.isAvailable(deviceId)) {
358 log.warn("Device {} is not ready for installing rules", deviceId);
359
360 try {
361 sleep(SLEEP_MS);
362 } catch (InterruptedException e) {
363 log.error("Failed to check device availability", e);
364 }
365 }
366
367 flowService.connectTables(deviceId, TENANT_INBOUND_TABLE, TENANT_DHCP_TABLE);
Jian Li543fe852021-02-04 17:25:01 +0900368 flowService.connectTables(deviceId, TENANT_DHCP_TABLE, TENANT_ARP_TABLE);
369 flowService.connectTables(deviceId, TENANT_ARP_TABLE, TENANT_ICMP_TABLE);
370 flowService.connectTables(deviceId, TENANT_ICMP_TABLE, TENANT_FORWARDING_TABLE);
Jian Lib5ab63c2021-02-03 17:54:28 +0900371
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900372 setDhcpRuleForTenantNetwork(deviceId, true);
Jian Lib5ab63c2021-02-03 17:54:28 +0900373 setForwardingRule(deviceId, true);
374
375 log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
376 }
377
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900378 private void setDhcpRuleForTenantNetwork(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900379 TrafficSelector selector = DefaultTrafficSelector.builder()
380 .matchEthType(Ethernet.TYPE_IPV4)
381 .matchIPProtocol(IPv4.PROTOCOL_UDP)
382 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
383 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
384 .build();
385
386 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
387 .punt()
388 .build();
389
390 flowService.setRule(
391 appId,
392 deviceId,
393 selector,
394 treatment,
395 PRIORITY_DHCP_RULE,
396 TENANT_DHCP_TABLE,
397 install);
398 }
399
Jian Li543fe852021-02-04 17:25:01 +0900400 private void setForwardingRule(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900401 TrafficSelector selector = DefaultTrafficSelector.builder().build();
402 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
403 .setOutput(PortNumber.NORMAL)
404 .build();
405
406 flowService.setRule(
407 appId,
408 deviceId,
409 selector,
410 treatment,
Jian Li543fe852021-02-04 17:25:01 +0900411 PRIORITY_FORWARDING_RULE,
Jian Lib5ab63c2021-02-03 17:54:28 +0900412 TENANT_FORWARDING_TABLE,
413 install);
414 }
415
Daniel Parkb9a22022021-03-04 18:58:47 +0900416 private void initGatewayNodeForInternalNetwork(KubevirtNetwork network,
417 KubevirtRouter router,
418 KubevirtNode electedGateway,
419 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900420 switch (network.type()) {
421 case VXLAN:
422 case GRE:
423 case GENEVE:
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900424 setDefaultEgressRuleToGatewayNode(router, network, electedGateway.intgBridge(), install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900425 kubevirtNodeService.completeNodes(WORKER).forEach(node -> {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900426 setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900427 electedGateway.intgBridge(),
428 network.tenantDeviceId(node.hostname()), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900429 setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900430 electedGateway.intgBridge(),
431 network.tenantDeviceId(node.hostname()), install);
Jian Li91358d62021-03-22 11:04:52 +0900432 setDefaultGatewayRuleToWorkerNodeTunBridge(router, network,
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900433 electedGateway.intgBridge(), node, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900434 });
Daniel Park150b9622021-03-24 12:30:50 +0900435 setGatewayProviderInterNetworkRoutingWithinSameRouter(network, router, electedGateway, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900436 break;
437 case FLAT:
438 case VLAN:
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900439 setGatewayArpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900440 electedGateway.intgBridge(), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900441 setGatewayIcmpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
Daniel Parkcc8e7462021-03-09 13:37:42 +0900442 electedGateway.intgBridge(), install);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900443 setGatewayProviderInterNetworkRoutingWithinSameRouter(network, router, electedGateway, install);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900444 break;
445 default:
446 // do nothing
447 break;
448 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900449 }
450
Jian Li91358d62021-03-22 11:04:52 +0900451 private void setDefaultGatewayRuleToWorkerNodeTunBridge(KubevirtRouter router,
452 KubevirtNetwork network,
453 DeviceId gwDeviceId,
454 KubevirtNode workerNode,
455 boolean install) {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900456 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900457
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900458 if (routerMacAddress == null) {
459 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
460 "there's no br-int port for device {}", gwDeviceId);
461 return;
462 }
463
464 KubevirtNode gwNode = kubevirtNodeService.node(gwDeviceId);
465
466 if (gwNode == null) {
467 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
468 "there's no gateway node for device {}", gwDeviceId);
469 return;
470 }
471
472
473 PortNumber patchPortNumber = tunnelToTenantPort(workerNode, network);
474 if (patchPortNumber == null) {
475 return;
476 }
477
478 PortNumber tunnelPortNumber = tunnelPort(workerNode, network);
479 if (tunnelPortNumber == null) {
480 return;
481 }
482
483 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
484 .matchInPort(patchPortNumber)
485 .matchEthType(Ethernet.TYPE_IPV4)
486 .matchEthDst((routerMacAddress));
487
488 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
489 .setTunnelId(Long.parseLong(network.segmentId()))
490 .extension(buildExtension(
491 deviceService,
492 workerNode.tunBridge(),
493 gwNode.dataIp().getIp4Address()),
494 workerNode.tunBridge())
495 .setOutput(tunnelPortNumber);
496
497 flowService.setRule(
498 appId,
499 workerNode.tunBridge(),
500 sBuilder.build(),
501 tBuilder.build(),
502 PRIORITY_FORWARDING_RULE,
503 TUNNEL_DEFAULT_TABLE,
504 install);
505 }
506
507 private void setDefaultEgressRuleToGatewayNode(KubevirtRouter router,
508 KubevirtNetwork network,
509 DeviceId gwDeviceId,
510 boolean install) {
511 MacAddress routerMacAddress = getRouterMacAddress(router);
512
513 if (routerMacAddress == null) {
514 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
515 "there's no br-int port for device {}", gwDeviceId);
516 return;
517 }
518
519 KubevirtNode gwNode = kubevirtNodeService.node(gwDeviceId);
520
521 if (gwNode == null) {
522 log.warn("Setting gateway default eggress rule to gateway for tenant internal network because " +
523 "there's no gateway node for device {}", gwDeviceId);
524 return;
525 }
526
527 PortNumber tunToIntPortNum = portNumber(gwNode.tunBridge(), TUNNEL_TO_INTEGRATION);
528
529 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
530 .matchTunnelId(Long.parseLong(network.segmentId()));
531
532 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
533 .setOutput(tunToIntPortNum);
534
535 flowService.setRule(
536 appId,
537 gwNode.tunBridge(),
538 sBuilder.build(),
539 tBuilder.build(),
540 PRIORITY_TUNNEL_RULE,
541 TUNNEL_DEFAULT_TABLE,
542 install);
543 }
544
545
546 private void setGatewayIcmpRuleForTenantInternalNetwork(KubevirtRouter router,
547 KubevirtNetwork network,
548 int tableNum,
549 DeviceId gwDeviceId,
550 DeviceId tenantDeviceId,
551 boolean install) {
552 MacAddress routerMacAddress = getRouterMacAddress(router);
553
554 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900555 log.warn("Setting gateway ICMP rule for internal network because " +
556 "there's no br-int port for device {}", gwDeviceId);
557 return;
558 }
559
560 Device device = deviceService.getDevice(tenantDeviceId);
561
562 if (device == null) {
563 log.warn("Setting gateway icmp rule for internal network because " +
564 "there's no tenant device for {} to install gateway arp rule",
565 tenantDeviceId);
566 return;
567 }
568
569
570 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
571 .matchEthType(Ethernet.TYPE_IPV4)
572 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
573 .matchIcmpType(TYPE_ECHO_REQUEST)
574 .matchIcmpCode(CODE_ECHO_REQEUST)
575 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
576
577 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
578 .extension(buildMoveEthSrcToDstExtension(device), device.id())
579 .extension(buildMoveIpSrcToDstExtension(device), device.id())
580 .extension(buildLoadExtension(device,
581 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
582 .extension(buildLoadExtension(device,
583 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
584 .setIpSrc(network.gatewayIp())
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900585 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900586 .setOutput(PortNumber.IN_PORT);
587
588 flowService.setRule(
589 appId,
590 tenantDeviceId,
591 sBuilder.build(),
592 tBuilder.build(),
593 PRIORITY_ICMP_RULE,
594 tableNum,
595 install);
596 }
597
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900598 private void setGatewayArpRuleForTenantInternalNetwork(KubevirtRouter router,
599 KubevirtNetwork network,
600 int tableNum,
601 DeviceId gwDeviceId,
602 DeviceId tenantDeviceId,
603 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900604
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900605 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900606
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900607 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900608 log.warn("Setting gateway arp rule for internal network because " +
609 "there's no br-int port for device {}", gwDeviceId);
610 return;
611 }
612
613 Device device = deviceService.getDevice(tenantDeviceId);
614
615 if (device == null) {
616 log.warn("Setting gateway arp rule for internal network because " +
617 "there's no tenant device for {} to install gateway arp rule",
618 tenantDeviceId);
619 return;
620 }
621
622
623 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
624 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
625 .matchArpOp(ARP.OP_REQUEST)
626 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
627
628 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
629 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
630 .extension(buildMoveArpShaToThaExtension(device), device.id())
631 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
632 .setArpOp(ARP.OP_REPLY)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900633 .setArpSha(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900634 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900635 .setEthSrc(routerMacAddress)
Daniel Parkcc8e7462021-03-09 13:37:42 +0900636 .setOutput(PortNumber.IN_PORT);
637
638 flowService.setRule(
639 appId,
640 device.id(),
641 sBuilder.build(),
642 tBuilder.build(),
643 PRIORITY_ARP_GATEWAY_RULE,
644 tableNum,
645 install
646 );
647 }
648
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900649 private void setGatewayProviderInterNetworkRoutingWithinSameRouter(
Daniel Parkcc8e7462021-03-09 13:37:42 +0900650 KubevirtNetwork network, KubevirtRouter router, KubevirtNode gatewayNode, boolean install) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900651 router.internal().forEach(srcNetwork -> {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900652 if (srcNetwork.equals(network.networkId())
653 || kubevirtNetworkService.network(srcNetwork) == null) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900654 return;
655 }
656
Daniel Parkcc8e7462021-03-09 13:37:42 +0900657 kubevirtPortService.ports(network.networkId()).forEach(port -> {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900658 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +0900659 port, gatewayNode, install);
660 });
Daniel Parkb9a22022021-03-04 18:58:47 +0900661 });
662 }
663
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900664 private void setGatewayInterNetworkRoutingFromNetworkToPort(KubevirtRouter router,
665 KubevirtNetwork srcNetwork,
666 KubevirtPort dstPort,
667 KubevirtNode gatewayNode,
668 boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900669 Device gwDevice = deviceService.getDevice(gatewayNode.intgBridge());
670
671 if (gwDevice == null) {
672 log.warn("Failed to set internal network routing rule because " +
673 "there's no device Id for device {}", gatewayNode.intgBridge());
674 return;
675 }
676
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900677 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900678
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900679 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900680 log.warn("Failed to set internal network routing rule because " +
681 "there's no br-int port for device {}", gatewayNode.intgBridge());
682 return;
683 }
684
Daniel Park150b9622021-03-24 12:30:50 +0900685 TrafficSelector.Builder sBuilder;
686 TrafficTreatment treatment;
Daniel Parkcc8e7462021-03-09 13:37:42 +0900687
Daniel Park150b9622021-03-24 12:30:50 +0900688 if (srcNetwork.type() == FLAT || srcNetwork.type() == VLAN) {
689 sBuilder = DefaultTrafficSelector.builder()
690 .matchEthType(Ethernet.TYPE_IPV4)
691 .matchEthDst(routerMacAddress)
692 .matchIPSrc(IpPrefix.valueOf(srcNetwork.cidr()))
693 .matchIPDst(IpPrefix.valueOf(dstPort.ipAddress(), 32));
Daniel Parkcc8e7462021-03-09 13:37:42 +0900694
Daniel Park150b9622021-03-24 12:30:50 +0900695 treatment = DefaultTrafficTreatment.builder()
696 .setEthSrc(routerMacAddress)
697 .setEthDst(dstPort.macAddress())
698 .transition(FORWARDING_TABLE)
699 .build();
700
701 flowService.setRule(
702 appId,
703 gwDevice.id(),
704 sBuilder.build(),
705 treatment,
706 PRIORITY_INTERNAL_ROUTING_RULE,
707 PRE_FLAT_TABLE,
708 install);
709 } else {
710 KubevirtNetwork dstNetwork = kubevirtNetworkService.network(dstPort.networkId());
711 if (dstNetwork == null) {
712 return;
713 }
714
715 KubevirtNode dstPortWorkerNode = kubevirtNodeService.node(dstPort.deviceId());
716 if (dstPortWorkerNode == null) {
717 return;
718 }
719
720 sBuilder = DefaultTrafficSelector.builder()
721 .matchEthType(Ethernet.TYPE_IPV4)
722 .matchEthDst(routerMacAddress)
723 .matchTunnelId(Long.parseLong(srcNetwork.segmentId()))
724 .matchIPSrc(IpPrefix.valueOf(srcNetwork.cidr()))
725 .matchIPDst(IpPrefix.valueOf(dstPort.ipAddress(), 32));
726
727 treatment = DefaultTrafficTreatment.builder()
728 .setTunnelId(Long.parseLong(dstNetwork.segmentId()))
729 .setEthSrc(routerMacAddress)
730 .setEthDst(dstPort.macAddress())
731 .extension(buildExtension(
732 deviceService,
733 gatewayNode.tunBridge(),
734 dstPortWorkerNode.dataIp().getIp4Address()),
735 gatewayNode.tunBridge())
736 .setOutput(PortNumber.IN_PORT)
737 .build();
738
739 flowService.setRule(
740 appId,
741 gatewayNode.tunBridge(),
742 sBuilder.build(),
743 treatment,
744 PRIORITY_INTERNAL_ROUTING_RULE,
745 TUNNEL_DEFAULT_TABLE,
746 install);
747 }
Daniel Parkcc8e7462021-03-09 13:37:42 +0900748 }
749
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900750 private void setGatewayArpRuleForProviderInternalNetwork(KubevirtRouter router, KubevirtNetwork network,
751 int tableNum, DeviceId gwDeviceId, boolean install) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900752
753
754 Device device = deviceService.getDevice(gwDeviceId);
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900755 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkcc8e7462021-03-09 13:37:42 +0900756
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900757 if (routerMacAddress == null) {
Daniel Parkcc8e7462021-03-09 13:37:42 +0900758 log.warn("Setting gateway arp rule for internal network because " +
759 "there's no br-int port for device {}", gwDeviceId);
Daniel Parkb9a22022021-03-04 18:58:47 +0900760 return;
761 }
762
Jian Li543fe852021-02-04 17:25:01 +0900763 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
764 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
765 .matchArpOp(ARP.OP_REQUEST)
766 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
767
768 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
769 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
770 .extension(buildMoveArpShaToThaExtension(device), device.id())
771 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
772 .setArpOp(ARP.OP_REPLY)
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900773 .setArpSha(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900774 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900775 .setEthSrc(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900776 .setOutput(PortNumber.IN_PORT);
777
778 flowService.setRule(
779 appId,
780 device.id(),
781 sBuilder.build(),
782 tBuilder.build(),
783 PRIORITY_ARP_GATEWAY_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900784 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900785 install
786 );
787 }
788
Daniel Parkb9a22022021-03-04 18:58:47 +0900789 /**
790 * Sends ICMP echo reply for the ICMP echo request from the kubevirt VM.
791 *
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900792 * @param router kubevirt router
Daniel Parkb9a22022021-03-04 18:58:47 +0900793 * @param network kubevirt network
794 * @param tableNum flow table number
795 * @param deviceId device id of the selected gateway for the network
796 * @param install install if true, remove otherwise
797 */
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900798 private void setGatewayIcmpRuleForProviderInternalNetwork(KubevirtRouter router, KubevirtNetwork network,
799 int tableNum, DeviceId deviceId, boolean install) {
800 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Parkb9a22022021-03-04 18:58:47 +0900801
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900802 if (routerMacAddress == null) {
Daniel Parkb9a22022021-03-04 18:58:47 +0900803 log.error("Setting gateway ICMP rule for internal network because " +
804 "there's no br-int port for device {}", deviceId);
805 return;
806 }
807
Jian Li543fe852021-02-04 17:25:01 +0900808 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
809 .matchEthType(Ethernet.TYPE_IPV4)
810 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
811 .matchIcmpType(TYPE_ECHO_REQUEST)
812 .matchIcmpCode(CODE_ECHO_REQEUST)
813 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
814
815 Device device = deviceService.getDevice(deviceId);
816 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
817 .extension(buildMoveEthSrcToDstExtension(device), device.id())
818 .extension(buildMoveIpSrcToDstExtension(device), device.id())
819 .extension(buildLoadExtension(device,
820 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
821 .extension(buildLoadExtension(device,
822 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
823 .setIpSrc(network.gatewayIp())
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900824 .setEthSrc(routerMacAddress)
Jian Li543fe852021-02-04 17:25:01 +0900825 .setOutput(PortNumber.IN_PORT);
826
827 flowService.setRule(
828 appId,
829 deviceId,
830 sBuilder.build(),
831 tBuilder.build(),
832 PRIORITY_ICMP_RULE,
Daniel Park4063f402021-02-25 09:14:22 +0900833 tableNum,
Jian Li543fe852021-02-04 17:25:01 +0900834 install);
835 }
836
Daniel Parkb9a22022021-03-04 18:58:47 +0900837 private class InternalRouterEventListener implements KubevirtRouterListener {
838 private boolean isRelevantHelper() {
839 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park4063f402021-02-25 09:14:22 +0900840 }
841
Daniel Parkb9a22022021-03-04 18:58:47 +0900842 @Override
843 public void event(KubevirtRouterEvent event) {
844 switch (event.type()) {
845 case KUBEVIRT_ROUTER_CREATED:
846 eventExecutor.execute(() -> processRouterCreation(event.subject()));
847 break;
848 case KUBEVIRT_ROUTER_REMOVED:
849 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
850 break;
851 case KUBEVIRT_ROUTER_UPDATED:
852 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
853 break;
854 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
855 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
856 event.internal()));
857 break;
858 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
859 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
860 event.internal()));
861 break;
862 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
863 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
864 event.gateway()));
865 break;
866 case KUBEVIRT_GATEWAY_NODE_DETACHED:
867 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
868 event.gateway()));
869 break;
870 case KUBEVIRT_GATEWAY_NODE_CHANGED:
871 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
872 event.gateway()));
873 break;
Daniel Park4063f402021-02-25 09:14:22 +0900874
Daniel Parkb9a22022021-03-04 18:58:47 +0900875 default:
876 //do nothing
877 break;
878 }
879 }
880
881 private void processRouterCreation(KubevirtRouter router) {
882 // When a router is created, we performs the election process to associate the router
883 // to the specific gateway. After the election, KubevirtNetwork handler installs bunch of rules
884 // to elected gateway node so that VMs associated to the router can ping to their gateway IP.
885 // SNAT and floating ip rule setup is out of this handler's scope and would be done with the other handlers
886 if (!isRelevantHelper()) {
887 return;
888 }
889 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
890 if (electedGw == null) {
891 return;
892 }
893
894 router.internal().forEach(networkName -> {
895 KubevirtNetwork network = networkService.network(networkName);
896
897 if (network != null) {
898 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
899 }
900 });
901 kubevirtRouterService.updateRouter(router.updatedElectedGateway(electedGw.hostname()));
902 }
903
904 private void processRouterDeletion(KubevirtRouter router) {
905 if (!isRelevantHelper()) {
906 return;
907 }
908 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
909 if (electedGw == null) {
910 return;
911 }
912
913 router.internal().forEach(networkName -> {
914 KubevirtNetwork network = networkService.network(networkName);
915
916 if (network != null) {
917 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
918 }
919 });
920 }
921
922 private void processRouterUpdate(KubevirtRouter router) {
923 if (!isRelevantHelper()) {
924 return;
925 }
926 if (router.electedGateway() == null) {
927 return;
928 }
929
930 KubevirtNode electedGw = nodeService.node(router.electedGateway());
931
932 router.internal().forEach(networkName -> {
933 KubevirtNetwork network = networkService.network(networkName);
934
935 if (network != null) {
936 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
937 }
938 });
939 }
940
941 private void processRouterInternalNetworksAttached(KubevirtRouter router,
942 Set<String> attachedInternalNetworks) {
943 if (!isRelevantHelper()) {
944 return;
945 }
946 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
947 if (electedGw == null) {
948 return;
949 }
950
951 attachedInternalNetworks.forEach(networkName -> {
952 KubevirtNetwork network = networkService.network(networkName);
953
954 if (network != null) {
955 initGatewayNodeForInternalNetwork(network, router, electedGw, true);
956 }
957 });
958 }
959
960 private void processRouterInternalNetworksDetached(KubevirtRouter router,
961 Set<String> detachedInternalNetworks) {
962 if (!isRelevantHelper()) {
963 return;
964 }
965 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(nodeService, router);
966 if (electedGw == null) {
967 return;
968 }
969
970 detachedInternalNetworks.forEach(networkName -> {
971 KubevirtNetwork network = networkService.network(networkName);
972
973 if (network != null) {
974 initGatewayNodeForInternalNetwork(network, router, electedGw, false);
975 }
Daniel Parkb9a22022021-03-04 18:58:47 +0900976
Daniel Parkcc8e7462021-03-09 13:37:42 +0900977 removeDetachedInternalNetworkRules(network, router, electedGw);
978 });
979 }
980
981 private void removeDetachedInternalNetworkRules(KubevirtNetwork removedNetwork, KubevirtRouter router,
982 KubevirtNode electedGw) {
Daniel Parke7e3d6a2021-03-10 07:49:11 +0900983 router.internal().stream().filter(networkId -> kubevirtNetworkService.network(networkId) != null)
984 .forEach(networkId -> {
985 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
986 setGatewayInterNetworkRoutingFromNetworkToPort(
987 router, removedNetwork, kubevirtPort, electedGw, false);
988 });
Daniel Parkcc8e7462021-03-09 13:37:42 +0900989 });
Daniel Parkb9a22022021-03-04 18:58:47 +0900990 }
991
992 private void processRouterGatewayNodeAttached(KubevirtRouter router,
993 String associatedGateway) {
994 if (!isRelevantHelper()) {
995 return;
996 }
997
998 KubevirtNode gatewayNode = nodeService.node(associatedGateway);
999 if (gatewayNode == null) {
1000 return;
1001 }
1002
1003 router.internal().forEach(networkName -> {
1004 KubevirtNetwork network = networkService.network(networkName);
1005
1006 if (network != null) {
1007 initGatewayNodeForInternalNetwork(network, router, gatewayNode, true);
1008 }
1009 });
1010 }
1011
1012 private void processRouterGatewayNodeDetached(KubevirtRouter router,
1013 String disAssociatedGateway) {
1014 if (!isRelevantHelper()) {
1015 return;
1016 }
1017
1018 KubevirtNode gatewayNode = nodeService.node(disAssociatedGateway);
1019 if (gatewayNode == null) {
1020 return;
1021 }
1022
1023 router.internal().forEach(networkName -> {
1024 KubevirtNetwork network = networkService.network(networkName);
1025
1026 if (network != null) {
1027 initGatewayNodeForInternalNetwork(network, router, gatewayNode, false);
1028 }
1029 });
1030 }
1031
1032 private void processRouterGatewayNodeChanged(KubevirtRouter router,
1033 String disAssociatedGateway) {
1034 if (!isRelevantHelper()) {
1035 return;
1036 }
1037
1038 KubevirtNode oldGatewayNode = nodeService.node(disAssociatedGateway);
1039 if (oldGatewayNode == null) {
1040 return;
1041 }
1042
1043 router.internal().forEach(networkName -> {
1044 KubevirtNetwork network = networkService.network(networkName);
1045
1046 if (network != null) {
1047 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, false);
1048 }
1049 });
1050
1051 KubevirtNode newGatewayNode = nodeService.node(router.electedGateway());
1052 if (newGatewayNode == null) {
1053 return;
1054 }
1055
1056 router.internal().forEach(networkName -> {
1057 KubevirtNetwork network = networkService.network(networkName);
1058
1059 if (network != null) {
1060 initGatewayNodeForInternalNetwork(network, router, oldGatewayNode, true);
1061 }
1062 });
1063 }
Daniel Park4063f402021-02-25 09:14:22 +09001064 }
1065
Jian Lib5ab63c2021-02-03 17:54:28 +09001066 private class InternalNetworkEventListener implements KubevirtNetworkListener {
1067
1068 private boolean isRelevantHelper() {
1069 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1070 }
1071
1072 @Override
1073 public void event(KubevirtNetworkEvent event) {
1074 switch (event.type()) {
1075 case KUBEVIRT_NETWORK_CREATED:
1076 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
1077 break;
1078 case KUBEVIRT_NETWORK_REMOVED:
1079 eventExecutor.execute(() -> processNetworkRemoval(event.subject()));
1080 break;
1081 case KUBEVIRT_NETWORK_UPDATED:
1082 default:
1083 // do nothing
1084 break;
1085 }
1086 }
1087
1088 private void processNetworkCreation(KubevirtNetwork network) {
1089 if (!isRelevantHelper()) {
1090 return;
1091 }
1092
1093 switch (network.type()) {
1094 case VXLAN:
1095 case GRE:
1096 case GENEVE:
1097 initIntegrationTunnelBridge(network);
1098 break;
1099 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +09001100 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001101 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001102 default:
1103 // do nothing
1104 break;
1105 }
1106 }
1107
1108 private void processNetworkRemoval(KubevirtNetwork network) {
1109 if (!isRelevantHelper()) {
1110 return;
1111 }
1112
1113 switch (network.type()) {
1114 case VXLAN:
1115 case GRE:
1116 case GENEVE:
1117 purgeIntegrationTunnelBridge(network);
1118 break;
1119 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +09001120 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001121 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001122 default:
1123 // do nothing
1124 break;
1125 }
1126 }
1127
1128 private void initIntegrationTunnelBridge(KubevirtNetwork network) {
1129 if (network.segmentId() == null) {
1130 return;
1131 }
1132
1133 nodeService.completeNodes().forEach(n -> {
1134 createBridge(n, network);
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001135 createPatchTenantInterface(n, network);
1136 setDefaultRulesForTenantNetwork(n, network);
Jian Lib5ab63c2021-02-03 17:54:28 +09001137 });
1138 }
1139
1140 private void purgeIntegrationTunnelBridge(KubevirtNetwork network) {
1141 if (network.segmentId() == null) {
1142 return;
1143 }
1144
1145 nodeService.completeNodes().forEach(n -> {
1146 removePatchInterface(n, network);
1147 removeBridge(n, network);
1148 });
1149 }
1150 }
1151
1152 private class InternalNodeEventListener implements KubevirtNodeListener {
1153
1154 private boolean isRelevantHelper() {
1155 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1156 }
1157
1158 @Override
1159 public void event(KubevirtNodeEvent event) {
1160 switch (event.type()) {
1161 case KUBEVIRT_NODE_COMPLETE:
1162 eventExecutor.execute(() -> processNodeCompletion(event.subject()));
1163 break;
Daniel Parkb9a22022021-03-04 18:58:47 +09001164 case KUBEVIRT_NODE_REMOVED:
1165 eventExecutor.execute(() -> processNodeDeletion(event.subject()));
1166 break;
Jian Lib5ab63c2021-02-03 17:54:28 +09001167 case KUBEVIRT_NODE_INCOMPLETE:
1168 case KUBEVIRT_NODE_UPDATED:
1169 default:
1170 // do nothing
1171 break;
1172 }
1173 }
1174
1175 private void processNodeCompletion(KubevirtNode node) {
1176 if (!isRelevantHelper()) {
1177 return;
1178 }
1179
Daniel Park4063f402021-02-25 09:14:22 +09001180 if (node.type().equals(WORKER)) {
1181 for (KubevirtNetwork network : networkService.networks()) {
1182 switch (network.type()) {
1183 case VXLAN:
1184 case GRE:
1185 case GENEVE:
1186 if (network.segmentId() == null) {
1187 continue;
1188 }
1189 createBridge(node, network);
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001190 createPatchTenantInterface(node, network);
1191 setDefaultRulesForTenantNetwork(node, network);
1192 setArpRulesForTenantNetwork(node, network);
1193 setIcmpRulesForTenantNetwork(node, network);
1194 setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(node, network);
Daniel Park4063f402021-02-25 09:14:22 +09001195 break;
1196 case FLAT:
1197 case VLAN:
1198 default:
1199 // do nothing
1200 break;
1201 }
1202 }
1203 } else if (node.type().equals(GATEWAY)) {
Daniel Parkb9a22022021-03-04 18:58:47 +09001204 updateGatewayNodeForRouter();
Daniel Park4063f402021-02-25 09:14:22 +09001205 for (KubevirtNetwork network : networkService.networks()) {
1206 switch (network.type()) {
1207 case FLAT:
1208 case VLAN:
Daniel Park4063f402021-02-25 09:14:22 +09001209 break;
1210 case VXLAN:
1211 case GRE:
1212 case GENEVE:
1213 default:
1214 // do nothing
1215 break;
1216 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001217 }
1218 }
1219 }
Daniel Parkb9a22022021-03-04 18:58:47 +09001220
1221 private void processNodeDeletion(KubevirtNode node) {
1222 if (!isRelevantHelper()) {
1223 return;
1224 }
1225
1226 if (node.type().equals(GATEWAY)) {
1227 updateGatewayNodeForRouter();
1228 for (KubevirtNetwork network : networkService.networks()) {
1229 switch (network.type()) {
1230 case FLAT:
1231 case VLAN:
1232 break;
1233 case VXLAN:
1234 case GRE:
1235 case GENEVE:
1236 default:
1237 // do nothing
1238 break;
1239 }
1240 }
1241 }
1242 }
1243
1244 private void updateGatewayNodeForRouter() {
1245 kubevirtRouterService.routers().forEach(router -> {
1246 KubevirtNode newGwNode = gatewayNodeForSpecifiedRouter(nodeService, router);
1247
1248 if (newGwNode == null) {
1249 return;
1250 }
1251 kubevirtRouterService.updateRouter(router.updatedElectedGateway(newGwNode.hostname()));
1252 });
1253 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001254 }
Daniel Parkcc8e7462021-03-09 13:37:42 +09001255
1256 private class InternalKubevirtPortListener implements KubevirtPortListener {
1257
1258 private boolean isRelevantHelper() {
1259 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1260 }
1261
1262 @Override
1263 public void event(KubevirtPortEvent event) {
1264 switch (event.type()) {
1265 case KUBEVIRT_PORT_CREATED:
1266 eventExecutor.execute(() -> processPortCreation(event.subject()));
1267 break;
1268 case KUBEVIRT_PORT_UPDATED:
1269 eventExecutor.execute(() -> processPortUpdate(event.subject()));
1270 break;
1271 case KUBEVIRT_PORT_REMOVED:
1272 eventExecutor.execute(() -> processPortDeletion(event.subject()));
1273 break;
1274 default:
1275 //do nothing
1276 break;
1277 }
1278 }
1279
1280 private void processPortCreation(KubevirtPort kubevirtPort) {
1281 if (!isRelevantHelper()) {
1282 return;
1283 }
1284
1285 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1286 if (router == null) {
1287 return;
1288 }
1289
1290 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1291
1292 if (gwNode != null) {
1293
1294 router.internal().forEach(srcNetwork -> {
1295 if (srcNetwork.equals(kubevirtPort.networkId())
1296 || kubevirtNetworkService.network(srcNetwork) == null) {
1297 return;
1298 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001299 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001300 kubevirtPort, gwNode, true);
1301 });
1302 }
1303 }
1304
1305 private void processPortUpdate(KubevirtPort kubevirtPort) {
1306 if (!isRelevantHelper()) {
1307 return;
1308 }
1309
1310 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1311 if (router == null) {
1312 return;
1313 }
1314
1315 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1316
1317 if (gwNode != null) {
1318
1319 router.internal().forEach(srcNetwork -> {
1320 if (srcNetwork.equals(kubevirtPort.networkId())
1321 || kubevirtNetworkService.network(srcNetwork) == null) {
1322 return;
1323 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001324 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001325 kubevirtPort, gwNode, true);
1326 });
1327 }
1328 }
1329
1330 private void processPortDeletion(KubevirtPort kubevirtPort) {
1331 if (!isRelevantHelper()) {
1332 return;
1333 }
1334
1335 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
1336 if (router == null) {
1337 return;
1338 }
1339
1340 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
1341
1342 if (gwNode != null) {
1343
1344 router.internal().forEach(srcNetwork -> {
1345 if (srcNetwork.equals(kubevirtPort.networkId())
1346 || kubevirtNetworkService.network(srcNetwork) == null) {
1347 return;
1348 }
Daniel Parke7e3d6a2021-03-10 07:49:11 +09001349 setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
Daniel Parkcc8e7462021-03-09 13:37:42 +09001350 kubevirtPort, gwNode, false);
1351 });
1352 }
1353
1354 }
1355 }
Jian Lib5ab63c2021-02-03 17:54:28 +09001356}