aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h
blob: b11841b690147195e52969f09460b77dbcd9cb71 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <hicn/transport/core/forwarder_interface.h>
#include <hicn/transport/core/prefix.h>
#include <hicn/transport/core/udp_socket_connector.h>

#include <deque>

namespace transport {

namespace core {

class HicnForwarderInterface
    : public ForwarderInterface<HicnForwarderInterface, UdpSocketConnector> {
  static constexpr uint8_t ack_code = 0xc2;
  static constexpr uint8_t nack_code = 0xc3;

 public:
  union addressLight {
    uint32_t ipv4;
    struct in6_addr ipv6;
  };

  struct route_to_self_command {
    uint8_t messageType;
    uint8_t commandID;
    uint16_t length;
    uint32_t seqNum;
    char symbolicOrConnid[16];
    union addressLight address;
    uint16_t cost;
    uint8_t addressType;
    uint8_t len;
  };

  using route_to_self_command = struct route_to_self_command;
  using ConnectorType = UdpSocketConnector;

  HicnForwarderInterface(UdpSocketConnector &connector);

  ~HicnForwarderInterface();

  void connect(bool is_consumer);

  void registerRoute(Prefix &prefix);

  std::uint16_t getMtu() { return interface_mtu; }

  TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl(
      const uint8_t *message) {
    return message[0] == ack_code || message[0] == nack_code;
  }

  TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl(
      Packet::MemBufPtr &&packet_buffer) {
    if (packet_buffer->data()[0] == nack_code) {
      throw errors::RuntimeException(
          "Received Nack message from hicn light forwarder.");
    }
  }

  void closeConnection();

 private:
  static constexpr std::uint16_t interface_mtu = 1500;
};

}  // namespace core

}  // namespace transport
ackground-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Defines the interface all connections use to communicate with the forwarder.
 */

/**
 * I/O is built around a callback structure.  The connection table contains an
 * operations structure built around function pointers.  These allow the
 * connection table to be agnostic about underlying connections.
 */

#ifndef io_h
#define io_h

#include <src/core/message.h>
#include <src/core/ticks.h>
#include <src/io/addressPair.h>
#include <src/utils/address.h>

// packet types for probing
#define PACKET_TYPE_PROBE_REQUEST 5
#define PACKET_TYPE_PROBE_REPLY 6

struct io_ops;
typedef struct io_ops IoOperations;

/**
 * @typedef IoOperations
 * @abstract The IO Operations structure abstracts an connection's properties
 * and send() method
 * @constant context Implementation specific opaque data, passed back on each
 * call
 * @constant send function pointer to send a message, does not destroy the
 * message
 * @constant getRemoteAddress function pointer to return the "to" address
 * associated with the connection. Some connections might not have a specific
 * peer, such as multicast, where its the group address.
 * @constant isUp test if the connection is up, ready to send a message.
 * @constant isLocal test if the connection is local to the host.
 * @constant getConnectionId returns the hicn-light id for the connection.
 * @constant destroy releases a refernce count on the connection and possibly
 * destroys the connection.
 * @constant class A unique identifier for each class that instantiates
 * IoOperations.
 * @constant getConnectionType Returns the type of connection (TCP, UDP, L2,
 * etc.) of the underlying connection.
 * @discussion <#Discussion#>
 */
struct io_ops {
  void *closure;
  bool (*send)(IoOperations *ops, const Address *nexthop, Message *message);
  bool (*sendCommandResponse)(IoOperations *ops, struct iovec *message);
  const Address *(*getRemoteAddress)(const IoOperations *ops);
  const AddressPair *(*getAddressPair)(const IoOperations *ops);
  bool (*isUp)(const IoOperations *ops);
  bool (*isLocal)(const IoOperations *ops);
  unsigned (*getConnectionId)(const IoOperations *ops);
  void (*destroy)(IoOperations **opsPtr);
  const void *(*class)(const IoOperations *ops);
  list_connections_type (*getConnectionType)(const IoOperations *ops);
  Ticks (*sendProbe)(IoOperations *ops, unsigned probeType, uint8_t *message);
};

