return resolveDomain(L2FloodDomain.class, id);
}
+ /**
+ * Get the subnet based on it's ID. Since subnet is on the bottom
+ * of the forwarding hierarchy, there is no other underlying domain
+ * from which {@link Subnet} could be resolved. That is why the
+ * argument refers directly to {@link SubnetId} and not
+ * {@link NetworkDomainId}
+ *
+ * @param id of the {@link Subnet}
+ * @return the {@link Subnet} or <code>null</code> if it does
+ * not exist
+ */
+ public Subnet resolveSubnet(SubnetId id) {
+ return resolveDomain(Subnet.class, id);
+ }
+
/**
* Resolve all subnets applicable to the given network domain ID
* @param id the {@link NetworkDomainId}
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
import org.opendaylight.groupbasedpolicy.util.IidFactory;
import org.opendaylight.groupbasedpolicy.util.SetUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointFields;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
return endpoints.getEndpointL3();
}
+ /**
+ * Reads endpointL3 from data store
+ * @param l3c id of {@link L3Context}
+ * @param ipAddress IP address of the endpoint
+ * @param tenantId ID of {@link Tenant} can be optionally specified
+ * @return {@link EndpointL3} if exists, otherwise null.
+ */
+ public EndpointL3 getL3Endpoint(L3ContextId l3c, IpAddress ipAddress, @Nullable TenantId tenantId) {
+ if (l3c == null || ipAddress == null) {
+ LOG.warn("[ContextId: {}, IpAddress: {}] Cannot read endpoint from DS unless both keys are specified!",
+ l3c, ipAddress);
+ return null;
+ }
+ ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
+ Optional<EndpointL3> endpointL3 = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
+ IidFactory.l3EndpointIid(l3c, ipAddress), rTx);
+ rTx.close();
+ if (!endpointL3.isPresent()) {
+ LOG.warn("EndpointL3 [{},{}] not found in data store.", l3c, ipAddress);
+ return null;
+ }
+ if(tenantId != null && !endpointL3.get().getTenant().equals(tenantId)) {
+ LOG.warn("EndpointL3 [{},{}] not found in data store for tenant: {}", l3c, ipAddress, tenantId);
+ return null;
+ }
+ return endpointL3.get();
+ }
+
/**
* Return all L3Prefix Endpoints from data store.
*
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ForwardingContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
EgKey epg = new EgKey(srcEp.getTenant(), epgId);
Set<EgKey> peers = Sets.union(Collections.singleton(epg), ctx.getCurrentPolicy().getPeers(epg));
for (EgKey peer : peers) {
- for (Endpoint peerEp : ctx.getEndpointManager().getEndpointsForGroup(peer)) {
+ Collection<Endpoint> endpointsForGroup = new HashSet<>();
+ endpointsForGroup.addAll(ctx.getEndpointManager().getEndpointsForGroup(peer));
+ endpointsForGroup.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(peer));
+ for (Endpoint peerEp : endpointsForGroup) {
currentTenant = peerEp.getTenant();
subnetsByTenant.put(currentTenant, getSubnets(currentTenant));
EpKey srcEpKey = new EpKey(srcEp.getL2Context(), srcEp.getMacAddress());
}
}
+
+
// set up next-hop destinations for all the endpoints in the endpoint
// group on the node
return;
}
- if (EndpointManager.isExternal(destEp, ctx.getTenant(destEp.getTenant()).getExternalImplicitGroups())) {
- LOG.error("syncEp(): External endpoints should not be seen here.");
- return;
- }
-
/*
* Only care about subnets for L3, but fetch them before loop. We need
* the local subnets for setting SRC MAC for routing. All Routing is now
}
OfOverlayContext ofc = destEp.getAugmentation(OfOverlayContext.class);
- if (Objects.equals(ofc.getNodeId(), nodeId)) {
+
+ // forwarding outside of internal domain should be done when dest EP or GW is external.
+ Subnet srcSubnet = ctx.getTenant(srcEp.getTenant()).resolveSubnet(new SubnetId(srcEp.getNetworkContainment()));
+ Endpoint l2Gw = this.getL2EndpointOfSubnetGateway(srcEp.getTenant(), srcSubnet);
+ boolean destEpIsExternal = destEp.getNetworkContainment() != null
+ && EndpointManager.isExternal(destEp, ctx.getTenant(destEp.getTenant()).getExternalImplicitGroups());
+ boolean subnetGwIsExternal = l2Gw != null
+ && EndpointManager.isExternal(l2Gw, ctx.getTenant(l2Gw.getTenant()).getExternalImplicitGroups());
+ if (destEpIsExternal || subnetGwIsExternal) {
+ if (ofc == null && destEp.getNetworkContainment().equals(srcEp.getNetworkContainment())) {
+ Flow flow = createExternalL2Flow(destEp, destEpFwdCtxOrds, nodeId);
+ if (flow != null) {
+ ofWriter.writeFlow(nodeId, TABLE_ID, flow);
+ }
+ } else if (l2Gw != null && EndpointManager.isExternal(l2Gw, ctx.getTenant(l2Gw.getTenant()).getExternalImplicitGroups())
+ && !destEp.getNetworkContainment().equals(srcEp.getNetworkContainment())) {
+ for (L3Address l3a : destEp.getL3Address()) {
+ if (l3a.getIpAddress() == null || l3a.getL3Context() == null) {
+ LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}",
+ destEp.getL3Address());
+ continue;
+ }
+ for (Subnet localSubnet : localSubnets) {
+ Flow extL3Flow = createExternalL3RoutedFlow(destEp, l3a, destEpFwdCtxOrds, localSubnet, nodeId);
+ if (extL3Flow != null) {
+ ofWriter.writeFlow(nodeId, TABLE_ID, extL3Flow);
+ } else {
+ LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
+ localSubnet.getIpPrefix().getValue());
+ }
+ }
+ }
+ }
+ }
+ else if (ofc != null && Objects.equals(ofc.getNodeId(), nodeId)) {
// this is a local endpoint; send to the approppriate local
// port
}
}
}
- } else {
+ } else if(ofc!= null) {
// this endpoint is on a different switch; send to the
// appropriate tunnel
if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
return flowb.build();
}
+ private Flow createExternalL3RoutedFlow(Endpoint destEp, L3Address destL3Address, EndpointFwdCtxOrdinals epFwdCtxOrds,
+ Subnet srcSubnet, NodeId nodeId) {
+
+ Subnet destSubnet = null;
+ HashSet<Subnet> subnets = getSubnets(destEp.getTenant());
+ if (subnets == null) {
+ LOG.trace("No subnets in tenant {}", destEp.getTenant());
+ return null;
+ }
+ NetworkDomainId epNetworkContainment = getEPNetworkContainment(destEp);
+ for (Subnet subnet : subnets) {
+ // TODO Li alagalah add IPv6 support
+ if (subnet.getId().getValue().equals(epNetworkContainment.getValue())) {
+ destSubnet = subnet;
+ break;
+ }
+ }
+ if (destSubnet == null) {
+ LOG.trace("Destination IP address does not match any subnet in tenant {}", destL3Address.getIpAddress());
+ return null;
+ }
+
+ if (destSubnet.getVirtualRouterIp() == null) {
+ LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", destSubnet.getIpPrefix(),
+ destL3Address.getKey());
+ return null;
+ }
+
+ if (srcSubnet.getVirtualRouterIp() == null) {
+ LOG.trace("Local subnet {} has no gateway IP", srcSubnet.getIpPrefix());
+ return null;
+ }
+ L3Context destL3c = getL3ContextForSubnet(destEp.getTenant(), destSubnet);
+ if (destL3c == null || destL3c.getId() == null) {
+ LOG.error("No L3 Context found associated with subnet {}", destSubnet.getId());
+ return null;
+ }
+ L3Context srcL3c = getL3ContextForSubnet(destEp.getTenant(), srcSubnet);
+ if (srcL3c == null || srcL3c.getId() == null) {
+ LOG.error("No L3 Context found associated with subnet {}", srcSubnet.getId());
+ return null;
+ }
+
+ if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) {
+ LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId()
+ .getValue(), destL3c.getId().getValue());
+ return null;
+ }
+
+ Endpoint l2Gw = getL2EndpointOfSubnetGateway(destEp.getTenant(), srcSubnet);
+ if(l2Gw == null) {
+ LOG.warn("The endpoint representing external gateway of subnet {} not found", srcSubnet);
+ return null;
+ }
+ MacAddress matcherMac = destEp.getMacAddress();
+ MacAddress destSubnetGatewayMac = l2Gw.getMacAddress();
+
+ ArrayList<Instruction> l3instructions = new ArrayList<>();
+ List<Action> applyActions = new ArrayList<>();
+ List<Action> l3ApplyActions = new ArrayList<>();
+
+ int order = 0;
+
+ Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
+ Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
+ Action setNextHop;
+
+ Set<NodeConnectorId> extPorts = ctx.getSwitchManager().getExternalPorts(nodeId);
+ if (extPorts == null || !extPorts.iterator().hasNext()) {
+ LOG.warn("No external interface on node: {}. External Gateway {} is not reachable!", nodeId, l2Gw.getKey());
+ return null;
+ }
+ // only one external port is supported for now
+ NodeConnectorId extPort = extPorts.iterator().next();
+
+ long portNum;
+ try {
+ portNum = getOfPortNum(extPort);
+ } catch (NumberFormatException ex) {
+ LOG.warn("Could not parse port number {}", extPort, ex);
+ return null;
+ }
+
+ setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
+ // END L3 LOCAL
+
+
+ Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
+ l3ApplyActions.add(setDlSrc);
+
+ Action setDlDst = setDlDstAction(l2Gw.getMacAddress());
+ l3ApplyActions.add(setDlDst);
+
+ order += 1;
+ applyActions.add(setdEPG);
+ applyActions.add(setdCG);
+ applyActions.add(setNextHop);
+
+ applyActions.addAll(l3ApplyActions);
+ Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
+ .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+ .build();
+
+ l3instructions.add(applyActionsIns);
+ Instruction gotoTable = new InstructionBuilder().setOrder(order++)
+ .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
+ .build();
+ l3instructions.add(gotoTable);
+ Layer3Match m = null;
+ Long etherType = null;
+ String ikey = null;
+ if (destL3Address.getIpAddress().getIpv4Address() != null) {
+ ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
+ etherType = IPv4;
+ m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
+ } else if (destL3Address.getIpAddress().getIpv6Address() != null) {
+ ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
+ etherType = IPv6;
+ m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
+ } else {
+ LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", destL3Address.toString());
+ return null;
+ }
+
+ MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
+ .setLayer3Match(m);
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, Long.valueOf(epFwdCtxOrds.getL3Id())));
+ Match match = mb.build();
+ FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "externalL3", match);
+ FlowBuilder flowb = base().setId(flowid)
+ .setPriority(Integer.valueOf(132))
+ .setMatch(match)
+ .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
+ return flowb.build();
+ }
+
+ private Endpoint getL2EndpointOfSubnetGateway(TenantId tenantId, Subnet subnet) {
+ if (subnet != null && subnet.getVirtualRouterIp() != null) {
+ IpAddress gwIpAddress = subnet.getVirtualRouterIp();
+ Collection<EndpointL3Prefix> prefixEps = ctx.getEndpointManager().getEndpointsL3PrefixForTenant(tenantId);
+ if (prefixEps != null) {
+ for (EndpointL3Prefix prefixEp : prefixEps) {
+ for (EndpointL3Gateways gw : prefixEp.getEndpointL3Gateways()) {
+ EndpointL3 l3Ep = ctx.getEndpointManager().getL3Endpoint(gw.getL3Context(), gwIpAddress,
+ prefixEp.getTenant());
+ if (l3Ep != null && l3Ep.getL2Context() != null && l3Ep.getMacAddress() != null) {
+ return ctx.getEndpointManager().getEndpoint(
+ new EpKey(l3Ep.getL2Context(), l3Ep.getMacAddress()));
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
private Flow createRemoteL2Flow(Endpoint ep, NodeId nodeId, EndpointFwdCtxOrdinals srcEpFwdCtxOrds,
EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc) {
return flowb.build();
}
+ private Flow createExternalL2Flow(Endpoint ep, EndpointFwdCtxOrdinals epFwdCtxOrds,NodeId nodeId) {
+
+ ArrayList<Instruction> instructions = new ArrayList<>();
+ List<Action> applyActions = new ArrayList<>();
+
+ int order = 0;
+
+ Action setdEPG = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(epFwdCtxOrds.getEpgId()));
+ Action setdCG = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(epFwdCtxOrds.getCgId()));
+ Action setNextHop;
+
+ // BEGIN L2 LOCAL
+ Set<NodeConnectorId> extPorts = ctx.getSwitchManager().getExternalPorts(nodeId);
+ if(extPorts == null || !extPorts.iterator().hasNext()) {
+ return null;
+ }
+ // Only one external port is currently supported.
+ NodeConnectorId extPort = extPorts.iterator().next();
+ long portNum;
+ try {
+ portNum = getOfPortNum(extPort);
+ } catch (NumberFormatException ex) {
+ LOG.warn("Could not parse port number {}", extPort, ex);
+ return null;
+ }
+ setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(portNum));
+
+ // END L2 LOCAL
+
+ order += 1;
+ applyActions.add(setdEPG);
+ applyActions.add(setdCG);
+ applyActions.add(setNextHop);
+ Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
+ .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+ .build();
+ instructions.add(applyActionsIns);
+
+ Instruction gotoTable = new InstructionBuilder().setOrder(order++)
+ .setInstruction(gotoTableIns(ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()))
+ .build();
+ instructions.add(gotoTable);
+
+ MatchBuilder mb = new MatchBuilder().setEthernetMatch(ethernetMatch(null, ep.getMacAddress(), null));
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(epFwdCtxOrds.getBdId())));
+ Match match = mb.build();
+ FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "externalL2", match);
+ FlowBuilder flowb = base().setId(flowid)
+ .setPriority(Integer.valueOf(50))
+ .setMatch(match)
+ .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
+ return flowb.build();
+ }
+
private Flow createRemoteL3RoutedFlow(Endpoint destEp, L3Address destL3Address, NodeId nodeId,
EndpointFwdCtxOrdinals srcEpFwdCtxOrds, EndpointFwdCtxOrdinals destEpFwdCtxOrds, OfOverlayContext ofc,
Subnet srcSubnet) {
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
+
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import java.math.BigInteger;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
import org.apache.commons.lang3.ArrayUtils;
+import org.opendaylight.groupbasedpolicy.dto.EgKey;
import org.opendaylight.groupbasedpolicy.dto.EpKey;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
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.EndpointL3;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
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.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
/**
* Manage the table that assigns source endpoint group, bridge domain, and
* router domain to registers to be used by other tables.
@Override
public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
- // TODO for consideration: default instruction is goto next table because when matching against eth type 0x8100
- // in PortSecurity, it's not possible to match against IPv4 addresses (only inf eth type would be 0x800)
- // We can't determine just from L2 layer if traffic should be passed from PortSecurity here to IngressNat or to
- // SourceMapper. Various 802.1q encapsulated IPs can pass through external ports - NATed or not NATed, remote
- // or directly connected.
- // All external ingress traffic is currently passed here and if no match is foud - no NAT is performed
- // and processing continues in SourceMapper.
+ /**
+ * To support provider networks, all external ingress traffic is currently passed here and
+ * if no match is foud - no NAT is performed and processing continues in DestinationMapper.
+ */
Flow flow = base()
.setTableId(TABLE_ID)
.setPriority(1)
- .setInstructions(FlowUtils.instructions(FlowUtils.gotoTableIns(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER())))
- .setId(FlowIdUtils.newFlowId("gotoSourceMapper"))
+ .setInstructions(
+ FlowUtils.instructions(FlowUtils.gotoTableIns(
+ ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())))
+ .setId(FlowIdUtils.newFlowId("gotoDestinationMapper"))
.build();
ofWriter.writeFlow(nodeId, TABLE_ID, flow);
// TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
+ // Flows for ingress NAT translation
Collection<Endpoint> endpointsForNode = ctx.getEndpointManager().getEndpointsForNode(nodeId);
Collection<EndpointL3> l3Endpoints = ctx.getEndpointManager().getL3EndpointsWithNat();
for (EndpointL3 l3Ep : l3Endpoints) {
}
}
}
+ //Flows for ingress traffic that does not have to be translated.
+ // TODO similar loop in DestinationMapper
+ for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+ for (EgKey egKey : ctx.getEndpointManager().getEgKeysForEndpoint(ep)) {
+ Set<EgKey> groups = ctx.getCurrentPolicy().getPeers(egKey);
+ for (EgKey peer : Sets.union(Collections.singleton(egKey), ctx.getCurrentPolicy().getPeers(egKey))) {
+ for (Endpoint extEp : ctx.getEndpointManager().getExtEpsNoLocForGroup(peer)) {
+ createIngressExternalFlows(extEp, nodeId, ofWriter);
+ }
+ }
+ }
+ }
}
private void createNatFlow(EndpointL3 l3Ep, NodeId nodeId, OfWriter ofWriter) throws Exception {
}
}
+ private void createIngressExternalFlows(Endpoint ep, NodeId nodeId, OfWriter ofWriter) throws Exception {
+ EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, ep);
+ if (epFwdCtxOrds == null) {
+ LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", ep);
+ return;
+ }
+ if (ep.getL3Address() != null) {
+ for (L3Address l3Addr : ep.getL3Address()) {
+ Flow ipFlow = buildIngressExternalIpFlow(l3Addr.getIpAddress(), epFwdCtxOrds);
+ if (ipFlow != null) {
+ ofWriter.writeFlow(nodeId, TABLE_ID, ipFlow);
+ }
+ }
+ }
+ Flow arpFlow = buildIngressExternalArpFlow(ep.getMacAddress(), epFwdCtxOrds);
+ if (arpFlow != null) {
+ ofWriter.writeFlow(nodeId, TABLE_ID, arpFlow);
+ }
+ }
+
private Flow buildNatFlow(IpAddress outsideDestAddress, IpAddress insideDestAddress, MacAddress toMac,
EndpointFwdCtxOrdinals epFwdCtxOrds) {
- // TODO Auto-generated method stub
- MatchBuilder mb = new MatchBuilder();
Action setDestIp;
- String outsideIpMatch;
- Layer3Match m;
-
Action setDestMac = setDlDstAction(toMac);
FlowId flowid = new FlowId(new StringBuilder().append("IngressNat")
.append("|")
.toString());
if (insideDestAddress.getIpv4Address() != null) {
setDestIp = setIpv4DstAction(insideDestAddress.getIpv4Address());
-
- outsideIpMatch = outsideDestAddress.getIpv4Address().getValue() + "/32";
- m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(outsideIpMatch)).build();
- mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv4)).setLayer3Match(m);
} else if (insideDestAddress.getIpv6Address() != null) {
setDestIp = setIpv6DstAction(insideDestAddress.getIpv6Address());
- outsideIpMatch = outsideDestAddress.getIpv6Address().getValue() + "/128";
- m = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(outsideIpMatch)).build();
- mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv6)).setLayer3Match(m);
} else {
return null;
}
-
- int egId = epFwdCtxOrds.getEpgId();
- int bdId = epFwdCtxOrds.getBdId();
- int fdId = epFwdCtxOrds.getFdId();
- int l3Id = epFwdCtxOrds.getL3Id();
- int cgId = epFwdCtxOrds.getCgId();
- int tunnelId = epFwdCtxOrds.getTunnelId();
- Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
- Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(cgId));
- Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
- Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
- Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
- Action tunIdAction = nxLoadTunIdAction(BigInteger.valueOf(tunnelId), false);
-
+ MatchBuilder mb = createMatchOnDstIpAddress(outsideDestAddress);
+ Action[] dstIpMacAction = {setDestIp, setDestMac};
FlowBuilder flowb = base().setPriority(Integer.valueOf(100))
.setId(flowid)
.setMatch(mb.build())
.setInstructions(
instructions(
- applyActionIns(setDestIp, setDestMac, segReg, scgReg, bdReg, fdReg, vrfReg, tunIdAction),
+ applyActionIns(ArrayUtils.addAll(dstIpMacAction, createEpFwdCtxActions(epFwdCtxOrds))),
gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
return flowb.build();
}
return flowb.build();
}
+ /**
+ * Builds flow for inbound IP traffic of registered external endpoint.
+ * Priority should be lower than in NAT flow.
+ */
+ private Flow buildIngressExternalIpFlow(IpAddress srcIpAddress, EndpointFwdCtxOrdinals epFwdCtxOrds) {
+ MatchBuilder mb = createMatchOnSrcIpAddress(srcIpAddress);
+ if (mb == null) {
+ return null;
+ }
+ FlowBuilder flowb = base().setPriority(Integer.valueOf(90))
+ .setId(FlowIdUtils.newFlowId(TABLE_ID, "inbound-external-ip", mb.build()))
+ .setMatch(mb.build())
+ .setInstructions(
+ instructions(applyActionIns(createEpFwdCtxActions(epFwdCtxOrds)),
+ gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
+ return flowb.build();
+ }
+
+ /**
+ * @param srcIpAddress can be IPv4 or IPv6
+ * @return {@link MatchBuilder} with specified L2 ethertype and L3 source address.
+ * Returns null if srcIpAddress is null.
+ */
+ private MatchBuilder createMatchOnSrcIpAddress(IpAddress srcIpAddress) {
+ return createMatchOnIpAddress(srcIpAddress, true);
+ }
+
+ private MatchBuilder createMatchOnDstIpAddress(IpAddress srcIpAddress) {
+ return createMatchOnIpAddress(srcIpAddress, false);
+ }
+
+ // use createMatchOnSrcIpAddress or createMatchOnDstIpAddress
+ private MatchBuilder createMatchOnIpAddress(IpAddress srcIpAddress, boolean isSourceAddress) {
+ MatchBuilder mb = new MatchBuilder();
+ String ipPrefix;
+ Layer3Match m;
+ if (srcIpAddress.getIpv4Address() != null) {
+ ipPrefix = srcIpAddress.getIpv4Address().getValue() + "/32";
+ m = (isSourceAddress) ? new Ipv4MatchBuilder().setIpv4Source(new Ipv4Prefix(ipPrefix)).build() :
+ new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ipPrefix)).build();
+ mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv4))
+ .setLayer3Match(m);
+ return mb;
+ } else if (srcIpAddress.getIpv6Address() != null) {
+ ipPrefix = srcIpAddress.getIpv6Address().getValue() + "/128";
+ m = (isSourceAddress) ? new Ipv6MatchBuilder().setIpv6Source(new Ipv6Prefix(ipPrefix)).build() :
+ new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ipPrefix)).build();
+ mb.setEthernetMatch(ethernetMatch(null, null, FlowUtils.IPv6))
+ .setLayer3Match(m);
+ return mb;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Builds flow for inbound ARP traffic of registered external endpoint.
+ * Priority should be lower than in ARP flow for NAT address.
+ */
+ private Flow buildIngressExternalArpFlow(MacAddress srcMac, EndpointFwdCtxOrdinals epFwdCtxOrds) {
+ if (srcMac == null) {
+ return null;
+ }
+ MatchBuilder mb = new MatchBuilder()
+ .setEthernetMatch(ethernetMatch(srcMac, null, ARP));
+ //.setLayer3Match(
+ // new ArpMatchBuilder()
+ // .setArpOp(Integer.valueOf(2))
+ // .build());
+ FlowBuilder flowb = base().setPriority(80);
+ flowb.setInstructions(instructions(applyActionIns(createEpFwdCtxActions(epFwdCtxOrds)),
+ gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
+ flowb.setId(FlowIdUtils.newFlowId(TABLE_ID, "inbound-external-arp", mb.build()));
+ flowb.setMatch(mb.build());
+ return flowb.build();
+ }
+
+ private Action[] createEpFwdCtxActions(EndpointFwdCtxOrdinals epFwdCtxOrds) {
+ int egId = epFwdCtxOrds.getEpgId();
+ int bdId = epFwdCtxOrds.getBdId();
+ int fdId = epFwdCtxOrds.getFdId();
+ int l3Id = epFwdCtxOrds.getL3Id();
+ int cgId = epFwdCtxOrds.getCgId();
+ int tunnelId = epFwdCtxOrds.getTunnelId();
+ Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
+ Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(cgId));
+ Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
+ Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
+ Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
+ Action tunIdAction = nxLoadTunIdAction(BigInteger.valueOf(tunnelId), false);
+ Action[] outsideArpActions = {segReg, scgReg, bdReg, fdReg, vrfReg, tunIdAction};
+ return outsideArpActions;
+ }
+
static byte[] bytesFromHexString(String values) {
String target = "";
if (values != null) {
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
import org.opendaylight.groupbasedpolicy.dto.EgKey;
import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
+import org.opendaylight.groupbasedpolicy.dto.EpKey;
import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
import org.opendaylight.groupbasedpolicy.dto.Policy;
import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
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.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
.getTenant()
.getPolicy()
.getExternalImplicitGroup();
- if (EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
- flow.setInstructions(instructions(gotoEgressNatInstruction));
- } else if (actionBuilderList == null) {
+ boolean performNat = false;
+ for (EndpointL3 natEp : ctx.getEndpointManager().getL3EndpointsWithNat()) {
+ if (natEp.getMacAddress() != null &&
+ natEp.getL2Context() != null &&
+ netElements.getSrcEp().getKey().equals(new EndpointKey(natEp.getL2Context(),
+ natEp.getMacAddress())) &&
+ EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
+ performNat = true;
+ break;
+ }
+ }
+ if (actionBuilderList == null) {
//TODO - analyse, what happen for unknown action, SFC, etc.
LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
continue;
- } else if (actionBuilderList.isEmpty()) {
- flow.setInstructions(instructions(gotoExternalInstruction));
+ }
+ if (actionBuilderList.isEmpty()) {
+ flow.setInstructions((performNat == true) ? instructions(gotoEgressNatInstruction) : instructions(gotoExternalInstruction));
} else {
- flow.setInstructions(instructions(applyActionIns(actionBuilderList), gotoExternalInstruction));
+ flow.setInstructions(instructions(applyActionIns(actionBuilderList),
+ (performNat == true) ? gotoEgressNatInstruction : gotoExternalInstruction));
}
ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
}
.setL2Context(bd)\r
.setTenant(tid)\r
.setEndpointGroup(eg)\r
- .setMacAddress(new MacAddress("00:00:00:00:00:01"));\r
+ .setMacAddress(new MacAddress("00:00:00:00:00:01"))\r
+ .setNetworkContainment(sub2);\r
}\r
\r
protected EndpointBuilder localEP() {\r