blob: 9acf35e7e5a749f8dc300752e20b59933a84a798 [file] [log] [blame]
Daniel Park2884b232021-03-04 18:58:47 +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 org.onlab.packet.ARP;
19import org.onlab.packet.EthType;
20import org.onlab.packet.Ethernet;
21import org.onlab.packet.Ip4Address;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.IpPrefix;
24import org.onlab.packet.MacAddress;
25import org.onlab.packet.TpPort;
Daniel Parkf3136042021-03-10 07:49:11 +090026import org.onlab.packet.VlanId;
Daniel Park2884b232021-03-04 18:58:47 +090027import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.LeadershipService;
29import org.onosproject.cluster.NodeId;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
33import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
Daniel Park2884b232021-03-04 18:58:47 +090034import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
35import org.onosproject.kubevirtnetworking.api.KubevirtPort;
36import org.onosproject.kubevirtnetworking.api.KubevirtPortEvent;
37import org.onosproject.kubevirtnetworking.api.KubevirtPortListener;
38import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
39import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
40import org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent;
41import org.onosproject.kubevirtnetworking.api.KubevirtRouterListener;
42import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
43import org.onosproject.kubevirtnetworking.util.RulePopulatorUtil;
44import org.onosproject.kubevirtnode.api.KubevirtNode;
45import org.onosproject.kubevirtnode.api.KubevirtNodeService;
46import org.onosproject.net.Device;
Daniel Park2884b232021-03-04 18:58:47 +090047import org.onosproject.net.PortNumber;
48import org.onosproject.net.device.DeviceAdminService;
49import org.onosproject.net.driver.DriverService;
50import org.onosproject.net.flow.DefaultTrafficSelector;
51import org.onosproject.net.flow.DefaultTrafficTreatment;
52import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
54import org.onosproject.net.flow.instructions.ExtensionTreatment;
Daniel Park157947f2021-04-09 17:50:53 +090055import org.onosproject.net.packet.DefaultOutboundPacket;
56import org.onosproject.net.packet.PacketService;
Daniel Park2884b232021-03-04 18:58:47 +090057import org.osgi.service.component.annotations.Activate;
58import org.osgi.service.component.annotations.Component;
59import org.osgi.service.component.annotations.Deactivate;
60import org.osgi.service.component.annotations.Reference;
61import org.osgi.service.component.annotations.ReferenceCardinality;
62import org.slf4j.Logger;
63
Daniel Park157947f2021-04-09 17:50:53 +090064import java.nio.ByteBuffer;
Daniel Park2884b232021-03-04 18:58:47 +090065import java.util.Objects;
66import java.util.Set;
67import java.util.concurrent.ExecutorService;
68
69import static java.util.concurrent.Executors.newSingleThreadExecutor;
70import static org.onlab.util.Tools.groupedThreads;
71import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
72import static org.onosproject.kubevirtnetworking.api.Constants.FLAT_TABLE;
73import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
74import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
75import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
76import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Daniel Parkf3136042021-03-10 07:49:11 +090077import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
Daniel Park2884b232021-03-04 18:58:47 +090078import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
Daniel Parkf3136042021-03-10 07:49:11 +090079import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
80import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
81import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
82import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
83import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
Daniel Park157947f2021-04-09 17:50:53 +090084import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.buildGarpPacket;
Daniel Parkf3136042021-03-10 07:49:11 +090085import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.externalPatchPortNum;
Daniel Park2884b232021-03-04 18:58:47 +090086import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
Daniel Parkbabde9c2021-03-09 13:37:42 +090087import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtPort;
Daniel Parkf3136042021-03-10 07:49:11 +090088import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
Daniel Park5a3e9392021-03-23 08:00:00 +090089import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterSnatIpAddress;
Daniel Parkf3136042021-03-10 07:49:11 +090090import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
Daniel Park2884b232021-03-04 18:58:47 +090091import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Daniel Parkf3136042021-03-10 07:49:11 +090092import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
Daniel Park2884b232021-03-04 18:58:47 +090093import static org.slf4j.LoggerFactory.getLogger;
94
95/**
96 * Handles kubevirt routing snat.
97 */
98
99@Component(immediate = true)
100public class KubevirtRoutingSnatHandler {
101 protected final Logger log = getLogger(getClass());
102 private static final int DEFAULT_TTL = 0xff;
103
104 private static final int TP_PORT_MINIMUM_NUM = 1025;
105 private static final int TP_PORT_MAXIMUM_NUM = 65535;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
108 protected CoreService coreService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
111 protected ClusterService clusterService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
114 protected LeadershipService leadershipService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
117 protected DeviceAdminService deviceService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
120 protected KubevirtPortService kubevirtPortService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
123 protected KubevirtNodeService kubevirtNodeService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
126 protected KubevirtNetworkService kubevirtNetworkService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
129 protected KubevirtFlowRuleService flowService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
132 protected DriverService driverService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park157947f2021-04-09 17:50:53 +0900135 protected PacketService packetService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park2884b232021-03-04 18:58:47 +0900138 protected KubevirtRouterService kubevirtRouterService;
139
140 private final ExecutorService eventExecutor = newSingleThreadExecutor(
141 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
142
143 private final InternalKubevirtPortListener kubevirtPortListener =
144 new InternalKubevirtPortListener();
145
146 private final InternalRouterEventListener kubevirtRouterlistener =
147 new InternalRouterEventListener();
148
Daniel Park2884b232021-03-04 18:58:47 +0900149 private ApplicationId appId;
150 private NodeId localNodeId;
151
152 @Activate
153 protected void activate() {
154 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
155 localNodeId = clusterService.getLocalNode().id();
156 leadershipService.runForLeadership(appId.name());
157
158 kubevirtPortService.addListener(kubevirtPortListener);
159 kubevirtRouterService.addListener(kubevirtRouterlistener);
Daniel Park2884b232021-03-04 18:58:47 +0900160
161 log.info("Started");
162 }
163
164 @Deactivate
165 protected void deactivate() {
166 leadershipService.withdraw(appId.name());
167 kubevirtPortService.removeListener(kubevirtPortListener);
168 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Daniel Park2884b232021-03-04 18:58:47 +0900169
170 eventExecutor.shutdown();
171
172 log.info("Stopped");
173 }
174
Daniel Park157947f2021-04-09 17:50:53 +0900175 private void initGatewayNodeSnatForRouter(KubevirtRouter router, String gateway, boolean install) {
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900176 if (router.electedGateway() == null) {
177 log.warn("Fail to initialize gateway node snat for router {} " +
178 "because there's no gateway assigned to it", router.name());
179 return;
180 }
181
Daniel Park157947f2021-04-09 17:50:53 +0900182 KubevirtNode electedGw = kubevirtNodeService.node(gateway);
Daniel Park2884b232021-03-04 18:58:47 +0900183 if (electedGw == null) {
184 log.warn("Fail to initialize gateway node snat for router {} " +
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900185 "because there's no gateway assigned to it", router.name());
Daniel Park2884b232021-03-04 18:58:47 +0900186 return;
187 }
188
189 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
190
191 if (routerSnatIp == null) {
192 log.warn("Fail to initialize gateway node snat for router {} " +
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900193 "because there's no gateway snat ip assigned to it", router.name());
Daniel Park2884b232021-03-04 18:58:47 +0900194 return;
195 }
196
Daniel Park5a3e9392021-03-23 08:00:00 +0900197 String externalNet = router.external().values().stream().findAny().orElse(null);
198 if (externalNet == null) {
199 return;
200 }
201
202 if (router.peerRouter() != null &&
203 router.peerRouter().ipAddress() != null && router.peerRouter().macAddress() != null) {
204 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(routerSnatIp), install);
205 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(routerSnatIp),
206 router.peerRouter().macAddress(), install);
207 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(routerSnatIp),
208 kubevirtNetworkService.network(externalNet), install);
209 }
Daniel Park2884b232021-03-04 18:58:47 +0900210 }
211
212 private void setArpResponseToPeerRouter(KubevirtNode gatewayNode, Ip4Address ip4Address, boolean install) {
213
214 TrafficSelector selector = DefaultTrafficSelector.builder()
Daniel Parkf3136042021-03-10 07:49:11 +0900215 .matchInPort(externalPatchPortNum(deviceService, gatewayNode))
Daniel Park2884b232021-03-04 18:58:47 +0900216 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
217 .matchArpOp(ARP.OP_REQUEST)
218 .matchArpTpa(ip4Address)
219 .build();
220
221 Device device = deviceService.getDevice(gatewayNode.intgBridge());
222
223 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
224 .extension(RulePopulatorUtil.buildMoveEthSrcToDstExtension(device), device.id())
225 .extension(RulePopulatorUtil.buildMoveArpShaToThaExtension(device), device.id())
226 .extension(RulePopulatorUtil.buildMoveArpSpaToTpaExtension(device), device.id())
227 .setArpOp(ARP.OP_REPLY)
228 .setEthSrc(DEFAULT_GATEWAY_MAC)
229 .setArpSha(DEFAULT_GATEWAY_MAC)
230 .setArpSpa(ip4Address)
231 .setOutput(PortNumber.IN_PORT)
232 .build();
233
234 flowService.setRule(
235 appId,
236 gatewayNode.intgBridge(),
237 selector,
238 treatment,
239 PRIORITY_ARP_GATEWAY_RULE,
240 PRE_FLAT_TABLE,
241 install);
242 }
243
Daniel Parkf3136042021-03-10 07:49:11 +0900244 private void setStatefulSnatUpstreamRules(KubevirtNode gatewayNode,
245 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900246 Ip4Address routerSnatIp,
247 MacAddress peerRouterMacAddress,
Daniel Parkf3136042021-03-10 07:49:11 +0900248 boolean install) {
249 MacAddress routerMacAddress = getRouterMacAddress(router);
250 if (routerMacAddress == null) {
251 return;
252 }
Daniel Park5a3e9392021-03-23 08:00:00 +0900253
254 if (routerSnatIp == null || peerRouterMacAddress == null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900255 return;
256 }
Daniel Park2884b232021-03-04 18:58:47 +0900257
Daniel Parkf3136042021-03-10 07:49:11 +0900258 TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
Daniel Park2884b232021-03-04 18:58:47 +0900259 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900260 .matchEthDst(routerMacAddress);
Daniel Park2884b232021-03-04 18:58:47 +0900261
262 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
263
264 ExtensionTreatment natTreatment = RulePopulatorUtil
265 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
266 .commit(true)
267 .natFlag(CT_NAT_SRC_FLAG)
268 .natAction(true)
Daniel Park5a3e9392021-03-23 08:00:00 +0900269 .natIp(routerSnatIp)
Daniel Park2884b232021-03-04 18:58:47 +0900270 .natPortMin(TpPort.tpPort(TP_PORT_MINIMUM_NUM))
271 .natPortMax(TpPort.tpPort(TP_PORT_MAXIMUM_NUM))
272 .build();
273
274 tBuilder.extension(natTreatment, gatewayNode.intgBridge())
Daniel Park5a3e9392021-03-23 08:00:00 +0900275 .setEthDst(peerRouterMacAddress)
Daniel Park2884b232021-03-04 18:58:47 +0900276 .setEthSrc(DEFAULT_GATEWAY_MAC)
Daniel Parkf3136042021-03-10 07:49:11 +0900277 .setOutput(externalPatchPortNum(deviceService, gatewayNode));
Daniel Park2884b232021-03-04 18:58:47 +0900278
279 flowService.setRule(
280 appId,
281 gatewayNode.intgBridge(),
Daniel Parkf3136042021-03-10 07:49:11 +0900282 selector.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900283 tBuilder.build(),
284 PRIORITY_STATEFUL_SNAT_RULE,
Daniel Parkf3136042021-03-10 07:49:11 +0900285 PRE_FLAT_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900286 install);
287 }
288
Daniel Parkf3136042021-03-10 07:49:11 +0900289 private void setStatefulSnatDownStreamRuleForKubevirtPort(KubevirtRouter router,
290 KubevirtNode gatewayNode,
291 KubevirtPort kubevirtPort,
292 boolean install) {
293 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Park2884b232021-03-04 18:58:47 +0900294
Daniel Parkf3136042021-03-10 07:49:11 +0900295 if (routerMacAddress == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900296 log.error("Failed to set stateful snat downstream rule because " +
297 "there's no br-int port for device {}", gatewayNode.intgBridge());
298 return;
299 }
300
301 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
302 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900303 .matchEthSrc(routerMacAddress)
Daniel Park2884b232021-03-04 18:58:47 +0900304 .matchIPDst(IpPrefix.valueOf(kubevirtPort.ipAddress(), 32));
305
Daniel Parkf3136042021-03-10 07:49:11 +0900306 KubevirtNetwork network = kubevirtNetworkService.network(kubevirtPort.networkId());
307
308 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Daniel Park2884b232021-03-04 18:58:47 +0900309 .setEthDst(kubevirtPort.macAddress())
Daniel Parkf3136042021-03-10 07:49:11 +0900310 .transition(FORWARDING_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900311
312 flowService.setRule(
313 appId,
314 gatewayNode.intgBridge(),
315 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900316 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900317 PRIORITY_STATEFUL_SNAT_RULE,
318 FLAT_TABLE,
319 install);
Daniel Parkf3136042021-03-10 07:49:11 +0900320
321 if (network.type() == VXLAN || network.type() == GENEVE || network.type() == GRE) {
322 setDownStreamRulesToGatewayTunBridge(router, network, kubevirtPort, install);
323 }
Daniel Park2884b232021-03-04 18:58:47 +0900324 }
325
Daniel Parkf3136042021-03-10 07:49:11 +0900326 private void setDownStreamRulesToGatewayTunBridge(KubevirtRouter router,
327 KubevirtNetwork network,
328 KubevirtPort port, boolean install) {
329 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
Daniel Park2884b232021-03-04 18:58:47 +0900330
Daniel Parkf3136042021-03-10 07:49:11 +0900331 if (electedGw == null) {
332 return;
333 }
Daniel Park2884b232021-03-04 18:58:47 +0900334
Daniel Parkf3136042021-03-10 07:49:11 +0900335 KubevirtNode workerNode = kubevirtNodeService.node(port.deviceId());
336 if (workerNode == null) {
337 return;
338 }
339
340 PortNumber tunnelPortNumber = tunnelPort(electedGw, network);
341 if (tunnelPortNumber == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900342 return;
343 }
344
345 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
346 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900347 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
348 .matchEthDst(port.macAddress());
349
350 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
351 .setTunnelId(Long.parseLong(network.segmentId()))
352 .extension(buildExtension(
353 deviceService,
354 electedGw.tunBridge(),
355 workerNode.dataIp().getIp4Address()),
356 electedGw.tunBridge())
357 .setOutput(tunnelPortNumber);
358
359 flowService.setRule(
360 appId,
361 electedGw.tunBridge(),
362 sBuilder.build(),
363 tBuilder.build(),
364 PRIORITY_FORWARDING_RULE,
365 TUNNEL_DEFAULT_TABLE,
366 install);
367 }
368
369 private void setStatefulSnatDownstreamRuleForRouter(KubevirtNode gatewayNode,
370 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900371 IpAddress routerSnatIp,
372 KubevirtNetwork externalNetwork,
Daniel Parkf3136042021-03-10 07:49:11 +0900373 boolean install) {
374
375 MacAddress routerMacAddress = getRouterMacAddress(router);
376
377 if (routerMacAddress == null) {
378 log.warn("Failed to set stateful snat downstream rule because " +
379 "there's no br-int port for device {}", gatewayNode.intgBridge());
380 return;
381 }
382
Daniel Parkf3136042021-03-10 07:49:11 +0900383 if (externalNetwork == null) {
384 log.warn("Failed to set stateful snat downstream rule because " +
385 "there's no external network router {}", router.name());
386 return;
387 }
388
389 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
390 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
391
392 if (externalNetwork.type() == VLAN) {
393 sBuilder.matchEthType(Ethernet.TYPE_VLAN)
394 .matchVlanId(VlanId.vlanId(externalNetwork.segmentId()));
395 tBuilder.popVlan();
396 } else {
397 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
398 }
399
Daniel Park5a3e9392021-03-23 08:00:00 +0900400 sBuilder.matchIPDst(IpPrefix.valueOf(routerSnatIp, 32));
Daniel Park2884b232021-03-04 18:58:47 +0900401
402 ExtensionTreatment natTreatment = RulePopulatorUtil
403 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
404 .commit(false)
405 .natAction(true)
Daniel Parkbabde9c2021-03-09 13:37:42 +0900406 .table((short) FLAT_TABLE)
Daniel Park2884b232021-03-04 18:58:47 +0900407 .build();
408
Daniel Parkf3136042021-03-10 07:49:11 +0900409 tBuilder.setEthSrc(routerMacAddress)
410 .extension(natTreatment, gatewayNode.intgBridge());
Daniel Park2884b232021-03-04 18:58:47 +0900411
412 flowService.setRule(
413 appId,
414 gatewayNode.intgBridge(),
415 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900416 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900417 PRIORITY_STATEFUL_SNAT_RULE,
Daniel Parkf3136042021-03-10 07:49:11 +0900418 PRE_FLAT_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900419 install);
Daniel Park2884b232021-03-04 18:58:47 +0900420 }
421
422 private class InternalRouterEventListener implements KubevirtRouterListener {
423 private boolean isRelevantHelper() {
424 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
425 }
426
427 @Override
428 public void event(KubevirtRouterEvent event) {
429 switch (event.type()) {
430 case KUBEVIRT_ROUTER_CREATED:
431 eventExecutor.execute(() -> processRouterCreation(event.subject()));
432 break;
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900433 case KUBEVIRT_SNAT_STATUS_DISABLED:
Daniel Park2884b232021-03-04 18:58:47 +0900434 case KUBEVIRT_ROUTER_REMOVED:
435 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
436 break;
437 case KUBEVIRT_ROUTER_UPDATED:
438 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
439 break;
440 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
441 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
442 event.internal()));
443 break;
444 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
445 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
446 event.internal()));
447 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900448 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
449 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
450 event.gateway()));
451 break;
452 case KUBEVIRT_GATEWAY_NODE_DETACHED:
453 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
454 event.gateway()));
455 break;
Daniel Park157947f2021-04-09 17:50:53 +0900456 case KUBEVIRT_GATEWAY_NODE_CHANGED:
457 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
458 event.gateway()));
459 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900460 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900461 eventExecutor.execute(() -> processRouterExternalNetAttached(event.subject(),
462 event.externalIp(), event.externalNet(),
463 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900464 break;
465 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900466 eventExecutor.execute(() -> processRouterExternalNetDetached(event.subject(),
467 event.externalIp(), event.externalNet(),
468 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900469 break;
Daniel Park2884b232021-03-04 18:58:47 +0900470 default:
471 //do nothing
472 break;
473 }
474 }
Daniel Parkf3136042021-03-10 07:49:11 +0900475
Daniel Park5a3e9392021-03-23 08:00:00 +0900476 private void processRouterExternalNetAttached(KubevirtRouter router, String externalIp, String externalNet,
477 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900478 if (!isRelevantHelper()) {
479 return;
480 }
481 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
482
483 if (electedGw == null) {
484 log.warn("Fail to process router external network attached gateway node snat for router {} " +
485 "there's no gateway assigned to it", router.name());
486 return;
487 }
488
Daniel Park5a3e9392021-03-23 08:00:00 +0900489 if (router.enableSnat() &&
490 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900491 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), true);
Daniel Park5a3e9392021-03-23 08:00:00 +0900492 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(externalIp),
493 peerRouterMac, true);
494 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
495 kubevirtNetworkService.network(externalNet), true);
Daniel Parkf3136042021-03-10 07:49:11 +0900496 }
497
498 router.internal()
499 .stream()
500 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
501 .map(kubevirtNetworkService::network)
502 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900503 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
504 setStatefulSnatDownStreamRuleForKubevirtPort(router,
505 electedGw, kubevirtPort, true);
506 });
507 });
508 }
509
Daniel Park5a3e9392021-03-23 08:00:00 +0900510 private void processRouterExternalNetDetached(KubevirtRouter router, String externalIp, String externalNet,
511 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900512 if (!isRelevantHelper()) {
513 return;
514 }
515 if (!isRelevantHelper()) {
516 return;
517 }
518 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
519
520 if (electedGw == null) {
521 log.warn("Fail to process router external network attached gateway node snat for router {} " +
522 "there's no gateway assigned to it", router.name());
523 return;
524 }
525
Daniel Park5a3e9392021-03-23 08:00:00 +0900526 if (router.enableSnat() &&
527 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900528 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), false);
Daniel Park5a3e9392021-03-23 08:00:00 +0900529 setStatefulSnatUpstreamRules(electedGw, router,
530 Ip4Address.valueOf(externalIp), peerRouterMac, false);
531 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
532 kubevirtNetworkService.network(externalNet), false);
Daniel Parkf3136042021-03-10 07:49:11 +0900533 }
534
535 router.internal()
536 .stream()
537 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
538 .map(kubevirtNetworkService::network)
539 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900540 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
541 setStatefulSnatDownStreamRuleForKubevirtPort(router,
542 electedGw, kubevirtPort, false);
543 });
544 });
545 }
546
547 private void processRouterGatewayNodeAttached(KubevirtRouter router, String attachedGatewayId) {
548 if (!isRelevantHelper()) {
549 return;
550 }
551
552 KubevirtNode attachedGateway = kubevirtNodeService.node(attachedGatewayId);
553 if (attachedGateway == null) {
554 return;
555 }
556
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900557 if (!router.enableSnat()) {
558 return;
559 }
560
Daniel Parkf3136042021-03-10 07:49:11 +0900561 router.internal()
562 .stream()
563 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
564 .map(kubevirtNetworkService::network)
565 .forEach(network -> {
566 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
567 if (routerSnatIp == null) {
568 return;
569 }
570 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
571 setStatefulSnatDownStreamRuleForKubevirtPort(router,
572 attachedGateway, kubevirtPort, true);
573 });
574 });
575 }
576
577 private void processRouterGatewayNodeDetached(KubevirtRouter router, String detachedGatewayId) {
578 if (!isRelevantHelper()) {
579 return;
580 }
581
582 KubevirtNode detachedGateway = kubevirtNodeService.node(detachedGatewayId);
583 if (detachedGateway == null) {
584 return;
585 }
586
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900587 if (!router.enableSnat()) {
588 return;
589 }
590
Daniel Parkf3136042021-03-10 07:49:11 +0900591 router.internal()
592 .stream()
593 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
594 .map(kubevirtNetworkService::network)
595 .forEach(network -> {
596 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
597 if (routerSnatIp == null) {
598 return;
599 }
600
601 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
602 setStatefulSnatDownStreamRuleForKubevirtPort(router,
603 detachedGateway, kubevirtPort, false);
604 });
605 });
606 }
607
Daniel Park2884b232021-03-04 18:58:47 +0900608 private void processRouterInternalNetworksAttached(KubevirtRouter router,
609 Set<String> attachedInternalNetworks) {
610 if (!isRelevantHelper()) {
611 return;
612 }
613
614 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
615 if (gwNode == null) {
616 return;
617 }
618
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900619 if (!router.enableSnat()) {
620 return;
621 }
622
Daniel Park2884b232021-03-04 18:58:47 +0900623 attachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900624 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
625 if (routerSnatIp == null) {
626 return;
627 }
628
Daniel Park2884b232021-03-04 18:58:47 +0900629 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900630 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900631 });
632 });
633 }
634
635 private void processRouterInternalNetworksDetached(KubevirtRouter router,
636 Set<String> detachedInternalNetworks) {
637 if (!isRelevantHelper()) {
638 return;
639 }
640
641 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
642 if (gwNode == null) {
643 return;
644 }
645
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900646 if (!router.enableSnat()) {
647 return;
648 }
649
Daniel Park2884b232021-03-04 18:58:47 +0900650 detachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900651 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
652 if (routerSnatIp == null) {
653 log.info("snatIp is null");
654 return;
655 }
656
Daniel Park2884b232021-03-04 18:58:47 +0900657 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900658 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900659 });
660 });
661 }
662 private void processRouterCreation(KubevirtRouter router) {
663 if (!isRelevantHelper()) {
664 return;
665 }
666 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900667 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Daniel Park2884b232021-03-04 18:58:47 +0900668 }
669 }
670
671 private void processRouterDeletion(KubevirtRouter router) {
672 if (!isRelevantHelper()) {
673 return;
674 }
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900675 if (!router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900676 initGatewayNodeSnatForRouter(router, router.electedGateway(), false);
Daniel Park2884b232021-03-04 18:58:47 +0900677 }
678 }
679
680 private void processRouterUpdate(KubevirtRouter router) {
681 if (!isRelevantHelper()) {
682 return;
683 }
684 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900685 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Daniel Park2884b232021-03-04 18:58:47 +0900686 }
687 }
Daniel Park157947f2021-04-09 17:50:53 +0900688
689 private void processRouterGatewayNodeChanged(KubevirtRouter router,
690 String disAssociatedGateway) {
691 if (!isRelevantHelper()) {
692 return;
693 }
694
695 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
696 initGatewayNodeSnatForRouter(router, disAssociatedGateway, false);
697 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
698
699 processRouterGatewayNodeDetached(router, disAssociatedGateway);
700 processRouterGatewayNodeAttached(router, router.electedGateway());
701
702 sendGarpPacketForSnatIp(router);
703 }
704 }
705
706 private void sendGarpPacketForSnatIp(KubevirtRouter router) {
707 if (router == null || router.electedGateway() == null) {
708 return;
709 }
710
711 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
712
713 if (routerSnatIp == null) {
714 log.warn("Fail to initialize gateway node snat for router {} " +
715 "because there's no gateway snat ip assigned to it", router.name());
716 return;
717 }
718
719 Ethernet ethernet = buildGarpPacket(DEFAULT_GATEWAY_MAC, IpAddress.valueOf(routerSnatIp));
720
721 if (ethernet == null) {
722 return;
723 }
724
725 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
726
727 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
728 .setOutput(externalPatchPortNum(deviceService, gatewayNode)).build();
729
730 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
731 ByteBuffer.wrap(ethernet.serialize())));
732 }
Daniel Park2884b232021-03-04 18:58:47 +0900733 }
734
Daniel Park2884b232021-03-04 18:58:47 +0900735 private class InternalKubevirtPortListener implements KubevirtPortListener {
736
737 private boolean isRelevantHelper() {
738 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
739 }
740
741 @Override
742 public void event(KubevirtPortEvent event) {
743 switch (event.type()) {
744 case KUBEVIRT_PORT_CREATED:
745 eventExecutor.execute(() -> processPortCreation(event.subject()));
746 break;
747 case KUBEVIRT_PORT_UPDATED:
748 eventExecutor.execute(() -> processPortUpdate(event.subject()));
749 break;
750 case KUBEVIRT_PORT_REMOVED:
751 eventExecutor.execute(() -> processPortDeletion(event.subject()));
752 break;
753 default:
754 //do nothing
755 break;
756 }
757 }
758
759 private void processPortCreation(KubevirtPort kubevirtPort) {
760 if (!isRelevantHelper()) {
761 return;
762 }
763
Daniel Parkbabde9c2021-03-09 13:37:42 +0900764 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900765 if (router == null) {
766 return;
767 }
768
769 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
770
771 if (gwNode != null) {
772 IpAddress gatewaySnatIp = getRouterSnatIpAddress(kubevirtRouterService, kubevirtPort.networkId());
773 if (gatewaySnatIp == null) {
774 return;
775 }
Daniel Parkf3136042021-03-10 07:49:11 +0900776 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900777 }
778 }
779
780 private void processPortUpdate(KubevirtPort kubevirtPort) {
781 if (!isRelevantHelper()) {
782 return;
783 }
784
Daniel Parkbabde9c2021-03-09 13:37:42 +0900785 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900786 if (router == null) {
787 return;
788 }
789
790 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
791
792 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900793 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900794 }
795 }
796
797 private void processPortDeletion(KubevirtPort kubevirtPort) {
798 if (!isRelevantHelper()) {
799 return;
800 }
801
Daniel Parkbabde9c2021-03-09 13:37:42 +0900802 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900803 if (router == null) {
804 return;
805 }
806
807 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
808
809 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900810 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900811 }
812 }
Daniel Park2884b232021-03-04 18:58:47 +0900813 }
Daniel Park2884b232021-03-04 18:58:47 +0900814}