Merge "Use StringBuilder instead of StringBuffer"
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / DestinationMapper.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, 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.groupbasedpolicy.renderer.ofoverlay.flow;
10
11 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
26 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
27 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
28 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
29 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
30 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
31 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
32 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
33 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
34 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
35
36 import java.math.BigInteger;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Map.Entry;
45 import java.util.Objects;
46 import java.util.Set;
47
48 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
49 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
50 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
51 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
52 import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
53 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
54 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
55 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
56 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
57 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
58 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
59 import org.opendaylight.groupbasedpolicy.resolver.TenantUtils;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
103 import org.opendaylight.yangtools.yang.binding.DataObject;
104 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
105 import org.slf4j.Logger;
106 import org.slf4j.LoggerFactory;
107
108 import com.google.common.base.Optional;
109 import com.google.common.collect.HashMultimap;
110 import com.google.common.collect.SetMultimap;
111 import com.google.common.collect.Sets;
112 import com.google.common.util.concurrent.CheckedFuture;
113
114 /**
115  * Manage the table that maps the destination address to the next hop for the
116  * path as well as applies any relevant routing transformations.
117  */
118 public class DestinationMapper extends FlowTable {
119
120     protected static final Logger LOG = LoggerFactory.getLogger(DestinationMapper.class);
121
122     // TODO Li alagalah: Improve UT coverage for this class.
123
124     // TODO Li alagalah: Use EndpointL3 for L3 flows, Endpoint for L2 flows
125     // This ensures we have the appropriate network-containment'
126
127     public static final short TABLE_ID = 2;
128     /**
129      * This is the MAC address of the magical router in the sky
130      */
131     public static final MacAddress ROUTER_MAC = new MacAddress("88:f0:31:b5:12:b5");
132     public static final MacAddress MULTICAST_MAC = new MacAddress("01:00:00:00:00:00");
133
134     public DestinationMapper(OfContext ctx) {
135         super(ctx);
136     }
137
138     Map<TenantId, HashSet<Subnet>> subnetsByTenant = new HashMap<TenantId, HashSet<Subnet>>();
139
140     @Override
141     public short getTableId() {
142         return TABLE_ID;
143     }
144
145     @Override
146     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
147
148         TenantId currentTenant;
149
150         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
151
152         SetMultimap<EpKey, EpKey> visitedEps = HashMultimap.create();
153         Set<EndpointFwdCtxOrdinals> epOrdSet = new HashSet<>();
154
155         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
156             Set<EndpointGroupId> srcEpgIds = new HashSet<>();
157             if (srcEp.getEndpointGroup() != null)
158                 srcEpgIds.add(srcEp.getEndpointGroup());
159             if (srcEp.getEndpointGroups() != null)
160                 srcEpgIds.addAll(srcEp.getEndpointGroups());
161
162             for (EndpointGroupId epgId : srcEpgIds) {
163                 EgKey epg = new EgKey(srcEp.getTenant(), epgId);
164                 Set<EgKey> peers = Sets.union(Collections.singleton(epg), policyInfo.getPeers(epg));
165                 for (EgKey peer : peers) {
166                     for (Endpoint peerEp : ctx.getEndpointManager().getEndpointsForGroup(peer)) {
167                         currentTenant = peerEp.getTenant();
168                         subnetsByTenant.put(currentTenant, getSubnets(currentTenant));
169                         EpKey srcEpKey = new EpKey(srcEp.getL2Context(), srcEp.getMacAddress());
170                         EpKey peerEpKey = new EpKey(peerEp.getL2Context(), peerEp.getMacAddress());
171
172                         if (visitedEps.get(srcEpKey) != null && visitedEps.get(srcEpKey).contains(peerEpKey)) {
173                             continue;
174                         }
175                         syncEP(flowMap, nodeId, policyInfo, srcEp, peerEp);
176                         visitedEps.put(srcEpKey, peerEpKey);
177
178                         // Process subnets and flood-domains for epPeer
179                         EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo,
180                                 peerEp);
181                         epOrdSet.add(epOrds);
182                     }
183                 }
184             }
185         }
186
187         for (Entry<TenantId, HashSet<Subnet>> subnetEntry : subnetsByTenant.entrySet()) {
188             if (subnetEntry.getValue() == null) {
189                 LOG.trace("Tenant: {} has empty subnet entry.", subnetEntry.getKey());
190                 continue;
191             }
192             currentTenant = subnetEntry.getKey();
193             for (Subnet sn : subnetEntry.getValue()) {
194                 L3Context l3c = getL3ContextForSubnet(currentTenant, sn);
195                 Flow arpFlow = createRouterArpFlow(currentTenant, nodeId, sn,
196                         OrdinalFactory.getContextOrdinal(currentTenant, l3c.getId()));
197                 if (arpFlow != null) {
198                     flowMap.writeFlow(nodeId, TABLE_ID, arpFlow);
199                 } else {
200                     LOG.debug(
201                             "Gateway ARP flow is not created, because virtual router IP has not been set for subnet {} .",
202                             sn.getIpPrefix().getValue());
203                 }
204             }
205         }
206
207         // Write broadcast flows per flood domain.
208         for (EndpointFwdCtxOrdinals epOrd : epOrdSet) {
209             if (groupExists(nodeId, epOrd.getFdId())) {
210                 flowMap.writeFlow(nodeId, TABLE_ID, createBroadcastFlow(epOrd));
211             }
212         }
213     }
214
215     // set up next-hop destinations for all the endpoints in the endpoint
216     // group on the node
217
218     private Flow createBroadcastFlow(EndpointFwdCtxOrdinals epOrd) {
219         FlowId flowId = new FlowId("broadcast|" + epOrd.getFdId());
220         MatchBuilder mb = new MatchBuilder()
221                             .setEthernetMatch(new EthernetMatchBuilder()
222                             .setEthernetDestination(new EthernetDestinationBuilder().
223                                                         setAddress(MULTICAST_MAC)
224                                                         .setMask(MULTICAST_MAC).build())
225                             .build());
226         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(epOrd.getFdId())));
227
228         FlowBuilder flowb = base().setPriority(Integer.valueOf(140))
229             .setId(flowId)
230             .setMatch(mb.build())
231             .setInstructions(
232                     instructions(applyActionIns(nxLoadTunIdAction(BigInteger.valueOf(epOrd.getFdId()), false),
233                             groupAction(Long.valueOf(epOrd.getFdId())))));
234
235         return flowb.build();
236     }
237
238     private boolean groupExists(NodeId nodeId, Integer fdId) throws Exception {
239         // Fetch existing GroupTables
240         if (ctx.getDataBroker() == null) {
241             return false;
242         }
243
244         ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
245         InstanceIdentifier<Node> niid = createNodePath(nodeId);
246         Optional<Node> r = t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
247         if (!r.isPresent())
248             return false;
249         FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
250         if (fcn == null)
251             return false;
252
253         if (fcn.getGroup() != null) {
254             for (Group g : fcn.getGroup()) {
255                 if (g.getGroupId().getValue().equals(Long.valueOf(fdId))) { // Group
256                                                                             // Exists.
257                     return true;
258                 }
259             }
260         }
261         return false;
262     }
263
264     private MacAddress routerPortMac(L3Context l3c, IpAddress ipAddress) {
265
266         if (ctx.getDataBroker() == null) {
267             return null;
268         }
269
270         MacAddress defaultMacAddress = ROUTER_MAC;
271
272         EndpointL3Key l3Key = new EndpointL3Key(ipAddress, l3c.getId());
273         InstanceIdentifier<EndpointL3> endpointsIid = InstanceIdentifier.builder(Endpoints.class)
274             .child(EndpointL3.class, l3Key)
275             .build();
276         ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
277
278         Optional<EndpointL3> r;
279         try {
280             r = t.read(LogicalDatastoreType.OPERATIONAL, endpointsIid).get();
281             if (!r.isPresent())
282                 return defaultMacAddress;
283             EndpointL3 epL3 = r.get();
284             if (epL3.getMacAddress() == null) {
285                 return defaultMacAddress;
286             } else {
287                 return epL3.getMacAddress();
288             }
289         } catch (Exception e) {
290             LOG.error("Error reading EndpointL3 {}.{}", l3c, ipAddress, e);
291             return null;
292         }
293     }
294
295     private L3Context getL3ContextForSubnet(TenantId tenantId, Subnet sn) {
296         L3Context l3c = ctx.getPolicyResolver().getTenant(tenantId).resolveL3Context(sn.getId());
297         return l3c;
298     }
299
300     private Flow createRouterArpFlow(TenantId tenantId, NodeId nodeId, Subnet sn, int l3Id) {
301         if (sn == null || sn.getVirtualRouterIp() == null) {
302             LOG.trace("Didn't create routerArpFlow since either subnet or subnet virtual router was null");
303             return null;
304         }
305         /*
306          * TODO: Li alagalah: This should be new Yang "gateways" list as well,
307          * that expresses the gateway and prefixes it is interface for. Should
308          * also check for external.
309          */
310         if (sn.getVirtualRouterIp().getIpv4Address() != null) {
311             String ikey = sn.getVirtualRouterIp().getIpv4Address().getValue();
312
313             L3Context l3c = getL3ContextForSubnet(tenantId, sn);
314             if (l3c == null) {
315                 LOG.error("No L3 Context found associated with subnet {}", sn.getId());
316             }
317
318             MacAddress routerMac = routerPortMac(l3c, sn.getVirtualRouterIp());
319             if (routerMac == null) {
320                 return null;
321             }
322
323             BigInteger intRouterMac = new BigInteger(1, bytesFromHexString(routerMac.getValue()));
324
325             FlowId flowId = new FlowId(new StringBuffer().append("routerarp|")
326                 .append(sn.getId().getValue())
327                 .append("|")
328                 .append(ikey)
329                 .append("|")
330                 .append(l3Id)
331                 .toString());
332             MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, null, ARP)).setLayer3Match(
333                     new ArpMatchBuilder().setArpOp(Integer.valueOf(1))
334                         .setArpTargetTransportAddress(new Ipv4Prefix(ikey + "/32"))
335                         .build());
336             addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(l3Id)));
337
338             FlowBuilder flowb = base().setPriority(150)
339                 .setId(flowId)
340                 .setMatch(mb.build())
341                 .setInstructions(
342                         instructions(applyActionIns(nxMoveEthSrcToEthDstAction(), setDlSrcAction(routerMac),
343                                 nxLoadArpOpAction(BigInteger.valueOf(2L)), nxMoveArpShaToArpThaAction(),
344                                 nxLoadArpShaAction(intRouterMac), nxMoveArpSpaToArpTpaAction(),
345                                 nxLoadArpSpaAction(ikey), outputAction(new NodeConnectorId(nodeId.getValue()
346                                         + ":INPORT")))));
347             return flowb.build();
348         } else {
349             LOG.warn("IPv6 virtual router {} for subnet {} not supported", sn.getVirtualRouterIp(), sn.getId()
350                 .getValue());
351             return null;
352         }
353
354     }
355
356     private Flow createLocalL2Flow(Endpoint ep, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
357
358         // TODO Li alagalah - refactor common code but keep simple method
359         ArrayList<Instruction> instructions = new ArrayList<>();
360         List<Action> applyActions = new ArrayList<>();
361
362         int order = 0;
363
364         Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
365         Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
366         Action setNextHop;
367         String nextHop;
368
369         // BEGIN L2 LOCAL
370         nextHop = ofc.getNodeConnectorId().getValue();
371
372         long portNum;
373         try {
374             portNum = getOfPortNum(ofc.getNodeConnectorId());
375         } catch (NumberFormatException ex) {
376             LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
377             return null;
378         }
379
380         setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
381
382         // END L2 LOCAL
383
384         order += 1;
385         applyActions.add(setdEPG);
386         applyActions.add(setdCG);
387         applyActions.add(setNextHop);
388         Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
389             .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
390             .build();
391         instructions.add(applyActionsIns);
392
393         Instruction gotoTable = new InstructionBuilder().setOrder(order++)
394             .setInstruction(gotoTableIns((short) (getTableId() + 1)))
395             .build();
396         instructions.add(gotoTable);
397
398         FlowId flowid = new FlowId(new StringBuilder().append(epFwdCtxOrds.getBdId())
399             .append("|l2|")
400             .append(ep.getMacAddress().getValue())
401             .append("|")
402             .append(nextHop)
403             .toString());
404         MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
405         addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
406         FlowBuilder flowb = base().setId(flowid)
407             .setPriority(Integer.valueOf(50))
408             .setMatch(mb.build())
409             .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
410         return flowb.build();
411     }
412
413     private void syncEP(FlowMap flowMap, NodeId nodeId, PolicyInfo policyInfo, Endpoint srcEp, Endpoint destEp)
414             throws Exception {
415
416         // TODO: Conditions messed up, but for now, send policyInfo until this
417         // is fixed.
418         EndpointFwdCtxOrdinals destEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, destEp);
419         EndpointFwdCtxOrdinals srcEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
420
421         if (destEp.getTenant() == null || (destEp.getEndpointGroup() == null && destEp.getEndpointGroups() == null)) {
422             LOG.trace("Didn't process endpoint due to either tenant, or EPG(s) being null", destEp.getKey());
423             return;
424         }
425         OfOverlayContext ofc = destEp.getAugmentation(OfOverlayContext.class);
426
427         // ////////////////////////////////////////////////////////////////////////////////////////
428         /*
429          * NOT HANDLING EXTERNALS TODO: alagalah Li: External Gateway
430          * functionality needed here.
431          */
432         if (LocationType.External.equals(ofc.getLocationType())) {
433             // XXX - TODO - perform NAT and send to the external network
434             // TODO: Use case neutron gateway interface
435             LOG.warn("External endpoints not yet supported");
436             return;
437         }
438
439         /*
440          * Only care about subnets for L3, but fetch them before loop. We need
441          * the local subnets for setting SRC MAC for routing. All Routing is now
442          * done locally! YAY! Instead of being shovelled L2 style across network
443          * ala Helium.
444          */
445         List<Subnet> localSubnets = getLocalSubnets(nodeId);
446         if (localSubnets == null) {
447             LOG.error("No subnets could be found locally for node: {}", nodeId);
448             return;
449         }
450
451         if (Objects.equals(ofc.getNodeId(), nodeId)) {
452             // this is a local endpoint; send to the approppriate local
453             // port
454
455             if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
456                 flowMap.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(destEp, destEpFwdCtxOrds, ofc));
457             }
458             // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
459             // The Endpoint conflation must end!
460             if (destEp.getL3Address() == null) {
461                 LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", destEp.getKey());
462                 return;
463             }
464
465             for (L3Address l3a : destEp.getL3Address()) {
466                 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
467                     LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
468                             destEp.getL3Address());
469                     continue;
470                 } else {
471                     for (Subnet localSubnet : localSubnets) {
472                         Flow flow = createLocalL3RoutedFlow(destEp, l3a, destEpFwdCtxOrds, ofc, localSubnet);
473                         if (flow != null) {
474                             flowMap.writeFlow(nodeId, TABLE_ID, flow);
475                         } else {
476                             LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
477                                     localSubnet.getIpPrefix().getValue());
478                         }
479                     }
480                 }
481             }
482         } else {
483             // this endpoint is on a different switch; send to the
484             // appropriate tunnel
485             if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
486                 Flow remoteL2Flow = createRemoteL2Flow(destEp, nodeId, srcEpFwdCtxOrds, destEpFwdCtxOrds, ofc);
487                 if (remoteL2Flow != null) {
488                     flowMap.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
489                 }
490             } else {
491                 LOG.trace("DestinationMapper: RemoteL2Flow: not created, in different BDs src: {} dst: {}",
492                         srcEpFwdCtxOrds.getBdId(), destEpFwdCtxOrds.getBdId());
493             }
494
495             // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
496             // The Endpoint conflation must end!
497             if (destEp.getL3Address() == null) {
498                 LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", destEp.getKey());
499                 return;
500             }
501             for (L3Address l3a : destEp.getL3Address()) {
502                 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
503                     LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
504                             destEp.getL3Address());
505                     continue;
506                 } else {
507                     for (Subnet localSubnet : localSubnets) {
508                         Flow remoteL3Flow = createRemoteL3RoutedFlow(destEp, l3a, nodeId, srcEpFwdCtxOrds,
509                                 destEpFwdCtxOrds, ofc, localSubnet);
510                         if (remoteL3Flow != null) {
511                             flowMap.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
512                         } else {
513                             LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
514                                     localSubnet.getIpPrefix().getValue());
515                         }
516                     }
517                 }
518             }
519         } // remote (tunnel)
520
521         // }
522
523     }
524
525     /*
526      * ################################## DestMapper Flow methods
527      * ##################################
528      */
529     private Flow createLocalL3RoutedFlow(Endpoint destEp, L3Address destL3Address, EndpointFwdCtxOrdinals epFwdCtxOrds,
530             OfOverlayContext ofc, Subnet srcSubnet) {
531
532         // TODO Li alagalah - refactor common code but keep simple method
533
534         Subnet destSubnet = null;
535         HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
536         if (subnets == null) {
537             LOG.trace("No subnets in tenant {}", destL3Address.getIpAddress());
538             return null;
539         }
540         NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
541         for (Subnet subnet : subnets) {
542             // TODO Li alagalah add IPv6 support
543             if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
544                 destSubnet = subnet;
545                 break;
546             }
547         }
548         if (destSubnet == null) {
549             LOG.trace("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
550             return null;
551         }
552
553         if (destSubnet.getVirtualRouterIp() == null) {
554             LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
555                     destL3Address.getKey());
556             return null;
557         }
558
559         if (srcSubnet.getVirtualRouterIp() == null) {
560             LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
561             return null;
562         }
563         L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
564         if (destL3c == null || destL3c.getId() == null) {
565             LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
566             return null;
567         }
568         L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
569         if (srcL3c == null || srcL3c.getId() == null) {
570             LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
571             return null;
572         }
573
574         if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
575             LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
576                 .getValue(), destL3c.getId().getValue());
577             return null;
578         }
579
580         MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
581         MacAddress epDestMac = destEp.getMacAddress();
582         MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
583
584         if (srcSubnet.getId().getValue().equals(destSubnet.getId().getValue())) {
585             // This is our final destination, so match on actual EP mac.
586             matcherMac = epDestMac;
587         }
588
589         ArrayList<Instruction> l3instructions = new ArrayList<>();
590         List<Action> applyActions = new ArrayList<>();
591         List<Action> l3ApplyActions = new ArrayList<>();
592
593         int order = 0;
594
595         Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
596         Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
597         Action setNextHop;
598         String nextHop;
599
600         // BEGIN L3 LOCAL
601         nextHop = ofc.getNodeConnectorId().getValue();
602
603         long portNum;
604         try {
605             portNum = getOfPortNum(ofc.getNodeConnectorId());
606         } catch (NumberFormatException ex) {
607             LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
608             return null;
609         }
610
611         setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
612         // END L3 LOCAL
613
614         // Lets not re-write the srcMac if its local.
615         if (!(matcherMac.getValue().equals(epDestMac.getValue()))) {
616             Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
617             l3ApplyActions.add(setDlSrc);
618         }
619
620         Action setDlDst = setDlDstAction(epDestMac);
621         l3ApplyActions.add(setDlDst);
622
623         Action decTtl = decNwTtlAction();
624         l3ApplyActions.add(decTtl);
625
626         order += 1;
627         applyActions.add(setdEPG);
628         applyActions.add(setdCG);
629         applyActions.add(setNextHop);
630
631         applyActions.addAll(l3ApplyActions);
632         Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
633             .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
634             .build();
635
636         l3instructions.add(applyActionsIns);
637         Instruction gotoTable = new InstructionBuilder().setOrder(order++)
638             .setInstruction(gotoTableIns((short) (getTableId() + 1)))
639             .build();
640         l3instructions.add(gotoTable);
641         Layer3Match m = null;
642         Long etherType = null;
643         String ikey = null;
644         if (destL3Address.getIpAddress().getIpv4Address() != null) {
645             ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
646             etherType = IPv4;
647             m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
648         } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
649             ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
650             etherType = IPv6;
651             m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
652         } else {
653             LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
654             return null;
655         }
656
657         FlowId flowid = new FlowId(new StringBuilder().append(Integer.toString(epFwdCtxOrds.getL3Id()))
658             .append("|l3|")
659             .append(ikey)
660             .append("|")
661             .append(Integer.toString(epFwdCtxOrds.getEpgId()))
662             .append("|")
663             .append(Integer.toString(epFwdCtxOrds.getCgId()))
664             .append("|")
665             .append(matcherMac)
666             .append("|")
667             .append(destSubnetGatewayMac)
668             .append("|")
669             .append(nextHop)
670             .toString());
671         MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
672             .setLayer3Match(m);
673         addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(epFwdCtxOrds.getL3Id())));
674         FlowBuilder flowb = base().setId(flowid)
675             .setPriority(Integer.valueOf(132))
676             .setMatch(mb.build())
677             .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
678         return flowb.build();
679     }
680
681     private Flow createRemoteL2Flow(Endpoint ep, NodeId nodeId, EndpointFwdCtxOrdinals srcEpFwdCtxOrds,
682             EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc) {
683
684         // TODO Li alagalah - refactor common code but keep simple method
685
686         // this endpoint is on a different switch; send to the
687         // appropriate tunnel
688
689         ArrayList<Instruction> instructions = new ArrayList<>();
690         List<Action> applyActions = new ArrayList<>();
691
692         int order = 0;
693
694         Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
695         Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
696         Action setNextHop;
697         String nextHop;
698
699         // BEGIN TUNNEL HANDLING
700         IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
701         NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
702         if (tunDst == null) {
703             LOG.warn("Failed to get Tunnel IP for NodeId {} with EP {}", nodeId, ep);
704             return null;
705         }
706         if (tunPort == null) {
707             LOG.warn("Failed to get Tunnel Port for NodeId {} with EP {}", nodeId, ep);
708             return null;
709         }
710
711         Action tundstAction;
712
713         if (tunDst.getIpv4Address() != null) {
714             nextHop = tunDst.getIpv4Address().getValue();
715             tundstAction = nxLoadTunIPv4Action(nextHop, false);
716         } else if (tunDst.getIpv6Address() != null) {
717             // nextHop = tunDst.getIpv6Address().getValue();
718             LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
719                     ofc.getNodeId());
720             return null;
721         } else {
722             // this shouldn't happen
723             LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
724             return null;
725         }
726
727         long portNum;
728         try {
729             portNum = getOfPortNum(tunPort);
730         } catch (NumberFormatException ex) {
731             LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
732             return null;
733         }
734
735         setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
736         applyActions.add(tundstAction);
737         // END TUNNEL
738
739         order += 1;
740         applyActions.add(setdEPG);
741         applyActions.add(setdCG);
742         applyActions.add(setNextHop);
743         Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
744             .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
745             .build();
746         instructions.add(applyActionsIns);
747
748         applyActionsIns = new InstructionBuilder().setOrder(order++)
749             .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
750             .build();
751
752         Instruction gotoTable = new InstructionBuilder().setOrder(order++)
753             .setInstruction(gotoTableIns((short) (getTableId() + 1)))
754             .build();
755         instructions.add(gotoTable);
756
757         FlowId flowid = new FlowId(new StringBuilder().append(destEpFwdCtxOrds.getBdId())
758             .append("|l2|")
759             .append(ep.getMacAddress().getValue())
760             .append("|")
761             .append(srcEpFwdCtxOrds.getBdId())
762             .append("|")
763             .append(nextHop)
764             .toString());
765         MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
766         addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(destEpFwdCtxOrds.getBdId())));
767         FlowBuilder flowb = base().setId(flowid)
768             .setPriority(Integer.valueOf(50))
769             .setMatch(mb.build())
770             .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
771
772         return flowb.build();
773     }
774
775     private Flow createRemoteL3RoutedFlow(Endpoint destEp, L3Address destL3Address, NodeId nodeId,
776             EndpointFwdCtxOrdinals srcEpFwdCtxOrds, EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc,
777             Subnet srcSubnet) {
778
779         // TODO Li alagalah - refactor common code but keep simple method
780
781         // this endpoint is on a different switch; send to the
782         // appropriate tunnel
783         Subnet destSubnet = null;
784         HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
785         if (subnets == null) {
786             LOG.trace("No subnets in tenant {}", destL3Address.getIpAddress());
787             return null;
788         }
789         NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
790         for (Subnet subnet : subnets) {
791             // TODO Li alagalah add IPv6 support
792             if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
793                 destSubnet = subnet;
794                 break;
795             }
796         }
797         if (destSubnet == null) {
798             LOG.info("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
799             return null;
800         }
801
802         if (destSubnet.getVirtualRouterIp() == null) {
803             LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
804                     destL3Address.getKey());
805             return null;
806         }
807
808         if (srcSubnet.getVirtualRouterIp() == null) {
809             LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
810             return null;
811         }
812         L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
813         if (destL3c == null || destL3c.getId() == null) {
814             LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
815             return null;
816         }
817         L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
818         if (srcL3c == null || srcL3c.getId() == null) {
819             LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
820             return null;
821         }
822
823         if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
824             LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
825                 .getValue(), destL3c.getId().getValue());
826             return null;
827         }
828
829         MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
830         MacAddress epDestMac = destEp.getMacAddress();
831         MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
832
833         ArrayList<Instruction> l3instructions = new ArrayList<>();
834         List<Action> applyActions = new ArrayList<>();
835         List<Action> l3ApplyActions = new ArrayList<>();
836
837         int order = 0;
838
839         Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
840         Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
841         Action setNextHop;
842         String nextHop;
843
844         // BEGIN TUNNEL HANDLING
845         IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
846         NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
847         if (tunDst == null) {
848             LOG.warn("Failed to get Tunnel IP for NodeId {} with L3Address {}", nodeId, destL3Address);
849             return null;
850         }
851         if (tunPort == null) {
852             LOG.warn("Failed to get Tunnel port for NodeId {} with L3Address {}", nodeId, destL3Address);
853             return null;
854         }
855
856         Action tundstAction;
857
858         if (tunDst.getIpv4Address() != null) {
859             nextHop = tunDst.getIpv4Address().getValue();
860             tundstAction = nxLoadTunIPv4Action(nextHop, false);
861         } else if (tunDst.getIpv6Address() != null) {
862             // nextHop = tunDst.getIpv6Address().getValue();
863             LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
864                     ofc.getNodeId());
865             return null;
866         } else {
867             // this shouldn't happen
868             LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
869             return null;
870         }
871
872         long portNum;
873         try {
874             portNum = getOfPortNum(tunPort);
875         } catch (NumberFormatException ex) {
876             LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
877             return null;
878         }
879
880         setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
881         applyActions.add(tundstAction);
882         // END TUNNEL
883
884         order += 1;
885         applyActions.add(setdEPG);
886         applyActions.add(setdCG);
887         applyActions.add(setNextHop);
888
889         Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
890         l3ApplyActions.add(setDlSrc);
891
892         Action setDlDst = setDlDstAction(epDestMac);
893         l3ApplyActions.add(setDlDst);
894
895         Action decTtl = decNwTtlAction();
896         l3ApplyActions.add(decTtl);
897
898         applyActions.addAll(l3ApplyActions);
899         Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
900             .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
901             .build();
902
903         l3instructions.add(applyActionsIns);
904         Instruction gotoTable = new InstructionBuilder().setOrder(order++)
905             .setInstruction(gotoTableIns((short) (getTableId() + 1)))
906             .build();
907         l3instructions.add(gotoTable);
908         Layer3Match m = null;
909         Long etherType = null;
910         String ikey = null;
911         if (destL3Address.getIpAddress().getIpv4Address() != null) {
912             ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
913             etherType = IPv4;
914             m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
915         } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
916             ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
917             etherType = IPv6;
918             m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
919         } else {
920             LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
921             return null;
922         }
923
924         FlowId flowid = new FlowId(new StringBuilder().append(Integer.toString(destEpFwdCtxOrds.getL3Id()))
925             .append("|l3|")
926             .append(ikey)
927             .append("|")
928             .append(matcherMac)
929             .append("|")
930             .append(destSubnetGatewayMac)
931             .append("|")
932             .append(srcEpFwdCtxOrds.getL3Id())
933             .append("|")
934             .append(nextHop)
935             .toString());
936         MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
937             .setLayer3Match(m);
938         addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(destEpFwdCtxOrds.getL3Id())));
939
940         FlowBuilder flowb = base().setId(flowid)
941             .setPriority(Integer.valueOf(132))
942             .setMatch(mb.build())
943             .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
944         return flowb.build();
945     }
946
947     private NetworkDomainId getEPNetworkContainment(Endpoint endpoint) {
948         if (endpoint.getNetworkContainment() != null) {
949             return endpoint.getNetworkContainment();
950         } else {
951             /*
952              * TODO: Be alagalah: Endpoint Refactor: This should be set on input
953              * which we can't do because of the backwards way endpoints were
954              * "architected".
955              */
956             return ctx.getPolicyResolver()
957                 .getTenant(endpoint.getTenant())
958                 .getEndpointGroup(endpoint.getEndpointGroup())
959                 .getNetworkDomain();
960         }
961     }
962
963     private HashSet<Subnet> getSubnets(final TenantId tenantId) {
964
965         // if (subnetsByTenant.get(tenantId) != null) {
966         // return subnetsByTenant.get(tenantId);
967         // }
968
969         if (ctx.getDataBroker() == null) {
970             return null;
971         }
972
973         ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
974         InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
975         Optional<Tenant> tenantInfo;
976         try {
977             tenantInfo = t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
978         } catch (Exception e) {
979             LOG.error("Could not read Tenant {}", tenantId, e);
980             return null;
981         }
982
983         HashSet<Subnet> subnets = new HashSet<Subnet>();
984
985         if (!tenantInfo.isPresent()) {
986             LOG.warn("Tenant {} not found", tenantId);
987             return null;
988         }
989
990         subnets.addAll(tenantInfo.get().getSubnet());
991         // subnetsByTenant.put(tenantId, subnets);
992         return subnets;
993     }
994
995     // Need a method to get subnets for EPs attached to the node locally
996     // to set the source Mac address for the router interface.
997     private List<Subnet> getLocalSubnets(NodeId nodeId) {
998         Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
999
1000         List<Subnet> localSubnets = new ArrayList<Subnet>();
1001
1002         for (Endpoint endpoint : endpointsForNode) {
1003             HashSet<Subnet> subnets = getSubnets(endpoint.getTenant());
1004             if (subnets == null) {
1005                 LOG.error("No local subnets.");
1006                 return null;
1007             }
1008             NetworkDomainId epNetworkContainment = getEPNetworkContainment(endpoint);
1009             for (Subnet subnet : subnets) {
1010                 if (epNetworkContainment.getValue().equals(subnet.getId().getValue())) {
1011                     localSubnets.add(subnet);
1012                 }
1013             }
1014         }
1015         return localSubnets;
1016     }
1017
1018     /**
1019      * Reads data from datastore as synchronous call.
1020      *
1021      * @return {@link Optional#isPresent()} is {@code true} if reading was
1022      *         successful and data exists in datastore; {@link Optional#isPresent()} is
1023      *         {@code false} otherwise
1024      */
1025     public static <T extends DataObject> Optional<T> readFromDs(LogicalDatastoreType store, InstanceIdentifier<T> path,
1026             ReadTransaction rTx) {
1027         CheckedFuture<Optional<T>, ReadFailedException> resultFuture = rTx.read(store, path);
1028         try {
1029             return resultFuture.checkedGet();
1030         } catch (ReadFailedException e) {
1031             LOG.warn("Read failed from DS.", e);
1032             return Optional.absent();
1033         }
1034     }
1035
1036     static byte[] bytesFromHexString(String values) {
1037         String target = "";
1038         if (values != null) {
1039             target = values;
1040         }
1041         String[] octets = target.split(":");
1042
1043         byte[] ret = new byte[octets.length];
1044         for (int i = 0; i < octets.length; i++) {
1045             ret[i] = Integer.valueOf(octets[i], 16).byteValue();
1046         }
1047         return ret;
1048     }
1049 }