/**
 * Returns the closure of the interface
 *
 * The creator of the closure sets this parameter to store its state.
 *
 * @param [in] ops A concrete instance of the interface
 *
 * @return The value set by the concrete instance of the interface.
 *
 * Example:
 * @clode
 * {

 * }
 * @endcode
 */
void *ioOperations_GetClosure(const IoOperations *ops);

/**
 * Release all memory related to the interface and implementation
 *
 * This function must release all referenced memory in the concrete
 * implementation and memory related to the IoOperations.  It should NULL the
 * input parameter.
 *
 * @param [in,out] opsPtr Pointer to interface.  Will be NULLed.
 *
 * Example:
 * @code
 *
 *   static void
 *   _etherConnection_InternalRelease(_EtherState *etherConnState)
 *   {
 *      // release internal state of _EtherState
 *   }
 *
 *   static void
 *   _etherConnection_Release(IoOperations **opsPtr)
 *   {
 *      IoOperations *ops = *opsPtr;
 *
 *      _EtherState *etherConnState = (_EtherState *)
 * ioOperations_GetClosure(ops);
 *      _etherConnection_InternalRelease(etherConnState);
 *
 *      parcMemory_Deallocate((void **) &ops);
 *   }
 *
 *   IoOperations *
 *   etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
 * AddressPair *pair)
 *   {
 *      size_t allocationSize = sizeof(_EtherState) + sizeof(IoOperations);
 *      IoOperations *ops = parcMemory_AllocateAndClear(allocationSize);
 *      if (ops) {
 *         // fill in other interface functions
 *         ops->destroy = &_etherConnection_Release;
 *         ops->closure = (uint8_t *) ops + sizeof(IoOperations);
 *
 *         _EtherState *etherConnState = ioOperations_GetClosure(ops);
 *         // fill in Ethernet state
 *      }
 *      return ops;
 *   }
 * @endcode
 */
void ioOperations_Release(IoOperations **opsPtr);

/**
 * Sends the specified Message out this connection
 *
 * The the implementation of send may queue the message, it must acquire a
 * reference to it.
 *
 * @param [in] ops The connection implementation.
 * @param [in] nexthop On multiple access networks, this parameter might be
 * used, usually NULL.
 * @param [in] message The message to send.  If the message will be queued, it
 * will be acquired.
 *
 * @return true The message was sent or queued
 * @retrun false An error occured and the message will not be sent or queued
 *
 * Example:
 * @code
 * {
 *     if (ioOperations_IsUp(conn->ops)) {
 *        return ioOperations_Send(conn->ops, NULL, message);
 *     }
 * }
 * @endcode
 */
bool ioOperations_Send(IoOperations *ops, const Address *nexthop,
                       Message *message);

bool ioOperations_SendCommandResponse(IoOperations *ops,
                       struct iovec *message);

/**
 * A connection is made up of a local and a remote address.  This function
 * returns the remote address.
 *
 * Represents the destination endpoint of the communication.
 *
 * @param [in] ops The connection implementation.
 *
 * @return non-null The remote address
 * @return null The connection does not have a remote address
 *
 * Example:
 * @code
 * {
 *    Address *local =  addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
 * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
 * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
 * addressPair_Create(local, remote); IoOperations *ops =
 * etherConnection_Create(forwarder, ether, pair);
 *
 *    const Address *test = ioOperations_GetRemoteAddress(ops);
 *    parcAssertTrue(addressEquals(test, remote), "Wrong remote address");
 *    ioOperations_Release(&ops);
 *    addressPair_Release(&pair);
 *    addressDestroy(&local);
 *    addressDestroy(&remote);
 * }
 * @endcode
 */
const Address *ioOperations_GetRemoteAddress(const IoOperations *ops);

/**
 * A connection is made up of a local and a remote address.  This function
 * returns the address pair.
 *
 * Represents the destination endpoint of the communication.
 *
 * @param [in] ops The connection implementation.
 *
 * @return non-null The address pair
 * @return null An error.
 *
 * Example:
 * @code
 * {
 *    Address *local =  addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
 * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
 * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
 * addressPair_Create(local, remote); IoOperations *ops =
 * etherConnection_Create(forwarder, ether, pair);
 *
 *    const AddressPair *test = ioOperations_GetAddressPair(ops);
 *    parcAssertTrue(addressPair(test, pair), "Wrong address pair");
 *    ioOperations_Release(&ops);
 *    addressPair_Release(&pair);
 *    addressDestroy(&local);
 *    addressDestroy(&remote);
 * }
 * @endcode
 */
