/* * Copyright (c) 2013, 2015 IBM Corporation 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.openflowplugin.openflow.md.util; import java.math.BigInteger; import java.util.Objects; import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.FlowConvertor; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow; 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.openflow.common.types.rev130731.FlowWildcardsV10; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmMatchType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.aggregate._case.MultipartRequestAggregateBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlowBuilder; public final class FlowCreatorUtil { /** * Default FLOW_MOD flags. */ public static final FlowModFlags DEFAULT_FLOW_MOD_FLAGS = new FlowModFlags(FlowConvertor.DEFAULT_OFPFF_CHECK_OVERLAP, FlowConvertor.DEFAULT_OFPFF_NO_BYT_COUNTS, FlowConvertor.DEFAULT_OFPFF_NO_PKT_COUNTS, FlowConvertor.DEFAULT_OFPFF_RESET_COUNTS, FlowConvertor.DEFAULT_OFPFF_FLOW_REM); private FlowCreatorUtil() { throw new AssertionError("FlowCreatorUtil is not expected to be instantiated."); } public static void setWildcardedFlowMatch(short version, MultipartRequestFlowBuilder flowBuilder) { if (version == OFConstants.OFP_VERSION_1_0) { flowBuilder.setMatchV10(createWildcardedMatchV10()); } if (version == OFConstants.OFP_VERSION_1_3) { flowBuilder.setMatch(createWildcardedMatch()); } } public static void setWildcardedFlowMatch(short version, MultipartRequestAggregateBuilder aggregateBuilder) { if (version == OFConstants.OFP_VERSION_1_0) { aggregateBuilder.setMatchV10(createWildcardedMatchV10()); } if (version == OFConstants.OFP_VERSION_1_3) { aggregateBuilder.setMatch(createWildcardedMatch()); } } /** * Method creates openflow 1.0 format match, that can match all the flow entries. * * @return V10 Match object */ public static MatchV10 createWildcardedMatchV10() { MatchV10Builder builder = new MatchV10Builder(); builder.setWildcards(new FlowWildcardsV10(true, true, true, true, true, true, true, true, true, true)); builder.setNwSrcMask((short) 0); builder.setNwDstMask((short) 0); builder.setInPort(0); builder.setDlSrc(new MacAddress("00:00:00:00:00:00")); builder.setDlDst(new MacAddress("00:00:00:00:00:00")); builder.setDlVlan(0); builder.setDlVlanPcp((short) 0); builder.setDlType(0); builder.setNwTos((short) 0); builder.setNwProto((short) 0); builder.setNwSrc(new Ipv4Address("0.0.0.0")); builder.setNwDst(new Ipv4Address("0.0.0.0")); builder.setTpSrc(0); builder.setTpDst(0); return builder.build(); } public static Match createWildcardedMatch() { return new MatchBuilder().setType(OxmMatchType.class).build(); } /** * Determine whether a flow entry can be modified or not. * * @param original An original flow entry. * @param updated An updated flow entry. * @param version Protocol version. * @return {@code true} only if a flow entry can be modified. */ public static boolean canModifyFlow(OriginalFlow original, UpdatedFlow updated, Short version) { // FLOW_MOD does not change match, priority, idle_timeout, hard_timeout, // flags, and cookie. if (!Objects.equals(original.getMatch(), updated.getMatch()) || !equalsWithDefault(original.getPriority(), updated.getPriority(), FlowConvertor.DEFAULT_PRIORITY) || !equalsWithDefault(original.getIdleTimeout(), updated.getIdleTimeout(), FlowConvertor.DEFAULT_IDLE_TIMEOUT) || !equalsWithDefault(original.getHardTimeout(), updated.getHardTimeout(), FlowConvertor.DEFAULT_HARD_TIMEOUT) || !equalsFlowModFlags(original.getFlags(), updated.getFlags())) { return false; } if (!Boolean.TRUE.equals(updated.isStrict()) && version != null && version.shortValue() != OFConstants.OFP_VERSION_1_0) { FlowCookie cookieMask = updated.getCookieMask(); if (cookieMask != null) { BigInteger mask = cookieMask.getValue(); if (mask != null && !mask.equals(BigInteger.ZERO)) { // Allow FLOW_MOD with filtering by cookie. return true; } } } FlowCookie oc = original.getCookie(); FlowCookie uc = updated.getCookie(); BigInteger orgCookie; BigInteger updCookie; if (oc == null) { if (uc == null) { return true; } orgCookie = OFConstants.DEFAULT_COOKIE; updCookie = uc.getValue(); } else { orgCookie = oc.getValue(); updCookie = (uc == null) ? OFConstants.DEFAULT_COOKIE : uc.getValue(); } return equalsWithDefault(orgCookie, updCookie, OFConstants.DEFAULT_COOKIE); } /** * Return {@code true} only if given two FLOW_MOD flags are identical. * * @param flags1 A value to be compared. * @param flags2 A value to be compared. * @return * {@code true} only if {@code flags1} and {@code flags2} are identical. */ public static boolean equalsFlowModFlags(FlowModFlags flags1, FlowModFlags flags2) { FlowModFlags f1; FlowModFlags f2; if (flags1 == null) { if (flags2 == null) { return true; } f1 = DEFAULT_FLOW_MOD_FLAGS; f2 = flags2; } else { f1 = flags1; f2 = (flags2 == null) ? DEFAULT_FLOW_MOD_FLAGS : flags2; } return equalsWithDefault(f1.isCHECKOVERLAP(), f2.isCHECKOVERLAP(), Boolean.FALSE) && equalsWithDefault(f1.isNOBYTCOUNTS(), f2.isNOBYTCOUNTS(), Boolean.FALSE) && equalsWithDefault(f1.isNOPKTCOUNTS(), f2.isNOPKTCOUNTS(), Boolean.FALSE) && equalsWithDefault(f1.isRESETCOUNTS(), f2.isRESETCOUNTS(), Boolean.FALSE) && equalsWithDefault(f1.isSENDFLOWREM(), f2.isSENDFLOWREM(), Boolean.FALSE); } /** * Return {@code true} only if given two values are identical. * * @param value1 A value to be compared. * @param value2 A value to be compared. * @param def * Default value. This value is used if {@code null} is passed to * {@code value1} or {@code value2}. * @param <T> Type of values. * @return * {@code true} only if {@code value1} and {@code value2} are identical. */ public static <T> boolean equalsWithDefault(T value1, T value2, T def) { if (value1 == null) { return value2 == null || value2.equals(def); } else if (value2 == null) { return value1.equals(def); } return value1.equals(value2); } }