Search in sources :

Example 36 with PortNumber

use of org.onosproject.net.PortNumber in project onos by opennetworkinglab.

the class OfdpaPipelineTraceable method apply.

@Override
public PipelineTraceableOutput apply(PipelineTraceableInput input) {
    PipelineTraceableOutput.Builder outputBuilder = PipelineTraceableOutput.builder();
    log.debug("Current packet {} - applying flow tables", input.ingressPacket());
    List<FlowEntry> outputFlows = new ArrayList<>();
    List<Instruction> deferredInstructions = new ArrayList<>();
    PipelineTraceableHitChain currentHitChain = PipelineTraceableHitChain.emptyHitChain();
    TrafficSelector currentPacket = DefaultTrafficSelector.builder(input.ingressPacket().packet()).build();
    // Init step - find out the first table
    int initialTableId = -1;
    FlowEntry nextTableIdEntry = findNextTableIdEntry(initialTableId, input.flows());
    if (nextTableIdEntry == null) {
        currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
        currentHitChain.dropped();
        return outputBuilder.appendToLog("No flow rules for device " + deviceId + ". Aborting").noFlows().addHitChain(currentHitChain).build();
    }
    // Iterates over the flow tables until the end of the pipeline
    TableId tableId = nextTableIdEntry.table();
    FlowEntry flowEntry;
    boolean lastTable = false;
    while (!lastTable) {
        log.debug("Searching a Flow Entry on table {} for packet {}", tableId, currentPacket);
        // Gets the rule that matches the incoming packet
        flowEntry = matchHighestPriority(currentPacket, tableId, input.flows());
        log.debug("Found Flow Entry {}", flowEntry);
        // If the flow entry on a table is null and we are on hardware we treat as table miss, with few exceptions
        if (flowEntry == null && isHardwareSwitch()) {
            log.debug("Ofdpa Hw setup, no flow rule means table miss");
            if (((IndexTableId) tableId).id() == MPLS_L3_TYPE_TABLE) {
                // Apparently a miss but Table 27 on OFDPA is a fixed table
                currentPacket = handleOfdpa27FixedTable(input.ingressPacket().packet(), currentPacket);
                // The nextTable should be ACL
                tableId = IndexTableId.of(ACL_TABLE - 1);
            }
            // Finding next table to go In case of miss
            nextTableIdEntry = findNextTableIdEntry(((IndexTableId) tableId).id(), input.flows());
            log.debug("Next table id entry {}", nextTableIdEntry);
            // (another possibility is max tableId)
            if (nextTableIdEntry == null && currentHitChain.hitChain().size() == 0) {
                currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
                currentHitChain.dropped();
                return outputBuilder.appendToLog("No flow rules for device " + deviceId + ". Aborting").noFlows().addHitChain(currentHitChain).build();
            } else if (nextTableIdEntry == null) {
                // Means that no more flow rules are present
                lastTable = true;
            } else if (((IndexTableId) tableId).id() == TMAC_TABLE) {
                // If the table is 20 OFDPA skips to table 50
                log.debug("A miss on Table 20 on OFDPA means that we skip directly to table 50");
                tableId = IndexTableId.of(BRIDGING_TABLE);
            } else if (((IndexTableId) tableId).id() == MULTICAST_ROUTING_TABLE) {
                // If the table is 40 OFDPA skips to table 60
                log.debug("A miss on Table 40 on OFDPA means that we skip directly to table 60");
                tableId = IndexTableId.of(ACL_TABLE);
            } else {
                tableId = nextTableIdEntry.table();
            }
        } else if (flowEntry == null) {
            currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
            currentHitChain.dropped();
            return outputBuilder.appendToLog("Packet has no match on table " + tableId + " in device " + deviceId + ". Dropping").noFlows().addHitChain(currentHitChain).build();
        } else {
            // If the table has a transition
            if (flowEntry.treatment().tableTransition() != null) {
                // Updates the next table we transitions to
                tableId = IndexTableId.of(flowEntry.treatment().tableTransition().tableId());
                log.debug("Flow Entry has transition to table Id {}", tableId);
                currentHitChain.addDataPlaneEntity(new DataPlaneEntity(flowEntry));
            } else {
                // Table has no transition so it means that it's an output rule if on the last table
                log.debug("Flow Entry has no transition to table, treating as last rule {}", flowEntry);
                currentHitChain.addDataPlaneEntity(new DataPlaneEntity(flowEntry));
                outputFlows.add(flowEntry);
                lastTable = true;
            }
            // Updates the packet according to the immediate actions of this flow rule.
            currentPacket = updatePacket(currentPacket, flowEntry.treatment().immediate()).build();
            // Saves the deferred rules for later maintaining the order
            deferredInstructions.addAll(flowEntry.treatment().deferred());
            // If the flow requires to clear deferred actions we do so for all the ones we encountered.
            if (flowEntry.treatment().clearedDeferred()) {
                deferredInstructions.clear();
            }
            // On table 10 OFDPA needs two rules to apply the vlan if none and then to transition to the next table.
            if (shouldMatchSecondVlanFlow(flowEntry)) {
                // Let's get the packet vlanId instruction
                VlanIdCriterion packetVlanIdCriterion = (VlanIdCriterion) currentPacket.getCriterion(Criterion.Type.VLAN_VID);
                // Let's get the flow entry vlan mod instructions
                ModVlanIdInstruction entryModVlanIdInstruction = (ModVlanIdInstruction) flowEntry.treatment().immediate().stream().filter(instruction -> instruction instanceof ModVlanIdInstruction).findFirst().orElse(null);
                // is a flow rule that matches on same criteria and with updated vlanId
                if (entryModVlanIdInstruction != null) {
                    FlowEntry secondVlanFlow = getSecondFlowEntryOnTable10(currentPacket, packetVlanIdCriterion, entryModVlanIdInstruction, input.flows());
                    // We found the flow that we expected
                    if (secondVlanFlow != null) {
                        currentHitChain.addDataPlaneEntity(new DataPlaneEntity(secondVlanFlow));
                    } else {
                        currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
                        currentHitChain.dropped();
                        return outputBuilder.appendToLog("Missing forwarding rule for tagged" + " packet on " + deviceId).noFlows().addHitChain(currentHitChain).build();
                    }
                }
            }
        }
    }
    // Creating a modifiable builder for the egress packet
    TrafficSelector.Builder egressPacket = DefaultTrafficSelector.builder(currentPacket);
    log.debug("Current packet {} - applying output flows", currentPacket);
    // Handling output flows which basically means handling output to controller.
    // OVS and OFDPA have both immediate -> OUTPUT:CONTROLLER. Theoretically there is no
    // need to reflect the updates performed on the packets and on the chain.
    List<PortNumber> outputPorts = new ArrayList<>();
    handleOutputFlows(currentPacket, outputFlows, egressPacket, outputPorts, currentHitChain, outputBuilder, input.ingressPacket().packet());
    // Immediate instructions
    log.debug("Current packet {} - applying immediate instructions", currentPacket);
    // Handling immediate instructions which basically means handling output to controller.
    // OVS has immediate -> group -> OUTPUT:CONTROLLER.
    List<DataPlaneEntity> entries = ImmutableList.copyOf(currentHitChain.hitChain());
    // Go to the next step - using a copy of the egress packet and of the hit chain
    PipelineTraceableHitChain newHitChain = PipelineTraceableHitChain.emptyHitChain();
    currentHitChain.hitChain().forEach(newHitChain::addDataPlaneEntity);
    TrafficSelector.Builder newEgressPacket = DefaultTrafficSelector.builder(egressPacket.build());
    for (DataPlaneEntity entry : entries) {
        flowEntry = entry.getFlowEntry();
        if (flowEntry != null) {
            getGroupsFromInstructions(input.groups(), flowEntry.treatment().immediate(), newEgressPacket, outputPorts, newHitChain, outputBuilder, input, false);
        }
    }
    // Deferred instructions
    log.debug("Current packet {} - applying deferred instructions", egressPacket.build());
    // egress packet and of the hit chain. This is the last step.
    if (deferredInstructions.size() > 0) {
        handleDeferredActions(egressPacket.build(), input.groups(), deferredInstructions, outputPorts, currentHitChain, outputBuilder, input);
    }
    // Let's store the partial hit chain and set a message
    if (outputPorts.isEmpty()) {
        currentHitChain.setEgressPacket(new PipelineTraceablePacket(egressPacket.build()));
        currentHitChain.dropped();
        outputBuilder.appendToLog("Packet has no output in device " + deviceId + ". Dropping").dropped().addHitChain(currentHitChain);
    }
    // Done!
    return outputBuilder.build();
}
Also used : IndexTableId(org.onosproject.net.flow.IndexTableId) TableId(org.onosproject.net.flow.TableId) IndexTableId(org.onosproject.net.flow.IndexTableId) ArrayList(java.util.ArrayList) L2ModificationInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction) OutputInstruction(org.onosproject.net.flow.instructions.Instructions.OutputInstruction) ModVlanIdInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction) Instruction(org.onosproject.net.flow.instructions.Instruction) ConnectPoint(org.onosproject.net.ConnectPoint) DataPlaneEntity(org.onosproject.net.DataPlaneEntity) ModVlanIdInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction) TrafficSelector(org.onosproject.net.flow.TrafficSelector) DefaultTrafficSelector(org.onosproject.net.flow.DefaultTrafficSelector) PipelineTraceableOutput(org.onosproject.net.PipelineTraceableOutput) PipelineTraceableHitChain(org.onosproject.net.PipelineTraceableHitChain) PortNumber(org.onosproject.net.PortNumber) FlowEntry(org.onosproject.net.flow.FlowEntry) PipelineTraceablePacket(org.onosproject.net.PipelineTraceablePacket) VlanIdCriterion(org.onosproject.net.flow.criteria.VlanIdCriterion)

