aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/ip/ip4_forward.c
diff options
context:
space:
mode:
authorNeale Ranns <neale@graphiant.com>2022-03-24 12:28:42 +0000
committerFlorin Coras <florin.coras@gmail.com>2022-03-24 15:39:16 +0000
commitaa7cfd04e7bb89208afe57cd84e96ced32153044 (patch)
tree7eb689d8d54aa30930c889b78de594d068e4e169 /src/vnet/ip/ip4_forward.c
parente99f762346ae018ce5b76b729a12f0cd091aec43 (diff)
ip: The check for 'same packet' must include the FIB index
Type: fix otherwise if two packets arrive with the same source address but from different VRFs, then they are treated as the same and they use the same LB and thus share the same fate. but the lookup, when done, results in two different LBs, and hence the fate can be different. Signed-off-by: Neale Ranns <neale@graphiant.com> Change-Id: Id6e16f7c577a561d9ddd7066339fa4385361d07f
Diffstat (limited to 'src/vnet/ip/ip4_forward.c')
-rw-r--r--src/vnet/ip/ip4_forward.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c
index 3556d357f50..c1bfc7d4ce5 100644
--- a/src/vnet/ip/ip4_forward.c
+++ b/src/vnet/ip/ip4_forward.c
@@ -1517,7 +1517,9 @@ ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
typedef struct
{
+ /* The src and fib-index together determine if packet n is the same as n-1 */
ip4_address_t src;
+ u32 fib_index;
u32 lbi;
u8 error;
u8 first;
@@ -1551,7 +1553,8 @@ ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
* vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
* adjacency for the source address (the remote sender's address)
*/
- if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
+ if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
+ (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
last_check->first)
{
lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
@@ -1587,6 +1590,7 @@ ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
last_check->lbi = lbi0;
last_check->error = *error0;
last_check->first = 0;
+ last_check->fib_index = vnet_buffer (b)->ip.fib_index;
}
else
{
@@ -1621,6 +1625,9 @@ ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
vnet_buffer (b[1])->ip.fib_index;
+ not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
+ not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
+
if (is_receive_dpo)
{
const receive_dpo_t *rd0, *rd1;
@@ -1683,6 +1690,7 @@ ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
last_check->lbi = lbi[1];
last_check->error = error[1];
last_check->first = 0;
+ last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
}
else
{
@@ -1752,10 +1760,11 @@ ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
* member to make sure the .lbi is initialised for the first
* packet.
*/
- .src = {.as_u32 = 0},
+ .src = { .as_u32 = 0 },
.lbi = ~0,
.error = IP4_ERROR_UNKNOWN_PROTOCOL,
.first = 1,
+ .fib_index = 0,
};
from = vlib_frame_vector_args (frame);
class="n">TCP, ICMP, icmptypes, icmpcodes from scapy.layers.l2 import Ether from scapy.packet import Raw from scapy.layers.dns import DNSRR, DNS, DNSQR class TestDns(VppTestCase): """ Dns Test Cases """ @classmethod def setUpClass(cls): super(TestDns, cls).setUpClass() @classmethod def tearDownClass(cls): super(TestDns, cls).tearDownClass() def setUp(self): super(TestDns, self).setUp() self.create_pg_interfaces(range(1)) for i in self.pg_interfaces: i.admin_up() i.config_ip4() i.resolve_arp() def tearDown(self): super(TestDns, self).tearDown() def create_stream(self, src_if): """Create input packet stream for defined interface. :param VppInterface src_if: Interface to create packet stream for. """ good_request = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / IP(src=src_if.remote_ip4) / UDP(sport=1234, dport=53) / DNS(rd=1, qd=DNSQR(qname="bozo.clown.org"))) bad_request = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / IP(src=src_if.remote_ip4) / UDP(sport=1234, dport=53) / DNS(rd=1, qd=DNSQR(qname="no.clown.org"))) pkts = [good_request, bad_request] return pkts def verify_capture(self, dst_if, capture): """Verify captured input packet stream for defined interface. :param VppInterface dst_if: Interface to verify captured packet stream for. :param list capture: Captured packet stream. """ self.logger.info("Verifying capture on interface %s" % dst_if.name) for packet in capture: dns = packet[DNS] self.assertEqual(dns.an[0].rdata, '1.2.3.4') def test_dns_unittest(self): """ DNS Name Resolver Basic Functional Test """ # Set up an upstream name resolver. We won't actually go there self.vapi.dns_name_server_add_del( is_ip6=0, is_add=1, server_address=IPv4Address(u'8.8.8.8').packed) # Enable name resolution self.vapi.dns_enable_disable(enable=1) # Manually add a static dns cache entry self.logger.info(self.vapi.cli("dns cache add bozo.clown.org 1.2.3.4")) # Test the binary API rv = self.vapi.dns_resolve_name(name=b'bozo.clown.org') self.assertEqual(rv.ip4_address, IPv4Address(u'1.2.3.4').packed) # Configure 127.0.0.1/8 on the pg interface self.vapi.sw_interface_add_del_address( sw_if_index=self.pg0.sw_if_index, prefix="127.0.0.1/8") # Send a couple of DNS request packets, one for bozo.clown.org # and one for no.clown.org which won't resolve pkts = self.create_stream(self.pg0) self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() pkts = self.pg0.get_capture(1) self.verify_capture(self.pg0, pkts) # Make sure that the cache contents are correct str = self.vapi.cli("show dns cache verbose") self.assertIn('1.2.3.4', str) self.assertIn('[P] no.clown.org:', str) if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)