summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip/ip46_address.h
blob: f726178ee63a132f63c2769144d04b45bd2ae5b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
 * Copyright (c) 2015-2019 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 included_ip46_address_h
#define included_ip46_address_h

#include <vnet/ip/ip6_packet.h>
#include <vnet/ip/ip4_packet.h>

typedef enum
{
  IP46_TYPE_ANY,
  IP46_TYPE_BOTH = IP46_TYPE_ANY,
  IP46_TYPE_IP4,
  IP46_TYPE_IP6
} ip46_type_t;

#define IP46_N_TYPES (IP46_TYPE_IP6+2)

#define FOREACH_IP46_TYPE(_type) \
  for (_type = IP46_TYPE_IP4; _type <= IP46_TYPE_IP6; _type++)

extern u8 *format_ip46_type (u8 * s, va_list * args);

/* *INDENT-OFF* */
typedef CLIB_PACKED (union ip46_address_t_ {
  struct {
    u32 pad[3];
    ip4_address_t ip4;
  };
  ip6_address_t ip6;
  u8 as_u8[16];
  u64 as_u64[2];
}) ip46_address_t;
/* *INDENT-ON* */


format_function_t format_ip46_address;

#define ip46_address_initializer {{{ 0 }}}

always_inline u8
ip46_address_is_ip4 (const ip46_address_t * ip46)
{
  return (((ip46)->pad[0] | (ip46)->pad[1] | (ip46)->pad[2]) == 0);
}

always_inline void
ip46_address_mask_ip4 (ip46_address_t * ip46)
{
  ((ip46)->pad[0] = (ip46)->pad[1] = (ip46)->pad[2] = 0);
}

always_inline void
ip46_address_set_ip4 (ip46_address_t * ip46, const ip4_address_t * ip)
{
  ip46_address_mask_ip4 (ip46);
  ip46->ip4 = *ip;
}

always_inline void
ip46_address_reset (ip46_address_t * ip46)
{
  ip46->as_u64[0] = ip46->as_u64[1] = 0;
}

always_inline int
ip46_address_cmp (const ip46_address_t * ip46_1,
		  const ip46_address_t * ip46_2)
{
  return (memcmp (ip46_1, ip46_2, sizeof (*ip46_1)));
}

always_inline u8
ip46_address_is_zero (const ip46_address_t * ip46)
{
  return (ip46->as_u64[0] == 0 && ip46->as_u64[1] == 0);
}

always_inline u8
ip46_address_is_equal (const ip46_address_t * ip46_1,
		       const ip46_address_t * ip46_2)
{
  return ((ip46_1->as_u64[0] == ip46_2->as_u64[0]) &&
	  (ip46_1->as_u64[1] == ip46_2->as_u64[1]));
}

static_always_inline int
ip4_address_is_equal (const ip4_address_t * ip4_1,
		      const ip4_address_t * ip4_2)
{
  return (ip4_1->as_u32 == ip4_2->as_u32);
}

static_always_inline int
ip46_address_is_equal_v4 (const ip46_address_t * ip46,
			  const ip4_address_t * ip4)
{
  return (ip46->ip4.as_u32 == ip4->as_u32);
}

static_always_inline int
ip46_address_is_equal_v6 (const ip46_address_t * ip46,
			  const ip6_address_t * ip6)
{
  return ((ip46->ip6.as_u64[0] == ip6->as_u64[0]) &&
	  (ip46->ip6.as_u64[1] == ip6->as_u64[1]));
}

static_always_inline void
ip46_address_copy (ip46_address_t * dst, const ip46_address_t * src)
{
  dst->as_u64[0] = src->as_u64[0];
  dst->as_u64[1] = src->as_u64[1];
}

static_always_inline void
ip46_address_set_ip6 (ip46_address_t * dst, const ip6_address_t * src)
{
  dst->as_u64[0] = src->as_u64[0];
  dst->as_u64[1] = src->as_u64[1];
}

always_inline ip46_address_t
to_ip46 (u32 is_ipv6, u8 * buf)
{
  ip46_address_t ip;
  if (is_ipv6)
    ip.ip6 = *((ip6_address_t *) buf);
  else
    ip46_address_set_ip4 (&ip, (ip4_address_t *) buf);
  return ip;
}

always_inline ip46_type_t
ip46_address_get_type (const ip46_address_t * ip)
{
  return (ip46_address_is_ip4 (ip) ? IP46_TYPE_IP4 : IP46_TYPE_IP6);
}

always_inline uword
ip46_address_is_multicast (const ip46_address_t * a)
{
  return ip46_address_is_ip4 (a) ? ip4_address_is_multicast (&a->ip4) :
    ip6_address_is_multicast (&a->ip6);
}

extern void ip4_address_increment (ip4_address_t * i);
extern void ip6_address_increment (ip6_address_t * i);
extern void ip46_address_increment (ip46_type_t type, ip46_address_t * ip);