Example 37 with PortNumber

use of org.onosproject.net.PortNumber in project onos by opennetworkinglab.

the class FujitsuT100DeviceDescription method parseT100OchPort.

private static PortDescription parseT100OchPort(HierarchicalConfiguration cfg, long count) {
    PortNumber portNumber = PortNumber.portNumber(count);
    HierarchicalConfiguration otuConfig = cfg.configurationAt("otu");
    boolean enabled = "up".equals(otuConfig.getString("administrative-state"));
    OduSignalType signalType = "OTU4".equals(otuConfig.getString("rate")) ? OduSignalType.ODU4 : null;
    // Unsure how to retrieve, outside knowledge it is tunable.
    boolean isTunable = true;
    OchSignal lambda = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 0, 4);
    DefaultAnnotations annotations = DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, cfg.getString("name")).build();
    return ochPortDescription(portNumber, enabled, signalType, isTunable, lambda, annotations);
}
Also used : OduSignalType(org.onosproject.net.OduSignalType) DefaultAnnotations(org.onosproject.net.DefaultAnnotations) OchSignal(org.onosproject.net.OchSignal) PortNumber(org.onosproject.net.PortNumber) HierarchicalConfiguration(org.apache.commons.configuration.HierarchicalConfiguration)

Example 38 with PortNumber

