mirror of https://github.com/torvalds/linux.git
ovpn: implement keepalive mechanism
OpenVPN supports configuring a periodic keepalive packet. message to allow the remote endpoint detect link failures. This change implements the keepalive sending and timer expiring logic. Signed-off-by: Antonio Quartulli <antonio@openvpn.net> Link: https://patch.msgid.link/20250415-b4-ovpn-v26-16-577f6097b964@openvpn.net Reviewed-by: Sabrina Dubroca <sd@queasysnail.net> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
a3aaef8cd1
commit
3ecfd9349f
|
|
@ -27,6 +27,33 @@
|
||||||
#include "skb.h"
|
#include "skb.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
|
const unsigned char ovpn_keepalive_message[OVPN_KEEPALIVE_SIZE] = {
|
||||||
|
0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb,
|
||||||
|
0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ovpn_is_keepalive - check if skb contains a keepalive message
|
||||||
|
* @skb: packet to check
|
||||||
|
*
|
||||||
|
* Assumes that the first byte of skb->data is defined.
|
||||||
|
*
|
||||||
|
* Return: true if skb contains a keepalive or false otherwise
|
||||||
|
*/
|
||||||
|
static bool ovpn_is_keepalive(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
if (*skb->data != ovpn_keepalive_message[0])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (skb->len != OVPN_KEEPALIVE_SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!pskb_may_pull(skb, OVPN_KEEPALIVE_SIZE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !memcmp(skb->data, ovpn_keepalive_message, OVPN_KEEPALIVE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Called after decrypt to write the IP packet to the device.
|
/* Called after decrypt to write the IP packet to the device.
|
||||||
* This method is expected to manage/free the skb.
|
* This method is expected to manage/free the skb.
|
||||||
*/
|
*/
|
||||||
|
|
@ -101,6 +128,9 @@ void ovpn_decrypt_post(void *data, int ret)
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* keep track of last received authenticated packet for keepalive */
|
||||||
|
WRITE_ONCE(peer->last_recv, ktime_get_real_seconds());
|
||||||
|
|
||||||
/* point to encapsulated IP packet */
|
/* point to encapsulated IP packet */
|
||||||
__skb_pull(skb, payload_offset);
|
__skb_pull(skb, payload_offset);
|
||||||
|
|
||||||
|
|
@ -118,6 +148,15 @@ void ovpn_decrypt_post(void *data, int ret)
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ovpn_is_keepalive(skb)) {
|
||||||
|
net_dbg_ratelimited("%s: ping received from peer %u\n",
|
||||||
|
netdev_name(peer->ovpn->dev),
|
||||||
|
peer->id);
|
||||||
|
/* we drop the packet, but this is not a failure */
|
||||||
|
consume_skb(skb);
|
||||||
|
goto drop_nocount;
|
||||||
|
}
|
||||||
|
|
||||||
net_info_ratelimited("%s: unsupported protocol received from peer %u\n",
|
net_info_ratelimited("%s: unsupported protocol received from peer %u\n",
|
||||||
netdev_name(peer->ovpn->dev), peer->id);
|
netdev_name(peer->ovpn->dev), peer->id);
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
@ -143,11 +182,12 @@ void ovpn_decrypt_post(void *data, int ret)
|
||||||
drop:
|
drop:
|
||||||
if (unlikely(skb))
|
if (unlikely(skb))
|
||||||
dev_dstats_rx_dropped(peer->ovpn->dev);
|
dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||||
|
kfree_skb(skb);
|
||||||
|
drop_nocount:
|
||||||
if (likely(peer))
|
if (likely(peer))
|
||||||
ovpn_peer_put(peer);
|
ovpn_peer_put(peer);
|
||||||
if (likely(ks))
|
if (likely(ks))
|
||||||
ovpn_crypto_key_slot_put(ks);
|
ovpn_crypto_key_slot_put(ks);
|
||||||
kfree_skb(skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX path entry point: decrypt packet and forward it to the device */
|
/* RX path entry point: decrypt packet and forward it to the device */
|
||||||
|
|
@ -221,6 +261,8 @@ void ovpn_encrypt_post(void *data, int ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len);
|
ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len);
|
||||||
|
/* keep track of last sent packet for keepalive */
|
||||||
|
WRITE_ONCE(peer->last_sent, ktime_get_real_seconds());
|
||||||
/* skb passed down the stack - don't free it */
|
/* skb passed down the stack - don't free it */
|
||||||
skb = NULL;
|
skb = NULL;
|
||||||
err_unlock:
|
err_unlock:
|
||||||
|
|
@ -346,3 +388,37 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
kfree_skb_list(skb);
|
kfree_skb_list(skb);
|
||||||
return NET_XMIT_DROP;
|
return NET_XMIT_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ovpn_xmit_special - encrypt and transmit an out-of-band message to peer
|
||||||
|
* @peer: peer to send the message to
|
||||||
|
* @data: message content
|
||||||
|
* @len: message length
|
||||||
|
*
|
||||||
|
* Assumes that caller holds a reference to peer, which will be
|
||||||
|
* passed to ovpn_send()
|
||||||
|
*/
|
||||||
|
void ovpn_xmit_special(struct ovpn_peer *peer, const void *data,
|
||||||
|
const unsigned int len)
|
||||||
|
{
|
||||||
|
struct ovpn_priv *ovpn;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
ovpn = peer->ovpn;
|
||||||
|
if (unlikely(!ovpn)) {
|
||||||
|
ovpn_peer_put(peer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = alloc_skb(256 + len, GFP_ATOMIC);
|
||||||
|
if (unlikely(!skb)) {
|
||||||
|
ovpn_peer_put(peer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb_reserve(skb, 128);
|
||||||
|
skb->priority = TC_PRIO_BESTEFFORT;
|
||||||
|
__skb_put_data(skb, data, len);
|
||||||
|
|
||||||
|
ovpn_send(ovpn, skb, peer);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,14 @@
|
||||||
/* max padding required by encryption */
|
/* max padding required by encryption */
|
||||||
#define OVPN_MAX_PADDING 16
|
#define OVPN_MAX_PADDING 16
|
||||||
|
|
||||||
|
#define OVPN_KEEPALIVE_SIZE 16
|
||||||
|
extern const unsigned char ovpn_keepalive_message[OVPN_KEEPALIVE_SIZE];
|
||||||
|
|
||||||
netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev);
|
netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||||
|
|
||||||
void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb);
|
void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb);
|
||||||
|
void ovpn_xmit_special(struct ovpn_peer *peer, const void *data,
|
||||||
|
const unsigned int len);
|
||||||
|
|
||||||
void ovpn_encrypt_post(void *data, int ret);
|
void ovpn_encrypt_post(void *data, int ret);
|
||||||
void ovpn_decrypt_post(void *data, int ret);
|
void ovpn_decrypt_post(void *data, int ret);
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,7 @@ static int ovpn_newlink(struct net_device *dev,
|
||||||
ovpn->dev = dev;
|
ovpn->dev = dev;
|
||||||
ovpn->mode = mode;
|
ovpn->mode = mode;
|
||||||
spin_lock_init(&ovpn->lock);
|
spin_lock_init(&ovpn->lock);
|
||||||
|
INIT_DELAYED_WORK(&ovpn->keepalive_work, ovpn_peer_keepalive_work);
|
||||||
|
|
||||||
/* Set carrier explicitly after registration, this way state is
|
/* Set carrier explicitly after registration, this way state is
|
||||||
* clearly defined.
|
* clearly defined.
|
||||||
|
|
@ -191,6 +192,7 @@ static void ovpn_dellink(struct net_device *dev, struct list_head *head)
|
||||||
{
|
{
|
||||||
struct ovpn_priv *ovpn = netdev_priv(dev);
|
struct ovpn_priv *ovpn = netdev_priv(dev);
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&ovpn->keepalive_work);
|
||||||
ovpn_peers_free(ovpn, NULL, OVPN_DEL_PEER_REASON_TEARDOWN);
|
ovpn_peers_free(ovpn, NULL, OVPN_DEL_PEER_REASON_TEARDOWN);
|
||||||
unregister_netdevice_queue(dev, head);
|
unregister_netdevice_queue(dev, head);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ struct ovpn_peer_collection {
|
||||||
* @peers: data structures holding multi-peer references
|
* @peers: data structures holding multi-peer references
|
||||||
* @peer: in P2P mode, this is the only remote peer
|
* @peer: in P2P mode, this is the only remote peer
|
||||||
* @gro_cells: pointer to the Generic Receive Offload cell
|
* @gro_cells: pointer to the Generic Receive Offload cell
|
||||||
|
* @keepalive_work: struct used to schedule keepalive periodic job
|
||||||
*/
|
*/
|
||||||
struct ovpn_priv {
|
struct ovpn_priv {
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
|
@ -48,6 +49,7 @@ struct ovpn_priv {
|
||||||
struct ovpn_peer_collection *peers;
|
struct ovpn_peer_collection *peers;
|
||||||
struct ovpn_peer __rcu *peer;
|
struct ovpn_peer __rcu *peer;
|
||||||
struct gro_cells gro_cells;
|
struct gro_cells gro_cells;
|
||||||
|
struct delayed_work keepalive_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _NET_OVPN_OVPNSTRUCT_H_ */
|
#endif /* _NET_OVPN_OVPNSTRUCT_H_ */
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,52 @@ static void unlock_ovpn(struct ovpn_priv *ovpn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ovpn_peer_keepalive_set - configure keepalive values for peer
|
||||||
|
* @peer: the peer to configure
|
||||||
|
* @interval: outgoing keepalive interval
|
||||||
|
* @timeout: incoming keepalive timeout
|
||||||
|
*/
|
||||||
|
void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)
|
||||||
|
{
|
||||||
|
time64_t now = ktime_get_real_seconds();
|
||||||
|
|
||||||
|
netdev_dbg(peer->ovpn->dev,
|
||||||
|
"scheduling keepalive for peer %u: interval=%u timeout=%u\n",
|
||||||
|
peer->id, interval, timeout);
|
||||||
|
|
||||||
|
peer->keepalive_interval = interval;
|
||||||
|
WRITE_ONCE(peer->last_sent, now);
|
||||||
|
peer->keepalive_xmit_exp = now + interval;
|
||||||
|
|
||||||
|
peer->keepalive_timeout = timeout;
|
||||||
|
WRITE_ONCE(peer->last_recv, now);
|
||||||
|
peer->keepalive_recv_exp = now + timeout;
|
||||||
|
|
||||||
|
/* now that interval and timeout have been changed, kick
|
||||||
|
* off the worker so that the next delay can be recomputed
|
||||||
|
*/
|
||||||
|
mod_delayed_work(system_wq, &peer->ovpn->keepalive_work, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ovpn_peer_keepalive_send - periodic worker sending keepalive packets
|
||||||
|
* @work: pointer to the work member of the related peer object
|
||||||
|
*
|
||||||
|
* NOTE: the reference to peer is not dropped because it gets inherited
|
||||||
|
* by ovpn_xmit_special()
|
||||||
|
*/
|
||||||
|
static void ovpn_peer_keepalive_send(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ovpn_peer *peer = container_of(work, struct ovpn_peer,
|
||||||
|
keepalive_work);
|
||||||
|
|
||||||
|
local_bh_disable();
|
||||||
|
ovpn_xmit_special(peer, ovpn_keepalive_message,
|
||||||
|
sizeof(ovpn_keepalive_message));
|
||||||
|
local_bh_enable();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ovpn_peer_new - allocate and initialize a new peer object
|
* ovpn_peer_new - allocate and initialize a new peer object
|
||||||
* @ovpn: the openvpn instance inside which the peer should be created
|
* @ovpn: the openvpn instance inside which the peer should be created
|
||||||
|
|
@ -65,6 +111,7 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id)
|
||||||
kref_init(&peer->refcount);
|
kref_init(&peer->refcount);
|
||||||
ovpn_peer_stats_init(&peer->vpn_stats);
|
ovpn_peer_stats_init(&peer->vpn_stats);
|
||||||
ovpn_peer_stats_init(&peer->link_stats);
|
ovpn_peer_stats_init(&peer->link_stats);
|
||||||
|
INIT_WORK(&peer->keepalive_work, ovpn_peer_keepalive_send);
|
||||||
|
|
||||||
ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL);
|
ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -948,3 +995,162 @@ void ovpn_peers_free(struct ovpn_priv *ovpn, struct sock *sk,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
|
||||||
|
time64_t now,
|
||||||
|
struct llist_head *release_list)
|
||||||
|
{
|
||||||
|
time64_t last_recv, last_sent, next_run1, next_run2;
|
||||||
|
unsigned long timeout, interval;
|
||||||
|
bool expired;
|
||||||
|
|
||||||
|
spin_lock_bh(&peer->lock);
|
||||||
|
/* we expect both timers to be configured at the same time,
|
||||||
|
* therefore bail out if either is not set
|
||||||
|
*/
|
||||||
|
if (!peer->keepalive_timeout || !peer->keepalive_interval) {
|
||||||
|
spin_unlock_bh(&peer->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for peer timeout */
|
||||||
|
expired = false;
|
||||||
|
timeout = peer->keepalive_timeout;
|
||||||
|
last_recv = READ_ONCE(peer->last_recv);
|
||||||
|
if (now < last_recv + timeout) {
|
||||||
|
peer->keepalive_recv_exp = last_recv + timeout;
|
||||||
|
next_run1 = peer->keepalive_recv_exp;
|
||||||
|
} else if (peer->keepalive_recv_exp > now) {
|
||||||
|
next_run1 = peer->keepalive_recv_exp;
|
||||||
|
} else {
|
||||||
|
expired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expired) {
|
||||||
|
/* peer is dead -> kill it and move on */
|
||||||
|
spin_unlock_bh(&peer->lock);
|
||||||
|
netdev_dbg(peer->ovpn->dev, "peer %u expired\n",
|
||||||
|
peer->id);
|
||||||
|
ovpn_peer_remove(peer, OVPN_DEL_PEER_REASON_EXPIRED,
|
||||||
|
release_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for peer keepalive */
|
||||||
|
expired = false;
|
||||||
|
interval = peer->keepalive_interval;
|
||||||
|
last_sent = READ_ONCE(peer->last_sent);
|
||||||
|
if (now < last_sent + interval) {
|
||||||
|
peer->keepalive_xmit_exp = last_sent + interval;
|
||||||
|
next_run2 = peer->keepalive_xmit_exp;
|
||||||
|
} else if (peer->keepalive_xmit_exp > now) {
|
||||||
|
next_run2 = peer->keepalive_xmit_exp;
|
||||||
|
} else {
|
||||||
|
expired = true;
|
||||||
|
next_run2 = now + interval;
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&peer->lock);
|
||||||
|
|
||||||
|
if (expired) {
|
||||||
|
/* a keepalive packet is required */
|
||||||
|
netdev_dbg(peer->ovpn->dev,
|
||||||
|
"sending keepalive to peer %u\n",
|
||||||
|
peer->id);
|
||||||
|
if (schedule_work(&peer->keepalive_work))
|
||||||
|
ovpn_peer_hold(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_run1 < next_run2)
|
||||||
|
return next_run1;
|
||||||
|
|
||||||
|
return next_run2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static time64_t ovpn_peer_keepalive_work_mp(struct ovpn_priv *ovpn,
|
||||||
|
time64_t now,
|
||||||
|
struct llist_head *release_list)
|
||||||
|
{
|
||||||
|
time64_t tmp_next_run, next_run = 0;
|
||||||
|
struct hlist_node *tmp;
|
||||||
|
struct ovpn_peer *peer;
|
||||||
|
int bkt;
|
||||||
|
|
||||||
|
lockdep_assert_held(&ovpn->lock);
|
||||||
|
|
||||||
|
hash_for_each_safe(ovpn->peers->by_id, bkt, tmp, peer, hash_entry_id) {
|
||||||
|
tmp_next_run = ovpn_peer_keepalive_work_single(peer, now,
|
||||||
|
release_list);
|
||||||
|
if (!tmp_next_run)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* the next worker run will be scheduled based on the shortest
|
||||||
|
* required interval across all peers
|
||||||
|
*/
|
||||||
|
if (!next_run || tmp_next_run < next_run)
|
||||||
|
next_run = tmp_next_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
static time64_t ovpn_peer_keepalive_work_p2p(struct ovpn_priv *ovpn,
|
||||||
|
time64_t now,
|
||||||
|
struct llist_head *release_list)
|
||||||
|
{
|
||||||
|
struct ovpn_peer *peer;
|
||||||
|
time64_t next_run = 0;
|
||||||
|
|
||||||
|
lockdep_assert_held(&ovpn->lock);
|
||||||
|
|
||||||
|
peer = rcu_dereference_protected(ovpn->peer,
|
||||||
|
lockdep_is_held(&ovpn->lock));
|
||||||
|
if (peer)
|
||||||
|
next_run = ovpn_peer_keepalive_work_single(peer, now,
|
||||||
|
release_list);
|
||||||
|
|
||||||
|
return next_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ovpn_peer_keepalive_work - run keepalive logic on each known peer
|
||||||
|
* @work: pointer to the work member of the related ovpn object
|
||||||
|
*
|
||||||
|
* Each peer has two timers (if configured):
|
||||||
|
* 1. peer timeout: when no data is received for a certain interval,
|
||||||
|
* the peer is considered dead and it gets killed.
|
||||||
|
* 2. peer keepalive: when no data is sent to a certain peer for a
|
||||||
|
* certain interval, a special 'keepalive' packet is explicitly sent.
|
||||||
|
*
|
||||||
|
* This function iterates across the whole peer collection while
|
||||||
|
* checking the timers described above.
|
||||||
|
*/
|
||||||
|
void ovpn_peer_keepalive_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ovpn_priv *ovpn = container_of(work, struct ovpn_priv,
|
||||||
|
keepalive_work.work);
|
||||||
|
time64_t next_run = 0, now = ktime_get_real_seconds();
|
||||||
|
LLIST_HEAD(release_list);
|
||||||
|
|
||||||
|
spin_lock_bh(&ovpn->lock);
|
||||||
|
switch (ovpn->mode) {
|
||||||
|
case OVPN_MODE_MP:
|
||||||
|
next_run = ovpn_peer_keepalive_work_mp(ovpn, now,
|
||||||
|
&release_list);
|
||||||
|
break;
|
||||||
|
case OVPN_MODE_P2P:
|
||||||
|
next_run = ovpn_peer_keepalive_work_p2p(ovpn, now,
|
||||||
|
&release_list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prevent rearming if the interface is being destroyed */
|
||||||
|
if (next_run > 0 &&
|
||||||
|
READ_ONCE(ovpn->dev->reg_state) == NETREG_REGISTERED) {
|
||||||
|
netdev_dbg(ovpn->dev,
|
||||||
|
"scheduling keepalive work: now=%llu next_run=%llu delta=%llu\n",
|
||||||
|
next_run, now, next_run - now);
|
||||||
|
schedule_delayed_work(&ovpn->keepalive_work,
|
||||||
|
(next_run - now) * HZ);
|
||||||
|
}
|
||||||
|
unlock_ovpn(ovpn, &release_list);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,20 @@
|
||||||
* @crypto: the crypto configuration (ciphers, keys, etc..)
|
* @crypto: the crypto configuration (ciphers, keys, etc..)
|
||||||
* @dst_cache: cache for dst_entry used to send to peer
|
* @dst_cache: cache for dst_entry used to send to peer
|
||||||
* @bind: remote peer binding
|
* @bind: remote peer binding
|
||||||
|
* @keepalive_interval: seconds after which a new keepalive should be sent
|
||||||
|
* @keepalive_xmit_exp: future timestamp when next keepalive should be sent
|
||||||
|
* @last_sent: timestamp of the last successfully sent packet
|
||||||
|
* @keepalive_timeout: seconds after which an inactive peer is considered dead
|
||||||
|
* @keepalive_recv_exp: future timestamp when the peer should expire
|
||||||
|
* @last_recv: timestamp of the last authenticated received packet
|
||||||
* @vpn_stats: per-peer in-VPN TX/RX stats
|
* @vpn_stats: per-peer in-VPN TX/RX stats
|
||||||
* @link_stats: per-peer link/transport TX/RX stats
|
* @link_stats: per-peer link/transport TX/RX stats
|
||||||
* @delete_reason: why peer was deleted (i.e. timeout, transport error, ..)
|
* @delete_reason: why peer was deleted (i.e. timeout, transport error, ..)
|
||||||
* @lock: protects binding to peer (bind)
|
* @lock: protects binding to peer (bind) and keepalive* fields
|
||||||
* @refcount: reference counter
|
* @refcount: reference counter
|
||||||
* @rcu: used to free peer in an RCU safe way
|
* @rcu: used to free peer in an RCU safe way
|
||||||
* @release_entry: entry for the socket release list
|
* @release_entry: entry for the socket release list
|
||||||
|
* @keepalive_work: used to schedule keepalive sending
|
||||||
*/
|
*/
|
||||||
struct ovpn_peer {
|
struct ovpn_peer {
|
||||||
struct ovpn_priv *ovpn;
|
struct ovpn_priv *ovpn;
|
||||||
|
|
@ -91,13 +98,20 @@ struct ovpn_peer {
|
||||||
struct ovpn_crypto_state crypto;
|
struct ovpn_crypto_state crypto;
|
||||||
struct dst_cache dst_cache;
|
struct dst_cache dst_cache;
|
||||||
struct ovpn_bind __rcu *bind;
|
struct ovpn_bind __rcu *bind;
|
||||||
|
unsigned long keepalive_interval;
|
||||||
|
unsigned long keepalive_xmit_exp;
|
||||||
|
time64_t last_sent;
|
||||||
|
unsigned long keepalive_timeout;
|
||||||
|
unsigned long keepalive_recv_exp;
|
||||||
|
time64_t last_recv;
|
||||||
struct ovpn_peer_stats vpn_stats;
|
struct ovpn_peer_stats vpn_stats;
|
||||||
struct ovpn_peer_stats link_stats;
|
struct ovpn_peer_stats link_stats;
|
||||||
enum ovpn_del_peer_reason delete_reason;
|
enum ovpn_del_peer_reason delete_reason;
|
||||||
spinlock_t lock; /* protects bind */
|
spinlock_t lock; /* protects bind and keepalive* */
|
||||||
struct kref refcount;
|
struct kref refcount;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
struct llist_node release_entry;
|
struct llist_node release_entry;
|
||||||
|
struct work_struct keepalive_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -136,4 +150,7 @@ struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
|
||||||
bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
|
bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
|
||||||
struct ovpn_peer *peer);
|
struct ovpn_peer *peer);
|
||||||
|
|
||||||
|
void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout);
|
||||||
|
void ovpn_peer_keepalive_work(struct work_struct *work);
|
||||||
|
|
||||||
#endif /* _NET_OVPN_OVPNPEER_H_ */
|
#endif /* _NET_OVPN_OVPNPEER_H_ */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue