blob: a79eeb0b956279a2347e9a3f974bb9b04971eab8 [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());
133 nodeService.completeNodes(WORKER)
Daniel Park2884b232021-03-04 18:58:47 +0900134 .forEach(node -> initializeWorkerNodePipeline(node.intgBridge()));
Jian Li43244382021-01-09 00:19:02 +0900135
136 log.info("Started");
137 }
138
139 @Deactivate
140 protected void deactivate() {
141 nodeService.removeListener(internalNodeListener);
142 configService.unregisterProperties(getClass(), false);
143 leadershipService.withdraw(appId.name());
144 deviceEventExecutor.shutdown();
145
146 log.info("Stopped");
147 }
148
149 @Modified
150 protected void modified(ComponentContext context) {
151 Dictionary<?, ?> properties = context.getProperties();
152 Boolean flag;
153
154 flag = Tools.isPropertyEnabled(properties, PROVIDER_NETWORK_ONLY);
155 if (flag == null) {
156 log.info("providerNetworkOnly is not configured, " +
157 "using current value of {}", providerNetworkOnly);
158 } else {
159 providerNetworkOnly = flag;
160 log.info("Configured. providerNetworkOnly is {}",
161 providerNetworkOnly ? "enabled" : "disabled");
162 }
163 }
164
165 @Override
166 public void setRule(ApplicationId appId, DeviceId deviceId,
167 TrafficSelector selector, TrafficTreatment treatment,
168 int priority, int tableType, boolean install) {
169
170 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
171 .forDevice(deviceId)
172 .withSelector(selector)
173 .withTreatment(treatment)
174 .withPriority(priority)
175 .fromApp(appId)
176 .forTable(tableType)
177 .makePermanent();
178
179 applyRule(flowRuleBuilder.build(), install);
180 }
181
182 @Override
183 public void setUpTableMissEntry(DeviceId deviceId, int table) {
184 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
185 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
186
187 treatment.drop();
188
Jian Lif89d9602021-04-27 19:05:49 +0900189 this.setRule(
190 appId,
191 deviceId,
192 selector.build(),
193 treatment.build(),
194 DROP_PRIORITY,
195 table,
196 true);
Jian Li43244382021-01-09 00:19:02 +0900197 }
198
199 @Override
200 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
201 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
202 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
203
204 treatment.transition(toTable);
205
Jian Lif89d9602021-04-27 19:05:49 +0900206 this.setRule(
207 appId,
208 deviceId,
209 selector.build(),
210 treatment.build(),
211 DROP_PRIORITY,
212 fromTable,
213 true);
Jian Li43244382021-01-09 00:19:02 +0900214 }
215
Jian Liea1ead72021-05-28 11:00:07 +0900216 @Override
217 public void purgeRules(DeviceId deviceId) {
Jian Li703c3312021-05-28 16:04:57 +0900218 flowRuleService.purgeFlowRules(deviceId);
Jian Liea1ead72021-05-28 11:00:07 +0900219 }
220
Jian Li43244382021-01-09 00:19:02 +0900221 private void applyRule(FlowRule flowRule, boolean install) {
222 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
223
224 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
225
226 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
227 @Override
228 public void onSuccess(FlowRuleOperations ops) {
229 log.debug("Provisioned vni or forwarding table");
230 }
231
232 @Override
233 public void onError(FlowRuleOperations ops) {
234 log.debug("Failed to provision vni or forwarding table");
235 }
236 }));
237 }
238
Daniel Park2884b232021-03-04 18:58:47 +0900239 protected void initializeGatewayNodePipeline(DeviceId deviceId) {
Jian Lif89d9602021-04-27 19:05:49 +0900240 // for inbound to gateway entry table transition
241 connectTables(deviceId, STAT_INBOUND_TABLE, GW_ENTRY_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900242
Jian Lif89d9602021-04-27 19:05:49 +0900243 // for gateway entry to gateway drop table transition
244 connectTables(deviceId, GW_ENTRY_TABLE, GW_DROP_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900245
Jian Lif89d9602021-04-27 19:05:49 +0900246 // for setting up default gateway drop table
247 setupGatewayNodeDropTable(deviceId);
Daniel Park2884b232021-03-04 18:58:47 +0900248
249 // for setting up default Forwarding table behavior which is NORMAL
250 setupForwardingTable(deviceId);
251 }
252 protected void initializeWorkerNodePipeline(DeviceId deviceId) {
Jian Li43244382021-01-09 00:19:02 +0900253 // for inbound table transition
254 connectTables(deviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE);
255 connectTables(deviceId, VTAP_INBOUND_TABLE, DHCP_TABLE);
256
Jian Lif89d9602021-04-27 19:05:49 +0900257 // for DHCP and ARP table transition
258 connectTables(deviceId, DHCP_TABLE, ARP_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900259
Jian Lif89d9602021-04-27 19:05:49 +0900260 // for ARP table and ACL egress table transition
261 connectTables(deviceId, ARP_TABLE, ACL_EGRESS_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900262
Jian Lif89d9602021-04-27 19:05:49 +0900263 // for setting up default ARP table behavior
264 setupArpTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900265
Daniel Park2884b232021-03-04 18:58:47 +0900266 // for setting up default Forwarding table behavior which is NORMAL
267 setupForwardingTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900268 }
269
Jian Lif89d9602021-04-27 19:05:49 +0900270 private void setupArpTable(DeviceId deviceId) {
271 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
272 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort());
Jian Li43244382021-01-09 00:19:02 +0900273
Jian Lif89d9602021-04-27 19:05:49 +0900274 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
275 tBuilder.transition(FORWARDING_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900276
Jian Lif89d9602021-04-27 19:05:49 +0900277 this.setRule(
278 appId,
279 deviceId,
280 sBuilder.build(),
281 tBuilder.build(),
282 PRIORITY_ARP_DEFAULT_RULE,
283 ARP_TABLE,
284 true);
Jian Li43244382021-01-09 00:19:02 +0900285 }
286
Daniel Park2884b232021-03-04 18:58:47 +0900287 private void setupForwardingTable(DeviceId deviceId) {
Jian Li43244382021-01-09 00:19:02 +0900288 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
289 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
290 .setOutput(PortNumber.NORMAL);
291
Jian Lif89d9602021-04-27 19:05:49 +0900292 this.setRule(
293 appId,
294 deviceId,
295 selector.build(),
296 treatment.build(),
297 LOW_PRIORITY,
298 FORWARDING_TABLE,
299 true);
Daniel Park2884b232021-03-04 18:58:47 +0900300 }
301
Jian Lif89d9602021-04-27 19:05:49 +0900302 private void setupGatewayNodeDropTable(DeviceId deviceId) {
Daniel Park2884b232021-03-04 18:58:47 +0900303 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
304 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
305 .drop();
306
Jian Lif89d9602021-04-27 19:05:49 +0900307 this.setRule(
308 appId,
309 deviceId,
310 selector.build(),
311 treatment.build(),
312 DROP_PRIORITY,
313 GW_DROP_TABLE,
314 true);
Jian Li43244382021-01-09 00:19:02 +0900315 }
316
317 private boolean getProviderNetworkOnlyFlag() {
318 Set<ConfigProperty> properties =
319 configService.getProperties(getClass().getName());
320 return getPropertyValueAsBoolean(properties, PROVIDER_NETWORK_ONLY);
321 }
322
323 private class InternalKubevirtNodeListener implements KubevirtNodeListener {
324
325 @Override
326 public boolean isRelevant(KubevirtNodeEvent event) {
Daniel Parka8968802021-02-25 09:14:22 +0900327 return event.subject().type().equals(WORKER) ||
328 event.subject().type().equals(GATEWAY);
Jian Li43244382021-01-09 00:19:02 +0900329 }
330
331 private boolean isRelevantHelper() {
332 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
333 }
334
335 @Override
336 public void event(KubevirtNodeEvent event) {
337 KubevirtNode node = event.subject();
338
339 switch (event.type()) {
340 case KUBEVIRT_NODE_COMPLETE:
341 deviceEventExecutor.execute(() -> {
342 log.info("COMPLETE node {} is detected", node.hostname());
343
344 if (!isRelevantHelper()) {
345 return;
346 }
347
Daniel Park2884b232021-03-04 18:58:47 +0900348 if (event.subject().type().equals(WORKER)) {
349 initializeWorkerNodePipeline(node.intgBridge());
350 } else {
351 initializeGatewayNodePipeline(node.intgBridge());
352 }
Jian Li43244382021-01-09 00:19:02 +0900353 });
354 break;
355 case KUBEVIRT_NODE_CREATED:
356 case KUBEVIRT_NODE_UPDATED:
357 case KUBEVIRT_NODE_REMOVED:
358 default:
359 // do nothing
360 break;
361 }
362 }
363 }
364}