Carmelo Cascone
Committed by Gerrit Code Review

Major refactoring of the BMv2 protocol module (onos1.6 cherry-pick)

- Created 3 separate sub-modules: API (doesn't depend on
    Thrift), CTL (depends on Thrift), THRIFT-API (to generate Thrift
    sources)
- Implemented 2 new services (for device configuration swapping and
    table entry management) needed to distribute BMv2-specific state
    among ONOS instances.
- Implemented a BMv2 controller (previously other modules where
    using separately a Thrift client and a server)
- Added a default BMv2 JSON configuration (default.json) and interpreter
    to be used for devices that connect for the first time to ONOS.
    This allows for basic services to work (i.e. LLDP link discovery,
    ARP proxy. etc.).
- Changed behavior of the flow rule translator and extension selector,
    now it allows extension to specify only some of the match parameters
    (before extension selectors were expected to describe the whole
    match key, i.e. all fields)
- Various renaming to better represent the API
- Various java doc fixes / improvements

Change-Id: Ida4b5e546b0def97c3552a6c05f7bce76fd32c28
Showing 72 changed files with 5100 additions and 1622 deletions
...@@ -39,7 +39,7 @@ public class ExtensionSelectorType { ...@@ -39,7 +39,7 @@ public class ExtensionSelectorType {
39 NICIRA_MATCH_NSH_CH3(4), 39 NICIRA_MATCH_NSH_CH3(4),
40 NICIRA_MATCH_NSH_CH4(5), 40 NICIRA_MATCH_NSH_CH4(5),
41 OFDPA_MATCH_VLAN_VID(16), 41 OFDPA_MATCH_VLAN_VID(16),
42 - P4_BMV2_MATCH_KEY(128); 42 + BMV2_MATCH_PARAMS(128);
43 43
44 private ExtensionSelectorType type; 44 private ExtensionSelectorType type;
45 45
......
...@@ -46,7 +46,7 @@ public final class ExtensionTreatmentType { ...@@ -46,7 +46,7 @@ public final class ExtensionTreatmentType {
46 NICIRA_SET_NSH_CH3(36), 46 NICIRA_SET_NSH_CH3(36),
47 NICIRA_SET_NSH_CH4(37), 47 NICIRA_SET_NSH_CH4(37),
48 OFDPA_SET_VLAN_ID(64), 48 OFDPA_SET_VLAN_ID(64),
49 - P4_BMV2_ACTION(128); 49 + BMV2_ACTION(128);
50 50
51 private ExtensionTreatmentType type; 51 private ExtensionTreatmentType type;
52 52
......
...@@ -33,6 +33,7 @@ import org.onlab.packet.VlanId; ...@@ -33,6 +33,7 @@ import org.onlab.packet.VlanId;
33 import org.onlab.util.Bandwidth; 33 import org.onlab.util.Bandwidth;
34 import org.onlab.util.ClosedOpenRange; 34 import org.onlab.util.ClosedOpenRange;
35 import org.onlab.util.Frequency; 35 import org.onlab.util.Frequency;
36 +import org.onlab.util.ImmutableByteSequence;
36 import org.onlab.util.KryoNamespace; 37 import org.onlab.util.KryoNamespace;
37 import org.onlab.util.Match; 38 import org.onlab.util.Match;
38 import org.onosproject.app.ApplicationState; 39 import org.onosproject.app.ApplicationState;
...@@ -535,6 +536,7 @@ public final class KryoNamespaces { ...@@ -535,6 +536,7 @@ public final class KryoNamespaces {
535 ) 536 )
536 .register(ClosedOpenRange.class) 537 .register(ClosedOpenRange.class)
537 .register(DiscreteResourceCodec.class) 538 .register(DiscreteResourceCodec.class)
539 + .register(ImmutableByteSequence.class)
538 .build("API"); 540 .build("API");
539 541
540 542
......
...@@ -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>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <parent>
22 + <artifactId>onos-bmv2-protocol</artifactId>
23 + <groupId>org.onosproject</groupId>
24 + <version>1.6.0-SNAPSHOT</version>
25 + </parent>
26 + <modelVersion>4.0.0</modelVersion>
27 +
28 + <packaging>bundle</packaging>
29 +
30 + <artifactId>onos-bmv2-protocol-api</artifactId>
31 +
32 + <dependencies>
33 + <dependency>
34 + <groupId>org.onosproject</groupId>
35 + <artifactId>onos-api</artifactId>
36 + <version>${project.version}</version>
37 + </dependency>
38 + <dependency>
39 + <groupId>org.apache.felix</groupId>
40 + <artifactId>org.apache.felix.scr.annotations</artifactId>
41 + </dependency>
42 + </dependencies>
43 +
44 +</project>
...\ No newline at end of file ...\ No newline at end of file
...@@ -14,8 +14,9 @@ ...@@ -14,8 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.collect.ImmutableList; 20 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Maps; 21 import com.google.common.collect.Maps;
21 22
...@@ -26,22 +27,23 @@ import java.util.Objects; ...@@ -26,22 +27,23 @@ import java.util.Objects;
26 import static com.google.common.base.MoreObjects.toStringHelper; 27 import static com.google.common.base.MoreObjects.toStringHelper;
27 28
28 /** 29 /**
29 - * BMv2 model action. 30 + * A BMv2 action model.
30 */ 31 */
31 -public final class Bmv2ModelAction { 32 +@Beta
33 +public final class Bmv2ActionModel {
32 34
33 private final String name; 35 private final String name;
34 private final int id; 36 private final int id;
35 - private final LinkedHashMap<String, Bmv2ModelRuntimeData> runtimeDatas = Maps.newLinkedHashMap(); 37 + private final LinkedHashMap<String, Bmv2RuntimeDataModel> runtimeDatas = Maps.newLinkedHashMap();
36 38
37 /** 39 /**
38 - * Creates a new action object. 40 + * Creates a new action model.
39 * 41 *
40 * @param name name 42 * @param name name
41 * @param id id 43 * @param id id
42 * @param runtimeDatas list of runtime data 44 * @param runtimeDatas list of runtime data
43 */ 45 */
44 - protected Bmv2ModelAction(String name, int id, List<Bmv2ModelRuntimeData> runtimeDatas) { 46 + protected Bmv2ActionModel(String name, int id, List<Bmv2RuntimeDataModel> runtimeDatas) {
45 this.name = name; 47 this.name = name;
46 this.id = id; 48 this.id = id;
47 runtimeDatas.forEach(r -> this.runtimeDatas.put(r.name(), r)); 49 runtimeDatas.forEach(r -> this.runtimeDatas.put(r.name(), r));
...@@ -66,22 +68,22 @@ public final class Bmv2ModelAction { ...@@ -66,22 +68,22 @@ public final class Bmv2ModelAction {
66 } 68 }
67 69
68 /** 70 /**
69 - * Returns this action's runtime data defined by the passed name, null 71 + * Returns this action's runtime data defined by the given name, null
70 * if not present. 72 * if not present.
71 * 73 *
72 * @return runtime data or null 74 * @return runtime data or null
73 */ 75 */
74 - public Bmv2ModelRuntimeData runtimeData(String name) { 76 + public Bmv2RuntimeDataModel runtimeData(String name) {
75 return runtimeDatas.get(name); 77 return runtimeDatas.get(name);
76 } 78 }
77 79
78 /** 80 /**
79 * Returns an immutable list of runtime data for this action. 81 * Returns an immutable list of runtime data for this action.
80 - * The list is ordered according to the values defined in the model. 82 + * The list is ordered according to the values defined in the configuration.
81 * 83 *
82 * @return list of runtime data. 84 * @return list of runtime data.
83 */ 85 */
84 - public List<Bmv2ModelRuntimeData> runtimeDatas() { 86 + public List<Bmv2RuntimeDataModel> runtimeDatas() {
85 return ImmutableList.copyOf(runtimeDatas.values()); 87 return ImmutableList.copyOf(runtimeDatas.values());
86 } 88 }
87 89
...@@ -98,7 +100,7 @@ public final class Bmv2ModelAction { ...@@ -98,7 +100,7 @@ public final class Bmv2ModelAction {
98 if (obj == null || getClass() != obj.getClass()) { 100 if (obj == null || getClass() != obj.getClass()) {
99 return false; 101 return false;
100 } 102 }
101 - final Bmv2ModelAction other = (Bmv2ModelAction) obj; 103 + final Bmv2ActionModel other = (Bmv2ActionModel) obj;
102 return Objects.equals(this.name, other.name) 104 return Objects.equals(this.name, other.name)
103 && Objects.equals(this.id, other.id) 105 && Objects.equals(this.id, other.id)
104 && Objects.equals(this.runtimeDatas, other.runtimeDatas); 106 && Objects.equals(this.runtimeDatas, other.runtimeDatas);
......
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.bmv2.api.context;
18 +
19 +import com.eclipsesource.json.JsonObject;
20 +import com.google.common.annotations.Beta;
21 +
22 +import java.util.List;
23 +
24 +/**
25 + * BMv2 packet processing configuration. Such a configuration is used to define the way BMv2 should process packets
26 + * (i.e. it defines the device ingress/egress pipelines, parser, tables, actions, etc.). It must be noted that this
27 + * class exposes only a subset of the configuration properties of a BMv2 device (only those that are needed for the
28 + * purpose of translating ONOS structures to BMv2 structures). Such a configuration is backed by a JSON object.
29 + * BMv2 JSON configuration files are usually generated using a P4 frontend compiler such as p4c-bmv2.
30 + */
31 +@Beta
32 +public interface Bmv2Configuration {
33 +
34 + /**
35 + * Return an unmodifiable view of the JSON backing this configuration.
36 + *
37 + * @return a JSON object.
38 + */
39 + JsonObject json();
40 +
41 + /**
42 + * Returns the header type associated with the given numeric ID, null if there's no such an ID in the configuration.
43 + *
44 + * @param id integer value
45 + * @return header type object or null
46 + */
47 + Bmv2HeaderTypeModel headerType(int id);
48 +
49 + /**
50 + * Returns the header type associated with the given name, null if there's no such a name in the configuration.
51 + *
52 + * @param name string value
53 + * @return header type object or null
54 + */
55 + Bmv2HeaderTypeModel headerType(String name);
56 +
57 + /**
58 + * Returns the list of all the header types defined by in this configuration. Values returned are sorted in
59 + * ascending order based on the numeric ID.
60 + *
61 + * @return list of header types
62 + */
63 + List<Bmv2HeaderTypeModel> headerTypes();
64 +
65 + /**
66 + * Returns the header associated with the given numeric ID, null if there's no such an ID in the configuration.
67 + *
68 + * @param id integer value
69 + * @return header object or null
70 + */
71 + Bmv2HeaderModel header(int id);
72 +
73 + /**
74 + * Returns the header associated with the given name, null if there's no such a name in the configuration.
75 + *
76 + * @param name string value
77 + * @return header object or null
78 + */
79 + Bmv2HeaderModel header(String name);
80 +
81 + /**
82 + * Returns the list of all the header instances defined in this configuration. Values returned are sorted in
83 + * ascending order based on the numeric ID.
84 + *
85 + * @return list of header types
86 + */
87 + List<Bmv2HeaderModel> headers();
88 +
89 + /**
90 + * Returns the action associated with the given numeric ID, null if there's no such an ID in the configuration.
91 + *
92 + * @param id integer value
93 + * @return action object or null
94 + */
95 + Bmv2ActionModel action(int id);
96 +
97 + /**
98 + * Returns the action associated with the given name, null if there's no such a name in the configuration.
99 + *
100 + * @param name string value
101 + * @return action object or null
102 + */
103 + Bmv2ActionModel action(String name);
104 +
105 + /**
106 + * Returns the list of all the actions defined by in this configuration. Values returned are sorted in ascending
107 + * order based on the numeric ID.
108 + *
109 + * @return list of actions
110 + */
111 + List<Bmv2ActionModel> actions();
112 +
113 + /**
114 + * Returns the table associated with the given numeric ID, null if there's no such an ID in the configuration.
115 + *
116 + * @param id integer value
117 + * @return table object or null
118 + */
119 + Bmv2TableModel table(int id);
120 +
121 + /**
122 + * Returns the table associated with the given name, null if there's no such a name in the configuration.
123 + *
124 + * @param name string value
125 + * @return table object or null
126 + */
127 + Bmv2TableModel table(String name);
128 +
129 + /**
130 + * Returns the list of all the tables defined by in this configuration. Values returned are sorted in ascending
131 + * order based on the numeric ID.
132 + *
133 + * @return list of actions
134 + */
135 + List<Bmv2TableModel> tables();
136 +}
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 import com.eclipsesource.json.JsonArray; 19 import com.eclipsesource.json.JsonArray;
20 import com.eclipsesource.json.JsonObject; 20 import com.eclipsesource.json.JsonObject;
...@@ -34,187 +34,104 @@ import java.util.SortedMap; ...@@ -34,187 +34,104 @@ import java.util.SortedMap;
34 import static com.google.common.base.Preconditions.checkArgument; 34 import static com.google.common.base.Preconditions.checkArgument;
35 35
36 /** 36 /**
37 - * Partial representation of a packet processing model for BMv2. Such a model is 37 + * Default implementation of a BMv2 configuration backed by a JSON object.
38 - * used to define the way BMv2 should process packets (i.e. it defines the
39 - * device ingress/egress pipelines, parser, tables, actions, etc.) and can be
40 - * generated (i.e. JSON) by compiling a P4 program using p4c-bm.
41 - * <p>
42 - * It must be noted that this class exposes only a subset of the full model
43 - * properties (only those that are needed for the purpose of mapping ONOS types
44 - * to BMv2 types.
45 - *
46 - * @see <a href="https://github.com/p4lang/p4c-bm">
47 - * P4 front-end compiler for BMv2 (p4c-bm)</a>
48 */ 38 */
49 -public final class Bmv2Model { 39 +public final class Bmv2DefaultConfiguration implements Bmv2Configuration {
50 40
51 private final JsonObject json; 41 private final JsonObject json;
52 - private final DualKeySortedMap<Bmv2ModelHeaderType> headerTypes = new DualKeySortedMap<>(); 42 + private final DualKeySortedMap<Bmv2HeaderTypeModel> headerTypes = new DualKeySortedMap<>();
53 - private final DualKeySortedMap<Bmv2ModelHeader> headers = new DualKeySortedMap<>(); 43 + private final DualKeySortedMap<Bmv2HeaderModel> headers = new DualKeySortedMap<>();
54 - private final DualKeySortedMap<Bmv2ModelAction> actions = new DualKeySortedMap<>(); 44 + private final DualKeySortedMap<Bmv2ActionModel> actions = new DualKeySortedMap<>();
55 - private final DualKeySortedMap<Bmv2ModelTable> tables = new DualKeySortedMap<>(); 45 + private final DualKeySortedMap<Bmv2TableModel> tables = new DualKeySortedMap<>();
56 46
57 - private Bmv2Model(JsonObject json) { 47 + private Bmv2DefaultConfiguration(JsonObject json) {
58 this.json = JsonObject.unmodifiableObject(json); 48 this.json = JsonObject.unmodifiableObject(json);
59 } 49 }
60 50
61 /** 51 /**
62 - * Returns a new BMv2 model object by parsing the passed JSON. 52 + * Returns a new BMv2 configuration object by parsing the passed JSON.
63 * 53 *
64 * @param json json 54 * @param json json
65 * @return a new BMv2 configuration object 55 * @return a new BMv2 configuration object
66 - * @see <a href="https://github.com/p4lang/behavioral-model/blob/master/docs/JSON_format.md"> 56 + * @see <a href="https://github.com/p4lang/behavioral-configuration/blob/master/docs/JSON_format.md">
67 * BMv2 JSON specification</a> 57 * BMv2 JSON specification</a>
68 */ 58 */
69 - public static Bmv2Model parse(JsonObject json) { 59 + public static Bmv2DefaultConfiguration parse(JsonObject json) {
70 checkArgument(json != null, "json cannot be null"); 60 checkArgument(json != null, "json cannot be null");
71 - // TODO: implement caching, no need to parse a json if we already have the model 61 + // TODO: implement caching, no need to parse a json if we already have the configuration
72 - Bmv2Model model = new Bmv2Model(json); 62 + Bmv2DefaultConfiguration configuration = new Bmv2DefaultConfiguration(json);
73 - model.doParse(); 63 + configuration.doParse();
74 - return model; 64 + return configuration;
75 } 65 }
76 66
77 - /** 67 + @Override
78 - * Returns the header type associated with the passed numeric id, 68 + public Bmv2HeaderTypeModel headerType(int id) {
79 - * null if there's no such an id in the model.
80 - *
81 - * @param id integer value
82 - * @return header type object or null
83 - */
84 - public Bmv2ModelHeaderType headerType(int id) {
85 return headerTypes.get(id); 69 return headerTypes.get(id);
86 } 70 }
87 71
88 - /** 72 + @Override
89 - * Returns the header type associated with the passed name, 73 + public Bmv2HeaderTypeModel headerType(String name) {
90 - * null if there's no such a name in the model.
91 - *
92 - * @param name string value
93 - * @return header type object or null
94 - */
95 - public Bmv2ModelHeaderType headerType(String name) {
96 return headerTypes.get(name); 74 return headerTypes.get(name);
97 } 75 }
98 76
99 - /** 77 + @Override
100 - * Returns the list of all the header types defined by in this model. 78 + public List<Bmv2HeaderTypeModel> headerTypes() {
101 - * Values returned are sorted in ascending order based on the numeric id.
102 - *
103 - * @return list of header types
104 - */
105 - public List<Bmv2ModelHeaderType> headerTypes() {
106 return ImmutableList.copyOf(headerTypes.sortedMap().values()); 79 return ImmutableList.copyOf(headerTypes.sortedMap().values());
107 } 80 }
108 81
109 - /** 82 + @Override
110 - * Returns the header associated with the passed numeric id, 83 + public Bmv2HeaderModel header(int id) {
111 - * null if there's no such an id in the model.
112 - *
113 - * @param id integer value
114 - * @return header object or null
115 - */
116 - public Bmv2ModelHeader header(int id) {
117 return headers.get(id); 84 return headers.get(id);
118 } 85 }
119 86
120 - /** 87 + @Override
121 - * Returns the header associated with the passed name, 88 + public Bmv2HeaderModel header(String name) {
122 - * null if there's no such a name in the model.
123 - *
124 - * @param name string value
125 - * @return header object or null
126 - */
127 - public Bmv2ModelHeader header(String name) {
128 return headers.get(name); 89 return headers.get(name);
129 } 90 }
130 91
131 - /** 92 + @Override
132 - * Returns the list of all the header instances defined in this model. 93 + public List<Bmv2HeaderModel> headers() {
133 - * Values returned are sorted in ascending order based on the numeric id.
134 - *
135 - * @return list of header types
136 - */
137 - public List<Bmv2ModelHeader> headers() {
138 return ImmutableList.copyOf(headers.sortedMap().values()); 94 return ImmutableList.copyOf(headers.sortedMap().values());
139 } 95 }
140 96
141 - /** 97 + @Override
142 - * Returns the action associated with the passed numeric id, 98 + public Bmv2ActionModel action(int id) {
143 - * null if there's no such an id in the model.
144 - *
145 - * @param id integer value
146 - * @return action object or null
147 - */
148 - public Bmv2ModelAction action(int id) {
149 return actions.get(id); 99 return actions.get(id);
150 } 100 }
151 101
152 - /** 102 + @Override
153 - * Returns the action associated with the passed name, 103 + public Bmv2ActionModel action(String name) {
154 - * null if there's no such a name in the model.
155 - *
156 - * @param name string value
157 - * @return action object or null
158 - */
159 - public Bmv2ModelAction action(String name) {
160 return actions.get(name); 104 return actions.get(name);
161 } 105 }
162 106
163 - /** 107 + @Override
164 - * Returns the list of all the actions defined by in this model. 108 + public List<Bmv2ActionModel> actions() {
165 - * Values returned are sorted in ascending order based on the numeric id.
166 - *
167 - * @return list of actions
168 - */
169 - public List<Bmv2ModelAction> actions() {
170 return ImmutableList.copyOf(actions.sortedMap().values()); 109 return ImmutableList.copyOf(actions.sortedMap().values());
171 } 110 }
172 111
173 - /** 112 + @Override
174 - * Returns the table associated with the passed numeric id, 113 + public Bmv2TableModel table(int id) {
175 - * null if there's no such an id in the model.
176 - *
177 - * @param id integer value
178 - * @return table object or null
179 - */
180 - public Bmv2ModelTable table(int id) {
181 return tables.get(id); 114 return tables.get(id);
182 } 115 }
183 116
184 - /** 117 + @Override
185 - * Returns the table associated with the passed name, 118 + public Bmv2TableModel table(String name) {
186 - * null if there's no such a name in the model.
187 - *
188 - * @param name string value
189 - * @return table object or null
190 - */
191 - public Bmv2ModelTable table(String name) {
192 return tables.get(name); 119 return tables.get(name);
193 } 120 }
194 121
195 - /** 122 + @Override
196 - * Returns the list of all the tables defined by in this model. 123 + public List<Bmv2TableModel> tables() {
197 - * Values returned are sorted in ascending order based on the numeric id.
198 - *
199 - * @return list of actions
200 - */
201 - public List<Bmv2ModelTable> tables() {
202 return ImmutableList.copyOf(tables.sortedMap().values()); 124 return ImmutableList.copyOf(tables.sortedMap().values());
203 } 125 }
204 126
205 - /** 127 + @Override
206 - * Return an unmodifiable view of the low-level JSON representation of this
207 - * model.
208 - *
209 - * @return a JSON object.
210 - */
211 public JsonObject json() { 128 public JsonObject json() {
212 return this.json; 129 return this.json;
213 } 130 }
214 131
215 /** 132 /**
216 - * Generates a hash code for this BMv2 model. The hash function is based 133 + * Generates a hash code for this BMv2 configuration. The hash function is based solely on the JSON backing this
217 - * solely on the low-level JSON representation. 134 + * configuration.
218 */ 135 */
219 @Override 136 @Override
220 public int hashCode() { 137 public int hashCode() {
...@@ -222,7 +139,7 @@ public final class Bmv2Model { ...@@ -222,7 +139,7 @@ public final class Bmv2Model {
222 } 139 }
223 140
224 /** 141 /**
225 - * Indicates whether some other BMv2 model is equal to this one. 142 + * Indicates whether some other BMv2 configuration is equal to this one.
226 * Equality is based solely on the low-level JSON representation. 143 * Equality is based solely on the low-level JSON representation.
227 * 144 *
228 * @param obj other object 145 * @param obj other object
...@@ -236,7 +153,7 @@ public final class Bmv2Model { ...@@ -236,7 +153,7 @@ public final class Bmv2Model {
236 if (obj == null || getClass() != obj.getClass()) { 153 if (obj == null || getClass() != obj.getClass()) {
237 return false; 154 return false;
238 } 155 }
239 - final Bmv2Model other = (Bmv2Model) obj; 156 + final Bmv2DefaultConfiguration other = (Bmv2DefaultConfiguration) obj;
240 return Objects.equal(this.json, other.json); 157 return Objects.equal(this.json, other.json);
241 } 158 }
242 159
...@@ -257,10 +174,10 @@ public final class Bmv2Model { ...@@ -257,10 +174,10 @@ public final class Bmv2Model {
257 JsonObject jHeaderType = val.asObject(); 174 JsonObject jHeaderType = val.asObject();
258 175
259 // populate fields list 176 // populate fields list
260 - List<Bmv2ModelFieldType> fieldTypes = Lists.newArrayList(); 177 + List<Bmv2FieldTypeModel> fieldTypes = Lists.newArrayList();
261 178
262 jHeaderType.get("fields").asArray().forEach(x -> fieldTypes.add( 179 jHeaderType.get("fields").asArray().forEach(x -> fieldTypes.add(
263 - new Bmv2ModelFieldType( 180 + new Bmv2FieldTypeModel(
264 x.asArray().get(0).asString(), 181 x.asArray().get(0).asString(),
265 x.asArray().get(1).asInt()))); 182 x.asArray().get(1).asInt())));
266 183
...@@ -268,7 +185,7 @@ public final class Bmv2Model { ...@@ -268,7 +185,7 @@ public final class Bmv2Model {
268 String name = jHeaderType.get("name").asString(); 185 String name = jHeaderType.get("name").asString();
269 int id = jHeaderType.get("id").asInt(); 186 int id = jHeaderType.get("id").asInt();
270 187
271 - Bmv2ModelHeaderType headerType = new Bmv2ModelHeaderType(name, 188 + Bmv2HeaderTypeModel headerType = new Bmv2HeaderTypeModel(name,
272 id, 189 id,
273 fieldTypes); 190 fieldTypes);
274 191
...@@ -284,7 +201,7 @@ public final class Bmv2Model { ...@@ -284,7 +201,7 @@ public final class Bmv2Model {
284 int id = jHeader.get("id").asInt(); 201 int id = jHeader.get("id").asInt();
285 String typeName = jHeader.get("header_type").asString(); 202 String typeName = jHeader.get("header_type").asString();
286 203
287 - Bmv2ModelHeader header = new Bmv2ModelHeader(name, 204 + Bmv2HeaderModel header = new Bmv2HeaderModel(name,
288 id, 205 id,
289 headerTypes.get(typeName), 206 headerTypes.get(typeName),
290 jHeader.get("metadata").asBoolean()); 207 jHeader.get("metadata").asBoolean());
...@@ -299,10 +216,10 @@ public final class Bmv2Model { ...@@ -299,10 +216,10 @@ public final class Bmv2Model {
299 JsonObject jAction = val.asObject(); 216 JsonObject jAction = val.asObject();
300 217
301 // populate runtime data list 218 // populate runtime data list
302 - List<Bmv2ModelRuntimeData> runtimeDatas = Lists.newArrayList(); 219 + List<Bmv2RuntimeDataModel> runtimeDatas = Lists.newArrayList();
303 220
304 jAction.get("runtime_data").asArray().forEach(jData -> runtimeDatas.add( 221 jAction.get("runtime_data").asArray().forEach(jData -> runtimeDatas.add(
305 - new Bmv2ModelRuntimeData( 222 + new Bmv2RuntimeDataModel(
306 jData.asObject().get("name").asString(), 223 jData.asObject().get("name").asString(),
307 jData.asObject().get("bitwidth").asInt() 224 jData.asObject().get("bitwidth").asInt()
308 ))); 225 )));
...@@ -311,7 +228,7 @@ public final class Bmv2Model { ...@@ -311,7 +228,7 @@ public final class Bmv2Model {
311 String name = jAction.get("name").asString(); 228 String name = jAction.get("name").asString();
312 int id = jAction.get("id").asInt(); 229 int id = jAction.get("id").asInt();
313 230
314 - Bmv2ModelAction action = new Bmv2ModelAction(name, 231 + Bmv2ActionModel action = new Bmv2ActionModel(name,
315 id, 232 id,
316 runtimeDatas); 233 runtimeDatas);
317 234
...@@ -326,15 +243,15 @@ public final class Bmv2Model { ...@@ -326,15 +243,15 @@ public final class Bmv2Model {
326 JsonObject jTable = val.asObject(); 243 JsonObject jTable = val.asObject();
327 244
328 // populate keys 245 // populate keys
329 - List<Bmv2ModelTableKey> keys = Lists.newArrayList(); 246 + List<Bmv2TableKeyModel> keys = Lists.newArrayList();
330 247
331 jTable.get("key").asArray().forEach(jKey -> { 248 jTable.get("key").asArray().forEach(jKey -> {
332 JsonArray target = jKey.asObject().get("target").asArray(); 249 JsonArray target = jKey.asObject().get("target").asArray();
333 250
334 - Bmv2ModelHeader header = header(target.get(0).asString()); 251 + Bmv2HeaderModel header = header(target.get(0).asString());
335 String typeName = target.get(1).asString(); 252 String typeName = target.get(1).asString();
336 253
337 - Bmv2ModelField field = new Bmv2ModelField( 254 + Bmv2FieldModel field = new Bmv2FieldModel(
338 header, header.type().field(typeName)); 255 header, header.type().field(typeName));
339 256
340 String matchTypeStr = jKey.asObject().get("match_type").asString(); 257 String matchTypeStr = jKey.asObject().get("match_type").asString();
...@@ -359,11 +276,11 @@ public final class Bmv2Model { ...@@ -359,11 +276,11 @@ public final class Bmv2Model {
359 "Unable to parse match type: " + matchTypeStr); 276 "Unable to parse match type: " + matchTypeStr);
360 } 277 }
361 278
362 - keys.add(new Bmv2ModelTableKey(matchType, field)); 279 + keys.add(new Bmv2TableKeyModel(matchType, field));
363 }); 280 });
364 281
365 // populate actions set 282 // populate actions set
366 - Set<Bmv2ModelAction> actionzz = Sets.newHashSet(); 283 + Set<Bmv2ActionModel> actionzz = Sets.newHashSet();
367 jTable.get("actions").asArray().forEach( 284 jTable.get("actions").asArray().forEach(
368 jAction -> actionzz.add(action(jAction.asString()))); 285 jAction -> actionzz.add(action(jAction.asString())));
369 286
...@@ -371,7 +288,7 @@ public final class Bmv2Model { ...@@ -371,7 +288,7 @@ public final class Bmv2Model {
371 String name = jTable.get("name").asString(); 288 String name = jTable.get("name").asString();
372 int id = jTable.get("id").asInt(); 289 int id = jTable.get("id").asInt();
373 290
374 - Bmv2ModelTable table = new Bmv2ModelTable(name, 291 + Bmv2TableModel table = new Bmv2TableModel(name,
375 id, 292 id,
376 jTable.get("match_type").asString(), 293 jTable.get("match_type").asString(),
377 jTable.get("type").asString(), 294 jTable.get("type").asString(),
...@@ -405,7 +322,7 @@ public final class Bmv2Model { ...@@ -405,7 +322,7 @@ public final class Bmv2Model {
405 } 322 }
406 323
407 private T get(String name) { 324 private T get(String name) {
408 - return get(strToIntMap.get(name)); 325 + return strToIntMap.get(name) == null ? null : get(strToIntMap.get(name));
409 } 326 }
410 327
411 private SortedMap<Integer, T> sortedMap() { 328 private SortedMap<Integer, T> sortedMap() {
......
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.bmv2.api.context;
18 +
19 +import com.google.common.annotations.Beta;
20 +import com.google.common.base.MoreObjects;
21 +import com.google.common.base.Objects;
22 +
23 +import static com.google.common.base.Preconditions.checkNotNull;
24 +
25 +/**
26 + * A BMv2 device context, defined by a configuration and an interpreter.
27 + */
28 +@Beta
29 +public final class Bmv2DeviceContext {
30 +
31 + private final Bmv2Configuration configuration;
32 + private final Bmv2Interpreter interpreter;
33 +
34 + /**
35 + * Creates a new BMv2 device context.
36 + *
37 + * @param configuration a configuration
38 + * @param interpreter an interpreter
39 + */
40 + public Bmv2DeviceContext(Bmv2Configuration configuration, Bmv2Interpreter interpreter) {
41 + this.configuration = checkNotNull(configuration, "configuration cannot be null");
42 + this.interpreter = checkNotNull(interpreter, "interpreter cannot be null");
43 + }
44 +
45 + /**
46 + * Returns the BMv2 configuration of this context.
47 + *
48 + * @return a configuration
49 + */
50 + public Bmv2Configuration configuration() {
51 + return configuration;
52 + }
53 +
54 + /**
55 + * Returns the BMv2 interpreter of this context.
56 + *
57 + * @return an interpreter
58 + */
59 + public Bmv2Interpreter interpreter() {
60 + return interpreter;
61 + }
62 +
63 + @Override
64 + public int hashCode() {
65 + return Objects.hashCode(configuration, interpreter);
66 + }
67 +
68 + @Override
69 + public boolean equals(Object obj) {
70 + if (this == obj) {
71 + return true;
72 + }
73 + if (obj == null || getClass() != obj.getClass()) {
74 + return false;
75 + }
76 + final Bmv2DeviceContext other = (Bmv2DeviceContext) obj;
77 + return Objects.equal(this.configuration, other.configuration)
78 + && Objects.equal(this.interpreter, other.interpreter);
79 + }
80 +
81 + @Override
82 + public String toString() {
83 + return MoreObjects.toStringHelper(this)
84 + .add("configuration", configuration)
85 + .add("interpreter", interpreter)
86 + .toString();
87 + }
88 +}
...@@ -14,21 +14,23 @@ ...@@ -14,21 +14,23 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 20 import com.google.common.base.Objects;
20 21
21 import static com.google.common.base.MoreObjects.toStringHelper; 22 import static com.google.common.base.MoreObjects.toStringHelper;
22 23
23 /** 24 /**
24 - * Representation of a BMv2 model's header field instance. 25 + * A BMv2 header field model.
25 */ 26 */
26 -public final class Bmv2ModelField { 27 +@Beta
28 +public final class Bmv2FieldModel {
27 29
28 - private final Bmv2ModelHeader header; 30 + private final Bmv2HeaderModel header;
29 - private final Bmv2ModelFieldType type; 31 + private final Bmv2FieldTypeModel type;
30 32
31 - protected Bmv2ModelField(Bmv2ModelHeader header, Bmv2ModelFieldType type) { 33 + protected Bmv2FieldModel(Bmv2HeaderModel header, Bmv2FieldTypeModel type) {
32 this.header = header; 34 this.header = header;
33 this.type = type; 35 this.type = type;
34 } 36 }
...@@ -38,7 +40,7 @@ public final class Bmv2ModelField { ...@@ -38,7 +40,7 @@ public final class Bmv2ModelField {
38 * 40 *
39 * @return a header instance 41 * @return a header instance
40 */ 42 */
41 - public Bmv2ModelHeader header() { 43 + public Bmv2HeaderModel header() {
42 return header; 44 return header;
43 } 45 }
44 46
...@@ -47,7 +49,7 @@ public final class Bmv2ModelField { ...@@ -47,7 +49,7 @@ public final class Bmv2ModelField {
47 * 49 *
48 * @return a field type value 50 * @return a field type value
49 */ 51 */
50 - public Bmv2ModelFieldType type() { 52 + public Bmv2FieldTypeModel type() {
51 return type; 53 return type;
52 } 54 }
53 55
...@@ -64,7 +66,7 @@ public final class Bmv2ModelField { ...@@ -64,7 +66,7 @@ public final class Bmv2ModelField {
64 if (obj == null || getClass() != obj.getClass()) { 66 if (obj == null || getClass() != obj.getClass()) {
65 return false; 67 return false;
66 } 68 }
67 - final Bmv2ModelField other = (Bmv2ModelField) obj; 69 + final Bmv2FieldModel other = (Bmv2FieldModel) obj;
68 return Objects.equal(this.header, other.header) 70 return Objects.equal(this.header, other.header)
69 && Objects.equal(this.type, other.type); 71 && Objects.equal(this.type, other.type);
70 } 72 }
......
...@@ -14,21 +14,23 @@ ...@@ -14,21 +14,23 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 20 import com.google.common.base.Objects;
20 21
21 import static com.google.common.base.MoreObjects.toStringHelper; 22 import static com.google.common.base.MoreObjects.toStringHelper;
22 23
23 /** 24 /**
24 - * BMv2 model header type field. 25 + * A BMv2 header type field model.
25 */ 26 */
26 -public final class Bmv2ModelFieldType { 27 +@Beta
28 +public final class Bmv2FieldTypeModel {
27 29
28 private final String name; 30 private final String name;
29 private final int bitWidth; 31 private final int bitWidth;
30 32
31 - protected Bmv2ModelFieldType(String name, int bitWidth) { 33 + protected Bmv2FieldTypeModel(String name, int bitWidth) {
32 this.name = name; 34 this.name = name;
33 this.bitWidth = bitWidth; 35 this.bitWidth = bitWidth;
34 } 36 }
...@@ -64,7 +66,7 @@ public final class Bmv2ModelFieldType { ...@@ -64,7 +66,7 @@ public final class Bmv2ModelFieldType {
64 if (obj == null || getClass() != obj.getClass()) { 66 if (obj == null || getClass() != obj.getClass()) {
65 return false; 67 return false;
66 } 68 }
67 - final Bmv2ModelFieldType other = (Bmv2ModelFieldType) obj; 69 + final Bmv2FieldTypeModel other = (Bmv2FieldTypeModel) obj;
68 return Objects.equal(this.name, other.name) 70 return Objects.equal(this.name, other.name)
69 && Objects.equal(this.bitWidth, other.bitWidth); 71 && Objects.equal(this.bitWidth, other.bitWidth);
70 } 72 }
......
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.bmv2.api.context;
18 +
19 +import com.google.common.annotations.Beta;
20 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
21 +import org.onosproject.net.flow.FlowRule;
22 +
23 +/**
24 + * Translator of ONOS flow rules to BMv2 table entries.
25 + */
26 +@Beta
27 +public interface Bmv2FlowRuleTranslator {
28 +
29 + /**
30 + * Returns a BMv2 table entry equivalent to the given flow rule for the given context.
31 + * <p>
32 + * Translation is performed according to the following logic:
33 + * <ul>
34 + * <li> table name: obtained from the context interpreter {@link Bmv2Interpreter#tableIdMap() table ID map}.
35 + * <li> match key: is built using both the context interpreter {@link Bmv2Interpreter#criterionTypeMap() criterion
36 + * map} and all {@link org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector extension selectors} (if any).
37 + * <li> action: is built using the context interpreter
38 + * {@link Bmv2Interpreter#mapTreatment(org.onosproject.net.flow.TrafficTreatment, Bmv2Configuration)
39 + * treatment mapping function} or the flow rule
40 + * {@link org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment} extension treatment} (if any).
41 + * <li> timeout: if the table supports timeout, use the same as the flow rule, otherwise none (i.e. permanent
42 + * entry).
43 + * </ul>
44 + *
45 + * @param rule a flow rule
46 + * @param context a context
47 + * @return a BMv2 table entry
48 + * @throws Bmv2FlowRuleTranslatorException if the flow rule cannot be translated
49 + */
50 + Bmv2TableEntry translate(FlowRule rule, Bmv2DeviceContext context) throws Bmv2FlowRuleTranslatorException;
51 +}
...@@ -14,41 +14,14 @@ ...@@ -14,41 +14,14 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.runtime; 17 +package org.onosproject.bmv2.api.context;
18 -
19 -import org.onlab.util.KryoNamespace;
20 -import org.onosproject.net.flow.AbstractExtension;
21 -import org.onosproject.net.flow.criteria.ExtensionSelector;
22 -import org.onosproject.net.flow.criteria.ExtensionSelectorType;
23 18
24 /** 19 /**
25 - * Extension selector for Bmv2 used as a wrapper for a {@link Bmv2MatchKey}. 20 + * BMv2 flow rule translator exception.
26 */ 21 */
27 -public class Bmv2ExtensionSelector extends AbstractExtension implements ExtensionSelector { 22 +public class Bmv2FlowRuleTranslatorException extends Exception {
28 -
29 - private final KryoNamespace appKryo = new KryoNamespace.Builder().build();
30 - private Bmv2MatchKey matchKey;
31 -
32 - public Bmv2ExtensionSelector(Bmv2MatchKey matchKey) {
33 - this.matchKey = matchKey;
34 - }
35 -
36 - public Bmv2MatchKey matchKey() {
37 - return matchKey;
38 - }
39 -
40 - @Override
41 - public ExtensionSelectorType type() {
42 - return ExtensionSelectorType.ExtensionSelectorTypes.P4_BMV2_MATCH_KEY.type();
43 - }
44 -
45 - @Override
46 - public byte[] serialize() {
47 - return appKryo.serialize(matchKey);
48 - }
49 23
50 - @Override 24 + public Bmv2FlowRuleTranslatorException(String msg) {
51 - public void deserialize(byte[] data) { 25 + super(msg);
52 - matchKey = appKryo.deserialize(data);
53 } 26 }
54 } 27 }
......
...@@ -14,31 +14,33 @@ ...@@ -14,31 +14,33 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 20 import com.google.common.base.Objects;
20 21
21 import static com.google.common.base.MoreObjects.toStringHelper; 22 import static com.google.common.base.MoreObjects.toStringHelper;
22 23
23 /** 24 /**
24 - * Representation of a BMv2 model header instance. 25 + * BMv2 header instance model.
25 */ 26 */
26 -public final class Bmv2ModelHeader { 27 +@Beta
28 +public final class Bmv2HeaderModel {
27 29
28 private final String name; 30 private final String name;
29 private final int id; 31 private final int id;
30 - private final Bmv2ModelHeaderType type; 32 + private final Bmv2HeaderTypeModel type;
31 private final boolean isMetadata; 33 private final boolean isMetadata;
32 34
33 /** 35 /**
34 - * Creates a new header instance. 36 + * Creates a new header instance model.
35 * 37 *
36 * @param name name 38 * @param name name
37 * @param id id 39 * @param id id
38 * @param type header type 40 * @param type header type
39 * @param metadata if is metadata 41 * @param metadata if is metadata
40 */ 42 */
41 - protected Bmv2ModelHeader(String name, int id, Bmv2ModelHeaderType type, boolean metadata) { 43 + protected Bmv2HeaderModel(String name, int id, Bmv2HeaderTypeModel type, boolean metadata) {
42 this.name = name; 44 this.name = name;
43 this.id = id; 45 this.id = id;
44 this.type = type; 46 this.type = type;
...@@ -68,7 +70,7 @@ public final class Bmv2ModelHeader { ...@@ -68,7 +70,7 @@ public final class Bmv2ModelHeader {
68 * 70 *
69 * @return a header type value 71 * @return a header type value
70 */ 72 */
71 - public Bmv2ModelHeaderType type() { 73 + public Bmv2HeaderTypeModel type() {
72 return type; 74 return type;
73 } 75 }
74 76
...@@ -94,7 +96,7 @@ public final class Bmv2ModelHeader { ...@@ -94,7 +96,7 @@ public final class Bmv2ModelHeader {
94 if (obj == null || getClass() != obj.getClass()) { 96 if (obj == null || getClass() != obj.getClass()) {
95 return false; 97 return false;
96 } 98 }
97 - final Bmv2ModelHeader other = (Bmv2ModelHeader) obj; 99 + final Bmv2HeaderModel other = (Bmv2HeaderModel) obj;
98 return Objects.equal(this.name, other.name) 100 return Objects.equal(this.name, other.name)
99 && Objects.equal(this.id, other.id) 101 && Objects.equal(this.id, other.id)
100 && Objects.equal(this.type, other.type) 102 && Objects.equal(this.type, other.type)
......
...@@ -14,8 +14,9 @@ ...@@ -14,8 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 20 import com.google.common.base.Objects;
20 import com.google.common.collect.ImmutableList; 21 import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.Maps; 22 import com.google.common.collect.Maps;
...@@ -26,22 +27,23 @@ import java.util.List; ...@@ -26,22 +27,23 @@ import java.util.List;
26 import static com.google.common.base.MoreObjects.toStringHelper; 27 import static com.google.common.base.MoreObjects.toStringHelper;
27 28
28 /** 29 /**
29 - * BMv2 model header type. 30 + * BMv2 header type model.
30 */ 31 */
31 -public final class Bmv2ModelHeaderType { 32 +@Beta
33 +public final class Bmv2HeaderTypeModel {
32 34
33 private final String name; 35 private final String name;
34 private final int id; 36 private final int id;
35 - private final LinkedHashMap<String, Bmv2ModelFieldType> fields = Maps.newLinkedHashMap(); 37 + private final LinkedHashMap<String, Bmv2FieldTypeModel> fields = Maps.newLinkedHashMap();
36 38
37 /** 39 /**
38 - * Creates a new header type instance. 40 + * Creates a new header type model.
39 * 41 *
40 * @param name name 42 * @param name name
41 * @param id id 43 * @param id id
42 * @param fieldTypes fields 44 * @param fieldTypes fields
43 */ 45 */
44 - protected Bmv2ModelHeaderType(String name, int id, List<Bmv2ModelFieldType> fieldTypes) { 46 + protected Bmv2HeaderTypeModel(String name, int id, List<Bmv2FieldTypeModel> fieldTypes) {
45 this.name = name; 47 this.name = name;
46 this.id = id; 48 this.id = id;
47 fieldTypes.forEach(f -> this.fields.put(f.name(), f)); 49 fieldTypes.forEach(f -> this.fields.put(f.name(), f));
...@@ -72,7 +74,7 @@ public final class Bmv2ModelHeaderType { ...@@ -72,7 +74,7 @@ public final class Bmv2ModelHeaderType {
72 * @param fieldName field name 74 * @param fieldName field name
73 * @return field or null 75 * @return field or null
74 */ 76 */
75 - public Bmv2ModelFieldType field(String fieldName) { 77 + public Bmv2FieldTypeModel field(String fieldName) {
76 return fields.get(fieldName); 78 return fields.get(fieldName);
77 } 79 }
78 80
...@@ -83,7 +85,7 @@ public final class Bmv2ModelHeaderType { ...@@ -83,7 +85,7 @@ public final class Bmv2ModelHeaderType {
83 * 85 *
84 * @return list of fields 86 * @return list of fields
85 */ 87 */
86 - public List<Bmv2ModelFieldType> fields() { 88 + public List<Bmv2FieldTypeModel> fields() {
87 return ImmutableList.copyOf(fields.values()); 89 return ImmutableList.copyOf(fields.values());
88 } 90 }
89 91
...@@ -100,7 +102,7 @@ public final class Bmv2ModelHeaderType { ...@@ -100,7 +102,7 @@ public final class Bmv2ModelHeaderType {
100 if (obj == null || getClass() != obj.getClass()) { 102 if (obj == null || getClass() != obj.getClass()) {
101 return false; 103 return false;
102 } 104 }
103 - final Bmv2ModelHeaderType other = (Bmv2ModelHeaderType) obj; 105 + final Bmv2HeaderTypeModel other = (Bmv2HeaderTypeModel) obj;
104 return Objects.equal(this.name, other.name) 106 return Objects.equal(this.name, other.name)
105 && Objects.equal(this.id, other.id) 107 && Objects.equal(this.id, other.id)
106 && Objects.equal(this.fields, other.fields); 108 && Objects.equal(this.fields, other.fields);
......
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.bmv2.api.context;
18 +
19 +import com.google.common.annotations.Beta;
20 +import com.google.common.collect.ImmutableBiMap;
21 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
22 +import org.onosproject.net.flow.TrafficTreatment;
23 +import org.onosproject.net.flow.criteria.Criterion;
24 +
25 +/**
26 + * A BMv2 configuration interpreter.
27 + */
28 +@Beta
29 +public interface Bmv2Interpreter {
30 +
31 + /**
32 + * Returns a bi-map describing a one-to-one relationship between ONOS flow rule table IDs and BMv2 table names.
33 + *
34 + * @return a {@link com.google.common.collect.BiMap} where the key is a ONOS flow rule table id and
35 + * the value is a BMv2 table names
36 + */
37 + ImmutableBiMap<Integer, String> tableIdMap();
38 +
39 + /**
40 + * Returns a bi-map describing a one-to-one relationship between ONOS criterion types and BMv2 header field names.
41 + * Header field names are formatted using the notation {@code header_name.field_member_name}.
42 + *
43 + * @return a {@link com.google.common.collect.BiMap} where the keys are ONOS criterion types and the values are
44 + * BMv2 header field names
45 + */
46 + ImmutableBiMap<Criterion.Type, String> criterionTypeMap();
47 +
48 + /**
49 + * Return a BMv2 action that is functionally equivalent to the given ONOS traffic treatment for the given
50 + * configuration.
51 + *
52 + * @param treatment a ONOS traffic treatment
53 + * @param configuration a BMv2 configuration
54 + * @return a BMv2 action object
55 + * @throws Bmv2InterpreterException if the treatment cannot be mapped to any BMv2 action
56 + */
57 + Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
58 + throws Bmv2InterpreterException;
59 +
60 +}
...@@ -14,18 +14,14 @@ ...@@ -14,18 +14,14 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.runtime; 17 +package org.onosproject.bmv2.api.context;
18 18
19 /** 19 /**
20 - * General exception of the Bmv2 runtime APIs. 20 + * A BMv2 interpreter exception.
21 */ 21 */
22 -public class Bmv2RuntimeException extends Exception { 22 +public class Bmv2InterpreterException extends Exception {
23 23
24 - public Bmv2RuntimeException(String message, Throwable cause) { 24 + public Bmv2InterpreterException(String message) {
25 - super(message, cause);
26 - }
27 -
28 - public Bmv2RuntimeException(String message) {
29 super(message); 25 super(message);
30 } 26 }
31 } 27 }
......
...@@ -14,27 +14,30 @@ ...@@ -14,27 +14,30 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 +
19 +import com.google.common.annotations.Beta;
18 20
19 import java.util.Objects; 21 import java.util.Objects;
20 22
21 import static com.google.common.base.MoreObjects.toStringHelper; 23 import static com.google.common.base.MoreObjects.toStringHelper;
22 24
23 /** 25 /**
24 - * BMv2 model action runtime data. 26 + * A BMv2 action runtime data model.
25 */ 27 */
26 -public final class Bmv2ModelRuntimeData { 28 +@Beta
29 +public final class Bmv2RuntimeDataModel {
27 30
28 private final String name; 31 private final String name;
29 private final int bitWidth; 32 private final int bitWidth;
30 33
31 /** 34 /**
32 - * Creates a new runtime data. 35 + * Creates a new runtime data model.
33 * 36 *
34 * @param name name 37 * @param name name
35 * @param bitWidth bitwidth 38 * @param bitWidth bitwidth
36 */ 39 */
37 - protected Bmv2ModelRuntimeData(String name, int bitWidth) { 40 + protected Bmv2RuntimeDataModel(String name, int bitWidth) {
38 this.name = name; 41 this.name = name;
39 this.bitWidth = bitWidth; 42 this.bitWidth = bitWidth;
40 } 43 }
...@@ -70,7 +73,7 @@ public final class Bmv2ModelRuntimeData { ...@@ -70,7 +73,7 @@ public final class Bmv2ModelRuntimeData {
70 if (obj == null || getClass() != obj.getClass()) { 73 if (obj == null || getClass() != obj.getClass()) {
71 return false; 74 return false;
72 } 75 }
73 - final Bmv2ModelRuntimeData other = (Bmv2ModelRuntimeData) obj; 76 + final Bmv2RuntimeDataModel other = (Bmv2RuntimeDataModel) obj;
74 return Objects.equals(this.name, other.name) 77 return Objects.equals(this.name, other.name)
75 && Objects.equals(this.bitWidth, other.bitWidth); 78 && Objects.equals(this.bitWidth, other.bitWidth);
76 } 79 }
......
...@@ -14,28 +14,30 @@ ...@@ -14,28 +14,30 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 20 import com.google.common.base.Objects;
20 import org.onosproject.bmv2.api.runtime.Bmv2MatchParam; 21 import org.onosproject.bmv2.api.runtime.Bmv2MatchParam;
21 22
22 import static com.google.common.base.MoreObjects.toStringHelper; 23 import static com.google.common.base.MoreObjects.toStringHelper;
23 24
24 /** 25 /**
25 - * Representation of a table key. 26 + * A BMv2 table key model.
26 */ 27 */
27 -public final class Bmv2ModelTableKey { 28 +@Beta
29 +public final class Bmv2TableKeyModel {
28 30
29 private final Bmv2MatchParam.Type matchType; 31 private final Bmv2MatchParam.Type matchType;
30 - private final Bmv2ModelField field; 32 + private final Bmv2FieldModel field;
31 33
32 /** 34 /**
33 - * Creates a new table key. 35 + * Creates a new table key model.
34 * 36 *
35 * @param matchType match type 37 * @param matchType match type
36 * @param field field instance 38 * @param field field instance
37 */ 39 */
38 - protected Bmv2ModelTableKey(Bmv2MatchParam.Type matchType, Bmv2ModelField field) { 40 + protected Bmv2TableKeyModel(Bmv2MatchParam.Type matchType, Bmv2FieldModel field) {
39 this.matchType = matchType; 41 this.matchType = matchType;
40 this.field = field; 42 this.field = field;
41 } 43 }
...@@ -55,7 +57,7 @@ public final class Bmv2ModelTableKey { ...@@ -55,7 +57,7 @@ public final class Bmv2ModelTableKey {
55 * 57 *
56 * @return a header field value 58 * @return a header field value
57 */ 59 */
58 - public Bmv2ModelField field() { 60 + public Bmv2FieldModel field() {
59 return field; 61 return field;
60 } 62 }
61 63
...@@ -72,7 +74,7 @@ public final class Bmv2ModelTableKey { ...@@ -72,7 +74,7 @@ public final class Bmv2ModelTableKey {
72 if (obj == null || getClass() != obj.getClass()) { 74 if (obj == null || getClass() != obj.getClass()) {
73 return false; 75 return false;
74 } 76 }
75 - final Bmv2ModelTableKey other = (Bmv2ModelTableKey) obj; 77 + final Bmv2TableKeyModel other = (Bmv2TableKeyModel) obj;
76 return Objects.equal(this.matchType, other.matchType) 78 return Objects.equal(this.matchType, other.matchType)
77 && Objects.equal(this.field, other.field); 79 && Objects.equal(this.field, other.field);
78 } 80 }
......
...@@ -14,8 +14,9 @@ ...@@ -14,8 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 +import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 20 import com.google.common.base.Objects;
20 21
21 import java.util.List; 22 import java.util.List;
...@@ -24,9 +25,10 @@ import java.util.Set; ...@@ -24,9 +25,10 @@ import java.util.Set;
24 import static com.google.common.base.MoreObjects.toStringHelper; 25 import static com.google.common.base.MoreObjects.toStringHelper;
25 26
26 /** 27 /**
27 - * BMv2 model table representation. 28 + * A BMv2 table model.
28 */ 29 */
29 -public final class Bmv2ModelTable { 30 +@Beta
31 +public final class Bmv2TableModel {
30 32
31 private final String name; 33 private final String name;
32 private final int id; 34 private final int id;
...@@ -35,11 +37,11 @@ public final class Bmv2ModelTable { ...@@ -35,11 +37,11 @@ public final class Bmv2ModelTable {
35 private final int maxSize; 37 private final int maxSize;
36 private final boolean hasCounters; 38 private final boolean hasCounters;
37 private final boolean hasTimeouts; 39 private final boolean hasTimeouts;
38 - private final List<Bmv2ModelTableKey> keys; 40 + private final List<Bmv2TableKeyModel> keys;
39 - private final Set<Bmv2ModelAction> actions; 41 + private final Set<Bmv2ActionModel> actions;
40 42
41 /** 43 /**
42 - * Creates a new table. 44 + * Creates a new table model.
43 * 45 *
44 * @param name name 46 * @param name name
45 * @param id id 47 * @param id id
...@@ -51,9 +53,9 @@ public final class Bmv2ModelTable { ...@@ -51,9 +53,9 @@ public final class Bmv2ModelTable {
51 * @param keys list of match keys 53 * @param keys list of match keys
52 * @param actions list of actions 54 * @param actions list of actions
53 */ 55 */
54 - protected Bmv2ModelTable(String name, int id, String matchType, String type, 56 + protected Bmv2TableModel(String name, int id, String matchType, String type,
55 int maxSize, boolean withCounters, boolean supportTimeout, 57 int maxSize, boolean withCounters, boolean supportTimeout,
56 - List<Bmv2ModelTableKey> keys, Set<Bmv2ModelAction> actions) { 58 + List<Bmv2TableKeyModel> keys, Set<Bmv2ActionModel> actions) {
57 this.name = name; 59 this.name = name;
58 this.id = id; 60 this.id = id;
59 this.matchType = matchType; 61 this.matchType = matchType;
...@@ -134,7 +136,7 @@ public final class Bmv2ModelTable { ...@@ -134,7 +136,7 @@ public final class Bmv2ModelTable {
134 * 136 *
135 * @return a list of match keys 137 * @return a list of match keys
136 */ 138 */
137 - public List<Bmv2ModelTableKey> keys() { 139 + public List<Bmv2TableKeyModel> keys() {
138 return keys; 140 return keys;
139 } 141 }
140 142
...@@ -143,7 +145,7 @@ public final class Bmv2ModelTable { ...@@ -143,7 +145,7 @@ public final class Bmv2ModelTable {
143 * 145 *
144 * @return a list of actions 146 * @return a list of actions
145 */ 147 */
146 - public Set<Bmv2ModelAction> actions() { 148 + public Set<Bmv2ActionModel> actions() {
147 return actions; 149 return actions;
148 } 150 }
149 151
...@@ -161,7 +163,7 @@ public final class Bmv2ModelTable { ...@@ -161,7 +163,7 @@ public final class Bmv2ModelTable {
161 if (obj == null || getClass() != obj.getClass()) { 163 if (obj == null || getClass() != obj.getClass()) {
162 return false; 164 return false;
163 } 165 }
164 - final Bmv2ModelTable other = (Bmv2ModelTable) obj; 166 + final Bmv2TableModel other = (Bmv2TableModel) obj;
165 return Objects.equal(this.name, other.name) 167 return Objects.equal(this.name, other.name)
166 && Objects.equal(this.id, other.id) 168 && Objects.equal(this.id, other.id)
167 && Objects.equal(this.matchType, other.matchType) 169 && Objects.equal(this.matchType, other.matchType)
......
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
15 */ 15 */
16 16
17 /** 17 /**
18 - * BMv2 configuration model classes. 18 + * BMv2 device context API.
19 */ 19 */
20 -package org.onosproject.bmv2.api.model;
...\ No newline at end of file ...\ No newline at end of file
20 +package org.onosproject.bmv2.api.context;
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -15,11 +15,6 @@ ...@@ -15,11 +15,6 @@
15 */ 15 */
16 16
17 /** 17 /**
18 - * Bmv2 API abstractions. 18 + * BMv2 protocol API.
19 - * <p>
20 - * Bmv2 APIs are divided in two sub-packages, runtime and model.
21 - * Runtime APIs are used to represent operations that can be performed at runtime
22 - * on a Bmv2 device, while model APIs are used to describe the Bmv2 packet
23 - * processing model.
24 */ 19 */
25 package org.onosproject.bmv2.api; 20 package org.onosproject.bmv2.api;
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
28 import static com.google.common.base.Preconditions.checkState; 28 import static com.google.common.base.Preconditions.checkState;
29 29
30 /** 30 /**
31 - * Bmv2 action representation. 31 + * An action of a BMv2 match-action table entry.
32 */ 32 */
33 public final class Bmv2Action { 33 public final class Bmv2Action {
34 34
...@@ -94,7 +94,7 @@ public final class Bmv2Action { ...@@ -94,7 +94,7 @@ public final class Bmv2Action {
94 } 94 }
95 95
96 /** 96 /**
97 - * A Bmv2 action builder. 97 + * A BMv2 action builder.
98 */ 98 */
99 public static final class Builder { 99 public static final class Builder {
100 100
...@@ -128,9 +128,9 @@ public final class Bmv2Action { ...@@ -128,9 +128,9 @@ public final class Bmv2Action {
128 } 128 }
129 129
130 /** 130 /**
131 - * Builds a Bmv2 action object. 131 + * Builds a BMv2 action object.
132 * 132 *
133 - * @return a Bmv2 action 133 + * @return a BMv2 action
134 */ 134 */
135 public Bmv2Action build() { 135 public Bmv2Action build() {
136 checkState(name != null, "action name not set"); 136 checkState(name != null, "action name not set");
......
...@@ -21,6 +21,8 @@ import org.onosproject.net.DeviceId; ...@@ -21,6 +21,8 @@ import org.onosproject.net.DeviceId;
21 21
22 import java.net.URI; 22 import java.net.URI;
23 import java.net.URISyntaxException; 23 import java.net.URISyntaxException;
24 +import java.util.regex.Matcher;
25 +import java.util.regex.Pattern;
24 26
25 import static com.google.common.base.Preconditions.checkNotNull; 27 import static com.google.common.base.Preconditions.checkNotNull;
26 28
...@@ -29,20 +31,25 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -29,20 +31,25 @@ import static com.google.common.base.Preconditions.checkNotNull;
29 */ 31 */
30 public final class Bmv2Device { 32 public final class Bmv2Device {
31 33
34 + public static final String N_A = "n/a";
35 +
32 public static final String SCHEME = "bmv2"; 36 public static final String SCHEME = "bmv2";
37 + public static final String PROTOCOL = "bmv2-thrift";
33 public static final String MANUFACTURER = "p4.org"; 38 public static final String MANUFACTURER = "p4.org";
34 public static final String HW_VERSION = "bmv2"; 39 public static final String HW_VERSION = "bmv2";
40 + public static final String SW_VERSION = N_A;
41 + public static final String SERIAL_NUMBER = N_A;
35 42
36 private final String thriftServerHost; 43 private final String thriftServerHost;
37 private final int thriftServerPort; 44 private final int thriftServerPort;
38 private final int internalDeviceId; 45 private final int internalDeviceId;
39 46
40 /** 47 /**
41 - * Creates a new Bmv2 device object. 48 + * Creates a new BMv2 device object.
42 * 49 *
43 - * @param thriftServerHost the host of the Thrift runtime server running inside the device 50 + * @param thriftServerHost the hostname / IP address of the Thrift runtime server running on the device
44 - * @param thriftServerPort the port of the Thrift runtime server running inside the device 51 + * @param thriftServerPort the port of the Thrift runtime server running on the device
45 - * @param internalDeviceId the internal device id 52 + * @param internalDeviceId the internal device ID number
46 */ 53 */
47 public Bmv2Device(String thriftServerHost, int thriftServerPort, int internalDeviceId) { 54 public Bmv2Device(String thriftServerHost, int thriftServerPort, int internalDeviceId) {
48 this.thriftServerHost = checkNotNull(thriftServerHost, "host cannot be null"); 55 this.thriftServerHost = checkNotNull(thriftServerHost, "host cannot be null");
...@@ -51,7 +58,17 @@ public final class Bmv2Device { ...@@ -51,7 +58,17 @@ public final class Bmv2Device {
51 } 58 }
52 59
53 /** 60 /**
54 - * Returns the hostname (or IP address) of the Thrift runtime server running inside the device. 61 + * Returns a Bmv2Device representing the given deviceId.
62 + *
63 + * @param deviceId a deviceId
64 + * @return
65 + */
66 + public static Bmv2Device of(DeviceId deviceId) {
67 + return DeviceIdParser.parse(checkNotNull(deviceId, "deviceId cannot be null"));
68 + }
69 +
70 + /**
71 + * Returns the hostname (or IP address) of the Thrift runtime server running on the device.
55 * 72 *
56 * @return a string value 73 * @return a string value
57 */ 74 */
...@@ -60,7 +77,7 @@ public final class Bmv2Device { ...@@ -60,7 +77,7 @@ public final class Bmv2Device {
60 } 77 }
61 78
62 /** 79 /**
63 - * Returns the port of the Thrift runtime server running inside the device. 80 + * Returns the port of the Thrift runtime server running on the device.
64 * 81 *
65 * @return an integer value 82 * @return an integer value
66 */ 83 */
...@@ -86,7 +103,8 @@ public final class Bmv2Device { ...@@ -86,7 +103,8 @@ public final class Bmv2Device {
86 public DeviceId asDeviceId() { 103 public DeviceId asDeviceId() {
87 try { 104 try {
88 // TODO: include internalDeviceId number in the deviceId URI 105 // TODO: include internalDeviceId number in the deviceId URI
89 - return DeviceId.deviceId(new URI(SCHEME, this.thriftServerHost + ":" + this.thriftServerPort, null)); 106 + return DeviceId.deviceId(new URI(SCHEME, this.thriftServerHost + ":" + this.thriftServerPort,
107 + String.valueOf(this.internalDeviceId)));
90 } catch (URISyntaxException e) { 108 } catch (URISyntaxException e) {
91 throw new IllegalArgumentException("Unable to build deviceID for device " + this.toString(), e); 109 throw new IllegalArgumentException("Unable to build deviceID for device " + this.toString(), e);
92 } 110 }
...@@ -113,6 +131,23 @@ public final class Bmv2Device { ...@@ -113,6 +131,23 @@ public final class Bmv2Device {
113 131
114 @Override 132 @Override
115 public String toString() { 133 public String toString() {
116 - return thriftServerHost + ":" + thriftServerPort + "/" + internalDeviceId; 134 + return asDeviceId().toString();
135 + }
136 +
137 + private static class DeviceIdParser {
138 +
139 + private static final Pattern REGEX = Pattern.compile(SCHEME + ":(.+):(\\d+)#(\\d+)");
140 +
141 + public static Bmv2Device parse(DeviceId deviceId) {
142 + Matcher matcher = REGEX.matcher(deviceId.toString());
143 + if (matcher.find()) {
144 + String host = matcher.group(1);
145 + int port = Integer.valueOf(matcher.group(2));
146 + int internalDeviceId = Integer.valueOf(matcher.group(3));
147 + return new Bmv2Device(host, port, internalDeviceId);
148 + } else {
149 + throw new RuntimeException("Unable to parse bmv2 device id string: " + deviceId.toString());
150 + }
151 + }
117 } 152 }
118 } 153 }
......
...@@ -18,14 +18,29 @@ package org.onosproject.bmv2.api.runtime; ...@@ -18,14 +18,29 @@ package org.onosproject.bmv2.api.runtime;
18 18
19 import org.apache.commons.lang3.tuple.Pair; 19 import org.apache.commons.lang3.tuple.Pair;
20 import org.onlab.util.ImmutableByteSequence; 20 import org.onlab.util.ImmutableByteSequence;
21 +import org.onosproject.net.DeviceId;
21 22
22 import java.util.Collection; 23 import java.util.Collection;
23 -import java.util.List;
24 24
25 /** 25 /**
26 - * RPC client to control a BMv2 device. 26 + * An agent to control a BMv2 device.
27 */ 27 */
28 -public interface Bmv2Client { 28 +public interface Bmv2DeviceAgent {
29 +
30 + /**
31 + * Returns the device ID of this agent.
32 + *
33 + * @return a device id
34 + */
35 + DeviceId deviceId();
36 +
37 + /**
38 + * Pings the device, returns true if the device is reachable, false otherwise.
39 + *
40 + * @return true if reachable, false otherwise
41 + */
42 + boolean ping();
43 +
29 /** 44 /**
30 * Adds a new table entry. 45 * Adds a new table entry.
31 * 46 *
...@@ -36,16 +51,14 @@ public interface Bmv2Client { ...@@ -36,16 +51,14 @@ public interface Bmv2Client {
36 long addTableEntry(Bmv2TableEntry entry) throws Bmv2RuntimeException; 51 long addTableEntry(Bmv2TableEntry entry) throws Bmv2RuntimeException;
37 52
38 /** 53 /**
39 - * Modifies a currently installed entry by updating its action. 54 + * Modifies an existing table entry by updating its action.
40 * 55 *
41 * @param tableName string value of table name 56 * @param tableName string value of table name
42 * @param entryId long value of entry ID 57 * @param entryId long value of entry ID
43 * @param action an action value 58 * @param action an action value
44 * @throws Bmv2RuntimeException if any error occurs 59 * @throws Bmv2RuntimeException if any error occurs
45 */ 60 */
46 - void modifyTableEntry(String tableName, 61 + void modifyTableEntry(String tableName, long entryId, Bmv2Action action) throws Bmv2RuntimeException;
47 - long entryId, Bmv2Action action)
48 - throws Bmv2RuntimeException;
49 62
50 /** 63 /**
51 * Deletes currently installed entry. 64 * Deletes currently installed entry.
...@@ -54,8 +67,7 @@ public interface Bmv2Client { ...@@ -54,8 +67,7 @@ public interface Bmv2Client {
54 * @param entryId long value of entry ID 67 * @param entryId long value of entry ID
55 * @throws Bmv2RuntimeException if any error occurs 68 * @throws Bmv2RuntimeException if any error occurs
56 */ 69 */
57 - void deleteTableEntry(String tableName, 70 + void deleteTableEntry(String tableName, long entryId) throws Bmv2RuntimeException;
58 - long entryId) throws Bmv2RuntimeException;
59 71
60 /** 72 /**
61 * Sets table default action. 73 * Sets table default action.
...@@ -64,11 +76,10 @@ public interface Bmv2Client { ...@@ -64,11 +76,10 @@ public interface Bmv2Client {
64 * @param action an action value 76 * @param action an action value
65 * @throws Bmv2RuntimeException if any error occurs 77 * @throws Bmv2RuntimeException if any error occurs
66 */ 78 */
67 - void setTableDefaultAction(String tableName, Bmv2Action action) 79 + void setTableDefaultAction(String tableName, Bmv2Action action) throws Bmv2RuntimeException;
68 - throws Bmv2RuntimeException;
69 80
70 /** 81 /**
71 - * Returns information of the ports currently configured in the switch. 82 + * Returns information on the ports currently configured in the switch.
72 * 83 *
73 * @return collection of port information 84 * @return collection of port information
74 * @throws Bmv2RuntimeException if any error occurs 85 * @throws Bmv2RuntimeException if any error occurs
...@@ -76,7 +87,7 @@ public interface Bmv2Client { ...@@ -76,7 +87,7 @@ public interface Bmv2Client {
76 Collection<Bmv2PortInfo> getPortsInfo() throws Bmv2RuntimeException; 87 Collection<Bmv2PortInfo> getPortsInfo() throws Bmv2RuntimeException;
77 88
78 /** 89 /**
79 - * Return a string representation of a table content. 90 + * Return a string representation of the given table content.
80 * 91 *
81 * @param tableName string value of table name 92 * @param tableName string value of table name
82 * @return table string dump 93 * @return table string dump
...@@ -85,24 +96,6 @@ public interface Bmv2Client { ...@@ -85,24 +96,6 @@ public interface Bmv2Client {
85 String dumpTable(String tableName) throws Bmv2RuntimeException; 96 String dumpTable(String tableName) throws Bmv2RuntimeException;
86 97
87 /** 98 /**
88 - * Returns a list of ids for the entries installed in the given table.
89 - *
90 - * @param tableName string value of table name
91 - * @return a list of entry ids
92 - * @throws Bmv2RuntimeException if any error occurs
93 - */
94 - List<Long> getInstalledEntryIds(String tableName) throws Bmv2RuntimeException;
95 -
96 - /**
97 - * Removes all entries installed in the given table.
98 - *
99 - * @param tableName string value of table name
100 - * @return the number of entries removed
101 - * @throws Bmv2RuntimeException if any error occurs
102 - */
103 - int cleanupTable(String tableName) throws Bmv2RuntimeException;
104 -
105 - /**
106 * Requests the device to transmit a given byte sequence over the given port. 99 * Requests the device to transmit a given byte sequence over the given port.
107 * 100 *
108 * @param portNumber a port number 101 * @param portNumber a port number
...@@ -112,14 +105,14 @@ public interface Bmv2Client { ...@@ -112,14 +105,14 @@ public interface Bmv2Client {
112 void transmitPacket(int portNumber, ImmutableByteSequence packet) throws Bmv2RuntimeException; 105 void transmitPacket(int portNumber, ImmutableByteSequence packet) throws Bmv2RuntimeException;
113 106
114 /** 107 /**
115 - * Reset the state of the switch (e.g. delete all entries, etc.). 108 + * Resets the state of the switch (e.g. delete all entries, etc.).
116 * 109 *
117 * @throws Bmv2RuntimeException if any error occurs 110 * @throws Bmv2RuntimeException if any error occurs
118 */ 111 */
119 void resetState() throws Bmv2RuntimeException; 112 void resetState() throws Bmv2RuntimeException;
120 113
121 /** 114 /**
122 - * Returns the JSON-formatted model configuration currently used to process packets. 115 + * Returns the JSON configuration currently used to process packets.
123 * 116 *
124 * @return a JSON-formatted string value 117 * @return a JSON-formatted string value
125 * @throws Bmv2RuntimeException if any error occurs 118 * @throws Bmv2RuntimeException if any error occurs
...@@ -127,7 +120,7 @@ public interface Bmv2Client { ...@@ -127,7 +120,7 @@ public interface Bmv2Client {
127 String dumpJsonConfig() throws Bmv2RuntimeException; 120 String dumpJsonConfig() throws Bmv2RuntimeException;
128 121
129 /** 122 /**
130 - * Returns the md5 hash of the JSON-formatted model configuration currently used to process packets. 123 + * Returns the md5 sum of the JSON-formatted model configuration currently used to process packets.
131 * 124 *
132 * @return a string value 125 * @return a string value
133 * @throws Bmv2RuntimeException if any error occurs 126 * @throws Bmv2RuntimeException if any error occurs
...@@ -143,4 +136,39 @@ public interface Bmv2Client { ...@@ -143,4 +136,39 @@ public interface Bmv2Client {
143 * @throws Bmv2RuntimeException if any error occurs 136 * @throws Bmv2RuntimeException if any error occurs
144 */ 137 */
145 Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException; 138 Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException;
139 +
140 + /**
141 + * Returns the counter values for a given counter and index.
142 + *
143 + * @param counterName a counter name
144 + * @param index an integer value
145 + * @return a pair of long values, where the left value is the number of bytes and the right value is the number of
146 + * packets
147 + * @throws Bmv2RuntimeException if any error occurs
148 + */
149 + Pair<Long, Long> readCounter(String counterName, int index) throws Bmv2RuntimeException;
150 +
151 + /**
152 + * Returns the ID of the current BMv2 process instance (used to distinguish between different executions of the
153 + * same BMv2 device).
154 + *
155 + * @return an integer value
156 + * @throws Bmv2RuntimeException if any error occurs
157 + */
158 + int getProcessInstanceId() throws Bmv2RuntimeException;
159 +
160 + /**
161 + * Uploads a new JSON configuration on the device.
162 + *
163 + * @param jsonString a string value
164 + * @throws Bmv2RuntimeException if any error occurs
165 + */
166 + void loadNewJsonConfig(String jsonString) throws Bmv2RuntimeException;
167 +
168 + /**
169 + * Triggers a configuration swap on the device.
170 + *
171 + * @throws Bmv2RuntimeException
172 + */
173 + void swapJsonConfig() throws Bmv2RuntimeException;
146 } 174 }
......
...@@ -23,9 +23,9 @@ import org.onlab.util.ImmutableByteSequence; ...@@ -23,9 +23,9 @@ import org.onlab.util.ImmutableByteSequence;
23 import static com.google.common.base.Preconditions.checkNotNull; 23 import static com.google.common.base.Preconditions.checkNotNull;
24 24
25 /** 25 /**
26 - * Representation of a Bmv2 exact match parameter. 26 + * Representation of a BMv2 exact match parameter.
27 */ 27 */
28 -public class Bmv2ExactMatchParam implements Bmv2MatchParam { 28 +public final class Bmv2ExactMatchParam implements Bmv2MatchParam {
29 29
30 private final ImmutableByteSequence value; 30 private final ImmutableByteSequence value;
31 31
......
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.bmv2.api.runtime;
18 +
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.base.Objects;
21 +import org.onlab.util.KryoNamespace;
22 +import org.onosproject.net.flow.AbstractExtension;
23 +import org.onosproject.net.flow.criteria.ExtensionSelector;
24 +import org.onosproject.net.flow.criteria.ExtensionSelectorType;
25 +
26 +import java.util.HashMap;
27 +import java.util.Map;
28 +
29 +import static com.google.common.base.Preconditions.checkNotNull;
30 +
31 +/**
32 + * Extension selector for BMv2 used as a wrapper for multiple BMv2 match parameters.
33 + */
34 +public final class Bmv2ExtensionSelector extends AbstractExtension implements ExtensionSelector {
35 +
36 + private final KryoNamespace appKryo = new KryoNamespace.Builder()
37 + .register(HashMap.class)
38 + .register(Bmv2MatchParam.class)
39 + .register(Bmv2ExactMatchParam.class)
40 + .register(Bmv2TernaryMatchParam.class)
41 + .register(Bmv2LpmMatchParam.class)
42 + .register(Bmv2ValidMatchParam.class)
43 + .build();
44 +
45 + private Map<String, Bmv2MatchParam> parameterMap;
46 +
47 + /**
48 + * Creates a new BMv2 extension selector for the given match parameters map, where the keys are expected to be field
49 + * names formatted as headerName.fieldMemberName (e.g. ethernet.dstAddr).
50 + *
51 + * @param paramMap a map
52 + */
53 + public Bmv2ExtensionSelector(Map<String, Bmv2MatchParam> paramMap) {
54 + this.parameterMap = checkNotNull(paramMap, "param map cannot be null");
55 + }
56 +
57 + /**
58 + * Returns the match parameters map of this selector.
59 + *
60 + * @return a match parameter map
61 + */
62 + public Map<String, Bmv2MatchParam> parameterMap() {
63 + return parameterMap;
64 + }
65 +
66 +
67 + @Override
68 + public ExtensionSelectorType type() {
69 + return ExtensionSelectorType.ExtensionSelectorTypes.BMV2_MATCH_PARAMS.type();
70 + }
71 +
72 + @Override
73 + public byte[] serialize() {
74 + return appKryo.serialize(parameterMap);
75 + }
76 +
77 + @Override
78 + public void deserialize(byte[] data) {
79 + this.parameterMap = appKryo.deserialize(data);
80 + }
81 +
82 + @Override
83 + public int hashCode() {
84 + return Objects.hashCode(parameterMap);
85 + }
86 +
87 + @Override
88 + public boolean equals(Object obj) {
89 + if (this == obj) {
90 + return true;
91 + }
92 + if (obj == null || getClass() != obj.getClass()) {
93 + return false;
94 + }
95 + final Bmv2ExtensionSelector other = (Bmv2ExtensionSelector) obj;
96 + return Objects.equal(this.parameterMap, other.parameterMap);
97 + }
98 +
99 + @Override
100 + public String toString() {
101 + return MoreObjects.toStringHelper(this)
102 + .add("parameterMap", parameterMap)
103 + .toString();
104 + }
105 +}
...@@ -16,15 +16,19 @@ ...@@ -16,15 +16,19 @@
16 16
17 package org.onosproject.bmv2.api.runtime; 17 package org.onosproject.bmv2.api.runtime;
18 18
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.base.Objects;
19 import org.onlab.util.KryoNamespace; 21 import org.onlab.util.KryoNamespace;
20 import org.onosproject.net.flow.AbstractExtension; 22 import org.onosproject.net.flow.AbstractExtension;
21 import org.onosproject.net.flow.instructions.ExtensionTreatment; 23 import org.onosproject.net.flow.instructions.ExtensionTreatment;
22 import org.onosproject.net.flow.instructions.ExtensionTreatmentType; 24 import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
23 25
26 +import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.BMV2_ACTION;
27 +
24 /** 28 /**
25 - * Extension treatment for Bmv2 used as a wrapper for a {@link Bmv2Action}. 29 + * Extension treatment for BMv2 used as a wrapper for a {@link Bmv2Action}.
26 */ 30 */
27 -public class Bmv2ExtensionTreatment extends AbstractExtension implements ExtensionTreatment { 31 +public final class Bmv2ExtensionTreatment extends AbstractExtension implements ExtensionTreatment {
28 32
29 private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); 33 private final KryoNamespace appKryo = new KryoNamespace.Builder().build();
30 private Bmv2Action action; 34 private Bmv2Action action;
...@@ -39,7 +43,7 @@ public class Bmv2ExtensionTreatment extends AbstractExtension implements Extensi ...@@ -39,7 +43,7 @@ public class Bmv2ExtensionTreatment extends AbstractExtension implements Extensi
39 43
40 @Override 44 @Override
41 public ExtensionTreatmentType type() { 45 public ExtensionTreatmentType type() {
42 - return ExtensionTreatmentType.ExtensionTreatmentTypes.P4_BMV2_ACTION.type(); 46 + return BMV2_ACTION.type();
43 } 47 }
44 48
45 @Override 49 @Override
...@@ -51,4 +55,28 @@ public class Bmv2ExtensionTreatment extends AbstractExtension implements Extensi ...@@ -51,4 +55,28 @@ public class Bmv2ExtensionTreatment extends AbstractExtension implements Extensi
51 public void deserialize(byte[] data) { 55 public void deserialize(byte[] data) {
52 action = appKryo.deserialize(data); 56 action = appKryo.deserialize(data);
53 } 57 }
58 +
59 + @Override
60 + public int hashCode() {
61 + return Objects.hashCode(action);
62 + }
63 +
64 + @Override
65 + public boolean equals(Object obj) {
66 + if (this == obj) {
67 + return true;
68 + }
69 + if (obj == null || getClass() != obj.getClass()) {
70 + return false;
71 + }
72 + final Bmv2ExtensionTreatment other = (Bmv2ExtensionTreatment) obj;
73 + return Objects.equal(this.action, other.action);
74 + }
75 +
76 + @Override
77 + public String toString() {
78 + return MoreObjects.toStringHelper(this)
79 + .add("action", action)
80 + .toString();
81 + }
54 } 82 }
......
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.bmv2.api.runtime;
18 +
19 +import com.google.common.base.Objects;
20 +import org.onosproject.net.flow.FlowRule;
21 +
22 +import java.util.Date;
23 +
24 +/**
25 + * A wrapper class for a ONOS flow rule installed on a BMv2 device.
26 + */
27 +public class Bmv2FlowRuleWrapper {
28 +
29 + private final FlowRule rule;
30 + private final long entryId;
31 + private final Date creationDate;
32 +
33 + /**
34 + * Creates a new flow rule wrapper.
35 + *
36 + * @param rule a flow rule
37 + * @param entryId a BMv2 table entry ID
38 + * @param creationDate the creation date of the flow rule
39 + */
40 + public Bmv2FlowRuleWrapper(FlowRule rule, long entryId, Date creationDate) {
41 + this.rule = rule;
42 + this.entryId = entryId;
43 + this.creationDate = new Date();
44 + }
45 +
46 + /**
47 + * Returns the flow rule contained by this wrapper.
48 + *
49 + * @return a flow rule
50 + */
51 + public FlowRule rule() {
52 + return rule;
53 + }
54 +
55 + /**
56 + * Return the seconds since when this flow rule was installed on the device.
57 + *
58 + * @return an integer value
59 + */
60 + public long lifeInSeconds() {
61 + return (new Date().getTime() - creationDate.getTime()) / 1000;
62 + }
63 +
64 + /**
65 + * Returns the creation date of this flow rule.
66 + *
67 + * @return a date
68 + */
69 + public Date creationDate() {
70 + return creationDate;
71 + }
72 +
73 + /**
74 + * Returns the BMv2 entry ID of this flow rule.
75 + *
76 + * @return a long value
77 + */
78 + public long entryId() {
79 + return entryId;
80 + }
81 +
82 + @Override
83 + public int hashCode() {
84 + return Objects.hashCode(rule, entryId, creationDate);
85 + }
86 +
87 + @Override
88 + public boolean equals(Object obj) {
89 + if (this == obj) {
90 + return true;
91 + }
92 + if (obj == null || getClass() != obj.getClass()) {
93 + return false;
94 + }
95 + final Bmv2FlowRuleWrapper other = (Bmv2FlowRuleWrapper) obj;
96 + return Objects.equal(this.rule, other.rule)
97 + && Objects.equal(this.entryId, other.entryId)
98 + && Objects.equal(this.creationDate, other.creationDate);
99 + }
100 +
101 + @Override
102 + public String toString() {
103 + return creationDate + "-" + rule.hashCode();
104 + }
105 +}
...@@ -24,9 +24,9 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -24,9 +24,9 @@ import static com.google.common.base.Preconditions.checkArgument;
24 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.base.Preconditions.checkNotNull;
25 25
26 /** 26 /**
27 - * Representation of a Bmv2 longest prefix match (LPM) parameter. 27 + * Representation of a BMv2 longest prefix match (LPM) parameter.
28 */ 28 */
29 -public class Bmv2LpmMatchParam implements Bmv2MatchParam { 29 +public final class Bmv2LpmMatchParam implements Bmv2MatchParam {
30 30
31 private final ImmutableByteSequence value; 31 private final ImmutableByteSequence value;
32 private final int prefixLength; 32 private final int prefixLength;
......
...@@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkArgument;
28 import static com.google.common.base.Preconditions.checkNotNull; 28 import static com.google.common.base.Preconditions.checkNotNull;
29 29
30 /** 30 /**
31 - * Bmv2 match key representation. 31 + * A match key of a BMv2 match-action table entry.
32 */ 32 */
33 public final class Bmv2MatchKey { 33 public final class Bmv2MatchKey {
34 34
...@@ -39,13 +39,17 @@ public final class Bmv2MatchKey { ...@@ -39,13 +39,17 @@ public final class Bmv2MatchKey {
39 this.matchParams = matchParams; 39 this.matchParams = matchParams;
40 } 40 }
41 41
42 + /**
43 + * Returns a new match key builder.
44 + *
45 + * @return a match key builder
46 + */
42 public static Builder builder() { 47 public static Builder builder() {
43 return new Builder(); 48 return new Builder();
44 } 49 }
45 50
46 /** 51 /**
47 - * Returns an immutable view of the ordered list of match parameters of this 52 + * Returns the list of match parameters of this match key.
48 - * match key.
49 * 53 *
50 * @return list match parameters 54 * @return list match parameters
51 */ 55 */
...@@ -79,7 +83,7 @@ public final class Bmv2MatchKey { ...@@ -79,7 +83,7 @@ public final class Bmv2MatchKey {
79 } 83 }
80 84
81 /** 85 /**
82 - * Builder of a Bmv2 match key. 86 + * Builder of a BMv2 match key.
83 */ 87 */
84 public static final class Builder { 88 public static final class Builder {
85 89
...@@ -89,6 +93,12 @@ public final class Bmv2MatchKey { ...@@ -89,6 +93,12 @@ public final class Bmv2MatchKey {
89 this.matchParams = Lists.newArrayList(); 93 this.matchParams = Lists.newArrayList();
90 } 94 }
91 95
96 + /**
97 + * Adds a match parameter to the match key.
98 + *
99 + * @param param a match parameter
100 + * @return this
101 + */
92 public Builder add(Bmv2MatchParam param) { 102 public Builder add(Bmv2MatchParam param) {
93 this.matchParams.add(checkNotNull(param)); 103 this.matchParams.add(checkNotNull(param));
94 return this; 104 return this;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
17 package org.onosproject.bmv2.api.runtime; 17 package org.onosproject.bmv2.api.runtime;
18 18
19 /** 19 /**
20 - * Representation of a Bmv2 match parameter. 20 + * Representation of a BMv2 match parameter.
21 */ 21 */
22 public interface Bmv2MatchParam { 22 public interface Bmv2MatchParam {
23 23
...@@ -29,7 +29,7 @@ public interface Bmv2MatchParam { ...@@ -29,7 +29,7 @@ public interface Bmv2MatchParam {
29 Type type(); 29 Type type();
30 30
31 /** 31 /**
32 - * Bmv2 match types. 32 + * BMv2 match types.
33 */ 33 */
34 enum Type { 34 enum Type {
35 /** 35 /**
......
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.bmv2.api.runtime;
18 +
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.base.Objects;
21 +
22 +/**
23 + * Representation of a table entry obtained by parsing a BMv2 table dump.
24 + */
25 +public final class Bmv2ParsedTableEntry {
26 + private final long entryId;
27 + private final Bmv2MatchKey matchKey;
28 + private final Bmv2Action action;
29 +
30 + /**
31 + * Creates a new parsed table entry.
32 + *
33 + * @param entryId an entry ID
34 + * @param matchKey a match key
35 + * @param action an action
36 + */
37 + public Bmv2ParsedTableEntry(long entryId, Bmv2MatchKey matchKey, Bmv2Action action) {
38 + this.entryId = entryId;
39 + this.matchKey = matchKey;
40 + this.action = action;
41 + }
42 +
43 + /**
44 + * Returns the entry ID.
45 + *
46 + * @return a long value
47 + */
48 + public long entryId() {
49 + return entryId;
50 + }
51 +
52 + /**
53 + * Returns the match key.
54 + *
55 + * @return a match key object
56 + */
57 + public Bmv2MatchKey matchKey() {
58 + return matchKey;
59 + }
60 +
61 + /**
62 + * Returns the action.
63 + *
64 + * @return an action object
65 + */
66 + public Bmv2Action action() {
67 + return action;
68 + }
69 +
70 + @Override
71 + public int hashCode() {
72 + return Objects.hashCode(entryId, matchKey, action);
73 + }
74 +
75 + @Override
76 + public boolean equals(Object obj) {
77 + if (this == obj) {
78 + return true;
79 + }
80 + if (obj == null || getClass() != obj.getClass()) {
81 + return false;
82 + }
83 + final Bmv2ParsedTableEntry other = (Bmv2ParsedTableEntry) obj;
84 + return Objects.equal(this.entryId, other.entryId)
85 + && Objects.equal(this.matchKey, other.matchKey)
86 + && Objects.equal(this.action, other.action);
87 + }
88 +
89 + @Override
90 + public String toString() {
91 + return MoreObjects.toStringHelper(this)
92 + .add("entryId", entryId)
93 + .add("matchKey", matchKey)
94 + .add("action", action)
95 + .toString();
96 + }
97 +}
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.bmv2.api.runtime;
18 +
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.base.Objects;
21 +
22 +/**
23 + * Information of a port of a BMv2 device.
24 + */
25 +public final class Bmv2PortInfo {
26 +
27 + private final String ifaceName;
28 + private final int number;
29 + private final boolean isUp;
30 +
31 + /**
32 + * Creates a new port description.
33 + *
34 + * @param ifaceName the common name of the network interface
35 + * @param number a port number
36 + * @param isUp interface status
37 + */
38 + public Bmv2PortInfo(String ifaceName, int number, boolean isUp) {
39 + this.ifaceName = ifaceName;
40 + this.number = number;
41 + this.isUp = isUp;
42 + }
43 +
44 + /**
45 + * Returns the common name the network interface used by this port.
46 + *
47 + * @return a string value
48 + */
49 + public String ifaceName() {
50 + return ifaceName;
51 + }
52 +
53 + /**
54 + * Returns the number of this port.
55 + *
56 + * @return an integer value
57 + */
58 + public int number() {
59 + return number;
60 + }
61 +
62 + /**
63 + * Returns true if the port is up, false otherwise.
64 + *
65 + * @return a boolean value
66 + */
67 + public boolean isUp() {
68 + return isUp;
69 + }
70 +
71 + @Override
72 + public int hashCode() {
73 + return Objects.hashCode(ifaceName, number, isUp);
74 + }
75 +
76 + @Override
77 + public boolean equals(Object obj) {
78 + if (this == obj) {
79 + return true;
80 + }
81 + if (obj == null || getClass() != obj.getClass()) {
82 + return false;
83 + }
84 + final Bmv2PortInfo other = (Bmv2PortInfo) obj;
85 + return Objects.equal(this.ifaceName, other.ifaceName)
86 + && Objects.equal(this.number, other.number)
87 + && Objects.equal(this.isUp, other.isUp);
88 + }
89 +
90 + @Override
91 + public String toString() {
92 + return MoreObjects.toStringHelper(this)
93 + .add("ifaceName", ifaceName)
94 + .add("number", number)
95 + .add("isUp", isUp)
96 + .toString();
97 + }
98 +}
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.bmv2.api.runtime;
18 +
19 +/**
20 + * General exception of the BMv2 runtime APIs.
21 + */
22 +public final class Bmv2RuntimeException extends Exception {
23 +
24 + private final Code code;
25 + private String codeString;
26 +
27 + public Bmv2RuntimeException(String message) {
28 + super(message);
29 + this.code = Code.OTHER;
30 + this.codeString = message;
31 + }
32 +
33 + public Bmv2RuntimeException(Throwable cause) {
34 + super(cause);
35 + this.code = Code.OTHER;
36 + this.codeString = cause.toString();
37 + }
38 +
39 + public Bmv2RuntimeException(Code code) {
40 + super(code.name());
41 + this.code = code;
42 + }
43 +
44 + public Code getCode() {
45 + return this.code;
46 + }
47 +
48 + public String explain() {
49 + return (codeString == null) ? code.name() : code.name() + " " + codeString;
50 + }
51 +
52 + @Override
53 + public String toString() {
54 + return getClass().getSimpleName() + " " + explain();
55 + }
56 +
57 + public enum Code {
58 + TABLE_FULL,
59 + TABLE_INVALID_HANDLE,
60 + TABLE_EXPIRED_HANDLE,
61 + TABLE_COUNTERS_DISABLED,
62 + TABLE_METERS_DISABLED,
63 + TABLE_AGEING_DISABLED,
64 + TABLE_INVALID_TABLE_NAME,
65 + TABLE_INVALID_ACTION_NAME,
66 + TABLE_WRONG_TABLE_TYPE,
67 + TABLE_INVALID_MBR_HANDLE,
68 + TABLE_MBR_STILL_USED,
69 + TABLE_MBR_ALREADY_IN_GRP,
70 + TABLE_MBR_NOT_IN_GRP,
71 + TABLE_INVALID_GRP_HANDLE,
72 + TABLE_GRP_STILL_USED,
73 + TABLE_EMPTY_GRP,
74 + TABLE_DUPLICATE_ENTRY,
75 + TABLE_BAD_MATCH_KEY,
76 + TABLE_INVALID_METER_OPERATION,
77 + TABLE_DEFAULT_ACTION_IS_CONST,
78 + TABLE_DEFAULT_ENTRY_IS_CONST,
79 + TABLE_GENERAL_ERROR,
80 + TABLE_UNKNOWN_ERROR,
81 +
82 + DEV_MGR_ERROR_GENERAL,
83 + DEV_MGR_UNKNOWN,
84 +
85 + COUNTER_INVALID_NAME,
86 + COUNTER_INVALID_INDEX,
87 + COUNTER_ERROR_GENERAL,
88 + COUNTER_ERROR_UNKNOWN,
89 +
90 + SWAP_CONFIG_DISABLED,
91 + SWAP_ONGOING,
92 + SWAP_NO_ONGOING,
93 + SWAP_ERROR_UKNOWN,
94 +
95 + // TODO: add other codes based on autogenerated Thrift APIs
96 +
97 + OTHER
98 + }
99 +}
...@@ -22,7 +22,7 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -22,7 +22,7 @@ import static com.google.common.base.Preconditions.checkArgument;
22 import static com.google.common.base.Preconditions.checkNotNull; 22 import static com.google.common.base.Preconditions.checkNotNull;
23 23
24 /** 24 /**
25 - * Bmv2 representation of a table entry. 25 + * An entry of a match-action table in a BMv2 device.
26 */ 26 */
27 public final class Bmv2TableEntry { 27 public final class Bmv2TableEntry {
28 28
...@@ -45,7 +45,7 @@ public final class Bmv2TableEntry { ...@@ -45,7 +45,7 @@ public final class Bmv2TableEntry {
45 } 45 }
46 46
47 /** 47 /**
48 - * Returns a new Bmv2 table entry builder. 48 + * Returns a new BMv2 table entry builder.
49 * 49 *
50 * @return a new builder. 50 * @return a new builder.
51 */ 51 */
...@@ -63,7 +63,7 @@ public final class Bmv2TableEntry { ...@@ -63,7 +63,7 @@ public final class Bmv2TableEntry {
63 } 63 }
64 64
65 /** 65 /**
66 - * Returns the match key. 66 + * Returns the match key of this table entry.
67 * 67 *
68 * @return match key 68 * @return match key
69 */ 69 */
...@@ -72,7 +72,7 @@ public final class Bmv2TableEntry { ...@@ -72,7 +72,7 @@ public final class Bmv2TableEntry {
72 } 72 }
73 73
74 /** 74 /**
75 - * Returns the action. 75 + * Returns the action of this table entry.
76 * 76 *
77 * @return action 77 * @return action
78 */ 78 */
...@@ -81,7 +81,7 @@ public final class Bmv2TableEntry { ...@@ -81,7 +81,7 @@ public final class Bmv2TableEntry {
81 } 81 }
82 82
83 /** 83 /**
84 - * Returns true is the entry has a valid priority value set. 84 + * Returns true is the entry has a valid priority.
85 * 85 *
86 * @return true if priority is set, false elsewhere 86 * @return true if priority is set, false elsewhere
87 */ 87 */
...@@ -90,7 +90,7 @@ public final class Bmv2TableEntry { ...@@ -90,7 +90,7 @@ public final class Bmv2TableEntry {
90 } 90 }
91 91
92 /** 92 /**
93 - * Return the entry priority. 93 + * Return the priority of this table entry.
94 * 94 *
95 * @return priority 95 * @return priority
96 */ 96 */
...@@ -99,7 +99,7 @@ public final class Bmv2TableEntry { ...@@ -99,7 +99,7 @@ public final class Bmv2TableEntry {
99 } 99 }
100 100
101 /** 101 /**
102 - * Returns true is the entry has a valid timeout value set. 102 + * Returns true is this table entry has a valid timeout.
103 * 103 *
104 * @return true if timeout is set, false elsewhere 104 * @return true if timeout is set, false elsewhere
105 */ 105 */
...@@ -108,9 +108,9 @@ public final class Bmv2TableEntry { ...@@ -108,9 +108,9 @@ public final class Bmv2TableEntry {
108 } 108 }
109 109
110 /** 110 /**
111 - * Returns the entry timeout in fractional seconds. 111 + * Returns the timeout (in fractional seconds) of this table entry.
112 * 112 *
113 - * @return timeout 113 + * @return a timeout vale (in fractional seconds)
114 */ 114 */
115 public final double timeout() { 115 public final double timeout() {
116 return timeout; 116 return timeout;
......
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.bmv2.api.runtime;
18 +
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.base.Objects;
21 +import org.onosproject.net.DeviceId;
22 +
23 +/**
24 + * A reference to a table entry installed on a BMv2 device.
25 + */
26 +public final class Bmv2TableEntryReference {
27 +
28 +
29 + private final DeviceId deviceId;
30 + private final String tableName;
31 + private final Bmv2MatchKey matchKey;
32 +
33 + /**
34 + * Creates a new table entry reference.
35 + *
36 + * @param deviceId a device ID
37 + * @param tableName a table name
38 + * @param matchKey a match key
39 + */
40 + public Bmv2TableEntryReference(DeviceId deviceId, String tableName, Bmv2MatchKey matchKey) {
41 + this.deviceId = deviceId;
42 + this.tableName = tableName;
43 + this.matchKey = matchKey;
44 + }
45 +
46 + /**
47 + * Returns the device ID of this table entry reference.
48 + *
49 + * @return a device ID
50 + */
51 + public DeviceId deviceId() {
52 + return deviceId;
53 + }
54 +
55 + /**
56 + * Returns the name of the table of this table entry reference.
57 + *
58 + * @return a table name
59 + */
60 + public String tableName() {
61 + return tableName;
62 + }
63 +
64 + /**
65 + * Returns the match key of this table entry reference.
66 + *
67 + * @return a match key
68 + */
69 + public Bmv2MatchKey matchKey() {
70 + return matchKey;
71 + }
72 +
73 + @Override
74 + public int hashCode() {
75 + return Objects.hashCode(deviceId, tableName, matchKey);
76 + }
77 +
78 + @Override
79 + public boolean equals(Object obj) {
80 + if (this == obj) {
81 + return true;
82 + }
83 + if (obj == null || getClass() != obj.getClass()) {
84 + return false;
85 + }
86 + final Bmv2TableEntryReference other = (Bmv2TableEntryReference) obj;
87 + return Objects.equal(this.deviceId, other.deviceId)
88 + && Objects.equal(this.tableName, other.tableName)
89 + && Objects.equal(this.matchKey, other.matchKey);
90 + }
91 +
92 + @Override
93 + public String toString() {
94 + return MoreObjects.toStringHelper(this)
95 + .add("deviceId", deviceId)
96 + .add("tableName", tableName)
97 + .add("matchKey", matchKey)
98 + .toString();
99 + }
100 +}
...@@ -24,9 +24,9 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -24,9 +24,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
24 import static com.google.common.base.Preconditions.checkState; 24 import static com.google.common.base.Preconditions.checkState;
25 25
26 /** 26 /**
27 - * Representation of a Bmv2 ternary match parameter. 27 + * Representation of a BMv2 ternary match parameter.
28 */ 28 */
29 -public class Bmv2TernaryMatchParam implements Bmv2MatchParam { 29 +public final class Bmv2TernaryMatchParam implements Bmv2MatchParam {
30 30
31 private final ImmutableByteSequence value; 31 private final ImmutableByteSequence value;
32 private final ImmutableByteSequence mask; 32 private final ImmutableByteSequence mask;
......
...@@ -22,9 +22,9 @@ import com.google.common.base.MoreObjects; ...@@ -22,9 +22,9 @@ import com.google.common.base.MoreObjects;
22 import java.util.Objects; 22 import java.util.Objects;
23 23
24 /** 24 /**
25 - * Representation of a Bmv2 valid match parameter. 25 + * Representation of a BMv2 valid match parameter.
26 */ 26 */
27 -public class Bmv2ValidMatchParam implements Bmv2MatchParam { 27 +public final class Bmv2ValidMatchParam implements Bmv2MatchParam {
28 28
29 private final boolean flag; 29 private final boolean flag;
30 30
......
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
15 */ 15 */
16 16
17 /** 17 /**
18 - * Bmv2 runtime APIs. 18 + * BMv2 runtime API.
19 */ 19 */
20 package org.onosproject.bmv2.api.runtime; 20 package org.onosproject.bmv2.api.runtime;
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -14,70 +14,64 @@ ...@@ -14,70 +14,64 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.runtime; 17 +package org.onosproject.bmv2.api.service;
18 18
19 -import org.onlab.util.ImmutableByteSequence; 19 +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
20 +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
21 +import org.onosproject.net.DeviceId;
20 22
21 /** 23 /**
22 - * A server that listens for requests from a BMv2 device. 24 + * A controller of BMv2 devices.
23 */ 25 */
24 -public interface Bmv2ControlPlaneServer { 26 +public interface Bmv2Controller {
27 +
25 /** 28 /**
26 - * Default listening port. 29 + * Default port.
27 */ 30 */
28 int DEFAULT_PORT = 40123; 31 int DEFAULT_PORT = 40123;
29 32
30 /** 33 /**
31 - * Register the given hello listener, to be called each time a hello message is received from a BMv2 device. 34 + * Return an agent to operate on the given device.
32 * 35 *
33 - * @param listener a hello listener 36 + * @param deviceId a device ID
37 + * @return a BMv2 agent
38 + * @throws Bmv2RuntimeException if the agent is not available
34 */ 39 */
35 - void addHelloListener(HelloListener listener); 40 + Bmv2DeviceAgent getAgent(DeviceId deviceId) throws Bmv2RuntimeException;
36 41
37 /** 42 /**
38 - * Unregister the given hello listener. 43 + * Returns true if the given device is reachable from this controller, false otherwise.
39 * 44 *
40 - * @param listener a hello listener 45 + * @param deviceId a device ID
46 + * @return a boolean value
41 */ 47 */
42 - void removeHelloListener(HelloListener listener); 48 + boolean isReacheable(DeviceId deviceId);
43 49
44 /** 50 /**
45 - * Register the given packet listener, to be called each time a packet-in message is received from a BMv2 device. 51 + * Register the given device listener.
52 + *
53 + * @param listener a device listener
54 + */
55 + void addDeviceListener(Bmv2DeviceListener listener);
56 +
57 + /**
58 + * Unregister the given device listener.
59 + *
60 + * @param listener a device listener
61 + */
62 + void removeDeviceListener(Bmv2DeviceListener listener);
63 +
64 + /**
65 + * Register the given packet listener.
46 * 66 *
47 * @param listener a packet listener 67 * @param listener a packet listener
48 */ 68 */
49 - void addPacketListener(PacketListener listener); 69 + void addPacketListener(Bmv2PacketListener listener);
50 70
51 /** 71 /**
52 * Unregister the given packet listener. 72 * Unregister the given packet listener.
53 * 73 *
54 * @param listener a packet listener 74 * @param listener a packet listener
55 */ 75 */
56 - void removePacketListener(PacketListener listener);
57 -
58 - interface HelloListener {
59 -
60 - /**
61 - * Handles a hello message.
62 - *
63 - * @param device the BMv2 device that originated the message
64 - */
65 - void handleHello(Bmv2Device device);
66 - }
67 -
68 - interface PacketListener {
69 -
70 - /**
71 - * Handles a packet-in message.
72 - *
73 - * @param device the BMv2 device that originated the message
74 - * @param inputPort the device port where the packet was received
75 - * @param reason a reason code
76 - * @param tableId the table id that originated this packet-in
77 - * @param contextId the context id where the packet-in was originated
78 - * @param packet the packet body
79 - */
80 - void handlePacketIn(Bmv2Device device, int inputPort, long reason, int tableId, int contextId,
81 - ImmutableByteSequence packet);
82 - }
83 -}
...\ No newline at end of file ...\ No newline at end of file
76 + void removePacketListener(Bmv2PacketListener listener);
77 +}
......
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.bmv2.api.service;
18 +
19 +import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
20 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
21 +import org.onosproject.net.DeviceId;
22 +
23 +/**
24 + * A service for managing BMv2 device contexts.
25 + */
26 +public interface Bmv2DeviceContextService {
27 +
28 + // TODO: handle the potential configuration states (e.g. RUNNING, SWAP_REQUESTED, etc.)
29 +
30 + /**
31 + * Returns the context of a given device. The context returned is the last one for which a configuration swap was
32 + * triggered, hence there's no guarantees that the device is enforcing the returned context's configuration at the
33 + * time of the call.
34 + *
35 + * @param deviceId a device ID
36 + * @return a BMv2 device context
37 + */
38 + Bmv2DeviceContext getContext(DeviceId deviceId);
39 +
40 + /**
41 + * Triggers a configuration swap on a given device.
42 + *
43 + * @param deviceId a device ID
44 + * @param context a BMv2 device context
45 + */
46 + void triggerConfigurationSwap(DeviceId deviceId, Bmv2DeviceContext context);
47 +
48 + /**
49 + * Binds the given interpreter with the given class loader so that other ONOS instances in the cluster can properly
50 + * load the interpreter.
51 + *
52 + * @param interpreterClass an interpreter class
53 + * @param loader a class loader
54 + */
55 + void registerInterpreterClassLoader(Class<? extends Bmv2Interpreter> interpreterClass, ClassLoader loader);
56 +
57 + /**
58 + * Notifies this service that a given device has been updated, meaning a potential context change.
59 + * It returns true if the device configuration is the same as the last for which a swap was triggered, false
60 + * otherwise. In the last case, the service will asynchronously trigger a swap to the last
61 + * configuration stored by this service. If no swap has already been triggered then a default configuration will be
62 + * applied.
63 + *
64 + * @param deviceId a device ID
65 + * @return a boolean value
66 + */
67 + boolean notifyDeviceChange(DeviceId deviceId);
68 +}
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.bmv2.api.service;
18 +
19 +import org.onosproject.bmv2.api.runtime.Bmv2Device;
20 +
21 +/**
22 + * A listener of BMv2 device events.
23 + */
24 +public interface Bmv2DeviceListener {
25 +
26 + /**
27 + * Handles a hello message.
28 + *
29 + * @param device the BMv2 device that originated the message
30 + * @param instanceId the ID of the BMv2 process instance
31 + * @param jsonConfigMd5 the MD5 sum of the JSON configuration currently running on the device
32 + */
33 + void handleHello(Bmv2Device device, int instanceId, String jsonConfigMd5);
34 +}
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.bmv2.api.service;
18 +
19 +import org.onlab.util.ImmutableByteSequence;
20 +import org.onosproject.bmv2.api.runtime.Bmv2Device;
21 +
22 +/**
23 + * A listener of BMv2 packet events.
24 + */
25 +public interface Bmv2PacketListener {
26 +
27 + /**
28 + * Handles a packet-in message.
29 + *
30 + * @param device the BMv2 device that originated the message
31 + * @param inputPort the device port where the packet was received
32 + * @param reason a reason code
33 + * @param tableId the ID of table that originated this packet-in
34 + * @param contextId the ID of the BMv2 context where the packet-in was originated
35 + * @param packet the packet raw data
36 + */
37 + void handlePacketIn(Bmv2Device device, int inputPort, long reason, int tableId, int contextId,
38 + ImmutableByteSequence packet);
39 +}
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.bmv2.api.service;
18 +
19 +
20 +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
21 +import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper;
22 +import org.onosproject.bmv2.api.runtime.Bmv2ParsedTableEntry;
23 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference;
24 +import org.onosproject.net.DeviceId;
25 +
26 +import java.util.List;
27 +
28 +/**
29 + * A service for managing BMv2 table entries.
30 + */
31 +public interface Bmv2TableEntryService {
32 +
33 + /**
34 + * Returns a flow rule translator.
35 + *
36 + * @return a flow rule translator
37 + */
38 + Bmv2FlowRuleTranslator getFlowRuleTranslator();
39 +
40 + /**
41 + * Returns a list of table entries installed in the given device and table. The table entries returned are the
42 + * result of a table dump parse.
43 + *
44 + * @param deviceId a device id
45 + * @param tableName a table name
46 + * @return a list of parsed table entries
47 + */
48 + List<Bmv2ParsedTableEntry> getTableEntries(DeviceId deviceId, String tableName);
49 +
50 + /**
51 + * Binds the given ONOS flow rule with a BMv2 table entry reference.
52 + *
53 + * @param entryRef a table entry reference
54 + * @param rule a BMv2 flow rule wrapper
55 + */
56 + void bindEntryReference(Bmv2TableEntryReference entryRef, Bmv2FlowRuleWrapper rule);
57 +
58 + /**
59 + * Returns the ONOS flow rule associated with the given BMv2 table entry reference, or null if there's no such a
60 + * mapping.
61 + *
62 + * @param entryRef a table entry reference
63 + * @return a BMv2 flow rule wrapper
64 + */
65 + Bmv2FlowRuleWrapper lookupEntryReference(Bmv2TableEntryReference entryRef);
66 +
67 + /**
68 + * Removes any flow rule previously bound with a given BMv2 table entry reference.
69 + *
70 + * @param entryRef a table entry reference
71 + */
72 + void unbindEntryReference(Bmv2TableEntryReference entryRef);
73 +}
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 +/**
18 + * BMv2 service API.
19 + */
20 +package org.onosproject.bmv2.api.service;
...\ No newline at end of file ...\ No newline at end of file
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.bmv2.api.utils;
18 +
19 +import org.onlab.util.HexString;
20 +import org.onlab.util.ImmutableByteSequence;
21 +
22 +import java.util.Arrays;
23 +
24 +import static com.google.common.base.Preconditions.checkArgument;
25 +import static com.google.common.base.Preconditions.checkNotNull;
26 +
27 +/**
28 + * Collection of util methods to deal with flow rule translation.
29 + */
30 +public final class Bmv2TranslatorUtils {
31 +
32 + private Bmv2TranslatorUtils() {
33 + // Ban constructor.
34 + }
35 +
36 + /**
37 + * Returns the number of bytes necessary to contain the given bit-width.
38 + *
39 + * @param bitWidth an integer value
40 + * @return an integer value
41 + */
42 + public static int roundToBytes(int bitWidth) {
43 + return (int) Math.ceil((double) bitWidth / 8);
44 + }
45 +
46 + /**
47 + * Trims or expands the given byte sequence so to fit a given bit-width.
48 + *
49 + * @param original a byte sequence
50 + * @param bitWidth an integer value
51 + * @return a new byte sequence
52 + * @throws ByteSequenceFitException if the byte sequence cannot be fitted in the given bit-width
53 + */
54 + public static ImmutableByteSequence fitByteSequence(ImmutableByteSequence original, int bitWidth)
55 + throws ByteSequenceFitException {
56 +
57 + checkNotNull(original, "byte sequence cannot be null");
58 + checkArgument(bitWidth > 0, "byte width must a non-zero positive integer");
59 +
60 + int newByteWidth = roundToBytes(bitWidth);
61 +
62 + if (original.size() == newByteWidth) {
63 + // nothing to do
64 + return original;
65 + }
66 +
67 + byte[] originalBytes = original.asArray();
68 +
69 + if (newByteWidth > original.size()) {
70 + // pad missing bytes with zeros
71 + return ImmutableByteSequence.copyFrom(Arrays.copyOf(originalBytes, newByteWidth));
72 + }
73 +
74 + byte[] newBytes = new byte[newByteWidth];
75 + // ImmutableByteSequence is always big-endian, hence check the array in reverse order
76 + int diff = originalBytes.length - newByteWidth;
77 + for (int i = originalBytes.length - 1; i > 0; i--) {
78 + byte ob = originalBytes[i]; // original byte
79 + byte nb; // new byte
80 + if (i > diff) {
81 + // no need to truncate, copy as is
82 + nb = ob;
83 + } else if (i == diff) {
84 + // truncate this byte, check if we're loosing something
85 + byte mask = (byte) ((1 >> ((bitWidth % 8) + 1)) - 1);
86 + if ((ob & ~mask) != 0) {
87 + throw new ByteSequenceFitException(originalBytes, bitWidth);
88 + } else {
89 + nb = (byte) (ob & mask);
90 + }
91 + } else {
92 + // drop this byte, check if we're loosing something
93 + if (originalBytes[i] != 0) {
94 + throw new ByteSequenceFitException(originalBytes, bitWidth);
95 + } else {
96 + continue;
97 + }
98 + }
99 + newBytes[i - diff] = nb;
100 + }
101 +
102 + return ImmutableByteSequence.copyFrom(newBytes);
103 + }
104 +
105 + /**
106 + * A byte sequence fit exception.
107 + */
108 + public static class ByteSequenceFitException extends Exception {
109 + public ByteSequenceFitException(byte[] bytes, int bitWidth) {
110 + super("cannot fit " + HexString.toHexString(bytes) + " into a " + bitWidth + " bits value");
111 + }
112 + }
113 +}
...@@ -14,45 +14,7 @@ ...@@ -14,45 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.runtime;
18 -
19 -import com.google.common.base.MoreObjects;
20 -import org.p4.bmv2.thrift.DevMgrPortInfo;
21 -
22 -import java.util.Collections;
23 -import java.util.Map;
24 -
25 /** 17 /**
26 - * Bmv2 representation of a switch port information. 18 + * BMv2 utils.
27 */ 19 */
28 -public final class Bmv2PortInfo { 20 +package org.onosproject.bmv2.api.utils;
29 -
30 - private final DevMgrPortInfo portInfo;
31 -
32 - public Bmv2PortInfo(DevMgrPortInfo portInfo) {
33 - this.portInfo = portInfo;
34 - }
35 -
36 - public final String ifaceName() {
37 - return portInfo.getIface_name();
38 - }
39 -
40 - public final int portNumber() {
41 - return portInfo.getPort_num();
42 - }
43 -
44 - public final boolean isUp() {
45 - return portInfo.isIs_up();
46 - }
47 -
48 - public final Map<String, String> getExtraProperties() {
49 - return Collections.unmodifiableMap(portInfo.getExtra());
50 - }
51 -
52 - @Override
53 - public final String toString() {
54 - return MoreObjects.toStringHelper(this)
55 - .addValue(portInfo)
56 - .toString();
57 - }
58 -}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -14,11 +14,12 @@ ...@@ -14,11 +14,12 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.api.context;
18 18
19 import com.eclipsesource.json.Json; 19 import com.eclipsesource.json.Json;
20 import com.eclipsesource.json.JsonObject; 20 import com.eclipsesource.json.JsonObject;
21 import com.google.common.testing.EqualsTester; 21 import com.google.common.testing.EqualsTester;
22 +import org.hamcrest.collection.IsIterableContainingInOrder;
22 import org.junit.Before; 23 import org.junit.Before;
23 import org.junit.Test; 24 import org.junit.Test;
24 import org.onosproject.bmv2.api.runtime.Bmv2MatchParam; 25 import org.onosproject.bmv2.api.runtime.Bmv2MatchParam;
...@@ -30,13 +31,12 @@ import static org.hamcrest.CoreMatchers.notNullValue; ...@@ -30,13 +31,12 @@ import static org.hamcrest.CoreMatchers.notNullValue;
30 import static org.hamcrest.MatcherAssert.assertThat; 31 import static org.hamcrest.MatcherAssert.assertThat;
31 import static org.hamcrest.Matchers.hasSize; 32 import static org.hamcrest.Matchers.hasSize;
32 import static org.hamcrest.Matchers.is; 33 import static org.hamcrest.Matchers.is;
33 -import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
34 import static org.hamcrest.core.IsEqual.equalTo; 34 import static org.hamcrest.core.IsEqual.equalTo;
35 35
36 /** 36 /**
37 - * BMv2 model parser test suite. 37 + * BMv2 JSON configuration parser test.
38 */ 38 */
39 -public class Bmv2ModelTest { 39 +public class Bmv2ConfigurationTest {
40 40
41 private JsonObject json; 41 private JsonObject json;
42 private JsonObject json2; 42 private JsonObject json2;
...@@ -44,28 +44,28 @@ public class Bmv2ModelTest { ...@@ -44,28 +44,28 @@ public class Bmv2ModelTest {
44 @Before 44 @Before
45 public void setUp() throws Exception { 45 public void setUp() throws Exception {
46 json = Json.parse(new BufferedReader(new InputStreamReader( 46 json = Json.parse(new BufferedReader(new InputStreamReader(
47 - this.getClass().getResourceAsStream("/simple_pipeline.json")))).asObject(); 47 + this.getClass().getResourceAsStream("/simple.json")))).asObject();
48 json2 = Json.parse(new BufferedReader(new InputStreamReader( 48 json2 = Json.parse(new BufferedReader(new InputStreamReader(
49 - this.getClass().getResourceAsStream("/simple_pipeline.json")))).asObject(); 49 + this.getClass().getResourceAsStream("/simple.json")))).asObject();
50 } 50 }
51 51
52 @Test 52 @Test
53 public void testParse() throws Exception { 53 public void testParse() throws Exception {
54 - Bmv2Model model = Bmv2Model.parse(json); 54 + Bmv2Configuration config = Bmv2DefaultConfiguration.parse(json);
55 - Bmv2Model model2 = Bmv2Model.parse(json2); 55 + Bmv2Configuration config2 = Bmv2DefaultConfiguration.parse(json2);
56 56
57 new EqualsTester() 57 new EqualsTester()
58 - .addEqualityGroup(model, model2) 58 + .addEqualityGroup(config, config2)
59 .testEquals(); 59 .testEquals();
60 60
61 /* Check header types */ 61 /* Check header types */
62 - Bmv2ModelHeaderType stdMetaT = model.headerType("standard_metadata_t"); 62 + Bmv2HeaderTypeModel stdMetaT = config.headerType("standard_metadata_t");
63 - Bmv2ModelHeaderType ethernetT = model.headerType("ethernet_t"); 63 + Bmv2HeaderTypeModel ethernetT = config.headerType("ethernet_t");
64 - Bmv2ModelHeaderType intrinsicMetaT = model.headerType("intrinsic_metadata_t"); 64 + Bmv2HeaderTypeModel intrinsicMetaT = config.headerType("intrinsic_metadata_t");
65 65
66 - Bmv2ModelHeaderType stdMetaT2 = model2.headerType("standard_metadata_t"); 66 + Bmv2HeaderTypeModel stdMetaT2 = config2.headerType("standard_metadata_t");
67 - Bmv2ModelHeaderType ethernetT2 = model2.headerType("ethernet_t"); 67 + Bmv2HeaderTypeModel ethernetT2 = config2.headerType("ethernet_t");
68 - Bmv2ModelHeaderType intrinsicMetaT2 = model2.headerType("intrinsic_metadata_t"); 68 + Bmv2HeaderTypeModel intrinsicMetaT2 = config2.headerType("intrinsic_metadata_t");
69 69
70 new EqualsTester() 70 new EqualsTester()
71 .addEqualityGroup(stdMetaT, stdMetaT2) 71 .addEqualityGroup(stdMetaT, stdMetaT2)
...@@ -88,7 +88,7 @@ public class Bmv2ModelTest { ...@@ -88,7 +88,7 @@ public class Bmv2ModelTest {
88 88
89 // check that fields are in order 89 // check that fields are in order
90 assertThat("Incorrect order for header type fields", 90 assertThat("Incorrect order for header type fields",
91 - stdMetaT.fields(), contains( 91 + stdMetaT.fields(), IsIterableContainingInOrder.contains(
92 stdMetaT.field("ingress_port"), 92 stdMetaT.field("ingress_port"),
93 stdMetaT.field("packet_length"), 93 stdMetaT.field("packet_length"),
94 stdMetaT.field("egress_spec"), 94 stdMetaT.field("egress_spec"),
...@@ -99,13 +99,13 @@ public class Bmv2ModelTest { ...@@ -99,13 +99,13 @@ public class Bmv2ModelTest {
99 stdMetaT.field("_padding"))); 99 stdMetaT.field("_padding")));
100 100
101 /* Check actions */ 101 /* Check actions */
102 - Bmv2ModelAction floodAction = model.action("flood"); 102 + Bmv2ActionModel floodAction = config.action("flood");
103 - Bmv2ModelAction dropAction = model.action("_drop"); 103 + Bmv2ActionModel dropAction = config.action("_drop");
104 - Bmv2ModelAction fwdAction = model.action("fwd"); 104 + Bmv2ActionModel fwdAction = config.action("set_egress_port");
105 105
106 - Bmv2ModelAction floodAction2 = model2.action("flood"); 106 + Bmv2ActionModel floodAction2 = config2.action("flood");
107 - Bmv2ModelAction dropAction2 = model2.action("_drop"); 107 + Bmv2ActionModel dropAction2 = config2.action("_drop");
108 - Bmv2ModelAction fwdAction2 = model2.action("fwd"); 108 + Bmv2ActionModel fwdAction2 = config2.action("set_egress_port");
109 109
110 new EqualsTester() 110 new EqualsTester()
111 .addEqualityGroup(floodAction, floodAction2) 111 .addEqualityGroup(floodAction, floodAction2)
...@@ -133,8 +133,8 @@ public class Bmv2ModelTest { ...@@ -133,8 +133,8 @@ public class Bmv2ModelTest {
133 fwdAction.runtimeData("port").bitWidth(), is(equalTo(9))); 133 fwdAction.runtimeData("port").bitWidth(), is(equalTo(9)));
134 134
135 /* Check tables */ 135 /* Check tables */
136 - Bmv2ModelTable table0 = model.table(0); 136 + Bmv2TableModel table0 = config.table(0);
137 - Bmv2ModelTable table02 = model2.table(0); 137 + Bmv2TableModel table02 = config2.table(0);
138 138
139 new EqualsTester() 139 new EqualsTester()
140 .addEqualityGroup(table0, table02) 140 .addEqualityGroup(table0, table02)
......
1 { 1 {
2 - "header_types": [ 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 - "name": "cpu_header_t",
89 - "id": 3,
90 - "fields": [
91 - [
92 - "device",
93 - 8
94 - ],
95 - [
96 - "reason",
97 - 8
98 - ]
99 - ],
100 - "length_exp": null,
101 - "max_length": null
102 - }
103 - ],
104 - "headers": [
105 - {
106 - "name": "standard_metadata",
107 - "id": 0,
108 - "header_type": "standard_metadata_t",
109 - "metadata": true
110 - },
111 - {
112 - "name": "ethernet",
113 - "id": 1,
114 - "header_type": "ethernet_t",
115 - "metadata": false
116 - },
117 - {
118 - "name": "intrinsic_metadata",
119 - "id": 2,
120 - "header_type": "intrinsic_metadata_t",
121 - "metadata": true
122 - },
123 - {
124 - "name": "cpu_header",
125 - "id": 3,
126 - "header_type": "cpu_header_t",
127 - "metadata": false
128 - }
129 - ],
130 - "header_stacks": [],
131 - "parsers": [
132 - {
133 - "name": "parser",
134 - "id": 0,
135 - "init_state": "start",
136 - "parse_states": [
137 { 3 {
138 - "name": "start", 4 + "name": "standard_metadata_t",
139 - "id": 0, 5 + "id": 0,
140 - "parser_ops": [], 6 + "fields": [
141 - "transition_key": [ 7 + [
142 - { 8 + "ingress_port",
143 - "type": "lookahead", 9 + 9
144 - "value": [ 10 + ],
145 - 0, 11 + [
146 - 64 12 + "packet_length",
147 - ] 13 + 32
148 - } 14 + ],
149 - ], 15 + [
150 - "transitions": [ 16 + "egress_spec",
151 - { 17 + 9
152 - "value": "0x0000000000000000", 18 + ],
153 - "mask": null, 19 + [
154 - "next_state": "parse_cpu_header" 20 + "egress_port",
155 - }, 21 + 9
156 - { 22 + ],
157 - "value": "default", 23 + [
158 - "mask": null, 24 + "egress_instance",
159 - "next_state": "parse_ethernet" 25 + 32
160 - } 26 + ],
161 - ] 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
162 }, 42 },
163 { 43 {
164 - "name": "parse_cpu_header", 44 + "name": "ethernet_t",
165 - "id": 1, 45 + "id": 1,
166 - "parser_ops": [ 46 + "fields": [
167 - { 47 + [
168 - "op": "extract", 48 + "dstAddr",
169 - "parameters": [ 49 + 48
170 - { 50 + ],
171 - "type": "regular", 51 + [
172 - "value": "cpu_header" 52 + "srcAddr",
173 - } 53 + 48
174 - ] 54 + ],
175 - } 55 + [
176 - ], 56 + "etherType",
177 - "transition_key": [], 57 + 16
178 - "transitions": [ 58 + ]
179 - { 59 + ],
180 - "value": "default", 60 + "length_exp": null,
181 - "mask": null, 61 + "max_length": null
182 - "next_state": "parse_ethernet"
183 - }
184 - ]
185 }, 62 },
186 { 63 {
187 - "name": "parse_ethernet", 64 + "name": "intrinsic_metadata_t",
188 - "id": 2, 65 + "id": 2,
189 - "parser_ops": [ 66 + "fields": [
190 - { 67 + [
191 - "op": "extract", 68 + "ingress_global_timestamp",
192 - "parameters": [ 69 + 32
193 - { 70 + ],
194 - "type": "regular", 71 + [
195 - "value": "ethernet" 72 + "lf_field_list",
196 - } 73 + 32
197 - ] 74 + ],
198 - } 75 + [
199 - ], 76 + "mcast_grp",
200 - "transition_key": [], 77 + 16
201 - "transitions": [ 78 + ],
202 - { 79 + [
203 - "value": "default", 80 + "egress_rid",
204 - "mask": null, 81 + 16
205 - "next_state": null 82 + ]
206 - } 83 + ],
207 - ] 84 + "length_exp": null,
85 + "max_length": null
208 } 86 }
209 - ] 87 + ],
210 - } 88 + "headers": [
211 - ],
212 - "deparsers": [
213 - {
214 - "name": "deparser",
215 - "id": 0,
216 - "order": [
217 - "cpu_header",
218 - "ethernet"
219 - ]
220 - }
221 - ],
222 - "meter_arrays": [],
223 - "actions": [
224 - {
225 - "name": "flood",
226 - "id": 0,
227 - "runtime_data": [],
228 - "primitives": [
229 { 89 {
230 - "op": "modify_field", 90 + "name": "standard_metadata",
231 - "parameters": [ 91 + "id": 0,
232 - { 92 + "header_type": "standard_metadata_t",
233 - "type": "field", 93 + "metadata": true
234 - "value": [ 94 + },
235 - "intrinsic_metadata",
236 - "mcast_grp"
237 - ]
238 - },
239 - {
240 - "type": "field",
241 - "value": [
242 - "standard_metadata",
243 - "ingress_port"
244 - ]
245 - }
246 - ]
247 - }
248 - ]
249 - },
250 - {
251 - "name": "_drop",
252 - "id": 1,
253 - "runtime_data": [],
254 - "primitives": [
255 { 95 {
256 - "op": "modify_field", 96 + "name": "ethernet",
257 - "parameters": [ 97 + "id": 1,
258 - { 98 + "header_type": "ethernet_t",
259 - "type": "field", 99 + "metadata": false
260 - "value": [ 100 + },
261 - "standard_metadata",
262 - "egress_spec"
263 - ]
264 - },
265 - {
266 - "type": "hexstr",
267 - "value": "0x1ff"
268 - }
269 - ]
270 - }
271 - ]
272 - },
273 - {
274 - "name": "fwd",
275 - "id": 2,
276 - "runtime_data": [
277 { 101 {
278 - "name": "port", 102 + "name": "intrinsic_metadata",
279 - "bitwidth": 9 103 + "id": 2,
104 + "header_type": "intrinsic_metadata_t",
105 + "metadata": true
280 } 106 }
281 - ], 107 + ],
282 - "primitives": [ 108 + "header_stacks": [],
109 + "parsers": [
283 { 110 {
284 - "op": "modify_field", 111 + "name": "parser",
285 - "parameters": [ 112 + "id": 0,
286 - { 113 + "init_state": "start",
287 - "type": "field", 114 + "parse_states": [
288 - "value": [ 115 + {
289 - "standard_metadata", 116 + "name": "start",
290 - "egress_spec" 117 + "id": 0,
291 - ] 118 + "parser_ops": [],
292 - }, 119 + "transition_key": [],
293 - { 120 + "transitions": [
294 - "type": "runtime_data", 121 + {
295 - "value": 0 122 + "value": "default",
296 - } 123 + "mask": null,
297 - ] 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 + ]
298 } 152 }
299 - ] 153 + ],
300 - }, 154 + "deparsers": [
301 - {
302 - "name": "send_to_cpu",
303 - "id": 3,
304 - "runtime_data": [
305 - {
306 - "name": "device",
307 - "bitwidth": 8
308 - },
309 { 155 {
310 - "name": "reason", 156 + "name": "deparser",
311 - "bitwidth": 8 157 + "id": 0,
158 + "order": [
159 + "ethernet"
160 + ]
312 } 161 }
313 - ], 162 + ],
314 - "primitives": [ 163 + "meter_arrays": [],
164 + "actions": [
315 { 165 {
316 - "op": "add_header", 166 + "name": "set_egress_port",
317 - "parameters": [ 167 + "id": 0,
318 - { 168 + "runtime_data": [
319 - "type": "header", 169 + {
320 - "value": "cpu_header" 170 + "name": "port",
321 - } 171 + "bitwidth": 9
322 - ] 172 + }
173 + ],
174 + "primitives": [
175 + {
176 + "op": "modify_field",
177 + "parameters": [
178 + {
179 + "type": "field",
180 + "value": [
181 + "standard_metadata",
182 + "egress_spec"
183 + ]
184 + },
185 + {
186 + "type": "runtime_data",
187 + "value": 0
188 + }
189 + ]
190 + }
191 + ]
323 }, 192 },
324 { 193 {
325 - "op": "modify_field", 194 + "name": "_drop",
326 - "parameters": [ 195 + "id": 1,
327 - { 196 + "runtime_data": [],
328 - "type": "field", 197 + "primitives": [
329 - "value": [ 198 + {
330 - "cpu_header", 199 + "op": "modify_field",
331 - "device" 200 + "parameters": [
332 - ] 201 + {
333 - }, 202 + "type": "field",
334 - { 203 + "value": [
335 - "type": "runtime_data", 204 + "standard_metadata",
336 - "value": 0 205 + "egress_spec"
337 - } 206 + ]
338 - ] 207 + },
208 + {
209 + "type": "hexstr",
210 + "value": "0x1ff"
211 + }
212 + ]
213 + }
214 + ]
339 }, 215 },
340 { 216 {
341 - "op": "modify_field", 217 + "name": "flood",
342 - "parameters": [ 218 + "id": 2,
343 - { 219 + "runtime_data": [],
344 - "type": "field", 220 + "primitives": [
345 - "value": [ 221 + {
346 - "cpu_header", 222 + "op": "modify_field",
347 - "reason" 223 + "parameters": [
348 - ] 224 + {
349 - }, 225 + "type": "field",
350 - { 226 + "value": [
351 - "type": "runtime_data", 227 + "intrinsic_metadata",
352 - "value": 1 228 + "mcast_grp"
353 - } 229 + ]
354 - ] 230 + },
231 + {
232 + "type": "field",
233 + "value": [
234 + "standard_metadata",
235 + "ingress_port"
236 + ]
237 + }
238 + ]
239 + }
240 + ]
355 }, 241 },
356 { 242 {
357 - "op": "modify_field", 243 + "name": "send_to_cpu",
358 - "parameters": [ 244 + "id": 3,
359 - { 245 + "runtime_data": [],
360 - "type": "field", 246 + "primitives": [
361 - "value": [ 247 + {
362 - "standard_metadata", 248 + "op": "modify_field",
363 - "egress_spec" 249 + "parameters": [
364 - ] 250 + {
365 - }, 251 + "type": "field",
366 - { 252 + "value": [
367 - "type": "hexstr", 253 + "standard_metadata",
368 - "value": "0xfa" 254 + "egress_spec"
369 - } 255 + ]
370 - ] 256 + },
257 + {
258 + "type": "hexstr",
259 + "value": "0xff"
260 + }
261 + ]
262 + }
263 + ]
371 } 264 }
372 - ] 265 + ],
373 - } 266 + "pipelines": [
374 - ],
375 - "pipelines": [
376 - {
377 - "name": "ingress",
378 - "id": 0,
379 - "init_table": "table0",
380 - "tables": [
381 { 267 {
382 - "name": "table0", 268 + "name": "ingress",
383 - "id": 0, 269 + "id": 0,
384 - "match_type": "ternary", 270 + "init_table": "table0",
385 - "type": "simple", 271 + "tables": [
386 - "max_size": 16384, 272 + {
387 - "with_counters": false, 273 + "name": "table0",
388 - "direct_meters": null, 274 + "id": 0,
389 - "support_timeout": false, 275 + "match_type": "ternary",
390 - "key": [ 276 + "type": "simple",
391 - { 277 + "max_size": 16384,
392 - "match_type": "ternary", 278 + "with_counters": false,
393 - "target": [ 279 + "direct_meters": null,
394 - "standard_metadata", 280 + "support_timeout": false,
395 - "ingress_port" 281 + "key": [
396 - ], 282 + {
397 - "mask": null 283 + "match_type": "ternary",
398 - }, 284 + "target": [
399 - { 285 + "standard_metadata",
400 - "match_type": "ternary", 286 + "ingress_port"
401 - "target": [ 287 + ],
402 - "ethernet", 288 + "mask": null
403 - "dstAddr" 289 + },
404 - ], 290 + {
405 - "mask": null 291 + "match_type": "ternary",
406 - }, 292 + "target": [
407 - { 293 + "ethernet",
408 - "match_type": "ternary", 294 + "dstAddr"
409 - "target": [ 295 + ],
410 - "ethernet", 296 + "mask": null
411 - "srcAddr" 297 + },
412 - ], 298 + {
413 - "mask": null 299 + "match_type": "ternary",
414 - }, 300 + "target": [
415 - { 301 + "ethernet",
416 - "match_type": "ternary", 302 + "srcAddr"
417 - "target": [ 303 + ],
418 - "ethernet", 304 + "mask": null
419 - "etherType" 305 + },
420 - ], 306 + {
421 - "mask": null 307 + "match_type": "ternary",
422 - } 308 + "target": [
423 - ], 309 + "ethernet",
424 - "actions": [ 310 + "etherType"
425 - "fwd", 311 + ],
426 - "flood", 312 + "mask": null
427 - "send_to_cpu", 313 + }
428 - "_drop" 314 + ],
429 - ], 315 + "actions": [
430 - "next_tables": { 316 + "set_egress_port",
431 - "fwd": null, 317 + "flood",
432 - "flood": null, 318 + "send_to_cpu",
433 - "send_to_cpu": null, 319 + "_drop"
434 - "_drop": null 320 + ],
435 - }, 321 + "next_tables": {
436 - "default_action": null 322 + "set_egress_port": null,
323 + "flood": null,
324 + "send_to_cpu": 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": []
437 } 339 }
438 - ],
439 - "conditionals": []
440 - },
441 - {
442 - "name": "egress",
443 - "id": 1,
444 - "init_table": null,
445 - "tables": [],
446 - "conditionals": []
447 - }
448 - ],
449 - "calculations": [],
450 - "checksums": [],
451 - "learn_lists": [],
452 - "field_lists": [],
453 - "counter_arrays": [],
454 - "register_arrays": [],
455 - "force_arith": [
456 - [
457 - "standard_metadata",
458 - "ingress_port"
459 - ],
460 - [
461 - "standard_metadata",
462 - "packet_length"
463 - ],
464 - [
465 - "standard_metadata",
466 - "egress_spec"
467 - ],
468 - [
469 - "standard_metadata",
470 - "egress_port"
471 - ],
472 - [
473 - "standard_metadata",
474 - "egress_instance"
475 - ],
476 - [
477 - "standard_metadata",
478 - "instance_type"
479 - ],
480 - [
481 - "standard_metadata",
482 - "clone_spec"
483 - ],
484 - [
485 - "standard_metadata",
486 - "_padding"
487 - ],
488 - [
489 - "intrinsic_metadata",
490 - "ingress_global_timestamp"
491 - ],
492 - [
493 - "intrinsic_metadata",
494 - "lf_field_list"
495 ], 340 ],
496 - [ 341 + "calculations": [],
497 - "intrinsic_metadata", 342 + "checksums": [],
498 - "mcast_grp" 343 + "learn_lists": [],
499 - ], 344 + "field_lists": [],
500 - [ 345 + "counter_arrays": [],
501 - "intrinsic_metadata", 346 + "register_arrays": [],
502 - "egress_rid" 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 + ]
503 ] 396 ]
504 - ]
505 } 397 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <parent>
22 + <artifactId>onos-bmv2-protocol</artifactId>
23 + <groupId>org.onosproject</groupId>
24 + <version>1.6.0-SNAPSHOT</version>
25 + </parent>
26 + <modelVersion>4.0.0</modelVersion>
27 +
28 + <artifactId>onos-bmv2-protocol-ctl</artifactId>
29 +
30 + <packaging>bundle</packaging>
31 +
32 + <dependencies>
33 + <dependency>
34 + <groupId>org.apache.thrift</groupId>
35 + <artifactId>libthrift</artifactId>
36 + <version>0.9.3</version>
37 + </dependency>
38 + <dependency>
39 + <groupId>org.onosproject</groupId>
40 + <artifactId>onos-bmv2-protocol-api</artifactId>
41 + <version>${project.version}</version>
42 + </dependency>
43 + <dependency>
44 + <groupId>org.onosproject</groupId>
45 + <artifactId>onos-bmv2-protocol-thrift-api</artifactId>
46 + <version>${project.version}</version>
47 + </dependency>
48 + <dependency>
49 + <groupId>org.apache.felix</groupId>
50 + <artifactId>org.apache.felix.scr.annotations</artifactId>
51 + </dependency>
52 + <dependency>
53 + <groupId>org.onosproject</groupId>
54 + <artifactId>onos-core-serializers</artifactId>
55 + <version>${project.version}</version>
56 + </dependency>
57 + </dependencies>
58 +
59 + <build>
60 + <plugins>
61 + <plugin>
62 + <groupId>org.apache.felix</groupId>
63 + <artifactId>maven-scr-plugin</artifactId>
64 + </plugin>
65 + <plugin>
66 + <groupId>org.onosproject</groupId>
67 + <artifactId>onos-maven-plugin</artifactId>
68 + </plugin>
69 + </plugins>
70 + </build>
71 +
72 +
73 +</project>
...\ No newline at end of file ...\ No newline at end of file
...@@ -16,7 +16,13 @@ ...@@ -16,7 +16,13 @@
16 16
17 package org.onosproject.bmv2.ctl; 17 package org.onosproject.bmv2.ctl;
18 18
19 +import com.google.common.cache.CacheBuilder;
20 +import com.google.common.cache.CacheLoader;
21 +import com.google.common.cache.LoadingCache;
22 +import com.google.common.cache.RemovalListener;
23 +import com.google.common.cache.RemovalNotification;
19 import com.google.common.collect.Maps; 24 import com.google.common.collect.Maps;
25 +import org.apache.commons.lang3.tuple.Pair;
20 import org.apache.felix.scr.annotations.Activate; 26 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 27 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 28 import org.apache.felix.scr.annotations.Deactivate;
...@@ -25,108 +31,189 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -25,108 +31,189 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.apache.felix.scr.annotations.Service; 31 import org.apache.felix.scr.annotations.Service;
26 import org.apache.thrift.TException; 32 import org.apache.thrift.TException;
27 import org.apache.thrift.TProcessor; 33 import org.apache.thrift.TProcessor;
34 +import org.apache.thrift.protocol.TBinaryProtocol;
35 +import org.apache.thrift.protocol.TMultiplexedProtocol;
28 import org.apache.thrift.protocol.TProtocol; 36 import org.apache.thrift.protocol.TProtocol;
29 import org.apache.thrift.server.TThreadPoolServer; 37 import org.apache.thrift.server.TThreadPoolServer;
30 import org.apache.thrift.transport.TServerSocket; 38 import org.apache.thrift.transport.TServerSocket;
31 import org.apache.thrift.transport.TServerTransport; 39 import org.apache.thrift.transport.TServerTransport;
32 import org.apache.thrift.transport.TSocket; 40 import org.apache.thrift.transport.TSocket;
41 +import org.apache.thrift.transport.TTransport;
33 import org.apache.thrift.transport.TTransportException; 42 import org.apache.thrift.transport.TTransportException;
34 import org.onlab.util.ImmutableByteSequence; 43 import org.onlab.util.ImmutableByteSequence;
35 -import org.onosproject.bmv2.api.runtime.Bmv2ControlPlaneServer; 44 +import org.onosproject.bmv2.api.service.Bmv2Controller;
36 import org.onosproject.bmv2.api.runtime.Bmv2Device; 45 import org.onosproject.bmv2.api.runtime.Bmv2Device;
46 +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
47 +import org.onosproject.bmv2.api.service.Bmv2DeviceListener;
48 +import org.onosproject.bmv2.api.service.Bmv2PacketListener;
49 +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
50 +import org.onosproject.bmv2.thriftapi.ControlPlaneService;
51 +import org.onosproject.bmv2.thriftapi.SimpleSwitch;
52 +import org.onosproject.bmv2.thriftapi.Standard;
37 import org.onosproject.core.CoreService; 53 import org.onosproject.core.CoreService;
38 -import org.p4.bmv2.thrift.ControlPlaneService; 54 +import org.onosproject.net.DeviceId;
39 import org.slf4j.Logger; 55 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory; 56 import org.slf4j.LoggerFactory;
41 57
42 import java.nio.ByteBuffer; 58 import java.nio.ByteBuffer;
59 +import java.util.List;
43 import java.util.Set; 60 import java.util.Set;
44 import java.util.concurrent.ConcurrentMap; 61 import java.util.concurrent.ConcurrentMap;
45 import java.util.concurrent.CopyOnWriteArraySet; 62 import java.util.concurrent.CopyOnWriteArraySet;
63 +import java.util.concurrent.ExecutionException;
46 import java.util.concurrent.ExecutorService; 64 import java.util.concurrent.ExecutorService;
47 import java.util.concurrent.Executors; 65 import java.util.concurrent.Executors;
48 import java.util.concurrent.TimeUnit; 66 import java.util.concurrent.TimeUnit;
49 67
68 +import static com.google.common.base.Preconditions.checkNotNull;
50 import static org.onlab.util.Tools.groupedThreads; 69 import static org.onlab.util.Tools.groupedThreads;
51 -import static org.p4.bmv2.thrift.ControlPlaneService.Processor;
52 70
71 +/**
72 + * Default implementation of a BMv2 controller.
73 + */
53 @Component(immediate = true) 74 @Component(immediate = true)
54 @Service 75 @Service
55 -public class Bmv2ControlPlaneThriftServer implements Bmv2ControlPlaneServer { 76 +public class Bmv2ControllerImpl implements Bmv2Controller {
56 77
57 private static final String APP_ID = "org.onosproject.bmv2"; 78 private static final String APP_ID = "org.onosproject.bmv2";
58 - private static final Logger LOG = LoggerFactory.getLogger(Bmv2ControlPlaneThriftServer.class);
59 79
60 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 80 + // Seconds after a client is expired (and connection closed) in the cache.
61 - protected CoreService coreService; 81 + private static final int CLIENT_CACHE_TIMEOUT = 60;
82 + // Number of connection retries after a network error.
83 + private static final int NUM_CONNECTION_RETRIES = 2;
84 + // Time between retries in milliseconds.
85 + private static final int TIME_BETWEEN_RETRIES = 10;
86 +
87 + private final Logger log = LoggerFactory.getLogger(this.getClass());
88 +
89 + // Cache where clients are removed after a predefined timeout.
90 + private final LoadingCache<DeviceId, Pair<TTransport, Bmv2DeviceThriftClient>> agentCache =
91 + CacheBuilder.newBuilder()
92 + .expireAfterAccess(CLIENT_CACHE_TIMEOUT, TimeUnit.SECONDS)
93 + .removalListener(new ClientRemovalListener())
94 + .build(new ClientLoader());
62 95
63 private final InternalTrackingProcessor trackingProcessor = new InternalTrackingProcessor(); 96 private final InternalTrackingProcessor trackingProcessor = new InternalTrackingProcessor();
97 +
64 private final ExecutorService executorService = Executors 98 private final ExecutorService executorService = Executors
65 - .newFixedThreadPool(16, groupedThreads("onos/bmv2", "control-plane-server", LOG)); 99 + .newFixedThreadPool(16, groupedThreads("onos/bmv2", "controller", log));
66 100
67 - private final Set<HelloListener> helloListeners = new CopyOnWriteArraySet<>(); 101 + private final Set<Bmv2DeviceListener> deviceListeners = new CopyOnWriteArraySet<>();
68 - private final Set<PacketListener> packetListeners = new CopyOnWriteArraySet<>(); 102 + private final Set<Bmv2PacketListener> packetListeners = new CopyOnWriteArraySet<>();
103 +
104 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 + protected CoreService coreService;
69 106
70 private TThreadPoolServer thriftServer; 107 private TThreadPoolServer thriftServer;
108 +
109 + // TODO: make it configurable trough component config
71 private int serverPort = DEFAULT_PORT; 110 private int serverPort = DEFAULT_PORT;
72 111
73 @Activate 112 @Activate
74 public void activate() { 113 public void activate() {
75 coreService.registerApplication(APP_ID); 114 coreService.registerApplication(APP_ID);
115 + startServer(serverPort);
116 + log.info("Activated");
117 + }
118 +
119 + @Deactivate
120 + public void deactivate() {
121 + stopServer();
122 + log.info("Deactivated");
123 + }
124 +
125 + private void startServer(int port) {
76 try { 126 try {
77 - TServerTransport transport = new TServerSocket(serverPort); 127 + TServerTransport transport = new TServerSocket(port);
78 - LOG.info("Starting server on port {}...", serverPort); 128 + log.info("Starting server on port {}...", port);
79 this.thriftServer = new TThreadPoolServer(new TThreadPoolServer.Args(transport) 129 this.thriftServer = new TThreadPoolServer(new TThreadPoolServer.Args(transport)
80 .processor(trackingProcessor) 130 .processor(trackingProcessor)
81 .executorService(executorService)); 131 .executorService(executorService));
82 executorService.execute(thriftServer::serve); 132 executorService.execute(thriftServer::serve);
83 } catch (TTransportException e) { 133 } catch (TTransportException e) {
84 - LOG.error("Unable to start server", e); 134 + log.error("Unable to start server", e);
85 } 135 }
86 - LOG.info("Activated");
87 } 136 }
88 137
89 - @Deactivate 138 + private void stopServer() {
90 - public void deactivate() {
91 // Stop the server if running... 139 // Stop the server if running...
92 if (thriftServer != null && !thriftServer.isServing()) { 140 if (thriftServer != null && !thriftServer.isServing()) {
93 thriftServer.stop(); 141 thriftServer.stop();
94 } 142 }
95 try { 143 try {
96 - executorService.awaitTermination(1, TimeUnit.SECONDS); 144 + executorService.shutdown();
145 + executorService.awaitTermination(5, TimeUnit.SECONDS);
97 } catch (InterruptedException e) { 146 } catch (InterruptedException e) {
98 - LOG.error("Server threads did not terminate"); 147 + List<Runnable> runningTasks = executorService.shutdownNow();
148 + log.warn("Unable to stop server threads: {}", runningTasks);
149 + }
150 + }
151 +
152 + @Override
153 + public Bmv2DeviceAgent getAgent(DeviceId deviceId) throws Bmv2RuntimeException {
154 + try {
155 + checkNotNull(deviceId, "deviceId cannot be null");
156 + return agentCache.get(deviceId).getRight();
157 + } catch (ExecutionException e) {
158 + throw new Bmv2RuntimeException(e);
159 + }
160 + }
161 +
162 + @Override
163 + public boolean isReacheable(DeviceId deviceId) {
164 + try {
165 + return getAgent(deviceId).ping();
166 + } catch (Bmv2RuntimeException e) {
167 + return false;
99 } 168 }
100 - executorService.shutdownNow();
101 - LOG.info("Deactivated");
102 } 169 }
103 170
104 @Override 171 @Override
105 - public void addHelloListener(HelloListener listener) { 172 + public void addDeviceListener(Bmv2DeviceListener listener) {
106 - if (!helloListeners.contains(listener)) { 173 + if (!deviceListeners.contains(listener)) {
107 - helloListeners.add(listener); 174 + deviceListeners.add(listener);
108 } 175 }
109 } 176 }
110 177
111 @Override 178 @Override
112 - public void removeHelloListener(HelloListener listener) { 179 + public void removeDeviceListener(Bmv2DeviceListener listener) {
113 - helloListeners.remove(listener); 180 + deviceListeners.remove(listener);
114 } 181 }
115 182
116 @Override 183 @Override
117 - public void addPacketListener(PacketListener listener) { 184 + public void addPacketListener(Bmv2PacketListener listener) {
118 if (!packetListeners.contains(listener)) { 185 if (!packetListeners.contains(listener)) {
119 packetListeners.add(listener); 186 packetListeners.add(listener);
120 } 187 }
121 } 188 }
122 189
123 @Override 190 @Override
124 - public void removePacketListener(PacketListener listener) { 191 + public void removePacketListener(Bmv2PacketListener listener) {
125 packetListeners.remove(listener); 192 packetListeners.remove(listener);
126 } 193 }
127 194
128 /** 195 /**
129 - * Handles service calls using registered listeners. 196 + * Client cache removal listener. Close the connection on cache removal.
197 + */
198 + private static class ClientRemovalListener implements
199 + RemovalListener<DeviceId, Pair<TTransport, Bmv2DeviceThriftClient>> {
200 +
201 + @Override
202 + public void onRemoval(RemovalNotification<DeviceId, Pair<TTransport, Bmv2DeviceThriftClient>> notification) {
203 + // close the transport connection
204 + Bmv2DeviceThriftClient client = notification.getValue().getRight();
205 + TTransport transport = notification.getValue().getLeft();
206 + // Locking here is ugly, but needed (see SafeThriftClient).
207 + synchronized (transport) {
208 + if (transport.isOpen()) {
209 + transport.close();
210 + }
211 + }
212 + }
213 + }
214 +
215 + /**
216 + * Handles Thrift calls from BMv2 devices using registered listeners.
130 */ 217 */
131 private final class InternalServiceHandler implements ControlPlaneService.Iface { 218 private final class InternalServiceHandler implements ControlPlaneService.Iface {
132 219
...@@ -143,34 +230,36 @@ public class Bmv2ControlPlaneThriftServer implements Bmv2ControlPlaneServer { ...@@ -143,34 +230,36 @@ public class Bmv2ControlPlaneThriftServer implements Bmv2ControlPlaneServer {
143 } 230 }
144 231
145 @Override 232 @Override
146 - public void hello(int thriftServerPort, int deviceId) { 233 + public void hello(int thriftServerPort, int deviceId, int instanceId, String jsonConfigMd5) {
147 // Locally note the remote device for future uses. 234 // Locally note the remote device for future uses.
148 String host = socket.getSocket().getInetAddress().getHostAddress(); 235 String host = socket.getSocket().getInetAddress().getHostAddress();
149 remoteDevice = new Bmv2Device(host, thriftServerPort, deviceId); 236 remoteDevice = new Bmv2Device(host, thriftServerPort, deviceId);
150 237
151 - if (helloListeners.size() == 0) { 238 + if (deviceListeners.size() == 0) {
152 - LOG.debug("Received hello, but there's no listener registered."); 239 + log.debug("Received hello, but there's no listener registered.");
153 } else { 240 } else {
154 - helloListeners.forEach(listener -> listener.handleHello(remoteDevice)); 241 + deviceListeners.forEach(
242 + l -> executorService.execute(() -> l.handleHello(remoteDevice, instanceId, jsonConfigMd5)));
155 } 243 }
156 } 244 }
157 245
158 @Override 246 @Override
159 public void packetIn(int port, long reason, int tableId, int contextId, ByteBuffer packet) { 247 public void packetIn(int port, long reason, int tableId, int contextId, ByteBuffer packet) {
160 if (remoteDevice == null) { 248 if (remoteDevice == null) {
161 - LOG.debug("Received packet-in, but the remote device is still unknown. Need a hello first..."); 249 + log.debug("Received packet-in, but the remote device is still unknown. Need a hello first...");
162 return; 250 return;
163 } 251 }
164 252
165 if (packetListeners.size() == 0) { 253 if (packetListeners.size() == 0) {
166 - LOG.debug("Received packet-in, but there's no listener registered."); 254 + log.debug("Received packet-in, but there's no listener registered.");
167 } else { 255 } else {
168 - packetListeners.forEach(listener -> listener.handlePacketIn(remoteDevice, 256 + packetListeners.forEach(
257 + l -> executorService.execute(() -> l.handlePacketIn(remoteDevice,
169 port, 258 port,
170 reason, 259 reason,
171 tableId, 260 tableId,
172 contextId, 261 contextId,
173 - ImmutableByteSequence.copyFrom(packet))); 262 + ImmutableByteSequence.copyFrom(packet))));
174 } 263 }
175 } 264 }
176 } 265 }
...@@ -183,19 +272,56 @@ public class Bmv2ControlPlaneThriftServer implements Bmv2ControlPlaneServer { ...@@ -183,19 +272,56 @@ public class Bmv2ControlPlaneThriftServer implements Bmv2ControlPlaneServer {
183 272
184 // Map sockets to processors. 273 // Map sockets to processors.
185 // TODO: implement it as a cache so unused sockets are expired automatically 274 // TODO: implement it as a cache so unused sockets are expired automatically
186 - private final ConcurrentMap<TSocket, Processor<InternalServiceHandler>> processors = Maps.newConcurrentMap(); 275 + private final ConcurrentMap<TSocket, ControlPlaneService.Processor<InternalServiceHandler>> processors =
276 + Maps.newConcurrentMap();
187 277
188 @Override 278 @Override
189 public boolean process(final TProtocol in, final TProtocol out) throws TException { 279 public boolean process(final TProtocol in, final TProtocol out) throws TException {
190 // Get the socket for this request. 280 // Get the socket for this request.
191 TSocket socket = (TSocket) in.getTransport(); 281 TSocket socket = (TSocket) in.getTransport();
192 // Get or create a processor for this socket 282 // Get or create a processor for this socket
193 - Processor<InternalServiceHandler> processor = processors.computeIfAbsent(socket, s -> { 283 + ControlPlaneService.Processor<InternalServiceHandler> processor = processors.computeIfAbsent(socket, s -> {
194 InternalServiceHandler handler = new InternalServiceHandler(s); 284 InternalServiceHandler handler = new InternalServiceHandler(s);
195 - return new Processor<>(handler); 285 + return new ControlPlaneService.Processor<>(handler);
196 }); 286 });
197 // Delegate to the processor we are decorating. 287 // Delegate to the processor we are decorating.
198 return processor.process(in, out); 288 return processor.process(in, out);
199 } 289 }
200 } 290 }
291 +
292 + /**
293 + * Transport/client cache loader.
294 + */
295 + private class ClientLoader extends CacheLoader<DeviceId, Pair<TTransport, Bmv2DeviceThriftClient>> {
296 +
297 + private final SafeThriftClient.Options options = new SafeThriftClient.Options(NUM_CONNECTION_RETRIES,
298 + TIME_BETWEEN_RETRIES);
299 +
300 + @Override
301 + public Pair<TTransport, Bmv2DeviceThriftClient> load(DeviceId deviceId)
302 + throws TTransportException {
303 + log.debug("Instantiating new client... > deviceId={}", deviceId);
304 + // Make the expensive call
305 + Bmv2Device device = Bmv2Device.of(deviceId);
306 + TTransport transport = new TSocket(device.thriftServerHost(), device.thriftServerPort());
307 + TProtocol protocol = new TBinaryProtocol(transport);
308 + // Our BMv2 device implements multiple Thrift services, create a client for each one on the same transport.
309 + Standard.Client standardClient = new Standard.Client(
310 + new TMultiplexedProtocol(protocol, "standard"));
311 + SimpleSwitch.Client simpleSwitch = new SimpleSwitch.Client(
312 + new TMultiplexedProtocol(protocol, "simple_switch"));
313 + // Wrap clients so to automatically have synchronization and resiliency to connectivity errors
314 + Standard.Iface safeStandardClient = SafeThriftClient.wrap(standardClient,
315 + Standard.Iface.class,
316 + options);
317 + SimpleSwitch.Iface safeSimpleSwitchClient = SafeThriftClient.wrap(simpleSwitch,
318 + SimpleSwitch.Iface.class,
319 + options);
320 + Bmv2DeviceThriftClient client = new Bmv2DeviceThriftClient(deviceId,
321 + transport,
322 + safeStandardClient,
323 + safeSimpleSwitchClient);
324 + return Pair.of(transport, client);
325 + }
326 + }
201 } 327 }
......
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.bmv2.ctl;
18 +
19 +import com.google.common.collect.ImmutableBiMap;
20 +import org.onlab.util.ImmutableByteSequence;
21 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
22 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
23 +import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
24 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
25 +import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
26 +import org.onosproject.net.flow.TrafficTreatment;
27 +import org.onosproject.net.flow.criteria.Criterion;
28 +import org.onosproject.net.flow.instructions.Instruction;
29 +
30 +import static org.onosproject.net.PortNumber.CONTROLLER;
31 +import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
32 +
33 +/**
34 + * Implementation of a BMv2 interpreter for the BMv2 default.json configuration.
35 + */
36 +public final class Bmv2DefaultInterpreterImpl implements Bmv2Interpreter {
37 +
38 + public static final String TABLE0 = "table0";
39 + public static final String SEND_TO_CPU = "send_to_cpu";
40 + public static final String DROP = "_drop";
41 + public static final String SET_EGRESS_PORT = "set_egress_port";
42 +
43 + // Lazily populate field map.
44 + private static final ImmutableBiMap<Criterion.Type, String> CRITERION_MAP = ImmutableBiMap.of(
45 + Criterion.Type.IN_PORT, "standard_metadata.ingress_port",
46 + Criterion.Type.ETH_DST, "ethernet.dstAddr",
47 + Criterion.Type.ETH_SRC, "ethernet.srcAddr",
48 + Criterion.Type.ETH_TYPE, "ethernet.etherType");
49 +
50 + private static final ImmutableBiMap<Integer, String> TABLE_MAP = ImmutableBiMap.of(
51 + 0, TABLE0);
52 +
53 + @Override
54 + public ImmutableBiMap<Criterion.Type, String> criterionTypeMap() {
55 + return CRITERION_MAP;
56 + }
57 +
58 + @Override
59 + public ImmutableBiMap<Integer, String> tableIdMap() {
60 + return TABLE_MAP;
61 + }
62 +
63 + @Override
64 + public Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
65 + throws Bmv2InterpreterException {
66 +
67 +
68 + if (treatment.allInstructions().size() == 0) {
69 + // No instructions means drop for us.
70 + return Bmv2Action.builder().withName(DROP).build();
71 + } else if (treatment.allInstructions().size() > 1) {
72 + // Otherwise, we understand treatments with only 1 instruction.
73 + throw new Bmv2InterpreterException("Treatment has multiple instructions");
74 + }
75 +
76 + Instruction instruction = treatment.allInstructions().get(0);
77 +
78 + switch (instruction.type()) {
79 + case OUTPUT:
80 + OutputInstruction outInstruction = (OutputInstruction) instruction;
81 + if (outInstruction.port() == CONTROLLER) {
82 + return Bmv2Action.builder().withName(SEND_TO_CPU).build();
83 + } else {
84 + return buildEgressAction(outInstruction, configuration);
85 + }
86 + case NOACTION:
87 + return Bmv2Action.builder().withName(DROP).build();
88 + default:
89 + throw new Bmv2InterpreterException("Instruction type not supported: " + instruction.type().name());
90 + }
91 + }
92 +
93 +
94 + /**
95 + * Builds an egress action equivalent to the given output instruction for the given configuration.
96 + *
97 + * @param instruction an output instruction
98 + * @param configuration a configuration
99 + * @return a BMv2 action
100 + * @throws Bmv2InterpreterException if the instruction cannot be translated to a BMv2 action
101 + */
102 + private Bmv2Action buildEgressAction(OutputInstruction instruction, Bmv2Configuration configuration)
103 + throws Bmv2InterpreterException {
104 +
105 + Bmv2Action.Builder actionBuilder = Bmv2Action.builder();
106 +
107 + actionBuilder.withName(SET_EGRESS_PORT);
108 +
109 + if (instruction.port().isLogical()) {
110 + throw new Bmv2InterpreterException("Output on logic port not supported: " + instruction);
111 + }
112 +
113 + // Get the byte sequence for the out port with the right length
114 + long portNumber = instruction.port().toLong();
115 + int bitWidth = configuration.action(SET_EGRESS_PORT).runtimeData("port").bitWidth();
116 + try {
117 + ImmutableByteSequence outPort = Bmv2TranslatorUtils.fitByteSequence(
118 + ImmutableByteSequence.copyFrom(portNumber), bitWidth);
119 + return Bmv2Action.builder().withName(SET_EGRESS_PORT).addParameter(outPort).build();
120 + } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
121 + throw new Bmv2InterpreterException(e.getMessage());
122 + }
123 + }
124 +}
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.bmv2.ctl;
18 +
19 +import com.eclipsesource.json.Json;
20 +import com.eclipsesource.json.JsonObject;
21 +import com.esotericsoftware.kryo.Kryo;
22 +import com.esotericsoftware.kryo.io.Input;
23 +import com.esotericsoftware.kryo.io.Output;
24 +import com.google.common.collect.Maps;
25 +import org.apache.felix.scr.annotations.Activate;
26 +import org.apache.felix.scr.annotations.Component;
27 +import org.apache.felix.scr.annotations.Deactivate;
28 +import org.apache.felix.scr.annotations.Reference;
29 +import org.apache.felix.scr.annotations.ReferenceCardinality;
30 +import org.apache.felix.scr.annotations.Service;
31 +import org.onlab.util.KryoNamespace;
32 +import org.onlab.util.SharedExecutors;
33 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
34 +import org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration;
35 +import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
36 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
37 +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
38 +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
39 +import org.onosproject.bmv2.api.service.Bmv2Controller;
40 +import org.onosproject.bmv2.api.service.Bmv2DeviceContextService;
41 +import org.onosproject.net.DeviceId;
42 +import org.onosproject.store.serializers.KryoNamespaces;
43 +import org.onosproject.store.service.ConsistentMap;
44 +import org.onosproject.store.service.Serializer;
45 +import org.onosproject.store.service.StorageService;
46 +import org.slf4j.Logger;
47 +import org.slf4j.LoggerFactory;
48 +
49 +import java.io.BufferedReader;
50 +import java.io.IOException;
51 +import java.io.InputStreamReader;
52 +import java.util.Map;
53 +import java.util.concurrent.ExecutorService;
54 +
55 +import static com.google.common.base.Preconditions.checkNotNull;
56 +
57 +@Component(immediate = true)
58 +@Service
59 +public class Bmv2DeviceContextServiceImpl implements Bmv2DeviceContextService {
60 +
61 + private static final String JSON_DEFAULT_CONFIG_PATH = "/default.json";
62 +
63 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 + private StorageService storageService;
65 +
66 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 + private Bmv2Controller controller;
68 +
69 + private final ExecutorService executorService = SharedExecutors.getPoolThreadExecutor();
70 +
71 + private ConsistentMap<DeviceId, Bmv2DeviceContext> contexts;
72 + private Map<DeviceId, Bmv2DeviceContext> contextsMap;
73 +
74 + private Map<String, ClassLoader> interpreterClassLoaders;
75 +
76 + private Bmv2DeviceContext defaultContext;
77 +
78 + private final Logger log = LoggerFactory.getLogger(getClass());
79 +
80 + @Activate
81 + public void activate() {
82 + KryoNamespace kryo = new KryoNamespace.Builder()
83 + .register(KryoNamespaces.API)
84 + .register(new BmvDeviceContextSerializer(), Bmv2DeviceContext.class)
85 + .build();
86 +
87 + this.contexts = storageService.<DeviceId, Bmv2DeviceContext>consistentMapBuilder()
88 + .withSerializer(Serializer.using(kryo))
89 + .withName("onos-bmv2-contexts")
90 + .build();
91 + contextsMap = contexts.asJavaMap();
92 +
93 + interpreterClassLoaders = Maps.newConcurrentMap();
94 +
95 + Bmv2Configuration defaultConfiguration = loadDefaultConfiguration();
96 + Bmv2Interpreter defaultInterpreter = new Bmv2DefaultInterpreterImpl();
97 + defaultContext = new Bmv2DeviceContext(defaultConfiguration, defaultInterpreter);
98 +
99 + interpreterClassLoaders.put(defaultInterpreter.getClass().getName(), this.getClass().getClassLoader());
100 +
101 + log.info("Started");
102 + }
103 +
104 + @Deactivate
105 + public void deactivate() {
106 + log.info("Stopped");
107 + }
108 +
109 + @Override
110 + public Bmv2DeviceContext getContext(DeviceId deviceId) {
111 + checkNotNull(deviceId, "device id cannot be null");
112 + return contextsMap.get(deviceId);
113 + }
114 +
115 + @Override
116 + public void triggerConfigurationSwap(DeviceId deviceId, Bmv2DeviceContext context) {
117 + checkNotNull(deviceId, "device id cannot be null");
118 + checkNotNull(context, "context cannot be null");
119 + if (!interpreterClassLoaders.containsKey(context.interpreter().getClass().getName())) {
120 + log.error("Unable to trigger configuration swap, missing class loader for context interpreter. " +
121 + "Please register it with registerInterpreterClassLoader()");
122 + } else {
123 + executorService.execute(() -> executeConfigurationSwap(deviceId, context));
124 + }
125 + }
126 +
127 + @Override
128 + public void registerInterpreterClassLoader(Class<? extends Bmv2Interpreter> interpreterClass, ClassLoader loader) {
129 + interpreterClassLoaders.put(interpreterClass.getName(), loader);
130 + }
131 +
132 + private void executeConfigurationSwap(DeviceId deviceId, Bmv2DeviceContext context) {
133 + contexts.compute(deviceId, (key, existingValue) -> {
134 + if (context.equals(existingValue)) {
135 + log.info("Dropping swap request as one has already been triggered for the given context.");
136 + return existingValue;
137 + }
138 + try {
139 + Bmv2DeviceAgent agent = controller.getAgent(deviceId);
140 + String jsonString = context.configuration().json().toString();
141 + agent.loadNewJsonConfig(jsonString);
142 + agent.swapJsonConfig();
143 + return context;
144 + } catch (Bmv2RuntimeException e) {
145 + log.error("Unable to swap configuration on {}: {}", deviceId, e.explain());
146 + return existingValue;
147 + }
148 + });
149 + }
150 +
151 + @Override
152 + public boolean notifyDeviceChange(DeviceId deviceId) {
153 + checkNotNull(deviceId, "device id cannot be null");
154 +
155 + Bmv2DeviceContext storedContext = getContext(deviceId);
156 +
157 + if (storedContext == null) {
158 + log.info("No context previously stored for {}, swapping to DEFAULT_CONTEXT.", deviceId);
159 + triggerConfigurationSwap(deviceId, defaultContext);
160 + // Device can be accepted.
161 + return false;
162 + } else {
163 + Bmv2Configuration deviceConfiguration = loadDeviceConfiguration(deviceId);
164 + if (deviceConfiguration == null) {
165 + log.warn("Unable to load configuration from device {}", deviceId);
166 + return false;
167 + }
168 + if (storedContext.configuration().equals(deviceConfiguration)) {
169 + return true;
170 + } else {
171 + log.info("Device context is different from the stored one, triggering configuration swap for {}...",
172 + deviceId);
173 + triggerConfigurationSwap(deviceId, storedContext);
174 + return false;
175 + }
176 + }
177 + }
178 +
179 + /**
180 + * Load and parse a BMv2 JSON configuration from the given device.
181 + *
182 + * @param deviceId a device id
183 + * @return a BMv2 configuration
184 + */
185 + private Bmv2Configuration loadDeviceConfiguration(DeviceId deviceId) {
186 + try {
187 + String jsonString = controller.getAgent(deviceId).dumpJsonConfig();
188 + return Bmv2DefaultConfiguration.parse(Json.parse(jsonString).asObject());
189 + } catch (Bmv2RuntimeException e) {
190 + log.warn("Unable to load JSON configuration from {}: {}", deviceId, e.explain());
191 + return null;
192 + }
193 + }
194 +
195 + /**
196 + * Loads default configuration from file.
197 + *
198 + * @return a BMv2 configuration
199 + */
200 + protected static Bmv2DefaultConfiguration loadDefaultConfiguration() {
201 + try {
202 + JsonObject json = Json.parse(new BufferedReader(new InputStreamReader(
203 + Bmv2DeviceContextServiceImpl.class.getResourceAsStream(JSON_DEFAULT_CONFIG_PATH)))).asObject();
204 + return Bmv2DefaultConfiguration.parse(json);
205 + } catch (IOException e) {
206 + throw new RuntimeException("Unable to load default configuration", e);
207 + }
208 + }
209 +
210 + /**
211 + * Internal BMv2 context serializer.
212 + */
213 + private class BmvDeviceContextSerializer extends com.esotericsoftware.kryo.Serializer<Bmv2DeviceContext> {
214 +
215 + @Override
216 + public void write(Kryo kryo, Output output, Bmv2DeviceContext context) {
217 + kryo.writeObject(output, context.configuration().json().toString());
218 + kryo.writeObject(output, context.interpreter().getClass().getName());
219 + }
220 +
221 + @Override
222 + public Bmv2DeviceContext read(Kryo kryo, Input input, Class<Bmv2DeviceContext> type) {
223 + String jsonStr = kryo.readObject(input, String.class);
224 + String interpreterClassName = kryo.readObject(input, String.class);
225 + Bmv2Configuration configuration = Bmv2DefaultConfiguration.parse(Json.parse(jsonStr).asObject());
226 + ClassLoader loader = interpreterClassLoaders.get(interpreterClassName);
227 + if (loader == null) {
228 + throw new IllegalStateException("No class loader registered for interpreter: " + interpreterClassName);
229 + }
230 + try {
231 + Bmv2Interpreter interpreter = (Bmv2Interpreter) loader.loadClass(interpreterClassName).newInstance();
232 + return new Bmv2DeviceContext(configuration, interpreter);
233 + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
234 + throw new RuntimeException("Unable to load interpreter class", e);
235 + }
236 + }
237 + }
238 +}
1 /* 1 /*
2 - * Copyright 2014-2016 Open Networking Laboratory 2 + * Copyright 2016-present Open Networking Laboratory
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
...@@ -16,24 +16,13 @@ ...@@ -16,24 +16,13 @@
16 16
17 package org.onosproject.bmv2.ctl; 17 package org.onosproject.bmv2.ctl;
18 18
19 -import com.google.common.cache.CacheBuilder;
20 -import com.google.common.cache.CacheLoader;
21 -import com.google.common.cache.LoadingCache;
22 -import com.google.common.cache.RemovalListener;
23 -import com.google.common.cache.RemovalNotification;
24 import com.google.common.collect.Lists; 19 import com.google.common.collect.Lists;
25 -import org.apache.commons.lang3.tuple.ImmutablePair;
26 import org.apache.commons.lang3.tuple.Pair; 20 import org.apache.commons.lang3.tuple.Pair;
27 import org.apache.thrift.TException; 21 import org.apache.thrift.TException;
28 -import org.apache.thrift.protocol.TBinaryProtocol;
29 -import org.apache.thrift.protocol.TMultiplexedProtocol;
30 -import org.apache.thrift.protocol.TProtocol;
31 -import org.apache.thrift.transport.TSocket;
32 import org.apache.thrift.transport.TTransport; 22 import org.apache.thrift.transport.TTransport;
33 -import org.apache.thrift.transport.TTransportException;
34 import org.onlab.util.ImmutableByteSequence; 23 import org.onlab.util.ImmutableByteSequence;
35 import org.onosproject.bmv2.api.runtime.Bmv2Action; 24 import org.onosproject.bmv2.api.runtime.Bmv2Action;
36 -import org.onosproject.bmv2.api.runtime.Bmv2Client; 25 +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
37 import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam; 26 import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
38 import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam; 27 import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
39 import org.onosproject.bmv2.api.runtime.Bmv2MatchKey; 28 import org.onosproject.bmv2.api.runtime.Bmv2MatchKey;
...@@ -42,57 +31,37 @@ import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; ...@@ -42,57 +31,37 @@ import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
42 import org.onosproject.bmv2.api.runtime.Bmv2TableEntry; 31 import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
43 import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam; 32 import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam;
44 import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam; 33 import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam;
34 +import org.onosproject.bmv2.thriftapi.BmAddEntryOptions;
35 +import org.onosproject.bmv2.thriftapi.BmCounterValue;
36 +import org.onosproject.bmv2.thriftapi.BmMatchParam;
37 +import org.onosproject.bmv2.thriftapi.BmMatchParamExact;
38 +import org.onosproject.bmv2.thriftapi.BmMatchParamLPM;
39 +import org.onosproject.bmv2.thriftapi.BmMatchParamTernary;
40 +import org.onosproject.bmv2.thriftapi.BmMatchParamType;
41 +import org.onosproject.bmv2.thriftapi.BmMatchParamValid;
42 +import org.onosproject.bmv2.thriftapi.SimpleSwitch;
43 +import org.onosproject.bmv2.thriftapi.Standard;
45 import org.onosproject.net.DeviceId; 44 import org.onosproject.net.DeviceId;
46 -import org.p4.bmv2.thrift.BmAddEntryOptions;
47 -import org.p4.bmv2.thrift.BmCounterValue;
48 -import org.p4.bmv2.thrift.BmMatchParam;
49 -import org.p4.bmv2.thrift.BmMatchParamExact;
50 -import org.p4.bmv2.thrift.BmMatchParamLPM;
51 -import org.p4.bmv2.thrift.BmMatchParamTernary;
52 -import org.p4.bmv2.thrift.BmMatchParamType;
53 -import org.p4.bmv2.thrift.BmMatchParamValid;
54 -import org.p4.bmv2.thrift.DevMgrPortInfo;
55 -import org.p4.bmv2.thrift.SimpleSwitch;
56 -import org.p4.bmv2.thrift.Standard;
57 import org.slf4j.Logger; 45 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory; 46 import org.slf4j.LoggerFactory;
59 47
60 import java.nio.ByteBuffer; 48 import java.nio.ByteBuffer;
61 import java.util.Collection; 49 import java.util.Collection;
62 import java.util.List; 50 import java.util.List;
63 -import java.util.concurrent.ExecutionException;
64 -import java.util.concurrent.TimeUnit;
65 import java.util.stream.Collectors; 51 import java.util.stream.Collectors;
66 52
67 -import static com.google.common.base.Preconditions.checkNotNull; 53 +import static org.onosproject.bmv2.ctl.Bmv2TExceptionParser.parseTException;
68 -import static org.onosproject.bmv2.ctl.SafeThriftClient.Options;
69 54
70 /** 55 /**
71 - * Implementation of a Thrift client to control the Bmv2 switch. 56 + * Implementation of a Thrift client to control a BMv2 device.
72 */ 57 */
73 -public final class Bmv2ThriftClient implements Bmv2Client { 58 +public final class Bmv2DeviceThriftClient implements Bmv2DeviceAgent {
74 59
75 - private static final Logger LOG = 60 + private final Logger log = LoggerFactory.getLogger(this.getClass());
76 - LoggerFactory.getLogger(Bmv2ThriftClient.class);
77 61
78 // FIXME: make context_id arbitrary for each call 62 // FIXME: make context_id arbitrary for each call
79 // See: https://github.com/p4lang/behavioral-model/blob/master/modules/bm_sim/include/bm_sim/context.h 63 // See: https://github.com/p4lang/behavioral-model/blob/master/modules/bm_sim/include/bm_sim/context.h
80 private static final int CONTEXT_ID = 0; 64 private static final int CONTEXT_ID = 0;
81 - // Seconds after a client is expired (and connection closed) in the cache.
82 - private static final int CLIENT_CACHE_TIMEOUT = 60;
83 - // Number of connection retries after a network error.
84 - private static final int NUM_CONNECTION_RETRIES = 3;
85 - // Time between retries in milliseconds.
86 - private static final int TIME_BETWEEN_RETRIES = 300;
87 -
88 - // Static client cache where clients are removed after a predefined timeout.
89 - private static final LoadingCache<DeviceId, Bmv2ThriftClient>
90 - CLIENT_CACHE = CacheBuilder.newBuilder()
91 - .expireAfterAccess(CLIENT_CACHE_TIMEOUT, TimeUnit.SECONDS)
92 - .removalListener(new ClientRemovalListener())
93 - .build(new ClientLoader());
94 -
95 - private static final Bmv2TableDumpParser TABLE_DUMP_PARSER = new Bmv2TableDumpParser();
96 65
97 private final Standard.Iface standardClient; 66 private final Standard.Iface standardClient;
98 private final SimpleSwitch.Iface simpleSwitchClient; 67 private final SimpleSwitch.Iface simpleSwitchClient;
...@@ -100,146 +69,32 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -100,146 +69,32 @@ public final class Bmv2ThriftClient implements Bmv2Client {
100 private final DeviceId deviceId; 69 private final DeviceId deviceId;
101 70
102 // ban constructor 71 // ban constructor
103 - private Bmv2ThriftClient(DeviceId deviceId, TTransport transport, Standard.Iface standardClient, 72 + protected Bmv2DeviceThriftClient(DeviceId deviceId, TTransport transport, Standard.Iface standardClient,
104 - SimpleSwitch.Iface simpleSwitchClient) { 73 + SimpleSwitch.Iface simpleSwitchClient) {
105 this.deviceId = deviceId; 74 this.deviceId = deviceId;
106 this.transport = transport; 75 this.transport = transport;
107 this.standardClient = standardClient; 76 this.standardClient = standardClient;
108 this.simpleSwitchClient = simpleSwitchClient; 77 this.simpleSwitchClient = simpleSwitchClient;
109 -
110 - LOG.debug("New client created! > deviceId={}", deviceId);
111 - }
112 -
113 - /**
114 - * Returns a client object to control the passed device.
115 - *
116 - * @param deviceId device id
117 - * @return bmv2 client object
118 - * @throws Bmv2RuntimeException if a connection to the device cannot be established
119 - */
120 - public static Bmv2ThriftClient of(DeviceId deviceId) throws Bmv2RuntimeException {
121 - try {
122 - checkNotNull(deviceId, "deviceId cannot be null");
123 - LOG.debug("Getting a client from cache... > deviceId{}", deviceId);
124 - return CLIENT_CACHE.get(deviceId);
125 - } catch (ExecutionException e) {
126 - LOG.debug("Exception while getting a client from cache: {} > ", e, deviceId);
127 - throw new Bmv2RuntimeException(e.getMessage(), e.getCause());
128 - }
129 } 78 }
130 79
131 - /** 80 + @Override
132 - * Force a close of the transport session (if one is open) with the given device. 81 + public DeviceId deviceId() {
133 - * 82 + return deviceId;
134 - * @param deviceId device id
135 - */
136 - public static void forceDisconnectOf(DeviceId deviceId) {
137 - CLIENT_CACHE.invalidate(deviceId);
138 } 83 }
139 84
140 - /** 85 + @Override
141 - * Pings the device. Returns true if the device is reachable, 86 + public boolean ping() {
142 - * false otherwise.
143 - *
144 - * @param deviceId device id
145 - * @return true if reachable, false otherwise
146 - */
147 - public static boolean ping(DeviceId deviceId) {
148 - // poll ports status as workaround to assess device reachability
149 try { 87 try {
150 - LOG.debug("Pinging device... > deviceId={}", deviceId); 88 + return this.simpleSwitchClient.ping();
151 - Bmv2ThriftClient client = of(deviceId); 89 + } catch (TException e) {
152 - boolean result = client.simpleSwitchClient.ping();
153 - LOG.debug("Device pinged! > deviceId={}, state={}", deviceId, result);
154 - return result;
155 - } catch (TException | Bmv2RuntimeException e) {
156 - LOG.debug("Device NOT reachable! > deviceId={}", deviceId);
157 return false; 90 return false;
158 } 91 }
159 } 92 }
160 93
161 - /**
162 - * Parse device ID into host and port.
163 - *
164 - * @param did device ID
165 - * @return a pair of host and port
166 - */
167 - private static Pair<String, Integer> parseDeviceId(DeviceId did) {
168 - String[] info = did.toString().split(":");
169 - if (info.length == 3) {
170 - String host = info[1];
171 - int port = Integer.parseInt(info[2]);
172 - return ImmutablePair.of(host, port);
173 - } else {
174 - throw new IllegalArgumentException(
175 - "Unable to parse BMv2 device ID "
176 - + did.toString()
177 - + ", expected format is scheme:host:port");
178 - }
179 - }
180 -
181 - /**
182 - * Builds a list of Bmv2/Thrift compatible match parameters.
183 - *
184 - * @param matchKey a bmv2 matchKey
185 - * @return list of thrift-compatible bm match parameters
186 - */
187 - private static List<BmMatchParam> buildMatchParamsList(Bmv2MatchKey matchKey) {
188 - List<BmMatchParam> paramsList = Lists.newArrayList();
189 - matchKey.matchParams().forEach(x -> {
190 - ByteBuffer value;
191 - ByteBuffer mask;
192 - switch (x.type()) {
193 - case EXACT:
194 - value = ByteBuffer.wrap(((Bmv2ExactMatchParam) x).value().asArray());
195 - paramsList.add(
196 - new BmMatchParam(BmMatchParamType.EXACT)
197 - .setExact(new BmMatchParamExact(value)));
198 - break;
199 - case TERNARY:
200 - value = ByteBuffer.wrap(((Bmv2TernaryMatchParam) x).value().asArray());
201 - mask = ByteBuffer.wrap(((Bmv2TernaryMatchParam) x).mask().asArray());
202 - paramsList.add(
203 - new BmMatchParam(BmMatchParamType.TERNARY)
204 - .setTernary(new BmMatchParamTernary(value, mask)));
205 - break;
206 - case LPM:
207 - value = ByteBuffer.wrap(((Bmv2LpmMatchParam) x).value().asArray());
208 - int prefixLength = ((Bmv2LpmMatchParam) x).prefixLength();
209 - paramsList.add(
210 - new BmMatchParam(BmMatchParamType.LPM)
211 - .setLpm(new BmMatchParamLPM(value, prefixLength)));
212 - break;
213 - case VALID:
214 - boolean flag = ((Bmv2ValidMatchParam) x).flag();
215 - paramsList.add(
216 - new BmMatchParam(BmMatchParamType.VALID)
217 - .setValid(new BmMatchParamValid(flag)));
218 - break;
219 - default:
220 - // should never be here
221 - throw new RuntimeException("Unknown match param type " + x.type().name());
222 - }
223 - });
224 - return paramsList;
225 - }
226 -
227 - /**
228 - * Build a list of Bmv2/Thrift compatible action parameters.
229 - *
230 - * @param action an action object
231 - * @return list of ByteBuffers
232 - */
233 - private static List<ByteBuffer> buildActionParamsList(Bmv2Action action) {
234 - List<ByteBuffer> buffers = Lists.newArrayList();
235 - action.parameters().forEach(p -> buffers.add(ByteBuffer.wrap(p.asArray())));
236 - return buffers;
237 - }
238 -
239 @Override 94 @Override
240 public final long addTableEntry(Bmv2TableEntry entry) throws Bmv2RuntimeException { 95 public final long addTableEntry(Bmv2TableEntry entry) throws Bmv2RuntimeException {
241 96
242 - LOG.debug("Adding table entry... > deviceId={}, entry={}", deviceId, entry); 97 + log.debug("Adding table entry... > deviceId={}, entry={}", deviceId, entry);
243 98
244 long entryId = -1; 99 long entryId = -1;
245 100
...@@ -265,23 +120,23 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -265,23 +120,23 @@ public final class Bmv2ThriftClient implements Bmv2Client {
265 CONTEXT_ID, entry.tableName(), entryId, msTimeout); 120 CONTEXT_ID, entry.tableName(), entryId, msTimeout);
266 } 121 }
267 122
268 - LOG.debug("Table entry added! > deviceId={}, entryId={}/{}", deviceId, entry.tableName(), entryId); 123 + log.debug("Table entry added! > deviceId={}, entryId={}/{}", deviceId, entry.tableName(), entryId);
269 124
270 return entryId; 125 return entryId;
271 126
272 } catch (TException e) { 127 } catch (TException e) {
273 - LOG.debug("Exception while adding table entry: {} > deviceId={}, tableName={}", 128 + log.debug("Exception while adding table entry: {} > deviceId={}, tableName={}",
274 e, deviceId, entry.tableName()); 129 e, deviceId, entry.tableName());
275 if (entryId != -1) { 130 if (entryId != -1) {
276 // entry is in inconsistent state (unable to add timeout), remove it 131 // entry is in inconsistent state (unable to add timeout), remove it
277 try { 132 try {
278 deleteTableEntry(entry.tableName(), entryId); 133 deleteTableEntry(entry.tableName(), entryId);
279 } catch (Bmv2RuntimeException e1) { 134 } catch (Bmv2RuntimeException e1) {
280 - LOG.debug("Unable to remove failed table entry: {} > deviceId={}, tableName={}", 135 + log.debug("Unable to remove failed table entry: {} > deviceId={}, tableName={}",
281 e1, deviceId, entry.tableName()); 136 e1, deviceId, entry.tableName());
282 } 137 }
283 } 138 }
284 - throw new Bmv2RuntimeException(e.getMessage(), e); 139 + throw parseTException(e);
285 } 140 }
286 } 141 }
287 142
...@@ -290,7 +145,7 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -290,7 +145,7 @@ public final class Bmv2ThriftClient implements Bmv2Client {
290 long entryId, Bmv2Action action) 145 long entryId, Bmv2Action action)
291 throws Bmv2RuntimeException { 146 throws Bmv2RuntimeException {
292 147
293 - LOG.debug("Modifying table entry... > deviceId={}, entryId={}/{}", deviceId, tableName, entryId); 148 + log.debug("Modifying table entry... > deviceId={}, entryId={}/{}", deviceId, tableName, entryId);
294 149
295 try { 150 try {
296 standardClient.bm_mt_modify_entry( 151 standardClient.bm_mt_modify_entry(
...@@ -299,11 +154,11 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -299,11 +154,11 @@ public final class Bmv2ThriftClient implements Bmv2Client {
299 entryId, 154 entryId,
300 action.name(), 155 action.name(),
301 buildActionParamsList(action)); 156 buildActionParamsList(action));
302 - LOG.debug("Table entry modified! > deviceId={}, entryId={}/{}", deviceId, tableName, entryId); 157 + log.debug("Table entry modified! > deviceId={}, entryId={}/{}", deviceId, tableName, entryId);
303 } catch (TException e) { 158 } catch (TException e) {
304 - LOG.debug("Exception while modifying table entry: {} > deviceId={}, entryId={}/{}", 159 + log.debug("Exception while modifying table entry: {} > deviceId={}, entryId={}/{}",
305 e, deviceId, tableName, entryId); 160 e, deviceId, tableName, entryId);
306 - throw new Bmv2RuntimeException(e.getMessage(), e); 161 + throw parseTException(e);
307 } 162 }
308 } 163 }
309 164
...@@ -311,15 +166,15 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -311,15 +166,15 @@ public final class Bmv2ThriftClient implements Bmv2Client {
311 public final void deleteTableEntry(String tableName, 166 public final void deleteTableEntry(String tableName,
312 long entryId) throws Bmv2RuntimeException { 167 long entryId) throws Bmv2RuntimeException {
313 168
314 - LOG.debug("Deleting table entry... > deviceId={}, entryId={}/{}", deviceId, tableName, entryId); 169 + log.debug("Deleting table entry... > deviceId={}, entryId={}/{}", deviceId, tableName, entryId);
315 170
316 try { 171 try {
317 standardClient.bm_mt_delete_entry(CONTEXT_ID, tableName, entryId); 172 standardClient.bm_mt_delete_entry(CONTEXT_ID, tableName, entryId);
318 - LOG.debug("Table entry deleted! > deviceId={}, entryId={}/{}", deviceId, tableName, entryId); 173 + log.debug("Table entry deleted! > deviceId={}, entryId={}/{}", deviceId, tableName, entryId);
319 } catch (TException e) { 174 } catch (TException e) {
320 - LOG.debug("Exception while deleting table entry: {} > deviceId={}, entryId={}/{}", 175 + log.debug("Exception while deleting table entry: {} > deviceId={}, entryId={}/{}",
321 e, deviceId, tableName, entryId); 176 e, deviceId, tableName, entryId);
322 - throw new Bmv2RuntimeException(e.getMessage(), e); 177 + throw parseTException(e);
323 } 178 }
324 } 179 }
325 180
...@@ -327,7 +182,7 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -327,7 +182,7 @@ public final class Bmv2ThriftClient implements Bmv2Client {
327 public final void setTableDefaultAction(String tableName, Bmv2Action action) 182 public final void setTableDefaultAction(String tableName, Bmv2Action action)
328 throws Bmv2RuntimeException { 183 throws Bmv2RuntimeException {
329 184
330 - LOG.debug("Setting table default... > deviceId={}, tableName={}, action={}", deviceId, tableName, action); 185 + log.debug("Setting table default... > deviceId={}, tableName={}, action={}", deviceId, tableName, action);
331 186
332 try { 187 try {
333 standardClient.bm_mt_set_default_action( 188 standardClient.bm_mt_set_default_action(
...@@ -335,226 +190,239 @@ public final class Bmv2ThriftClient implements Bmv2Client { ...@@ -335,226 +190,239 @@ public final class Bmv2ThriftClient implements Bmv2Client {
335 tableName, 190 tableName,
336 action.name(), 191 action.name(),
337 buildActionParamsList(action)); 192 buildActionParamsList(action));
338 - LOG.debug("Table default set! > deviceId={}, tableName={}, action={}", deviceId, tableName, action); 193 + log.debug("Table default set! > deviceId={}, tableName={}, action={}", deviceId, tableName, action);
339 } catch (TException e) { 194 } catch (TException e) {
340 - LOG.debug("Exception while setting table default : {} > deviceId={}, tableName={}, action={}", 195 + log.debug("Exception while setting table default : {} > deviceId={}, tableName={}, action={}",
341 e, deviceId, tableName, action); 196 e, deviceId, tableName, action);
342 - throw new Bmv2RuntimeException(e.getMessage(), e); 197 + throw parseTException(e);
343 } 198 }
344 } 199 }
345 200
346 @Override 201 @Override
347 public Collection<Bmv2PortInfo> getPortsInfo() throws Bmv2RuntimeException { 202 public Collection<Bmv2PortInfo> getPortsInfo() throws Bmv2RuntimeException {
348 203
349 - LOG.debug("Retrieving port info... > deviceId={}", deviceId); 204 + log.debug("Retrieving port info... > deviceId={}", deviceId);
350 205
351 try { 206 try {
352 - List<DevMgrPortInfo> portInfos = standardClient.bm_dev_mgr_show_ports(); 207 + return standardClient.bm_dev_mgr_show_ports().stream()
353 - 208 + .map(p -> new Bmv2PortInfo(p.getIface_name(), p.getPort_num(), p.isIs_up()))
354 - Collection<Bmv2PortInfo> bmv2PortInfos = Lists.newArrayList(); 209 + .collect(Collectors.toList());
355 -
356 - bmv2PortInfos.addAll(
357 - portInfos.stream()
358 - .map(Bmv2PortInfo::new)
359 - .collect(Collectors.toList()));
360 -
361 - LOG.debug("Port info retrieved! > deviceId={}, portInfos={}", deviceId, bmv2PortInfos);
362 -
363 - return bmv2PortInfos;
364 -
365 } catch (TException e) { 210 } catch (TException e) {
366 - LOG.debug("Exception while retrieving port info: {} > deviceId={}", e, deviceId); 211 + log.debug("Exception while retrieving port info: {} > deviceId={}", e, deviceId);
367 - throw new Bmv2RuntimeException(e.getMessage(), e); 212 + throw parseTException(e);
368 } 213 }
369 } 214 }
370 215
371 @Override 216 @Override
372 public String dumpTable(String tableName) throws Bmv2RuntimeException { 217 public String dumpTable(String tableName) throws Bmv2RuntimeException {
373 218
374 - LOG.debug("Retrieving table dump... > deviceId={}, tableName={}", deviceId, tableName); 219 + log.debug("Retrieving table dump... > deviceId={}, tableName={}", deviceId, tableName);
375 220
376 try { 221 try {
377 String dump = standardClient.bm_dump_table(CONTEXT_ID, tableName); 222 String dump = standardClient.bm_dump_table(CONTEXT_ID, tableName);
378 - LOG.debug("Table dump retrieved! > deviceId={}, tableName={}", deviceId, tableName); 223 + log.debug("Table dump retrieved! > deviceId={}, tableName={}", deviceId, tableName);
379 return dump; 224 return dump;
380 } catch (TException e) { 225 } catch (TException e) {
381 - LOG.debug("Exception while retrieving table dump: {} > deviceId={}, tableName={}", 226 + log.debug("Exception while retrieving table dump: {} > deviceId={}, tableName={}",
382 e, deviceId, tableName); 227 e, deviceId, tableName);
383 - throw new Bmv2RuntimeException(e.getMessage(), e); 228 + throw parseTException(e);
384 } 229 }
385 } 230 }
386 231
387 @Override 232 @Override
388 - public List<Long> getInstalledEntryIds(String tableName) throws Bmv2RuntimeException {
389 -
390 - LOG.debug("Getting entry ids... > deviceId={}, tableName={}", deviceId, tableName);
391 -
392 - try {
393 - List<Long> entryIds = TABLE_DUMP_PARSER.getEntryIds(dumpTable(tableName));
394 - LOG.debug("Entry ids retrieved! > deviceId={}, tableName={}, entryIdsCount={}",
395 - deviceId, tableName, entryIds.size());
396 - return entryIds;
397 - } catch (Bmv2TableDumpParser.Bmv2TableDumpParserException e) {
398 - LOG.debug("Exception while retrieving entry ids: {} > deviceId={}, tableName={}",
399 - e, deviceId, tableName);
400 - throw new Bmv2RuntimeException(e.getMessage(), e);
401 - }
402 - }
403 -
404 - @Override
405 - public int cleanupTable(String tableName) throws Bmv2RuntimeException {
406 -
407 - LOG.debug("Starting table cleanup... > deviceId={}, tableName={}", deviceId, tableName);
408 -
409 - List<Long> entryIds = getInstalledEntryIds(tableName);
410 -
411 - int count = 0;
412 - for (Long entryId : entryIds) {
413 - try {
414 - standardClient.bm_mt_delete_entry(CONTEXT_ID, tableName, entryId);
415 - count++;
416 - } catch (TException e) {
417 - LOG.warn("Exception while deleting entry: {} > deviceId={}, tableName={}, entryId={}",
418 - e.toString(), deviceId, tableName, entryId);
419 - }
420 - }
421 -
422 - return count;
423 - }
424 -
425 - @Override
426 public void transmitPacket(int portNumber, ImmutableByteSequence packet) throws Bmv2RuntimeException { 233 public void transmitPacket(int portNumber, ImmutableByteSequence packet) throws Bmv2RuntimeException {
427 234
428 - LOG.debug("Requesting packet transmission... > portNumber={}, packet={}", portNumber, packet); 235 + log.debug("Requesting packet transmission... > portNumber={}, packetSize={}", portNumber, packet.size());
429 236
430 try { 237 try {
431 238
432 simpleSwitchClient.push_packet(portNumber, ByteBuffer.wrap(packet.asArray())); 239 simpleSwitchClient.push_packet(portNumber, ByteBuffer.wrap(packet.asArray()));
433 - LOG.debug("Packet transmission requested! > portNumber={}, packet={}", portNumber, packet); 240 + log.debug("Packet transmission requested! > portNumber={}, packetSize={}", portNumber, packet.size());
434 } catch (TException e) { 241 } catch (TException e) {
435 - LOG.debug("Exception while requesting packet transmission: {} > portNumber={}, packet={}", 242 + log.debug("Exception while requesting packet transmission: {} > portNumber={}, packetSize={}",
436 - e, portNumber, packet); 243 + e, portNumber, packet.size());
437 - throw new Bmv2RuntimeException(e.getMessage(), e); 244 + throw parseTException(e);
438 } 245 }
439 } 246 }
440 247
441 @Override 248 @Override
442 public void resetState() throws Bmv2RuntimeException { 249 public void resetState() throws Bmv2RuntimeException {
443 250
444 - LOG.debug("Resetting device state... > deviceId={}", deviceId); 251 + log.debug("Resetting device state... > deviceId={}", deviceId);
445 252
446 try { 253 try {
447 standardClient.bm_reset_state(); 254 standardClient.bm_reset_state();
448 - LOG.debug("Device state reset! > deviceId={}", deviceId); 255 + log.debug("Device state reset! > deviceId={}", deviceId);
449 } catch (TException e) { 256 } catch (TException e) {
450 - LOG.debug("Exception while resetting device state: {} > deviceId={}", e, deviceId); 257 + log.debug("Exception while resetting device state: {} > deviceId={}", e, deviceId);
451 - throw new Bmv2RuntimeException(e.getMessage(), e); 258 + throw parseTException(e);
452 } 259 }
453 } 260 }
454 261
455 @Override 262 @Override
456 public String dumpJsonConfig() throws Bmv2RuntimeException { 263 public String dumpJsonConfig() throws Bmv2RuntimeException {
457 264
458 - LOG.debug("Dumping device config... > deviceId={}", deviceId); 265 + log.debug("Dumping device config... > deviceId={}", deviceId);
459 266
460 try { 267 try {
461 String config = standardClient.bm_get_config(); 268 String config = standardClient.bm_get_config();
462 - LOG.debug("Device config dumped! > deviceId={}, configLength={}", deviceId, config.length()); 269 + log.debug("Device config dumped! > deviceId={}, configLength={}", deviceId, config.length());
463 return config; 270 return config;
464 } catch (TException e) { 271 } catch (TException e) {
465 - LOG.debug("Exception while dumping device config: {} > deviceId={}", e, deviceId); 272 + log.debug("Exception while dumping device config: {} > deviceId={}", e, deviceId);
466 - throw new Bmv2RuntimeException(e.getMessage(), e); 273 + throw parseTException(e);
467 } 274 }
468 } 275 }
469 276
470 @Override 277 @Override
471 public Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException { 278 public Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException {
472 279
473 - LOG.debug("Reading table entry counters... > deviceId={}, tableName={}, entryId={}", 280 + log.debug("Reading table entry counters... > deviceId={}, tableName={}, entryId={}",
474 deviceId, tableName, entryId); 281 deviceId, tableName, entryId);
475 282
476 try { 283 try {
477 BmCounterValue counterValue = standardClient.bm_mt_read_counter(CONTEXT_ID, tableName, entryId); 284 BmCounterValue counterValue = standardClient.bm_mt_read_counter(CONTEXT_ID, tableName, entryId);
478 - LOG.debug("Table entry counters retrieved! > deviceId={}, tableName={}, entryId={}, bytes={}, packets={}", 285 + log.debug("Table entry counters retrieved! > deviceId={}, tableName={}, entryId={}, bytes={}, packets={}",
479 deviceId, tableName, entryId, counterValue.bytes, counterValue.packets); 286 deviceId, tableName, entryId, counterValue.bytes, counterValue.packets);
480 return Pair.of(counterValue.bytes, counterValue.packets); 287 return Pair.of(counterValue.bytes, counterValue.packets);
481 } catch (TException e) { 288 } catch (TException e) {
482 - LOG.debug("Exception while reading table counters: {} > deviceId={}, tableName={}, entryId={}", 289 + log.debug("Exception while reading table counters: {} > deviceId={}, tableName={}, entryId={}",
290 + e.toString(), deviceId);
291 + throw parseTException(e);
292 + }
293 + }
294 +
295 + @Override
296 + public Pair<Long, Long> readCounter(String counterName, int index) throws Bmv2RuntimeException {
297 +
298 + log.debug("Reading table entry counters... > deviceId={}, counterName={}, index={}",
299 + deviceId, counterName, index);
300 +
301 + try {
302 + BmCounterValue counterValue = standardClient.bm_counter_read(CONTEXT_ID, counterName, index);
303 + log.debug("Table entry counters retrieved! >deviceId={}, counterName={}, index={}, bytes={}, packets={}",
304 + deviceId, counterName, index, counterValue.bytes, counterValue.packets);
305 + return Pair.of(counterValue.bytes, counterValue.packets);
306 + } catch (TException e) {
307 + log.debug("Exception while reading table counters: {} > deviceId={}, counterName={}, index={}",
483 e.toString(), deviceId); 308 e.toString(), deviceId);
484 - throw new Bmv2RuntimeException(e.getMessage(), e); 309 + throw parseTException(e);
310 + }
311 + }
312 +
313 + @Override
314 + public int getProcessInstanceId() throws Bmv2RuntimeException {
315 + log.debug("Getting process instance ID... > deviceId={}", deviceId);
316 + try {
317 + int instanceId = simpleSwitchClient.get_process_instance_id();
318 + log.debug("TProcess instance ID retrieved! > deviceId={}, instanceId={}",
319 + deviceId, instanceId);
320 + return instanceId;
321 + } catch (TException e) {
322 + log.debug("Exception while getting process instance ID: {} > deviceId={}", e.toString(), deviceId);
323 + throw parseTException(e);
485 } 324 }
486 } 325 }
487 326
488 @Override 327 @Override
489 public String getJsonConfigMd5() throws Bmv2RuntimeException { 328 public String getJsonConfigMd5() throws Bmv2RuntimeException {
490 329
491 - LOG.debug("Getting device config md5... > deviceId={}", deviceId); 330 + log.debug("Getting device config md5... > deviceId={}", deviceId);
492 331
493 try { 332 try {
494 String md5 = standardClient.bm_get_config_md5(); 333 String md5 = standardClient.bm_get_config_md5();
495 - LOG.debug("Device config md5 received! > deviceId={}, configMd5={}", deviceId, md5); 334 + log.debug("Device config md5 received! > deviceId={}, configMd5={}", deviceId, md5);
496 return md5; 335 return md5;
497 } catch (TException e) { 336 } catch (TException e) {
498 - LOG.debug("Exception while getting device config md5: {} > deviceId={}", e, deviceId); 337 + log.debug("Exception while getting device config md5: {} > deviceId={}", e, deviceId);
499 - throw new Bmv2RuntimeException(e.getMessage(), e); 338 + throw parseTException(e);
500 } 339 }
501 } 340 }
502 341
503 - /** 342 + @Override
504 - * Transport/client cache loader. 343 + public void loadNewJsonConfig(String jsonString) throws Bmv2RuntimeException {
505 - */ 344 +
506 - private static class ClientLoader 345 + log.debug("Loading new JSON config on device... > deviceId={}, jsonStringLength={}",
507 - extends CacheLoader<DeviceId, Bmv2ThriftClient> { 346 + deviceId, jsonString.length());
508 - 347 +
509 - private static final Options RECONN_OPTIONS = new Options(NUM_CONNECTION_RETRIES, TIME_BETWEEN_RETRIES); 348 + try {
510 - 349 + standardClient.bm_load_new_config(jsonString);
511 - @Override 350 + log.debug("JSON config loaded! > deviceId={}", deviceId);
512 - public Bmv2ThriftClient load(DeviceId deviceId) 351 + } catch (TException e) {
513 - throws TTransportException { 352 + log.debug("Exception while loading JSON config: {} > deviceId={}", e, deviceId);
514 - LOG.debug("Creating new client in cache... > deviceId={}", deviceId); 353 + throw parseTException(e);
515 - Pair<String, Integer> info = parseDeviceId(deviceId); 354 + }
516 - //make the expensive call 355 + }
517 - TTransport transport = new TSocket( 356 +
518 - info.getLeft(), info.getRight()); 357 + @Override
519 - TProtocol protocol = new TBinaryProtocol(transport); 358 + public void swapJsonConfig() throws Bmv2RuntimeException {
520 - // Our BMv2 device implements multiple Thrift services, create a client for each one on the same transport. 359 +
521 - Standard.Client standardClient = new Standard.Client( 360 + log.debug("Swapping JSON config on device... > deviceId={}", deviceId);
522 - new TMultiplexedProtocol(protocol, "standard")); 361 +
523 - SimpleSwitch.Client simpleSwitch = new SimpleSwitch.Client( 362 + try {
524 - new TMultiplexedProtocol(protocol, "simple_switch")); 363 + standardClient.bm_swap_configs();
525 - // Wrap clients so to automatically have synchronization and resiliency to connectivity errors 364 + log.debug("JSON config swapped! > deviceId={}", deviceId);
526 - Standard.Iface safeStandardClient = SafeThriftClient.wrap(standardClient, 365 + } catch (TException e) {
527 - Standard.Iface.class, 366 + log.debug("Exception while swapping JSON config: {} > deviceId={}", e, deviceId);
528 - RECONN_OPTIONS); 367 + throw parseTException(e);
529 - SimpleSwitch.Iface safeSimpleSwitchClient = SafeThriftClient.wrap(simpleSwitch,
530 - SimpleSwitch.Iface.class,
531 - RECONN_OPTIONS);
532 -
533 - return new Bmv2ThriftClient(deviceId, transport, safeStandardClient, safeSimpleSwitchClient);
534 } 368 }
535 } 369 }
536 370
537 /** 371 /**
538 - * Client cache removal listener. Close the connection on cache removal. 372 + * Builds a list of Bmv2/Thrift compatible match parameters.
373 + *
374 + * @param matchKey a bmv2 matchKey
375 + * @return list of thrift-compatible bm match parameters
539 */ 376 */
540 - private static class ClientRemovalListener implements 377 + private static List<BmMatchParam> buildMatchParamsList(Bmv2MatchKey matchKey) {
541 - RemovalListener<DeviceId, Bmv2ThriftClient> { 378 + List<BmMatchParam> paramsList = Lists.newArrayList();
542 - 379 + matchKey.matchParams().forEach(x -> {
543 - @Override 380 + ByteBuffer value;
544 - public void onRemoval(RemovalNotification<DeviceId, Bmv2ThriftClient> notification) { 381 + ByteBuffer mask;
545 - // close the transport connection 382 + switch (x.type()) {
546 - Bmv2ThriftClient client = notification.getValue(); 383 + case EXACT:
547 - // Locking here is ugly, but needed (see SafeThriftClient). 384 + value = ByteBuffer.wrap(((Bmv2ExactMatchParam) x).value().asArray());
548 - synchronized (client.transport) { 385 + paramsList.add(
549 - LOG.debug("Closing transport session... > deviceId={}", client.deviceId); 386 + new BmMatchParam(BmMatchParamType.EXACT)
550 - if (client.transport.isOpen()) { 387 + .setExact(new BmMatchParamExact(value)));
551 - client.transport.close(); 388 + break;
552 - LOG.debug("Transport session closed! > deviceId={}", client.deviceId); 389 + case TERNARY:
553 - } else { 390 + value = ByteBuffer.wrap(((Bmv2TernaryMatchParam) x).value().asArray());
554 - LOG.debug("Transport session was already closed! deviceId={}", client.deviceId); 391 + mask = ByteBuffer.wrap(((Bmv2TernaryMatchParam) x).mask().asArray());
555 - } 392 + paramsList.add(
393 + new BmMatchParam(BmMatchParamType.TERNARY)
394 + .setTernary(new BmMatchParamTernary(value, mask)));
395 + break;
396 + case LPM:
397 + value = ByteBuffer.wrap(((Bmv2LpmMatchParam) x).value().asArray());
398 + int prefixLength = ((Bmv2LpmMatchParam) x).prefixLength();
399 + paramsList.add(
400 + new BmMatchParam(BmMatchParamType.LPM)
401 + .setLpm(new BmMatchParamLPM(value, prefixLength)));
402 + break;
403 + case VALID:
404 + boolean flag = ((Bmv2ValidMatchParam) x).flag();
405 + paramsList.add(
406 + new BmMatchParam(BmMatchParamType.VALID)
407 + .setValid(new BmMatchParamValid(flag)));
408 + break;
409 + default:
410 + // should never be here
411 + throw new RuntimeException("Unknown match param type " + x.type().name());
556 } 412 }
557 - LOG.debug("Removing client from cache... > deviceId={}", client.deviceId); 413 + });
558 - } 414 + return paramsList;
415 + }
416 +
417 + /**
418 + * Build a list of Bmv2/Thrift compatible action parameters.
419 + *
420 + * @param action an action object
421 + * @return list of ByteBuffers
422 + */
423 + private static List<ByteBuffer> buildActionParamsList(Bmv2Action action) {
424 + List<ByteBuffer> buffers = Lists.newArrayList();
425 + action.parameters().forEach(p -> buffers.add(ByteBuffer.wrap(p.asArray())));
426 + return buffers;
559 } 427 }
560 } 428 }
......
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.bmv2.ctl;
18 +
19 +import com.google.common.annotations.Beta;
20 +import com.google.common.collect.Sets;
21 +import org.onlab.util.ImmutableByteSequence;
22 +import org.onosproject.bmv2.api.context.Bmv2ActionModel;
23 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
24 +import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
25 +import org.onosproject.bmv2.api.context.Bmv2FieldModel;
26 +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
27 +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslatorException;
28 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
29 +import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
30 +import org.onosproject.bmv2.api.context.Bmv2RuntimeDataModel;
31 +import org.onosproject.bmv2.api.context.Bmv2TableKeyModel;
32 +import org.onosproject.bmv2.api.context.Bmv2TableModel;
33 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
34 +import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
35 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
36 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
37 +import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
38 +import org.onosproject.bmv2.api.runtime.Bmv2MatchKey;
39 +import org.onosproject.bmv2.api.runtime.Bmv2MatchParam;
40 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
41 +import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam;
42 +import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
43 +import org.onosproject.net.flow.FlowRule;
44 +import org.onosproject.net.flow.TrafficSelector;
45 +import org.onosproject.net.flow.TrafficTreatment;
46 +import org.onosproject.net.flow.criteria.Criterion;
47 +import org.onosproject.net.flow.criteria.EthCriterion;
48 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
49 +import org.onosproject.net.flow.criteria.ExtensionCriterion;
50 +import org.onosproject.net.flow.criteria.PortCriterion;
51 +import org.onosproject.net.flow.instructions.ExtensionTreatment;
52 +import org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes;
53 +import org.onosproject.net.flow.instructions.Instruction;
54 +import org.onosproject.net.flow.instructions.Instructions;
55 +import org.onosproject.net.flow.instructions.Instructions.ExtensionInstructionWrapper;
56 +import org.slf4j.Logger;
57 +import org.slf4j.LoggerFactory;
58 +
59 +import java.util.Collections;
60 +import java.util.Map;
61 +import java.util.Optional;
62 +import java.util.Set;
63 +import java.util.stream.Collectors;
64 +
65 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.roundToBytes;
66 +import static org.onosproject.net.flow.criteria.Criterion.Type.EXTENSION;
67 +import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.BMV2_MATCH_PARAMS;
68 +
69 +/**
70 + * Default implementation of a BMv2 flow rule translator.
71 + */
72 +@Beta
73 +public class Bmv2FlowRuleTranslatorImpl implements Bmv2FlowRuleTranslator {
74 +
75 + private final Logger log = LoggerFactory.getLogger(this.getClass());
76 +
77 + @Override
78 + public Bmv2TableEntry translate(FlowRule rule, Bmv2DeviceContext context)
79 + throws Bmv2FlowRuleTranslatorException {
80 +
81 + Bmv2Configuration configuration = context.configuration();
82 + Bmv2Interpreter interpreter = context.interpreter();
83 +
84 + int tableId = rule.tableId();
85 + String tableName = interpreter.tableIdMap().get(tableId);
86 +
87 + Bmv2TableModel table = (tableName == null) ? configuration.table(tableId) : configuration.table(tableName);
88 +
89 + if (table == null) {
90 + throw new Bmv2FlowRuleTranslatorException("Unknown table ID: " + tableId);
91 + }
92 +
93 + /* Translate selector */
94 + Bmv2MatchKey bmv2MatchKey = buildMatchKey(interpreter, rule.selector(), table);
95 +
96 + /* Translate treatment */
97 + TrafficTreatment treatment = rule.treatment();
98 + Bmv2Action bmv2Action = null;
99 + // If treatment has only 1 instruction of type extension, use that
100 + for (Instruction inst : treatment.allInstructions()) {
101 + if (inst.type() == Instruction.Type.EXTENSION) {
102 + if (treatment.allInstructions().size() == 1) {
103 + bmv2Action = getActionFromExtension((ExtensionInstructionWrapper) inst);
104 + } else {
105 + throw new Bmv2FlowRuleTranslatorException("Unable to translate traffic treatment, found multiple " +
106 + "instructions of which one is an extension: " +
107 + treatment.toString());
108 + }
109 + }
110 + }
111 +
112 + if (bmv2Action == null) {
113 + // No extension, use interpreter to build action.
114 + try {
115 + bmv2Action = interpreter.mapTreatment(treatment, configuration);
116 + } catch (Bmv2InterpreterException e) {
117 + throw new Bmv2FlowRuleTranslatorException("Unable to translate treatment. " + e.toString());
118 + }
119 + }
120 +
121 + if (bmv2Action == null) {
122 + // Interpreter returned null.
123 + throw new Bmv2FlowRuleTranslatorException("Unable to translate treatment");
124 + }
125 +
126 + // Check action
127 + Bmv2ActionModel actionModel = configuration.action(bmv2Action.name());
128 + if (actionModel == null) {
129 + throw new Bmv2FlowRuleTranslatorException("Unknown action " + bmv2Action.name());
130 + }
131 + if (!table.actions().contains(actionModel)) {
132 + throw new Bmv2FlowRuleTranslatorException("Action " + bmv2Action.name()
133 + + " is not defined for table " + tableName);
134 + }
135 + if (actionModel.runtimeDatas().size() != bmv2Action.parameters().size()) {
136 + throw new Bmv2FlowRuleTranslatorException("Wrong number of parameters for action "
137 + + actionModel.name() + ", expected "
138 + + actionModel.runtimeDatas().size() + ", but found "
139 + + bmv2Action.parameters().size());
140 + }
141 + for (int i = 0; i < actionModel.runtimeDatas().size(); i++) {
142 + Bmv2RuntimeDataModel data = actionModel.runtimeDatas().get(i);
143 + ImmutableByteSequence param = bmv2Action.parameters().get(i);
144 + if (param.size() != roundToBytes(data.bitWidth())) {
145 + throw new Bmv2FlowRuleTranslatorException("Wrong byte-width for parameter " + data.name()
146 + + " of action " + actionModel.name()
147 + + ", expected " + roundToBytes(data.bitWidth())
148 + + " bytes, but found " + param.size());
149 + }
150 + }
151 +
152 + Bmv2TableEntry.Builder tableEntryBuilder = Bmv2TableEntry.builder();
153 +
154 + // In BMv2 0 is the highest priority.
155 + int newPriority = Integer.MAX_VALUE - rule.priority();
156 +
157 + tableEntryBuilder
158 + .withTableName(table.name())
159 + .withPriority(newPriority)
160 + .withMatchKey(bmv2MatchKey)
161 + .withAction(bmv2Action);
162 +
163 + if (!rule.isPermanent()) {
164 + if (table.hasTimeouts()) {
165 + tableEntryBuilder.withTimeout((double) rule.timeout());
166 + } else {
167 + log.warn("Flow rule is temporary but table {} doesn't support timeouts, translating to permanent",
168 + table.name());
169 + }
170 +
171 + }
172 +
173 + return tableEntryBuilder.build();
174 + }
175 +
176 + private Bmv2TernaryMatchParam buildTernaryParam(Bmv2FieldModel field, Criterion criterion, int bitWidth)
177 + throws Bmv2FlowRuleTranslatorException {
178 +
179 + // Value and mask will be filled according to criterion type
180 + ImmutableByteSequence value;
181 + ImmutableByteSequence mask = null;
182 +
183 + int byteWidth = roundToBytes(bitWidth);
184 +
185 + switch (criterion.type()) {
186 + case IN_PORT:
187 + long port = ((PortCriterion) criterion).port().toLong();
188 + value = ImmutableByteSequence.copyFrom(port);
189 + break;
190 + case ETH_DST:
191 + EthCriterion c = (EthCriterion) criterion;
192 + value = ImmutableByteSequence.copyFrom(c.mac().toBytes());
193 + if (c.mask() != null) {
194 + mask = ImmutableByteSequence.copyFrom(c.mask().toBytes());
195 + }
196 + break;
197 + case ETH_SRC:
198 + EthCriterion c2 = (EthCriterion) criterion;
199 + value = ImmutableByteSequence.copyFrom(c2.mac().toBytes());
200 + if (c2.mask() != null) {
201 + mask = ImmutableByteSequence.copyFrom(c2.mask().toBytes());
202 + }
203 + break;
204 + case ETH_TYPE:
205 + short ethType = ((EthTypeCriterion) criterion).ethType().toShort();
206 + value = ImmutableByteSequence.copyFrom(ethType);
207 + break;
208 + // TODO: implement building for other criterion types (easy with DefaultCriterion of ONOS-4034)
209 + default:
210 + throw new Bmv2FlowRuleTranslatorException("Feature not implemented, ternary builder for criterion" +
211 + "type: " + criterion.type().name());
212 + }
213 +
214 + // Fit byte sequence in field model bit-width.
215 + try {
216 + value = Bmv2TranslatorUtils.fitByteSequence(value, bitWidth);
217 + } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
218 + throw new Bmv2FlowRuleTranslatorException(
219 + "Fit exception for criterion " + criterion.type().name() + " value, " + e.getMessage());
220 + }
221 +
222 + if (mask == null) {
223 + // no mask, all ones
224 + mask = ImmutableByteSequence.ofOnes(byteWidth);
225 + } else {
226 + try {
227 + mask = Bmv2TranslatorUtils.fitByteSequence(mask, bitWidth);
228 + } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
229 + throw new Bmv2FlowRuleTranslatorException(
230 + "Fit exception for criterion " + criterion.type().name() + " mask, " + e.getMessage());
231 + }
232 + }
233 +
234 + return new Bmv2TernaryMatchParam(value, mask);
235 + }
236 +
237 + private Bmv2Action getActionFromExtension(Instructions.ExtensionInstructionWrapper inst)
238 + throws Bmv2FlowRuleTranslatorException {
239 +
240 + ExtensionTreatment extTreatment = inst.extensionInstruction();
241 +
242 + if (extTreatment.type() == ExtensionTreatmentTypes.BMV2_ACTION.type()) {
243 + if (extTreatment instanceof Bmv2ExtensionTreatment) {
244 + return ((Bmv2ExtensionTreatment) extTreatment).getAction();
245 + } else {
246 + throw new Bmv2FlowRuleTranslatorException("Unable to decode treatment extension: " + extTreatment);
247 + }
248 + } else {
249 + throw new Bmv2FlowRuleTranslatorException("Unsupported treatment extension type: " + extTreatment.type());
250 + }
251 + }
252 +
253 + private Bmv2MatchKey buildMatchKey(Bmv2Interpreter interpreter, TrafficSelector selector, Bmv2TableModel tableModel)
254 + throws Bmv2FlowRuleTranslatorException {
255 +
256 + // Find a bmv2 extension selector (if any) and get the parameter map.
257 + Optional<Bmv2ExtensionSelector> extSelector = selector.criteria().stream()
258 + .filter(c -> c.type().equals(EXTENSION))
259 + .map(c -> (ExtensionCriterion) c)
260 + .map(ExtensionCriterion::extensionSelector)
261 + .filter(c -> c.type().equals(BMV2_MATCH_PARAMS.type()))
262 + .map(c -> (Bmv2ExtensionSelector) c)
263 + .findFirst();
264 + Map<String, Bmv2MatchParam> extParamMap =
265 + (extSelector.isPresent()) ? extSelector.get().parameterMap() : Collections.emptyMap();
266 +
267 + Set<Criterion> translatedCriteria = Sets.newHashSet();
268 + Set<String> usedExtParams = Sets.newHashSet();
269 +
270 + Bmv2MatchKey.Builder matchKeyBuilder = Bmv2MatchKey.builder();
271 +
272 + keysLoop:
273 + for (Bmv2TableKeyModel keyModel : tableModel.keys()) {
274 +
275 + // use fieldName dot notation (e.g. ethernet.dstAddr)
276 + String fieldName = keyModel.field().header().name() + "." + keyModel.field().type().name();
277 +
278 + int bitWidth = keyModel.field().type().bitWidth();
279 + int byteWidth = roundToBytes(bitWidth);
280 +
281 + Criterion.Type criterionType = interpreter.criterionTypeMap().inverse().get(fieldName);
282 +
283 + if (!extParamMap.containsKey(fieldName) &&
284 + (criterionType == null || selector.getCriterion(criterionType) == null)) {
285 + // Neither an extension nor a mapping / criterion is available for this field.
286 + switch (keyModel.matchType()) {
287 + case TERNARY:
288 + // Wildcard field
289 + matchKeyBuilder.withWildcard(byteWidth);
290 + break;
291 + case LPM:
292 + // LPM with prefix 0
293 + matchKeyBuilder.add(new Bmv2LpmMatchParam(ImmutableByteSequence.ofZeros(byteWidth), 0));
294 + break;
295 + default:
296 + throw new Bmv2FlowRuleTranslatorException("No value found for required match field "
297 + + fieldName);
298 + }
299 + // Next key
300 + continue keysLoop;
301 + }
302 +
303 + Bmv2MatchParam matchParam;
304 +
305 + if (extParamMap.containsKey(fieldName)) {
306 + // Parameter found in extension
307 + if (criterionType != null && selector.getCriterion(criterionType) != null) {
308 + // Found also a criterion that can be mapped. This is bad.
309 + throw new Bmv2FlowRuleTranslatorException("Both an extension and a criterion mapping are defined " +
310 + "for match field " + fieldName);
311 + }
312 +
313 + matchParam = extParamMap.get(fieldName);
314 + usedExtParams.add(fieldName);
315 +
316 + // Check parameter type and size
317 + if (!keyModel.matchType().equals(matchParam.type())) {
318 + throw new Bmv2FlowRuleTranslatorException("Wrong match type for parameter " + fieldName
319 + + ", expected " + keyModel.matchType().name()
320 + + ", but found " + matchParam.type().name());
321 + }
322 + int foundByteWidth;
323 + switch (keyModel.matchType()) {
324 + case EXACT:
325 + Bmv2ExactMatchParam m1 = (Bmv2ExactMatchParam) matchParam;
326 + foundByteWidth = m1.value().size();
327 + break;
328 + case TERNARY:
329 + Bmv2TernaryMatchParam m2 = (Bmv2TernaryMatchParam) matchParam;
330 + foundByteWidth = m2.value().size();
331 + break;
332 + case LPM:
333 + Bmv2LpmMatchParam m3 = (Bmv2LpmMatchParam) matchParam;
334 + foundByteWidth = m3.value().size();
335 + break;
336 + case VALID:
337 + foundByteWidth = -1;
338 + break;
339 + default:
340 + // should never be her
341 + throw new RuntimeException("Unrecognized match type " + keyModel.matchType().name());
342 + }
343 + if (foundByteWidth != -1 && foundByteWidth != byteWidth) {
344 + throw new Bmv2FlowRuleTranslatorException("Wrong byte-width for match parameter " + fieldName
345 + + ", expected " + byteWidth + ", but found "
346 + + foundByteWidth);
347 + }
348 +
349 + } else {
350 + // A criterion mapping is available for this key
351 + Criterion criterion = selector.getCriterion(criterionType);
352 + translatedCriteria.add(criterion);
353 + switch (keyModel.matchType()) {
354 + case TERNARY:
355 + matchParam = buildTernaryParam(keyModel.field(), criterion, bitWidth);
356 + break;
357 + default:
358 + // TODO: implement other match param builders (exact, LPM, etc.)
359 + throw new Bmv2FlowRuleTranslatorException("Feature not yet implemented, match param builder: "
360 + + keyModel.matchType().name());
361 + }
362 + }
363 +
364 + matchKeyBuilder.add(matchParam);
365 + }
366 +
367 + // Check if all criteria have been translated
368 + Set<Criterion> ignoredCriteria = selector.criteria()
369 + .stream()
370 + .filter(c -> !c.type().equals(EXTENSION))
371 + .filter(c -> !translatedCriteria.contains(c))
372 + .collect(Collectors.toSet());
373 +
374 + if (ignoredCriteria.size() > 0) {
375 + throw new Bmv2FlowRuleTranslatorException("The following criteria cannot be translated for table "
376 + + tableModel.name() + ": " + ignoredCriteria.toString());
377 + }
378 +
379 + // Check is all extension parameters have been used
380 + Set<String> ignoredExtParams = extParamMap.keySet()
381 + .stream()
382 + .filter(k -> !usedExtParams.contains(k))
383 + .collect(Collectors.toSet());
384 +
385 + if (ignoredExtParams.size() > 0) {
386 + throw new Bmv2FlowRuleTranslatorException("The following extension match parameters cannot be used for " +
387 + "table " + tableModel.name() + ": "
388 + + ignoredExtParams.toString());
389 + }
390 +
391 + return matchKeyBuilder.build();
392 + }
393 +
394 +}
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.bmv2.ctl;
18 +
19 +
20 +import org.apache.thrift.TException;
21 +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
22 +import org.onosproject.bmv2.thriftapi.InvalidCounterOperation;
23 +import org.onosproject.bmv2.thriftapi.InvalidDevMgrOperation;
24 +import org.onosproject.bmv2.thriftapi.InvalidLearnOperation;
25 +import org.onosproject.bmv2.thriftapi.InvalidMcOperation;
26 +import org.onosproject.bmv2.thriftapi.InvalidMeterOperation;
27 +import org.onosproject.bmv2.thriftapi.InvalidRegisterOperation;
28 +import org.onosproject.bmv2.thriftapi.InvalidSwapOperation;
29 +import org.onosproject.bmv2.thriftapi.InvalidTableOperation;
30 +
31 +import static org.onosproject.bmv2.api.runtime.Bmv2RuntimeException.Code;
32 +
33 +/**
34 + * Utility class to translate a Thrift exception into a Bmv2RuntimeException.
35 + */
36 +final class Bmv2TExceptionParser {
37 +
38 + private Bmv2TExceptionParser() {
39 + // ban constructor.
40 + }
41 +
42 + static Bmv2RuntimeException parseTException(TException cause) {
43 + try {
44 + return new Bmv2RuntimeException(getCode(cause));
45 + } catch (ParserException e) {
46 + return new Bmv2RuntimeException(e.codeString);
47 + }
48 + }
49 +
50 + private static Code getCode(TException e) throws ParserException {
51 + if (e instanceof InvalidTableOperation) {
52 + InvalidTableOperation t = (InvalidTableOperation) e;
53 + switch (t.getCode()) {
54 + case TABLE_FULL:
55 + return Code.TABLE_FULL;
56 + case INVALID_HANDLE:
57 + return Code.TABLE_INVALID_HANDLE;
58 + case EXPIRED_HANDLE:
59 + return Code.TABLE_EXPIRED_HANDLE;
60 + case COUNTERS_DISABLED:
61 + return Code.TABLE_COUNTERS_DISABLED;
62 + case METERS_DISABLED:
63 + return Code.TABLE_METERS_DISABLED;
64 + case AGEING_DISABLED:
65 + return Code.TABLE_AGEING_DISABLED;
66 + case INVALID_TABLE_NAME:
67 + return Code.TABLE_INVALID_TABLE_NAME;
68 + case INVALID_ACTION_NAME:
69 + return Code.TABLE_INVALID_ACTION_NAME;
70 + case WRONG_TABLE_TYPE:
71 + return Code.TABLE_WRONG_TABLE_TYPE;
72 + case INVALID_MBR_HANDLE:
73 + return Code.TABLE_INVALID_MBR_HANDLE;
74 + case MBR_STILL_USED:
75 + return Code.TABLE_MBR_STILL_USED;
76 + case MBR_ALREADY_IN_GRP:
77 + return Code.TABLE_MBR_ALREADY_IN_GRP;
78 + case MBR_NOT_IN_GRP:
79 + return Code.TABLE_MBR_NOT_IN_GRP;
80 + case INVALID_GRP_HANDLE:
81 + return Code.TABLE_INVALID_GRP_HANDLE;
82 + case GRP_STILL_USED:
83 + return Code.TABLE_GRP_STILL_USED;
84 + case EMPTY_GRP:
85 + return Code.TABLE_EMPTY_GRP;
86 + case DUPLICATE_ENTRY:
87 + return Code.TABLE_DUPLICATE_ENTRY;
88 + case BAD_MATCH_KEY:
89 + return Code.TABLE_BAD_MATCH_KEY;
90 + case INVALID_METER_OPERATION:
91 + return Code.TABLE_INVALID_METER_OPERATION;
92 + case DEFAULT_ACTION_IS_CONST:
93 + return Code.TABLE_DEFAULT_ACTION_IS_CONST;
94 + case DEFAULT_ENTRY_IS_CONST:
95 + return Code.TABLE_DEFAULT_ENTRY_IS_CONST;
96 + case ERROR:
97 + return Code.TABLE_GENERAL_ERROR;
98 + default:
99 + return Code.TABLE_UNKNOWN_ERROR;
100 + }
101 + } else if (e instanceof InvalidCounterOperation) {
102 + InvalidCounterOperation t = (InvalidCounterOperation) e;
103 + switch (t.getCode()) {
104 + case INVALID_COUNTER_NAME:
105 + return Code.COUNTER_INVALID_NAME;
106 + case INVALID_INDEX:
107 + return Code.COUNTER_INVALID_INDEX;
108 + case ERROR:
109 + return Code.COUNTER_ERROR_GENERAL;
110 + default:
111 + return Code.COUNTER_ERROR_UNKNOWN;
112 + }
113 + } else if (e instanceof InvalidDevMgrOperation) {
114 + InvalidDevMgrOperation t = (InvalidDevMgrOperation) e;
115 + switch (t.getCode()) {
116 + case ERROR:
117 + return Code.DEV_MGR_ERROR_GENERAL;
118 + default:
119 + return Code.DEV_MGR_UNKNOWN;
120 + }
121 + } else if (e instanceof InvalidSwapOperation) {
122 + InvalidSwapOperation t = (InvalidSwapOperation) e;
123 + switch (t.getCode()) {
124 + case CONFIG_SWAP_DISABLED:
125 + return Code.SWAP_CONFIG_DISABLED;
126 + case ONGOING_SWAP:
127 + return Code.SWAP_ONGOING;
128 + case NO_ONGOING_SWAP:
129 + return Code.SWAP_NO_ONGOING;
130 + default:
131 + return Code.SWAP_ERROR_UKNOWN;
132 + }
133 + } else if (e instanceof InvalidMeterOperation) {
134 + // TODO
135 + throw new ParserException(e.toString());
136 + } else if (e instanceof InvalidRegisterOperation) {
137 + // TODO
138 + throw new ParserException(e.toString());
139 + } else if (e instanceof InvalidLearnOperation) {
140 + // TODO
141 + throw new ParserException(e.toString());
142 + } else if (e instanceof InvalidMcOperation) {
143 + // TODO
144 + throw new ParserException(e.toString());
145 + } else {
146 + throw new ParserException(e.toString());
147 + }
148 + }
149 +
150 + private static class ParserException extends Exception {
151 +
152 + private String codeString;
153 +
154 + public ParserException(String codeString) {
155 + this.codeString = codeString;
156 + }
157 + }
158 +}
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.bmv2.ctl;
18 +
19 +import com.google.common.cache.CacheBuilder;
20 +import com.google.common.cache.CacheLoader;
21 +import com.google.common.cache.CacheStats;
22 +import com.google.common.cache.LoadingCache;
23 +import com.google.common.collect.Lists;
24 +import org.apache.commons.lang3.tuple.Pair;
25 +import org.onlab.util.HexString;
26 +import org.onlab.util.ImmutableByteSequence;
27 +import org.onlab.util.SharedScheduledExecutors;
28 +import org.onosproject.bmv2.api.context.Bmv2ActionModel;
29 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
30 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
31 +import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
32 +import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
33 +import org.onosproject.bmv2.api.runtime.Bmv2MatchKey;
34 +import org.onosproject.bmv2.api.runtime.Bmv2ParsedTableEntry;
35 +import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam;
36 +import org.slf4j.Logger;
37 +import org.slf4j.LoggerFactory;
38 +
39 +import java.util.Arrays;
40 +import java.util.Collections;
41 +import java.util.List;
42 +import java.util.Optional;
43 +import java.util.concurrent.ExecutionException;
44 +import java.util.concurrent.TimeUnit;
45 +import java.util.regex.Matcher;
46 +import java.util.regex.Pattern;
47 +import java.util.stream.Collectors;
48 +
49 +import static com.google.common.base.Preconditions.checkNotNull;
50 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
51 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.ByteSequenceFitException;
52 +
53 +/**
54 + * BMv2 table dump parser.
55 + */
56 +public final class Bmv2TableDumpParser {
57 +
58 + // Examples of a BMv2 table dump can be found in Bmv2TableDumpParserTest
59 +
60 + // 1: entry id, 2: match string, 3: action string
61 + private static final String ENTRY_PATTERN_REGEX = "(\\d+): (.*) => (.*)";
62 + // 1: match values, 2: masks
63 + private static final String MATCH_TERNARY_PATTERN_REGEX = "([0-9a-fA-F ]+) &&& ([0-9a-fA-F ]+)";
64 + // 1: match values, 2: masks
65 + private static final String MATCH_LPM_PATTERN_REGEX = "([0-9a-fA-F ]+) / ([0-9a-fA-F ]+)";
66 + // 1: match values
67 + private static final String MATCH_EXACT_PATTERN_REGEX = "([0-9a-fA-F ]+)";
68 + // 1: action name, 2: action params
69 + private static final String ACTION_PATTERN_REGEX = "(.+) - ?([0-9a-fA-F ,]*)";
70 +
71 + private static final Pattern ENTRY_PATTERN = Pattern.compile(ENTRY_PATTERN_REGEX);
72 + private static final Pattern MATCH_TERNARY_PATTERN = Pattern.compile(MATCH_TERNARY_PATTERN_REGEX);
73 + private static final Pattern MATCH_LPM_PATTERN = Pattern.compile(MATCH_LPM_PATTERN_REGEX);
74 + private static final Pattern MATCH_EXACT_PATTERN = Pattern.compile(MATCH_EXACT_PATTERN_REGEX);
75 + private static final Pattern ACTION_PATTERN = Pattern.compile(ACTION_PATTERN_REGEX);
76 +
77 + // Cache to avoid re-parsing known lines.
78 + // The assumption here is that entries are not updated too frequently, so that the entry id doesn't change often.
79 + // Otherwise, we should cache only the match and action strings...
80 + private static final LoadingCache<Pair<String, Bmv2Configuration>, Optional<Bmv2ParsedTableEntry>> ENTRY_CACHE =
81 + CacheBuilder.newBuilder()
82 + .expireAfterAccess(60, TimeUnit.SECONDS)
83 + .recordStats()
84 + .build(new CacheLoader<Pair<String, Bmv2Configuration>, Optional<Bmv2ParsedTableEntry>>() {
85 + @Override
86 + public Optional<Bmv2ParsedTableEntry> load(Pair<String, Bmv2Configuration> key) throws Exception {
87 + // Very expensive call.
88 + return Optional.ofNullable(parseLine(key.getLeft(), key.getRight()));
89 + }
90 + });
91 +
92 + private static final Logger log = LoggerFactory.getLogger(Bmv2TableDumpParser.class);
93 +
94 + private static final long STATS_LOG_FREQUENCY = 3; // minutes
95 +
96 + static {
97 + SharedScheduledExecutors.getSingleThreadExecutor().scheduleAtFixedRate(
98 + () -> reportStats(), 0, STATS_LOG_FREQUENCY, TimeUnit.MINUTES);
99 + }
100 +
101 + private Bmv2TableDumpParser() {
102 + // Ban constructor.
103 + }
104 +
105 + /**
106 + * Parse the given BMv2 table dump.
107 + *
108 + * @param tableDump a string value
109 + * @return a list of {@link Bmv2ParsedTableEntry}
110 + */
111 + public static List<Bmv2ParsedTableEntry> parse(String tableDump, Bmv2Configuration configuration) {
112 + checkNotNull(tableDump, "tableDump cannot be null");
113 + // Parse all lines
114 + List<Bmv2ParsedTableEntry> result = Arrays.stream(tableDump.split("\n"))
115 + .map(line -> Pair.of(line, configuration))
116 + .map(Bmv2TableDumpParser::loadFromCache)
117 + .filter(Optional::isPresent)
118 + .map(Optional::get)
119 + .collect(Collectors.toList());
120 + return result;
121 + }
122 +
123 + private static Optional<Bmv2ParsedTableEntry> loadFromCache(Pair<String, Bmv2Configuration> key) {
124 + try {
125 + return ENTRY_CACHE.get(key);
126 + } catch (ExecutionException e) {
127 + Throwable t = e.getCause();
128 + if (t instanceof Bmv2TableDumpParserException) {
129 + Bmv2TableDumpParserException parserException = (Bmv2TableDumpParserException) t;
130 + log.warn("{}", parserException.getMessage());
131 + } else {
132 + log.error("Exception while parsing table dump line", e);
133 + }
134 + return Optional.empty();
135 + }
136 + }
137 +
138 + private static void reportStats() {
139 + CacheStats stats = ENTRY_CACHE.stats();
140 + log.info("Cache stats: requestCount={}, hitRate={}, exceptionsCount={}, avgLoadPenalty={}",
141 + stats.requestCount(), stats.hitRate(), stats.loadExceptionCount(), stats.averageLoadPenalty());
142 + }
143 +
144 + private static Bmv2ParsedTableEntry parseLine(String line, Bmv2Configuration configuration)
145 + throws Bmv2TableDumpParserException {
146 + Matcher matcher = ENTRY_PATTERN.matcher(line);
147 + if (matcher.find()) {
148 + long entryId = parseEntryId(matcher, 1);
149 + String matchString = parseMatchString(matcher, 2);
150 + String actionString = parseActionString(matcher, 3);
151 + Bmv2MatchKey matchKey = parseMatchKey(matchString);
152 + Bmv2Action action = parseAction(actionString, configuration);
153 + return new Bmv2ParsedTableEntry(entryId, matchKey, action);
154 + } else {
155 + // Not a table entry
156 + return null;
157 + }
158 + }
159 +
160 + private static Long parseEntryId(Matcher matcher, int groupIdx) throws Bmv2TableDumpParserException {
161 + String str = matcher.group(groupIdx);
162 + if (str == null) {
163 + throw new Bmv2TableDumpParserException("Unable to find entry ID: " + matcher.group());
164 + }
165 + long entryId;
166 + try {
167 + entryId = Long.valueOf(str.trim());
168 + } catch (NumberFormatException e) {
169 + throw new Bmv2TableDumpParserException("Unable to parse entry id for string: " + matcher.group());
170 + }
171 + return entryId;
172 + }
173 +
174 + private static String parseMatchString(Matcher matcher, int groupIdx) throws Bmv2TableDumpParserException {
175 + String str = matcher.group(groupIdx);
176 + if (str == null) {
177 + throw new Bmv2TableDumpParserException("Unable to find match string: " + matcher.group());
178 + }
179 + return str.trim();
180 + }
181 +
182 + private static String parseActionString(Matcher matcher, int groupIdx) throws Bmv2TableDumpParserException {
183 + String str = matcher.group(groupIdx);
184 + if (str == null) {
185 + throw new Bmv2TableDumpParserException("Unable to find action string: " + matcher.group());
186 + }
187 + return str.trim();
188 + }
189 +
190 + private static Bmv2MatchKey parseMatchKey(String str) throws Bmv2TableDumpParserException {
191 +
192 + Bmv2MatchKey.Builder builder = Bmv2MatchKey.builder();
193 +
194 + // Try with ternary...
195 + Matcher matcher = MATCH_TERNARY_PATTERN.matcher(str);
196 + if (matcher.find()) {
197 + // Ternary Match.
198 + List<ImmutableByteSequence> values = parseMatchValues(matcher, 1);
199 + List<ImmutableByteSequence> masks = parseMatchMasks(matcher, 2, values);
200 + for (int i = 0; i < values.size(); i++) {
201 + builder.add(new Bmv2TernaryMatchParam(values.get(i), masks.get(i)));
202 + }
203 + return builder.build();
204 + }
205 +
206 + // FIXME: LPM match parsing broken if table key contains also a ternary match
207 + // Also it assumes the lpm parameter is the last one, which is wrong.
208 + // Try with LPM...
209 + matcher = MATCH_LPM_PATTERN.matcher(str);
210 + if (matcher.find()) {
211 + // Lpm Match.
212 + List<ImmutableByteSequence> values = parseMatchValues(matcher, 1);
213 + int prefixLength = parseLpmPrefix(matcher, 2);
214 + for (int i = 0; i < values.size() - 1; i++) {
215 + builder.add(new Bmv2ExactMatchParam(values.get(i)));
216 + }
217 + builder.add(new Bmv2LpmMatchParam(values.get(values.size() - 1), prefixLength));
218 + return builder.build();
219 + }
220 +
221 + // Try with exact...
222 + matcher = MATCH_EXACT_PATTERN.matcher(str);
223 + if (matcher.find()) {
224 + // Exact match.
225 + parseMatchValues(matcher, 1)
226 + .stream()
227 + .map(Bmv2ExactMatchParam::new)
228 + .forEach(builder::add);
229 + return builder.build();
230 + }
231 +
232 + throw new Bmv2TableDumpParserException("Unable to parse match string: " + str);
233 + }
234 +
235 + private static List<ImmutableByteSequence> parseMatchValues(Matcher matcher, int groupIdx)
236 + throws Bmv2TableDumpParserException {
237 + String matchString = matcher.group(groupIdx);
238 + if (matchString == null) {
239 + throw new Bmv2TableDumpParserException("Unable to find match params for string: " + matcher.group());
240 + }
241 + List<ImmutableByteSequence> result = Lists.newArrayList();
242 + for (String paramString : matchString.split(" ")) {
243 + byte[] bytes = HexString.fromHexString(paramString, null);
244 + result.add(ImmutableByteSequence.copyFrom(bytes));
245 + }
246 + return result;
247 + }
248 +
249 + private static List<ImmutableByteSequence> parseMatchMasks(Matcher matcher, int groupIdx,
250 + List<ImmutableByteSequence> matchParams)
251 + throws Bmv2TableDumpParserException {
252 + String maskString = matcher.group(groupIdx);
253 + if (maskString == null) {
254 + throw new Bmv2TableDumpParserException("Unable to find mask for string: " + matcher.group());
255 + }
256 + List<ImmutableByteSequence> result = Lists.newArrayList();
257 + /*
258 + Mask here is a hex string with no spaces, hence individual mask params can be derived according
259 + to given matchParam sizes.
260 + */
261 + byte[] maskBytes = HexString.fromHexString(maskString, null);
262 + int startPosition = 0;
263 + for (ImmutableByteSequence bs : matchParams) {
264 + if (startPosition + bs.size() > maskBytes.length) {
265 + throw new Bmv2TableDumpParserException("Invalid length for mask in string: " + matcher.group());
266 + }
267 + ImmutableByteSequence maskParam = ImmutableByteSequence.copyFrom(maskBytes,
268 + startPosition,
269 + startPosition + bs.size() - 1);
270 + result.add(maskParam);
271 + startPosition += bs.size();
272 + }
273 + return result;
274 + }
275 +
276 + private static int parseLpmPrefix(Matcher matcher, int groupIdx)
277 + throws Bmv2TableDumpParserException {
278 + String str = matcher.group(groupIdx);
279 + if (str == null) {
280 + throw new Bmv2TableDumpParserException("Unable to find LPM prefix for string: " + matcher.group());
281 + }
282 + // For some reason the dumped prefix has 16 bits more than the one programmed
283 + try {
284 + return Integer.valueOf(str.trim()) - 16;
285 + } catch (NumberFormatException e) {
286 + throw new Bmv2TableDumpParserException("Unable to parse LPM prefix from string: " + matcher.group());
287 + }
288 + }
289 +
290 + private static Bmv2Action parseAction(String str, Bmv2Configuration configuration)
291 + throws Bmv2TableDumpParserException {
292 + Matcher matcher = ACTION_PATTERN.matcher(str);
293 + if (matcher.find()) {
294 + String actionName = parseActionName(matcher, 1);
295 + Bmv2ActionModel actionModel = configuration.action(actionName);
296 + if (actionModel == null) {
297 + throw new Bmv2TableDumpParserException("Not such an action in configuration: " + actionName);
298 + }
299 + Bmv2Action.Builder builder = Bmv2Action.builder().withName(actionName);
300 + List<ImmutableByteSequence> actionParams = parseActionParams(matcher, 2);
301 + if (actionParams.size() != actionModel.runtimeDatas().size()) {
302 + throw new Bmv2TableDumpParserException("Invalid number of parameters for action: " + actionName);
303 + }
304 + for (int i = 0; i < actionModel.runtimeDatas().size(); i++) {
305 + try {
306 + // fit param byte-width according to configuration.
307 + builder.addParameter(fitByteSequence(actionParams.get(i),
308 + actionModel.runtimeDatas().get(i).bitWidth()));
309 + } catch (ByteSequenceFitException e) {
310 + throw new Bmv2TableDumpParserException("Unable to parse action param: " + e.toString());
311 + }
312 + }
313 + return builder.build();
314 + }
315 + throw new Bmv2TableDumpParserException("Unable to parse action string: " + str.trim());
316 + }
317 +
318 + private static String parseActionName(Matcher matcher, int groupIdx) throws Bmv2TableDumpParserException {
319 + String actionName = matcher.group(groupIdx);
320 + if (actionName == null) {
321 + throw new Bmv2TableDumpParserException("Unable to find action name for string: " + matcher.group());
322 + }
323 + return actionName.trim();
324 + }
325 +
326 + private static List<ImmutableByteSequence> parseActionParams(Matcher matcher, int groupIdx)
327 + throws Bmv2TableDumpParserException {
328 + String paramsString = matcher.group(groupIdx);
329 + if (paramsString == null) {
330 + throw new Bmv2TableDumpParserException("Unable to find action params for string: " + matcher.group());
331 + }
332 + if (paramsString.length() == 0) {
333 + return Collections.emptyList();
334 + }
335 + return Arrays.stream(paramsString.split(","))
336 + .map(String::trim)
337 + .map(s -> HexString.fromHexString(s, null))
338 + .map(ImmutableByteSequence::copyFrom)
339 + .collect(Collectors.toList());
340 + }
341 +
342 + public static class Bmv2TableDumpParserException extends Exception {
343 + public Bmv2TableDumpParserException(String msg) {
344 + super(msg);
345 + }
346 + }
347 +}
...\ No newline at end of file ...\ No newline at end of file
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.bmv2.ctl;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.apache.felix.scr.annotations.Service;
25 +import org.onlab.util.KryoNamespace;
26 +import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
27 +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
28 +import org.onosproject.bmv2.api.service.Bmv2DeviceContextService;
29 +import org.onosproject.bmv2.api.service.Bmv2Controller;
30 +import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
31 +import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
32 +import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper;
33 +import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
34 +import org.onosproject.bmv2.api.runtime.Bmv2MatchKey;
35 +import org.onosproject.bmv2.api.runtime.Bmv2ParsedTableEntry;
36 +import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
37 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference;
38 +import org.onosproject.bmv2.api.service.Bmv2TableEntryService;
39 +import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam;
40 +import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam;
41 +import org.onosproject.net.DeviceId;
42 +import org.onosproject.store.serializers.KryoNamespaces;
43 +import org.onosproject.store.service.EventuallyConsistentMap;
44 +import org.onosproject.store.service.StorageService;
45 +import org.onosproject.store.service.WallClockTimestamp;
46 +import org.slf4j.Logger;
47 +import org.slf4j.LoggerFactory;
48 +
49 +import java.util.Collections;
50 +import java.util.List;
51 +
52 +import static com.google.common.base.Preconditions.checkNotNull;
53 +
54 +/**
55 + * Implementation of the Bmv2TableEntryService.
56 + */
57 +@Component(immediate = true)
58 +@Service
59 +public class Bmv2TableEntryServiceImpl implements Bmv2TableEntryService {
60 +
61 + private final Logger log = LoggerFactory.getLogger(this.getClass());
62 +
63 + private final Bmv2FlowRuleTranslator translator = new Bmv2FlowRuleTranslatorImpl();
64 +
65 + private EventuallyConsistentMap<Bmv2TableEntryReference, Bmv2FlowRuleWrapper> flowRules;
66 +
67 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 + protected StorageService storageService;
69 +
70 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 + protected Bmv2Controller controller;
72 +
73 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 + protected Bmv2DeviceContextService contextService;
75 +
76 +
77 + @Activate
78 + public void activate() {
79 + KryoNamespace kryo = new KryoNamespace.Builder()
80 + .register(KryoNamespaces.API)
81 + .register(Bmv2TableEntryReference.class)
82 + .register(Bmv2MatchKey.class)
83 + .register(Bmv2ExactMatchParam.class)
84 + .register(Bmv2TernaryMatchParam.class)
85 + .register(Bmv2LpmMatchParam.class)
86 + .register(Bmv2ValidMatchParam.class)
87 + .register(Bmv2FlowRuleWrapper.class)
88 + .build();
89 +
90 + flowRules = storageService.<Bmv2TableEntryReference, Bmv2FlowRuleWrapper>eventuallyConsistentMapBuilder()
91 + .withSerializer(kryo)
92 + .withTimestampProvider((k, v) -> new WallClockTimestamp())
93 + .withName("onos-bmv2-flowrules")
94 + .build();
95 +
96 + log.info("Started");
97 + }
98 +
99 + @Deactivate
100 + public void deactivate() {
101 + log.info("Stopped");
102 + }
103 +
104 + @Override
105 + public Bmv2FlowRuleTranslator getFlowRuleTranslator() {
106 + return translator;
107 + }
108 +
109 + @Override
110 + public List<Bmv2ParsedTableEntry> getTableEntries(DeviceId deviceId, String tableName) {
111 + try {
112 + Bmv2DeviceContext context = contextService.getContext(deviceId);
113 + if (context == null) {
114 + log.warn("Unable to get table entries, found null context for {}", deviceId);
115 + return Collections.emptyList();
116 + }
117 + Bmv2DeviceAgent agent = controller.getAgent(deviceId);
118 + String tableDump = agent.dumpTable(tableName);
119 + return Bmv2TableDumpParser.parse(tableDump, context.configuration());
120 + } catch (Bmv2RuntimeException e) {
121 + log.warn("Unable to get table entries for {}: {}", deviceId, e.explain());
122 + return Collections.emptyList();
123 + }
124 + }
125 +
126 + @Override
127 + public Bmv2FlowRuleWrapper lookupEntryReference(Bmv2TableEntryReference entryRef) {
128 + checkNotNull(entryRef, "table entry reference cannot be null");
129 + return flowRules.get(entryRef);
130 + }
131 +
132 + @Override
133 + public void bindEntryReference(Bmv2TableEntryReference entryRef, Bmv2FlowRuleWrapper rule) {
134 + checkNotNull(entryRef, "table entry reference cannot be null");
135 + checkNotNull(rule, "bmv2 flow rule cannot be null");
136 + flowRules.put(entryRef, rule);
137 + }
138 +
139 + @Override
140 + public void unbindEntryReference(Bmv2TableEntryReference entryRef) {
141 + checkNotNull(entryRef, "table entry reference cannot be null");
142 + flowRules.remove(entryRef);
143 + }
144 +}
...@@ -218,8 +218,8 @@ public final class SafeThriftClient { ...@@ -218,8 +218,8 @@ public final class SafeThriftClient {
218 // Thrift transport layer is not thread-safe (it's a wrapper on a socket), hence we need locking. 218 // Thrift transport layer is not thread-safe (it's a wrapper on a socket), hence we need locking.
219 synchronized (transport) { 219 synchronized (transport) {
220 220
221 - LOG.debug("Invoking client method... > method={}, fromThread={}", 221 + LOG.debug("Invoking method... > fromThread={}, method={}, args={}",
222 - method.getName(), Thread.currentThread().getId()); 222 + Thread.currentThread().getId(), method.getName(), args);
223 223
224 try { 224 try {
225 225
...@@ -235,15 +235,13 @@ public final class SafeThriftClient { ...@@ -235,15 +235,13 @@ public final class SafeThriftClient {
235 // If here, transport has been successfully open, hence new exceptions will be thrown. 235 // If here, transport has been successfully open, hence new exceptions will be thrown.
236 return method.invoke(baseClient, args); 236 return method.invoke(baseClient, args);
237 } catch (InvocationTargetException e1) { 237 } catch (InvocationTargetException e1) {
238 - LOG.debug("Exception while invoking client method: {} > method={}, fromThread={}", 238 + LOG.debug("Exception: {}", e1.getTargetException());
239 - e1, method.getName(), Thread.currentThread().getId());
240 throw e1.getTargetException(); 239 throw e1.getTargetException();
241 } 240 }
242 } 241 }
243 } 242 }
244 // Target exception is neither a TTransportException nor a restartable cause. 243 // Target exception is neither a TTransportException nor a restartable cause.
245 - LOG.debug("Exception while invoking client method: {} > method={}, fromThread={}", 244 + LOG.debug("Exception: {}", e.getTargetException());
246 - e, method.getName(), Thread.currentThread().getId());
247 throw e.getTargetException(); 245 throw e.getTargetException();
248 } 246 }
249 } 247 }
......
1 /* 1 /*
2 - * Copyright 2014-2016 Open Networking Laboratory 2 + * Copyright 2016-present Open Networking Laboratory
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
......
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": "intrinsic_metadata_t",
45 + "id": 1,
46 + "fields": [
47 + [
48 + "ingress_global_timestamp",
49 + 32
50 + ],
51 + [
52 + "lf_field_list",
53 + 32
54 + ],
55 + [
56 + "mcast_grp",
57 + 16
58 + ],
59 + [
60 + "egress_rid",
61 + 16
62 + ]
63 + ],
64 + "length_exp": null,
65 + "max_length": null
66 + },
67 + {
68 + "name": "ethernet_t",
69 + "id": 2,
70 + "fields": [
71 + [
72 + "dstAddr",
73 + 48
74 + ],
75 + [
76 + "srcAddr",
77 + 48
78 + ],
79 + [
80 + "etherType",
81 + 16
82 + ]
83 + ],
84 + "length_exp": null,
85 + "max_length": null
86 + },
87 + {
88 + "name": "ipv4_t",
89 + "id": 3,
90 + "fields": [
91 + [
92 + "version",
93 + 4
94 + ],
95 + [
96 + "ihl",
97 + 4
98 + ],
99 + [
100 + "diffserv",
101 + 8
102 + ],
103 + [
104 + "totalLen",
105 + 16
106 + ],
107 + [
108 + "identification",
109 + 16
110 + ],
111 + [
112 + "flags",
113 + 3
114 + ],
115 + [
116 + "fragOffset",
117 + 13
118 + ],
119 + [
120 + "ttl",
121 + 8
122 + ],
123 + [
124 + "protocol",
125 + 8
126 + ],
127 + [
128 + "hdrChecksum",
129 + 16
130 + ],
131 + [
132 + "srcAddr",
133 + 32
134 + ],
135 + [
136 + "dstAddr",
137 + 32
138 + ]
139 + ],
140 + "length_exp": null,
141 + "max_length": null
142 + },
143 + {
144 + "name": "tcp_t",
145 + "id": 4,
146 + "fields": [
147 + [
148 + "srcPort",
149 + 16
150 + ],
151 + [
152 + "dstPort",
153 + 16
154 + ],
155 + [
156 + "seqNo",
157 + 32
158 + ],
159 + [
160 + "ackNo",
161 + 32
162 + ],
163 + [
164 + "dataOffset",
165 + 4
166 + ],
167 + [
168 + "res",
169 + 3
170 + ],
171 + [
172 + "ecn",
173 + 3
174 + ],
175 + [
176 + "ctrl",
177 + 6
178 + ],
179 + [
180 + "window",
181 + 16
182 + ],
183 + [
184 + "checksum",
185 + 16
186 + ],
187 + [
188 + "urgentPtr",
189 + 16
190 + ]
191 + ],
192 + "length_exp": null,
193 + "max_length": null
194 + },
195 + {
196 + "name": "udp_t",
197 + "id": 5,
198 + "fields": [
199 + [
200 + "srcPort",
201 + 16
202 + ],
203 + [
204 + "dstPort",
205 + 16
206 + ],
207 + [
208 + "length_",
209 + 16
210 + ],
211 + [
212 + "checksum",
213 + 16
214 + ]
215 + ],
216 + "length_exp": null,
217 + "max_length": null
218 + }
219 + ],
220 + "headers": [
221 + {
222 + "name": "standard_metadata",
223 + "id": 0,
224 + "header_type": "standard_metadata_t",
225 + "metadata": true
226 + },
227 + {
228 + "name": "intrinsic_metadata",
229 + "id": 1,
230 + "header_type": "intrinsic_metadata_t",
231 + "metadata": true
232 + },
233 + {
234 + "name": "ethernet",
235 + "id": 2,
236 + "header_type": "ethernet_t",
237 + "metadata": false
238 + },
239 + {
240 + "name": "ipv4",
241 + "id": 3,
242 + "header_type": "ipv4_t",
243 + "metadata": false
244 + },
245 + {
246 + "name": "tcp",
247 + "id": 4,
248 + "header_type": "tcp_t",
249 + "metadata": false
250 + },
251 + {
252 + "name": "udp",
253 + "id": 5,
254 + "header_type": "udp_t",
255 + "metadata": false
256 + }
257 + ],
258 + "header_stacks": [],
259 + "parsers": [
260 + {
261 + "name": "parser",
262 + "id": 0,
263 + "init_state": "start",
264 + "parse_states": [
265 + {
266 + "name": "start",
267 + "id": 0,
268 + "parser_ops": [],
269 + "transition_key": [],
270 + "transitions": [
271 + {
272 + "value": "default",
273 + "mask": null,
274 + "next_state": "parse_ethernet"
275 + }
276 + ]
277 + },
278 + {
279 + "name": "parse_ethernet",
280 + "id": 1,
281 + "parser_ops": [
282 + {
283 + "op": "extract",
284 + "parameters": [
285 + {
286 + "type": "regular",
287 + "value": "ethernet"
288 + }
289 + ]
290 + }
291 + ],
292 + "transition_key": [
293 + {
294 + "type": "field",
295 + "value": [
296 + "ethernet",
297 + "etherType"
298 + ]
299 + }
300 + ],
301 + "transitions": [
302 + {
303 + "value": "0x0800",
304 + "mask": null,
305 + "next_state": "parse_ipv4"
306 + },
307 + {
308 + "value": "default",
309 + "mask": null,
310 + "next_state": null
311 + }
312 + ]
313 + },
314 + {
315 + "name": "parse_ipv4",
316 + "id": 2,
317 + "parser_ops": [
318 + {
319 + "op": "extract",
320 + "parameters": [
321 + {
322 + "type": "regular",
323 + "value": "ipv4"
324 + }
325 + ]
326 + }
327 + ],
328 + "transition_key": [
329 + {
330 + "type": "field",
331 + "value": [
332 + "ipv4",
333 + "fragOffset"
334 + ]
335 + },
336 + {
337 + "type": "field",
338 + "value": [
339 + "ipv4",
340 + "protocol"
341 + ]
342 + }
343 + ],
344 + "transitions": [
345 + {
346 + "value": "0x000006",
347 + "mask": null,
348 + "next_state": "parse_tcp"
349 + },
350 + {
351 + "value": "0x000011",
352 + "mask": null,
353 + "next_state": "parse_udp"
354 + },
355 + {
356 + "value": "default",
357 + "mask": null,
358 + "next_state": null
359 + }
360 + ]
361 + },
362 + {
363 + "name": "parse_tcp",
364 + "id": 3,
365 + "parser_ops": [
366 + {
367 + "op": "extract",
368 + "parameters": [
369 + {
370 + "type": "regular",
371 + "value": "tcp"
372 + }
373 + ]
374 + }
375 + ],
376 + "transition_key": [],
377 + "transitions": [
378 + {
379 + "value": "default",
380 + "mask": null,
381 + "next_state": null
382 + }
383 + ]
384 + },
385 + {
386 + "name": "parse_udp",
387 + "id": 4,
388 + "parser_ops": [
389 + {
390 + "op": "extract",
391 + "parameters": [
392 + {
393 + "type": "regular",
394 + "value": "udp"
395 + }
396 + ]
397 + }
398 + ],
399 + "transition_key": [],
400 + "transitions": [
401 + {
402 + "value": "default",
403 + "mask": null,
404 + "next_state": null
405 + }
406 + ]
407 + }
408 + ]
409 + }
410 + ],
411 + "deparsers": [
412 + {
413 + "name": "deparser",
414 + "id": 0,
415 + "order": [
416 + "ethernet",
417 + "ipv4",
418 + "udp",
419 + "tcp"
420 + ]
421 + }
422 + ],
423 + "meter_arrays": [],
424 + "actions": [
425 + {
426 + "name": "_drop",
427 + "id": 0,
428 + "runtime_data": [],
429 + "primitives": [
430 + {
431 + "op": "modify_field",
432 + "parameters": [
433 + {
434 + "type": "field",
435 + "value": [
436 + "standard_metadata",
437 + "egress_spec"
438 + ]
439 + },
440 + {
441 + "type": "hexstr",
442 + "value": "0x1ff"
443 + }
444 + ]
445 + }
446 + ]
447 + },
448 + {
449 + "name": "count_packet",
450 + "id": 1,
451 + "runtime_data": [],
452 + "primitives": [
453 + {
454 + "op": "count",
455 + "parameters": [
456 + {
457 + "type": "counter_array",
458 + "value": "ingress_port_counter"
459 + },
460 + {
461 + "type": "field",
462 + "value": [
463 + "standard_metadata",
464 + "ingress_port"
465 + ]
466 + }
467 + ]
468 + },
469 + {
470 + "op": "count",
471 + "parameters": [
472 + {
473 + "type": "counter_array",
474 + "value": "egress_port_counter"
475 + },
476 + {
477 + "type": "field",
478 + "value": [
479 + "standard_metadata",
480 + "egress_spec"
481 + ]
482 + }
483 + ]
484 + }
485 + ]
486 + },
487 + {
488 + "name": "send_to_cpu",
489 + "id": 2,
490 + "runtime_data": [],
491 + "primitives": [
492 + {
493 + "op": "modify_field",
494 + "parameters": [
495 + {
496 + "type": "field",
497 + "value": [
498 + "standard_metadata",
499 + "egress_spec"
500 + ]
501 + },
502 + {
503 + "type": "hexstr",
504 + "value": "0xff"
505 + }
506 + ]
507 + }
508 + ]
509 + },
510 + {
511 + "name": "set_egress_port",
512 + "id": 3,
513 + "runtime_data": [
514 + {
515 + "name": "port",
516 + "bitwidth": 9
517 + }
518 + ],
519 + "primitives": [
520 + {
521 + "op": "modify_field",
522 + "parameters": [
523 + {
524 + "type": "field",
525 + "value": [
526 + "standard_metadata",
527 + "egress_spec"
528 + ]
529 + },
530 + {
531 + "type": "runtime_data",
532 + "value": 0
533 + }
534 + ]
535 + }
536 + ]
537 + }
538 + ],
539 + "pipelines": [
540 + {
541 + "name": "ingress",
542 + "id": 0,
543 + "init_table": "table0",
544 + "tables": [
545 + {
546 + "name": "port_count_table",
547 + "id": 0,
548 + "match_type": "exact",
549 + "type": "simple",
550 + "max_size": 16384,
551 + "with_counters": false,
552 + "direct_meters": null,
553 + "support_timeout": false,
554 + "key": [],
555 + "actions": [
556 + "count_packet"
557 + ],
558 + "next_tables": {
559 + "count_packet": null
560 + },
561 + "default_action": null,
562 + "base_default_next": null
563 + },
564 + {
565 + "name": "table0",
566 + "id": 1,
567 + "match_type": "ternary",
568 + "type": "simple",
569 + "max_size": 16384,
570 + "with_counters": true,
571 + "direct_meters": null,
572 + "support_timeout": true,
573 + "key": [
574 + {
575 + "match_type": "ternary",
576 + "target": [
577 + "standard_metadata",
578 + "ingress_port"
579 + ],
580 + "mask": null
581 + },
582 + {
583 + "match_type": "ternary",
584 + "target": [
585 + "ethernet",
586 + "dstAddr"
587 + ],
588 + "mask": null
589 + },
590 + {
591 + "match_type": "ternary",
592 + "target": [
593 + "ethernet",
594 + "srcAddr"
595 + ],
596 + "mask": null
597 + },
598 + {
599 + "match_type": "ternary",
600 + "target": [
601 + "ethernet",
602 + "etherType"
603 + ],
604 + "mask": null
605 + }
606 + ],
607 + "actions": [
608 + "set_egress_port",
609 + "send_to_cpu",
610 + "_drop"
611 + ],
612 + "next_tables": {
613 + "set_egress_port": "_condition_0",
614 + "send_to_cpu": "_condition_0",
615 + "_drop": "_condition_0"
616 + },
617 + "default_action": null,
618 + "base_default_next": "_condition_0"
619 + }
620 + ],
621 + "conditionals": [
622 + {
623 + "name": "_condition_0",
624 + "id": 0,
625 + "expression": {
626 + "type": "expression",
627 + "value": {
628 + "op": "<",
629 + "left": {
630 + "type": "field",
631 + "value": [
632 + "standard_metadata",
633 + "egress_spec"
634 + ]
635 + },
636 + "right": {
637 + "type": "hexstr",
638 + "value": "0xfe"
639 + }
640 + }
641 + },
642 + "true_next": "port_count_table",
643 + "false_next": null
644 + }
645 + ]
646 + },
647 + {
648 + "name": "egress",
649 + "id": 1,
650 + "init_table": null,
651 + "tables": [],
652 + "conditionals": []
653 + }
654 + ],
655 + "calculations": [],
656 + "checksums": [],
657 + "learn_lists": [],
658 + "field_lists": [],
659 + "counter_arrays": [
660 + {
661 + "name": "ingress_port_counter",
662 + "id": 0,
663 + "is_direct": false,
664 + "size": 254
665 + },
666 + {
667 + "name": "egress_port_counter",
668 + "id": 1,
669 + "is_direct": false,
670 + "size": 254
671 + },
672 + {
673 + "name": "table0_counter",
674 + "id": 2,
675 + "is_direct": true,
676 + "binding": "table0"
677 + }
678 + ],
679 + "register_arrays": [],
680 + "force_arith": [
681 + [
682 + "standard_metadata",
683 + "ingress_port"
684 + ],
685 + [
686 + "standard_metadata",
687 + "packet_length"
688 + ],
689 + [
690 + "standard_metadata",
691 + "egress_spec"
692 + ],
693 + [
694 + "standard_metadata",
695 + "egress_port"
696 + ],
697 + [
698 + "standard_metadata",
699 + "egress_instance"
700 + ],
701 + [
702 + "standard_metadata",
703 + "instance_type"
704 + ],
705 + [
706 + "standard_metadata",
707 + "clone_spec"
708 + ],
709 + [
710 + "standard_metadata",
711 + "_padding"
712 + ],
713 + [
714 + "intrinsic_metadata",
715 + "ingress_global_timestamp"
716 + ],
717 + [
718 + "intrinsic_metadata",
719 + "lf_field_list"
720 + ],
721 + [
722 + "intrinsic_metadata",
723 + "mcast_grp"
724 + ],
725 + [
726 + "intrinsic_metadata",
727 + "egress_rid"
728 + ]
729 + ]
730 +}
...\ No newline at end of file ...\ No newline at end of file
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.bmv2.ctl;
18 +
19 +import com.google.common.testing.EqualsTester;
20 +import org.junit.Test;
21 +import org.onlab.packet.MacAddress;
22 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
23 +import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
24 +import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
25 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
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.net.DeviceId;
31 +import org.onosproject.net.PortNumber;
32 +import org.onosproject.net.flow.DefaultFlowRule;
33 +import org.onosproject.net.flow.DefaultTrafficSelector;
34 +import org.onosproject.net.flow.DefaultTrafficTreatment;
35 +import org.onosproject.net.flow.FlowRule;
36 +import org.onosproject.net.flow.TrafficSelector;
37 +import org.onosproject.net.flow.TrafficTreatment;
38 +
39 +import java.util.Random;
40 +
41 +import static org.hamcrest.CoreMatchers.equalTo;
42 +import static org.hamcrest.CoreMatchers.is;
43 +import static org.hamcrest.MatcherAssert.assertThat;
44 +import static org.onosproject.bmv2.ctl.Bmv2DefaultInterpreterImpl.TABLE0;
45 +
46 +/**
47 + * Tests for {@link Bmv2FlowRuleTranslatorImpl}.
48 + */
49 +public class Bmv2FlowRuleTranslatorImplTest {
50 +
51 + private Random random = new Random();
52 + private Bmv2Configuration configuration = Bmv2DeviceContextServiceImpl.loadDefaultConfiguration();
53 + private Bmv2Interpreter interpreter = new Bmv2DefaultInterpreterImpl();
54 + private Bmv2DeviceContext context = new Bmv2DeviceContext(configuration, interpreter);
55 + private Bmv2FlowRuleTranslator translator = new Bmv2FlowRuleTranslatorImpl();
56 +
57 + @Test
58 + public void testTranslate() throws Exception {
59 +
60 + DeviceId deviceId = DeviceId.NONE;
61 + ApplicationId appId = new DefaultApplicationId(1, "test");
62 + int tableId = 0;
63 + MacAddress ethDstMac = MacAddress.valueOf(random.nextLong());
64 + MacAddress ethSrcMac = MacAddress.valueOf(random.nextLong());
65 + short ethType = (short) (0x0000FFFF & random.nextInt());
66 + short outPort = (short) random.nextInt(65);
67 + short inPort = (short) random.nextInt(65);
68 + int timeout = random.nextInt(100);
69 + int priority = random.nextInt(100);
70 +
71 + TrafficSelector matchInPort1 = DefaultTrafficSelector
72 + .builder()
73 + .matchInPort(PortNumber.portNumber(inPort))
74 + .matchEthDst(ethDstMac)
75 + .matchEthSrc(ethSrcMac)
76 + .matchEthType(ethType)
77 + .build();
78 +
79 + TrafficTreatment outPort2 = DefaultTrafficTreatment
80 + .builder()
81 + .setOutput(PortNumber.portNumber(outPort))
82 + .build();
83 +
84 + FlowRule rule1 = DefaultFlowRule.builder()
85 + .forDevice(deviceId)
86 + .forTable(tableId)
87 + .fromApp(appId)
88 + .withSelector(matchInPort1)
89 + .withTreatment(outPort2)
90 + .makeTemporary(timeout)
91 + .withPriority(priority)
92 + .build();
93 +
94 + FlowRule rule2 = DefaultFlowRule.builder()
95 + .forDevice(deviceId)
96 + .forTable(tableId)
97 + .fromApp(appId)
98 + .withSelector(matchInPort1)
99 + .withTreatment(outPort2)
100 + .makeTemporary(timeout)
101 + .withPriority(priority)
102 + .build();
103 +
104 + Bmv2TableEntry entry1 = translator.translate(rule1, context);
105 + Bmv2TableEntry entry2 = translator.translate(rule1, context);
106 +
107 + // check equality, i.e. same rules must produce same entries
108 + new EqualsTester()
109 + .addEqualityGroup(rule1, rule2)
110 + .addEqualityGroup(entry1, entry2)
111 + .testEquals();
112 +
113 + int numMatchParams = configuration.table(TABLE0).keys().size();
114 + // parse values stored in entry1
115 + Bmv2TernaryMatchParam inPortParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(0);
116 + Bmv2TernaryMatchParam ethDstParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(1);
117 + Bmv2TernaryMatchParam ethSrcParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(2);
118 + Bmv2TernaryMatchParam ethTypeParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(3);
119 + double expectedTimeout = (double) (configuration.table(TABLE0).hasTimeouts() ? rule1.timeout() : -1);
120 +
121 + // check that the number of parameters in the entry is the same as the number of table keys
122 + assertThat("Incorrect number of match parameters",
123 + entry1.matchKey().matchParams().size(), is(equalTo(numMatchParams)));
124 +
125 + // check that values stored in entry are the same used for the flow rule
126 + assertThat("Incorrect inPort match param value",
127 + inPortParam.value().asReadOnlyBuffer().getShort(), is(equalTo(inPort)));
128 + assertThat("Incorrect ethDestMac match param value",
129 + ethDstParam.value().asArray(), is(equalTo(ethDstMac.toBytes())));
130 + assertThat("Incorrect ethSrcMac match param value",
131 + ethSrcParam.value().asArray(), is(equalTo(ethSrcMac.toBytes())));
132 + assertThat("Incorrect ethType match param value",
133 + ethTypeParam.value().asReadOnlyBuffer().getShort(), is(equalTo(ethType)));
134 + assertThat("Incorrect priority value",
135 + entry1.priority(), is(equalTo(Integer.MAX_VALUE - rule1.priority())));
136 + assertThat("Incorrect timeout value",
137 + entry1.timeout(), is(equalTo(expectedTimeout)));
138 +
139 + }
140 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -14,35 +14,36 @@ ...@@ -14,35 +14,36 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.bmv2.api.model; 17 +package org.onosproject.bmv2.ctl;
18 18
19 import org.junit.Test; 19 import org.junit.Test;
20 -import org.onosproject.bmv2.ctl.Bmv2TableDumpParser; 20 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
21 - 21 +import org.onosproject.bmv2.api.runtime.Bmv2ParsedTableEntry;
22 +
23 +import java.io.IOException;
24 +import java.net.URISyntaxException;
25 +import java.nio.charset.Charset;
26 +import java.nio.file.Files;
27 +import java.nio.file.Paths;
22 import java.util.List; 28 import java.util.List;
23 29
24 import static org.hamcrest.MatcherAssert.assertThat; 30 import static org.hamcrest.MatcherAssert.assertThat;
25 -import static org.hamcrest.core.Is.is; 31 +import static org.hamcrest.Matchers.equalTo;
26 -import static org.hamcrest.core.IsEqual.equalTo;
27 32
28 public class Bmv2TableDumpParserTest { 33 public class Bmv2TableDumpParserTest {
29 34
30 - @Test 35 + private Bmv2Configuration configuration = Bmv2DeviceContextServiceImpl.loadDefaultConfiguration();
31 - public void testParse() throws Exception, Bmv2TableDumpParser.Bmv2TableDumpParserException {
32 -
33 - String text =
34 - "0: 0000 000000000000 000000000000 &&& 0000000000000000000000000000 => send_to_cpu -\n" +
35 - "1: 0000 000000000000 000000000000 &&& 0000000000000000000000000000 => send_to_cpu -\n" +
36 - "2: 0000 000000000000 000000000000 &&& 0000000000000000000000000000 => send_to_cpu -\n" +
37 - "3: 0000 000000000000 000000000000 &&& 0000000000000000000000000000 => send_to_cpu -";
38 36
39 - Bmv2TableDumpParser parser = new Bmv2TableDumpParser(); 37 + @Test
40 - 38 + public void testParse() throws Exception {
41 - List<Long> result = parser.getEntryIds(text); 39 + String text = readFile();
40 + List<Bmv2ParsedTableEntry> result = Bmv2TableDumpParser.parse(text, configuration);
41 + assertThat(result.size(), equalTo(10));
42 + }
42 43
43 - assertThat("invalid parsed values", result.get(0), is(equalTo(0L))); 44 + private String readFile()
44 - assertThat("invalid parsed values", result.get(1), is(equalTo(1L))); 45 + throws IOException, URISyntaxException {
45 - assertThat("invalid parsed values", result.get(2), is(equalTo(2L))); 46 + byte[] encoded = Files.readAllBytes(Paths.get(this.getClass().getResource("/tabledump.txt").toURI()));
46 - assertThat("invalid parsed values", result.get(3), is(equalTo(3L))); 47 + return new String(encoded, Charset.defaultCharset());
47 } 48 }
48 } 49 }
......
1 +0: 0000 000000000000 000000000000 0806 &&& 0000000000000000000000000000ffff => send_to_cpu -
2 +1: 0000 000000000000 000000000000 0800 &&& 0000000000000000000000000000ffff => send_to_cpu -
3 +2: 0000 000000000000 000000000000 88cc &&& 0000000000000000000000000000ffff => send_to_cpu -
4 +3: 0000 000000000000 000000000000 8942 &&& 0000000000000000000000000000ffff => send_to_cpu -
5 +4: 0001 000400000001 000400000000 0000 &&& ffffffffffffffffffffffffffff0000 => set_egress_port - 2,
6 +5: 0002 000400000000 000400000001 0000 &&& ffffffffffffffffffffffffffff0000 => set_egress_port - 1,
7 +51539607552: 0001 0000 => set_egress_port - 1,
8 +51539607553: 0001 0002 => set_egress_port - 3,
9 +51539607554: 0001 0001 => set_egress_port - 2,
10 +51539607555: 0001 0003 => set_egress_port - 4,
...\ No newline at end of file ...\ No newline at end of file
...@@ -26,243 +26,15 @@ ...@@ -26,243 +26,15 @@
26 <modelVersion>4.0.0</modelVersion> 26 <modelVersion>4.0.0</modelVersion>
27 27
28 <artifactId>onos-bmv2-protocol</artifactId> 28 <artifactId>onos-bmv2-protocol</artifactId>
29 - <version>1.7.0-SNAPSHOT</version>
30 29
31 - <packaging>bundle</packaging> 30 + <modules>
31 + <module>api</module>
32 + <module>ctl</module>
33 + <module>thrift-api</module>
34 + </modules>
32 35
33 - <description>BMv2 protocol subsystem</description> 36 + <packaging>pom</packaging>
34 -
35 - <properties>
36 - <!-- BMv2 Commit ID and Thrift version -->
37 - <bmv2.commit>4421bafd6d26740b0bbf802c2e9f9f54c1211b13</bmv2.commit>
38 - <bmv2.thrift.version>0.9.3</bmv2.thrift.version>
39 - <!-- Do not change below -->
40 - <bmv2.baseurl>
41 - https://raw.githubusercontent.com/ccascone/behavioral-model/${bmv2.commit}
42 - </bmv2.baseurl>
43 - <bmv2.thrift.srcdir>${project.basedir}/src/main/thrift</bmv2.thrift.srcdir>
44 - <thrift.path>${project.build.directory}/thrift-compiler/</thrift.path>
45 - <thrift.filename>thrift-${os.detected.classifier}.exe</thrift.filename>
46 - </properties>
47 -
48 - <dependencies>
49 - <dependency>
50 - <groupId>org.apache.thrift</groupId>
51 - <artifactId>libthrift</artifactId>
52 - <version>${bmv2.thrift.version}</version>
53 - </dependency>
54 - <dependency>
55 - <groupId>org.onosproject</groupId>
56 - <artifactId>onos-api</artifactId>
57 - <version>${project.version}</version>
58 - </dependency>
59 - <dependency>
60 - <groupId>org.apache.felix</groupId>
61 - <artifactId>org.apache.felix.scr.annotations</artifactId>
62 - </dependency>
63 - </dependencies>
64 37
65 - <repositories> 38 + <description>BMv2 protocol subsystem</description>
66 - <!-- Needed for thrift-compiler, which is hosted on GitHub -->
67 - <repository>
68 - <id>jitpack.io</id>
69 - <url>https://jitpack.io</url>
70 - </repository>
71 - </repositories>
72 -
73 - <build>
74 - <extensions>
75 - <extension>
76 - <groupId>kr.motd.maven</groupId>
77 - <artifactId>os-maven-plugin</artifactId>
78 - <version>1.4.0.Final</version>
79 - </extension>
80 - </extensions>
81 -
82 - <plugins>
83 - <!-- Download Thrift source files from BMv2 Github repo -->
84 - <plugin>
85 - <groupId>org.codehaus.mojo</groupId>
86 - <artifactId>wagon-maven-plugin</artifactId>
87 - <version>1.0</version>
88 - <executions>
89 - <execution>
90 - <id>download-bmv2-thrift-standard</id>
91 - <phase>initialize</phase>
92 - <goals>
93 - <goal>download-single</goal>
94 - </goals>
95 - <configuration>
96 - <url>${bmv2.baseurl}</url>
97 - <fromFile>thrift_src/standard.thrift</fromFile>
98 - <toDir>${bmv2.thrift.srcdir}</toDir>
99 - </configuration>
100 - </execution>
101 - <execution>
102 - <id>download-bmv2-thrift-simple_pre</id>
103 - <phase>initialize</phase>
104 - <goals>
105 - <goal>download-single</goal>
106 - </goals>
107 - <configuration>
108 - <url>${bmv2.baseurl}</url>
109 - <fromFile>thrift_src/simple_pre.thrift</fromFile>
110 - <toDir>${bmv2.thrift.srcdir}</toDir>
111 - </configuration>
112 - </execution>
113 - <execution>
114 - <id>download-bmv2-thrift-simple_pre_lag</id>
115 - <phase>initialize</phase>
116 - <goals>
117 - <goal>download-single</goal>
118 - </goals>
119 - <configuration>
120 - <url>${bmv2.baseurl}</url>
121 - <fromFile>thrift_src/simple_pre_lag.thrift
122 - </fromFile>
123 - <toDir>${bmv2.thrift.srcdir}</toDir>
124 - </configuration>
125 - </execution>
126 - <execution>
127 - <id>download-bmv2-thrift-simple_switch</id>
128 - <phase>initialize</phase>
129 - <goals>
130 - <goal>download-single</goal>
131 - </goals>
132 - <configuration>
133 - <url>${bmv2.baseurl}</url>
134 - <fromFile>
135 - targets/simple_switch/thrift/simple_switch.thrift
136 - </fromFile>
137 - <toDir>${bmv2.thrift.srcdir}</toDir>
138 - </configuration>
139 - </execution>
140 - <execution>
141 - <id>download-bmv2-thrift-simple_switch-cpservice</id>
142 - <phase>initialize</phase>
143 - <goals>
144 - <goal>download-single</goal>
145 - </goals>
146 - <configuration>
147 - <url>${bmv2.baseurl}</url>
148 - <fromFile>
149 - targets/simple_switch/thrift/control_plane.thrift
150 - </fromFile>
151 - <toDir>${bmv2.thrift.srcdir}</toDir>
152 - </configuration>
153 - </execution>
154 - </executions>
155 - </plugin>
156 - <!-- Extract Thrift compiler -->
157 - <plugin>
158 - <groupId>org.apache.maven.plugins</groupId>
159 - <artifactId>maven-dependency-plugin</artifactId>
160 - <executions>
161 - <execution>
162 - <id>unpack</id>
163 - <phase>initialize</phase>
164 - <goals>
165 - <goal>unpack</goal>
166 - </goals>
167 - <configuration>
168 - <artifactItems>
169 - <artifactItem>
170 - <groupId>com.github.ccascone</groupId>
171 - <artifactId>mvn-thrift-compiler</artifactId>
172 - <version>1.1_${bmv2.thrift.version}</version>
173 - <type>jar</type>
174 - <includes>${thrift.filename}</includes>
175 - <outputDirectory>${project.build.directory}/thrift-compiler</outputDirectory>
176 - </artifactItem>
177 - </artifactItems>
178 - </configuration>
179 - </execution>
180 - </executions>
181 - </plugin>
182 - <!-- Add missing java namespace to Thrift files -->
183 - <plugin>
184 - <groupId>org.codehaus.mojo</groupId>
185 - <artifactId>exec-maven-plugin</artifactId>
186 - <version>1.4.0</version>
187 - <executions>
188 - <execution>
189 - <id>add-bmv2-thrift-java-namespace</id>
190 - <phase>initialize</phase>
191 - <goals>
192 - <goal>exec</goal>
193 - </goals>
194 - <configuration>
195 - <executable>${bmv2.thrift.srcdir}/patch.sh
196 - </executable>
197 - </configuration>
198 - </execution>
199 - <execution>
200 - <id>set-thrift-compiler-permissions</id>
201 - <phase>initialize</phase>
202 - <goals>
203 - <goal>exec</goal>
204 - </goals>
205 - <configuration>
206 - <executable>chmod</executable>
207 - <arguments>
208 - <argument>+x</argument>
209 - <argument>${thrift.path}/${thrift.filename}</argument>
210 - </arguments>
211 - </configuration>
212 - </execution>
213 - </executions>
214 - </plugin>
215 - <!-- Compile Thrift files -->
216 - <plugin>
217 - <groupId>org.apache.thrift.tools</groupId>
218 - <artifactId>maven-thrift-plugin</artifactId>
219 - <version>0.1.11</version>
220 - <configuration>
221 - <thriftExecutable>${thrift.path}/${thrift.filename}</thriftExecutable>
222 - <outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
223 - </configuration>
224 - <executions>
225 - <execution>
226 - <id>thrift-sources</id>
227 - <phase>initialize</phase>
228 - <goals>
229 - <goal>compile</goal>
230 - </goals>
231 - </execution>
232 - </executions>
233 - </plugin>
234 - <!-- Make generated sources visible -->
235 - <plugin>
236 - <groupId>org.codehaus.mojo</groupId>
237 - <artifactId>build-helper-maven-plugin</artifactId>
238 - <version>1.4</version>
239 - <executions>
240 - <execution>
241 - <id>add-thrift-sources-to-path</id>
242 - <phase>generate-sources</phase>
243 - <goals>
244 - <goal>add-source</goal>
245 - </goals>
246 - <configuration>
247 - <sources>
248 - <source>
249 - ${project.build.directory}/generated-sources
250 - </source>
251 - </sources>
252 - </configuration>
253 - </execution>
254 - </executions>
255 - </plugin>
256 - <!-- OSGi -->
257 - <plugin>
258 - <groupId>org.apache.felix</groupId>
259 - <artifactId>maven-scr-plugin</artifactId>
260 - </plugin>
261 - <plugin>
262 - <groupId>org.onosproject</groupId>
263 - <artifactId>onos-maven-plugin</artifactId>
264 - </plugin>
265 - </plugins>
266 - </build>
267 39
268 </project> 40 </project>
...\ No newline at end of file ...\ No newline at end of file
......
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.bmv2.ctl;
18 -
19 -import com.google.common.collect.Lists;
20 -import org.apache.commons.lang3.tuple.Pair;
21 -
22 -import java.util.List;
23 -import java.util.regex.Matcher;
24 -import java.util.regex.Pattern;
25 -import java.util.stream.Collectors;
26 -
27 -import static com.google.common.base.Preconditions.checkNotNull;
28 -
29 -/**
30 - * String parser for the BMv2 table dump.
31 - */
32 -public class Bmv2TableDumpParser {
33 -
34 - /*
35 - Example of BMv2 table dump:
36 - 0: 0000 000000000000 000000000000 0806 &&& 0000000000000000000000000000ffff => send_to_cpu -
37 -
38 - For each entry, we want to match the id and all the rest.
39 - */
40 - private static final String ENTRY_PATTERN_STRING = "(\\d+):(.+)";
41 - private static final Pattern ENTRY_PATTERN = Pattern.compile(ENTRY_PATTERN_STRING);
42 -
43 - /**
44 - * Returns a list of entry Ids for the given table dump.
45 - *
46 - * @param tableDump a string value
47 - * @return a list of long values
48 - * @throws Bmv2TableDumpParserException if dump can't be parsed
49 - */
50 - public List<Long> getEntryIds(String tableDump) throws Bmv2TableDumpParserException {
51 - return parse(tableDump).stream().map(Pair::getKey).collect(Collectors.toList());
52 - }
53 -
54 - private List<Pair<Long, String>> parse(String tableDump) throws Bmv2TableDumpParserException {
55 - checkNotNull(tableDump, "tableDump cannot be null");
56 -
57 - List<Pair<Long, String>> results = Lists.newArrayList();
58 -
59 - // TODO: consider caching parser results for speed.
60 -
61 - Matcher matcher = ENTRY_PATTERN.matcher(tableDump);
62 -
63 - while (matcher.find()) {
64 - String entryString = matcher.group(1);
65 - if (entryString == null) {
66 - throw new Bmv2TableDumpParserException("Unable to parse entry for string: " + matcher.group());
67 - }
68 - Long entryId = -1L;
69 - try {
70 - entryId = Long.valueOf(entryString.trim());
71 - } catch (NumberFormatException e) {
72 - throw new Bmv2TableDumpParserException("Unable to parse entry id for string: " + matcher.group());
73 - }
74 - String allTheRest = matcher.group(2);
75 - if (allTheRest == null) {
76 - throw new Bmv2TableDumpParserException("Unable to parse entry for string: " + matcher.group());
77 - }
78 - results.add(Pair.of(entryId, allTheRest));
79 - }
80 -
81 - return results;
82 - }
83 -
84 - public class Bmv2TableDumpParserException extends Throwable {
85 - public Bmv2TableDumpParserException(String msg) {
86 - super(msg);
87 - }
88 - }
89 -}
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <parent>
22 + <artifactId>onos-bmv2-protocol</artifactId>
23 + <groupId>org.onosproject</groupId>
24 + <version>1.6.0-SNAPSHOT</version>
25 + </parent>
26 +
27 + <modelVersion>4.0.0</modelVersion>
28 +
29 + <artifactId>onos-bmv2-protocol-thrift-api</artifactId>
30 +
31 + <packaging>bundle</packaging>
32 +
33 + <properties>
34 + <!-- BMv2 Commit ID and Thrift version -->
35 + <bmv2.commit>e55f9cdaee5e3d729f839e7ec6c322dd66c1a1a0</bmv2.commit>
36 + <bmv2.thrift.version>0.9.3</bmv2.thrift.version>
37 + <!-- Do not change below -->
38 + <bmv2.baseurl>
39 + https://raw.githubusercontent.com/ccascone/behavioral-model/${bmv2.commit}
40 + </bmv2.baseurl>
41 + <bmv2.thrift.srcdir>${project.basedir}/src/main/thrift</bmv2.thrift.srcdir>
42 + <thrift.path>${project.build.directory}/thrift-compiler/</thrift.path>
43 + <thrift.filename>thrift-${os.detected.classifier}.exe</thrift.filename>
44 + </properties>
45 +
46 + <dependencies>
47 + <dependency>
48 + <groupId>org.apache.thrift</groupId>
49 + <artifactId>libthrift</artifactId>
50 + <version>0.9.3</version>
51 + </dependency>
52 + </dependencies>
53 +
54 + <repositories>
55 + <!-- Needed for thrift-compiler, which is hosted on GitHub -->
56 + <repository>
57 + <id>jitpack.io</id>
58 + <url>https://jitpack.io</url>
59 + </repository>
60 + </repositories>
61 +
62 + <build>
63 + <extensions>
64 + <extension>
65 + <groupId>kr.motd.maven</groupId>
66 + <artifactId>os-maven-plugin</artifactId>
67 + <version>1.4.0.Final</version>
68 + </extension>
69 + </extensions>
70 +
71 + <plugins>
72 + <!-- Download Thrift source files from BMv2 Github repo -->
73 + <plugin>
74 + <groupId>org.codehaus.mojo</groupId>
75 + <artifactId>wagon-maven-plugin</artifactId>
76 + <version>1.0</version>
77 + <executions>
78 + <execution>
79 + <id>download-bmv2-thrift-standard</id>
80 + <phase>initialize</phase>
81 + <goals>
82 + <goal>download-single</goal>
83 + </goals>
84 + <configuration>
85 + <url>${bmv2.baseurl}</url>
86 + <fromFile>thrift_src/standard.thrift</fromFile>
87 + <toDir>${bmv2.thrift.srcdir}</toDir>
88 + </configuration>
89 + </execution>
90 + <execution>
91 + <id>download-bmv2-thrift-simple_pre</id>
92 + <phase>initialize</phase>
93 + <goals>
94 + <goal>download-single</goal>
95 + </goals>
96 + <configuration>
97 + <url>${bmv2.baseurl}</url>
98 + <fromFile>thrift_src/simple_pre.thrift</fromFile>
99 + <toDir>${bmv2.thrift.srcdir}</toDir>
100 + </configuration>
101 + </execution>
102 + <execution>
103 + <id>download-bmv2-thrift-simple_pre_lag</id>
104 + <phase>initialize</phase>
105 + <goals>
106 + <goal>download-single</goal>
107 + </goals>
108 + <configuration>
109 + <url>${bmv2.baseurl}</url>
110 + <fromFile>thrift_src/simple_pre_lag.thrift
111 + </fromFile>
112 + <toDir>${bmv2.thrift.srcdir}</toDir>
113 + </configuration>
114 + </execution>
115 + <execution>
116 + <id>download-bmv2-thrift-simple_switch</id>
117 + <phase>initialize</phase>
118 + <goals>
119 + <goal>download-single</goal>
120 + </goals>
121 + <configuration>
122 + <url>${bmv2.baseurl}</url>
123 + <fromFile>
124 + targets/simple_switch/thrift/simple_switch.thrift
125 + </fromFile>
126 + <toDir>${bmv2.thrift.srcdir}</toDir>
127 + </configuration>
128 + </execution>
129 + <execution>
130 + <id>download-bmv2-thrift-simple_switch-cpservice</id>
131 + <phase>initialize</phase>
132 + <goals>
133 + <goal>download-single</goal>
134 + </goals>
135 + <configuration>
136 + <url>${bmv2.baseurl}</url>
137 + <fromFile>
138 + targets/simple_switch/thrift/control_plane.thrift
139 + </fromFile>
140 + <toDir>${bmv2.thrift.srcdir}</toDir>
141 + </configuration>
142 + </execution>
143 + </executions>
144 + </plugin>
145 + <!-- Extract Thrift compiler -->
146 + <plugin>
147 + <groupId>org.apache.maven.plugins</groupId>
148 + <artifactId>maven-dependency-plugin</artifactId>
149 + <executions>
150 + <execution>
151 + <id>unpack</id>
152 + <phase>initialize</phase>
153 + <goals>
154 + <goal>unpack</goal>
155 + </goals>
156 + <configuration>
157 + <artifactItems>
158 + <artifactItem>
159 + <groupId>com.github.ccascone</groupId>
160 + <artifactId>mvn-thrift-compiler</artifactId>
161 + <version>1.1_${bmv2.thrift.version}</version>
162 + <type>jar</type>
163 + <includes>${thrift.filename}</includes>
164 + <outputDirectory>${project.build.directory}/thrift-compiler</outputDirectory>
165 + </artifactItem>
166 + </artifactItems>
167 + </configuration>
168 + </execution>
169 + </executions>
170 + </plugin>
171 + <!-- Add missing java namespace to Thrift files -->
172 + <plugin>
173 + <groupId>org.codehaus.mojo</groupId>
174 + <artifactId>exec-maven-plugin</artifactId>
175 + <version>1.4.0</version>
176 + <executions>
177 + <execution>
178 + <id>add-bmv2-thrift-java-namespace</id>
179 + <phase>initialize</phase>
180 + <goals>
181 + <goal>exec</goal>
182 + </goals>
183 + <configuration>
184 + <executable>${bmv2.thrift.srcdir}/patch.sh
185 + </executable>
186 + </configuration>
187 + </execution>
188 + <execution>
189 + <id>set-thrift-compiler-permissions</id>
190 + <phase>initialize</phase>
191 + <goals>
192 + <goal>exec</goal>
193 + </goals>
194 + <configuration>
195 + <executable>chmod</executable>
196 + <arguments>
197 + <argument>+x</argument>
198 + <argument>${thrift.path}/${thrift.filename}</argument>
199 + </arguments>
200 + </configuration>
201 + </execution>
202 + </executions>
203 + </plugin>
204 + <!-- Compile Thrift files -->
205 + <plugin>
206 + <groupId>org.apache.thrift.tools</groupId>
207 + <artifactId>maven-thrift-plugin</artifactId>
208 + <version>0.1.11</version>
209 + <configuration>
210 + <thriftExecutable>${thrift.path}/${thrift.filename}</thriftExecutable>
211 + <outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
212 + </configuration>
213 + <executions>
214 + <execution>
215 + <id>thrift-sources</id>
216 + <phase>initialize</phase>
217 + <goals>
218 + <goal>compile</goal>
219 + </goals>
220 + </execution>
221 + </executions>
222 + </plugin>
223 + <!-- Make generated sources visible -->
224 + <plugin>
225 + <groupId>org.codehaus.mojo</groupId>
226 + <artifactId>build-helper-maven-plugin</artifactId>
227 + <version>1.4</version>
228 + <executions>
229 + <execution>
230 + <id>add-thrift-sources-to-path</id>
231 + <phase>generate-sources</phase>
232 + <goals>
233 + <goal>add-source</goal>
234 + </goals>
235 + <configuration>
236 + <sources>
237 + <source>
238 + ${project.build.directory}/generated-sources
239 + </source>
240 + </sources>
241 + </configuration>
242 + </execution>
243 + </executions>
244 + </plugin>
245 + </plugins>
246 + </build>
247 +</project>
...\ No newline at end of file ...\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
18 set -e 18 set -e
19 19
20 basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 20 basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
21 -ns="org.p4.bmv2.thrift" 21 +ns="org.onosproject.bmv2.thriftapi"
22 22
23 # add java namespace at beginning of file 23 # add java namespace at beginning of file
24 for f in ${basedir}/*.thrift 24 for f in ${basedir}/*.thrift
......
...@@ -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
......
...@@ -73,6 +73,24 @@ public final class ImmutableByteSequence { ...@@ -73,6 +73,24 @@ public final class ImmutableByteSequence {
73 } 73 }
74 74
75 /** 75 /**
76 + * Creates a new immutable byte sequence with the same content and order of
77 + * the passed byte array, from/to the given indexes (inclusive).
78 + *
79 + * @param original a byte array value
80 + * @return a new immutable byte sequence
81 + */
82 + public static ImmutableByteSequence copyFrom(byte[] original, int fromIdx, int toIdx) {
83 + checkArgument(original != null && original.length > 0,
84 + "Cannot copy from an empty or null array");
85 + checkArgument(toIdx >= fromIdx && toIdx < original.length, "invalid indexes");
86 + ByteBuffer buffer = ByteBuffer.allocate((toIdx - fromIdx) + 1);
87 + for (int i = fromIdx; i <= toIdx; i++) {
88 + buffer.put(original[i]);
89 + }
90 + return new ImmutableByteSequence(buffer);
91 + }
92 +
93 + /**
76 * Creates a new immutable byte sequence copying bytes from the given 94 * Creates a new immutable byte sequence copying bytes from the given
77 * ByteBuffer {@link ByteBuffer}. If the byte buffer order is not big-endian 95 * ByteBuffer {@link ByteBuffer}. If the byte buffer order is not big-endian
78 * bytes will be copied in reverse order. 96 * bytes will be copied in reverse order.
......