Committed by
Thomas Vachuska
Various changes in BMv2 driver and provider modules (onos1.6 cherry-pick)
Driver notable changes: - Implemented new behaviors, removed deprecated ones - Removed flow rule translator classes (now under protocol module) - Improved FlowRuleProgrammable: now it uses BMv2TableEntryService to lookup/bind flow rules with BMv2 table entries, retrieves flow statistics, better exception handling when adding/replacing/removing table entries. - Improved PacketProgrammable: better exception handling and logging Provider notable changes: - Bmv2DeviceProvider: detects and notifies device configuration changes and reboots to Bmv2DeviceContextService, added support for periodic polling of port statistics - Bmv2PacketProvider: implemented workaround for OutboundPackets with flood treatment Change-Id: I79b756b533d4afb6b70025a137b2e811fd42a4e8
Showing
31 changed files
with
744 additions
and
1529 deletions
| ... | @@ -20,6 +20,6 @@ | ... | @@ -20,6 +20,6 @@ |
| 20 | <feature name="${project.artifactId}" version="${project.version}" | 20 | <feature name="${project.artifactId}" version="${project.version}" |
| 21 | description="${project.description}"> | 21 | description="${project.description}"> |
| 22 | <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle> | 22 | <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle> |
| 23 | - <bundle>mvn:${project.groupId}/onos-bmv2-protocol/${project.version}</bundle> | 23 | + <bundle>mvn:${project.groupId}/onos-bmv2-protocol-api/${project.version}</bundle> |
| 24 | </feature> | 24 | </feature> |
| 25 | </features> | 25 | </features> | ... | ... |
| ... | @@ -22,11 +22,11 @@ | ... | @@ -22,11 +22,11 @@ |
| 22 | <artifactId>onos-drivers-general</artifactId> | 22 | <artifactId>onos-drivers-general</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | <version>1.7.0-SNAPSHOT</version> | 24 | <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | <modelVersion>4.0.0</modelVersion> | 27 | <modelVersion>4.0.0</modelVersion> |
| 27 | 28 | ||
| 28 | <artifactId>onos-drivers-bmv2</artifactId> | 29 | <artifactId>onos-drivers-bmv2</artifactId> |
| 29 | - <version>1.7.0-SNAPSHOT</version> | ||
| 30 | 30 | ||
| 31 | <packaging>bundle</packaging> | 31 | <packaging>bundle</packaging> |
| 32 | 32 | ||
| ... | @@ -36,7 +36,7 @@ | ... | @@ -36,7 +36,7 @@ |
| 36 | <onos.app.name>org.onosproject.drivers.bmv2</onos.app.name> | 36 | <onos.app.name>org.onosproject.drivers.bmv2</onos.app.name> |
| 37 | <onos.app.origin>ON.Lab</onos.app.origin> | 37 | <onos.app.origin>ON.Lab</onos.app.origin> |
| 38 | <onos.app.category>Drivers</onos.app.category> | 38 | <onos.app.category>Drivers</onos.app.category> |
| 39 | - <onos.app.title>BMv2 Device Drivers</onos.app.title> | 39 | + <onos.app.title>BMv2 Drivers</onos.app.title> |
| 40 | <onos.app.url>http://onosproject.org</onos.app.url> | 40 | <onos.app.url>http://onosproject.org</onos.app.url> |
| 41 | <onos.app.requires> | 41 | <onos.app.requires> |
| 42 | org.onosproject.bmv2 | 42 | org.onosproject.bmv2 |
| ... | @@ -46,7 +46,7 @@ | ... | @@ -46,7 +46,7 @@ |
| 46 | <dependencies> | 46 | <dependencies> |
| 47 | <dependency> | 47 | <dependency> |
| 48 | <groupId>org.onosproject</groupId> | 48 | <groupId>org.onosproject</groupId> |
| 49 | - <artifactId>onos-bmv2-protocol</artifactId> | 49 | + <artifactId>onos-bmv2-protocol-api</artifactId> |
| 50 | <version>${project.version}</version> | 50 | <version>${project.version}</version> |
| 51 | </dependency> | 51 | </dependency> |
| 52 | <dependency> | 52 | <dependency> | ... | ... |
drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DeviceDescriptionDiscovery.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.drivers.bmv2; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableList; | ||
| 20 | +import com.google.common.collect.Lists; | ||
| 21 | +import org.onlab.packet.ChassisId; | ||
| 22 | +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; | ||
| 23 | +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | ||
| 24 | +import org.onosproject.bmv2.api.service.Bmv2Controller; | ||
| 25 | +import org.onosproject.net.AnnotationKeys; | ||
| 26 | +import org.onosproject.net.DefaultAnnotations; | ||
| 27 | +import org.onosproject.net.DeviceId; | ||
| 28 | +import org.onosproject.net.PortNumber; | ||
| 29 | +import org.onosproject.net.device.DefaultDeviceDescription; | ||
| 30 | +import org.onosproject.net.device.DefaultPortDescription; | ||
| 31 | +import org.onosproject.net.device.DeviceDescription; | ||
| 32 | +import org.onosproject.net.device.DeviceDescriptionDiscovery; | ||
| 33 | +import org.onosproject.net.device.PortDescription; | ||
| 34 | +import org.onosproject.net.driver.AbstractHandlerBehaviour; | ||
| 35 | +import org.slf4j.Logger; | ||
| 36 | +import org.slf4j.LoggerFactory; | ||
| 37 | + | ||
| 38 | +import java.math.BigInteger; | ||
| 39 | +import java.util.List; | ||
| 40 | + | ||
| 41 | +import static org.onosproject.bmv2.api.runtime.Bmv2Device.*; | ||
| 42 | +import static org.onosproject.net.Device.Type.SWITCH; | ||
| 43 | + | ||
| 44 | +/** | ||
| 45 | + * Implementation of the device description discovery behaviour for BMv2. | ||
| 46 | + */ | ||
| 47 | +public class Bmv2DeviceDescriptionDiscovery extends AbstractHandlerBehaviour implements DeviceDescriptionDiscovery { | ||
| 48 | + | ||
| 49 | + private static final String JSON_CONFIG_MD5 = "bmv2JsonConfigMd5"; | ||
| 50 | + private static final String PROCESS_INSTANCE_ID = "bmv2ProcessInstanceId"; | ||
| 51 | + | ||
| 52 | + private final Logger log = LoggerFactory.getLogger(this.getClass()); | ||
| 53 | + | ||
| 54 | + private Bmv2Controller controller; | ||
| 55 | + | ||
| 56 | + private boolean init() { | ||
| 57 | + controller = handler().get(Bmv2Controller.class); | ||
| 58 | + if (controller == null) { | ||
| 59 | + log.warn("Failed to get a BMv2 controller"); | ||
| 60 | + return false; | ||
| 61 | + } | ||
| 62 | + return true; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Override | ||
| 66 | + public DeviceDescription discoverDeviceDetails() { | ||
| 67 | + | ||
| 68 | + if (!init()) { | ||
| 69 | + return null; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + DeviceId deviceId = handler().data().deviceId(); | ||
| 73 | + | ||
| 74 | + Bmv2DeviceAgent deviceAgent; | ||
| 75 | + try { | ||
| 76 | + deviceAgent = controller.getAgent(deviceId); | ||
| 77 | + } catch (Bmv2RuntimeException e) { | ||
| 78 | + log.error("Failed to connect to Bmv2 device", e); | ||
| 79 | + return null; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder(); | ||
| 83 | + | ||
| 84 | + try { | ||
| 85 | + String md5 = deviceAgent.getJsonConfigMd5(); | ||
| 86 | + BigInteger i = new BigInteger(1, md5.getBytes()); | ||
| 87 | + annotationsBuilder.set(JSON_CONFIG_MD5, String.format("%1$032X", i).toLowerCase()); | ||
| 88 | + } catch (Bmv2RuntimeException e) { | ||
| 89 | + log.warn("Unable to dump JSON configuration from {}: {}", deviceId, e.explain()); | ||
| 90 | + } | ||
| 91 | + try { | ||
| 92 | + int instanceId = deviceAgent.getProcessInstanceId(); | ||
| 93 | + annotationsBuilder.set(PROCESS_INSTANCE_ID, String.valueOf(instanceId)); | ||
| 94 | + } catch (Bmv2RuntimeException e) { | ||
| 95 | + log.warn("Unable to get process instance ID from {}: {}", deviceId, e.explain()); | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + annotationsBuilder.set(AnnotationKeys.PROTOCOL, PROTOCOL); | ||
| 99 | + | ||
| 100 | + return new DefaultDeviceDescription(deviceId.uri(), | ||
| 101 | + SWITCH, | ||
| 102 | + MANUFACTURER, | ||
| 103 | + HW_VERSION, | ||
| 104 | + SW_VERSION, | ||
| 105 | + SERIAL_NUMBER, | ||
| 106 | + new ChassisId(), | ||
| 107 | + annotationsBuilder.build()); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + @Override | ||
| 111 | + public List<PortDescription> discoverPortDetails() { | ||
| 112 | + | ||
| 113 | + if (!init()) { | ||
| 114 | + return null; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + DeviceId deviceId = handler().data().deviceId(); | ||
| 118 | + | ||
| 119 | + Bmv2DeviceAgent deviceAgent; | ||
| 120 | + try { | ||
| 121 | + deviceAgent = controller.getAgent(deviceId); | ||
| 122 | + } catch (Bmv2RuntimeException e) { | ||
| 123 | + log.error("Failed to connect to Bmv2 device", e); | ||
| 124 | + return null; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + List<PortDescription> portDescriptions = Lists.newArrayList(); | ||
| 128 | + | ||
| 129 | + try { | ||
| 130 | + deviceAgent.getPortsInfo().forEach(p -> { | ||
| 131 | + PortNumber portNumber = PortNumber.portNumber((long) p.number(), p.ifaceName()); | ||
| 132 | + portDescriptions.add(new DefaultPortDescription(portNumber, p.isUp(), DefaultAnnotations.EMPTY)); | ||
| 133 | + }); | ||
| 134 | + } catch (Bmv2RuntimeException e) { | ||
| 135 | + log.error("Unable to get port descriptions of {}: {}", deviceId, e); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + return ImmutableList.copyOf(portDescriptions); | ||
| 139 | + } | ||
| 140 | +} |
| ... | @@ -20,7 +20,7 @@ import org.apache.felix.scr.annotations.Component; | ... | @@ -20,7 +20,7 @@ import org.apache.felix.scr.annotations.Component; |
| 20 | import org.onosproject.net.driver.AbstractDriverLoader; | 20 | import org.onosproject.net.driver.AbstractDriverLoader; |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | - * Loader for barefoot drivers from specific xml. | 23 | + * Loader for BMv2 drivers from xml file. |
| 24 | */ | 24 | */ |
| 25 | @Component(immediate = true) | 25 | @Component(immediate = true) |
| 26 | public class Bmv2DriversLoader extends AbstractDriverLoader { | 26 | public class Bmv2DriversLoader extends AbstractDriverLoader { | ... | ... |
| ... | @@ -14,7 +14,29 @@ | ... | @@ -14,7 +14,29 @@ |
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | +package org.onosproject.drivers.bmv2; | ||
| 18 | + | ||
| 19 | +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector; | ||
| 20 | +import org.onosproject.net.behaviour.ExtensionSelectorResolver; | ||
| 21 | +import org.onosproject.net.driver.AbstractHandlerBehaviour; | ||
| 22 | +import org.onosproject.net.flow.criteria.ExtensionSelector; | ||
| 23 | +import org.onosproject.net.flow.criteria.ExtensionSelectorType; | ||
| 24 | + | ||
| 25 | +import java.util.Collections; | ||
| 26 | + | ||
| 27 | +import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.BMV2_MATCH_PARAMS; | ||
| 28 | + | ||
| 17 | /** | 29 | /** |
| 18 | - * Translators of ONOS abstractions to BMv2 model-dependent abstractions. | 30 | + * Implementation of the extension selector resolver behaviour for BMv2. |
| 19 | */ | 31 | */ |
| 20 | -package org.onosproject.drivers.bmv2.translators; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 32 | +public class Bmv2ExtensionSelectorResolver extends AbstractHandlerBehaviour implements ExtensionSelectorResolver { | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public ExtensionSelector getExtensionSelector(ExtensionSelectorType type) { | ||
| 36 | + if (type.equals(BMV2_MATCH_PARAMS.type())) { | ||
| 37 | + return new Bmv2ExtensionSelector(Collections.emptyMap()); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + return null; | ||
| 41 | + } | ||
| 42 | +} | ... | ... |
| ... | @@ -14,14 +14,26 @@ | ... | @@ -14,14 +14,26 @@ |
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -package org.onosproject.drivers.bmv2.translators; | 17 | +package org.onosproject.drivers.bmv2; |
| 18 | + | ||
| 19 | +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment; | ||
| 20 | +import org.onosproject.net.behaviour.ExtensionTreatmentResolver; | ||
| 21 | +import org.onosproject.net.driver.AbstractHandlerBehaviour; | ||
| 22 | +import org.onosproject.net.flow.instructions.ExtensionTreatment; | ||
| 23 | +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; | ||
| 24 | + | ||
| 25 | +import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.BMV2_ACTION; | ||
| 18 | 26 | ||
| 19 | /** | 27 | /** |
| 20 | - * BMv2 flow rule translator exception. | 28 | + * Implementation of the extension treatment resolver behavior for BMv2. |
| 21 | */ | 29 | */ |
| 22 | -public class Bmv2FlowRuleTranslatorException extends Exception { | 30 | +public class Bmv2ExtensionTreatmentResolver extends AbstractHandlerBehaviour implements ExtensionTreatmentResolver { |
| 23 | 31 | ||
| 24 | - Bmv2FlowRuleTranslatorException(String msg) { | 32 | + @Override |
| 25 | - super(msg); | 33 | + public ExtensionTreatment getExtensionInstruction(ExtensionTreatmentType type) { |
| 34 | + if (type.equals(BMV2_ACTION.type())) { | ||
| 35 | + return new Bmv2ExtensionTreatment(null); | ||
| 36 | + } | ||
| 37 | + return null; | ||
| 26 | } | 38 | } |
| 27 | } | 39 | } | ... | ... |
| ... | @@ -16,28 +16,25 @@ | ... | @@ -16,28 +16,25 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.drivers.bmv2; | 17 | package org.onosproject.drivers.bmv2; |
| 18 | 18 | ||
| 19 | -import com.eclipsesource.json.Json; | ||
| 20 | -import com.google.common.cache.CacheBuilder; | ||
| 21 | -import com.google.common.cache.CacheLoader; | ||
| 22 | -import com.google.common.cache.LoadingCache; | ||
| 23 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
| 24 | import com.google.common.collect.Maps; | 20 | import com.google.common.collect.Maps; |
| 25 | -import com.google.common.collect.Sets; | ||
| 26 | import org.apache.commons.lang3.tuple.Pair; | 21 | import org.apache.commons.lang3.tuple.Pair; |
| 27 | -import org.apache.commons.lang3.tuple.Triple; | 22 | +import org.onosproject.bmv2.api.context.Bmv2Configuration; |
| 28 | -import org.onosproject.bmv2.api.model.Bmv2Model; | 23 | +import org.onosproject.bmv2.api.context.Bmv2DeviceContext; |
| 29 | -import org.onosproject.bmv2.api.runtime.Bmv2Client; | 24 | +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator; |
| 25 | +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslatorException; | ||
| 26 | +import org.onosproject.bmv2.api.context.Bmv2Interpreter; | ||
| 27 | +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; | ||
| 28 | +import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper; | ||
| 30 | import org.onosproject.bmv2.api.runtime.Bmv2MatchKey; | 29 | import org.onosproject.bmv2.api.runtime.Bmv2MatchKey; |
| 30 | +import org.onosproject.bmv2.api.runtime.Bmv2ParsedTableEntry; | ||
| 31 | import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | 31 | import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; |
| 32 | import org.onosproject.bmv2.api.runtime.Bmv2TableEntry; | 32 | import org.onosproject.bmv2.api.runtime.Bmv2TableEntry; |
| 33 | -import org.onosproject.bmv2.ctl.Bmv2ThriftClient; | 33 | +import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference; |
| 34 | -import org.onosproject.drivers.bmv2.translators.Bmv2DefaultFlowRuleTranslator; | 34 | +import org.onosproject.bmv2.api.service.Bmv2Controller; |
| 35 | -import org.onosproject.drivers.bmv2.translators.Bmv2FlowRuleTranslator; | 35 | +import org.onosproject.bmv2.api.service.Bmv2DeviceContextService; |
| 36 | -import org.onosproject.drivers.bmv2.translators.Bmv2FlowRuleTranslatorException; | 36 | +import org.onosproject.bmv2.api.service.Bmv2TableEntryService; |
| 37 | -import org.onosproject.drivers.bmv2.translators.Bmv2SimpleTranslatorConfig; | ||
| 38 | -import org.onosproject.net.Device; | ||
| 39 | import org.onosproject.net.DeviceId; | 37 | import org.onosproject.net.DeviceId; |
| 40 | -import org.onosproject.net.device.DeviceService; | ||
| 41 | import org.onosproject.net.driver.AbstractHandlerBehaviour; | 38 | import org.onosproject.net.driver.AbstractHandlerBehaviour; |
| 42 | import org.onosproject.net.flow.DefaultFlowEntry; | 39 | import org.onosproject.net.flow.DefaultFlowEntry; |
| 43 | import org.onosproject.net.flow.FlowEntry; | 40 | import org.onosproject.net.flow.FlowEntry; |
| ... | @@ -50,97 +47,130 @@ import java.util.Collection; | ... | @@ -50,97 +47,130 @@ import java.util.Collection; |
| 50 | import java.util.Collections; | 47 | import java.util.Collections; |
| 51 | import java.util.Date; | 48 | import java.util.Date; |
| 52 | import java.util.List; | 49 | import java.util.List; |
| 53 | -import java.util.Set; | ||
| 54 | import java.util.concurrent.ConcurrentMap; | 50 | import java.util.concurrent.ConcurrentMap; |
| 55 | -import java.util.concurrent.ExecutionException; | ||
| 56 | -import java.util.concurrent.TimeUnit; | ||
| 57 | 51 | ||
| 52 | +import static org.onosproject.bmv2.api.runtime.Bmv2RuntimeException.Code.*; | ||
| 58 | import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED; | 53 | import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED; |
| 59 | 54 | ||
| 60 | /** | 55 | /** |
| 61 | - * Flow rule programmable device behaviour implementation for BMv2. | 56 | + * Implementation of the flow rule programmable behaviour for BMv2. |
| 62 | */ | 57 | */ |
| 63 | -public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | 58 | +public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable { |
| 64 | - implements FlowRuleProgrammable { | 59 | + |
| 65 | - | 60 | + private final Logger log = LoggerFactory.getLogger(this.getClass()); |
| 66 | - private static final Logger LOG = | 61 | + |
| 67 | - LoggerFactory.getLogger(Bmv2FlowRuleProgrammable.class); | 62 | + // Needed to synchronize operations over the same table entry. |
| 68 | - | 63 | + private static final ConcurrentMap<Bmv2TableEntryReference, Boolean> ENTRY_LOCKS = Maps.newConcurrentMap(); |
| 69 | - // There's no Bmv2 client method to poll flow entries from the device. Use a local store. | 64 | + |
| 70 | - // FIXME: this information should be distributed across instances of the cluster. | 65 | + private Bmv2Controller controller; |
| 71 | - private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, TimestampedFlowRule>> | 66 | + private Bmv2TableEntryService tableEntryService; |
| 72 | - ENTRIES_MAP = Maps.newConcurrentMap(); | 67 | + private Bmv2DeviceContextService contextService; |
| 73 | - | 68 | + |
| 74 | - // Cache model objects instead of parsing the JSON each time. | 69 | + private boolean init() { |
| 75 | - private static final LoadingCache<String, Bmv2Model> MODEL_CACHE = CacheBuilder.newBuilder() | 70 | + controller = handler().get(Bmv2Controller.class); |
| 76 | - .expireAfterAccess(60, TimeUnit.SECONDS) | 71 | + tableEntryService = handler().get(Bmv2TableEntryService.class); |
| 77 | - .build(new CacheLoader<String, Bmv2Model>() { | 72 | + contextService = handler().get(Bmv2DeviceContextService.class); |
| 78 | - @Override | 73 | + if (controller == null) { |
| 79 | - public Bmv2Model load(String jsonString) throws Exception { | 74 | + log.warn("Failed to get a BMv2 controller"); |
| 80 | - // Expensive call. | 75 | + return false; |
| 81 | - return Bmv2Model.parse(Json.parse(jsonString).asObject()); | 76 | + } |
| 82 | - } | 77 | + if (tableEntryService == null) { |
| 83 | - }); | 78 | + log.warn("Failed to get a BMv2 table entry service"); |
| 79 | + return false; | ||
| 80 | + } | ||
| 81 | + if (contextService == null) { | ||
| 82 | + log.warn("Failed to get a BMv2 device context service"); | ||
| 83 | + return false; | ||
| 84 | + } | ||
| 85 | + return true; | ||
| 86 | + } | ||
| 84 | 87 | ||
| 85 | @Override | 88 | @Override |
| 86 | public Collection<FlowEntry> getFlowEntries() { | 89 | public Collection<FlowEntry> getFlowEntries() { |
| 87 | 90 | ||
| 91 | + if (!init()) { | ||
| 92 | + return Collections.emptyList(); | ||
| 93 | + } | ||
| 94 | + | ||
| 88 | DeviceId deviceId = handler().data().deviceId(); | 95 | DeviceId deviceId = handler().data().deviceId(); |
| 89 | 96 | ||
| 90 | - Bmv2Client deviceClient; | 97 | + Bmv2DeviceAgent deviceAgent; |
| 91 | try { | 98 | try { |
| 92 | - deviceClient = Bmv2ThriftClient.of(deviceId); | 99 | + deviceAgent = controller.getAgent(deviceId); |
| 93 | } catch (Bmv2RuntimeException e) { | 100 | } catch (Bmv2RuntimeException e) { |
| 94 | - LOG.error("Failed to connect to Bmv2 device", e); | 101 | + log.error("Failed to get BMv2 device agent: {}", e.explain()); |
| 95 | return Collections.emptyList(); | 102 | return Collections.emptyList(); |
| 96 | } | 103 | } |
| 97 | 104 | ||
| 98 | - Bmv2Model model = getTranslator(deviceId).config().model(); | 105 | + Bmv2DeviceContext context = contextService.getContext(deviceId); |
| 106 | + if (context == null) { | ||
| 107 | + log.warn("Unable to get device context for {}", deviceId); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + Bmv2Interpreter interpreter = context.interpreter(); | ||
| 111 | + Bmv2Configuration configuration = context.configuration(); | ||
| 99 | 112 | ||
| 100 | List<FlowEntry> entryList = Lists.newArrayList(); | 113 | List<FlowEntry> entryList = Lists.newArrayList(); |
| 101 | 114 | ||
| 102 | - model.tables().forEach(table -> { | 115 | + configuration.tables().forEach(table -> { |
| 103 | - // For each table declared in the model for this device, do: | 116 | + // For each table in the configuration AND exposed by the interpreter. |
| 104 | - try { | 117 | + if (!interpreter.tableIdMap().inverse().containsKey(table.name())) { |
| 105 | - // Bmv2 doesn't support proper polling for table entries, but only a string based table dump. | 118 | + return; |
| 106 | - // The trick here is to first dump the entry ids currently installed in the device for a given table, | 119 | + } |
| 107 | - // and then filter ENTRIES_MAP based on the retrieved values. | 120 | + |
| 108 | - Set<Long> installedEntryIds = Sets.newHashSet(deviceClient.getInstalledEntryIds(table.name())); | 121 | + // Bmv2 doesn't support proper polling for table entries, but only a string based table dump. |
| 109 | - ENTRIES_MAP.forEach((key, value) -> { | 122 | + // The trick here is to first dump the entries currently installed in the device for a given table, |
| 110 | - if (key.getLeft() == deviceId && key.getMiddle() == table.name() | 123 | + // and then query a service for the corresponding, previously applied, flow rule. |
| 111 | - && value != null) { | 124 | + List<Bmv2ParsedTableEntry> installedEntries = tableEntryService.getTableEntries(deviceId, table.name()); |
| 112 | - long entryId = value.getKey(); | 125 | + installedEntries.forEach(parsedEntry -> { |
| 113 | - // Filter entries_map for this device and table. | 126 | + Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, |
| 114 | - if (installedEntryIds.contains(entryId)) { | 127 | + table.name(), |
| 115 | - // Entry is installed. | 128 | + parsedEntry.matchKey()); |
| 116 | - long bytes = 0L; | 129 | + ENTRY_LOCKS.compute(entryRef, (key, value) -> { |
| 117 | - long packets = 0L; | 130 | + |
| 118 | - if (table.hasCounters()) { | 131 | + Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookupEntryReference(entryRef); |
| 119 | - // Read counter values from device. | 132 | + |
| 120 | - try { | 133 | + if (frWrapper == null) { |
| 121 | - Pair<Long, Long> counterValue = deviceClient.readTableEntryCounter(table.name(), | 134 | + log.warn("missing reference from table entry service, BUG? " + |
| 122 | - entryId); | 135 | + "deviceId={}, tableName={}, matchKey={}", |
| 123 | - bytes = counterValue.getLeft(); | 136 | + deviceId, table.name(), entryRef.matchKey()); |
| 124 | - packets = counterValue.getRight(); | 137 | + return null; |
| 125 | - } catch (Bmv2RuntimeException e) { | 138 | + } |
| 126 | - LOG.warn("Unable to get counter values for entry {} of table {} of device {}: {}", | 139 | + |
| 127 | - entryId, table.name(), deviceId, e.toString()); | 140 | + long remoteEntryId = parsedEntry.entryId(); |
| 128 | - } | 141 | + long localEntryId = frWrapper.entryId(); |
| 129 | - } | 142 | + |
| 130 | - TimestampedFlowRule tsRule = value.getRight(); | 143 | + if (remoteEntryId != localEntryId) { |
| 131 | - FlowEntry entry = new DefaultFlowEntry(tsRule.rule(), ADDED, | 144 | + log.warn("getFlowEntries(): inconsistent entry id! BUG? Updating it... remote={}, local={}", |
| 132 | - tsRule.lifeInSeconds(), packets, bytes); | 145 | + remoteEntryId, localEntryId); |
| 133 | - entryList.add(entry); | 146 | + frWrapper = new Bmv2FlowRuleWrapper(frWrapper.rule(), remoteEntryId, |
| 134 | - } else { | 147 | + frWrapper.creationDate()); |
| 135 | - // No such entry on device, can remove from local store. | 148 | + tableEntryService.bindEntryReference(entryRef, frWrapper); |
| 136 | - ENTRIES_MAP.remove(key); | 149 | + } |
| 150 | + | ||
| 151 | + long bytes = 0L; | ||
| 152 | + long packets = 0L; | ||
| 153 | + | ||
| 154 | + if (table.hasCounters()) { | ||
| 155 | + // Read counter values from device. | ||
| 156 | + try { | ||
| 157 | + Pair<Long, Long> counterValue = deviceAgent.readTableEntryCounter(table.name(), | ||
| 158 | + remoteEntryId); | ||
| 159 | + bytes = counterValue.getLeft(); | ||
| 160 | + packets = counterValue.getRight(); | ||
| 161 | + } catch (Bmv2RuntimeException e) { | ||
| 162 | + log.warn("Unable to get counters for entry {}/{} of device {}: {}", | ||
| 163 | + table.name(), remoteEntryId, deviceId, e.explain()); | ||
| 137 | } | 164 | } |
| 138 | } | 165 | } |
| 166 | + | ||
| 167 | + FlowEntry entry = new DefaultFlowEntry(frWrapper.rule(), ADDED, frWrapper.lifeInSeconds(), | ||
| 168 | + packets, bytes); | ||
| 169 | + entryList.add(entry); | ||
| 170 | + return true; | ||
| 139 | }); | 171 | }); |
| 140 | - } catch (Bmv2RuntimeException e) { | 172 | + |
| 141 | - LOG.error("Unable to get flow entries for table {} of device {}: {}", | 173 | + }); |
| 142 | - table.name(), deviceId, e.toString()); | ||
| 143 | - } | ||
| 144 | }); | 174 | }); |
| 145 | 175 | ||
| 146 | return Collections.unmodifiableCollection(entryList); | 176 | return Collections.unmodifiableCollection(entryList); |
| ... | @@ -160,17 +190,27 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -160,17 +190,27 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
| 160 | 190 | ||
| 161 | private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules, Operation operation) { | 191 | private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules, Operation operation) { |
| 162 | 192 | ||
| 193 | + if (!init()) { | ||
| 194 | + return Collections.emptyList(); | ||
| 195 | + } | ||
| 196 | + | ||
| 163 | DeviceId deviceId = handler().data().deviceId(); | 197 | DeviceId deviceId = handler().data().deviceId(); |
| 164 | 198 | ||
| 165 | - Bmv2Client deviceClient; | 199 | + Bmv2DeviceAgent deviceAgent; |
| 166 | try { | 200 | try { |
| 167 | - deviceClient = Bmv2ThriftClient.of(deviceId); | 201 | + deviceAgent = controller.getAgent(deviceId); |
| 168 | } catch (Bmv2RuntimeException e) { | 202 | } catch (Bmv2RuntimeException e) { |
| 169 | - LOG.error("Failed to connect to Bmv2 device", e); | 203 | + log.error("Failed to get BMv2 device agent: {}", e.explain()); |
| 170 | return Collections.emptyList(); | 204 | return Collections.emptyList(); |
| 171 | } | 205 | } |
| 172 | 206 | ||
| 173 | - Bmv2FlowRuleTranslator translator = getTranslator(deviceId); | 207 | + Bmv2DeviceContext context = contextService.getContext(deviceId); |
| 208 | + if (context == null) { | ||
| 209 | + log.error("Unable to get device context for {}", deviceId); | ||
| 210 | + return Collections.emptyList(); | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + Bmv2FlowRuleTranslator translator = tableEntryService.getFlowRuleTranslator(); | ||
| 174 | 214 | ||
| 175 | List<FlowRule> processedFlowRules = Lists.newArrayList(); | 215 | List<FlowRule> processedFlowRules = Lists.newArrayList(); |
| 176 | 216 | ||
| ... | @@ -179,120 +219,114 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -179,120 +219,114 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
| 179 | Bmv2TableEntry bmv2Entry; | 219 | Bmv2TableEntry bmv2Entry; |
| 180 | 220 | ||
| 181 | try { | 221 | try { |
| 182 | - bmv2Entry = translator.translate(rule); | 222 | + bmv2Entry = translator.translate(rule, context); |
| 183 | } catch (Bmv2FlowRuleTranslatorException e) { | 223 | } catch (Bmv2FlowRuleTranslatorException e) { |
| 184 | - LOG.error("Unable to translate flow rule: {}", e.getMessage()); | 224 | + log.warn("Unable to translate flow rule: {} - {}", e.getMessage(), rule); |
| 185 | continue; | 225 | continue; |
| 186 | } | 226 | } |
| 187 | 227 | ||
| 188 | String tableName = bmv2Entry.tableName(); | 228 | String tableName = bmv2Entry.tableName(); |
| 189 | - Triple<DeviceId, String, Bmv2MatchKey> entryKey = Triple.of(deviceId, tableName, bmv2Entry.matchKey()); | 229 | + Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, tableName, bmv2Entry.matchKey()); |
| 190 | 230 | ||
| 191 | /* | 231 | /* |
| 192 | From here on threads are synchronized over entryKey, i.e. serialize operations | 232 | From here on threads are synchronized over entryKey, i.e. serialize operations |
| 193 | over the same matchKey of a specific table and device. | 233 | over the same matchKey of a specific table and device. |
| 194 | */ | 234 | */ |
| 195 | - ENTRIES_MAP.compute(entryKey, (key, value) -> { | 235 | + ENTRY_LOCKS.compute(entryRef, (key, value) -> { |
| 236 | + // Get from store | ||
| 237 | + Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookupEntryReference(entryRef); | ||
| 196 | try { | 238 | try { |
| 197 | if (operation == Operation.APPLY) { | 239 | if (operation == Operation.APPLY) { |
| 198 | // Apply entry | 240 | // Apply entry |
| 199 | long entryId; | 241 | long entryId; |
| 200 | - if (value != null) { | 242 | + if (frWrapper != null) { |
| 201 | // Existing entry. | 243 | // Existing entry. |
| 202 | - entryId = value.getKey(); | 244 | + entryId = frWrapper.entryId(); |
| 203 | - try { | 245 | + // Tentatively delete entry before re-adding. |
| 204 | - // Tentatively delete entry before re-adding. | 246 | + // It might not exist on device due to inconsistencies. |
| 205 | - // It might not exist on device due to inconsistencies. | 247 | + silentlyRemove(deviceAgent, entryRef.tableName(), entryId); |
| 206 | - deviceClient.deleteTableEntry(bmv2Entry.tableName(), entryId); | ||
| 207 | - value = null; | ||
| 208 | - } catch (Bmv2RuntimeException e) { | ||
| 209 | - // Silently drop exception as we can probably fix this by re-adding the entry. | ||
| 210 | - } | ||
| 211 | } | 248 | } |
| 212 | // Add entry. | 249 | // Add entry. |
| 213 | - entryId = deviceClient.addTableEntry(bmv2Entry); | 250 | + entryId = doAddEntry(deviceAgent, bmv2Entry); |
| 214 | - value = Pair.of(entryId, new TimestampedFlowRule(rule)); | 251 | + frWrapper = new Bmv2FlowRuleWrapper(rule, entryId, new Date()); |
| 215 | } else { | 252 | } else { |
| 216 | // Remove entry | 253 | // Remove entry |
| 217 | - if (value == null) { | 254 | + if (frWrapper == null) { |
| 218 | // Entry not found in map, how come? | 255 | // Entry not found in map, how come? |
| 219 | - LOG.debug("Trying to remove entry, but entry ID not found: " + entryKey); | 256 | + forceRemove(deviceAgent, entryRef.tableName(), entryRef.matchKey()); |
| 220 | } else { | 257 | } else { |
| 221 | - deviceClient.deleteTableEntry(tableName, value.getKey()); | 258 | + long entryId = frWrapper.entryId(); |
| 222 | - value = null; | 259 | + doRemove(deviceAgent, entryRef.tableName(), entryId, entryRef.matchKey()); |
| 223 | } | 260 | } |
| 261 | + frWrapper = null; | ||
| 224 | } | 262 | } |
| 225 | // If here, no exceptions... things went well :) | 263 | // If here, no exceptions... things went well :) |
| 226 | processedFlowRules.add(rule); | 264 | processedFlowRules.add(rule); |
| 227 | } catch (Bmv2RuntimeException e) { | 265 | } catch (Bmv2RuntimeException e) { |
| 228 | - LOG.warn("Unable to {} flow rule: {}", operation.name().toLowerCase(), e.toString()); | 266 | + log.warn("Unable to {} flow rule: {}", operation.name(), e.explain()); |
| 267 | + } | ||
| 268 | + // Update binding in table entry service. | ||
| 269 | + if (frWrapper != null) { | ||
| 270 | + tableEntryService.bindEntryReference(entryRef, frWrapper); | ||
| 271 | + return true; | ||
| 272 | + } else { | ||
| 273 | + tableEntryService.unbindEntryReference(entryRef); | ||
| 274 | + return null; | ||
| 229 | } | 275 | } |
| 230 | - return value; | ||
| 231 | }); | 276 | }); |
| 232 | } | 277 | } |
| 233 | 278 | ||
| 234 | return processedFlowRules; | 279 | return processedFlowRules; |
| 235 | } | 280 | } |
| 236 | 281 | ||
| 237 | - /** | 282 | + private long doAddEntry(Bmv2DeviceAgent agent, Bmv2TableEntry entry) throws Bmv2RuntimeException { |
| 238 | - * Gets the appropriate flow rule translator based on the device running configuration. | 283 | + try { |
| 239 | - * | 284 | + return agent.addTableEntry(entry); |
| 240 | - * @param deviceId a device id | 285 | + } catch (Bmv2RuntimeException e) { |
| 241 | - * @return a flow rule translator | 286 | + if (e.getCode() != TABLE_DUPLICATE_ENTRY) { |
| 242 | - */ | 287 | + forceRemove(agent, entry.tableName(), entry.matchKey()); |
| 243 | - private Bmv2FlowRuleTranslator getTranslator(DeviceId deviceId) { | 288 | + return agent.addTableEntry(entry); |
| 244 | - | 289 | + } else { |
| 245 | - DeviceService deviceService = handler().get(DeviceService.class); | 290 | + throw e; |
| 246 | - if (deviceService == null) { | 291 | + } |
| 247 | - LOG.error("Unable to get device service"); | ||
| 248 | - return null; | ||
| 249 | } | 292 | } |
| 293 | + } | ||
| 250 | 294 | ||
| 251 | - Device device = deviceService.getDevice(deviceId); | 295 | + private void doRemove(Bmv2DeviceAgent agent, String tableName, long entryId, Bmv2MatchKey matchKey) |
| 252 | - if (device == null) { | 296 | + throws Bmv2RuntimeException { |
| 253 | - LOG.error("Unable to get device {}", deviceId); | 297 | + try { |
| 254 | - return null; | 298 | + agent.deleteTableEntry(tableName, entryId); |
| 299 | + } catch (Bmv2RuntimeException e) { | ||
| 300 | + if (e.getCode() == TABLE_INVALID_HANDLE || e.getCode() == TABLE_EXPIRED_HANDLE) { | ||
| 301 | + // entry is not there with the declared ID, try with a forced remove. | ||
| 302 | + forceRemove(agent, tableName, matchKey); | ||
| 303 | + } else { | ||
| 304 | + throw e; | ||
| 305 | + } | ||
| 255 | } | 306 | } |
| 307 | + } | ||
| 256 | 308 | ||
| 257 | - String jsonString = device.annotations().value("bmv2JsonConfigValue"); | 309 | + private void forceRemove(Bmv2DeviceAgent agent, String tableName, Bmv2MatchKey matchKey) |
| 258 | - if (jsonString == null) { | 310 | + throws Bmv2RuntimeException { |
| 259 | - LOG.error("Unable to read bmv2 JSON config from device {}", deviceId); | 311 | + // Find the entryID (expensive call!) |
| 260 | - return null; | 312 | + for (Bmv2ParsedTableEntry pEntry : tableEntryService.getTableEntries(agent.deviceId(), tableName)) { |
| 313 | + if (pEntry.matchKey().equals(matchKey)) { | ||
| 314 | + // Remove entry and drop exceptions. | ||
| 315 | + silentlyRemove(agent, tableName, pEntry.entryId()); | ||
| 316 | + break; | ||
| 317 | + } | ||
| 261 | } | 318 | } |
| 319 | + } | ||
| 262 | 320 | ||
| 263 | - Bmv2Model model; | 321 | + private void silentlyRemove(Bmv2DeviceAgent agent, String tableName, long entryId) { |
| 264 | try { | 322 | try { |
| 265 | - model = MODEL_CACHE.get(jsonString); | 323 | + agent.deleteTableEntry(tableName, entryId); |
| 266 | - } catch (ExecutionException e) { | 324 | + } catch (Bmv2RuntimeException e) { |
| 267 | - LOG.error("Unable to parse bmv2 JSON config for device {}:", deviceId, e.getCause()); | 325 | + // do nothing |
| 268 | - return null; | ||
| 269 | } | 326 | } |
| 270 | - | ||
| 271 | - // TODO: get translator config dynamically. | ||
| 272 | - // Now it's hardcoded, selection should be based on the device bmv2 model. | ||
| 273 | - Bmv2FlowRuleTranslator.TranslatorConfig translatorConfig = new Bmv2SimpleTranslatorConfig(model); | ||
| 274 | - return new Bmv2DefaultFlowRuleTranslator(translatorConfig); | ||
| 275 | } | 327 | } |
| 276 | 328 | ||
| 277 | private enum Operation { | 329 | private enum Operation { |
| 278 | APPLY, REMOVE | 330 | APPLY, REMOVE |
| 279 | } | 331 | } |
| 280 | - | ||
| 281 | - private class TimestampedFlowRule { | ||
| 282 | - private final FlowRule rule; | ||
| 283 | - private final Date addedDate; | ||
| 284 | - | ||
| 285 | - public TimestampedFlowRule(FlowRule rule) { | ||
| 286 | - this.rule = rule; | ||
| 287 | - this.addedDate = new Date(); | ||
| 288 | - } | ||
| 289 | - | ||
| 290 | - public FlowRule rule() { | ||
| 291 | - return rule; | ||
| 292 | - } | ||
| 293 | - | ||
| 294 | - public long lifeInSeconds() { | ||
| 295 | - return (new Date().getTime() - addedDate.getTime()) / 1000; | ||
| 296 | - } | ||
| 297 | - } | ||
| 298 | } | 332 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -17,56 +17,59 @@ | ... | @@ -17,56 +17,59 @@ |
| 17 | package org.onosproject.drivers.bmv2; | 17 | package org.onosproject.drivers.bmv2; |
| 18 | 18 | ||
| 19 | import org.onlab.util.ImmutableByteSequence; | 19 | import org.onlab.util.ImmutableByteSequence; |
| 20 | -import org.onosproject.bmv2.api.runtime.Bmv2Client; | 20 | +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; |
| 21 | import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | 21 | import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; |
| 22 | -import org.onosproject.bmv2.ctl.Bmv2ThriftClient; | 22 | +import org.onosproject.bmv2.api.service.Bmv2Controller; |
| 23 | import org.onosproject.net.DeviceId; | 23 | import org.onosproject.net.DeviceId; |
| 24 | import org.onosproject.net.driver.AbstractHandlerBehaviour; | 24 | import org.onosproject.net.driver.AbstractHandlerBehaviour; |
| 25 | import org.onosproject.net.flow.TrafficTreatment; | 25 | import org.onosproject.net.flow.TrafficTreatment; |
| 26 | -import org.onosproject.net.flow.instructions.Instructions; | ||
| 27 | import org.onosproject.net.packet.OutboundPacket; | 26 | import org.onosproject.net.packet.OutboundPacket; |
| 28 | import org.onosproject.net.packet.PacketProgrammable; | 27 | import org.onosproject.net.packet.PacketProgrammable; |
| 29 | import org.slf4j.Logger; | 28 | import org.slf4j.Logger; |
| 30 | import org.slf4j.LoggerFactory; | 29 | import org.slf4j.LoggerFactory; |
| 31 | 30 | ||
| 31 | +import java.util.List; | ||
| 32 | + | ||
| 32 | import static java.lang.Math.toIntExact; | 33 | import static java.lang.Math.toIntExact; |
| 33 | -import static org.onosproject.net.PortNumber.FLOOD; | 34 | +import static java.util.stream.Collectors.toList; |
| 34 | import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT; | 35 | import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT; |
| 36 | +import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction; | ||
| 35 | 37 | ||
| 36 | /** | 38 | /** |
| 37 | - * Packet programmable device behaviour implementation for BMv2. | 39 | + * Implementation of the packet programmable behaviour for BMv2. |
| 38 | */ | 40 | */ |
| 39 | public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable { | 41 | public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable { |
| 40 | 42 | ||
| 41 | - private static final Logger LOG = | 43 | + private final Logger log = LoggerFactory.getLogger(this.getClass()); |
| 42 | - LoggerFactory.getLogger(Bmv2PacketProgrammable.class); | ||
| 43 | 44 | ||
| 44 | @Override | 45 | @Override |
| 45 | public void emit(OutboundPacket packet) { | 46 | public void emit(OutboundPacket packet) { |
| 46 | 47 | ||
| 47 | TrafficTreatment treatment = packet.treatment(); | 48 | TrafficTreatment treatment = packet.treatment(); |
| 48 | 49 | ||
| 49 | - treatment.allInstructions().forEach(inst -> { | 50 | + // BMv2 supports only OUTPUT instructions. |
| 50 | - if (inst.type().equals(OUTPUT)) { | 51 | + List<OutputInstruction> outInstructions = treatment.allInstructions() |
| 51 | - Instructions.OutputInstruction outInst = (Instructions.OutputInstruction) inst; | 52 | + .stream() |
| 52 | - if (outInst.port().isLogical()) { | 53 | + .filter(i -> i.type().equals(OUTPUT)) |
| 53 | - if (outInst.port() == FLOOD) { | 54 | + .map(i -> (OutputInstruction) i) |
| 54 | - // TODO: implement flood | 55 | + .collect(toList()); |
| 55 | - LOG.info("Flood not implemented", outInst); | 56 | + |
| 56 | - } | 57 | + if (treatment.allInstructions().size() != outInstructions.size()) { |
| 57 | - LOG.info("Output on logical port not supported: {}", outInst); | 58 | + // There are other instructions that are not of type OUTPUT |
| 58 | - } else { | 59 | + log.warn("Dropping emit request, treatment nor supported: {}", treatment); |
| 59 | - try { | 60 | + return; |
| 60 | - long longPort = outInst.port().toLong(); | 61 | + } |
| 61 | - int portNumber = toIntExact(longPort); | 62 | + |
| 62 | - send(portNumber, packet); | 63 | + outInstructions.forEach(outInst -> { |
| 63 | - } catch (ArithmeticException e) { | 64 | + if (outInst.port().isLogical()) { |
| 64 | - LOG.error("Port number overflow! Cannot send packet on port {} (long), as the bmv2" + | 65 | + log.warn("Dropping emit request, logical port not supported: {}", outInst.port()); |
| 65 | - " device only accepts int port values."); | ||
| 66 | - } | ||
| 67 | - } | ||
| 68 | } else { | 66 | } else { |
| 69 | - LOG.info("Instruction type not supported: {}", inst.type().name()); | 67 | + try { |
| 68 | + int portNumber = toIntExact(outInst.port().toLong()); | ||
| 69 | + send(portNumber, packet); | ||
| 70 | + } catch (ArithmeticException e) { | ||
| 71 | + log.error("Dropping emit request, port number too big: {}", outInst.port().toLong()); | ||
| 72 | + } | ||
| 70 | } | 73 | } |
| 71 | }); | 74 | }); |
| 72 | } | 75 | } |
| ... | @@ -75,19 +78,25 @@ public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements | ... | @@ -75,19 +78,25 @@ public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements |
| 75 | 78 | ||
| 76 | DeviceId deviceId = handler().data().deviceId(); | 79 | DeviceId deviceId = handler().data().deviceId(); |
| 77 | 80 | ||
| 78 | - Bmv2Client deviceClient; | 81 | + Bmv2Controller controller = handler().get(Bmv2Controller.class); |
| 82 | + if (controller == null) { | ||
| 83 | + log.error("Failed to get BMv2 controller"); | ||
| 84 | + return; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + Bmv2DeviceAgent deviceAgent; | ||
| 79 | try { | 88 | try { |
| 80 | - deviceClient = Bmv2ThriftClient.of(deviceId); | 89 | + deviceAgent = controller.getAgent(deviceId); |
| 81 | } catch (Bmv2RuntimeException e) { | 90 | } catch (Bmv2RuntimeException e) { |
| 82 | - LOG.error("Failed to connect to Bmv2 device", e); | 91 | + log.error("Failed to get Bmv2 device agent for {}: {}", deviceId, e.explain()); |
| 83 | return; | 92 | return; |
| 84 | } | 93 | } |
| 85 | 94 | ||
| 86 | ImmutableByteSequence bs = ImmutableByteSequence.copyFrom(packet.data()); | 95 | ImmutableByteSequence bs = ImmutableByteSequence.copyFrom(packet.data()); |
| 87 | try { | 96 | try { |
| 88 | - deviceClient.transmitPacket(port, bs); | 97 | + deviceAgent.transmitPacket(port, bs); |
| 89 | } catch (Bmv2RuntimeException e) { | 98 | } catch (Bmv2RuntimeException e) { |
| 90 | - LOG.info("Unable to push packet to device: deviceId={}, packet={}", deviceId, bs); | 99 | + log.warn("Unable to emit packet trough {}: {}", deviceId, e.explain()); |
| 91 | } | 100 | } |
| 92 | } | 101 | } |
| 93 | } | 102 | } | ... | ... |
| ... | @@ -37,8 +37,8 @@ public class Bmv2Pipeliner extends AbstractHandlerBehaviour implements Pipeliner | ... | @@ -37,8 +37,8 @@ public class Bmv2Pipeliner extends AbstractHandlerBehaviour implements Pipeliner |
| 37 | 37 | ||
| 38 | @Override | 38 | @Override |
| 39 | public void init(DeviceId deviceId, PipelinerContext context) { | 39 | public void init(DeviceId deviceId, PipelinerContext context) { |
| 40 | - // TODO: get multi-table pipeliner dynamically based on BMv2 device running model | 40 | + // TODO: get multi-table pipeliner dynamically based on BMv2 device running model (hard). |
| 41 | - // Right now we only support single table pipelines | 41 | + // Right now we are able to map flow objectives only in the first table of the pipeline. |
| 42 | pipeliner = new DefaultSingleTablePipeline(); | 42 | pipeliner = new DefaultSingleTablePipeline(); |
| 43 | pipeliner.init(deviceId, context); | 43 | pipeliner.init(deviceId, context); |
| 44 | } | 44 | } | ... | ... |
| 1 | -/* | ||
| 2 | - * Copyright 2014-2016 Open Networking Laboratory | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package org.onosproject.drivers.bmv2; | ||
| 18 | - | ||
| 19 | -import com.google.common.collect.ImmutableList; | ||
| 20 | -import com.google.common.collect.Lists; | ||
| 21 | -import org.onosproject.bmv2.api.runtime.Bmv2Client; | ||
| 22 | -import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | ||
| 23 | -import org.onosproject.bmv2.ctl.Bmv2ThriftClient; | ||
| 24 | -import org.onosproject.net.DefaultAnnotations; | ||
| 25 | -import org.onosproject.net.PortNumber; | ||
| 26 | -import org.onosproject.net.SparseAnnotations; | ||
| 27 | -import org.onosproject.net.behaviour.PortDiscovery; | ||
| 28 | -import org.onosproject.net.device.DefaultPortDescription; | ||
| 29 | -import org.onosproject.net.device.PortDescription; | ||
| 30 | -import org.onosproject.net.driver.AbstractHandlerBehaviour; | ||
| 31 | -import org.slf4j.Logger; | ||
| 32 | -import org.slf4j.LoggerFactory; | ||
| 33 | - | ||
| 34 | -import java.util.Collections; | ||
| 35 | -import java.util.List; | ||
| 36 | - | ||
| 37 | -public class Bmv2PortDiscovery extends AbstractHandlerBehaviour | ||
| 38 | - implements PortDiscovery { | ||
| 39 | - | ||
| 40 | - private final Logger log = | ||
| 41 | - LoggerFactory.getLogger(this.getClass()); | ||
| 42 | - | ||
| 43 | - @Override | ||
| 44 | - public List<PortDescription> getPorts() { | ||
| 45 | - Bmv2Client deviceClient; | ||
| 46 | - try { | ||
| 47 | - deviceClient = Bmv2ThriftClient.of(handler().data().deviceId()); | ||
| 48 | - } catch (Bmv2RuntimeException e) { | ||
| 49 | - log.error("Failed to connect to Bmv2 device", e); | ||
| 50 | - return Collections.emptyList(); | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - List<PortDescription> portDescriptions = Lists.newArrayList(); | ||
| 54 | - | ||
| 55 | - try { | ||
| 56 | - | ||
| 57 | - deviceClient.getPortsInfo().forEach( | ||
| 58 | - p -> { | ||
| 59 | - DefaultAnnotations.Builder builder = | ||
| 60 | - DefaultAnnotations.builder(); | ||
| 61 | - p.getExtraProperties().forEach(builder::set); | ||
| 62 | - SparseAnnotations annotations = builder.build(); | ||
| 63 | - | ||
| 64 | - portDescriptions.add(new DefaultPortDescription( | ||
| 65 | - PortNumber.portNumber( | ||
| 66 | - (long) p.portNumber(), | ||
| 67 | - p.ifaceName()), | ||
| 68 | - p.isUp(), | ||
| 69 | - annotations | ||
| 70 | - )); | ||
| 71 | - }); | ||
| 72 | - } catch (Bmv2RuntimeException e) { | ||
| 73 | - log.error("Unable to get port description from Bmv2 device", e); | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - return ImmutableList.copyOf(portDescriptions); | ||
| 77 | - } | ||
| 78 | -} |
| 1 | -/* | ||
| 2 | - * Copyright 2016-present Open Networking Laboratory | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package org.onosproject.drivers.bmv2.translators; | ||
| 18 | - | ||
| 19 | -import com.google.common.annotations.Beta; | ||
| 20 | -import org.onlab.util.ImmutableByteSequence; | ||
| 21 | -import org.onosproject.bmv2.api.model.Bmv2ModelField; | ||
| 22 | -import org.onosproject.bmv2.api.model.Bmv2ModelTable; | ||
| 23 | -import org.onosproject.bmv2.api.model.Bmv2ModelTableKey; | ||
| 24 | -import org.onosproject.bmv2.api.runtime.Bmv2Action; | ||
| 25 | -import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector; | ||
| 26 | -import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment; | ||
| 27 | -import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam; | ||
| 28 | -import org.onosproject.bmv2.api.runtime.Bmv2MatchKey; | ||
| 29 | -import org.onosproject.bmv2.api.runtime.Bmv2TableEntry; | ||
| 30 | -import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam; | ||
| 31 | -import org.onosproject.net.flow.FlowRule; | ||
| 32 | -import org.onosproject.net.flow.TrafficSelector; | ||
| 33 | -import org.onosproject.net.flow.TrafficTreatment; | ||
| 34 | -import org.onosproject.net.flow.criteria.Criterion; | ||
| 35 | -import org.onosproject.net.flow.criteria.EthCriterion; | ||
| 36 | -import org.onosproject.net.flow.criteria.EthTypeCriterion; | ||
| 37 | -import org.onosproject.net.flow.criteria.ExtensionCriterion; | ||
| 38 | -import org.onosproject.net.flow.criteria.ExtensionSelector; | ||
| 39 | -import org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes; | ||
| 40 | -import org.onosproject.net.flow.criteria.PortCriterion; | ||
| 41 | -import org.onosproject.net.flow.instructions.ExtensionTreatment; | ||
| 42 | -import org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes; | ||
| 43 | -import org.onosproject.net.flow.instructions.Instruction; | ||
| 44 | -import org.onosproject.net.flow.instructions.Instructions; | ||
| 45 | -import org.onosproject.net.flow.instructions.Instructions.ExtensionInstructionWrapper; | ||
| 46 | - | ||
| 47 | -/** | ||
| 48 | - * Default Bmv2 flow rule translator implementation. | ||
| 49 | - * <p> | ||
| 50 | - * Flow rules are translated into {@link Bmv2TableEntry BMv2 table entries} according to the following logic: | ||
| 51 | - * <ul> | ||
| 52 | - * <li> table name: obtained from the Bmv2 model using the flow rule table ID; | ||
| 53 | - * <li> match key: if the flow rule selector defines only a criterion of type {@link Criterion.Type#EXTENSION EXTENSION} | ||
| 54 | - * , then the latter is expected to contain a {@link Bmv2ExtensionSelector Bmv2ExtensionSelector}, which should provide | ||
| 55 | - * a match key already formatted for the given table; otherwise a match key is built using the | ||
| 56 | - * {@link TranslatorConfig#fieldToCriterionTypeMap() mapping} defined by this translator configuration. | ||
| 57 | - * <li> action: if the flow rule treatment contains only one instruction of type | ||
| 58 | - * {@link Instruction.Type#EXTENSION EXTENSION}, then the latter is expected to contain a {@link Bmv2ExtensionTreatment} | ||
| 59 | - * , which should provide a {@link Bmv2Action} already formatted for the given table; otherwise, an action is | ||
| 60 | - * {@link TranslatorConfig#buildAction(TrafficTreatment) built} using this translator configuration. | ||
| 61 | - * <li> priority: the same as the flow rule. | ||
| 62 | - * <li> timeout: if the table supports timeout, use the same as the flow rule, otherwise none (i.e. permanent entry). | ||
| 63 | - * </ul> | ||
| 64 | - */ | ||
| 65 | -@Beta | ||
| 66 | -public class Bmv2DefaultFlowRuleTranslator implements Bmv2FlowRuleTranslator { | ||
| 67 | - | ||
| 68 | - private final TranslatorConfig config; | ||
| 69 | - | ||
| 70 | - public Bmv2DefaultFlowRuleTranslator(TranslatorConfig config) { | ||
| 71 | - this.config = config; | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - private static Bmv2TernaryMatchParam buildTernaryParam(Bmv2ModelField field, Criterion criterion, int byteWidth) | ||
| 75 | - throws Bmv2FlowRuleTranslatorException { | ||
| 76 | - | ||
| 77 | - // Value and mask will be filled according to criterion type | ||
| 78 | - ImmutableByteSequence value; | ||
| 79 | - ImmutableByteSequence mask = null; | ||
| 80 | - | ||
| 81 | - switch (criterion.type()) { | ||
| 82 | - case IN_PORT: | ||
| 83 | - // FIXME: allow port numbers of variable bit length (based on model), truncating when necessary | ||
| 84 | - short port = (short) ((PortCriterion) criterion).port().toLong(); | ||
| 85 | - value = ImmutableByteSequence.copyFrom(port); | ||
| 86 | - break; | ||
| 87 | - case ETH_DST: | ||
| 88 | - EthCriterion c = (EthCriterion) criterion; | ||
| 89 | - value = ImmutableByteSequence.copyFrom(c.mac().toBytes()); | ||
| 90 | - if (c.mask() != null) { | ||
| 91 | - mask = ImmutableByteSequence.copyFrom(c.mask().toBytes()); | ||
| 92 | - } | ||
| 93 | - break; | ||
| 94 | - case ETH_SRC: | ||
| 95 | - EthCriterion c2 = (EthCriterion) criterion; | ||
| 96 | - value = ImmutableByteSequence.copyFrom(c2.mac().toBytes()); | ||
| 97 | - if (c2.mask() != null) { | ||
| 98 | - mask = ImmutableByteSequence.copyFrom(c2.mask().toBytes()); | ||
| 99 | - } | ||
| 100 | - break; | ||
| 101 | - case ETH_TYPE: | ||
| 102 | - short ethType = ((EthTypeCriterion) criterion).ethType().toShort(); | ||
| 103 | - value = ImmutableByteSequence.copyFrom(ethType); | ||
| 104 | - break; | ||
| 105 | - // TODO: implement building for other criterion types (easy with DefaultCriterion of ONOS-4034) | ||
| 106 | - default: | ||
| 107 | - throw new Bmv2FlowRuleTranslatorException("Feature not implemented, ternary builder for criterion" + | ||
| 108 | - "type: " + criterion.type().name()); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - if (mask == null) { | ||
| 112 | - // no mask, all ones | ||
| 113 | - mask = ImmutableByteSequence.ofOnes(byteWidth); | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - return new Bmv2TernaryMatchParam(value, mask); | ||
| 117 | - } | ||
| 118 | - | ||
| 119 | - private static Bmv2MatchKey getMatchKeyFromExtension(ExtensionCriterion criterion) | ||
| 120 | - throws Bmv2FlowRuleTranslatorException { | ||
| 121 | - | ||
| 122 | - ExtensionSelector extSelector = criterion.extensionSelector(); | ||
| 123 | - | ||
| 124 | - if (extSelector.type() == ExtensionSelectorTypes.P4_BMV2_MATCH_KEY.type()) { | ||
| 125 | - if (extSelector instanceof Bmv2ExtensionSelector) { | ||
| 126 | - return ((Bmv2ExtensionSelector) extSelector).matchKey(); | ||
| 127 | - } else { | ||
| 128 | - throw new Bmv2FlowRuleTranslatorException("Unable to decode extension selector " + extSelector); | ||
| 129 | - } | ||
| 130 | - } else { | ||
| 131 | - throw new Bmv2FlowRuleTranslatorException("Unsupported extension selector type " + extSelector.type()); | ||
| 132 | - } | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - private static Bmv2Action getActionFromExtension(Instructions.ExtensionInstructionWrapper inst) | ||
| 136 | - throws Bmv2FlowRuleTranslatorException { | ||
| 137 | - | ||
| 138 | - ExtensionTreatment extTreatment = inst.extensionInstruction(); | ||
| 139 | - | ||
| 140 | - if (extTreatment.type() == ExtensionTreatmentTypes.P4_BMV2_ACTION.type()) { | ||
| 141 | - if (extTreatment instanceof Bmv2ExtensionTreatment) { | ||
| 142 | - return ((Bmv2ExtensionTreatment) extTreatment).getAction(); | ||
| 143 | - } else { | ||
| 144 | - throw new Bmv2FlowRuleTranslatorException("Unable to decode treatment extension: " + extTreatment); | ||
| 145 | - } | ||
| 146 | - } else { | ||
| 147 | - throw new Bmv2FlowRuleTranslatorException("Unsupported treatment extension type: " + extTreatment.type()); | ||
| 148 | - } | ||
| 149 | - } | ||
| 150 | - | ||
| 151 | - private static Bmv2MatchKey buildMatchKey(TranslatorConfig config, TrafficSelector selector, Bmv2ModelTable table) | ||
| 152 | - throws Bmv2FlowRuleTranslatorException { | ||
| 153 | - | ||
| 154 | - Bmv2MatchKey.Builder matchKeyBuilder = Bmv2MatchKey.builder(); | ||
| 155 | - | ||
| 156 | - for (Bmv2ModelTableKey key : table.keys()) { | ||
| 157 | - | ||
| 158 | - String fieldName = key.field().header().name() + "." + key.field().type().name(); | ||
| 159 | - int byteWidth = (int) Math.ceil((double) key.field().type().bitWidth() / 8.0); | ||
| 160 | - Criterion.Type criterionType = config.fieldToCriterionTypeMap().get(fieldName); | ||
| 161 | - | ||
| 162 | - if (criterionType == null || selector.getCriterion(criterionType) == null) { | ||
| 163 | - // A mapping is not available or the selector doesn't have such a type | ||
| 164 | - switch (key.matchType()) { | ||
| 165 | - case TERNARY: | ||
| 166 | - // Wildcard field | ||
| 167 | - matchKeyBuilder.withWildcard(byteWidth); | ||
| 168 | - break; | ||
| 169 | - case LPM: | ||
| 170 | - // LPM with prefix 0 | ||
| 171 | - matchKeyBuilder.add(new Bmv2LpmMatchParam(ImmutableByteSequence.ofZeros(byteWidth), 0)); | ||
| 172 | - break; | ||
| 173 | - default: | ||
| 174 | - throw new Bmv2FlowRuleTranslatorException("Match field not supported: " + fieldName); | ||
| 175 | - } | ||
| 176 | - // Next key | ||
| 177 | - continue; | ||
| 178 | - } | ||
| 179 | - | ||
| 180 | - Criterion criterion = selector.getCriterion(criterionType); | ||
| 181 | - Bmv2TernaryMatchParam matchParam = null; | ||
| 182 | - | ||
| 183 | - switch (key.matchType()) { | ||
| 184 | - case TERNARY: | ||
| 185 | - matchParam = buildTernaryParam(key.field(), criterion, byteWidth); | ||
| 186 | - break; | ||
| 187 | - default: | ||
| 188 | - // TODO: implement other match param builders (exact, LPM, etc.) | ||
| 189 | - throw new Bmv2FlowRuleTranslatorException("Feature not implemented, match param builder: " | ||
| 190 | - + key.matchType().name()); | ||
| 191 | - } | ||
| 192 | - | ||
| 193 | - matchKeyBuilder.add(matchParam); | ||
| 194 | - } | ||
| 195 | - | ||
| 196 | - return matchKeyBuilder.build(); | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | - @Override | ||
| 200 | - public Bmv2TableEntry translate(FlowRule rule) | ||
| 201 | - throws Bmv2FlowRuleTranslatorException { | ||
| 202 | - | ||
| 203 | - int tableId = rule.tableId(); | ||
| 204 | - | ||
| 205 | - Bmv2ModelTable table = config.model().table(tableId); | ||
| 206 | - | ||
| 207 | - if (table == null) { | ||
| 208 | - throw new Bmv2FlowRuleTranslatorException("Unknown table ID: " + tableId); | ||
| 209 | - } | ||
| 210 | - | ||
| 211 | - /* Translate selector */ | ||
| 212 | - | ||
| 213 | - TrafficSelector selector = rule.selector(); | ||
| 214 | - Bmv2MatchKey bmv2MatchKey = null; | ||
| 215 | - | ||
| 216 | - // If selector has only 1 criterion of type extension, use that | ||
| 217 | - Criterion criterion = selector.getCriterion(Criterion.Type.EXTENSION); | ||
| 218 | - if (criterion != null) { | ||
| 219 | - if (selector.criteria().size() == 1) { | ||
| 220 | - bmv2MatchKey = getMatchKeyFromExtension((ExtensionCriterion) criterion); | ||
| 221 | - } else { | ||
| 222 | - throw new Bmv2FlowRuleTranslatorException("Unable to translate traffic selector, found multiple " + | ||
| 223 | - "criteria of which one is an extension: " + | ||
| 224 | - selector.toString()); | ||
| 225 | - } | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | - if (bmv2MatchKey == null) { | ||
| 229 | - // not an extension | ||
| 230 | - bmv2MatchKey = buildMatchKey(config, selector, table); | ||
| 231 | - } | ||
| 232 | - | ||
| 233 | - /* Translate treatment */ | ||
| 234 | - | ||
| 235 | - TrafficTreatment treatment = rule.treatment(); | ||
| 236 | - Bmv2Action bmv2Action = null; | ||
| 237 | - | ||
| 238 | - // If treatment has only 1 instruction of type extension, use that | ||
| 239 | - for (Instruction inst : treatment.allInstructions()) { | ||
| 240 | - if (inst.type() == Instruction.Type.EXTENSION) { | ||
| 241 | - if (treatment.allInstructions().size() == 1) { | ||
| 242 | - bmv2Action = getActionFromExtension((ExtensionInstructionWrapper) inst); | ||
| 243 | - } else { | ||
| 244 | - throw new Bmv2FlowRuleTranslatorException("Unable to translate traffic treatment, found multiple " + | ||
| 245 | - "instructions of which one is an extension: " + | ||
| 246 | - selector.toString()); | ||
| 247 | - } | ||
| 248 | - } | ||
| 249 | - } | ||
| 250 | - | ||
| 251 | - if (bmv2Action == null) { | ||
| 252 | - // No extension, use config to build action | ||
| 253 | - bmv2Action = config.buildAction(treatment); | ||
| 254 | - } | ||
| 255 | - | ||
| 256 | - if (bmv2Action == null) { | ||
| 257 | - // Config returned null | ||
| 258 | - throw new Bmv2FlowRuleTranslatorException("Unable to translate treatment: " + treatment); | ||
| 259 | - } | ||
| 260 | - | ||
| 261 | - Bmv2TableEntry.Builder tableEntryBuilder = Bmv2TableEntry.builder(); | ||
| 262 | - | ||
| 263 | - // In BMv2 0 is the highest priority, i.e. the opposite than ONOS. | ||
| 264 | - int newPriority = Integer.MAX_VALUE - rule.priority(); | ||
| 265 | - | ||
| 266 | - tableEntryBuilder | ||
| 267 | - .withTableName(table.name()) | ||
| 268 | - .withPriority(newPriority) | ||
| 269 | - .withMatchKey(bmv2MatchKey) | ||
| 270 | - .withAction(bmv2Action); | ||
| 271 | - | ||
| 272 | - if (!rule.isPermanent()) { | ||
| 273 | - if (table.hasTimeouts()) { | ||
| 274 | - tableEntryBuilder.withTimeout((double) rule.timeout()); | ||
| 275 | - } | ||
| 276 | - //FIXME: add warn log or exception? | ||
| 277 | - } | ||
| 278 | - | ||
| 279 | - return tableEntryBuilder.build(); | ||
| 280 | - } | ||
| 281 | - | ||
| 282 | - @Override | ||
| 283 | - public TranslatorConfig config() { | ||
| 284 | - return this.config; | ||
| 285 | - } | ||
| 286 | -} |
| 1 | -/* | ||
| 2 | - * Copyright 2016-present Open Networking Laboratory | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package org.onosproject.drivers.bmv2.translators; | ||
| 18 | - | ||
| 19 | -import com.google.common.annotations.Beta; | ||
| 20 | -import org.onosproject.bmv2.api.model.Bmv2Model; | ||
| 21 | -import org.onosproject.net.flow.criteria.Criterion; | ||
| 22 | - | ||
| 23 | -import java.util.Map; | ||
| 24 | - | ||
| 25 | -import static org.onosproject.drivers.bmv2.translators.Bmv2FlowRuleTranslator.TranslatorConfig; | ||
| 26 | - | ||
| 27 | -/** | ||
| 28 | - * Default implementation of a BMv2 flow rule translator configuration. | ||
| 29 | - */ | ||
| 30 | -@Beta | ||
| 31 | -public abstract class Bmv2DefaultTranslatorConfig implements TranslatorConfig { | ||
| 32 | - | ||
| 33 | - private final Bmv2Model model; | ||
| 34 | - private final Map<String, Criterion.Type> fieldMap; | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * Creates a new translator configuration. | ||
| 38 | - * | ||
| 39 | - * @param model a BMv2 packet processing model | ||
| 40 | - * @param fieldMap a field-to-criterion type map | ||
| 41 | - */ | ||
| 42 | - protected Bmv2DefaultTranslatorConfig(Bmv2Model model, Map<String, Criterion.Type> fieldMap) { | ||
| 43 | - this.model = model; | ||
| 44 | - this.fieldMap = fieldMap; | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - @Override | ||
| 48 | - public Bmv2Model model() { | ||
| 49 | - return this.model; | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - @Override | ||
| 53 | - public Map<String, Criterion.Type> fieldToCriterionTypeMap() { | ||
| 54 | - return this.fieldMap; | ||
| 55 | - } | ||
| 56 | -} |
| 1 | -/* | ||
| 2 | - * Copyright 2016-present Open Networking Laboratory | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package org.onosproject.drivers.bmv2.translators; | ||
| 18 | - | ||
| 19 | -import com.google.common.annotations.Beta; | ||
| 20 | -import org.onosproject.bmv2.api.model.Bmv2Model; | ||
| 21 | -import org.onosproject.bmv2.api.runtime.Bmv2Action; | ||
| 22 | -import org.onosproject.bmv2.api.runtime.Bmv2TableEntry; | ||
| 23 | -import org.onosproject.net.flow.FlowRule; | ||
| 24 | -import org.onosproject.net.flow.TrafficTreatment; | ||
| 25 | -import org.onosproject.net.flow.criteria.Criterion; | ||
| 26 | - | ||
| 27 | -import java.util.Map; | ||
| 28 | - | ||
| 29 | -/** | ||
| 30 | - * Translator of ONOS flow rules to BMv2 table entries. Translation depends on a | ||
| 31 | - * {@link TranslatorConfig translator configuration}. | ||
| 32 | - */ | ||
| 33 | -@Beta | ||
| 34 | -public interface Bmv2FlowRuleTranslator { | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * Returns a new BMv2 table entry equivalent to the given flow rule. | ||
| 38 | - * | ||
| 39 | - * @param rule a flow rule | ||
| 40 | - * @return a BMv2 table entry | ||
| 41 | - * @throws Bmv2FlowRuleTranslatorException if the flow rule cannot be | ||
| 42 | - * translated | ||
| 43 | - */ | ||
| 44 | - Bmv2TableEntry translate(FlowRule rule) throws Bmv2FlowRuleTranslatorException; | ||
| 45 | - | ||
| 46 | - /** | ||
| 47 | - * Returns the configuration of this translator. | ||
| 48 | - * | ||
| 49 | - * @return a translator configuration | ||
| 50 | - */ | ||
| 51 | - TranslatorConfig config(); | ||
| 52 | - | ||
| 53 | - /** | ||
| 54 | - * BMv2 flow rules translator configuration. Such a configuration is used to | ||
| 55 | - * generate table entries that are compatible with a given {@link Bmv2Model}. | ||
| 56 | - */ | ||
| 57 | - @Beta | ||
| 58 | - interface TranslatorConfig { | ||
| 59 | - /** | ||
| 60 | - * Return the {@link Bmv2Model} associated with this configuration. | ||
| 61 | - * | ||
| 62 | - * @return a BMv2 model | ||
| 63 | - */ | ||
| 64 | - Bmv2Model model(); | ||
| 65 | - | ||
| 66 | - /** | ||
| 67 | - * Returns a map describing a one-to-one relationship between BMv2 | ||
| 68 | - * header field names and ONOS criterion types. Header field names are | ||
| 69 | - * formatted using the notation {@code header_name.field_name} | ||
| 70 | - * representing a specific header field instance extracted by the BMv2 | ||
| 71 | - * parser (e.g. {@code ethernet.dstAddr}). | ||
| 72 | - * | ||
| 73 | - * @return a map where the keys represent BMv2 header field names and | ||
| 74 | - * values are criterion types | ||
| 75 | - */ | ||
| 76 | - Map<String, Criterion.Type> fieldToCriterionTypeMap(); | ||
| 77 | - | ||
| 78 | - /** | ||
| 79 | - * Return a BMv2 action that is equivalent to the given ONOS traffic | ||
| 80 | - * treatment. | ||
| 81 | - * | ||
| 82 | - * @param treatment a traffic treatment | ||
| 83 | - * @return a BMv2 action object | ||
| 84 | - * @throws Bmv2FlowRuleTranslatorException if the treatment cannot be | ||
| 85 | - * translated to a BMv2 action | ||
| 86 | - */ | ||
| 87 | - Bmv2Action buildAction(TrafficTreatment treatment) | ||
| 88 | - throws Bmv2FlowRuleTranslatorException; | ||
| 89 | - } | ||
| 90 | -} |
| 1 | -/* | ||
| 2 | - * Copyright 2016-present Open Networking Laboratory | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package org.onosproject.drivers.bmv2.translators; | ||
| 18 | - | ||
| 19 | -import com.google.common.annotations.Beta; | ||
| 20 | -import com.google.common.collect.ImmutableMap; | ||
| 21 | -import org.onlab.util.ImmutableByteSequence; | ||
| 22 | -import org.onosproject.bmv2.api.model.Bmv2Model; | ||
| 23 | -import org.onosproject.bmv2.api.runtime.Bmv2Action; | ||
| 24 | -import org.onosproject.net.PortNumber; | ||
| 25 | -import org.onosproject.net.flow.TrafficTreatment; | ||
| 26 | -import org.onosproject.net.flow.criteria.Criterion; | ||
| 27 | -import org.onosproject.net.flow.instructions.Instruction; | ||
| 28 | -import org.onosproject.net.flow.instructions.Instructions; | ||
| 29 | - | ||
| 30 | -import java.util.Map; | ||
| 31 | - | ||
| 32 | -/** | ||
| 33 | - * Implementation of a Bmv2 flow rule translator configuration for the | ||
| 34 | - * simple.p4 model. | ||
| 35 | - */ | ||
| 36 | -@Beta | ||
| 37 | -public class Bmv2SimpleTranslatorConfig extends Bmv2DefaultTranslatorConfig { | ||
| 38 | - | ||
| 39 | - // Lazily populate field map. | ||
| 40 | - private static final Map<String, Criterion.Type> FIELD_MAP = ImmutableMap.of( | ||
| 41 | - "standard_metadata.ingress_port", Criterion.Type.IN_PORT, | ||
| 42 | - "ethernet.dstAddr", Criterion.Type.ETH_DST, | ||
| 43 | - "ethernet.srcAddr", Criterion.Type.ETH_SRC, | ||
| 44 | - "ethernet.etherType", Criterion.Type.ETH_TYPE); | ||
| 45 | - | ||
| 46 | - /** | ||
| 47 | - * Creates a new simple pipeline translator configuration. | ||
| 48 | - */ | ||
| 49 | - public Bmv2SimpleTranslatorConfig(Bmv2Model model) { | ||
| 50 | - // Populate fieldMap. | ||
| 51 | - super(model, FIELD_MAP); | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - private static Bmv2Action buildDropAction() { | ||
| 55 | - return Bmv2Action.builder() | ||
| 56 | - .withName("_drop") | ||
| 57 | - .build(); | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - private static Bmv2Action buildPushToCpAction() { | ||
| 61 | - return Bmv2Action.builder() | ||
| 62 | - .withName("send_to_cpu") | ||
| 63 | - .build(); | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - private static Bmv2Action buildFwdAction(Instructions.OutputInstruction inst) | ||
| 67 | - throws Bmv2FlowRuleTranslatorException { | ||
| 68 | - | ||
| 69 | - Bmv2Action.Builder actionBuilder = Bmv2Action.builder(); | ||
| 70 | - | ||
| 71 | - actionBuilder.withName("fwd"); | ||
| 72 | - | ||
| 73 | - if (inst.port().isLogical()) { | ||
| 74 | - if (inst.port() == PortNumber.CONTROLLER) { | ||
| 75 | - return buildPushToCpAction(); | ||
| 76 | - } else { | ||
| 77 | - throw new Bmv2FlowRuleTranslatorException( | ||
| 78 | - "Output logic port number not supported: " + inst); | ||
| 79 | - } | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - actionBuilder.addParameter( | ||
| 83 | - ImmutableByteSequence.copyFrom((short) inst.port().toLong())); | ||
| 84 | - | ||
| 85 | - return actionBuilder.build(); | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - @Override | ||
| 89 | - public Bmv2Action buildAction(TrafficTreatment treatment) | ||
| 90 | - throws Bmv2FlowRuleTranslatorException { | ||
| 91 | - | ||
| 92 | - | ||
| 93 | - if (treatment.allInstructions().size() == 0) { | ||
| 94 | - // No instructions means drop. | ||
| 95 | - return buildDropAction(); | ||
| 96 | - } else if (treatment.allInstructions().size() > 1) { | ||
| 97 | - // Otherwise, we understand treatments with only 1 instruction. | ||
| 98 | - throw new Bmv2FlowRuleTranslatorException( | ||
| 99 | - "Treatment not supported, more than 1 instructions found: " | ||
| 100 | - + treatment.toString()); | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - Instruction instruction = treatment.allInstructions().get(0); | ||
| 104 | - | ||
| 105 | - switch (instruction.type()) { | ||
| 106 | - case OUTPUT: | ||
| 107 | - return buildFwdAction((Instructions.OutputInstruction) instruction); | ||
| 108 | - case NOACTION: | ||
| 109 | - return buildDropAction(); | ||
| 110 | - default: | ||
| 111 | - throw new Bmv2FlowRuleTranslatorException( | ||
| 112 | - "Instruction type not supported: " | ||
| 113 | - + instruction.type().name()); | ||
| 114 | - } | ||
| 115 | - } | ||
| 116 | -} |
| ... | @@ -16,14 +16,18 @@ | ... | @@ -16,14 +16,18 @@ |
| 16 | ~ limitations under the License. | 16 | ~ limitations under the License. |
| 17 | --> | 17 | --> |
| 18 | <drivers> | 18 | <drivers> |
| 19 | - <driver name="bmv2-thrift" manufacturer="p4.org" hwVersion="bmv2" swVersion="unknown"> | 19 | + <driver name="bmv2-thrift" manufacturer="p4.org" hwVersion="bmv2" swVersion="n/a"> |
| 20 | - <behaviour api="org.onosproject.net.behaviour.PortDiscovery" | 20 | + <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery" |
| 21 | - impl="org.onosproject.drivers.bmv2.Bmv2PortDiscovery"/> | 21 | + impl="org.onosproject.drivers.bmv2.Bmv2DeviceDescriptionDiscovery"/> |
| 22 | <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable" | 22 | <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable" |
| 23 | impl="org.onosproject.drivers.bmv2.Bmv2FlowRuleProgrammable"/> | 23 | impl="org.onosproject.drivers.bmv2.Bmv2FlowRuleProgrammable"/> |
| 24 | <behaviour api="org.onosproject.net.behaviour.Pipeliner" | 24 | <behaviour api="org.onosproject.net.behaviour.Pipeliner" |
| 25 | impl="org.onosproject.drivers.bmv2.Bmv2Pipeliner"/> | 25 | impl="org.onosproject.drivers.bmv2.Bmv2Pipeliner"/> |
| 26 | <behaviour api="org.onosproject.net.packet.PacketProgrammable" | 26 | <behaviour api="org.onosproject.net.packet.PacketProgrammable" |
| 27 | impl="org.onosproject.drivers.bmv2.Bmv2PacketProgrammable"/> | 27 | impl="org.onosproject.drivers.bmv2.Bmv2PacketProgrammable"/> |
| 28 | + <behaviour api="org.onosproject.net.behaviour.ExtensionSelectorResolver" | ||
| 29 | + impl="org.onosproject.drivers.bmv2.Bmv2ExtensionSelectorResolver"/> | ||
| 30 | + <behaviour api="org.onosproject.net.behaviour.ExtensionTreatmentResolver" | ||
| 31 | + impl="org.onosproject.drivers.bmv2.Bmv2ExtensionTreatmentResolver"/> | ||
| 28 | </driver> | 32 | </driver> |
| 29 | </drivers> | 33 | </drivers> | ... | ... |
| 1 | -/* | ||
| 2 | - * Copyright 2014-2016 Open Networking Laboratory | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package org.onosproject.drivers.bmv2; | ||
| 18 | - | ||
| 19 | -import com.eclipsesource.json.Json; | ||
| 20 | -import com.eclipsesource.json.JsonObject; | ||
| 21 | -import com.google.common.testing.EqualsTester; | ||
| 22 | -import org.junit.Before; | ||
| 23 | -import org.junit.Test; | ||
| 24 | -import org.onlab.packet.MacAddress; | ||
| 25 | -import org.onosproject.bmv2.api.model.Bmv2Model; | ||
| 26 | -import org.onosproject.bmv2.api.runtime.Bmv2TableEntry; | ||
| 27 | -import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam; | ||
| 28 | -import org.onosproject.core.ApplicationId; | ||
| 29 | -import org.onosproject.core.DefaultApplicationId; | ||
| 30 | -import org.onosproject.drivers.bmv2.translators.Bmv2DefaultFlowRuleTranslator; | ||
| 31 | -import org.onosproject.drivers.bmv2.translators.Bmv2FlowRuleTranslator; | ||
| 32 | -import org.onosproject.drivers.bmv2.translators.Bmv2SimpleTranslatorConfig; | ||
| 33 | -import org.onosproject.net.DeviceId; | ||
| 34 | -import org.onosproject.net.PortNumber; | ||
| 35 | -import org.onosproject.net.flow.DefaultFlowRule; | ||
| 36 | -import org.onosproject.net.flow.DefaultTrafficSelector; | ||
| 37 | -import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
| 38 | -import org.onosproject.net.flow.FlowRule; | ||
| 39 | -import org.onosproject.net.flow.TrafficSelector; | ||
| 40 | -import org.onosproject.net.flow.TrafficTreatment; | ||
| 41 | - | ||
| 42 | -import java.io.BufferedReader; | ||
| 43 | -import java.io.IOException; | ||
| 44 | -import java.io.InputStream; | ||
| 45 | -import java.io.InputStreamReader; | ||
| 46 | -import java.util.Random; | ||
| 47 | - | ||
| 48 | -import static org.hamcrest.CoreMatchers.equalTo; | ||
| 49 | -import static org.hamcrest.CoreMatchers.is; | ||
| 50 | -import static org.hamcrest.MatcherAssert.assertThat; | ||
| 51 | - | ||
| 52 | -/** | ||
| 53 | - * Tests for {@link Bmv2DefaultFlowRuleTranslator}. | ||
| 54 | - */ | ||
| 55 | -public class Bmv2DefaultFlowRuleTranslatorTest { | ||
| 56 | - | ||
| 57 | - private static final String JSON_CONFIG_PATH = "/simple.json"; | ||
| 58 | - private Random random = new Random(); | ||
| 59 | - private Bmv2Model model; | ||
| 60 | - private Bmv2FlowRuleTranslator.TranslatorConfig config; | ||
| 61 | - private Bmv2FlowRuleTranslator translator; | ||
| 62 | - | ||
| 63 | - @Before | ||
| 64 | - public void setUp() throws Exception { | ||
| 65 | - InputStream inputStream = Bmv2SimpleTranslatorConfig.class | ||
| 66 | - .getResourceAsStream(JSON_CONFIG_PATH); | ||
| 67 | - InputStreamReader reader = new InputStreamReader(inputStream); | ||
| 68 | - BufferedReader bufReader = new BufferedReader(reader); | ||
| 69 | - JsonObject json = null; | ||
| 70 | - try { | ||
| 71 | - json = Json.parse(bufReader).asObject(); | ||
| 72 | - } catch (IOException e) { | ||
| 73 | - throw new RuntimeException("Unable to parse JSON file: " + e.getMessage()); | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - this.model = Bmv2Model.parse(json); | ||
| 77 | - this.config = new Bmv2SimpleTranslatorConfig(model); | ||
| 78 | - this.translator = new Bmv2DefaultFlowRuleTranslator(config); | ||
| 79 | - | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - | ||
| 83 | - @Test | ||
| 84 | - public void testCompiler() throws Exception { | ||
| 85 | - | ||
| 86 | - DeviceId deviceId = DeviceId.NONE; | ||
| 87 | - ApplicationId appId = new DefaultApplicationId(1, "test"); | ||
| 88 | - int tableId = 0; | ||
| 89 | - MacAddress ethDstMac = MacAddress.valueOf(random.nextLong()); | ||
| 90 | - MacAddress ethSrcMac = MacAddress.valueOf(random.nextLong()); | ||
| 91 | - short ethType = (short) (0x0000FFFF & random.nextInt()); | ||
| 92 | - short outPort = (short) random.nextInt(65); | ||
| 93 | - short inPort = (short) random.nextInt(65); | ||
| 94 | - int timeout = random.nextInt(100); | ||
| 95 | - int priority = random.nextInt(100); | ||
| 96 | - | ||
| 97 | - TrafficSelector matchInPort1 = DefaultTrafficSelector | ||
| 98 | - .builder() | ||
| 99 | - .matchInPort(PortNumber.portNumber(inPort)) | ||
| 100 | - .matchEthDst(ethDstMac) | ||
| 101 | - .matchEthSrc(ethSrcMac) | ||
| 102 | - .matchEthType(ethType) | ||
| 103 | - .build(); | ||
| 104 | - | ||
| 105 | - TrafficTreatment outPort2 = DefaultTrafficTreatment | ||
| 106 | - .builder() | ||
| 107 | - .setOutput(PortNumber.portNumber(outPort)) | ||
| 108 | - .build(); | ||
| 109 | - | ||
| 110 | - FlowRule rule1 = DefaultFlowRule.builder() | ||
| 111 | - .forDevice(deviceId) | ||
| 112 | - .forTable(tableId) | ||
| 113 | - .fromApp(appId) | ||
| 114 | - .withSelector(matchInPort1) | ||
| 115 | - .withTreatment(outPort2) | ||
| 116 | - .makeTemporary(timeout) | ||
| 117 | - .withPriority(priority) | ||
| 118 | - .build(); | ||
| 119 | - | ||
| 120 | - FlowRule rule2 = DefaultFlowRule.builder() | ||
| 121 | - .forDevice(deviceId) | ||
| 122 | - .forTable(tableId) | ||
| 123 | - .fromApp(appId) | ||
| 124 | - .withSelector(matchInPort1) | ||
| 125 | - .withTreatment(outPort2) | ||
| 126 | - .makeTemporary(timeout) | ||
| 127 | - .withPriority(priority) | ||
| 128 | - .build(); | ||
| 129 | - | ||
| 130 | - Bmv2TableEntry entry1 = translator.translate(rule1); | ||
| 131 | - Bmv2TableEntry entry2 = translator.translate(rule1); | ||
| 132 | - | ||
| 133 | - // check equality, i.e. same rules must produce same entries | ||
| 134 | - new EqualsTester() | ||
| 135 | - .addEqualityGroup(rule1, rule2) | ||
| 136 | - .addEqualityGroup(entry1, entry2) | ||
| 137 | - .testEquals(); | ||
| 138 | - | ||
| 139 | - int numMatchParams = model.table(0).keys().size(); | ||
| 140 | - // parse values stored in entry1 | ||
| 141 | - Bmv2TernaryMatchParam inPortParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(0); | ||
| 142 | - Bmv2TernaryMatchParam ethDstParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(1); | ||
| 143 | - Bmv2TernaryMatchParam ethSrcParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(2); | ||
| 144 | - Bmv2TernaryMatchParam ethTypeParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(3); | ||
| 145 | - double expectedTimeout = (double) (model.table(0).hasTimeouts() ? rule1.timeout() : -1); | ||
| 146 | - | ||
| 147 | - // check that the number of parameters in the entry is the same as the number of table keys | ||
| 148 | - assertThat("Incorrect number of match parameters", | ||
| 149 | - entry1.matchKey().matchParams().size(), is(equalTo(numMatchParams))); | ||
| 150 | - | ||
| 151 | - // check that values stored in entry are the same used for the flow rule | ||
| 152 | - assertThat("Incorrect inPort match param value", | ||
| 153 | - inPortParam.value().asReadOnlyBuffer().getShort(), is(equalTo(inPort))); | ||
| 154 | - assertThat("Incorrect ethDestMac match param value", | ||
| 155 | - ethDstParam.value().asArray(), is(equalTo(ethDstMac.toBytes()))); | ||
| 156 | - assertThat("Incorrect ethSrcMac match param value", | ||
| 157 | - ethSrcParam.value().asArray(), is(equalTo(ethSrcMac.toBytes()))); | ||
| 158 | - assertThat("Incorrect ethType match param value", | ||
| 159 | - ethTypeParam.value().asReadOnlyBuffer().getShort(), is(equalTo(ethType))); | ||
| 160 | - assertThat("Incorrect priority value", | ||
| 161 | - entry1.priority(), is(equalTo(Integer.MAX_VALUE - rule1.priority()))); | ||
| 162 | - assertThat("Incorrect timeout value", | ||
| 163 | - entry1.timeout(), is(equalTo(expectedTimeout))); | ||
| 164 | - | ||
| 165 | - } | ||
| 166 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | -{ | ||
| 2 | - "header_types": [ | ||
| 3 | - { | ||
| 4 | - "name": "standard_metadata_t", | ||
| 5 | - "id": 0, | ||
| 6 | - "fields": [ | ||
| 7 | - [ | ||
| 8 | - "ingress_port", | ||
| 9 | - 9 | ||
| 10 | - ], | ||
| 11 | - [ | ||
| 12 | - "packet_length", | ||
| 13 | - 32 | ||
| 14 | - ], | ||
| 15 | - [ | ||
| 16 | - "egress_spec", | ||
| 17 | - 9 | ||
| 18 | - ], | ||
| 19 | - [ | ||
| 20 | - "egress_port", | ||
| 21 | - 9 | ||
| 22 | - ], | ||
| 23 | - [ | ||
| 24 | - "egress_instance", | ||
| 25 | - 32 | ||
| 26 | - ], | ||
| 27 | - [ | ||
| 28 | - "instance_type", | ||
| 29 | - 32 | ||
| 30 | - ], | ||
| 31 | - [ | ||
| 32 | - "clone_spec", | ||
| 33 | - 32 | ||
| 34 | - ], | ||
| 35 | - [ | ||
| 36 | - "_padding", | ||
| 37 | - 5 | ||
| 38 | - ] | ||
| 39 | - ], | ||
| 40 | - "length_exp": null, | ||
| 41 | - "max_length": null | ||
| 42 | - }, | ||
| 43 | - { | ||
| 44 | - "name": "ethernet_t", | ||
| 45 | - "id": 1, | ||
| 46 | - "fields": [ | ||
| 47 | - [ | ||
| 48 | - "dstAddr", | ||
| 49 | - 48 | ||
| 50 | - ], | ||
| 51 | - [ | ||
| 52 | - "srcAddr", | ||
| 53 | - 48 | ||
| 54 | - ], | ||
| 55 | - [ | ||
| 56 | - "etherType", | ||
| 57 | - 16 | ||
| 58 | - ] | ||
| 59 | - ], | ||
| 60 | - "length_exp": null, | ||
| 61 | - "max_length": null | ||
| 62 | - }, | ||
| 63 | - { | ||
| 64 | - "name": "intrinsic_metadata_t", | ||
| 65 | - "id": 2, | ||
| 66 | - "fields": [ | ||
| 67 | - [ | ||
| 68 | - "ingress_global_timestamp", | ||
| 69 | - 32 | ||
| 70 | - ], | ||
| 71 | - [ | ||
| 72 | - "lf_field_list", | ||
| 73 | - 32 | ||
| 74 | - ], | ||
| 75 | - [ | ||
| 76 | - "mcast_grp", | ||
| 77 | - 16 | ||
| 78 | - ], | ||
| 79 | - [ | ||
| 80 | - "egress_rid", | ||
| 81 | - 16 | ||
| 82 | - ] | ||
| 83 | - ], | ||
| 84 | - "length_exp": null, | ||
| 85 | - "max_length": null | ||
| 86 | - } | ||
| 87 | - ], | ||
| 88 | - "headers": [ | ||
| 89 | - { | ||
| 90 | - "name": "standard_metadata", | ||
| 91 | - "id": 0, | ||
| 92 | - "header_type": "standard_metadata_t", | ||
| 93 | - "metadata": true | ||
| 94 | - }, | ||
| 95 | - { | ||
| 96 | - "name": "ethernet", | ||
| 97 | - "id": 1, | ||
| 98 | - "header_type": "ethernet_t", | ||
| 99 | - "metadata": false | ||
| 100 | - }, | ||
| 101 | - { | ||
| 102 | - "name": "intrinsic_metadata", | ||
| 103 | - "id": 2, | ||
| 104 | - "header_type": "intrinsic_metadata_t", | ||
| 105 | - "metadata": true | ||
| 106 | - } | ||
| 107 | - ], | ||
| 108 | - "header_stacks": [], | ||
| 109 | - "parsers": [ | ||
| 110 | - { | ||
| 111 | - "name": "parser", | ||
| 112 | - "id": 0, | ||
| 113 | - "init_state": "start", | ||
| 114 | - "parse_states": [ | ||
| 115 | - { | ||
| 116 | - "name": "start", | ||
| 117 | - "id": 0, | ||
| 118 | - "parser_ops": [], | ||
| 119 | - "transition_key": [], | ||
| 120 | - "transitions": [ | ||
| 121 | - { | ||
| 122 | - "value": "default", | ||
| 123 | - "mask": null, | ||
| 124 | - "next_state": "parse_ethernet" | ||
| 125 | - } | ||
| 126 | - ] | ||
| 127 | - }, | ||
| 128 | - { | ||
| 129 | - "name": "parse_ethernet", | ||
| 130 | - "id": 1, | ||
| 131 | - "parser_ops": [ | ||
| 132 | - { | ||
| 133 | - "op": "extract", | ||
| 134 | - "parameters": [ | ||
| 135 | - { | ||
| 136 | - "type": "regular", | ||
| 137 | - "value": "ethernet" | ||
| 138 | - } | ||
| 139 | - ] | ||
| 140 | - } | ||
| 141 | - ], | ||
| 142 | - "transition_key": [], | ||
| 143 | - "transitions": [ | ||
| 144 | - { | ||
| 145 | - "value": "default", | ||
| 146 | - "mask": null, | ||
| 147 | - "next_state": null | ||
| 148 | - } | ||
| 149 | - ] | ||
| 150 | - } | ||
| 151 | - ] | ||
| 152 | - } | ||
| 153 | - ], | ||
| 154 | - "deparsers": [ | ||
| 155 | - { | ||
| 156 | - "name": "deparser", | ||
| 157 | - "id": 0, | ||
| 158 | - "order": [ | ||
| 159 | - "ethernet" | ||
| 160 | - ] | ||
| 161 | - } | ||
| 162 | - ], | ||
| 163 | - "meter_arrays": [], | ||
| 164 | - "actions": [ | ||
| 165 | - { | ||
| 166 | - "name": "flood", | ||
| 167 | - "id": 0, | ||
| 168 | - "runtime_data": [], | ||
| 169 | - "primitives": [ | ||
| 170 | - { | ||
| 171 | - "op": "modify_field", | ||
| 172 | - "parameters": [ | ||
| 173 | - { | ||
| 174 | - "type": "field", | ||
| 175 | - "value": [ | ||
| 176 | - "intrinsic_metadata", | ||
| 177 | - "mcast_grp" | ||
| 178 | - ] | ||
| 179 | - }, | ||
| 180 | - { | ||
| 181 | - "type": "field", | ||
| 182 | - "value": [ | ||
| 183 | - "standard_metadata", | ||
| 184 | - "ingress_port" | ||
| 185 | - ] | ||
| 186 | - } | ||
| 187 | - ] | ||
| 188 | - } | ||
| 189 | - ] | ||
| 190 | - }, | ||
| 191 | - { | ||
| 192 | - "name": "_drop", | ||
| 193 | - "id": 1, | ||
| 194 | - "runtime_data": [], | ||
| 195 | - "primitives": [ | ||
| 196 | - { | ||
| 197 | - "op": "modify_field", | ||
| 198 | - "parameters": [ | ||
| 199 | - { | ||
| 200 | - "type": "field", | ||
| 201 | - "value": [ | ||
| 202 | - "standard_metadata", | ||
| 203 | - "egress_spec" | ||
| 204 | - ] | ||
| 205 | - }, | ||
| 206 | - { | ||
| 207 | - "type": "hexstr", | ||
| 208 | - "value": "0x1ff" | ||
| 209 | - } | ||
| 210 | - ] | ||
| 211 | - } | ||
| 212 | - ] | ||
| 213 | - }, | ||
| 214 | - { | ||
| 215 | - "name": "fwd", | ||
| 216 | - "id": 2, | ||
| 217 | - "runtime_data": [ | ||
| 218 | - { | ||
| 219 | - "name": "port", | ||
| 220 | - "bitwidth": 9 | ||
| 221 | - } | ||
| 222 | - ], | ||
| 223 | - "primitives": [ | ||
| 224 | - { | ||
| 225 | - "op": "modify_field", | ||
| 226 | - "parameters": [ | ||
| 227 | - { | ||
| 228 | - "type": "field", | ||
| 229 | - "value": [ | ||
| 230 | - "standard_metadata", | ||
| 231 | - "egress_spec" | ||
| 232 | - ] | ||
| 233 | - }, | ||
| 234 | - { | ||
| 235 | - "type": "runtime_data", | ||
| 236 | - "value": 0 | ||
| 237 | - } | ||
| 238 | - ] | ||
| 239 | - } | ||
| 240 | - ] | ||
| 241 | - }, | ||
| 242 | - { | ||
| 243 | - "name": "push_to_cp", | ||
| 244 | - "id": 3, | ||
| 245 | - "runtime_data": [], | ||
| 246 | - "primitives": [ | ||
| 247 | - { | ||
| 248 | - "op": "modify_field", | ||
| 249 | - "parameters": [ | ||
| 250 | - { | ||
| 251 | - "type": "field", | ||
| 252 | - "value": [ | ||
| 253 | - "standard_metadata", | ||
| 254 | - "egress_spec" | ||
| 255 | - ] | ||
| 256 | - }, | ||
| 257 | - { | ||
| 258 | - "type": "hexstr", | ||
| 259 | - "value": "0x200" | ||
| 260 | - } | ||
| 261 | - ] | ||
| 262 | - } | ||
| 263 | - ] | ||
| 264 | - } | ||
| 265 | - ], | ||
| 266 | - "pipelines": [ | ||
| 267 | - { | ||
| 268 | - "name": "ingress", | ||
| 269 | - "id": 0, | ||
| 270 | - "init_table": "table0", | ||
| 271 | - "tables": [ | ||
| 272 | - { | ||
| 273 | - "name": "table0", | ||
| 274 | - "id": 0, | ||
| 275 | - "match_type": "ternary", | ||
| 276 | - "type": "simple", | ||
| 277 | - "max_size": 16384, | ||
| 278 | - "with_counters": false, | ||
| 279 | - "direct_meters": null, | ||
| 280 | - "support_timeout": false, | ||
| 281 | - "key": [ | ||
| 282 | - { | ||
| 283 | - "match_type": "ternary", | ||
| 284 | - "target": [ | ||
| 285 | - "standard_metadata", | ||
| 286 | - "ingress_port" | ||
| 287 | - ], | ||
| 288 | - "mask": null | ||
| 289 | - }, | ||
| 290 | - { | ||
| 291 | - "match_type": "ternary", | ||
| 292 | - "target": [ | ||
| 293 | - "ethernet", | ||
| 294 | - "dstAddr" | ||
| 295 | - ], | ||
| 296 | - "mask": null | ||
| 297 | - }, | ||
| 298 | - { | ||
| 299 | - "match_type": "ternary", | ||
| 300 | - "target": [ | ||
| 301 | - "ethernet", | ||
| 302 | - "srcAddr" | ||
| 303 | - ], | ||
| 304 | - "mask": null | ||
| 305 | - }, | ||
| 306 | - { | ||
| 307 | - "match_type": "ternary", | ||
| 308 | - "target": [ | ||
| 309 | - "ethernet", | ||
| 310 | - "etherType" | ||
| 311 | - ], | ||
| 312 | - "mask": null | ||
| 313 | - } | ||
| 314 | - ], | ||
| 315 | - "actions": [ | ||
| 316 | - "fwd", | ||
| 317 | - "flood", | ||
| 318 | - "push_to_cp", | ||
| 319 | - "_drop" | ||
| 320 | - ], | ||
| 321 | - "next_tables": { | ||
| 322 | - "fwd": null, | ||
| 323 | - "flood": null, | ||
| 324 | - "push_to_cp": null, | ||
| 325 | - "_drop": null | ||
| 326 | - }, | ||
| 327 | - "default_action": null, | ||
| 328 | - "base_default_next": null | ||
| 329 | - } | ||
| 330 | - ], | ||
| 331 | - "conditionals": [] | ||
| 332 | - }, | ||
| 333 | - { | ||
| 334 | - "name": "egress", | ||
| 335 | - "id": 1, | ||
| 336 | - "init_table": null, | ||
| 337 | - "tables": [], | ||
| 338 | - "conditionals": [] | ||
| 339 | - } | ||
| 340 | - ], | ||
| 341 | - "calculations": [], | ||
| 342 | - "checksums": [], | ||
| 343 | - "learn_lists": [], | ||
| 344 | - "field_lists": [], | ||
| 345 | - "counter_arrays": [], | ||
| 346 | - "register_arrays": [], | ||
| 347 | - "force_arith": [ | ||
| 348 | - [ | ||
| 349 | - "standard_metadata", | ||
| 350 | - "ingress_port" | ||
| 351 | - ], | ||
| 352 | - [ | ||
| 353 | - "standard_metadata", | ||
| 354 | - "packet_length" | ||
| 355 | - ], | ||
| 356 | - [ | ||
| 357 | - "standard_metadata", | ||
| 358 | - "egress_spec" | ||
| 359 | - ], | ||
| 360 | - [ | ||
| 361 | - "standard_metadata", | ||
| 362 | - "egress_port" | ||
| 363 | - ], | ||
| 364 | - [ | ||
| 365 | - "standard_metadata", | ||
| 366 | - "egress_instance" | ||
| 367 | - ], | ||
| 368 | - [ | ||
| 369 | - "standard_metadata", | ||
| 370 | - "instance_type" | ||
| 371 | - ], | ||
| 372 | - [ | ||
| 373 | - "standard_metadata", | ||
| 374 | - "clone_spec" | ||
| 375 | - ], | ||
| 376 | - [ | ||
| 377 | - "standard_metadata", | ||
| 378 | - "_padding" | ||
| 379 | - ], | ||
| 380 | - [ | ||
| 381 | - "intrinsic_metadata", | ||
| 382 | - "ingress_global_timestamp" | ||
| 383 | - ], | ||
| 384 | - [ | ||
| 385 | - "intrinsic_metadata", | ||
| 386 | - "lf_field_list" | ||
| 387 | - ], | ||
| 388 | - [ | ||
| 389 | - "intrinsic_metadata", | ||
| 390 | - "mcast_grp" | ||
| 391 | - ], | ||
| 392 | - [ | ||
| 393 | - "intrinsic_metadata", | ||
| 394 | - "egress_rid" | ||
| 395 | - ] | ||
| 396 | - ] | ||
| 397 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -41,7 +41,7 @@ | ... | @@ -41,7 +41,7 @@ |
| 41 | <module>utilities</module> | 41 | <module>utilities</module> |
| 42 | <module>lumentum</module> | 42 | <module>lumentum</module> |
| 43 | <module>bti</module> | 43 | <module>bti</module> |
| 44 | - <!--<module>bmv2</module>--> | 44 | + <module>bmv2</module> |
| 45 | <module>corsa</module> | 45 | <module>corsa</module> |
| 46 | <module>optical</module> | 46 | <module>optical</module> |
| 47 | </modules> | 47 | </modules> | ... | ... |
| ... | @@ -21,7 +21,8 @@ | ... | @@ -21,7 +21,8 @@ |
| 21 | <parent> | 21 | <parent> |
| 22 | <artifactId>onos-bmv2-protocol</artifactId> | 22 | <artifactId>onos-bmv2-protocol</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | - <version>1.6.0-SNAPSHOT</version> | 24 | + <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | <modelVersion>4.0.0</modelVersion> | 27 | <modelVersion>4.0.0</modelVersion> |
| 27 | 28 | ... | ... |
| ... | @@ -21,7 +21,8 @@ | ... | @@ -21,7 +21,8 @@ |
| 21 | <parent> | 21 | <parent> |
| 22 | <artifactId>onos-bmv2-protocol</artifactId> | 22 | <artifactId>onos-bmv2-protocol</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | - <version>1.6.0-SNAPSHOT</version> | 24 | + <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | <modelVersion>4.0.0</modelVersion> | 27 | <modelVersion>4.0.0</modelVersion> |
| 27 | 28 | ... | ... |
| ... | @@ -22,6 +22,7 @@ | ... | @@ -22,6 +22,7 @@ |
| 22 | <artifactId>onos-protocols</artifactId> | 22 | <artifactId>onos-protocols</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | <version>1.7.0-SNAPSHOT</version> | 24 | <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | <modelVersion>4.0.0</modelVersion> | 27 | <modelVersion>4.0.0</modelVersion> |
| 27 | 28 | ... | ... |
| ... | @@ -21,7 +21,8 @@ | ... | @@ -21,7 +21,8 @@ |
| 21 | <parent> | 21 | <parent> |
| 22 | <artifactId>onos-bmv2-protocol</artifactId> | 22 | <artifactId>onos-bmv2-protocol</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | - <version>1.6.0-SNAPSHOT</version> | 24 | + <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | 27 | ||
| 27 | <modelVersion>4.0.0</modelVersion> | 28 | <modelVersion>4.0.0</modelVersion> | ... | ... |
| ... | @@ -22,7 +22,9 @@ | ... | @@ -22,7 +22,9 @@ |
| 22 | <bundle>mvn:${project.groupId}/onos-bmv2-provider-device/${project.version}</bundle> | 22 | <bundle>mvn:${project.groupId}/onos-bmv2-provider-device/${project.version}</bundle> |
| 23 | <bundle>mvn:${project.groupId}/onos-bmv2-provider-packet/${project.version}</bundle> | 23 | <bundle>mvn:${project.groupId}/onos-bmv2-provider-packet/${project.version}</bundle> |
| 24 | <bundle>mvn:org.apache.thrift/libthrift/0.9.3</bundle> | 24 | <bundle>mvn:org.apache.thrift/libthrift/0.9.3</bundle> |
| 25 | - <bundle>mvn:${project.groupId}/onos-bmv2-protocol/${project.version}</bundle> | 25 | + <bundle>mvn:${project.groupId}/onos-bmv2-protocol-api/${project.version}</bundle> |
| 26 | + <bundle>mvn:${project.groupId}/onos-bmv2-protocol-ctl/${project.version}</bundle> | ||
| 27 | + <bundle>mvn:${project.groupId}/onos-bmv2-protocol-thrift-api/${project.version}</bundle> | ||
| 26 | </feature> | 28 | </feature> |
| 27 | </features> | 29 | </features> |
| 28 | 30 | ... | ... |
| ... | @@ -22,6 +22,7 @@ | ... | @@ -22,6 +22,7 @@ |
| 22 | <artifactId>onos-bmv2-providers</artifactId> | 22 | <artifactId>onos-bmv2-providers</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | <version>1.7.0-SNAPSHOT</version> | 24 | <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | 27 | ||
| 27 | <modelVersion>4.0.0</modelVersion> | 28 | <modelVersion>4.0.0</modelVersion> |
| ... | @@ -33,7 +34,7 @@ | ... | @@ -33,7 +34,7 @@ |
| 33 | 34 | ||
| 34 | <properties> | 35 | <properties> |
| 35 | <onos.app.name>org.onosproject.bmv2</onos.app.name> | 36 | <onos.app.name>org.onosproject.bmv2</onos.app.name> |
| 36 | - <onos.app.title>BMv2 Provider</onos.app.title> | 37 | + <onos.app.title>BMv2 Providers</onos.app.title> |
| 37 | <onos.app.category>Provider</onos.app.category> | 38 | <onos.app.category>Provider</onos.app.category> |
| 38 | </properties> | 39 | </properties> |
| 39 | 40 | ... | ... |
| ... | @@ -22,6 +22,7 @@ | ... | @@ -22,6 +22,7 @@ |
| 22 | <artifactId>onos-bmv2-providers</artifactId> | 22 | <artifactId>onos-bmv2-providers</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | <version>1.7.0-SNAPSHOT</version> | 24 | <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | <modelVersion>4.0.0</modelVersion> | 27 | <modelVersion>4.0.0</modelVersion> |
| 27 | 28 | ||
| ... | @@ -33,12 +34,12 @@ | ... | @@ -33,12 +34,12 @@ |
| 33 | <dependencies> | 34 | <dependencies> |
| 34 | <dependency> | 35 | <dependency> |
| 35 | <groupId>org.onosproject</groupId> | 36 | <groupId>org.onosproject</groupId> |
| 36 | - <artifactId>onos-drivers-bmv2</artifactId> | 37 | + <artifactId>onos-core-common</artifactId> |
| 37 | <version>${project.version}</version> | 38 | <version>${project.version}</version> |
| 38 | </dependency> | 39 | </dependency> |
| 39 | <dependency> | 40 | <dependency> |
| 40 | <groupId>org.onosproject</groupId> | 41 | <groupId>org.onosproject</groupId> |
| 41 | - <artifactId>onos-core-common</artifactId> | 42 | + <artifactId>onos-bmv2-protocol-api</artifactId> |
| 42 | <version>${project.version}</version> | 43 | <version>${project.version}</version> |
| 43 | </dependency> | 44 | </dependency> |
| 44 | </dependencies> | 45 | </dependencies> | ... | ... |
| ... | @@ -23,36 +23,38 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; | ... | @@ -23,36 +23,38 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 23 | import org.jboss.netty.util.HashedWheelTimer; | 23 | import org.jboss.netty.util.HashedWheelTimer; |
| 24 | import org.jboss.netty.util.Timeout; | 24 | import org.jboss.netty.util.Timeout; |
| 25 | import org.jboss.netty.util.TimerTask; | 25 | import org.jboss.netty.util.TimerTask; |
| 26 | -import org.onlab.packet.ChassisId; | ||
| 27 | -import org.onlab.util.HexString; | ||
| 28 | import org.onlab.util.Timer; | 26 | import org.onlab.util.Timer; |
| 29 | -import org.onosproject.bmv2.api.runtime.Bmv2ControlPlaneServer; | ||
| 30 | import org.onosproject.bmv2.api.runtime.Bmv2Device; | 27 | import org.onosproject.bmv2.api.runtime.Bmv2Device; |
| 31 | import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | 28 | import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; |
| 32 | -import org.onosproject.bmv2.ctl.Bmv2ThriftClient; | 29 | +import org.onosproject.bmv2.api.service.Bmv2Controller; |
| 30 | +import org.onosproject.bmv2.api.service.Bmv2DeviceContextService; | ||
| 31 | +import org.onosproject.bmv2.api.service.Bmv2DeviceListener; | ||
| 33 | import org.onosproject.common.net.AbstractDeviceProvider; | 32 | import org.onosproject.common.net.AbstractDeviceProvider; |
| 34 | import org.onosproject.core.ApplicationId; | 33 | import org.onosproject.core.ApplicationId; |
| 35 | import org.onosproject.core.CoreService; | 34 | import org.onosproject.core.CoreService; |
| 36 | import org.onosproject.incubator.net.config.basics.ConfigException; | 35 | import org.onosproject.incubator.net.config.basics.ConfigException; |
| 37 | -import org.onosproject.net.AnnotationKeys; | ||
| 38 | -import org.onosproject.net.DefaultAnnotations; | ||
| 39 | import org.onosproject.net.Device; | 36 | import org.onosproject.net.Device; |
| 40 | import org.onosproject.net.DeviceId; | 37 | import org.onosproject.net.DeviceId; |
| 41 | import org.onosproject.net.MastershipRole; | 38 | import org.onosproject.net.MastershipRole; |
| 42 | import org.onosproject.net.PortNumber; | 39 | import org.onosproject.net.PortNumber; |
| 43 | -import org.onosproject.net.behaviour.PortDiscovery; | ||
| 44 | import org.onosproject.net.config.ConfigFactory; | 40 | import org.onosproject.net.config.ConfigFactory; |
| 45 | import org.onosproject.net.config.NetworkConfigEvent; | 41 | import org.onosproject.net.config.NetworkConfigEvent; |
| 46 | import org.onosproject.net.config.NetworkConfigListener; | 42 | import org.onosproject.net.config.NetworkConfigListener; |
| 47 | import org.onosproject.net.config.NetworkConfigRegistry; | 43 | import org.onosproject.net.config.NetworkConfigRegistry; |
| 48 | -import org.onosproject.net.device.DefaultDeviceDescription; | ||
| 49 | import org.onosproject.net.device.DeviceDescription; | 44 | import org.onosproject.net.device.DeviceDescription; |
| 45 | +import org.onosproject.net.device.DeviceDescriptionDiscovery; | ||
| 50 | import org.onosproject.net.device.DeviceService; | 46 | import org.onosproject.net.device.DeviceService; |
| 51 | import org.onosproject.net.device.PortDescription; | 47 | import org.onosproject.net.device.PortDescription; |
| 48 | +import org.onosproject.net.device.PortStatistics; | ||
| 49 | +import org.onosproject.net.driver.DefaultDriverData; | ||
| 50 | +import org.onosproject.net.driver.DefaultDriverHandler; | ||
| 51 | +import org.onosproject.net.driver.Driver; | ||
| 52 | import org.onosproject.net.provider.ProviderId; | 52 | import org.onosproject.net.provider.ProviderId; |
| 53 | import org.slf4j.Logger; | 53 | import org.slf4j.Logger; |
| 54 | 54 | ||
| 55 | +import java.util.Collection; | ||
| 55 | import java.util.List; | 56 | import java.util.List; |
| 57 | +import java.util.Objects; | ||
| 56 | import java.util.concurrent.ConcurrentMap; | 58 | import java.util.concurrent.ConcurrentMap; |
| 57 | import java.util.concurrent.ExecutorService; | 59 | import java.util.concurrent.ExecutorService; |
| 58 | import java.util.concurrent.Executors; | 60 | import java.util.concurrent.Executors; |
| ... | @@ -60,9 +62,9 @@ import java.util.concurrent.TimeUnit; | ... | @@ -60,9 +62,9 @@ import java.util.concurrent.TimeUnit; |
| 60 | 62 | ||
| 61 | import static org.onlab.util.Tools.groupedThreads; | 63 | import static org.onlab.util.Tools.groupedThreads; |
| 62 | import static org.onosproject.bmv2.api.runtime.Bmv2Device.*; | 64 | import static org.onosproject.bmv2.api.runtime.Bmv2Device.*; |
| 63 | -import static org.onosproject.bmv2.ctl.Bmv2ThriftClient.forceDisconnectOf; | ||
| 64 | -import static org.onosproject.bmv2.ctl.Bmv2ThriftClient.ping; | ||
| 65 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; | 65 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; |
| 66 | +import static org.onosproject.provider.bmv2.device.impl.Bmv2PortStatisticsGetter.getPortStatistics; | ||
| 67 | +import static org.onosproject.provider.bmv2.device.impl.Bmv2PortStatisticsGetter.initCounters; | ||
| 66 | import static org.slf4j.LoggerFactory.getLogger; | 68 | import static org.slf4j.LoggerFactory.getLogger; |
| 67 | 69 | ||
| 68 | /** | 70 | /** |
| ... | @@ -71,11 +73,24 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -71,11 +73,24 @@ import static org.slf4j.LoggerFactory.getLogger; |
| 71 | @Component(immediate = true) | 73 | @Component(immediate = true) |
| 72 | public class Bmv2DeviceProvider extends AbstractDeviceProvider { | 74 | public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 73 | 75 | ||
| 74 | - private static final Logger LOG = getLogger(Bmv2DeviceProvider.class); | ||
| 75 | - | ||
| 76 | private static final String APP_NAME = "org.onosproject.bmv2"; | 76 | private static final String APP_NAME = "org.onosproject.bmv2"; |
| 77 | - private static final String UNKNOWN = "unknown"; | 77 | + |
| 78 | - private static final int POLL_INTERVAL = 5; // seconds | 78 | + private static final int POLL_INTERVAL = 5_000; // milliseconds |
| 79 | + | ||
| 80 | + private final Logger log = getLogger(this.getClass()); | ||
| 81 | + | ||
| 82 | + private final ExecutorService executorService = Executors | ||
| 83 | + .newFixedThreadPool(16, groupedThreads("onos/bmv2", "device-discovery", log)); | ||
| 84 | + | ||
| 85 | + private final NetworkConfigListener cfgListener = new InternalNetworkConfigListener(); | ||
| 86 | + | ||
| 87 | + private final ConfigFactory cfgFactory = new InternalConfigFactory(); | ||
| 88 | + | ||
| 89 | + private final ConcurrentMap<DeviceId, DeviceDescription> activeDevices = Maps.newConcurrentMap(); | ||
| 90 | + | ||
| 91 | + private final DevicePoller devicePoller = new DevicePoller(); | ||
| 92 | + | ||
| 93 | + private final InternalDeviceListener deviceListener = new InternalDeviceListener(); | ||
| 79 | 94 | ||
| 80 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 95 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 81 | protected NetworkConfigRegistry netCfgService; | 96 | protected NetworkConfigRegistry netCfgService; |
| ... | @@ -87,16 +102,11 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -87,16 +102,11 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 87 | protected DeviceService deviceService; | 102 | protected DeviceService deviceService; |
| 88 | 103 | ||
| 89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 104 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 90 | - protected Bmv2ControlPlaneServer controlPlaneServer; | 105 | + protected Bmv2Controller controller; |
| 91 | 106 | ||
| 92 | - private final ExecutorService deviceDiscoveryExecutor = Executors | 107 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 93 | - .newFixedThreadPool(5, groupedThreads("onos/bmv2", "device-discovery", LOG)); | 108 | + protected Bmv2DeviceContextService contextService; |
| 94 | 109 | ||
| 95 | - private final NetworkConfigListener cfgListener = new InternalNetworkConfigListener(); | ||
| 96 | - private final ConfigFactory cfgFactory = new InternalConfigFactory(); | ||
| 97 | - private final ConcurrentMap<DeviceId, Boolean> activeDevices = Maps.newConcurrentMap(); | ||
| 98 | - private final DevicePoller devicePoller = new DevicePoller(); | ||
| 99 | - private final InternalHelloListener helloListener = new InternalHelloListener(); | ||
| 100 | private ApplicationId appId; | 110 | private ApplicationId appId; |
| 101 | 111 | ||
| 102 | /** | 112 | /** |
| ... | @@ -111,7 +121,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -111,7 +121,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 111 | appId = coreService.registerApplication(APP_NAME); | 121 | appId = coreService.registerApplication(APP_NAME); |
| 112 | netCfgService.registerConfigFactory(cfgFactory); | 122 | netCfgService.registerConfigFactory(cfgFactory); |
| 113 | netCfgService.addListener(cfgListener); | 123 | netCfgService.addListener(cfgListener); |
| 114 | - controlPlaneServer.addHelloListener(helloListener); | 124 | + controller.addDeviceListener(deviceListener); |
| 115 | devicePoller.start(); | 125 | devicePoller.start(); |
| 116 | super.activate(); | 126 | super.activate(); |
| 117 | } | 127 | } |
| ... | @@ -119,16 +129,16 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -119,16 +129,16 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 119 | @Override | 129 | @Override |
| 120 | protected void deactivate() { | 130 | protected void deactivate() { |
| 121 | devicePoller.stop(); | 131 | devicePoller.stop(); |
| 122 | - controlPlaneServer.removeHelloListener(helloListener); | 132 | + controller.removeDeviceListener(deviceListener); |
| 123 | try { | 133 | try { |
| 124 | activeDevices.forEach((did, value) -> { | 134 | activeDevices.forEach((did, value) -> { |
| 125 | - deviceDiscoveryExecutor.execute(() -> disconnectDevice(did)); | 135 | + executorService.execute(() -> disconnectDevice(did)); |
| 126 | }); | 136 | }); |
| 127 | - deviceDiscoveryExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS); | 137 | + executorService.awaitTermination(1000, TimeUnit.MILLISECONDS); |
| 128 | } catch (InterruptedException e) { | 138 | } catch (InterruptedException e) { |
| 129 | - LOG.error("Device discovery threads did not terminate"); | 139 | + log.error("Device discovery threads did not terminate"); |
| 130 | } | 140 | } |
| 131 | - deviceDiscoveryExecutor.shutdownNow(); | 141 | + executorService.shutdownNow(); |
| 132 | netCfgService.unregisterConfigFactory(cfgFactory); | 142 | netCfgService.unregisterConfigFactory(cfgFactory); |
| 133 | netCfgService.removeListener(cfgListener); | 143 | netCfgService.removeListener(cfgListener); |
| 134 | super.deactivate(); | 144 | super.deactivate(); |
| ... | @@ -137,14 +147,12 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -137,14 +147,12 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 137 | @Override | 147 | @Override |
| 138 | public void triggerProbe(DeviceId deviceId) { | 148 | public void triggerProbe(DeviceId deviceId) { |
| 139 | // Asynchronously trigger probe task. | 149 | // Asynchronously trigger probe task. |
| 140 | - deviceDiscoveryExecutor.execute(() -> executeProbe(deviceId)); | 150 | + executorService.execute(() -> executeProbe(deviceId)); |
| 141 | } | 151 | } |
| 142 | 152 | ||
| 143 | private void executeProbe(DeviceId did) { | 153 | private void executeProbe(DeviceId did) { |
| 144 | boolean reachable = isReachable(did); | 154 | boolean reachable = isReachable(did); |
| 145 | - LOG.debug("Probed device: id={}, reachable={}", | 155 | + log.debug("Probed device: id={}, reachable={}", did.toString(), reachable); |
| 146 | - did.toString(), | ||
| 147 | - reachable); | ||
| 148 | if (reachable) { | 156 | if (reachable) { |
| 149 | discoverDevice(did); | 157 | discoverDevice(did); |
| 150 | } else { | 158 | } else { |
| ... | @@ -154,85 +162,108 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -154,85 +162,108 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 154 | 162 | ||
| 155 | @Override | 163 | @Override |
| 156 | public void roleChanged(DeviceId deviceId, MastershipRole newRole) { | 164 | public void roleChanged(DeviceId deviceId, MastershipRole newRole) { |
| 157 | - LOG.debug("roleChanged() is not yet implemented"); | 165 | + log.debug("roleChanged() is not yet implemented"); |
| 158 | // TODO: implement mastership handling | 166 | // TODO: implement mastership handling |
| 159 | } | 167 | } |
| 160 | 168 | ||
| 161 | @Override | 169 | @Override |
| 162 | public boolean isReachable(DeviceId deviceId) { | 170 | public boolean isReachable(DeviceId deviceId) { |
| 163 | - return ping(deviceId); | 171 | + return controller.isReacheable(deviceId); |
| 164 | } | 172 | } |
| 165 | 173 | ||
| 166 | @Override | 174 | @Override |
| 167 | public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) { | 175 | public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) { |
| 168 | - LOG.debug("changePortState() is not yet implemented"); | 176 | + log.warn("changePortState() not supported"); |
| 169 | - // TODO: implement port handling | ||
| 170 | } | 177 | } |
| 171 | 178 | ||
| 172 | private void discoverDevice(DeviceId did) { | 179 | private void discoverDevice(DeviceId did) { |
| 173 | - LOG.debug("Starting device discovery... deviceId={}", did); | 180 | + log.debug("Starting device discovery... deviceId={}", did); |
| 174 | - | 181 | + activeDevices.compute(did, (k, lastDescription) -> { |
| 175 | - // Atomically notify device to core and update port information. | 182 | + DeviceDescription thisDescription = getDeviceDescription(did); |
| 176 | - activeDevices.compute(did, (k, v) -> { | 183 | + if (thisDescription != null) { |
| 177 | - if (!deviceService.isAvailable(did)) { | 184 | + boolean descriptionChanged = lastDescription != null && |
| 178 | - // Device not available in the core, connect it now. | 185 | + (!Objects.equals(thisDescription, lastDescription) || |
| 179 | - DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder() | 186 | + !Objects.equals(thisDescription.annotations(), lastDescription.annotations())); |
| 180 | - .set(AnnotationKeys.PROTOCOL, SCHEME); | 187 | + if (descriptionChanged || !deviceService.isAvailable(did)) { |
| 181 | - dumpJsonConfigToAnnotations(did, annotationsBuilder); | 188 | + // Device description changed or device not available in the core. |
| 182 | - DeviceDescription descr = new DefaultDeviceDescription( | 189 | + if (contextService.notifyDeviceChange(did)) { |
| 183 | - did.uri(), Device.Type.SWITCH, MANUFACTURER, HW_VERSION, | 190 | + // Configuration is the expected one, we can proceed notifying the core. |
| 184 | - UNKNOWN, UNKNOWN, new ChassisId(), annotationsBuilder.build()); | 191 | + resetDeviceState(did); |
| 185 | - // Reset device state (cleanup entries, etc.) | 192 | + initPortCounters(did); |
| 186 | - resetDeviceState(did); | 193 | + providerService.deviceConnected(did, thisDescription); |
| 187 | - providerService.deviceConnected(did, descr); | 194 | + updatePortsAndStats(did); |
| 195 | + } | ||
| 196 | + } | ||
| 197 | + return thisDescription; | ||
| 198 | + } else { | ||
| 199 | + log.warn("Unable to get device description for {}", did); | ||
| 200 | + return lastDescription; | ||
| 188 | } | 201 | } |
| 189 | - updatePorts(did); | ||
| 190 | - return true; | ||
| 191 | }); | 202 | }); |
| 192 | } | 203 | } |
| 193 | 204 | ||
| 194 | - private void dumpJsonConfigToAnnotations(DeviceId did, DefaultAnnotations.Builder builder) { | 205 | + private DeviceDescription getDeviceDescription(DeviceId did) { |
| 195 | - // TODO: store json config string somewhere else, possibly in a Bmv2Controller (see ONOS-4419) | 206 | + Device device = deviceService.getDevice(did); |
| 207 | + DeviceDescriptionDiscovery discovery = null; | ||
| 208 | + if (device == null) { | ||
| 209 | + // Device not yet in the core. Manually get a driver. | ||
| 210 | + Driver driver = driverService.getDriver(MANUFACTURER, HW_VERSION, SW_VERSION); | ||
| 211 | + if (driver.hasBehaviour(DeviceDescriptionDiscovery.class)) { | ||
| 212 | + discovery = driver.createBehaviour(new DefaultDriverHandler(new DefaultDriverData(driver, did)), | ||
| 213 | + DeviceDescriptionDiscovery.class); | ||
| 214 | + } | ||
| 215 | + } else if (device.is(DeviceDescriptionDiscovery.class)) { | ||
| 216 | + discovery = device.as(DeviceDescriptionDiscovery.class); | ||
| 217 | + } | ||
| 218 | + if (discovery == null) { | ||
| 219 | + log.warn("No DeviceDescriptionDiscovery behavior for device {}", did); | ||
| 220 | + return null; | ||
| 221 | + } else { | ||
| 222 | + return discovery.discoverDeviceDetails(); | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + private void resetDeviceState(DeviceId did) { | ||
| 196 | try { | 227 | try { |
| 197 | - String md5 = Bmv2ThriftClient.of(did).getJsonConfigMd5(); | 228 | + controller.getAgent(did).resetState(); |
| 198 | - // Convert to hex string for readability. | ||
| 199 | - md5 = HexString.toHexString(md5.getBytes()); | ||
| 200 | - String jsonString = Bmv2ThriftClient.of(did).dumpJsonConfig(); | ||
| 201 | - builder.set("bmv2JsonConfigMd5", md5); | ||
| 202 | - builder.set("bmv2JsonConfigValue", jsonString); | ||
| 203 | } catch (Bmv2RuntimeException e) { | 229 | } catch (Bmv2RuntimeException e) { |
| 204 | - LOG.warn("Unable to dump device JSON config from device {}: {}", did, e.toString()); | 230 | + log.warn("Unable to reset {}: {}", did, e.toString()); |
| 205 | } | 231 | } |
| 206 | } | 232 | } |
| 207 | 233 | ||
| 208 | - private void resetDeviceState(DeviceId did) { | 234 | + private void initPortCounters(DeviceId did) { |
| 209 | try { | 235 | try { |
| 210 | - Bmv2ThriftClient.of(did).resetState(); | 236 | + initCounters(controller.getAgent(did)); |
| 211 | } catch (Bmv2RuntimeException e) { | 237 | } catch (Bmv2RuntimeException e) { |
| 212 | - LOG.warn("Unable to reset {}: {}", did, e.toString()); | 238 | + log.warn("Unable to init counter on {}: {}", did, e.explain()); |
| 213 | } | 239 | } |
| 214 | } | 240 | } |
| 215 | 241 | ||
| 216 | - private void updatePorts(DeviceId did) { | 242 | + private void updatePortsAndStats(DeviceId did) { |
| 217 | Device device = deviceService.getDevice(did); | 243 | Device device = deviceService.getDevice(did); |
| 218 | - if (device.is(PortDiscovery.class)) { | 244 | + if (device.is(DeviceDescriptionDiscovery.class)) { |
| 219 | - PortDiscovery portConfig = device.as(PortDiscovery.class); | 245 | + DeviceDescriptionDiscovery discovery = device.as(DeviceDescriptionDiscovery.class); |
| 220 | - List<PortDescription> portDescriptions = portConfig.getPorts(); | 246 | + List<PortDescription> portDescriptions = discovery.discoverPortDetails(); |
| 221 | - providerService.updatePorts(did, portDescriptions); | 247 | + if (portDescriptions != null) { |
| 248 | + providerService.updatePorts(did, portDescriptions); | ||
| 249 | + } | ||
| 222 | } else { | 250 | } else { |
| 223 | - LOG.warn("No PortDiscovery behavior for device {}", did); | 251 | + log.warn("No DeviceDescriptionDiscovery behavior for device {}", did); |
| 252 | + } | ||
| 253 | + try { | ||
| 254 | + Collection<PortStatistics> portStats = getPortStatistics(controller.getAgent(did), | ||
| 255 | + deviceService.getPorts(did)); | ||
| 256 | + providerService.updatePortStatistics(did, portStats); | ||
| 257 | + } catch (Bmv2RuntimeException e) { | ||
| 258 | + log.warn("Unable to get port statistics for {}: {}", did, e.explain()); | ||
| 224 | } | 259 | } |
| 225 | } | 260 | } |
| 226 | 261 | ||
| 227 | private void disconnectDevice(DeviceId did) { | 262 | private void disconnectDevice(DeviceId did) { |
| 228 | - LOG.debug("Trying to disconnect device from core... deviceId={}", did); | 263 | + log.debug("Trying to disconnect device from core... deviceId={}", did); |
| 229 | - | ||
| 230 | - // Atomically disconnect device. | ||
| 231 | activeDevices.compute(did, (k, v) -> { | 264 | activeDevices.compute(did, (k, v) -> { |
| 232 | if (deviceService.isAvailable(did)) { | 265 | if (deviceService.isAvailable(did)) { |
| 233 | providerService.deviceDisconnected(did); | 266 | providerService.deviceDisconnected(did); |
| 234 | - // Make sure to close the transport session with device. Do we really need this? | ||
| 235 | - forceDisconnectOf(did); | ||
| 236 | } | 267 | } |
| 237 | return null; | 268 | return null; |
| 238 | }); | 269 | }); |
| ... | @@ -269,10 +300,10 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -269,10 +300,10 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 269 | triggerProbe(bmv2Device.asDeviceId()); | 300 | triggerProbe(bmv2Device.asDeviceId()); |
| 270 | }); | 301 | }); |
| 271 | } catch (ConfigException e) { | 302 | } catch (ConfigException e) { |
| 272 | - LOG.error("Unable to read config: " + e); | 303 | + log.error("Unable to read config: " + e); |
| 273 | } | 304 | } |
| 274 | } else { | 305 | } else { |
| 275 | - LOG.error("Unable to read config (was null)"); | 306 | + log.error("Unable to read config (was null)"); |
| 276 | } | 307 | } |
| 277 | } | 308 | } |
| 278 | 309 | ||
| ... | @@ -285,18 +316,18 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -285,18 +316,18 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 285 | } | 316 | } |
| 286 | 317 | ||
| 287 | /** | 318 | /** |
| 288 | - * Listener triggered by Bmv2ControlPlaneServer each time a hello message is received. | 319 | + * Listener triggered by the BMv2 controller each time a hello message is received. |
| 289 | */ | 320 | */ |
| 290 | - private class InternalHelloListener implements Bmv2ControlPlaneServer.HelloListener { | 321 | + private class InternalDeviceListener implements Bmv2DeviceListener { |
| 291 | @Override | 322 | @Override |
| 292 | - public void handleHello(Bmv2Device device) { | 323 | + public void handleHello(Bmv2Device device, int instanceId, String jsonConfigMd5) { |
| 293 | log.debug("Received hello from {}", device); | 324 | log.debug("Received hello from {}", device); |
| 294 | triggerProbe(device.asDeviceId()); | 325 | triggerProbe(device.asDeviceId()); |
| 295 | } | 326 | } |
| 296 | } | 327 | } |
| 297 | 328 | ||
| 298 | /** | 329 | /** |
| 299 | - * Task that periodically trigger device probes. | 330 | + * Task that periodically trigger device probes to check for device status and update port informations. |
| 300 | */ | 331 | */ |
| 301 | private class DevicePoller implements TimerTask { | 332 | private class DevicePoller implements TimerTask { |
| 302 | 333 | ||
| ... | @@ -304,20 +335,31 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -304,20 +335,31 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 304 | private Timeout timeout; | 335 | private Timeout timeout; |
| 305 | 336 | ||
| 306 | @Override | 337 | @Override |
| 307 | - public void run(Timeout timeout) throws Exception { | 338 | + public void run(Timeout tout) throws Exception { |
| 308 | - if (timeout.isCancelled()) { | 339 | + if (tout.isCancelled()) { |
| 309 | return; | 340 | return; |
| 310 | } | 341 | } |
| 311 | - log.debug("Executing polling on {} devices...", activeDevices.size()); | 342 | + activeDevices.keySet() |
| 312 | - activeDevices.forEach((did, value) -> triggerProbe(did)); | 343 | + .stream() |
| 313 | - timeout.getTimer().newTimeout(this, POLL_INTERVAL, TimeUnit.SECONDS); | 344 | + // Filter out devices not yet created in the core. |
| 345 | + .filter(did -> deviceService.getDevice(did) != null) | ||
| 346 | + .forEach(did -> executorService.execute(() -> pollingTask(did))); | ||
| 347 | + tout.getTimer().newTimeout(this, POLL_INTERVAL, TimeUnit.MILLISECONDS); | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + private void pollingTask(DeviceId deviceId) { | ||
| 351 | + if (isReachable(deviceId)) { | ||
| 352 | + updatePortsAndStats(deviceId); | ||
| 353 | + } else { | ||
| 354 | + disconnectDevice(deviceId); | ||
| 355 | + } | ||
| 314 | } | 356 | } |
| 315 | 357 | ||
| 316 | /** | 358 | /** |
| 317 | * Starts the collector. | 359 | * Starts the collector. |
| 318 | */ | 360 | */ |
| 319 | - synchronized void start() { | 361 | + synchronized void start() { |
| 320 | - LOG.info("Starting device poller..."); | 362 | + log.info("Starting device poller..."); |
| 321 | timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS); | 363 | timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS); |
| 322 | } | 364 | } |
| 323 | 365 | ||
| ... | @@ -325,7 +367,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -325,7 +367,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 325 | * Stops the collector. | 367 | * Stops the collector. |
| 326 | */ | 368 | */ |
| 327 | synchronized void stop() { | 369 | synchronized void stop() { |
| 328 | - LOG.info("Stopping device poller..."); | 370 | + log.info("Stopping device poller..."); |
| 329 | timeout.cancel(); | 371 | timeout.cancel(); |
| 330 | } | 372 | } |
| 331 | } | 373 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.provider.bmv2.device.impl; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.Lists; | ||
| 20 | +import org.apache.commons.lang3.tuple.Pair; | ||
| 21 | +import org.onosproject.bmv2.api.runtime.Bmv2Action; | ||
| 22 | +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; | ||
| 23 | +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | ||
| 24 | +import org.onosproject.net.Port; | ||
| 25 | +import org.onosproject.net.device.DefaultPortStatistics; | ||
| 26 | +import org.onosproject.net.device.PortStatistics; | ||
| 27 | +import org.slf4j.Logger; | ||
| 28 | +import org.slf4j.LoggerFactory; | ||
| 29 | + | ||
| 30 | +import java.util.Collection; | ||
| 31 | +import java.util.List; | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * Utility class to read port statistics from a BMv2 device. | ||
| 35 | + */ | ||
| 36 | +final class Bmv2PortStatisticsGetter { | ||
| 37 | + | ||
| 38 | + // TODO: make counters configuration dependent | ||
| 39 | + | ||
| 40 | + private static final String TABLE_NAME = "port_count_table"; | ||
| 41 | + private static final String ACTION_NAME = "count_packet"; | ||
| 42 | + private static final String EGRESS_COUNTER = "egress_port_counter"; | ||
| 43 | + private static final String INGRESS_COUNTER = "ingress_port_counter"; | ||
| 44 | + | ||
| 45 | + private static final Logger log = LoggerFactory.getLogger(Bmv2PortStatisticsGetter.class); | ||
| 46 | + | ||
| 47 | + private Bmv2PortStatisticsGetter() { | ||
| 48 | + // ban constructor. | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Returns a collection of port statistics for given ports using the given BMv2 device agent. | ||
| 53 | + * | ||
| 54 | + * @param deviceAgent a device agent | ||
| 55 | + * @param ports a collection of ports | ||
| 56 | + * @return a collection of port statistics | ||
| 57 | + */ | ||
| 58 | + static Collection<PortStatistics> getPortStatistics(Bmv2DeviceAgent deviceAgent, Collection<Port> ports) { | ||
| 59 | + | ||
| 60 | + List<PortStatistics> ps = Lists.newArrayList(); | ||
| 61 | + | ||
| 62 | + for (Port port : ports) { | ||
| 63 | + int portNumber = (int) port.number().toLong(); | ||
| 64 | + try { | ||
| 65 | + Pair<Long, Long> egressCounter = deviceAgent.readCounter(EGRESS_COUNTER, portNumber); | ||
| 66 | + Pair<Long, Long> ingressCounter = deviceAgent.readCounter(INGRESS_COUNTER, portNumber); | ||
| 67 | + ps.add(DefaultPortStatistics.builder() | ||
| 68 | + .setPort(portNumber) | ||
| 69 | + .setBytesSent(egressCounter.getLeft()) | ||
| 70 | + .setPacketsSent(egressCounter.getRight()) | ||
| 71 | + .setBytesReceived(ingressCounter.getLeft()) | ||
| 72 | + .setPacketsReceived(ingressCounter.getRight()) | ||
| 73 | + .build()); | ||
| 74 | + } catch (Bmv2RuntimeException e) { | ||
| 75 | + log.info("Unable to read port statistics from {}: {}", port, e.explain()); | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + return ps; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * Initialize port counters on the given device agent. | ||
| 84 | + * | ||
| 85 | + * @param deviceAgent a device agent. | ||
| 86 | + */ | ||
| 87 | + static void initCounters(Bmv2DeviceAgent deviceAgent) { | ||
| 88 | + try { | ||
| 89 | + deviceAgent.setTableDefaultAction(TABLE_NAME, Bmv2Action.builder().withName(ACTION_NAME).build()); | ||
| 90 | + } catch (Bmv2RuntimeException e) { | ||
| 91 | + log.debug("Failed to provision counters on {}: {}", deviceAgent.deviceId(), e.explain()); | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | +} | ||
| 95 | + |
| ... | @@ -22,6 +22,7 @@ | ... | @@ -22,6 +22,7 @@ |
| 22 | <artifactId>onos-bmv2-providers</artifactId> | 22 | <artifactId>onos-bmv2-providers</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | <version>1.7.0-SNAPSHOT</version> | 24 | <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | <modelVersion>4.0.0</modelVersion> | 27 | <modelVersion>4.0.0</modelVersion> |
| 27 | 28 | ||
| ... | @@ -34,12 +35,12 @@ | ... | @@ -34,12 +35,12 @@ |
| 34 | <dependencies> | 35 | <dependencies> |
| 35 | <dependency> | 36 | <dependency> |
| 36 | <groupId>org.onosproject</groupId> | 37 | <groupId>org.onosproject</groupId> |
| 37 | - <artifactId>onos-drivers-bmv2</artifactId> | 38 | + <artifactId>onos-core-common</artifactId> |
| 38 | <version>${project.version}</version> | 39 | <version>${project.version}</version> |
| 39 | </dependency> | 40 | </dependency> |
| 40 | <dependency> | 41 | <dependency> |
| 41 | <groupId>org.onosproject</groupId> | 42 | <groupId>org.onosproject</groupId> |
| 42 | - <artifactId>onos-core-common</artifactId> | 43 | + <artifactId>onos-bmv2-protocol-api</artifactId> |
| 43 | <version>${project.version}</version> | 44 | <version>${project.version}</version> |
| 44 | </dependency> | 45 | </dependency> |
| 45 | </dependencies> | 46 | </dependencies> | ... | ... |
| ... | @@ -23,12 +23,14 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -23,12 +23,14 @@ import org.apache.felix.scr.annotations.Reference; |
| 23 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 23 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 24 | import org.onlab.packet.Ethernet; | 24 | import org.onlab.packet.Ethernet; |
| 25 | import org.onlab.util.ImmutableByteSequence; | 25 | import org.onlab.util.ImmutableByteSequence; |
| 26 | -import org.onosproject.bmv2.api.runtime.Bmv2ControlPlaneServer; | ||
| 27 | import org.onosproject.bmv2.api.runtime.Bmv2Device; | 26 | import org.onosproject.bmv2.api.runtime.Bmv2Device; |
| 27 | +import org.onosproject.bmv2.api.service.Bmv2Controller; | ||
| 28 | +import org.onosproject.bmv2.api.service.Bmv2PacketListener; | ||
| 28 | import org.onosproject.core.CoreService; | 29 | import org.onosproject.core.CoreService; |
| 29 | import org.onosproject.net.ConnectPoint; | 30 | import org.onosproject.net.ConnectPoint; |
| 30 | import org.onosproject.net.Device; | 31 | import org.onosproject.net.Device; |
| 31 | import org.onosproject.net.DeviceId; | 32 | import org.onosproject.net.DeviceId; |
| 33 | +import org.onosproject.net.Port; | ||
| 32 | import org.onosproject.net.PortNumber; | 34 | import org.onosproject.net.PortNumber; |
| 33 | import org.onosproject.net.device.DeviceService; | 35 | import org.onosproject.net.device.DeviceService; |
| 34 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 36 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
| ... | @@ -49,6 +51,12 @@ import org.slf4j.Logger; | ... | @@ -49,6 +51,12 @@ import org.slf4j.Logger; |
| 49 | import org.slf4j.LoggerFactory; | 51 | import org.slf4j.LoggerFactory; |
| 50 | 52 | ||
| 51 | import java.nio.ByteBuffer; | 53 | import java.nio.ByteBuffer; |
| 54 | +import java.util.Optional; | ||
| 55 | + | ||
| 56 | +import static org.onosproject.net.PortNumber.FLOOD; | ||
| 57 | +import static org.onosproject.net.flow.DefaultTrafficTreatment.emptyTreatment; | ||
| 58 | +import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT; | ||
| 59 | +import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction; | ||
| 52 | 60 | ||
| 53 | /** | 61 | /** |
| 54 | * Implementation of a packet provider for BMv2. | 62 | * Implementation of a packet provider for BMv2. |
| ... | @@ -56,11 +64,11 @@ import java.nio.ByteBuffer; | ... | @@ -56,11 +64,11 @@ import java.nio.ByteBuffer; |
| 56 | @Component(immediate = true) | 64 | @Component(immediate = true) |
| 57 | public class Bmv2PacketProvider extends AbstractProvider implements PacketProvider { | 65 | public class Bmv2PacketProvider extends AbstractProvider implements PacketProvider { |
| 58 | 66 | ||
| 59 | - private static final Logger LOG = LoggerFactory.getLogger(Bmv2PacketProvider.class); | 67 | + private final Logger log = LoggerFactory.getLogger(Bmv2PacketProvider.class); |
| 60 | private static final String APP_NAME = "org.onosproject.bmv2"; | 68 | private static final String APP_NAME = "org.onosproject.bmv2"; |
| 61 | 69 | ||
| 62 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 70 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 63 | - protected Bmv2ControlPlaneServer controlPlaneServer; | 71 | + protected Bmv2Controller controller; |
| 64 | 72 | ||
| 65 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 73 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 66 | protected CoreService coreService; | 74 | protected CoreService coreService; |
| ... | @@ -86,28 +94,28 @@ public class Bmv2PacketProvider extends AbstractProvider implements PacketProvid | ... | @@ -86,28 +94,28 @@ public class Bmv2PacketProvider extends AbstractProvider implements PacketProvid |
| 86 | protected void activate() { | 94 | protected void activate() { |
| 87 | providerService = providerRegistry.register(this); | 95 | providerService = providerRegistry.register(this); |
| 88 | coreService.registerApplication(APP_NAME); | 96 | coreService.registerApplication(APP_NAME); |
| 89 | - controlPlaneServer.addPacketListener(packetListener); | 97 | + controller.addPacketListener(packetListener); |
| 90 | - LOG.info("Started"); | 98 | + log.info("Started"); |
| 91 | } | 99 | } |
| 92 | 100 | ||
| 93 | @Deactivate | 101 | @Deactivate |
| 94 | public void deactivate() { | 102 | public void deactivate() { |
| 95 | - controlPlaneServer.removePacketListener(packetListener); | 103 | + controller.removePacketListener(packetListener); |
| 96 | providerRegistry.unregister(this); | 104 | providerRegistry.unregister(this); |
| 97 | providerService = null; | 105 | providerService = null; |
| 98 | - LOG.info("Stopped"); | 106 | + log.info("Stopped"); |
| 99 | } | 107 | } |
| 100 | 108 | ||
| 101 | @Override | 109 | @Override |
| 102 | public void emit(OutboundPacket packet) { | 110 | public void emit(OutboundPacket packet) { |
| 103 | if (packet != null) { | 111 | if (packet != null) { |
| 104 | - DeviceId did = packet.sendThrough(); | 112 | + DeviceId deviceId = packet.sendThrough(); |
| 105 | - Device device = deviceService.getDevice(did); | 113 | + Device device = deviceService.getDevice(deviceId); |
| 106 | if (device.is(PacketProgrammable.class)) { | 114 | if (device.is(PacketProgrammable.class)) { |
| 107 | PacketProgrammable packetProgrammable = device.as(PacketProgrammable.class); | 115 | PacketProgrammable packetProgrammable = device.as(PacketProgrammable.class); |
| 108 | packetProgrammable.emit(packet); | 116 | packetProgrammable.emit(packet); |
| 109 | } else { | 117 | } else { |
| 110 | - LOG.info("Unable to send packet, no PacketProgrammable behavior for device {}", did); | 118 | + log.info("No PacketProgrammable behavior for device {}", deviceId); |
| 111 | } | 119 | } |
| 112 | } | 120 | } |
| 113 | } | 121 | } |
| ... | @@ -117,47 +125,75 @@ public class Bmv2PacketProvider extends AbstractProvider implements PacketProvid | ... | @@ -117,47 +125,75 @@ public class Bmv2PacketProvider extends AbstractProvider implements PacketProvid |
| 117 | */ | 125 | */ |
| 118 | private class Bmv2PacketContext extends DefaultPacketContext { | 126 | private class Bmv2PacketContext extends DefaultPacketContext { |
| 119 | 127 | ||
| 120 | - public Bmv2PacketContext(long time, InboundPacket inPkt, OutboundPacket outPkt, boolean block) { | 128 | + Bmv2PacketContext(long time, InboundPacket inPkt, OutboundPacket outPkt, boolean block) { |
| 121 | super(time, inPkt, outPkt, block); | 129 | super(time, inPkt, outPkt, block); |
| 122 | } | 130 | } |
| 123 | 131 | ||
| 124 | @Override | 132 | @Override |
| 125 | public void send() { | 133 | public void send() { |
| 126 | - if (!this.block()) { | 134 | + |
| 127 | - if (this.outPacket().treatment() == null) { | 135 | + if (this.block()) { |
| 128 | - TrafficTreatment treatment = (this.treatmentBuilder() == null) | 136 | + log.info("Unable to send, packet context not blocked"); |
| 129 | - ? DefaultTrafficTreatment.emptyTreatment() | 137 | + return; |
| 130 | - : this.treatmentBuilder().build(); | 138 | + } |
| 131 | - OutboundPacket newPkt = new DefaultOutboundPacket(this.outPacket().sendThrough(), | 139 | + |
| 132 | - treatment, | 140 | + DeviceId deviceId = outPacket().sendThrough(); |
| 133 | - this.outPacket().data()); | 141 | + ByteBuffer rawData = outPacket().data(); |
| 134 | - emit(newPkt); | 142 | + |
| 135 | - } else { | 143 | + TrafficTreatment treatment; |
| 136 | - emit(outPacket()); | 144 | + if (outPacket().treatment() == null) { |
| 137 | - } | 145 | + treatment = (treatmentBuilder() == null) ? emptyTreatment() : treatmentBuilder().build(); |
| 146 | + } else { | ||
| 147 | + treatment = outPacket().treatment(); | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + // BMv2 doesn't support FLOOD for packet-outs. | ||
| 151 | + // Workaround here is to perform multiple emits, one for each device port != packet inPort. | ||
| 152 | + Optional<OutputInstruction> floodInst = treatment.allInstructions() | ||
| 153 | + .stream() | ||
| 154 | + .filter(i -> i.type().equals(OUTPUT)) | ||
| 155 | + .map(i -> (OutputInstruction) i) | ||
| 156 | + .filter(i -> i.port().equals(FLOOD)) | ||
| 157 | + .findAny(); | ||
| 158 | + | ||
| 159 | + if (floodInst.isPresent() && treatment.allInstructions().size() == 1) { | ||
| 160 | + // Only one instruction and is FLOOD. Do the trick. | ||
| 161 | + PortNumber inPort = inPacket().receivedFrom().port(); | ||
| 162 | + deviceService.getPorts(outPacket().sendThrough()) | ||
| 163 | + .stream() | ||
| 164 | + .map(Port::number) | ||
| 165 | + .filter(port -> !port.equals(inPort)) | ||
| 166 | + .map(outPort -> DefaultTrafficTreatment.builder().setOutput(outPort).build()) | ||
| 167 | + .map(outTreatment -> new DefaultOutboundPacket(deviceId, outTreatment, rawData)) | ||
| 168 | + .forEach(Bmv2PacketProvider.this::emit); | ||
| 138 | } else { | 169 | } else { |
| 139 | - LOG.info("Unable to send, packet context not blocked"); | 170 | + // Not FLOOD treatment, what to do is up to driver. |
| 171 | + emit(new DefaultOutboundPacket(deviceId, treatment, rawData)); | ||
| 140 | } | 172 | } |
| 141 | } | 173 | } |
| 142 | } | 174 | } |
| 143 | 175 | ||
| 144 | /** | 176 | /** |
| 145 | - * Internal packet listener to get packet events from the Bmv2ControlPlaneServer. | 177 | + * Internal packet listener to handle packet-in events received from the BMv2 controller. |
| 146 | */ | 178 | */ |
| 147 | - private class InternalPacketListener implements Bmv2ControlPlaneServer.PacketListener { | 179 | + private class InternalPacketListener implements Bmv2PacketListener { |
| 180 | + | ||
| 148 | @Override | 181 | @Override |
| 149 | public void handlePacketIn(Bmv2Device device, int inputPort, long reason, int tableId, int contextId, | 182 | public void handlePacketIn(Bmv2Device device, int inputPort, long reason, int tableId, int contextId, |
| 150 | ImmutableByteSequence packet) { | 183 | ImmutableByteSequence packet) { |
| 184 | + Ethernet ethPkt = new Ethernet(); | ||
| 185 | + ethPkt.deserialize(packet.asArray(), 0, packet.size()); | ||
| 151 | 186 | ||
| 152 | - Ethernet eth = new Ethernet(); | 187 | + DeviceId deviceId = device.asDeviceId(); |
| 153 | - eth.deserialize(packet.asArray(), 0, packet.size()); | 188 | + ConnectPoint receivedFrom = new ConnectPoint(deviceId, PortNumber.portNumber(inputPort)); |
| 189 | + | ||
| 190 | + ByteBuffer rawData = ByteBuffer.wrap(packet.asArray()); | ||
| 191 | + | ||
| 192 | + InboundPacket inPkt = new DefaultInboundPacket(receivedFrom, ethPkt, rawData); | ||
| 193 | + OutboundPacket outPkt = new DefaultOutboundPacket(deviceId, null, rawData); | ||
| 154 | 194 | ||
| 155 | - InboundPacket inPkt = new DefaultInboundPacket(new ConnectPoint(device.asDeviceId(), | ||
| 156 | - PortNumber.portNumber(inputPort)), | ||
| 157 | - eth, ByteBuffer.wrap(packet.asArray())); | ||
| 158 | - OutboundPacket outPkt = new DefaultOutboundPacket(device.asDeviceId(), null, | ||
| 159 | - ByteBuffer.wrap(packet.asArray())); | ||
| 160 | PacketContext pktCtx = new Bmv2PacketContext(System.currentTimeMillis(), inPkt, outPkt, false); | 195 | PacketContext pktCtx = new Bmv2PacketContext(System.currentTimeMillis(), inPkt, outPkt, false); |
| 196 | + | ||
| 161 | providerService.processPacket(pktCtx); | 197 | providerService.processPacket(pktCtx); |
| 162 | } | 198 | } |
| 163 | } | 199 | } | ... | ... |
| ... | @@ -22,6 +22,7 @@ | ... | @@ -22,6 +22,7 @@ |
| 22 | <artifactId>onos-providers</artifactId> | 22 | <artifactId>onos-providers</artifactId> |
| 23 | <groupId>org.onosproject</groupId> | 23 | <groupId>org.onosproject</groupId> |
| 24 | <version>1.7.0-SNAPSHOT</version> | 24 | <version>1.7.0-SNAPSHOT</version> |
| 25 | + <relativePath>../pom.xml</relativePath> | ||
| 25 | </parent> | 26 | </parent> |
| 26 | 27 | ||
| 27 | <modelVersion>4.0.0</modelVersion> | 28 | <modelVersion>4.0.0</modelVersion> | ... | ... |
| ... | @@ -46,7 +46,7 @@ | ... | @@ -46,7 +46,7 @@ |
| 46 | <module>lldpcommon</module> | 46 | <module>lldpcommon</module> |
| 47 | <module>lldp</module> | 47 | <module>lldp</module> |
| 48 | <module>netcfglinks</module> | 48 | <module>netcfglinks</module> |
| 49 | - <!--<module>bmv2</module>--> | 49 | + <module>bmv2</module> |
| 50 | <module>isis</module> | 50 | <module>isis</module> |
| 51 | </modules> | 51 | </modules> |
| 52 | 52 | ... | ... |
-
Please register or login to post a comment