X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=openflowplugin-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fimpl%2Fprotocol%2Fserialization%2Fmessages%2FFlowMessageSerializer.java;h=3eb2ad90abdaaccfd30f2f101d4c6c4817f442b8;hb=734f0886b8caf65dd749136ef8707b498d4e80fb;hp=7050c0780c37e8b3e20feb69064485329b3360ad;hpb=b03142bd8679394f2f719ff97f59c9b7ac64c2d8;p=openflowplugin.git diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/FlowMessageSerializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/FlowMessageSerializer.java index 7050c0780c..3eb2ad90ab 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/FlowMessageSerializer.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/FlowMessageSerializer.java @@ -5,20 +5,17 @@ * 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.impl.protocol.serialization.messages; -import com.google.common.base.MoreObjects; +import static java.util.Objects.requireNonNull; +import static java.util.Objects.requireNonNullElse; + import io.netty.buffer.ByteBuf; -import java.math.BigInteger; import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; +import java.util.Map; import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer; import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry; import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistryInjector; @@ -26,8 +23,8 @@ import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; import org.opendaylight.openflowjava.util.ByteBufUtils; import org.opendaylight.openflowplugin.api.OFConstants; -import org.opendaylight.openflowplugin.impl.protocol.serialization.util.ActionUtil; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.ActionList; +import org.opendaylight.openflowplugin.impl.protocol.serialization.util.InstructionUtil; +import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.OrderComparator; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstActionCase; @@ -40,6 +37,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.src.action._case.SetTpSrcActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessage; @@ -53,55 +51,55 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.IpMatchFields; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; +import org.opendaylight.yangtools.yang.binding.util.BindingMap; +import org.opendaylight.yangtools.yang.common.Uint16; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint64; +import org.opendaylight.yangtools.yang.common.Uint8; /** * Translates FlowMod messages. * OF protocol versions: 1.3 */ -public class FlowMessageSerializer extends AbstractMessageSerializer implements SerializerRegistryInjector { +public class FlowMessageSerializer extends AbstractMessageSerializer implements + SerializerRegistryInjector { private static final FlowCookie DEFAULT_COOKIE = new FlowCookie(OFConstants.DEFAULT_COOKIE); private static final FlowCookie DEFAULT_COOKIE_MASK = new FlowCookie(OFConstants.DEFAULT_COOKIE_MASK); - private static final Short DEFAULT_TABLE_ID = (short) 0; - private static final Integer DEFAULT_IDLE_TIMEOUT = 0; - private static final Integer DEFAULT_HARD_TIMEOUT = 0; - private static final Integer DEFAULT_PRIORITY = OFConstants.DEFAULT_FLOW_PRIORITY; - private static final Long DEFAULT_BUFFER_ID = OFConstants.OFP_NO_BUFFER; - private static final BigInteger DEFAULT_OUT_PORT = BigInteger.valueOf(OFConstants.OFPP_ANY); - private static final Long DEFAULT_OUT_GROUP = OFConstants.OFPG_ANY; - private static final byte PADDING_IN_FLOW_MOD_MESSAGE = 2; + private static final Uint8 DEFAULT_TABLE_ID = Uint8.ZERO; + private static final Uint16 DEFAULT_IDLE_TIMEOUT = Uint16.ZERO; + private static final Uint16 DEFAULT_HARD_TIMEOUT = Uint16.ZERO; + private static final Uint16 DEFAULT_PRIORITY = OFConstants.DEFAULT_FLOW_PRIORITY; + private static final Uint32 DEFAULT_BUFFER_ID = OFConstants.OFP_NO_BUFFER; + private static final Uint64 DEFAULT_OUT_PORT = Uint64.valueOf(OFConstants.OFPP_ANY); + private static final Uint32 DEFAULT_OUT_GROUP = OFConstants.OFPG_ANY; private static final FlowModFlags DEFAULT_FLAGS = new FlowModFlags(false, false, false, false, false); - private static final Integer PUSH_VLAN = 0x8100; - - private static final Comparator COMPARATOR = (inst1, inst2) -> { - if (inst1.getOrder() == null || inst2.getOrder() == null) return 0; - return inst1.getOrder().compareTo(inst2.getOrder()); - }; + private static final Uint16 PUSH_VLAN = Uint16.valueOf(0x8100); + private static final Integer PUSH_TAG = PUSH_VLAN.toJava(); + private static final VlanCfi PUSH_CFI = new VlanCfi(1); private static final VlanMatch VLAN_MATCH_FALSE = new VlanMatchBuilder() .setVlanId(new VlanIdBuilder() .setVlanIdPresent(false) - .setVlanId(new VlanId(0)) + .setVlanId(new VlanId(Uint16.ZERO)) .build()) .build(); private static final VlanMatch VLAN_MATCH_TRUE = new VlanMatchBuilder() .setVlanId(new VlanIdBuilder() .setVlanIdPresent(true) - .setVlanId(new VlanId(0)) + .setVlanId(new VlanId(Uint16.ZERO)) .build()) .build(); private SerializerRegistry registry; @Override - public void serialize(FlowMessage message, ByteBuf outBuffer) { - if (isSetVlanIdActionCasePresent(message)) { + public void serialize(final FlowMessage message, final ByteBuf outBuffer) { + if (!isVlanMatchPresent(message) && isSetVlanIdActionCasePresent(message)) { writeVlanFlow(message, outBuffer); } else { writeFlow(message, outBuffer); @@ -110,264 +108,276 @@ public class FlowMessageSerializer extends AbstractMessageSerializer>getSerializer(new MessageTypeKey<>(message.getVersion(), Match.class)) - .serialize(message.getMatch(), outBuffer); + private void writeVlanFlow(final FlowMessage message, final ByteBuf outBuffer) { + writeFlow(new FlowMessageBuilder(message) + .setMatch(new MatchBuilder(message.getMatch()).setVlanMatch(VLAN_MATCH_FALSE).build()) + .setInstructions(new InstructionsBuilder().setInstruction(updateSetVlanIdAction(message)).build()) + .build(), outBuffer); + writeFlow(new FlowMessageBuilder(message) + .setMatch(new MatchBuilder(message.getMatch()).setVlanMatch(VLAN_MATCH_TRUE).build()) + .build(), outBuffer); + } + /** + * Serialize OpenFlowPlugin match to raw bytes. + * + * @param message OpenFlow flow mod message + * @param outBuffer output buffer + */ + private void writeMatch(final FlowMessage message, final ByteBuf outBuffer) { + requireNonNull(registry).>getSerializer( + new MessageTypeKey<>(message.getVersion(), Match.class)).serialize(message.getMatch(), outBuffer); } /** - * Serialize OpenFlowPlugin instructions and set ip protocol of set-tp-src and set-tp-dst actions of need - * @param message OpenFlow flow mod message + * Serialize OpenFlowPlugin instructions and set ip protocol of set-tp-src and set-tp-dst actions of need. + * + * @param message OpenFlow flow mod message * @param outBuffer output buffer */ - @SuppressWarnings("unchecked") private void writeInstructions(final FlowMessage message, final ByteBuf outBuffer) { - // Try to get IP protocol from IP match - final Optional protocol = Optional - .ofNullable(message.getMatch()) - .flatMap(m -> Optional.ofNullable(m.getIpMatch())) - .map(IpMatchFields::getIpProtocol); + final var instructions = message.getInstructions(); + if (instructions == null) { + // Nothing to do + return; + } + + // Extract all instructions ... + Stream flowInstructions = instructions.nonnullInstruction().values().stream() + .filter(Objects::nonNull) + .sorted(OrderComparator.build()) + .map(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Instruction::getInstruction) + .filter(Objects::nonNull); + + // ... updated them if needed ... + final Uint8 protocol = extractProtocol(message); + if (protocol != null) { + flowInstructions = flowInstructions.map(insn -> updateInstruction(insn, protocol)); + } + + // ... and serialize them + flowInstructions.forEach(i -> InstructionUtil.writeInstruction(i, EncodeConstants.OF_VERSION_1_3, registry, + outBuffer)); + } - // Update instructions if needed and then serialize all instructions - Optional.ofNullable(message.getInstructions()) - .flatMap(is -> Optional.ofNullable(is.getInstruction())) - .ifPresent(is -> is - .stream() - .filter(Objects::nonNull) - .sorted(COMPARATOR) - .map(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Instruction::getInstruction) - .filter(Objects::nonNull) - .map(i -> protocol.flatMap(p -> updateInstruction(i, p)).orElse(i)) - .forEach(i -> registry.>getSerializer( - new MessageTypeKey<>( - EncodeConstants.OF13_VERSION_ID, - (Class) i.getImplementedInterface())) - .serialize(i, outBuffer) - )); + // Try to get IP protocol from IP match + private static @Nullable Uint8 extractProtocol(final FlowMessage message) { + final var match = message.getMatch(); + if (match != null) { + final var ipMatch = match.getIpMatch(); + if (ipMatch != null) { + return ipMatch.getIpProtocol(); + } + } + return null; } /** - * Determine type of instruction and update it's actions if it is apply-actions instruction + * Determine type of instruction and update it's actions if it is apply-actions instruction. + * * @param instruction instruction - * @param protocol protocol - * @return updated instruction or empty + * @param protocol protocol + * @return updated or original instruction */ - private static Optional updateInstruction(final Instruction instruction, final Short protocol) { - if( ApplyActionsCase.class.isInstance(instruction)) { - return Optional.ofNullable(ApplyActionsCase.class.cast(instruction).getApplyActions()) - .flatMap(aa -> Optional.ofNullable(aa.getAction())) - .map(as -> (Instruction) new ApplyActionsCaseBuilder() - .setApplyActions(new ApplyActionsBuilder() - .setAction(as.stream() - .map(a -> updateSetTpActions(a, protocol)) - .collect(Collectors.toList())) - .build()) - .build()); + private static Instruction updateInstruction(final Instruction instruction, final Uint8 protocol) { + if (instruction instanceof ApplyActionsCase applyActionsCase) { + final var actions = applyActionsCase.getApplyActions(); + if (actions != null) { + return new ApplyActionsCaseBuilder() + .setApplyActions(new ApplyActionsBuilder() + .setAction(actions.nonnullAction().values().stream() + .filter(Objects::nonNull) + .map(a -> updateSetTpActions(a, protocol)) + .collect(BindingMap.toOrderedMap())) + .build()) + .build(); + } } - - return Optional.empty(); + return instruction; } /** - * If action is set-tp-src or set-tp-dst, inject IP protocol into it, otherwise return original action - * @param action OpenFlow action + * If action is set-tp-src or set-tp-dst, inject IP protocol into it, otherwise return original action. + * + * @param action OpenFlow action * @param protocol IP protocol * @return updated OpenFlow action */ - private static Action updateSetTpActions(Action action, Short protocol) { - if (SetTpSrcActionCase.class.isInstance(action.getAction())) { - final SetTpSrcActionCase actionCase = SetTpSrcActionCase.class.cast(action.getAction()); - + private static Action updateSetTpActions(final Action action, final Uint8 protocol) { + if (action.getAction() instanceof SetTpSrcActionCase actionCase) { return new ActionBuilder(action) - .setAction(new SetTpSrcActionCaseBuilder(actionCase) - .setSetTpSrcAction(new SetTpSrcActionBuilder( - actionCase.getSetTpSrcAction()) - .setIpProtocol(protocol) - .build()) - .build()) - .build(); - } else if (SetTpDstActionCase.class.isInstance(action.getAction())) { - final SetTpDstActionCase actionCase = SetTpDstActionCase.class.cast(action.getAction()); - + .setAction(new SetTpSrcActionCaseBuilder(actionCase) + .setSetTpSrcAction(new SetTpSrcActionBuilder( + actionCase.getSetTpSrcAction()) + .setIpProtocol(protocol) + .build()) + .build()) + .build(); + } else if (action.getAction() instanceof SetTpDstActionCase actionCase) { return new ActionBuilder(action) - .setAction(new SetTpDstActionCaseBuilder(actionCase) - .setSetTpDstAction(new SetTpDstActionBuilder( - actionCase.getSetTpDstAction()) - .setIpProtocol(protocol) - .build()) - .build()) - .build(); + .setAction(new SetTpDstActionCaseBuilder(actionCase) + .setSetTpDstAction(new SetTpDstActionBuilder(actionCase.getSetTpDstAction()) + .setIpProtocol(protocol) + .build()) + .build()) + .build(); } // Return original action if no modifications are needed return action; } - - /** - * Instead of serializing this flow normally, we need to split it to two parts if flow contains - * #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase} - * @param message flow mod message - * @param outBuffer output buffer - */ - private void writeVlanFlow(final FlowMessage message, final ByteBuf outBuffer) { - Optional.ofNullable(message.getMatch()) - .ifPresent(match -> Optional.ofNullable(match.getVlanMatch()) - .map(v -> Stream.of( - new FlowMessageBuilder(message) - .setMatch(new MatchBuilder(match) - .setVlanMatch(new VlanMatchBuilder(v) - .setVlanId(new VlanIdBuilder() - .setVlanIdPresent(v.getVlanId().isVlanIdPresent()) - .setVlanId(v.getVlanId().getVlanId()) - .build()) - .build()) - .build()) - .build()) - ).orElseGet(() -> Stream.of( - new FlowMessageBuilder(message) - .setMatch(new MatchBuilder(match) - .setVlanMatch(VLAN_MATCH_FALSE) - .build()) - .setInstructions(new InstructionsBuilder() - .setInstruction(updateSetVlanIdAction(message)) - .build()) - .build(), - new FlowMessageBuilder(message) - .setMatch(new MatchBuilder(match) - .setVlanMatch(VLAN_MATCH_TRUE) - .build()) - .build()) - ).forEach(m -> writeFlow(m, outBuffer))); - } - /** - * Create copy of instructions of original flow but insert #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase} - * before each #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase} + * Create copy of instructions of original flow but insert + * #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase} + * before each + * #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase}. + * * @param message OpenFlowPlugin flow mod message * @return list of instructions */ - private static List updateSetVlanIdAction(final FlowMessage message) { - return message.getInstructions().getInstruction() - .stream() - .map(i -> { + private static Map< + org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey, + org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> + updateSetVlanIdAction(final FlowMessage message) { + return message.getInstructions().nonnullInstruction().values().stream() + .map(FlowMessageSerializer::updateSetVlanIdAction) + .collect(BindingMap.toOrderedMap()); + } + + private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction + updateSetVlanIdAction(final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction + .list.Instruction insn) { + if (insn.getInstruction() instanceof ApplyActionsCase applyActionsCase) { + final var applyActions = applyActionsCase.getApplyActions(); + if (applyActions != null) { + final var actions = applyActions.getAction(); + if (actions != null && !actions.isEmpty()) { final int[] offset = { 0 }; - return ApplyActionsCase.class.isInstance(i.getInstruction()) - ? Optional - .ofNullable(ApplyActionsCase.class.cast(i.getInstruction()).getApplyActions()) - .flatMap(as -> Optional.ofNullable(as.getAction())) - .map(a -> ActionUtil.sortActions(a) - .stream() + return new InstructionBuilder(insn) + .setInstruction(new ApplyActionsCaseBuilder() + .setApplyActions(new ApplyActionsBuilder() + .setAction(actions.values().stream() + .sorted(OrderComparator.build()) .flatMap(action -> { - final List actions = new ArrayList<>(); + final var actionList = new ArrayList(); - // If current action is SetVlanId, insert PushVlan action before it and update order - if (SetVlanIdActionCase.class.isInstance(action.getAction())) { - actions.add(new ActionBuilder() - .setAction(new PushVlanActionCaseBuilder() + // If current action is SetVlanId, insert PushVlan action before it and update + // order + if (action.getAction() instanceof SetVlanIdActionCase setVlanIdActionCase) { + actionList.add(new ActionBuilder() + .setAction(new PushVlanActionCaseBuilder() .setPushVlanAction(new PushVlanActionBuilder() - .setCfi(new VlanCfi(1)) - .setVlanId(SetVlanIdActionCase.class.cast(action.getAction()).getSetVlanIdAction().getVlanId()) - .setEthernetType(PUSH_VLAN) - .setTag(PUSH_VLAN) - .build()) + .setCfi(PUSH_CFI) + .setVlanId(setVlanIdActionCase.getSetVlanIdAction().getVlanId()) + .setEthernetType(PUSH_VLAN) + .setTag(PUSH_TAG) + .build()) .build()) - .setKey(action.getKey()) + .withKey(action.key()) + .setOrder(action.getOrder() + offset[0]) + .build()); + offset[0]++; + } + + // Update offset of action if there is any inserted PushVlan actions + actionList.add(offset[0] <= 0 ? action : new ActionBuilder(action) .setOrder(action.getOrder() + offset[0]) + .withKey(new ActionKey(action.getOrder() + offset[0])) .build()); - - offset[0]++; - } - - // Update offset of action if there is any inserted PushVlan actions - actions.add(offset[0] > 0 - ? new ActionBuilder(action).setOrder(action.getOrder() + offset[0]).build() - : action); - - return actions.stream(); - })) - .map(as -> new InstructionBuilder(i) - .setInstruction(new ApplyActionsCaseBuilder() - .setApplyActions(new ApplyActionsBuilder() - .setAction(as.collect(Collectors.toList())) - .build()) - .build()) - .build()) - .orElse(i) - : i; - }).collect(Collectors.toList()); + return actionList.stream(); + }).collect(BindingMap.toOrderedMap())) + .build()) + .build()) + .build(); + } + } + } + return insn; } /** - * Create integer bit mask from #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags} + * Create integer bit mask from + * #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags}. + * * @param flags flow mod flags * @return bit mask */ private static int createFlowModFlagsBitmask(final FlowModFlags flags) { return ByteBufUtils.fillBitMask(0, - flags.isSENDFLOWREM(), - flags.isCHECKOVERLAP(), - flags.isRESETCOUNTS(), - flags.isNOPKTCOUNTS(), - flags.isNOBYTCOUNTS()); + flags.getSENDFLOWREM(), + flags.getCHECKOVERLAP(), + flags.getRESETCOUNTS(), + flags.getNOPKTCOUNTS(), + flags.getNOBYTCOUNTS()); + } + + /** + * Determine if flow contains vlan match. + * + * @param flow flow + * @return true if flow contains vlan match + */ + private static boolean isVlanMatchPresent(final Flow flow) { + final var match = flow.getMatch(); + return match != null && match.getVlanMatch() != null; } /** - * Determine if flow contains #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase} - * instruction with #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase} action + * Determine if flow contains + * #{@link org.opendaylight.yang.gen.v1.urn.opendaylight + * .flow.types.rev131026.instruction.instruction.ApplyActionsCase} instruction with + * #{@link org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase} + * action. + * * @param flow OpenFlowPlugin flow * @return true if flow contains SetVlanIdAction */ private static boolean isSetVlanIdActionCasePresent(final Flow flow) { - return Optional - .ofNullable(flow.getInstructions()) - .flatMap(is -> Optional.ofNullable(is.getInstruction())) - .flatMap(is -> is - .stream() - .map(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Instruction::getInstruction) - .filter(ApplyActionsCase.class::isInstance) - .map(i -> ApplyActionsCase.class.cast(i).getApplyActions()) - .filter(Objects::nonNull) - .map(ActionList::getAction) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .map(Action::getAction) - .filter(SetVlanIdActionCase.class::isInstance) - .findFirst()) - .isPresent(); + final var instructions = flow.getInstructions(); + return instructions != null && instructions.nonnullInstruction().values().stream() + .map(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Instruction::getInstruction) + .filter(ApplyActionsCase.class::isInstance) + .map(i -> ((ApplyActionsCase) i).getApplyActions()) + .filter(Objects::nonNull) + .flatMap(actionList -> actionList.nonnullAction().values().stream()) + .map(Action::getAction) + .anyMatch(SetVlanIdActionCase.class::isInstance); } @Override @@ -376,7 +386,7 @@ public class FlowMessageSerializer extends AbstractMessageSerializer