@@ -2165,12 +2165,12 @@ static int __bpf_redirect(struct sk_buff *skb, struct net_device *dev,
2165
2165
}
2166
2166
2167
2167
#if IS_ENABLED (CONFIG_IPV6 )
2168
- static int bpf_out_neigh_v6 (struct net * net , struct sk_buff * skb )
2168
+ static int bpf_out_neigh_v6 (struct net * net , struct sk_buff * skb ,
2169
+ struct net_device * dev , struct bpf_nh_params * nh )
2169
2170
{
2170
- struct dst_entry * dst = skb_dst (skb );
2171
- struct net_device * dev = dst -> dev ;
2172
2171
u32 hh_len = LL_RESERVED_SPACE (dev );
2173
2172
const struct in6_addr * nexthop ;
2173
+ struct dst_entry * dst = NULL ;
2174
2174
struct neighbour * neigh ;
2175
2175
2176
2176
if (dev_xmit_recursion ()) {
@@ -2196,8 +2196,13 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb)
2196
2196
}
2197
2197
2198
2198
rcu_read_lock_bh ();
2199
- nexthop = rt6_nexthop (container_of (dst , struct rt6_info , dst ),
2200
- & ipv6_hdr (skb )-> daddr );
2199
+ if (!nh ) {
2200
+ dst = skb_dst (skb );
2201
+ nexthop = rt6_nexthop (container_of (dst , struct rt6_info , dst ),
2202
+ & ipv6_hdr (skb )-> daddr );
2203
+ } else {
2204
+ nexthop = & nh -> ipv6_nh ;
2205
+ }
2201
2206
neigh = ip_neigh_gw6 (dev , nexthop );
2202
2207
if (likely (!IS_ERR (neigh ))) {
2203
2208
int ret ;
@@ -2210,36 +2215,43 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb)
2210
2215
return ret ;
2211
2216
}
2212
2217
rcu_read_unlock_bh ();
2213
- IP6_INC_STATS (dev_net (dst -> dev ),
2214
- ip6_dst_idev (dst ), IPSTATS_MIB_OUTNOROUTES );
2218
+ if (dst )
2219
+ IP6_INC_STATS (dev_net (dst -> dev ),
2220
+ ip6_dst_idev (dst ), IPSTATS_MIB_OUTNOROUTES );
2215
2221
out_drop :
2216
2222
kfree_skb (skb );
2217
2223
return - ENETDOWN ;
2218
2224
}
2219
2225
2220
- static int __bpf_redirect_neigh_v6 (struct sk_buff * skb , struct net_device * dev )
2226
+ static int __bpf_redirect_neigh_v6 (struct sk_buff * skb , struct net_device * dev ,
2227
+ struct bpf_nh_params * nh )
2221
2228
{
2222
2229
const struct ipv6hdr * ip6h = ipv6_hdr (skb );
2223
2230
struct net * net = dev_net (dev );
2224
2231
int err , ret = NET_XMIT_DROP ;
2225
- struct dst_entry * dst ;
2226
- struct flowi6 fl6 = {
2227
- .flowi6_flags = FLOWI_FLAG_ANYSRC ,
2228
- .flowi6_mark = skb -> mark ,
2229
- .flowlabel = ip6_flowinfo (ip6h ),
2230
- .flowi6_oif = dev -> ifindex ,
2231
- .flowi6_proto = ip6h -> nexthdr ,
2232
- .daddr = ip6h -> daddr ,
2233
- .saddr = ip6h -> saddr ,
2234
- };
2235
2232
2236
- dst = ipv6_stub -> ipv6_dst_lookup_flow (net , NULL , & fl6 , NULL );
2237
- if (IS_ERR (dst ))
2238
- goto out_drop ;
2233
+ if (!nh ) {
2234
+ struct dst_entry * dst ;
2235
+ struct flowi6 fl6 = {
2236
+ .flowi6_flags = FLOWI_FLAG_ANYSRC ,
2237
+ .flowi6_mark = skb -> mark ,
2238
+ .flowlabel = ip6_flowinfo (ip6h ),
2239
+ .flowi6_oif = dev -> ifindex ,
2240
+ .flowi6_proto = ip6h -> nexthdr ,
2241
+ .daddr = ip6h -> daddr ,
2242
+ .saddr = ip6h -> saddr ,
2243
+ };
2244
+
2245
+ dst = ipv6_stub -> ipv6_dst_lookup_flow (net , NULL , & fl6 , NULL );
2246
+ if (IS_ERR (dst ))
2247
+ goto out_drop ;
2239
2248
2240
- skb_dst_set (skb , dst );
2249
+ skb_dst_set (skb , dst );
2250
+ } else if (nh -> nh_family != AF_INET6 ) {
2251
+ goto out_drop ;
2252
+ }
2241
2253
2242
- err = bpf_out_neigh_v6 (net , skb );
2254
+ err = bpf_out_neigh_v6 (net , skb , dev , nh );
2243
2255
if (unlikely (net_xmit_eval (err )))
2244
2256
dev -> stats .tx_errors ++ ;
2245
2257
else
@@ -2252,19 +2264,18 @@ static int __bpf_redirect_neigh_v6(struct sk_buff *skb, struct net_device *dev)
2252
2264
return ret ;
2253
2265
}
2254
2266
#else
2255
- static int __bpf_redirect_neigh_v6 (struct sk_buff * skb , struct net_device * dev )
2267
+ static int __bpf_redirect_neigh_v6 (struct sk_buff * skb , struct net_device * dev ,
2268
+ struct bpf_nh_params * nh )
2256
2269
{
2257
2270
kfree_skb (skb );
2258
2271
return NET_XMIT_DROP ;
2259
2272
}
2260
2273
#endif /* CONFIG_IPV6 */
2261
2274
2262
2275
#if IS_ENABLED (CONFIG_INET )
2263
- static int bpf_out_neigh_v4 (struct net * net , struct sk_buff * skb )
2276
+ static int bpf_out_neigh_v4 (struct net * net , struct sk_buff * skb ,
2277
+ struct net_device * dev , struct bpf_nh_params * nh )
2264
2278
{
2265
- struct dst_entry * dst = skb_dst (skb );
2266
- struct rtable * rt = container_of (dst , struct rtable , dst );
2267
- struct net_device * dev = dst -> dev ;
2268
2279
u32 hh_len = LL_RESERVED_SPACE (dev );
2269
2280
struct neighbour * neigh ;
2270
2281
bool is_v6gw = false;
@@ -2292,7 +2303,21 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb)
2292
2303
}
2293
2304
2294
2305
rcu_read_lock_bh ();
2295
- neigh = ip_neigh_for_gw (rt , skb , & is_v6gw );
2306
+ if (!nh ) {
2307
+ struct dst_entry * dst = skb_dst (skb );
2308
+ struct rtable * rt = container_of (dst , struct rtable , dst );
2309
+
2310
+ neigh = ip_neigh_for_gw (rt , skb , & is_v6gw );
2311
+ } else if (nh -> nh_family == AF_INET6 ) {
2312
+ neigh = ip_neigh_gw6 (dev , & nh -> ipv6_nh );
2313
+ is_v6gw = true;
2314
+ } else if (nh -> nh_family == AF_INET ) {
2315
+ neigh = ip_neigh_gw4 (dev , nh -> ipv4_nh );
2316
+ } else {
2317
+ rcu_read_unlock_bh ();
2318
+ goto out_drop ;
2319
+ }
2320
+
2296
2321
if (likely (!IS_ERR (neigh ))) {
2297
2322
int ret ;
2298
2323
@@ -2309,33 +2334,37 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb)
2309
2334
return - ENETDOWN ;
2310
2335
}
2311
2336
2312
- static int __bpf_redirect_neigh_v4 (struct sk_buff * skb , struct net_device * dev )
2337
+ static int __bpf_redirect_neigh_v4 (struct sk_buff * skb , struct net_device * dev ,
2338
+ struct bpf_nh_params * nh )
2313
2339
{
2314
2340
const struct iphdr * ip4h = ip_hdr (skb );
2315
2341
struct net * net = dev_net (dev );
2316
2342
int err , ret = NET_XMIT_DROP ;
2317
- struct rtable * rt ;
2318
- struct flowi4 fl4 = {
2319
- .flowi4_flags = FLOWI_FLAG_ANYSRC ,
2320
- .flowi4_mark = skb -> mark ,
2321
- .flowi4_tos = RT_TOS (ip4h -> tos ),
2322
- .flowi4_oif = dev -> ifindex ,
2323
- .flowi4_proto = ip4h -> protocol ,
2324
- .daddr = ip4h -> daddr ,
2325
- .saddr = ip4h -> saddr ,
2326
- };
2327
2343
2328
- rt = ip_route_output_flow (net , & fl4 , NULL );
2329
- if (IS_ERR (rt ))
2330
- goto out_drop ;
2331
- if (rt -> rt_type != RTN_UNICAST && rt -> rt_type != RTN_LOCAL ) {
2332
- ip_rt_put (rt );
2333
- goto out_drop ;
2334
- }
2344
+ if (!nh ) {
2345
+ struct flowi4 fl4 = {
2346
+ .flowi4_flags = FLOWI_FLAG_ANYSRC ,
2347
+ .flowi4_mark = skb -> mark ,
2348
+ .flowi4_tos = RT_TOS (ip4h -> tos ),
2349
+ .flowi4_oif = dev -> ifindex ,
2350
+ .flowi4_proto = ip4h -> protocol ,
2351
+ .daddr = ip4h -> daddr ,
2352
+ .saddr = ip4h -> saddr ,
2353
+ };
2354
+ struct rtable * rt ;
2355
+
2356
+ rt = ip_route_output_flow (net , & fl4 , NULL );
2357
+ if (IS_ERR (rt ))
2358
+ goto out_drop ;
2359
+ if (rt -> rt_type != RTN_UNICAST && rt -> rt_type != RTN_LOCAL ) {
2360
+ ip_rt_put (rt );
2361
+ goto out_drop ;
2362
+ }
2335
2363
2336
- skb_dst_set (skb , & rt -> dst );
2364
+ skb_dst_set (skb , & rt -> dst );
2365
+ }
2337
2366
2338
- err = bpf_out_neigh_v4 (net , skb );
2367
+ err = bpf_out_neigh_v4 (net , skb , dev , nh );
2339
2368
if (unlikely (net_xmit_eval (err )))
2340
2369
dev -> stats .tx_errors ++ ;
2341
2370
else
@@ -2348,14 +2377,16 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev)
2348
2377
return ret ;
2349
2378
}
2350
2379
#else
2351
- static int __bpf_redirect_neigh_v4 (struct sk_buff * skb , struct net_device * dev )
2380
+ static int __bpf_redirect_neigh_v4 (struct sk_buff * skb , struct net_device * dev ,
2381
+ struct bpf_nh_params * nh )
2352
2382
{
2353
2383
kfree_skb (skb );
2354
2384
return NET_XMIT_DROP ;
2355
2385
}
2356
2386
#endif /* CONFIG_INET */
2357
2387
2358
- static int __bpf_redirect_neigh (struct sk_buff * skb , struct net_device * dev )
2388
+ static int __bpf_redirect_neigh (struct sk_buff * skb , struct net_device * dev ,
2389
+ struct bpf_nh_params * nh )
2359
2390
{
2360
2391
struct ethhdr * ethh = eth_hdr (skb );
2361
2392
@@ -2370,9 +2401,9 @@ static int __bpf_redirect_neigh(struct sk_buff *skb, struct net_device *dev)
2370
2401
skb_reset_network_header (skb );
2371
2402
2372
2403
if (skb -> protocol == htons (ETH_P_IP ))
2373
- return __bpf_redirect_neigh_v4 (skb , dev );
2404
+ return __bpf_redirect_neigh_v4 (skb , dev , nh );
2374
2405
else if (skb -> protocol == htons (ETH_P_IPV6 ))
2375
- return __bpf_redirect_neigh_v6 (skb , dev );
2406
+ return __bpf_redirect_neigh_v6 (skb , dev , nh );
2376
2407
out :
2377
2408
kfree_skb (skb );
2378
2409
return - ENOTSUPP ;
@@ -2382,7 +2413,8 @@ static int __bpf_redirect_neigh(struct sk_buff *skb, struct net_device *dev)
2382
2413
enum {
2383
2414
BPF_F_NEIGH = (1ULL << 1 ),
2384
2415
BPF_F_PEER = (1ULL << 2 ),
2385
- #define BPF_F_REDIRECT_INTERNAL (BPF_F_NEIGH | BPF_F_PEER)
2416
+ BPF_F_NEXTHOP = (1ULL << 3 ),
2417
+ #define BPF_F_REDIRECT_INTERNAL (BPF_F_NEIGH | BPF_F_PEER | BPF_F_NEXTHOP)
2386
2418
};
2387
2419
2388
2420
BPF_CALL_3 (bpf_clone_redirect , struct sk_buff * , skb , u32 , ifindex , u64 , flags )
@@ -2455,7 +2487,8 @@ int skb_do_redirect(struct sk_buff *skb)
2455
2487
return - EAGAIN ;
2456
2488
}
2457
2489
return flags & BPF_F_NEIGH ?
2458
- __bpf_redirect_neigh (skb , dev ) :
2490
+ __bpf_redirect_neigh (skb , dev , flags & BPF_F_NEXTHOP ?
2491
+ & ri -> nh : NULL ) :
2459
2492
__bpf_redirect (skb , dev , flags );
2460
2493
out_drop :
2461
2494
kfree_skb (skb );
@@ -2504,16 +2537,21 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = {
2504
2537
.arg2_type = ARG_ANYTHING ,
2505
2538
};
2506
2539
2507
- BPF_CALL_2 (bpf_redirect_neigh , u32 , ifindex , u64 , flags )
2540
+ BPF_CALL_4 (bpf_redirect_neigh , u32 , ifindex , struct bpf_redir_neigh * , params ,
2541
+ int , plen , u64 , flags )
2508
2542
{
2509
2543
struct bpf_redirect_info * ri = this_cpu_ptr (& bpf_redirect_info );
2510
2544
2511
- if (unlikely (flags ))
2545
+ if (unlikely (( plen && plen < sizeof ( * params )) || flags ))
2512
2546
return TC_ACT_SHOT ;
2513
2547
2514
- ri -> flags = BPF_F_NEIGH ;
2548
+ ri -> flags = BPF_F_NEIGH | ( plen ? BPF_F_NEXTHOP : 0 ) ;
2515
2549
ri -> tgt_index = ifindex ;
2516
2550
2551
+ BUILD_BUG_ON (sizeof (struct bpf_redir_neigh ) != sizeof (struct bpf_nh_params ));
2552
+ if (plen )
2553
+ memcpy (& ri -> nh , params , sizeof (ri -> nh ));
2554
+
2517
2555
return TC_ACT_REDIRECT ;
2518
2556
}
2519
2557
@@ -2522,7 +2560,9 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {
2522
2560
.gpl_only = false,
2523
2561
.ret_type = RET_INTEGER ,
2524
2562
.arg1_type = ARG_ANYTHING ,
2525
- .arg2_type = ARG_ANYTHING ,
2563
+ .arg2_type = ARG_PTR_TO_MEM_OR_NULL ,
2564
+ .arg3_type = ARG_CONST_SIZE_OR_ZERO ,
2565
+ .arg4_type = ARG_ANYTHING ,
2526
2566
};
2527
2567
2528
2568
BPF_CALL_2 (bpf_msg_apply_bytes , struct sk_msg * , msg , u32 , bytes )
0 commit comments