Jonathan Hart
Committed by Gerrit Code Review

Send PIM Join/Prune messages based on events from the McastService.

Also change Interface to return a list of addresses rather than a set
to allow applications to rely on the order of configuration

Change-Id: Ie7f62fee507639325ee0a77b8db4088dae34597e
......@@ -47,6 +47,13 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-routing-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-cli</artifactId>
<version>${project.version}</version>
</dependency>
......
......@@ -31,6 +31,7 @@ import java.util.Set;
public class PimInterfacesListCommand extends AbstractShellCommand {
private static final String FORMAT = "interfaceName=%s, holdTime=%s, priority=%s, genId=%s";
private static final String ROUTE_FORMAT = " %s";
@Override
protected void execute() {
......@@ -38,10 +39,13 @@ public class PimInterfacesListCommand extends AbstractShellCommand {
Set<PIMInterface> interfaces = interfaceService.getPimInterfaces();
interfaces.forEach(
pimIntf -> print(FORMAT, pimIntf.getInterface().name(),
pimIntf.getHoldtime(), pimIntf.getPriority(),
pimIntf.getGenerationId()));
interfaces.forEach(pimIntf -> {
print(FORMAT, pimIntf.getInterface().name(),
pimIntf.getHoldtime(), pimIntf.getPriority(),
pimIntf.getGenerationId());
pimIntf.getRoutes().forEach(route -> print(ROUTE_FORMAT, route));
});
}
}
......
......@@ -22,6 +22,7 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.PIM;
import org.onlab.packet.pim.PIMAddrUnicast;
import org.onlab.packet.pim.PIMHello;
import org.onlab.packet.pim.PIMHelloOption;
import org.onlab.packet.pim.PIMJoinPrune;
......@@ -30,6 +31,7 @@ import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;
......@@ -37,9 +39,11 @@ import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
......@@ -55,6 +59,9 @@ public final class PIMInterface {
private final Logger log = getLogger(getClass());
private static final int JOIN_PERIOD = 60;
private static final double HOLD_TIME_MULTIPLIER = 3.5;
private final PacketService packetService;
private Interface onosInterface;
......@@ -82,6 +89,8 @@ public final class PIMInterface {
// A map of all our PIM neighbors keyed on our neighbors IP address
private Map<IpAddress, PIMNeighbor> pimNeighbors = new HashMap<>();
private Map<McastRoute, RouteData> routes = new ConcurrentHashMap<>();
/**
* Create a PIMInterface from an ONOS Interface.
*
......@@ -151,8 +160,8 @@ public final class PIMInterface {
*
* @return a set of Ip Addresses on this interface
*/
public Set<InterfaceIpAddress> getIpAddresses() {
return onosInterface.ipAddresses();
public List<InterfaceIpAddress> getIpAddresses() {
return onosInterface.ipAddressesList();
}
/**
......@@ -161,12 +170,12 @@ public final class PIMInterface {
* @return the choosen IP address or null if none
*/
public IpAddress getIpAddress() {
if (onosInterface.ipAddresses().isEmpty()) {
if (onosInterface.ipAddressesList().isEmpty()) {
return null;
}
IpAddress ipaddr = null;
for (InterfaceIpAddress ifipaddr : onosInterface.ipAddresses()) {
for (InterfaceIpAddress ifipaddr : onosInterface.ipAddressesList()) {
ipaddr = ifipaddr.ipAddress();
break;
}
......@@ -218,6 +227,10 @@ public final class PIMInterface {
return pimNeighbors.values();
}
public Collection<McastRoute> getRoutes() {
return routes.keySet();
}
/**
* Checks whether any of our neighbors have expired, and cleans up their
* state if they have.
......@@ -402,6 +415,100 @@ public final class PIMInterface {
}
public void addRoute(McastRoute route, IpAddress nextHop, MacAddress nextHopMac) {
RouteData data = new RouteData(nextHop, nextHopMac);
routes.put(route, data);
sendJoinPrune(route, data, true);
}
public void removeRoute(McastRoute route) {
RouteData data = routes.remove(route);
if (data != null) {
sendJoinPrune(route, data, false);
}
}
public void sendJoins() {
routes.entrySet().forEach(entry -> {
if (entry.getValue().timestamp + TimeUnit.SECONDS.toMillis(JOIN_PERIOD) >
System.currentTimeMillis()) {
return;
}
sendJoinPrune(entry.getKey(), entry.getValue(), true);
});
}
private void sendJoinPrune(McastRoute route, RouteData data, boolean join) {
PIMJoinPrune jp = new PIMJoinPrune();
jp.addJoinPrune(route.source().toIpPrefix(), route.group().toIpPrefix(), join);
jp.setHoldTime(join ? (short) Math.floor(JOIN_PERIOD * HOLD_TIME_MULTIPLIER) : 0);
jp.setUpstreamAddr(new PIMAddrUnicast(data.ipAddress.toString()));
PIM pim = new PIM();
pim.setPIMType(PIM.TYPE_JOIN_PRUNE_REQUEST);
pim.setPayload(jp);
IPv4 ipv4 = new IPv4();
ipv4.setDestinationAddress(PIM.PIM_ADDRESS.getIp4Address().toInt());
ipv4.setSourceAddress(getIpAddress().getIp4Address().toInt());
ipv4.setProtocol(IPv4.PROTOCOL_PIM);
ipv4.setTtl((byte) 1);
ipv4.setDiffServ((byte) 0xc0);
ipv4.setPayload(pim);
Ethernet eth = new Ethernet();
eth.setSourceMACAddress(onosInterface.mac());
eth.setDestinationMACAddress(MacAddress.valueOf("01:00:5E:00:00:0d"));
eth.setEtherType(Ethernet.TYPE_IPV4);
eth.setPayload(ipv4);
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(onosInterface.connectPoint().port())
.build();
packetService.emit(new DefaultOutboundPacket(onosInterface.connectPoint().deviceId(),
treatment, ByteBuffer.wrap(eth.serialize())));
data.timestamp = System.currentTimeMillis();
}
/*private void sendPrune(McastRoute route, RouteData data) {
PIMJoinPrune jp = new PIMJoinPrune();
jp.addJoinPrune(route.source().toIpPrefix(), route.group().toIpPrefix(), false);
jp.setHoldTime((short) 0);
jp.setUpstreamAddr(new PIMAddrUnicast(data.ipAddress.toString()));
PIM pim = new PIM();
pim.setPIMType(PIM.TYPE_JOIN_PRUNE_REQUEST);
pim.setPayload(jp);
IPv4 ipv4 = new IPv4();
ipv4.setDestinationAddress(PIM.PIM_ADDRESS.getIp4Address().toInt());
ipv4.setSourceAddress(getIpAddress().getIp4Address().toInt());
ipv4.setProtocol(IPv4.PROTOCOL_PIM);
ipv4.setTtl((byte) 1);
ipv4.setDiffServ((byte) 0xc0);
ipv4.setPayload(pim);
Ethernet eth = new Ethernet();
eth.setSourceMACAddress(onosInterface.mac());
eth.setDestinationMACAddress(MacAddress.valueOf("01:00:5E:00:00:0d"));
eth.setEtherType(Ethernet.TYPE_IPV4);
eth.setPayload(ipv4);
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(onosInterface.connectPoint().port())
.build();
packetService.emit(new DefaultOutboundPacket(onosInterface.connectPoint().deviceId(),
treatment, ByteBuffer.wrap(eth.serialize())));
}*/
/**
* Returns a builder for a PIM interface.
*
......@@ -514,4 +621,16 @@ public final class PIMInterface {
}
}
private static class RouteData {
public final IpAddress ipAddress;
public final MacAddress macAddress;
public long timestamp;
public RouteData(IpAddress ip, MacAddress mac) {
this.ipAddress = ip;
this.macAddress = mac;
timestamp = System.currentTimeMillis();
}
}
}
......
......@@ -29,12 +29,22 @@ import org.onosproject.incubator.net.intf.InterfaceEvent;
import org.onosproject.incubator.net.intf.InterfaceListener;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.host.HostService;
import org.onosproject.net.mcast.McastEvent;
import org.onosproject.net.mcast.McastListener;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.mcast.MulticastRouteService;
import org.onosproject.net.packet.PacketService;
import org.onosproject.routing.RouteEntry;
import org.onosproject.routing.RoutingService;
import org.slf4j.Logger;
import java.util.Map;
......@@ -73,6 +83,8 @@ public class PIMInterfaceManager implements PIMInterfaceService {
private final int timeoutTaskPeriod = DEFAULT_TASK_PERIOD_MS;
private final int joinTaskPeriod = 10000;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
......@@ -82,13 +94,26 @@ public class PIMInterfaceManager implements PIMInterfaceService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected InterfaceService interfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MulticastRouteService multicastRouteService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingService unicastRoutingService;
// Store PIM Interfaces in a map key'd by ConnectPoint
private final Map<ConnectPoint, PIMInterface> pimInterfaces = Maps.newConcurrentMap();
private final Map<McastRoute, PIMInterface> routes = Maps.newConcurrentMap();
private final InternalNetworkConfigListener configListener =
new InternalNetworkConfigListener();
private final InternalInterfaceListener interfaceListener =
new InternalInterfaceListener();
private final InternalMulticastListener multicastListener =
new InternalMulticastListener();
private final ConfigFactory<ConnectPoint, PimInterfaceConfig> pimConfigFactory
= new ConfigFactory<ConnectPoint, PimInterfaceConfig>(
......@@ -115,6 +140,9 @@ public class PIMInterfaceManager implements PIMInterfaceService {
networkConfig.addListener(configListener);
interfaceService.addListener(interfaceListener);
multicastRouteService.addListener(multicastListener);
multicastRouteService.getRoutes().forEach(this::addRoute);
// Schedule the periodic hello sender.
scheduledExecutorService.scheduleAtFixedRate(
......@@ -128,6 +156,11 @@ public class PIMInterfaceManager implements PIMInterfaceService {
() -> pimInterfaces.values().forEach(PIMInterface::checkNeighborTimeouts)),
0, timeoutTaskPeriod, TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleAtFixedRate(
SafeRecurringTask.wrap(
() -> pimInterfaces.values().forEach(PIMInterface::sendJoins)),
0, joinTaskPeriod, TimeUnit.MILLISECONDS);
log.info("Started");
}
......@@ -135,6 +168,7 @@ public class PIMInterfaceManager implements PIMInterfaceService {
public void deactivate() {
interfaceService.removeListener(interfaceListener);
networkConfig.removeListener(configListener);
multicastRouteService.removeListener(multicastListener);
networkConfig.unregisterConfigFactory(pimConfigFactory);
// Shutdown the periodic hello task.
......@@ -202,6 +236,65 @@ public class PIMInterfaceManager implements PIMInterfaceService {
return builder.build();
}
private void addRoute(McastRoute route) {
PIMInterface pimInterface = getSourceInterface(route);
if (pimInterface == null) {
return;
}
routes.put(route, pimInterface);
}
private void removeRoute(McastRoute route) {
PIMInterface pimInterface = routes.remove(route);
if (pimInterface == null) {
return;
}
pimInterface.removeRoute(route);
}
private PIMInterface getSourceInterface(McastRoute route) {
RouteEntry routeEntry = unicastRoutingService.getLongestMatchableRouteEntry(route.source());
if (routeEntry == null) {
log.warn("No route to source {}", route.source());
return null;
}
Interface intf = interfaceService.getMatchingInterface(routeEntry.nextHop());
if (intf == null) {
log.warn("No interface with route to next hop {}", routeEntry.nextHop());
return null;
}
PIMInterface pimInterface = pimInterfaces.get(intf.connectPoint());
if (pimInterface == null) {
log.warn("PIM is not enabled on interface {}", intf);
return null;
}
Set<Host> hosts = hostService.getHostsByIp(routeEntry.nextHop());
Host host = null;
for (Host h : hosts) {
if (h.vlan().equals(intf.vlan())) {
host = h;
}
}
if (host == null) {
log.warn("Next hop host entry not found: {}", routeEntry.nextHop());
return null;
}
pimInterface.addRoute(route, routeEntry.nextHop(), host.mac());
return pimInterface;
}
/**
* Listener for network config events.
*/
......@@ -261,4 +354,26 @@ public class PIMInterfaceManager implements PIMInterfaceService {
}
}
}
/**
* Listener for multicast route events.
*/
private class InternalMulticastListener implements McastListener {
@Override
public void event(McastEvent event) {
switch (event.type()) {
case ROUTE_ADDED:
addRoute(event.subject().route());
break;
case ROUTE_REMOVED:
removeRoute(event.subject().route());
break;
case SOURCE_ADDED:
case SINK_ADDED:
case SINK_REMOVED:
default:
break;
}
}
}
}
......
......@@ -15,9 +15,9 @@
*/
package org.onosproject.routing.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
......@@ -57,6 +57,7 @@ import org.onosproject.routing.RouteEntry;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
......@@ -124,7 +125,7 @@ public class IntentSynchronizerTest extends AbstractIntentTest {
* Sets up InterfaceService.
*/
private void setUpInterfaceService() {
Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
List<InterfaceIpAddress> interfaceIpAddresses1 = Lists.newArrayList();
interfaceIpAddresses1.add(new InterfaceIpAddress(
IpAddress.valueOf("192.168.10.101"),
IpPrefix.valueOf("192.168.10.0/24")));
......@@ -133,7 +134,7 @@ public class IntentSynchronizerTest extends AbstractIntentTest {
VlanId.NONE);
interfaces.add(sw1Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
List<InterfaceIpAddress> interfaceIpAddresses2 = Lists.newArrayList();
interfaceIpAddresses2.add(
new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
IpPrefix.valueOf("192.168.20.0/24")));
......@@ -142,7 +143,7 @@ public class IntentSynchronizerTest extends AbstractIntentTest {
VlanId.NONE);
interfaces.add(sw2Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
List<InterfaceIpAddress> interfaceIpAddresses3 = Lists.newArrayList();
interfaceIpAddresses3.add(
new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
IpPrefix.valueOf("192.168.30.0/24")));
......@@ -155,7 +156,7 @@ public class IntentSynchronizerTest extends AbstractIntentTest {
new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
IpPrefix.valueOf("192.168.40.0/24"));
Interface sw4Eth1 = new Interface(SW4_ETH1,
Sets.newHashSet(interfaceIpAddress4),
Lists.newArrayList(interfaceIpAddress4),
MacAddress.valueOf("00:00:00:00:00:04"),
VlanId.vlanId((short) 1));
......
......@@ -173,7 +173,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
new InterfaceIpAddress(IpAddress.valueOf("192.168.10.101"),
IpPrefix.valueOf("192.168.10.0/24"));
Interface intfsw1eth1 = new Interface(s1Eth1,
Collections.singleton(ia1),
Collections.singletonList(ia1),
MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
......@@ -183,7 +183,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
IpPrefix.valueOf("192.168.20.0/24"));
Interface intfsw2eth1 = new Interface(s2Eth1,
Collections.singleton(ia2),
Collections.singletonList(ia2),
MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.NONE);
configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1);
......@@ -193,7 +193,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
IpPrefix.valueOf("192.168.30.0/24"));
Interface intfsw2eth1intf2 = new Interface(s2Eth1,
Collections.singleton(ia3),
Collections.singletonList(ia3),
MacAddress.valueOf("00:00:00:00:00:03"),
VlanId.NONE);
configuredInterfaces.put(interfaceSw2Eth1intf2, intfsw2eth1intf2);
......
......@@ -16,6 +16,7 @@
package org.onosproject.sdnip;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
......@@ -53,6 +54,7 @@ import org.onosproject.routing.config.RoutingConfigurationService;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -151,7 +153,7 @@ public class SdnIpFibTest extends AbstractIntentTest {
* Sets up InterfaceService.
*/
private void setUpInterfaceService() {
Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
List<InterfaceIpAddress> interfaceIpAddresses1 = Lists.newArrayList();
interfaceIpAddresses1.add(new InterfaceIpAddress(
IpAddress.valueOf("192.168.10.101"),
IpPrefix.valueOf("192.168.10.0/24")));
......@@ -160,7 +162,7 @@ public class SdnIpFibTest extends AbstractIntentTest {
VlanId.NONE);
interfaces.add(sw1Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
List<InterfaceIpAddress> interfaceIpAddresses2 = Lists.newArrayList();
interfaceIpAddresses2.add(
new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
IpPrefix.valueOf("192.168.20.0/24")));
......@@ -169,7 +171,7 @@ public class SdnIpFibTest extends AbstractIntentTest {
VlanId.NONE);
interfaces.add(sw2Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
List<InterfaceIpAddress> interfaceIpAddresses3 = Lists.newArrayList();
interfaceIpAddresses3.add(
new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
IpPrefix.valueOf("192.168.30.0/24")));
......@@ -182,7 +184,7 @@ public class SdnIpFibTest extends AbstractIntentTest {
new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
IpPrefix.valueOf("192.168.40.0/24"));
Interface sw4Eth1 = new Interface(SW4_ETH1,
Sets.newHashSet(interfaceIpAddress4),
Lists.newArrayList(interfaceIpAddress4),
MacAddress.valueOf("00:00:00:00:00:04"),
VlanId.vlanId((short) 1));
......
......@@ -137,7 +137,7 @@ public class DeviceConfiguration implements DeviceProperties {
// skip if there is no corresponding device for this ConenctPoint
if (info != null) {
// Extract subnet information
Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
interfaceAddresses.forEach(interfaceAddress -> {
// Do not add /0 and /32 to gateway IP list
int prefixLength = interfaceAddress.subnetAddress().prefixLength();
......@@ -495,4 +495,4 @@ public class DeviceConfiguration implements DeviceProperties {
public Set<ConnectPoint> excludedPorts() {
return excludedPorts;
}
}
\ No newline at end of file
}
......
......@@ -16,7 +16,7 @@
package org.onosproject.cli.net;
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
......@@ -28,7 +28,7 @@ import org.onosproject.incubator.net.intf.InterfaceAdminService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.host.InterfaceIpAddress;
import java.util.Set;
import java.util.List;
/**
* Adds a new interface configuration.
......@@ -66,7 +66,7 @@ public class InterfaceAddCommand extends AbstractShellCommand {
protected void execute() {
InterfaceAdminService interfaceService = get(InterfaceAdminService.class);
Set<InterfaceIpAddress> ipAddresses = Sets.newHashSet();
List<InterfaceIpAddress> ipAddresses = Lists.newArrayList();
if (ips != null) {
for (String strIp : ips) {
ipAddresses.add(InterfaceIpAddress.valueOf(strIp));
......
......@@ -185,7 +185,7 @@ public class HostMonitorTest {
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE))
.andReturn(new Interface(cp, Collections.singletonList(IA1), sourceMac, VlanId.NONE))
.anyTimes();
replay(interfaceService);
......@@ -253,7 +253,7 @@ public class HostMonitorTest {
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.NONE))
.andReturn(new Interface(cp, Collections.singletonList(IA2), sourceMac2, VlanId.NONE))
.anyTimes();
replay(interfaceService);
......@@ -323,7 +323,7 @@ public class HostMonitorTest {
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan)))
.andReturn(new Interface(cp, Collections.singletonList(IA1), sourceMac, VlanId.vlanId(vlan)))
.anyTimes();
replay(interfaceService);
......@@ -392,7 +392,7 @@ public class HostMonitorTest {
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.vlanId(vlan)))
.andReturn(new Interface(cp, Collections.singletonList(IA2), sourceMac2, VlanId.vlanId(vlan)))
.anyTimes();
replay(interfaceService);
......
......@@ -15,6 +15,7 @@
*/
package org.onosproject.net.proxyarp.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
......@@ -295,10 +296,10 @@ public class ProxyArpManagerTest {
InterfaceIpAddress ia4 = new InterfaceIpAddress(addr4, prefix4);
// Setting up interfaces
Interface intf1 = new Interface(cp, Sets.newHashSet(ia1, ia3),
Interface intf1 = new Interface(cp, Lists.newArrayList(ia1, ia3),
MacAddress.valueOf(2 * i - 1),
VlanId.vlanId((short) 1));
Interface intf2 = new Interface(cp, Sets.newHashSet(ia2, ia4),
Interface intf2 = new Interface(cp, Lists.newArrayList(ia2, ia4),
MacAddress.valueOf(2 * i),
VlanId.NONE);
......@@ -312,7 +313,7 @@ public class ProxyArpManagerTest {
}
for (int i = LAST_CONF_DEVICE_INTF_VLAN_IP + 1; i <= LAST_CONF_DEVICE_INTF_VLAN; i++) {
ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
Interface intf1 = new Interface(cp, null,
Interface intf1 = new Interface(cp, Collections.emptyList(),
MacAddress.NONE,
VlanId.vlanId((short) 1));
......@@ -850,7 +851,7 @@ public class ProxyArpManagerTest {
expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
expect(interfaceService.getInterfacesByIp(ourIp))
.andReturn(Collections.singleton(new Interface(getLocation(1),
Collections.singleton(new InterfaceIpAddress(ourIp, IpPrefix.valueOf("10.0.1.1/24"))),
Collections.singletonList(new InterfaceIpAddress(ourIp, IpPrefix.valueOf("10.0.1.1/24"))),
ourMac, VLAN1)));
expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null);
replay(hostService);
......@@ -883,7 +884,7 @@ public class ProxyArpManagerTest {
expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
expect(interfaceService.getInterfacesByIp(ourIp))
.andReturn(Collections.singleton(new Interface(getLocation(1),
Collections.singleton(new InterfaceIpAddress(
Collections.singletonList(new InterfaceIpAddress(
ourIp,
IpPrefix.valueOf("1000::1/64"))),
ourMac,
......
......@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.annotations.Beta;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
......@@ -29,6 +30,7 @@ import org.onosproject.net.config.Config;
import org.onosproject.net.host.InterfaceIpAddress;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
......@@ -61,7 +63,7 @@ public class InterfaceConfig extends Config<ConnectPoint> {
for (JsonNode intfNode : array) {
String name = intfNode.path(NAME).asText(null);
Set<InterfaceIpAddress> ips = getIps(intfNode);
List<InterfaceIpAddress> ips = getIps(intfNode);
String mac = intfNode.path(MAC).asText();
MacAddress macAddr = mac.isEmpty() ? null : MacAddress.valueOf(mac);
......@@ -98,7 +100,7 @@ public class InterfaceConfig extends Config<ConnectPoint> {
}
if (!intf.ipAddresses().isEmpty()) {
intfNode.set(IPS, putIps(intf.ipAddresses()));
intfNode.set(IPS, putIps(intf.ipAddressesList()));
}
if (!intf.vlan().equals(VlanId.NONE)) {
......@@ -133,8 +135,8 @@ public class InterfaceConfig extends Config<ConnectPoint> {
return vlan;
}
private Set<InterfaceIpAddress> getIps(JsonNode node) {
Set<InterfaceIpAddress> ips = Sets.newHashSet();
private List<InterfaceIpAddress> getIps(JsonNode node) {
List<InterfaceIpAddress> ips = Lists.newArrayList();
JsonNode ipsNode = node.get(IPS);
if (ipsNode != null) {
......@@ -145,7 +147,7 @@ public class InterfaceConfig extends Config<ConnectPoint> {
return ips;
}
private ArrayNode putIps(Set<InterfaceIpAddress> intfIpAddresses) {
private ArrayNode putIps(List<InterfaceIpAddress> intfIpAddresses) {
ArrayNode ipArray = mapper.createArrayNode();
intfIpAddresses.forEach(i -> ipArray.add(i.toString()));
......
......@@ -17,14 +17,16 @@ package org.onosproject.incubator.net.intf;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.host.InterfaceIpAddress;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -38,7 +40,7 @@ public class Interface {
private final String name;
private final ConnectPoint connectPoint;
private final Set<InterfaceIpAddress> ipAddresses;
private final List<InterfaceIpAddress> ipAddresses;
private final MacAddress macAddress;
private final VlanId vlan;
......@@ -47,16 +49,38 @@ public class Interface {
*
* @param name name of the interface
* @param connectPoint the connect point this interface maps to
* @param ipAddresses Set of IP addresses
* @param ipAddresses list of IP addresses
* @param macAddress MAC address
* @param vlan VLAN ID
*/
public Interface(String name, ConnectPoint connectPoint,
List<InterfaceIpAddress> ipAddresses,
MacAddress macAddress, VlanId vlan) {
this.name = name == null ? NO_INTERFACE_NAME : name;
this.connectPoint = checkNotNull(connectPoint);
this.ipAddresses = ipAddresses == null ? Lists.newArrayList() : ipAddresses;
this.macAddress = macAddress == null ? MacAddress.NONE : macAddress;
this.vlan = vlan == null ? VlanId.NONE : vlan;
}
/**
* Creates new Interface with the provided configuration.
*
* @param name name of the interface
* @param connectPoint the connect point this interface maps to
* @param ipAddresses set of IP addresses
* @param macAddress MAC address
* @param vlan VLAN ID
* @deprecated in Falcon release, in favour of ordered list
*/
@Deprecated
public Interface(String name, ConnectPoint connectPoint,
Set<InterfaceIpAddress> ipAddresses,
MacAddress macAddress, VlanId vlan) {
this.name = name == null ? NO_INTERFACE_NAME : name;
this.connectPoint = checkNotNull(connectPoint);
this.ipAddresses = ipAddresses == null ? Sets.newHashSet() : ipAddresses;
this.ipAddresses = ipAddresses == null ? Lists.newArrayList() :
ipAddresses.stream().collect(Collectors.toList());
this.macAddress = macAddress == null ? MacAddress.NONE : macAddress;
this.vlan = vlan == null ? VlanId.NONE : vlan;
}
......@@ -68,7 +92,9 @@ public class Interface {
* @param ipAddresses Set of IP addresses
* @param macAddress MAC address
* @param vlan VLAN ID
* @deprecated in Falcon release - use constructors with names instead
*/
@Deprecated
public Interface(ConnectPoint connectPoint,
Set<InterfaceIpAddress> ipAddresses,
MacAddress macAddress, VlanId vlan) {
......@@ -76,6 +102,22 @@ public class Interface {
}
/**
* Creates new Interface with the provided configuration.
*
* @param connectPoint the connect point this interface maps to
* @param ipAddresses Set of IP addresses
* @param macAddress MAC address
* @param vlan VLAN ID
* @deprecated in Falcon release - use constructors with names instead
*/
@Deprecated
public Interface(ConnectPoint connectPoint,
List<InterfaceIpAddress> ipAddresses,
MacAddress macAddress, VlanId vlan) {
this(NO_INTERFACE_NAME, connectPoint, ipAddresses, macAddress, vlan);
}
/**
* Retrieves the name of the interface.
*
* @return name
......@@ -97,8 +139,20 @@ public class Interface {
* Retrieves the set of IP addresses that are assigned to the interface.
*
* @return the set of interface IP addresses
* @deprecated in Falcon release in favour of an ordered list
*/
@Deprecated
public Set<InterfaceIpAddress> ipAddresses() {
return ipAddresses.stream().collect(Collectors.toSet());
}
/**
* Retrieves a list of IP addresses that are assigned to the interface in
* the order that they were configured.
*
* @return list of IP addresses
*/
public List<InterfaceIpAddress> ipAddressesList() {
return ipAddresses;
}
......
......@@ -16,6 +16,7 @@
package org.onosproject.incubator.net.intf.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.Before;
......@@ -35,6 +36,7 @@ import org.onosproject.net.config.NetworkConfigServiceAdapter;
import org.onosproject.net.host.InterfaceIpAddress;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -87,7 +89,7 @@ public class InterfaceManagerTest {
InterfaceIpAddress ia = InterfaceIpAddress.valueOf("192.168." + i + ".1/24");
Interface intf = new Interface(cp,
Sets.newHashSet(ia),
Collections.singletonList(ia),
MacAddress.valueOf(i),
VlanId.vlanId((short) i));
......@@ -150,7 +152,7 @@ public class InterfaceManagerTest {
VlanId vlanId = VlanId.vlanId((short) 1);
ConnectPoint cp = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
Interface newIntf = new Interface(cp,
Collections.emptySet(),
Collections.emptyList(),
MacAddress.valueOf(100),
vlanId);
......@@ -184,14 +186,14 @@ public class InterfaceManagerTest {
// Create an interface that is the same as the existing one, but adds a
// new IP address
Interface intf = createInterface(1);
Set<InterfaceIpAddress> addresses = Sets.newHashSet(intf.ipAddresses());
List<InterfaceIpAddress> addresses = Lists.newArrayList(intf.ipAddresses());
addresses.add(InterfaceIpAddress.valueOf("192.168.100.1/24"));
intf = new Interface(intf.connectPoint(), addresses, intf.mac(), intf.vlan());
// Create a new interface on the same connect point as the existing one
InterfaceIpAddress newAddr = InterfaceIpAddress.valueOf("192.168.101.1/24");
Interface newIntf = new Interface(cp,
Collections.singleton(newAddr),
Collections.singletonList(newAddr),
MacAddress.valueOf(101),
VlanId.vlanId((short) 101));
......