use of org.onosproject.net.PortNumber in project onos by opennetworkinglab.

the class ResourcesCommand method doExecute.

@Override
protected void doExecute() {
    resourceService = get(ResourceQueryService.class);
    if (typeStrings != null) {
        typesToPrint = new HashSet<>(Arrays.asList(typeStrings));
    } else {
        typesToPrint = Collections.emptySet();
    }
    if (deviceIdStr != null && portNumberStr != null) {
        DeviceId deviceId = deviceId(deviceIdStr);
        PortNumber portNumber = PortNumber.fromString(portNumberStr);
        printResource(Resources.discrete(deviceId, portNumber).resource(), 0);
    } else if (deviceIdStr != null) {
        DeviceId deviceId = deviceId(deviceIdStr);
        printResource(Resources.discrete(deviceId).resource(), 0);
    } else {
        printResource(Resource.ROOT, 0);
    }
}
Also used : ResourceQueryService(org.onosproject.net.resource.ResourceQueryService) DeviceId(org.onosproject.net.DeviceId) PortNumber(org.onosproject.net.PortNumber)

Example 39 with PortNumber

use of org.onosproject.net.PortNumber in project onos by opennetworkinglab.

the class LinkCollectionCompiler method manageSpIntent.

/**
 * Manages the Intents with a single ingress point (p2p, sp2mp)
 * creating properly the selector builder and the treatment builder.
 *
 * @param selectorBuilder the selector builder to update
 * @param treatmentBuilder the treatment builder to update
 * @param intent the intent to compile
 * @param deviceId the current device
 * @param outPorts the output ports of this device
 */
