Java tutorial
/* * Copyright 2017-present Open Networking Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.simplefabric; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.intf.Interface; import org.onosproject.net.ConnectPoint; import org.onosproject.net.EncapsulationType; import org.onosproject.net.FilteredConnectPoint; import org.onosproject.net.Host; import org.onosproject.net.ResourceGroup; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.host.HostService; import org.onosproject.net.intent.Constraint; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentService; import org.onosproject.net.intent.Key; import org.onosproject.net.intent.MultiPointToSinglePointIntent; import org.onosproject.net.intent.SinglePointToMultiPointIntent; import org.onosproject.net.intent.constraint.EncapsulationConstraint; import org.onosproject.net.intent.constraint.PartialFailureConstraint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Set; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Map; import java.util.stream.Collectors; /** * An implementation of L2NetworkOperationService. * Handles the execution order of the L2 Network operations generated by the * application. */ @Component(immediate = true, enabled = false) public class SimpleFabricL2Forward { public static final String BROADCAST = "BCAST"; public static final String UNICAST = "UNI"; private final Logger log = LoggerFactory.getLogger(getClass()); protected ApplicationId l2ForwardAppId; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected CoreService coreService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected IntentService intentService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected HostService hostService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected SimpleFabricService simpleFabric; public static final ImmutableList<Constraint> L2NETWORK_CONSTRAINTS = ImmutableList .of(new PartialFailureConstraint()); private Map<Key, SinglePointToMultiPointIntent> bctIntentsMap = Maps.newConcurrentMap(); private Map<Key, MultiPointToSinglePointIntent> uniIntentsMap = Maps.newConcurrentMap(); private Set<Key> toBePurgedIntentKeys = new HashSet<>(); private final InternalSimpleFabricListener simpleFabricListener = new InternalSimpleFabricListener(); @Activate public void activate() { l2ForwardAppId = coreService.registerApplication(simpleFabric.L2FORWARD_APP_ID); log.info("simple fabric l2 forwaring starting with l2net app id {}", l2ForwardAppId.toString()); simpleFabric.addListener(simpleFabricListener); refresh(); checkIntentsPurge(); log.info("simple fabric l2forward started"); } @Deactivate public void deactivate() { log.info("simple fabric l2forward stopping"); simpleFabric.removeListener(simpleFabricListener); for (Intent intent : bctIntentsMap.values()) { intentService.withdraw(intent); toBePurgedIntentKeys.add(intent.key()); } for (Intent intent : uniIntentsMap.values()) { intentService.withdraw(intent); toBePurgedIntentKeys.add(intent.key()); } for (Key key : toBePurgedIntentKeys) { Intent intentToPurge = intentService.getIntent(key); if (intentToPurge != null) { intentService.purge(intentToPurge); } } // do not set clear for switch compatibility //bctIntentsMap.clear(); //uniIntentsMap.clear(); log.info("simple fabric l2forward stopped"); } private void refresh() { log.debug("simple fabric l2forward refresh"); Map<Key, SinglePointToMultiPointIntent> newBctIntentsMap = Maps.newConcurrentMap(); Map<Key, MultiPointToSinglePointIntent> newUniIntentsMap = Maps.newConcurrentMap(); for (L2Network l2Network : simpleFabric.getL2Networks()) { // scans all l2network regardless of dirty flag // if l2Network.l2Forward == false or number of interfaces() < 2, no Intents generated for (SinglePointToMultiPointIntent intent : buildBrcIntents(l2Network)) { newBctIntentsMap.put(intent.key(), intent); } for (MultiPointToSinglePointIntent intent : buildUniIntents(l2Network, hostsFromL2Network(l2Network))) { newUniIntentsMap.put(intent.key(), intent); } if (l2Network.dirty()) { l2Network.setDirty(false); } } boolean bctUpdated = false; for (SinglePointToMultiPointIntent intent : bctIntentsMap.values()) { SinglePointToMultiPointIntent newIntent = newBctIntentsMap.get(intent.key()); if (newIntent == null) { log.info("simple fabric l2forward withdraw broadcast intent: {}", intent.key().toString()); toBePurgedIntentKeys.add(intent.key()); intentService.withdraw(intent); bctUpdated = true; } } for (SinglePointToMultiPointIntent intent : newBctIntentsMap.values()) { SinglePointToMultiPointIntent oldIntent = bctIntentsMap.get(intent.key()); if (oldIntent == null || !oldIntent.filteredEgressPoints().equals(intent.filteredEgressPoints()) || !oldIntent.filteredIngressPoint().equals(intent.filteredIngressPoint()) || !oldIntent.selector().equals(intent.selector()) || !oldIntent.treatment().equals(intent.treatment()) || !oldIntent.constraints().equals(intent.constraints())) { log.info("simple fabric l2forward submit broadcast intent: {}", intent.key().toString()); toBePurgedIntentKeys.remove(intent.key()); intentService.submit(intent); bctUpdated = true; } } boolean uniUpdated = false; for (MultiPointToSinglePointIntent intent : uniIntentsMap.values()) { MultiPointToSinglePointIntent newIntent = newUniIntentsMap.get(intent.key()); if (newIntent == null) { log.info("simple fabric l2forward withdraw unicast intent: {}", intent.key().toString()); toBePurgedIntentKeys.add(intent.key()); intentService.withdraw(intent); uniUpdated = true; } } for (MultiPointToSinglePointIntent intent : newUniIntentsMap.values()) { MultiPointToSinglePointIntent oldIntent = uniIntentsMap.get(intent.key()); if (oldIntent == null || !oldIntent.filteredEgressPoint().equals(intent.filteredEgressPoint()) || !oldIntent.filteredIngressPoints().equals(intent.filteredIngressPoints()) || !oldIntent.selector().equals(intent.selector()) || !oldIntent.treatment().equals(intent.treatment()) || !oldIntent.constraints().equals(intent.constraints())) { log.info("simple fabric l2forward submit unicast intent: {}", intent.key().toString()); toBePurgedIntentKeys.remove(intent.key()); intentService.submit(intent); uniUpdated = true; } } if (bctUpdated) { bctIntentsMap = newBctIntentsMap; } if (uniUpdated) { uniIntentsMap = newUniIntentsMap; } } private void checkIntentsPurge() { // check intents to be purge if (!toBePurgedIntentKeys.isEmpty()) { Set<Key> purgedKeys = new HashSet<>(); for (Key key : toBePurgedIntentKeys) { Intent intentToPurge = intentService.getIntent(key); if (intentToPurge == null) { log.info("simple fabric l2forward purged intent: key={}", key.toString()); purgedKeys.add(key); } else { switch (intentService.getIntentState(key)) { case FAILED: case WITHDRAWN: log.info("simple fabric l2forward try to purge intent: key={}", key.toString()); intentService.purge(intentToPurge); break; case INSTALL_REQ: case INSTALLED: case INSTALLING: case RECOMPILING: case COMPILING: log.warn("simple fabric l2forward withdraw intent to purge: key={}", key); intentService.withdraw(intentToPurge); break; case WITHDRAW_REQ: case WITHDRAWING: case PURGE_REQ: case CORRUPT: default: // no action break; } } } toBePurgedIntentKeys.removeAll(purgedKeys); } } // Generates Unicast Intents and broadcast Intents for the L2 Network. private Set<Intent> generateL2NetworkIntents(L2Network l2Network) { return new ImmutableSet.Builder<Intent>().addAll(buildBrcIntents(l2Network)) .addAll(buildUniIntents(l2Network, hostsFromL2Network(l2Network))).build(); } // Build Boadcast Intents for a L2 Network. private Set<SinglePointToMultiPointIntent> buildBrcIntents(L2Network l2Network) { Set<Interface> interfaces = l2Network.interfaces(); if (interfaces.size() < 2 || !l2Network.l2Forward() || !l2Network.l2Broadcast()) { return ImmutableSet.of(); } Set<SinglePointToMultiPointIntent> brcIntents = Sets.newHashSet(); ResourceGroup resourceGroup = ResourceGroup.of(l2Network.name()); // Generates broadcast Intents from any network interface to other // network interface from the L2 Network. interfaces.forEach(src -> { FilteredConnectPoint srcFcp = buildFilteredConnectedPoint(src); Set<FilteredConnectPoint> dstFcps = interfaces.stream().filter(iface -> !iface.equals(src)) .map(this::buildFilteredConnectedPoint).collect(Collectors.toSet()); Key key = buildKey(l2Network.name(), "BCAST", srcFcp.connectPoint(), MacAddress.BROADCAST); TrafficSelector selector = DefaultTrafficSelector.builder().matchEthDst(MacAddress.BROADCAST).build(); SinglePointToMultiPointIntent.Builder intentBuilder = SinglePointToMultiPointIntent.builder() .appId(l2ForwardAppId).key(key).selector(selector).filteredIngressPoint(srcFcp) .filteredEgressPoints(dstFcps) .constraints(buildConstraints(L2NETWORK_CONSTRAINTS, l2Network.encapsulation())) .priority(SimpleFabricService.PRI_L2NETWORK_BROADCAST).resourceGroup(resourceGroup); brcIntents.add(intentBuilder.build()); }); return brcIntents; } // Builds unicast Intents for a L2 Network. private Set<MultiPointToSinglePointIntent> buildUniIntents(L2Network l2Network, Set<Host> hosts) { Set<Interface> interfaces = l2Network.interfaces(); if (!l2Network.l2Forward() || interfaces.size() < 2) { return ImmutableSet.of(); } Set<MultiPointToSinglePointIntent> uniIntents = Sets.newHashSet(); ResourceGroup resourceGroup = ResourceGroup.of(l2Network.name()); hosts.forEach(host -> { FilteredConnectPoint hostFcp = buildFilteredConnectedPoint(host); Set<FilteredConnectPoint> srcFcps = interfaces.stream().map(this::buildFilteredConnectedPoint) .filter(fcp -> !fcp.equals(hostFcp)).collect(Collectors.toSet()); Key key = buildKey(l2Network.name(), "UNI", hostFcp.connectPoint(), host.mac()); TrafficSelector selector = DefaultTrafficSelector.builder().matchEthDst(host.mac()).build(); MultiPointToSinglePointIntent.Builder intentBuilder = MultiPointToSinglePointIntent.builder() .appId(l2ForwardAppId).key(key).selector(selector).filteredIngressPoints(srcFcps) .filteredEgressPoint(hostFcp) .constraints(buildConstraints(L2NETWORK_CONSTRAINTS, l2Network.encapsulation())) .priority(SimpleFabricService.PRI_L2NETWORK_UNICAST).resourceGroup(resourceGroup); uniIntents.add(intentBuilder.build()); }); return uniIntents; } // Intent generate utilities private Set<Host> hostsFromL2Network(L2Network l2Network) { Set<Interface> interfaces = l2Network.interfaces(); return interfaces.stream().map(this::hostsFromInterface).flatMap(Collection::stream) .collect(Collectors.toSet()); } private Set<Host> hostsFromInterface(Interface iface) { return hostService.getConnectedHosts(iface.connectPoint()).stream() .filter(host -> host.vlan().equals(iface.vlan())).collect(Collectors.toSet()); } private Key buildKey(String l2NetworkName, String type, ConnectPoint cPoint, MacAddress dstMac) { return Key.of(l2NetworkName + "-" + type + "-" + cPoint.toString() + "-" + dstMac, l2ForwardAppId); } private List<Constraint> buildConstraints(List<Constraint> constraints, EncapsulationType encapsulation) { if (!encapsulation.equals(EncapsulationType.NONE)) { List<Constraint> newConstraints = new ArrayList<>(constraints); constraints.stream().filter(c -> c instanceof EncapsulationConstraint).forEach(newConstraints::remove); newConstraints.add(new EncapsulationConstraint(encapsulation)); return ImmutableList.copyOf(newConstraints); } return constraints; } private FilteredConnectPoint buildFilteredConnectedPoint(Interface iface) { Objects.requireNonNull(iface); TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder(); if (iface.vlan() != null && !iface.vlan().equals(VlanId.NONE)) { trafficSelector.matchVlanId(iface.vlan()); } return new FilteredConnectPoint(iface.connectPoint(), trafficSelector.build()); } protected FilteredConnectPoint buildFilteredConnectedPoint(Host host) { Objects.requireNonNull(host); TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder(); if (host.vlan() != null && !host.vlan().equals(VlanId.NONE)) { trafficSelector.matchVlanId(host.vlan()); } return new FilteredConnectPoint(host.location(), trafficSelector.build()); } // Dump command handler private void dump(String subject, PrintStream out) { if ("intents".equals(subject)) { out.println("L2Forward Broadcast Intents:\n"); for (SinglePointToMultiPointIntent intent : bctIntentsMap.values()) { out.println(" " + intent.key().toString() + ": " + intent.selector().criteria() + ", [" + intent.filteredIngressPoint().connectPoint() + "] -> " + intent.filteredEgressPoints() .stream().map(FilteredConnectPoint::connectPoint).collect(Collectors.toSet())); } out.println(""); out.println("L2Forward Unicast Intents:\n"); for (MultiPointToSinglePointIntent intent : uniIntentsMap.values()) { out.println( " " + intent.key().toString() + ": " + intent.selector().criteria() + ", [" + intent.filteredIngressPoints().stream().map(FilteredConnectPoint::connectPoint) .collect(Collectors.toSet()) + "] -> " + intent.filteredEgressPoint().connectPoint()); } out.println(""); out.println("L2Forward Intents to Be Purged:\n"); for (Key key : toBePurgedIntentKeys) { out.println(" " + key.toString()); } out.println(""); } } // Listener private class InternalSimpleFabricListener implements SimpleFabricListener { @Override public void event(SimpleFabricEvent event) { switch (event.type()) { case SIMPLE_FABRIC_UPDATED: refresh(); checkIntentsPurge(); break; case SIMPLE_FABRIC_IDLE: refresh(); checkIntentsPurge(); break; case SIMPLE_FABRIC_DUMP: dump(event.subject(), event.out()); break; default: // NOTE: nothing to do on SIMPLE_FABRIC_FLUSH break; } } } }