6e01bd703e0d2ce0618f6c3bc373f8d75296b797
[affinity.git] / affinity / implementation / src / main / java / org / opendaylight / affinity / affinity / internal / AffinityManagerImpl.java
1 /*
2  * Copyright (c) 2013 Plexxi, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.affinity.affinity.internal;
10
11
12 import org.opendaylight.yang.gen.v1.affinity.rev130925.AffinityService;
13 import org.opendaylight.yang.gen.v1.affinity.rev130925.HostEndpoint;
14 import org.opendaylight.yang.gen.v1.affinity.rev130925.host_endpoint.L2address;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
16
17 import org.opendaylight.yang.gen.v1.affinity.rev130925.CreategroupInput;
18 import org.opendaylight.yang.gen.v1.affinity.rev130925.AddendpointInput;
19
20 import java.util.concurrent.Future;
21 import org.opendaylight.controller.sal.common.util.Futures;
22 import org.opendaylight.controller.sal.common.util.Rpcs;
23
24 import org.opendaylight.yangtools.yang.common.RpcError;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26
27
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.net.UnknownHostException;
32 import java.net.InetAddress;
33 import java.net.NetworkInterface;
34 import java.net.SocketException;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.Date;
38 import java.util.Dictionary;
39 import java.util.EnumSet;
40 import java.util.Enumeration;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.AbstractMap;
46 import java.util.Set;
47 import java.util.concurrent.ConcurrentHashMap;
48 import java.util.concurrent.ConcurrentMap;
49 import java.util.concurrent.CopyOnWriteArrayList;
50 import java.util.ArrayList;
51 import java.util.EnumSet;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Map.Entry;
57 import java.util.Set;
58 import java.util.concurrent.ConcurrentHashMap;
59 import java.util.concurrent.ConcurrentMap;
60
61 import org.apache.felix.dm.Component;
62 import org.eclipse.osgi.framework.console.CommandInterpreter;
63 import org.eclipse.osgi.framework.console.CommandProvider;
64 import org.opendaylight.controller.clustering.services.CacheConfigException;
65 import org.opendaylight.controller.clustering.services.CacheExistException;
66 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
67 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
68 import org.opendaylight.controller.clustering.services.IClusterServices;
69 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
70 //import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
71 //import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
72 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
73 import org.opendaylight.controller.sal.flowprogrammer.Flow;
74 import org.opendaylight.controller.sal.utils.IPProtocols;
75
76 import org.opendaylight.controller.sal.core.IContainer;
77 import org.opendaylight.controller.sal.core.Node;
78 import org.opendaylight.controller.sal.core.Host;
79 import org.opendaylight.controller.sal.core.NodeConnector;
80 import org.opendaylight.controller.sal.core.NodeTable;
81 import org.opendaylight.controller.sal.core.Property;
82 import org.opendaylight.controller.sal.core.UpdateType;
83
84 import org.opendaylight.controller.sal.flowprogrammer.Flow;
85 import org.opendaylight.controller.sal.match.Match;
86 import org.opendaylight.controller.sal.match.MatchType;
87 import org.opendaylight.controller.sal.match.MatchField;
88 import org.opendaylight.controller.sal.action.Action;
89 import org.opendaylight.controller.sal.action.Output;
90 import org.opendaylight.controller.sal.utils.EtherTypes;
91
92 import org.opendaylight.controller.sal.reader.FlowOnNode;
93 import org.opendaylight.controller.sal.reader.IReadService;
94 import org.opendaylight.controller.sal.reader.IReadServiceListener;
95 import org.opendaylight.controller.sal.utils.GlobalConstants;
96 import org.opendaylight.controller.sal.utils.IObjectReader;
97 import org.opendaylight.controller.sal.utils.ObjectReader;
98 import org.opendaylight.controller.sal.utils.ObjectWriter;
99 import org.opendaylight.controller.sal.utils.NetUtils;
100
101 import org.opendaylight.controller.hosttracker.IfIptoHost;
102 import org.opendaylight.controller.sal.utils.Status;
103 import org.opendaylight.controller.sal.utils.StatusCode;
104
105 import org.opendaylight.controller.sal.utils.ServiceHelper;
106 import org.opendaylight.affinity.affinity.AffinityGroup;
107 import org.opendaylight.affinity.affinity.AffinityLink;
108 import org.opendaylight.affinity.affinity.AffinityIdentifier;
109 import org.opendaylight.affinity.affinity.IAffinityManager;
110 import org.opendaylight.affinity.affinity.IAffinityManagerAware;
111
112 import org.opendaylight.controller.hosttracker.IfIptoHost;
113 import org.opendaylight.controller.hosttracker.IfNewHostNotify;
114 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
115 import org.opendaylight.controller.switchmanager.ISwitchManager;
116 import org.opendaylight.affinity.l2agent.IfL2Agent;
117 import org.opendaylight.affinity.nfchainagent.NFchainAgent;
118 import org.opendaylight.affinity.nfchainagent.NFchainconfig;
119 import org.opendaylight.affinity.affinity.InetAddressMask;
120
121 import org.slf4j.Logger;
122 import org.slf4j.LoggerFactory;
123
124 /**
125  * Affinity configuration.
126  */
127 public class AffinityManagerImpl implements IAffinityManager, AffinityService, IfNewHostNotify,
128                                             IConfigurationContainerAware, IObjectReader, ICacheUpdateAware<Long, String> {
129     private static final Logger log = LoggerFactory.getLogger(AffinityManagerImpl.class);
130
131     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
132     private static final String SAVE = "Save";
133     private String affinityLinkFileName = null;
134     private String affinityGroupFileName = null;
135     //    private IForwardingRulesManager ruleManager;
136     private IFlowProgrammerService programmer = null;
137     private NFchainAgent nfchainagent = null;
138     
139     private ISwitchManager switchManager = null;
140     private IfL2Agent l2agent = null;
141     private IfIptoHost hostTracker = null;
142
143     private ConcurrentMap<String, AffinityGroup> affinityGroupList;
144     private ConcurrentMap<String, AffinityLink> affinityLinkList;
145     private ConcurrentMap<Long, String> configSaveEvent;
146
147
148     private final Set<IAffinityManagerAware> affinityManagerAware = Collections
149             .synchronizedSet(new HashSet<IAffinityManagerAware>());
150
151     private byte[] MAC;
152     private static boolean hostRefresh = true;
153     private int hostRetryCount = 5;
154     private IClusterContainerServices clusterContainerService = null;
155     private String containerName = GlobalConstants.DEFAULT.toString();
156     private boolean isDefaultContainer = true;
157     private static final int REPLACE_RETRY = 1;
158
159     private static short REDIRECT_IPSWITCH_PRIORITY = 3;
160
161     public enum ReasonCode {
162         SUCCESS("Success"), FAILURE("Failure"), INVALID_CONF(
163                 "Invalid Configuration"), EXIST("Entry Already Exist"), CONFLICT(
164                         "Configuration Conflict with Existing Entry");
165
166         private final String name;
167
168         private ReasonCode(String name) {
169             this.name = name;
170         }
171
172         @Override
173         public String toString() {
174             return name;
175         }
176     }
177
178     /* Only default container. */
179     public String getContainerName() {
180         return containerName;
181     }
182
183     public void startUp() {
184         // Initialize configuration file names
185         affinityLinkFileName = ROOT + "affinityConfig_link" + this.getContainerName()
186             + ".conf";
187         affinityGroupFileName = ROOT + "affinityConfig_group" + this.getContainerName()
188             + ".conf";
189         log.debug("configuration file names " + affinityLinkFileName + "and " + affinityGroupFileName);
190         // Instantiate cluster synced variables
191         allocateCaches();
192         retrieveCaches();
193
194         /*
195          * Read startup and build database if we have not already gotten the
196          * configurations synced from another node
197          */
198         if (affinityGroupList.isEmpty() || affinityLinkList.isEmpty()) {
199             loadAffinityConfiguration();
200         }
201     }
202
203     public void shutDown() {
204     }
205
206     @SuppressWarnings("deprecation")
207     private void allocateCaches() {
208         if (this.clusterContainerService == null) {
209             this.nonClusterObjectCreate();
210             log.warn("un-initialized clusterContainerService, can't create cache");
211             return;
212         }
213         try {
214             clusterContainerService.createCache(
215                     "affinity.affinityGroupList",
216                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
217             clusterContainerService.createCache(
218                     "affinity.affinityLinkList",
219                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
220             clusterContainerService.createCache(
221                     "affinity.configSaveEvent",
222                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
223         } catch (CacheConfigException cce) {
224             log.error("\nCache configuration invalid - check cache mode");
225         } catch (CacheExistException ce) {
226             log.error("\nCache already exits - destroy and recreate if needed");
227         }
228     }
229
230     @SuppressWarnings({ "unchecked", "deprecation" })
231     private void retrieveCaches() {
232         if (this.clusterContainerService == null) {
233             log.info("un-initialized clusterContainerService, can't retrieve cache");
234             return;
235         }
236         affinityGroupList = (ConcurrentMap<String, AffinityGroup>) clusterContainerService
237             .getCache("affinity.affinityGroupList");
238         if (affinityGroupList == null) {
239             log.error("\nFailed to get cache for affinityGroupList");
240         }
241         affinityLinkList = (ConcurrentMap<String, AffinityLink>) clusterContainerService
242             .getCache("affinity.affinityLinkList");
243         if (affinityLinkList == null) {
244             log.error("\nFailed to get cache for affinityLinkList");
245         }
246
247         configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
248             .getCache("affinity.configSaveEvent");
249         if (configSaveEvent == null) {
250             log.error("\nFailed to get cache for configSaveEvent");
251         }
252     }
253
254     private void nonClusterObjectCreate() {
255         affinityLinkList = new ConcurrentHashMap<String, AffinityLink>();
256         affinityGroupList = new ConcurrentHashMap<String, AffinityGroup>();
257         configSaveEvent = new ConcurrentHashMap<Long, String>();
258     }
259
260
261     void setHostTracker(IfIptoHost h) {
262         log.info("Setting hosttracker {}", h);
263         this.hostTracker = h;
264     }
265
266     void unsetHostTracker(IfIptoHost h) {
267         if (this.hostTracker.equals(h)) {
268             this.hostTracker = null;
269         }
270     }
271     /*    public void setForwardingRulesManager(
272             IForwardingRulesManager forwardingRulesManager) {
273         log.debug("Setting ForwardingRulesManager");
274         this.ruleManager = forwardingRulesManager;
275     }
276
277     public void unsetForwardingRulesManager(
278             IForwardingRulesManager forwardingRulesManager) {
279         if (this.ruleManager == forwardingRulesManager) {
280             this.ruleManager = null;
281         }
282     }
283     */
284     public void setFlowProgrammerService(IFlowProgrammerService s)
285     {
286         this.programmer = s;
287     }
288
289     public void unsetFlowProgrammerService(IFlowProgrammerService s) {
290         if (this.programmer == s) {
291             this.programmer = null;
292         }
293     }
294
295     void setNFchainAgent(NFchainAgent s)
296     {
297         log.info("Setting nfchainagent {}", s);
298         this.nfchainagent = s;
299     }
300
301     void unsetNFchainAgent(NFchainAgent s) {
302         if (this.nfchainagent == s) {
303             this.nfchainagent = null;
304         }
305     }
306
307     void setL2Agent(IfL2Agent s)
308     {
309         log.info("Setting l2agent {}", s);
310         this.l2agent = s;
311     }
312
313     void unsetL2Agent(IfL2Agent s) {
314         if (this.l2agent == s) {
315             this.l2agent = null;
316         }
317     }
318
319     void setSwitchManager(ISwitchManager s)
320     {
321         this.switchManager = s;
322     }
323
324     void unsetSwitchManager(ISwitchManager s) {
325         if (this.switchManager == s) {
326             this.switchManager = null;
327         }
328     }
329
330     /*
331     public void setForwardingRulesManager(
332             IForwardingRulesManager forwardingRulesManager) {
333         this.ruleManager = forwardingRulesManager;
334     }
335
336     public void unsetForwardingRulesManager(
337             IForwardingRulesManager forwardingRulesManager) {
338         if (this.ruleManager == forwardingRulesManager) {
339             this.ruleManager = null;
340         }
341     }
342     */
343     
344     public Status addAffinityLink(AffinityLink al) {
345         boolean putNewLink = false;
346
347         if (affinityLinkList.containsKey(al.getName())) {
348             return new Status(StatusCode.CONFLICT,
349                               "AffinityLink with the specified name already configured.");
350         }
351
352         
353         AffinityLink alCurr = affinityLinkList.get(al.getName());
354         if (alCurr == null) {
355             if (affinityLinkList.putIfAbsent(al.getName(), al) == null) {
356                 putNewLink = true;
357             } 
358         } else {
359             putNewLink = affinityLinkList.replace(al.getName(), alCurr, al);
360         }
361
362         if (!putNewLink) {
363             String msg = "Cluster conflict: Conflict while adding the subnet " + al.getName();
364             return new Status(StatusCode.CONFLICT, msg);
365         }
366
367         return new Status(StatusCode.SUCCESS);
368     }
369
370     /*    public byte [] InetAddressToMAC(InetAddress inetAddr) {
371         //        HostNodeConnector 
372         log.debug("Find {} -> {} using hostTracker {}", inetAddr, host, hostTracker);
373         byte [] dst_mac = host.getDataLayerAddressBytes();
374         return dst_mac;
375     }
376     */
377
378     public Status removeAffinityLink(String name) {
379         affinityLinkList.remove(name);
380         return new Status(StatusCode.SUCCESS);
381     }
382
383     public Status removeAffinityLink(AffinityLink al) {
384         AffinityLink alCurr = affinityLinkList.get(al.getName());
385         if (alCurr != null) {
386             affinityLinkList.remove(alCurr);
387             return new Status(StatusCode.SUCCESS);
388         } else {
389             String msg = "Affinity Link with specified name does not exist." + al.getName();
390             return new Status(StatusCode.INTERNALERROR, msg);
391         }
392     }
393     
394     @Override
395     public AffinityLink getAffinityLink(String linkName) {
396         return affinityLinkList.get(linkName);
397     }
398
399     @Override
400     public List<AffinityLink> getAllAffinityLinks() {
401         return new ArrayList<AffinityLink>(affinityLinkList.values());
402     }
403
404     @Override
405     public Status addAffinityGroup(AffinityGroup ag) {
406         boolean putNewGroup = false;
407         String name = ag.getName();
408         if (affinityGroupList.containsKey(name)) {
409             return new Status(StatusCode.CONFLICT,
410                               "AffinityGroup with the specified name already configured.");
411         } 
412         AffinityGroup agCurr = affinityGroupList.get(name);
413         if (agCurr == null) {
414             if (affinityGroupList.putIfAbsent(name, ag) == null) {
415                 putNewGroup = true;
416             } 
417         } else {
418             putNewGroup = affinityGroupList.replace(name, agCurr, ag);
419         }
420
421         if (!putNewGroup) {
422             String msg = "Cluster conflict: Conflict while adding the subnet " + name;
423             return new Status(StatusCode.CONFLICT, msg);
424         }
425         
426         return new Status(StatusCode.SUCCESS);
427     }
428
429     /* Check for errors. */
430     @Override
431     public Status removeAffinityGroup(String name) {
432         affinityGroupList.remove(name);
433         return new Status(StatusCode.SUCCESS);
434     }
435
436     @Override
437     public AffinityGroup getAffinityGroup(String groupName) {
438         log.debug("getAffinityGroup" + groupName);
439         return affinityGroupList.get(groupName);
440     }
441
442     @Override
443     public List<AffinityGroup> getAllAffinityGroups() {
444         return new ArrayList<AffinityGroup>(affinityGroupList.values());
445     }
446
447     /* Find where this is used. */
448     @Override
449     public Object readObject(ObjectInputStream ois)
450             throws FileNotFoundException, IOException, ClassNotFoundException {
451         // Perform the class deserialization locally, from inside the package
452         // where the class is defined
453         return ois.readObject();
454     }
455
456     @SuppressWarnings("unchecked")
457     private void loadAffinityConfiguration() {
458         ObjectReader objReader = new ObjectReader();
459         ConcurrentMap<String, AffinityGroup> groupList = (ConcurrentMap<String, AffinityGroup>) objReader.read(this, affinityGroupFileName);
460         ConcurrentMap<String, AffinityLink> linkList = (ConcurrentMap<String, AffinityLink>) objReader.read(this, affinityLinkFileName);
461         
462         /* group list */
463         if (groupList != null) {
464             for (AffinityGroup ag : groupList.values()) {
465                 addAffinityGroup(ag);
466             }
467         }
468
469         /* link list */
470         if (linkList != null) {
471             for (AffinityLink al : linkList.values()) {
472                 addAffinityLink(al);
473             }
474         }
475     }
476
477     @Override 
478     public ArrayList<AffinityIdentifier> getAllElementsByAffinityIdentifier(AffinityGroup ag) {
479         return ag.getAllElements();
480     }
481  
482     @Override 
483     public List<Host> getAllElementsByHost(AffinityGroup ag) {
484         List<Host> hostList= new ArrayList<Host>();
485
486         for (AffinityIdentifier h : ag.getAllElements()) {
487             /* TBD: Do not assume this to be an InetAddress. */ 
488             h.print();
489             if (hostTracker != null) {
490                 Host host1 = hostTracker.hostFind((InetAddress) h.get());
491                 hostList.add(host1);
492             }
493         }
494         return hostList;
495     }
496
497     @Override
498     public List<Entry<Host, Host>> getAllFlowsByHost(AffinityLink al) {
499         List<Entry<Host,Host>> hostPairList= new ArrayList<Entry<Host, Host>>();
500
501         AffinityGroup fromGroup = al.getFromGroup();
502         AffinityGroup toGroup = al.getToGroup();
503         
504         for (AffinityIdentifier h1 : fromGroup.getAllElements()) {
505             for (AffinityIdentifier h2 : toGroup.getAllElements()) {
506                 if (hostTracker != null) {
507                     Host host1 = hostTracker.hostFind((InetAddress) h1.get());
508                     Host host2 = hostTracker.hostFind((InetAddress) h2.get());
509                     log.debug("Flow between {}, {}", host1, host2);
510                     Entry<Host, Host> hp1=new AbstractMap.SimpleEntry<Host, Host>(host1, host2);
511                     hostPairList.add(hp1);
512                 }
513             }
514         }
515         return hostPairList;
516     }
517
518     @Override 
519     public List<Entry<AffinityIdentifier, AffinityIdentifier>> getAllFlowsByAffinityIdentifier(AffinityLink al) {
520         List<Entry<AffinityIdentifier, AffinityIdentifier>> hostPairList= new ArrayList<Entry<AffinityIdentifier, AffinityIdentifier>>();
521
522         AffinityGroup fromGroup = al.getFromGroup();
523         AffinityGroup toGroup = al.getToGroup();
524         
525         for (AffinityIdentifier h1 : fromGroup.getAllElements()) {
526             for (AffinityIdentifier h2 : toGroup.getAllElements()) {
527                 Entry<AffinityIdentifier, AffinityIdentifier> hp1=new AbstractMap.SimpleEntry<AffinityIdentifier, AffinityIdentifier>(h1, h2);
528                 log.debug("Adding hostPair {} -> {}", h1, h2);
529                 hostPairList.add(hp1);
530             }
531         }
532         return hostPairList;
533     }
534
535     private void notifyHostUpdate(HostNodeConnector host, boolean added) {
536         if (host == null) {
537             return;
538         }
539         log.info("Host update received (new = {}).", added);
540     }
541
542     @Override
543     public void notifyHTClient(HostNodeConnector host) {
544         notifyHostUpdate(host, true);
545     }
546
547     @Override
548     public void notifyHTClientHostRemoved(HostNodeConnector host) {
549         notifyHostUpdate(host, false);
550     }
551
552
553     @Override
554     public Status saveConfiguration() {
555         return saveAffinityConfig();
556     }
557
558     @Override
559     public Status saveAffinityConfig() {
560         // Publish the save config event to the cluster nodes
561         configSaveEvent.put(new Date().getTime(), SAVE);
562         return saveAffinityConfigInternal();
563     }
564
565     public Status saveAffinityConfigInternal() {
566         Status retS = null, retP = null;
567         ObjectWriter objWriter = new ObjectWriter();
568
569         retS = objWriter.write(new ConcurrentHashMap<String, AffinityLink>(
570                 affinityLinkList), affinityLinkFileName);
571
572         retP = objWriter.write(new ConcurrentHashMap<String, AffinityGroup>(
573                 affinityGroupList), affinityGroupFileName);
574
575         if (retS.isSuccess() && retP.isSuccess()) {
576             return new Status(StatusCode.SUCCESS, "Configuration saved.");
577         } else {
578             return new Status(StatusCode.INTERNALERROR, "Save failed");
579         }
580     }
581
582     @Override
583     public void entryCreated(Long key, String cacheName, boolean local) {
584     }
585
586     @Override
587     public void entryUpdated(Long key, String new_value, String cacheName,
588             boolean originLocal) {
589         saveAffinityConfigInternal();
590     }
591
592     @Override
593     public void entryDeleted(Long key, String cacheName, boolean originLocal) {
594     }
595
596     /**
597      * Function called by the dependency manager when all the required
598      * dependencies are satisfied
599      *
600      */
601     void init() {
602         log.debug("INIT called!");
603         containerName = GlobalConstants.DEFAULT.toString();
604         startUp();
605     }
606
607     /**
608      * Function called by the dependency manager when at least one
609      * dependency become unsatisfied or when the component is shutting
610      * down because for example bundle is being stopped.
611      *
612      */
613     void destroy() {
614         log.debug("DESTROY called!");
615     }
616
617     /**
618      * Function called by dependency manager after "init ()" is called
619      * and after the services provided by the class are registered in
620      * the service registry
621      *
622      */
623     void start() {
624         log.debug("START called!");
625     }
626
627     /**
628      * Function called after registering the service in OSGi service registry.
629      */
630     void started() {
631         // Retrieve current statistics so we don't have to wait for next refresh
632         IAffinityManager affinityManager = (IAffinityManager) ServiceHelper.getInstance(
633                 IAffinityManager.class, this.getContainerName(), this);
634         if (affinityManager != null) {
635             log.debug("STARTED method called!");
636         }
637     }
638
639     /**
640      * Function called by the dependency manager before the services
641      * exported by the component are unregistered, this will be
642      * followed by a "destroy ()" calls
643      *
644      */
645     void stop() {
646         log.debug("STOP called!");
647     }
648
649     void setClusterContainerService(IClusterContainerServices s) {
650         log.debug("Cluster Service set for affinity mgr");
651         this.clusterContainerService = s;
652     }
653
654     void unsetClusterContainerService(IClusterContainerServices s) {
655         if (this.clusterContainerService == s) {
656             log.debug("Cluster Service removed for affinity mgr!");
657             this.clusterContainerService = null;
658         }
659     }
660     
661     /* Add a nfchain config for this affinity link. */
662     List<Flow> getFlowlist(AffinityLink al) {
663         InetAddress from = null, to = null;
664
665         log.info("get flowlist affinity link = {}", al.getName());
666         List<Flow> flowlist = new ArrayList<Flow>();
667         List<Entry<AffinityIdentifier,AffinityIdentifier>> hostPairList= getAllFlowsByAffinityIdentifier(al);
668
669         /* Create a Flow for each host pair in the affinity link. */
670         for (Entry<AffinityIdentifier,AffinityIdentifier> hostPair : hostPairList) {
671             log.info("Processing next hostPair {} ", hostPair);
672
673             Match match = new Match();
674             Object addr;
675             Object addrmask;
676
677             /* Set source fields. */
678             if (hostPair.getKey().get() instanceof InetAddress) {
679                 addr = hostPair.getKey().get();
680                 match.setField(new MatchField(MatchType.NW_SRC, (InetAddress) addr, null));
681             } else if (hostPair.getKey().get() instanceof InetAddressMask) {
682                 addrmask = hostPair.getKey().get();
683                 InetAddress faddr = ((InetAddressMask) addrmask).getNetworkAddress();
684                 InetAddress fmask = NetUtils.getInetNetworkMask((int) ((InetAddressMask) addrmask).getMask(), false);
685                 match.setField(new MatchField(MatchType.NW_SRC, faddr, fmask));
686             } 
687             /* xxx mac address ... */
688             
689             /* Set destination fields. */
690             if (hostPair.getValue().get() instanceof InetAddress) {
691                 addr = (InetAddress) hostPair.getValue().get();
692                 match.setField(new MatchField(MatchType.NW_DST, addr, null));
693             } else if (hostPair.getValue().get() instanceof InetAddressMask) {
694                 addrmask = (InetAddressMask) hostPair.getValue().get();
695                 InetAddress taddr = ((InetAddressMask) addrmask).getNetworkAddress();
696                 InetAddress tmask = NetUtils.getInetNetworkMask((int) ((InetAddressMask) addrmask).getMask(), false);
697                 match.setField(new MatchField(MatchType.NW_DST, taddr, tmask));
698             } 
699             /* xxx mac address ... */
700
701             /* Set other fields. */
702             match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());  
703             Flow flow = new Flow(match, null);
704             flow.setPriority(REDIRECT_IPSWITCH_PRIORITY);
705             flowlist.add(flow);
706         }
707         return flowlist;
708     }
709
710     /* From affinity link, create a nfc config. Pass this nfc config to nfchainagent. */
711     public Status addNfchain(AffinityLink al) {
712         List<Flow> flowlist = getFlowlist(al);
713         InetAddress waypoint = NetUtils.parseInetAddress(al.getWaypoint());
714         NFchainconfig nfcc = new NFchainconfig(al.getName(), flowlist, waypoint);
715         String key = al.getName();
716         nfchainagent.addNfchain(key, nfcc);
717         log.info("Added nfchain {}", al.getName());
718         return new Status(StatusCode.SUCCESS);
719     }
720
721     public Status enableRedirect(AffinityLink al) throws Exception {
722         String nfccname = al.getName();
723         return nfchainagent.enable(nfccname);
724     }
725  
726    public Status disableRedirect(AffinityLink al) throws Exception {
727         String nfccname = al.getName();
728         return nfchainagent.disable(nfccname);
729     }
730
731    public Status removeNfchain(AffinityLink al) throws Exception {
732         String nfccname = al.getName();
733         return nfchainagent.removeNfchain(nfccname);
734     }
735
736
737    /* public methods for the yang service. */
738    public Future<RpcResult<Void>> creategroup(CreategroupInput input) {
739        AffinityGroup ag1 = new AffinityGroup(input.getName());
740        
741        /* Correctly translate between status fields. */
742        Status ret = addAffinityGroup(ag1);
743        RpcResult<Void> result = Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
744        return Futures.immediateFuture(result);
745    }
746     
747    public Future<RpcResult<Void>> addendpoint(AddendpointInput input) {
748        AffinityGroup ag = getAffinityGroup(input.getGroupname());
749        RpcResult<Void> result;
750
751        if (ag != null) {
752            HostEndpoint endpoint = input.getEndpoint();
753            L2address l2address = endpoint.getL2address();
754            Ipv4Prefix l3address = endpoint.getL3address();
755            
756            /*   ag.addL2address(); */
757            ag.addInetMask(l3address.toString());
758            result = Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
759        } else {
760            result = Rpcs.<Void> getRpcResult(false, null, Collections.<RpcError> emptySet());
761        }
762        return Futures.immediateFuture(result);
763    }
764 }