private void manageSpIntent(TrafficSelector.Builder selectorBuilder, TrafficTreatment.Builder treatmentBuilder, LinkCollectionIntent intent, DeviceId deviceId, Set<PortNumber> outPorts) {
    /*
         * Sanity check.
         */
    if (intent.filteredIngressPoints().size() != 1) {
        throw new IntentCompilationException(WRONG_INGRESS);
    }
    /*
         * For the p2p and sp2mp the transition initial state
         * to final state is performed at the egress.
         */
    Optional<FilteredConnectPoint> filteredIngressPoint = intent.filteredIngressPoints().stream().findFirst();
    /*
         * We build the final selector, adding the selector
         * of the FIP to the Intent selector and potentially
         * overriding its matches.
         */
    filteredIngressPoint.get().trafficSelector().criteria().forEach(selectorBuilder::add);
    /*
         * In this scenario, potentially we can have several output
         * ports. First we have to insert in the treatment the actions
         * for the core.
         */
    List<FilteredConnectPoint> egressPoints = Lists.newArrayList();
    for (PortNumber outPort : outPorts) {
        Optional<FilteredConnectPoint> filteredEgressPoint = getFilteredConnectPointFromIntent(deviceId, outPort, intent);
        if (!filteredEgressPoint.isPresent()) {
            treatmentBuilder.setOutput(outPort);
        } else {
            egressPoints.add(filteredEgressPoint.get());
        }
    }
    /*
         * The idea is to order the egress points. Before we deal
         * with the egress points which looks like similar to the ingress
         * point then the others.
         */
    TrafficSelector prevState = filteredIngressPoint.get().trafficSelector();
    if (optimizeTreatments()) {
        egressPoints = orderedEgressPoints(prevState, egressPoints);
    }
    /*
         * Then we deal with the egress points.
         */
    generateEgressActions(treatmentBuilder, egressPoints, prevState, intent);
}
Also used : TrafficSelector(org.onosproject.net.flow.TrafficSelector) DefaultTrafficSelector(org.onosproject.net.flow.DefaultTrafficSelector) IntentCompilationException(org.onosproject.net.intent.IntentCompilationException) PortNumber(org.onosproject.net.PortNumber) FilteredConnectPoint(org.onosproject.net.FilteredConnectPoint)

Example 40 with PortNumber

use of org.onosproject.net.PortNumber in project onos by opennetworkinglab.

the class LinkCollectionCompiler method manageOutputPorts.

/**
 * Helper method which handles the proper generation of the ouput actions.
 *
 * @param outPorts the output ports
 * @param deviceId the current device
 * @param intent the intent to compile
 * @param outLabels the output labels
 * @param type the encapsulation type
 * @param preCondition the previous state
 * @param treatmentBuilder the builder to update with the ouput actions
 */
