@@ -2165,12 +2165,12 @@ static int __bpf_redirect(struct sk_buff *skb, struct net_device *dev,
21652165}
21662166
21672167#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 )
21692170{
2170- struct dst_entry * dst = skb_dst (skb );
2171- struct net_device * dev = dst -> dev ;
21722171 u32 hh_len = LL_RESERVED_SPACE (dev );
21732172 const struct in6_addr * nexthop ;
2173+ struct dst_entry * dst = NULL ;
21742174 struct neighbour * neigh ;
21752175
21762176 if (dev_xmit_recursion ()) {
@@ -2196,8 +2196,13 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb)
21962196 }
21972197
21982198 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+ }
22012206 neigh = ip_neigh_gw6 (dev , nexthop );
22022207 if (likely (!IS_ERR (neigh ))) {
22032208 int ret ;
@@ -2210,36 +2215,43 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb)
22102215 return ret ;
22112216 }
22122217 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 );
22152221out_drop :
22162222 kfree_skb (skb );
22172223 return - ENETDOWN ;
22182224}
22192225
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 )
22212228{
22222229 const struct ipv6hdr * ip6h = ipv6_hdr (skb );
22232230 struct net * net = dev_net (dev );
22242231 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- };
22352232
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 ;
22392248
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+ }
22412253
2242- err = bpf_out_neigh_v6 (net , skb );
2254+ err = bpf_out_neigh_v6 (net , skb , dev , nh );
22432255 if (unlikely (net_xmit_eval (err )))
22442256 dev -> stats .tx_errors ++ ;
22452257 else
@@ -2252,19 +2264,18 @@ static int __bpf_redirect_neigh_v6(struct sk_buff *skb, struct net_device *dev)
22522264 return ret ;
22532265}
22542266#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 )
22562269{
22572270 kfree_skb (skb );
22582271 return NET_XMIT_DROP ;
22592272}
22602273#endif /* CONFIG_IPV6 */
22612274
22622275#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 )
22642278{
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 ;
22682279 u32 hh_len = LL_RESERVED_SPACE (dev );
22692280 struct neighbour * neigh ;
22702281 bool is_v6gw = false;
@@ -2292,7 +2303,21 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb)
22922303 }
22932304
22942305 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+
22962321 if (likely (!IS_ERR (neigh ))) {
22972322 int ret ;
22982323
@@ -2309,33 +2334,37 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb)
23092334 return - ENETDOWN ;
23102335}
23112336
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 )
23132339{
23142340 const struct iphdr * ip4h = ip_hdr (skb );
23152341 struct net * net = dev_net (dev );
23162342 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- };
23272343
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+ }
23352363
2336- skb_dst_set (skb , & rt -> dst );
2364+ skb_dst_set (skb , & rt -> dst );
2365+ }
23372366
2338- err = bpf_out_neigh_v4 (net , skb );
2367+ err = bpf_out_neigh_v4 (net , skb , dev , nh );
23392368 if (unlikely (net_xmit_eval (err )))
23402369 dev -> stats .tx_errors ++ ;
23412370 else
@@ -2348,14 +2377,16 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev)
23482377 return ret ;
23492378}
23502379#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 )
23522382{
23532383 kfree_skb (skb );
23542384 return NET_XMIT_DROP ;
23552385}
23562386#endif /* CONFIG_INET */
23572387
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 )
23592390{
23602391 struct ethhdr * ethh = eth_hdr (skb );
23612392
@@ -2370,9 +2401,9 @@ static int __bpf_redirect_neigh(struct sk_buff *skb, struct net_device *dev)
23702401 skb_reset_network_header (skb );
23712402
23722403 if (skb -> protocol == htons (ETH_P_IP ))
2373- return __bpf_redirect_neigh_v4 (skb , dev );
2404+ return __bpf_redirect_neigh_v4 (skb , dev , nh );
23742405 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 );
23762407out :
23772408 kfree_skb (skb );
23782409 return - ENOTSUPP ;
@@ -2382,7 +2413,8 @@ static int __bpf_redirect_neigh(struct sk_buff *skb, struct net_device *dev)
23822413enum {
23832414 BPF_F_NEIGH = (1ULL << 1 ),
23842415 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)
23862418};
23872419
23882420BPF_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)
24552487 return - EAGAIN ;
24562488 }
24572489 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 ) :
24592492 __bpf_redirect (skb , dev , flags );
24602493out_drop :
24612494 kfree_skb (skb );
@@ -2504,16 +2537,21 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = {
25042537 .arg2_type = ARG_ANYTHING ,
25052538};
25062539
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 )
25082542{
25092543 struct bpf_redirect_info * ri = this_cpu_ptr (& bpf_redirect_info );
25102544
2511- if (unlikely (flags ))
2545+ if (unlikely (( plen && plen < sizeof ( * params )) || flags ))
25122546 return TC_ACT_SHOT ;
25132547
2514- ri -> flags = BPF_F_NEIGH ;
2548+ ri -> flags = BPF_F_NEIGH | ( plen ? BPF_F_NEXTHOP : 0 ) ;
25152549 ri -> tgt_index = ifindex ;
25162550
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+
25172555 return TC_ACT_REDIRECT ;
25182556}
25192557
@@ -2522,7 +2560,9 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {
25222560 .gpl_only = false,
25232561 .ret_type = RET_INTEGER ,
25242562 .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 ,
25262566};
25272567
25282568BPF_CALL_2 (bpf_msg_apply_bytes , struct sk_msg * , msg , u32 , bytes )
0 commit comments