f7d22acd726bbc44f96af1a4466834f1fa08e5a4
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / SourceMapper.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.addNxTunIdMatch;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
18
19 import java.math.BigInteger;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.Map;
23 import java.util.Set;
24
25 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
26 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
27 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
28 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
29 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
30 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.google.common.collect.Sets;
54
55 /**
56  * Manage the table that assigns source endpoint group, bridge domain, and
57  * router domain to registers to be used by other tables.
58  */
59 public class SourceMapper extends FlowTable {
60
61     protected static final Logger LOG = LoggerFactory.getLogger(SourceMapper.class);
62
63     // TODO Li alagalah Improve UT coverage for this class.
64     public static short TABLE_ID;
65
66     public SourceMapper(OfContext ctx, short tableId) {
67         super(ctx);
68         this.TABLE_ID=tableId;
69     }
70
71     @Override
72     public short getTableId() {
73         return TABLE_ID;
74     }
75
76     @Override
77     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
78
79         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
80
81         // Handle case where packets from from External
82         Map<EndpointKey, EndpointL3> l3EpWithNatByL2Key = ctx.getEndpointManager().getL3EpWithNatByL2Key();
83         for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
84             OfOverlayContext ofc = ep.getAugmentation(OfOverlayContext.class);
85
86             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(ep.getTenant());
87             if (tenant == null)
88                 continue;
89
90             EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, ep);
91             EgKey sepg = new EgKey(ep.getTenant(), ep.getEndpointGroup());
92
93             createRemoteTunnels(flowMap, nodeId, ep, policyInfo, epFwdCtxOrds);
94
95             if (ep.getTenant() == null || (ep.getEndpointGroup() == null && ep.getEndpointGroups() == null)) {
96                 continue;
97             }
98
99             if (ofc != null && ofc.getNodeConnectorId() != null
100                     && (ofc.getLocationType() == null || LocationType.Internal.equals(ofc.getLocationType()))) {
101                 /**
102                  * Sync the local EP information.
103                  */
104                 syncEP(flowMap, nodeId, ep, ofc.getNodeConnectorId(), epFwdCtxOrds);
105
106             }
107 //            if (l3EpWithNatByL2Key.containsKey(ep.getKey())) {
108 //                Set<NodeConnectorId> external = ctx.getSwitchManager().getExternalPorts(nodeId);
109 //                for (NodeConnectorId ncId : external) {
110 //                    // TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
111 //                    syncEP(flowMap, nodeId, ep, ncId, epFwdCtxOrds);
112 //                }
113 //            }
114         }
115     }
116
117     private void createRemoteTunnels(FlowMap flowMap, NodeId nodeId, Endpoint ep, PolicyInfo policyInfo,
118             EndpointFwdCtxOrdinals epFwdCtxOrds) throws Exception {
119         Set<EgKey> epgs = new HashSet<>();
120
121         // Get EPGs and add to Set to remove duplicates
122         // TODO alagalah Li: test EndpointManager.getEgKeys
123         if (ep.getEndpointGroup() != null) {
124             epgs.add(new EgKey(ep.getTenant(), ep.getEndpointGroup()));
125         }
126         if (ep.getEndpointGroups() != null) {
127             for (EndpointGroupId epgId : ep.getEndpointGroups()) {
128                 epgs.add(new EgKey(ep.getTenant(), epgId));
129             }
130         }
131
132         // Create tunnels on remote Nodes that may talk to us.
133         for (EgKey epg : epgs) {
134             Set<EgKey> peers = Sets.union(Collections.singleton(epg), policyInfo.getPeers(epg));
135             for (EgKey peer : peers) {
136                 for (NodeId remoteNodeId : ctx.getEndpointManager().getNodesForGroup(peer)) {
137
138                     // Please do not check for remote v local nodeID, we need local to local tunnels
139                     // in the case of chaining - The Great Dr Sunal.
140                     NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(remoteNodeId, TunnelTypeVxlan.class);
141                     if (tunPort == null) {
142                         LOG.trace("No tunnel port for tunnel in SourceMapper between local:{} and remote:{}",
143                                 nodeId.getValue(), remoteNodeId.getValue());
144                         continue;
145                     }
146                     flowMap.writeFlow(remoteNodeId, TABLE_ID, createTunnelFlow(tunPort, epFwdCtxOrds));
147                     flowMap.writeFlow(remoteNodeId, TABLE_ID, createBroadcastFlow(tunPort, epFwdCtxOrds));
148                 }
149             }
150         }
151     }
152
153     private Flow createBroadcastFlow(NodeConnectorId tunPort, EndpointFwdCtxOrdinals epFwdCtxOrds) {
154
155         int fdId = epFwdCtxOrds.getFdId();
156
157         FlowId flowid = new FlowId(new StringBuilder().append(tunPort.getValue())
158             .append("|tunnel|")
159             .append("|")
160             .append(fdId)
161             .toString());
162
163         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
164         addNxTunIdMatch(mb, fdId);
165
166         // set condition group register to all ones to
167         // bypass
168         // policy enforcement
169         /*
170          * TODO: This breaks distributed policy enforcement
171          * especially wrt multi-action. BAD. Must be addressed
172          * (this is why we can't have nice things).
173          * This can be fixed with new tunnelId ordinal in
174          * Ordinal Factory.
175          */
176
177         Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
178
179         FlowBuilder flowb = base().setId(flowid)
180             .setPriority(Integer.valueOf(150))
181             .setMatch(mb.build())
182             .setInstructions(instructions(applyActionIns(fdReg), gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
183         return flowb.build();
184     }
185
186     private Flow createTunnelFlow(NodeConnectorId tunPort, EndpointFwdCtxOrdinals epFwdCtxOrds) {
187         // ... this is a remote node.
188
189         int egId = epFwdCtxOrds.getEpgId();
190         int bdId = epFwdCtxOrds.getBdId();
191         int fdId = epFwdCtxOrds.getFdId();
192         int l3Id = epFwdCtxOrds.getL3Id();
193         int tunnelId = epFwdCtxOrds.getTunnelId();
194
195         FlowId flowid = new FlowId(new StringBuilder().append(tunPort.getValue())
196             .append("|tunnel|")
197             .append(egId)
198             .append("|")
199             .append(bdId)
200             .append("|")
201             .append(fdId)
202             .append("|")
203             .append(l3Id)
204             .append("|")
205             .append(tunnelId)
206             .toString());
207
208         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
209         addNxTunIdMatch(mb, tunnelId);
210
211         Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
212         // set condition group register to all ones to
213         // bypass
214         // policy enforcement
215         /*
216          * TODO: This breaks distributed policy enforcement
217          * especially wrt multi-action. BAD. Must be addressed
218          * (this is why we can't have nice things).
219          * This can be fixed with new tunnelId ordinal in
220          * Ordinal Factory.
221          */
222         Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(0xffffff));
223         Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
224         Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
225         Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
226         FlowBuilder flowb = base().setId(flowid)
227             .setPriority(Integer.valueOf(150))
228             .setMatch(mb.build())
229             .setInstructions(
230                     instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg),
231                             gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
232         return flowb.build();
233     }
234
235     private void syncEP(FlowMap flowMap, NodeId nodeId, Endpoint ep, NodeConnectorId ncId, EndpointFwdCtxOrdinals epFwdCtxOrds) throws Exception {
236
237         // TODO alagalah Li/Be: We should also match on EndpointL3 with the appropriate
238         // network containment. This would solve a lot of problems and prepare for EndpointL3 RPC.
239
240         int egId = epFwdCtxOrds.getEpgId();
241         int bdId = epFwdCtxOrds.getBdId();
242         int fdId = epFwdCtxOrds.getFdId();
243         int l3Id = epFwdCtxOrds.getL3Id();
244         int cgId = epFwdCtxOrds.getCgId();
245         int tunnelId = epFwdCtxOrds.getTunnelId();
246
247         FlowId flowid = new FlowId(new StringBuilder().append(ncId.getValue())
248             .append("|")
249             .append(ep.getMacAddress().getValue())
250             .append("|")
251             .append(egId)
252             .append("|")
253             .append(bdId)
254             .append("|")
255             .append(fdId)
256             .append("|")
257             .append(l3Id)
258             .append("|")
259             .append(cgId)
260             .toString());
261         Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
262         Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(cgId));
263         Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
264         Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
265         Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
266         Action tunIdAction = nxLoadTunIdAction(BigInteger.valueOf(tunnelId), false);
267
268         FlowBuilder flowb = base().setPriority(Integer.valueOf(100))
269             .setId(flowid)
270             .setMatch(
271                     new MatchBuilder().setEthernetMatch(ethernetMatch(ep.getMacAddress(), null, null))
272                         .setInPort(ncId)
273                         .build())
274             .setInstructions(
275                     instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg,tunIdAction),
276                             gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
277         flowMap.writeFlow(nodeId, TABLE_ID, flowb.build());
278     }
279
280 }