org.opendaylight.protocol.pcep.pcc.mock.PCCTunnelManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.protocol.pcep.pcc.mock.PCCTunnelManagerImpl.java

Source

/*
 * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package org.opendaylight.protocol.pcep.pcc.mock;

import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLsp;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLspTlvs;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLspTlvsEndofSync;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createPath;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createPcRtpMessage;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createSrp;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.reqToRptPath;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.updToRptPath;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.net.InetAddresses;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
import java.math.BigInteger;
import java.net.InetAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.protocol.pcep.pcc.mock.api.LspType;
import org.opendaylight.protocol.pcep.pcc.mock.api.PCCSession;
import org.opendaylight.protocol.pcep.pcc.mock.api.PCCTunnelManager;
import org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil;
import org.opendaylight.protocol.pcep.spi.PCEPErrors;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Lsp1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Lsp1Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Srp1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Srp1Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.pcinitiate.message.pcinitiate.message.Requests;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.OperationalStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Pcrpt;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PlspId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.SrpIdNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.Lsp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.LspBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.Tlvs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcrpt.message.pcrpt.message.reports.Path;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcrpt.message.pcrpt.message.reports.PathBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcupd.message.pcupd.message.Updates;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.srp.object.Srp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.srp.object.SrpBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.ero.Subobject;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCase;

public final class PCCTunnelManagerImpl implements PCCTunnelManager {

    private static final Optional<Srp> NO_SRP = Optional.absent();
    @GuardedBy("this")
    private final Map<Integer, PCCSession> sessions = new HashMap<>();
    private final AtomicLong plspIDsCounter;
    private final String address;
    private final Timer timer;
    private final int redelegationTimeout;
    private final int stateTimeout;
    private final int lspsCount;
    private final Optional<TimerHandler> timerHandler;
    @GuardedBy("this")
    private final Map<PlspId, PCCTunnel> tunnels = new HashMap<>();
    private PCCSyncOptimization syncOptimization;

    public PCCTunnelManagerImpl(final int lspsCount, final InetAddress address, final int redelegationTimeout,
            final int stateTimeout, final Timer timer, final Optional<TimerHandler> timerHandler) {
        Preconditions.checkArgument(lspsCount >= 0);
        this.redelegationTimeout = redelegationTimeout;
        this.stateTimeout = stateTimeout;
        this.plspIDsCounter = new AtomicLong(lspsCount);
        this.address = InetAddresses.toAddrString(Preconditions.checkNotNull(address));
        this.timer = Preconditions.checkNotNull(timer);
        this.timerHandler = timerHandler;
        this.lspsCount = lspsCount;
    }

    protected void reportToAll(final Updates update, final PCCSession session) {
        final PlspId plspId = update.getLsp().getPlspId();
        final PCCTunnel tunnel = this.tunnels.get(plspId);
        final long srpId = update.getSrp().getOperationId().getValue();
        if (tunnel != null) {
            if (hasDelegation(tunnel, session)) {
                final Srp srp = createSrp(update.getSrp().getOperationId().getValue());
                final Path path = updToRptPath(update.getPath());
                final List<Subobject> subobjects = update.getPath().getEro().getSubobject();
                final Lsp lsp = update.getLsp();
                sendToAll(tunnel, plspId, subobjects, srp, path, lsp);
                //update tunnel state
                tunnel.setLspState(path);
            } else {
                session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UPDATE_REQ_FOR_NON_LSP, srpId));
            }
        } else {
            session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
        }
    }

    private void returnDelegation(final Updates update, final PCCSession session) {
        final PlspId plspId = update.getLsp().getPlspId();
        final PCCTunnel tunnel = this.tunnels.get(plspId);
        final long srpId = update.getSrp().getOperationId().getValue();
        if (tunnel != null) {
            //check if session really has a delegation
            if (hasDelegation(tunnel, session)) {
                //send report D=0
                final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.<List<Subobject>>absent());
                final Pcrpt pcrtp = createPcRtpMessage(
                        new LspBuilder(update.getLsp()).setSync(true).setOperational(OperationalStatus.Up)
                                .setDelegate(false).setTlvs(tlvs).build(),
                        Optional.of(createSrp(srpId)), tunnel.getLspState());
                session.sendReport(pcrtp);
                //start state timer
                startStateTimeout(tunnel, plspId);
                //if PCC's LSP, start re-delegation timer
                if (tunnel.getType() == LspType.PCC_LSP) {
                    startRedelegationTimer(tunnel, plspId, session);
                } else {
                    //if PCE-initiated LSP, revoke delegation instantly
                    setDelegation(plspId, null);
                }
            } else {
                session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UPDATE_REQ_FOR_NON_LSP, srpId));
            }
        } else {
            session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
        }
    }

    protected void takeDelegation(final Requests request, final PCCSession session) {
        final PlspId plspId = request.getLsp().getPlspId();
        final PCCTunnel tunnel = this.tunnels.get(plspId);
        final long srpId = request.getSrp().getOperationId().getValue();
        if (tunnel != null) {
            //check if tunnel has no delegation
            if ((tunnel.getType() == LspType.PCE_LSP) && ((tunnel.getDelegationHolder() == -1)
                    || (tunnel.getDelegationHolder() == session.getId()))) {
                //set delegation
                tunnel.cancelTimeouts();
                setDelegation(plspId, session);
                //send report
                final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.<List<Subobject>>absent());
                session.sendReport(createPcRtpMessage(
                        new LspBuilder(request.getLsp()).setSync(true).setOperational(OperationalStatus.Up)
                                .setDelegate(true).setTlvs(tlvs).build(),
                        Optional.of(createSrp(srpId)), tunnel.getLspState()));
            } else {
                session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.LSP_NOT_PCE_INITIATED, srpId));
            }
        } else {
            session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
        }
    }

    @Override
    public synchronized void onSessionUp(final PCCSession session) {
        this.syncOptimization = new PCCSyncOptimization(session);
        lazyTunnelInicialization();

        //first session - delegate all PCC's LSPs only when reporting at startup
        if (!this.sessions.containsKey(session.getId()) && (session.getId() == 0)) {
            for (final PlspId plspId : this.tunnels.keySet()) {
                setDelegation(plspId, session);
            }
        }
        this.sessions.put(session.getId(), session);

        if (!this.syncOptimization.isTriggeredInitSyncEnabled()) {
            lspReport(session);
        }
    }

    @Override
    public synchronized void onSessionDown(final PCCSession session) {
        for (final Entry<PlspId, PCCTunnel> entry : this.tunnels.entrySet()) {
            final PCCTunnel tunnel = entry.getValue();
            final PlspId plspId = entry.getKey();
            //deal with delegations
            if (hasDelegation(tunnel, session)) {
                startStateTimeout(tunnel, entry.getKey());
                startRedelegationTimer(tunnel, plspId, session);
            }
        }
    }

    protected void addTunnel(final Requests request, final PCCSession session) {
        final PlspId plspId = new PlspId(this.plspIDsCounter.incrementAndGet());
        final PCCTunnel tunnel = new PCCTunnel(
                request.getLsp().getTlvs().getSymbolicPathName().getPathName().getValue(), session.getId(),
                LspType.PCE_LSP, reqToRptPath(request));
        sendToAll(tunnel, plspId, request.getEro().getSubobject(),
                createSrp(request.getSrp().getOperationId().getValue()), tunnel.getLspState(),
                new LspBuilder(request.getLsp())
                        .addAugmentation(Lsp1.class, new Lsp1Builder().setCreate(true).build()).build());
        this.tunnels.put(plspId, tunnel);
    }

    protected void removeTunnel(final Requests request, final PCCSession session) {
        final PlspId plspId = request.getLsp().getPlspId();
        final PCCTunnel tunnel = this.tunnels.get(plspId);
        final long srpId = request.getSrp().getOperationId().getValue();
        if (tunnel != null) {
            if (tunnel.getType() == LspType.PCE_LSP) {
                if (hasDelegation(tunnel, session)) {
                    this.tunnels.remove(plspId);
                    sendToAll(tunnel, plspId, tunnel.getLspState().getEro().getSubobject(),
                            new SrpBuilder(request.getSrp())
                                    .addAugmentation(Srp1.class, new Srp1Builder().setRemove(true).build()).build(),
                            reqToRptPath(request), request.getLsp());
                } else {
                    session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UPDATE_REQ_FOR_NON_LSP, srpId));
                }
            } else {
                session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.LSP_NOT_PCE_INITIATED, srpId));
            }
        } else {
            session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
        }
    }

    @Override
    public void onMessagePcupd(@Nonnull final Updates update, @Nonnull final PCCSession session) {
        final Lsp lsp = update.getLsp();
        if (isInitialSyncTriggered(lsp)) {
            lspReport(session);
            if (this.timerHandler.isPresent()) {
                this.timerHandler.get().createDisconnectTask();
            }
        } else if (isReSyncTriggered(lsp)) {
            handledDbTriggeredResync(update, session);
        } else if ((lsp.isDelegate() != null) && lsp.isDelegate()) {
            //regular LSP update
            reportToAll(update, session);
        } else {
            //returning LSP delegation
            returnDelegation(update, session);
        }
    }

    @Override
    public void onMessagePcInitiate(@Nonnull final Requests request, @Nonnull final PCCSession session) {
        if ((request.getSrp().getAugmentation(Srp1.class) != null)
                && request.getSrp().getAugmentation(Srp1.class).isRemove()) {
            //remove LSP
            removeTunnel(request, session);
        } else if ((request.getLsp().isDelegate() != null) && request.getLsp().isDelegate()
                && (request.getEndpointsObj() == null)) {
            //take LSP delegation
            takeDelegation(request, session);
        } else {
            //create LSP
            addTunnel(request, session);
        }
    }

    private Tlvs buildTlvs(final PCCTunnel tunnel, final Long plspId,
            final Optional<List<Subobject>> subobjectsList) {
        final List<Subobject> subObject = subobjectsList.isPresent() ? subobjectsList.get()
                : tunnel.getLspState().getEro().getSubobject();
        final String destinationAddress = getDestinationAddress(subObject, this.address);

        return createLspTlvs(plspId, true, destinationAddress, this.address, this.address,
                Optional.of(tunnel.getPathName()), this.syncOptimization.incrementLspDBVersion());
    }

    private void lazyTunnelInicialization() {
        if (this.tunnels.isEmpty()) {
            final BigInteger dbV = this.syncOptimization.getLocalLspDbVersionValue();
            if (this.syncOptimization.isSyncAvoidanceEnabled() && !((dbV != null) && dbV.equals(BigInteger.ONE))) {
                this.tunnels.putAll(PCCTunnelBuilder.createTunnels(this.address, dbV.intValue()));
            } else {
                this.tunnels.putAll(PCCTunnelBuilder.createTunnels(this.address, this.lspsCount));
            }
        }
    }

    private boolean isReSyncTriggered(final Lsp lsp) {
        return this.syncOptimization.isTriggeredReSyncEnabled() && lsp.isSync();
    }

    private boolean isInitialSyncTriggered(final Lsp lsp) {
        return (lsp.getPlspId().getValue() == 0) && lsp.isSync()
                && this.syncOptimization.isTriggeredInitSyncEnabled();
    }

    private void handledDbTriggeredResync(final Updates update, final PCCSession session) {
        this.syncOptimization.setResynchronizingState(Boolean.TRUE);
        final SrpIdNumber operationId = update.getSrp().getOperationId();
        if (update.getLsp().getPlspId().getValue() == 0) {
            reportAllKnownLsp(Optional.of(operationId), session);
        } else {
            reportLsp(update.getLsp().getPlspId(), operationId, session);
        }
        sendEndOfSynchronization(session, Optional.of(operationId));
        this.syncOptimization.setResynchronizingState(Boolean.FALSE);
    }

    private void lspReport(final PCCSession session) {
        if (!this.tunnels.isEmpty()) {
            if (!this.syncOptimization.isSyncAvoidanceEnabled()) {
                reportAllKnownLsp(session);
                sendEndOfSynchronization(session);
            } else if (!this.syncOptimization.doesLspDbMatch()) {
                if (this.syncOptimization.isDeltaSyncEnabled()) {
                    reportMissedLsp(session);
                    sendEndOfSynchronization(session);
                } else {
                    reportAllKnownLsp(session);
                    sendEndOfSynchronization(session);
                }
            }
        }
    }

    /**
     * Reports Missed Lsp when DbVersion doesnt match
     *
     * @param session
     */
    private void reportMissedLsp(final PCCSession session) {
        for (long missedLsp = this.syncOptimization.getRemoteLspDbVersionValue().longValue()
                + 1; missedLsp <= this.syncOptimization.getLocalLspDbVersionValue().longValue(); missedLsp++) {
            final PlspId plspId = new PlspId(missedLsp);
            final PCCTunnel tunnel = this.tunnels.get(plspId);
            createLspAndSendReport(missedLsp, tunnel, session, Optional.<Boolean>absent(), NO_SRP);
        }
    }

    private void createLspAndSendReport(final long plspId, final PCCTunnel tunnel, final PCCSession session,
            final Optional<Boolean> isSync, final Optional<Srp> srp) {
        final boolean delegation = hasDelegation(tunnel, session);
        if (delegation) {
            tunnel.cancelTimeouts();
        }
        final String destinationAddress = getDestinationAddress(tunnel.getLspState().getEro().getSubobject(),
                this.address);
        final Tlvs tlvs = createLspTlvs(plspId, true, destinationAddress, this.address, this.address,
                Optional.of(tunnel.getPathName()), this.syncOptimization.incrementLspDBVersion());

        final boolean sync = isSync.isPresent() ? isSync.get() : this.syncOptimization.isSyncNeedIt();
        final Lsp lsp = createLsp(plspId, sync, Optional.fromNullable(tlvs), delegation, false);
        final Pcrpt pcrtp = createPcRtpMessage(lsp, srp, tunnel.getLspState());
        session.sendReport(pcrtp);
    }

    private void sendEndOfSynchronization(final PCCSession session) {
        sendEndOfSynchronization(session, Optional.<SrpIdNumber>absent());
    }

    private void sendEndOfSynchronization(final PCCSession session, final Optional<SrpIdNumber> operationId) {
        Srp srp = null;
        if (operationId.isPresent()) {
            srp = new SrpBuilder().setOperationId(operationId.get()).build();
        }
        Optional<Tlvs> tlv = Optional.absent();
        if (this.syncOptimization.isSyncAvoidanceEnabled()) {
            tlv = createLspTlvsEndofSync(this.syncOptimization.incrementLspDBVersion().get());
        }
        final Pcrpt pcrtp = createPcRtpMessage(createLsp(0, false, tlv, true, false), Optional.fromNullable(srp),
                createPath(Collections.<Subobject>emptyList()));
        session.sendReport(pcrtp);
    }

    private void reportAllKnownLsp(final PCCSession session) {
        reportAllKnownLsp(Optional.<SrpIdNumber>absent(), session);
    }

    private void reportAllKnownLsp(final Optional<SrpIdNumber> operationId, final PCCSession session) {
        Srp srp = null;
        if (operationId.isPresent()) {
            srp = new SrpBuilder().setOperationId(operationId.get()).build();
        }

        for (final Entry<PlspId, PCCTunnel> entry : this.tunnels.entrySet()) {
            final PCCTunnel tunnel = entry.getValue();
            final long plspId = entry.getKey().getValue();
            createLspAndSendReport(plspId, tunnel, session, Optional.<Boolean>absent(), Optional.fromNullable(srp));
        }
    }

    private void reportLsp(final PlspId plspId, final SrpIdNumber operationId, final PCCSession session) {
        final PCCTunnel tunnel = this.tunnels.get(plspId);
        if (tunnel == null) {
            return;
        }
        final Srp srp = new SrpBuilder().setOperationId(operationId).build();
        createLspAndSendReport(plspId.getValue(), tunnel, session, Optional.of(Boolean.TRUE), Optional.of(srp));
    }

    private void sendToAll(final PCCTunnel tunnel, final PlspId plspId, final List<Subobject> subobjects,
            final Srp srp, final Path path, final Lsp lsp) {
        for (final PCCSession session : this.sessions.values()) {
            final boolean isDelegated = hasDelegation(tunnel, session);
            final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.of(subobjects));

            final Pcrpt pcRpt = createPcRtpMessage(new LspBuilder(lsp).setPlspId(plspId)
                    .setOperational(OperationalStatus.Up).setDelegate(isDelegated).setSync(true)
                    .addAugmentation(Lsp1.class,
                            new Lsp1Builder().setCreate(tunnel.getType() == LspType.PCE_LSP).build())
                    .setTlvs(tlvs).build(), Optional.fromNullable(srp), path);
            session.sendReport(pcRpt);
        }
    }

    private void startStateTimeout(final PCCTunnel tunnel, final PlspId plspId) {
        if (this.stateTimeout > -1) {
            final Timeout newStateTimeout = this.timer.newTimeout(new TimerTask() {
                @Override
                public void run(final Timeout timeout) throws Exception {
                    if (tunnel.getType() == LspType.PCE_LSP) {
                        PCCTunnelManagerImpl.this.tunnels.remove(plspId);
                        //report tunnel removal to all
                        sendToAll(tunnel, plspId, Collections.<Subobject>emptyList(), createSrp(0),
                                new PathBuilder().build(),
                                createLsp(plspId.getValue(), false, Optional.<Tlvs>absent(), false, true));
                    }
                }
            }, this.stateTimeout, TimeUnit.SECONDS);
            tunnel.setStateTimeout(newStateTimeout);
        }
    }

    private void startRedelegationTimer(final PCCTunnel tunnel, final PlspId plspId, final PCCSession session) {
        final Timeout newRedelegationTimeout = this.timer.newTimeout(new TimerTask() {
            @Override
            public void run(final Timeout timeout) throws Exception {
                //remove delegation
                PCCTunnelManagerImpl.this.setDelegation(plspId, null);
                //delegate to another PCE
                int index = session.getId();
                for (int i = 1; i < PCCTunnelManagerImpl.this.sessions.size(); i++) {
                    index++;
                    if (index == PCCTunnelManagerImpl.this.sessions.size()) {
                        index = 0;
                    }
                    final PCCSession nextSession = PCCTunnelManagerImpl.this.sessions.get(index);
                    if (nextSession != null) {
                        tunnel.cancelTimeouts();
                        final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.<List<Subobject>>absent());

                        nextSession.sendReport(createPcRtpMessage(
                                createLsp(plspId.getValue(), true, Optional.fromNullable(tlvs), true, false),
                                NO_SRP, tunnel.getLspState()));
                        tunnel.setDelegationHolder(nextSession.getId());
                        break;
                    }
                }
            }
        }, this.redelegationTimeout, TimeUnit.SECONDS);
        tunnel.setRedelegationTimeout(newRedelegationTimeout);
    }

    private void setDelegation(final PlspId plspId, final PCCSession session) {
        final PCCTunnel tunnel = this.tunnels.get(plspId);
        final int sessionId;
        if (session != null) {
            sessionId = session.getId();
        } else {
            sessionId = PCCTunnelBuilder.PCC_DELEGATION;
        }
        tunnel.setDelegationHolder(sessionId);
    }

    private static boolean hasDelegation(final PCCTunnel tunnel, final PCCSession session) {
        final int sessionId = session.getId();
        final int delegationHolder = tunnel.getDelegationHolder();
        return delegationHolder == sessionId;
    }

    private static String getDestinationAddress(final List<Subobject> subobjects, final String defaultAddress) {
        if ((subobjects != null) && !subobjects.isEmpty()) {
            final String prefix = ((IpPrefixCase) subobjects.get(subobjects.size() - 1).getSubobjectType())
                    .getIpPrefix().getIpPrefix().getIpv4Prefix().getValue();
            return prefix.substring(0, prefix.indexOf('/'));
        }
        return defaultAddress;
    }
}