Committed by
Gerrit Code Review
Add basic ability to add and remove interfaces
Change-Id: I11fd764304a4e7ab298336f3033a4417ba4be28d
Showing
6 changed files
with
290 additions
and
11 deletions
| 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.net; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.Sets; | ||
| 20 | +import org.apache.karaf.shell.commands.Command; | ||
| 21 | +import org.apache.karaf.shell.commands.Option; | ||
| 22 | +import org.onlab.packet.MacAddress; | ||
| 23 | +import org.onlab.packet.VlanId; | ||
| 24 | +import org.onosproject.cli.AbstractShellCommand; | ||
| 25 | +import org.onosproject.incubator.net.intf.Interface; | ||
| 26 | +import org.onosproject.incubator.net.intf.InterfaceAdminService; | ||
| 27 | +import org.onosproject.net.ConnectPoint; | ||
| 28 | +import org.onosproject.net.host.InterfaceIpAddress; | ||
| 29 | + | ||
| 30 | +import java.util.Set; | ||
| 31 | + | ||
| 32 | +/** | ||
| 33 | + * Adds a new interface configuration. | ||
| 34 | + */ | ||
| 35 | +@Command(scope = "onos", name = "add-interface", | ||
| 36 | + description = "Adds a new configured interface") | ||
| 37 | +public class InterfaceAddCommand extends AbstractShellCommand { | ||
| 38 | + | ||
| 39 | + @Option(name = "-c", aliases = "--connectPoint", | ||
| 40 | + description = "Device port that the interface is associated with", | ||
| 41 | + required = true, multiValued = false) | ||
| 42 | + private String connectPoint = null; | ||
| 43 | + | ||
| 44 | + @Option(name = "-m", aliases = "--mac", | ||
| 45 | + description = "MAC address of the interface", | ||
| 46 | + required = true, multiValued = false) | ||
| 47 | + private String mac = null; | ||
| 48 | + | ||
| 49 | + @Option(name = "-i", aliases = "--ip", | ||
| 50 | + description = "IP address configured on the interface\n" + | ||
| 51 | + "(e.g. 10.0.1.1/24). Can be specified multiple times.", | ||
| 52 | + required = false, multiValued = true) | ||
| 53 | + private String[] ips = null; | ||
| 54 | + | ||
| 55 | + @Option(name = "-v", aliases = "--vlan", | ||
| 56 | + description = "VLAN configured on the interface", | ||
| 57 | + required = false, multiValued = false) | ||
| 58 | + private String vlan = null; | ||
| 59 | + | ||
| 60 | + @Override | ||
| 61 | + protected void execute() { | ||
| 62 | + InterfaceAdminService interfaceService = get(InterfaceAdminService.class); | ||
| 63 | + | ||
| 64 | + Set<InterfaceIpAddress> ipAddresses = Sets.newHashSet(); | ||
| 65 | + if (ips != null) { | ||
| 66 | + for (String strIp : ips) { | ||
| 67 | + ipAddresses.add(InterfaceIpAddress.valueOf(strIp)); | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + VlanId vlanId = vlan == null ? VlanId.NONE : VlanId.vlanId(Short.parseShort(vlan)); | ||
| 72 | + | ||
| 73 | + Interface intf = new Interface(ConnectPoint.deviceConnectPoint(connectPoint), | ||
| 74 | + ipAddresses, MacAddress.valueOf(mac), vlanId); | ||
| 75 | + | ||
| 76 | + interfaceService.add(intf); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | +} |
| 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.net; | ||
| 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.incubator.net.intf.InterfaceAdminService; | ||
| 24 | +import org.onosproject.net.ConnectPoint; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * Removes an interface configuration. | ||
| 28 | + */ | ||
| 29 | +@Command(scope = "onos", name = "remove-interface", | ||
| 30 | + description = "Removes a configured interface") | ||
| 31 | +public class InterfaceRemoveCommand extends AbstractShellCommand { | ||
| 32 | + | ||
| 33 | + @Argument(index = 0, name = "connectPoint", | ||
| 34 | + description = "Connect point of the interface", | ||
| 35 | + required = true, multiValued = false) | ||
| 36 | + private String connectPoint = null; | ||
| 37 | + | ||
| 38 | + @Argument(index = 1, name = "vlan", | ||
| 39 | + description = "Interface vlan", | ||
| 40 | + required = true, multiValued = false) | ||
| 41 | + private String vlan = null; | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + protected void execute() { | ||
| 45 | + InterfaceAdminService interfaceService = get(InterfaceAdminService.class); | ||
| 46 | + | ||
| 47 | + interfaceService.remove(ConnectPoint.deviceConnectPoint(connectPoint), | ||
| 48 | + VlanId.vlanId(Short.parseShort(vlan))); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | +} |
| ... | @@ -352,6 +352,19 @@ | ... | @@ -352,6 +352,19 @@ |
| 352 | <action class="org.onosproject.cli.net.InterfacesListCommand"/> | 352 | <action class="org.onosproject.cli.net.InterfacesListCommand"/> |
| 353 | </command> | 353 | </command> |
| 354 | <command> | 354 | <command> |
| 355 | + <action class="org.onosproject.cli.net.InterfaceAddCommand"/> | ||
| 356 | + <optional-completers> | ||
| 357 | + <entry key="-c" value-ref="connectPointCompleter"/> | ||
| 358 | + <entry key="--connectPoint" value-ref="connectPointCompleter"/> | ||
| 359 | + </optional-completers> | ||
| 360 | + </command> | ||
| 361 | + <command> | ||
| 362 | + <action class="org.onosproject.cli.net.InterfaceRemoveCommand"/> | ||
| 363 | + <completers> | ||
| 364 | + <ref component-id="connectPointCompleter"/> | ||
| 365 | + </completers> | ||
| 366 | + </command> | ||
| 367 | + <command> | ||
| 355 | <action class="org.onosproject.cli.net.GroupsListCommand"/> | 368 | <action class="org.onosproject.cli.net.GroupsListCommand"/> |
| 356 | </command> | 369 | </command> |
| 357 | 370 | ... | ... |
| ... | @@ -17,13 +17,15 @@ | ... | @@ -17,13 +17,15 @@ |
| 17 | package org.onosproject.incubator.net.config.basics; | 17 | package org.onosproject.incubator.net.config.basics; |
| 18 | 18 | ||
| 19 | import com.fasterxml.jackson.databind.JsonNode; | 19 | import com.fasterxml.jackson.databind.JsonNode; |
| 20 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
| 21 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 20 | import com.google.common.annotations.Beta; | 22 | import com.google.common.annotations.Beta; |
| 21 | import com.google.common.collect.Sets; | 23 | import com.google.common.collect.Sets; |
| 22 | import org.onlab.packet.MacAddress; | 24 | import org.onlab.packet.MacAddress; |
| 23 | import org.onlab.packet.VlanId; | 25 | import org.onlab.packet.VlanId; |
| 24 | -import org.onosproject.net.config.Config; | ||
| 25 | import org.onosproject.incubator.net.intf.Interface; | 26 | import org.onosproject.incubator.net.intf.Interface; |
| 26 | import org.onosproject.net.ConnectPoint; | 27 | import org.onosproject.net.ConnectPoint; |
| 28 | +import org.onosproject.net.config.Config; | ||
| 27 | import org.onosproject.net.host.InterfaceIpAddress; | 29 | import org.onosproject.net.host.InterfaceIpAddress; |
| 28 | 30 | ||
| 29 | import java.util.Set; | 31 | import java.util.Set; |
| ... | @@ -37,7 +39,6 @@ public class InterfaceConfig extends Config<ConnectPoint> { | ... | @@ -37,7 +39,6 @@ public class InterfaceConfig extends Config<ConnectPoint> { |
| 37 | public static final String MAC = "mac"; | 39 | public static final String MAC = "mac"; |
| 38 | public static final String VLAN = "vlan"; | 40 | public static final String VLAN = "vlan"; |
| 39 | 41 | ||
| 40 | - public static final String IP_MISSING_ERROR = "Must have at least one IP address"; | ||
| 41 | public static final String MAC_MISSING_ERROR = "Must have a MAC address for each interface"; | 42 | public static final String MAC_MISSING_ERROR = "Must have a MAC address for each interface"; |
| 42 | public static final String CONFIG_VALUE_ERROR = "Error parsing config value"; | 43 | public static final String CONFIG_VALUE_ERROR = "Error parsing config value"; |
| 43 | 44 | ||
| ... | @@ -53,9 +54,6 @@ public class InterfaceConfig extends Config<ConnectPoint> { | ... | @@ -53,9 +54,6 @@ public class InterfaceConfig extends Config<ConnectPoint> { |
| 53 | try { | 54 | try { |
| 54 | for (JsonNode intfNode : array) { | 55 | for (JsonNode intfNode : array) { |
| 55 | Set<InterfaceIpAddress> ips = getIps(intfNode); | 56 | Set<InterfaceIpAddress> ips = getIps(intfNode); |
| 56 | - if (ips.isEmpty()) { | ||
| 57 | - throw new ConfigException(IP_MISSING_ERROR); | ||
| 58 | - } | ||
| 59 | 57 | ||
| 60 | if (intfNode.path(MAC).isMissingNode()) { | 58 | if (intfNode.path(MAC).isMissingNode()) { |
| 61 | throw new ConfigException(MAC_MISSING_ERROR); | 59 | throw new ConfigException(MAC_MISSING_ERROR); |
| ... | @@ -63,10 +61,7 @@ public class InterfaceConfig extends Config<ConnectPoint> { | ... | @@ -63,10 +61,7 @@ public class InterfaceConfig extends Config<ConnectPoint> { |
| 63 | 61 | ||
| 64 | MacAddress mac = MacAddress.valueOf(intfNode.path(MAC).asText()); | 62 | MacAddress mac = MacAddress.valueOf(intfNode.path(MAC).asText()); |
| 65 | 63 | ||
| 66 | - VlanId vlan = VlanId.NONE; | 64 | + VlanId vlan = getVlan(intfNode); |
| 67 | - if (!intfNode.path(VLAN).isMissingNode()) { | ||
| 68 | - vlan = VlanId.vlanId(Short.valueOf(intfNode.path(VLAN).asText())); | ||
| 69 | - } | ||
| 70 | 65 | ||
| 71 | interfaces.add(new Interface(subject, ips, mac, vlan)); | 66 | interfaces.add(new Interface(subject, ips, mac, vlan)); |
| 72 | } | 67 | } |
| ... | @@ -77,13 +72,64 @@ public class InterfaceConfig extends Config<ConnectPoint> { | ... | @@ -77,13 +72,64 @@ public class InterfaceConfig extends Config<ConnectPoint> { |
| 77 | return interfaces; | 72 | return interfaces; |
| 78 | } | 73 | } |
| 79 | 74 | ||
| 75 | + /** | ||
| 76 | + * Adds an interface to the config. | ||
| 77 | + * | ||
| 78 | + * @param intf interface to add | ||
| 79 | + */ | ||
| 80 | + public void addInterface(Interface intf) { | ||
| 81 | + ObjectNode intfNode = array.addObject(); | ||
| 82 | + intfNode.put(MAC, intf.mac().toString()); | ||
| 83 | + | ||
| 84 | + if (!intf.ipAddresses().isEmpty()) { | ||
| 85 | + intfNode.set(IPS, putIps(intf.ipAddresses())); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + if (!intf.vlan().equals(VlanId.NONE)) { | ||
| 89 | + intfNode.put(VLAN, intf.vlan().toString()); | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * Removes an interface from the config. | ||
| 95 | + * | ||
| 96 | + * @param intf interface to remove | ||
| 97 | + */ | ||
| 98 | + public void removeInterface(Interface intf) { | ||
| 99 | + for (int i = 0; i < array.size(); i++) { | ||
| 100 | + if (intf.vlan().equals(getVlan(node))) { | ||
| 101 | + array.remove(i); | ||
| 102 | + break; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + private VlanId getVlan(JsonNode node) { | ||
| 108 | + VlanId vlan = VlanId.NONE; | ||
| 109 | + if (!node.path(VLAN).isMissingNode()) { | ||
| 110 | + vlan = VlanId.vlanId(Short.valueOf(node.path(VLAN).asText())); | ||
| 111 | + } | ||
| 112 | + return vlan; | ||
| 113 | + } | ||
| 114 | + | ||
| 80 | private Set<InterfaceIpAddress> getIps(JsonNode node) { | 115 | private Set<InterfaceIpAddress> getIps(JsonNode node) { |
| 81 | Set<InterfaceIpAddress> ips = Sets.newHashSet(); | 116 | Set<InterfaceIpAddress> ips = Sets.newHashSet(); |
| 82 | 117 | ||
| 83 | JsonNode ipsNode = node.get(IPS); | 118 | JsonNode ipsNode = node.get(IPS); |
| 84 | - ipsNode.forEach(jsonNode -> ips.add(InterfaceIpAddress.valueOf(jsonNode.asText()))); | 119 | + if (ipsNode != null) { |
| 120 | + ipsNode.forEach(jsonNode -> | ||
| 121 | + ips.add(InterfaceIpAddress.valueOf(jsonNode.asText()))); | ||
| 122 | + } | ||
| 85 | 123 | ||
| 86 | return ips; | 124 | return ips; |
| 87 | } | 125 | } |
| 88 | 126 | ||
| 127 | + private ArrayNode putIps(Set<InterfaceIpAddress> intfIpAddresses) { | ||
| 128 | + ArrayNode ipArray = mapper.createArrayNode(); | ||
| 129 | + | ||
| 130 | + intfIpAddresses.forEach(i -> ipArray.add(i.toString())); | ||
| 131 | + | ||
| 132 | + return ipArray; | ||
| 133 | + } | ||
| 134 | + | ||
| 89 | } | 135 | } | ... | ... |
incubator/api/src/main/java/org/onosproject/incubator/net/intf/InterfaceAdminService.java
0 → 100644
| 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.incubator.net.intf; | ||
| 18 | + | ||
| 19 | +import org.onlab.packet.VlanId; | ||
| 20 | +import org.onosproject.net.ConnectPoint; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * Provides a means to modify the interfaces configuration. | ||
| 24 | + */ | ||
| 25 | +public interface InterfaceAdminService { | ||
| 26 | + /** | ||
| 27 | + * Adds a new interface configuration to the system. | ||
| 28 | + * | ||
| 29 | + * @param intf interface to add | ||
| 30 | + */ | ||
| 31 | + void add(Interface intf); | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * Removes an interface configuration from the system. | ||
| 35 | + * | ||
| 36 | + * @param connectPoint connect point of the interface | ||
| 37 | + * @param vlanId vlan id | ||
| 38 | + */ | ||
| 39 | + void remove(ConnectPoint connectPoint, VlanId vlanId); | ||
| 40 | +} |
| ... | @@ -29,6 +29,7 @@ import org.onlab.packet.VlanId; | ... | @@ -29,6 +29,7 @@ import org.onlab.packet.VlanId; |
| 29 | import org.onosproject.incubator.net.config.basics.ConfigException; | 29 | import org.onosproject.incubator.net.config.basics.ConfigException; |
| 30 | import org.onosproject.incubator.net.config.basics.InterfaceConfig; | 30 | import org.onosproject.incubator.net.config.basics.InterfaceConfig; |
| 31 | import org.onosproject.incubator.net.intf.Interface; | 31 | import org.onosproject.incubator.net.intf.Interface; |
| 32 | +import org.onosproject.incubator.net.intf.InterfaceAdminService; | ||
| 32 | import org.onosproject.incubator.net.intf.InterfaceService; | 33 | import org.onosproject.incubator.net.intf.InterfaceService; |
| 33 | import org.onosproject.net.ConnectPoint; | 34 | import org.onosproject.net.ConnectPoint; |
| 34 | import org.onosproject.net.config.NetworkConfigEvent; | 35 | import org.onosproject.net.config.NetworkConfigEvent; |
| ... | @@ -50,7 +51,8 @@ import static java.util.stream.Collectors.toSet; | ... | @@ -50,7 +51,8 @@ import static java.util.stream.Collectors.toSet; |
| 50 | */ | 51 | */ |
| 51 | @Service | 52 | @Service |
| 52 | @Component(immediate = true) | 53 | @Component(immediate = true) |
| 53 | -public class InterfaceManager implements InterfaceService { | 54 | +public class InterfaceManager implements InterfaceService, |
| 55 | + InterfaceAdminService { | ||
| 54 | 56 | ||
| 55 | private final Logger log = LoggerFactory.getLogger(getClass()); | 57 | private final Logger log = LoggerFactory.getLogger(getClass()); |
| 56 | 58 | ||
| ... | @@ -153,6 +155,54 @@ public class InterfaceManager implements InterfaceService { | ... | @@ -153,6 +155,54 @@ public class InterfaceManager implements InterfaceService { |
| 153 | interfaces.remove(port); | 155 | interfaces.remove(port); |
| 154 | } | 156 | } |
| 155 | 157 | ||
| 158 | + @Override | ||
| 159 | + public void add(Interface intf) { | ||
| 160 | + if (interfaces.containsKey(intf.connectPoint())) { | ||
| 161 | + boolean conflict = interfaces.get(intf.connectPoint()).stream() | ||
| 162 | + .filter(i -> i.connectPoint().equals(intf.connectPoint())) | ||
| 163 | + .filter(i -> i.mac().equals(intf.mac())) | ||
| 164 | + .filter(i -> i.vlan().equals(intf.vlan())) | ||
| 165 | + .findAny().isPresent(); | ||
| 166 | + | ||
| 167 | + if (conflict) { | ||
| 168 | + log.error("Can't add interface because it conflicts with existing config"); | ||
| 169 | + return; | ||
| 170 | + } | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + InterfaceConfig config = | ||
| 174 | + configService.addConfig(intf.connectPoint(), CONFIG_CLASS); | ||
| 175 | + | ||
| 176 | + config.addInterface(intf); | ||
| 177 | + | ||
| 178 | + configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node()); | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + @Override | ||
| 182 | + public void remove(ConnectPoint connectPoint, VlanId vlanId) { | ||
| 183 | + Optional<Interface> intf = interfaces.get(connectPoint).stream() | ||
| 184 | + .filter(i -> i.vlan().equals(vlanId)) | ||
| 185 | + .findAny(); | ||
| 186 | + | ||
| 187 | + if (!intf.isPresent()) { | ||
| 188 | + log.error("Can't find interface {}/{} to remove", connectPoint, vlanId); | ||
| 189 | + return; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + InterfaceConfig config = configService.addConfig(intf.get().connectPoint(), CONFIG_CLASS); | ||
| 193 | + config.removeInterface(intf.get()); | ||
| 194 | + | ||
| 195 | + try { | ||
| 196 | + if (config.getInterfaces().isEmpty()) { | ||
| 197 | + configService.removeConfig(connectPoint, CONFIG_CLASS); | ||
| 198 | + } else { | ||
| 199 | + configService.applyConfig(intf.get().connectPoint(), CONFIG_CLASS, config.node()); | ||
| 200 | + } | ||
| 201 | + } catch (ConfigException e) { | ||
| 202 | + log.error("Error reading interfaces JSON", e); | ||
| 203 | + } | ||
| 204 | + } | ||
| 205 | + | ||
| 156 | /** | 206 | /** |
| 157 | * Listener for network config events. | 207 | * Listener for network config events. |
| 158 | */ | 208 | */ | ... | ... |
-
Please register or login to post a comment