/* * Copyright (c) 2017 Serro LLC. 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.nic.of.renderer.impl; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.nic.of.renderer.exception.DataflowCreationException; import org.opendaylight.nic.of.renderer.exception.MeterCreationExeption; import org.opendaylight.nic.of.renderer.exception.MeterRemovalExeption; import org.opendaylight.nic.of.renderer.exception.PushFlowFlorAllDevicesException; import org.opendaylight.nic.of.renderer.strategy.MeterExecutor; import org.opendaylight.nic.of.renderer.utils.TopologyUtils; import org.opendaylight.nic.utils.MdsalUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; 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; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; 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.inventory.rev130819.tables.table.FlowKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags; 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.InstructionsBuilder; 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.MeterCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.meter._case.MeterBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId; 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.Ipv4MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.nic.renderer.api.dataflow.rev170309.dataflows.Dataflow; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; public class OFRuleWithMeterManager { private static final Logger LOG = LoggerFactory.getLogger(OFRuleWithMeterManager.class); private final MdsalUtils mdsalUtils; private final DataBroker dataBroker; private final MeterExecutor meterExecutor; private final Long OFP_NO_BUFFER = Long.valueOf(4294967295L); private final AtomicLong flowCookieInc = new AtomicLong(0x3a00000000000000L); private final Long ETHER_TYPE = 0x0800L; private final IdManagerService idManagerService; protected OFRuleWithMeterManager(final DataBroker dataBroker, final IdManagerService idManagerService) { this.dataBroker = dataBroker; this.mdsalUtils = new MdsalUtils(dataBroker); this.meterExecutor = new MeterExecutor(dataBroker, idManagerService); this.idManagerService = idManagerService; } public FlowBuilder createFlow(final Dataflow dataFlow) throws DataflowCreationException { FlowBuilder flowBuilder = new FlowBuilder(); try { final FlowModFlags flowModFlags = new FlowModFlags(false, false, false, false, false); final FlowId flowId = new FlowId(dataFlow.getId().toString()); final FlowKey flowKey = new FlowKey(flowId); final MeterId meterId = new MeterId(dataFlow.getMeterId().longValue()); flowBuilder.setFlowName("NIC_METER" + meterId.getValue()); flowBuilder.setId(new FlowId(Long.toString(flowBuilder.hashCode()))); flowBuilder.setMatch(createMatch(dataFlow.getSourceIpAddress())); flowBuilder.setInstructions(createInstruction(meterId)); flowBuilder.setPriority(OFRendererConstants.DEFAULT_PRIORITY); flowBuilder.setCookie(new FlowCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement()))); flowBuilder.setBufferId(OFP_NO_BUFFER); flowBuilder.setHardTimeout((int) dataFlow.getTimeout()); flowBuilder.setIdleTimeout((int) dataFlow.getTimeout()); flowBuilder.setFlags(flowModFlags); flowBuilder.setKey(flowKey); } catch (Exception e) { throw new DataflowCreationException(e.getMessage()); } return flowBuilder; } public MeterId retrieveMeterId(final Dataflow dataflow) throws MeterCreationExeption { final Short id = dataflow.getMeterId(); final MeterId meterId = (id != null ? new MeterId(id.longValue()) : meterExecutor.createMeter(dataflow)); return meterId; } public MeterId createMeter(final String id, final long dropRate) throws MeterCreationExeption { return meterExecutor.createMeter(id, dropRate); } public Future<RpcResult<Void>> removeMeter(final Long meterId, final String dataflowId) throws MeterRemovalExeption { return meterExecutor.removeMeter(meterId, dataflowId); } private Match createMatch(Ipv4Prefix ipv4Prefix) { final Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder(); ipv4MatchBuilder.setIpv4Source(ipv4Prefix); Layer3Match layer3Match = ipv4MatchBuilder.build(); final MatchBuilder matchBuilder = new MatchBuilder(); final EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder(); final EthernetTypeBuilder ethernetTypeBuilder = new EthernetTypeBuilder(); ethernetTypeBuilder.setType(new EtherType(ETHER_TYPE)); ethernetMatchBuilder.setEthernetType(ethernetTypeBuilder.build()); matchBuilder.setLayer3Match(layer3Match); matchBuilder.setEthernetMatch(ethernetMatchBuilder.build()); return matchBuilder.build(); } private Instructions createInstruction(final MeterId meterId) { MeterBuilder meterBuilder = new MeterBuilder(); meterBuilder.setMeterId(meterId); Instruction instruction = new InstructionBuilder() .setOrder(0) .setInstruction(new MeterCaseBuilder() .setMeter(meterBuilder.build()).build()).build(); List<Instruction> instructions = new ArrayList<>(); instructions.add(instruction); InstructionsBuilder instructionsBuilder = new InstructionsBuilder(); instructionsBuilder.setInstruction(instructions); return instructionsBuilder.build(); } public boolean sendToMdsal(final FlowBuilder flowBuilder, final NodeId nodeId) { final NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(nodeId); nodeBuilder.setKey(new NodeKey(nodeId)); return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, retrieveIdentifier(nodeBuilder, flowBuilder), flowBuilder.build()); } public void pushFlowForAllDevices(final FlowBuilder flowBuilder) throws PushFlowFlorAllDevicesException { final Set<Boolean> results = new HashSet<>(); final Map<Node, List<NodeConnector>> nodeMap = TopologyUtils.getNodes(dataBroker); for (Map.Entry<Node, List<NodeConnector>> entry : nodeMap.entrySet()) { final boolean result = sendToMdsal(flowBuilder, entry.getKey().getId()); results.add(result); } if (!results.contains(true)) { throw new PushFlowFlorAllDevicesException(nodeMap.entrySet().toString()); } } public boolean removeFromMdsal(final FlowBuilder flowBuilder, final NodeId nodeId) { final NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(nodeId); nodeBuilder.setKey(new NodeKey(nodeId)); return mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, retrieveIdentifier(nodeBuilder, flowBuilder)); } private InstanceIdentifier<Flow> retrieveIdentifier(final NodeBuilder nodeBuilder, final FlowBuilder flowBuilder) { flowBuilder.setTableId(OFRendererConstants.FALLBACK_TABLE_ID); InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow> flowIID = InstanceIdentifier.builder(Nodes.class) .child(Node.class, nodeBuilder.getKey()) .augmentation(FlowCapableNode.class) .child(Table.class, new TableKey(flowBuilder.getTableId())) .child(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow.class, flowBuilder.getKey()) .build(); return flowIID; } }