+ MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
+ MacAddress epDestMac = destEp.getMacAddress();
+ MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
+
+ ArrayList<Instruction> l3instructions = new ArrayList<>();
+ List<Action> applyActions = new ArrayList<>();
+ List<Action> l3ApplyActions = new ArrayList<>();
+
+ int order = 0;
+
+ Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
+ Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
+ Action setNextHop;
+ String nextHop;
+
+ // BEGIN TUNNEL HANDLING
+ IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
+ NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
+ if (tunDst == null) {
+ LOG.warn("Failed to get Tunnel IP for NodeId {} with L3Address {}", nodeId, destL3Address);
+ return null;
+ }
+ if (tunPort == null) {
+ LOG.warn("Failed to get Tunnel port for NodeId {} with L3Address {}", nodeId, destL3Address);
+ return null;
+ }
+
+ Action tundstAction;
+
+ if (tunDst.getIpv4Address() != null) {
+ nextHop = tunDst.getIpv4Address().getValue();
+ tundstAction = nxLoadTunIPv4Action(nextHop, false);
+ } else if (tunDst.getIpv6Address() != null) {
+ // nextHop = tunDst.getIpv6Address().getValue();
+ LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
+ ofc.getNodeId());
+ return null;
+ } else {
+ // this shouldn't happen
+ LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
+ return null;
+ }
+
+ long portNum;
+ try {
+ portNum = getOfPortNum(tunPort);
+ } catch (NumberFormatException ex) {
+ LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
+ return null;
+ }
+
+ setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
+ applyActions.add(tundstAction);
+ // END TUNNEL
+
+ order += 1;
+ applyActions.add(setdEPG);
+ applyActions.add(setdCG);
+ applyActions.add(setNextHop);
+
+ Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
+ l3ApplyActions.add(setDlSrc);
+
+ Action setDlDst = setDlDstAction(epDestMac);
+ l3ApplyActions.add(setDlDst);
+
+ Action decTtl = decNwTtlAction();
+ l3ApplyActions.add(decTtl);
+
+ applyActions.addAll(l3ApplyActions);
+ Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
+ .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+ .build();
+
+ l3instructions.add(applyActionsIns);
+ Instruction gotoTable = new InstructionBuilder().setOrder(order++)
+ .setInstruction(gotoTableIns((short) (getTableId() + 1)))
+ .build();
+ l3instructions.add(gotoTable);
+ Layer3Match m = null;
+ Long etherType = null;
+ String ikey = null;
+ if (destL3Address.getIpAddress().getIpv4Address() != null) {
+ ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
+ etherType = IPv4;
+ m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
+ } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
+ ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
+ etherType = IPv6;
+ m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
+ } else {
+ LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
+ return null;
+ }
+
+ FlowId flowid = new FlowId(new StringBuilder().append(Integer.toString(destEpFwdCtxOrds.getL3Id()))
+ .append("|l3|")
+ .append(ikey)
+ .append("|")
+ .append(matcherMac)
+ .append("|")
+ .append(destSubnetGatewayMac)
+ .append("|")
+ .append(srcEpFwdCtxOrds.getL3Id())
+ .append("|")
+ .append(nextHop)
+ .toString());
+ MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
+ .setLayer3Match(m);
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(destEpFwdCtxOrds.getL3Id())));
+
+ FlowBuilder flowb = base().setId(flowid)
+ .setPriority(Integer.valueOf(132))
+ .setMatch(mb.build())
+ .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
+ return flowb.build();
+ }
+
+ private NetworkDomainId getEPNetworkContainment(Endpoint endpoint) {
+ if (endpoint.getNetworkContainment() != null) {
+ return endpoint.getNetworkContainment();
+ } else {
+ /*
+ * TODO: Be alagalah: Endpoint Refactor: This should be set on input
+ * which we can't do because of the backwards way endpoints were
+ * "architected".
+ */
+ return ctx.getPolicyResolver()
+ .getTenant(endpoint.getTenant())
+ .getEndpointGroup(endpoint.getEndpointGroup())
+ .getNetworkDomain();
+ }
+ }
+
+ private HashSet<Subnet> getSubnets(final TenantId tenantId) {
+
+ // if (subnetsByTenant.get(tenantId) != null) {
+ // return subnetsByTenant.get(tenantId);
+ // }
+
+ if (ctx.getDataBroker() == null) {
+ return null;
+ }
+
+ ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
+ InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
+ Optional<Tenant> tenantInfo;
+ try {
+ tenantInfo = t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
+ } catch (Exception e) {
+ LOG.error("Could not read Tenant {}", tenantId, e);
+ return null;
+ }
+
+ HashSet<Subnet> subnets = new HashSet<Subnet>();
+
+ if (!tenantInfo.isPresent()) {
+ LOG.warn("Tenant {} not found", tenantId);
+ return null;
+ }
+
+ subnets.addAll(tenantInfo.get().getSubnet());
+ // subnetsByTenant.put(tenantId, subnets);
+ return subnets;
+ }
+
+ // Need a method to get subnets for EPs attached to the node locally
+ // to set the source Mac address for the router interface.
+ private List<Subnet> getLocalSubnets(NodeId nodeId) {
+ Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
+
+ List<Subnet> localSubnets = new ArrayList<Subnet>();
+
+ for (Endpoint endpoint : endpointsForNode) {
+ HashSet<Subnet> subnets = getSubnets(endpoint.getTenant());
+ if (subnets == null) {
+ LOG.error("No local subnets.");
+ return null;
+ }
+ NetworkDomainId epNetworkContainment = getEPNetworkContainment(endpoint);
+ for (Subnet subnet : subnets) {
+ if (epNetworkContainment.getValue().equals(subnet.getId().getValue())) {
+ localSubnets.add(subnet);
+ }