3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.samples.simpleforwarding.internal;
12 import java.util.ArrayList;
13 import java.util.EnumSet;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.LinkedList;
18 import java.util.List;
21 import java.util.concurrent.ConcurrentMap;
23 import org.opendaylight.controller.clustering.services.CacheConfigException;
24 import org.opendaylight.controller.clustering.services.CacheExistException;
25 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
26 import org.opendaylight.controller.clustering.services.IClusterServices;
27 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
28 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
29 import org.opendaylight.controller.hosttracker.IfIptoHost;
30 import org.opendaylight.controller.hosttracker.IfNewHostNotify;
31 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
32 import org.opendaylight.controller.sal.action.Action;
33 import org.opendaylight.controller.sal.action.Output;
34 import org.opendaylight.controller.sal.action.PopVlan;
35 import org.opendaylight.controller.sal.action.SetDlDst;
36 import org.opendaylight.controller.sal.action.SetVlanId;
37 import org.opendaylight.controller.sal.core.Edge;
38 import org.opendaylight.controller.sal.core.Node;
39 import org.opendaylight.controller.sal.core.NodeConnector;
40 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
41 import org.opendaylight.controller.sal.core.Path;
42 import org.opendaylight.controller.sal.core.Property;
43 import org.opendaylight.controller.sal.core.State;
44 import org.opendaylight.controller.sal.core.UpdateType;
45 import org.opendaylight.controller.sal.flowprogrammer.Flow;
46 import org.opendaylight.controller.sal.match.Match;
47 import org.opendaylight.controller.sal.match.MatchType;
48 import org.opendaylight.controller.sal.routing.IListenRoutingUpdates;
49 import org.opendaylight.controller.sal.routing.IRouting;
50 import org.opendaylight.controller.sal.utils.EtherTypes;
51 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
52 import org.opendaylight.controller.sal.utils.Status;
53 import org.opendaylight.controller.samples.simpleforwarding.HostNodePair;
54 import org.opendaylight.controller.switchmanager.IInventoryListener;
55 import org.opendaylight.controller.switchmanager.ISwitchManager;
56 import org.opendaylight.controller.topologymanager.ITopologyManager;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
62 public class SimpleForwardingImpl implements IfNewHostNotify,
63 IListenRoutingUpdates, IInventoryListener {
64 private static Logger log = LoggerFactory
65 .getLogger(SimpleForwardingImpl.class);
66 private static short DEFAULT_IPSWITCH_PRIORITY = 1;
67 private IfIptoHost hostTracker;
68 private IForwardingRulesManager frm;
69 private ITopologyManager topologyManager;
70 private IRouting routing;
71 private ConcurrentMap<HostNodePair, HashMap<NodeConnector, FlowEntry>> rulesDB;
72 private Map<Node, List<FlowEntry>> tobePrunedPos = new HashMap<Node, List<FlowEntry>>();
73 private IClusterContainerServices clusterContainerService = null;
74 private ISwitchManager switchManager;
77 * Return codes from the programming of the perHost rules in HW
80 public enum RulesProgrammingReturnCode {
81 SUCCESS, FAILED_FEW_SWITCHES, FAILED_ALL_SWITCHES, FAILED_WRONG_PARAMS
84 public void setRouting(IRouting routing) {
85 this.routing = routing;
88 public void unsetRouting(IRouting routing) {
89 if (this.routing == routing) {
94 public ITopologyManager getTopologyManager() {
95 return topologyManager;
98 public void setTopologyManager(ITopologyManager topologyManager) {
99 log.debug("Setting topologyManager");
100 this.topologyManager = topologyManager;
103 public void unsetTopologyManager(ITopologyManager topologyManager) {
104 if (this.topologyManager == topologyManager) {
105 this.topologyManager = null;
109 public void setHostTracker(IfIptoHost hostTracker) {
110 log.debug("Setting HostTracker");
111 this.hostTracker = hostTracker;
114 public void setForwardingRulesManager(
115 IForwardingRulesManager forwardingRulesManager) {
116 log.debug("Setting ForwardingRulesManager");
117 this.frm = forwardingRulesManager;
120 public void unsetHostTracker(IfIptoHost hostTracker) {
121 if (this.hostTracker == hostTracker) {
122 this.hostTracker = null;
126 public void unsetForwardingRulesManager(
127 IForwardingRulesManager forwardingRulesManager) {
128 if (this.frm == forwardingRulesManager) {
134 * Function called when the bundle gets activated
137 public void startUp() {
143 * Function called when the bundle gets stopped
146 public void shutDown() {
147 log.debug("Destroy all the host Rules given we are shutting down");
148 uninstallPerHostRules();
152 @SuppressWarnings("deprecation")
153 private void allocateCaches() {
154 if (this.clusterContainerService == null) {
155 log.info("un-initialized clusterContainerService, can't create cache");
160 clusterContainerService.createCache("forwarding.ipswitch.rules",
161 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
162 } catch (CacheExistException cee) {
163 log.error("\nCache already exists - destroy and recreate if needed");
164 } catch (CacheConfigException cce) {
165 log.error("\nCache configuration invalid - check cache mode");
169 @SuppressWarnings({ "unchecked", "deprecation" })
170 private void retrieveCaches() {
171 if (this.clusterContainerService == null) {
172 log.info("un-initialized clusterContainerService, can't retrieve cache");
176 rulesDB = (ConcurrentMap<HostNodePair, HashMap<NodeConnector, FlowEntry>>) clusterContainerService
177 .getCache("forwarding.ipswitch.rules");
178 if (rulesDB == null) {
179 log.error("\nFailed to get rulesDB handle");
183 @SuppressWarnings("deprecation")
184 private void destroyCaches() {
185 if (this.clusterContainerService == null) {
186 log.info("un-initialized clusterContainerService, can't destroy cache");
190 clusterContainerService.destroyCache("forwarding.ipswitch.rules");
193 @SuppressWarnings("unused")
194 private void updatePerHostRuleInSW(HostNodeConnector host, Node currNode,
195 Node rootNode, Edge link, HostNodePair key,
196 Set<NodeConnector> passedPorts) {
198 // link parameter it's optional
199 if (host == null || key == null || currNode == null || rootNode == null) {
202 Set<NodeConnector> ports = passedPorts;
203 // TODO: Replace this with SAL equivalent when available
204 //if (container == null) {
205 ports = new HashSet<NodeConnector>();
206 ports.add(NodeConnectorCreator.createNodeConnector(
207 NodeConnectorIDType.ALL, NodeConnector.SPECIALNODECONNECTORID,
211 HashMap<NodeConnector, FlowEntry> pos = this.rulesDB.get(key);
213 pos = new HashMap<NodeConnector, FlowEntry>();
216 log.debug("Empty port list, nothing to do");
219 for (NodeConnector inPort : ports) {
221 * skip the port connected to the target host
223 if (currNode.equals(rootNode)
224 && (host.getnodeConnector().equals(inPort))) {
227 FlowEntry removed_po = pos.remove(inPort);
228 Match match = new Match();
229 List<Action> actions = new ArrayList<Action>();
230 // IP destination based forwarding
231 //on /32 entries only!
232 match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
233 match.setField(MatchType.NW_DST, host.getNetworkAddress());
235 //Action for the policy if to
236 //forward to a port except on the
237 //switch where the host sits,
238 //which is to rewrite also the MAC
239 //and to forward on the Host port
240 NodeConnector outPort = null;
242 if (currNode.equals(rootNode)) {
243 outPort = host.getnodeConnector();
244 if (inPort.equals(outPort)) {
250 actions.add(new SetDlDst(host.getDataLayerAddressBytes()));
252 if (!inPort.getType().equals(
253 NodeConnectorIDType.ALL)) {
255 * Container mode: at the destination switch, we need to strip out the tag (VLAN)
257 actions.add(new PopVlan());
261 * currNode is NOT the rootNode
264 outPort = link.getTailNodeConnector();
265 if (inPort.equals(outPort)) {
267 * skip the outgoing port
272 * If outPort is network link, add VLAN tag
274 if (topologyManager.isInternal(outPort)) {
275 log.debug("outPort {}/{} is internal uplink port",
278 log.debug("outPort {}/{} is host facing port",
282 if ((!inPort.getType().equals(
283 NodeConnectorIDType.ALL))
284 && (topologyManager.isInternal(outPort))) {
285 Node nextNode = link.getHeadNodeConnector()
287 // TODO: Replace this with SAL equivalent
288 //short tag = container.getTag((Long)nextNode.getNodeID());
291 log.debug("adding SET_VLAN {} for traffic " +
292 "leaving {}/{} toward switch {}",
293 new Object[] { tag, currNode, outPort,
295 actions.add(new SetVlanId(tag));
297 log.debug("No tag assigned to switch {}", nextNode);
302 if (outPort != null) {
303 actions.add(new Output(outPort));
305 if (!inPort.getType().equals(NodeConnectorIDType.ALL)) {
307 * include input port in the flow match field
309 match.setField(MatchType.IN_PORT, inPort);
311 if (topologyManager.isInternal(inPort)) {
312 log.debug("inPort {}/{} is internal uplink port", currNode,
315 log.debug("inPort {}/{} is host facing port", currNode,
319 * for incoming network link; if the VLAN tag is defined, include it for incoming flow matching
321 if (topologyManager.isInternal(inPort)) {
322 // TODO: Replace this with SAL equivalent
323 //short tag = container.getTag((Long)currNode.getNodeID());
326 log.debug("adding MATCH VLAN {} for traffic entering" +
328 new Object[] {tag, currNode, inPort});
329 match.setField(MatchType.DL_VLAN, tag);
331 log.debug("No tag assigned to switch {}", currNode);
335 // Make sure the priority for IP switch entries is
336 // set to a level just above default drop entries
337 Flow flow = new Flow(match, actions);
338 flow.setIdleTimeout((short) 0);
339 flow.setHardTimeout((short) 0);
340 flow.setPriority(DEFAULT_IPSWITCH_PRIORITY);
342 String policyName = host.getNetworkAddress().getHostAddress()
344 String flowName = "["
345 + (!inPort.getType().equals(NodeConnectorIDType.ALL) ?
346 (inPort.getID()).toString()
348 + host.getNetworkAddress().getHostAddress() + "/32 on N "
350 FlowEntry po = new FlowEntry(policyName, flowName, flow, currNode);
352 // Now save the rule in the DB rule,
353 // so on updates from topology we can
356 this.rulesDB.put(key, pos);
357 if (!inPort.getType().equals(NodeConnectorIDType.ALL)) {
358 log.debug("Adding Match(inPort = {} , DIP = {})" +
359 " Action(outPort= {}) to node {}",
360 new Object[] { inPort,
361 host.getNetworkAddress().getHostAddress(),
363 if ((removed_po != null)
364 && (!po.getFlow().getMatch().equals(
365 removed_po.getFlow().getMatch()))) {
366 log.debug("Old Flow match: {}, New Flow match: {}",
367 removed_po.getFlow().getMatch(), po.getFlow()
369 addTobePrunedPolicy(currNode, removed_po, po);
373 log.debug("Adding policyMatch(DIP = {}) Action(outPort= {}) " +
374 "to node {}", new Object[] {
375 host.getNetworkAddress().getHostAddress(), outPort,
382 * Calculate the per-Host rules to be installed in the rulesDB,
383 * and that will later on be installed in HW, this routine will
384 * implicitly calculate the shortest path tree among the switch
385 * to which the host is attached and all the other switches in the
386 * network and will automatically create all the rules that allow
387 * a /32 destination IP based forwarding, as in traditional IP
390 * @param host Host for which we are going to prepare the rules in the rulesDB
392 * @return A set of switches touched by the calculation
394 private Set<Node> preparePerHostRules(HostNodeConnector host) {
398 if (this.routing == null) {
401 if (this.switchManager == null) {
404 if (this.rulesDB == null) {
408 Node rootNode = host.getnodeconnectorNode();
409 Set<Node> nodes = this.switchManager.getNodes();
410 Set<Node> switchesToProgram = new HashSet<Node>();
412 HashMap<NodeConnector, FlowEntry> pos;
415 for (Node node : nodes) {
416 if (node.equals(rootNode)) {
417 // We skip it because for the node with host attached
418 // we will process in every case even if there are no
423 Path res = this.routing.getRoute(node, rootNode);
424 if ((res == null) || ((links = res.getEdges()) == null)) {
425 // Still the path that connect node to rootNode
427 log.debug("NO Route/Path between SW[{}] --> SW[{}] cleaning " +
428 "potentially existing entries", node, rootNode);
429 key = new HostNodePair(host, node);
430 pos = this.rulesDB.get(key);
432 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
435 //Uninstall the policy
436 this.frm.uninstallFlowEntry(po);
439 this.rulesDB.remove(key);
444 log.debug("Route between SW[{}] --> SW[{}]", node, rootNode);
446 Node currNode = node;
447 key = new HostNodePair(host, currNode);
449 for (curr = 0; curr < links.size(); curr++) {
450 link = links.get(curr);
452 log.error("Could not retrieve the Link");
456 log.debug(link.toString());
458 // Index all the switches to be programmed
459 // switchesToProgram.add(currNode);
460 Set<NodeConnector> ports = null;
461 ports = switchManager.getUpNodeConnectors(currNode);
462 updatePerHostRuleInSW(host, currNode, rootNode, link, key,
464 if ((this.rulesDB.get(key)) != null) {
466 * Calling updatePerHostRuleInSW() doesn't guarantee that rules will be
467 * added in currNode (e.g, there is only one link from currNode to rootNode
468 * This check makes sure that there are some rules in the rulesDB for the
469 * given key prior to adding switch to switchesToProgram
471 switchesToProgram.add(currNode);
473 currNode = link.getHeadNodeConnector().getNode();
474 key = new HostNodePair(host, currNode);
478 // This rule will be added no matter if any topology is built
479 // or no, it serve as a way to handle the case of a node with
480 // multiple hosts attached to it but not yet connected to the
482 switchesToProgram.add(rootNode);
483 Set<NodeConnector> ports = switchManager
484 .getUpNodeConnectors(rootNode);
485 updatePerHostRuleInSW(host, rootNode, rootNode, null, new HostNodePair(
486 host, rootNode), ports);
488 // log.debug("Getting out at the end!");
489 return switchesToProgram;
493 * Calculate the per-Host rules to be installed in the rulesDB
494 * from a specific switch when a host facing port comes up.
495 * These rules will later on be installed in HW. This routine
496 * will implicitly calculate the shortest path from the switch
497 * where the port has come up to the switch where host is ,
498 * attached and will automatically create all the rules that allow
499 * a /32 destination IP based forwarding, as in traditional IP
502 * @param host Host for which we are going to prepare the rules in the rulesDB
503 * @param swId Switch ID where the port has come up
505 * @return A set of switches touched by the calculation
507 private Set<Node> preparePerHostPerSwitchRules(HostNodeConnector host,
508 Node node, NodeConnector swport) {
509 if ((host == null) || (node == null)) {
512 if (this.routing == null) {
515 if (this.switchManager == null) {
518 if (this.rulesDB == null) {
522 Node rootNode = host.getnodeconnectorNode();
523 Set<Node> switchesToProgram = new HashSet<Node>();
525 Map<NodeConnector, FlowEntry> pos;
527 Set<NodeConnector> ports = new HashSet<NodeConnector>();
531 Path res = this.routing.getRoute(node, rootNode);
532 if ((res == null) || ((links = res.getEdges()) == null)) {
533 // Still the path that connect node to rootNode
535 log.debug("NO Route/Path between SW[{}] --> SW[{}] cleaning " +
536 "potentially existing entries", node, rootNode);
537 key = new HostNodePair(host, node);
538 pos = this.rulesDB.get(key);
540 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
543 //Uninstall the policy
544 this.frm.uninstallFlowEntry(po);
547 this.rulesDB.remove(key);
552 log.debug("Route between SW[{}] --> SW[{}]", node, rootNode);
554 Node currNode = node;
555 key = new HostNodePair(host, currNode);
557 for (curr = 0; curr < links.size(); curr++) {
558 link = links.get(curr);
560 log.error("Could not retrieve the Link");
564 log.debug("Link [{}/{}] --> [{}/{}]", new Object[] {
565 currNode, link.getHeadNodeConnector(),
566 link.getHeadNodeConnector().getNode(),
567 link.getTailNodeConnector()});
569 // Index all the switches to be programmed
570 switchesToProgram.add(currNode);
571 updatePerHostRuleInSW(host, currNode, rootNode, link, key, ports);
572 break; // come out of the loop for port up case, interested only in programming one switch
575 // This rule will be added no matter if any topology is built
576 // or no, it serve as a way to handle the case of a node with
577 // multiple hosts attached to it but not yet connected to the
579 // switchesToProgram.add(rootNode);
580 //updatePerHostRuleInSW(host, rootNode,
582 // new HostNodePair(host, rootNode),ports);
584 // log.debug("Getting out at the end!");
585 return switchesToProgram;
589 * Routine that fetch the per-Host rules from the rulesDB and
590 * install in HW, the one having the same match rules will be
591 * overwritten silently.
593 * @param host host for which we want to install in HW the per-Host rules
594 * @param switchesToProgram list of switches to be programmed in
595 * HW, usually are them all, but better to be explicit, that list
596 * may change with time based on new switch addition/removal
598 * @return a return code that convey the programming status of the HW
600 private RulesProgrammingReturnCode installPerHostRules(
601 HostNodeConnector host, Set<Node> switchesToProgram) {
602 RulesProgrammingReturnCode retCode = RulesProgrammingReturnCode.SUCCESS;
603 if (host == null || switchesToProgram == null) {
604 return RulesProgrammingReturnCode.FAILED_WRONG_PARAMS;
606 Map<NodeConnector, FlowEntry> pos;
608 // Now program every single switch
609 log.debug("Inside installPerHostRules");
610 for (Node swId : switchesToProgram) {
611 HostNodePair key = new HostNodePair(host, swId);
612 pos = this.rulesDB.get(key);
616 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
619 // Populate the Policy field now
620 Status poStatus = this.frm.installFlowEntry(po);
621 if (!poStatus.isSuccess()) {
622 log.error("Failed to install policy: "
623 + po.getGroupName() + " ("
624 + poStatus.getDescription() + ")");
626 retCode = RulesProgrammingReturnCode.FAILED_FEW_SWITCHES;
627 // Remove the entry from the DB, it was not installed!
628 this.rulesDB.remove(key);
630 log.debug("Successfully installed policy "
631 + po.toString() + " on switch " + swId);
634 log.error("Cannot find a policy for SW:({}) Host: ({})",
636 /* // Now dump every single rule */
637 /* for (HostNodePair dumpkey : this.rulesDB.keySet()) { */
638 /* po = this.rulesDB.get(dumpkey); */
639 /* log.debug("Dumping entry H{" + dumpkey.getHost() + "} S{" + dumpkey.getSwitchId() + "} = {" + (po == null ? "null policy" : po)); */
644 log.debug("Leaving installPerHostRules");
649 * Cleanup all the host rules for a given host
651 * @param host Host for which the host rules need to be cleaned
652 * up, the host could be null in that case it match all the hosts
654 * @return a return code that convey the programming status of the HW
656 private RulesProgrammingReturnCode uninstallPerHostRules(
657 HostNodeConnector host) {
658 RulesProgrammingReturnCode retCode = RulesProgrammingReturnCode.SUCCESS;
659 Map<NodeConnector, FlowEntry> pos;
661 // Now program every single switch
662 for (HostNodePair key : this.rulesDB.keySet()) {
663 if (host == null || key.getHost().equals(host)) {
664 pos = this.rulesDB.get(key);
665 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
668 // Uninstall the policy
669 this.frm.uninstallFlowEntry(po);
672 this.rulesDB.remove(key);
679 * Cleanup all the host rules for a given node, triggered when the
680 * switch disconnects, so there is no reason for Hw cleanup
681 * because it's disconnected anyhow
682 * TBD - Revisit above stmt in light of CSCus88743
683 * @param targetNode Node for which we want to do cleanup
686 private void uninstallPerNodeRules(Node targetNode) {
687 //RulesProgrammingReturnCode retCode = RulesProgrammingReturnCode.SUCCESS;
688 Map<NodeConnector, FlowEntry> pos;
691 // Now program every single switch
692 for (HostNodePair key : this.rulesDB.keySet()) {
693 Node node = key.getNode();
694 if (targetNode == null || node.equals(targetNode)) {
695 log.debug("Work on {} host {}", node, key.getHost());
696 pos = this.rulesDB.get(key);
697 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
700 // Uninstall the policy
701 this.frm.uninstallFlowEntry(po);
704 log.debug("Remove {}", key);
705 this.rulesDB.remove(key);
711 * Cleanup all the host rules currently present in the rulesDB
713 * @return a return code that convey the programming status of the HW
715 private RulesProgrammingReturnCode uninstallPerHostRules() {
716 return uninstallPerHostRules(null);
720 public void recalculateDone() {
721 if (this.hostTracker == null) {
722 //Not yet ready to process all the updates
725 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
726 for (HostNodeConnector host : allHosts) {
727 Set<Node> switches = preparePerHostRules(host);
728 if (switches != null) {
729 // This will refresh existing rules, by overwriting
731 installPerHostRules(host, switches);
732 pruneExcessRules(switches);
737 void addTobePrunedPolicy(Node swId, FlowEntry po, FlowEntry new_po) {
738 List<FlowEntry> pl = tobePrunedPos.get(swId);
740 pl = new LinkedList<FlowEntry>();
741 tobePrunedPos.put(swId, pl);
744 log.debug("Adding Pruned Policy for SwId: {}", swId);
745 log.debug("Old Policy: {}", po);
746 log.debug("New Policy: {}", new_po);
749 private void pruneExcessRules(Set<Node> switches) {
750 for (Node swId : switches) {
751 List<FlowEntry> pl = tobePrunedPos.get(swId);
755 "Policies for Switch: {} in the list to be deleted: {}",
757 Iterator<FlowEntry> plIter = pl.iterator();
758 //for (Policy po: pl) {
759 while (plIter.hasNext()) {
760 FlowEntry po = plIter.next();
761 log.error("Removing Policy, Switch: {} Policy: {}", swId,
763 this.frm.uninstallFlowEntry(po);
767 // tobePrunedPos.remove(swId);
772 * A Host facing port has come up in a container. Add rules on the switch where this
773 * port has come up for all the known hosts to the controller.
774 * @param swId switch id of the port where port came up
775 * @param swPort port which came up
777 private void updateRulesforHIFup(Node node, NodeConnector swPort) {
778 if (this.hostTracker == null) {
779 //Not yet ready to process all the updates
782 log.debug("Host Facing Port in a container came up, install the rules for all hosts from this port !");
783 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
784 for (HostNodeConnector host : allHosts) {
785 if (node.equals(host.getnodeconnectorNode())
786 && swPort.equals(host.getnodeConnector())) {
788 * This host resides behind the same switch and port for which a port up
789 * message is received. Ideally this should not happen, but if it does,
790 * don't program any rules for this host
794 Set<Node> switches = preparePerHostPerSwitchRules(host, node,
796 if (switches != null) {
797 // This will refresh existing rules, by overwriting
799 installPerHostRules(host, switches);
806 public void notifyHTClient(HostNodeConnector host) {
810 Set<Node> switches = preparePerHostRules(host);
811 if (switches != null) {
812 installPerHostRules(host, switches);
817 public void notifyHTClientHostRemoved(HostNodeConnector host) {
821 uninstallPerHostRules(host);
825 public void notifyNode(Node node, UpdateType type,
826 Map<String, Property> propMap) {
832 log.debug("Node {} gone, doing a cleanup", node);
833 uninstallPerNodeRules(node);
841 public void notifyNodeConnector(NodeConnector nodeConnector,
842 UpdateType type, Map<String, Property> propMap) {
843 if (nodeConnector == null)
854 State state = (State) propMap.get(State.StatePropName);
855 if ((state != null) && (state.getValue() == State.EDGE_UP)) {
864 handleNodeConnectorStatusUp(nodeConnector);
866 handleNodeConnectorStatusDown(nodeConnector);
870 private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
871 if (topologyManager == null) {
872 log.debug("topologyManager is not set yet");
876 if (topologyManager.isInternal(nodeConnector)) {
877 log.debug("{} is not a host facing link", nodeConnector);
881 log.debug("{} is up", nodeConnector);
882 updateRulesforHIFup(nodeConnector.getNode(), nodeConnector);
885 private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) {
886 log.debug("{} is down", nodeConnector);
889 void setClusterContainerService(IClusterContainerServices s) {
890 log.debug("Cluster Service set");
891 this.clusterContainerService = s;
894 void unsetClusterContainerService(IClusterContainerServices s) {
895 if (this.clusterContainerService == s) {
896 log.debug("Cluster Service removed!");
897 this.clusterContainerService = null;
902 * Function called by the dependency manager when all the required
903 * dependencies are satisfied
911 * Function called by the dependency manager when at least one
912 * dependency become unsatisfied or when the component is shutting
913 * down because for example bundle is being stopped.
920 * Function called by dependency manager after "init ()" is called
921 * and after the services provided by the class are registered in
922 * the service registry
929 * Function called by the dependency manager before the services
930 * exported by the component are unregistered, this will be
931 * followed by a "destroy ()" calls
937 public void setSwitchManager(ISwitchManager switchManager) {
938 this.switchManager = switchManager;
941 public void unsetSwitchManager(ISwitchManager switchManager) {
942 if (this.switchManager == switchManager) {
943 this.switchManager = null;