Ray Milkey

Implement point to point intent compiler and cli commands to create them

1 +package org.onlab.onos.cli.net;
2 +
3 +import org.apache.karaf.shell.commands.Argument;
4 +import org.apache.karaf.shell.commands.Command;
5 +import org.onlab.onos.cli.AbstractShellCommand;
6 +import org.onlab.onos.net.ConnectPoint;
7 +import org.onlab.onos.net.DeviceId;
8 +import org.onlab.onos.net.PortNumber;
9 +import org.onlab.onos.net.flow.DefaultTrafficSelector;
10 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
11 +import org.onlab.onos.net.flow.TrafficSelector;
12 +import org.onlab.onos.net.flow.TrafficTreatment;
13 +import org.onlab.onos.net.intent.Intent;
14 +import org.onlab.onos.net.intent.IntentId;
15 +import org.onlab.onos.net.intent.IntentService;
16 +import org.onlab.onos.net.intent.PointToPointIntent;
17 +
18 +/**
19 + * Installs point-to-point connectivity intents.
20 + */
21 +@Command(scope = "onos", name = "add-point-intent",
22 + description = "Installs point-to-point connectivity intent")
23 +public class AddPointToPointIntentCommand extends AbstractShellCommand {
24 +
25 + @Argument(index = 0, name = "ingressDevice",
26 + description = "Ingress Device/Port Description",
27 + required = true, multiValued = false)
28 + String ingressDeviceString = null;
29 +
30 + @Argument(index = 1, name = "egressDevice",
31 + description = "Egress Device/Port Description",
32 + required = true, multiValued = false)
33 + String egressDeviceString = null;
34 +
35 + private static long id = 1;
36 +
37 + @Override
38 + protected void execute() {
39 + IntentService service = get(IntentService.class);
40 +
41 + DeviceId ingressDeviceId = DeviceId.deviceId(getDeviceId(ingressDeviceString));
42 + PortNumber ingressPortNumber =
43 + PortNumber.portNumber(getPortNumber(ingressDeviceString));
44 + ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
45 +
46 + DeviceId egressDeviceId = DeviceId.deviceId(getDeviceId(egressDeviceString));
47 + PortNumber egressPortNumber =
48 + PortNumber.portNumber(getPortNumber(egressDeviceString));
49 + ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
50 +
51 + TrafficSelector selector = DefaultTrafficSelector.builder().build();
52 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
53 +
54 + Intent intent =
55 + new PointToPointIntent(new IntentId(id++),
56 + selector,
57 + treatment,
58 + ingress,
59 + egress);
60 + service.submit(intent);
61 + }
62 +
63 + /**
64 + * Extracts the port number portion of the ConnectPoint.
65 + *
66 + * @param deviceString string representing the device/port
67 + * @return port number as a string, empty string if the port is not found
68 + */
69 + private String getPortNumber(String deviceString) {
70 + int slash = deviceString.indexOf('/');
71 + if (slash <= 0) {
72 + return "";
73 + }
74 + return deviceString.substring(slash + 1, deviceString.length());
75 + }
76 +
77 + /**
78 + * Extracts the device ID portion of the ConnectPoint.
79 + *
80 + * @param deviceString string representing the device/port
81 + * @return device ID string
82 + */
83 + private String getDeviceId(String deviceString) {
84 + int slash = deviceString.indexOf('/');
85 + if (slash <= 0) {
86 + return "";
87 + }
88 + return deviceString.substring(0, slash);
89 + }
90 +}
1 +package org.onlab.onos.cli.net;
2 +
3 +import java.util.List;
4 +import java.util.SortedSet;
5 +
6 +import org.apache.karaf.shell.console.Completer;
7 +import org.apache.karaf.shell.console.completer.StringsCompleter;
8 +import org.onlab.onos.cli.AbstractShellCommand;
9 +import org.onlab.onos.net.Device;
10 +import org.onlab.onos.net.Port;
11 +import org.onlab.onos.net.device.DeviceService;
12 +
13 +/**
14 + * ConnectPoint completer.
15 + */
16 +public class ConnectPointCompleter implements Completer {
17 + @Override
18 + public int complete(String buffer, int cursor, List<String> candidates) {
19 + // Delegate string completer
20 + StringsCompleter delegate = new StringsCompleter();
21 +
22 + // Fetch our service and feed it's offerings to the string completer
23 + DeviceService service = AbstractShellCommand.get(DeviceService.class);
24 +
25 + // Generate the device ID/port number identifiers
26 + for (Device device : service.getDevices()) {
27 + SortedSet<String> strings = delegate.getStrings();
28 +
29 + for (Port port : service.getPorts(device.id())) {
30 + strings.add(device.id().toString() + "/" + port.number());
31 + }
32 + }
33 +
34 + // Now let the completer do the work for figuring out what to offer.
35 + return delegate.complete(buffer, cursor, candidates);
36 + }
37 +
38 +}
...@@ -75,6 +75,13 @@ ...@@ -75,6 +75,13 @@
75 <ref component-id="hostIdCompleter"/> 75 <ref component-id="hostIdCompleter"/>
76 </completers> 76 </completers>
77 </command> 77 </command>
78 + <command>
79 + <action class="org.onlab.onos.cli.net.AddPointToPointIntentCommand"/>
80 + <completers>
81 + <ref component-id="connectPointCompleter"/>
82 + <ref component-id="connectPointCompleter"/>
83 + </completers>
84 + </command>
78 85
79 <command> 86 <command>
80 <action class="org.onlab.onos.cli.net.ClustersListCommand"/> 87 <action class="org.onlab.onos.cli.net.ClustersListCommand"/>
...@@ -116,5 +123,6 @@ ...@@ -116,5 +123,6 @@
116 <bean id="hostIdCompleter" class="org.onlab.onos.cli.net.HostIdCompleter"/> 123 <bean id="hostIdCompleter" class="org.onlab.onos.cli.net.HostIdCompleter"/>
117 <bean id="intentIdCompleter" class="org.onlab.onos.cli.net.IntentIdCompleter"/> 124 <bean id="intentIdCompleter" class="org.onlab.onos.cli.net.IntentIdCompleter"/>
118 <bean id="flowRuleStatusCompleter" class="org.onlab.onos.cli.net.FlowRuleStatusCompleter"/> 125 <bean id="flowRuleStatusCompleter" class="org.onlab.onos.cli.net.FlowRuleStatusCompleter"/>
126 + <bean id="connectPointCompleter" class="org.onlab.onos.cli.net.ConnectPointCompleter"/>
119 127
120 </blueprint> 128 </blueprint>
......
1 +package org.onlab.onos.net.intent.impl;
2 +
3 +import java.util.ArrayList;
4 +import java.util.Arrays;
5 +import java.util.List;
6 +import java.util.Set;
7 +
8 +import org.apache.felix.scr.annotations.Activate;
9 +import org.apache.felix.scr.annotations.Component;
10 +import org.apache.felix.scr.annotations.Deactivate;
11 +import org.apache.felix.scr.annotations.Reference;
12 +import org.apache.felix.scr.annotations.ReferenceCardinality;
13 +import org.onlab.onos.net.ConnectPoint;
14 +import org.onlab.onos.net.DefaultEdgeLink;
15 +import org.onlab.onos.net.DefaultPath;
16 +import org.onlab.onos.net.Link;
17 +import org.onlab.onos.net.Path;
18 +import org.onlab.onos.net.host.HostService;
19 +import org.onlab.onos.net.intent.IdGenerator;
20 +import org.onlab.onos.net.intent.Intent;
21 +import org.onlab.onos.net.intent.IntentCompiler;
22 +import org.onlab.onos.net.intent.IntentExtensionService;
23 +import org.onlab.onos.net.intent.IntentId;
24 +import org.onlab.onos.net.intent.PathIntent;
25 +import org.onlab.onos.net.intent.PointToPointIntent;
26 +import org.onlab.onos.net.provider.ProviderId;
27 +import org.onlab.onos.net.topology.PathService;
28 +
29 +/**
30 + * A intent compiler for {@link org.onlab.onos.net.intent.HostToHostIntent}.
31 + */
32 +@Component(immediate = true)
33 +public class PointToPointIntentCompiler
34 + implements IntentCompiler<PointToPointIntent> {
35 +
36 + private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true);
37 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
38 + protected IntentExtensionService intentManager;
39 +
40 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
41 + protected PathService pathService;
42 +
43 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
44 + protected HostService hostService;
45 +
46 + private IdGenerator<IntentId> intentIdGenerator;
47 +
48 + @Activate
49 + public void activate() {
50 + IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
51 + intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
52 + intentManager.registerCompiler(PointToPointIntent.class, this);
53 + }
54 +
55 + @Deactivate
56 + public void deactivate() {
57 + intentManager.unregisterCompiler(PointToPointIntent.class);
58 + }
59 +
60 + @Override
61 + public List<Intent> compile(PointToPointIntent intent) {
62 + Path path = getPath(intent.ingressPoint(), intent.egressPoint());
63 +
64 + List<Link> links = new ArrayList<>();
65 + links.add(DefaultEdgeLink.createEdgeLink(intent.ingressPoint(), true));
66 + links.addAll(path.links());
67 + links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
68 +
69 + return Arrays.asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
70 + path.annotations()),
71 + intent));
72 + }
73 +
74 + /**
75 + * Creates a path intent from the specified path and original
76 + * connectivity intent.
77 + *
78 + * @param path path to create an intent for
79 + * @param intent original intent
80 + */
81 + private Intent createPathIntent(Path path,
82 + PointToPointIntent intent) {
83 +
84 + return new PathIntent(intentIdGenerator.getNewId(),
85 + intent.selector(), intent.treatment(),
86 + path.src(), path.dst(), path);
87 + }
88 +
89 + /**
90 + * Computes a path between two ConnectPoints.
91 + *
92 + * @param one start of the path
93 + * @param two end of the path
94 + * @return Path between the two
95 + * @throws PathNotFoundException if a path cannot be found
96 + */
97 + private Path getPath(ConnectPoint one, ConnectPoint two) {
98 + Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId());
99 + if (paths.isEmpty()) {
100 + throw new PathNotFoundException("No path from " + one + " to " + two);
101 + }
102 + // TODO: let's be more intelligent about this eventually
103 + return paths.iterator().next();
104 + }
105 +}