@@ -1175,7 +1175,9 @@ int sk_attach_bpf(u32 ufd, struct sock *sk)
1175
1175
return 0 ;
1176
1176
}
1177
1177
1178
- static u64 bpf_skb_store_bytes (u64 r1 , u64 r2 , u64 r3 , u64 r4 , u64 r5 )
1178
+ #define BPF_RECOMPUTE_CSUM (flags ) ((flags) & 1)
1179
+
1180
+ static u64 bpf_skb_store_bytes (u64 r1 , u64 r2 , u64 r3 , u64 r4 , u64 flags )
1179
1181
{
1180
1182
struct sk_buff * skb = (struct sk_buff * ) (long ) r1 ;
1181
1183
unsigned int offset = (unsigned int ) r2 ;
@@ -1192,7 +1194,7 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
1192
1194
*
1193
1195
* so check for invalid 'offset' and too large 'len'
1194
1196
*/
1195
- if (offset > 0xffff || len > sizeof (buf ))
1197
+ if (unlikely ( offset > 0xffff || len > sizeof (buf ) ))
1196
1198
return - EFAULT ;
1197
1199
1198
1200
if (skb_cloned (skb ) && !skb_clone_writable (skb , offset + len ))
@@ -1202,15 +1204,16 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
1202
1204
if (unlikely (!ptr ))
1203
1205
return - EFAULT ;
1204
1206
1205
- skb_postpull_rcsum (skb , ptr , len );
1207
+ if (BPF_RECOMPUTE_CSUM (flags ))
1208
+ skb_postpull_rcsum (skb , ptr , len );
1206
1209
1207
1210
memcpy (ptr , from , len );
1208
1211
1209
1212
if (ptr == buf )
1210
1213
/* skb_store_bits cannot return -EFAULT here */
1211
1214
skb_store_bits (skb , offset , ptr , len );
1212
1215
1213
- if (skb -> ip_summed == CHECKSUM_COMPLETE )
1216
+ if (BPF_RECOMPUTE_CSUM ( flags ) && skb -> ip_summed == CHECKSUM_COMPLETE )
1214
1217
skb -> csum = csum_add (skb -> csum , csum_partial (ptr , len , 0 ));
1215
1218
return 0 ;
1216
1219
}
@@ -1223,6 +1226,99 @@ const struct bpf_func_proto bpf_skb_store_bytes_proto = {
1223
1226
.arg2_type = ARG_ANYTHING ,
1224
1227
.arg3_type = ARG_PTR_TO_STACK ,
1225
1228
.arg4_type = ARG_CONST_STACK_SIZE ,
1229
+ .arg5_type = ARG_ANYTHING ,
1230
+ };
1231
+
1232
+ #define BPF_HEADER_FIELD_SIZE (flags ) ((flags) & 0x0f)
1233
+ #define BPF_IS_PSEUDO_HEADER (flags ) ((flags) & 0x10)
1234
+
1235
+ static u64 bpf_l3_csum_replace (u64 r1 , u64 offset , u64 from , u64 to , u64 flags )
1236
+ {
1237
+ struct sk_buff * skb = (struct sk_buff * ) (long ) r1 ;
1238
+ __sum16 sum , * ptr ;
1239
+
1240
+ if (unlikely (offset > 0xffff ))
1241
+ return - EFAULT ;
1242
+
1243
+ if (skb_cloned (skb ) && !skb_clone_writable (skb , offset + sizeof (sum )))
1244
+ return - EFAULT ;
1245
+
1246
+ ptr = skb_header_pointer (skb , offset , sizeof (sum ), & sum );
1247
+ if (unlikely (!ptr ))
1248
+ return - EFAULT ;
1249
+
1250
+ switch (BPF_HEADER_FIELD_SIZE (flags )) {
1251
+ case 2 :
1252
+ csum_replace2 (ptr , from , to );
1253
+ break ;
1254
+ case 4 :
1255
+ csum_replace4 (ptr , from , to );
1256
+ break ;
1257
+ default :
1258
+ return - EINVAL ;
1259
+ }
1260
+
1261
+ if (ptr == & sum )
1262
+ /* skb_store_bits guaranteed to not return -EFAULT here */
1263
+ skb_store_bits (skb , offset , ptr , sizeof (sum ));
1264
+
1265
+ return 0 ;
1266
+ }
1267
+
1268
+ const struct bpf_func_proto bpf_l3_csum_replace_proto = {
1269
+ .func = bpf_l3_csum_replace ,
1270
+ .gpl_only = false,
1271
+ .ret_type = RET_INTEGER ,
1272
+ .arg1_type = ARG_PTR_TO_CTX ,
1273
+ .arg2_type = ARG_ANYTHING ,
1274
+ .arg3_type = ARG_ANYTHING ,
1275
+ .arg4_type = ARG_ANYTHING ,
1276
+ .arg5_type = ARG_ANYTHING ,
1277
+ };
1278
+
1279
+ static u64 bpf_l4_csum_replace (u64 r1 , u64 offset , u64 from , u64 to , u64 flags )
1280
+ {
1281
+ struct sk_buff * skb = (struct sk_buff * ) (long ) r1 ;
1282
+ u32 is_pseudo = BPF_IS_PSEUDO_HEADER (flags );
1283
+ __sum16 sum , * ptr ;
1284
+
1285
+ if (unlikely (offset > 0xffff ))
1286
+ return - EFAULT ;
1287
+
1288
+ if (skb_cloned (skb ) && !skb_clone_writable (skb , offset + sizeof (sum )))
1289
+ return - EFAULT ;
1290
+
1291
+ ptr = skb_header_pointer (skb , offset , sizeof (sum ), & sum );
1292
+ if (unlikely (!ptr ))
1293
+ return - EFAULT ;
1294
+
1295
+ switch (BPF_HEADER_FIELD_SIZE (flags )) {
1296
+ case 2 :
1297
+ inet_proto_csum_replace2 (ptr , skb , from , to , is_pseudo );
1298
+ break ;
1299
+ case 4 :
1300
+ inet_proto_csum_replace4 (ptr , skb , from , to , is_pseudo );
1301
+ break ;
1302
+ default :
1303
+ return - EINVAL ;
1304
+ }
1305
+
1306
+ if (ptr == & sum )
1307
+ /* skb_store_bits guaranteed to not return -EFAULT here */
1308
+ skb_store_bits (skb , offset , ptr , sizeof (sum ));
1309
+
1310
+ return 0 ;
1311
+ }
1312
+
1313
+ const struct bpf_func_proto bpf_l4_csum_replace_proto = {
1314
+ .func = bpf_l4_csum_replace ,
1315
+ .gpl_only = false,
1316
+ .ret_type = RET_INTEGER ,
1317
+ .arg1_type = ARG_PTR_TO_CTX ,
1318
+ .arg2_type = ARG_ANYTHING ,
1319
+ .arg3_type = ARG_ANYTHING ,
1320
+ .arg4_type = ARG_ANYTHING ,
1321
+ .arg5_type = ARG_ANYTHING ,
1226
1322
};
1227
1323
1228
1324
static const struct bpf_func_proto *
@@ -1250,6 +1346,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
1250
1346
switch (func_id ) {
1251
1347
case BPF_FUNC_skb_store_bytes :
1252
1348
return & bpf_skb_store_bytes_proto ;
1349
+ case BPF_FUNC_l3_csum_replace :
1350
+ return & bpf_l3_csum_replace_proto ;
1351
+ case BPF_FUNC_l4_csum_replace :
1352
+ return & bpf_l4_csum_replace_proto ;
1253
1353
default :
1254
1354
return sk_filter_func_proto (func_id );
1255
1355
}
0 commit comments