const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops);

/**
 * Returns true if the underlying connection is in operation
 *
 * An UP connection is able to send and receive packets. If a subsystem needs to
 * take actions when a connection goes UP or DOWN, it should subscribe as a
 * Missive listener.
 *
 * @param [in] ops The connection implementation.
 *
 * @return true The connection is UP
 * @return false The connection is not UP
 *
 * Example:
 * @code
 * {
 *     if (ioOperations_IsUp(conn->ops)) {
 *        return ioOperations_Send(conn->ops, NULL, message);
 *     }
 * }
 * @endcode
 */
bool ioOperations_IsUp(const IoOperations *ops);

/**
 * If the remote address is local to this system, returns true
 *
 * Will return true if an INET or INET6 connection is on localhost.  Will return
 * true for AF_UNIX.  An Ethernet connection is not local.
 *
 * @param [in] ops The connection implementation.
 *
 * @return true The remote address is local to the system
 * @return false The remote address is not local
 *
 * Example:
 * @code
 * {
 *     // Is the ingress connection remote?  If so check for non-zero and
 * decrement if (!ioOperations(ingressConnectionOps) { uint8_t hoplimit =
 * message_GetHopLimit(interestMessage); if (hoplimit == 0) {
 *           // error
 *        } else {
 *           hoplimit--;
 *        }
 *        // take actions on hoplimit
 *     }
 * }
 * @endcode
 */
bool ioOperations_IsLocal(const IoOperations *ops);

/**
 * Returns the connection ID represented by this IoOperations in the
 * ConnectionTable.
 *
 * <#Paragraphs Of Explanation#>
 *
 * @param [in] ops The connection implementation.
 *
 * @return number The connection ID in the connection table.
 *
 * Example:
 * @code
 * {
 *     unsigned id = ioOperations_GetConnectionId(ingressIoOps);
 *     const Connection *conn =
 * connectionTable_FindById(forwarder->connectionTable, id);
 * }
 * @endcode
 */
unsigned ioOperations_GetConnectionId(const IoOperations *ops);

/**
 * A pointer that represents the class of the connection
 *
 * Each concrete implementation has a class pointer that is unique to the
 * implementation (not instance). Each implementation is free to choose how to
 * determine the value, so long as it is unique on the system. This is a
 * system-local value.
 *
 * @param [in] ops The connection implementation.
 *
 * @return non-null A pointer value unique to the implementation (not instance).
 *
 * Example:
 * @code
 *   bool
 *   etherConnection_IsInstanceOf(const Connection *conn)
 *   {
 *      bool result = false;
 *      if (conn != NULL) {
 *         IoOperations *ops = connection_GetIoOperations(conn);
 *         const void *class = ioOperations_Class(ops);
 *         result = (class == _etherConnection_Class(ops));
 *      }
 *      return result;
 *   }
 * @endcode
 */
const void *ioOperations_Class(const IoOperations *ops);

/**
 * Returns the transport type of the connection (TCP, UDP, L2, etc.).
 *
 * TCP and AF_UNIX are both stream connections and will both return
 * "Connection_TCP". Ethernet will return "Connection_L2".
 *
 * @param [in] ops The connection implementation.
 *
 * @return Connection_TCP A TCP4, TCP6, or AF_UNIX connection
 * @return Connection_UDP A UDP4 or UDP6 connection
 * @return Connection_L2 An Ethernet connection
 *
 * Example:
 * @code
 * {
 *     ConnectionType type =
 * ioOperations_GetConnectionType(connection_GetIoOperations(connection));
 *     Connection *Conn =
 * Connection_Create(connection_GetConnectionId(connection), localAddress,
 * remoteAddress, type);
 * }
 * @endcode
 */
list_connections_type ioOperations_GetConnectionType(const IoOperations *ops);

Ticks ioOperations_SendProbe(IoOperations *ops, unsigned probeType,
                             uint8_t *message);
#endif  // io_h