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

Merge branch 'mlxsw-dip-sip-mangling'

Ido Schimmel says:

====================
mlxsw: Add SIP and DIP mangling support

Danielle says:

On Spectrum-2 onwards, it is possible to overwrite SIP and DIP address
of an IPv4 or IPv6 packet in the ACL engine. That corresponds to pedit
munges of, respectively, ip src and ip dst fields, and likewise for ip6.
Offload these munges on the systems where they are supported.

Patchset overview:
Patch #1: introduces SIP_DIP_ACTION and its fields.
Patch #2-#3: adds the new pedit fields, and dispatches on them on
Spectrum-2 and above.
Patch #4 adds a selftest.
====================

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

+394 -9
+77
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
··· 1957 1957 } 1958 1958 EXPORT_SYMBOL(mlxsw_afa_block_append_mcrouter); 1959 1959 1960 + /* SIP DIP Action 1961 + * -------------- 1962 + * The SIP_DIP_ACTION is used for modifying the SIP and DIP fields of the 1963 + * packet, e.g. for NAT. The L3 checksum is updated. Also, if the L4 is TCP or 1964 + * if the L4 is UDP and the checksum field is not zero, then the L4 checksum is 1965 + * updated. 1966 + */ 1967 + 1968 + #define MLXSW_AFA_IP_CODE 0x11 1969 + #define MLXSW_AFA_IP_SIZE 2 1970 + 1971 + enum mlxsw_afa_ip_s_d { 1972 + /* ip refers to dip */ 1973 + MLXSW_AFA_IP_S_D_DIP, 1974 + /* ip refers to sip */ 1975 + MLXSW_AFA_IP_S_D_SIP, 1976 + }; 1977 + 1978 + /* afa_ip_s_d 1979 + * Source or destination. 1980 + */ 1981 + MLXSW_ITEM32(afa, ip, s_d, 0x00, 31, 1); 1982 + 1983 + enum mlxsw_afa_ip_m_l { 1984 + /* LSB: ip[63:0] refers to ip[63:0] */ 1985 + MLXSW_AFA_IP_M_L_LSB, 1986 + /* MSB: ip[63:0] refers to ip[127:64] */ 1987 + MLXSW_AFA_IP_M_L_MSB, 1988 + }; 1989 + 1990 + /* afa_ip_m_l 1991 + * MSB or LSB. 1992 + */ 1993 + MLXSW_ITEM32(afa, ip, m_l, 0x00, 30, 1); 1994 + 1995 + /* afa_ip_ip_63_32 1996 + * Bits [63:32] in the IP address to change to. 1997 + */ 1998 + MLXSW_ITEM32(afa, ip, ip_63_32, 0x08, 0, 32); 1999 + 2000 + /* afa_ip_ip_31_0 2001 + * Bits [31:0] in the IP address to change to. 2002 + */ 2003 + MLXSW_ITEM32(afa, ip, ip_31_0, 0x0C, 0, 32); 2004 + 2005 + static void mlxsw_afa_ip_pack(char *payload, enum mlxsw_afa_ip_s_d s_d, 2006 + enum mlxsw_afa_ip_m_l m_l, u32 ip_31_0, 2007 + u32 ip_63_32) 2008 + { 2009 + mlxsw_afa_ip_s_d_set(payload, s_d); 2010 + mlxsw_afa_ip_m_l_set(payload, m_l); 2011 + mlxsw_afa_ip_ip_31_0_set(payload, ip_31_0); 2012 + mlxsw_afa_ip_ip_63_32_set(payload, ip_63_32); 2013 + } 2014 + 2015 + int mlxsw_afa_block_append_ip(struct mlxsw_afa_block *block, bool is_dip, 2016 + bool is_lsb, u32 val_31_0, u32 val_63_32, 2017 + struct netlink_ext_ack *extack) 2018 + { 2019 + enum mlxsw_afa_ip_s_d s_d = is_dip ? MLXSW_AFA_IP_S_D_DIP : 2020 + MLXSW_AFA_IP_S_D_SIP; 2021 + enum mlxsw_afa_ip_m_l m_l = is_lsb ? MLXSW_AFA_IP_M_L_LSB : 2022 + MLXSW_AFA_IP_M_L_MSB; 2023 + char *act = mlxsw_afa_block_append_action(block, 2024 + MLXSW_AFA_IP_CODE, 2025 + MLXSW_AFA_IP_SIZE); 2026 + 2027 + if (IS_ERR(act)) { 2028 + NL_SET_ERR_MSG_MOD(extack, "Cannot append IP action"); 2029 + return PTR_ERR(act); 2030 + } 2031 + 2032 + mlxsw_afa_ip_pack(act, s_d, m_l, val_31_0, val_63_32); 2033 + return 0; 2034 + } 2035 + EXPORT_SYMBOL(mlxsw_afa_block_append_ip); 2036 + 1960 2037 /* L4 Port Action 1961 2038 * -------------- 1962 2039 * The L4_PORT_ACTION is used for modifying the sport and dport fields of the packet, e.g. for NAT.
+3
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
··· 92 92 int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block, 93 93 u16 expected_irif, u16 min_mtu, 94 94 bool rmid_valid, u32 kvdl_index); 95 + int mlxsw_afa_block_append_ip(struct mlxsw_afa_block *block, bool is_dip, 96 + bool is_lsb, u32 val_31_0, u32 val_63_32, 97 + struct netlink_ext_ack *extack); 95 98 int mlxsw_afa_block_append_l4port(struct mlxsw_afa_block *block, bool is_dport, u16 l4_port, 96 99 struct netlink_ext_ack *extack); 97 100 int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block,
+24 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 820 820 /* spectrum2_kvdl.c */ 821 821 extern const struct mlxsw_sp_kvdl_ops mlxsw_sp2_kvdl_ops; 822 822 823 + enum mlxsw_sp_acl_mangle_field { 824 + MLXSW_SP_ACL_MANGLE_FIELD_IP_DSFIELD, 825 + MLXSW_SP_ACL_MANGLE_FIELD_IP_DSCP, 826 + MLXSW_SP_ACL_MANGLE_FIELD_IP_ECN, 827 + MLXSW_SP_ACL_MANGLE_FIELD_IP_SPORT, 828 + MLXSW_SP_ACL_MANGLE_FIELD_IP_DPORT, 829 + MLXSW_SP_ACL_MANGLE_FIELD_IP4_SIP, 830 + MLXSW_SP_ACL_MANGLE_FIELD_IP4_DIP, 831 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_1, 832 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_2, 833 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_3, 834 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_4, 835 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_1, 836 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_2, 837 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_3, 838 + MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_4, 839 + }; 840 + 823 841 struct mlxsw_sp_acl_rule_info { 824 842 unsigned int priority; 825 843 struct mlxsw_afk_element_values values; ··· 846 828 ingress_bind_blocker:1, 847 829 egress_bind_blocker:1, 848 830 counter_valid:1, 849 - policer_index_valid:1; 831 + policer_index_valid:1, 832 + ipv6_valid:1; 850 833 unsigned int counter_index; 851 834 u16 policer_index; 835 + struct { 836 + u32 prev_val; 837 + enum mlxsw_sp_acl_mangle_field prev_field; 838 + } ipv6; 852 839 }; 853 840 854 841 /* spectrum_flow.c */
+83 -8
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
··· 505 505 extack); 506 506 } 507 507 508 - enum mlxsw_sp_acl_mangle_field { 509 - MLXSW_SP_ACL_MANGLE_FIELD_IP_DSFIELD, 510 - MLXSW_SP_ACL_MANGLE_FIELD_IP_DSCP, 511 - MLXSW_SP_ACL_MANGLE_FIELD_IP_ECN, 512 - MLXSW_SP_ACL_MANGLE_FIELD_IP_SPORT, 513 - MLXSW_SP_ACL_MANGLE_FIELD_IP_DPORT, 514 - }; 515 - 516 508 struct mlxsw_sp_acl_mangle_action { 517 509 enum flow_action_mangle_base htype; 518 510 /* Offset is u32-aligned. */ ··· 553 561 554 562 MLXSW_SP_ACL_MANGLE_ACTION_UDP(0, 0x0000ffff, 16, IP_SPORT), 555 563 MLXSW_SP_ACL_MANGLE_ACTION_UDP(0, 0xffff0000, 0, IP_DPORT), 564 + 565 + MLXSW_SP_ACL_MANGLE_ACTION_IP4(12, 0x00000000, 0, IP4_SIP), 566 + MLXSW_SP_ACL_MANGLE_ACTION_IP4(16, 0x00000000, 0, IP4_DIP), 567 + 568 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(8, 0x00000000, 0, IP6_SIP_1), 569 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(12, 0x00000000, 0, IP6_SIP_2), 570 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(16, 0x00000000, 0, IP6_SIP_3), 571 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(20, 0x00000000, 0, IP6_SIP_4), 572 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(24, 0x00000000, 0, IP6_DIP_1), 573 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(28, 0x00000000, 0, IP6_DIP_2), 574 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(32, 0x00000000, 0, IP6_DIP_3), 575 + MLXSW_SP_ACL_MANGLE_ACTION_IP6(36, 0x00000000, 0, IP6_DIP_4), 556 576 }; 557 577 558 578 static int ··· 603 599 return err; 604 600 } 605 601 602 + static int 603 + mlxsw_sp2_acl_rulei_act_mangle_field_ip_odd(struct mlxsw_sp_acl_rule_info *rulei, 604 + enum mlxsw_sp_acl_mangle_field field, 605 + u32 val, struct netlink_ext_ack *extack) 606 + { 607 + if (!rulei->ipv6_valid) { 608 + rulei->ipv6.prev_val = val; 609 + rulei->ipv6_valid = true; 610 + rulei->ipv6.prev_field = field; 611 + return 0; 612 + } 613 + 614 + NL_SET_ERR_MSG_MOD(extack, "Unsupported mangle field order"); 615 + return -EOPNOTSUPP; 616 + } 617 + 606 618 static int mlxsw_sp2_acl_rulei_act_mangle_field(struct mlxsw_sp *mlxsw_sp, 607 619 struct mlxsw_sp_acl_rule_info *rulei, 608 620 struct mlxsw_sp_acl_mangle_action *mact, ··· 635 615 return mlxsw_afa_block_append_l4port(rulei->act_block, false, val, extack); 636 616 case MLXSW_SP_ACL_MANGLE_FIELD_IP_DPORT: 637 617 return mlxsw_afa_block_append_l4port(rulei->act_block, true, val, extack); 618 + /* IPv4 fields */ 619 + case MLXSW_SP_ACL_MANGLE_FIELD_IP4_SIP: 620 + return mlxsw_afa_block_append_ip(rulei->act_block, false, 621 + true, val, 0, extack); 622 + case MLXSW_SP_ACL_MANGLE_FIELD_IP4_DIP: 623 + return mlxsw_afa_block_append_ip(rulei->act_block, true, 624 + true, val, 0, extack); 625 + /* IPv6 fields */ 626 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_1: 627 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_3: 628 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_1: 629 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_3: 630 + return mlxsw_sp2_acl_rulei_act_mangle_field_ip_odd(rulei, 631 + mact->field, 632 + val, extack); 633 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_2: 634 + if (rulei->ipv6_valid && 635 + rulei->ipv6.prev_field == MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_1) { 636 + rulei->ipv6_valid = false; 637 + return mlxsw_afa_block_append_ip(rulei->act_block, 638 + false, false, val, 639 + rulei->ipv6.prev_val, 640 + extack); 641 + } 642 + break; 643 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_4: 644 + if (rulei->ipv6_valid && 645 + rulei->ipv6.prev_field == MLXSW_SP_ACL_MANGLE_FIELD_IP6_SIP_3) { 646 + rulei->ipv6_valid = false; 647 + return mlxsw_afa_block_append_ip(rulei->act_block, 648 + false, true, val, 649 + rulei->ipv6.prev_val, 650 + extack); 651 + } 652 + break; 653 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_2: 654 + if (rulei->ipv6_valid && 655 + rulei->ipv6.prev_field == MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_1) { 656 + rulei->ipv6_valid = false; 657 + return mlxsw_afa_block_append_ip(rulei->act_block, 658 + true, false, val, 659 + rulei->ipv6.prev_val, 660 + extack); 661 + } 662 + break; 663 + case MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_4: 664 + if (rulei->ipv6_valid && 665 + rulei->ipv6.prev_field == MLXSW_SP_ACL_MANGLE_FIELD_IP6_DIP_3) { 666 + rulei->ipv6_valid = false; 667 + return mlxsw_afa_block_append_ip(rulei->act_block, 668 + true, true, val, 669 + rulei->ipv6.prev_val, 670 + extack); 671 + } 672 + break; 638 673 default: 639 674 break; 640 675 }
+6
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
··· 233 233 return -EOPNOTSUPP; 234 234 } 235 235 } 236 + 237 + if (rulei->ipv6_valid) { 238 + NL_SET_ERR_MSG_MOD(extack, "Unsupported mangle field"); 239 + return -EOPNOTSUPP; 240 + } 241 + 236 242 return 0; 237 243 } 238 244
+201
tools/testing/selftests/net/forwarding/pedit_ip.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # This test sends traffic from H1 to H2. Either on ingress of $swp1, or on 5 + # egress of $swp2, the traffic is acted upon by a pedit action. An ingress 6 + # filter installed on $h2 verifies that the packet looks like expected. 7 + # 8 + # +----------------------+ +----------------------+ 9 + # | H1 | | H2 | 10 + # | + $h1 | | $h2 + | 11 + # | | 192.0.2.1/28 | | 192.0.2.2/28 | | 12 + # +----|-----------------+ +----------------|-----+ 13 + # | | 14 + # +----|----------------------------------------------------------------|-----+ 15 + # | SW | | | 16 + # | +-|----------------------------------------------------------------|-+ | 17 + # | | + $swp1 BR $swp2 + | | 18 + # | +--------------------------------------------------------------------+ | 19 + # +---------------------------------------------------------------------------+ 20 + 21 + ALL_TESTS=" 22 + ping_ipv4 23 + ping_ipv6 24 + test_ip4_src 25 + test_ip4_dst 26 + test_ip6_src 27 + test_ip6_dst 28 + " 29 + 30 + NUM_NETIFS=4 31 + source lib.sh 32 + source tc_common.sh 33 + 34 + h1_create() 35 + { 36 + simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64 37 + } 38 + 39 + h1_destroy() 40 + { 41 + simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64 42 + } 43 + 44 + h2_create() 45 + { 46 + simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64 47 + tc qdisc add dev $h2 clsact 48 + } 49 + 50 + h2_destroy() 51 + { 52 + tc qdisc del dev $h2 clsact 53 + simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64 54 + } 55 + 56 + switch_create() 57 + { 58 + ip link add name br1 up type bridge vlan_filtering 1 59 + ip link set dev $swp1 master br1 60 + ip link set dev $swp1 up 61 + ip link set dev $swp2 master br1 62 + ip link set dev $swp2 up 63 + 64 + tc qdisc add dev $swp1 clsact 65 + tc qdisc add dev $swp2 clsact 66 + } 67 + 68 + switch_destroy() 69 + { 70 + tc qdisc del dev $swp2 clsact 71 + tc qdisc del dev $swp1 clsact 72 + 73 + ip link set dev $swp2 down 74 + ip link set dev $swp2 nomaster 75 + ip link set dev $swp1 down 76 + ip link set dev $swp1 nomaster 77 + ip link del dev br1 78 + } 79 + 80 + setup_prepare() 81 + { 82 + h1=${NETIFS[p1]} 83 + swp1=${NETIFS[p2]} 84 + 85 + swp2=${NETIFS[p3]} 86 + h2=${NETIFS[p4]} 87 + 88 + h2mac=$(mac_get $h2) 89 + 90 + vrf_prepare 91 + h1_create 92 + h2_create 93 + switch_create 94 + } 95 + 96 + cleanup() 97 + { 98 + pre_cleanup 99 + 100 + switch_destroy 101 + h2_destroy 102 + h1_destroy 103 + vrf_cleanup 104 + } 105 + 106 + ping_ipv4() 107 + { 108 + ping_test $h1 192.0.2.2 109 + } 110 + 111 + ping_ipv6() 112 + { 113 + ping6_test $h1 2001:db8:1::2 114 + } 115 + 116 + do_test_pedit_ip() 117 + { 118 + local pedit_locus=$1; shift 119 + local pedit_action=$1; shift 120 + local match_prot=$1; shift 121 + local match_flower=$1; shift 122 + local mz_flags=$1; shift 123 + 124 + tc filter add $pedit_locus handle 101 pref 1 \ 125 + flower action pedit ex munge $pedit_action 126 + tc filter add dev $h2 ingress handle 101 pref 1 prot $match_prot \ 127 + flower skip_hw $match_flower action pass 128 + 129 + RET=0 130 + 131 + $MZ $mz_flags $h1 -c 10 -d 20msec -p 100 -a own -b $h2mac -q -t ip 132 + 133 + local pkts 134 + pkts=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= 10" \ 135 + tc_rule_handle_stats_get "dev $h2 ingress" 101) 136 + check_err $? "Expected to get 10 packets, but got $pkts." 137 + 138 + pkts=$(tc_rule_handle_stats_get "$pedit_locus" 101) 139 + ((pkts >= 10)) 140 + check_err $? "Expected to get 10 packets on pedit rule, but got $pkts." 141 + 142 + log_test "$pedit_locus pedit $pedit_action" 143 + 144 + tc filter del dev $h2 ingress pref 1 145 + tc filter del $pedit_locus pref 1 146 + } 147 + 148 + do_test_pedit_ip6() 149 + { 150 + local locus=$1; shift 151 + local pedit_addr=$1; shift 152 + local flower_addr=$1; shift 153 + 154 + do_test_pedit_ip "$locus" "$pedit_addr set 2001:db8:2::1" ipv6 \ 155 + "$flower_addr 2001:db8:2::1" \ 156 + "-6 -A 2001:db8:1::1 -B 2001:db8:1::2" 157 + } 158 + 159 + do_test_pedit_ip4() 160 + { 161 + local locus=$1; shift 162 + local pedit_addr=$1; shift 163 + local flower_addr=$1; shift 164 + 165 + do_test_pedit_ip "$locus" "$pedit_addr set 198.51.100.1" ip \ 166 + "$flower_addr 198.51.100.1" \ 167 + "-A 192.0.2.1 -B 192.0.2.2" 168 + } 169 + 170 + test_ip4_src() 171 + { 172 + do_test_pedit_ip4 "dev $swp1 ingress" "ip src" src_ip 173 + do_test_pedit_ip4 "dev $swp2 egress" "ip src" src_ip 174 + } 175 + 176 + test_ip4_dst() 177 + { 178 + do_test_pedit_ip4 "dev $swp1 ingress" "ip dst" dst_ip 179 + do_test_pedit_ip4 "dev $swp2 egress" "ip dst" dst_ip 180 + } 181 + 182 + test_ip6_src() 183 + { 184 + do_test_pedit_ip6 "dev $swp1 ingress" "ip6 src" src_ip 185 + do_test_pedit_ip6 "dev $swp2 egress" "ip6 src" src_ip 186 + } 187 + 188 + test_ip6_dst() 189 + { 190 + do_test_pedit_ip6 "dev $swp1 ingress" "ip6 dst" dst_ip 191 + do_test_pedit_ip6 "dev $swp2 egress" "ip6 dst" dst_ip 192 + } 193 + 194 + trap cleanup EXIT 195 + 196 + setup_prepare 197 + setup_wait 198 + 199 + tests_run 200 + 201 + exit $EXIT_STATUS