2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
11 import static com.google.common.base.Preconditions.checkNotNull;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
26 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
27 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
28 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
29 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
30 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
31 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
32 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
33 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
34 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
35 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
36 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
38 import java.math.BigInteger;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
46 import java.util.Map.Entry;
47 import java.util.Objects;
50 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
51 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.groupbasedpolicy.util.IidFactory;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3Gateways;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
106 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
107 import org.slf4j.Logger;
108 import org.slf4j.LoggerFactory;
110 import com.google.common.base.Optional;
111 import com.google.common.base.Strings;
112 import com.google.common.collect.HashMultimap;
113 import com.google.common.collect.SetMultimap;
114 import com.google.common.collect.Sets;
117 * Manage the table that maps the destination address to the next hop for the
118 * path as well as applies any relevant routing transformations.
120 public class DestinationMapper extends FlowTable {
122 protected static final Logger LOG = LoggerFactory.getLogger(DestinationMapper.class);
124 // TODO Li alagalah: Improve UT coverage for this class.
126 // TODO Li alagalah: Use EndpointL3 for L3 flows, Endpoint for L2 flows
127 // This ensures we have the appropriate network-containment'
129 public static short TABLE_ID;
131 * This is the MAC address of the magical router in the sky
133 public static final MacAddress ROUTER_MAC = new MacAddress("88:f0:31:b5:12:b5");
134 public static final MacAddress MULTICAST_MAC = new MacAddress("01:00:00:00:00:00");
135 public static final Integer BASE_L3_PRIORITY = 100;
137 public DestinationMapper(OfContext ctx, short tableId) {
139 this.TABLE_ID = tableId;
142 Map<TenantId, HashSet<Subnet>> subnetsByTenant = new HashMap<TenantId, HashSet<Subnet>>();
145 public short getTableId() {
150 public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
152 TenantId currentTenant = null;
154 flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
156 SetMultimap<EpKey, EpKey> visitedEps = HashMultimap.create();
157 Set<EndpointFwdCtxOrdinals> epOrdSet = new HashSet<>();
159 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
160 Set<EndpointGroupId> srcEpgIds = new HashSet<>();
161 if (srcEp.getEndpointGroup() != null)
162 srcEpgIds.add(srcEp.getEndpointGroup());
163 if (srcEp.getEndpointGroups() != null)
164 srcEpgIds.addAll(srcEp.getEndpointGroups());
166 for (EndpointGroupId epgId : srcEpgIds) {
167 EgKey epg = new EgKey(srcEp.getTenant(), epgId);
168 Set<EgKey> peers = Sets.union(Collections.singleton(epg), policyInfo.getPeers(epg));
169 for (EgKey peer : peers) {
170 for (Endpoint peerEp : ctx.getEndpointManager().getEndpointsForGroup(peer)) {
171 currentTenant = peerEp.getTenant();
172 subnetsByTenant.put(currentTenant, getSubnets(currentTenant));
173 EpKey srcEpKey = new EpKey(srcEp.getL2Context(), srcEp.getMacAddress());
174 EpKey peerEpKey = new EpKey(peerEp.getL2Context(), peerEp.getMacAddress());
176 if (visitedEps.get(srcEpKey) != null && visitedEps.get(srcEpKey).contains(peerEpKey)) {
179 syncEP(flowMap, nodeId, policyInfo, srcEp, peerEp);
180 visitedEps.put(srcEpKey, peerEpKey);
182 // Process subnets and flood-domains for epPeer
183 EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo,
185 epOrdSet.add(epOrds);
191 for (Entry<TenantId, HashSet<Subnet>> subnetEntry : subnetsByTenant.entrySet()) {
192 if (subnetEntry.getValue() == null) {
193 LOG.trace("Tenant: {} has empty subnet entry.", subnetEntry.getKey());
196 currentTenant = subnetEntry.getKey();
197 for (Subnet sn : subnetEntry.getValue()) {
198 L3Context l3c = getL3ContextForSubnet(currentTenant, sn);
199 Flow arpFlow = createRouterArpFlow(currentTenant, nodeId, sn,
200 OrdinalFactory.getContextOrdinal(currentTenant, l3c.getId()));
201 if (arpFlow != null) {
202 flowMap.writeFlow(nodeId, TABLE_ID, arpFlow);
205 "Gateway ARP flow is not created, because virtual router IP has not been set for subnet {} .",
206 sn.getIpPrefix().getValue());
211 // Write broadcast flows per flood domain.
212 for (EndpointFwdCtxOrdinals epOrd : epOrdSet) {
213 if (groupExists(nodeId, epOrd.getFdId())) {
214 flowMap.writeFlow(nodeId, TABLE_ID, createBroadcastFlow(epOrd));
218 // L3 Prefix Endpoint handling
219 Collection<EndpointL3Prefix> prefixEps = ctx.getEndpointManager().getEndpointsL3PrefixForTenant(currentTenant);
220 if (prefixEps != null) {
221 LOG.trace("DestinationMapper - Processing L3PrefixEndpoints");
222 for (EndpointL3Prefix prefixEp : prefixEps) {
223 Flow prefixFlow = createL3PrefixFlow(prefixEp, policyInfo, nodeId);
224 if (prefixFlow != null) {
225 flowMap.writeFlow(nodeId, TABLE_ID, prefixFlow);
226 LOG.trace("Wrote L3Prefix flow");
233 // set up next-hop destinations for all the endpoints in the endpoint
236 private Flow createL3PrefixFlow(EndpointL3Prefix prefixEp, PolicyInfo policyInfo, NodeId nodeId) throws Exception {
238 * Priority: 100+lengthprefix
239 * Match: prefix, l3c, "mac address of router" ?
241 * - set Reg2, Reg3 for L3Ep by L2Ep ?
243 * - Reg7: use switch location external port else punt for now
245 * - Reg7: grab L2Ep from L3Ep and use its location info
246 * - goto_table: POLENF (will check there for external on EP)
249 ReadOnlyTransaction rTx = ctx.getDataBroker().newReadOnlyTransaction();
250 // TODO Bug #3440 Target: Be - should support for more than first gateway.
251 EndpointL3Gateways l3Gateway = prefixEp.getEndpointL3Gateways().get(0);
252 Optional<EndpointL3> optL3Ep = readFromDs(LogicalDatastoreType.OPERATIONAL,
253 IidFactory.l3EndpointIid(l3Gateway.getL3Context(), l3Gateway.getIpAddress()), rTx);
254 if (!optL3Ep.isPresent()) {
255 LOG.error("createL3PrefixFlow - L3Endpoint gateway {} for L3Prefix {} not found.", l3Gateway, prefixEp);
258 EndpointL3 l3Ep = optL3Ep.get();
259 Optional<Endpoint> optL2Ep = readFromDs(LogicalDatastoreType.OPERATIONAL,
260 IidFactory.endpointIid(l3Ep.getL2Context(), l3Ep.getMacAddress()), rTx);
261 if (!optL2Ep.isPresent()) {
262 LOG.error("createL3PrefixFlow - L2Endpoint for L3Gateway {} not found.", l3Ep);
265 Endpoint l2Ep = optL2Ep.get();
266 EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, l2Ep);
268 NetworkDomainId epNetworkContainment = getEPNetworkContainment(l2Ep);
270 MacAddress epDestMac = l2Ep.getMacAddress();
271 MacAddress destSubnetGatewayMac = l2Ep.getMacAddress();
273 ArrayList<Instruction> l3instructions = new ArrayList<>();
274 List<Action> applyActions = new ArrayList<>();
275 List<Action> l3ApplyActions = new ArrayList<>();
279 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
280 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
284 OfOverlayContext ofc = l2Ep.getAugmentation(OfOverlayContext.class);
285 LocationType location;
287 if (ofc != null && ofc.getLocationType() != null) {
288 location = ofc.getLocationType();
289 } else if (ofc != null) {
290 // Augmentation, but using default location
291 location = LocationType.Internal;
293 LOG.info("createL3PrefixFlow - Endpoint {} had no augmentation.", l2Ep);
299 if (location.equals(LocationType.Internal)) {
300 checkNotNull(ofc.getNodeConnectorId());
301 nextHop = ofc.getNodeConnectorId().getValue();
303 portNum = getOfPortNum(ofc.getNodeConnectorId());
304 } catch (NumberFormatException ex) {
305 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
311 Set<NodeConnectorId> externalPorts = ctx.getSwitchManager().getExternalPorts(nodeId);
312 checkNotNull(externalPorts);
313 for (NodeConnectorId externalPort : externalPorts) {
314 // TODO Bug #3440 Target: Be - should support for more than first external port.
315 //TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
316 nextHop = externalPort.getValue();
318 portNum = getOfPortNum(externalPort);
319 } catch (NumberFormatException ex) {
320 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
327 if (Strings.isNullOrEmpty(nextHop)
329 LOG.error("createL3Prefix - Cannot find nodeConnectorId for {} for Prefix: ", l2Ep, prefixEp);
332 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
334 Action setDlDst = setDlDstAction(epDestMac);
335 l3ApplyActions.add(setDlDst);
337 Action decTtl = decNwTtlAction();
338 l3ApplyActions.add(decTtl);
341 applyActions.add(setdEPG);
342 applyActions.add(setdCG);
343 applyActions.add(setNextHop);
345 applyActions.addAll(l3ApplyActions);
346 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
347 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
350 l3instructions.add(applyActionsIns);
351 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
352 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
354 l3instructions.add(gotoTable);
356 Layer3Match m = null;
357 Long etherType = null;
359 Integer prefixLength=0;
360 if (prefixEp.getIpPrefix().getIpv4Prefix() != null) {
361 ikey = prefixEp.getIpPrefix().getIpv4Prefix().getValue();
363 prefixLength=Integer.valueOf(prefixEp.getIpPrefix().getIpv4Prefix().getValue().split("/")[1]);
364 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
365 } else if (prefixEp.getIpPrefix().getIpv6Prefix() != null) {
366 ikey = prefixEp.getIpPrefix().getIpv6Prefix().getValue();
369 * This will result in flows with priority between 100-228, but since its matching on IPv6 prefix as well
370 * this shouldn't pose and issue, as the priority is more important within the address space of the matcher,
371 * even though technically flows are processed in priority order.
374 prefixLength=Integer.valueOf(prefixEp.getIpPrefix().getIpv6Prefix().getValue().split("/")[1]);
375 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
377 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", prefixEp);
381 FlowId flowid = new FlowId(new StringBuilder().append(Integer.toString(epFwdCtxOrds.getL3Id()))
382 .append("|l3prefix|")
385 .append(destSubnetGatewayMac)
389 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, null, etherType));
390 // MatchBuilder mb = new MatchBuilder();//.setLayer3Match(m);
391 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(epFwdCtxOrds.getL3Id())));
392 FlowBuilder flowb = base().setId(flowid)
393 .setPriority(Integer.valueOf(BASE_L3_PRIORITY+prefixLength))
394 .setMatch(mb.build())
395 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
396 return flowb.build();
399 private Flow createBroadcastFlow(EndpointFwdCtxOrdinals epOrd) {
400 FlowId flowId = new FlowId("broadcast|" + epOrd.getFdId());
401 MatchBuilder mb = new MatchBuilder().setEthernetMatch(new EthernetMatchBuilder().setEthernetDestination(
402 new EthernetDestinationBuilder().setAddress(MULTICAST_MAC).setMask(MULTICAST_MAC).build()).build());
403 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(epOrd.getFdId())));
405 FlowBuilder flowb = base().setPriority(Integer.valueOf(140))
407 .setMatch(mb.build())
409 instructions(applyActionIns(nxLoadTunIdAction(BigInteger.valueOf(epOrd.getFdId()), false),
410 groupAction(Long.valueOf(epOrd.getFdId())))));
412 return flowb.build();
415 private boolean groupExists(NodeId nodeId, Integer fdId) throws Exception {
416 // Fetch existing GroupTables
417 if (ctx.getDataBroker() == null) {
421 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
422 InstanceIdentifier<Node> niid = createNodePath(nodeId);
423 Optional<Node> r = t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
426 FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
430 if (fcn.getGroup() != null) {
431 for (Group g : fcn.getGroup()) {
432 if (g.getGroupId().getValue().equals(Long.valueOf(fdId))) { // Group
441 private MacAddress routerPortMac(L3Context l3c, IpAddress ipAddress) {
443 if (ctx.getDataBroker() == null) {
447 MacAddress defaultMacAddress = ROUTER_MAC;
449 EndpointL3Key l3Key = new EndpointL3Key(ipAddress, l3c.getId());
450 InstanceIdentifier<EndpointL3> endpointsIid = InstanceIdentifier.builder(Endpoints.class)
451 .child(EndpointL3.class, l3Key)
453 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
455 Optional<EndpointL3> r;
457 r = t.read(LogicalDatastoreType.OPERATIONAL, endpointsIid).get();
459 return defaultMacAddress;
460 EndpointL3 epL3 = r.get();
461 if (epL3.getMacAddress() == null) {
462 return defaultMacAddress;
464 return epL3.getMacAddress();
466 } catch (Exception e) {
467 LOG.error("Error reading EndpointL3 {}.{}", l3c, ipAddress, e);
472 private L3Context getL3ContextForSubnet(TenantId tenantId, Subnet sn) {
473 L3Context l3c = ctx.getPolicyResolver().getTenant(tenantId).resolveL3Context(sn.getId());
477 private Flow createRouterArpFlow(TenantId tenantId, NodeId nodeId, Subnet sn, int l3Id) {
478 if (sn == null || sn.getVirtualRouterIp() == null) {
479 LOG.trace("Didn't create routerArpFlow since either subnet or subnet virtual router was null");
483 * TODO: Li alagalah: This should be new Yang "gateways" list as well,
484 * that expresses the gateway and prefixes it is interface for. Should
485 * also check for external.
487 if (sn.getVirtualRouterIp().getIpv4Address() != null) {
488 String ikey = sn.getVirtualRouterIp().getIpv4Address().getValue();
490 L3Context l3c = getL3ContextForSubnet(tenantId, sn);
492 LOG.error("No L3 Context found associated with subnet {}", sn.getId());
495 MacAddress routerMac = routerPortMac(l3c, sn.getVirtualRouterIp());
496 if (routerMac == null) {
500 BigInteger intRouterMac = new BigInteger(1, bytesFromHexString(routerMac.getValue()));
502 FlowId flowId = new FlowId(new StringBuffer().append("routerarp|")
503 .append(sn.getId().getValue())
509 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, null, ARP)).setLayer3Match(
510 new ArpMatchBuilder().setArpOp(Integer.valueOf(1))
511 .setArpTargetTransportAddress(new Ipv4Prefix(ikey + "/32"))
513 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(l3Id)));
515 FlowBuilder flowb = base().setPriority(150)
517 .setMatch(mb.build())
519 instructions(applyActionIns(nxMoveEthSrcToEthDstAction(), setDlSrcAction(routerMac),
520 nxLoadArpOpAction(BigInteger.valueOf(2L)), nxMoveArpShaToArpThaAction(),
521 nxLoadArpShaAction(intRouterMac), nxMoveArpSpaToArpTpaAction(),
522 nxLoadArpSpaAction(ikey), outputAction(new NodeConnectorId(nodeId.getValue()
524 return flowb.build();
526 LOG.warn("IPv6 virtual router {} for subnet {} not supported", sn.getVirtualRouterIp(), sn.getId()
533 private Flow createLocalL2Flow(Endpoint ep, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
535 // TODO Li alagalah - refactor common code but keep simple method
536 ArrayList<Instruction> instructions = new ArrayList<>();
537 List<Action> applyActions = new ArrayList<>();
541 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
542 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
547 nextHop = ofc.getNodeConnectorId().getValue();
551 portNum = getOfPortNum(ofc.getNodeConnectorId());
552 } catch (NumberFormatException ex) {
553 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
557 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
562 applyActions.add(setdEPG);
563 applyActions.add(setdCG);
564 applyActions.add(setNextHop);
565 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
566 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
568 instructions.add(applyActionsIns);
570 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
571 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
573 instructions.add(gotoTable);
575 FlowId flowid = new FlowId(new StringBuilder().append(epFwdCtxOrds.getBdId())
577 .append(ep.getMacAddress().getValue())
581 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
582 addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
583 FlowBuilder flowb = base().setId(flowid)
584 .setPriority(Integer.valueOf(50))
585 .setMatch(mb.build())
586 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
587 return flowb.build();
590 private void syncEP(FlowMap flowMap, NodeId nodeId, PolicyInfo policyInfo, Endpoint srcEp, Endpoint destEp)
593 // TODO: Conditions messed up, but for now, send policyInfo until this
595 EndpointFwdCtxOrdinals destEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, destEp);
596 EndpointFwdCtxOrdinals srcEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
598 if (destEp.getTenant() == null || (destEp.getEndpointGroup() == null && destEp.getEndpointGroups() == null)) {
599 LOG.trace("Didn't process endpoint due to either tenant, or EPG(s) being null", destEp.getKey());
602 OfOverlayContext ofc = destEp.getAugmentation(OfOverlayContext.class);
604 // ////////////////////////////////////////////////////////////////////////////////////////
606 * NOT HANDLING EXTERNALS TODO: alagalah Li: External Gateway
607 * functionality needed here.
609 if (LocationType.External.equals(ofc.getLocationType())) {
610 // XXX - TODO - perform NAT and send to the external network
611 // TODO: Use case neutron gateway interface
612 LOG.warn("External endpoints not yet supported");
617 * Only care about subnets for L3, but fetch them before loop. We need
618 * the local subnets for setting SRC MAC for routing. All Routing is now
619 * done locally! YAY! Instead of being shovelled L2 style across network
622 List<Subnet> localSubnets = getLocalSubnets(nodeId);
623 if (localSubnets == null) {
624 LOG.error("No subnets could be found locally for node: {}", nodeId);
628 if (Objects.equals(ofc.getNodeId(), nodeId)) {
629 // this is a local endpoint; send to the approppriate local
632 if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
633 flowMap.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(destEp, destEpFwdCtxOrds, ofc));
635 // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
636 // The Endpoint conflation must end!
637 if (destEp.getL3Address() == null) {
638 LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", destEp.getKey());
642 for (L3Address l3a : destEp.getL3Address()) {
643 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
644 LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
645 destEp.getL3Address());
648 for (Subnet localSubnet : localSubnets) {
649 Flow flow = createLocalL3RoutedFlow(destEp, l3a, destEpFwdCtxOrds, ofc, localSubnet);
651 flowMap.writeFlow(nodeId, TABLE_ID, flow);
653 LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
654 localSubnet.getIpPrefix().getValue());
660 // this endpoint is on a different switch; send to the
661 // appropriate tunnel
662 if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
663 Flow remoteL2Flow = createRemoteL2Flow(destEp, nodeId, srcEpFwdCtxOrds, destEpFwdCtxOrds, ofc);
664 if (remoteL2Flow != null) {
665 flowMap.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
668 LOG.trace("DestinationMapper: RemoteL2Flow: not created, in different BDs src: {} dst: {}",
669 srcEpFwdCtxOrds.getBdId(), destEpFwdCtxOrds.getBdId());
672 // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
673 // The Endpoint conflation must end!
674 if (destEp.getL3Address() == null) {
675 LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", destEp.getKey());
678 for (L3Address l3a : destEp.getL3Address()) {
679 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
680 LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
681 destEp.getL3Address());
684 for (Subnet localSubnet : localSubnets) {
685 Flow remoteL3Flow = createRemoteL3RoutedFlow(destEp, l3a, nodeId, srcEpFwdCtxOrds,
686 destEpFwdCtxOrds, ofc, localSubnet);
687 if (remoteL3Flow != null) {
688 flowMap.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
690 LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
691 localSubnet.getIpPrefix().getValue());
703 * ################################## DestMapper Flow methods
704 * ##################################
706 private Flow createLocalL3RoutedFlow(Endpoint destEp, L3Address destL3Address, EndpointFwdCtxOrdinals epFwdCtxOrds,
707 OfOverlayContext ofc, Subnet srcSubnet) {
709 // TODO Li alagalah - refactor common code but keep simple method
711 Subnet destSubnet = null;
712 HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
713 if (subnets == null) {
714 LOG.trace("No subnets in tenant {}", destEp.getTenant());
717 NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
718 for (Subnet subnet : subnets) {
719 // TODO Li alagalah add IPv6 support
720 if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
725 if (destSubnet == null) {
726 LOG.trace("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
730 if (destSubnet.getVirtualRouterIp() == null) {
731 LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
732 destL3Address.getKey());
736 if (srcSubnet.getVirtualRouterIp() == null) {
737 LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
740 L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
741 if (destL3c == null || destL3c.getId() == null) {
742 LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
745 L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
746 if (srcL3c == null || srcL3c.getId() == null) {
747 LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
751 if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
752 LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
753 .getValue(), destL3c.getId().getValue());
757 MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
758 MacAddress epDestMac = destEp.getMacAddress();
759 MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
761 if (srcSubnet.getId().getValue().equals(destSubnet.getId().getValue())) {
762 // This is our final destination, so match on actual EP mac.
763 matcherMac = epDestMac;
766 ArrayList<Instruction> l3instructions = new ArrayList<>();
767 List<Action> applyActions = new ArrayList<>();
768 List<Action> l3ApplyActions = new ArrayList<>();
772 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
773 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
778 nextHop = ofc.getNodeConnectorId().getValue();
782 portNum = getOfPortNum(ofc.getNodeConnectorId());
783 } catch (NumberFormatException ex) {
784 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
788 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
791 // Lets not re-write the srcMac if its local.
792 if (!(matcherMac.getValue().equals(epDestMac.getValue()))) {
793 Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
794 l3ApplyActions.add(setDlSrc);
797 Action setDlDst = setDlDstAction(epDestMac);
798 l3ApplyActions.add(setDlDst);
800 Action decTtl = decNwTtlAction();
801 l3ApplyActions.add(decTtl);
804 applyActions.add(setdEPG);
805 applyActions.add(setdCG);
806 applyActions.add(setNextHop);
808 applyActions.addAll(l3ApplyActions);
809 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
810 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
813 l3instructions.add(applyActionsIns);
814 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
815 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
817 l3instructions.add(gotoTable);
818 Layer3Match m = null;
819 Long etherType = null;
821 if (destL3Address.getIpAddress().getIpv4Address() != null) {
822 ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
824 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
825 } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
826 ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
828 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
830 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
834 FlowId flowid = new FlowId(new StringBuilder().append(Integer.toString(epFwdCtxOrds.getL3Id()))
838 .append(Integer.toString(epFwdCtxOrds.getEpgId()))
840 .append(Integer.toString(epFwdCtxOrds.getCgId()))
844 .append(destSubnetGatewayMac)
848 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
850 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(epFwdCtxOrds.getL3Id())));
851 FlowBuilder flowb = base().setId(flowid)
852 .setPriority(Integer.valueOf(132))
853 .setMatch(mb.build())
854 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
855 return flowb.build();
858 private Flow createRemoteL2Flow(Endpoint ep, NodeId nodeId, EndpointFwdCtxOrdinals srcEpFwdCtxOrds,
859 EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc) {
861 // TODO Li alagalah - refactor common code but keep simple method
863 // this endpoint is on a different switch; send to the
864 // appropriate tunnel
866 ArrayList<Instruction> instructions = new ArrayList<>();
867 List<Action> applyActions = new ArrayList<>();
871 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
872 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
876 // BEGIN TUNNEL HANDLING
877 IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
878 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
879 if (tunDst == null) {
880 LOG.warn("Failed to get Tunnel IP for NodeId {} with EP {}", nodeId, ep);
883 if (tunPort == null) {
884 LOG.warn("Failed to get Tunnel Port for NodeId {} with EP {}", nodeId, ep);
890 if (tunDst.getIpv4Address() != null) {
891 nextHop = tunDst.getIpv4Address().getValue();
892 tundstAction = nxLoadTunIPv4Action(nextHop, false);
893 } else if (tunDst.getIpv6Address() != null) {
894 // nextHop = tunDst.getIpv6Address().getValue();
895 LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
899 // this shouldn't happen
900 LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
906 portNum = getOfPortNum(tunPort);
907 } catch (NumberFormatException ex) {
908 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
912 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
913 applyActions.add(tundstAction);
917 applyActions.add(setdEPG);
918 applyActions.add(setdCG);
919 applyActions.add(setNextHop);
920 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
921 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
923 instructions.add(applyActionsIns);
925 applyActionsIns = new InstructionBuilder().setOrder(order++)
926 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
929 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
930 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
932 instructions.add(gotoTable);
934 FlowId flowid = new FlowId(new StringBuilder().append(destEpFwdCtxOrds.getBdId())
936 .append(ep.getMacAddress().getValue())
938 .append(srcEpFwdCtxOrds.getBdId())
942 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
943 addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(destEpFwdCtxOrds.getBdId())));
944 FlowBuilder flowb = base().setId(flowid)
945 .setPriority(Integer.valueOf(50))
946 .setMatch(mb.build())
947 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
949 return flowb.build();
952 private Flow createRemoteL3RoutedFlow(Endpoint destEp, L3Address destL3Address, NodeId nodeId,
953 EndpointFwdCtxOrdinals srcEpFwdCtxOrds, EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc,
956 // TODO Li alagalah - refactor common code but keep simple method
958 // this endpoint is on a different switch; send to the
959 // appropriate tunnel
960 Subnet destSubnet = null;
961 HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
962 if (subnets == null) {
963 LOG.trace("No subnets in tenant {}", destEp.getTenant());
966 NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
967 for (Subnet subnet : subnets) {
968 // TODO Li alagalah add IPv6 support
969 if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
974 if (destSubnet == null) {
975 LOG.info("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
979 if (destSubnet.getVirtualRouterIp() == null) {
980 LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
981 destL3Address.getKey());
985 if (srcSubnet.getVirtualRouterIp() == null) {
986 LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
989 L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
990 if (destL3c == null || destL3c.getId() == null) {
991 LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
994 L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
995 if (srcL3c == null || srcL3c.getId() == null) {
996 LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
1000 if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
1001 LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
1002 .getValue(), destL3c.getId().getValue());
1006 MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
1007 MacAddress epDestMac = destEp.getMacAddress();
1008 MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
1010 ArrayList<Instruction> l3instructions = new ArrayList<>();
1011 List<Action> applyActions = new ArrayList<>();
1012 List<Action> l3ApplyActions = new ArrayList<>();
1016 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
1017 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
1021 // BEGIN TUNNEL HANDLING
1022 IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
1023 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
1024 if (tunDst == null) {
1025 LOG.warn("Failed to get Tunnel IP for NodeId {} with L3Address {}", nodeId, destL3Address);
1028 if (tunPort == null) {
1029 LOG.warn("Failed to get Tunnel port for NodeId {} with L3Address {}", nodeId, destL3Address);
1033 Action tundstAction;
1035 if (tunDst.getIpv4Address() != null) {
1036 nextHop = tunDst.getIpv4Address().getValue();
1037 tundstAction = nxLoadTunIPv4Action(nextHop, false);
1038 } else if (tunDst.getIpv6Address() != null) {
1039 // nextHop = tunDst.getIpv6Address().getValue();
1040 LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
1044 // this shouldn't happen
1045 LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
1051 portNum = getOfPortNum(tunPort);
1052 } catch (NumberFormatException ex) {
1053 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
1057 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
1058 applyActions.add(tundstAction);
1062 applyActions.add(setdEPG);
1063 applyActions.add(setdCG);
1064 applyActions.add(setNextHop);
1066 Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
1067 l3ApplyActions.add(setDlSrc);
1069 Action setDlDst = setDlDstAction(epDestMac);
1070 l3ApplyActions.add(setDlDst);
1072 Action decTtl = decNwTtlAction();
1073 l3ApplyActions.add(decTtl);
1075 applyActions.addAll(l3ApplyActions);
1076 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
1077 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
1080 l3instructions.add(applyActionsIns);
1081 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
1082 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
1084 l3instructions.add(gotoTable);
1085 Layer3Match m = null;
1086 Long etherType = null;
1088 if (destL3Address.getIpAddress().getIpv4Address() != null) {
1089 ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
1091 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
1092 } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
1093 ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
1095 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
1097 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
1101 FlowId flowid = new FlowId(new StringBuilder().append(Integer.toString(destEpFwdCtxOrds.getL3Id()))
1107 .append(destSubnetGatewayMac)
1109 .append(srcEpFwdCtxOrds.getL3Id())
1113 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
1115 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(destEpFwdCtxOrds.getL3Id())));
1117 FlowBuilder flowb = base().setId(flowid)
1118 .setPriority(Integer.valueOf(132))
1119 .setMatch(mb.build())
1120 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
1121 return flowb.build();
1124 private NetworkDomainId getEPNetworkContainment(Endpoint endpoint) {
1125 if (endpoint.getNetworkContainment() != null) {
1126 return endpoint.getNetworkContainment();
1129 * TODO: Be alagalah: Endpoint Refactor: This should be set on input
1130 * which we can't do because of the backwards way endpoints were
1133 return ctx.getPolicyResolver()
1134 .getTenant(endpoint.getTenant())
1135 .getEndpointGroup(endpoint.getEndpointGroup())
1136 .getNetworkDomain();
1140 private HashSet<Subnet> getSubnets(final TenantId tenantId) {
1142 // if (subnetsByTenant.get(tenantId) != null) {
1143 // return subnetsByTenant.get(tenantId);
1146 if (ctx.getDataBroker() == null) {
1150 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
1151 InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
1152 Optional<Tenant> tenantInfo;
1154 tenantInfo = t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
1155 } catch (Exception e) {
1156 LOG.error("Could not read Tenant {}", tenantId, e);
1160 HashSet<Subnet> subnets = new HashSet<Subnet>();
1162 if (!tenantInfo.isPresent()) {
1163 LOG.warn("Tenant {} not found", tenantId);
1167 subnets.addAll(tenantInfo.get().getSubnet());
1168 // subnetsByTenant.put(tenantId, subnets);
1172 // Need a method to get subnets for EPs attached to the node locally
1173 // to set the source Mac address for the router interface.
1174 private List<Subnet> getLocalSubnets(NodeId nodeId) {
1175 Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
1177 List<Subnet> localSubnets = new ArrayList<Subnet>();
1179 for (Endpoint endpoint : endpointsForNode) {
1180 HashSet<Subnet> subnets = getSubnets(endpoint.getTenant());
1181 if (subnets == null) {
1182 LOG.error("No local subnets.");
1185 NetworkDomainId epNetworkContainment = getEPNetworkContainment(endpoint);
1186 for (Subnet subnet : subnets) {
1187 if (epNetworkContainment.getValue().equals(subnet.getId().getValue())) {
1188 localSubnets.add(subnet);
1192 return localSubnets;
1195 static byte[] bytesFromHexString(String values) {
1197 if (values != null) {
1200 String[] octets = target.split(":");
1202 byte[] ret = new byte[octets.length];
1203 for (int i = 0; i < octets.length; i++) {
1204 ret[i] = Integer.valueOf(octets[i], 16).byteValue();