[CORD-1751] Preventing attacks on DHCP-Relay
Change-Id: I46f7ba2490994e71c9f7d881cbe44785720f1e37
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index 0c031fd..210d0c9 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -17,7 +17,10 @@
package org.onosproject.dhcprelay;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -33,16 +36,32 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
import org.onlab.packet.dhcp.CircuitId;
import org.onlab.packet.dhcp.DhcpOption;
import org.onlab.packet.dhcp.DhcpRelayAgentOption;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.dhcprelay.api.DhcpHandler;
import org.onosproject.dhcprelay.api.DhcpServerInfo;
import org.onosproject.dhcprelay.config.DhcpServerConfig;
+import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.dhcprelay.store.DhcpRecord;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostProvider;
@@ -50,6 +69,7 @@
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteStore;
@@ -76,6 +96,7 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -85,6 +106,8 @@
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
import static org.onlab.packet.MacAddress.valueOf;
import static org.onlab.packet.dhcp.DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID;
+import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
+import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
@Component
@Service
@@ -92,6 +115,27 @@
public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider {
public static final String DHCP_V4_RELAY_APP = "org.onosproject.Dhcp4HandlerImpl";
public static final ProviderId PROVIDER_ID = new ProviderId("dhcp4", DHCP_V4_RELAY_APP);
+ private static final String BROADCAST_IP = "255.255.255.255";
+ private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
+
+ private static final TrafficSelector CLIENT_SERVER_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchIPSrc(Ip4Address.ZERO.toIpPrefix())
+ .matchIPDst(Ip4Address.valueOf(BROADCAST_IP).toIpPrefix())
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .build();
+ private static final TrafficSelector SERVER_RELAY_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .build();
+ static final Set<TrafficSelector> DHCP_SELECTORS = ImmutableSet.of(
+ CLIENT_SERVER_SELECTOR,
+ SERVER_RELAY_SELECTOR
+ );
private static Logger log = LoggerFactory.getLogger(Dhcp4HandlerImpl.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -112,7 +156,18 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry providerRegistry;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+
protected HostProviderService providerService;
+ protected ApplicationId appId;
+ protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
private InternalHostListener hostListener = new InternalHostListener();
private List<DhcpServerInfo> defaultServerInfoList = Lists.newArrayList();
@@ -120,6 +175,7 @@
@Activate
protected void activate() {
+ appId = coreService.registerApplication(DHCP_V4_RELAY_APP);
hostService.addListener(hostListener);
providerService = providerRegistry.register(this);
}
@@ -163,6 +219,30 @@
return indirectServerInfoList;
}
+ @Override
+ public void updateIgnoreVlanConfig(IgnoreDhcpConfig config) {
+ if (config == null) {
+ ignoredVlans.forEach(((deviceId, vlanId) -> {
+ processIgnoreVlanRule(deviceId, vlanId, REMOVE);
+ }));
+ return;
+ }
+ config.ignoredVlans().forEach((deviceId, vlanId) -> {
+ if (ignoredVlans.get(deviceId).contains(vlanId)) {
+ // don't need to process if it already ignored
+ return;
+ }
+ processIgnoreVlanRule(deviceId, vlanId, ADD);
+ });
+
+ ignoredVlans.forEach((deviceId, vlanId) -> {
+ if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
+ // not contains in new config, remove it
+ processIgnoreVlanRule(deviceId, vlanId, REMOVE);
+ }
+ });
+ }
+
public void setDhcpServerConfigs(Collection<DhcpServerConfig> configs, List<DhcpServerInfo> serverInfoList) {
if (configs.size() == 0) {
// no config to update
@@ -188,6 +268,7 @@
});
oldServerInfo.getDhcpServerIp4().ifPresent(serverIp -> {
hostService.stopMonitoringIp(serverIp);
+ cancelDhcpPacket(serverIp);
});
}
@@ -202,7 +283,8 @@
log.debug("DHCP server connect point: {}", newServerInfo.getDhcpServerConnectPoint().orElse(null));
log.debug("DHCP server IP: {}", newServerInfo.getDhcpServerIp4().orElse(null));
- IpAddress ipToProbe;
+ Ip4Address serverIp = newServerInfo.getDhcpServerIp4().get();
+ Ip4Address ipToProbe;
if (newServerInfo.getDhcpGatewayIp4().isPresent()) {
ipToProbe = newServerInfo.getDhcpGatewayIp4().get();
} else {
@@ -228,6 +310,7 @@
nonDupServerInfoList.addAll(serverInfoList);
serverInfoList.clear();
serverInfoList.addAll(nonDupServerInfoList);
+ requestDhcpPacket(serverIp);
}
@Override
@@ -414,7 +497,6 @@
indirectRelayAgentIp = indirectServerInfo.getRelayAgentIp4().orElse(null);
}
-
Ip4Address clientInterfaceIp =
interfaceService.getInterfacesByPort(context.inPacket().receivedFrom())
.stream()
@@ -982,9 +1064,6 @@
case HOST_REMOVED:
hostRemoved(event.subject());
break;
- case HOST_MOVED:
- hostMoved(event.subject());
- break;
default:
break;
}
@@ -992,114 +1071,39 @@
}
/**
- * Handle host move.
- * If the host DHCP server or gateway and it moved to the location different
- * to user configured, unsets the connect mac and vlan
- *
- * @param host the host
- */
- private void hostMoved(Host host) {
- Set<ConnectPoint> hostConnectPoints = host.locations().stream()
- .map(hl -> new ConnectPoint(hl.elementId(), hl.port()))
- .collect(Collectors.toSet());
- DhcpServerInfo serverInfo;
- ConnectPoint dhcpServerConnectPoint;
- Ip4Address dhcpGatewayIp;
- Ip4Address dhcpServerIp;
-
- if (!defaultServerInfoList.isEmpty()) {
- serverInfo = defaultServerInfoList.get(0);
- dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp4().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- }
-
- if (!indirectServerInfoList.isEmpty()) {
- // Indirect server
- serverInfo = indirectServerInfoList.get(0);
- dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp4().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- }
- }
-
- /**
* Handle host updated.
* If the host is DHCP server or gateway, update connect mac and vlan.
*
* @param host the host
*/
private void hostUpdated(Host host) {
- DhcpServerInfo serverInfo;
- Ip4Address dhcpGatewayIp;
- Ip4Address dhcpServerIp;
-
- if (!defaultServerInfoList.isEmpty()) {
- serverInfo = defaultServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp4().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- }
-
- if (!indirectServerInfoList.isEmpty()) {
- serverInfo = indirectServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp4().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- }
-
+ hostUpdated(host, defaultServerInfoList);
+ hostUpdated(host, indirectServerInfoList);
}
+ private void hostUpdated(Host host, List<DhcpServerInfo> srverInfoList) {
+ DhcpServerInfo serverInfo;
+ Ip4Address targetIp;
+ if (!srverInfoList.isEmpty()) {
+ serverInfo = srverInfoList.get(0);
+ targetIp = serverInfo.getDhcpGatewayIp4().orElse(null);
+ Ip4Address serverIp = serverInfo.getDhcpServerIp4().orElse(null);
+
+ if (targetIp == null) {
+ targetIp = serverIp;
+ }
+
+ if (targetIp != null) {
+ if (host.ipAddresses().contains(targetIp)) {
+ serverInfo.setDhcpConnectMac(host.mac());
+ serverInfo.setDhcpConnectVlan(host.vlan());
+ requestDhcpPacket(serverIp);
+ }
+ }
+ }
+ }
+
+
/**
* Handle host removed.
* If the host is DHCP server or gateway, unset connect mac and vlan.
@@ -1107,45 +1111,165 @@
* @param host the host
*/
private void hostRemoved(Host host) {
+ hostRemoved(host, defaultServerInfoList);
+ hostRemoved(host, indirectServerInfoList);
+ }
+
+ private void hostRemoved(Host host, List<DhcpServerInfo> serverInfoList) {
DhcpServerInfo serverInfo;
- Ip4Address dhcpGatewayIp;
- Ip4Address dhcpServerIp;
- if (!defaultServerInfoList.isEmpty()) {
- serverInfo = defaultServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp4().orElse(null);
+ Ip4Address targetIp;
+ if (!serverInfoList.isEmpty()) {
+ serverInfo = serverInfoList.get(0);
+ Ip4Address serverIp = serverInfo.getDhcpServerIp4().orElse(null);
+ targetIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
+ if (targetIp == null) {
+ targetIp = serverIp;
}
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
+
+ if (targetIp != null) {
+ if (host.ipAddresses().contains(targetIp)) {
serverInfo.setDhcpConnectVlan(null);
serverInfo.setDhcpConnectMac(null);
+ cancelDhcpPacket(serverIp);
}
}
}
+ }
- if (!indirectServerInfoList.isEmpty()) {
- serverInfo = indirectServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp4().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp4().orElse(null);
+ private void requestDhcpPacket(Ip4Address serverIp) {
+ requestServerDhcpPacket(serverIp);
+ requestClientDhcpPacket(serverIp);
+ }
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
+ private void cancelDhcpPacket(Ip4Address serverIp) {
+ cancelServerDhcpPacket(serverIp);
+ cancelClientDhcpPacket(serverIp);
+ }
+
+ private void cancelServerDhcpPacket(Ip4Address serverIp) {
+ TrafficSelector serverSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPSrc(serverIp.toIpPrefix())
+ .build();
+ packetService.cancelPackets(serverSelector,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void requestServerDhcpPacket(Ip4Address serverIp) {
+ TrafficSelector serverSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPSrc(serverIp.toIpPrefix())
+ .build();
+ packetService.requestPackets(serverSelector,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void cancelClientDhcpPacket(Ip4Address serverIp) {
+ // Packet comes from relay
+ TrafficSelector indirectClientSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPDst(serverIp.toIpPrefix())
+ .build();
+ packetService.cancelPackets(indirectClientSelector,
+ PacketPriority.CONTROL,
+ appId);
+
+ // Packet comes from client
+ packetService.cancelPackets(CLIENT_SERVER_SELECTOR,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void requestClientDhcpPacket(Ip4Address serverIp) {
+ // Packet comes from relay
+ TrafficSelector indirectClientSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPDst(serverIp.toIpPrefix())
+ .build();
+ packetService.requestPackets(indirectClientSelector,
+ PacketPriority.CONTROL,
+ appId);
+
+ // Packet comes from client
+ packetService.requestPackets(CLIENT_SERVER_SELECTOR,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ /**
+ * Process the ignore rules.
+ *
+ * @param deviceId the device id
+ * @param vlanId the vlan to be ignored
+ * @param op the operation, ADD to install; REMOVE to uninstall rules
+ */
+ private void processIgnoreVlanRule(DeviceId deviceId, VlanId vlanId, Objective.Operation op) {
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
+ AtomicInteger installedCount = new AtomicInteger(DHCP_SELECTORS.size());
+ DHCP_SELECTORS.forEach(trafficSelector -> {
+ TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
+ .matchVlanId(vlanId)
+ .build();
+
+ ForwardingObjective.Builder builder = DefaultForwardingObjective.builder()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withSelector(selector)
+ .withPriority(IGNORE_CONTROL_PRIORITY)
+ .withTreatment(dropTreatment)
+ .fromApp(appId);
+
+
+ ObjectiveContext objectiveContext = new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Ignore rule {} (Vlan id {}, device {}, selector {})",
+ op, vlanId, deviceId, selector);
+ int countDown = installedCount.decrementAndGet();
+ if (countDown != 0) {
+ return;
+ }
+ switch (op) {
+ case ADD:
+ ignoredVlans.put(deviceId, vlanId);
+ break;
+ case REMOVE:
+ ignoredVlans.remove(deviceId, vlanId);
+ break;
+ default:
+ log.warn("Unsupported objective operation {}", op);
+ break;
+ }
}
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.warn("Can't {} ignore rule (vlan id {}, selector {}, device {}) due to {}",
+ op, vlanId, selector, deviceId, error);
}
+ };
+
+ ForwardingObjective fwd;
+ switch (op) {
+ case ADD:
+ fwd = builder.add(objectiveContext);
+ break;
+ case REMOVE:
+ fwd = builder.remove(objectiveContext);
+ break;
+ default:
+ log.warn("Unsupported objective operation {}", op);
+ return;
}
- }
+
+ Device device = deviceService.getDevice(deviceId);
+ if (device == null || !device.is(Pipeliner.class)) {
+ log.warn("Device {} is not available now, wait until device is available", deviceId);
+ return;
+ }
+ flowObjectiveService.apply(deviceId, fwd);
+ });
}
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index 3e6ce74..b4d2176 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -17,7 +17,9 @@
package org.onosproject.dhcprelay;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Deactivate;
import com.google.common.collect.Sets;
@@ -35,6 +37,7 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
import org.onlab.packet.dhcp.Dhcp6RelayOption;
@@ -46,9 +49,24 @@
import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
import org.onlab.util.HexString;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.dhcprelay.api.DhcpHandler;
import org.onosproject.dhcprelay.api.DhcpServerInfo;
+import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
@@ -60,6 +78,7 @@
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteStore;
@@ -84,11 +103,13 @@
import java.util.Optional;
import java.util.Set;
import java.util.ArrayList;
-import java.util.stream.Collectors;
+import java.util.concurrent.atomic.AtomicInteger;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
+import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
@Component
@Service
@@ -96,6 +117,26 @@
public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
public static final String DHCP_V6_RELAY_APP = "org.onosproject.Dhcp6HandlerImpl";
public static final ProviderId PROVIDER_ID = new ProviderId("dhcp6", DHCP_V6_RELAY_APP);
+ private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
+
+ private static final TrafficSelector CLIENT_SERVER_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6)
+ .matchIPProtocol(IPv6.PROTOCOL_UDP)
+ .matchIPv6Src(IpPrefix.IPV6_LINK_LOCAL_PREFIX)
+ .matchIPv6Dst(Ip6Address.ALL_DHCP_RELAY_AGENTS_AND_SERVERS.toIpPrefix())
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
+ .build();
+ private static final TrafficSelector SERVER_RELAY_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6)
+ .matchIPProtocol(IPv6.PROTOCOL_UDP)
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
+ .build();
+ static final Set<TrafficSelector> DHCP_SELECTORS = ImmutableSet.of(
+ CLIENT_SERVER_SELECTOR,
+ SERVER_RELAY_SELECTOR
+ );
private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -116,8 +157,20 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry providerRegistry;
- private InternalHostListener hostListener = new InternalHostListener();
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+
protected HostProviderService providerService;
+ protected ApplicationId appId;
+ protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
+ private InternalHostListener hostListener = new InternalHostListener();
+
private Ip6Address dhcpServerIp = null;
// dhcp server may be connected directly to the SDN network or
// via an external gateway. When connected directly, the dhcpConnectPoint, dhcpConnectMac,
@@ -156,6 +209,7 @@
@Activate
protected void activate() {
+ appId = coreService.registerApplication(DHCP_V6_RELAY_APP);
providerService = providerRegistry.register(this);
hostService.addListener(hostListener);
}
@@ -190,6 +244,30 @@
}
@Override
+ public void updateIgnoreVlanConfig(IgnoreDhcpConfig config) {
+ if (config == null) {
+ ignoredVlans.forEach(((deviceId, vlanId) -> {
+ processIgnoreVlanRule(deviceId, vlanId, REMOVE);
+ }));
+ return;
+ }
+ config.ignoredVlans().forEach((deviceId, vlanId) -> {
+ if (ignoredVlans.get(deviceId).contains(vlanId)) {
+ // don't need to process if it already ignored
+ return;
+ }
+ processIgnoreVlanRule(deviceId, vlanId, ADD);
+ });
+
+ ignoredVlans.forEach((deviceId, vlanId) -> {
+ if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
+ // not contains in new config, remove it
+ processIgnoreVlanRule(deviceId, vlanId, REMOVE);
+ }
+ });
+ }
+
+ @Override
public void processDhcpPacket(PacketContext context, BasePacket payload) {
checkNotNull(payload, "DHCP6 payload can't be null");
checkState(payload instanceof DHCP6, "Payload is not a DHCP6");
@@ -1053,6 +1131,7 @@
});
oldServerInfo.getDhcpServerIp6().ifPresent(serverIp -> {
hostService.stopMonitoringIp(serverIp);
+ cancelDhcpPacket(serverIp);
});
}
@@ -1067,7 +1146,8 @@
log.debug("DHCP server connect point: {}", newServerInfo.getDhcpServerConnectPoint().orElse(null));
log.debug("DHCP server IP: {}", newServerInfo.getDhcpServerIp6().orElse(null));
- IpAddress ipToProbe;
+ Ip6Address serverIp = newServerInfo.getDhcpServerIp6().get();
+ Ip6Address ipToProbe;
if (newServerInfo.getDhcpGatewayIp6().isPresent()) {
ipToProbe = newServerInfo.getDhcpGatewayIp6().get();
} else {
@@ -1093,6 +1173,7 @@
nonDupServerInfoList.addAll(serverInfoList);
serverInfoList.clear();
serverInfoList.addAll(nonDupServerInfoList);
+ requestDhcpPacket(serverIp);
}
class InternalHostListener implements HostListener {
@@ -1106,9 +1187,6 @@
case HOST_REMOVED:
hostRemoved(event.subject());
break;
- case HOST_MOVED:
- hostMoved(event.subject());
- break;
default:
break;
}
@@ -1116,119 +1194,39 @@
}
/**
- * Handle host move.
- * If the host DHCP server or gateway and it moved to the location different
- * to user configured, unsets the connect mac and vlan
- *
- * @param host the host
- */
- private void hostMoved(Host host) {
- Set<ConnectPoint> hostConnectPoints = host.locations().stream()
- .map(hl -> new ConnectPoint(hl.elementId(), hl.port()))
- .collect(Collectors.toSet());
- DhcpServerInfo serverInfo;
- ConnectPoint dhcpServerConnectPoint;
- Ip6Address dhcpGatewayIp;
- Ip6Address dhcpServerIp;
-
- if (!defaultServerInfoList.isEmpty()) {
- serverInfo = defaultServerInfoList.get(0);
- dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
- if (dhcpServerConnectPoint == null) {
- return;
- }
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- }
-
- if (!indirectServerInfoList.isEmpty()) {
- serverInfo = indirectServerInfoList.get(0);
- dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
- if (dhcpServerConnectPoint == null) {
- return;
- }
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp) &&
- !hostConnectPoints.contains(dhcpServerConnectPoint)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- }
- reloadServerSettings();
- }
-
- /**
* Handle host updated.
* If the host is DHCP server or gateway, update connect mac and vlan.
*
* @param host the host
*/
private void hostUpdated(Host host) {
- DhcpServerInfo serverInfo;
- Ip6Address dhcpGatewayIp;
- Ip6Address dhcpServerIp;
- if (!defaultServerInfoList.isEmpty()) {
- serverInfo = defaultServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- }
-
- if (!indirectServerInfoList.isEmpty()) {
- serverInfo = indirectServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectMac(host.mac());
- serverInfo.setDhcpConnectVlan(host.vlan());
- }
- }
- }
+ hostUpdated(host, defaultServerInfoList);
+ hostUpdated(host, indirectServerInfoList);
reloadServerSettings();
}
+ private void hostUpdated(Host host, List<DhcpServerInfo> serverInfoList) {
+ DhcpServerInfo serverInfo;
+ Ip6Address targetIp;
+ if (!serverInfoList.isEmpty()) {
+ serverInfo = serverInfoList.get(0);
+ Ip6Address serverIp = serverInfo.getDhcpServerIp6().orElse(null);
+ targetIp = serverInfo.getDhcpGatewayIp6().orElse(null);
+
+ if (targetIp == null) {
+ targetIp = serverIp;
+ }
+
+ if (targetIp != null) {
+ if (host.ipAddresses().contains(targetIp)) {
+ serverInfo.setDhcpConnectMac(host.mac());
+ serverInfo.setDhcpConnectVlan(host.vlan());
+ requestDhcpPacket(serverIp);
+ }
+ }
+ }
+ }
+
/**
* Handle host removed.
* If the host is DHCP server or gateway, unset connect mac and vlan.
@@ -1236,50 +1234,34 @@
* @param host the host
*/
private void hostRemoved(Host host) {
- DhcpServerInfo serverInfo;
- Ip6Address dhcpGatewayIp;
- Ip6Address dhcpServerIp;
-
- if (!defaultServerInfoList.isEmpty()) {
- serverInfo = defaultServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
-
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- }
-
- if (!indirectServerInfoList.isEmpty()) {
- serverInfo = indirectServerInfoList.get(0);
- dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
- dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
-
- if (dhcpGatewayIp != null) {
- if (host.ipAddresses().contains(dhcpGatewayIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- if (dhcpServerIp != null) {
- if (host.ipAddresses().contains(dhcpServerIp)) {
- serverInfo.setDhcpConnectVlan(null);
- serverInfo.setDhcpConnectMac(null);
- }
- }
- }
+ hostRemoved(host, defaultServerInfoList);
+ hostRemoved(host, indirectServerInfoList);
reloadServerSettings();
}
+ private void hostRemoved(Host host, List<DhcpServerInfo> serverInfoList) {
+ DhcpServerInfo serverInfo;
+ Ip6Address targetIp;
+
+ if (!serverInfoList.isEmpty()) {
+ serverInfo = serverInfoList.get(0);
+ Ip6Address serverIp = serverInfo.getDhcpServerIp6().orElse(null);
+ targetIp = serverInfo.getDhcpGatewayIp6().orElse(null);
+
+ if (targetIp == null) {
+ targetIp = serverIp;
+ }
+
+ if (targetIp != null) {
+ if (host.ipAddresses().contains(targetIp)) {
+ serverInfo.setDhcpConnectVlan(null);
+ serverInfo.setDhcpConnectMac(null);
+ cancelDhcpPacket(serverIp);
+ }
+ }
+ }
+ }
+
private void reloadServerSettings() {
DhcpServerInfo serverInfo;
if (!defaultServerInfoList.isEmpty()) {
@@ -1369,4 +1351,139 @@
return iface.vlanTagged().contains(vlanId);
}
+ private void requestDhcpPacket(Ip6Address serverIp) {
+ requestServerDhcpPacket(serverIp);
+ requestClientDhcpPacket(serverIp);
+ }
+
+ private void cancelDhcpPacket(Ip6Address serverIp) {
+ cancelServerDhcpPacket(serverIp);
+ cancelClientDhcpPacket(serverIp);
+ }
+
+ private void cancelServerDhcpPacket(Ip6Address serverIp) {
+ TrafficSelector serverSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPv6Src(serverIp.toIpPrefix())
+ .build();
+ packetService.cancelPackets(serverSelector,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void requestServerDhcpPacket(Ip6Address serverIp) {
+ TrafficSelector serverSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPv6Src(serverIp.toIpPrefix())
+ .build();
+ packetService.requestPackets(serverSelector,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void cancelClientDhcpPacket(Ip6Address serverIp) {
+ // Packet comes from relay
+ TrafficSelector indirectClientSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPv6Dst(serverIp.toIpPrefix())
+ .build();
+ packetService.cancelPackets(indirectClientSelector,
+ PacketPriority.CONTROL,
+ appId);
+
+ // Packet comes from client
+ packetService.cancelPackets(CLIENT_SERVER_SELECTOR,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void requestClientDhcpPacket(Ip6Address serverIp) {
+ // Packet comes from relay
+ TrafficSelector indirectClientSelector =
+ DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
+ .matchIPv6Dst(serverIp.toIpPrefix())
+ .build();
+ packetService.requestPackets(indirectClientSelector,
+ PacketPriority.CONTROL,
+ appId);
+
+ // Packet comes from client
+ packetService.requestPackets(CLIENT_SERVER_SELECTOR,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ /**
+ * Process the ignore rules.
+ *
+ * @param deviceId the device id
+ * @param vlanId the vlan to be ignored
+ * @param op the operation, ADD to install; REMOVE to uninstall rules
+ */
+ private void processIgnoreVlanRule(DeviceId deviceId, VlanId vlanId, Objective.Operation op) {
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
+ AtomicInteger installedCount = new AtomicInteger(DHCP_SELECTORS.size());
+ DHCP_SELECTORS.forEach(trafficSelector -> {
+ TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
+ .matchVlanId(vlanId)
+ .build();
+
+ ForwardingObjective.Builder builder = DefaultForwardingObjective.builder()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withSelector(selector)
+ .withPriority(IGNORE_CONTROL_PRIORITY)
+ .withTreatment(dropTreatment)
+ .fromApp(appId);
+
+
+ ObjectiveContext objectiveContext = new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Ignore rule {} (Vlan id {}, device {}, selector {})",
+ op, vlanId, deviceId, selector);
+ int countDown = installedCount.decrementAndGet();
+ if (countDown != 0) {
+ return;
+ }
+ switch (op) {
+ case ADD:
+ ignoredVlans.put(deviceId, vlanId);
+ break;
+ case REMOVE:
+ ignoredVlans.remove(deviceId, vlanId);
+ break;
+ default:
+ log.warn("Unsupported objective operation {}", op);
+ break;
+ }
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.warn("Can't {} ignore rule (vlan id {}, selector {}, device {}) due to {}",
+ op, vlanId, selector, deviceId, error);
+ }
+ };
+
+ ForwardingObjective fwd;
+ switch (op) {
+ case ADD:
+ fwd = builder.add(objectiveContext);
+ break;
+ case REMOVE:
+ fwd = builder.remove(objectiveContext);
+ break;
+ default:
+ log.warn("Unsupported objective operation {}", op);
+ return;
+ }
+
+ Device device = deviceService.getDevice(deviceId);
+ if (device == null || !device.is(Pipeliner.class)) {
+ log.warn("Device {} is not available now, wait until device is available", deviceId);
+ return;
+ }
+ flowObjectiveService.apply(deviceId, fwd);
+ });
+ }
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index e1f9939..15026eb 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -23,12 +23,11 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
-import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
+import com.google.common.collect.Streams;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -46,7 +45,6 @@
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
-import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
import org.onlab.util.Tools;
@@ -62,22 +60,12 @@
import org.onosproject.dhcprelay.store.DhcpRecord;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
import org.onosproject.dhcprelay.config.DhcpServerConfig;
import org.onosproject.net.Host;
-import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.config.Config;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.UdpPortCriterion;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
@@ -104,8 +92,6 @@
import com.google.common.collect.ImmutableSet;
import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
-import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
-import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
/**
* DHCP Relay Agent Application Component.
@@ -116,36 +102,10 @@
public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
public static final String ROUTE_STORE_IMPL =
"org.onosproject.routeservice.store.RouteStoreImpl";
- private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
- .build();
- private static final TrafficSelector DHCP_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
- .build();
- private static final TrafficSelector DHCP6_SERVER_SELECTOR = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV6)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
- .build();
- private static final TrafficSelector DHCP6_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV6)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
- .build();
- static final List<TrafficSelector> DHCP_SELECTORS = ImmutableList.of(
- DHCP_SERVER_SELECTOR,
- DHCP_CLIENT_SELECTOR,
- DHCP6_SERVER_SELECTOR,
- DHCP6_CLIENT_SELECTOR
- );
+
private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_ARP)
.build();
- private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
private final Logger log = LoggerFactory.getLogger(getClass());
private final InternalConfigListener cfgListener = new InternalConfigListener();
@@ -201,9 +161,6 @@
protected ComponentConfigService compCfgService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected FlowObjectiveService flowObjectiveService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
@@ -218,7 +175,6 @@
label = "Enable Address resolution protocol")
protected boolean arpEnabled = true;
- protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
protected DeviceListener deviceListener = new InternalDeviceListener();
private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
private ApplicationId appId;
@@ -236,8 +192,6 @@
//add the packet processor
packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
- // listen host event for dhcp server or the gateway
- requestDhcpPackets();
modified(context);
// Enable distribute route store
@@ -254,7 +208,6 @@
cfgService.removeListener(cfgListener);
factories.forEach(cfgService::unregisterConfigFactory);
packetService.removeProcessor(dhcpRelayPacketProcessor);
- cancelDhcpPackets();
cancelArpPackets();
compCfgService.unregisterProperties(getClass(), false);
deviceService.removeListener(deviceListener);
@@ -280,6 +233,12 @@
}
}
+ private static List<TrafficSelector> buildClientDhcpSelectors() {
+ return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
+ Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
+ .collect(Collectors.toList());
+ }
+
/**
* Updates DHCP relay app configuration.
*/
@@ -318,7 +277,8 @@
v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
}
if (config instanceof IgnoreDhcpConfig) {
- updateIgnoreVlanRules((IgnoreDhcpConfig) config);
+ v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
+ v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
}
}
@@ -331,125 +291,11 @@
v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
}
if (config instanceof IgnoreDhcpConfig) {
- ignoredVlans.forEach(((deviceId, vlanId) -> {
- processIgnoreVlanRule(deviceId, vlanId, REMOVE);
- }));
+ v4Handler.updateIgnoreVlanConfig(null);
+ v6Handler.updateIgnoreVlanConfig(null);
}
}
- private void updateIgnoreVlanRules(IgnoreDhcpConfig config) {
- config.ignoredVlans().forEach((deviceId, vlanId) -> {
- if (ignoredVlans.get(deviceId).contains(vlanId)) {
- // don't need to process if it already ignored
- return;
- }
- processIgnoreVlanRule(deviceId, vlanId, ADD);
- });
-
- ignoredVlans.forEach((deviceId, vlanId) -> {
- if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
- // not contains in new config, remove it
- processIgnoreVlanRule(deviceId, vlanId, REMOVE);
- }
- });
- }
-
- /**
- * Process the ignore rules.
- *
- * @param deviceId the device id
- * @param vlanId the vlan to be ignored
- * @param op the operation, ADD to install; REMOVE to uninstall rules
- */
- private void processIgnoreVlanRule(DeviceId deviceId, VlanId vlanId, Objective.Operation op) {
- TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
- dropTreatment.clearedDeferred();
- AtomicInteger installedCount = new AtomicInteger(DHCP_SELECTORS.size());
- DHCP_SELECTORS.forEach(trafficSelector -> {
- UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
- int udpDstPort = udpDst.udpPort().toInt();
- TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
- .matchVlanId(vlanId)
- .build();
-
- ForwardingObjective.Builder builder = DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withSelector(selector)
- .withPriority(IGNORE_CONTROL_PRIORITY)
- .withTreatment(dropTreatment)
- .fromApp(appId);
-
-
- ObjectiveContext objectiveContext = new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.info("Ignore rule {} (Vlan id {}, device {}, UDP dst {})",
- op, vlanId, deviceId, udpDstPort);
- int countDown = installedCount.decrementAndGet();
- if (countDown != 0) {
- return;
- }
- switch (op) {
- case ADD:
-
- ignoredVlans.put(deviceId, vlanId);
- break;
- case REMOVE:
- ignoredVlans.remove(deviceId, vlanId);
- break;
- default:
- log.warn("Unsupported objective operation {}", op);
- break;
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Can't {} ignore rule (vlan id {}, udp dst {}, device {}) due to {}",
- op, vlanId, udpDstPort, deviceId, error);
- }
- };
-
- ForwardingObjective fwd;
- switch (op) {
- case ADD:
- fwd = builder.add(objectiveContext);
- break;
- case REMOVE:
- fwd = builder.remove(objectiveContext);
- break;
- default:
- log.warn("Unsupported objective operation {}", op);
- return;
- }
-
- Device device = deviceService.getDevice(deviceId);
- if (device == null || !device.is(Pipeliner.class)) {
- log.warn("Device {} is not available now, wait until device is available", deviceId);
- return;
- }
- flowObjectiveService.apply(deviceId, fwd);
- });
- }
-
- /**
- * Request DHCP packet in via PacketService.
- */
- private void requestDhcpPackets() {
- DHCP_SELECTORS.forEach(trafficSelector -> {
- packetService.requestPackets(trafficSelector, PacketPriority.CONTROL, appId);
- });
- }
-
- /**
- * Cancel requested DHCP packets in via packet service.
- */
- private void cancelDhcpPackets() {
- DHCP_SELECTORS.forEach(trafficSelector -> {
- packetService.cancelPackets(trafficSelector, PacketPriority.CONTROL, appId);
- });
- }
-
/**
* Request ARP packet in via PacketService.
*/
@@ -663,14 +509,10 @@
Device device = event.subject();
switch (event.type()) {
case DEVICE_ADDED:
- deviceAdd(device.id());
- break;
- case DEVICE_REMOVED:
- ignoredVlans.removeAll(device.id());
+ updateIgnoreVlanConfigs();
break;
case DEVICE_AVAILABILITY_CHANGED:
deviceAvailabilityChanged(device);
-
default:
break;
}
@@ -678,23 +520,14 @@
private void deviceAvailabilityChanged(Device device) {
if (deviceService.isAvailable(device.id())) {
- deviceAdd(device.id());
- } else {
- ignoredVlans.removeAll(device.id());
+ updateIgnoreVlanConfigs();
}
}
- private void deviceAdd(DeviceId deviceId) {
+ private void updateIgnoreVlanConfigs() {
IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
- if (config == null) {
- log.debug("No ignoreVlan config found for {}. Do nothing.", deviceId);
- return;
- }
-
- Collection<VlanId> vlanIds = config.ignoredVlans().get(deviceId);
- vlanIds.forEach(vlanId -> {
- processIgnoreVlanRule(deviceId, vlanId, ADD);
- });
+ v4Handler.updateIgnoreVlanConfig(config);
+ v6Handler.updateIgnoreVlanConfig(config);
}
}
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
index 2efeca4..5397d18 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
@@ -22,6 +22,7 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.dhcprelay.config.DhcpServerConfig;
+import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.packet.PacketContext;
@@ -161,4 +162,11 @@
* @param configs the config
*/
void setIndirectDhcpServerConfigs(Collection<DhcpServerConfig> configs);
+
+ /**
+ * Push IgnoreDhcpConfig to the handler.
+ *
+ * @param config the config
+ */
+ void updateIgnoreVlanConfig(IgnoreDhcpConfig config);
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java
index 19d8ed2..39683cd 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java
@@ -27,6 +27,9 @@
import java.util.Optional;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
/**
* DHCP server configuration.
*/
@@ -100,6 +103,11 @@
}
});
}
+
+ checkNotNull(connectPoint, "Connect point of DHCP server can't be null");
+ checkState(serverIp4Addr != null || serverIp6Addr != null,
+ "Should exist at least one server IP for DHCPv4 or DHCPv6");
+
}
/**
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
index 0de95f0..eb24ae2 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -22,6 +22,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import com.google.common.collect.Streams;
import com.google.common.io.Resources;
import org.apache.commons.io.Charsets;
import org.easymock.Capture;
@@ -116,7 +117,6 @@
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
-import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_SELECTORS;
public class DhcpRelayManagerTest {
private static final short VLAN_LEN = 2;
@@ -227,6 +227,8 @@
// Relay agent config
private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
+ private static final List<TrafficSelector> DHCP_SELECTORS = buildClientDhcpSelectors();
+
// Components
private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
@@ -246,6 +248,10 @@
private MockRouteStore mockRouteStore;
private MockDhcpRelayStore mockDhcpRelayStore;
private HostProviderService mockHostProviderService;
+ private FlowObjectiveService flowObjectiveService;
+ private DeviceService deviceService;
+ private Dhcp4HandlerImpl v4Handler;
+ private Dhcp6HandlerImpl v6Handler;
private static Interface createInterface(String name, ConnectPoint connectPoint,
List<InterfaceIpAddress> interfaceIps,
@@ -286,38 +292,47 @@
packetService = new MockPacketService();
manager.packetService = packetService;
manager.compCfgService = createNiceMock(ComponentConfigService.class);
- manager.deviceService = createNiceMock(DeviceService.class);
+ deviceService = createNiceMock(DeviceService.class);
Device device = createNiceMock(Device.class);
expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
- expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
- expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
- replay(manager.deviceService, device);
+ expect(deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
+ expect(deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
+ replay(deviceService, device);
mockRouteStore = new MockRouteStore();
mockDhcpRelayStore = new MockDhcpRelayStore();
manager.dhcpRelayStore = mockDhcpRelayStore;
+ manager.deviceService = deviceService;
manager.interfaceService = new MockInterfaceService();
- manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
+ flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
mockHostProviderService = createNiceMock(HostProviderService.class);
- Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
+ v4Handler = new Dhcp4HandlerImpl();
v4Handler.providerService = mockHostProviderService;
v4Handler.dhcpRelayStore = mockDhcpRelayStore;
v4Handler.hostService = manager.hostService;
v4Handler.interfaceService = manager.interfaceService;
v4Handler.packetService = manager.packetService;
v4Handler.routeStore = mockRouteStore;
+ v4Handler.coreService = createNiceMock(CoreService.class);
+ v4Handler.flowObjectiveService = flowObjectiveService;
+ v4Handler.appId = TestApplicationId.create(Dhcp4HandlerImpl.DHCP_V4_RELAY_APP);
+ v4Handler.deviceService = deviceService;
manager.v4Handler = v4Handler;
- Dhcp6HandlerImpl v6Handler = new Dhcp6HandlerImpl();
+ v6Handler = new Dhcp6HandlerImpl();
v6Handler.dhcpRelayStore = mockDhcpRelayStore;
v6Handler.hostService = manager.hostService;
v6Handler.interfaceService = manager.interfaceService;
v6Handler.packetService = manager.packetService;
v6Handler.routeStore = mockRouteStore;
v6Handler.providerService = mockHostProviderService;
+ v6Handler.coreService = createNiceMock(CoreService.class);
+ v6Handler.flowObjectiveService = flowObjectiveService;
+ v6Handler.appId = TestApplicationId.create(Dhcp6HandlerImpl.DHCP_V6_RELAY_APP);
+ v6Handler.deviceService = deviceService;
manager.v6Handler = v6Handler;
// properties
@@ -454,26 +469,25 @@
config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
- manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
+ flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
expectLastCall().times(DHCP_SELECTORS.size());
Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
- manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
+ flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
expectLastCall().times(DHCP_SELECTORS.size());
- replay(manager.flowObjectiveService);
+ replay(flowObjectiveService);
manager.updateConfig(config);
- verify(manager.flowObjectiveService);
+ verify(flowObjectiveService);
List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
- TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
- dropTreatment.clearedDeferred();
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
for (int index = 0; index < objectivesFromDev1.size(); index++) {
TrafficSelector selector =
- DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
+ DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
.matchVlanId(IGNORED_VLAN)
.build();
ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
@@ -487,7 +501,8 @@
});
}
objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
- assertEquals(2, manager.ignoredVlans.size());
+ assertEquals(2, v4Handler.ignoredVlans.size());
+ assertEquals(2, v6Handler.ignoredVlans.size());
}
/**
@@ -495,31 +510,32 @@
*/
@Test
public void testRemoveIgnoreVlan() {
- manager.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
- manager.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
+ v4Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
+ v4Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
+ v6Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
+ v6Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
IgnoreDhcpConfig config = new IgnoreDhcpConfig();
Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
- manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
+ flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
expectLastCall().times(DHCP_SELECTORS.size());
Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
- manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
+ flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
expectLastCall().times(DHCP_SELECTORS.size());
- replay(manager.flowObjectiveService);
+ replay(flowObjectiveService);
manager.removeConfig(config);
- verify(manager.flowObjectiveService);
+ verify(flowObjectiveService);
List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
- TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
- dropTreatment.clearedDeferred();
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
for (int index = 0; index < objectivesFromDev1.size(); index++) {
TrafficSelector selector =
- DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
+ DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
.matchVlanId(IGNORED_VLAN)
.build();
ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
@@ -533,7 +549,8 @@
});
}
objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
- assertEquals(0, manager.ignoredVlans.size());
+ assertEquals(0, v4Handler.ignoredVlans.size());
+ assertEquals(0, v6Handler.ignoredVlans.size());
}
/**
@@ -555,14 +572,15 @@
config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
- manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
+ flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
expectLastCall().times(DHCP_SELECTORS.size());
- replay(manager.flowObjectiveService, manager.deviceService, device);
+ replay(flowObjectiveService, manager.deviceService, device);
manager.updateConfig(config);
capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
- assertEquals(1, manager.ignoredVlans.size());
+ assertEquals(1, v4Handler.ignoredVlans.size());
+ assertEquals(1, v6Handler.ignoredVlans.size());
}
/**
@@ -576,7 +594,7 @@
json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
- reset(manager.cfgService, manager.flowObjectiveService, manager.deviceService);
+ reset(manager.cfgService, flowObjectiveService, manager.deviceService);
expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
.andReturn(config).anyTimes();
@@ -586,13 +604,13 @@
expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
- manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
+ flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
expectLastCall().times(DHCP_SELECTORS.size());
- replay(manager.cfgService, manager.flowObjectiveService, manager.deviceService, device);
- assertEquals(0, manager.ignoredVlans.size());
+ replay(manager.cfgService, flowObjectiveService, manager.deviceService, device);
manager.deviceListener.event(event);
capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
- assertEquals(1, manager.ignoredVlans.size());
+ assertEquals(1, v4Handler.ignoredVlans.size());
+ assertEquals(1, v6Handler.ignoredVlans.size());
}
/**
@@ -1296,6 +1314,12 @@
return interfaceIdBytes;
}
+ private static List<TrafficSelector> buildClientDhcpSelectors() {
+ return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
+ Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
+ .collect(Collectors.toList());
+ }
+
private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java b/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java
index 54e0925..ecddc3a 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java
@@ -32,6 +32,19 @@
public static final int BIT_LENGTH = IpAddress.INET6_BIT_LENGTH;
/**
+ * A link-scoped multicast address used by a DHCP client to communicate with
+ * neighboring DHCP relay agents and servers. (RFC 3315)
+ */
+ public static final Ip6Address ALL_DHCP_RELAY_AGENTS_AND_SERVERS =
+ Ip6Address.valueOf("ff02::1:2");
+ /**
+ * A site-scoped multicast address used by a DHCP relay agent to
+ * communicate with DHCP servers. (RFC 3315)
+ */
+ public static final Ip6Address ALL_DHCP_SERVERS =
+ Ip6Address.valueOf("ff05::1:3");
+
+ /**
* All-zero unspecified IPv6 address.
*/
public static final Ip6Address ZERO = Ip6Address.valueOf("::");