Jonathan Hart
Committed by Gerrit Code Review

CORD fabric app

Change-Id: I2d261762b432170463e1dbc40432193cad28c9b2
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 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 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20 + <parent>
21 + <artifactId>onos-apps</artifactId>
22 + <groupId>org.onosproject</groupId>
23 + <version>1.2.0-SNAPSHOT</version>
24 + <relativePath>../pom.xml</relativePath>
25 + </parent>
26 + <modelVersion>4.0.0</modelVersion>
27 +
28 + <artifactId>onos-app-cordfabric</artifactId>
29 +
30 + <packaging>bundle</packaging>
31 + <description>Simple fabric application for CORD</description>
32 +
33 + <properties>
34 + <onos.app.name>org.onosproject.cordfabric</onos.app.name>
35 + </properties>
36 +
37 + <dependencies>
38 + <dependency>
39 + <groupId>org.onosproject</groupId>
40 + <artifactId>onos-cli</artifactId>
41 + <version>${project.version}</version>
42 + </dependency>
43 +
44 + <dependency>
45 + <groupId>org.apache.karaf.shell</groupId>
46 + <artifactId>org.apache.karaf.shell.console</artifactId>
47 + </dependency>
48 + </dependencies>
49 +</project>
1 +/*
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 + */
16 +
17 +package org.onosproject.cordfabric;
18 +
19 +import com.google.common.collect.HashMultimap;
20 +import com.google.common.collect.Multimap;
21 +import com.google.common.collect.Multimaps;
22 +import org.apache.felix.scr.annotations.Activate;
23 +import org.apache.felix.scr.annotations.Component;
24 +import org.apache.felix.scr.annotations.Deactivate;
25 +import org.apache.felix.scr.annotations.Reference;
26 +import org.apache.felix.scr.annotations.ReferenceCardinality;
27 +import org.apache.felix.scr.annotations.Service;
28 +import org.onlab.packet.VlanId;
29 +import org.onosproject.core.ApplicationId;
30 +import org.onosproject.core.CoreService;
31 +import org.onosproject.net.ConnectPoint;
32 +import org.onosproject.net.DeviceId;
33 +import org.onosproject.net.PortNumber;
34 +import org.onosproject.net.flow.DefaultTrafficSelector;
35 +import org.onosproject.net.flow.DefaultTrafficTreatment;
36 +import org.onosproject.net.flow.TrafficSelector;
37 +import org.onosproject.net.flow.TrafficTreatment;
38 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
39 +import org.onosproject.net.flowobjective.FlowObjectiveService;
40 +import org.onosproject.net.flowobjective.ForwardingObjective;
41 +import org.onosproject.net.flowobjective.Objective;
42 +import org.onosproject.net.flowobjective.ObjectiveContext;
43 +import org.onosproject.net.flowobjective.ObjectiveError;
44 +import org.slf4j.Logger;
45 +import org.slf4j.LoggerFactory;
46 +
47 +import java.util.List;
48 +import java.util.stream.Collectors;
49 +
50 +import static com.google.common.base.Preconditions.checkArgument;
51 +import static com.google.common.base.Preconditions.checkNotNull;
52 +import static org.slf4j.LoggerFactory.getLogger;
53 +
54 +/**
55 + * CORD fabric application.
56 + */
57 +@Service
58 +@Component(immediate = true)
59 +public class CordFabricManager implements FabricService {
60 +
61 + private final Logger log = getLogger(getClass());
62 +
63 + private ApplicationId appId;
64 +
65 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 + protected CoreService coreService;
67 +
68 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 + protected FlowObjectiveService flowObjectiveService;
70 +
71 + private static final int PRIORITY = 1000;
72 +
73 + private final Multimap<VlanId, ConnectPoint> vlans = HashMultimap.create();
74 +
75 + @Activate
76 + public void activate() {
77 + appId = coreService.registerApplication("org.onosproject.cordfabric");
78 +
79 + log.info("Started");
80 + }
81 +
82 + @Deactivate
83 + public void deactivate() {
84 + log.info("Stopped");
85 + }
86 +
87 + @Override
88 + public void addVlan(VlanId vlanId, List<ConnectPoint> ports) {
89 + checkNotNull(vlanId);
90 + checkNotNull(ports);
91 + checkArgument(ports.size() > 1);
92 + verifyPorts(ports);
93 +
94 + removeVlan(vlanId);
95 +
96 + ports.forEach(cp -> {
97 + if (vlans.put(vlanId, cp)) {
98 + addForwarding(vlanId, cp.deviceId(), cp.port(),
99 + ports.stream()
100 + .filter(p -> p != cp)
101 + .map(ConnectPoint::port)
102 + .collect(Collectors.toList()));
103 + }
104 + });
105 + }
106 +
107 + @Override
108 + public void removeVlan(VlanId vlanId) {
109 + vlans.removeAll(vlanId)
110 + .forEach(cp -> removeForwarding(vlanId, cp.deviceId(), cp.port()));
111 + }
112 +
113 + @Override
114 + public Multimap<VlanId, ConnectPoint> getVlans() {
115 + return Multimaps.unmodifiableMultimap(vlans);
116 + }
117 +
118 + private static void verifyPorts(List<ConnectPoint> ports) {
119 + DeviceId deviceId = ports.get(0).deviceId();
120 + for (ConnectPoint connectPoint : ports) {
121 + if (!connectPoint.deviceId().equals(deviceId)) {
122 + throw new IllegalArgumentException("Ports must all be on the same device");
123 + }
124 + }
125 + }
126 +
127 + private void addForwarding(VlanId vlanId, DeviceId deviceId, PortNumber inPort,
128 + List<PortNumber> outPorts) {
129 + TrafficSelector selector = DefaultTrafficSelector.builder()
130 + .matchVlanId(vlanId)
131 + .matchInPort(inPort)
132 + .build();
133 +
134 + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
135 +
136 + outPorts.forEach(p -> treatmentBuilder.setOutput(p));
137 +
138 + ForwardingObjective objective = DefaultForwardingObjective.builder()
139 + .fromApp(appId)
140 + .makePermanent()
141 + .withFlag(ForwardingObjective.Flag.VERSATILE)
142 + .withPriority(PRIORITY)
143 + .withSelector(selector)
144 + .withTreatment(treatmentBuilder.build())
145 + .add(new ObjectiveHandler());
146 +
147 + flowObjectiveService.forward(deviceId, objective);
148 + }
149 +
150 + private void removeForwarding(VlanId vlanId, DeviceId deviceId, PortNumber inPort) {
151 + TrafficSelector selector = DefaultTrafficSelector.builder()
152 + .matchVlanId(vlanId)
153 + .matchInPort(inPort)
154 + .build();
155 +
156 + ForwardingObjective objective = DefaultForwardingObjective.builder()
157 + .fromApp(appId)
158 + .makePermanent()
159 + .withFlag(ForwardingObjective.Flag.VERSATILE)
160 + .withPriority(PRIORITY)
161 + .withSelector(selector)
162 + .withTreatment(DefaultTrafficTreatment.builder().build())
163 + .remove(new ObjectiveHandler());
164 +
165 + flowObjectiveService.forward(deviceId, objective);
166 + }
167 +
168 + private static class ObjectiveHandler implements ObjectiveContext {
169 + private static Logger log = LoggerFactory.getLogger(ObjectiveHandler.class);
170 +
171 + @Override
172 + public void onSuccess(Objective objective) {
173 + log.info("Flow objective operation successful: {}", objective);
174 + }
175 +
176 + @Override
177 + public void onError(Objective objective, ObjectiveError error) {
178 + log.info("Flow objective operation failed: {}", objective);
179 + }
180 + }
181 +}
1 +/*
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 + */
16 +
17 +package org.onosproject.cordfabric;
18 +
19 +import com.google.common.collect.Multimap;
20 +import org.onlab.packet.VlanId;
21 +import org.onosproject.net.ConnectPoint;
22 +
23 +import java.util.List;
24 +
25 +/**
26 + * Service used to interact with fabric.
27 + */
28 +public interface FabricService {
29 +
30 + /**
31 + * Remaps a vlan to the specified ports. The specified ports will be the
32 + * only ports in this vlan once the operation completes.
33 + *
34 + * @param vlanId vlan ID to add/modify
35 + * @param ports list of ports to add to the vlan
36 + */
37 + void addVlan(VlanId vlanId, List<ConnectPoint> ports);
38 +
39 + /**
40 + * Removes a vlan from all ports in the fabric.
41 + *
42 + * @param vlanId ID of vlan to remove
43 + */
44 + void removeVlan(VlanId vlanId);
45 +
46 + /**
47 + * Returns the vlan to port mapping for all vlans/ports configured in the
48 + * fabric.
49 + *
50 + * @return mapping of vlan to port
51 + */
52 + Multimap<VlanId, ConnectPoint> getVlans();
53 +}
1 +/*
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 + */
16 +
17 +package org.onosproject.cordfabric.cli;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onlab.packet.VlanId;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.cordfabric.FabricService;
24 +import org.onosproject.net.ConnectPoint;
25 +
26 +import java.util.ArrayList;
27 +import java.util.List;
28 +
29 +/**
30 + * Adds a vlan to the fabric.
31 + */
32 +@Command(scope = "onos", name = "add-fabric-vlan",
33 + description = "Adds a VLAN to the fabric")
34 +public class FabricAddCommand extends AbstractShellCommand {
35 +
36 + @Argument(index = 0, name = "vlanid", description = "VLAN ID",
37 + required = true, multiValued = false)
38 + private String vlanIdString = null;
39 +
40 + @Argument(index = 1, name = "ports",
41 + description = "List of ports in the VLAN",
42 + required = true, multiValued = true)
43 + private String[] portStrings = null;
44 +
45 + @Override
46 + protected void execute() {
47 + FabricService service = AbstractShellCommand.get(FabricService.class);
48 +
49 + VlanId vlan = VlanId.vlanId(Short.parseShort(vlanIdString));
50 +
51 + if (portStrings.length < 2) {
52 + throw new IllegalArgumentException("Must have at least 2 ports");
53 + }
54 +
55 + List<ConnectPoint> ports = new ArrayList<>(portStrings.length);
56 +
57 + for (String portString : portStrings) {
58 + ports.add(ConnectPoint.deviceConnectPoint(portString));
59 + }
60 +
61 + service.addVlan(vlan, ports);
62 + }
63 +}
1 +/*
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 + */
16 +
17 +package org.onosproject.cordfabric.cli;
18 +
19 +import com.google.common.collect.Multimap;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onlab.packet.VlanId;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.cordfabric.FabricService;
24 +import org.onosproject.net.ConnectPoint;
25 +
26 +/**
27 + * Shows the vlans in the fabric.
28 + */
29 +@Command(scope = "onos", name = "fabric",
30 + description = "Shows the fabric vlans")
31 +public class FabricShowCommand extends AbstractShellCommand {
32 +
33 + private static final String VLAN_HEADER_LINE_FORMAT = "VLAN %s";
34 + private static final String PORT_LINE_FORMAT = "\t%s";
35 +
36 + @Override
37 + protected void execute() {
38 + FabricService service = AbstractShellCommand.get(FabricService.class);
39 +
40 + Multimap<VlanId, ConnectPoint> vlans = service.getVlans();
41 +
42 + vlans.keySet().forEach(vlanId -> {
43 + print(VLAN_HEADER_LINE_FORMAT, vlanId);
44 + vlans.get(vlanId).forEach(cp -> print(PORT_LINE_FORMAT, cp));
45 + });
46 + }
47 +}
1 +<!--
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 + -->
16 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 +
18 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 + <command>
20 + <action class="org.onosproject.cordfabric.cli.FabricShowCommand"/>
21 + </command>
22 + <command>
23 + <action class="org.onosproject.cordfabric.cli.FabricAddCommand"/>
24 + <completers>
25 + <ref component-id="placeholderCompleter"/>
26 + <ref component-id="connectPointCompleter"/>
27 + </completers>
28 + </command>
29 + </command-bundle>
30 +
31 + <bean id="connectPointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/>
32 + <bean id="placeholderCompleter" class="org.onosproject.cli.PlaceholderCompleter"/>
33 +</blueprint>
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
47 <module>bgprouter</module> 47 <module>bgprouter</module>
48 <module>test</module> 48 <module>test</module>
49 <module>segmentrouting</module> 49 <module>segmentrouting</module>
50 + <module>cordfabric</module>
50 </modules> 51 </modules>
51 52
52 <properties> 53 <properties>
......
1 +/*
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 + */
16 +
17 +package org.onosproject.cli;
18 +
19 +import org.apache.karaf.shell.console.completer.StringsCompleter;
20 +
21 +import java.util.List;
22 +import java.util.SortedSet;
23 +
24 +/**
25 + * A completer that can be used as a placeholder for arguments that don't
26 + * need/want completers.
27 + */
28 +public class PlaceholderCompleter extends AbstractCompleter {
29 +
30 + @Override
31 + public int complete(String s, int i, List<String> list) {
32 + // Populate a string completer with what the user has typed so far
33 + StringsCompleter delegate = new StringsCompleter();
34 + SortedSet<String> strings = delegate.getStrings();
35 + if (s != null) {
36 + strings.add(s);
37 + }
38 + return delegate.complete(s, i, list);
39 + }
40 +}