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
455455 struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
456456 struct request_sock *req,
457457 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);
459460 int tcp_disconnect(struct sock *sk, int flags);
460461
461462 void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);
@@ -2035,7 +2036,8 @@ struct tcp_request_sock_ops { · 1573 unmodified lines
20352036 int (*send_synack)(const struct sock *sk, struct dst_entry *dst,
20362037 struct flowi *fl, struct request_sock *req,
20372038 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);
20392041 };
20402042
20412043 extern 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
41754175 BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),
41764176 BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4),
41774177 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5),
4178+ BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = (1<<6),
41784179 /* Mask of all currently supported cb flags */
4179− BPF_SOCK_OPS_ALL_CB_FLAGS = 0x3F,
4180+ BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F,
41804181 };
41814182
41824183 /* 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
68246824 }
68256825 if (fastopen_sk) {
68266826 af_ops->send_synack(fastopen_sk, dst, &fl, req,
6827− &foc, TCP_SYNACK_FASTOPEN);
6827+ &foc, TCP_SYNACK_FASTOPEN, skb);
68286828 /* Add the child socket directly into the accept queue */
68296829 if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) {
68306830 reqsk_fastopen_remove(fastopen_sk, req, false);
@@ -6842,7 +6842,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, · 11 unmodified lines
68426842 tcp_timeout_init((struct sock *)req));
68436843 af_ops->send_synack(sk, dst, &fl, req, &foc,
68446844 !want_cookie ? TCP_SYNACK_NORMAL :
6845− TCP_SYNACK_COOKIE);
6845+ TCP_SYNACK_COOKIE,
6846+ skb);
68466847 if (want_cookie) {
68476848 reqsk_free(req);
68486849 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
965965 struct flowi *fl,
966966 struct request_sock *req,
967967 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)
969970 {
970971 const struct inet_request_sock *ireq = inet_rsk(req);
971972 struct flowi4 fl4;
@@ -976,7 +977,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, · 4 unmodified lines
976977 if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
977978 return -1;
978979
979− skb = tcp_make_synack(sk, dst, req, foc, synack_type);
980+ skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb);
980981
981982 if (skb) {
982983 __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
438438 u8 ws; /* window scale, 0 to disable */
439439 u8 num_sack_blocks; /* number of SACK blocks to include */
440440 u8 hash_size; /* bytes in hash_location */
441+ u8 bpf_opt_len; /* length of BPF hdr option */
441442 __u8 *hash_location; /* temporary pointer, overloaded */
442443 __u32 tsval, tsecr; /* need to include OPTION_TS */
443444 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
452453 #endif
453454 }
454455
456+#ifdef CONFIG_CGROUP_BPF
457+/* req, syn_skb and synack_type are used when writing synack */
458+static 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+
476+static 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
491+static 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+
500+static 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+
455509 /* Write previously computed TCP options to the packet.
456510 *
457511 * 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
691745 }
692746 }
693747
748+ bpf_skops_hdr_opt_len(sk, skb, NULL, NULL, 0, opts, &remaining);
749+
694750 return MAX_TCP_OPTION_SPACE - remaining;
695751 }
696752
@@ -701,7 +757,8 @@ static unsigned int tcp_synack_options(const struct sock *sk, · 4 unmodified lines
701757 struct tcp_out_options *opts,
702758 const struct tcp_md5sig_key *md5,
703759 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)
705762 {
706763 struct inet_request_sock *ireq = inet_rsk(req);
707764 unsigned int remaining = MAX_TCP_OPTION_SPACE;
@@ -758,6 +815,9 @@ static unsigned int tcp_synack_options(const struct sock *sk, · 50 unmodified lines
758815
759816 smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining);
760817
818+ bpf_skops_hdr_opt_len((struct sock *)sk, skb, req, syn_skb,
819+ synack_type, opts, &remaining);
820+
761821 return MAX_TCP_OPTION_SPACE - remaining;
762822 }
763823
@@ -826,6 +886,15 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb · 62 unmodified lines
826886 opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
827887 }
828888
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+
829898 return size;
830899 }
831900
@@ -1213,6 +1282,9 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, · 381 unmodified lines
12131282 }
12141283 #endif
12151284
1285+ /* BPF prog is the last one writing header option */
1286+ bpf_skops_write_hdr_opt(sk, skb, NULL, NULL, 0, &opts);
1287+
12161288 INDIRECT_CALL_INET(icsk->icsk_af_ops->send_check,
12171289 tcp_v6_send_check, tcp_v4_send_check,
12181290 sk, skb);
@@ -3336,20 +3408,20 @@ int tcp_send_synack(struct sock *sk) · 2117 unmodified lines
33363408 }
33373409
33383410 /**
3339− * tcp_make_synack - Prepare a SYN-ACK.
3340− * sk: listener socket
3341− * dst: dst entry attached to the SYNACK
3342− * req: request_sock pointer
3343− * foc: cookie for tcp fast open
3344− * synack_type: Type of synback to prepare
3345− *
3346− * Allocate one skb and build a SYNACK packet.
3347− * @dst is consumed : Caller should not use it again.
3411+ * tcp_make_synack - Allocate one skb and build a SYNACK packet.
3412+ * @sk: listener socket
3413+ * @dst: dst entry attached to the SYNACK. It is consumed and caller
3414+ * should not use it again.
3415+ * @req: request_sock pointer
3416+ * @foc: cookie for tcp fast open
3417+ * @synack_type: Type of synack to prepare
3418+ * @syn_skb: SYN packet just received. It could be NULL for rtx case.
33483419 */
33493420 struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
33503421 struct request_sock *req,
33513422 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)
33533425 {
33543426 struct inet_request_sock *ireq = inet_rsk(req);
33553427 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
34083480 md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req));
34093481 #endif
34103482 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;
34113485 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);
34133488
34143489 skb_push(skb, tcp_header_size);
34153490 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
34413516 rcu_read_unlock();
34423517 #endif
34433518
3519+ bpf_skops_write_hdr_opt((struct sock *)sk, skb, req, syn_skb,
3520+ synack_type, &opts);
3521+
34443522 skb->skb_mstamp_ns = now;
34453523 tcp_add_tx_delay(skb, tp);
34463524
@@ -3936,7 +4014,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) · 489 unmodified lines
39364014 int res;
39374015
39384016 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);
39404019 if (!res) {
39414020 __TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS);
39424021 __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
501501 struct flowi *fl,
502502 struct request_sock *req,
503503 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)
505506 {
506507 struct inet_request_sock *ireq = inet_rsk(req);
507508 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
515516 IPPROTO_TCP)) == NULL)
516517 goto done;
517518
518− skb = tcp_make_synack(sk, dst, req, foc, synack_type);
519+ skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb);
519520
520521 if (skb) {
521522 __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
41754175 BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),
41764176 BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4),
41774177 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5),
4178+ BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = (1<<6),
41784179 /* Mask of all currently supported cb flags */
4179− BPF_SOCK_OPS_ALL_CB_FLAGS = 0x3F,
4180+ BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F,
41804181 };
41814182
41824183 /* List of known BPF sock_ops operators.