Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'fib-rule-selftest'

Roopa Prabhu says:

====================
fib rule selftest

This series adds a new test to test fib rules.
ip route get is used to test fib rule matches.
This series also extends ip route get to match on
sport and dport to test recent support of sport
and dport fib rule match.

v2 - address ido's commemt to make sport dport
ip route get to work correctly for input route
get. I don't support ip route get on ip-proto match yet.
ip route get creates a udp packet and i have left
it at that. We could extend ip route get to support
a few ip proto matches in followup patches.

v3 - Support ip_proto (only tcp and udp) match in getroute.
dropped printing of new match attrs in ip route get,
because ipv6 does not print it. And ipv6 currrently shares
the dump api with ipv6 notify and its better to not add them
to the notify api. dropped it to keep the api consistent between
ipv4 and ipv6 (though uid is already printed in the ipv4 case).
If we need it, both ipv4 and ipv6 can be enhanced to provide
a separate get api. Moved skb creation for ipv4 to a separate func.

v4 - drop separate skb for netlink and fix concerns around rcu and netlink
reply (as pointed out by DaveM). I now try to reset the skb after the route
lookup and before the netlink send (testing shows this is ok. More eyes and
any feedback here will be helpful)

v5 - dropped RTA_TABLE ipv4_rtm_policy update from this series and posted
it separately for net (feedback from Eric)
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+406 -41
+3
include/net/ip.h
··· 664 664 int ip_misc_proc_init(void); 665 665 #endif 666 666 667 + int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto, 668 + struct netlink_ext_ack *extack); 669 + 667 670 #endif /* _IP_H */
+3
include/uapi/linux/rtnetlink.h
··· 327 327 RTA_PAD, 328 328 RTA_UID, 329 329 RTA_TTL_PROPAGATE, 330 + RTA_IP_PROTO, 331 + RTA_SPORT, 332 + RTA_DPORT, 330 333 __RTA_MAX 331 334 }; 332 335
+1 -1
net/ipv4/Makefile
··· 14 14 udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ 15 15 fib_frontend.o fib_semantics.o fib_trie.o fib_notifier.o \ 16 16 inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o \ 17 - metrics.o 17 + metrics.o netlink.o 18 18 19 19 obj-$(CONFIG_BPFILTER) += bpfilter/ 20 20
+3
net/ipv4/fib_frontend.c
··· 649 649 [RTA_ENCAP] = { .type = NLA_NESTED }, 650 650 [RTA_UID] = { .type = NLA_U32 }, 651 651 [RTA_MARK] = { .type = NLA_U32 }, 652 + [RTA_IP_PROTO] = { .type = NLA_U8 }, 653 + [RTA_SPORT] = { .type = NLA_U16 }, 654 + [RTA_DPORT] = { .type = NLA_U16 }, 652 655 }; 653 656 654 657 static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
+23
net/ipv4/netlink.c
··· 1 + #include <linux/netlink.h> 2 + #include <linux/rtnetlink.h> 3 + #include <linux/types.h> 4 + #include <net/net_namespace.h> 5 + #include <net/netlink.h> 6 + #include <net/ip.h> 7 + 8 + int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto, 9 + struct netlink_ext_ack *extack) 10 + { 11 + *ip_proto = nla_get_u8(attr); 12 + 13 + switch (*ip_proto) { 14 + case IPPROTO_TCP: 15 + case IPPROTO_UDP: 16 + case IPPROTO_ICMP: 17 + return 0; 18 + default: 19 + NL_SET_ERR_MSG(extack, "Unsupported ip proto"); 20 + return -EOPNOTSUPP; 21 + } 22 + } 23 + EXPORT_SYMBOL_GPL(rtm_getroute_parse_ip_proto);
+107 -39
net/ipv4/route.c
··· 2574 2574 EXPORT_SYMBOL_GPL(ip_route_output_flow); 2575 2575 2576 2576 /* called with rcu_read_lock held */ 2577 - static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id, 2578 - struct flowi4 *fl4, struct sk_buff *skb, u32 portid, 2579 - u32 seq) 2577 + static int rt_fill_info(struct net *net, __be32 dst, __be32 src, 2578 + struct rtable *rt, u32 table_id, struct flowi4 *fl4, 2579 + struct sk_buff *skb, u32 portid, u32 seq) 2580 2580 { 2581 - struct rtable *rt = skb_rtable(skb); 2582 2581 struct rtmsg *r; 2583 2582 struct nlmsghdr *nlh; 2584 2583 unsigned long expires = 0; ··· 2673 2674 } 2674 2675 } else 2675 2676 #endif 2676 - if (nla_put_u32(skb, RTA_IIF, skb->dev->ifindex)) 2677 + if (nla_put_u32(skb, RTA_IIF, fl4->flowi4_iif)) 2677 2678 goto nla_put_failure; 2678 2679 } 2679 2680 ··· 2688 2689 return -EMSGSIZE; 2689 2690 } 2690 2691 2692 + static struct sk_buff *inet_rtm_getroute_build_skb(__be32 src, __be32 dst, 2693 + u8 ip_proto, __be16 sport, 2694 + __be16 dport) 2695 + { 2696 + struct sk_buff *skb; 2697 + struct iphdr *iph; 2698 + 2699 + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 2700 + if (!skb) 2701 + return NULL; 2702 + 2703 + /* Reserve room for dummy headers, this skb can pass 2704 + * through good chunk of routing engine. 2705 + */ 2706 + skb_reset_mac_header(skb); 2707 + skb_reset_network_header(skb); 2708 + skb->protocol = htons(ETH_P_IP); 2709 + iph = skb_put(skb, sizeof(struct iphdr)); 2710 + iph->protocol = ip_proto; 2711 + iph->saddr = src; 2712 + iph->daddr = dst; 2713 + iph->version = 0x4; 2714 + iph->frag_off = 0; 2715 + iph->ihl = 0x5; 2716 + skb_set_transport_header(skb, skb->len); 2717 + 2718 + switch (iph->protocol) { 2719 + case IPPROTO_UDP: { 2720 + struct udphdr *udph; 2721 + 2722 + udph = skb_put_zero(skb, sizeof(struct udphdr)); 2723 + udph->source = sport; 2724 + udph->dest = dport; 2725 + udph->len = sizeof(struct udphdr); 2726 + udph->check = 0; 2727 + break; 2728 + } 2729 + case IPPROTO_TCP: { 2730 + struct tcphdr *tcph; 2731 + 2732 + tcph = skb_put_zero(skb, sizeof(struct tcphdr)); 2733 + tcph->source = sport; 2734 + tcph->dest = dport; 2735 + tcph->doff = sizeof(struct tcphdr) / 4; 2736 + tcph->rst = 1; 2737 + tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), 2738 + src, dst, 0); 2739 + break; 2740 + } 2741 + case IPPROTO_ICMP: { 2742 + struct icmphdr *icmph; 2743 + 2744 + icmph = skb_put_zero(skb, sizeof(struct icmphdr)); 2745 + icmph->type = ICMP_ECHO; 2746 + icmph->code = 0; 2747 + } 2748 + } 2749 + 2750 + return skb; 2751 + } 2752 + 2691 2753 static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, 2692 2754 struct netlink_ext_ack *extack) 2693 2755 { 2694 2756 struct net *net = sock_net(in_skb->sk); 2695 - struct rtmsg *rtm; 2696 2757 struct nlattr *tb[RTA_MAX+1]; 2758 + u32 table_id = RT_TABLE_MAIN; 2759 + __be16 sport = 0, dport = 0; 2697 2760 struct fib_result res = {}; 2761 + u8 ip_proto = IPPROTO_UDP; 2698 2762 struct rtable *rt = NULL; 2763 + struct sk_buff *skb; 2764 + struct rtmsg *rtm; 2699 2765 struct flowi4 fl4; 2700 2766 __be32 dst = 0; 2701 2767 __be32 src = 0; 2768 + kuid_t uid; 2702 2769 u32 iif; 2703 2770 int err; 2704 2771 int mark; 2705 - struct sk_buff *skb; 2706 - u32 table_id = RT_TABLE_MAIN; 2707 - kuid_t uid; 2708 2772 2709 2773 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy, 2710 2774 extack); 2711 2775 if (err < 0) 2712 - goto errout; 2776 + return err; 2713 2777 2714 2778 rtm = nlmsg_data(nlh); 2715 - 2716 - skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 2717 - if (!skb) { 2718 - err = -ENOBUFS; 2719 - goto errout; 2720 - } 2721 - 2722 - /* Reserve room for dummy headers, this skb can pass 2723 - through good chunk of routing engine. 2724 - */ 2725 - skb_reset_mac_header(skb); 2726 - skb_reset_network_header(skb); 2727 - 2728 2779 src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0; 2729 2780 dst = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0; 2730 2781 iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; ··· 2784 2735 else 2785 2736 uid = (iif ? INVALID_UID : current_uid()); 2786 2737 2787 - /* Bugfix: need to give ip_route_input enough of an IP header to 2788 - * not gag. 2789 - */ 2790 - ip_hdr(skb)->protocol = IPPROTO_UDP; 2791 - ip_hdr(skb)->saddr = src; 2792 - ip_hdr(skb)->daddr = dst; 2738 + if (tb[RTA_IP_PROTO]) { 2739 + err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO], 2740 + &ip_proto, extack); 2741 + if (err) 2742 + return err; 2743 + } 2793 2744 2794 - skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); 2745 + if (tb[RTA_SPORT]) 2746 + sport = nla_get_be16(tb[RTA_SPORT]); 2747 + 2748 + if (tb[RTA_DPORT]) 2749 + dport = nla_get_be16(tb[RTA_DPORT]); 2750 + 2751 + skb = inet_rtm_getroute_build_skb(src, dst, ip_proto, sport, dport); 2752 + if (!skb) 2753 + return -ENOBUFS; 2795 2754 2796 2755 memset(&fl4, 0, sizeof(fl4)); 2797 2756 fl4.daddr = dst; ··· 2808 2751 fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0; 2809 2752 fl4.flowi4_mark = mark; 2810 2753 fl4.flowi4_uid = uid; 2754 + if (sport) 2755 + fl4.fl4_sport = sport; 2756 + if (dport) 2757 + fl4.fl4_dport = dport; 2758 + fl4.flowi4_proto = ip_proto; 2811 2759 2812 2760 rcu_read_lock(); 2813 2761 ··· 2822 2760 dev = dev_get_by_index_rcu(net, iif); 2823 2761 if (!dev) { 2824 2762 err = -ENODEV; 2825 - goto errout_free; 2763 + goto errout_rcu; 2826 2764 } 2827 2765 2828 - skb->protocol = htons(ETH_P_IP); 2766 + fl4.flowi4_iif = iif; /* for rt_fill_info */ 2829 2767 skb->dev = dev; 2830 2768 skb->mark = mark; 2831 2769 err = ip_route_input_rcu(skb, dst, src, rtm->rtm_tos, ··· 2845 2783 } 2846 2784 2847 2785 if (err) 2848 - goto errout_free; 2786 + goto errout_rcu; 2849 2787 2850 2788 if (rtm->rtm_flags & RTM_F_NOTIFY) 2851 2789 rt->rt_flags |= RTCF_NOTIFY; ··· 2853 2791 if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE) 2854 2792 table_id = res.table ? res.table->tb_id : 0; 2855 2793 2794 + /* reset skb for netlink reply msg */ 2795 + skb_trim(skb, 0); 2796 + skb_reset_network_header(skb); 2797 + skb_reset_transport_header(skb); 2798 + skb_reset_mac_header(skb); 2799 + 2856 2800 if (rtm->rtm_flags & RTM_F_FIB_MATCH) { 2857 2801 if (!res.fi) { 2858 2802 err = fib_props[res.type].error; 2859 2803 if (!err) 2860 2804 err = -EHOSTUNREACH; 2861 - goto errout_free; 2805 + goto errout_rcu; 2862 2806 } 2863 2807 err = fib_dump_info(skb, NETLINK_CB(in_skb).portid, 2864 2808 nlh->nlmsg_seq, RTM_NEWROUTE, table_id, 2865 2809 rt->rt_type, res.prefix, res.prefixlen, 2866 2810 fl4.flowi4_tos, res.fi, 0); 2867 2811 } else { 2868 - err = rt_fill_info(net, dst, src, table_id, &fl4, skb, 2812 + err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb, 2869 2813 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq); 2870 2814 } 2871 2815 if (err < 0) 2872 - goto errout_free; 2816 + goto errout_rcu; 2873 2817 2874 2818 rcu_read_unlock(); 2875 2819 2876 2820 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); 2877 - errout: 2878 - return err; 2879 2821 2880 2822 errout_free: 2823 + return err; 2824 + errout_rcu: 2881 2825 rcu_read_unlock(); 2882 2826 kfree_skb(skb); 2883 - goto errout; 2827 + goto errout_free; 2884 2828 } 2885 2829 2886 2830 void ip_rt_multicast_event(struct in_device *in_dev)
+17
net/ipv6/route.c
··· 63 63 #include <net/lwtunnel.h> 64 64 #include <net/ip_tunnels.h> 65 65 #include <net/l3mdev.h> 66 + #include <net/ip.h> 66 67 #include <trace/events/fib6.h> 67 68 68 69 #include <linux/uaccess.h> ··· 4084 4083 [RTA_UID] = { .type = NLA_U32 }, 4085 4084 [RTA_MARK] = { .type = NLA_U32 }, 4086 4085 [RTA_TABLE] = { .type = NLA_U32 }, 4086 + [RTA_IP_PROTO] = { .type = NLA_U8 }, 4087 + [RTA_SPORT] = { .type = NLA_U16 }, 4088 + [RTA_DPORT] = { .type = NLA_U16 }, 4087 4089 }; 4088 4090 4089 4091 static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, ··· 4798 4794 nla_get_u32(tb[RTA_UID])); 4799 4795 else 4800 4796 fl6.flowi6_uid = iif ? INVALID_UID : current_uid(); 4797 + 4798 + if (tb[RTA_SPORT]) 4799 + fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]); 4800 + 4801 + if (tb[RTA_DPORT]) 4802 + fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]); 4803 + 4804 + if (tb[RTA_IP_PROTO]) { 4805 + err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO], 4806 + &fl6.flowi6_proto, extack); 4807 + if (err) 4808 + goto errout; 4809 + } 4801 4810 4802 4811 if (iif) { 4803 4812 struct net_device *dev;
+1 -1
tools/testing/selftests/net/Makefile
··· 6 6 7 7 TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh 8 8 TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh 9 - TEST_PROGS += udpgso_bench.sh 9 + TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh 10 10 TEST_PROGS_EXTENDED := in_netns.sh 11 11 TEST_GEN_FILES = socket 12 12 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy
+248
tools/testing/selftests/net/fib_rule_tests.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # This test is for checking IPv4 and IPv6 FIB rules API 5 + 6 + ret=0 7 + 8 + PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 9 + IP="ip -netns testns" 10 + 11 + RTABLE=100 12 + GW_IP4=192.51.100.2 13 + SRC_IP=192.51.100.3 14 + GW_IP6=2001:db8:1::2 15 + SRC_IP6=2001:db8:1::3 16 + 17 + DEV_ADDR=192.51.100.1 18 + DEV=dummy0 19 + 20 + log_test() 21 + { 22 + local rc=$1 23 + local expected=$2 24 + local msg="$3" 25 + 26 + if [ ${rc} -eq ${expected} ]; then 27 + nsuccess=$((nsuccess+1)) 28 + printf "\n TEST: %-50s [ OK ]\n" "${msg}" 29 + else 30 + nfail=$((nfail+1)) 31 + printf "\n TEST: %-50s [FAIL]\n" "${msg}" 32 + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 33 + echo 34 + echo "hit enter to continue, 'q' to quit" 35 + read a 36 + [ "$a" = "q" ] && exit 1 37 + fi 38 + fi 39 + } 40 + 41 + log_section() 42 + { 43 + echo 44 + echo "######################################################################" 45 + echo "TEST SECTION: $*" 46 + echo "######################################################################" 47 + } 48 + 49 + setup() 50 + { 51 + set -e 52 + ip netns add testns 53 + $IP link set dev lo up 54 + 55 + $IP link add dummy0 type dummy 56 + $IP link set dev dummy0 up 57 + $IP address add 198.51.100.1/24 dev dummy0 58 + $IP -6 address add 2001:db8:1::1/64 dev dummy0 59 + 60 + set +e 61 + } 62 + 63 + cleanup() 64 + { 65 + $IP link del dev dummy0 &> /dev/null 66 + ip netns del testns 67 + } 68 + 69 + fib_check_iproute_support() 70 + { 71 + ip rule help 2>&1 | grep -q $1 72 + if [ $? -ne 0 ]; then 73 + echo "SKIP: iproute2 iprule too old, missing $1 match" 74 + return 1 75 + fi 76 + 77 + ip route get help 2>&1 | grep -q $2 78 + if [ $? -ne 0 ]; then 79 + echo "SKIP: iproute2 get route too old, missing $2 match" 80 + return 1 81 + fi 82 + 83 + return 0 84 + } 85 + 86 + fib_rule6_del() 87 + { 88 + $IP -6 rule del $1 89 + log_test $? 0 "rule6 del $1" 90 + } 91 + 92 + fib_rule6_del_by_pref() 93 + { 94 + pref=$($IP -6 rule show | grep "$1 lookup $TABLE" | cut -d ":" -f 1) 95 + $IP -6 rule del pref $pref 96 + } 97 + 98 + fib_rule6_test_match_n_redirect() 99 + { 100 + local match="$1" 101 + local getmatch="$2" 102 + 103 + $IP -6 rule add $match table $RTABLE 104 + $IP -6 route get $GW_IP6 $getmatch | grep -q "table $RTABLE" 105 + log_test $? 0 "rule6 check: $1" 106 + 107 + fib_rule6_del_by_pref "$match" 108 + log_test $? 0 "rule6 del by pref: $match" 109 + } 110 + 111 + fib_rule6_test() 112 + { 113 + # setup the fib rule redirect route 114 + $IP -6 route add table $RTABLE default via $GW_IP6 dev $DEV onlink 115 + 116 + match="oif $DEV" 117 + fib_rule6_test_match_n_redirect "$match" "$match" "oif redirect to table" 118 + 119 + match="from $SRC_IP6 iif $DEV" 120 + fib_rule6_test_match_n_redirect "$match" "$match" "iif redirect to table" 121 + 122 + match="tos 0x10" 123 + fib_rule6_test_match_n_redirect "$match" "$match" "tos redirect to table" 124 + 125 + match="fwmark 0x64" 126 + getmatch="mark 0x64" 127 + fib_rule6_test_match_n_redirect "$match" "$getmatch" "fwmark redirect to table" 128 + 129 + fib_check_iproute_support "uidrange" "uid" 130 + if [ $? -eq 0 ]; then 131 + match="uidrange 100-100" 132 + getmatch="uid 100" 133 + fib_rule6_test_match_n_redirect "$match" "$getmatch" "uid redirect to table" 134 + fi 135 + 136 + fib_check_iproute_support "sport" "sport" 137 + if [ $? -eq 0 ]; then 138 + match="sport 666 dport 777" 139 + fib_rule6_test_match_n_redirect "$match" "$match" "sport and dport redirect to table" 140 + fi 141 + 142 + fib_check_iproute_support "ipproto" "ipproto" 143 + if [ $? -eq 0 ]; then 144 + match="ipproto tcp" 145 + fib_rule6_test_match_n_redirect "$match" "$match" "ipproto match" 146 + fi 147 + 148 + fib_check_iproute_support "ipproto" "ipproto" 149 + if [ $? -eq 0 ]; then 150 + match="ipproto icmp" 151 + fib_rule6_test_match_n_redirect "$match" "$match" "ipproto icmp match" 152 + fi 153 + } 154 + 155 + fib_rule4_del() 156 + { 157 + $IP rule del $1 158 + log_test $? 0 "del $1" 159 + } 160 + 161 + fib_rule4_del_by_pref() 162 + { 163 + pref=$($IP rule show | grep "$1 lookup $TABLE" | cut -d ":" -f 1) 164 + $IP rule del pref $pref 165 + } 166 + 167 + fib_rule4_test_match_n_redirect() 168 + { 169 + local match="$1" 170 + local getmatch="$2" 171 + 172 + $IP rule add $match table $RTABLE 173 + $IP route get $GW_IP4 $getmatch | grep -q "table $RTABLE" 174 + log_test $? 0 "rule4 check: $1" 175 + 176 + fib_rule4_del_by_pref "$match" 177 + log_test $? 0 "rule4 del by pref: $match" 178 + } 179 + 180 + fib_rule4_test() 181 + { 182 + # setup the fib rule redirect route 183 + $IP route add table $RTABLE default via $GW_IP4 dev $DEV onlink 184 + 185 + match="oif $DEV" 186 + fib_rule4_test_match_n_redirect "$match" "$match" "oif redirect to table" 187 + 188 + match="from $SRC_IP iif $DEV" 189 + fib_rule4_test_match_n_redirect "$match" "$match" "iif redirect to table" 190 + 191 + match="tos 0x10" 192 + fib_rule4_test_match_n_redirect "$match" "$match" "tos redirect to table" 193 + 194 + match="fwmark 0x64" 195 + getmatch="mark 0x64" 196 + fib_rule4_test_match_n_redirect "$match" "$getmatch" "fwmark redirect to table" 197 + 198 + fib_check_iproute_support "uidrange" "uid" 199 + if [ $? -eq 0 ]; then 200 + match="uidrange 100-100" 201 + getmatch="uid 100" 202 + fib_rule4_test_match_n_redirect "$match" "$getmatch" "uid redirect to table" 203 + fi 204 + 205 + fib_check_iproute_support "sport" "sport" 206 + if [ $? -eq 0 ]; then 207 + match="sport 666 dport 777" 208 + fib_rule4_test_match_n_redirect "$match" "$match" "sport and dport redirect to table" 209 + fi 210 + 211 + fib_check_iproute_support "ipproto" "ipproto" 212 + if [ $? -eq 0 ]; then 213 + match="ipproto tcp" 214 + fib_rule4_test_match_n_redirect "$match" "$match" "ipproto tcp match" 215 + fi 216 + 217 + fib_check_iproute_support "ipproto" "ipproto" 218 + if [ $? -eq 0 ]; then 219 + match="ipproto icmp" 220 + fib_rule4_test_match_n_redirect "$match" "$match" "ipproto icmp match" 221 + fi 222 + } 223 + 224 + run_fibrule_tests() 225 + { 226 + log_section "IPv4 fib rule" 227 + fib_rule4_test 228 + log_section "IPv6 fib rule" 229 + fib_rule6_test 230 + } 231 + 232 + if [ "$(id -u)" -ne 0 ];then 233 + echo "SKIP: Need root privileges" 234 + exit 0 235 + fi 236 + 237 + if [ ! -x "$(command -v ip)" ]; then 238 + echo "SKIP: Could not run test without ip tool" 239 + exit 0 240 + fi 241 + 242 + # start clean 243 + cleanup &> /dev/null 244 + setup 245 + run_fibrule_tests 246 + cleanup 247 + 248 + exit $ret