blob: 8980733d2847ea277b24f49ffbb22343b2aa9b28 [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -07001/*
2 * Copyright 2015 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 */
16package org.onosproject.driver.pipeline;
17
alshabibfd430b62015-12-16 18:56:38 -080018import com.google.common.collect.Lists;
19import org.apache.commons.lang3.tuple.ImmutablePair;
20import org.apache.commons.lang3.tuple.Pair;
alshabib0ccde6d2015-05-30 18:22:36 -070021import org.onlab.osgi.ServiceDirectory;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070022import org.onlab.packet.EthType;
alshabibfd430b62015-12-16 18:56:38 -080023import org.onlab.packet.IPv4;
24import org.onlab.packet.VlanId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
alshabib2cc73cb2015-06-30 20:26:56 -070027import org.onosproject.net.DefaultAnnotations;
28import org.onosproject.net.Device;
alshabib0ccde6d2015-05-30 18:22:36 -070029import org.onosproject.net.DeviceId;
alshabib2cc73cb2015-06-30 20:26:56 -070030import org.onosproject.net.MastershipRole;
alshabib0ccde6d2015-05-30 18:22:36 -070031import org.onosproject.net.PortNumber;
32import org.onosproject.net.behaviour.Pipeliner;
33import org.onosproject.net.behaviour.PipelinerContext;
alshabib2cc73cb2015-06-30 20:26:56 -070034import org.onosproject.net.device.DefaultDeviceDescription;
35import org.onosproject.net.device.DeviceDescription;
36import org.onosproject.net.device.DeviceProvider;
37import org.onosproject.net.device.DeviceProviderRegistry;
alshabib2cc73cb2015-06-30 20:26:56 -070038import org.onosproject.net.device.DeviceService;
alshabib0ccde6d2015-05-30 18:22:36 -070039import org.onosproject.net.driver.AbstractHandlerBehaviour;
40import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070041import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070042import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.FlowRule;
44import org.onosproject.net.flow.FlowRuleOperations;
45import org.onosproject.net.flow.FlowRuleOperationsContext;
46import org.onosproject.net.flow.FlowRuleService;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
alshabibfd430b62015-12-16 18:56:38 -080049import org.onosproject.net.flow.criteria.Criteria;
50import org.onosproject.net.flow.criteria.Criterion;
51import org.onosproject.net.flow.criteria.EthTypeCriterion;
52import org.onosproject.net.flow.criteria.IPProtocolCriterion;
53import org.onosproject.net.flow.criteria.PortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080054import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080055import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070056import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080057import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070058import org.onosproject.net.flowobjective.FilteringObjective;
59import org.onosproject.net.flowobjective.ForwardingObjective;
60import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080061import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070062import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2cc73cb2015-06-30 20:26:56 -070063import org.onosproject.net.provider.AbstractProvider;
64import org.onosproject.net.provider.ProviderId;
alshabib0ccde6d2015-05-30 18:22:36 -070065import org.slf4j.Logger;
66
alshabibfd430b62015-12-16 18:56:38 -080067import java.util.Collection;
68import java.util.List;
69import java.util.Optional;
70import java.util.stream.Collectors;
71
alshabib2cc73cb2015-06-30 20:26:56 -070072import static com.google.common.base.Preconditions.checkNotNull;
alshabib0ccde6d2015-05-30 18:22:36 -070073import static org.slf4j.LoggerFactory.getLogger;
74
75/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070076 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070077 */
alshabibfd430b62015-12-16 18:56:38 -080078
Jonathan Hartb92cc512015-11-16 23:05:21 -080079public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070080
alshabibfd430b62015-12-16 18:56:38 -080081 private static final Integer QQ_TABLE = 1;
alshabib0ccde6d2015-05-30 18:22:36 -070082 private final Logger log = getLogger(getClass());
83
alshabib2cc73cb2015-06-30 20:26:56 -070084 static final ProviderId PID = new ProviderId("olt", "org.onosproject.olt", true);
85
86 static final String DEVICE = "isAccess";
87 static final String OLT = "true";
88
alshabib0ccde6d2015-05-30 18:22:36 -070089 private ServiceDirectory serviceDirectory;
90 private FlowRuleService flowRuleService;
91 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070092 private CoreService coreService;
93
94 private ApplicationId appId;
alshabib0ccde6d2015-05-30 18:22:36 -070095
alshabib2cc73cb2015-06-30 20:26:56 -070096 private DeviceProvider provider = new AnnotationProvider();
97
alshabib0ccde6d2015-05-30 18:22:36 -070098 @Override
99 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800100 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700101 this.serviceDirectory = context.directory();
102 this.deviceId = deviceId;
alshabib2cc73cb2015-06-30 20:26:56 -0700103 DeviceProviderRegistry registry =
alshabibfd430b62015-12-16 18:56:38 -0800104 serviceDirectory.get(DeviceProviderRegistry.class);
alshabib0ccde6d2015-05-30 18:22:36 -0700105 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700106 coreService = serviceDirectory.get(CoreService.class);
alshabibb32cefe2015-06-08 18:15:05 -0700107
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700108 appId = coreService.registerApplication(
109 "org.onosproject.driver.OLTPipeline");
110
alshabibb32cefe2015-06-08 18:15:05 -0700111 }
112
alshabib0ccde6d2015-05-30 18:22:36 -0700113 @Override
114 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800115 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700116
alshabibfd430b62015-12-16 18:56:38 -0800117 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
118 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
119 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
120 .limit(1)
121 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700122
alshabibbb424232016-01-15 12:20:25 -0800123 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
124 log.error("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800125 fail(filter, ObjectiveError.UNSUPPORTED);
126 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700127 }
alshabibfd430b62015-12-16 18:56:38 -0800128 } else {
129 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700130 return;
131 }
132
alshabibfd430b62015-12-16 18:56:38 -0800133 if (filter.key().type() != Criterion.Type.IN_PORT) {
134 fail(filter, ObjectiveError.BADPARAMS);
135 return;
136 }
137
138 EthTypeCriterion ethType = (EthTypeCriterion)
139 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
140
141 if (ethType == null) {
142 fail(filter, ObjectiveError.BADPARAMS);
143 return;
144 }
145
alshabibbb424232016-01-15 12:20:25 -0800146 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800147 provisionEapol(filter, ethType, output);
alshabibbb424232016-01-15 12:20:25 -0800148 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800149 IPProtocolCriterion ipProto = (IPProtocolCriterion)
150 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
151 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
152 provisionIGMP(filter, ethType, ipProto, output);
alshabibbb424232016-01-15 12:20:25 -0800153 } else {
154 log.error("OLT can only filter igmp");
155 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800156 }
157 } else {
alshabibbb424232016-01-15 12:20:25 -0800158 log.error("OLT can only filter eapol and igmp");
alshabibfd430b62015-12-16 18:56:38 -0800159 fail(filter, ObjectiveError.UNSUPPORTED);
160 }
161
162 }
163
164
165 @Override
166 public void forward(ForwardingObjective fwd) {
alshabib0ccde6d2015-05-30 18:22:36 -0700167 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700168
alshabibfd430b62015-12-16 18:56:38 -0800169 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700170
alshabibfd430b62015-12-16 18:56:38 -0800171 Optional<Instruction> vlanIntruction = instructions.stream()
172 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
173 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
174 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
175 ((L2ModificationInstruction) i).subtype() ==
176 L2ModificationInstruction.L2SubType.VLAN_POP)
177 .findAny();
178
179 if (!vlanIntruction.isPresent()) {
180 fail(fwd, ObjectiveError.BADPARAMS);
181 return;
182 }
183
184 L2ModificationInstruction vlanIns =
185 (L2ModificationInstruction) vlanIntruction.get();
186
187 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
188 installUpstreamRules(fwd);
189 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
190 installDownstreamRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700191 } else {
alshabibfd430b62015-12-16 18:56:38 -0800192 log.error("Unknown OLT operation: {}", fwd);
193 fail(fwd, ObjectiveError.UNSUPPORTED);
194 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700195 }
196
alshabibfd430b62015-12-16 18:56:38 -0800197 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700198
alshabib0ccde6d2015-05-30 18:22:36 -0700199 }
200
201 @Override
202 public void next(NextObjective nextObjective) {
Jonathan Hart3e594642015-10-20 17:31:24 -0700203 throw new UnsupportedOperationException("OLT does not next hop.");
alshabib0ccde6d2015-05-30 18:22:36 -0700204 }
205
alshabibfd430b62015-12-16 18:56:38 -0800206 private void installDownstreamRules(ForwardingObjective fwd) {
207 List<Pair<Instruction, Instruction>> vlanOps =
208 vlanOps(fwd,
209 L2ModificationInstruction.L2SubType.VLAN_POP);
210
211 if (vlanOps == null) {
212 return;
213 }
214
215 Instruction output = fetchOutput(fwd, "downstream");
216
217 if (output == null) {
218 return;
219 }
220
221 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
222
alshabibfa0dc662016-01-13 11:23:53 -0800223 TrafficSelector selector = fwd.selector();
224
225 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
226 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
227 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
228
229 if (outerVlan == null || innerVlan == null || inport == null) {
230 log.error("Forwarding objective is underspecified: {}", fwd);
231 fail(fwd, ObjectiveError.BADPARAMS);
232 return;
233 }
234
alshabib2f74f2c2016-01-14 13:29:35 -0800235 Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId());
236
alshabibfa0dc662016-01-13 11:23:53 -0800237 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabibfd430b62015-12-16 18:56:38 -0800238 .forDevice(deviceId)
239 .fromApp(appId)
240 .makePermanent()
241 .withPriority(fwd.priority())
alshabibfa0dc662016-01-13 11:23:53 -0800242 .withSelector(buildSelector(inport, outerVlan))
alshabibfd430b62015-12-16 18:56:38 -0800243 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
244 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800245
alshabibfa0dc662016-01-13 11:23:53 -0800246 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabibfd430b62015-12-16 18:56:38 -0800247 .forDevice(deviceId)
248 .fromApp(appId)
249 .forTable(QQ_TABLE)
250 .makePermanent()
251 .withPriority(fwd.priority())
alshabib2f74f2c2016-01-14 13:29:35 -0800252 .withSelector(buildSelector(inport, innerVid))
alshabibfd430b62015-12-16 18:56:38 -0800253 .withTreatment(buildTreatment(popAndRewrite.getRight(),
254 output));
255
256 applyRules(fwd, inner, outer);
257
258 }
259
260 private void installUpstreamRules(ForwardingObjective fwd) {
261 List<Pair<Instruction, Instruction>> vlanOps =
262 vlanOps(fwd,
263 L2ModificationInstruction.L2SubType.VLAN_PUSH);
264
265 if (vlanOps == null) {
266 return;
267 }
268
269 Instruction output = fetchOutput(fwd, "upstream");
270
271 if (output == null) {
272 return;
273 }
274
275 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
276
277 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
278
279 FlowRule.Builder inner = DefaultFlowRule.builder()
280 .forDevice(deviceId)
281 .fromApp(appId)
282 .makePermanent()
283 .withPriority(fwd.priority())
284 .withSelector(fwd.selector())
285 .withTreatment(buildTreatment(innerPair.getRight(),
286 Instructions.transition(QQ_TABLE)));
287
288 PortCriterion inPort = (PortCriterion)
289 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
290
291 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
292 innerPair.getRight()).vlanId();
293
294 FlowRule.Builder outer = DefaultFlowRule.builder()
295 .forDevice(deviceId)
296 .fromApp(appId)
297 .forTable(QQ_TABLE)
298 .makePermanent()
299 .withPriority(fwd.priority())
300 .withSelector(buildSelector(inPort,
301 Criteria.matchVlanId(cVlanId)))
302 .withTreatment(buildTreatment(outerPair.getLeft(),
303 outerPair.getRight(),
304 output));
305
306 applyRules(fwd, inner, outer);
307
308 }
309
310 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
311 Instruction output = fwd.treatment().allInstructions().stream()
312 .filter(i -> i.type() == Instruction.Type.OUTPUT)
313 .findFirst().orElse(null);
314
315 if (output == null) {
316 log.error("OLT {} rule has no output", direction);
317 fail(fwd, ObjectiveError.BADPARAMS);
318 return null;
319 }
320 return output;
321 }
322
323 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
324 L2ModificationInstruction.L2SubType type) {
325
326 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
327 fwd.treatment().allInstructions(), type);
328
329 if (vlanOps == null) {
330 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
331 ? "downstream" : "upstream";
332 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
333 fail(fwd, ObjectiveError.BADPARAMS);
334 return null;
335 }
336 return vlanOps;
337 }
338
339
340 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
341 L2ModificationInstruction.L2SubType type) {
342
343 List<Instruction> vlanPushs = findL2Instructions(
344 type,
345 instructions);
346 List<Instruction> vlanSets = findL2Instructions(
347 L2ModificationInstruction.L2SubType.VLAN_ID,
348 instructions);
349
350 if (vlanPushs.size() != vlanSets.size()) {
351 return null;
352 }
353
354 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
355
356 for (int i = 0; i < vlanPushs.size(); i++) {
357 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
358 }
359 return pairs;
360 }
361
362 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
363 List<Instruction> actions) {
364 return actions.stream()
365 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
366 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
367 .collect(Collectors.toList());
368 }
369
370 private void provisionEapol(FilteringObjective filter,
371 EthTypeCriterion ethType,
372 Instructions.OutputInstruction output) {
373
374 TrafficSelector selector = buildSelector(filter.key(), ethType);
375 TrafficTreatment treatment = buildTreatment(output);
376 buildAndApplyRule(filter, selector, treatment);
377
378 }
379
380 private void provisionIGMP(FilteringObjective filter, EthTypeCriterion ethType,
381 IPProtocolCriterion ipProto,
382 Instructions.OutputInstruction output) {
383 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
384 TrafficTreatment treatment = buildTreatment(output);
385 buildAndApplyRule(filter, selector, treatment);
386 }
387
388 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
389 TrafficTreatment treatment) {
390 FlowRule rule = DefaultFlowRule.builder()
391 .forDevice(deviceId)
392 .forTable(0)
393 .fromApp(filter.appId())
394 .makePermanent()
395 .withSelector(selector)
396 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800397 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800398 .build();
399
400 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
401
402 switch (filter.type()) {
403 case PERMIT:
404 opsBuilder.add(rule);
405 break;
406 case DENY:
407 opsBuilder.remove(rule);
408 break;
409 default:
410 log.warn("Unknown filter type : {}", filter.type());
411 fail(filter, ObjectiveError.UNSUPPORTED);
412 }
413
414 applyFlowRules(opsBuilder, filter);
415 }
416
417 private void applyRules(ForwardingObjective fwd,
418 FlowRule.Builder inner, FlowRule.Builder outer) {
419 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
420 switch (fwd.op()) {
421 case ADD:
422 builder.add(inner.build()).add(outer.build());
423 break;
424 case REMOVE:
425 builder.remove(inner.build()).remove(outer.build());
426 break;
427 case ADD_TO_EXISTING:
428 break;
429 case REMOVE_FROM_EXISTING:
430 break;
431 default:
432 log.warn("Unknown forwarding operation: {}", fwd.op());
433 }
434
435 applyFlowRules(builder, fwd);
436 }
437
438 private void applyFlowRules(FlowRuleOperations.Builder builder,
439 Objective objective) {
440 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
441 @Override
442 public void onSuccess(FlowRuleOperations ops) {
443 pass(objective);
444 }
445
446 @Override
447 public void onError(FlowRuleOperations ops) {
448 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
449 }
450 }));
451 }
452
453 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
454 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800455 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800456 .limit(1)
457 .findFirst().orElse(null);
458 }
459
460 private TrafficSelector buildSelector(Criterion... criteria) {
461
462
463 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
464
465 for (Criterion c : criteria) {
466 sBuilder.add(c);
467 }
468
469 return sBuilder.build();
470 }
471
472 private TrafficTreatment buildTreatment(Instruction... instructions) {
473
474
475 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
476
477 for (Instruction i : instructions) {
478 tBuilder.add(i);
479 }
480
481 return tBuilder.build();
482 }
483
484
485 private void fail(Objective obj, ObjectiveError error) {
486 if (obj.context().isPresent()) {
487 obj.context().get().onError(obj, error);
488 }
489 }
490
491 private void pass(Objective obj) {
492 if (obj.context().isPresent()) {
493 obj.context().get().onSuccess(obj);
494 }
495 }
496
alshabib2cc73cb2015-06-30 20:26:56 -0700497 /**
498 * Build a device description.
Jonathan Hart3e594642015-10-20 17:31:24 -0700499 *
alshabib2cc73cb2015-06-30 20:26:56 -0700500 * @param deviceId a deviceId
alshabibfd430b62015-12-16 18:56:38 -0800501 * @param key the key of the annotation
502 * @param value the value for the annotation
alshabib2cc73cb2015-06-30 20:26:56 -0700503 * @return a device description
504 */
505 private DeviceDescription description(DeviceId deviceId, String key, String value) {
506 DeviceService deviceService = serviceDirectory.get(DeviceService.class);
507 Device device = deviceService.getDevice(deviceId);
508
509 checkNotNull(device, "Device not found in device service.");
510
511 DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
512 if (value != null) {
513 builder.set(key, value);
514 } else {
515 builder.remove(key);
516 }
517 return new DefaultDeviceDescription(device.id().uri(), device.type(),
518 device.manufacturer(), device.hwVersion(),
519 device.swVersion(), device.serialNumber(),
520 device.chassisId(), builder.build());
521 }
522
523 /**
524 * Simple ancillary provider used to annotate device.
525 */
526 private static final class AnnotationProvider
527 extends AbstractProvider implements DeviceProvider {
528 private AnnotationProvider() {
529 super(PID);
530 }
531
532 @Override
533 public void triggerProbe(DeviceId deviceId) {
534 }
535
536 @Override
537 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
538 }
539
540 @Override
541 public boolean isReachable(DeviceId deviceId) {
542 return false;
543 }
544 }
545
alshabib0ccde6d2015-05-30 18:22:36 -0700546}