blob: 371a479ecd150661d694c2d2dd1fa3a38b4e4a7c [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.staticflowentry;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.Comparator;
8import java.util.Iterator;
9import java.util.HashMap;
10import java.util.List;
11import java.util.Map;
12import java.util.Map.Entry;
13import java.util.Set;
14import java.util.concurrent.ConcurrentHashMap;
15
16import net.floodlightcontroller.core.FloodlightContext;
17import net.floodlightcontroller.core.IFloodlightProviderService;
18import net.floodlightcontroller.core.IFloodlightProviderService.Role;
19import net.floodlightcontroller.core.IHAListener;
20import net.floodlightcontroller.core.IOFMessageListener;
21import net.floodlightcontroller.core.IOFSwitch;
22import net.floodlightcontroller.core.IOFSwitchListener;
23import net.floodlightcontroller.core.annotations.LogMessageCategory;
24import net.floodlightcontroller.core.annotations.LogMessageDoc;
25import net.floodlightcontroller.core.module.FloodlightModuleContext;
26import net.floodlightcontroller.core.module.FloodlightModuleException;
27import net.floodlightcontroller.core.module.IFloodlightModule;
28import net.floodlightcontroller.core.module.IFloodlightService;
29import net.floodlightcontroller.core.util.AppCookie;
30import net.floodlightcontroller.restserver.IRestApiService;
31import net.floodlightcontroller.staticflowentry.web.StaticFlowEntryWebRoutable;
32import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
33import net.floodlightcontroller.storage.IResultSet;
34import net.floodlightcontroller.storage.IStorageSourceService;
35import net.floodlightcontroller.storage.IStorageSourceListener;
36
37import net.floodlightcontroller.storage.StorageException;
38import org.openflow.protocol.OFFlowMod;
39import org.openflow.protocol.OFFlowRemoved;
40import org.openflow.protocol.OFMatch;
41import org.openflow.protocol.OFMessage;
Pankaj Berde465ac7c2013-05-23 13:47:49 -070042import org.openflow.protocol.OFPhysicalPort;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080043import org.openflow.protocol.OFType;
44import org.openflow.protocol.factory.BasicFactory;
45import org.openflow.util.HexString;
46import org.openflow.util.U16;
47import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
50@LogMessageCategory("Static Flow Pusher")
51/**
52 * This module is responsible for maintaining a set of static flows on
53 * switches. This is just a big 'ol dumb list of flows and something external
54 * is responsible for ensuring they make sense for the network.
55 */
56public class StaticFlowEntryPusher
57 implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
58 IStorageSourceListener, IOFMessageListener, IHAListener {
59 protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class);
60 public static final String StaticFlowName = "staticflowentry";
61
62 public static final int STATIC_FLOW_APP_ID = 10;
63
64 public static final String TABLE_NAME = "controller_staticflowtableentry";
65 public static final String COLUMN_NAME = "name";
66 public static final String COLUMN_SWITCH = "switch_id";
67 public static final String COLUMN_ACTIVE = "active";
68 public static final String COLUMN_IDLE_TIMEOUT = "idle_timeout";
69 public static final String COLUMN_HARD_TIMEOUT = "hard_timeout";
70 public static final String COLUMN_PRIORITY = "priority";
71 public static final String COLUMN_COOKIE = "cookie";
72 public static final String COLUMN_WILDCARD = "wildcards";
73 public static final String COLUMN_IN_PORT = "in_port";
74 public static final String COLUMN_DL_SRC = "dl_src";
75 public static final String COLUMN_DL_DST = "dl_dst";
76 public static final String COLUMN_DL_VLAN = "dl_vlan";
77 public static final String COLUMN_DL_VLAN_PCP = "dl_vlan_pcp";
78 public static final String COLUMN_DL_TYPE = "dl_type";
79 public static final String COLUMN_NW_TOS = "nw_tos";
80 public static final String COLUMN_NW_PROTO = "nw_proto";
81 public static final String COLUMN_NW_SRC = "nw_src"; // includes CIDR-style
82 // netmask, e.g.
83 // "128.8.128.0/24"
84 public static final String COLUMN_NW_DST = "nw_dst";
85 public static final String COLUMN_TP_DST = "tp_dst";
86 public static final String COLUMN_TP_SRC = "tp_src";
87 public static final String COLUMN_ACTIONS = "actions";
88 public static String ColumnNames[] = { COLUMN_NAME, COLUMN_SWITCH,
89 COLUMN_ACTIVE, COLUMN_IDLE_TIMEOUT, COLUMN_HARD_TIMEOUT,
90 COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_WILDCARD, COLUMN_IN_PORT,
91 COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_VLAN, COLUMN_DL_VLAN_PCP,
92 COLUMN_DL_TYPE, COLUMN_NW_TOS, COLUMN_NW_PROTO, COLUMN_NW_SRC,
93 COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, COLUMN_ACTIONS };
94
95
96 protected IFloodlightProviderService floodlightProvider;
97 protected IStorageSourceService storageSource;
98 protected IRestApiService restApi;
99
100 // Map<DPID, Map<Name, FlowMod>> ; FlowMod can be null to indicate non-active
101 protected Map<String, Map<String, OFFlowMod>> entriesFromStorage;
102 // Entry Name -> DPID of Switch it's on
103 protected Map<String, String> entry2dpid;
104
105 private BasicFactory ofMessageFactory;
106
107 // Class to sort FlowMod's by priority, from lowest to highest
108 class FlowModSorter implements Comparator<String> {
109 private String dpid;
110 public FlowModSorter(String dpid) {
111 this.dpid = dpid;
112 }
113 @Override
114 public int compare(String o1, String o2) {
115 OFFlowMod f1 = entriesFromStorage.get(dpid).get(o1);
116 OFFlowMod f2 = entriesFromStorage.get(dpid).get(o2);
117 if (f1 == null || f2 == null) // sort active=false flows by key
118 return o1.compareTo(o2);
119 return U16.f(f1.getPriority()) - U16.f(f2.getPriority());
120 }
121 };
122
123 /**
124 * used for debugging and unittests
125 * @return the number of static flow entries as cached from storage
126 */
127 public int countEntries() {
128 int size = 0;
129 if (entriesFromStorage == null)
130 return 0;
131 for (String ofswitch : entriesFromStorage.keySet())
132 size += entriesFromStorage.get(ofswitch).size();
133 return size;
134 }
135
136 public IFloodlightProviderService getFloodlightProvider() {
137 return floodlightProvider;
138 }
139
140 public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
141 this.floodlightProvider = floodlightProvider;
142 }
143
144 public void setStorageSource(IStorageSourceService storageSource) {
145 this.storageSource = storageSource;
146 }
147
148 /**
149 * Reads from our entriesFromStorage for the specified switch and
150 * sends the FlowMods down to the controller in <b>sorted</b> order.
151 *
152 * Sorted is important to maintain correctness of the switch:
153 * if a packet would match both a lower and a higher priority
154 * rule, then we want it to match the higher priority or nothing,
155 * but never just the lower priority one. Inserting from high to
156 * low priority fixes this.
157 *
158 * TODO consider adding a "block all" flow mod and then removing it
159 * while starting up.
160 *
161 * @param sw The switch to send entries to
162 */
163 protected void sendEntriesToSwitch(IOFSwitch sw) {
164 String dpid = sw.getStringId();
165
166 if ((entriesFromStorage != null) && (entriesFromStorage.containsKey(dpid))) {
167 Map<String, OFFlowMod> entries = entriesFromStorage.get(dpid);
168 List<String> sortedList = new ArrayList<String>(entries.keySet());
169 // weird that Collections.sort() returns void
170 Collections.sort( sortedList, new FlowModSorter(dpid));
171 for (String entryName : sortedList) {
172 OFFlowMod flowMod = entries.get(entryName);
173 if (flowMod != null) {
174 if (log.isDebugEnabled()) {
175 log.debug("Pushing static entry {} for {}", dpid, entryName);
176 }
177 writeFlowModToSwitch(sw, flowMod);
178 }
179 }
180 }
181 }
182
183 /**
184 * Used only for bundle-local indexing
185 *
186 * @param map
187 * @return
188 */
189
190 protected Map<String, String> computeEntry2DpidMap(
191 Map<String, Map<String, OFFlowMod>> map) {
192 Map<String, String> ret = new HashMap<String, String>();
193 for(String dpid : map.keySet()) {
194 for( String entry: map.get(dpid).keySet())
195 ret.put(entry, dpid);
196 }
197 return ret;
198 }
199
200 /**
201 * Read entries from storageSource, and store them in a hash
202 *
203 * @return
204 */
205 @LogMessageDoc(level="ERROR",
206 message="failed to access storage: {reason}",
207 explanation="Could not retrieve static flows from the system " +
208 "database",
209 recommendation=LogMessageDoc.CHECK_CONTROLLER)
210 private Map<String, Map<String, OFFlowMod>> readEntriesFromStorage() {
211 Map<String, Map<String, OFFlowMod>> entries = new ConcurrentHashMap<String, Map<String, OFFlowMod>>();
212 try {
213 Map<String, Object> row;
214 // null1=no predicate, null2=no ordering
215 IResultSet resultSet = storageSource.executeQuery(TABLE_NAME,
216 ColumnNames, null, null);
217 for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
218 row = it.next().getRow();
219 parseRow(row, entries);
220 }
221 } catch (StorageException e) {
222 log.error("failed to access storage: {}", e.getMessage());
223 // if the table doesn't exist, then wait to populate later via
224 // setStorageSource()
225 }
226 return entries;
227 }
228
229 /**
230 * Take a single row, turn it into a flowMod, and add it to the
231 * entries{$dpid}.{$entryName}=FlowMod
232 *
233 * IF an entry is in active, mark it with FlowMod = null
234 *
235 * @param row
236 * @param entries
237 */
238
239 void parseRow(Map<String, Object> row,
240 Map<String, Map<String, OFFlowMod>> entries) {
241 String switchName = null;
242 String entryName = null;
243
244 StringBuffer matchString = new StringBuffer();
245 if (ofMessageFactory == null) // lazy init
246 ofMessageFactory = new BasicFactory();
247
248 OFFlowMod flowMod = (OFFlowMod) ofMessageFactory
249 .getMessage(OFType.FLOW_MOD);
250
251 if (!row.containsKey(COLUMN_SWITCH) || !row.containsKey(COLUMN_NAME)) {
252 log.debug(
253 "skipping entry with missing required 'switch' or 'name' entry: {}",
254 row);
255 return;
256 }
257 // most error checking done with ClassCastException
258 try {
259 // first, snag the required entries, for debugging info
260 switchName = (String) row.get(COLUMN_SWITCH);
261 entryName = (String) row.get(COLUMN_NAME);
262 if (!entries.containsKey(switchName))
263 entries.put(switchName, new HashMap<String, OFFlowMod>());
264 StaticFlowEntries.initDefaultFlowMod(flowMod, entryName);
265
266 for (String key : row.keySet()) {
267 if (row.get(key) == null)
268 continue;
269 if ( key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME)
270 || key.equals("id"))
271 continue; // already handled
272 // explicitly ignore timeouts and wildcards
273 if ( key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT) ||
274 key.equals(COLUMN_WILDCARD))
275 continue;
276 if ( key.equals(COLUMN_ACTIVE)) {
277 if (! Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) {
278 log.debug("skipping inactive entry {} for switch {}",
279 entryName, switchName);
280 entries.get(switchName).put(entryName, null); // mark this an inactive
281 return;
282 }
283 } else if ( key.equals(COLUMN_ACTIONS)){
284 StaticFlowEntries.parseActionString(flowMod, (String) row.get(COLUMN_ACTIONS), log);
285 } else if ( key.equals(COLUMN_COOKIE)) {
286 flowMod.setCookie(
287 StaticFlowEntries.computeEntryCookie(flowMod,
288 Integer.valueOf((String) row.get(COLUMN_COOKIE)),
289 entryName)
290 );
291 } else if ( key.equals(COLUMN_PRIORITY)) {
292 flowMod.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY))));
293 } else { // the rest of the keys are for OFMatch().fromString()
294 if (matchString.length() > 0)
295 matchString.append(",");
296 matchString.append(key + "=" + row.get(key).toString());
297 }
298 }
299 } catch (ClassCastException e) {
300 if (entryName != null && switchName != null)
301 log.debug(
302 "skipping entry {} on switch {} with bad data : "
303 + e.getMessage(), entryName, switchName);
304 else
305 log.debug("skipping entry with bad data: {} :: {} ",
306 e.getMessage(), e.getStackTrace());
307 }
308
309 OFMatch ofMatch = new OFMatch();
310 String match = matchString.toString();
311 try {
312 ofMatch.fromString(match);
313 } catch (IllegalArgumentException e) {
314 log.debug(
315 "ignoring flow entry {} on switch {} with illegal OFMatch() key: "
316 + match, entryName, switchName);
317 return;
318 }
319 flowMod.setMatch(ofMatch);
320
321 entries.get(switchName).put(entryName, flowMod);
322 }
323
324 @Override
325 public void addedSwitch(IOFSwitch sw) {
326 log.debug("addedSwitch {}; processing its static entries", sw);
327 sendEntriesToSwitch(sw);
328 }
329
330 @Override
331 public void removedSwitch(IOFSwitch sw) {
332 log.debug("removedSwitch {}", sw);
333 // do NOT delete from our internal state; we're tracking the rules,
334 // not the switches
335 }
336
337 @Override
338 public void switchPortChanged(Long switchId) {
339 // no-op
340 }
341
342 /**
343 * This handles both rowInsert() and rowUpdate()
344 */
345
346 @Override
347 public void rowsModified(String tableName, Set<Object> rowKeys) {
348 log.debug("Modifying Table {}", tableName);
349
350 HashMap<String, Map<String, OFFlowMod>> entriesToAdd =
351 new HashMap<String, Map<String, OFFlowMod>>();
352 // build up list of what was added
353 for(Object key: rowKeys) {
354 IResultSet resultSet = storageSource.getRow(tableName, key);
355 for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
356 Map<String, Object> row = it.next().getRow();
357 parseRow(row, entriesToAdd);
358 }
359 }
360 // batch updates by switch and blast them out
361 for (String dpid : entriesToAdd.keySet()) {
362 if (!entriesFromStorage.containsKey(dpid))
363 entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>());
364 List<OFMessage> outQueue = new ArrayList<OFMessage>();
365 for(String entry : entriesToAdd.get(dpid).keySet()) {
366 OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry);
367 OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry);
368 if (oldFlowMod != null) { // remove any pre-existing rule
369 oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
370 outQueue.add(oldFlowMod);
371 }
372 if (newFlowMod != null) {
373 entriesFromStorage.get(dpid).put(entry, newFlowMod);
374 outQueue.add(newFlowMod);
375 entry2dpid.put(entry, dpid);
376 } else {
377 entriesFromStorage.get(dpid).remove(entry);
378 entry2dpid.remove(entry);
379 }
380 }
381
382 writeOFMessagesToSwitch(HexString.toLong(dpid), outQueue);
383 }
384 }
385
386 @Override
387 public void rowsDeleted(String tableName, Set<Object> rowKeys) {
388 if (log.isDebugEnabled()) {
389 log.debug("deleting from Table {}", tableName);
390 }
391
392 for(Object obj : rowKeys) {
393 if (!(obj instanceof String)) {
394 log.debug("tried to delete non-string key {}; ignoring", obj);
395 continue;
396 }
397 deleteStaticFlowEntry((String) obj);
398 }
399 }
400
401 @LogMessageDoc(level="ERROR",
402 message="inconsistent internal state: no switch has rule {rule}",
403 explanation="Inconsistent internat state discovered while " +
404 "deleting a static flow rule",
405 recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
406 private boolean deleteStaticFlowEntry(String entryName) {
407 String dpid = entry2dpid.get(entryName);
408 if (log.isDebugEnabled()) {
409 log.debug("Deleting flow {} for switch {}", entryName, dpid);
410 }
411 if (dpid == null) {
412 log.error("inconsistent internal state: no switch has rule {}",
413 entryName);
414 return false;
415 }
416
417 // send flow_mod delete
418 OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName);
419 flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
420
421 if (entriesFromStorage.containsKey(dpid) &&
422 entriesFromStorage.get(dpid).containsKey(entryName)) {
423 entriesFromStorage.get(dpid).remove(entryName);
424 } else {
425 log.debug("Tried to delete non-existent entry {} for switch {}",
426 entryName, dpid);
427 return false;
428 }
429
430 writeFlowModToSwitch(HexString.toLong(dpid), flowMod);
431 return true;
432 }
433
434 /**
435 * Writes a list of OFMessages to a switch
436 * @param dpid The datapath ID of the switch to write to
437 * @param messages The list of OFMessages to write.
438 */
439 @LogMessageDoc(level="ERROR",
440 message="Tried to write to switch {switch} but got {error}",
441 explanation="An I/O error occured while trying to write a " +
442 "static flow to a switch",
443 recommendation=LogMessageDoc.CHECK_SWITCH)
444 private void writeOFMessagesToSwitch(long dpid, List<OFMessage> messages) {
445 IOFSwitch ofswitch = floodlightProvider.getSwitches().get(dpid);
446 if (ofswitch != null) { // is the switch connected
447 try {
448 if (log.isDebugEnabled()) {
449 log.debug("Sending {} new entries to {}", messages.size(), dpid);
450 }
451 ofswitch.write(messages, null);
452 ofswitch.flush();
453 } catch (IOException e) {
454 log.error("Tried to write to switch {} but got {}", dpid, e.getMessage());
455 }
456 }
457 }
458
459 /**
460 * Writes an OFFlowMod to a switch. It checks to make sure the switch
461 * exists before it sends
462 * @param dpid The data to write the flow mod to
463 * @param flowMod The OFFlowMod to write
464 */
465 private void writeFlowModToSwitch(long dpid, OFFlowMod flowMod) {
466 Map<Long,IOFSwitch> switches = floodlightProvider.getSwitches();
467 IOFSwitch ofSwitch = switches.get(dpid);
468 if (ofSwitch == null) {
469 if (log.isDebugEnabled()) {
470 log.debug("Not deleting key {} :: switch {} not connected",
471 dpid);
472 }
473 return;
474 }
475 writeFlowModToSwitch(ofSwitch, flowMod);
476 }
477
478 /**
479 * Writes an OFFlowMod to a switch
480 * @param sw The IOFSwitch to write to
481 * @param flowMod The OFFlowMod to write
482 */
483 @LogMessageDoc(level="ERROR",
484 message="Tried to write OFFlowMod to {switch} but got {error}",
485 explanation="An I/O error occured while trying to write a " +
486 "static flow to a switch",
487 recommendation=LogMessageDoc.CHECK_SWITCH)
488 private void writeFlowModToSwitch(IOFSwitch sw, OFFlowMod flowMod) {
489 try {
490 sw.write(flowMod, null);
491 sw.flush();
492 } catch (IOException e) {
493 log.error("Tried to write OFFlowMod to {} but failed: {}",
494 HexString.toHexString(sw.getId()), e.getMessage());
495 }
496 }
497
498 @Override
499 public String getName() {
500 return StaticFlowName;
501 }
502
503 @Override
504 @LogMessageDoc(level="ERROR",
505 message="Got a FlowRemove message for a infinite " +
506 "timeout flow: {flow} from switch {switch}",
507 explanation="Flows with infinite timeouts should not expire. " +
508 "The switch has expired the flow anyway.",
509 recommendation=LogMessageDoc.REPORT_SWITCH_BUG)
510 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
511 switch (msg.getType()) {
512 case FLOW_REMOVED:
513 break;
514 default:
515 return Command.CONTINUE;
516 }
517 OFFlowRemoved flowRemoved = (OFFlowRemoved) msg;
518 long cookie = flowRemoved.getCookie();
519 /**
520 * This is just to sanity check our assumption that static flows
521 * never expire.
522 */
523 if( AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) {
524 if (flowRemoved.getReason() !=
525 OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE)
526 log.error("Got a FlowRemove message for a infinite " +
527 "timeout flow: {} from switch {}", msg, sw);
528 return Command.STOP; // only for us
529 } else
530 return Command.CONTINUE;
531 }
532
533 @Override
534 public boolean isCallbackOrderingPrereq(OFType type, String name) {
535 return false; // no dependency for non-packet in
536 }
537
538 @Override
539 public boolean isCallbackOrderingPostreq(OFType type, String name) {
540 return false; // no dependency for non-packet in
541 }
542
543 // IFloodlightModule
544
545 @Override
546 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
547 Collection<Class<? extends IFloodlightService>> l =
548 new ArrayList<Class<? extends IFloodlightService>>();
549 l.add(IStaticFlowEntryPusherService.class);
550 return l;
551 }
552
553 @Override
554 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
555 Map<Class<? extends IFloodlightService>,
556 IFloodlightService> m =
557 new HashMap<Class<? extends IFloodlightService>,
558 IFloodlightService>();
559 m.put(IStaticFlowEntryPusherService.class, this);
560 return m;
561 }
562
563 @Override
564 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
565 Collection<Class<? extends IFloodlightService>> l =
566 new ArrayList<Class<? extends IFloodlightService>>();
567 l.add(IFloodlightProviderService.class);
568 l.add(IStorageSourceService.class);
569 l.add(IRestApiService.class);
570 return l;
571 }
572
573 @Override
574 public void init(FloodlightModuleContext context)
575 throws FloodlightModuleException {
576 floodlightProvider =
577 context.getServiceImpl(IFloodlightProviderService.class);
578 storageSource =
579 context.getServiceImpl(IStorageSourceService.class);
580 restApi =
581 context.getServiceImpl(IRestApiService.class);
582 }
583
584 @Override
585 public void startUp(FloodlightModuleContext context) {
586 floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
587 floodlightProvider.addOFSwitchListener(this);
588 floodlightProvider.addHAListener(this);
589
590 // assumes no switches connected at startup()
591 storageSource.createTable(TABLE_NAME, null);
592 storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_NAME);
593 storageSource.addListener(TABLE_NAME, this);
594 entriesFromStorage = readEntriesFromStorage();
595 entry2dpid = computeEntry2DpidMap(entriesFromStorage);
596 restApi.addRestletRoutable(new StaticFlowEntryWebRoutable());
597 }
598
599 // IStaticFlowEntryPusherService methods
600
601 @Override
602 public void addFlow(String name, OFFlowMod fm, String swDpid) {
603 Map<String, Object> fmMap = StaticFlowEntries.flowModToStorageEntry(fm, swDpid, name);
604 entry2dpid.put(name, swDpid);
605 Map<String, OFFlowMod> switchEntries = entriesFromStorage.get(swDpid);
606 if (switchEntries == null) {
607 switchEntries = new HashMap<String, OFFlowMod>();
608 entriesFromStorage.put(swDpid, switchEntries);
609 }
610 switchEntries.put(name, fm);
611 storageSource.insertRowAsync(TABLE_NAME, fmMap);
612 }
613
614 @Override
615 public void deleteFlow(String name) {
616 storageSource.deleteRowAsync(TABLE_NAME, name);
617 // TODO - What if there is a delay in storage?
618 }
619
620 @Override
621 public void deleteAllFlows() {
622 for (String entry : entry2dpid.keySet()) {
623 deleteFlow(entry);
624 }
625 }
626
627 @Override
628 public void deleteFlowsForSwitch(long dpid) {
629 String sDpid = HexString.toHexString(dpid);
630
631 for (Entry<String, String> e : entry2dpid.entrySet()) {
632 if (e.getValue().equals(sDpid))
633 deleteFlow(e.getKey());
634 }
635 }
636
637 @Override
638 public Map<String, Map<String, OFFlowMod>> getFlows() {
639 return entriesFromStorage;
640 }
641
642 @Override
643 public Map<String, OFFlowMod> getFlows(String dpid) {
644 return entriesFromStorage.get(dpid);
645 }
646
647
648 // IHAListener
649
650 @Override
651 public void roleChanged(Role oldRole, Role newRole) {
652 switch(newRole) {
653 case MASTER:
654 if (oldRole == Role.SLAVE) {
655 log.debug("Re-reading static flows from storage due " +
656 "to HA change from SLAVE->MASTER");
657 entriesFromStorage = readEntriesFromStorage();
658 entry2dpid = computeEntry2DpidMap(entriesFromStorage);
659 }
660 break;
661 case SLAVE:
662 log.debug("Clearing in-memory flows due to " +
663 "HA change to SLAVE");
664 entry2dpid.clear();
665 entriesFromStorage.clear();
666 break;
667 default:
668 break;
669 }
670 }
671
672 @Override
673 public void controllerNodeIPsChanged(
674 Map<String, String> curControllerNodeIPs,
675 Map<String, String> addedControllerNodeIPs,
676 Map<String, String> removedControllerNodeIPs) {
677 // ignore
678 }
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700679
680 @Override
681 public void switchPortAdded(Long switchId, OFPhysicalPort port) {
682 // TODO Auto-generated method stub
683
684 }
685
686 @Override
687 public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
688 // TODO Auto-generated method stub
689
690 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800691
692}