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.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.nxLoadArpOpAction;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
26 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
27 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setIpv4DstAction;
28 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setIpv6DstAction;
30 import java.math.BigInteger;
31 import java.util.Collection;
33 import org.opendaylight.groupbasedpolicy.dto.EpKey;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
65 * Manage the table that assigns source endpoint group, bridge domain, and
66 * router domain to registers to be used by other tables.
68 public class IngressNatMapper extends FlowTable {
70 protected static final Logger LOG = LoggerFactory.getLogger(IngressNatMapper.class);
72 // TODO Li alagalah Improve UT coverage for this class.
73 public static short TABLE_ID;
75 public IngressNatMapper(OfContext ctx, short tableId) {
81 public short getTableId() {
86 public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
88 // TODO for consideration: default instruction is goto next table because when matching against eth type 0x8100
89 // in PortSecurity, it's not possible to match against IPv4 addresses (only inf eth type would be 0x800)
90 // We can't determine just from L2 layer if traffic should be passed from PortSecurity here to IngressNat or to
91 // SourceMapper. Various 802.1q encapsulated IPs can pass through external ports - NATed or not NATed, remote
92 // or directly connected.
93 // All external ingress traffic is currently passed here and if no match is foud - no NAT is performed
94 // and processing continues in SourceMapper.
98 .setInstructions(FlowUtils.instructions(FlowUtils.gotoTableIns(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER())))
99 .setId(FlowIdUtils.newFlowId("gotoSourceMapper"))
101 ofWriter.writeFlow(nodeId, TABLE_ID, flow);
103 // TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
105 Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
106 Collection<EndpointL3> l3Endpoints = ctx.getEndpointManager().getL3EndpointsWithNat();
107 for (EndpointL3 l3Ep : l3Endpoints) {
108 if (l3Ep.getL2Context() != null && l3Ep.getMacAddress() !=null ) {
109 Endpoint ep = ctx.getEndpointManager().getEndpoint(new EpKey(l3Ep.getL2Context(), l3Ep.getMacAddress()));
110 if (endpointsForNode.contains(ep)) {
111 createNatFlow(l3Ep, nodeId, ofWriter);
117 private void createNatFlow(EndpointL3 l3Ep, NodeId nodeId, OfWriter ofWriter) throws Exception {
118 NatAddress natAugL3Endpoint = l3Ep.getAugmentation(NatAddress.class);
119 // Match on L3 Nat Augmentation in Destination, set to IPAddress/Mac, send to SourceMapper
120 if (natAugL3Endpoint == null) {
123 Endpoint ep = ctx.getEndpointManager().getEndpoint(new EpKey(l3Ep.getL2Context(), l3Ep.getMacAddress()));
124 EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, ep);
125 if (epFwdCtxOrds == null) {
126 LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", ep);
129 Flow flow = buildNatFlow(natAugL3Endpoint.getNatAddress(), l3Ep.getIpAddress(), l3Ep.getMacAddress(), epFwdCtxOrds);
131 ofWriter.writeFlow(nodeId, TABLE_ID, flow);
133 flow = createOutsideArpFlow(natAugL3Endpoint.getNatAddress(), l3Ep.getMacAddress(), nodeId);
135 ofWriter.writeFlow(nodeId, TABLE_ID, flow);
139 private Flow buildNatFlow(IpAddress outsideDestAddress, IpAddress insideDestAddress, MacAddress toMac,
140 EndpointFwdCtxOrdinals epFwdCtxOrds) {
141 // TODO Auto-generated method stub
142 MatchBuilder mb = new MatchBuilder();
144 String outsideIpMatch;
147 Action setDestMac = setDlDstAction(toMac);
148 FlowId flowid = new FlowId(new StringBuilder().append("IngressNat")
150 .append(outsideDestAddress)
152 .append(insideDestAddress)
156 if (insideDestAddress.getIpv4Address() != null) {
157 setDestIp = setIpv4DstAction(insideDestAddress.getIpv4Address());
159 outsideIpMatch = outsideDestAddress.getIpv4Address().getValue() + "/32";
160 m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(outsideIpMatch)).build();
161 mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv4)).setLayer3Match(m);
162 } else if (insideDestAddress.getIpv6Address() != null) {
163 setDestIp = setIpv6DstAction(insideDestAddress.getIpv6Address());
164 outsideIpMatch = outsideDestAddress.getIpv6Address().getValue() + "/128";
165 m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(outsideIpMatch)).build();
166 mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv6)).setLayer3Match(m);
171 int egId = epFwdCtxOrds.getEpgId();
172 int bdId = epFwdCtxOrds.getBdId();
173 int fdId = epFwdCtxOrds.getFdId();
174 int l3Id = epFwdCtxOrds.getL3Id();
175 int cgId = epFwdCtxOrds.getCgId();
176 int tunnelId = epFwdCtxOrds.getTunnelId();
177 Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
178 Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(cgId));
179 Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
180 Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
181 Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
182 Action tunIdAction = nxLoadTunIdAction(BigInteger.valueOf(tunnelId), false);
184 FlowBuilder flowb = base().setPriority(Integer.valueOf(100))
186 .setMatch(mb.build())
189 applyActionIns(setDestIp, setDestMac, segReg, scgReg, bdReg, fdReg, vrfReg, tunIdAction),
190 gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
191 return flowb.build();
194 private Flow createOutsideArpFlow(IpAddress outsideDestAddress, MacAddress toMac, NodeId nodeId) {
196 String ikey = outsideDestAddress.getIpv4Address().getValue();
197 BigInteger intMac = new BigInteger(1, bytesFromHexString(toMac.getValue()));
199 FlowId flowId = new FlowId(new StringBuffer().append("outside-ip-arp|").append(ikey).toString());
200 MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, null, ARP)).setLayer3Match(
201 new ArpMatchBuilder().setArpOp(Integer.valueOf(1))
202 .setArpTargetTransportAddress(new Ipv4Prefix(ikey + "/32"))
205 FlowBuilder flowb = base().setPriority(150)
207 .setMatch(mb.build())
209 instructions(applyActionIns(nxMoveEthSrcToEthDstAction(), setDlSrcAction(toMac),
210 nxLoadArpOpAction(BigInteger.valueOf(2L)), nxMoveArpShaToArpThaAction(),
211 nxLoadArpShaAction(intMac), nxMoveArpSpaToArpTpaAction(), nxLoadArpSpaAction(ikey),
212 outputAction(new NodeConnectorId(nodeId.getValue() + ":INPORT")))));
213 return flowb.build();
216 static byte[] bytesFromHexString(String values) {
218 if (values != null) {
221 String[] octets = target.split(":");
223 byte[] ret = new byte[octets.length];
224 for (int i = 0; i < octets.length; i++) {
225 ret[i] = Integer.valueOf(octets[i], 16).byteValue();