blob: 716ec9c024bddc317588fb627b508a7e15a90939 [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 Park1aeb8eb2022-04-04 08:28:54 +090047import org.onosproject.net.DeviceId;
Daniel Park2884b232021-03-04 18:58:47 +090048import org.onosproject.net.PortNumber;
49import org.onosproject.net.device.DeviceAdminService;
50import org.onosproject.net.driver.DriverService;
51import org.onosproject.net.flow.DefaultTrafficSelector;
52import org.onosproject.net.flow.DefaultTrafficTreatment;
53import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
55import org.onosproject.net.flow.instructions.ExtensionTreatment;
Daniel Park157947f2021-04-09 17:50:53 +090056import org.onosproject.net.packet.DefaultOutboundPacket;
57import org.onosproject.net.packet.PacketService;
Daniel Park2884b232021-03-04 18:58:47 +090058import org.osgi.service.component.annotations.Activate;
59import org.osgi.service.component.annotations.Component;
60import org.osgi.service.component.annotations.Deactivate;
61import org.osgi.service.component.annotations.Reference;
62import org.osgi.service.component.annotations.ReferenceCardinality;
63import org.slf4j.Logger;
64
Daniel Park157947f2021-04-09 17:50:53 +090065import java.nio.ByteBuffer;
Daniel Park2884b232021-03-04 18:58:47 +090066import java.util.Objects;
67import java.util.Set;
68import java.util.concurrent.ExecutorService;
69
70import static java.util.concurrent.Executors.newSingleThreadExecutor;
71import static org.onlab.util.Tools.groupedThreads;
72import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
Daniel Park2884b232021-03-04 18:58:47 +090073import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090074import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
75import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
Daniel Park2884b232021-03-04 18:58:47 +090076import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Daniel Park2884b232021-03-04 18:58:47 +090077import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Daniel Parkf3136042021-03-10 07:49:11 +090078import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
Daniel Park2884b232021-03-04 18:58:47 +090079import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
Daniel Parkf3136042021-03-10 07:49:11 +090080import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
81import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
82import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
Jian Li4b3436a2022-03-23 13:07:19 +090083import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.STT;
Daniel Parkf3136042021-03-10 07:49:11 +090084import 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
Daniel Park2884b232021-03-04 18:58:47 +0900151 private ApplicationId appId;
152 private NodeId localNodeId;
153
154 @Activate
155 protected void activate() {
156 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
157 localNodeId = clusterService.getLocalNode().id();
158 leadershipService.runForLeadership(appId.name());
159
160 kubevirtPortService.addListener(kubevirtPortListener);
161 kubevirtRouterService.addListener(kubevirtRouterlistener);
Daniel Park2884b232021-03-04 18:58:47 +0900162
163 log.info("Started");
164 }
165
166 @Deactivate
167 protected void deactivate() {
168 leadershipService.withdraw(appId.name());
169 kubevirtPortService.removeListener(kubevirtPortListener);
170 kubevirtRouterService.removeListener(kubevirtRouterlistener);
Daniel Park2884b232021-03-04 18:58:47 +0900171
172 eventExecutor.shutdown();
173
174 log.info("Stopped");
175 }
176
Daniel Park157947f2021-04-09 17:50:53 +0900177 private void initGatewayNodeSnatForRouter(KubevirtRouter router, String gateway, boolean install) {
Daniel Park05a94582021-05-12 10:57:02 +0900178 if (gateway == null) {
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900179 log.warn("Fail to initialize gateway node snat for router {} " +
180 "because there's no gateway assigned to it", router.name());
181 return;
182 }
183
Daniel Park157947f2021-04-09 17:50:53 +0900184 KubevirtNode electedGw = kubevirtNodeService.node(gateway);
Daniel Park2884b232021-03-04 18:58:47 +0900185 if (electedGw == null) {
186 log.warn("Fail to initialize gateway node snat for router {} " +
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900187 "because there's no gateway assigned to it", router.name());
Daniel Park2884b232021-03-04 18:58:47 +0900188 return;
189 }
190
191 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
192
193 if (routerSnatIp == null) {
194 log.warn("Fail to initialize gateway node snat for router {} " +
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900195 "because there's no gateway snat ip assigned to it", router.name());
Daniel Park2884b232021-03-04 18:58:47 +0900196 return;
197 }
198
Daniel Park5a3e9392021-03-23 08:00:00 +0900199 String externalNet = router.external().values().stream().findAny().orElse(null);
200 if (externalNet == null) {
201 return;
202 }
203
204 if (router.peerRouter() != null &&
205 router.peerRouter().ipAddress() != null && router.peerRouter().macAddress() != null) {
206 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(routerSnatIp), install);
207 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(routerSnatIp),
208 router.peerRouter().macAddress(), install);
209 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(routerSnatIp),
210 kubevirtNetworkService.network(externalNet), install);
211 }
Daniel Park2884b232021-03-04 18:58:47 +0900212 }
213
214 private void setArpResponseToPeerRouter(KubevirtNode gatewayNode, Ip4Address ip4Address, boolean install) {
215
216 TrafficSelector selector = DefaultTrafficSelector.builder()
Daniel Parkf3136042021-03-10 07:49:11 +0900217 .matchInPort(externalPatchPortNum(deviceService, gatewayNode))
Daniel Park2884b232021-03-04 18:58:47 +0900218 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
219 .matchArpOp(ARP.OP_REQUEST)
220 .matchArpTpa(ip4Address)
221 .build();
222
223 Device device = deviceService.getDevice(gatewayNode.intgBridge());
224
225 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
226 .extension(RulePopulatorUtil.buildMoveEthSrcToDstExtension(device), device.id())
227 .extension(RulePopulatorUtil.buildMoveArpShaToThaExtension(device), device.id())
228 .extension(RulePopulatorUtil.buildMoveArpSpaToTpaExtension(device), device.id())
229 .setArpOp(ARP.OP_REPLY)
230 .setEthSrc(DEFAULT_GATEWAY_MAC)
231 .setArpSha(DEFAULT_GATEWAY_MAC)
232 .setArpSpa(ip4Address)
233 .setOutput(PortNumber.IN_PORT)
234 .build();
235
236 flowService.setRule(
237 appId,
238 gatewayNode.intgBridge(),
239 selector,
240 treatment,
241 PRIORITY_ARP_GATEWAY_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900242 GW_ENTRY_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900243 install);
244 }
245
Daniel Parkf3136042021-03-10 07:49:11 +0900246 private void setStatefulSnatUpstreamRules(KubevirtNode gatewayNode,
247 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900248 Ip4Address routerSnatIp,
249 MacAddress peerRouterMacAddress,
Daniel Parkf3136042021-03-10 07:49:11 +0900250 boolean install) {
251 MacAddress routerMacAddress = getRouterMacAddress(router);
252 if (routerMacAddress == null) {
253 return;
254 }
Daniel Park5a3e9392021-03-23 08:00:00 +0900255
256 if (routerSnatIp == null || peerRouterMacAddress == null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900257 return;
258 }
Daniel Park2884b232021-03-04 18:58:47 +0900259
Daniel Parkf3136042021-03-10 07:49:11 +0900260 TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
Daniel Park2884b232021-03-04 18:58:47 +0900261 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900262 .matchEthDst(routerMacAddress);
Daniel Park2884b232021-03-04 18:58:47 +0900263
264 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
265
266 ExtensionTreatment natTreatment = RulePopulatorUtil
267 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
268 .commit(true)
269 .natFlag(CT_NAT_SRC_FLAG)
270 .natAction(true)
Daniel Park5a3e9392021-03-23 08:00:00 +0900271 .natIp(routerSnatIp)
Daniel Park2884b232021-03-04 18:58:47 +0900272 .natPortMin(TpPort.tpPort(TP_PORT_MINIMUM_NUM))
273 .natPortMax(TpPort.tpPort(TP_PORT_MAXIMUM_NUM))
274 .build();
275
276 tBuilder.extension(natTreatment, gatewayNode.intgBridge())
Daniel Park5a3e9392021-03-23 08:00:00 +0900277 .setEthDst(peerRouterMacAddress)
Daniel Park2884b232021-03-04 18:58:47 +0900278 .setEthSrc(DEFAULT_GATEWAY_MAC)
Daniel Parkf3136042021-03-10 07:49:11 +0900279 .setOutput(externalPatchPortNum(deviceService, gatewayNode));
Daniel Park2884b232021-03-04 18:58:47 +0900280
281 flowService.setRule(
282 appId,
283 gatewayNode.intgBridge(),
Daniel Parkf3136042021-03-10 07:49:11 +0900284 selector.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900285 tBuilder.build(),
286 PRIORITY_STATEFUL_SNAT_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900287 GW_ENTRY_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900288 install);
289 }
290
Daniel Parkf3136042021-03-10 07:49:11 +0900291 private void setStatefulSnatDownStreamRuleForKubevirtPort(KubevirtRouter router,
292 KubevirtNode gatewayNode,
293 KubevirtPort kubevirtPort,
294 boolean install) {
295 MacAddress routerMacAddress = getRouterMacAddress(router);
Daniel Park2884b232021-03-04 18:58:47 +0900296
Daniel Parkf3136042021-03-10 07:49:11 +0900297 if (routerMacAddress == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900298 log.error("Failed to set stateful snat downstream rule because " +
299 "there's no br-int port for device {}", gatewayNode.intgBridge());
300 return;
301 }
302
303 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
304 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900305 .matchEthSrc(routerMacAddress)
Daniel Park2884b232021-03-04 18:58:47 +0900306 .matchIPDst(IpPrefix.valueOf(kubevirtPort.ipAddress(), 32));
307
Daniel Parkf3136042021-03-10 07:49:11 +0900308 KubevirtNetwork network = kubevirtNetworkService.network(kubevirtPort.networkId());
309
310 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Daniel Park2884b232021-03-04 18:58:47 +0900311 .setEthDst(kubevirtPort.macAddress())
Daniel Parkf3136042021-03-10 07:49:11 +0900312 .transition(FORWARDING_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900313
314 flowService.setRule(
315 appId,
316 gatewayNode.intgBridge(),
317 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900318 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900319 PRIORITY_STATEFUL_SNAT_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900320 GW_DROP_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900321 install);
Daniel Parkf3136042021-03-10 07:49:11 +0900322
Jian Li4b3436a2022-03-23 13:07:19 +0900323 if (network.type() == VXLAN || network.type() == GENEVE || network.type() == GRE || network.type() == STT) {
Daniel Park328fb602021-05-31 13:49:53 +0900324 setDownStreamRulesToGatewayTunBridge(network, gatewayNode, kubevirtPort, install);
Daniel Parkf3136042021-03-10 07:49:11 +0900325 }
Daniel Park2884b232021-03-04 18:58:47 +0900326 }
327
Daniel Park328fb602021-05-31 13:49:53 +0900328 private void setDownStreamRulesToGatewayTunBridge(KubevirtNetwork network,
329 KubevirtNode electedGw,
Daniel Parkf3136042021-03-10 07:49:11 +0900330 KubevirtPort port, boolean install) {
Daniel Parkf3136042021-03-10 07:49:11 +0900331 KubevirtNode workerNode = kubevirtNodeService.node(port.deviceId());
332 if (workerNode == null) {
333 return;
334 }
335
336 PortNumber tunnelPortNumber = tunnelPort(electedGw, network);
337 if (tunnelPortNumber == null) {
Daniel Park2884b232021-03-04 18:58:47 +0900338 return;
339 }
340
341 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
342 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkf3136042021-03-10 07:49:11 +0900343 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
344 .matchEthDst(port.macAddress());
345
346 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
347 .setTunnelId(Long.parseLong(network.segmentId()))
348 .extension(buildExtension(
349 deviceService,
350 electedGw.tunBridge(),
351 workerNode.dataIp().getIp4Address()),
352 electedGw.tunBridge())
353 .setOutput(tunnelPortNumber);
354
355 flowService.setRule(
356 appId,
357 electedGw.tunBridge(),
358 sBuilder.build(),
359 tBuilder.build(),
360 PRIORITY_FORWARDING_RULE,
361 TUNNEL_DEFAULT_TABLE,
362 install);
363 }
364
365 private void setStatefulSnatDownstreamRuleForRouter(KubevirtNode gatewayNode,
366 KubevirtRouter router,
Daniel Park5a3e9392021-03-23 08:00:00 +0900367 IpAddress routerSnatIp,
368 KubevirtNetwork externalNetwork,
Daniel Parkf3136042021-03-10 07:49:11 +0900369 boolean install) {
370
371 MacAddress routerMacAddress = getRouterMacAddress(router);
372
373 if (routerMacAddress == null) {
374 log.warn("Failed to set stateful snat downstream rule because " +
375 "there's no br-int port for device {}", gatewayNode.intgBridge());
376 return;
377 }
378
Daniel Parkf3136042021-03-10 07:49:11 +0900379 if (externalNetwork == null) {
380 log.warn("Failed to set stateful snat downstream rule because " +
381 "there's no external network router {}", router.name());
382 return;
383 }
384
385 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
386 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
387
Daniel Park40ecb2a2022-03-15 23:57:02 +0900388 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
389
Daniel Parkf3136042021-03-10 07:49:11 +0900390 if (externalNetwork.type() == VLAN) {
Daniel Park40ecb2a2022-03-15 23:57:02 +0900391 sBuilder.matchVlanId(VlanId.vlanId(externalNetwork.segmentId()));
Daniel Parkf3136042021-03-10 07:49:11 +0900392 tBuilder.popVlan();
Daniel Parkf3136042021-03-10 07:49:11 +0900393 }
394
Daniel Park5a3e9392021-03-23 08:00:00 +0900395 sBuilder.matchIPDst(IpPrefix.valueOf(routerSnatIp, 32));
Daniel Park2884b232021-03-04 18:58:47 +0900396
397 ExtensionTreatment natTreatment = RulePopulatorUtil
398 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
399 .commit(false)
400 .natAction(true)
Jian Lif89d9602021-04-27 19:05:49 +0900401 .table((short) GW_DROP_TABLE)
Daniel Park2884b232021-03-04 18:58:47 +0900402 .build();
403
Daniel Parkf3136042021-03-10 07:49:11 +0900404 tBuilder.setEthSrc(routerMacAddress)
405 .extension(natTreatment, gatewayNode.intgBridge());
Daniel Park2884b232021-03-04 18:58:47 +0900406
407 flowService.setRule(
408 appId,
409 gatewayNode.intgBridge(),
410 sBuilder.build(),
Daniel Parkf3136042021-03-10 07:49:11 +0900411 tBuilder.build(),
Daniel Park2884b232021-03-04 18:58:47 +0900412 PRIORITY_STATEFUL_SNAT_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900413 GW_ENTRY_TABLE,
Daniel Park2884b232021-03-04 18:58:47 +0900414 install);
Daniel Park2884b232021-03-04 18:58:47 +0900415 }
416
417 private class InternalRouterEventListener implements KubevirtRouterListener {
418 private boolean isRelevantHelper() {
419 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
420 }
421
422 @Override
423 public void event(KubevirtRouterEvent event) {
424 switch (event.type()) {
425 case KUBEVIRT_ROUTER_CREATED:
426 eventExecutor.execute(() -> processRouterCreation(event.subject()));
427 break;
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900428 case KUBEVIRT_SNAT_STATUS_DISABLED:
Daniel Park2884b232021-03-04 18:58:47 +0900429 case KUBEVIRT_ROUTER_REMOVED:
430 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
431 break;
432 case KUBEVIRT_ROUTER_UPDATED:
433 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
434 break;
435 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED:
436 eventExecutor.execute(() -> processRouterInternalNetworksAttached(event.subject(),
437 event.internal()));
438 break;
439 case KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED:
440 eventExecutor.execute(() -> processRouterInternalNetworksDetached(event.subject(),
441 event.internal()));
442 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900443 case KUBEVIRT_GATEWAY_NODE_ATTACHED:
444 eventExecutor.execute(() -> processRouterGatewayNodeAttached(event.subject(),
445 event.gateway()));
446 break;
447 case KUBEVIRT_GATEWAY_NODE_DETACHED:
448 eventExecutor.execute(() -> processRouterGatewayNodeDetached(event.subject(),
449 event.gateway()));
450 break;
Daniel Park157947f2021-04-09 17:50:53 +0900451 case KUBEVIRT_GATEWAY_NODE_CHANGED:
452 eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
453 event.gateway()));
454 break;
Daniel Parkf3136042021-03-10 07:49:11 +0900455 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900456 eventExecutor.execute(() -> processRouterExternalNetAttached(event.subject(),
457 event.externalIp(), event.externalNet(),
458 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900459 break;
460 case KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED:
Daniel Park5a3e9392021-03-23 08:00:00 +0900461 eventExecutor.execute(() -> processRouterExternalNetDetached(event.subject(),
462 event.externalIp(), event.externalNet(),
463 event.externalPeerRouterIp(), event.peerRouterMac()));
Daniel Parkf3136042021-03-10 07:49:11 +0900464 break;
Daniel Park2884b232021-03-04 18:58:47 +0900465 default:
466 //do nothing
467 break;
468 }
469 }
Daniel Parkf3136042021-03-10 07:49:11 +0900470
Daniel Park5a3e9392021-03-23 08:00:00 +0900471 private void processRouterExternalNetAttached(KubevirtRouter router, String externalIp, String externalNet,
472 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900473 if (!isRelevantHelper()) {
474 return;
475 }
476 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
477
478 if (electedGw == null) {
479 log.warn("Fail to process router external network attached gateway node snat for router {} " +
480 "there's no gateway assigned to it", router.name());
481 return;
482 }
483
Daniel Park5a3e9392021-03-23 08:00:00 +0900484 if (router.enableSnat() &&
485 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900486 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), true);
Daniel Park5a3e9392021-03-23 08:00:00 +0900487 setStatefulSnatUpstreamRules(electedGw, router, Ip4Address.valueOf(externalIp),
488 peerRouterMac, true);
489 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
490 kubevirtNetworkService.network(externalNet), true);
Daniel Parkf3136042021-03-10 07:49:11 +0900491 }
492
493 router.internal()
494 .stream()
495 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
496 .map(kubevirtNetworkService::network)
497 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900498 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
499 setStatefulSnatDownStreamRuleForKubevirtPort(router,
500 electedGw, kubevirtPort, true);
501 });
502 });
503 }
504
Daniel Park5a3e9392021-03-23 08:00:00 +0900505 private void processRouterExternalNetDetached(KubevirtRouter router, String externalIp, String externalNet,
506 String peerRouterIp, MacAddress peerRouterMac) {
Daniel Parkf3136042021-03-10 07:49:11 +0900507 if (!isRelevantHelper()) {
508 return;
509 }
510 if (!isRelevantHelper()) {
511 return;
512 }
Daniel Park05a94582021-05-12 10:57:02 +0900513 KubevirtNode electedGw = kubevirtNodeService.node(router.electedGateway());
Daniel Parkf3136042021-03-10 07:49:11 +0900514
515 if (electedGw == null) {
516 log.warn("Fail to process router external network attached gateway node snat for router {} " +
517 "there's no gateway assigned to it", router.name());
518 return;
519 }
520
Daniel Park5a3e9392021-03-23 08:00:00 +0900521 if (router.enableSnat() &&
522 peerRouterIp != null && peerRouterMac != null && externalIp != null && externalNet != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900523 setArpResponseToPeerRouter(electedGw, Ip4Address.valueOf(externalIp), false);
Daniel Park5a3e9392021-03-23 08:00:00 +0900524 setStatefulSnatUpstreamRules(electedGw, router,
525 Ip4Address.valueOf(externalIp), peerRouterMac, false);
526 setStatefulSnatDownstreamRuleForRouter(electedGw, router, Ip4Address.valueOf(externalIp),
527 kubevirtNetworkService.network(externalNet), false);
Daniel Parkf3136042021-03-10 07:49:11 +0900528 }
529
530 router.internal()
531 .stream()
532 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
533 .map(kubevirtNetworkService::network)
534 .forEach(network -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900535 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
536 setStatefulSnatDownStreamRuleForKubevirtPort(router,
537 electedGw, kubevirtPort, false);
538 });
539 });
540 }
541
542 private void processRouterGatewayNodeAttached(KubevirtRouter router, String attachedGatewayId) {
543 if (!isRelevantHelper()) {
544 return;
545 }
546
547 KubevirtNode attachedGateway = kubevirtNodeService.node(attachedGatewayId);
548 if (attachedGateway == null) {
549 return;
550 }
551
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900552 if (!router.enableSnat()) {
553 return;
554 }
555
Daniel Parkf3136042021-03-10 07:49:11 +0900556 router.internal()
557 .stream()
558 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
559 .map(kubevirtNetworkService::network)
560 .forEach(network -> {
561 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
562 if (routerSnatIp == null) {
563 return;
564 }
565 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
566 setStatefulSnatDownStreamRuleForKubevirtPort(router,
567 attachedGateway, kubevirtPort, true);
568 });
569 });
570 }
571
572 private void processRouterGatewayNodeDetached(KubevirtRouter router, String detachedGatewayId) {
573 if (!isRelevantHelper()) {
574 return;
575 }
576
577 KubevirtNode detachedGateway = kubevirtNodeService.node(detachedGatewayId);
578 if (detachedGateway == null) {
579 return;
580 }
581
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900582 if (!router.enableSnat()) {
583 return;
584 }
585
Daniel Parkf3136042021-03-10 07:49:11 +0900586 router.internal()
587 .stream()
588 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
589 .map(kubevirtNetworkService::network)
590 .forEach(network -> {
591 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
592 if (routerSnatIp == null) {
593 return;
594 }
595
596 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
597 setStatefulSnatDownStreamRuleForKubevirtPort(router,
598 detachedGateway, kubevirtPort, false);
599 });
600 });
601 }
602
Daniel Park2884b232021-03-04 18:58:47 +0900603 private void processRouterInternalNetworksAttached(KubevirtRouter router,
604 Set<String> attachedInternalNetworks) {
605 if (!isRelevantHelper()) {
606 return;
607 }
608
609 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
610 if (gwNode == null) {
611 return;
612 }
613
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900614 if (!router.enableSnat()) {
615 return;
616 }
617
Daniel Park2884b232021-03-04 18:58:47 +0900618 attachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900619 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
620 if (routerSnatIp == null) {
621 return;
622 }
623
Daniel Park2884b232021-03-04 18:58:47 +0900624 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900625 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900626 });
627 });
628 }
629
630 private void processRouterInternalNetworksDetached(KubevirtRouter router,
631 Set<String> detachedInternalNetworks) {
632 if (!isRelevantHelper()) {
633 return;
634 }
635
636 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
637 if (gwNode == null) {
638 return;
639 }
640
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900641 if (!router.enableSnat()) {
642 return;
643 }
644
Daniel Park2884b232021-03-04 18:58:47 +0900645 detachedInternalNetworks.forEach(networkId -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900646 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
647 if (routerSnatIp == null) {
648 log.info("snatIp is null");
649 return;
650 }
651
Daniel Park2884b232021-03-04 18:58:47 +0900652 kubevirtPortService.ports(networkId).forEach(kubevirtPort -> {
Daniel Parkf3136042021-03-10 07:49:11 +0900653 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900654 });
655 });
656 }
657 private void processRouterCreation(KubevirtRouter router) {
658 if (!isRelevantHelper()) {
659 return;
660 }
661 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900662 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Daniel Park2884b232021-03-04 18:58:47 +0900663 }
664 }
665
666 private void processRouterDeletion(KubevirtRouter router) {
667 if (!isRelevantHelper()) {
668 return;
669 }
Daniel Parkde238262021-06-14 07:31:06 +0900670
671
672 if (!router.external().isEmpty() && router.peerRouter() != null && router.electedGateway() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900673 initGatewayNodeSnatForRouter(router, router.electedGateway(), false);
Daniel Parka5ba88d2021-05-28 15:46:46 +0900674
Daniel Parkde238262021-06-14 07:31:06 +0900675 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
Daniel Parka5ba88d2021-05-28 15:46:46 +0900676
Daniel Parkde238262021-06-14 07:31:06 +0900677 router.internal()
678 .stream()
679 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
680 .map(kubevirtNetworkService::network)
681 .forEach(network -> {
682 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
683 if (routerSnatIp == null) {
684 return;
685 }
686
687 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
688 setStatefulSnatDownStreamRuleForKubevirtPort(router,
689 gatewayNode, kubevirtPort, false);
690 });
Daniel Parka5ba88d2021-05-28 15:46:46 +0900691 });
Daniel Parkde238262021-06-14 07:31:06 +0900692 }
Daniel Park2884b232021-03-04 18:58:47 +0900693 }
694
695 private void processRouterUpdate(KubevirtRouter router) {
696 if (!isRelevantHelper()) {
697 return;
698 }
699 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park157947f2021-04-09 17:50:53 +0900700 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
Jian Li0ab242b2021-07-16 17:41:13 +0900701
702 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
703
704 router.internal()
705 .stream()
706 .filter(networkId -> kubevirtNetworkService.network(networkId) != null)
707 .map(kubevirtNetworkService::network)
708 .forEach(network -> {
709 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
710 if (routerSnatIp == null) {
711 return;
712 }
713
714 kubevirtPortService.ports(network.networkId()).forEach(kubevirtPort -> {
715 setStatefulSnatDownStreamRuleForKubevirtPort(router,
716 gatewayNode, kubevirtPort, true);
717 });
718 });
Daniel Parkc7dece92022-04-11 13:11:12 +0900719 sendGarpPacketForSnatIp(router);
Daniel Park2884b232021-03-04 18:58:47 +0900720 }
721 }
Daniel Park157947f2021-04-09 17:50:53 +0900722
723 private void processRouterGatewayNodeChanged(KubevirtRouter router,
724 String disAssociatedGateway) {
725 if (!isRelevantHelper()) {
726 return;
727 }
728
729 if (router.enableSnat() && !router.external().isEmpty() && router.peerRouter() != null) {
Daniel Park1aeb8eb2022-04-04 08:28:54 +0900730 DeviceId disAssociatedGatewayIntDeviceId = kubevirtNodeService.node(disAssociatedGateway).intgBridge();
731
732 //Only do this in case disassociated gateway device is still alive.
733 if (disAssociatedGatewayIntDeviceId != null &&
734 deviceService.isAvailable(disAssociatedGatewayIntDeviceId)) {
735 initGatewayNodeSnatForRouter(router, disAssociatedGateway, false);
736 }
Daniel Park157947f2021-04-09 17:50:53 +0900737 initGatewayNodeSnatForRouter(router, router.electedGateway(), true);
738
739 processRouterGatewayNodeDetached(router, disAssociatedGateway);
740 processRouterGatewayNodeAttached(router, router.electedGateway());
741
742 sendGarpPacketForSnatIp(router);
743 }
744 }
745
746 private void sendGarpPacketForSnatIp(KubevirtRouter router) {
747 if (router == null || router.electedGateway() == null) {
748 return;
749 }
750
751 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
752
753 if (routerSnatIp == null) {
754 log.warn("Fail to initialize gateway node snat for router {} " +
755 "because there's no gateway snat ip assigned to it", router.name());
756 return;
757 }
758
759 Ethernet ethernet = buildGarpPacket(DEFAULT_GATEWAY_MAC, IpAddress.valueOf(routerSnatIp));
760
761 if (ethernet == null) {
762 return;
763 }
764
765 KubevirtNode gatewayNode = kubevirtNodeService.node(router.electedGateway());
766
767 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
768 .setOutput(externalPatchPortNum(deviceService, gatewayNode)).build();
769
770 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
771 ByteBuffer.wrap(ethernet.serialize())));
772 }
Daniel Park2884b232021-03-04 18:58:47 +0900773 }
774
Daniel Park2884b232021-03-04 18:58:47 +0900775 private class InternalKubevirtPortListener implements KubevirtPortListener {
776
777 private boolean isRelevantHelper() {
778 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
779 }
780
781 @Override
782 public void event(KubevirtPortEvent event) {
783 switch (event.type()) {
784 case KUBEVIRT_PORT_CREATED:
785 eventExecutor.execute(() -> processPortCreation(event.subject()));
786 break;
787 case KUBEVIRT_PORT_UPDATED:
788 eventExecutor.execute(() -> processPortUpdate(event.subject()));
789 break;
790 case KUBEVIRT_PORT_REMOVED:
791 eventExecutor.execute(() -> processPortDeletion(event.subject()));
792 break;
Jian Li969abd82022-10-17 18:28:19 +0900793 case KUBEVIRT_PORT_MIGRATED:
794 eventExecutor.execute(() -> processPortCreation(event.subject()));
795 eventExecutor.execute(() -> processPortDeletion(event.oldSubject()));
796 break;
Daniel Park2884b232021-03-04 18:58:47 +0900797 default:
798 //do nothing
799 break;
800 }
801 }
802
803 private void processPortCreation(KubevirtPort kubevirtPort) {
804 if (!isRelevantHelper()) {
805 return;
806 }
807
Daniel Parkbabde9c2021-03-09 13:37:42 +0900808 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900809 if (router == null) {
810 return;
811 }
812
813 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
814
815 if (gwNode != null) {
816 IpAddress gatewaySnatIp = getRouterSnatIpAddress(kubevirtRouterService, kubevirtPort.networkId());
817 if (gatewaySnatIp == null) {
818 return;
819 }
Daniel Parkf3136042021-03-10 07:49:11 +0900820 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900821 }
822 }
823
824 private void processPortUpdate(KubevirtPort kubevirtPort) {
825 if (!isRelevantHelper()) {
826 return;
827 }
828
Daniel Parkbabde9c2021-03-09 13:37:42 +0900829 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900830 if (router == null) {
831 return;
832 }
833
834 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
835
836 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900837 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, true);
Daniel Park2884b232021-03-04 18:58:47 +0900838 }
839 }
840
841 private void processPortDeletion(KubevirtPort kubevirtPort) {
842 if (!isRelevantHelper()) {
843 return;
844 }
845
Daniel Parkbabde9c2021-03-09 13:37:42 +0900846 KubevirtRouter router = getRouterForKubevirtPort(kubevirtRouterService, kubevirtPort);
Daniel Park2884b232021-03-04 18:58:47 +0900847 if (router == null) {
848 return;
849 }
850
851 KubevirtNode gwNode = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
852
853 if (gwNode != null) {
Daniel Parkf3136042021-03-10 07:49:11 +0900854 setStatefulSnatDownStreamRuleForKubevirtPort(router, gwNode, kubevirtPort, false);
Daniel Park2884b232021-03-04 18:58:47 +0900855 }
856 }
Daniel Park2884b232021-03-04 18:58:47 +0900857 }
Daniel Park2884b232021-03-04 18:58:47 +0900858}