blob: 221fc99cecf3003aa8639d62fe14f7d295c52785 [file] [log] [blame]
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -08001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -08003 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.sdnip;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080017
Pingping Linc07781f2015-10-30 00:44:41 -070018import static java.util.concurrent.Executors.newSingleThreadExecutor;
19import static org.onlab.util.Tools.groupedThreads;
20
21import java.util.HashMap;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Map;
25import java.util.Map.Entry;
26import java.util.concurrent.ConcurrentHashMap;
27import java.util.concurrent.ExecutorService;
28
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070029import org.onosproject.core.ApplicationId;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070030import org.onosproject.net.intent.Intent;
31import org.onosproject.net.intent.IntentService;
32import org.onosproject.net.intent.IntentState;
Luca Prete86ac7d12015-12-02 23:36:49 -080033import org.onosproject.net.intent.IntentUtils;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070034import org.onosproject.net.intent.Key;
Jonathan Hart9a426f82015-09-03 15:43:13 +020035import org.onosproject.routing.IntentSynchronizationService;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
Jonathan Hart51372182014-12-03 21:32:34 -080039/**
40 * Synchronizes intents between the in-memory intent store and the
41 * IntentService.
42 */
Jonathan Hart9a426f82015-09-03 15:43:13 +020043public class IntentSynchronizer implements IntentSynchronizationService {
Pavlin Radoslavov2aa1f322015-03-11 17:59:44 -070044
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080045 private static final Logger log =
46 LoggerFactory.getLogger(IntentSynchronizer.class);
47
48 private final ApplicationId appId;
49 private final IntentService intentService;
Jonathan Hart9a426f82015-09-03 15:43:13 +020050
51 private final Map<Key, Intent> intents;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080052
53 //
Luca Prete00043db2015-11-03 15:40:40 -080054 // State to deal with the Leader election and pushing Intents
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080055 //
Luca Prete00043db2015-11-03 15:40:40 -080056 private final ExecutorService intentsSynchronizerExecutor;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080057 private volatile boolean isElectedLeader = false;
58 private volatile boolean isActivatedLeader = false;
59
60 /**
61 * Class constructor.
62 *
63 * @param appId the Application ID
64 * @param intentService the intent service
Jonathan Hart9a426f82015-09-03 15:43:13 +020065 */
Luca Prete00043db2015-11-03 15:40:40 -080066 public IntentSynchronizer(ApplicationId appId, IntentService intentService) {
Jonathan Hart9a426f82015-09-03 15:43:13 +020067 this(appId, intentService,
Luca Prete00043db2015-11-03 15:40:40 -080068 newSingleThreadExecutor(groupedThreads("onos/" + appId, "sync")));
Jonathan Hart9a426f82015-09-03 15:43:13 +020069 }
70
71 /**
72 * Class constructor.
73 *
74 * @param appId the Application ID
75 * @param intentService the intent service
76 * @param executorService executor service for synchronization thread
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080077 */
Luca Prete3401a3f2015-11-19 11:43:01 -080078 public IntentSynchronizer(ApplicationId appId, IntentService intentService,
Jonathan Hart9a426f82015-09-03 15:43:13 +020079 ExecutorService executorService) {
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080080 this.appId = appId;
81 this.intentService = intentService;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080082
Jonathan Hart9a426f82015-09-03 15:43:13 +020083 intents = new ConcurrentHashMap<>();
Jonathan Hart552e31f2015-02-06 11:11:59 -080084
Luca Prete00043db2015-11-03 15:40:40 -080085 intentsSynchronizerExecutor = executorService;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080086 }
87
88 /**
89 * Starts the synchronizer.
90 */
91 public void start() {
Jonathan Hart9a426f82015-09-03 15:43:13 +020092
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080093 }
94
95 /**
96 * Stops the synchronizer.
97 */
98 public void stop() {
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -080099 synchronized (this) {
100 // Stop the thread(s)
Luca Prete00043db2015-11-03 15:40:40 -0800101 intentsSynchronizerExecutor.shutdownNow();
Pingping Linc07781f2015-10-30 00:44:41 -0700102 log.info("Intents Synchronizer Executor shutdown completed");
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800103
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800104 }
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800105 }
106
Pingping Linc07781f2015-10-30 00:44:41 -0700107 /**
108 * Withdraws all intents.
109 */
110 public void removeIntents() {
111 if (!isElectedLeader) {
112 // only leader will withdraw intents
113 return;
114 }
115
116 log.debug("Intent Synchronizer shutdown: withdrawing all intents...");
117
118 for (Entry<Key, Intent> entry : intents.entrySet()) {
119 intentService.withdraw(entry.getValue());
120 log.debug("Intent Synchronizer withdrawing intent: {}",
121 entry.getValue());
122 }
123
124 intents.clear();
125 log.info("Tried to clean all intents");
126 }
127
Jonathan Hart9a426f82015-09-03 15:43:13 +0200128 @Override
129 public void submit(Intent intent) {
130 synchronized (this) {
131 intents.put(intent.key(), intent);
132 if (isElectedLeader && isActivatedLeader) {
Luca Prete00043db2015-11-03 15:40:40 -0800133 log.trace("Submitting intent: {}", intent);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200134 intentService.submit(intent);
135 }
136 }
137 }
138
139 @Override
140 public void withdraw(Intent intent) {
141 synchronized (this) {
142 intents.remove(intent.key(), intent);
143 if (isElectedLeader && isActivatedLeader) {
Luca Prete00043db2015-11-03 15:40:40 -0800144 log.trace("Withdrawing intent: {}", intent);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200145 intentService.withdraw(intent);
146 }
147 }
148 }
149
Jonathan Hart51372182014-12-03 21:32:34 -0800150 /**
Luca Prete00043db2015-11-03 15:40:40 -0800151 * Signals the synchronizer that the leadership has changed.
Jonathan Hart51372182014-12-03 21:32:34 -0800152 *
153 * @param isLeader true if this instance is now the leader, otherwise false
154 */
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800155 public void leaderChanged(boolean isLeader) {
Luca Prete00043db2015-11-03 15:40:40 -0800156 log.debug("Leader changed: {}", isLeader);
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800157
158 if (!isLeader) {
159 this.isElectedLeader = false;
160 this.isActivatedLeader = false;
161 return; // Nothing to do
162 }
163 this.isActivatedLeader = false;
164 this.isElectedLeader = true;
165
Jonathan Hart9a426f82015-09-03 15:43:13 +0200166 // Run the synchronization method off-thread
Luca Prete00043db2015-11-03 15:40:40 -0800167 intentsSynchronizerExecutor.execute(this::synchronizeIntents);
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800168 }
169
Jonathan Hart9a426f82015-09-03 15:43:13 +0200170 private void synchronizeIntents() {
171 Map<Key, Intent> serviceIntents = new HashMap<>();
172 intentService.getIntents().forEach(i -> {
173 if (i.appId().equals(appId)) {
174 serviceIntents.put(i.key(), i);
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800175 }
Jonathan Hart9a426f82015-09-03 15:43:13 +0200176 });
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800177
Jonathan Hart9a426f82015-09-03 15:43:13 +0200178 List<Intent> intentsToAdd = new LinkedList<>();
179 List<Intent> intentsToRemove = new LinkedList<>();
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800180
Jonathan Hart9a426f82015-09-03 15:43:13 +0200181 for (Intent localIntent : intents.values()) {
182 Intent serviceIntent = serviceIntents.remove(localIntent.key());
183 if (serviceIntent == null) {
184 intentsToAdd.add(localIntent);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800185 } else {
Jonathan Hart9a426f82015-09-03 15:43:13 +0200186 IntentState state = intentService.getIntentState(serviceIntent.key());
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800187 if (!IntentUtils.intentsAreEqual(serviceIntent, localIntent) || state == null ||
Jonathan Hart9a426f82015-09-03 15:43:13 +0200188 state == IntentState.WITHDRAW_REQ ||
189 state == IntentState.WITHDRAWING ||
190 state == IntentState.WITHDRAWN) {
191 intentsToAdd.add(localIntent);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800192 }
Pingping Line28ae4c2015-03-13 11:37:03 -0700193 }
194 }
Jonathan Hart9a426f82015-09-03 15:43:13 +0200195
196 for (Intent serviceIntent : serviceIntents.values()) {
197 IntentState state = intentService.getIntentState(serviceIntent.key());
198 if (state != null && state != IntentState.WITHDRAW_REQ
199 && state != IntentState.WITHDRAWING
200 && state != IntentState.WITHDRAWN) {
201 intentsToRemove.add(serviceIntent);
202 }
203 }
204
Luca Prete00043db2015-11-03 15:40:40 -0800205 log.debug("Intent Synchronizer: submitting {}, withdrawing {}",
Jonathan Hart9a426f82015-09-03 15:43:13 +0200206 intentsToAdd.size(), intentsToRemove.size());
207
208 // Withdraw Intents
209 for (Intent intent : intentsToRemove) {
210 intentService.withdraw(intent);
Luca Prete00043db2015-11-03 15:40:40 -0800211 log.trace("Intent Synchronizer: withdrawing intent: {}",
Jonathan Hart9a426f82015-09-03 15:43:13 +0200212 intent);
213 }
214 if (!isElectedLeader) {
Luca Prete00043db2015-11-03 15:40:40 -0800215 log.debug("Intent Synchronizer: cannot withdraw intents: " +
Jonathan Hart9a426f82015-09-03 15:43:13 +0200216 "not elected leader anymore");
217 isActivatedLeader = false;
Pingping Line28ae4c2015-03-13 11:37:03 -0700218 return;
219 }
220
Jonathan Hart9a426f82015-09-03 15:43:13 +0200221 // Add Intents
222 for (Intent intent : intentsToAdd) {
223 intentService.submit(intent);
Luca Prete00043db2015-11-03 15:40:40 -0800224 log.trace("Intent Synchronizer: submitting intent: {}",
Jonathan Hart9a426f82015-09-03 15:43:13 +0200225 intent);
226 }
227 if (!isElectedLeader) {
Luca Prete00043db2015-11-03 15:40:40 -0800228 log.debug("Intent Synchronizer: cannot submit intents: " +
Jonathan Hart9a426f82015-09-03 15:43:13 +0200229 "not elected leader anymore");
230 isActivatedLeader = false;
Pingping Line28ae4c2015-03-13 11:37:03 -0700231 return;
Jonathan Hart9a426f82015-09-03 15:43:13 +0200232 }
233
234 if (isElectedLeader) {
235 isActivatedLeader = true; // Allow push of Intents
Pingping Line28ae4c2015-03-13 11:37:03 -0700236 } else {
Jonathan Hart9a426f82015-09-03 15:43:13 +0200237 isActivatedLeader = false;
Pingping Line28ae4c2015-03-13 11:37:03 -0700238 }
Luca Prete00043db2015-11-03 15:40:40 -0800239 log.debug("Intent synchronization completed");
Pingping Line28ae4c2015-03-13 11:37:03 -0700240 }
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800241}