blob: 726abf2c0a4667b0a3504b95d4add31be0c1eaae [file] [log] [blame]
Daniel Parke7e3d6a2021-03-10 07:49:11 +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.IpPrefix;
22import org.onlab.packet.MacAddress;
23import org.onosproject.cluster.ClusterService;
24import org.onosproject.cluster.LeadershipService;
25import org.onosproject.cluster.NodeId;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
29import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
30import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
31import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
32import org.onosproject.kubevirtnetworking.api.KubevirtPort;
33import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
34import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
35import org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent;
36import org.onosproject.kubevirtnetworking.api.KubevirtRouterListener;
37import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
38import org.onosproject.kubevirtnetworking.util.RulePopulatorUtil;
39import org.onosproject.kubevirtnode.api.KubevirtNode;
40import org.onosproject.kubevirtnode.api.KubevirtNodeService;
41import org.onosproject.net.Device;
42import org.onosproject.net.PortNumber;
43import org.onosproject.net.device.DeviceAdminService;
44import org.onosproject.net.driver.DriverService;
45import org.onosproject.net.flow.DefaultTrafficSelector;
46import org.onosproject.net.flow.DefaultTrafficTreatment;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.osgi.service.component.annotations.Activate;
50import org.osgi.service.component.annotations.Component;
51import org.osgi.service.component.annotations.Deactivate;
52import org.osgi.service.component.annotations.Reference;
53import org.osgi.service.component.annotations.ReferenceCardinality;
54import org.slf4j.Logger;
55
56import java.util.Objects;
57import java.util.concurrent.ExecutorService;
58
59import static java.util.concurrent.Executors.newSingleThreadExecutor;
60import static org.onlab.util.Tools.groupedThreads;
61import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
62import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
63import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
64import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
65import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FLOATING_IP_RULE;
66import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
67import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
68import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
69import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
70import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
71import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.externalPatchPortNum;
72import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
73import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
74import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
75import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
76import static org.slf4j.LoggerFactory.getLogger;
77
78/**
79 * Handles kubevirt floating ip.
80 */
81@Component(immediate = true)
82public class KubevirtFloatingIpHandler {
83 protected final Logger log = getLogger(getClass());
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY)
86 protected CoreService coreService;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY)
89 protected ClusterService clusterService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY)
92 protected LeadershipService leadershipService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY)
95 protected DeviceAdminService deviceService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY)
98 protected KubevirtPortService kubevirtPortService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
101 protected KubevirtNodeService kubevirtNodeService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
104 protected KubevirtNetworkService kubevirtNetworkService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
107 protected KubevirtFlowRuleService flowService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
110 protected DriverService driverService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
113 protected KubevirtRouterService kubevirtRouterService;
114
115 private final ExecutorService eventExecutor = newSingleThreadExecutor(
116 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
117
118 private ApplicationId appId;
119 private NodeId localNodeId;
120
121 private final InternalRouterEventListener kubevirtRouterlistener =
122 new InternalRouterEventListener();
123
124 @Activate
125 protected void activate() {
126 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
127 localNodeId = clusterService.getLocalNode().id();
128 leadershipService.runForLeadership(appId.name());
129 kubevirtRouterService.addListener(kubevirtRouterlistener);
130
131 log.info("Started");
132 }
133
134 @Deactivate
135 protected void deactivate() {
136 leadershipService.withdraw(appId.name());
137 kubevirtRouterService.removeListener(kubevirtRouterlistener);
138
139 eventExecutor.shutdown();
140
141 log.info("Stopped");
142 }
143
144 private void setFloatingIpRules(KubevirtRouter router,
145 KubevirtFloatingIp floatingIp,
146 boolean install) {
147
148 KubevirtPort kubevirtPort = getKubevirtPort(floatingIp);
149 if (kubevirtPort == null) {
150 log.warn("Failed to install floating Ip rules for floating ip {} " +
151 "because there's no kubevirt port associated to it", floatingIp.floatingIp());
152 return;
153 }
154
155 KubevirtNetwork kubevirtNetwork = kubevirtNetworkService.network(kubevirtPort.networkId());
156 if (kubevirtNetwork.type() == VXLAN || kubevirtNetwork.type() == GENEVE || kubevirtNetwork.type() == GRE) {
157 setFloatingIpDownstreamRulesToGatewayTunBridge(router, floatingIp, kubevirtNetwork, kubevirtPort, install);
158 }
159
160 setFloatingIpArpResponseRules(router, floatingIp, kubevirtPort, install);
161 setFloatingIpUpstreamRules(router, floatingIp, kubevirtPort, install);
162 setFloatingIpDownstreamRules(router, floatingIp, kubevirtPort, install);
163 }
164
165 private void setFloatingIpArpResponseRules(KubevirtRouter router,
166 KubevirtFloatingIp floatingIp,
167 KubevirtPort port,
168 boolean install) {
169
170 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
171
172 if (electedGw == null) {
173 log.warn("Failed to install floating Ip rules for floating ip {} " +
174 "because there's no gateway assigned to it", floatingIp.floatingIp());
175 return;
176 }
177
178 TrafficSelector selector = DefaultTrafficSelector.builder()
179 .matchInPort(externalPatchPortNum(deviceService, electedGw))
180 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
181 .matchArpOp(ARP.OP_REQUEST)
182 .matchArpTpa(floatingIp.floatingIp().getIp4Address())
183 .build();
184
185 Device device = deviceService.getDevice(electedGw.intgBridge());
186
187 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
188 .extension(RulePopulatorUtil.buildMoveEthSrcToDstExtension(device), device.id())
189 .extension(RulePopulatorUtil.buildMoveArpShaToThaExtension(device), device.id())
190 .extension(RulePopulatorUtil.buildMoveArpSpaToTpaExtension(device), device.id())
191 .setArpOp(ARP.OP_REPLY)
192 .setEthSrc(port.macAddress())
193 .setArpSha(port.macAddress())
194 .setArpSpa(floatingIp.floatingIp().getIp4Address())
195 .setOutput(PortNumber.IN_PORT)
196 .build();
197
198 flowService.setRule(
199 appId,
200 electedGw.intgBridge(),
201 selector,
202 treatment,
203 PRIORITY_ARP_GATEWAY_RULE,
204 PRE_FLAT_TABLE,
205 install);
206 }
207 private KubevirtPort getKubevirtPort(KubevirtFloatingIp floatingIp) {
208
209 return kubevirtPortService.ports().stream()
210 .filter(port -> port.ipAddress().equals(floatingIp.fixedIp()))
211 .findAny().orElse(null);
212 }
213
214 private void setFloatingIpUpstreamRules(KubevirtRouter router,
215 KubevirtFloatingIp floatingIp,
216 KubevirtPort port,
217 boolean install) {
218
219 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
220
221 if (electedGw == null) {
222 log.warn("Failed to install floating Ip rules for floating ip {} " +
223 "because there's no gateway assigned to it", floatingIp.floatingIp());
224 return;
225 }
226
227 MacAddress peerMacAddress = router.peerRouter().macAddress();
228
229 if (peerMacAddress == null) {
230 log.warn("Failed to install floating Ip rules for floating ip {} and router {}" +
231 "because there's no peer router mac address", floatingIp.floatingIp(),
232 router.name());
233 return;
234 }
235
236 MacAddress routerMacAddress = getRouterMacAddress(router);
237
238 TrafficSelector selector = DefaultTrafficSelector.builder()
239 .matchEthType(Ethernet.TYPE_IPV4)
240 .matchEthSrc(port.macAddress())
241 .matchEthDst(routerMacAddress)
242 .matchIPSrc(IpPrefix.valueOf(floatingIp.fixedIp(), 32))
243 .build();
244
245
246 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
247 .setEthDst(peerMacAddress)
248 .setEthSrc(port.macAddress())
249 .setIpSrc(floatingIp.floatingIp())
250 .setOutput(externalPatchPortNum(deviceService, electedGw))
251 .build();
252
253 flowService.setRule(
254 appId,
255 electedGw.intgBridge(),
256 selector,
257 treatment,
258 PRIORITY_FLOATING_IP_RULE,
259 PRE_FLAT_TABLE,
260 install);
261 }
262
263 private void setFloatingIpDownstreamRules(KubevirtRouter router,
264 KubevirtFloatingIp floatingIp,
265 KubevirtPort port,
266 boolean install) {
267 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
268
269 if (electedGw == null) {
270 log.warn("Failed to install floating Ip rules for floating ip {} " +
271 "because there's no gateway assigned to it", floatingIp.floatingIp());
272 return;
273 }
274
275 MacAddress routerMacAddress = getRouterMacAddress(router);
276
277 TrafficSelector selector = DefaultTrafficSelector.builder()
278 .matchEthType(Ethernet.TYPE_IPV4)
279 .matchEthDst(port.macAddress())
280 .matchIPDst(IpPrefix.valueOf(floatingIp.floatingIp(), 32))
281 .build();
282
283 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
284 .setEthSrc(routerMacAddress)
285 .setEthDst(port.macAddress())
286 .setIpDst(floatingIp.fixedIp())
287 .transition(FORWARDING_TABLE)
288 .build();
289
290 flowService.setRule(
291 appId,
292 electedGw.intgBridge(),
293 selector,
294 treatment,
295 PRIORITY_FLOATING_IP_RULE,
296 PRE_FLAT_TABLE,
297 install);
298 }
299
300
301 private void setFloatingIpDownstreamRulesToGatewayTunBridge(KubevirtRouter router,
302 KubevirtFloatingIp floatingIp,
303 KubevirtNetwork network,
304 KubevirtPort port,
305 boolean install) {
306 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
307
308 if (electedGw == null) {
309 log.warn("Failed to install floating Ip rules for floating ip {} " +
310 "because there's no gateway assigned to it", floatingIp.floatingIp());
311 return;
312 }
313
314 KubevirtNode workerNode = kubevirtNodeService.node(port.deviceId());
315 if (workerNode == null) {
316 log.warn("Failed to install floating Ip rules for floating ip {} " +
317 "because fail to fine the worker node that the associated port is running on",
318 floatingIp.floatingIp());
319 }
320
321 PortNumber tunnelPortNumber = tunnelPort(electedGw, network);
322 if (tunnelPortNumber == null) {
323 return;
324 }
325
326
327 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
328 .matchEthType(Ethernet.TYPE_IPV4)
329 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
330 .matchEthDst(port.macAddress());
331
332 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
333 .setTunnelId(Long.parseLong(network.segmentId()))
334 .extension(buildExtension(
335 deviceService,
336 electedGw.tunBridge(),
337 workerNode.dataIp().getIp4Address()),
338 electedGw.tunBridge())
339 .setOutput(tunnelPortNumber);
340
341 flowService.setRule(
342 appId,
343 electedGw.tunBridge(),
344 sBuilder.build(),
345 tBuilder.build(),
346 PRIORITY_FORWARDING_RULE,
347 TUNNEL_DEFAULT_TABLE,
348 install);
349 }
350
351 private class InternalRouterEventListener implements KubevirtRouterListener {
352 private boolean isRelevantHelper() {
353 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
354 }
355
356
357 @Override
358 public void event(KubevirtRouterEvent event) {
359 switch (event.type()) {
360 case KUBEVIRT_ROUTER_CREATED:
361 eventExecutor.execute(() -> processRouterCreation(event.subject()));
362 break;
363 case KUBEVIRT_ROUTER_UPDATED:
364 eventExecutor.execute(() -> processRouterUpdate(event.subject()));
365 break;
366 case KUBEVIRT_ROUTER_REMOVED:
367 eventExecutor.execute(() -> processRouterDeletion(event.subject()));
368 break;
369 case KUBEVIRT_FLOATING_IP_ASSOCIATED:
370 eventExecutor.execute(() -> processFloatingIpAssociation(event.subject(),
371 event.floatingIp()));
372 break;
373 case KUBEVIRT_FLOATING_IP_DISASSOCIATED:
374 eventExecutor.execute(() -> processFloatingIpDisassociation(event.subject(),
375 event.floatingIp()));
376 break;
377
378 default:
379 //do nothing
380 break;
381 }
382 }
383
384 private void processRouterCreation(KubevirtRouter router) {
385 if (!isRelevantHelper()) {
386 return;
387 }
388 kubevirtRouterService.floatingIpsByRouter(router.name())
389 .stream()
390 .filter(fip -> fip.fixedIp() != null)
391 .forEach(fip -> {
392 processFloatingIpAssociation(router, fip);
393 });
394 }
395
396 private void processRouterDeletion(KubevirtRouter router) {
397 if (!isRelevantHelper()) {
398 return;
399 }
400 kubevirtRouterService.floatingIpsByRouter(router.name())
401 .stream()
402 .filter(fip -> fip.fixedIp() != null)
403 .forEach(fip -> {
404 processFloatingIpDisassociation(router, fip);
405 });
406 }
407
408 private void processRouterUpdate(KubevirtRouter router) {
409 if (!isRelevantHelper()) {
410 return;
411 }
412 kubevirtRouterService.floatingIpsByRouter(router.name())
413 .stream()
414 .filter(fip -> fip.fixedIp() != null)
415 .forEach(fip -> {
416 processFloatingIpAssociation(router, fip);
417 });
418 }
419
420 private void processFloatingIpAssociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
421 if (!isRelevantHelper()) {
422 return;
423 }
424 setFloatingIpRules(router, floatingIp, true);
425 }
426
427 private void processFloatingIpDisassociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
428 if (!isRelevantHelper()) {
429 return;
430 }
431 setFloatingIpRules(router, floatingIp, false);
432 }
433 }
434}