geneve: support geneve interface acting as a bvi
create geneve tunnel local 10.10.10.10 remote 10.10.10.9 vni 48 decap-next node ethernet-input l3-mode set interface ip address geneve_tunnel0 11.11.11.12/24 Type: feature Change-Id: I579ce879553d72a2e8048e33d0c0122674996b81 Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:

committed by
Andrew Yourtchenko

parent
5a849e3b35
commit
7fc88cf3a1
@ -13,7 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
option version = "2.0.0";
|
||||
option version = "2.1.0";
|
||||
|
||||
import "vnet/interface_types.api";
|
||||
import "vnet/ethernet/ethernet_types.api";
|
||||
@ -21,6 +21,7 @@ import "vnet/ip/ip_types.api";
|
||||
|
||||
define geneve_add_del_tunnel
|
||||
{
|
||||
option deprecated="20.06";
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
bool is_add;
|
||||
@ -39,6 +40,27 @@ define geneve_add_del_tunnel_reply
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
};
|
||||
|
||||
define geneve_add_del_tunnel2
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
bool is_add;
|
||||
vl_api_address_t local_address;
|
||||
vl_api_address_t remote_address;
|
||||
vl_api_interface_index_t mcast_sw_if_index;
|
||||
u32 encap_vrf_id;
|
||||
u32 decap_next_index;
|
||||
u32 vni;
|
||||
bool l3_mode;
|
||||
};
|
||||
|
||||
define geneve_add_del_tunnel2_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
};
|
||||
|
||||
define geneve_tunnel_dump
|
||||
{
|
||||
u32 client_index;
|
||||
|
@ -81,6 +81,7 @@ format_geneve_tunnel (u8 * s, va_list * args)
|
||||
|
||||
s = format (s, "encap-dpo-idx %d ", t->next_dpo.dpoi_index);
|
||||
s = format (s, "decap-next-%U ", format_decap_next, t->decap_next_index);
|
||||
s = format (s, "l3-mode %u ", t->l3_mode);
|
||||
|
||||
if (PREDICT_FALSE (ip46_address_is_multicast (&t->remote)))
|
||||
s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
|
||||
@ -105,12 +106,21 @@ geneve_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
|
||||
return /* no error */ 0;
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
geneve_mac_change (vnet_hw_interface_t * hi,
|
||||
const u8 * old_address, const u8 * mac_address)
|
||||
{
|
||||
l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
VNET_DEVICE_CLASS (geneve_device_class, static) = {
|
||||
.name = "GENEVE",
|
||||
.format_device_name = format_geneve_name,
|
||||
.format_tx_trace = format_geneve_encap_trace,
|
||||
.admin_up_down_function = geneve_interface_admin_up_down,
|
||||
.mac_addr_change_function = geneve_mac_change,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@ -206,8 +216,9 @@ _(vni) \
|
||||
_(mcast_sw_if_index) \
|
||||
_(encap_fib_index) \
|
||||
_(decap_next_index) \
|
||||
_(local) \
|
||||
_(remote)
|
||||
_(local) \
|
||||
_(remote) \
|
||||
_(l3_mode)
|
||||
|
||||
static int
|
||||
geneve_rewrite (geneve_tunnel_t * t, bool is_ip6)
|
||||
@ -400,39 +411,30 @@ int vnet_geneve_add_del_tunnel
|
||||
hash_set (vxm->geneve4_tunnel_by_key, key4.as_u64, t - vxm->tunnels);
|
||||
|
||||
vnet_hw_interface_t *hi;
|
||||
if (vec_len (vxm->free_geneve_tunnel_hw_if_indices) > 0)
|
||||
if (a->l3_mode)
|
||||
{
|
||||
vnet_interface_main_t *im = &vnm->interface_main;
|
||||
hw_if_index = vxm->free_geneve_tunnel_hw_if_indices
|
||||
[vec_len (vxm->free_geneve_tunnel_hw_if_indices) - 1];
|
||||
_vec_len (vxm->free_geneve_tunnel_hw_if_indices) -= 1;
|
||||
|
||||
hi = vnet_get_hw_interface (vnm, hw_if_index);
|
||||
hi->dev_instance = t - vxm->tunnels;
|
||||
hi->hw_instance = hi->dev_instance;
|
||||
|
||||
/* clear old stats of freed tunnel before reuse */
|
||||
sw_if_index = hi->sw_if_index;
|
||||
vnet_interface_counter_lock (im);
|
||||
vlib_zero_combined_counter
|
||||
(&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
|
||||
sw_if_index);
|
||||
vlib_zero_combined_counter (&im->combined_sw_if_counters
|
||||
[VNET_INTERFACE_COUNTER_RX],
|
||||
sw_if_index);
|
||||
vlib_zero_simple_counter (&im->sw_if_counters
|
||||
[VNET_INTERFACE_COUNTER_DROP],
|
||||
sw_if_index);
|
||||
vnet_interface_counter_unlock (im);
|
||||
u32 t_idx = t - vxm->tunnels;
|
||||
u8 address[6] =
|
||||
{ 0xd0, 0x0b, 0xee, 0xd0, (u8) (t_idx >> 8), (u8) t_idx };
|
||||
clib_error_t *error =
|
||||
ethernet_register_interface (vnm, geneve_device_class.index,
|
||||
t_idx,
|
||||
address, &hw_if_index, 0);
|
||||
if (error)
|
||||
{
|
||||
clib_error_report (error);
|
||||
return VNET_API_ERROR_INVALID_REGISTRATION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hw_if_index = vnet_register_interface
|
||||
(vnm, geneve_device_class.index, t - vxm->tunnels,
|
||||
geneve_hw_class.index, t - vxm->tunnels);
|
||||
hi = vnet_get_hw_interface (vnm, hw_if_index);
|
||||
}
|
||||
|
||||
hi = vnet_get_hw_interface (vnm, hw_if_index);
|
||||
|
||||
/* Set geneve tunnel output node */
|
||||
u32 encap_index = !is_ip6 ?
|
||||
geneve4_encap_node.index : geneve6_encap_node.index;
|
||||
@ -564,7 +566,11 @@ int vnet_geneve_add_del_tunnel
|
||||
/* make sure tunnel is removed from l2 bd or xconnect */
|
||||
set_int_l2_mode (vxm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0,
|
||||
L2_BD_PORT_TYPE_NORMAL, 0, 0);
|
||||
vec_add1 (vxm->free_geneve_tunnel_hw_if_indices, t->hw_if_index);
|
||||
|
||||
if (t->l3_mode)
|
||||
ethernet_delete_interface (vnm, t->hw_if_index);
|
||||
else
|
||||
vnet_delete_hw_interface (vnm, t->hw_if_index);
|
||||
|
||||
vxm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
|
||||
|
||||
@ -651,6 +657,7 @@ geneve_add_del_tunnel_command_fn (vlib_main_t * vm,
|
||||
u8 grp_set = 0;
|
||||
u8 ipv4_set = 0;
|
||||
u8 ipv6_set = 0;
|
||||
u8 l3_mode = 0;
|
||||
u32 encap_fib_index = 0;
|
||||
u32 mcast_sw_if_index = ~0;
|
||||
u32 decap_next_index = GENEVE_INPUT_NEXT_L2_INPUT;
|
||||
@ -736,6 +743,10 @@ geneve_add_del_tunnel_command_fn (vlib_main_t * vm,
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else if (unformat (line_input, "l3-mode"))
|
||||
{
|
||||
l3_mode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = clib_error_return (0, "parse error: '%U'",
|
||||
@ -864,7 +875,7 @@ VLIB_CLI_COMMAND (create_geneve_tunnel_command, static) = {
|
||||
.short_help =
|
||||
"create geneve tunnel local <local-vtep-addr>"
|
||||
" {remote <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>"
|
||||
" [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [del]",
|
||||
" [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [l3-mode] [del]",
|
||||
.function = geneve_add_del_tunnel_command_fn,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
@ -135,6 +135,8 @@ typedef struct
|
||||
* The tunnels sibling index on the FIB entry's dependency list.
|
||||
*/
|
||||
u32 sibling_index;
|
||||
|
||||
u8 l3_mode;
|
||||
} geneve_tunnel_t;
|
||||
|
||||
#define foreach_geneve_input_next \
|
||||
@ -173,9 +175,6 @@ typedef struct
|
||||
/* mcast shared info */
|
||||
uword *mcast_shared; /* keyed on mcast ip46 addr */
|
||||
|
||||
/* Free vlib hw_if_indices */
|
||||
u32 *free_geneve_tunnel_hw_if_indices;
|
||||
|
||||
/* Mapping from sw_if_index to tunnel index */
|
||||
u32 *tunnel_index_by_sw_if_index;
|
||||
|
||||
@ -205,6 +204,7 @@ typedef struct
|
||||
u32 encap_fib_index;
|
||||
u32 decap_next_index;
|
||||
u32 vni;
|
||||
u8 l3_mode;
|
||||
} vnet_geneve_add_del_tunnel_args_t;
|
||||
|
||||
int vnet_geneve_add_del_tunnel
|
||||
|
@ -45,6 +45,7 @@
|
||||
#define foreach_vpe_api_msg \
|
||||
_(SW_INTERFACE_SET_GENEVE_BYPASS, sw_interface_set_geneve_bypass) \
|
||||
_(GENEVE_ADD_DEL_TUNNEL, geneve_add_del_tunnel) \
|
||||
_(GENEVE_ADD_DEL_TUNNEL2, geneve_add_del_tunnel2) \
|
||||
_(GENEVE_TUNNEL_DUMP, geneve_tunnel_dump)
|
||||
|
||||
static void
|
||||
@ -114,6 +115,58 @@ out:
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
static void vl_api_geneve_add_del_tunnel2_t_handler
|
||||
(vl_api_geneve_add_del_tunnel2_t * mp)
|
||||
{
|
||||
vl_api_geneve_add_del_tunnel2_reply_t *rmp;
|
||||
int rv = 0;
|
||||
ip4_main_t *im = &ip4_main;
|
||||
|
||||
uword *p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id));
|
||||
if (!p)
|
||||
{
|
||||
rv = VNET_API_ERROR_NO_SUCH_FIB;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vnet_geneve_add_del_tunnel_args_t a = {
|
||||
.is_add = mp->is_add,
|
||||
.is_ip6 = mp->remote_address.af,
|
||||
.mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
|
||||
.encap_fib_index = p[0],
|
||||
.decap_next_index = ntohl (mp->decap_next_index),
|
||||
.vni = ntohl (mp->vni),
|
||||
.l3_mode = mp->l3_mode,
|
||||
};
|
||||
|
||||
ip_address_decode (&mp->remote_address, &a.remote);
|
||||
ip_address_decode (&mp->local_address, &a.local);
|
||||
|
||||
/* Check src & dst are different */
|
||||
if (ip46_address_cmp (&a.remote, &a.local) == 0)
|
||||
{
|
||||
rv = VNET_API_ERROR_SAME_SRC_DST;
|
||||
goto out;
|
||||
}
|
||||
if (ip46_address_is_multicast (&a.remote) &&
|
||||
!vnet_sw_if_index_is_api_valid (a.mcast_sw_if_index))
|
||||
{
|
||||
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||
goto out;
|
||||
}
|
||||
|
||||
u32 sw_if_index = ~0;
|
||||
rv = vnet_geneve_add_del_tunnel (&a, &sw_if_index);
|
||||
|
||||
out:
|
||||
/* *INDENT-OFF* */
|
||||
REPLY_MACRO2(VL_API_GENEVE_ADD_DEL_TUNNEL2_REPLY,
|
||||
({
|
||||
rmp->sw_if_index = ntohl (sw_if_index);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
static void send_geneve_tunnel_details
|
||||
(geneve_tunnel_t * t, vl_api_registration_t * reg, u32 context)
|
||||
{
|
||||
|
@ -6,8 +6,8 @@ import unittest
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from template_bd import BridgeDomain
|
||||
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from scapy.layers.l2 import Ether, ARP
|
||||
from scapy.layers.inet import IP, UDP, ICMP
|
||||
from scapy.contrib.geneve import GENEVE
|
||||
|
||||
import util
|
||||
@ -234,5 +234,74 @@ class TestGeneve(BridgeDomain, VppTestCase):
|
||||
self.logger.info(self.vapi.cli("show geneve tunnel"))
|
||||
|
||||
|
||||
class TestGeneveL3(VppTestCase):
|
||||
""" GENEVE L3 Test Case """
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestGeneveL3, cls).setUpClass()
|
||||
try:
|
||||
cls.create_pg_interfaces(range(2))
|
||||
cls.interfaces = list(cls.pg_interfaces)
|
||||
|
||||
for i in cls.interfaces:
|
||||
i.admin_up()
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
except Exception:
|
||||
super(TestGeneveL3, cls).tearDownClass()
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestGeneveL3, cls).tearDownClass()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestGeneveL3, self).tearDown()
|
||||
|
||||
def show_commands_at_teardown(self):
|
||||
self.logger.info(self.vapi.cli("show geneve tunnel"))
|
||||
self.logger.info(self.vapi.cli("show ip neighbor"))
|
||||
|
||||
def test_l3_packet(self):
|
||||
vni = 1234
|
||||
r = self.vapi.add_node_next(node_name="geneve4-input",
|
||||
next_name="ethernet-input")
|
||||
r = self.vapi.geneve_add_del_tunnel2(
|
||||
is_add=1,
|
||||
local_address=self.pg0.local_ip4,
|
||||
remote_address=self.pg0.remote_ip4,
|
||||
vni=vni,
|
||||
l3_mode=1,
|
||||
decap_next_index=r.node_index)
|
||||
|
||||
self.vapi.sw_interface_add_del_address(
|
||||
sw_if_index=r.sw_if_index, prefix="10.0.0.1/24")
|
||||
|
||||
pkt = (Ether(src=self.pg0.remote_mac, dst="d0:0b:ee:d0:00:00") /
|
||||
IP(src='10.0.0.2', dst='10.0.0.1') /
|
||||
ICMP())
|
||||
|
||||
encap = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
|
||||
UDP(sport=6081, dport=6081, chksum=0) /
|
||||
GENEVE(vni=vni))
|
||||
|
||||
arp = (Ether(src=self.pg0.remote_mac, dst="d0:0b:ee:d0:00:00") /
|
||||
ARP(op="is-at", hwsrc=self.pg0.remote_mac,
|
||||
hwdst="d0:0b:ee:d0:00:00", psrc="10.0.0.2",
|
||||
pdst="10.0.0.1"))
|
||||
|
||||
rx = self.send_and_expect(self.pg0, encap/pkt*1, self.pg0)
|
||||
rx = self.send_and_assert_no_replies(self.pg0, encap/arp*1, self.pg0)
|
||||
rx = self.send_and_expect(self.pg0, encap/pkt*1, self.pg0)
|
||||
self.assertEqual(rx[0][ICMP].type, 0) # echo reply
|
||||
|
||||
r = self.vapi.geneve_add_del_tunnel2(
|
||||
is_add=0,
|
||||
local_address=self.pg0.local_ip4,
|
||||
remote_address=self.pg0.remote_ip4,
|
||||
vni=vni)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
|
Reference in New Issue
Block a user