urpf: Unicast reverse Path Forwarding (plugin)

Type: feature

 - move the IP4 code to plugin
 - add ip6 support
 - add suport for uRPF on TX
 - add tests

Change-Id: I074c2debc486d3e79c12fad4b8dbd72c41e841a0
Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
Neale Ranns
2020-04-02 15:02:16 +00:00
committed by Ole Trøan
parent dc3e966485
commit d724e4f43b
20 changed files with 1658 additions and 616 deletions

View File

@@ -0,0 +1,27 @@
# Copyright (c) 2020 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
add_vpp_plugin(urpf
SOURCES
urpf.c
urpf_api.c
ip4_urpf.c
ip6_urpf.c
MULTIARCH_SOURCES
ip4_urpf.c
ip6_urpf.c
API_FILES
urpf.api
)

171
src/plugins/urpf/ip4_urpf.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2015 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ip/ip4_source_check.c: IP v4 check source address (unicast RPF check)
*
* Copyright (c) 2008 Eliot Dresselhaus
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <urpf/urpf.h>
#include <urpf/urpf_dp.h>
static char *ip4_urpf_error_strings[] = {
#define _(a,b) "ip4-" # b,
foreach_urpf_error
#undef _
};
VLIB_NODE_FN (ip4_rx_urpf_loose) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP4, VLIB_RX, URPF_MODE_LOOSE));
}
VLIB_NODE_FN (ip4_rx_urpf_strict) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP4, VLIB_RX, URPF_MODE_STRICT));
}
VLIB_NODE_FN (ip4_tx_urpf_loose) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP4, VLIB_TX, URPF_MODE_LOOSE));
}
VLIB_NODE_FN (ip4_tx_urpf_strict) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP4, VLIB_TX, URPF_MODE_STRICT));
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip4_rx_urpf_loose) = {
.name = "ip4-rx-urpf-loose",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip4-drop",
},
.n_errors = ARRAY_LEN (ip4_urpf_error_strings),
.error_strings = ip4_urpf_error_strings,
.format_buffer = format_ip4_header,
.format_trace = format_urpf_trace,
};
VLIB_REGISTER_NODE (ip4_rx_urpf_strict) = {
.name = "ip4-rx-urpf-strict",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip4-drop",
},
.n_errors = ARRAY_LEN (ip4_urpf_error_strings),
.error_strings = ip4_urpf_error_strings,
.format_buffer = format_ip4_header,
.format_trace = format_urpf_trace,
};
VLIB_REGISTER_NODE (ip4_tx_urpf_loose) = {
.name = "ip4-tx-urpf-loose",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip4-drop",
},
.n_errors = ARRAY_LEN (ip4_urpf_error_strings),
.error_strings = ip4_urpf_error_strings,
.format_buffer = format_ip4_header,
.format_trace = format_urpf_trace,
};
VLIB_REGISTER_NODE (ip4_tx_urpf_strict) = {
.name = "ip4-tx-urpf-strict",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip4-drop",
},
.n_errors = ARRAY_LEN (ip4_urpf_error_strings),
.error_strings = ip4_urpf_error_strings,
.format_buffer = format_ip4_header,
.format_trace = format_urpf_trace,
};
VNET_FEATURE_INIT (ip4_rx_urpf_loose_feat, static) =
{
.arc_name = "ip4-unicast",
.node_name = "ip4-rx-urpf-loose",
.runs_before = VNET_FEATURES ("ip4-rx-urpf-strict"),
};
VNET_FEATURE_INIT (ip4_rx_urpf_strict_feat, static) =
{
.arc_name = "ip4-unicast",
.node_name = "ip4-rx-urpf-strict",
.runs_before = VNET_FEATURES ("ip4-policer-classify"),
};
VNET_FEATURE_INIT (ip4_tx_urpf_loose_feat, static) =
{
.arc_name = "ip4-output",
.node_name = "ip4-tx-urpf-loose",
};
VNET_FEATURE_INIT (ip4_tx_urpf_strict_feat, static) =
{
.arc_name = "ip4-output",
.node_name = "ip4-tx-urpf-strict",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

171
src/plugins/urpf/ip6_urpf.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2015 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ip/ip4_source_check.c: IP v4 check source address (unicast RPF check)
*
* Copyright (c) 2008 Eliot Dresselhaus
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <urpf/urpf.h>
#include <urpf/urpf_dp.h>
static char *ip6_urpf_error_strings[] = {
#define _(a,b) "ip6-" # b,
foreach_urpf_error
#undef _
};
VLIB_NODE_FN (ip6_rx_urpf_loose) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP6, VLIB_RX, URPF_MODE_LOOSE));
}
VLIB_NODE_FN (ip6_rx_urpf_strict) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP6, VLIB_RX, URPF_MODE_STRICT));
}
VLIB_NODE_FN (ip6_tx_urpf_loose) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP6, VLIB_TX, URPF_MODE_LOOSE));
}
VLIB_NODE_FN (ip6_tx_urpf_strict) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (urpf_inline (vm, node, frame, AF_IP6, VLIB_TX, URPF_MODE_STRICT));
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_rx_urpf_loose) = {
.name = "ip6-rx-urpf-loose",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip6-drop",
},
.n_errors = ARRAY_LEN (ip6_urpf_error_strings),
.error_strings = ip6_urpf_error_strings,
.format_buffer = format_ip6_header,
.format_trace = format_urpf_trace,
};
VLIB_REGISTER_NODE (ip6_rx_urpf_strict) = {
.name = "ip6-rx-urpf-strict",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip6-drop",
},
.n_errors = ARRAY_LEN (ip6_urpf_error_strings),
.error_strings = ip6_urpf_error_strings,
.format_buffer = format_ip6_header,
.format_trace = format_urpf_trace,
};
VLIB_REGISTER_NODE (ip6_tx_urpf_loose) = {
.name = "ip6-tx-urpf-loose",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip6-drop",
},
.n_errors = ARRAY_LEN (ip6_urpf_error_strings),
.error_strings = ip6_urpf_error_strings,
.format_buffer = format_ip6_header,
.format_trace = format_urpf_trace,
};
VLIB_REGISTER_NODE (ip6_tx_urpf_strict) = {
.name = "ip6-tx-urpf-strict",
.vector_size = sizeof (u32),
.n_next_nodes = URPF_N_NEXT,
.next_nodes = {
[URPF_NEXT_DROP] = "ip6-drop",
},
.n_errors = ARRAY_LEN (ip6_urpf_error_strings),
.error_strings = ip6_urpf_error_strings,
.format_buffer = format_ip6_header,
.format_trace = format_urpf_trace,
};
VNET_FEATURE_INIT (ip6_rx_urpf_loose_feat, static) =
{
.arc_name = "ip6-unicast",
.node_name = "ip6-rx-urpf-loose",
.runs_before = VNET_FEATURES ("ip6-rx-urpf-strict"),
};
VNET_FEATURE_INIT (ip6_rx_urpf_strict_feat, static) =
{
.arc_name = "ip6-unicast",
.node_name = "ip6-rx-urpf-strict",
.runs_before = VNET_FEATURES ("ip6-policer-classify"),
};
VNET_FEATURE_INIT (ip6_tx_urpf_loose_feat, static) =
{
.arc_name = "ip6-output",
.node_name = "ip6-tx-urpf-loose",
};
VNET_FEATURE_INIT (ip6_tx_urpf_strict_feat, static) =
{
.arc_name = "ip6-output",
.node_name = "ip6-tx-urpf-strict",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@@ -0,0 +1,295 @@
#!/usr/bin/env python3
import unittest
from framework import VppTestCase, VppTestRunner
from scapy.packet import Raw
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP, ICMP
from scapy.layers.inet6 import IPv6
from vpp_papi import VppEnum
N_PKTS = 63
class TestURPF(VppTestCase):
""" Unicast Reverse Path Forwarding Test Case """
@classmethod
def setUpClass(cls):
super(TestURPF, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(TestURPF, cls).tearDownClass()
def setUp(self):
super(TestURPF, self).setUp()
# create 4 pg interfaces so there are a few addresses
# in the FIB
self.create_pg_interfaces(range(4))
for i in self.pg_interfaces:
i.admin_up()
i.config_ip4()
i.resolve_arp()
i.config_ip6()
i.resolve_ndp()
def tearDown(self):
for i in self.pg_interfaces:
i.unconfig_ip4()
i.unconfig_ip6()
i.admin_down()
super(TestURPF, self).tearDown()
def test_urpf4(self):
""" uRPF IP4 """
e = VppEnum
p_spoof_loose = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IP(src="3.3.3.3", dst=self.pg1.remote_ip4) /
UDP(sport=1234, dport=1234) /
Raw(b'\xa5' * 100)) * N_PKTS
p_spoof_strict = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IP(src=self.pg2.remote_ip4,
dst=self.pg1.remote_ip4) /
UDP(sport=1234, dport=1234) /
Raw(b'\xa5' * 100)) * N_PKTS
p_good = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IP(src=self.pg0.remote_ip4,
dst=self.pg1.remote_ip4) /
UDP(sport=1234, dport=1234) /
Raw(b'\xa5' * 100)) * N_PKTS
#
# before adding the uRPF, ensure all packets are forwarded
#
self.send_and_expect(self.pg0, p_good, self.pg1)
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
#
# apply loose uRPF check on pg0 rx
#
self.vapi.urpf_update(is_input=True,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
af=e.vl_api_address_family_t.ADDRESS_IP4,
sw_if_index=self.pg0.sw_if_index)
# good packets still pass
self.send_and_expect(self.pg0, p_good, self.pg1)
# packets from address for which there is a route are forwarded
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
# packets from address to which there is no route are dropped
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip4-rx-urpf-loose", N_PKTS)
#
# crank it up to strict mode
#
self.vapi.urpf_update(is_input=True,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
af=e.vl_api_address_family_t.ADDRESS_IP4,
sw_if_index=self.pg0.sw_if_index)
# good packets still pass
self.send_and_expect(self.pg0, p_good, self.pg1)
# packets that would not be routed back thru pg0 are dropped
self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip4-rx-urpf-strict", 2 * N_PKTS)
#
# disable uRPF, all traffic should pass
#
self.vapi.urpf_update(is_input=True,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
af=e.vl_api_address_family_t.ADDRESS_IP4,
sw_if_index=self.pg0.sw_if_index)
self.send_and_expect(self.pg0, p_good, self.pg1)
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
#
# Now apply in the TX direction
# for loose it is the same deal, they should not be forwarded
# if there's no route
# for strict they should not be forwarded if they would be
# forwarded thru that interface.
#
self.vapi.urpf_update(is_input=False,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
af=e.vl_api_address_family_t.ADDRESS_IP4,
sw_if_index=self.pg1.sw_if_index)
self.send_and_expect(self.pg0, p_good, self.pg1)
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip4-tx-urpf-loose", N_PKTS)
self.vapi.urpf_update(is_input=False,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
af=e.vl_api_address_family_t.ADDRESS_IP4,
sw_if_index=self.pg1.sw_if_index)
self.send_and_expect(self.pg0, p_good, self.pg1)
# the strict packet, from a peer is allowed, since it does
# not forward via pg1
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip4-tx-urpf-strict", N_PKTS)
# change the strict packet so that it would forward through pg1
p_spoof_strict = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IP(src=self.pg1.remote_ip4,
dst=self.pg1.remote_ip4) /
UDP(sport=1234, dport=1234) /
Raw(b'\xa5' * 100)) * N_PKTS
self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
self.assert_error_counter_equal("ip4-tx-urpf-strict", 2 * N_PKTS)
# cleanup
self.vapi.urpf_update(is_input=False,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
af=e.vl_api_address_family_t.ADDRESS_IP4,
sw_if_index=self.pg1.sw_if_index)
def test_urpf6(self):
""" uRPF IP6 """
e = VppEnum
p_spoof_loose = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IPv6(src="3::3", dst=self.pg1.remote_ip6) /
UDP(sport=1236, dport=1236) /
Raw(b'\xa5' * 100)) * N_PKTS
p_spoof_strict = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IPv6(src=self.pg2.remote_ip6,
dst=self.pg1.remote_ip6) /
UDP(sport=1236, dport=1236) /
Raw(b'\xa5' * 100)) * N_PKTS
p_good = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IPv6(src=self.pg0.remote_ip6,
dst=self.pg1.remote_ip6) /
UDP(sport=1236, dport=1236) /
Raw(b'\xa5' * 100)) * N_PKTS
#
# before adding the uRPF, ensure all packets are forwarded
#
self.send_and_expect(self.pg0, p_good, self.pg1)
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
#
# apply loose uRPF check on pg0 rx
#
self.vapi.urpf_update(is_input=True,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
af=e.vl_api_address_family_t.ADDRESS_IP6,
sw_if_index=self.pg0.sw_if_index)
# good packets still pass
self.send_and_expect(self.pg0, p_good, self.pg1)
# packets from address for which there is a route are forwarded
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
# packets from address to which there is no route are dropped
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip6-rx-urpf-loose", N_PKTS)
#
# crank it up to strict mode
#
self.vapi.urpf_update(is_input=True,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
af=e.vl_api_address_family_t.ADDRESS_IP6,
sw_if_index=self.pg0.sw_if_index)
# good packets still pass
self.send_and_expect(self.pg0, p_good, self.pg1)
# packets that would not be routed back thru pg0 are dropped
self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip6-rx-urpf-strict", 2 * N_PKTS)
#
# disable uRPF, all traffic should pass
#
self.vapi.urpf_update(is_input=True,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
af=e.vl_api_address_family_t.ADDRESS_IP6,
sw_if_index=self.pg0.sw_if_index)
self.send_and_expect(self.pg0, p_good, self.pg1)
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
#
# Now apply in the TX direction
# for loose it is the same deal, they should not be forwarded
# if there's no route
# for strict they should not be forwarded if they would be
# forwarded thru that interface.
#
self.vapi.urpf_update(is_input=False,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
af=e.vl_api_address_family_t.ADDRESS_IP6,
sw_if_index=self.pg1.sw_if_index)
self.send_and_expect(self.pg0, p_good, self.pg1)
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip6-tx-urpf-loose", N_PKTS)
self.vapi.urpf_update(is_input=False,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
af=e.vl_api_address_family_t.ADDRESS_IP6,
sw_if_index=self.pg1.sw_if_index)
self.send_and_expect(self.pg0, p_good, self.pg1)
# the strict packet, from a peer is allowed, since it does
# not forward via pg1
self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
self.assert_error_counter_equal("ip6-tx-urpf-strict", N_PKTS)
# change the strict packet so that it would forward through pg1
p_spoof_strict = (Ether(dst=self.pg0.local_mac,
src=self.pg0.remote_mac) /
IPv6(src=self.pg1.remote_ip6,
dst=self.pg1.remote_ip6) /
UDP(sport=1236, dport=1236) /
Raw(b'\xa5' * 100)) * N_PKTS
self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
self.assert_error_counter_equal("ip6-tx-urpf-strict", 2 * N_PKTS)
# cleanup
self.vapi.urpf_update(is_input=False,
mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
af=e.vl_api_address_family_t.ADDRESS_IP6,
sw_if_index=self.pg1.sw_if_index)
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)

