b779fc5ef33c0162aa0302c4f77c9a7bc28947f2
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / DestinationMapper.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
10
11 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
26 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
27 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
28 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.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;
35
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;
42 import java.util.Set;
43
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;
91
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;
96
97 /**
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.
100  *
101  */
102 public class DestinationMapper extends FlowTable {
103     protected static final Logger LOG =
104             LoggerFactory.getLogger(DestinationMapper.class);
105
106     //TODO Li alagalah: Improve UT coverage for this class.
107
108     //TODO Li alagalah: Use EndpointL3 for L3 flows, Endpoint for L2 flows
109     // This ensures we have the appropriate network-containment'
110
111     public static final short TABLE_ID = 2;
112     /**
113      * This is the MAC address of the magical router in the sky
114      */
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");
119
120     public DestinationMapper(OfContext ctx) {
121         super(ctx);
122     }
123
124     @Override
125     public short getTableId() {
126         return TABLE_ID;
127     }
128
129     @Override
130     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap)
131             throws Exception {
132
133         flowMap.writeFlow(nodeId,TABLE_ID,dropFlow(Integer.valueOf(1), null));
134
135         Set<EpKey> visitedEps = new HashSet<>();
136         Multimap<Integer,Subnet> subnetsByL3c = HashMultimap.create();
137         Set<Integer> fdIds = new HashSet<>();
138
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);
145
146                     //Process subnets and flood-domains for epPeer
147                     EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, epPeer);
148
149                     subnetsByL3c.putAll(epOrds.getL3Id(),ctx.getPolicyResolver().getTenant(peer.getTenantId()).resolveSubnets(epOrds.getNetworkContainment()));
150                     fdIds.add(epOrds.getFdId());
151                 }
152             }
153         }
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));
158             }
159         }
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));
164             }
165         }
166     }
167     // set up next-hop destinations for all the endpoints in the endpoint
168     // group on the node
169
170
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)
180                                 .build())
181                         .build());
182         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
183
184         FlowBuilder flowb = base()
185                 .setPriority(Integer.valueOf(140))
186                 .setId(flowId)
187                 .setMatch(mb.build())
188                 .setInstructions(instructions(applyActionIns(nxMoveRegTunIdAction(NxmNxReg0.class, false),
189                         groupAction(Long.valueOf(fdId)))));
190         return flowb.build();
191     }
192
193
194
195     private boolean groupExists(NodeId nodeId, Integer fdId) throws Exception {
196         // Fetch existing GroupTables
197         if(ctx.getDataBroker()==null) {
198             return false;
199         }
200
201         ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
202         InstanceIdentifier<Node> niid = createNodePath(nodeId);
203         Optional<Node> r =
204                 t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
205         if (!r.isPresent())
206             return false;
207         FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
208         if (fcn == null)
209             return false;
210
211         if (fcn.getGroup() != null) {
212             for (Group g : fcn.getGroup()) {
213                 if (g.getGroupId().getValue().equals(Long.valueOf(fdId))) { // Group
214                                                                             // Exists.
215                     return true;
216                 }
217             }
218         }
219         return false;
220     }
221
222
223     private Flow createRouterArpFlow(NodeId nodeId,
224             Subnet sn,
225             int l3Id) {
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())
232                         .append("|")
233                         .append(ikey)
234                         .append("|")
235                         .append(l3Id)
236                         .toString());
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"))
242                                     .build());
243                     addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
244                             Long.valueOf(l3Id)));
245                     BigInteger routerMac =
246                             new BigInteger(1, bytesFromHexString(ROUTER_MAC
247                                     .getValue()));
248                     FlowBuilder flowb = base()
249                             .setPriority(150)
250                             .setId(flowId)
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();
261             } else {
262                 LOG.warn("IPv6 virtual router {} for subnet {} not supported",
263                         sn.getVirtualRouterIp(), sn.getId().getValue());
264             }
265         }
266         return null;
267     }
268
269
270     private Flow createLocalL2Flow(Endpoint ep, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
271
272         //TODO Li alagalah - refactor common code but keep simple method
273         ArrayList<Instruction> instructions = new ArrayList<>();
274         List<Action> applyActions = new ArrayList<>();
275
276         int order = 0;
277
278         Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
279                 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
280         Action setdCG = nxLoadRegAction(NxmNxReg3.class,
281                 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
282         Action setNextHop;
283         String nextHop;
284
285
286
287         // BEGIN L2 LOCAL
288         nextHop = ofc.getNodeConnectorId().getValue();
289
290         long portNum;
291         try {
292             portNum = getOfPortNum(ofc.getNodeConnectorId());
293         } catch (NumberFormatException ex) {
294             LOG.warn("Could not parse port number {}",
295                     ofc.getNodeConnectorId(), ex);
296             return null;
297         }
298
299         setNextHop = nxLoadRegAction(NxmNxReg7.class,
300                 BigInteger.valueOf(portNum));
301
302         //END L2 LOCAL
303
304         order += 1;
305         applyActions.add(setdEPG);
306         applyActions.add(setdCG);
307         applyActions.add(setNextHop);
308         Instruction applyActionsIns = new InstructionBuilder()
309                 .setOrder(order++)
310                 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
311                 .build();
312         instructions.add(applyActionsIns);
313
314         Instruction gotoTable = new InstructionBuilder()
315                 .setOrder(order++)
316                 .setInstruction(gotoTableIns((short) (getTableId() + 1)))
317                 .build();
318         instructions.add(gotoTable);
319
320
321         FlowId flowid = new FlowId(new StringBuilder()
322                 .append(epFwdCtxOrds.getBdId())
323                 .append("|l2|")
324                 .append(ep.getMacAddress().getValue())
325                 .append("|")
326                 .append(nextHop)
327                 .toString());
328         MatchBuilder mb = new MatchBuilder()
329                 .setEthernetMatch(ethernetMatch(null,
330                         ep.getMacAddress(),
331                         null));
332         addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
333         FlowBuilder flowb = base()
334                 .setId(flowid)
335                 .setPriority(Integer.valueOf(50))
336                 .setMatch(mb.build())
337                 .setInstructions(new InstructionsBuilder()
338                         .setInstruction(instructions)
339                         .build());
340         return flowb.build();
341     }
342
343
344     private void syncEP(FlowMap flowMap,
345             NodeId nodeId, PolicyInfo policyInfo,
346             Endpoint epPeer, Set<EpKey> visitedEps)
347             throws Exception {
348
349         EpKey epPeerKey = new EpKey(epPeer.getL2Context(),epPeer.getMacAddress());
350
351         if (visitedEps.contains(epPeerKey)) {
352             return;
353         }
354         visitedEps.add(epPeerKey);
355
356         // TODO: Conditions messed up, but for now, send policyInfo until this is fixed.
357         EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, epPeer);
358
359         if (epPeer.getTenant() == null || (epPeer.getEndpointGroup() == null && epPeer.getEndpointGroups() == null))
360             return;
361         OfOverlayContext ofc = epPeer.getAugmentation(OfOverlayContext.class);
362
363
364
365         //////////////////////////////////////////////////////////////////////////////////////////
366         /*
367          * NOT HANDLING EXTERNALS
368          */
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");
373             return;
374         }
375
376         if (Objects.equals(ofc.getNodeId(), nodeId)) {
377             // this is a local endpoint; send to the approppriate local
378             // port
379
380             flowMap.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(epPeer,epFwdCtxOrds,ofc));
381
382             if (epPeer.getL3Address() == null)
383                 return;
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());
387                     continue;
388                 } else {
389                     flowMap.writeFlow(nodeId, TABLE_ID, createLocalL3Flow(epPeer,l3a, epFwdCtxOrds,ofc));
390                 }
391             }
392         } else {
393             // this endpoint is on a different switch; send to the
394             // appropriate tunnel
395
396             Flow remoteL2Flow = createRemoteL2Flow(epPeer, nodeId, epFwdCtxOrds, ofc);
397             if (remoteL2Flow != null) {
398                 flowMap.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
399             }
400
401             if (epPeer.getL3Address() == null)
402                 return;
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());
406                     continue;
407                 } else {
408                     Flow remoteL3Flow = createRemoteL3Flow(l3a, nodeId,epFwdCtxOrds, ofc);
409                     if (remoteL3Flow != null) {
410                         flowMap.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
411                     }
412                 }
413             }
414         } // remote (tunnel)
415
416
417
418         // }
419
420     }
421
422     /* ##################################
423      * DestMapper Flow methods
424      * ##################################
425      */
426     private Flow createLocalL3Flow(Endpoint ep,L3Address l3a, EndpointFwdCtxOrdinals epFwdCtxOrds,OfOverlayContext ofc) {
427
428         //TODO Li alagalah - refactor common code but keep simple method
429
430         ArrayList<Instruction> l3instructions = new ArrayList<>();
431         List<Action> applyActions = new ArrayList<>();
432         List<Action> l3ApplyActions = new ArrayList<>();
433
434         int order = 0;
435
436         Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
437                 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
438         Action setdCG = nxLoadRegAction(NxmNxReg3.class,
439                 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
440         Action setNextHop;
441         String nextHop;
442
443         Action setDlSrc = setDlSrcAction(ROUTER_MAC);
444         Action decTtl = decNwTtlAction();
445
446         // BEGIN L3 LOCAL
447         nextHop = ofc.getNodeConnectorId().getValue();
448
449         long portNum;
450         try {
451             portNum = getOfPortNum(ofc.getNodeConnectorId());
452         } catch (NumberFormatException ex) {
453             LOG.warn("Could not parse port number {}",
454                     ofc.getNodeConnectorId(), ex);
455             return null;
456         }
457
458         setNextHop = nxLoadRegAction(NxmNxReg7.class,
459                 BigInteger.valueOf(portNum));
460
461         Action setDlDst = setDlDstAction(ep.getMacAddress());
462         l3ApplyActions.add(setDlDst);
463         //END L3 LOCAL
464
465         l3ApplyActions.add(setDlSrc);
466         l3ApplyActions.add(decTtl);
467         order += 1;
468         applyActions.add(setdEPG);
469         applyActions.add(setdCG);
470         applyActions.add(setNextHop);
471
472         applyActions.addAll(l3ApplyActions);
473         Instruction applyActionsIns = new InstructionBuilder()
474                 .setOrder(order++)
475                 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
476                 .build();
477
478         l3instructions.add(applyActionsIns);
479         Instruction gotoTable = new InstructionBuilder()
480         .setOrder(order++)
481         .setInstruction(gotoTableIns((short) (getTableId() + 1)))
482         .build();
483         l3instructions.add(gotoTable);
484         Layer3Match m = null;
485         Long etherType = null;
486         String ikey = null;
487         if (l3a.getIpAddress().getIpv4Address() != null) {
488             ikey = l3a.getIpAddress().getIpv4Address().getValue() + "/32";
489             etherType = IPv4;
490             m = new Ipv4MatchBuilder()
491                     .setIpv4Destination(new Ipv4Prefix(ikey))
492                     .build();
493         } else if (l3a.getIpAddress().getIpv6Address() != null) {
494             ikey = l3a.getIpAddress().getIpv6Address().getValue() + "/128";
495             etherType = IPv6;
496             m = new Ipv6MatchBuilder()
497                     .setIpv6Destination(new Ipv6Prefix(ikey))
498                     .build();
499         } else {
500             LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.",l3a.toString());
501             return null;
502         }
503
504         FlowId flowid = new FlowId(new StringBuilder()
505                 .append(Integer.toString(epFwdCtxOrds.getL3Id()))
506                 .append("|l3|")
507                 .append(ikey)
508                 .append("|")
509                 .append(Integer.toString(epFwdCtxOrds.getEpgId()))
510                 .append(" ")
511                 .append(Integer.toString(epFwdCtxOrds.getCgId()))
512                 .append("|")
513                 .append(nextHop)
514                 .toString());
515         MatchBuilder mb = new MatchBuilder()
516                 .setEthernetMatch(ethernetMatch(null,
517                         ROUTER_MAC,
518                         etherType))
519                 .setLayer3Match(m);
520         addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
521                 Long.valueOf(epFwdCtxOrds.getL3Id())));
522         FlowBuilder flowb = base()
523                 .setId(flowid)
524                 .setPriority(Integer.valueOf(132))
525                 .setMatch(mb.build())
526                 .setInstructions(new InstructionsBuilder()
527                         .setInstruction(l3instructions)
528                         .build());
529         return flowb.build();
530     }
531
532     private Flow createRemoteL2Flow(Endpoint ep, NodeId nodeId, EndpointFwdCtxOrdinals epFwdCtxOrds, OfOverlayContext ofc) {
533
534         //TODO Li alagalah - refactor common code but keep simple method
535
536         // this endpoint is on a different switch; send to the
537         // appropriate tunnel
538
539         ArrayList<Instruction> instructions = new ArrayList<>();
540         List<Action> applyActions = new ArrayList<>();
541
542
543         int order = 0;
544
545         Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
546                 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
547         Action setdCG = nxLoadRegAction(NxmNxReg3.class,
548                 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
549         Action setNextHop;
550         String nextHop;
551
552         // BEGIN TUNNEL HANDLING
553         IpAddress tunDst =
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);
559             return null;
560         }
561         if (tunPort == null) {
562             LOG.warn("Failed to get Tunnel Port for NodeId {} with EP {}", nodeId, ep);
563             return null;
564         }
565
566         Action tundstAction;
567
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(),
575                     ofc.getNodeId());
576             return null;
577         } else {
578             // this shouldn't happen
579             LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
580             return null;
581         }
582
583         long portNum;
584         try {
585             portNum = getOfPortNum(tunPort);
586         } catch (NumberFormatException ex) {
587             LOG.warn("Could not parse port number {}",
588                     ofc.getNodeConnectorId(), ex);
589             return null;
590         }
591
592         setNextHop = nxLoadRegAction(NxmNxReg7.class,
593                 BigInteger.valueOf(portNum));
594         Action tunIdAction =
595                 nxMoveRegTunIdAction(NxmNxReg0.class, false);
596
597         applyActions.add(tunIdAction);
598         applyActions.add(tundstAction);
599         // END TUNNEL
600
601         order += 1;
602         applyActions.add(setdEPG);
603         applyActions.add(setdCG);
604         applyActions.add(setNextHop);
605         Instruction applyActionsIns = new InstructionBuilder()
606                 .setOrder(order++)
607                 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
608                 .build();
609         instructions.add(applyActionsIns);
610
611         applyActionsIns = new InstructionBuilder()
612                 .setOrder(order++)
613                 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
614                 .build();
615
616         Instruction gotoTable = new InstructionBuilder()
617                 .setOrder(order++)
618                 .setInstruction(gotoTableIns((short) (getTableId() + 1)))
619                 .build();
620         instructions.add(gotoTable);
621
622         FlowId flowid = new FlowId(new StringBuilder()
623                 .append(epFwdCtxOrds.getBdId())
624                 .append("|l2|")
625                 .append(ep.getMacAddress().getValue())
626                 .append("|")
627                 .append(nextHop)
628                 .toString());
629         MatchBuilder mb = new MatchBuilder()
630                 .setEthernetMatch(ethernetMatch(null,
631                         ep.getMacAddress(),
632                         null));
633         addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
634         FlowBuilder flowb = base()
635                 .setId(flowid)
636                 .setPriority(Integer.valueOf(50))
637                 .setMatch(mb.build())
638                 .setInstructions(new InstructionsBuilder()
639                         .setInstruction(instructions)
640                         .build());
641
642         return flowb.build();
643     }
644
645
646     private Flow createRemoteL3Flow(L3Address l3a, NodeId nodeId, EndpointFwdCtxOrdinals epFwdCtxOrds,OfOverlayContext ofc) {
647
648         //TODO Li alagalah - refactor common code but keep simple method
649
650
651         // this endpoint is on a different switch; send to the
652         // appropriate tunnel
653
654         ArrayList<Instruction> l3instructions = new ArrayList<>();
655         List<Action> applyActions = new ArrayList<>();
656         List<Action> l3ApplyActions = new ArrayList<>();
657
658
659         int order = 0;
660
661         Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
662                 BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
663         Action setdCG = nxLoadRegAction(NxmNxReg3.class,
664                 BigInteger.valueOf(epFwdCtxOrds.getCgId()));
665         Action setNextHop;
666         String nextHop;
667
668         Action setDlSrc = setDlSrcAction(ROUTER_MAC);
669         Action decTtl = decNwTtlAction();
670
671         // BEGIN TUNNEL HANDLING
672         IpAddress tunDst =
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);
678             return null;
679         }
680         if (tunPort == null) {
681             LOG.warn("Failed to get Tunnel port for NodeId {} with L3Address {}", nodeId, l3a);
682             return null;
683         }
684
685         Action tundstAction;
686
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(),
694                     ofc.getNodeId());
695             return null;
696         } else {
697             // this shouldn't happen
698             LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
699             return null;
700         }
701
702         long portNum;
703         try {
704             portNum = getOfPortNum(tunPort);
705         } catch (NumberFormatException ex) {
706             LOG.warn("Could not parse port number {}",
707                     ofc.getNodeConnectorId(), ex);
708             return null;
709         }
710
711         setNextHop = nxLoadRegAction(NxmNxReg7.class,
712                 BigInteger.valueOf(portNum));
713         Action tunIdAction =
714                 nxMoveRegTunIdAction(NxmNxReg0.class, false);
715
716         applyActions.add(tunIdAction);
717         applyActions.add(tundstAction);
718         // END TUNNEL
719
720
721         l3ApplyActions.add(setDlSrc);
722         l3ApplyActions.add(decTtl);
723         order += 1;
724         applyActions.add(setdEPG);
725         applyActions.add(setdCG);
726         applyActions.add(setNextHop);
727         l3ApplyActions.add(setDlSrc);
728         l3ApplyActions.add(decTtl);
729
730         applyActions.addAll(l3ApplyActions);
731         Instruction applyActionsIns = new InstructionBuilder()
732                 .setOrder(order++)
733                 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
734                 .build();
735
736         l3instructions.add(applyActionsIns);
737         Instruction gotoTable = new InstructionBuilder()
738         .setOrder(order++)
739         .setInstruction(gotoTableIns((short) (getTableId() + 1)))
740         .build();
741         l3instructions.add(gotoTable);
742         Layer3Match m = null;
743         Long etherType = null;
744         String ikey = null;
745         if (l3a.getIpAddress().getIpv4Address() != null) {
746             ikey = l3a.getIpAddress().getIpv4Address().getValue() + "/32";
747             etherType = IPv4;
748             m = new Ipv4MatchBuilder()
749                     .setIpv4Destination(new Ipv4Prefix(ikey))
750                     .build();
751         } else if (l3a.getIpAddress().getIpv6Address() != null) {
752             ikey = l3a.getIpAddress().getIpv6Address().getValue() + "/128";
753             etherType = IPv6;
754             m = new Ipv6MatchBuilder()
755                     .setIpv6Destination(new Ipv6Prefix(ikey))
756                     .build();
757         } else {
758             LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.",l3a.toString());
759             return null;
760         }
761
762         FlowId flowid = new FlowId(new StringBuilder()
763                 .append(Integer.toString(epFwdCtxOrds.getL3Id()))
764                 .append("|l3|")
765                 .append(ikey)
766                 .append("|")
767                 .append(Integer.toString(epFwdCtxOrds.getEpgId()))
768                 .append(" ")
769                 .append(Integer.toString(epFwdCtxOrds.getCgId()))
770                 .append("|")
771                 .append(nextHop)
772                 .toString());
773         MatchBuilder mb = new MatchBuilder()
774                 .setEthernetMatch(ethernetMatch(null,
775                         ROUTER_MAC,
776                         etherType))
777                 .setLayer3Match(m);
778         addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
779                 Long.valueOf(epFwdCtxOrds.getL3Id())));
780         FlowBuilder flowb = base()
781                 .setId(flowid)
782                 .setPriority(Integer.valueOf(132))
783                 .setMatch(mb.build())
784                 .setInstructions(new InstructionsBuilder()
785                         .setInstruction(l3instructions)
786                         .build());
787         return flowb.build();
788     }
789
790
791     static byte[] bytesFromHexString(String values) {
792         String target = "";
793         if (values != null) {
794             target = values;
795         }
796         String[] octets = target.split(":");
797
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();
801         }
802         return ret;
803     }
804 }