blob: 26e27ff6205f5714d56860fe0602b574532023a1 [file] [log] [blame]
Daniel Parkf3136042021-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
Daniel Parkf3136042021-03-10 07:49:11 +0900300 private void setFloatingIpDownstreamRulesToGatewayTunBridge(KubevirtRouter router,
301 KubevirtFloatingIp floatingIp,
302 KubevirtNetwork network,
303 KubevirtPort port,
304 boolean install) {
305 KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
306
307 if (electedGw == null) {
308 log.warn("Failed to install floating Ip rules for floating ip {} " +
309 "because there's no gateway assigned to it", floatingIp.floatingIp());
310 return;
311 }
312
313 KubevirtNode workerNode = kubevirtNodeService.node(port.deviceId());
314 if (workerNode == null) {
315 log.warn("Failed to install floating Ip rules for floating ip {} " +
316 "because fail to fine the worker node that the associated port is running on",
317 floatingIp.floatingIp());
Jian Li9793ec42021-03-19 15:03:32 +0900318 return;
Daniel Parkf3136042021-03-10 07:49:11 +0900319 }
320
321 PortNumber tunnelPortNumber = tunnelPort(electedGw, network);
322 if (tunnelPortNumber == null) {
323 return;
324 }
325
Daniel Parkf3136042021-03-10 07:49:11 +0900326 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
327 .matchEthType(Ethernet.TYPE_IPV4)
328 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
329 .matchEthDst(port.macAddress());
330
331 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
332 .setTunnelId(Long.parseLong(network.segmentId()))
333 .extension(buildExtension(
334 deviceService,
335 electedGw.tunBridge(),
336 workerNode.dataIp().getIp4Address()),
337 electedGw.tunBridge())
338 .setOutput(tunnelPortNumber);
339
340 flowService.setRule(
341 appId,
342 electedGw.tunBridge(),
343 sBuilder.build(),
344 tBuilder.build(),
345 PRIORITY_FORWARDING_RULE,
346 TUNNEL_DEFAULT_TABLE,
347 install);
348 }
349
350 private class InternalRouterEventListener implements KubevirtRouterListener {
351 private boolean isRelevantHelper() {
352 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
353 }
354
355
356 @Override
357 public void event(KubevirtRouterEvent event) {
358 switch (event.type()) {
Daniel Parkf3136042021-03-10 07:49:11 +0900359 case KUBEVIRT_FLOATING_IP_ASSOCIATED:
360 eventExecutor.execute(() -> processFloatingIpAssociation(event.subject(),
361 event.floatingIp()));
362 break;
363 case KUBEVIRT_FLOATING_IP_DISASSOCIATED:
364 eventExecutor.execute(() -> processFloatingIpDisassociation(event.subject(),
365 event.floatingIp()));
366 break;
367
368 default:
369 //do nothing
370 break;
371 }
372 }
373
Daniel Parkf3136042021-03-10 07:49:11 +0900374 private void processFloatingIpAssociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
375 if (!isRelevantHelper()) {
376 return;
377 }
378 setFloatingIpRules(router, floatingIp, true);
379 }
380
381 private void processFloatingIpDisassociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
382 if (!isRelevantHelper()) {
383 return;
384 }
385 setFloatingIpRules(router, floatingIp, false);
386 }
387 }
388}