162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * INETPEER - A storage for permanent information about peers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Andrey V. Savochkin <saw@msu.ru> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _NET_INETPEER_H 962306a36Sopenharmony_ci#define _NET_INETPEER_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/jiffies.h> 1462306a36Sopenharmony_ci#include <linux/spinlock.h> 1562306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1662306a36Sopenharmony_ci#include <net/ipv6.h> 1762306a36Sopenharmony_ci#include <linux/atomic.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* IPv4 address key for cache lookups */ 2062306a36Sopenharmony_cistruct ipv4_addr_key { 2162306a36Sopenharmony_ci __be32 addr; 2262306a36Sopenharmony_ci int vif; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define INETPEER_MAXKEYSZ (sizeof(struct in6_addr) / sizeof(u32)) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct inetpeer_addr { 2862306a36Sopenharmony_ci union { 2962306a36Sopenharmony_ci struct ipv4_addr_key a4; 3062306a36Sopenharmony_ci struct in6_addr a6; 3162306a36Sopenharmony_ci u32 key[INETPEER_MAXKEYSZ]; 3262306a36Sopenharmony_ci }; 3362306a36Sopenharmony_ci __u16 family; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct inet_peer { 3762306a36Sopenharmony_ci struct rb_node rb_node; 3862306a36Sopenharmony_ci struct inetpeer_addr daddr; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci u32 metrics[RTAX_MAX]; 4162306a36Sopenharmony_ci u32 rate_tokens; /* rate limiting for ICMP */ 4262306a36Sopenharmony_ci u32 n_redirects; 4362306a36Sopenharmony_ci unsigned long rate_last; 4462306a36Sopenharmony_ci /* 4562306a36Sopenharmony_ci * Once inet_peer is queued for deletion (refcnt == 0), following field 4662306a36Sopenharmony_ci * is not available: rid 4762306a36Sopenharmony_ci * We can share memory with rcu_head to help keep inet_peer small. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci union { 5062306a36Sopenharmony_ci struct { 5162306a36Sopenharmony_ci atomic_t rid; /* Frag reception counter */ 5262306a36Sopenharmony_ci }; 5362306a36Sopenharmony_ci struct rcu_head rcu; 5462306a36Sopenharmony_ci }; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* following fields might be frequently dirtied */ 5762306a36Sopenharmony_ci __u32 dtime; /* the time of last use of not referenced entries */ 5862306a36Sopenharmony_ci refcount_t refcnt; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct inet_peer_base { 6262306a36Sopenharmony_ci struct rb_root rb_root; 6362306a36Sopenharmony_ci seqlock_t lock; 6462306a36Sopenharmony_ci int total; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid inet_peer_base_init(struct inet_peer_base *); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid inet_initpeers(void) __init; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define INETPEER_METRICS_NEW (~(u32) 0) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci iaddr->a4.addr = ip; 7662306a36Sopenharmony_ci iaddr->a4.vif = 0; 7762306a36Sopenharmony_ci iaddr->family = AF_INET; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return iaddr->a4.addr; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, 8662306a36Sopenharmony_ci struct in6_addr *in6) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci iaddr->a6 = *in6; 8962306a36Sopenharmony_ci iaddr->family = AF_INET6; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return &iaddr->a6; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* can be called with or without local BH being disabled */ 9862306a36Sopenharmony_cistruct inet_peer *inet_getpeer(struct inet_peer_base *base, 9962306a36Sopenharmony_ci const struct inetpeer_addr *daddr, 10062306a36Sopenharmony_ci int create); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, 10362306a36Sopenharmony_ci __be32 v4daddr, 10462306a36Sopenharmony_ci int vif, int create) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct inetpeer_addr daddr; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci daddr.a4.addr = v4daddr; 10962306a36Sopenharmony_ci daddr.a4.vif = vif; 11062306a36Sopenharmony_ci daddr.family = AF_INET; 11162306a36Sopenharmony_ci return inet_getpeer(base, &daddr, create); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, 11562306a36Sopenharmony_ci const struct in6_addr *v6daddr, 11662306a36Sopenharmony_ci int create) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct inetpeer_addr daddr; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci daddr.a6 = *v6daddr; 12162306a36Sopenharmony_ci daddr.family = AF_INET6; 12262306a36Sopenharmony_ci return inet_getpeer(base, &daddr, create); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, 12662306a36Sopenharmony_ci const struct inetpeer_addr *b) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int i, n; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (a->family == AF_INET) 13162306a36Sopenharmony_ci n = sizeof(a->a4) / sizeof(u32); 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci n = sizeof(a->a6) / sizeof(u32); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci for (i = 0; i < n; i++) { 13662306a36Sopenharmony_ci if (a->key[i] == b->key[i]) 13762306a36Sopenharmony_ci continue; 13862306a36Sopenharmony_ci if (a->key[i] < b->key[i]) 13962306a36Sopenharmony_ci return -1; 14062306a36Sopenharmony_ci return 1; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* can be called from BH context or outside */ 14762306a36Sopenharmony_civoid inet_putpeer(struct inet_peer *p); 14862306a36Sopenharmony_cibool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_civoid inetpeer_invalidate_tree(struct inet_peer_base *); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#endif /* _NET_INETPEER_H */ 153