blob: ab997428309b41051da0ac87e73e54c843f5a856 [file] [log] [blame]
Jian Li4b5048a2020-10-08 02:57:45 +09001/*
2 * Copyright 2020-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.openstacknetworking.impl;
17
18
Jian Li6d2ffbf2020-11-04 15:58:18 +090019import org.onlab.packet.ARP;
Jian Li4b5048a2020-10-08 02:57:45 +090020import org.onlab.packet.Ethernet;
Jian Li6d2ffbf2020-11-04 15:58:18 +090021import org.onlab.packet.IPv4;
22import org.onlab.packet.Ip4Address;
Jian Li4b5048a2020-10-08 02:57:45 +090023import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
25import org.onlab.packet.MacAddress;
Jian Li6d2ffbf2020-11-04 15:58:18 +090026import org.onlab.packet.TpPort;
Jian Li4b5048a2020-10-08 02:57:45 +090027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Jian Li6d2ffbf2020-11-04 15:58:18 +090029import org.onosproject.net.Port;
Jian Li4b5048a2020-10-08 02:57:45 +090030import org.onosproject.net.PortNumber;
Jian Li6d2ffbf2020-11-04 15:58:18 +090031import org.onosproject.net.device.DeviceService;
Jian Li4b5048a2020-10-08 02:57:45 +090032import org.onosproject.net.flow.DefaultTrafficSelector;
33import org.onosproject.net.flow.DefaultTrafficTreatment;
34import org.onosproject.net.flow.TrafficSelector;
35import org.onosproject.net.flow.TrafficTreatment;
36import org.onosproject.openstacknetworking.api.Constants;
37import org.onosproject.openstacknetworking.api.InstancePort;
38import org.onosproject.openstacknetworking.api.InstancePortService;
39import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
40import org.onosproject.openstacknetworking.api.OpenstackGroupRuleService;
41import org.onosproject.openstacknetworking.api.OpenstackK8sIntegrationService;
42import org.onosproject.openstacknetworking.api.OpenstackNetwork;
43import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
44import org.onosproject.openstacknode.api.OpenstackNode;
45import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li6d2ffbf2020-11-04 15:58:18 +090046import org.openstack4j.model.network.Network;
Jian Li4b5048a2020-10-08 02:57:45 +090047import org.osgi.service.component.annotations.Activate;
48import org.osgi.service.component.annotations.Component;
49import org.osgi.service.component.annotations.Deactivate;
50import org.osgi.service.component.annotations.Reference;
51import org.osgi.service.component.annotations.ReferenceCardinality;
52import org.slf4j.Logger;
53
Jian Li6d2ffbf2020-11-04 15:58:18 +090054import java.util.Map;
55import java.util.Objects;
56
57import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Jian Li4b5048a2020-10-08 02:57:45 +090058import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
59import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
60import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CNI_PT_IP_RULE;
Jian Li6d2ffbf2020-11-04 15:58:18 +090061import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CNI_PT_NODE_PORT_ARP_EXT_RULE;
62import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CNI_PT_NODE_PORT_ARP_RULE;
63import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CNI_PT_NODE_PORT_IP_RULE;
Jian Li4b5048a2020-10-08 02:57:45 +090064import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
65import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
66import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.shiftIpDomain;
Jian Li6d2ffbf2020-11-04 15:58:18 +090067import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.structurePortName;
68import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildPortRangeMatches;
69import static org.onosproject.openstacknode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
Jian Li4b5048a2020-10-08 02:57:45 +090070import static org.slf4j.LoggerFactory.getLogger;
71
72/**
73 * Implementation of openstack kubernetes integration service.
74 */
75
76@Component(
77 immediate = true,
78 service = { OpenstackK8sIntegrationService.class }
79)
80public class OpenstackK8sIntegrationManager implements OpenstackK8sIntegrationService {
81
82 protected final Logger log = getLogger(getClass());
83
Jian Li6d2ffbf2020-11-04 15:58:18 +090084 private static final String SHIFTED_IP_PREFIX = "172.10";
85 private static final int NODE_PORT_MIN = 30000;
86 private static final int NODE_PORT_MAX = 32767;
87 public static final String NODE_FAKE_IP_STR = "172.172.172.172";
Jian Li4b5048a2020-10-08 02:57:45 +090088
89 @Reference(cardinality = ReferenceCardinality.MANDATORY)
90 protected CoreService coreService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY)
93 protected OpenstackFlowRuleService osFlowRuleService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY)
96 protected OpenstackGroupRuleService osGroupRuleService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY)
99 protected OpenstackNodeService osNodeService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
102 protected OpenstackNetworkService osNetworkService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
105 protected InstancePortService instancePortService;
106
Jian Li6d2ffbf2020-11-04 15:58:18 +0900107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
108 protected DeviceService deviceService;
109
Jian Li4b5048a2020-10-08 02:57:45 +0900110 private ApplicationId appId;
111
112 @Activate
113 protected void activate() {
114 appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
115
116 log.info("Started");
117 }
118
119 @Deactivate
120 protected void deactivate() {
121 log.info("Stopped");
122 }
123
124 @Override
125 public void installCniPtNodeRules(IpAddress k8sNodeIp,
126 IpPrefix podCidr, IpPrefix serviceCidr,
127 IpAddress podGatewayIp, String osK8sIntPortName,
128 MacAddress k8sIntOsPortMac) {
129 setNodeToPodIpRules(k8sNodeIp, podCidr, serviceCidr,
130 podGatewayIp, osK8sIntPortName, k8sIntOsPortMac, true);
131 setPodToNodeIpRules(k8sNodeIp, podGatewayIp, osK8sIntPortName, true);
132 }
133
134 @Override
135 public void uninstallCniPtNodeRules(IpAddress k8sNodeIp,
136 IpPrefix podCidr, IpPrefix serviceCidr,
137 IpAddress podGatewayIp, String osK8sIntPortName,
138 MacAddress k8sIntOsPortMac) {
139 setNodeToPodIpRules(k8sNodeIp, podCidr, serviceCidr,
140 podGatewayIp, osK8sIntPortName, k8sIntOsPortMac, false);
141 setPodToNodeIpRules(k8sNodeIp, podGatewayIp, osK8sIntPortName, false);
142 }
143
Jian Li6d2ffbf2020-11-04 15:58:18 +0900144 @Override
145 public void installCniPtNodePortRules(IpAddress k8sNodeIp, String osK8sExtPortName) {
146 setNodePortIngressRules(k8sNodeIp, osK8sExtPortName, true);
147 setNodePortEgressRules(k8sNodeIp, osK8sExtPortName, true);
148
149 setArpRequestRules(k8sNodeIp, osK8sExtPortName, true);
150 setArpReplyRules(k8sNodeIp, osK8sExtPortName, true);
151 }
152
153 @Override
154 public void uninstallCniPtNodePortRules(IpAddress k8sNodeIp, String osK8sExtPortName) {
155 setNodePortIngressRules(k8sNodeIp, osK8sExtPortName, false);
156 setNodePortEgressRules(k8sNodeIp, osK8sExtPortName, false);
157
158 setArpRequestRules(k8sNodeIp, osK8sExtPortName, false);
159 setArpReplyRules(k8sNodeIp, osK8sExtPortName, false);
160 }
161
Jian Li4b5048a2020-10-08 02:57:45 +0900162 private void setNodeToPodIpRules(IpAddress k8sNodeIp,
163 IpPrefix podCidr, IpPrefix serviceCidr,
164 IpAddress gatewayIp, String osK8sIntPortName,
165 MacAddress k8sIntOsPortMac, boolean install) {
166
Jian Li6d2ffbf2020-11-04 15:58:18 +0900167 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
Jian Li4b5048a2020-10-08 02:57:45 +0900168
169 if (osNode == null) {
170 return;
171 }
172
173 PortNumber osK8sIntPortNum = osNode.portNumByName(osK8sIntPortName);
174
175 if (osK8sIntPortNum == null) {
176 return;
177 }
178
179 TrafficSelector originalPodSelector = DefaultTrafficSelector.builder()
180 .matchEthType(Ethernet.TYPE_IPV4)
181 .matchIPSrc(IpPrefix.valueOf(k8sNodeIp, 32))
182 .matchIPDst(podCidr)
183 .build();
184
185 TrafficSelector transformedPodSelector = DefaultTrafficSelector.builder()
186 .matchEthType(Ethernet.TYPE_IPV4)
187 .matchIPSrc(IpPrefix.valueOf(k8sNodeIp, 32))
188 .matchIPDst(IpPrefix.valueOf(shiftIpDomain(podCidr.toString(), SHIFTED_IP_PREFIX)))
189 .build();
190
191 TrafficSelector serviceSelector = DefaultTrafficSelector.builder()
192 .matchEthType(Ethernet.TYPE_IPV4)
193 .matchIPSrc(IpPrefix.valueOf(k8sNodeIp, 32))
194 .matchIPDst(serviceCidr)
195 .build();
196
197 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
198 .setIpSrc(gatewayIp)
199 .setEthSrc(k8sIntOsPortMac)
200 .setOutput(osK8sIntPortNum)
201 .build();
202
203 osFlowRuleService.setRule(
204 appId,
205 osNode.intgBridge(),
206 originalPodSelector,
207 treatment,
208 PRIORITY_CNI_PT_IP_RULE,
209 FLAT_TABLE,
210 install
211 );
212
213 osFlowRuleService.setRule(
214 appId,
215 osNode.intgBridge(),
216 transformedPodSelector,
217 treatment,
218 PRIORITY_CNI_PT_IP_RULE,
219 FLAT_TABLE,
220 install
221 );
222
223 osFlowRuleService.setRule(
224 appId,
225 osNode.intgBridge(),
226 serviceSelector,
227 treatment,
228 PRIORITY_CNI_PT_IP_RULE,
229 FLAT_TABLE,
230 install
231 );
232 }
233
234 private void setPodToNodeIpRules(IpAddress k8sNodeIp, IpAddress gatewayIp,
235 String osK8sIntPortName, boolean install) {
Jian Li6d2ffbf2020-11-04 15:58:18 +0900236 InstancePort instPort = instPortByNodeIp(k8sNodeIp);
Jian Li4b5048a2020-10-08 02:57:45 +0900237
238 if (instPort == null) {
239 return;
240 }
241
Jian Li6d2ffbf2020-11-04 15:58:18 +0900242 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
Jian Li4b5048a2020-10-08 02:57:45 +0900243
244 if (osNode == null) {
245 return;
246 }
247
248 PortNumber osK8sIntPortNum = osNode.portNumByName(osK8sIntPortName);
249
250 if (osK8sIntPortNum == null) {
251 return;
252 }
253
254 TrafficSelector selector = DefaultTrafficSelector.builder()
255 .matchEthType(Ethernet.TYPE_IPV4)
256 .matchIPDst(IpPrefix.valueOf(gatewayIp, 32))
257 .matchInPort(osK8sIntPortNum)
258 .build();
259
260 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
261 .setIpDst(k8sNodeIp)
262 .setEthDst(instPort.macAddress())
263 .transition(STAT_FLAT_OUTBOUND_TABLE)
264 .build();
265
266 osFlowRuleService.setRule(
267 appId,
268 osNode.intgBridge(),
269 selector,
270 treatment,
271 PRIORITY_CNI_PT_IP_RULE,
272 DHCP_TABLE,
273 install
274 );
275 }
Jian Li6d2ffbf2020-11-04 15:58:18 +0900276
277 private void setNodePortIngressRules(IpAddress k8sNodeIp,
278 String osK8sExtPortName,
279 boolean install) {
280 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
281
282 if (osNode == null) {
283 return;
284 }
285
286 PortNumber osK8sExtPortNum = portNumberByNodeIpAndPortName(k8sNodeIp, osK8sExtPortName);
287
288 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
289 .setOutput(osK8sExtPortNum)
290 .build();
291
292 Map<TpPort, TpPort> portRangeMatchMap =
293 buildPortRangeMatches(NODE_PORT_MIN, NODE_PORT_MAX);
294
295 portRangeMatchMap.forEach((key, value) -> {
296 TrafficSelector.Builder tcpSelectorBuilder = DefaultTrafficSelector.builder()
297 .matchEthType(Ethernet.TYPE_IPV4)
298 .matchIPDst(IpPrefix.valueOf(k8sNodeIp, 32))
299 .matchIPProtocol(IPv4.PROTOCOL_TCP)
300 .matchTcpDstMasked(key, value);
301
302 TrafficSelector.Builder udpSelectorBuilder = DefaultTrafficSelector.builder()
303 .matchEthType(Ethernet.TYPE_IPV4)
304 .matchIPDst(IpPrefix.valueOf(k8sNodeIp, 32))
305 .matchIPProtocol(IPv4.PROTOCOL_UDP)
306 .matchUdpDstMasked(key, value);
307
308 osFlowRuleService.setRule(
309 appId,
310 osNode.intgBridge(),
311 tcpSelectorBuilder.build(),
312 treatment,
313 PRIORITY_CNI_PT_NODE_PORT_IP_RULE,
314 FLAT_TABLE,
315 install
316 );
317
318 osFlowRuleService.setRule(
319 appId,
320 osNode.intgBridge(),
321 udpSelectorBuilder.build(),
322 treatment,
323 PRIORITY_CNI_PT_NODE_PORT_IP_RULE,
324 FLAT_TABLE,
325 install
326 );
327 });
328 }
329
330 private void setNodePortEgressRules(IpAddress k8sNodeIp,
331 String osK8sExtPortName,
332 boolean install) {
333 InstancePort instPort = instPortByNodeIp(k8sNodeIp);
334
335 if (instPort == null) {
336 return;
337 }
338
339 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
340
341 if (osNode == null) {
342 return;
343 }
344
345 PortNumber osK8sExtPortNum = portNumberByNodeIpAndPortName(k8sNodeIp, osK8sExtPortName);
346
347 Port phyPort = phyPortByInstPort(instPort);
348
349 if (phyPort == null) {
350 log.warn("No phys interface found for instance port {}", instPort);
351 return;
352 }
353
354 TrafficSelector selector = DefaultTrafficSelector.builder()
355 .matchEthType(Ethernet.TYPE_IPV4)
356 .matchInPort(osK8sExtPortNum)
357 .build();
358
359 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
360 .setEthSrc(instPort.macAddress())
361 .setOutput(phyPort.number())
362 .build();
363
364 osFlowRuleService.setRule(
365 appId,
366 osNode.intgBridge(),
367 selector,
368 treatment,
369 PRIORITY_CNI_PT_NODE_PORT_IP_RULE,
370 DHCP_TABLE,
371 install
372 );
373 }
374
375 private void setArpRequestRules(IpAddress k8sNodeIp, String osK8sExtPortName, boolean install) {
376 InstancePort instPort = instPortByNodeIp(k8sNodeIp);
377
378 if (instPort == null) {
379 return;
380 }
381
382 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
383
384 if (osNode == null) {
385 return;
386 }
387
388 PortNumber osK8sExtPortNum = portNumberByNodeIpAndPortName(k8sNodeIp, osK8sExtPortName);
389
390 TrafficSelector selector = DefaultTrafficSelector.builder()
391 .matchEthType(Ethernet.TYPE_ARP)
392 .matchArpOp(ARP.OP_REQUEST)
393 .matchInPort(osK8sExtPortNum)
394 .build();
395
396 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
397 .transition(STAT_FLAT_OUTBOUND_TABLE)
398 .build();
399
400 osFlowRuleService.setRule(
401 appId,
402 osNode.intgBridge(),
403 selector,
404 treatment,
405 PRIORITY_CNI_PT_NODE_PORT_ARP_RULE,
406 DHCP_TABLE,
407 install
408 );
409
410 Port phyPort = phyPortByInstPort(instPort);
411
412 if (phyPort == null) {
413 log.warn("No phys interface found for instance port {}", instPort);
414 return;
415 }
416
417 TrafficTreatment extTreatment = DefaultTrafficTreatment.builder()
418 .setOutput(phyPort.number())
419 .build();
420
421 osFlowRuleService.setRule(
422 appId,
423 osNode.intgBridge(),
424 selector,
425 extTreatment,
426 PRIORITY_CNI_PT_NODE_PORT_ARP_EXT_RULE,
427 FLAT_TABLE,
428 install
429 );
430 }
431
432 private void setArpReplyRules(IpAddress k8sNodeIp, String osK8sExtPortName, boolean install) {
433 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
434
435 if (osNode == null) {
436 return;
437 }
438
439 PortNumber osK8sExtPortNum = portNumberByNodeIpAndPortName(k8sNodeIp, osK8sExtPortName);
440
441 TrafficSelector selector = DefaultTrafficSelector.builder()
442 .matchEthType(Ethernet.TYPE_ARP)
443 .matchArpOp(ARP.OP_REPLY)
444 .matchArpTpa(Ip4Address.valueOf(NODE_FAKE_IP_STR))
445 .build();
446
447 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
448 .setOutput(osK8sExtPortNum)
449 .build();
450
451 osFlowRuleService.setRule(
452 appId,
453 osNode.intgBridge(),
454 selector,
455 treatment,
456 PRIORITY_CNI_PT_NODE_PORT_ARP_RULE,
457 FLAT_TABLE,
458 install
459 );
460 }
461
462 private InstancePort instPortByNodeIp(IpAddress k8sNodeIp) {
463 return instancePortService.instancePorts().stream().filter(p -> {
464 OpenstackNetwork.Type netType = osNetworkService.networkType(p.networkId());
465 return netType == FLAT && p.ipAddress().equals(k8sNodeIp);
466 }).findAny().orElse(null);
467 }
468
469 private OpenstackNode osNodeByNodeIp(IpAddress k8sNodeIp) {
470 InstancePort instPort = instPortByNodeIp(k8sNodeIp);
471
472 if (instPort == null) {
473 return null;
474 }
475
476 return osNodeService.node(instPort.deviceId());
477 }
478
479 private PortNumber portNumberByNodeIpAndPortName(IpAddress k8sNodeIp, String portName) {
480 OpenstackNode osNode = osNodeByNodeIp(k8sNodeIp);
481
482 if (osNode == null) {
483 return null;
484 }
485
486 return osNode.portNumByName(portName);
487 }
488
489 private Port phyPortByInstPort(InstancePort instPort) {
490 Network network = osNetworkService.network(instPort.networkId());
491
492 if (network == null) {
493 log.warn("The network does not exist");
494 return null;
495 }
496
497 return deviceService.getPorts(instPort.deviceId()).stream()
498 .filter(port -> {
499 String annotPortName = port.annotations().value(PORT_NAME);
500 String portName = structurePortName(INTEGRATION_TO_PHYSICAL_PREFIX
501 + network.getProviderPhyNet());
502 return Objects.equals(annotPortName, portName);
503 }).findAny().orElse(null);
504 }
Jian Li4b5048a2020-10-08 02:57:45 +0900505}