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