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