#endif /* included_ip46_address_h */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
an class="n">assertEqual(pkt[IP].src, self.pg0.local_ip4) if not local_only: if not mcast_pkt: self.assertEqual(pkt[IP].dst, self.pg0.remote_ip4) else: self.assertEqual(pkt[IP].dst, type(self).mcast_ip4) # Verify UDP destination port is VXLAN 4789, source UDP port could be # arbitrary. self.assertEqual(pkt[UDP].dport, self.dport) # Verify UDP checksum self.assert_udp_checksum_valid(pkt) # Verify VNI self.assertEqual(pkt[VXLAN].vni, vni) @classmethod def create_vxlan_flood_test_bd(cls, vni, n_ucast_tunnels, port): # Create 10 ucast vxlan tunnels under bd ip_range_start = 10 ip_range_end = ip_range_start + n_ucast_tunnels next_hop_address = cls.pg0.remote_ip4 for dest_ip4 in ip4_range(next_hop_address, ip_range_start, ip_range_end): # add host route so dest_ip4 will not be resolved rip = VppIpRoute(cls, dest_ip4, 32, [VppRoutePath(next_hop_address, INVALID_INDEX)], register=False) rip.add_vpp_config() r = VppVxlanTunnel(cls, src=cls.pg0.local_ip4, src_port=port, dst_port=port, dst=dest_ip4, vni=vni) r.add_vpp_config() cls.vapi.sw_interface_set_l2_bridge(r.sw_if_index, bd_id=vni) @classmethod def add_del_shared_mcast_dst_load(cls, port, is_add): """ add or del tunnels sharing the same mcast dst to test vxlan ref_count mechanism """ n_shared_dst_tunnels = 20 vni_start = 10000 vni_end = vni_start + n_shared_dst_tunnels for vni in range(vni_start, vni_end): r = VppVxlanTunnel(cls, src=cls.pg0.local_ip4, src_port=port, dst_port=port, dst=cls.mcast_ip4, mcast_sw_if_index=1, vni=vni) if is_add: r.add_vpp_config() if r.sw_if_index == 0xffffffff: raise ValueError("bad sw_if_index: ~0") else: r.remove_vpp_config() @classmethod def add_shared_mcast_dst_load(cls, port): cls.add_del_shared_mcast_dst_load(port=port, is_add=1) @classmethod def del_shared_mcast_dst_load(cls, port): cls.add_del_shared_mcast_dst_load(port=port, is_add=0) @classmethod def add_del_mcast_tunnels_load(cls, port, is_add): """ add or del tunnels to test vxlan stability """ n_distinct_dst_tunnels = 200 ip_range_start = 10 ip_range_end = ip_range_start + n_distinct_dst_tunnels for dest_ip4 in ip4_range(cls.mcast_ip4, ip_range_start, ip_range_end): vni = bytearray(socket.inet_pton(socket.AF_INET, dest_ip4))[3] r = VppVxlanTunnel(cls, src=cls.pg0.local_ip4, src_port=port, dst_port=port, dst=dest_ip4, mcast_sw_if_index=1, vni=vni) if is_add: r.add_vpp_config() else: r.remove_vpp_config() @classmethod def add_mcast_tunnels_load(cls, port): cls.add_del_mcast_tunnels_load(port=port, is_add=1) @classmethod def del_mcast_tunnels_load(cls, port): cls.add_del_mcast_tunnels_load(port=port, is_add=0) # Class method to start the VXLAN test case. # Overrides setUpClass method in VppTestCase class. # Python try..except statement is used to ensure that the tear down of # the class will be executed even if exception is raised. # @param cls The class pointer. @classmethod def setUpClass(cls): super(TestVxlan, cls).setUpClass() try: cls.flags = 0x8 # Create 2 pg interfaces. cls.create_pg_interfaces(range(4)) for pg in cls.pg_interfaces: pg.admin_up() # Configure IPv4 addresses on VPP pg0. cls.pg0.config_ip4() # Resolve MAC address for VPP's IP address on pg0. cls.pg0.resolve_arp() # Our Multicast address cls.mcast_ip4 = '239.1.1.1' cls.mcast_mac = util.mcast_ip_to_mac(cls.mcast_ip4) except Exception: cls.tearDownClass() raise @classmethod def tearDownClass(cls): super(TestVxlan, cls).tearDownClass() def setUp(self): super(TestVxlan, self).setUp() def createVxLANInterfaces(self, port=4789): # Create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg1 # into BD. self.dport = port self.single_tunnel_vni = 0x12345 self.single_tunnel_bd = 1 r = VppVxlanTunnel(self, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4, src_port=self.dport, dst_port=self.dport, vni=self.single_tunnel_vni) r.add_vpp_config() self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, bd_id=self.single_tunnel_bd) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=self.single_tunnel_bd) # Setup vni 2 to test multicast flooding self.n_ucast_tunnels = 10 self.mcast_flood_bd = 2 self.create_vxlan_flood_test_bd(self.mcast_flood_bd, self.n_ucast_tunnels, self.dport) r = VppVxlanTunnel(self, src=self.pg0.local_ip4, dst=self.mcast_ip4, src_port=self.dport, dst_port=self.dport, mcast_sw_if_index=1, vni=self.mcast_flood_bd) r.add_vpp_config() self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, bd_id=self.mcast_flood_bd) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.mcast_flood_bd) # Add and delete mcast tunnels to check stability self.add_shared_mcast_dst_load(self.dport) self.add_mcast_tunnels_load(self.dport) self.del_shared_mcast_dst_load(self.dport) self.del_mcast_tunnels_load(self.dport) # Setup vni 3 to test unicast flooding self.ucast_flood_bd = 3 self.create_vxlan_flood_test_bd(self.ucast_flood_bd, self.n_ucast_tunnels, self.dport) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg3.sw_if_index, bd_id=self.ucast_flood_bd) # Set scapy listen custom port for VxLAN bind_layers(UDP, VXLAN, dport=self.dport) def encap_big_packet(self): self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1500, 0, 0, 0]) frame = (Ether(src='00:00:00:00:00:02', dst='00:00:00:00:00:01') / IP(src='4.3.2.1', dst='1.2.3.4') / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 1450)) self.pg1.add_stream([frame]) self.pg0.enable_capture() self.pg_start() # Pick first received frame and check if it's correctly encapsulated. out = self.pg0.get_capture(2) ether = out[0] pkt = reassemble4(out) pkt = ether / pkt self.check_encapsulation(pkt, self.single_tunnel_vni) payload = self.decapsulate(pkt) # TODO: Scapy bug? # self.assert_eq_pkts(payload, frame) """ Tests with default port (4789) """ def test_decap(self): """ Decapsulation test from BridgeDoman """ self.createVxLANInterfaces() super(TestVxlan, self).test_decap() def test_encap(self): """ Encapsulation test from BridgeDoman """ self.createVxLANInterfaces() super(TestVxlan, self).test_encap() def test_encap_big_packet(self): """ Encapsulation test send big frame from pg1 Verify receipt of encapsulated frames on pg0 """ self.createVxLANInterfaces() self.encap_big_packet() def test_ucast_flood(self): """ Unicast flood test from BridgeDoman """ self.createVxLANInterfaces() super(TestVxlan, self).test_ucast_flood() def test_mcast_flood(self): """ Multicast flood test from BridgeDoman """ self.createVxLANInterfaces() super(TestVxlan, self).test_mcast_flood() def test_mcast_rcv(self): """ Multicast receive test from BridgeDoman """ self.createVxLANInterfaces() super(TestVxlan, self).test_mcast_rcv() """ Tests with custom port """ def test_decap_custom_port(self): """ Decapsulation test custom port from BridgeDoman """ self.createVxLANInterfaces(1111) super(TestVxlan, self).test_decap() def test_encap_custom_port(self): """ Encapsulation test custom port from BridgeDoman """ self.createVxLANInterfaces(1111) super(TestVxlan, self).test_encap() def test_ucast_flood_custom_port(self): """ Unicast flood test custom port from BridgeDoman """ self.createVxLANInterfaces(1111) super(TestVxlan, self).test_ucast_flood() def test_mcast_flood_custom_port(self): """ Multicast flood test custom port from BridgeDoman """ self.createVxLANInterfaces(1111) super(TestVxlan, self).test_mcast_flood() def test_mcast_rcv_custom_port(self): """ Multicast receive test custom port from BridgeDoman """ self.createVxLANInterfaces(1111) super(TestVxlan, self).test_mcast_rcv() # Method to define VPP actions before tear down of the test case. # Overrides tearDown method in VppTestCase class. # @param self The object pointer. def tearDown(self): super(TestVxlan, self).tearDown() def show_commands_at_teardown(self): self.logger.info(self.vapi.cli("show bridge-domain 1 detail")) self.logger.info(self.vapi.cli("show bridge-domain 2 detail")) self.logger.info(self.vapi.cli("show bridge-domain 3 detail")) self.logger.info(self.vapi.cli("show vxlan tunnel")) class TestVxlan2(VppTestCase): """ VXLAN Test Case """ def setUp(self): super(TestVxlan2, self).setUp() # Create 2 pg interfaces. self.create_pg_interfaces(range(4)) for pg in self.pg_interfaces: pg.admin_up() # Configure IPv4 addresses on VPP pg0. self.pg0.config_ip4() self.pg0.resolve_arp() def tearDown(self): super(TestVxlan2, self).tearDown() def test_xconnect(self): """ VXLAN source address not local """ # # test the broken configuration of a VXLAN tunnel whose # source address is not local ot the box. packets sent # through the tunnel should be dropped # t = VppVxlanTunnel(self, src="10.0.0.5", dst=self.pg0.local_ip4, vni=1000) t.add_vpp_config() t.admin_up() self.vapi.sw_interface_set_l2_xconnect(t.sw_if_index, self.pg1.sw_if_index, enable=1) self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index, t.sw_if_index, enable=1) p = (Ether(src="00:11:22:33:44:55", dst="00:00:00:11:22:33") / IP(src="4.3.2.1", dst="1.2.3.4") / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 1450)) rx = self.send_and_assert_no_replies(self.pg1, [p]) if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)