blob: 517c1cea3be522b893378b57b76052e229c74359 [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;
Daniel Park2884b232021-03-04 18:58:47 +090072import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090073import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
74import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
Daniel Park2884b232021-03-04 18:58:47 +090075import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Daniel Park2884b232021-03-04 18:58:47 +090076import 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 Park05a94582021-05-12 10:57:02 +0900176 if (gateway == null) {
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900177 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,
Jian Lif89d9602021-04-27 19:05:49 +0900240 GW_ENTRY_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900241 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,
Jian Lif89d9602021-04-27 19:05:49 +0900285 GW_ENTRY_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,
Jian Lif89d9602021-04-27 19:05:49 +0900318 GW_DROP_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900319 install);
Daniel Parkf3136042021-03-10 07:49:11 +0900320
321 if (network.type() == VXLAN || network.type() == GENEVE || network.type() == GRE) {
Daniel Park328fb602021-05-31 13:49:53 +0900322 setDownStreamRulesToGatewayTunBridge(network, gatewayNode, kubevirtPort, install);
Daniel Parkf3136042021-03-10 07:49:11 +0900323 }
Daniel Park2884b232021-03-04 18:58:47 +0900324 }
325
Daniel Park328fb602021-05-31 13:49:53 +0900326 private void setDownStreamRulesToGatewayTunBridge(KubevirtNetwork network,
327 KubevirtNode electedGw,
Daniel Parkf3136042021-03-10 07:49:11 +0900328 KubevirtPort port, boolean install) {
Daniel Parkf3136042021-03-10 07:49:11 +0900329 KubevirtNode workerNode = kubevirtNodeService.node(port.deviceId());
330 if (workerNode == null) {
331 return;
332 }
333
334 PortNumber tunnelPortNumber = tunnelPort(electedGw, network);
335 if (tunnelPortNumber == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900336 return;
337 }
338
339 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
340 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900341 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
342 .matchEthDst(port.macAddress());
343
344 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
345 .setTunnelId(Long.parseLong(network.segmentId()))
346 .extension(buildExtension(
347 deviceService,
348 electedGw.tunBridge(),
349 workerNode.dataIp().getIp4Address()),
350 electedGw.tunBridge())
351 .setOutput(tunnelPortNumber);
352
353 flowService.setRule(
354 appId,
355 electedGw.tunBridge(),
356 sBuilder.build(),
357 tBuilder.build(),
358 PRIORITY_FORWARDING_RULE,
359 TUNNEL_DEFAULT_TABLE,
360 install);
361 }
362
363 private void setStatefulSnatDownstreamRuleForRouter(KubevirtNode gatewayNode,
364 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900365 IpAddress routerSnatIp,
366 KubevirtNetwork externalNetwork,
Daniel Parkf3136042021-03-10 07:49:11 +0900367 boolean install) {
368
369 MacAddress routerMacAddress = getRouterMacAddress(router);
370
371 if (routerMacAddress == null) {
372 log.warn("Failed to set stateful snat downstream rule because " +
373 "there's no br-int port for device {}", gatewayNode.intgBridge());
374 return;
375 }
376
Daniel Parkf3136042021-03-10 07:49:11 +0900377 if (externalNetwork == null) {
378 log.warn("Failed to set stateful snat downstream rule because " +
379 "there's no external network router {}", router.name());
380 return;
381 }
382
383 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
384 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
385
386 if (externalNetwork.type() == VLAN) {
387 sBuilder.matchEthType(Ethernet.TYPE_VLAN)
388 .matchVlanId(VlanId.vlanId(externalNetwork.segmentId()));
389 tBuilder.popVlan();
390 } else {
391 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
392 }
393
Daniel Park5a3e9392021-03-23 08:00:00 +0900394 sBuilder.matchIPDst(IpPrefix.valueOf(routerSnatIp, 32));
Daniel Park2884b232021-03-04 18:58:47 +0900395
396 ExtensionTreatment natTreatment = RulePopulatorUtil
397 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
398 .commit(false)
399 .natAction(true)
Jian Lif89d9602021-04-27 19:05:49 +0900400 .table((short) GW_DROP_TABLE)
Daniel Park2884b232021-03-04 18:58:47 +0900401 .build();
402
Daniel Parkf3136042021-03-10 07:49:11 +0900403 tBuilder.setEthSrc(routerMacAddress)
404 .extension(natTreatment, gatewayNode.intgBridge());
Daniel Park2884b232021-03-04 18:58:47 +0900405
406 flowService.setRule(
407 appId,
408 gatewayNode.intgBridge(),
409 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900410 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900411 PRIORITY_STATEFUL_SNAT_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900412 GW_ENTRY_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900413 install);
Daniel Park2884b232021-03-04 18:58:47 +0900414 }
415
416 private class InternalRouterEventListener implements KubevirtRouterListener {
417 private boolean isRelevantHelper() {
418 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
419 }
420
421 @Override
422 public void event(KubevirtRouterEvent event) {
423 switch (event.type()) {
424 case KUBEVIRT_ROUTER_CREATED:
425 eventExecutor.execute(() -> processRouterCreation(event.subject()));
426 break;
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900427 case KUBEVIRT_SNAT_STATUS_DISABLED:
Daniel Park2884b232021-03-04 18:58:47 +0900428 case KUBEVIRT_ROUTER_REMOVED:
429 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
430 break;
431 case KUBEVIRT_ROUTER_UPDATED:
432 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
433 break;
434 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
435 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
436 event.internal()));
437 break;
438 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
439 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
440 event.internal()));
441 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900442 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
443 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
444 event.gateway()));
445 break;
446 case KUBEVIRT_GATEWAY_NODE_DETACHED:
447 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
448 event.gateway()));
449 break;
Daniel Park157947f2021-04-09 17:50:53 +0900450 case KUBEVIRT_GATEWAY_NODE_CHANGED:
451 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
452 event.gateway()));
453 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900454 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900455 eventExecutor.execute(() -> processRouterExternalNetAttached(event.subject(),
456 event.externalIp(), event.externalNet(),
457 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900458 break;
459 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900460 eventExecutor.execute(() -> processRouterExternalNetDetached(event.subject(),
461 event.externalIp(), event.externalNet(),
462 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900463 break;
Daniel Park2884b232021-03-04 18:58:47 +0900464 default:
465 //do nothing
466 break;
467 }
468 }
Daniel Parkf3136042021-03-10 07:49:11 +0900469
Daniel Park5a3e9392021-03-23 08:00:00 +0900470 private void processRouterExternalNetAttached(KubevirtRouter router, String externalIp, String externalNet,
471 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900472 if (!isRelevantHelper()) {
473 return;
474 }
475 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
476
477 if (electedGw == null) {
478 log.warn("Fail to process router external network attached gateway node snat for router {} " +
479 "there's no gateway assigned to it", router.name());
480 return;
481 }
482
Daniel Park5a3e9392021-03-23 08:00:00 +0900483 if (router.enableSnat() &&
484 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900485 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), true);
Daniel Park5a3e9392021-03-23 08:00:00 +0900486 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(externalIp),
487 peerRouterMac, true);
488 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
489 kubevirtNetworkService.network(externalNet), true);
Daniel Parkf3136042021-03-10 07:49:11 +0900490 }
491
492 router.internal()
493 .stream()
494 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
495 .map(kubevirtNetworkService::network)
496 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900497 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
498 setStatefulSnatDownStreamRuleForKubevirtPort(router,
499 electedGw, kubevirtPort, true);
500 });
501 });
502 }
503
Daniel Park5a3e9392021-03-23 08:00:00 +0900504 private void processRouterExternalNetDetached(KubevirtRouter router, String externalIp, String externalNet,
505 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900506 if (!isRelevantHelper()) {
507 return;
508 }
509 if (!isRelevantHelper()) {
510 return;
511 }
Daniel Park05a94582021-05-12 10:57:02 +0900512 KubevirtNode electedGw = kubevirtNodeService.node(router.electedGateway());
Daniel Parkf3136042021-03-10 07:49:11 +0900513
514 if (electedGw == null) {
515 log.warn("Fail to process router external network attached gateway node snat for router {} " +
516 "there's no gateway assigned to it", router.name());
517 return;
518 }
519
Daniel Park5a3e9392021-03-23 08:00:00 +0900520 if (router.enableSnat() &&
521 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900522 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), false);
Daniel Park5a3e9392021-03-23 08:00:00 +0900523 setStatefulSnatUpstreamRules(electedGw, router,
524 Ip4Address.valueOf(externalIp), peerRouterMac, false);
525 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
526 kubevirtNetworkService.network(externalNet), false);
Daniel Parkf3136042021-03-10 07:49:11 +0900527 }
528
529 router.internal()
530 .stream()
531 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
532 .map(kubevirtNetworkService::network)
533 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900534 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
535 setStatefulSnatDownStreamRuleForKubevirtPort(router,
536 electedGw, kubevirtPort, false);
537 });
538 });
539 }
540
541 private void processRouterGatewayNodeAttached(KubevirtRouter router, String attachedGatewayId) {
542 if (!isRelevantHelper()) {
543 return;
544 }
545
546 KubevirtNode attachedGateway = kubevirtNodeService.node(attachedGatewayId);
547 if (attachedGateway == null) {
548 return;
549 }
550
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900551 if (!router.enableSnat()) {
552 return;
553 }
554
Daniel Parkf3136042021-03-10 07:49:11 +0900555 router.internal()
556 .stream()
557 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
558 .map(kubevirtNetworkService::network)
559 .forEach(network -> {
560 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
561 if (routerSnatIp == null) {
562 return;
563 }
564 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
565 setStatefulSnatDownStreamRuleForKubevirtPort(router,
566 attachedGateway, kubevirtPort, true);
567 });
568 });
569 }
570
571 private void processRouterGatewayNodeDetached(KubevirtRouter router, String detachedGatewayId) {
572 if (!isRelevantHelper()) {
573 return;
574 }
575
576 KubevirtNode detachedGateway = kubevirtNodeService.node(detachedGatewayId);
577 if (detachedGateway == null) {
578 return;
579 }
580
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900581 if (!router.enableSnat()) {
582 return;
583 }
584
Daniel Parkf3136042021-03-10 07:49:11 +0900585 router.internal()
586 .stream()
587 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
588 .map(kubevirtNetworkService::network)
589 .forEach(network -> {
590 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
591 if (routerSnatIp == null) {
592 return;
593 }
594
595 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
596 setStatefulSnatDownStreamRuleForKubevirtPort(router,
597 detachedGateway, kubevirtPort, false);
598 });
599 });
600 }
601
Daniel Park2884b232021-03-04 18:58:47 +0900602 private void processRouterInternalNetworksAttached(KubevirtRouter router,
603 Set<String> attachedInternalNetworks) {
604 if (!isRelevantHelper()) {
605 return;
606 }
607
608 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
609 if (gwNode == null) {
610 return;
611 }
612
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900613 if (!router.enableSnat()) {
614 return;
615 }
616
Daniel Park2884b232021-03-04 18:58:47 +0900617 attachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900618 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
619 if (routerSnatIp == null) {
620 return;
621 }
622
Daniel Park2884b232021-03-04 18:58:47 +0900623 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900624 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900625 });
626 });
627 }
628
629 private void processRouterInternalNetworksDetached(KubevirtRouter router,
630 Set<String> detachedInternalNetworks) {
631 if (!isRelevantHelper()) {
632 return;
633 }
634
635 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
636 if (gwNode == null) {
637 return;
638 }
639
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900640 if (!router.enableSnat()) {
641 return;
642 }
643
Daniel Park2884b232021-03-04 18:58:47 +0900644 detachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900645 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
646 if (routerSnatIp == null) {
647 log.info("snatIp is null");
648 return;
649 }
650
Daniel Park2884b232021-03-04 18:58:47 +0900651 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900652 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900653 });
654 });
655 }
656 private void processRouterCreation(KubevirtRouter router) {
657 if (!isRelevantHelper()) {
658 return;
659 }
660 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900661 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Daniel Park2884b232021-03-04 18:58:47 +0900662 }
663 }
664
665 private void processRouterDeletion(KubevirtRouter router) {
666 if (!isRelevantHelper()) {
667 return;
668 }
Daniel Parkde238262021-06-14 07:31:06 +0900669
670
671 if (!router.external().isEmpty() && router.peerRouter() != null && router.electedGateway() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900672 initGatewayNodeSnatForRouter(router, router.electedGateway(), false);
Daniel Parka5ba88d2021-05-28 15:46:46 +0900673
Daniel Parkde238262021-06-14 07:31:06 +0900674 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
Daniel Parka5ba88d2021-05-28 15:46:46 +0900675
Daniel Parkde238262021-06-14 07:31:06 +0900676 router.internal()
677 .stream()
678 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
679 .map(kubevirtNetworkService::network)
680 .forEach(network -> {
681 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
682 if (routerSnatIp == null) {
683 return;
684 }
685
686 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
687 setStatefulSnatDownStreamRuleForKubevirtPort(router,
688 gatewayNode, kubevirtPort, false);
689 });
Daniel Parka5ba88d2021-05-28 15:46:46 +0900690 });
Daniel Parkde238262021-06-14 07:31:06 +0900691 }
Daniel Park2884b232021-03-04 18:58:47 +0900692 }
693
694 private void processRouterUpdate(KubevirtRouter router) {
695 if (!isRelevantHelper()) {
696 return;
697 }
698 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900699 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Jian Li0ab242b2021-07-16 17:41:13 +0900700
701 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
702
703 router.internal()
704 .stream()
705 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
706 .map(kubevirtNetworkService::network)
707 .forEach(network -> {
708 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
709 if (routerSnatIp == null) {
710 return;
711 }
712
713 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
714 setStatefulSnatDownStreamRuleForKubevirtPort(router,
715 gatewayNode, kubevirtPort, true);
716 });
717 });
Daniel Park2884b232021-03-04 18:58:47 +0900718 }
719 }
Daniel Park157947f2021-04-09 17:50:53 +0900720
721 private void processRouterGatewayNodeChanged(KubevirtRouter router,
722 String disAssociatedGateway) {
723 if (!isRelevantHelper()) {
724 return;
725 }
726
727 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
728 initGatewayNodeSnatForRouter(router, disAssociatedGateway, false);
729 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
730
731 processRouterGatewayNodeDetached(router, disAssociatedGateway);
732 processRouterGatewayNodeAttached(router, router.electedGateway());
733
734 sendGarpPacketForSnatIp(router);
735 }
736 }
737
738 private void sendGarpPacketForSnatIp(KubevirtRouter router) {
739 if (router == null || router.electedGateway() == null) {
740 return;
741 }
742
743 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
744
745 if (routerSnatIp == null) {
746 log.warn("Fail to initialize gateway node snat for router {} " +
747 "because there's no gateway snat ip assigned to it", router.name());
748 return;
749 }
750
751 Ethernet ethernet = buildGarpPacket(DEFAULT_GATEWAY_MAC, IpAddress.valueOf(routerSnatIp));
752
753 if (ethernet == null) {
754 return;
755 }
756
757 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
758
759 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
760 .setOutput(externalPatchPortNum(deviceService, gatewayNode)).build();
761
762 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
763 ByteBuffer.wrap(ethernet.serialize())));
764 }
Daniel Park2884b232021-03-04 18:58:47 +0900765 }
766
Daniel Park2884b232021-03-04 18:58:47 +0900767 private class InternalKubevirtPortListener implements KubevirtPortListener {
768
769 private boolean isRelevantHelper() {
770 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
771 }
772
773 @Override
774 public void event(KubevirtPortEvent event) {
775 switch (event.type()) {
776 case KUBEVIRT_PORT_CREATED:
777 eventExecutor.execute(() -> processPortCreation(event.subject()));
778 break;
779 case KUBEVIRT_PORT_UPDATED:
780 eventExecutor.execute(() -> processPortUpdate(event.subject()));
781 break;
782 case KUBEVIRT_PORT_REMOVED:
783 eventExecutor.execute(() -> processPortDeletion(event.subject()));
784 break;
785 default:
786 //do nothing
787 break;
788 }
789 }
790
791 private void processPortCreation(KubevirtPort kubevirtPort) {
792 if (!isRelevantHelper()) {
793 return;
794 }
795
Daniel Parkbabde9c2021-03-09 13:37:42 +0900796 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900797 if (router == null) {
798 return;
799 }
800
801 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
802
803 if (gwNode != null) {
804 IpAddress gatewaySnatIp = getRouterSnatIpAddress(kubevirtRouterService, kubevirtPort.networkId());
805 if (gatewaySnatIp == null) {
806 return;
807 }
Daniel Parkf3136042021-03-10 07:49:11 +0900808 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900809 }
810 }
811
812 private void processPortUpdate(KubevirtPort kubevirtPort) {
813 if (!isRelevantHelper()) {
814 return;
815 }
816
Daniel Parkbabde9c2021-03-09 13:37:42 +0900817 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900818 if (router == null) {
819 return;
820 }
821
822 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
823
824 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900825 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900826 }
827 }
828
829 private void processPortDeletion(KubevirtPort kubevirtPort) {
830 if (!isRelevantHelper()) {
831 return;
832 }
833
Daniel Parkbabde9c2021-03-09 13:37:42 +0900834 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900835 if (router == null) {
836 return;
837 }
838
839 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
840
841 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900842 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900843 }
844 }
Daniel Park2884b232021-03-04 18:58:47 +0900845 }
Daniel Park2884b232021-03-04 18:58:47 +0900846}