59
src/plugins/urpf/urpf.api Normal file
View File

@@ -0,0 +1,59 @@
/* Hey Emacs use -*- mode: C -*- */
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \file
This file defines the vpp control-plane API messages
used to control the URPF plugin
*/
option version = "1.0.0";
import "vnet/ip/ip_types.api";
import "vnet/fib/fib_types.api";
import "vnet/interface_types.api";
enum urpf_mode:u8
{
URPF_API_MODE_OFF,
URPF_API_MODE_LOOSE,
URPF_API_MODE_STRICT,
};
/**
* @brief Enable uRPF on a given interface in a given direction
* @param client_index - opaque cookie to identify the sender
* @param context - sender context, to match reply w/ request
* @param mode - Mode
* @param af - Address Family
* @param sw_if_index - Interface
* @param is_input - Direction.
*/
autoreply define urpf_update
{
u32 client_index;
u32 context;
bool is_input[default = true];
vl_api_urpf_mode_t mode;
vl_api_address_family_t af;
vl_api_interface_index_t sw_if_index;
};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

323
src/plugins/urpf/urpf.c Normal file
View File

File diff suppressed because it is too large Load Diff

50
src/plugins/urpf/urpf.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __URPF_H__
#define __URPF_H__
#include <vnet/ip/ip_types.h>
#define foreach_urpf_mode \
_(OFF, "off") \
_(LOOSE, "loose") \
_(STRICT, "strict") \
typedef enum urpf_mode_t_
{
#define _(a,b) URPF_MODE_##a,
foreach_urpf_mode
#undef _
} __clib_packed urpf_mode_t;
#define URPF_N_MODES (URPF_MODE_STRICT+1)
extern u8 *format_urpf_mode (u8 * s, va_list * a);
extern void urpf_update (urpf_mode_t mode,
u32 sw_if_index,
ip_address_family_t af, vlib_dir_t dir);
#endif
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

