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 com.google.common.base.Optional;
12 import com.google.common.base.Strings;
13 import com.google.common.collect.HashMultimap;
14 import com.google.common.collect.SetMultimap;
15 import com.google.common.collect.Sets;
16 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
19 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
20 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
21 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
22 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
23 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
24 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
25 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
26 import org.opendaylight.groupbasedpolicy.resolver.TenantUtils;
27 import org.opendaylight.groupbasedpolicy.util.IidFactory;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3Gateways;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
78 import java.math.BigInteger;
79 import java.util.ArrayList;
80 import java.util.Collection;
81 import java.util.Collections;
82 import java.util.HashMap;
83 import java.util.HashSet;
84 import java.util.List;
86 import java.util.Map.Entry;
87 import java.util.Objects;
90 import static com.google.common.base.Preconditions.checkNotNull;
91 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
92 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
93 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
94 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
95 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
96 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
97 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
98 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
99 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
100 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
101 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
102 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
103 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
104 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
105 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
106 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
107 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
108 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
109 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
110 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
111 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
112 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
113 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
114 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
115 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
118 * Manage the table that maps the destination address to the next hop for the
119 * path as well as applies any relevant routing transformations.
121 public class DestinationMapper extends FlowTable {
123 protected static final Logger LOG = LoggerFactory.getLogger(DestinationMapper.class);
125 // TODO Li alagalah: Improve UT coverage for this class.
127 // TODO Li alagalah: Use EndpointL3 for L3 flows, Endpoint for L2 flows
128 // This ensures we have the appropriate network-containment'
130 public static short TABLE_ID;
132 * This is the MAC address of the magical router in the sky
134 public static final MacAddress ROUTER_MAC = new MacAddress("88:f0:31:b5:12:b5");
135 public static final MacAddress MULTICAST_MAC = new MacAddress("01:00:00:00:00:00");
136 public static final Integer BASE_L3_PRIORITY = 100;
138 public DestinationMapper(OfContext ctx, short tableId) {
140 this.TABLE_ID = tableId;
143 Map<TenantId, HashSet<Subnet>> subnetsByTenant = new HashMap<TenantId, HashSet<Subnet>>();
146 public short getTableId() {
151 public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
153 TenantId currentTenant = null;
155 flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
157 SetMultimap<EpKey, EpKey> visitedEps = HashMultimap.create();
158 Set<EndpointFwdCtxOrdinals> epOrdSet = new HashSet<>();
160 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
161 Set<EndpointGroupId> srcEpgIds = new HashSet<>();
162 if (srcEp.getEndpointGroup() != null)
163 srcEpgIds.add(srcEp.getEndpointGroup());
164 if (srcEp.getEndpointGroups() != null)
165 srcEpgIds.addAll(srcEp.getEndpointGroups());
167 for (EndpointGroupId epgId : srcEpgIds) {
168 EgKey epg = new EgKey(srcEp.getTenant(), epgId);
169 Set<EgKey> peers = Sets.union(Collections.singleton(epg), policyInfo.getPeers(epg));
170 for (EgKey peer : peers) {
171 for (Endpoint peerEp : ctx.getEndpointManager().getEndpointsForGroup(peer)) {
172 currentTenant = peerEp.getTenant();
173 subnetsByTenant.put(currentTenant, getSubnets(currentTenant));
174 EpKey srcEpKey = new EpKey(srcEp.getL2Context(), srcEp.getMacAddress());
175 EpKey peerEpKey = new EpKey(peerEp.getL2Context(), peerEp.getMacAddress());
177 if (visitedEps.get(srcEpKey) != null && visitedEps.get(srcEpKey).contains(peerEpKey)) {
180 syncEP(flowMap, nodeId, policyInfo, srcEp, peerEp);
181 visitedEps.put(srcEpKey, peerEpKey);
183 // Process subnets and flood-domains for epPeer
184 EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo,
186 if (epOrds == null) {
187 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", peerEp);
191 epOrdSet.add(epOrds);
197 for (Entry<TenantId, HashSet<Subnet>> subnetEntry : subnetsByTenant.entrySet()) {
198 if (subnetEntry.getValue() == null) {
199 LOG.trace("Tenant: {} has empty subnet entry.", subnetEntry.getKey());
202 currentTenant = subnetEntry.getKey();
203 for (Subnet sn : subnetEntry.getValue()) {
204 L3Context l3c = getL3ContextForSubnet(currentTenant, sn);
205 Flow arpFlow = createRouterArpFlow(currentTenant, nodeId, sn,
206 OrdinalFactory.getContextOrdinal(currentTenant, l3c.getId()));
207 if (arpFlow != null) {
208 flowMap.writeFlow(nodeId, TABLE_ID, arpFlow);
211 "Gateway ARP flow is not created, because virtual router IP has not been set for subnet {} .",
212 sn.getIpPrefix().getValue());
217 // Write broadcast flows per flood domain.
218 for (EndpointFwdCtxOrdinals epOrd : epOrdSet) {
219 if (groupExists(nodeId, epOrd.getFdId())) {
220 flowMap.writeFlow(nodeId, TABLE_ID, createBroadcastFlow(epOrd));
224 // L3 Prefix Endpoint handling
225 Collection<EndpointL3Prefix> prefixEps = ctx.getEndpointManager().getEndpointsL3PrefixForTenant(currentTenant);
226 if (prefixEps != null) {
227 LOG.trace("DestinationMapper - Processing L3PrefixEndpoints");
228 for (EndpointL3Prefix prefixEp : prefixEps) {
229 List<Subnet> localSubnets = getLocalSubnets(nodeId);
230 if (localSubnets == null) {
233 for (Subnet localSubnet: localSubnets) {
234 Flow prefixFlow = createL3PrefixFlow(prefixEp, policyInfo, nodeId, localSubnet);
235 if (prefixFlow != null) {
236 flowMap.writeFlow(nodeId, TABLE_ID, prefixFlow);
237 LOG.trace("Wrote L3Prefix flow");
244 // set up next-hop destinations for all the endpoints in the endpoint
247 private Flow createL3PrefixFlow(EndpointL3Prefix prefixEp, PolicyInfo policyInfo, NodeId nodeId, Subnet subnet) throws Exception {
249 * Priority: 100+lengthprefix
250 * Match: prefix, l3c, "mac address of router" ?
252 * - set Reg2, Reg3 for L3Ep by L2Ep ?
254 * - Reg7: use switch location external port else punt for now
256 * - Reg7: grab L2Ep from L3Ep and use its location info
257 * - goto_table: POLENF (will check there for external on EP)
260 ReadOnlyTransaction rTx = ctx.getDataBroker().newReadOnlyTransaction();
261 // TODO Bug #3440 Target: Be - should support for more than first gateway.
262 EndpointL3Gateways l3Gateway = prefixEp.getEndpointL3Gateways().get(0);
263 Optional<EndpointL3> optL3Ep = readFromDs(LogicalDatastoreType.OPERATIONAL,
264 IidFactory.l3EndpointIid(l3Gateway.getL3Context(), l3Gateway.getIpAddress()), rTx);
265 if (!optL3Ep.isPresent()) {
266 LOG.error("createL3PrefixFlow - L3Endpoint gateway {} for L3Prefix {} not found.", l3Gateway, prefixEp);
269 EndpointL3 l3Ep = optL3Ep.get();
270 if (l3Ep.getL2Context() == null || l3Ep.getMacAddress() == null) {
271 LOG.debug("L3 endpoint representing L3 gateway does not contain L2-context or MAC address. {}", l3Ep);
274 Optional<Endpoint> optL2Ep = readFromDs(LogicalDatastoreType.OPERATIONAL,
275 IidFactory.endpointIid(l3Ep.getL2Context(), l3Ep.getMacAddress()), rTx);
276 if (!optL2Ep.isPresent()) {
277 LOG.error("createL3PrefixFlow - L2Endpoint for L3Gateway {} not found.", l3Ep);
280 Endpoint l2Ep = optL2Ep.get();
281 EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, l2Ep);
282 if (epFwdCtxOrds == null) {
283 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", l2Ep);
287 NetworkDomainId epNetworkContainment = getEPNetworkContainment(l2Ep);
289 MacAddress epDestMac = l2Ep.getMacAddress();
290 MacAddress destSubnetGatewayMac = l2Ep.getMacAddress();
291 L3Context destL3c = getL3ContextForSubnet(prefixEp.getTenant(), subnet);
292 if (destL3c == null || destL3c.getId() == null) {
293 LOG.error("No L3 Context found associated with subnet {}", subnet.getId());
297 MacAddress matcherMac = routerPortMac(destL3c, subnet.getVirtualRouterIp());
299 ArrayList<Instruction> l3instructions = new ArrayList<>();
300 List<Action> applyActions = new ArrayList<>();
301 List<Action> l3ApplyActions = new ArrayList<>();
305 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
306 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
310 OfOverlayContext ofc = l2Ep.getAugmentation(OfOverlayContext.class);
311 LocationType location;
313 if (ofc != null && ofc.getLocationType() != null) {
314 location = ofc.getLocationType();
315 } else if (ofc != null) {
316 // Augmentation, but using default location
317 location = LocationType.Internal;
319 LOG.info("createL3PrefixFlow - Endpoint {} had no augmentation.", l2Ep);
325 if (location.equals(LocationType.Internal)) {
326 checkNotNull(ofc.getNodeConnectorId());
327 nextHop = ofc.getNodeConnectorId().getValue();
329 portNum = getOfPortNum(ofc.getNodeConnectorId());
330 } catch (NumberFormatException ex) {
331 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
337 Set<NodeConnectorId> externalPorts = ctx.getSwitchManager().getExternalPorts(nodeId);
338 checkNotNull(externalPorts);
339 for (NodeConnectorId externalPort : externalPorts) {
340 // TODO Bug #3440 Target: Be - should support for more than first external port.
341 //TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
342 nextHop = externalPort.getValue();
344 portNum = getOfPortNum(externalPort);
345 } catch (NumberFormatException ex) {
346 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
353 if (Strings.isNullOrEmpty(nextHop)
355 LOG.error("createL3Prefix - Cannot find nodeConnectorId for {} for Prefix: ", l2Ep, prefixEp);
358 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
360 Action setDlDst = setDlDstAction(epDestMac);
361 l3ApplyActions.add(setDlDst);
363 Action decTtl = decNwTtlAction();
364 l3ApplyActions.add(decTtl);
367 applyActions.add(setdEPG);
368 applyActions.add(setdCG);
369 applyActions.add(setNextHop);
371 applyActions.addAll(l3ApplyActions);
372 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
373 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
376 l3instructions.add(applyActionsIns);
377 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
378 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
380 l3instructions.add(gotoTable);
382 Layer3Match m = null;
383 Long etherType = null;
385 Integer prefixLength=0;
386 if (prefixEp.getIpPrefix().getIpv4Prefix() != null) {
387 ikey = prefixEp.getIpPrefix().getIpv4Prefix().getValue();
389 prefixLength=Integer.valueOf(prefixEp.getIpPrefix().getIpv4Prefix().getValue().split("/")[1]);
390 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
391 } else if (prefixEp.getIpPrefix().getIpv6Prefix() != null) {
392 ikey = prefixEp.getIpPrefix().getIpv6Prefix().getValue();
395 * This will result in flows with priority between 100-228, but since its matching on IPv6 prefix as well
396 * this shouldn't pose and issue, as the priority is more important within the address space of the matcher,
397 * even though technically flows are processed in priority order.
400 prefixLength=Integer.valueOf(prefixEp.getIpPrefix().getIpv6Prefix().getValue().split("/")[1]);
401 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
403 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", prefixEp);
407 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType));
408 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(epFwdCtxOrds.getL3Id())));
409 Match match = mb.build();
410 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L3prefix", match);
411 FlowBuilder flowb = base().setId(flowid)
412 .setPriority(Integer.valueOf(BASE_L3_PRIORITY+prefixLength))
414 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
415 return flowb.build();
418 private Flow createBroadcastFlow(EndpointFwdCtxOrdinals epOrd) {
419 MatchBuilder mb = new MatchBuilder()
420 .setEthernetMatch(new EthernetMatchBuilder()
421 .setEthernetDestination(new EthernetDestinationBuilder().
422 setAddress(MULTICAST_MAC)
423 .setMask(MULTICAST_MAC).build())
425 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(epOrd.getFdId())));
427 Match match = mb.build();
428 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "broadcast", match);
429 FlowBuilder flowb = base().setPriority(Integer.valueOf(140))
433 instructions(applyActionIns(nxLoadTunIdAction(BigInteger.valueOf(epOrd.getFdId()), false),
434 groupAction(Long.valueOf(epOrd.getFdId())))));
436 return flowb.build();
439 private boolean groupExists(NodeId nodeId, Integer fdId) throws Exception {
440 // Fetch existing GroupTables
441 if (ctx.getDataBroker() == null) {
445 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
446 InstanceIdentifier<Node> niid = createNodePath(nodeId);
447 Optional<Node> r = t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
450 FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
454 if (fcn.getGroup() != null) {
455 for (Group g : fcn.getGroup()) {
456 if (g.getGroupId().getValue().equals(Long.valueOf(fdId))) { // Group
465 private MacAddress routerPortMac(L3Context l3c, IpAddress ipAddress) {
467 if (ctx.getDataBroker() == null) {
471 MacAddress defaultMacAddress = ROUTER_MAC;
473 EndpointL3Key l3Key = new EndpointL3Key(ipAddress, l3c.getId());
474 InstanceIdentifier<EndpointL3> endpointsIid = InstanceIdentifier.builder(Endpoints.class)
475 .child(EndpointL3.class, l3Key)
477 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
479 Optional<EndpointL3> r;
481 r = t.read(LogicalDatastoreType.OPERATIONAL, endpointsIid).get();
483 return defaultMacAddress;
484 EndpointL3 epL3 = r.get();
485 if (epL3.getMacAddress() == null) {
486 return defaultMacAddress;
488 return epL3.getMacAddress();
490 } catch (Exception e) {
491 LOG.error("Error reading EndpointL3 {}.{}", l3c, ipAddress, e);
496 private L3Context getL3ContextForSubnet(TenantId tenantId, Subnet sn) {
497 IndexedTenant indexedTenant = ctx.getPolicyResolver().getTenant(tenantId);
498 if (indexedTenant == null) {
499 LOG.debug("Tenant {} is null, cannot get L3 context", tenantId);
502 L3Context l3c = indexedTenant.resolveL3Context(sn.getId());
506 private Flow createRouterArpFlow(TenantId tenantId, NodeId nodeId, Subnet sn, int l3Id) {
507 if (sn == null || sn.getVirtualRouterIp() == null) {
508 LOG.trace("Didn't create routerArpFlow since either subnet or subnet virtual router was null");
512 * TODO: Li alagalah: This should be new Yang "gateways" list as well,
513 * that expresses the gateway and prefixes it is interface for. Should
514 * also check for external.
516 if (sn.getVirtualRouterIp().getIpv4Address() != null) {
517 String ikey = sn.getVirtualRouterIp().getIpv4Address().getValue();
519 L3Context l3c = getL3ContextForSubnet(tenantId, sn);
521 LOG.error("No L3 Context found associated with subnet {}", sn.getId());
524 MacAddress routerMac = routerPortMac(l3c, sn.getVirtualRouterIp());
525 if (routerMac == null) {
529 BigInteger intRouterMac = new BigInteger(1, bytesFromHexString(routerMac.getValue()));
531 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, null, ARP)).setLayer3Match(
532 new ArpMatchBuilder().setArpOp(Integer.valueOf(1))
533 .setArpTargetTransportAddress(new Ipv4Prefix(ikey + "/32"))
535 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(l3Id)));
537 Match match = mb.build();
538 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "routerarp", match);
539 FlowBuilder flowb = base().setPriority(150)
543 instructions(applyActionIns(nxMoveEthSrcToEthDstAction(), setDlSrcAction(routerMac),
544 nxLoadArpOpAction(BigInteger.valueOf(2L)), nxMoveArpShaToArpThaAction(),
545 nxLoadArpShaAction(intRouterMac), nxMoveArpSpaToArpTpaAction(),
546 nxLoadArpSpaAction(ikey), outputAction(new NodeConnectorId(nodeId.getValue()
548 return flowb.build();
550 LOG.warn("IPv6 virtual router {} for subnet {} not supported", sn.getVirtualRouterIp(), sn.getId()
557 private Flow createLocalL2Flow(Endpoint ep, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
559 // TODO Li alagalah - refactor common code but keep simple method
560 ArrayList<Instruction> instructions = new ArrayList<>();
561 List<Action> applyActions = new ArrayList<>();
565 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
566 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
571 nextHop = ofc.getNodeConnectorId().getValue();
575 portNum = getOfPortNum(ofc.getNodeConnectorId());
576 } catch (NumberFormatException ex) {
577 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
581 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
586 applyActions.add(setdEPG);
587 applyActions.add(setdCG);
588 applyActions.add(setNextHop);
589 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
590 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
592 instructions.add(applyActionsIns);
594 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
595 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
597 instructions.add(gotoTable);
599 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
600 addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
601 Match match = mb.build();
602 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "localL2", match);
603 FlowBuilder flowb = base().setId(flowid)
604 .setPriority(Integer.valueOf(50))
606 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
607 return flowb.build();
610 private void syncEP(FlowMap flowMap, NodeId nodeId, PolicyInfo policyInfo, Endpoint srcEp, Endpoint destEp)
613 if (ctx.getPolicyResolver().getTenant(srcEp.getTenant()) == null
614 || ctx.getPolicyResolver().getTenant(destEp.getTenant()) == null) {
615 LOG.debug("Source or destination EP references empty tenant srcEp:{} destEp:{}", srcEp, destEp);
619 // TODO: Conditions messed up, but for now, send policyInfo until this
621 EndpointFwdCtxOrdinals destEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, destEp);
622 if (destEpFwdCtxOrds == null) {
623 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", destEp);
626 EndpointFwdCtxOrdinals srcEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
627 if (srcEpFwdCtxOrds == null) {
628 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
633 if (destEp.getTenant() == null || (destEp.getEndpointGroup() == null && destEp.getEndpointGroups() == null)) {
634 if (destEp.getTenant() == null) {
635 LOG.debug("Didn't process endpoint {} due to tenant being null", destEp.getKey());
637 LOG.debug("Didn't process endpoint {} due to EPG(s) being null", destEp.getKey());
641 OfOverlayContext ofc = destEp.getAugmentation(OfOverlayContext.class);
643 if (LocationType.External.equals(ofc.getLocationType())) {
644 LOG.error("syncEp(): External endpoints should not be seen here.");
649 * Only care about subnets for L3, but fetch them before loop. We need
650 * the local subnets for setting SRC MAC for routing. All Routing is now
651 * done locally! YAY! Instead of being shovelled L2 style across network
654 List<Subnet> localSubnets = getLocalSubnets(nodeId);
655 if (localSubnets == null) {
656 LOG.error("No subnets could be found locally for node: {}", nodeId);
660 if (Objects.equals(ofc.getNodeId(), nodeId)) {
661 // this is a local endpoint; send to the approppriate local
664 if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
665 flowMap.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(destEp, destEpFwdCtxOrds, ofc));
667 // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
668 // The Endpoint conflation must end!
669 if (destEp.getL3Address() == null) {
670 LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", destEp.getKey());
674 for (L3Address l3a : destEp.getL3Address()) {
675 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
676 LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
677 destEp.getL3Address());
680 for (Subnet localSubnet : localSubnets) {
681 Flow flow = createLocalL3RoutedFlow(destEp, l3a, destEpFwdCtxOrds, ofc, localSubnet);
683 flowMap.writeFlow(nodeId, TABLE_ID, flow);
685 LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
686 localSubnet.getIpPrefix().getValue());
692 // this endpoint is on a different switch; send to the
693 // appropriate tunnel
694 if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
695 Flow remoteL2Flow = createRemoteL2Flow(destEp, nodeId, srcEpFwdCtxOrds, destEpFwdCtxOrds, ofc);
696 if (remoteL2Flow != null) {
697 flowMap.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
700 LOG.trace("DestinationMapper: RemoteL2Flow: not created, in different BDs src: {} dst: {}",
701 srcEpFwdCtxOrds.getBdId(), destEpFwdCtxOrds.getBdId());
704 // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
705 // The Endpoint conflation must end!
706 if (destEp.getL3Address() == null) {
707 LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", destEp.getKey());
710 for (L3Address l3a : destEp.getL3Address()) {
711 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
712 LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
713 destEp.getL3Address());
716 for (Subnet localSubnet : localSubnets) {
717 Flow remoteL3Flow = createRemoteL3RoutedFlow(destEp, l3a, nodeId, srcEpFwdCtxOrds,
718 destEpFwdCtxOrds, ofc, localSubnet);
719 if (remoteL3Flow != null) {
720 flowMap.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
722 LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
723 localSubnet.getIpPrefix().getValue());
735 * ################################## DestMapper Flow methods
736 * ##################################
738 private Flow createLocalL3RoutedFlow(Endpoint destEp, L3Address destL3Address, EndpointFwdCtxOrdinals epFwdCtxOrds,
739 OfOverlayContext ofc, Subnet srcSubnet) {
741 // TODO Li alagalah - refactor common code but keep simple method
743 Subnet destSubnet = null;
744 HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
745 if (subnets == null) {
746 LOG.trace("No subnets in tenant {}", destEp.getTenant());
749 NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
750 for (Subnet subnet : subnets) {
751 // TODO Li alagalah add IPv6 support
752 if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
757 if (destSubnet == null) {
758 LOG.trace("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
762 if (destSubnet.getVirtualRouterIp() == null) {
763 LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
764 destL3Address.getKey());
768 if (srcSubnet.getVirtualRouterIp() == null) {
769 LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
772 L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
773 if (destL3c == null || destL3c.getId() == null) {
774 LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
777 L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
778 if (srcL3c == null || srcL3c.getId() == null) {
779 LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
783 if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
784 LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
785 .getValue(), destL3c.getId().getValue());
789 MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
790 MacAddress epDestMac = destEp.getMacAddress();
791 MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
793 if (srcSubnet.getId().getValue().equals(destSubnet.getId().getValue())) {
794 // This is our final destination, so match on actual EP mac.
795 matcherMac = epDestMac;
798 ArrayList<Instruction> l3instructions = new ArrayList<>();
799 List<Action> applyActions = new ArrayList<>();
800 List<Action> l3ApplyActions = new ArrayList<>();
804 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
805 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
810 nextHop = ofc.getNodeConnectorId().getValue();
814 portNum = getOfPortNum(ofc.getNodeConnectorId());
815 } catch (NumberFormatException ex) {
816 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
820 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
823 // Lets not re-write the srcMac if its local.
824 if (!(matcherMac.getValue().equals(epDestMac.getValue()))) {
825 Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
826 l3ApplyActions.add(setDlSrc);
829 Action setDlDst = setDlDstAction(epDestMac);
830 l3ApplyActions.add(setDlDst);
832 Action decTtl = decNwTtlAction();
833 l3ApplyActions.add(decTtl);
836 applyActions.add(setdEPG);
837 applyActions.add(setdCG);
838 applyActions.add(setNextHop);
840 applyActions.addAll(l3ApplyActions);
841 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
842 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
845 l3instructions.add(applyActionsIns);
846 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
847 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
849 l3instructions.add(gotoTable);
850 Layer3Match m = null;
851 Long etherType = null;
853 if (destL3Address.getIpAddress().getIpv4Address() != null) {
854 ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
856 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
857 } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
858 ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
860 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
862 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
866 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
868 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(epFwdCtxOrds.getL3Id())));
869 Match match = mb.build();
870 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "localL3", match);
871 FlowBuilder flowb = base().setId(flowid)
872 .setPriority(Integer.valueOf(132))
874 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
875 return flowb.build();
878 private Flow createRemoteL2Flow(Endpoint ep, NodeId nodeId, EndpointFwdCtxOrdinals srcEpFwdCtxOrds,
879 EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc) {
881 // TODO Li alagalah - refactor common code but keep simple method
883 // this endpoint is on a different switch; send to the
884 // appropriate tunnel
886 ArrayList<Instruction> instructions = new ArrayList<>();
887 List<Action> applyActions = new ArrayList<>();
891 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
892 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
896 // BEGIN TUNNEL HANDLING
897 IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
898 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
899 if (tunDst == null) {
900 LOG.warn("Failed to get Tunnel IP for NodeId {} with EP {}", nodeId, ep);
903 if (tunPort == null) {
904 LOG.warn("Failed to get Tunnel Port for NodeId {} with EP {}", nodeId, ep);
910 if (tunDst.getIpv4Address() != null) {
911 nextHop = tunDst.getIpv4Address().getValue();
912 tundstAction = nxLoadTunIPv4Action(nextHop, false);
913 } else if (tunDst.getIpv6Address() != null) {
914 // nextHop = tunDst.getIpv6Address().getValue();
915 LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
919 // this shouldn't happen
920 LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
926 portNum = getOfPortNum(tunPort);
927 } catch (NumberFormatException ex) {
928 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
932 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
933 applyActions.add(tundstAction);
937 applyActions.add(setdEPG);
938 applyActions.add(setdCG);
939 applyActions.add(setNextHop);
940 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
941 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
943 instructions.add(applyActionsIns);
945 applyActionsIns = new InstructionBuilder().setOrder(order++)
946 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
949 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
950 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
952 instructions.add(gotoTable);
954 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
955 addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(destEpFwdCtxOrds.getBdId())));
956 Match match = mb.build();
957 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "remoteL2", match);
958 FlowBuilder flowb = base().setId(flowid)
959 .setPriority(Integer.valueOf(50))
961 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
963 return flowb.build();
966 private Flow createRemoteL3RoutedFlow(Endpoint destEp, L3Address destL3Address, NodeId nodeId,
967 EndpointFwdCtxOrdinals srcEpFwdCtxOrds, EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc,
970 // TODO Li alagalah - refactor common code but keep simple method
972 // this endpoint is on a different switch; send to the
973 // appropriate tunnel
974 Subnet destSubnet = null;
975 HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
976 if (subnets == null) {
977 LOG.trace("No subnets in tenant {}", destEp.getTenant());
980 NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
981 for (Subnet subnet : subnets) {
982 // TODO Li alagalah add IPv6 support
983 if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
988 if (destSubnet == null) {
989 LOG.info("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
993 if (destSubnet.getVirtualRouterIp() == null) {
994 LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
995 destL3Address.getKey());
999 if (srcSubnet.getVirtualRouterIp() == null) {
1000 LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
1003 L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
1004 if (destL3c == null || destL3c.getId() == null) {
1005 LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
1008 L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
1009 if (srcL3c == null || srcL3c.getId() == null) {
1010 LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
1014 if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
1015 LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
1016 .getValue(), destL3c.getId().getValue());
1020 MacAddress matcherMac = routerPortMac(destL3c, srcSubnet.getVirtualRouterIp());
1021 MacAddress epDestMac = destEp.getMacAddress();
1022 MacAddress destSubnetGatewayMac = routerPortMac(destL3c, destSubnet.getVirtualRouterIp());
1023 if (srcSubnet.getId().getValue().equals(destSubnet.getId().getValue())) {
1024 // This is our final destination, so match on actual EP mac.
1025 matcherMac = epDestMac;
1027 ArrayList<Instruction> l3instructions = new ArrayList<>();
1028 List<Action> applyActions = new ArrayList<>();
1029 List<Action> l3ApplyActions = new ArrayList<>();
1033 Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(destEpFwdCtxOrds.getEpgId()));
1034 Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(destEpFwdCtxOrds.getCgId()));
1038 // BEGIN TUNNEL HANDLING
1039 IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class);
1040 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
1041 if (tunDst == null) {
1042 LOG.warn("Failed to get Tunnel IP for NodeId {} with L3Address {}", nodeId, destL3Address);
1045 if (tunPort == null) {
1046 LOG.warn("Failed to get Tunnel port for NodeId {} with L3Address {}", nodeId, destL3Address);
1050 Action tundstAction;
1052 if (tunDst.getIpv4Address() != null) {
1053 nextHop = tunDst.getIpv4Address().getValue();
1054 tundstAction = nxLoadTunIPv4Action(nextHop, false);
1055 } else if (tunDst.getIpv6Address() != null) {
1056 // nextHop = tunDst.getIpv6Address().getValue();
1057 LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
1061 // this shouldn't happen
1062 LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
1068 portNum = getOfPortNum(tunPort);
1069 } catch (NumberFormatException ex) {
1070 LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), ex);
1074 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
1075 applyActions.add(tundstAction);
1079 applyActions.add(setdEPG);
1080 applyActions.add(setdCG);
1081 applyActions.add(setNextHop);
1083 // Lets not re-write the srcMac if its local.
1084 if (!(matcherMac.getValue().equals(epDestMac.getValue()))) {
1085 Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
1086 l3ApplyActions.add(setDlSrc);
1089 Action setDlDst = setDlDstAction(epDestMac);
1090 l3ApplyActions.add(setDlDst);
1092 Action decTtl = decNwTtlAction();
1093 l3ApplyActions.add(decTtl);
1095 applyActions.addAll(l3ApplyActions);
1096 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
1097 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
1100 l3instructions.add(applyActionsIns);
1101 Instruction gotoTable = new InstructionBuilder().setOrder(order++)
1102 .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
1104 l3instructions.add(gotoTable);
1105 Layer3Match m = null;
1106 Long etherType = null;
1108 if (destL3Address.getIpAddress().getIpv4Address() != null) {
1109 ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
1111 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
1112 } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
1113 ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
1115 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
1117 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
1121 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
1123 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(destEpFwdCtxOrds.getL3Id())));
1124 Match match = mb.build();
1125 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "remoteL3", match);
1126 FlowBuilder flowb = base().setId(flowid)
1127 .setPriority(Integer.valueOf(132))
1129 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
1130 return flowb.build();
1133 private NetworkDomainId getEPNetworkContainment(Endpoint endpoint) {
1134 if (endpoint.getNetworkContainment() != null) {
1135 return endpoint.getNetworkContainment();
1138 * TODO: Be alagalah: Endpoint Refactor: This should be set on input
1139 * which we can't do because of the backwards way endpoints were
1142 return ctx.getPolicyResolver()
1143 .getTenant(endpoint.getTenant())
1144 .getEndpointGroup(endpoint.getEndpointGroup())
1145 .getNetworkDomain();
1149 private HashSet<Subnet> getSubnets(final TenantId tenantId) {
1151 // if (subnetsByTenant.get(tenantId) != null) {
1152 // return subnetsByTenant.get(tenantId);
1155 if (ctx.getDataBroker() == null) {
1159 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
1160 InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
1161 Optional<Tenant> tenantInfo;
1163 tenantInfo = t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
1164 } catch (Exception e) {
1165 LOG.error("Could not read Tenant {}", tenantId, e);
1169 HashSet<Subnet> subnets = new HashSet<Subnet>();
1171 if (!tenantInfo.isPresent()) {
1172 LOG.warn("Tenant {} not found", tenantId);
1176 subnets.addAll(tenantInfo.get().getSubnet());
1177 // subnetsByTenant.put(tenantId, subnets);
1181 // Need a method to get subnets for EPs attached to the node locally
1182 // to set the source Mac address for the router interface.
1183 private List<Subnet> getLocalSubnets(NodeId nodeId) {
1184 Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
1186 List<Subnet> localSubnets = new ArrayList<Subnet>();
1188 for (Endpoint endpoint : endpointsForNode) {
1189 HashSet<Subnet> subnets = getSubnets(endpoint.getTenant());
1190 if (subnets == null) {
1191 LOG.debug("No local subnets in tenant {} for EP {}.", endpoint.getTenant(), endpoint.getKey());
1194 NetworkDomainId epNetworkContainment = getEPNetworkContainment(endpoint);
1195 for (Subnet subnet : subnets) {
1196 if (epNetworkContainment.getValue().equals(subnet.getId().getValue())) {
1197 localSubnets.add(subnet);
1201 return localSubnets;
1204 static byte[] bytesFromHexString(String values) {
1206 if (values != null) {
1209 String[] octets = target.split(":");
1211 byte[] ret = new byte[octets.length];
1212 for (int i = 0; i < octets.length; i++) {
1213 ret[i] = Integer.valueOf(octets[i], 16).byteValue();