History

bpf: tcp: Add bpf_skops_hdr_opt_len() and bpf_skops_write_hdr_opt()

The bpf prog needs to parse the SYN header to learn what options have been sent by the peer's bpf-prog before writing its options into SYNACK. This patch adds a "syn_skb" arg to tcp_make_synack() and send_synack(). This syn_skb will eventually be made available (as read-only) to the bpf prog. This will be the only SYN packet available to the bpf prog during syncookie. For other regular cases, the bpf prog can also use the saved_syn. When writing options, the bpf prog will first be called to tell the kernel its required number of bytes. It is done by the new bpf_skops_hdr_opt_len(). The bpf prog will only be called when the new BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG is set in tp->bpf_sock_ops_cb_flags. When the bpf prog returns, the kernel will know how many bytes are needed and then update the "*remaining" arg accordingly. 4 byte alignment will be included in the "*remaining" before this function returns. The 4 byte aligned number of bytes will also be stored into the opts->bpf_opt_len. "bpf_opt_len" is a newly added member to the struct tcp_out_options. Then the new bpf_skops_write_hdr_opt() will call the bpf prog to write the header options. The bpf prog is only called if it has reserved spaces before (opts->bpf_opt_len > 0). The bpf prog is the last one getting a chance to reserve header space and writing the header option. These two functions are half implemented to highlight the changes in TCP stack. The actual codes preparing the bpf running context and invoking the bpf prog will be added in the later patch with other necessary bpf pieces.

Martin KaFai Lau committed 6 years ago

Commit 331fca41 parent 00d211a7 files · +109 −23Browse files

Unified · Split

7 files
  1. include/net/tcp.h +4 −2
  2. include/uapi/linux/bpf.h +2 −1
  3. net/ipv4/tcp_input.c +3 −2
  4. net/ipv4/tcp_ipv4.c +3 −2
  5. net/ipv4/tcp_output.c +92 −13
  6. net/ipv6/tcp_ipv6.c +3 −2
  7. tools/include/uapi/linux/bpf.h +2 −1