private void manageOutputPorts(Set<PortNumber> outPorts, DeviceId deviceId, LinkCollectionIntent intent, Map<ConnectPoint, Identifier<?>> outLabels, EncapsulationType type, TrafficSelector.Builder preCondition, TrafficTreatment.Builder treatmentBuilder) {
    /*
         * We need to order the actions. First the actions
         * related to the not-egress points. At the same time we collect
         * also the egress points.
         */
    List<FilteredConnectPoint> egressPoints = Lists.newArrayList();
    for (PortNumber outPort : outPorts) {
        Optional<FilteredConnectPoint> filteredEgressPoint = getFilteredConnectPointFromIntent(deviceId, outPort, intent);
        if (!filteredEgressPoint.isPresent()) {
            /*
                 * We build a temporary selector for the encapsulation.
                 */
            TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
            /*
                 * We retrieve the associated label to the output port.
                 */
            ConnectPoint cp = new ConnectPoint(deviceId, outPort);
            Identifier<?> outLabel = outLabels.get(cp);
            /*
                 * If there are not labels, we cannot handle.
                 */
            if (outLabel == null) {
                throw new IntentCompilationException(String.format(NO_LABELS, cp));
            }
            /*
                 * In the core we match using encapsulation.
                 */
            updateSelectorFromEncapsulation(encapBuilder, type, outLabel);
            /*
                 * We generate the transition.
                 */
            TrafficTreatment forwardingTreatment = forwardingTreatment(preCondition.build(), encapBuilder.build(), getEthType(intent.selector()));
            /*
                 * We add the instruction necessary to the transition.
                 */
            forwardingTreatment.allInstructions().stream().filter(inst -> inst.type() != Instruction.Type.NOACTION).forEach(treatmentBuilder::add);
            /*
                 * Finally we set the output action.
                 */
            treatmentBuilder.setOutput(outPort);
            /*
                 * The encapsulation modifies the packet. If we are optimizing
                 * we have to update the state.
                 */
            if (optimizeTreatments()) {
                preCondition = encapBuilder;
            }
        } else {
            egressPoints.add(filteredEgressPoint.get());
        }
    }
    /*
         * The idea is to order the egress points. Before we deal
         * with the egress points which looks like similar to the
         * selector derived from the previous state then the
         * the others.
         */
    TrafficSelector prevState = preCondition.build();
    if (optimizeTreatments()) {
        egressPoints = orderedEgressPoints(prevState, egressPoints);
    }
    /*
         * In this case, we have to transit to the final
         * state.
         */
    generateEgressActions(treatmentBuilder, egressPoints, prevState, intent);
}
Also used : PortNumber(org.onosproject.net.PortNumber) LoggerFactory(org.slf4j.LoggerFactory) ModIPv6FlowLabelInstruction(org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction) Link(org.onosproject.net.Link) DefaultTrafficTreatment(org.onosproject.net.flow.DefaultTrafficTreatment) ConnectPoint(org.onosproject.net.ConnectPoint) Ethernet(org.onlab.packet.Ethernet) Map(java.util.Map) L2ModificationInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction) Ip4Address(org.onlab.packet.Ip4Address) L3ModificationInstruction(org.onosproject.net.flow.instructions.L3ModificationInstruction) Set(java.util.Set) ModVlanIdInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) EthType(org.onlab.packet.EthType) ModTransportPortInstruction(org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction) List(java.util.List) EncapsulationType(org.onosproject.net.EncapsulationType) ModEtherInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction) ModTunnelIdInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction) Optional(java.util.Optional) DeviceId(org.onosproject.net.DeviceId) TunnelIdCriterion(org.onosproject.net.flow.criteria.TunnelIdCriterion) IpPrefix(org.onlab.packet.IpPrefix) MplsCriterion(org.onosproject.net.flow.criteria.MplsCriterion) Identifier(org.onlab.util.Identifier) L4ModificationInstruction(org.onosproject.net.flow.instructions.L4ModificationInstruction) LabelAllocator(org.onosproject.net.resource.impl.LabelAllocator) ModMplsLabelInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction) DomainConstraint(org.onosproject.net.intent.constraint.DomainConstraint) IntentCompilationException(org.onosproject.net.intent.IntentCompilationException) ModIPInstruction(org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction) ModArpIPInstruction(org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction) EncapsulationConstraint(org.onosproject.net.intent.constraint.EncapsulationConstraint) ModVlanPcpInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction) Type(org.onosproject.net.flow.criteria.Criterion.Type) Lists(com.google.common.collect.Lists) TrafficSelector(org.onosproject.net.flow.TrafficSelector) ImmutableList(com.google.common.collect.ImmutableList) DomainService(org.onosproject.net.domain.DomainService) L0ModificationInstruction(org.onosproject.net.flow.instructions.L0ModificationInstruction) DomainPointToPointIntent(org.onosproject.net.domain.DomainPointToPointIntent) Intent(org.onosproject.net.intent.Intent) LOCAL(org.onosproject.net.domain.DomainId.LOCAL) Criteria(org.onosproject.net.flow.criteria.Criteria) DefaultTrafficSelector(org.onosproject.net.flow.DefaultTrafficSelector) Criterion(org.onosproject.net.flow.criteria.Criterion) TrafficTreatment(org.onosproject.net.flow.TrafficTreatment) ModMplsBosInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction) Logger(org.slf4j.Logger) MplsLabel(org.onlab.packet.MplsLabel) EthTypeCriterion(org.onosproject.net.flow.criteria.EthTypeCriterion) Instruction(org.onosproject.net.flow.instructions.Instruction) VlanId(org.onlab.packet.VlanId) ModArpEthInstruction(org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction) LinkCollectionIntent(org.onosproject.net.intent.LinkCollectionIntent) Maps(com.google.common.collect.Maps) SetMultimap(com.google.common.collect.SetMultimap) DomainId(org.onosproject.net.domain.DomainId) L1ModificationInstruction(org.onosproject.net.flow.instructions.L1ModificationInstruction) VlanIdCriterion(org.onosproject.net.flow.criteria.VlanIdCriterion) ModArpOpInstruction(org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction) FilteredConnectPoint(org.onosproject.net.FilteredConnectPoint) TrafficSelector(org.onosproject.net.flow.TrafficSelector) DefaultTrafficSelector(org.onosproject.net.flow.DefaultTrafficSelector) IntentCompilationException(org.onosproject.net.intent.IntentCompilationException) PortNumber(org.onosproject.net.PortNumber) DefaultTrafficTreatment(org.onosproject.net.flow.DefaultTrafficTreatment) TrafficTreatment(org.onosproject.net.flow.TrafficTreatment) ConnectPoint(org.onosproject.net.ConnectPoint) FilteredConnectPoint(org.onosproject.net.FilteredConnectPoint) FilteredConnectPoint(org.onosproject.net.FilteredConnectPoint)

Aggregations

PortNumber (org.onosproject.net.PortNumber)336 DeviceId (org.onosproject.net.DeviceId)136 TrafficTreatment (org.onosproject.net.flow.TrafficTreatment)109 DefaultTrafficTreatment (org.onosproject.net.flow.DefaultTrafficTreatment)103 ConnectPoint (org.onosproject.net.ConnectPoint)82 TrafficSelector (org.onosproject.net.flow.TrafficSelector)80 DefaultTrafficSelector (org.onosproject.net.flow.DefaultTrafficSelector)74 Port (org.onosproject.net.Port)67 ArrayList (java.util.ArrayList)64 Set (java.util.Set)64 List (java.util.List)59 Logger (org.slf4j.Logger)58 Collectors (java.util.stream.Collectors)51 DeviceService (org.onosproject.net.device.DeviceService)49 VlanId (org.onlab.packet.VlanId)42 MacAddress (org.onlab.packet.MacAddress)41 Device (org.onosproject.net.Device)40 FlowRule (org.onosproject.net.flow.FlowRule)40 Optional (java.util.Optional)39 Sets (com.google.common.collect.Sets)35