/* * 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.flow; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNsiMatch; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNspMatch; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxTunIdMatch; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxTunIpv4DstMatch; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix; 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.Match; 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.go.to.table._case.GoToTable; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction; 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.model.match.types.rev131026.match.Layer3Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder; 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.openflowjava.nx.match.rev140421.NxmNxReg7; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; /** *
* * Flow that allows ALL traffic incoming from chain last hop *
* Allow from chain flow
* Table = 0
* Priority = 1200
* Matches:
* - Nshc1
* - Nsp
* - Nsi
* - in_port (tunnel port) {@link NodeConnectorId}
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
* TODO: looks like duplicity, the same flow is created in policy enforcer
* Allow from chain tunnel
* Table = 4
* Priority = 65000
* Matches:
* - in_port (tunnel port) {@link NodeConnectorId}
* - Reg7 (fixed value 0xffffff) {@link NxmNxReg7}
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
* Create external flow
* Table = 6
* Priority = 1000 (if dst node == src node, priority = 1500)
* Matches:
* - Reg6 {@link NxmNxReg6}
* - tunnel ID
* - nsp
* - nsi
* - tun_dst (only if dst node == src node)
* Actions:
* - set nshc1
* - set nshc2
* - load tunnel ID
* - load tunnel ipv4
* - output:(tunnel port)
*
* Chain tunnel flow
* Table = 2
* Priority = 150
* Matches:
* - in_port (tunnel port) {@link NodeConnectorId}
* - tunnel ID
* - nsp
* - nsi
* Actions:
* - Reg0 {@link NxmNxReg0}
* - Reg1 {@link NxmNxReg1}
* - Reg4 {@link NxmNxReg4}
* - Reg5 {@link NxmNxReg5}
* - Reg6 {@link NxmNxReg6}
* - {@link GoToTable} DESTINATION MAPPER table
*
* Chain broadcast flow
* Table = 2
* Priority = 150
* Matches:
* - in_port (tunnel port) {@link NodeConnectorId}
* - tunnel ID
* - nsp
* - nsi
* Actions:
* - load Reg5 {@link NxmNxReg5}
* - {@link GoToTable} DESTINATION MAPPER table
*/
public class ChainActionFlows {
private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
public ChainActionFlows() {
}
public static void createChainTunnelFlows(SfcNshHeader sfcNshHeader, NetworkElements netElements, OfWriter ofWriter,
OfContext ctx, Direction direction) {
NodeId localNodeId = netElements.getLocalNodeId();
EndpointFwdCtxOrdinals epOrdinals = netElements.getSrcEpOrdinals();
NodeConnectorId localNodeTunPort = ctx.getSwitchManager().getTunnelPort(localNodeId, TunnelTypeVxlanGpe.class);
Ipv4Address tunDestAddress = ctx.getSwitchManager()
.getTunnelIP(netElements.getDstNodeId(), TunnelTypeVxlanGpe.class)
.getIpv4Address();
if (localNodeTunPort == null) {
LOG.error("createChainTunnelFlows: No valid VXLAN GPE tunnel for Node {} ", localNodeId);
return;
}
if (direction.equals(Direction.In)) {
ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), allowFromChainPort(
sfcNshHeader, localNodeTunPort, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), ctx));
for (Flow flow : createChainTunnelFlow(sfcNshHeader, localNodeTunPort, netElements,
ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx)) {
ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), flow);
}
ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(),
allowFromChainTunnel(localNodeTunPort, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()));
ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(),
createChainBroadcastFlow(sfcNshHeader, localNodeTunPort, epOrdinals,
ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
} else {
ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER(),
createExternalFlow(sfcNshHeader, localNodeTunPort, netElements, ctx.getPolicyManager(),
ctx.getSwitchManager(), tunDestAddress));
}
}
private static Flow createChainBroadcastFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
EndpointFwdCtxOrdinals epFwdCtxOrds, short tableId, OfContext ctx) {
int fdId = epFwdCtxOrds.getFdId();
MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
addNxTunIdMatch(mb, fdId);
org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action fdReg =
nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
Match match = mb.build();
FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainbroadcast", match);
FlowBuilder flowb = base(tableId).setId(flowId)
.setPriority(150)
.setMatch(match)
.setInstructions(instructions(applyActionIns(fdReg),
gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
return flowb.build();
}
private static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements,
PolicyManager policyManager, SwitchManager switchManager, Ipv4Address ipTunDest) {
short tableId = policyManager.getTABLEID_EXTERNAL_MAPPER();
org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadC1;
org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action outputAction;
Integer priority = 1000;
int matchTunnelId = netElements.getSrcEpOrdinals().getTunnelId();
long setTunnelId = netElements.getDstEpOrdinals().getTunnelId();
Long l3c = (long) netElements.getSrcEpOrdinals().getL3Id();
loadC1 = nxLoadNshc1RegAction(sfcNshHeader.getNshMetaC1());
// Test for if SFF is on same node
IpAddress ipAddress = switchManager.getTunnelIP(netElements.getLocalNodeId(), TunnelTypeVxlanGpe.class);
if (ipAddress != null && ipAddress.getIpv4Address().equals(sfcNshHeader.getNshTunIpDst())) {
Integer newPort = returnOfPortFromNodeConnector(tunPort);
outputAction = FlowUtils.createActionResubmit(newPort, policyManager.getTABLEID_SFC_EGRESS());
} else {
outputAction = outputAction(tunPort);
}
org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadC2 =
nxLoadNshc2RegAction(setTunnelId);
org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
nxLoadTunIdAction(BigInteger.valueOf(setTunnelId), false);
org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
nxLoadTunIPv4Action(sfcNshHeader.getNshTunIpDst().getValue(), false);
MatchBuilder mb = new MatchBuilder();
addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, l3c));
addNxTunIdMatch(mb, matchTunnelId);
addNxNspMatch(mb, sfcNshHeader.getNshNspToChain());
addNxNsiMatch(mb, sfcNshHeader.getNshNsiToChain());
if (!netElements.getDstNodeId().equals(netElements.getSrcNodeId())) {
addNxTunIpv4DstMatch(mb, ipTunDest);
priority = 1500;
}
Match match = mb.build();
FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainexternal", match);
FlowBuilder flowb =
base(tableId).setId(flowId).setPriority(priority).setMatch(match).setInstructions(
instructions(applyActionIns(loadC1, loadC2, loadChainTunDest, loadChainTunVnid, outputAction)));
return flowb.build();
}
private static List