/*
 * Copyright (c) 2009 University of Washington
 *
 * SPDX-License-Identifier: GPL-2.0-only
 */
#ifndef IPV4_ROUTING_PROTOCOL_H
#define IPV4_ROUTING_PROTOCOL_H

#include "ipv4-header.h"
#include "ipv4-interface-address.h"
#include "ipv4.h"

#include "ns3/callback.h"
#include "ns3/nstime.h"
#include "ns3/object.h"
#include "ns3/output-stream-wrapper.h"
#include "ns3/packet.h"
#include "ns3/socket.h"

namespace ns3
{

class Ipv4MulticastRoute;
class Ipv4Route;
class NetDevice;

/**
 * @ingroup internet
 * @defgroup ipv4Routing IPv4 Routing Protocols.
 *
 * The classes in this group implement different routing protocols
 * for IPv4. Other modules could implement further protocols
 * (e.g., AODV, OLSR, etc.).
 */

/**
 * @ingroup ipv4Routing
 * @brief Abstract base class for IPv4 routing protocols.
 *
 * Defines two virtual functions for packet routing and forwarding.  The first,
 * RouteOutput(), is used for locally originated packets, and the second,
 * RouteInput(), is used for forwarding and/or delivering received packets.
 * Also defines the signatures of four callbacks used in RouteInput().
 *
 */
class Ipv4RoutingProtocol : public Object
{
  public:
    /**
     * @brief Get the type ID.
     * @return the object TypeId
     */
    static TypeId GetTypeId();

    /// Callback for unicast packets to be forwarded
    typedef Callback<void, Ptr<Ipv4Route>, Ptr<const Packet>, const Ipv4Header&>
        UnicastForwardCallback;

    /// Callback for multicast packets to be forwarded
    typedef Callback<void, Ptr<Ipv4MulticastRoute>, Ptr<const Packet>, const Ipv4Header&>
        MulticastForwardCallback;

    /// Callback for packets to be locally delivered
    typedef Callback<void, Ptr<const Packet>, const Ipv4Header&, uint32_t> LocalDeliverCallback;

    /// Callback for routing errors (e.g., no route found)
    typedef Callback<void, Ptr<const Packet>, const Ipv4Header&, Socket::SocketErrno> ErrorCallback;

    /**
     * @brief Query routing cache for an existing route, for an outbound packet
     *
     * This lookup is used by transport protocols.  It does not cause any
     * packet to be forwarded, and is synchronous.  Can be used for
     * multicast or unicast.  The Linux equivalent is ip_route_output()
     *
     * The header input parameter may have an uninitialized value
     * for the source address, but the destination address should always be
     * properly set by the caller.
     *
     * @param p packet to be routed.  Note that this method may modify the packet.
     *          Callers may also pass in a null pointer.
     * @param header input parameter (used to form key to search for the route)
     * @param oif Output interface Netdevice.  May be zero, or may be bound via
     *            socket options to a particular output interface.
     * @param sockerr Output parameter; socket errno
     *
     * @returns a code that indicates what happened in the lookup
     */
    virtual Ptr<Ipv4Route> RouteOutput(Ptr<Packet> p,
                                       const Ipv4Header& header,
                                       Ptr<NetDevice> oif,
                                       Socket::SocketErrno& sockerr) = 0;

    /**
     * @brief Route an input packet (to be forwarded or locally delivered)
     *
     * This lookup is used in the forwarding process.  The packet is
     * handed over to the Ipv4RoutingProtocol, and will get forwarded onward
     * by one of the callbacks.  The Linux equivalent is ip_route_input().
     * There are four valid outcomes, and a matching callbacks to handle each.
     *
     * @param p received packet
     * @param header input parameter used to form a search key for a route
     * @param idev Pointer to ingress network device
     * @param ucb Callback for the case in which the packet is to be forwarded
     *            as unicast
     * @param mcb Callback for the case in which the packet is to be forwarded
     *            as multicast
     * @param lcb Callback for the case in which the packet is to be locally
     *            delivered
     * @param ecb Callback to call if there is an error in forwarding
     * @returns true if the Ipv4RoutingProtocol takes responsibility for
     *          forwarding or delivering the packet, false otherwise
     */
    virtual bool RouteInput(Ptr<const Packet> p,
                            const Ipv4Header& header,
                            Ptr<const NetDevice> idev,
                            const UnicastForwardCallback& ucb,
                            const MulticastForwardCallback& mcb,
                            const LocalDeliverCallback& lcb,
                            const ErrorCallback& ecb) = 0;

    /**
     * @param interface the index of the interface we are being notified about
     *
     * Protocols are expected to implement this method to be notified of the state change of
     * an interface in a node.
     */
    virtual void NotifyInterfaceUp(uint32_t interface) = 0;
    /**
     * @param interface the index of the interface we are being notified about
     *
     * Protocols are expected to implement this method to be notified of the state change of
     * an interface in a node.
     */
    virtual void NotifyInterfaceDown(uint32_t interface) = 0;

    /**
     * @param interface the index of the interface we are being notified about
     * @param address a new address being added to an interface
     *
     * Protocols are expected to implement this method to be notified whenever
     * a new address is added to an interface. Typically used to add a 'network route' on an
     * interface. Can be invoked on an up or down interface.
     */
    virtual void NotifyAddAddress(uint32_t interface, Ipv4InterfaceAddress address) = 0;

    /**
     * @param interface the index of the interface we are being notified about
     * @param address a new address being added to an interface
     *
     * Protocols are expected to implement this method to be notified whenever
     * a new address is removed from an interface. Typically used to remove the 'network route' of
     * an interface. Can be invoked on an up or down interface.
     */
    virtual void NotifyRemoveAddress(uint32_t interface, Ipv4InterfaceAddress address) = 0;

    /**
     * @param ipv4 the ipv4 object this routing protocol is being associated with
     *
     * Typically, invoked directly or indirectly from ns3::Ipv4::SetRoutingProtocol
     */
    virtual void SetIpv4(Ptr<Ipv4> ipv4) = 0;

    /**
     * @brief Print the Routing Table entries
     *
     * @param stream The ostream the Routing table is printed to
     * @param unit The time unit to be used in the report
     */
    virtual void PrintRoutingTable(Ptr<OutputStreamWrapper> stream,
                                   Time::Unit unit = Time::S) const = 0;
};

} // namespace ns3

#endif /* IPV4_ROUTING_PROTOCOL_H */
