| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* Copyright(c) 2023 Huawei Technologies Co., Ltd |
| */ |
| |
| #ifndef __BPF_SOCKMAP_H__ |
| #define __BPF_SOCKMAP_H__ |
| |
| #include <stddef.h> |
| #include <stdbool.h> |
| #include <linux/types.h> |
| #include <linux/bpf.h> |
| |
| #include <bpf/bpf_helpers.h> |
| #include <bpf/bpf_endian.h> |
| |
| #define LOG_DEBUG 0 |
| #define SOCKMAP_SIZE 100000 |
| |
| #if LOG_DEBUG |
| #define net_dbg bpf_printk |
| #define net_err bpf_printk |
| #else |
| #define net_dbg(fmt, ...) do {} while (0) |
| #define net_err bpf_printk |
| #endif |
| |
| struct sock_key { |
| __u32 sip4; |
| __u32 dip4; |
| __u32 sport; |
| __u32 dport; |
| } __attribute__((packed)); |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_SOCKHASH); |
| __type(key, struct sock_key); |
| __type(value, int); |
| __uint(max_entries, SOCKMAP_SIZE); |
| __uint(map_flags, 0); |
| } redissock_map SEC(".maps"); |
| |
| struct sock_info { |
| __u64 redir_rx_cnt; |
| __u64 redir_tx_cnt; |
| int sk_flags; |
| }; |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_HASH); |
| __type(key, struct sock_key); |
| __type(value, struct sock_info); |
| __uint(max_entries, SOCKMAP_SIZE); |
| __uint(map_flags, 0); |
| } sockflag_map SEC(".maps"); |
| |
| static inline void sock_key2peerkey(struct sock_key *key, struct sock_key *peer_key) |
| { |
| peer_key->sip4 = key->dip4; |
| peer_key->sport = key->dport; |
| peer_key->dip4 = key->sip4; |
| peer_key->dport = key->sport; |
| } |
| |
| static inline void extract_key4_from_ops(struct bpf_sock_ops *ops, struct sock_key *key) |
| { |
| key->dip4 = ops->remote_ip4; |
| key->sip4 = ops->local_ip4; |
| |
| // local_port is in host byte order |
| // and remote_port is in network byte order |
| key->sport = ops->local_port; |
| key->dport = bpf_ntohl(ops->remote_port); |
| } |
| |
| static inline void bpf_sock_ops_ipv4(struct bpf_sock_ops *skops) |
| { |
| struct sock_key key = {}; |
| |
| extract_key4_from_ops(skops, &key); |
| bpf_sock_hash_update(skops, &redissock_map, &key, BPF_NOEXIST); |
| } |
| |
| static inline void bpf_sockmap_ipv4_insert(struct bpf_sock_ops *skops) |
| { |
| if (bpf_ntohl(skops->remote_port) == 22 || skops->local_port == 22) |
| return; |
| |
| bpf_sock_ops_ipv4(skops); |
| } |
| |
| static inline void bpf_sockmap_ipv4_cleanup(struct bpf_sock_ops *skops, __u64 *cnt) |
| { |
| struct sock_info *p_skinfo = NULL; |
| struct sock_key key = {}; |
| |
| extract_key4_from_ops(skops, &key); |
| p_skinfo = bpf_map_lookup_elem(&sockflag_map, &key); |
| if (p_skinfo) { |
| if (cnt) |
| *cnt = p_skinfo->redir_tx_cnt; |
| bpf_map_delete_elem(&sockflag_map, &key); |
| } |
| } |
| |
| static inline void extract_key4_from_msg(struct sk_msg_md *msg, struct sock_key *key) |
| { |
| key->sip4 = msg->local_ip4; |
| key->dip4 = msg->remote_ip4; |
| |
| // local_port is in host byte order |
| // and remote_port is in network byte order |
| key->sport = msg->local_port; |
| key->dport = bpf_ntohl(msg->remote_port); |
| } |
| |
| SEC("sk_msg") int redis_redir(struct sk_msg_md *msg) |
| { |
| struct sock_info *p_skinfo = NULL; |
| struct sock_info skinfo = {0}; |
| struct sock_key peer_key = {}; |
| struct sock_key key = {}; |
| int ret, addinfo = 0; |
| |
| extract_key4_from_msg(msg, &key); |
| sock_key2peerkey(&key, &peer_key); |
| |
| p_skinfo = bpf_map_lookup_elem(&sockflag_map, &key); |
| if (p_skinfo != NULL && p_skinfo->sk_flags == 1) |
| return SK_PASS; |
| |
| if (p_skinfo == NULL) { |
| addinfo = 1; |
| p_skinfo = &skinfo; |
| } |
| |
| ret = bpf_msg_redirect_hash(msg, &redissock_map, &peer_key, BPF_F_INGRESS); |
| if (ret == SK_DROP) { |
| if (p_skinfo->sk_flags != 1) |
| p_skinfo->sk_flags = 1; |
| } |
| |
| p_skinfo->redir_tx_cnt++; |
| if (addinfo) |
| bpf_map_update_elem(&sockflag_map, &key, p_skinfo, BPF_ANY); |
| |
| return SK_PASS; |
| } |
| #endif |