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:
Ole Troan
2020-06-17 22:57:13 +02:00
committed by Andrew Yourtchenko
parent 5a849e3b35
commit 7fc88cf3a1
5 changed files with 189 additions and 34 deletions

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
option version = "2.0.0"; option version = "2.1.0";
import "vnet/interface_types.api"; import "vnet/interface_types.api";
import "vnet/ethernet/ethernet_types.api"; import "vnet/ethernet/ethernet_types.api";
@ -21,6 +21,7 @@ import "vnet/ip/ip_types.api";
define geneve_add_del_tunnel define geneve_add_del_tunnel
{ {
option deprecated="20.06";
u32 client_index; u32 client_index;
u32 context; u32 context;
bool is_add; bool is_add;
@ -39,6 +40,27 @@ define geneve_add_del_tunnel_reply
vl_api_interface_index_t sw_if_index; 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 define geneve_tunnel_dump
{ {
u32 client_index; u32 client_index;

View File

@ -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, "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, "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))) if (PREDICT_FALSE (ip46_address_is_multicast (&t->remote)))
s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index); 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; 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* */ /* *INDENT-OFF* */
VNET_DEVICE_CLASS (geneve_device_class, static) = { VNET_DEVICE_CLASS (geneve_device_class, static) = {
.name = "GENEVE", .name = "GENEVE",
.format_device_name = format_geneve_name, .format_device_name = format_geneve_name,
.format_tx_trace = format_geneve_encap_trace, .format_tx_trace = format_geneve_encap_trace,
.admin_up_down_function = geneve_interface_admin_up_down, .admin_up_down_function = geneve_interface_admin_up_down,
.mac_addr_change_function = geneve_mac_change,
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@ -207,7 +217,8 @@ _(mcast_sw_if_index) \
_(encap_fib_index) \ _(encap_fib_index) \
_(decap_next_index) \ _(decap_next_index) \
_(local) \ _(local) \
_(remote) _(remote) \
_(l3_mode)
static int static int
geneve_rewrite (geneve_tunnel_t * t, bool is_ip6) 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); hash_set (vxm->geneve4_tunnel_by_key, key4.as_u64, t - vxm->tunnels);
vnet_hw_interface_t *hi; 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; u32 t_idx = t - vxm->tunnels;
hw_if_index = vxm->free_geneve_tunnel_hw_if_indices u8 address[6] =
[vec_len (vxm->free_geneve_tunnel_hw_if_indices) - 1]; { 0xd0, 0x0b, 0xee, 0xd0, (u8) (t_idx >> 8), (u8) t_idx };
_vec_len (vxm->free_geneve_tunnel_hw_if_indices) -= 1; clib_error_t *error =
ethernet_register_interface (vnm, geneve_device_class.index,
hi = vnet_get_hw_interface (vnm, hw_if_index); t_idx,
hi->dev_instance = t - vxm->tunnels; address, &hw_if_index, 0);
hi->hw_instance = hi->dev_instance; if (error)
{
/* clear old stats of freed tunnel before reuse */ clib_error_report (error);
sw_if_index = hi->sw_if_index; return VNET_API_ERROR_INVALID_REGISTRATION;
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);
} }
else else
{ {
hw_if_index = vnet_register_interface hw_if_index = vnet_register_interface
(vnm, geneve_device_class.index, t - vxm->tunnels, (vnm, geneve_device_class.index, t - vxm->tunnels,
geneve_hw_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 */ /* Set geneve tunnel output node */
u32 encap_index = !is_ip6 ? u32 encap_index = !is_ip6 ?
geneve4_encap_node.index : geneve6_encap_node.index; 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 */ /* 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, set_int_l2_mode (vxm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0,
L2_BD_PORT_TYPE_NORMAL, 0, 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; 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 grp_set = 0;
u8 ipv4_set = 0; u8 ipv4_set = 0;
u8 ipv6_set = 0; u8 ipv6_set = 0;
u8 l3_mode = 0;
u32 encap_fib_index = 0; u32 encap_fib_index = 0;
u32 mcast_sw_if_index = ~0; u32 mcast_sw_if_index = ~0;
u32 decap_next_index = GENEVE_INPUT_NEXT_L2_INPUT; 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; goto done;
} }
} }
else if (unformat (line_input, "l3-mode"))
{
l3_mode = 1;
}
else else
{ {
error = clib_error_return (0, "parse error: '%U'", error = clib_error_return (0, "parse error: '%U'",
@ -864,7 +875,7 @@ VLIB_CLI_COMMAND (create_geneve_tunnel_command, static) = {
.short_help = .short_help =
"create geneve tunnel local <local-vtep-addr>" "create geneve tunnel local <local-vtep-addr>"
" {remote <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>" " {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, .function = geneve_add_del_tunnel_command_fn,
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */

View File

@ -135,6 +135,8 @@ typedef struct
* The tunnels sibling index on the FIB entry's dependency list. * The tunnels sibling index on the FIB entry's dependency list.
*/ */
u32 sibling_index; u32 sibling_index;
u8 l3_mode;
} geneve_tunnel_t; } geneve_tunnel_t;
#define foreach_geneve_input_next \ #define foreach_geneve_input_next \
@ -173,9 +175,6 @@ typedef struct
/* mcast shared info */ /* mcast shared info */
uword *mcast_shared; /* keyed on mcast ip46 addr */ 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 */ /* Mapping from sw_if_index to tunnel index */
u32 *tunnel_index_by_sw_if_index; u32 *tunnel_index_by_sw_if_index;
@ -205,6 +204,7 @@ typedef struct
u32 encap_fib_index; u32 encap_fib_index;
u32 decap_next_index; u32 decap_next_index;
u32 vni; u32 vni;
u8 l3_mode;
} vnet_geneve_add_del_tunnel_args_t; } vnet_geneve_add_del_tunnel_args_t;
int vnet_geneve_add_del_tunnel int vnet_geneve_add_del_tunnel

View File

@ -45,6 +45,7 @@
#define foreach_vpe_api_msg \ #define foreach_vpe_api_msg \
_(SW_INTERFACE_SET_GENEVE_BYPASS, sw_interface_set_geneve_bypass) \ _(SW_INTERFACE_SET_GENEVE_BYPASS, sw_interface_set_geneve_bypass) \
_(GENEVE_ADD_DEL_TUNNEL, geneve_add_del_tunnel) \ _(GENEVE_ADD_DEL_TUNNEL, geneve_add_del_tunnel) \
_(GENEVE_ADD_DEL_TUNNEL2, geneve_add_del_tunnel2) \
_(GENEVE_TUNNEL_DUMP, geneve_tunnel_dump) _(GENEVE_TUNNEL_DUMP, geneve_tunnel_dump)
static void static void
@ -114,6 +115,58 @@ out:
/* *INDENT-ON* */ /* *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 static void send_geneve_tunnel_details
(geneve_tunnel_t * t, vl_api_registration_t * reg, u32 context) (geneve_tunnel_t * t, vl_api_registration_t * reg, u32 context)
{ {

View File

@ -6,8 +6,8 @@ import unittest
from framework import VppTestCase, VppTestRunner from framework import VppTestCase, VppTestRunner
from template_bd import BridgeDomain from template_bd import BridgeDomain
from scapy.layers.l2 import Ether from scapy.layers.l2 import Ether, ARP
from scapy.layers.inet import IP, UDP from scapy.layers.inet import IP, UDP, ICMP
from scapy.contrib.geneve import GENEVE from scapy.contrib.geneve import GENEVE
import util import util
@ -234,5 +234,74 @@ class TestGeneve(BridgeDomain, VppTestCase):
self.logger.info(self.vapi.cli("show geneve tunnel")) 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__': if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner) unittest.main(testRunner=VppTestRunner)