| /* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of version 2 of the GNU General Public | |
| * License as published by the Free Software Foundation. | |
| * | |
| * This program is distributed in the hope that it will be useful, but | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * General Public License for more details. | |
| */ | |
| #include <uapi/linux/bpf.h> | |
| #include <uapi/linux/if_ether.h> | |
| #include <uapi/linux/if_packet.h> | |
| #include <uapi/linux/ip.h> | |
| #include "../../tools/testing/selftests/bpf/bpf_helpers.h" | |
| #include "../../tools/testing/selftests/bpf/bpf_endian.h" | |
| /* Sockmap sample program connects a client and a backend together | |
| * using cgroups. | |
| * | |
| * client:X <---> frontend:80 client:X <---> backend:80 | |
| * | |
| * For simplicity we hard code values here and bind 1:1. The hard | |
| * coded values are part of the setup in sockmap.sh script that | |
| * is associated with this BPF program. | |
| * | |
| * The bpf_printk is verbose and prints information as connections | |
| * are established and verdicts are decided. | |
| */ | |
| #define bpf_printk(fmt, ...) \ | |
| ({ \ | |
| char ____fmt[] = fmt; \ | |
| bpf_trace_printk(____fmt, sizeof(____fmt), \ | |
| ##__VA_ARGS__); \ | |
| }) | |
| struct bpf_map_def SEC("maps") sock_map = { | |
| .type = BPF_MAP_TYPE_SOCKMAP, | |
| .key_size = sizeof(int), | |
| .value_size = sizeof(int), | |
| .max_entries = 20, | |
| }; | |
| SEC("sk_skb1") | |
| int bpf_prog1(struct __sk_buff *skb) | |
| { | |
| return skb->len; | |
| } | |
| SEC("sk_skb2") | |
| int bpf_prog2(struct __sk_buff *skb) | |
| { | |
| __u32 lport = skb->local_port; | |
| __u32 rport = skb->remote_port; | |
| int ret = 0; | |
| if (lport == 10000) | |
| ret = 10; | |
| else | |
| ret = 1; | |
| bpf_printk("sockmap: %d -> %d @ %d\n", lport, bpf_ntohl(rport), ret); | |
| return bpf_sk_redirect_map(skb, &sock_map, ret, 0); | |
| } | |
| SEC("sockops") | |
| int bpf_sockmap(struct bpf_sock_ops *skops) | |
| { | |
| __u32 lport, rport; | |
| int op, err = 0, index, key, ret; | |
| op = (int) skops->op; | |
| switch (op) { | |
| case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: | |
| lport = skops->local_port; | |
| rport = skops->remote_port; | |
| if (lport == 10000) { | |
| ret = 1; | |
| err = bpf_sock_map_update(skops, &sock_map, &ret, | |
| BPF_NOEXIST); | |
| bpf_printk("passive(%i -> %i) map ctx update err: %d\n", | |
| lport, bpf_ntohl(rport), err); | |
| } | |
| break; | |
| case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: | |
| lport = skops->local_port; | |
| rport = skops->remote_port; | |
| if (bpf_ntohl(rport) == 10001) { | |
| ret = 10; | |
| err = bpf_sock_map_update(skops, &sock_map, &ret, | |
| BPF_NOEXIST); | |
| bpf_printk("active(%i -> %i) map ctx update err: %d\n", | |
| lport, bpf_ntohl(rport), err); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| return 0; | |
| } | |
| char _license[] SEC("license") = "GPL"; |