108
src/plugins/urpf/urpf_api.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <urpf/urpf.h>
#include <vnet/plugin/plugin.h>
#include <vnet/ip/ip_types_api.h>
#include <vpp/app/version.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
/* define message IDs */
#include <vnet/format_fns.h>
#include <urpf/urpf.api_enum.h>
#include <urpf/urpf.api_types.h>
/**
* Base message ID fot the plugin
*/
static u32 urpf_base_msg_id;
#define REPLY_MSG_ID_BASE urpf_base_msg_id
#include <vlibapi/api_helper_macros.h>
static int
urpf_mode_decode (vl_api_urpf_mode_t in, urpf_mode_t * out)
{
if (0)
;
#define _(a,b) \
else if (URPF_API_MODE_##a == in) \
{ \
*out = URPF_MODE_##a; \
return (0); \
}
foreach_urpf_mode
#undef _
return (VNET_API_ERROR_INVALID_VALUE);
}
static void
vl_api_urpf_update_t_handler (vl_api_urpf_update_t * mp)
{
vl_api_urpf_update_reply_t *rmp;
ip_address_family_t af;
urpf_mode_t mode;
int rv = 0;
VALIDATE_SW_IF_INDEX (mp);
rv = urpf_mode_decode (mp->mode, &mode);
if (rv)
goto done;
rv = ip_address_family_decode (mp->af, &af);
if (rv)
goto done;
urpf_update (mode, htonl (mp->sw_if_index), af,
(mp->is_input ? VLIB_RX : VLIB_TX));
BAD_SW_IF_INDEX_LABEL;
done:
REPLY_MACRO (VL_API_URPF_UPDATE_REPLY);
}
#include <urpf/urpf.api.c>
static clib_error_t *
urpf_api_init (vlib_main_t * vm)
{
/* Ask for a correctly-sized block of API message decode slots */
urpf_base_msg_id = setup_message_id_table ();
return 0;
}
VLIB_INIT_FUNCTION (urpf_api_init);
/* *INDENT-OFF* */
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "Unicast Reverse Path Forwarding (uRPF)",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

331
src/plugins/urpf/urpf_dp.h Normal file
View File

File diff suppressed because it is too large Load Diff