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 org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
26 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
27 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
28 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
29 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
30 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
31 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveRegTunIdAction;
32 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
33 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
34 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
36 import java.math.BigInteger;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Objects;
44 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
45 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
46 import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
47 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
48 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
49 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
50 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
51 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
52 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
88 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
92 import com.google.common.base.Optional;
93 import com.google.common.collect.HashMultimap;
94 import com.google.common.collect.Multimap;
95 import com.google.common.collect.Sets;
98 * Manage the table that maps the destination address to the next hop for the
99 * path as well as applies any relevant routing transformations.
102 public class DestinationMapper extends FlowTable {
103 protected static final Logger LOG =
104 LoggerFactory.getLogger(DestinationMapper.class);
106 //TODO Li alagalah: Improve UT coverage for this class.
108 //TODO Li alagalah: Use EndpointL3 for L3 flows, Endpoint for L2 flows
109 // This ensures we have the appropriate network-containment'
111 public static final short TABLE_ID = 2;
113 * This is the MAC address of the magical router in the sky
115 public static final MacAddress ROUTER_MAC =
116 new MacAddress("88:f0:31:b5:12:b5");
117 public static final MacAddress MULTICAST_MAC =
118 new MacAddress("01:00:00:00:00:00");
120 public DestinationMapper(OfContext ctx) {
125 public short getTableId() {
130 public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap)
133 flowMap.writeFlow(nodeId,TABLE_ID,dropFlow(Integer.valueOf(1), null));
135 Set<EpKey> visitedEps = new HashSet<>();
136 Multimap<Integer,Subnet> subnetsByL3c = HashMultimap.create();
137 Set<Integer> fdIds = new HashSet<>();
139 for (EgKey epg : ctx.getEndpointManager().getGroupsForNode(nodeId)) {
140 Set<EgKey> peers = Sets.union(Collections.singleton(epg),
141 policyInfo.getPeers(epg));
142 for (EgKey peer : peers) {
143 for(Endpoint epPeer : ctx.getEndpointManager().getEndpointsForGroup(peer)) {
144 syncEP(flowMap, nodeId, policyInfo, epPeer, visitedEps);
146 //Process subnets and flood-domains for epPeer
147 EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, epPeer);
149 subnetsByL3c.putAll(epOrds.getL3Id(),ctx.getPolicyResolver().getTenant(peer.getTenantId()).resolveSubnets(epOrds.getNetworkContainment()));
150 fdIds.add(epOrds.getFdId());
154 // Write subnet flows
155 for (Integer subnetKey : subnetsByL3c.keySet()) {
156 for(Subnet sn:subnetsByL3c.get(subnetKey)) {
157 flowMap.writeFlow(nodeId, TABLE_ID, createRouterArpFlow(nodeId, sn, subnetKey));
160 // Write broadcast flows per flood domain.
161 for (Integer fdId : fdIds) {
162 if (groupExists(nodeId, fdId)) {
163 flowMap.writeFlow(nodeId, TABLE_ID, createBroadcastFlow(fdId));
167 // set up next-hop destinations for all the endpoints in the endpoint
171 private Flow createBroadcastFlow(int fdId) {
172 FlowId flowId = new FlowId(new StringBuilder()
173 .append("broadcast|")
174 .append(fdId).toString());
175 MatchBuilder mb = new MatchBuilder()
176 .setEthernetMatch(new EthernetMatchBuilder()
177 .setEthernetDestination(new EthernetDestinationBuilder()
178 .setAddress(MULTICAST_MAC)
179 .setMask(MULTICAST_MAC)
182 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
184 FlowBuilder flowb = base()
185 .setPriority(Integer.valueOf(140))
187 .setMatch(mb.build())
188 .setInstructions(instructions(applyActionIns(nxMoveRegTunIdAction(NxmNxReg0.class, false),
189 groupAction(Long.valueOf(fdId)))));
190 return flowb.build();
195 private boolean groupExists(NodeId nodeId, Integer fdId) throws Exception {
196 // Fetch existing GroupTables
197 if(ctx.getDataBroker()==null) {
201 ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
202 InstanceIdentifier<Node> niid = createNodePath(nodeId);
204 t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
207 FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
211 if (fcn.getGroup() != null) {
212 for (Group g : fcn.getGroup()) {
213 if (g.getGroupId().getValue().equals(Long.valueOf(fdId))) { // Group
223 private Flow createRouterArpFlow(NodeId nodeId,
226 if (sn != null && sn.getVirtualRouterIp() != null) {
227 if (sn.getVirtualRouterIp().getIpv4Address() != null) {
228 String ikey = sn.getVirtualRouterIp().getIpv4Address().getValue();
229 FlowId flowId = new FlowId(new StringBuffer()
230 .append("routerarp|")
231 .append(sn.getId().getValue())
237 MatchBuilder mb = new MatchBuilder()
238 .setEthernetMatch(ethernetMatch(null, null, ARP))
239 .setLayer3Match(new ArpMatchBuilder()
240 .setArpOp(Integer.valueOf(1))
241 .setArpTargetTransportAddress(new Ipv4Prefix(ikey + "/32"))
243 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
244 Long.valueOf(l3Id)));
245 BigInteger routerMac =
246 new BigInteger(1, bytesFromHexString(ROUTER_MAC
248 FlowBuilder flowb = base()
251 .setMatch(mb.build())
252 .setInstructions(instructions(applyActionIns(nxMoveEthSrcToEthDstAction(),
253 setDlSrcAction(ROUTER_MAC),
254 nxLoadArpOpAction(BigInteger.valueOf(2L)),
255 nxMoveArpShaToArpThaAction(),
256 nxLoadArpShaAction(routerMac),
257 nxMoveArpSpaToArpTpaAction(),
258 nxLoadArpSpaAction(ikey),
259 outputAction(new NodeConnectorId(nodeId.getValue() + ":INPORT")))));
260 return flowb.build();
262 LOG.warn("IPv6 virtual router {} for subnet {} not supported",
263 sn.getVirtualRouterIp(), sn.getId().getValue());
270 private Flow createLocalL2Flow(Endpoint ep, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
272 //TODO Li alagalah - refactor common code but keep simple method
273 ArrayList<Instruction> instructions = new ArrayList<>();
274 List<Action> applyActions = new ArrayList<>();
278 Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
279 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
280 Action setdCG = nxLoadRegAction(NxmNxReg3.class,
281 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
288 nextHop = ofc.getNodeConnectorId().getValue();
292 portNum = getOfPortNum(ofc.getNodeConnectorId());
293 } catch (NumberFormatException ex) {
294 LOG.warn("Could not parse port number {}",
295 ofc.getNodeConnectorId(), ex);
299 setNextHop = nxLoadRegAction(NxmNxReg7.class,
300 BigInteger.valueOf(portNum));
305 applyActions.add(setdEPG);
306 applyActions.add(setdCG);
307 applyActions.add(setNextHop);
308 Instruction applyActionsIns = new InstructionBuilder()
310 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
312 instructions.add(applyActionsIns);
314 Instruction gotoTable = new InstructionBuilder()
316 .setInstruction(gotoTableIns((short) (getTableId() + 1)))
318 instructions.add(gotoTable);
321 FlowId flowid = new FlowId(new StringBuilder()
322 .append(epFwdCtxOrds.getBdId())
324 .append(ep.getMacAddress().getValue())
328 MatchBuilder mb = new MatchBuilder()
329 .setEthernetMatch(ethernetMatch(null,
332 addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
333 FlowBuilder flowb = base()
335 .setPriority(Integer.valueOf(50))
336 .setMatch(mb.build())
337 .setInstructions(new InstructionsBuilder()
338 .setInstruction(instructions)
340 return flowb.build();
344 private void syncEP(FlowMap flowMap,
345 NodeId nodeId, PolicyInfo policyInfo,
346 Endpoint epPeer, Set<EpKey> visitedEps)
349 EpKey epPeerKey = new EpKey(epPeer.getL2Context(),epPeer.getMacAddress());
351 if (visitedEps.contains(epPeerKey)) {
354 visitedEps.add(epPeerKey);
356 // TODO: Conditions messed up, but for now, send policyInfo until this is fixed.
357 EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, epPeer);
359 if (epPeer.getTenant() == null || (epPeer.getEndpointGroup() == null && epPeer.getEndpointGroups() == null))
361 OfOverlayContext ofc = epPeer.getAugmentation(OfOverlayContext.class);
365 //////////////////////////////////////////////////////////////////////////////////////////
367 * NOT HANDLING EXTERNALS
369 if (LocationType.External.equals(ofc.getLocationType())) {
370 // XXX - TODO - perform NAT and send to the external network
371 // TODO: Use case neutron gateway interface
372 LOG.warn("External endpoints not yet supported");
376 if (Objects.equals(ofc.getNodeId(), nodeId)) {
377 // this is a local endpoint; send to the approppriate local
380 flowMap.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(epPeer,epFwdCtxOrds,ofc));
382 if (epPeer.getL3Address() == null)
384 for (L3Address l3a : epPeer.getL3Address()) {
385 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
386 LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",epPeer.getL3Address().toString());
389 flowMap.writeFlow(nodeId, TABLE_ID, createLocalL3Flow(epPeer,l3a, epFwdCtxOrds,ofc));
393 // this endpoint is on a different switch; send to the
394 // appropriate tunnel
396 Flow remoteL2Flow = createRemoteL2Flow(epPeer, nodeId, epFwdCtxOrds, ofc);
397 if (remoteL2Flow != null) {
398 flowMap.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
401 if (epPeer.getL3Address() == null)
403 for (L3Address l3a : epPeer.getL3Address()) {
404 if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
405 LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",epPeer.getL3Address().toString());
408 Flow remoteL3Flow = createRemoteL3Flow(l3a, nodeId,epFwdCtxOrds, ofc);
409 if (remoteL3Flow != null) {
410 flowMap.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
422 /* ##################################
423 * DestMapper Flow methods
424 * ##################################
426 private Flow createLocalL3Flow(Endpoint ep,L3Address l3a, EndpointFwdCtxOrdinals epFwdCtxOrds,OfOverlayContext ofc) {
428 //TODO Li alagalah - refactor common code but keep simple method
430 ArrayList<Instruction> l3instructions = new ArrayList<>();
431 List<Action> applyActions = new ArrayList<>();
432 List<Action> l3ApplyActions = new ArrayList<>();
436 Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
437 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
438 Action setdCG = nxLoadRegAction(NxmNxReg3.class,
439 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
443 Action setDlSrc = setDlSrcAction(ROUTER_MAC);
444 Action decTtl = decNwTtlAction();
447 nextHop = ofc.getNodeConnectorId().getValue();
451 portNum = getOfPortNum(ofc.getNodeConnectorId());
452 } catch (NumberFormatException ex) {
453 LOG.warn("Could not parse port number {}",
454 ofc.getNodeConnectorId(), ex);
458 setNextHop = nxLoadRegAction(NxmNxReg7.class,
459 BigInteger.valueOf(portNum));
461 Action setDlDst = setDlDstAction(ep.getMacAddress());
462 l3ApplyActions.add(setDlDst);
465 l3ApplyActions.add(setDlSrc);
466 l3ApplyActions.add(decTtl);
468 applyActions.add(setdEPG);
469 applyActions.add(setdCG);
470 applyActions.add(setNextHop);
472 applyActions.addAll(l3ApplyActions);
473 Instruction applyActionsIns = new InstructionBuilder()
475 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
478 l3instructions.add(applyActionsIns);
479 Instruction gotoTable = new InstructionBuilder()
481 .setInstruction(gotoTableIns((short) (getTableId() + 1)))
483 l3instructions.add(gotoTable);
484 Layer3Match m = null;
485 Long etherType = null;
487 if (l3a.getIpAddress().getIpv4Address() != null) {
488 ikey = l3a.getIpAddress().getIpv4Address().getValue() + "/32";
490 m = new Ipv4MatchBuilder()
491 .setIpv4Destination(new Ipv4Prefix(ikey))
493 } else if (l3a.getIpAddress().getIpv6Address() != null) {
494 ikey = l3a.getIpAddress().getIpv6Address().getValue() + "/128";
496 m = new Ipv6MatchBuilder()
497 .setIpv6Destination(new Ipv6Prefix(ikey))
500 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.",l3a.toString());
504 FlowId flowid = new FlowId(new StringBuilder()
505 .append(Integer.toString(epFwdCtxOrds.getL3Id()))
509 .append(Integer.toString(epFwdCtxOrds.getEpgId()))
511 .append(Integer.toString(epFwdCtxOrds.getCgId()))
515 MatchBuilder mb = new MatchBuilder()
516 .setEthernetMatch(ethernetMatch(null,
520 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
521 Long.valueOf(epFwdCtxOrds.getL3Id())));
522 FlowBuilder flowb = base()
524 .setPriority(Integer.valueOf(132))
525 .setMatch(mb.build())
526 .setInstructions(new InstructionsBuilder()
527 .setInstruction(l3instructions)
529 return flowb.build();
532 private Flow createRemoteL2Flow(Endpoint ep, NodeId nodeId, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
534 //TODO Li alagalah - refactor common code but keep simple method
536 // this endpoint is on a different switch; send to the
537 // appropriate tunnel
539 ArrayList<Instruction> instructions = new ArrayList<>();
540 List<Action> applyActions = new ArrayList<>();
545 Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
546 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
547 Action setdCG = nxLoadRegAction(NxmNxReg3.class,
548 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
552 // BEGIN TUNNEL HANDLING
554 ctx.getSwitchManager().getTunnelIP(ofc.getNodeId());
555 NodeConnectorId tunPort =
556 ctx.getSwitchManager().getTunnelPort(nodeId);
557 if (tunDst == null) {
558 LOG.warn("Failed to get Tunnel IP for NodeId {} with EP {}", nodeId, ep);
561 if (tunPort == null) {
562 LOG.warn("Failed to get Tunnel Port for NodeId {} with EP {}", nodeId, ep);
568 if (tunDst.getIpv4Address() != null) {
569 nextHop = tunDst.getIpv4Address().getValue();
570 tundstAction = nxLoadTunIPv4Action(nextHop, false);
571 } else if (tunDst.getIpv6Address() != null) {
572 // nextHop = tunDst.getIpv6Address().getValue();
573 LOG.error("IPv6 tunnel destination {} for {} not supported",
574 tunDst.getIpv6Address().getValue(),
578 // this shouldn't happen
579 LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
585 portNum = getOfPortNum(tunPort);
586 } catch (NumberFormatException ex) {
587 LOG.warn("Could not parse port number {}",
588 ofc.getNodeConnectorId(), ex);
592 setNextHop = nxLoadRegAction(NxmNxReg7.class,
593 BigInteger.valueOf(portNum));
595 nxMoveRegTunIdAction(NxmNxReg0.class, false);
597 applyActions.add(tunIdAction);
598 applyActions.add(tundstAction);
602 applyActions.add(setdEPG);
603 applyActions.add(setdCG);
604 applyActions.add(setNextHop);
605 Instruction applyActionsIns = new InstructionBuilder()
607 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
609 instructions.add(applyActionsIns);
611 applyActionsIns = new InstructionBuilder()
613 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
616 Instruction gotoTable = new InstructionBuilder()
618 .setInstruction(gotoTableIns((short) (getTableId() + 1)))
620 instructions.add(gotoTable);
622 FlowId flowid = new FlowId(new StringBuilder()
623 .append(epFwdCtxOrds.getBdId())
625 .append(ep.getMacAddress().getValue())
629 MatchBuilder mb = new MatchBuilder()
630 .setEthernetMatch(ethernetMatch(null,
633 addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
634 FlowBuilder flowb = base()
636 .setPriority(Integer.valueOf(50))
637 .setMatch(mb.build())
638 .setInstructions(new InstructionsBuilder()
639 .setInstruction(instructions)
642 return flowb.build();
646 private Flow createRemoteL3Flow(L3Address l3a, NodeId nodeId, EndpointFwdCtxOrdinals epFwdCtxOrds,OfOverlayContext ofc) {
648 //TODO Li alagalah - refactor common code but keep simple method
651 // this endpoint is on a different switch; send to the
652 // appropriate tunnel
654 ArrayList<Instruction> l3instructions = new ArrayList<>();
655 List<Action> applyActions = new ArrayList<>();
656 List<Action> l3ApplyActions = new ArrayList<>();
661 Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
662 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
663 Action setdCG = nxLoadRegAction(NxmNxReg3.class,
664 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
668 Action setDlSrc = setDlSrcAction(ROUTER_MAC);
669 Action decTtl = decNwTtlAction();
671 // BEGIN TUNNEL HANDLING
673 ctx.getSwitchManager().getTunnelIP(ofc.getNodeId());
674 NodeConnectorId tunPort =
675 ctx.getSwitchManager().getTunnelPort(nodeId);
676 if (tunDst == null) {
677 LOG.warn("Failed to get Tunnel IP for NodeId {} with L3Address {}", nodeId, l3a);
680 if (tunPort == null) {
681 LOG.warn("Failed to get Tunnel port for NodeId {} with L3Address {}", nodeId, l3a);
687 if (tunDst.getIpv4Address() != null) {
688 nextHop = tunDst.getIpv4Address().getValue();
689 tundstAction = nxLoadTunIPv4Action(nextHop, false);
690 } else if (tunDst.getIpv6Address() != null) {
691 // nextHop = tunDst.getIpv6Address().getValue();
692 LOG.error("IPv6 tunnel destination {} for {} not supported",
693 tunDst.getIpv6Address().getValue(),
697 // this shouldn't happen
698 LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
704 portNum = getOfPortNum(tunPort);
705 } catch (NumberFormatException ex) {
706 LOG.warn("Could not parse port number {}",
707 ofc.getNodeConnectorId(), ex);
711 setNextHop = nxLoadRegAction(NxmNxReg7.class,
712 BigInteger.valueOf(portNum));
714 nxMoveRegTunIdAction(NxmNxReg0.class, false);
716 applyActions.add(tunIdAction);
717 applyActions.add(tundstAction);
721 l3ApplyActions.add(setDlSrc);
722 l3ApplyActions.add(decTtl);
724 applyActions.add(setdEPG);
725 applyActions.add(setdCG);
726 applyActions.add(setNextHop);
727 l3ApplyActions.add(setDlSrc);
728 l3ApplyActions.add(decTtl);
730 applyActions.addAll(l3ApplyActions);
731 Instruction applyActionsIns = new InstructionBuilder()
733 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
736 l3instructions.add(applyActionsIns);
737 Instruction gotoTable = new InstructionBuilder()
739 .setInstruction(gotoTableIns((short) (getTableId() + 1)))
741 l3instructions.add(gotoTable);
742 Layer3Match m = null;
743 Long etherType = null;
745 if (l3a.getIpAddress().getIpv4Address() != null) {
746 ikey = l3a.getIpAddress().getIpv4Address().getValue() + "/32";
748 m = new Ipv4MatchBuilder()
749 .setIpv4Destination(new Ipv4Prefix(ikey))
751 } else if (l3a.getIpAddress().getIpv6Address() != null) {
752 ikey = l3a.getIpAddress().getIpv6Address().getValue() + "/128";
754 m = new Ipv6MatchBuilder()
755 .setIpv6Destination(new Ipv6Prefix(ikey))
758 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.",l3a.toString());
762 FlowId flowid = new FlowId(new StringBuilder()
763 .append(Integer.toString(epFwdCtxOrds.getL3Id()))
767 .append(Integer.toString(epFwdCtxOrds.getEpgId()))
769 .append(Integer.toString(epFwdCtxOrds.getCgId()))
773 MatchBuilder mb = new MatchBuilder()
774 .setEthernetMatch(ethernetMatch(null,
778 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
779 Long.valueOf(epFwdCtxOrds.getL3Id())));
780 FlowBuilder flowb = base()
782 .setPriority(Integer.valueOf(132))
783 .setMatch(mb.build())
784 .setInstructions(new InstructionsBuilder()
785 .setInstruction(l3instructions)
787 return flowb.build();
791 static byte[] bytesFromHexString(String values) {
793 if (values != null) {
796 String[] octets = target.split(":");
798 byte[] ret = new byte[octets.length];
799 for (int i = 0; i < octets.length; i++) {
800 ret[i] = Integer.valueOf(octets[i], 16).byteValue();