228820f95393eccd5e1064e89d7f038d17ff31da
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / IngressNatMapper.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.addNxRegMatch;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
26 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
27 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
28 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setIpv4DstAction;
29 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setIpv6DstAction;
30
31 import java.math.BigInteger;
32 import java.util.Collection;
33 import java.util.List;
34
35 import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
39 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
40 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.napt.translations.fields.napt.translations.NaptTranslation;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 /**
72  * Manage the table that assigns source endpoint group, bridge domain, and
73  * router domain to registers to be used by other tables.
74  */
75 public class IngressNatMapper extends FlowTable {
76
77     protected static final Logger LOG = LoggerFactory.getLogger(IngressNatMapper.class);
78
79     // TODO Li alagalah Improve UT coverage for this class.
80     public static short TABLE_ID;
81
82     public IngressNatMapper(OfContext ctx, short tableId) {
83         super(ctx);
84         TABLE_ID = tableId;
85     }
86
87     @Override
88     public short getTableId() {
89         return TABLE_ID;
90     }
91
92     @Override
93     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
94
95         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
96
97         // TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
98
99         Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
100         Collection<EndpointL3> l3Endpoints = ctx.getEndpointManager().getL3EndpointsWithNat();
101         for (EndpointL3 l3Ep : l3Endpoints) {
102             if (l3Ep.getL2Context() != null && l3Ep.getMacAddress() !=null ) {
103                 Endpoint ep = ctx.getEndpointManager().getEndpoint(new EpKey(l3Ep.getL2Context(), l3Ep.getMacAddress()));
104                 if (endpointsForNode.contains(ep)) {
105                     createNatFlow(l3Ep, nodeId, flowMap, policyInfo);
106                 }
107             }
108         }
109     }
110
111     private void createNatFlow(EndpointL3 l3Ep, NodeId nodeId, FlowMap flowMap, PolicyInfo policyInfo) throws Exception {
112         List<NaptTranslation> naptAugL3Endpoint = ctx.getEndpointManager().getNaptAugL3Endpoint(l3Ep);
113         // Match on L3 Nat Augmentation in Destination, set to IPAddress/Mac, send to SourceMapper
114         if (naptAugL3Endpoint == null) {
115             return;
116         }
117         Flow flow = null;
118         for (NaptTranslation nat : naptAugL3Endpoint) {
119             Endpoint ep = ctx.getEndpointManager().getEndpoint(new EpKey(l3Ep.getL2Context(), l3Ep.getMacAddress()));
120             EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, ep);
121             if (epFwdCtxOrds == null) {
122                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", ep);
123                 continue;
124             }
125
126
127             flow = buildNatFlow(nat.getIpAddress(), l3Ep.getIpAddress(), l3Ep.getMacAddress(), epFwdCtxOrds);
128             if (flow != null) {
129                 flowMap.writeFlow(nodeId, TABLE_ID, flow);
130             }
131             flow = createOutsideArpFlow(nat.getIpAddress(), l3Ep.getMacAddress(), nodeId);
132             if (flow != null) {
133                 flowMap.writeFlow(nodeId, TABLE_ID, flow);
134             }
135             break;
136         }
137
138     }
139
140     private Flow buildNatFlow(IpAddress outsideDestAddress, IpAddress insideDestAddress, MacAddress toMac,
141             EndpointFwdCtxOrdinals epFwdCtxOrds) {
142         // TODO Auto-generated method stub
143         MatchBuilder mb = new MatchBuilder();
144         Action setDestIp;
145         String outsideIpMatch;
146         Layer3Match m;
147
148         Action setDestMac = setDlDstAction(toMac);
149         FlowId flowid = new FlowId(new StringBuilder().append("IngressNat")
150             .append("|")
151             .append(outsideDestAddress)
152             .append("|")
153             .append(insideDestAddress)
154             .append("|")
155             .append(toMac)
156             .toString());
157         if (insideDestAddress.getIpv4Address() != null) {
158             setDestIp = setIpv4DstAction(insideDestAddress.getIpv4Address());
159
160             outsideIpMatch = outsideDestAddress.getIpv4Address().getValue() + "/32";
161             m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(outsideIpMatch)).build();
162             mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv4)).setLayer3Match(m);
163         } else if (insideDestAddress.getIpv6Address() != null) {
164             setDestIp = setIpv6DstAction(insideDestAddress.getIpv6Address());
165             outsideIpMatch = outsideDestAddress.getIpv6Address().getValue() + "/128";
166             m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(outsideIpMatch)).build();
167             mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv6)).setLayer3Match(m);
168         } else {
169             return null;
170         }
171
172         int egId = epFwdCtxOrds.getEpgId();
173         int bdId = epFwdCtxOrds.getBdId();
174         int fdId = epFwdCtxOrds.getFdId();
175         int l3Id = epFwdCtxOrds.getL3Id();
176         int cgId = epFwdCtxOrds.getCgId();
177         int tunnelId = epFwdCtxOrds.getTunnelId();
178         Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
179         Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(cgId));
180         Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
181         Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
182         Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
183         Action tunIdAction = nxLoadTunIdAction(BigInteger.valueOf(tunnelId), false);
184
185         FlowBuilder flowb = base().setPriority(Integer.valueOf(100))
186             .setId(flowid)
187             .setMatch(mb.build())
188             .setInstructions(
189                     instructions(
190                             applyActionIns(setDestIp, setDestMac, segReg, scgReg, bdReg, fdReg, vrfReg, tunIdAction),
191                             gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
192         return flowb.build();
193     }
194
195     private Flow createOutsideArpFlow(IpAddress outsideDestAddress, MacAddress toMac, NodeId nodeId) {
196
197         String ikey = outsideDestAddress.getIpv4Address().getValue();
198         BigInteger intMac = new BigInteger(1, bytesFromHexString(toMac.getValue()));
199
200         FlowId flowId = new FlowId(new StringBuffer().append("outside-ip-arp|").append(ikey).toString());
201         MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, null, ARP)).setLayer3Match(
202                 new ArpMatchBuilder().setArpOp(Integer.valueOf(1))
203                     .setArpTargetTransportAddress(new Ipv4Prefix(ikey + "/32"))
204                     .build());
205
206         FlowBuilder flowb = base().setPriority(150)
207             .setId(flowId)
208             .setMatch(mb.build())
209             .setInstructions(
210                     instructions(applyActionIns(nxMoveEthSrcToEthDstAction(), setDlSrcAction(toMac),
211                             nxLoadArpOpAction(BigInteger.valueOf(2L)), nxMoveArpShaToArpThaAction(),
212                             nxLoadArpShaAction(intMac), nxMoveArpSpaToArpTpaAction(), nxLoadArpSpaAction(ikey),
213                             outputAction(new NodeConnectorId(nodeId.getValue() + ":INPORT")))));
214         return flowb.build();
215     }
216
217     static byte[] bytesFromHexString(String values) {
218         String target = "";
219         if (values != null) {
220             target = values;
221         }
222         String[] octets = target.split(":");
223
224         byte[] ret = new byte[octets.length];
225         for (int i = 0; i < octets.length; i++) {
226             ret[i] = Integer.valueOf(octets[i], 16).byteValue();
227         }
228         return ret;
229     }
230 }