blob: 6fe457a799e73dec76aa52f46e83e18252ec263c [file] [log] [blame]
Jian Li43244382021-01-09 00:19:02 +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
Jian Lif89d9602021-04-27 19:05:49 +090018import org.onlab.packet.EthType;
Jian Li43244382021-01-09 00:19:02 +090019import org.onlab.util.Tools;
20import org.onosproject.cfg.ComponentConfigService;
21import org.onosproject.cfg.ConfigProperty;
22import org.onosproject.cluster.ClusterService;
23import org.onosproject.cluster.LeadershipService;
24import org.onosproject.cluster.NodeId;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
28import org.onosproject.kubevirtnode.api.KubevirtNode;
29import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
30import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
31import org.onosproject.kubevirtnode.api.KubevirtNodeService;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Liea1ead72021-05-28 11:00:07 +090038import org.onosproject.net.flow.FlowEntry;
Jian Li43244382021-01-09 00:19:02 +090039import org.onosproject.net.flow.FlowRule;
40import org.onosproject.net.flow.FlowRuleOperations;
41import org.onosproject.net.flow.FlowRuleOperationsContext;
42import org.onosproject.net.flow.FlowRuleService;
43import org.onosproject.net.flow.TrafficSelector;
44import org.onosproject.net.flow.TrafficTreatment;
45import org.osgi.service.component.ComponentContext;
46import org.osgi.service.component.annotations.Activate;
47import org.osgi.service.component.annotations.Component;
48import org.osgi.service.component.annotations.Deactivate;
49import org.osgi.service.component.annotations.Modified;
50import org.osgi.service.component.annotations.Reference;
51import org.osgi.service.component.annotations.ReferenceCardinality;
52import org.slf4j.Logger;
53
54import java.util.Dictionary;
55import java.util.Objects;
56import java.util.Set;
57import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Executors;
Jian Liea1ead72021-05-28 11:00:07 +090059import java.util.stream.StreamSupport;
Jian Li43244382021-01-09 00:19:02 +090060
61import static org.onlab.util.Tools.groupedThreads;
62import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
Jian Li43244382021-01-09 00:19:02 +090063import static org.onosproject.kubevirtnetworking.api.Constants.ARP_TABLE;
Jian Li43244382021-01-09 00:19:02 +090064import static org.onosproject.kubevirtnetworking.api.Constants.DHCP_TABLE;
Jian Li43244382021-01-09 00:19:02 +090065import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090066import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
67import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
Jian Li43244382021-01-09 00:19:02 +090068import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Jian Lif89d9602021-04-27 19:05:49 +090069import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_DEFAULT_RULE;
Jian Li43244382021-01-09 00:19:02 +090070import static org.onosproject.kubevirtnetworking.api.Constants.STAT_INBOUND_TABLE;
Jian Li43244382021-01-09 00:19:02 +090071import static org.onosproject.kubevirtnetworking.api.Constants.VTAP_INBOUND_TABLE;
Jian Li43244382021-01-09 00:19:02 +090072import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY;
73import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY_DEFAULT;
74import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
Daniel Parka8968802021-02-25 09:14:22 +090075import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
Jian Li43244382021-01-09 00:19:02 +090076import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
77import static org.slf4j.LoggerFactory.getLogger;
78
79/**
80 * Sets flow rules directly using FlowRuleService.
81 */
82@Component(
83 immediate = true,
84 service = KubevirtFlowRuleService.class,
85 property = {
86 PROVIDER_NETWORK_ONLY + ":Boolean=" + PROVIDER_NETWORK_ONLY_DEFAULT
87 }
88)
89public class KubevirtFlowRuleManager implements KubevirtFlowRuleService {
90
91 private final Logger log = getLogger(getClass());
92
93 private static final int DROP_PRIORITY = 0;
94 private static final int LOW_PRIORITY = 10000;
Jian Li43244382021-01-09 00:19:02 +090095
96 /** Use provider network only. */
97 private boolean providerNetworkOnly = PROVIDER_NETWORK_ONLY_DEFAULT;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY)
100 protected FlowRuleService flowRuleService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
103 protected CoreService coreService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
106 protected ClusterService clusterService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
109 protected LeadershipService leadershipService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
112 protected DeviceService deviceService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
115 protected ComponentConfigService configService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
118 protected KubevirtNodeService nodeService;
119
120 private final ExecutorService deviceEventExecutor = Executors.newSingleThreadExecutor(
121 groupedThreads(getClass().getSimpleName(), "device-event"));
122 private final KubevirtNodeListener internalNodeListener = new InternalKubevirtNodeListener();
123
124 private ApplicationId appId;
125 private NodeId localNodeId;
126
127 @Activate
128 protected void activate() {
129 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
130 coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
131 configService.registerProperties(getClass());
132 nodeService.addListener(internalNodeListener);
133 localNodeId = clusterService.getLocalNode().id();
134 leadershipService.runForLeadership(appId.name());
135 nodeService.completeNodes(WORKER)
Daniel Park2884b232021-03-04 18:58:47 +0900136 .forEach(node -> initializeWorkerNodePipeline(node.intgBridge()));
Jian Li43244382021-01-09 00:19:02 +0900137
138 log.info("Started");
139 }
140
141 @Deactivate
142 protected void deactivate() {
143 nodeService.removeListener(internalNodeListener);
144 configService.unregisterProperties(getClass(), false);
145 leadershipService.withdraw(appId.name());
146 deviceEventExecutor.shutdown();
147
148 log.info("Stopped");
149 }
150
151 @Modified
152 protected void modified(ComponentContext context) {
153 Dictionary<?, ?> properties = context.getProperties();
154 Boolean flag;
155
156 flag = Tools.isPropertyEnabled(properties, PROVIDER_NETWORK_ONLY);
157 if (flag == null) {
158 log.info("providerNetworkOnly is not configured, " +
159 "using current value of {}", providerNetworkOnly);
160 } else {
161 providerNetworkOnly = flag;
162 log.info("Configured. providerNetworkOnly is {}",
163 providerNetworkOnly ? "enabled" : "disabled");
164 }
165 }
166
167 @Override
168 public void setRule(ApplicationId appId, DeviceId deviceId,
169 TrafficSelector selector, TrafficTreatment treatment,
170 int priority, int tableType, boolean install) {
171
172 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
173 .forDevice(deviceId)
174 .withSelector(selector)
175 .withTreatment(treatment)
176 .withPriority(priority)
177 .fromApp(appId)
178 .forTable(tableType)
179 .makePermanent();
180
181 applyRule(flowRuleBuilder.build(), install);
182 }
183
184 @Override
185 public void setUpTableMissEntry(DeviceId deviceId, int table) {
186 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
187 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
188
189 treatment.drop();
190
Jian Lif89d9602021-04-27 19:05:49 +0900191 this.setRule(
192 appId,
193 deviceId,
194 selector.build(),
195 treatment.build(),
196 DROP_PRIORITY,
197 table,
198 true);
Jian Li43244382021-01-09 00:19:02 +0900199 }
200
201 @Override
202 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
203 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
204 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
205
206 treatment.transition(toTable);
207
Jian Lif89d9602021-04-27 19:05:49 +0900208 this.setRule(
209 appId,
210 deviceId,
211 selector.build(),
212 treatment.build(),
213 DROP_PRIORITY,
214 fromTable,
215 true);
Jian Li43244382021-01-09 00:19:02 +0900216 }
217
Jian Liea1ead72021-05-28 11:00:07 +0900218 @Override
219 public void purgeRules(DeviceId deviceId) {
220 Iterable<FlowEntry> fes = flowRuleService.getFlowEntries(deviceId);
221 flowRuleService.removeFlowRules(StreamSupport.stream(
222 fes.spliterator(), false).toArray(FlowEntry[]::new));
223 }
224
Jian Li43244382021-01-09 00:19:02 +0900225 private void applyRule(FlowRule flowRule, boolean install) {
226 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
227
228 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
229
230 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
231 @Override
232 public void onSuccess(FlowRuleOperations ops) {
233 log.debug("Provisioned vni or forwarding table");
234 }
235
236 @Override
237 public void onError(FlowRuleOperations ops) {
238 log.debug("Failed to provision vni or forwarding table");
239 }
240 }));
241 }
242
Daniel Park2884b232021-03-04 18:58:47 +0900243 protected void initializeGatewayNodePipeline(DeviceId deviceId) {
Jian Lif89d9602021-04-27 19:05:49 +0900244 // for inbound to gateway entry table transition
245 connectTables(deviceId, STAT_INBOUND_TABLE, GW_ENTRY_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900246
Jian Lif89d9602021-04-27 19:05:49 +0900247 // for gateway entry to gateway drop table transition
248 connectTables(deviceId, GW_ENTRY_TABLE, GW_DROP_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900249
Jian Lif89d9602021-04-27 19:05:49 +0900250 // for setting up default gateway drop table
251 setupGatewayNodeDropTable(deviceId);
Daniel Park2884b232021-03-04 18:58:47 +0900252
253 // for setting up default Forwarding table behavior which is NORMAL
254 setupForwardingTable(deviceId);
255 }
256 protected void initializeWorkerNodePipeline(DeviceId deviceId) {
Jian Li43244382021-01-09 00:19:02 +0900257 // for inbound table transition
258 connectTables(deviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE);
259 connectTables(deviceId, VTAP_INBOUND_TABLE, DHCP_TABLE);
260
Jian Lif89d9602021-04-27 19:05:49 +0900261 // for DHCP and ARP table transition
262 connectTables(deviceId, DHCP_TABLE, ARP_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900263
Jian Lif89d9602021-04-27 19:05:49 +0900264 // for ARP table and ACL egress table transition
265 connectTables(deviceId, ARP_TABLE, ACL_EGRESS_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900266
Jian Lif89d9602021-04-27 19:05:49 +0900267 // for setting up default ARP table behavior
268 setupArpTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900269
Daniel Park2884b232021-03-04 18:58:47 +0900270 // for setting up default Forwarding table behavior which is NORMAL
271 setupForwardingTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900272 }
273
Jian Lif89d9602021-04-27 19:05:49 +0900274 private void setupArpTable(DeviceId deviceId) {
275 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
276 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort());
Jian Li43244382021-01-09 00:19:02 +0900277
Jian Lif89d9602021-04-27 19:05:49 +0900278 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
279 tBuilder.transition(FORWARDING_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900280
Jian Lif89d9602021-04-27 19:05:49 +0900281 this.setRule(
282 appId,
283 deviceId,
284 sBuilder.build(),
285 tBuilder.build(),
286 PRIORITY_ARP_DEFAULT_RULE,
287 ARP_TABLE,
288 true);
Jian Li43244382021-01-09 00:19:02 +0900289 }
290
Daniel Park2884b232021-03-04 18:58:47 +0900291 private void setupForwardingTable(DeviceId deviceId) {
Jian Li43244382021-01-09 00:19:02 +0900292 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
293 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
294 .setOutput(PortNumber.NORMAL);
295
Jian Lif89d9602021-04-27 19:05:49 +0900296 this.setRule(
297 appId,
298 deviceId,
299 selector.build(),
300 treatment.build(),
301 LOW_PRIORITY,
302 FORWARDING_TABLE,
303 true);
Daniel Park2884b232021-03-04 18:58:47 +0900304 }
305
Jian Lif89d9602021-04-27 19:05:49 +0900306 private void setupGatewayNodeDropTable(DeviceId deviceId) {
Daniel Park2884b232021-03-04 18:58:47 +0900307 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
308 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
309 .drop();
310
Jian Lif89d9602021-04-27 19:05:49 +0900311 this.setRule(
312 appId,
313 deviceId,
314 selector.build(),
315 treatment.build(),
316 DROP_PRIORITY,
317 GW_DROP_TABLE,
318 true);
Jian Li43244382021-01-09 00:19:02 +0900319 }
320
321 private boolean getProviderNetworkOnlyFlag() {
322 Set<ConfigProperty> properties =
323 configService.getProperties(getClass().getName());
324 return getPropertyValueAsBoolean(properties, PROVIDER_NETWORK_ONLY);
325 }
326
327 private class InternalKubevirtNodeListener implements KubevirtNodeListener {
328
329 @Override
330 public boolean isRelevant(KubevirtNodeEvent event) {
Daniel Parka8968802021-02-25 09:14:22 +0900331 return event.subject().type().equals(WORKER) ||
332 event.subject().type().equals(GATEWAY);
Jian Li43244382021-01-09 00:19:02 +0900333 }
334
335 private boolean isRelevantHelper() {
336 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
337 }
338
339 @Override
340 public void event(KubevirtNodeEvent event) {
341 KubevirtNode node = event.subject();
342
343 switch (event.type()) {
344 case KUBEVIRT_NODE_COMPLETE:
345 deviceEventExecutor.execute(() -> {
346 log.info("COMPLETE node {} is detected", node.hostname());
347
348 if (!isRelevantHelper()) {
349 return;
350 }
351
Daniel Park2884b232021-03-04 18:58:47 +0900352 if (event.subject().type().equals(WORKER)) {
353 initializeWorkerNodePipeline(node.intgBridge());
354 } else {
355 initializeGatewayNodePipeline(node.intgBridge());
356 }
Jian Li43244382021-01-09 00:19:02 +0900357 });
358 break;
359 case KUBEVIRT_NODE_CREATED:
360 case KUBEVIRT_NODE_UPDATED:
361 case KUBEVIRT_NODE_REMOVED:
362 default:
363 // do nothing
364 break;
365 }
366 }
367 }
368}