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.net.InetAddress;
13 import java.util.ArrayList;
14 import java.util.EnumSet;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.LinkedList;
19 import java.util.List;
22 import java.util.concurrent.ConcurrentMap;
24 import org.opendaylight.controller.clustering.services.CacheConfigException;
25 import org.opendaylight.controller.clustering.services.CacheExistException;
26 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
27 import org.opendaylight.controller.clustering.services.IClusterServices;
28 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
29 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
30 import org.opendaylight.controller.hosttracker.IfIptoHost;
31 import org.opendaylight.controller.hosttracker.IfNewHostNotify;
32 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
33 import org.opendaylight.controller.sal.action.Action;
34 import org.opendaylight.controller.sal.action.Output;
35 import org.opendaylight.controller.sal.action.PopVlan;
36 import org.opendaylight.controller.sal.action.SetDlDst;
37 import org.opendaylight.controller.sal.action.SetVlanId;
38 import org.opendaylight.controller.sal.core.Edge;
39 import org.opendaylight.controller.sal.core.Node;
40 import org.opendaylight.controller.sal.core.NodeConnector;
41 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
42 import org.opendaylight.controller.sal.core.Path;
43 import org.opendaylight.controller.sal.core.Property;
44 import org.opendaylight.controller.sal.core.State;
45 import org.opendaylight.controller.sal.core.UpdateType;
46 import org.opendaylight.controller.sal.flowprogrammer.Flow;
47 import org.opendaylight.controller.sal.match.Match;
48 import org.opendaylight.controller.sal.match.MatchType;
49 import org.opendaylight.controller.sal.packet.Ethernet;
50 import org.opendaylight.controller.sal.packet.IDataPacketService;
51 import org.opendaylight.controller.sal.packet.IListenDataPacket;
52 import org.opendaylight.controller.sal.packet.IPv4;
53 import org.opendaylight.controller.sal.packet.Packet;
54 import org.opendaylight.controller.sal.packet.PacketResult;
55 import org.opendaylight.controller.sal.packet.RawPacket;
56 import org.opendaylight.controller.sal.routing.IListenRoutingUpdates;
57 import org.opendaylight.controller.sal.routing.IRouting;
58 import org.opendaylight.controller.sal.utils.EtherTypes;
59 import org.opendaylight.controller.sal.utils.NetUtils;
60 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
61 import org.opendaylight.controller.sal.utils.Status;
62 import org.opendaylight.controller.samples.simpleforwarding.HostNodePair;
63 import org.opendaylight.controller.switchmanager.IInventoryListener;
64 import org.opendaylight.controller.switchmanager.ISwitchManager;
65 import org.opendaylight.controller.topologymanager.ITopologyManager;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
70 * This class implements basic L3 forwarding within the managed devices.
71 * Forwarding is only done within configured subnets.</br>
73 * The basic flow is that the module listens for new hosts from the
74 * {@link org.opendaylight.controller.hosttracker.IfIptoHost HostTracker}
75 * service and on discovering a new host it first calls
76 * <tt>preparePerHostRules()</tt> to create a set of new rules that must be
77 * installed in the network. This is done by repeatedly calling
78 * <tt>updatePerHostRuleInSW()</tt> for each switch in the network. Then it
79 * installs those rules using <tt>installPerHostRules()</tt>.
81 public class SimpleForwardingImpl implements IfNewHostNotify,
82 IListenRoutingUpdates, IInventoryListener, IListenDataPacket {
83 private static Logger log = LoggerFactory.getLogger(SimpleForwardingImpl.class);
84 private static short DEFAULT_IPSWITCH_PRIORITY = 1;
85 static final String FORWARDING_RULES_CACHE_NAME = "forwarding.ipswitch.rules";
86 private IfIptoHost hostTracker;
87 private IForwardingRulesManager frm;
88 private ITopologyManager topologyManager;
89 private IRouting routing;
92 * The set of all forwarding rules: (host) -> (switch -> flowmod). Note that
93 * the host includes an attachment point and that while the switch appears
94 * to be a switch's port, in actuality it is a special port which just
95 * represents the switch.
97 private ConcurrentMap<HostNodePair, HashMap<NodeConnector, FlowEntry>> rulesDB;
98 private Map<Node, List<FlowEntry>> tobePrunedPos = new HashMap<Node, List<FlowEntry>>();
99 private IClusterContainerServices clusterContainerService = null;
100 private ISwitchManager switchManager;
101 private IDataPacketService dataPacketService;
104 * Return codes from the programming of the perHost rules in HW
106 public enum RulesProgrammingReturnCode {
107 SUCCESS, FAILED_FEW_SWITCHES, FAILED_ALL_SWITCHES, FAILED_WRONG_PARAMS
109 public void setDataPacketService(IDataPacketService s) {
110 log.debug("Setting dataPacketService");
111 this.dataPacketService = s;
114 public void unsetDataPacketService(IDataPacketService s) {
115 if (this.dataPacketService == s) {
116 this.dataPacketService = null;
120 public void setRouting(IRouting routing) {
121 log.debug("Setting routing");
122 this.routing = routing;
125 public void unsetRouting(IRouting routing) {
126 if (this.routing == routing) {
131 public void setTopologyManager(ITopologyManager topologyManager) {
132 log.debug("Setting topologyManager");
133 this.topologyManager = topologyManager;
136 public void unsetTopologyManager(ITopologyManager topologyManager) {
137 if (this.topologyManager == topologyManager) {
138 this.topologyManager = null;
142 public void setHostTracker(IfIptoHost hostTracker) {
143 log.debug("Setting HostTracker");
144 this.hostTracker = hostTracker;
147 public void setForwardingRulesManager(
148 IForwardingRulesManager forwardingRulesManager) {
149 log.debug("Setting ForwardingRulesManager");
150 this.frm = forwardingRulesManager;
153 public void unsetHostTracker(IfIptoHost hostTracker) {
154 if (this.hostTracker == hostTracker) {
155 this.hostTracker = null;
159 public void unsetForwardingRulesManager(
160 IForwardingRulesManager forwardingRulesManager) {
161 if (this.frm == forwardingRulesManager) {
167 * Function called when the bundle gets activated
170 public void startUp() {
176 * Function called when the bundle gets stopped
179 public void shutDown() {
180 log.debug("Destroy all the host Rules given we are shutting down");
181 uninstallPerHostRules();
185 private void allocateCaches() {
186 if (this.clusterContainerService == null) {
187 log.trace("un-initialized clusterContainerService, can't create cache");
192 clusterContainerService.createCache(FORWARDING_RULES_CACHE_NAME,
193 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
194 } catch (CacheExistException cee) {
195 log.error("\nCache already exists - destroy and recreate if needed");
196 } catch (CacheConfigException cce) {
197 log.error("\nCache configuration invalid - check cache mode");
201 @SuppressWarnings({ "unchecked" })
202 private void retrieveCaches() {
203 if (this.clusterContainerService == null) {
204 log.trace("un-initialized clusterContainerService, can't retrieve cache");
208 rulesDB = (ConcurrentMap<HostNodePair, HashMap<NodeConnector, FlowEntry>>) clusterContainerService
209 .getCache(FORWARDING_RULES_CACHE_NAME);
210 if (rulesDB == null) {
211 log.error("\nFailed to get rulesDB handle");
215 private void destroyCaches() {
216 if (this.clusterContainerService == null) {
217 log.trace("un-initialized clusterContainerService, can't destroy cache");
221 clusterContainerService.destroyCache(FORWARDING_RULES_CACHE_NAME);
225 * Populates <tt>rulesDB</tt> with rules specifying how to reach
226 * <tt>host</tt> from <tt>currNode</tt> assuming that:
228 * <li><tt>host</tt> is attached to <tt>rootNode</tt>
229 * <li><tt>link</tt> is the next part of the path to reach <tt>rootNode</tt>
230 * from <tt>currNode</tt>
231 * <li><tt>rulesDB.get(key)</tt> represents the list of rules stored about
232 * <tt>host</tt> at <tt>currNode</tt>
236 * The host to be reached.
238 * The current node being processed.
240 * The node to be reached. Really, the switch which host is
243 * The link to follow from curNode to get to rootNode
245 * The key to store computed rules at in the rulesDB. For now,
246 * this is a {@link HostNodePair} of host and currNode.
248 private void updatePerHostRuleInSW(HostNodeConnector host, Node currNode,
249 Node rootNode, Edge link, HostNodePair key) {
251 // only the link parameter is optional
252 if (host == null || key == null || currNode == null || rootNode == null) {
256 Set<NodeConnector> ports = new HashSet<NodeConnector>();
257 // add a special port of type ALL and port 0 to represent the node
258 // without specifying a port on that node
259 ports.add(NodeConnectorCreator.createNodeConnector(
260 NodeConnectorIDType.ALL, NodeConnector.SPECIALNODECONNECTORID,
263 HashMap<NodeConnector, FlowEntry> pos = this.rulesDB.get(key);
265 pos = new HashMap<NodeConnector, FlowEntry>();
268 for (NodeConnector inPort : ports) {
269 // skip the port connected to the target host
270 if (currNode.equals(rootNode)
271 && (host.getnodeConnector().equals(inPort))) {
275 // remove the current rule, if any
276 FlowEntry removed_po = pos.remove(inPort);
277 Match match = new Match();
278 List<Action> actions = new ArrayList<Action>();
280 // IP destination based forwarding on /32 entries only!
281 match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
282 match.setField(MatchType.NW_DST, host.getNetworkAddress());
284 /* Action for the policy is to forward to a port except on the
285 * switch where the host sits, which is to rewrite also the MAC
286 * and to forward on the Host port */
287 NodeConnector outPort = null;
289 if (currNode.equals(rootNode)) {
290 /* If we're at the root node, then rewrite the DL addr and
291 * possibly pop the VLAN tag. This allows for MAC rewriting
292 * in the core of the network assuming we can uniquely ID
293 * packets based on IP address. */
295 outPort = host.getnodeConnector();
296 if (inPort.equals(outPort)) {
297 // TODO: isn't this code skipped already by the above continue?
298 // skip the host port
301 actions.add(new SetDlDst(host.getDataLayerAddressBytes()));
303 if (!inPort.getType().equals(NodeConnectorIDType.ALL)) {
304 // Container mode: at the destination switch, we need to strip out the tag (VLAN)
305 actions.add(new PopVlan());
308 // currNode is NOT the rootNode, find the next hop and create a rule
310 outPort = link.getTailNodeConnector();
311 if (inPort.equals(outPort)) {
312 // skip the outgoing port
316 // If outPort is network link, add VLAN tag
317 if (topologyManager.isInternal(outPort)) {
318 log.debug("outPort {}/{} is internal uplink port",
321 log.debug("outPort {}/{} is host facing port",
325 if ((!inPort.getType().equals(NodeConnectorIDType.ALL))
326 && (topologyManager.isInternal(outPort))) {
327 Node nextNode = link.getHeadNodeConnector()
329 // TODO: Replace this with SAL equivalent
330 //short tag = container.getTag((Long)nextNode.getNodeID());
333 log.debug("adding SET_VLAN {} for traffic " +
334 "leaving {}/{} toward switch {}",
335 new Object[] { tag, currNode, outPort,
337 actions.add(new SetVlanId(tag));
339 log.debug("No tag assigned to switch {}", nextNode);
344 if (outPort != null) {
345 actions.add(new Output(outPort));
347 if (!inPort.getType().equals(NodeConnectorIDType.ALL)) {
348 // include input port in the flow match field
349 match.setField(MatchType.IN_PORT, inPort);
351 if (topologyManager.isInternal(inPort)) {
352 log.debug("inPort {}/{} is internal uplink port", currNode,
355 log.debug("inPort {}/{} is host facing port", currNode,
359 // for incoming network link; if the VLAN tag is defined, include it for incoming flow matching
360 if (topologyManager.isInternal(inPort)) {
361 // TODO: Replace this with SAL equivalent
362 //short tag = container.getTag((Long)currNode.getNodeID());
365 log.debug("adding MATCH VLAN {} for traffic entering" +
367 new Object[] {tag, currNode, inPort});
368 match.setField(MatchType.DL_VLAN, tag);
370 log.debug("No tag assigned to switch {}", currNode);
374 // Make sure the priority for IP switch entries is
375 // set to a level just above default drop entries
376 Flow flow = new Flow(match, actions);
377 flow.setIdleTimeout((short) 0);
378 flow.setHardTimeout((short) 0);
379 flow.setPriority(DEFAULT_IPSWITCH_PRIORITY);
381 String policyName = host.getNetworkAddress().getHostAddress()
383 String flowName = "["
384 + (!inPort.getType().equals(NodeConnectorIDType.ALL) ?
385 (inPort.getID()).toString()
387 + host.getNetworkAddress().getHostAddress() + "/32 on N "
389 FlowEntry po = new FlowEntry(policyName, flowName, flow, currNode);
391 /* Now save the rule in the DB rule, so on updates from topology we
394 this.rulesDB.put(key, pos);
395 if (!inPort.getType().equals(NodeConnectorIDType.ALL)) {
396 log.debug("Adding Match(inPort = {} , DIP = {})" +
397 " Action(outPort= {}) to node {}",
398 new Object[] { inPort,
399 host.getNetworkAddress().getHostAddress(),
401 if ((removed_po != null)
402 && (!po.getFlow().getMatch().equals(
403 removed_po.getFlow().getMatch()))) {
404 log.debug("Old Flow match: {}, New Flow match: {}",
405 removed_po.getFlow().getMatch(), po.getFlow()
407 addTobePrunedPolicy(currNode, removed_po, po);
411 log.debug("Adding policyMatch(DIP = {}) Action(outPort= {}) " +
412 "to node {}", new Object[] {
413 host.getNetworkAddress().getHostAddress(), outPort,
420 * Calculate the per-Host rules to be installed in the rulesDB,
421 * and that will later on be installed in HW, this routine will
422 * implicitly calculate the shortest path tree among the switch
423 * to which the host is attached and all the other switches in the
424 * network and will automatically create all the rules that allow
425 * a /32 destination IP based forwarding, as in traditional IP
428 * @param host Host for which we are going to prepare the rules in the rulesDB
430 * @return A set of switches touched by the calculation
432 private Set<Node> preparePerHostRules(HostNodeConnector host) {
437 //TODO: race condition! unset* functions can make these null.
438 if (this.routing == null) {
441 if (this.switchManager == null) {
444 if (this.rulesDB == null) {
448 Node rootNode = host.getnodeconnectorNode();
449 Set<Node> nodes = this.switchManager.getNodes();
450 Set<Node> switchesToProgram = new HashSet<Node>();
452 HashMap<NodeConnector, FlowEntry> pos;
455 // for all nodes in the system
456 for (Node node : nodes) {
457 if (node.equals(rootNode)) {
458 // We skip it because for the node with host attached
459 // we will process in every case even if there are no
464 Path res = this.routing.getRoute(node, rootNode);
465 if ((res == null) || ((links = res.getEdges()) == null)) {
466 // No route from node to rootNode can be found, back out any
467 // existing forwarding rules if they exist.
468 log.debug("NO Route/Path between SW[{}] --> SW[{}] cleaning " +
469 "potentially existing entries", node, rootNode);
470 key = new HostNodePair(host, node);
471 pos = this.rulesDB.get(key);
473 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
476 // uninstall any existing rules we put in the
477 // ForwardingRulesManager
478 this.frm.uninstallFlowEntry(po);
481 this.rulesDB.remove(key);
486 log.debug("Route between SW[{}] --> SW[{}]", node, rootNode);
487 Node currNode = node;
488 key = new HostNodePair(host, currNode);
490 // for each link in the route from here to there
491 for (Edge link : links) {
493 log.error("Could not retrieve the Link");
494 // TODO: should we keep going?
498 log.debug(link.toString());
500 // Index all the switches to be programmed
501 updatePerHostRuleInSW(host, currNode, rootNode, link, key);
502 if ((this.rulesDB.get(key)) != null) {
503 /* Calling updatePerHostRuleInSW() doesn't guarantee that
504 * rules will be added in currNode (e.g, there is only one
505 * link from currNode to rootNode This check makes sure that
506 * there are some rules in the rulesDB for the given key
507 * prior to adding switch to switchesToProgram
509 switchesToProgram.add(currNode);
511 currNode = link.getHeadNodeConnector().getNode();
512 key = new HostNodePair(host, currNode);
516 // This rule will be added no matter if any topology is built
517 // or no, it serve as a way to handle the case of a node with
518 // multiple hosts attached to it but not yet connected to the
520 switchesToProgram.add(rootNode);
521 updatePerHostRuleInSW(host, rootNode, rootNode, null,
522 new HostNodePair(host, rootNode));
524 // log.debug("Getting out at the end!");
525 return switchesToProgram;
529 * Calculate the per-Host rules to be installed in the rulesDB
530 * from a specific switch when a host facing port comes up.
531 * These rules will later on be installed in HW. This routine
532 * will implicitly calculate the shortest path from the switch
533 * where the port has come up to the switch where host is ,
534 * attached and will automatically create all the rules that allow
535 * a /32 destination IP based forwarding, as in traditional IP
538 * @param host Host for which we are going to prepare the rules in the rulesDB
539 * @param swId Switch ID where the port has come up
541 * @return A set of switches touched by the calculation
543 private Set<Node> preparePerHostPerSwitchRules(HostNodeConnector host,
544 Node node, NodeConnector swport) {
545 if ((host == null) || (node == null)) {
548 if (this.routing == null) {
551 if (this.switchManager == null) {
554 if (this.rulesDB == null) {
558 Node rootNode = host.getnodeconnectorNode();
559 Set<Node> switchesToProgram = new HashSet<Node>();
561 Map<NodeConnector, FlowEntry> pos;
565 Path res = this.routing.getRoute(node, rootNode);
566 if ((res == null) || ((links = res.getEdges()) == null)) {
567 // the routing service doesn't know how to get there from here
568 log.debug("NO Route/Path between SW[{}] --> SW[{}] cleaning " +
569 "potentially existing entries", node, rootNode);
570 key = new HostNodePair(host, node);
571 pos = this.rulesDB.get(key);
573 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
576 //Uninstall the policy
577 this.frm.uninstallFlowEntry(po);
580 this.rulesDB.remove(key);
585 log.debug("Route between SW[{}] --> SW[{}]", node, rootNode);
587 Node currNode = node;
588 key = new HostNodePair(host, currNode);
590 for (curr = 0; curr < links.size(); curr++) {
591 link = links.get(curr);
593 log.error("Could not retrieve the Link");
597 log.debug("Link [{}/{}] --> [{}/{}]", new Object[] {
598 currNode, link.getHeadNodeConnector(),
599 link.getHeadNodeConnector().getNode(),
600 link.getTailNodeConnector()});
602 // Index all the switches to be programmed
603 switchesToProgram.add(currNode);
604 updatePerHostRuleInSW(host, currNode, rootNode, link, key);
605 break; // come out of the loop for port up case, interested only in programming one switch
608 // This rule will be added no matter if any topology is built
609 // or no, it serve as a way to handle the case of a node with
610 // multiple hosts attached to it but not yet connected to the
612 // switchesToProgram.add(rootNode);
613 //updatePerHostRuleInSW(host, rootNode,
615 // new HostNodePair(host, rootNode),ports);
617 // log.debug("Getting out at the end!");
618 return switchesToProgram;
622 * Routine that fetch the per-Host rules from the rulesDB and
623 * install in HW, the one having the same match rules will be
624 * overwritten silently.
626 * @param host host for which we want to install in HW the per-Host rules
627 * @param switchesToProgram list of switches to be programmed in
628 * HW, usually are them all, but better to be explicit, that list
629 * may change with time based on new switch addition/removal
631 * @return a return code that convey the programming status of the HW
633 private RulesProgrammingReturnCode installPerHostRules(
634 HostNodeConnector host, Set<Node> switchesToProgram) {
635 RulesProgrammingReturnCode retCode = RulesProgrammingReturnCode.SUCCESS;
636 if (host == null || switchesToProgram == null) {
637 return RulesProgrammingReturnCode.FAILED_WRONG_PARAMS;
639 Map<NodeConnector, FlowEntry> pos;
641 // Now program every single switch
642 log.debug("Inside installPerHostRules");
643 for (Node swId : switchesToProgram) {
644 HostNodePair key = new HostNodePair(host, swId);
645 pos = this.rulesDB.get(key);
649 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
652 // Populate the Policy field now
653 Status poStatus = this.frm.modifyOrAddFlowEntry(po);
654 if (!poStatus.isSuccess()) {
655 log.error("Failed to install policy: "
656 + po.getGroupName() + " ("
657 + poStatus.getDescription() + ")");
659 retCode = RulesProgrammingReturnCode.FAILED_FEW_SWITCHES;
660 // Remove the entry from the DB, it was not installed!
661 this.rulesDB.remove(key);
663 log.debug("Successfully installed policy "
664 + po.toString() + " on switch " + swId);
667 log.error("Cannot find a policy for SW:({}) Host: ({})",
669 /* // Now dump every single rule */
670 /* for (HostNodePair dumpkey : this.rulesDB.keySet()) { */
671 /* po = this.rulesDB.get(dumpkey); */
672 /* log.debug("Dumping entry H{" + dumpkey.getHost() + "} S{" + dumpkey.getSwitchId() + "} = {" + (po == null ? "null policy" : po)); */
677 log.debug("Leaving installPerHostRules");
682 * Cleanup all the host rules for a given host
684 * @param host Host for which the host rules need to be cleaned
685 * up, the host could be null in that case it match all the hosts
687 * @return a return code that convey the programming status of the HW
689 private RulesProgrammingReturnCode uninstallPerHostRules(HostNodeConnector host) {
690 RulesProgrammingReturnCode retCode = RulesProgrammingReturnCode.SUCCESS;
691 Map<NodeConnector, FlowEntry> pos;
693 // Now program every single switch
694 for (HostNodePair key : this.rulesDB.keySet()) {
695 if (host == null || key.getHost().equals(host)) {
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 this.rulesDB.remove(key);
711 * Cleanup all the host rules for a given node, triggered when the
712 * switch disconnects, so there is no reason for Hw cleanup
713 * because it's disconnected anyhow
714 * TBD - Revisit above stmt in light of CSCus88743
715 * @param targetNode Node for which we want to do cleanup
718 private void uninstallPerNodeRules(Node targetNode) {
719 //RulesProgrammingReturnCode retCode = RulesProgrammingReturnCode.SUCCESS;
720 Map<NodeConnector, FlowEntry> pos;
723 // Now program every single switch
724 for (HostNodePair key : this.rulesDB.keySet()) {
725 Node node = key.getNode();
726 if (targetNode == null || node.equals(targetNode)) {
727 log.debug("Work on {} host {}", node, key.getHost());
728 pos = this.rulesDB.get(key);
729 for (Map.Entry<NodeConnector, FlowEntry> e : pos.entrySet()) {
732 // Uninstall the policy
733 this.frm.uninstallFlowEntry(po);
736 log.debug("Remove {}", key);
737 this.rulesDB.remove(key);
743 * Cleanup all the host rules currently present in the rulesDB
745 * @return a return code that convey the programming status of the HW
747 private RulesProgrammingReturnCode uninstallPerHostRules() {
748 return uninstallPerHostRules(null);
752 public void recalculateDone() {
753 if (this.hostTracker == null) {
754 //Not yet ready to process all the updates
755 //TODO: we should make sure that this call is executed eventually
758 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
759 for (HostNodeConnector host : allHosts) {
760 Set<Node> switches = preparePerHostRules(host);
761 if (switches != null) {
762 // This will refresh existing rules, by overwriting
764 installPerHostRules(host, switches);
765 pruneExcessRules(switches);
770 void addTobePrunedPolicy(Node swId, FlowEntry po, FlowEntry new_po) {
771 List<FlowEntry> pl = tobePrunedPos.get(swId);
773 pl = new LinkedList<FlowEntry>();
774 tobePrunedPos.put(swId, pl);
777 log.debug("Adding Pruned Policy for SwId: {}", swId);
778 log.debug("Old Policy: {}", po);
779 log.debug("New Policy: {}", new_po);
782 private void pruneExcessRules(Set<Node> switches) {
783 for (Node swId : switches) {
784 List<FlowEntry> pl = tobePrunedPos.get(swId);
786 log.debug("Policies for Switch: {} in the list to be deleted: {}", swId, pl);
787 Iterator<FlowEntry> plIter = pl.iterator();
788 //for (Policy po: pl) {
789 while (plIter.hasNext()) {
790 FlowEntry po = plIter.next();
791 log.error("Removing Policy, Switch: {} Policy: {}", swId, po);
792 this.frm.uninstallFlowEntry(po);
796 // tobePrunedPos.remove(swId);
801 * A Host facing port has come up in a container. Add rules on the switch where this
802 * port has come up for all the known hosts to the controller.
803 * @param swId switch id of the port where port came up
804 * @param swPort port which came up
806 private void updateRulesforHIFup(Node node, NodeConnector swPort) {
807 if (this.hostTracker == null) {
808 //Not yet ready to process all the updates
811 log.debug("Host Facing Port in a container came up, install the rules for all hosts from this port !");
812 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
813 for (HostNodeConnector host : allHosts) {
814 if (node.equals(host.getnodeconnectorNode())) {
816 * This host resides behind the same switch and port for which a port up
817 * message is received. Ideally this should not happen, but if it does,
818 * don't program any rules for this host
822 Set<Node> switches = preparePerHostPerSwitchRules(host, node,
824 if (switches != null) {
825 // This will refresh existing rules, by overwriting
827 installPerHostRules(host, switches);
834 public void notifyHTClient(HostNodeConnector host) {
838 Set<Node> switches = preparePerHostRules(host);
839 if (switches != null) {
840 installPerHostRules(host, switches);
845 public void notifyHTClientHostRemoved(HostNodeConnector host) {
849 uninstallPerHostRules(host);
853 public void notifyNode(Node node, UpdateType type,
854 Map<String, Property> propMap) {
861 log.debug("Node {} gone, doing a cleanup", node);
862 uninstallPerNodeRules(node);
870 public void notifyNodeConnector(NodeConnector nodeConnector,
871 UpdateType type, Map<String, Property> propMap) {
872 if (nodeConnector == null) {
884 State state = (State) propMap.get(State.StatePropName);
885 if ((state != null) && (state.getValue() == State.EDGE_UP)) {
894 handleNodeConnectorStatusUp(nodeConnector);
896 handleNodeConnectorStatusDown(nodeConnector);
900 private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
901 if (topologyManager == null) {
902 log.debug("topologyManager is not set yet");
906 if (topologyManager.isInternal(nodeConnector)) {
907 log.debug("{} is not a host facing link", nodeConnector);
911 log.debug("{} is up", nodeConnector);
912 updateRulesforHIFup(nodeConnector.getNode(), nodeConnector);
915 private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) {
916 log.debug("{} is down", nodeConnector);
919 void setClusterContainerService(IClusterContainerServices s) {
920 log.debug("Cluster Service set");
921 this.clusterContainerService = s;
924 void unsetClusterContainerService(IClusterContainerServices s) {
925 if (this.clusterContainerService == s) {
926 log.debug("Cluster Service removed!");
927 this.clusterContainerService = null;
932 * Function called by the dependency manager when all the required
933 * dependencies are satisfied
941 * Function called by the dependency manager when at least one
942 * dependency become unsatisfied or when the component is shutting
943 * down because for example bundle is being stopped.
950 * Function called by dependency manager after "init ()" is called
951 * and after the services provided by the class are registered in
952 * the service registry
959 * Function called by the dependency manager before the services
960 * exported by the component are unregistered, this will be
961 * followed by a "destroy ()" calls
967 public void setSwitchManager(ISwitchManager switchManager) {
968 this.switchManager = switchManager;
971 public void unsetSwitchManager(ISwitchManager switchManager) {
972 if (this.switchManager == switchManager) {
973 this.switchManager = null;
978 public PacketResult receiveDataPacket(RawPacket inPkt) {
980 return PacketResult.IGNORED;
982 log.trace("Received a frame of size: {}", inPkt.getPacketData().length);
983 Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
984 if (formattedPak instanceof Ethernet) {
985 Object nextPak = formattedPak.getPayload();
986 if (nextPak instanceof IPv4) {
987 log.trace("Handle punted IP packet: {}", formattedPak);
988 handlePuntedIPPacket((IPv4) nextPak, inPkt.getIncomingNodeConnector());
991 return PacketResult.IGNORED;
995 private void handlePuntedIPPacket(IPv4 pkt, NodeConnector incomingNodeConnector) {
996 InetAddress dIP = NetUtils.getInetAddress(pkt.getDestinationAddress());
997 if (dIP == null || hostTracker == null) {
998 log.debug("Invalid param(s) in handlePuntedIPPacket.. DestIP: {}. hostTracker: {}", dIP, hostTracker);
1001 HostNodeConnector destHost = hostTracker.hostFind(dIP);
1002 if (destHost != null
1003 && (routing == null ||
1004 routing.getRoute(incomingNodeConnector.getNode(), destHost.getnodeconnectorNode()) != null)) {
1006 log.trace("Host {} is at {}", dIP, destHost.getnodeConnector());
1007 HostNodePair key = new HostNodePair(destHost, incomingNodeConnector.getNode());
1009 // If SimpleForwarding is aware of this host, it will try to install
1010 // a path. Forward packet until it's done.
1011 if (dataPacketService != null && this.rulesDB.containsKey(key)) {
1015 * if we know where the host is and there's a path from where this
1016 * packet was punted to where the host is, then attempt best effort delivery to the host
1018 NodeConnector nc = destHost.getnodeConnector();
1019 log.trace("Forwarding punted IP received at {} to {}", incomingNodeConnector, nc);
1020 // re-encode the Ethernet packet (the parent of the IPv4 packet)
1021 RawPacket rp = this.dataPacketService.encodeDataPacket(pkt.getParent());
1022 rp.setOutgoingNodeConnector(nc);
1023 this.dataPacketService.transmitDataPacket(rp);