/*
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.ingressnat;
import com.google.common.collect.Sets;
import org.opendaylight.groupbasedpolicy.dto.EgKey;
import org.opendaylight.groupbasedpolicy.dto.EpKey;
import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMove;
import java.util.Collection;
import java.util.Collections;
/**
* <h1>Manage the table processing NAT translation (table=1)</h1>
*
* Ingress NAT translation flows, created for every L3 endpoints with NAT which also contain L2 context
* <p>
* <i>Nat flow:</i><br>
* Priority = 100<br>
* Matches:<br>
* - nw_dst (destination ip address)<br>
* Actions:<br>
* - loadReg0 {@link NxmNxReg0}<br>
* - loadReg1 {@link NxmNxReg1}<br>
* - loadReg4 {@link NxmNxReg4}<br>
* - loadReg5 {@link NxmNxReg5}<br>
* - loadReg6 {@link NxmNxReg6}<br>
* - loadTunnelId<br>
* - {@link GoToTable} DESTINATION MAPPER table
* <p>
* <i>Outside Arp flow:</i><br>
* Priority = 150<br>
* Matches:<br>
* - arp, (ethertype)<br>
* - set arp target transport address<br>
* Actions:<br>
* - move eth_src = eth_dst {@link NxRegMove}<br>
* - set dl src_mac {@link MacAddress}<br>
* - load arp_op {@link NxRegLoad}<br>
* - move arp_sha = arp_tha {@link NxRegMove}<br>
* - load arp_sha {@link NxRegLoad}<br>
* - move arp_spa = arp_tpa {@link NxRegMove}<br>
* - load arp_spa {@link NxRegLoad}<br>
* - output:port {@link NodeConnectorId}
* <p>
* Flows for ingress traffic. Created for every external endpoint without location<br>
* <p>
* <i>Ingress external IP flow</i><br>
* Priority = 90<br>
* Matches:<br>
* - nw_src (source ip address)<br>
* Actions:<br>
* - loadReg0 {@link NxmNxReg0}<br>
* - loadReg1 {@link NxmNxReg1}<br>
* - loadReg4 {@link NxmNxReg4}<br>
* - loadReg5 {@link NxmNxReg5}<br>
* - loadReg6 {@link NxmNxReg6}<br>
* - loadTunnelId<br>
* - {@link GoToTable} DESTINATION MAPPER table
* <p>
* <i>Ingress external Arp flow</i><br>
* Priority = 80<br>
* Matches:<br>
* - arp_spa (source arp address)<br>
* Actions:<br>
* - loadReg0 {@link NxmNxReg0}<br>
* - loadReg1 {@link NxmNxReg1}<br>
* - loadReg4 {@link NxmNxReg4}<br>
* - loadReg5 {@link NxmNxReg5}<br>
* - loadReg6 {@link NxmNxReg6}<br>
* - loadTunnelId<br>
* - {@link GoToTable} DESTINATION MAPPER table
*
*/
public class IngressNatMapper extends FlowTable {
// Priorities
private static final Integer BASE = 1;
private static final Integer ARP_EXTERNAL = 80;
private static final Integer NAT_EXTERNAL = 90;
private static final Integer NAT = 100;
private static final Integer ARP = 150;
private final short tableId;
public IngressNatMapper(OfContext ctx, short tableId) {
super(ctx);
this.tableId = tableId;
}
@Override
public short getTableId() {
return tableId;
}
@Override
public void sync(Endpoint endpoint, OfWriter ofWriter) {
NodeId endpointNodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint);
if (endpointNodeId == null) {
LOG.warn("Endpoint {} has no location specified, skipped", endpoint);
return;
}
IngressNatMapperFlows flows = new IngressNatMapperFlows(endpointNodeId, tableId);
syncFlows(flows, endpoint, ofWriter);
}
void syncFlows(IngressNatMapperFlows flows, Endpoint endpoint, OfWriter ofWriter) {
// To support provider networks, all external ingress traffic is currently passed here and
// if no match is found - no NAT is performed and processing continues in DestinationMapper.
// Base flow
short destinationMapperId = ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER();
flows.baseFlow(destinationMapperId, BASE, ofWriter);
// Flows for ingress NAT translation
Collection<EndpointL3> l3Endpoints = ctx.getEndpointManager().getL3EndpointsWithNat();
OrdinalFactory.EndpointFwdCtxOrdinals epFwdCtxOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
EndpointKey endpointKey = endpoint.getKey();
for (EndpointL3 l3Endpoint : l3Endpoints) {
L2BridgeDomainId l2Context = l3Endpoint.getL2Context();
MacAddress macAddress = l3Endpoint.getMacAddress();
if (l2Context != null && macAddress != null) {
Endpoint l2EpFromL3Ep = ctx.getEndpointManager().getEndpoint(new EpKey(l2Context, macAddress));
if(endpointKey.equals(l2EpFromL3Ep.getKey())) {
if (epFwdCtxOrdinals != null) {
flows.createNatFlow(destinationMapperId, l3Endpoint, epFwdCtxOrdinals, NAT, ofWriter);
}
IndexedTenant tenant = ctx.getTenant(endpoint.getTenant());
if (tenant != null) {
flows.createArpFlow(tenant, l3Endpoint, ARP, ofWriter);
}
// L3 Endpoint found, end of loop
break;
}
}
}
// Flows for ingress traffic that does not have to be translated.
for (EgKey endpointGroupKey : ctx.getEndpointManager().getEgKeysForEndpoint(endpoint)) {
for (EgKey peer : Sets.union(Collections.singleton(endpointGroupKey),
ctx.getCurrentPolicy().getPeers(endpointGroupKey))) {
for (Endpoint externalEndpoint : ctx.getEndpointManager().getExtEpsNoLocForGroup(peer)) {
if (epFwdCtxOrdinals != null) {
flows.createIngressExternalNatFlows(destinationMapperId, externalEndpoint, epFwdCtxOrdinals,
NAT_EXTERNAL, ofWriter);
flows.createIngressExternalArpFlows(destinationMapperId, externalEndpoint, epFwdCtxOrdinals,
ARP_EXTERNAL, ofWriter);
}
}
}
}
}
}