blob: a2667f9e6e9d9f1430ea50cc18c0880dd3fc3e64 [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;
Jian Li517597a2021-03-22 11:04:52 +090045import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
46import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
Daniel Park2884b232021-03-04 18:58:47 +090047import org.onosproject.kubevirtnode.api.KubevirtNodeService;
48import org.onosproject.net.Device;
Daniel Park2884b232021-03-04 18:58:47 +090049import org.onosproject.net.PortNumber;
50import org.onosproject.net.device.DeviceAdminService;
51import org.onosproject.net.driver.DriverService;
52import org.onosproject.net.flow.DefaultTrafficSelector;
53import org.onosproject.net.flow.DefaultTrafficTreatment;
54import org.onosproject.net.flow.TrafficSelector;
55import org.onosproject.net.flow.TrafficTreatment;
56import org.onosproject.net.flow.instructions.ExtensionTreatment;
Daniel Park157947f2021-04-09 17:50:53 +090057import org.onosproject.net.packet.DefaultOutboundPacket;
58import org.onosproject.net.packet.PacketService;
Daniel Park2884b232021-03-04 18:58:47 +090059import org.osgi.service.component.annotations.Activate;
60import org.osgi.service.component.annotations.Component;
61import org.osgi.service.component.annotations.Deactivate;
62import org.osgi.service.component.annotations.Reference;
63import org.osgi.service.component.annotations.ReferenceCardinality;
64import org.slf4j.Logger;
65
Daniel Park157947f2021-04-09 17:50:53 +090066import java.nio.ByteBuffer;
Daniel Park2884b232021-03-04 18:58:47 +090067import java.util.Objects;
68import java.util.Set;
69import java.util.concurrent.ExecutorService;
70
71import static java.util.concurrent.Executors.newSingleThreadExecutor;
72import static org.onlab.util.Tools.groupedThreads;
73import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
74import static org.onosproject.kubevirtnetworking.api.Constants.FLAT_TABLE;
75import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
76import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
77import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
78import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Daniel Parkf3136042021-03-10 07:49:11 +090079import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
Daniel Park2884b232021-03-04 18:58:47 +090080import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
Daniel Parkf3136042021-03-10 07:49:11 +090081import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
82import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
83import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
84import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
85import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
Daniel Park157947f2021-04-09 17:50:53 +090086import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.buildGarpPacket;
Daniel Parkf3136042021-03-10 07:49:11 +090087import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.externalPatchPortNum;
Daniel Park2884b232021-03-04 18:58:47 +090088import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
Daniel Parkbabde9c2021-03-09 13:37:42 +090089import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterForKubevirtPort;
Daniel Parkf3136042021-03-10 07:49:11 +090090import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
Daniel Park5a3e9392021-03-23 08:00:00 +090091import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterSnatIpAddress;
Daniel Parkf3136042021-03-10 07:49:11 +090092import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
Daniel Park2884b232021-03-04 18:58:47 +090093import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Daniel Parkf3136042021-03-10 07:49:11 +090094import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
Daniel Park2884b232021-03-04 18:58:47 +090095import static org.slf4j.LoggerFactory.getLogger;
96
97/**
98 * Handles kubevirt routing snat.
99 */
100
101@Component(immediate = true)
102public class KubevirtRoutingSnatHandler {
103 protected final Logger log = getLogger(getClass());
104 private static final int DEFAULT_TTL = 0xff;
105
106 private static final int TP_PORT_MINIMUM_NUM = 1025;
107 private static final int TP_PORT_MAXIMUM_NUM = 65535;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
110 protected CoreService coreService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
113 protected ClusterService clusterService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
116 protected LeadershipService leadershipService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
119 protected DeviceAdminService deviceService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
122 protected KubevirtPortService kubevirtPortService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
125 protected KubevirtNodeService kubevirtNodeService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
128 protected KubevirtNetworkService kubevirtNetworkService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
131 protected KubevirtFlowRuleService flowService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
134 protected DriverService driverService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park157947f2021-04-09 17:50:53 +0900137 protected PacketService packetService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park2884b232021-03-04 18:58:47 +0900140 protected KubevirtRouterService kubevirtRouterService;
141
142 private final ExecutorService eventExecutor = newSingleThreadExecutor(
143 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
144
145 private final InternalKubevirtPortListener kubevirtPortListener =
146 new InternalKubevirtPortListener();
147
148 private final InternalRouterEventListener kubevirtRouterlistener =
149 new InternalRouterEventListener();
150
Jian Li517597a2021-03-22 11:04:52 +0900151 private final InternalNodeEventListener kubevirtNodeListener =
152 new InternalNodeEventListener();
153
Daniel Park2884b232021-03-04 18:58:47 +0900154 private ApplicationId appId;
155 private NodeId localNodeId;
156
157 @Activate
158 protected void activate() {
159 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
160 localNodeId = clusterService.getLocalNode().id();
161 leadershipService.runForLeadership(appId.name());
162
163 kubevirtPortService.addListener(kubevirtPortListener);
164 kubevirtRouterService.addListener(kubevirtRouterlistener);
Jian Li517597a2021-03-22 11:04:52 +0900165 kubevirtNodeService.addListener(kubevirtNodeListener);
Daniel Park2884b232021-03-04 18:58:47 +0900166
167 log.info("Started");
168 }
169
170 @Deactivate
171 protected void deactivate() {
172 leadershipService.withdraw(appId.name());
Jian Li517597a2021-03-22 11:04:52 +0900173 kubevirtNodeService.removeListener(kubevirtNodeListener);
Daniel Park2884b232021-03-04 18:58:47 +0900174 kubevirtPortService.removeListener(kubevirtPortListener);
175 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Daniel Park2884b232021-03-04 18:58:47 +0900176
177 eventExecutor.shutdown();
178
179 log.info("Stopped");
180 }
181
Daniel Park157947f2021-04-09 17:50:53 +0900182 private void initGatewayNodeSnatForRouter(KubevirtRouter router, String gateway, boolean install) {
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900183 if (router.electedGateway() == null) {
184 log.warn("Fail to initialize gateway node snat for router {} " +
185 "because there's no gateway assigned to it", router.name());
186 return;
187 }
188
Daniel Park157947f2021-04-09 17:50:53 +0900189 KubevirtNode electedGw = kubevirtNodeService.node(gateway);
Daniel Park2884b232021-03-04 18:58:47 +0900190 if (electedGw == null) {
191 log.warn("Fail to initialize gateway node snat for router {} " +
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900192 "because there's no gateway assigned to it", router.name());
Daniel Park2884b232021-03-04 18:58:47 +0900193 return;
194 }
195
196 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
197
198 if (routerSnatIp == null) {
199 log.warn("Fail to initialize gateway node snat for router {} " +
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900200 "because there's no gateway snat ip assigned to it", router.name());
Daniel Park2884b232021-03-04 18:58:47 +0900201 return;
202 }
203
Daniel Park5a3e9392021-03-23 08:00:00 +0900204 String externalNet = router.external().values().stream().findAny().orElse(null);
205 if (externalNet == null) {
206 return;
207 }
208
209 if (router.peerRouter() != null &&
210 router.peerRouter().ipAddress() != null && router.peerRouter().macAddress() != null) {
211 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(routerSnatIp), install);
212 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(routerSnatIp),
213 router.peerRouter().macAddress(), install);
214 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(routerSnatIp),
215 kubevirtNetworkService.network(externalNet), install);
216 }
Daniel Park2884b232021-03-04 18:58:47 +0900217 }
218
219 private void setArpResponseToPeerRouter(KubevirtNode gatewayNode, Ip4Address ip4Address, boolean install) {
220
221 TrafficSelector selector = DefaultTrafficSelector.builder()
Daniel Parkf3136042021-03-10 07:49:11 +0900222 .matchInPort(externalPatchPortNum(deviceService, gatewayNode))
Daniel Park2884b232021-03-04 18:58:47 +0900223 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
224 .matchArpOp(ARP.OP_REQUEST)
225 .matchArpTpa(ip4Address)
226 .build();
227
228 Device device = deviceService.getDevice(gatewayNode.intgBridge());
229
230 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
231 .extension(RulePopulatorUtil.buildMoveEthSrcToDstExtension(device), device.id())
232 .extension(RulePopulatorUtil.buildMoveArpShaToThaExtension(device), device.id())
233 .extension(RulePopulatorUtil.buildMoveArpSpaToTpaExtension(device), device.id())
234 .setArpOp(ARP.OP_REPLY)
235 .setEthSrc(DEFAULT_GATEWAY_MAC)
236 .setArpSha(DEFAULT_GATEWAY_MAC)
237 .setArpSpa(ip4Address)
238 .setOutput(PortNumber.IN_PORT)
239 .build();
240
241 flowService.setRule(
242 appId,
243 gatewayNode.intgBridge(),
244 selector,
245 treatment,
246 PRIORITY_ARP_GATEWAY_RULE,
247 PRE_FLAT_TABLE,
248 install);
249 }
250
Daniel Parkf3136042021-03-10 07:49:11 +0900251 private void setStatefulSnatUpstreamRules(KubevirtNode gatewayNode,
252 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900253 Ip4Address routerSnatIp,
254 MacAddress peerRouterMacAddress,
Daniel Parkf3136042021-03-10 07:49:11 +0900255 boolean install) {
256 MacAddress routerMacAddress = getRouterMacAddress(router);
257 if (routerMacAddress == null) {
258 return;
259 }
Daniel Park5a3e9392021-03-23 08:00:00 +0900260
261 if (routerSnatIp == null || peerRouterMacAddress == null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900262 return;
263 }
Daniel Park2884b232021-03-04 18:58:47 +0900264
Daniel Parkf3136042021-03-10 07:49:11 +0900265 TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
Daniel Park2884b232021-03-04 18:58:47 +0900266 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900267 .matchEthDst(routerMacAddress);
Daniel Park2884b232021-03-04 18:58:47 +0900268
269 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
270
271 ExtensionTreatment natTreatment = RulePopulatorUtil
272 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
273 .commit(true)
274 .natFlag(CT_NAT_SRC_FLAG)
275 .natAction(true)
Daniel Park5a3e9392021-03-23 08:00:00 +0900276 .natIp(routerSnatIp)
Daniel Park2884b232021-03-04 18:58:47 +0900277 .natPortMin(TpPort.tpPort(TP_PORT_MINIMUM_NUM))
278 .natPortMax(TpPort.tpPort(TP_PORT_MAXIMUM_NUM))
279 .build();
280
281 tBuilder.extension(natTreatment, gatewayNode.intgBridge())
Daniel Park5a3e9392021-03-23 08:00:00 +0900282 .setEthDst(peerRouterMacAddress)
Daniel Park2884b232021-03-04 18:58:47 +0900283 .setEthSrc(DEFAULT_GATEWAY_MAC)
Daniel Parkf3136042021-03-10 07:49:11 +0900284 .setOutput(externalPatchPortNum(deviceService, gatewayNode));
Daniel Park2884b232021-03-04 18:58:47 +0900285
286 flowService.setRule(
287 appId,
288 gatewayNode.intgBridge(),
Daniel Parkf3136042021-03-10 07:49:11 +0900289 selector.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900290 tBuilder.build(),
291 PRIORITY_STATEFUL_SNAT_RULE,
Daniel Parkf3136042021-03-10 07:49:11 +0900292 PRE_FLAT_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900293 install);
294 }
295
Daniel Parkf3136042021-03-10 07:49:11 +0900296 private void setStatefulSnatDownStreamRuleForKubevirtPort(KubevirtRouter router,
297 KubevirtNode gatewayNode,
298 KubevirtPort kubevirtPort,
299 boolean install) {
300 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Park2884b232021-03-04 18:58:47 +0900301
Daniel Parkf3136042021-03-10 07:49:11 +0900302 if (routerMacAddress == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900303 log.error("Failed to set stateful snat downstream rule because " +
304 "there's no br-int port for device {}", gatewayNode.intgBridge());
305 return;
306 }
307
308 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
309 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900310 .matchEthSrc(routerMacAddress)
Daniel Park2884b232021-03-04 18:58:47 +0900311 .matchIPDst(IpPrefix.valueOf(kubevirtPort.ipAddress(), 32));
312
Daniel Parkf3136042021-03-10 07:49:11 +0900313 KubevirtNetwork network = kubevirtNetworkService.network(kubevirtPort.networkId());
314
315 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Daniel Park2884b232021-03-04 18:58:47 +0900316 .setEthDst(kubevirtPort.macAddress())
Daniel Parkf3136042021-03-10 07:49:11 +0900317 .transition(FORWARDING_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900318
319 flowService.setRule(
320 appId,
321 gatewayNode.intgBridge(),
322 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900323 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900324 PRIORITY_STATEFUL_SNAT_RULE,
325 FLAT_TABLE,
326 install);
Daniel Parkf3136042021-03-10 07:49:11 +0900327
328 if (network.type() == VXLAN || network.type() == GENEVE || network.type() == GRE) {
329 setDownStreamRulesToGatewayTunBridge(router, network, kubevirtPort, install);
330 }
Daniel Park2884b232021-03-04 18:58:47 +0900331 }
332
Daniel Parkf3136042021-03-10 07:49:11 +0900333 private void setDownStreamRulesToGatewayTunBridge(KubevirtRouter router,
334 KubevirtNetwork network,
335 KubevirtPort port, boolean install) {
336 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
Daniel Park2884b232021-03-04 18:58:47 +0900337
Daniel Parkf3136042021-03-10 07:49:11 +0900338 if (electedGw == null) {
339 return;
340 }
Daniel Park2884b232021-03-04 18:58:47 +0900341
Daniel Parkf3136042021-03-10 07:49:11 +0900342 KubevirtNode workerNode = kubevirtNodeService.node(port.deviceId());
343 if (workerNode == null) {
344 return;
345 }
346
347 PortNumber tunnelPortNumber = tunnelPort(electedGw, network);
348 if (tunnelPortNumber == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900349 return;
350 }
351
352 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
353 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900354 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
355 .matchEthDst(port.macAddress());
356
357 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
358 .setTunnelId(Long.parseLong(network.segmentId()))
359 .extension(buildExtension(
360 deviceService,
361 electedGw.tunBridge(),
362 workerNode.dataIp().getIp4Address()),
363 electedGw.tunBridge())
364 .setOutput(tunnelPortNumber);
365
366 flowService.setRule(
367 appId,
368 electedGw.tunBridge(),
369 sBuilder.build(),
370 tBuilder.build(),
371 PRIORITY_FORWARDING_RULE,
372 TUNNEL_DEFAULT_TABLE,
373 install);
374 }
375
376 private void setStatefulSnatDownstreamRuleForRouter(KubevirtNode gatewayNode,
377 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900378 IpAddress routerSnatIp,
379 KubevirtNetwork externalNetwork,
Daniel Parkf3136042021-03-10 07:49:11 +0900380 boolean install) {
381
382 MacAddress routerMacAddress = getRouterMacAddress(router);
383
384 if (routerMacAddress == null) {
385 log.warn("Failed to set stateful snat downstream rule because " +
386 "there's no br-int port for device {}", gatewayNode.intgBridge());
387 return;
388 }
389
Daniel Parkf3136042021-03-10 07:49:11 +0900390 if (externalNetwork == null) {
391 log.warn("Failed to set stateful snat downstream rule because " +
392 "there's no external network router {}", router.name());
393 return;
394 }
395
396 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
397 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
398
399 if (externalNetwork.type() == VLAN) {
400 sBuilder.matchEthType(Ethernet.TYPE_VLAN)
401 .matchVlanId(VlanId.vlanId(externalNetwork.segmentId()));
402 tBuilder.popVlan();
403 } else {
404 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
405 }
406
Daniel Park5a3e9392021-03-23 08:00:00 +0900407 sBuilder.matchIPDst(IpPrefix.valueOf(routerSnatIp, 32));
Daniel Park2884b232021-03-04 18:58:47 +0900408
409 ExtensionTreatment natTreatment = RulePopulatorUtil
410 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
411 .commit(false)
412 .natAction(true)
Daniel Parkbabde9c2021-03-09 13:37:42 +0900413 .table((short) FLAT_TABLE)
Daniel Park2884b232021-03-04 18:58:47 +0900414 .build();
415
Daniel Parkf3136042021-03-10 07:49:11 +0900416 tBuilder.setEthSrc(routerMacAddress)
417 .extension(natTreatment, gatewayNode.intgBridge());
Daniel Park2884b232021-03-04 18:58:47 +0900418
419 flowService.setRule(
420 appId,
421 gatewayNode.intgBridge(),
422 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900423 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900424 PRIORITY_STATEFUL_SNAT_RULE,
Daniel Parkf3136042021-03-10 07:49:11 +0900425 PRE_FLAT_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900426 install);
Daniel Park2884b232021-03-04 18:58:47 +0900427 }
428
429 private class InternalRouterEventListener implements KubevirtRouterListener {
430 private boolean isRelevantHelper() {
431 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
432 }
433
434 @Override
435 public void event(KubevirtRouterEvent event) {
436 switch (event.type()) {
437 case KUBEVIRT_ROUTER_CREATED:
438 eventExecutor.execute(() -> processRouterCreation(event.subject()));
439 break;
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900440 case KUBEVIRT_SNAT_STATUS_DISABLED:
Daniel Park2884b232021-03-04 18:58:47 +0900441 case KUBEVIRT_ROUTER_REMOVED:
442 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
443 break;
444 case KUBEVIRT_ROUTER_UPDATED:
445 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
446 break;
447 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
448 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
449 event.internal()));
450 break;
451 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
452 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
453 event.internal()));
454 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900455 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
456 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
457 event.gateway()));
458 break;
459 case KUBEVIRT_GATEWAY_NODE_DETACHED:
460 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
461 event.gateway()));
462 break;
Daniel Park157947f2021-04-09 17:50:53 +0900463 case KUBEVIRT_GATEWAY_NODE_CHANGED:
464 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
465 event.gateway()));
466 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900467 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900468 eventExecutor.execute(() -> processRouterExternalNetAttached(event.subject(),
469 event.externalIp(), event.externalNet(),
470 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900471 break;
472 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900473 eventExecutor.execute(() -> processRouterExternalNetDetached(event.subject(),
474 event.externalIp(), event.externalNet(),
475 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900476 break;
Daniel Park2884b232021-03-04 18:58:47 +0900477 default:
478 //do nothing
479 break;
480 }
481 }
Daniel Parkf3136042021-03-10 07:49:11 +0900482
Daniel Park5a3e9392021-03-23 08:00:00 +0900483 private void processRouterExternalNetAttached(KubevirtRouter router, String externalIp, String externalNet,
484 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900485 if (!isRelevantHelper()) {
486 return;
487 }
488 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
489
490 if (electedGw == null) {
491 log.warn("Fail to process router external network attached gateway node snat for router {} " +
492 "there's no gateway assigned to it", router.name());
493 return;
494 }
495
Daniel Park5a3e9392021-03-23 08:00:00 +0900496 if (router.enableSnat() &&
497 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900498 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), true);
Daniel Park5a3e9392021-03-23 08:00:00 +0900499 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(externalIp),
500 peerRouterMac, true);
501 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
502 kubevirtNetworkService.network(externalNet), true);
Daniel Parkf3136042021-03-10 07:49:11 +0900503 }
504
505 router.internal()
506 .stream()
507 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
508 .map(kubevirtNetworkService::network)
509 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900510 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
511 setStatefulSnatDownStreamRuleForKubevirtPort(router,
512 electedGw, kubevirtPort, true);
513 });
514 });
515 }
516
Daniel Park5a3e9392021-03-23 08:00:00 +0900517 private void processRouterExternalNetDetached(KubevirtRouter router, String externalIp, String externalNet,
518 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900519 if (!isRelevantHelper()) {
520 return;
521 }
522 if (!isRelevantHelper()) {
523 return;
524 }
525 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
526
527 if (electedGw == null) {
528 log.warn("Fail to process router external network attached gateway node snat for router {} " +
529 "there's no gateway assigned to it", router.name());
530 return;
531 }
532
Daniel Park5a3e9392021-03-23 08:00:00 +0900533 if (router.enableSnat() &&
534 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900535 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), false);
Daniel Park5a3e9392021-03-23 08:00:00 +0900536 setStatefulSnatUpstreamRules(electedGw, router,
537 Ip4Address.valueOf(externalIp), peerRouterMac, false);
538 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
539 kubevirtNetworkService.network(externalNet), false);
Daniel Parkf3136042021-03-10 07:49:11 +0900540 }
541
542 router.internal()
543 .stream()
544 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
545 .map(kubevirtNetworkService::network)
546 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900547 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
548 setStatefulSnatDownStreamRuleForKubevirtPort(router,
549 electedGw, kubevirtPort, false);
550 });
551 });
552 }
553
554 private void processRouterGatewayNodeAttached(KubevirtRouter router, String attachedGatewayId) {
555 if (!isRelevantHelper()) {
556 return;
557 }
558
559 KubevirtNode attachedGateway = kubevirtNodeService.node(attachedGatewayId);
560 if (attachedGateway == null) {
561 return;
562 }
563
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900564 if (!router.enableSnat()) {
565 return;
566 }
567
Daniel Parkf3136042021-03-10 07:49:11 +0900568 router.internal()
569 .stream()
570 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
571 .map(kubevirtNetworkService::network)
572 .forEach(network -> {
573 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
574 if (routerSnatIp == null) {
575 return;
576 }
577 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
578 setStatefulSnatDownStreamRuleForKubevirtPort(router,
579 attachedGateway, kubevirtPort, true);
580 });
581 });
582 }
583
584 private void processRouterGatewayNodeDetached(KubevirtRouter router, String detachedGatewayId) {
585 if (!isRelevantHelper()) {
586 return;
587 }
588
589 KubevirtNode detachedGateway = kubevirtNodeService.node(detachedGatewayId);
590 if (detachedGateway == null) {
591 return;
592 }
593
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900594 if (!router.enableSnat()) {
595 return;
596 }
597
Daniel Parkf3136042021-03-10 07:49:11 +0900598 router.internal()
599 .stream()
600 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
601 .map(kubevirtNetworkService::network)
602 .forEach(network -> {
603 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
604 if (routerSnatIp == null) {
605 return;
606 }
607
608 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
609 setStatefulSnatDownStreamRuleForKubevirtPort(router,
610 detachedGateway, kubevirtPort, false);
611 });
612 });
613 }
614
Daniel Park2884b232021-03-04 18:58:47 +0900615 private void processRouterInternalNetworksAttached(KubevirtRouter router,
616 Set<String> attachedInternalNetworks) {
617 if (!isRelevantHelper()) {
618 return;
619 }
620
621 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
622 if (gwNode == null) {
623 return;
624 }
625
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900626 if (!router.enableSnat()) {
627 return;
628 }
629
Daniel Park2884b232021-03-04 18:58:47 +0900630 attachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900631 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
632 if (routerSnatIp == null) {
633 return;
634 }
635
Daniel Park2884b232021-03-04 18:58:47 +0900636 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900637 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900638 });
639 });
640 }
641
642 private void processRouterInternalNetworksDetached(KubevirtRouter router,
643 Set<String> detachedInternalNetworks) {
644 if (!isRelevantHelper()) {
645 return;
646 }
647
648 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
649 if (gwNode == null) {
650 return;
651 }
652
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900653 if (!router.enableSnat()) {
654 return;
655 }
656
Daniel Park2884b232021-03-04 18:58:47 +0900657 detachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900658 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
659 if (routerSnatIp == null) {
660 log.info("snatIp is null");
661 return;
662 }
663
Daniel Park2884b232021-03-04 18:58:47 +0900664 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900665 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900666 });
667 });
668 }
669 private void processRouterCreation(KubevirtRouter router) {
670 if (!isRelevantHelper()) {
671 return;
672 }
673 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900674 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Daniel Park2884b232021-03-04 18:58:47 +0900675 }
676 }
677
678 private void processRouterDeletion(KubevirtRouter router) {
679 if (!isRelevantHelper()) {
680 return;
681 }
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900682 if (!router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900683 initGatewayNodeSnatForRouter(router, router.electedGateway(), false);
Daniel Park2884b232021-03-04 18:58:47 +0900684 }
685 }
686
687 private void processRouterUpdate(KubevirtRouter router) {
688 if (!isRelevantHelper()) {
689 return;
690 }
691 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900692 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Daniel Park2884b232021-03-04 18:58:47 +0900693 }
694 }
Daniel Park157947f2021-04-09 17:50:53 +0900695
696 private void processRouterGatewayNodeChanged(KubevirtRouter router,
697 String disAssociatedGateway) {
698 if (!isRelevantHelper()) {
699 return;
700 }
701
702 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
703 initGatewayNodeSnatForRouter(router, disAssociatedGateway, false);
704 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
705
706 processRouterGatewayNodeDetached(router, disAssociatedGateway);
707 processRouterGatewayNodeAttached(router, router.electedGateway());
708
709 sendGarpPacketForSnatIp(router);
710 }
711 }
712
713 private void sendGarpPacketForSnatIp(KubevirtRouter router) {
714 if (router == null || router.electedGateway() == null) {
715 return;
716 }
717
718 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
719
720 if (routerSnatIp == null) {
721 log.warn("Fail to initialize gateway node snat for router {} " +
722 "because there's no gateway snat ip assigned to it", router.name());
723 return;
724 }
725
726 Ethernet ethernet = buildGarpPacket(DEFAULT_GATEWAY_MAC, IpAddress.valueOf(routerSnatIp));
727
728 if (ethernet == null) {
729 return;
730 }
731
732 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
733
734 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
735 .setOutput(externalPatchPortNum(deviceService, gatewayNode)).build();
736
737 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
738 ByteBuffer.wrap(ethernet.serialize())));
739 }
Daniel Park2884b232021-03-04 18:58:47 +0900740 }
741
Daniel Park2884b232021-03-04 18:58:47 +0900742 private class InternalKubevirtPortListener implements KubevirtPortListener {
743
744 private boolean isRelevantHelper() {
745 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
746 }
747
748 @Override
749 public void event(KubevirtPortEvent event) {
750 switch (event.type()) {
751 case KUBEVIRT_PORT_CREATED:
752 eventExecutor.execute(() -> processPortCreation(event.subject()));
753 break;
754 case KUBEVIRT_PORT_UPDATED:
755 eventExecutor.execute(() -> processPortUpdate(event.subject()));
756 break;
757 case KUBEVIRT_PORT_REMOVED:
758 eventExecutor.execute(() -> processPortDeletion(event.subject()));
759 break;
760 default:
761 //do nothing
762 break;
763 }
764 }
765
766 private void processPortCreation(KubevirtPort kubevirtPort) {
767 if (!isRelevantHelper()) {
768 return;
769 }
770
Daniel Parkbabde9c2021-03-09 13:37:42 +0900771 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900772 if (router == null) {
773 return;
774 }
775
776 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
777
778 if (gwNode != null) {
779 IpAddress gatewaySnatIp = getRouterSnatIpAddress(kubevirtRouterService, kubevirtPort.networkId());
780 if (gatewaySnatIp == null) {
781 return;
782 }
Daniel Parkf3136042021-03-10 07:49:11 +0900783 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900784 }
785 }
786
787 private void processPortUpdate(KubevirtPort kubevirtPort) {
788 if (!isRelevantHelper()) {
789 return;
790 }
791
Daniel Parkbabde9c2021-03-09 13:37:42 +0900792 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900793 if (router == null) {
794 return;
795 }
796
797 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
798
799 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900800 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900801 }
802 }
803
804 private void processPortDeletion(KubevirtPort kubevirtPort) {
805 if (!isRelevantHelper()) {
806 return;
807 }
808
Daniel Parkbabde9c2021-03-09 13:37:42 +0900809 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900810 if (router == null) {
811 return;
812 }
813
814 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
815
816 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900817 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900818 }
819 }
Daniel Park2884b232021-03-04 18:58:47 +0900820 }
Jian Li517597a2021-03-22 11:04:52 +0900821
822 private class InternalNodeEventListener implements KubevirtNodeListener {
823
824 @Override
825 public void event(KubevirtNodeEvent event) {
826
827 }
828 }
Daniel Park2884b232021-03-04 18:58:47 +0900829}