/*
 * ipsec_itf.c: IPSec dedicated interface type
 *
 * Copyright (c) 2020 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.
 */

#ifndef __IPSEC_ITF_H__
#define __IPSEC_ITF_H__

#include <vnet/tunnel/tunnel.h>
#include <vnet/ipsec/ipsec_sa.h>

/**
 * @brief A dedicated IPSec interface type
 *
 * In order to support route based VPNs one needs 3 elements: an interface,
 * for routing to resolve routes through, an SA from the peer to describe
 * security, and encap, to describe how to reach the peer. There are two
 * ways one could model this:
 *
 *  interface + encap + SA = (interface + encap) + SA =
 *          ipip-interface + SA transport mode
 *
 * or
 *
 *  interface + encap + SA = interface + (encap + SA) =
 *          IPSec-interface + SA tunnel mode
 *
 * It's a question of where you add the parenthesis, from the perspective
 * of the external user the effect is identical.
 *
 * The IPsec interface serves as the encap-free interface to be used
 * in conjunction with an encap-describing tunnel mode SA.
 *
 * VPP supports both models, which modelshould you pick?
 * A route based VPN could impose 0, 1 or 2 encaps. the support matrix for
 * these use cases is:
 *
 *        |  0  |  1  |  2  |
 *  --------------------------
 *  ipip  |  N  |  Y  |  Y  |
 *  ipsec |  P  |  Y  |  P  |
 *
 * Where P = potentially.
 * ipsec could potnetially support 0 encap (i.e. transport mode) since neither
 * the interface nor the SA *requires* encap. However, for a route beased VPN
 * to use transport mode is probably wrong since one shouldn't use thransport
 * mode for transit traffic, since without encap it is not guaranteed to return.
 * ipsec could potnetially support 2 encaps, but that would require the SA to
 * describe both, something it does not do at this time.
 *
 * ipsec currently does not support:
 *   - multipoint interfaces
 * but this is only because it is not yet implemented, rather than it cannot
 * be done.
 *
 * Internally the difference is that the midchain adjacency for the IPSec
 * interface has no associated encap (whereas for an ipip tunnel it describes
 * the peer). Consequently, features on the output arc see packets without
 * any encap. Since the protecting SAs are in tunnel mode,
 * they apply the encap. The midchain adj is stacked only once the proctecting
 * SA is known, since only then is the peer known. Otherwise the VLIB graph
 * nodes used are the same:
 *    (routing) --> ipX-michain --> espX-encrypt --> adj-midchain-tx --> (routing)
 * where X = 4 or 6.
 *
 * Some benefits to the ipsec interface:
 *   - it is slightly more efficient since the encapsulating IP header has
 *     its checksum updated only once.
 *   - even when the interface is admin up traffic cannot be sent to a peer
 *     unless the SA is available (since it's the SA that determines the
 *     encap). With ipip interfaces a client must use the admin state to
 *     prevent sending until the SA is available.
 *
 * The best recommendations i can make are:
 *   - pick a model that supports your use case
 *   - make sure any other features you wish to use are supported by the model
 *   - choose the model that best fits your control plane's model.
 *
 *
 * gun reloaded, fire away.
 */
typedef struct ipsec_itf_t_
{
  tunnel_mode_t ii_mode;
  int ii_user_instance;
  u32 ii_sw_if_index;
} __clib_packed ipsec_itf_t;


extern int ipsec_itf_create (u32 user_instance,
			     tunnel_mode_t mode, u32 * sw_if_indexp);
extern int ipsec_itf_delete (u32 sw_if_index);

extern void ipsec_itf_adj_stack (adj_index_t ai, u32 sai);
extern void ipsec_itf_adj_unstack (adj_index_t ai);

extern u8 *format_ipsec_itf (u8 * s, va_list * a);

extern ipsec_itf_t *ipsec_itf_get (index_t ii);

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */

#endif