Implement point to point intent compiler and cli commands to create them
Showing
4 changed files
with
241 additions
and
0 deletions
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 | +} |
-
Please register or login to post a comment