pppoe: make pppoe plugin work with dot1q subinterfaces

- Enabling arc "device-input" with the next node "pppoe-input" on the pppoe cp interface: to get rid of L3_MAC_MISMATCH error
- Parsing in the "pppoe-input" node fixed to parse all headers from the scratch
- Getting mac address directly from encap interface when filling up DPO adjacency. Anyway, in the case of the dot1q subinterface, we need to get vlan tags to fill the DPO adjacency.

Type: improvement

Change-Id: I5405931b0f58bef7b852c079a7e66e0da8b5de0f
Signed-off-by: Stanislav Zaikin <zstaseg@gmail.com>
This commit is contained in:
zstas
2020-05-09 16:57:23 +00:00
committed by Damjan Marion
parent 58d66743aa
commit 340b10a38e
8 changed files with 265 additions and 39 deletions
+24
View File
@@ -86,6 +86,30 @@ define pppoe_session_details
vl_api_mac_address_t client_mac;
};
/** \brief Create PPPOE control plane interface
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - software index of the interface
@param is_add - to create or to delete
*/
define pppoe_add_del_cp
{
u32 client_index;
u32 context;
vl_api_interface_index_t sw_if_index;
u8 is_add;
option vat_help = "[ sw_if_index <intfc> is_add <bool> ]";
};
/** \brief reply for create PPPOE control plane interface
@param retval - return code
*/
define pppoe_add_del_cp_reply
{
u32 context;
i32 retval;
};
/*
* Local Variables:
* eval: (c-set-style "gnu")
+52 -14
View File
@@ -98,23 +98,53 @@ pppoe_build_rewrite (vnet_main_t * vnm,
u32 sw_if_index,
vnet_link_t link_type, const void *dst_address)
{
int len = sizeof (pppoe_header_t) + sizeof (ethernet_header_t);
pppoe_main_t *pem = &pppoe_main;
pppoe_session_t *t;
vnet_hw_interface_t *hi;
vnet_sw_interface_t *si;
pppoe_header_t *pppoe;
u32 session_id;
u8 *rw = 0;
session_id = pem->session_index_by_sw_if_index[sw_if_index];
t = pool_elt_at_index (pem->sessions, session_id);
int len = sizeof (pppoe_header_t) + sizeof (ethernet_header_t);
si = vnet_get_sw_interface (vnm, t->encap_if_index);
if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
{
if (si->sub.eth.flags.one_tag == 1)
{
len += sizeof (ethernet_vlan_header_t);
}
}
vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
ethernet_header_t *eth_hdr = (ethernet_header_t *) rw;
clib_memcpy (eth_hdr->dst_address, t->client_mac, 6);
clib_memcpy (eth_hdr->src_address, t->local_mac, 6);
eth_hdr->type = clib_host_to_net_u16 (ETHERNET_TYPE_PPPOE_SESSION);
pppoe = (pppoe_header_t *) (eth_hdr + 1);
if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
{
if (si->sub.eth.flags.one_tag == 1)
{
eth_hdr->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
ethernet_vlan_header_t *vlan =
(ethernet_vlan_header_t *) (eth_hdr + 1);
vlan->type = clib_host_to_net_u16 (ETHERNET_TYPE_PPPOE_SESSION);
vlan->priority_cfi_and_id =
clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
pppoe = (pppoe_header_t *) (vlan + 1);
}
si = vnet_get_sw_interface (vnm, si->sup_sw_if_index);
}
// set the right mac addresses
hi = vnet_get_hw_interface (vnm, si->hw_if_index);
clib_memcpy (eth_hdr->src_address, hi->hw_address, 6);
clib_memcpy (eth_hdr->dst_address, t->client_mac, 6);
pppoe_header_t *pppoe = (pppoe_header_t *) (eth_hdr + 1);
pppoe->ver_type = PPPOE_VER_TYPE;
pppoe->code = 0;
pppoe->session_id = clib_host_to_net_u16 (t->session_id);
@@ -142,20 +172,16 @@ static void
pppoe_fixup (vlib_main_t * vm,
const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
{
const pppoe_session_t *t;
//const pppoe_session_t *t;
pppoe_header_t *pppoe0;
uword len = (uword) data;
/* update the rewrite string */
pppoe0 = vlib_buffer_get_current (b0) + sizeof (ethernet_header_t);
pppoe0 = vlib_buffer_get_current (b0) + len;
pppoe0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
- sizeof (pppoe_header_t)
+ sizeof (pppoe0->ppp_proto)
- sizeof (ethernet_header_t));
/* Swap to the the packet's output interface to the encap (not the
* session) interface */
t = data;
vnet_buffer (b0)->sw_if_index[VLIB_TX] = t->encap_if_index;
+ sizeof (pppoe0->ppp_proto) - len);
}
static void
@@ -165,6 +191,7 @@ pppoe_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
dpo_id_t dpo = DPO_INVALID;
ip_adjacency_t *adj;
pppoe_session_t *t;
vnet_sw_interface_t *si;
u32 session_id;
ASSERT (ADJ_INDEX_INVALID != ai);
@@ -173,12 +200,23 @@ pppoe_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
session_id = pem->session_index_by_sw_if_index[sw_if_index];
t = pool_elt_at_index (pem->sessions, session_id);
uword len = sizeof (ethernet_header_t);
si = vnet_get_sw_interface (vnm, t->encap_if_index);
if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
{
if (si->sub.eth.flags.one_tag == 1)
{
len += sizeof (ethernet_vlan_header_t);
}
}
switch (adj->lookup_next_index)
{
case IP_LOOKUP_NEXT_ARP:
case IP_LOOKUP_NEXT_GLEAN:
case IP_LOOKUP_NEXT_BCAST:
adj_nbr_midchain_update_rewrite (ai, pppoe_fixup, t,
adj_nbr_midchain_update_rewrite (ai, pppoe_fixup, (void *) len,
ADJ_FLAG_NONE,
pppoe_build_rewrite (vnm,
sw_if_index,
@@ -190,7 +228,7 @@ pppoe_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
* Construct a partial rewrite from the known ethernet mcast dest MAC
* There's no MAC fixup, so the last 2 parameters are 0
*/
adj_mcast_midchain_update_rewrite (ai, pppoe_fixup, t,
adj_mcast_midchain_update_rewrite (ai, pppoe_fixup, (void *) len,
ADJ_FLAG_NONE,
pppoe_build_rewrite (vnm,
sw_if_index,
+2
View File
@@ -205,6 +205,8 @@ typedef struct
u32 cp_if_index;
} vnet_pppoe_add_del_tap_args_t;
int pppoe_add_del_cp (u32 cp_if_index, u8 is_add);
always_inline u64
pppoe_make_key (u8 * mac_address, u16 session_id)
{
+14
View File
@@ -139,6 +139,20 @@ vl_api_pppoe_session_dump_t_handler (vl_api_pppoe_session_dump_t * mp)
}
}
static void
vl_api_pppoe_add_del_cp_t_handler (vl_api_pppoe_add_del_cp_t * mp)
{
vl_api_pppoe_add_del_cp_reply_t *rmp;
i32 rv = 0;
pppoe_main_t *pem = &pppoe_main;
rv = pppoe_add_del_cp (ntohl (mp->sw_if_index), mp->is_add);
/* *INDENT-OFF* */
REPLY_MACRO(VL_API_PPPOE_ADD_DEL_CP_REPLY);
/* *INDENT-ON* */
}
#include <pppoe/pppoe.api.c>
static clib_error_t *
pppoe_api_hookup (vlib_main_t * vm)
+28 -1
View File
@@ -17,6 +17,30 @@
#include <pppoe/pppoe.h>
int
pppoe_add_del_cp (u32 cp_if_index, u8 is_add)
{
pppoe_main_t *pem = &pppoe_main;
if (cp_if_index == 0)
{
return ~0;
}
vnet_feature_enable_disable ("device-input", "pppoe-input",
cp_if_index, is_add, 0, 0);
if (is_add)
{
pem->cp_if_index = cp_if_index;
}
else
{
pem->cp_if_index = ~0;
}
return 0;
}
static clib_error_t *
pppoe_add_del_cp_command_fn (vlib_main_t * vm,
unformat_input_t * input,
@@ -55,6 +79,9 @@ pppoe_add_del_cp_command_fn (vlib_main_t * vm,
goto done;
}
vnet_feature_enable_disable ("device-input", "pppoe-input",
cp_if_index, is_add, 0, 0);
if (is_add)
{
pem->cp_if_index = cp_if_index;
@@ -74,7 +101,7 @@ done:
VLIB_CLI_COMMAND (create_pppoe_cp_cmd, static) =
{
.path = "create pppoe cp",
.short_help = "create pppoe cp if-name <intfc> [del]",
.short_help = "create pppoe cp-if-index <intfc> [del]",
.function = pppoe_add_del_cp_command_fn,
};
/* *INDENT-ON* */
+3
View File
@@ -153,6 +153,9 @@ VLIB_NODE_FN (pppoe_cp_dispatch_node) (vlib_main_t * vm,
/* set src mac address */
si = vnet_get_sw_interface(vnm, tx_sw_if_index0);
if( si->type == VNET_SW_INTERFACE_TYPE_SUB ) {
si = vnet_get_sw_interface(vnm, si->sup_sw_if_index);
}
hi = vnet_get_hw_interface (vnm, si->hw_if_index);
clib_memcpy_fast (vlib_buffer_get_current (b0)+6, hi->hw_address, 6);
}
+97 -24
View File
@@ -82,14 +82,16 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
vlib_buffer_t * b0, * b1;
u32 next0, next1;
ethernet_header_t *h0, *h1;
ethernet_vlan_header_t *vlan0 = 0, *vlan1 = 0;
pppoe_header_t * pppoe0, * pppoe1;
u16 ppp_proto0 = 0, ppp_proto1 = 0;
pppoe_session_t * t0, * t1;
u32 error0, error1;
u32 error0 = 0, error1 = 0;
u32 sw_if_index0, sw_if_index1, len0, len1;
pppoe_entry_key_t key0, key1;
pppoe_entry_result_t result0, result1;
u32 bucket0, bucket1;
u16 type0, type1;
/* Prefetch next iteration. */
{
@@ -119,24 +121,40 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
error0 = 0;
error1 = 0;
/* leaves current_data pointing at the pppoe header */
pppoe0 = vlib_buffer_get_current (b0);
pppoe1 = vlib_buffer_get_current (b1);
ppp_proto0 = clib_net_to_host_u16(pppoe0->ppp_proto);
ppp_proto1 = clib_net_to_host_u16(pppoe1->ppp_proto);
/* get client mac */
vlib_buffer_reset(b0);
h0 = vlib_buffer_get_current (b0);
/* get pppoe header */
type0 = clib_net_to_host_u16(h0->type);
if(type0 == ETHERNET_TYPE_VLAN){
vlan0 = (ethernet_vlan_header_t *)(h0+1);
type0 = clib_net_to_host_u16(vlan0->type);
pppoe0 = (pppoe_header_t*)(vlan0+1);
if( type0 != ETHERNET_TYPE_PPPOE_DISCOVERY && type0 != ETHERNET_TYPE_PPPOE_SESSION ) {
error0 = PPPOE_ERROR_BAD_VER_TYPE;
next0 = PPPOE_INPUT_NEXT_DROP;
goto trace0;
}
} else {
pppoe0 = (pppoe_header_t*)(h0+1);
}
ppp_proto0 = clib_net_to_host_u16(pppoe0->ppp_proto);
/* Manipulate packet 0 */
if ((ppp_proto0 != PPP_PROTOCOL_ip4)
&& (ppp_proto0 != PPP_PROTOCOL_ip6))
{
vlan0 == 0 ?
vlib_buffer_advance(b0, sizeof(*h0))
:
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0));
error0 = PPPOE_ERROR_CONTROL_PLANE;
next0 = PPPOE_INPUT_NEXT_CP_INPUT;
goto trace0;
}
/* get client mac */
vlib_buffer_reset(b0);
h0 = vlib_buffer_get_current (b0);
pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
h0->src_address, pppoe0->session_id,
@@ -152,7 +170,10 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
result0.fields.session_index);
/* Pop Eth and PPPoE header */
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*pppoe0));
vlan0 == 0 ?
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*pppoe0))
:
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0)+sizeof(*pppoe0));
next0 = (ppp_proto0==PPP_PROTOCOL_ip4)?
PPPOE_INPUT_NEXT_IP4_INPUT
@@ -194,20 +215,40 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
tr->session_id = clib_net_to_host_u32(pppoe0->session_id);
}
/* get client mac */
vlib_buffer_reset(b1);
h1 = vlib_buffer_get_current (b1);
/* get pppoe header */
type1 = clib_net_to_host_u16(h1->type);
if(type1 == ETHERNET_TYPE_VLAN){
vlan1 = (ethernet_vlan_header_t *)(h1+1);
type1 = clib_net_to_host_u16(vlan1->type);
pppoe1 = (pppoe_header_t*)(vlan1+1);
if( type1 != ETHERNET_TYPE_PPPOE_DISCOVERY && type1 != ETHERNET_TYPE_PPPOE_SESSION ) {
error1 = PPPOE_ERROR_BAD_VER_TYPE;
next1 = PPPOE_INPUT_NEXT_DROP;
goto trace1;
}
} else {
pppoe1 = (pppoe_header_t*)(h1+1);
}
ppp_proto1 = clib_net_to_host_u16(pppoe1->ppp_proto);
/* Manipulate packet 1 */
if ((ppp_proto1 != PPP_PROTOCOL_ip4)
&& (ppp_proto1 != PPP_PROTOCOL_ip6))
{
vlan1 == 0 ?
vlib_buffer_advance(b1, sizeof(*h1))
:
vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*vlan1));
error1 = PPPOE_ERROR_CONTROL_PLANE;
next1 = PPPOE_INPUT_NEXT_CP_INPUT;
goto trace1;
}
/* get client mac */
vlib_buffer_reset(b1);
h1 = vlib_buffer_get_current (b1);
pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
h1->src_address, pppoe1->session_id,
&key1, &bucket1, &result1);
@@ -222,7 +263,10 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
result1.fields.session_index);
/* Pop Eth and PPPoE header */
vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*pppoe1));
vlan1 == 0 ?
vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*pppoe1))
:
vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*vlan1)+sizeof(*pppoe1));
next1 = (ppp_proto1==PPP_PROTOCOL_ip4)?
PPPOE_INPUT_NEXT_IP4_INPUT
@@ -275,6 +319,7 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
vlib_buffer_t * b0;
u32 next0;
ethernet_header_t *h0;
ethernet_vlan_header_t *vlan0 = 0;
pppoe_header_t * pppoe0;
u16 ppp_proto0 = 0;
pppoe_session_t * t0;
@@ -283,6 +328,7 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
pppoe_entry_key_t key0;
pppoe_entry_result_t result0;
u32 bucket0;
u32 type0;
bi0 = from[0];
to_next[0] = bi0;
@@ -294,22 +340,39 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
b0 = vlib_get_buffer (vm, bi0);
error0 = 0;
/* leaves current_data pointing at the pppoe header */
pppoe0 = vlib_buffer_get_current (b0);
ppp_proto0 = clib_net_to_host_u16(pppoe0->ppp_proto);
/* get client mac */
vlib_buffer_reset(b0);
h0 = vlib_buffer_get_current (b0);
/* get pppoe header */
type0 = clib_net_to_host_u16(h0->type);
if(type0 == ETHERNET_TYPE_VLAN){
vlan0 = (ethernet_vlan_header_t *)(h0+1);
type0 = clib_net_to_host_u16(vlan0->type);
pppoe0 = (pppoe_header_t*)(vlan0+1);
if( type0 != ETHERNET_TYPE_PPPOE_DISCOVERY && type0 != ETHERNET_TYPE_PPPOE_SESSION ) {
error0 = PPPOE_ERROR_BAD_VER_TYPE;
next0 = PPPOE_INPUT_NEXT_DROP;
goto trace00;
}
} else {
pppoe0 = (pppoe_header_t*)(h0+1);
}
ppp_proto0 = clib_net_to_host_u16(pppoe0->ppp_proto);
if ((ppp_proto0 != PPP_PROTOCOL_ip4)
&& (ppp_proto0 != PPP_PROTOCOL_ip6))
{
vlan0 == 0 ?
vlib_buffer_advance(b0, sizeof(*h0))
:
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0));
error0 = PPPOE_ERROR_CONTROL_PLANE;
next0 = PPPOE_INPUT_NEXT_CP_INPUT;
goto trace00;
}
/* get client mac */
vlib_buffer_reset(b0);
h0 = vlib_buffer_get_current (b0);
pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
h0->src_address, pppoe0->session_id,
&key0, &bucket0, &result0);
@@ -324,7 +387,10 @@ VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
result0.fields.session_index);
/* Pop Eth and PPPoE header */
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*pppoe0));
vlan0 == 0 ?
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*pppoe0))
:
vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0)+sizeof(*pppoe0));
next0 = (ppp_proto0==PPP_PROTOCOL_ip4)?
PPPOE_INPUT_NEXT_IP4_INPUT
@@ -416,4 +482,11 @@ VLIB_REGISTER_NODE (pppoe_input_node) = {
.format_trace = format_pppoe_rx_trace,
};
/* *INDENT-OFF* */
VNET_FEATURE_INIT (pppoe_input_node, static) =
{
.arc_name = "device-input",
.node_name = "pppoe-input",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
/* *INDENT-ON */
+45
View File
@@ -237,4 +237,49 @@ api_pppoe_session_dump (vat_main_t * vam)
return ret;
}
static void vl_api_pppoe_add_del_cp_reply_t_handler
(vl_api_pppoe_add_del_session_reply_t * mp)
{
vat_main_t *vam = &vat_main;
i32 retval = ntohl (mp->retval);
if (vam->async_mode)
{
vam->async_errors += (retval < 0);
}
else
{
vam->retval = retval;
vam->result_ready = 1;
}
}
static int
api_pppoe_add_del_cp (vat_main_t * vam)
{
unformat_input_t *line_input = vam->input;
vl_api_pppoe_add_del_cp_t *mp;
u8 is_add = 1;
u32 sw_if_index = ~0;
int ret;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "del"))
{
is_add = 0;
}
else if (unformat (line_input, "cp-if-index %d", &sw_if_index))
;
}
M (PPPOE_ADD_DEL_CP, mp);
mp->is_add = is_add;
mp->sw_if_index = sw_if_index;
S (mp);
W (ret);
return ret;
}
#include <pppoe/pppoe.api_test.c>