/* * Copyright (c) 2016 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.openflowplugin.openflow.md.core.sal.convertor; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; import org.opendaylight.openflowjava.protocol.api.util.BinContent; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.data.ActionConvertorData; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupModCommand; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GroupModInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.grouping.BucketsList; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.grouping.BucketsListBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Decodes the SAL - Group Mod Message and encodes into a OF * Library for the OFPT_GROUP_MOD Message. Input:SAL Layer Group command data. * * Example usage: *
 * {@code
 * VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(version);
 * data.setDatapathId(datapathId);
 * Optional ofGroup = convertorManager.convert(salGroup, data);
 * }
 * 
*/ public class GroupConvertor extends Convertor { private static final List> TYPES = Arrays.asList(Group.class, AddGroupInput.class, RemoveGroupInput.class, UpdatedGroup.class); /** * Create default empty group mod input builder * Use this method, if result from convertor is empty. * * @param version Openflow version * @return default empty group mod input builder */ public static GroupModInputBuilder defaultResult(short version) { return new GroupModInputBuilder() .setVersion(version); } private static final Logger LOG = LoggerFactory.getLogger(GroupConvertor.class); private static final Integer DEFAULT_WEIGHT = 0; private static final Long OFPP_ANY = Long.parseLong("ffffffff", 16); private static final Long DEFAULT_WATCH_PORT = OFPP_ANY; private static final Long OFPG_ANY = Long.parseLong("ffffffff", 16); private static final Long DEFAULT_WATCH_GROUP = OFPG_ANY; private static final Comparator COMPARATOR = (bucket1, bucket2) -> { if (bucket1.getBucketId() == null || bucket2.getBucketId() == null) return 0; return bucket1.getBucketId().getValue().compareTo(bucket2.getBucketId().getValue()); }; private List salToOFBucketList(Buckets buckets, short version, int groupType, BigInteger datapathid) { final List bucketLists = new ArrayList<>(); final ActionConvertorData data = new ActionConvertorData(version); data.setDatapathId(datapathid); for (org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket groupBucket : buckets .getBucket()) { BucketsListBuilder bucketBuilder = new BucketsListBuilder(); salToOFBucketListWeight(groupBucket, bucketBuilder, groupType); salToOFBucketListWatchGroup(groupBucket, bucketBuilder, groupType); salToOFBucketListWatchPort(groupBucket, bucketBuilder, groupType); Optional> bucketActionList = getConvertorExecutor().convert( groupBucket.getAction(), data); bucketBuilder.setAction(bucketActionList.orElse(Collections.emptyList())); BucketsList bucket = bucketBuilder.build(); bucketLists.add(bucket); } return bucketLists; } private static void salToOFBucketListWatchPort(Bucket groupBucket, BucketsListBuilder bucketBuilder, int groupType) { if (null != groupBucket.getWatchPort()) { bucketBuilder.setWatchPort(new PortNumber(groupBucket.getWatchPort())); } else { bucketBuilder.setWatchPort(new PortNumber(BinContent.intToUnsignedLong(DEFAULT_WATCH_PORT.intValue()))); if (groupType == GroupType.OFPGTFF.getIntValue()) { LOG.error("WatchPort required for this OFPGT_FF"); } } } private static void salToOFBucketListWatchGroup(Bucket groupBucket, BucketsListBuilder bucketBuilder, int groupType) { if (null != groupBucket.getWatchGroup()) { bucketBuilder.setWatchGroup(groupBucket.getWatchGroup()); } else { bucketBuilder.setWatchGroup(BinContent.intToUnsignedLong(DEFAULT_WATCH_GROUP.intValue())); if (groupType == GroupType.OFPGTFF.getIntValue()) { LOG.error("WatchGroup required for this OFPGT_FF"); } } } private static void salToOFBucketListWeight(Bucket groupBucket, BucketsListBuilder bucketBuilder, int groupType) { if (null != groupBucket.getWeight()) { bucketBuilder.setWeight(groupBucket.getWeight()); } else { bucketBuilder.setWeight(DEFAULT_WEIGHT); if (groupType == GroupType.OFPGTSELECT.getIntValue()) { LOG.error("Weight value required for this OFPGT_SELECT"); } } } @Override public Collection> getTypes() { return TYPES; } @Override public GroupModInputBuilder convert(Group source, VersionDatapathIdConvertorData data) { GroupModInputBuilder groupModInputBuilder = new GroupModInputBuilder(); if (source instanceof AddGroupInput) { groupModInputBuilder.setCommand(GroupModCommand.OFPGCADD); } else if (source instanceof RemoveGroupInput) { groupModInputBuilder.setCommand(GroupModCommand.OFPGCDELETE); } else if (source instanceof UpdatedGroup) { groupModInputBuilder.setCommand(GroupModCommand.OFPGCMODIFY); } if (GroupTypes.GroupAll.equals(source.getGroupType())) { groupModInputBuilder.setType(GroupType.OFPGTALL); } if (GroupTypes.GroupSelect.equals(source.getGroupType())) { groupModInputBuilder.setType(GroupType.OFPGTSELECT); } if (GroupTypes.GroupIndirect.equals(source.getGroupType())) { groupModInputBuilder.setType(GroupType.OFPGTINDIRECT); } if (GroupTypes.GroupFf.equals(source.getGroupType())) { groupModInputBuilder.setType(GroupType.OFPGTFF); } groupModInputBuilder.setGroupId(new GroupId(source.getGroupId().getValue())); // Only if the bucket is configured for the group then add it // During group deletion do not push the buckets if (groupModInputBuilder.getCommand() != GroupModCommand.OFPGCDELETE) { if ((source.getBuckets() != null) && (source.getBuckets().getBucket().size() != 0)) { Collections.sort(source.getBuckets().getBucket(), COMPARATOR); List bucketLists = salToOFBucketList(source.getBuckets(), data.getVersion(), source.getGroupType().getIntValue(), data.getDatapathId()); groupModInputBuilder.setBucketsList(bucketLists); } } groupModInputBuilder.setVersion(data.getVersion()); return groupModInputBuilder; } }