18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * INETPEER - A storage for permanent information about peers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: Andrey V. Savochkin <saw@msu.ru> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef _NET_INETPEER_H 98c2ecf20Sopenharmony_ci#define _NET_INETPEER_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 148c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 158c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 168c2ecf20Sopenharmony_ci#include <net/ipv6.h> 178c2ecf20Sopenharmony_ci#include <linux/atomic.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* IPv4 address key for cache lookups */ 208c2ecf20Sopenharmony_cistruct ipv4_addr_key { 218c2ecf20Sopenharmony_ci __be32 addr; 228c2ecf20Sopenharmony_ci int vif; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define INETPEER_MAXKEYSZ (sizeof(struct in6_addr) / sizeof(u32)) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct inetpeer_addr { 288c2ecf20Sopenharmony_ci union { 298c2ecf20Sopenharmony_ci struct ipv4_addr_key a4; 308c2ecf20Sopenharmony_ci struct in6_addr a6; 318c2ecf20Sopenharmony_ci u32 key[INETPEER_MAXKEYSZ]; 328c2ecf20Sopenharmony_ci }; 338c2ecf20Sopenharmony_ci __u16 family; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct inet_peer { 378c2ecf20Sopenharmony_ci struct rb_node rb_node; 388c2ecf20Sopenharmony_ci struct inetpeer_addr daddr; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci u32 metrics[RTAX_MAX]; 418c2ecf20Sopenharmony_ci u32 rate_tokens; /* rate limiting for ICMP */ 428c2ecf20Sopenharmony_ci u32 n_redirects; 438c2ecf20Sopenharmony_ci unsigned long rate_last; 448c2ecf20Sopenharmony_ci /* 458c2ecf20Sopenharmony_ci * Once inet_peer is queued for deletion (refcnt == 0), following field 468c2ecf20Sopenharmony_ci * is not available: rid 478c2ecf20Sopenharmony_ci * We can share memory with rcu_head to help keep inet_peer small. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci union { 508c2ecf20Sopenharmony_ci struct { 518c2ecf20Sopenharmony_ci atomic_t rid; /* Frag reception counter */ 528c2ecf20Sopenharmony_ci }; 538c2ecf20Sopenharmony_ci struct rcu_head rcu; 548c2ecf20Sopenharmony_ci }; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* following fields might be frequently dirtied */ 578c2ecf20Sopenharmony_ci __u32 dtime; /* the time of last use of not referenced entries */ 588c2ecf20Sopenharmony_ci refcount_t refcnt; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct inet_peer_base { 628c2ecf20Sopenharmony_ci struct rb_root rb_root; 638c2ecf20Sopenharmony_ci seqlock_t lock; 648c2ecf20Sopenharmony_ci int total; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_civoid inet_peer_base_init(struct inet_peer_base *); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid inet_initpeers(void) __init; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define INETPEER_METRICS_NEW (~(u32) 0) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci iaddr->a4.addr = ip; 768c2ecf20Sopenharmony_ci iaddr->a4.vif = 0; 778c2ecf20Sopenharmony_ci iaddr->family = AF_INET; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return iaddr->a4.addr; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, 868c2ecf20Sopenharmony_ci struct in6_addr *in6) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci iaddr->a6 = *in6; 898c2ecf20Sopenharmony_ci iaddr->family = AF_INET6; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return &iaddr->a6; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* can be called with or without local BH being disabled */ 988c2ecf20Sopenharmony_cistruct inet_peer *inet_getpeer(struct inet_peer_base *base, 998c2ecf20Sopenharmony_ci const struct inetpeer_addr *daddr, 1008c2ecf20Sopenharmony_ci int create); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, 1038c2ecf20Sopenharmony_ci __be32 v4daddr, 1048c2ecf20Sopenharmony_ci int vif, int create) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct inetpeer_addr daddr; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci daddr.a4.addr = v4daddr; 1098c2ecf20Sopenharmony_ci daddr.a4.vif = vif; 1108c2ecf20Sopenharmony_ci daddr.family = AF_INET; 1118c2ecf20Sopenharmony_ci return inet_getpeer(base, &daddr, create); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, 1158c2ecf20Sopenharmony_ci const struct in6_addr *v6daddr, 1168c2ecf20Sopenharmony_ci int create) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct inetpeer_addr daddr; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci daddr.a6 = *v6daddr; 1218c2ecf20Sopenharmony_ci daddr.family = AF_INET6; 1228c2ecf20Sopenharmony_ci return inet_getpeer(base, &daddr, create); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, 1268c2ecf20Sopenharmony_ci const struct inetpeer_addr *b) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int i, n; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (a->family == AF_INET) 1318c2ecf20Sopenharmony_ci n = sizeof(a->a4) / sizeof(u32); 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci n = sizeof(a->a6) / sizeof(u32); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 1368c2ecf20Sopenharmony_ci if (a->key[i] == b->key[i]) 1378c2ecf20Sopenharmony_ci continue; 1388c2ecf20Sopenharmony_ci if (a->key[i] < b->key[i]) 1398c2ecf20Sopenharmony_ci return -1; 1408c2ecf20Sopenharmony_ci return 1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* can be called from BH context or outside */ 1478c2ecf20Sopenharmony_civoid inet_putpeer(struct inet_peer *p); 1488c2ecf20Sopenharmony_cibool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_civoid inetpeer_invalidate_tree(struct inet_peer_base *); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci#endif /* _NET_INETPEER_H */ 153