blob: 8d722869acfc5283da0f3cfa29b1aa8e32bef492 [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;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleOperations;
40import org.onosproject.net.flow.FlowRuleOperationsContext;
41import org.onosproject.net.flow.FlowRuleService;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.osgi.service.component.ComponentContext;
45import org.osgi.service.component.annotations.Activate;
46import org.osgi.service.component.annotations.Component;
47import org.osgi.service.component.annotations.Deactivate;
48import org.osgi.service.component.annotations.Modified;
49import org.osgi.service.component.annotations.Reference;
50import org.osgi.service.component.annotations.ReferenceCardinality;
51import org.slf4j.Logger;
52
53import java.util.Dictionary;
54import java.util.Objects;
55import java.util.Set;
56import java.util.concurrent.ExecutorService;
57import java.util.concurrent.Executors;
58
59import static org.onlab.util.Tools.groupedThreads;
60import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
Jian Li43244382021-01-09 00:19:02 +090061import static org.onosproject.kubevirtnetworking.api.Constants.ARP_TABLE;
Jian Li43244382021-01-09 00:19:02 +090062import static org.onosproject.kubevirtnetworking.api.Constants.DHCP_TABLE;
Jian Li43244382021-01-09 00:19:02 +090063import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090064import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
65import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
Jian Li43244382021-01-09 00:19:02 +090066import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Jian Lif89d9602021-04-27 19:05:49 +090067import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_DEFAULT_RULE;
Jian Li43244382021-01-09 00:19:02 +090068import static org.onosproject.kubevirtnetworking.api.Constants.STAT_INBOUND_TABLE;
Jian Li43244382021-01-09 00:19:02 +090069import static org.onosproject.kubevirtnetworking.api.Constants.VTAP_INBOUND_TABLE;
Jian Li43244382021-01-09 00:19:02 +090070import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY;
71import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY_DEFAULT;
72import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
Daniel Parka8968802021-02-25 09:14:22 +090073import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
Jian Li43244382021-01-09 00:19:02 +090074import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
75import static org.slf4j.LoggerFactory.getLogger;
76
77/**
78 * Sets flow rules directly using FlowRuleService.
79 */
80@Component(
81 immediate = true,
82 service = KubevirtFlowRuleService.class,
83 property = {
84 PROVIDER_NETWORK_ONLY + ":Boolean=" + PROVIDER_NETWORK_ONLY_DEFAULT
85 }
86)
87public class KubevirtFlowRuleManager implements KubevirtFlowRuleService {
88
89 private final Logger log = getLogger(getClass());
90
91 private static final int DROP_PRIORITY = 0;
92 private static final int LOW_PRIORITY = 10000;
Jian Li43244382021-01-09 00:19:02 +090093
94 /** Use provider network only. */
95 private boolean providerNetworkOnly = PROVIDER_NETWORK_ONLY_DEFAULT;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY)
98 protected FlowRuleService flowRuleService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
101 protected CoreService coreService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
104 protected ClusterService clusterService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
107 protected LeadershipService leadershipService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
110 protected DeviceService deviceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
113 protected ComponentConfigService configService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
116 protected KubevirtNodeService nodeService;
117
118 private final ExecutorService deviceEventExecutor = Executors.newSingleThreadExecutor(
119 groupedThreads(getClass().getSimpleName(), "device-event"));
120 private final KubevirtNodeListener internalNodeListener = new InternalKubevirtNodeListener();
121
122 private ApplicationId appId;
123 private NodeId localNodeId;
124
125 @Activate
126 protected void activate() {
127 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
128 coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
129 configService.registerProperties(getClass());
130 nodeService.addListener(internalNodeListener);
131 localNodeId = clusterService.getLocalNode().id();
132 leadershipService.runForLeadership(appId.name());
Daniel Park17fe7982022-04-04 17:48:01 +0900133 nodeService.completeNodes(WORKER).forEach(this::initializeGatewayNodePipeline);
Jian Li43244382021-01-09 00:19:02 +0900134 log.info("Started");
135 }
136
137 @Deactivate
138 protected void deactivate() {
139 nodeService.removeListener(internalNodeListener);
140 configService.unregisterProperties(getClass(), false);
141 leadershipService.withdraw(appId.name());
142 deviceEventExecutor.shutdown();
143
144 log.info("Stopped");
145 }
146
147 @Modified
148 protected void modified(ComponentContext context) {
149 Dictionary<?, ?> properties = context.getProperties();
150 Boolean flag;
151
152 flag = Tools.isPropertyEnabled(properties, PROVIDER_NETWORK_ONLY);
153 if (flag == null) {
154 log.info("providerNetworkOnly is not configured, " +
155 "using current value of {}", providerNetworkOnly);
156 } else {
157 providerNetworkOnly = flag;
158 log.info("Configured. providerNetworkOnly is {}",
159 providerNetworkOnly ? "enabled" : "disabled");
160 }
161 }
162
163 @Override
164 public void setRule(ApplicationId appId, DeviceId deviceId,
165 TrafficSelector selector, TrafficTreatment treatment,
166 int priority, int tableType, boolean install) {
167
168 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
169 .forDevice(deviceId)
170 .withSelector(selector)
171 .withTreatment(treatment)
172 .withPriority(priority)
173 .fromApp(appId)
174 .forTable(tableType)
175 .makePermanent();
176
177 applyRule(flowRuleBuilder.build(), install);
178 }
179
180 @Override
181 public void setUpTableMissEntry(DeviceId deviceId, int table) {
182 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
183 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
184
185 treatment.drop();
186
Jian Lif89d9602021-04-27 19:05:49 +0900187 this.setRule(
188 appId,
189 deviceId,
190 selector.build(),
191 treatment.build(),
192 DROP_PRIORITY,
193 table,
194 true);
Jian Li43244382021-01-09 00:19:02 +0900195 }
196
197 @Override
198 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
199 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
200 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
201
202 treatment.transition(toTable);
203
Jian Lif89d9602021-04-27 19:05:49 +0900204 this.setRule(
205 appId,
206 deviceId,
207 selector.build(),
208 treatment.build(),
209 DROP_PRIORITY,
210 fromTable,
211 true);
Jian Li43244382021-01-09 00:19:02 +0900212 }
213
Jian Liea1ead72021-05-28 11:00:07 +0900214 @Override
215 public void purgeRules(DeviceId deviceId) {
Jian Li703c3312021-05-28 16:04:57 +0900216 flowRuleService.purgeFlowRules(deviceId);
Jian Liea1ead72021-05-28 11:00:07 +0900217 }
218
Jian Li43244382021-01-09 00:19:02 +0900219 private void applyRule(FlowRule flowRule, boolean install) {
220 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
221
222 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
223
224 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
225 @Override
226 public void onSuccess(FlowRuleOperations ops) {
227 log.debug("Provisioned vni or forwarding table");
228 }
229
230 @Override
231 public void onError(FlowRuleOperations ops) {
232 log.debug("Failed to provision vni or forwarding table");
233 }
234 }));
235 }
236
Daniel Park17fe7982022-04-04 17:48:01 +0900237 protected void initializeGatewayNodePipeline(KubevirtNode kubevirtNode) {
238 DeviceId deviceId = kubevirtNode.intgBridge();
Jian Lif89d9602021-04-27 19:05:49 +0900239 // for inbound to gateway entry table transition
240 connectTables(deviceId, STAT_INBOUND_TABLE, GW_ENTRY_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900241
Jian Lif89d9602021-04-27 19:05:49 +0900242 // for gateway entry to gateway drop table transition
243 connectTables(deviceId, GW_ENTRY_TABLE, GW_DROP_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900244
Jian Lif89d9602021-04-27 19:05:49 +0900245 // for setting up default gateway drop table
246 setupGatewayNodeDropTable(deviceId);
Daniel Park2884b232021-03-04 18:58:47 +0900247
248 // for setting up default Forwarding table behavior which is NORMAL
Daniel Park17fe7982022-04-04 17:48:01 +0900249 setupNormalTable(deviceId, FORWARDING_TABLE);
250
251 kubevirtNode.phyIntfs().stream().filter(intf -> intf.physBridge() != null)
252 .forEach(phyIntf -> {
253 setupNormalTable(phyIntf.physBridge(), STAT_INBOUND_TABLE);
254 });
Daniel Park2884b232021-03-04 18:58:47 +0900255 }
Daniel Park17fe7982022-04-04 17:48:01 +0900256 protected void initializeWorkerNodePipeline(KubevirtNode kubevirtNode) {
257 DeviceId deviceId = kubevirtNode.intgBridge();
Jian Li43244382021-01-09 00:19:02 +0900258 // for inbound table transition
259 connectTables(deviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE);
260 connectTables(deviceId, VTAP_INBOUND_TABLE, DHCP_TABLE);
261
Jian Lif89d9602021-04-27 19:05:49 +0900262 // for DHCP and ARP table transition
263 connectTables(deviceId, DHCP_TABLE, ARP_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900264
Jian Lif89d9602021-04-27 19:05:49 +0900265 // for ARP table and ACL egress table transition
266 connectTables(deviceId, ARP_TABLE, ACL_EGRESS_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900267
Jian Lif89d9602021-04-27 19:05:49 +0900268 // for setting up default ARP table behavior
269 setupArpTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900270
Daniel Park2884b232021-03-04 18:58:47 +0900271 // for setting up default Forwarding table behavior which is NORMAL
Daniel Park17fe7982022-04-04 17:48:01 +0900272 setupNormalTable(deviceId, FORWARDING_TABLE);
273
274 kubevirtNode.phyIntfs().stream().filter(intf -> intf.physBridge() != null)
275 .forEach(phyIntf -> {
276 setupNormalTable(phyIntf.physBridge(), STAT_INBOUND_TABLE);
277 });
Jian Li43244382021-01-09 00:19:02 +0900278 }
279
Jian Lif89d9602021-04-27 19:05:49 +0900280 private void setupArpTable(DeviceId deviceId) {
281 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
282 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort());
Jian Li43244382021-01-09 00:19:02 +0900283
Jian Lif89d9602021-04-27 19:05:49 +0900284 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
285 tBuilder.transition(FORWARDING_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900286
Jian Lif89d9602021-04-27 19:05:49 +0900287 this.setRule(
288 appId,
289 deviceId,
290 sBuilder.build(),
291 tBuilder.build(),
292 PRIORITY_ARP_DEFAULT_RULE,
293 ARP_TABLE,
294 true);
Jian Li43244382021-01-09 00:19:02 +0900295 }
296
Daniel Park17fe7982022-04-04 17:48:01 +0900297 private void setupNormalTable(DeviceId deviceId, int tableNum) {
Jian Li43244382021-01-09 00:19:02 +0900298 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
299 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
300 .setOutput(PortNumber.NORMAL);
301
Jian Lif89d9602021-04-27 19:05:49 +0900302 this.setRule(
303 appId,
304 deviceId,
305 selector.build(),
306 treatment.build(),
307 LOW_PRIORITY,
Daniel Park17fe7982022-04-04 17:48:01 +0900308 tableNum,
Jian Lif89d9602021-04-27 19:05:49 +0900309 true);
Daniel Park2884b232021-03-04 18:58:47 +0900310 }
311
Jian Lif89d9602021-04-27 19:05:49 +0900312 private void setupGatewayNodeDropTable(DeviceId deviceId) {
Daniel Park2884b232021-03-04 18:58:47 +0900313 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
314 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
315 .drop();
316
Jian Lif89d9602021-04-27 19:05:49 +0900317 this.setRule(
318 appId,
319 deviceId,
320 selector.build(),
321 treatment.build(),
322 DROP_PRIORITY,
323 GW_DROP_TABLE,
324 true);
Jian Li43244382021-01-09 00:19:02 +0900325 }
326
327 private boolean getProviderNetworkOnlyFlag() {
328 Set<ConfigProperty> properties =
329 configService.getProperties(getClass().getName());
330 return getPropertyValueAsBoolean(properties, PROVIDER_NETWORK_ONLY);
331 }
332
333 private class InternalKubevirtNodeListener implements KubevirtNodeListener {
334
335 @Override
336 public boolean isRelevant(KubevirtNodeEvent event) {
Daniel Parka8968802021-02-25 09:14:22 +0900337 return event.subject().type().equals(WORKER) ||
338 event.subject().type().equals(GATEWAY);
Jian Li43244382021-01-09 00:19:02 +0900339 }
340
341 private boolean isRelevantHelper() {
342 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
343 }
344
345 @Override
346 public void event(KubevirtNodeEvent event) {
347 KubevirtNode node = event.subject();
348
349 switch (event.type()) {
350 case KUBEVIRT_NODE_COMPLETE:
351 deviceEventExecutor.execute(() -> {
352 log.info("COMPLETE node {} is detected", node.hostname());
353
354 if (!isRelevantHelper()) {
355 return;
356 }
357
Daniel Park2884b232021-03-04 18:58:47 +0900358 if (event.subject().type().equals(WORKER)) {
Daniel Park17fe7982022-04-04 17:48:01 +0900359 initializeWorkerNodePipeline(node);
Daniel Park2884b232021-03-04 18:58:47 +0900360 } else {
Daniel Park17fe7982022-04-04 17:48:01 +0900361 initializeGatewayNodePipeline(node);
Daniel Park2884b232021-03-04 18:58:47 +0900362 }
Jian Li43244382021-01-09 00:19:02 +0900363 });
364 break;
365 case KUBEVIRT_NODE_CREATED:
366 case KUBEVIRT_NODE_UPDATED:
367 case KUBEVIRT_NODE_REMOVED:
368 default:
369 // do nothing
370 break;
371 }
372 }
373 }
374}