include/net/tcp.h+4−2
@@ -455,7 +455,8 @@ enum tcp_synack_type { · 454 unmodified lines
455struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,455struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
456 struct request_sock *req,456 struct request_sock *req,
457 struct tcp_fastopen_cookie *foc,457 struct tcp_fastopen_cookie *foc,
458 enum tcp_synack_type synack_type);458 enum tcp_synack_type synack_type,
459 struct sk_buff *syn_skb);
459int tcp_disconnect(struct sock *sk, int flags);460int tcp_disconnect(struct sock *sk, int flags);
460 461
461void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);462void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);
@@ -2035,7 +2036,8 @@ struct tcp_request_sock_ops { · 1573 unmodified lines
2035 int (*send_synack)(const struct sock *sk, struct dst_entry *dst,2036 int (*send_synack)(const struct sock *sk, struct dst_entry *dst,
2036 struct flowi *fl, struct request_sock *req,2037 struct flowi *fl, struct request_sock *req,
2037 struct tcp_fastopen_cookie *foc,2038 struct tcp_fastopen_cookie *foc,
2038 enum tcp_synack_type synack_type);2039 enum tcp_synack_type synack_type,
2040 struct sk_buff *syn_skb);
2039};2041};
2040 2042
2041extern const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops;2043extern const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops;
include/uapi/linux/bpf.h+2−1
@@ -4175,8 +4175,9 @@ enum { · 4174 unmodified lines
4175 BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),4175 BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),
4176 BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4),4176 BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4),
4177 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5),4177 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5),
4178 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = (1<<6),
4178/* Mask of all currently supported cb flags */4179/* Mask of all currently supported cb flags */
4179 BPF_SOCK_OPS_ALL_CB_FLAGS = 0x3F,4180 BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F,
4180};4181};
4181 4182
4182/* List of known BPF sock_ops operators.4183/* List of known BPF sock_ops operators.
net/ipv4/tcp_input.c+3−2
@@ -6824,7 +6824,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, · 6823 unmodified lines
6824 }6824 }
6825 if (fastopen_sk) {6825 if (fastopen_sk) {
6826 af_ops->send_synack(fastopen_sk, dst, &fl, req,6826 af_ops->send_synack(fastopen_sk, dst, &fl, req,
6827 &foc, TCP_SYNACK_FASTOPEN);6827 &foc, TCP_SYNACK_FASTOPEN, skb);
6828 /* Add the child socket directly into the accept queue */6828 /* Add the child socket directly into the accept queue */
6829 if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) {6829 if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) {
6830 reqsk_fastopen_remove(fastopen_sk, req, false);6830 reqsk_fastopen_remove(fastopen_sk, req, false);
@@ -6842,7 +6842,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, · 11 unmodified lines
6842 tcp_timeout_init((struct sock *)req));6842 tcp_timeout_init((struct sock *)req));
6843 af_ops->send_synack(sk, dst, &fl, req, &foc,6843 af_ops->send_synack(sk, dst, &fl, req, &foc,
6844 !want_cookie ? TCP_SYNACK_NORMAL :6844 !want_cookie ? TCP_SYNACK_NORMAL :
6845 TCP_SYNACK_COOKIE);6845 TCP_SYNACK_COOKIE,
6846 skb);
6846 if (want_cookie) {6847 if (want_cookie) {
6847 reqsk_free(req);6848 reqsk_free(req);
6848 return 0;6849 return 0;
net/ipv4/tcp_ipv4.c+3−2
@@ -965,7 +965,8 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, · 964 unmodified lines
965 struct flowi *fl,965 struct flowi *fl,
966 struct request_sock *req,966 struct request_sock *req,
967 struct tcp_fastopen_cookie *foc,967 struct tcp_fastopen_cookie *foc,
968 enum tcp_synack_type synack_type)968 enum tcp_synack_type synack_type,
969 struct sk_buff *syn_skb)
969{970{
970 const struct inet_request_sock *ireq = inet_rsk(req);971 const struct inet_request_sock *ireq = inet_rsk(req);
971 struct flowi4 fl4;972 struct flowi4 fl4;
@@ -976,7 +977,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, · 4 unmodified lines
976 if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)977 if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
977 return -1;978 return -1;
978 979
979 skb = tcp_make_synack(sk, dst, req, foc, synack_type);980 skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb);
980 981
981 if (skb) {982 if (skb) {
982 __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);983 __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
net/ipv4/tcp_output.c+92−13
@@ -438,6 +438,7 @@ struct tcp_out_options { · 437 unmodified lines
438 u8 ws; /* window scale, 0 to disable */438 u8 ws; /* window scale, 0 to disable */
439 u8 num_sack_blocks; /* number of SACK blocks to include */439 u8 num_sack_blocks; /* number of SACK blocks to include */
440 u8 hash_size; /* bytes in hash_location */440 u8 hash_size; /* bytes in hash_location */
441 u8 bpf_opt_len; /* length of BPF hdr option */
441 __u8 *hash_location; /* temporary pointer, overloaded */442 __u8 *hash_location; /* temporary pointer, overloaded */
442 __u32 tsval, tsecr; /* need to include OPTION_TS */443 __u32 tsval, tsecr; /* need to include OPTION_TS */
443 struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */444 struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
@@ -452,6 +453,59 @@ static void mptcp_options_write(__be32 *ptr, struct tcp_out_options *opts) · 8 unmodified lines
452#endif453#endif
453}454}
454 455
456#ifdef CONFIG_CGROUP_BPF
457/* req, syn_skb and synack_type are used when writing synack */
458static void bpf_skops_hdr_opt_len(struct sock *sk, struct sk_buff *skb,
459 struct request_sock *req,
460 struct sk_buff *syn_skb,
461 enum tcp_synack_type synack_type,
462 struct tcp_out_options *opts,
463 unsigned int *remaining)
464{
465 if (likely(!BPF_SOCK_OPS_TEST_FLAG(tcp_sk(sk),
466 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG)) ||
467 !*remaining)
468 return;
469
470 /* The bpf running context preparation and the actual bpf prog
471 * calling will be implemented in a later PATCH together with
472 * other bpf pieces.
473 */
474}
475
476static void bpf_skops_write_hdr_opt(struct sock *sk, struct sk_buff *skb,
477 struct request_sock *req,
478 struct sk_buff *syn_skb,
479 enum tcp_synack_type synack_type,
480 struct tcp_out_options *opts)
481{
482 if (likely(!opts->bpf_opt_len))
483 return;
484
485 /* The bpf running context preparation and the actual bpf prog
486 * calling will be implemented in a later PATCH together with
487 * other bpf pieces.
488 */
489}
490#else
491static void bpf_skops_hdr_opt_len(struct sock *sk, struct sk_buff *skb,
492 struct request_sock *req,
493 struct sk_buff *syn_skb,
494 enum tcp_synack_type synack_type,
495 struct tcp_out_options *opts,
496 unsigned int *remaining)
497{
498}
499
500static void bpf_skops_write_hdr_opt(struct sock *sk, struct sk_buff *skb,
501 struct request_sock *req,
502 struct sk_buff *syn_skb,
503 enum tcp_synack_type synack_type,
504 struct tcp_out_options *opts)
505{
506}
507#endif
508
455/* Write previously computed TCP options to the packet.509/* Write previously computed TCP options to the packet.
456 *510 *
457 * Beware: Something in the Internet is very sensitive to the ordering of511 * Beware: Something in the Internet is very sensitive to the ordering of
@@ -691,6 +745,8 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, · 233 unmodified lines
691 }745 }
692 }746 }
693 747
748 bpf_skops_hdr_opt_len(sk, skb, NULL, NULL, 0, opts, &remaining);
749
694 return MAX_TCP_OPTION_SPACE - remaining;750 return MAX_TCP_OPTION_SPACE - remaining;
695}751}
696 752
@@ -701,7 +757,8 @@ static unsigned int tcp_synack_options(const struct sock *sk, · 4 unmodified lines
701 struct tcp_out_options *opts,757 struct tcp_out_options *opts,
702 const struct tcp_md5sig_key *md5,758 const struct tcp_md5sig_key *md5,
703 struct tcp_fastopen_cookie *foc,759 struct tcp_fastopen_cookie *foc,
704 enum tcp_synack_type synack_type)760 enum tcp_synack_type synack_type,
761 struct sk_buff *syn_skb)
705{762{
706 struct inet_request_sock *ireq = inet_rsk(req);763 struct inet_request_sock *ireq = inet_rsk(req);
707 unsigned int remaining = MAX_TCP_OPTION_SPACE;764 unsigned int remaining = MAX_TCP_OPTION_SPACE;
@@ -758,6 +815,9 @@ static unsigned int tcp_synack_options(const struct sock *sk, · 50 unmodified lines
758 815
759 smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining);816 smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining);
760 817
818 bpf_skops_hdr_opt_len((struct sock *)sk, skb, req, syn_skb,
819 synack_type, opts, &remaining);
820
761 return MAX_TCP_OPTION_SPACE - remaining;821 return MAX_TCP_OPTION_SPACE - remaining;
762}822}
763 823
@@ -826,6 +886,15 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb · 62 unmodified lines
826 opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;886 opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
827 }887 }
828 888
889 if (unlikely(BPF_SOCK_OPS_TEST_FLAG(tp,
890 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG))) {
891 unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
892
893 bpf_skops_hdr_opt_len(sk, skb, NULL, NULL, 0, opts, &remaining);
894
895 size = MAX_TCP_OPTION_SPACE - remaining;
896 }
897
829 return size;898 return size;
830}899}
831 900
@@ -1213,6 +1282,9 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, · 381 unmodified lines
1213 }1282 }
1214#endif1283#endif
1215 1284
1285 /* BPF prog is the last one writing header option */
1286 bpf_skops_write_hdr_opt(sk, skb, NULL, NULL, 0, &opts);
1287
1216 INDIRECT_CALL_INET(icsk->icsk_af_ops->send_check,1288 INDIRECT_CALL_INET(icsk->icsk_af_ops->send_check,
1217 tcp_v6_send_check, tcp_v4_send_check,1289 tcp_v6_send_check, tcp_v4_send_check,
1218 sk, skb);1290 sk, skb);
@@ -3336,20 +3408,20 @@ int tcp_send_synack(struct sock *sk) · 2117 unmodified lines
3336}3408}
3337 3409
3338/**3410/**
3339 * tcp_make_synack - Prepare a SYN-ACK.3411 * tcp_make_synack - Allocate one skb and build a SYNACK packet.
3340 * sk: listener socket3412 * @sk: listener socket
3341 * dst: dst entry attached to the SYNACK3413 * @dst: dst entry attached to the SYNACK. It is consumed and caller
3342 * req: request_sock pointer3414 * should not use it again.
3343 * foc: cookie for tcp fast open3415 * @req: request_sock pointer
3344 * synack_type: Type of synback to prepare3416 * @foc: cookie for tcp fast open
3345 *3417 * @synack_type: Type of synack to prepare
3346 * Allocate one skb and build a SYNACK packet.3418 * @syn_skb: SYN packet just received. It could be NULL for rtx case.
3347 * @dst is consumed : Caller should not use it again.
3348 */3419 */
3349struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,3420struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
3350 struct request_sock *req,3421 struct request_sock *req,
3351 struct tcp_fastopen_cookie *foc,3422 struct tcp_fastopen_cookie *foc,
3352 enum tcp_synack_type synack_type)3423 enum tcp_synack_type synack_type,
3424 struct sk_buff *syn_skb)
3353{3425{
3354 struct inet_request_sock *ireq = inet_rsk(req);3426 struct inet_request_sock *ireq = inet_rsk(req);
3355 const struct tcp_sock *tp = tcp_sk(sk);3427 const struct tcp_sock *tp = tcp_sk(sk);
@@ -3408,8 +3480,11 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, · 52 unmodified lines
3408 md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req));3480 md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req));
3409#endif3481#endif
3410 skb_set_hash(skb, tcp_rsk(req)->txhash, PKT_HASH_TYPE_L4);3482 skb_set_hash(skb, tcp_rsk(req)->txhash, PKT_HASH_TYPE_L4);
3483 /* bpf program will be interested in the tcp_flags */
3484 TCP_SKB_CB(skb)->tcp_flags = TCPHDR_SYN | TCPHDR_ACK;
3411 tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, md5,3485 tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, md5,
3412 foc, synack_type) + sizeof(*th);3486 foc, synack_type,
3487 syn_skb) + sizeof(*th);
3413 3488
3414 skb_push(skb, tcp_header_size);3489 skb_push(skb, tcp_header_size);
3415 skb_reset_transport_header(skb);3490 skb_reset_transport_header(skb);
@@ -3441,6 +3516,9 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, · 25 unmodified lines
3441 rcu_read_unlock();3516 rcu_read_unlock();
3442#endif3517#endif
3443 3518
3519 bpf_skops_write_hdr_opt((struct sock *)sk, skb, req, syn_skb,
3520 synack_type, &opts);
3521
3444 skb->skb_mstamp_ns = now;3522 skb->skb_mstamp_ns = now;
3445 tcp_add_tx_delay(skb, tp);3523 tcp_add_tx_delay(skb, tp);
3446 3524
@@ -3936,7 +4014,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) · 489 unmodified lines
3936 int res;4014 int res;
3937 4015
3938 tcp_rsk(req)->txhash = net_tx_rndhash();4016 tcp_rsk(req)->txhash = net_tx_rndhash();
3939 res = af_ops->send_synack(sk, NULL, &fl, req, NULL, TCP_SYNACK_NORMAL);4017 res = af_ops->send_synack(sk, NULL, &fl, req, NULL, TCP_SYNACK_NORMAL,
4018 NULL);
3940 if (!res) {4019 if (!res) {
3941 __TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS);4020 __TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS);
3942 __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);4021 __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
net/ipv6/tcp_ipv6.c+3−2
@@ -501,7 +501,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, · 500 unmodified lines
501 struct flowi *fl,501 struct flowi *fl,
502 struct request_sock *req,502 struct request_sock *req,
503 struct tcp_fastopen_cookie *foc,503 struct tcp_fastopen_cookie *foc,
504 enum tcp_synack_type synack_type)504 enum tcp_synack_type synack_type,
505 struct sk_buff *syn_skb)
505{506{
506 struct inet_request_sock *ireq = inet_rsk(req);507 struct inet_request_sock *ireq = inet_rsk(req);
507 struct ipv6_pinfo *np = tcp_inet6_sk(sk);508 struct ipv6_pinfo *np = tcp_inet6_sk(sk);
@@ -515,7 +516,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, · 7 unmodified lines
515 IPPROTO_TCP)) == NULL)516 IPPROTO_TCP)) == NULL)
516 goto done;517 goto done;
517 518
518 skb = tcp_make_synack(sk, dst, req, foc, synack_type);519 skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb);
519 520
520 if (skb) {521 if (skb) {
521 __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr,522 __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr,
tools/include/uapi/linux/bpf.h+2−1
@@ -4175,8 +4175,9 @@ enum { · 4174 unmodified lines
4175 BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),4175 BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),
4176 BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4),4176 BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4),
4177 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5),4177 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5),
4178 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = (1<<6),
4178/* Mask of all currently supported cb flags */4179/* Mask of all currently supported cb flags */
4179 BPF_SOCK_OPS_ALL_CB_FLAGS = 0x3F,4180 BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F,
4180};4181};
4181 4182
4182/* List of known BPF sock_ops operators.4183/* List of known BPF sock_ops operators.