LCOV - code coverage report
Current view: top level - plugins/pppoe - pppoe.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 198 302 65.6 %
Date: 2023-07-05 22:20:52 Functions: 24 26 92.3 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2017 Intel and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : #include <stdint.h>
      18             : #include <net/if.h>
      19             : #include <sys/ioctl.h>
      20             : #include <inttypes.h>
      21             : 
      22             : #include <vlib/vlib.h>
      23             : #include <vlib/unix/unix.h>
      24             : #include <vnet/ethernet/ethernet.h>
      25             : #include <vnet/fib/fib_entry.h>
      26             : #include <vnet/fib/fib_table.h>
      27             : #include <vnet/dpo/interface_tx_dpo.h>
      28             : #include <vnet/plugin/plugin.h>
      29             : #include <vpp/app/version.h>
      30             : #include <vnet/ppp/packet.h>
      31             : #include <pppoe/pppoe.h>
      32             : #include <vnet/adj/adj_midchain.h>
      33             : #include <vnet/adj/adj_mcast.h>
      34             : 
      35             : #include <vppinfra/hash.h>
      36             : #include <vppinfra/bihash_template.c>
      37             : 
      38             : pppoe_main_t pppoe_main;
      39             : 
      40             : static fib_source_t pppoe_fib_src;
      41             : 
      42             : u8 *
      43           6 : format_pppoe_session (u8 * s, va_list * args)
      44             : {
      45           6 :   pppoe_session_t *t = va_arg (*args, pppoe_session_t *);
      46           6 :   pppoe_main_t *pem = &pppoe_main;
      47             : 
      48           6 :   s = format (s, "[%d] sw-if-index %d client-ip %U session-id %d ",
      49           6 :               t - pem->sessions, t->sw_if_index,
      50             :               format_ip46_address, &t->client_ip, IP46_TYPE_ANY,
      51           6 :               t->session_id);
      52             : 
      53           6 :   s = format (s, "encap-if-index %d decap-fib-index %d\n",
      54             :               t->encap_if_index, t->decap_fib_index);
      55             : 
      56           6 :   s = format (s, "    local-mac %U  client-mac %U",
      57           6 :               format_ethernet_address, t->local_mac,
      58           6 :               format_ethernet_address, t->client_mac);
      59             : 
      60           6 :   return s;
      61             : }
      62             : 
      63             : static u8 *
      64          12 : format_pppoe_name (u8 * s, va_list * args)
      65             : {
      66          12 :   u32 dev_instance = va_arg (*args, u32);
      67          12 :   return format (s, "pppoe_session%d", dev_instance);
      68             : }
      69             : 
      70             : static clib_error_t *
      71          16 : pppoe_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
      72             : {
      73          16 :   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
      74             :     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
      75          16 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
      76             : 
      77          16 :   return /* no error */ 0;
      78             : }
      79             : 
      80             : /* *INDENT-OFF* */
      81        4479 : VNET_DEVICE_CLASS (pppoe_device_class,static) = {
      82             :   .name = "PPPoE",
      83             :   .format_device_name = format_pppoe_name,
      84             :   .admin_up_down_function = pppoe_interface_admin_up_down,
      85             : };
      86             : /* *INDENT-ON* */
      87             : 
      88             : static u8 *
      89           0 : format_pppoe_header_with_length (u8 * s, va_list * args)
      90             : {
      91           0 :   u32 dev_instance = va_arg (*args, u32);
      92           0 :   s = format (s, "unimplemented dev %u", dev_instance);
      93           0 :   return s;
      94             : }
      95             : 
      96             : static u8 *
      97           8 : pppoe_build_rewrite (vnet_main_t * vnm,
      98             :                      u32 sw_if_index,
      99             :                      vnet_link_t link_type, const void *dst_address)
     100             : {
     101           8 :   pppoe_main_t *pem = &pppoe_main;
     102             :   pppoe_session_t *t;
     103             :   vnet_hw_interface_t *hi;
     104             :   vnet_sw_interface_t *si;
     105             :   pppoe_header_t *pppoe;
     106             :   u32 session_id;
     107           8 :   u8 *rw = 0;
     108             : 
     109           8 :   session_id = pem->session_index_by_sw_if_index[sw_if_index];
     110           8 :   t = pool_elt_at_index (pem->sessions, session_id);
     111             : 
     112           8 :   int len = sizeof (pppoe_header_t) + sizeof (ethernet_header_t);
     113           8 :   si = vnet_get_sw_interface (vnm, t->encap_if_index);
     114           8 :   if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
     115             :     {
     116           0 :       if (si->sub.eth.flags.one_tag == 1)
     117             :         {
     118           0 :           len += sizeof (ethernet_vlan_header_t);
     119             :         }
     120             :     }
     121             : 
     122           8 :   vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
     123             : 
     124           8 :   ethernet_header_t *eth_hdr = (ethernet_header_t *) rw;
     125           8 :   eth_hdr->type = clib_host_to_net_u16 (ETHERNET_TYPE_PPPOE_SESSION);
     126           8 :   pppoe = (pppoe_header_t *) (eth_hdr + 1);
     127             : 
     128           8 :   if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
     129             :     {
     130           0 :       if (si->sub.eth.flags.one_tag == 1)
     131             :         {
     132           0 :           eth_hdr->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     133           0 :           ethernet_vlan_header_t *vlan =
     134             :             (ethernet_vlan_header_t *) (eth_hdr + 1);
     135           0 :           vlan->type = clib_host_to_net_u16 (ETHERNET_TYPE_PPPOE_SESSION);
     136           0 :           vlan->priority_cfi_and_id =
     137           0 :             clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
     138           0 :           pppoe = (pppoe_header_t *) (vlan + 1);
     139             :         }
     140           0 :       si = vnet_get_sw_interface (vnm, si->sup_sw_if_index);
     141             :     }
     142             : 
     143             :   // set the right mac addresses
     144           8 :   hi = vnet_get_hw_interface (vnm, si->hw_if_index);
     145           8 :   clib_memcpy (eth_hdr->src_address, hi->hw_address, 6);
     146           8 :   clib_memcpy (eth_hdr->dst_address, t->client_mac, 6);
     147             : 
     148           8 :   pppoe->ver_type = PPPOE_VER_TYPE;
     149           8 :   pppoe->code = 0;
     150           8 :   pppoe->session_id = clib_host_to_net_u16 (t->session_id);
     151           8 :   pppoe->length = 0;         /* To be filled in at run-time */
     152             : 
     153           8 :   switch (link_type)
     154             :     {
     155           8 :     case VNET_LINK_IP4:
     156           8 :       pppoe->ppp_proto = clib_host_to_net_u16 (PPP_PROTOCOL_ip4);
     157           8 :       break;
     158           0 :     case VNET_LINK_IP6:
     159           0 :       pppoe->ppp_proto = clib_host_to_net_u16 (PPP_PROTOCOL_ip6);
     160           0 :       break;
     161           0 :     default:
     162           0 :       break;
     163             :     }
     164             : 
     165           8 :   return rw;
     166             : }
     167             : 
     168             : /**
     169             :  * @brief Fixup the adj rewrite post encap. Insert the packet's length
     170             :  */
     171             : static void
     172          67 : pppoe_fixup (vlib_main_t * vm,
     173             :              const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
     174             : {
     175             :   //const pppoe_session_t *t;
     176             :   pppoe_header_t *pppoe0;
     177          67 :   uword len = (uword) data;
     178             : 
     179             :   /* update the rewrite string */
     180          67 :   pppoe0 = vlib_buffer_get_current (b0) + len;
     181             : 
     182          67 :   pppoe0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
     183             :                                          - sizeof (pppoe_header_t)
     184          67 :                                          + sizeof (pppoe0->ppp_proto) - len);
     185          67 : }
     186             : 
     187             : static void
     188           8 : pppoe_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
     189             : {
     190           8 :   pppoe_main_t *pem = &pppoe_main;
     191           8 :   dpo_id_t dpo = DPO_INVALID;
     192             :   ip_adjacency_t *adj;
     193             :   pppoe_session_t *t;
     194             :   vnet_sw_interface_t *si;
     195             :   u32 session_id;
     196             : 
     197           8 :   ASSERT (ADJ_INDEX_INVALID != ai);
     198             : 
     199           8 :   adj = adj_get (ai);
     200           8 :   session_id = pem->session_index_by_sw_if_index[sw_if_index];
     201           8 :   t = pool_elt_at_index (pem->sessions, session_id);
     202             : 
     203           8 :   uword len = sizeof (ethernet_header_t);
     204             : 
     205           8 :   si = vnet_get_sw_interface (vnm, t->encap_if_index);
     206           8 :   if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
     207             :     {
     208           0 :       if (si->sub.eth.flags.one_tag == 1)
     209             :         {
     210           0 :           len += sizeof (ethernet_vlan_header_t);
     211             :         }
     212             :     }
     213             : 
     214           8 :   switch (adj->lookup_next_index)
     215             :     {
     216           8 :     case IP_LOOKUP_NEXT_ARP:
     217             :     case IP_LOOKUP_NEXT_GLEAN:
     218             :     case IP_LOOKUP_NEXT_BCAST:
     219           8 :       adj_nbr_midchain_update_rewrite (ai, pppoe_fixup, (void *) len,
     220             :                                        ADJ_FLAG_NONE,
     221             :                                        pppoe_build_rewrite (vnm,
     222             :                                                             sw_if_index,
     223           8 :                                                             adj->ia_link,
     224             :                                                             NULL));
     225           8 :       break;
     226           0 :     case IP_LOOKUP_NEXT_MCAST:
     227             :       /*
     228             :        * Construct a partial rewrite from the known ethernet mcast dest MAC
     229             :        * There's no MAC fixup, so the last 2 parameters are 0
     230             :        */
     231           0 :       adj_mcast_midchain_update_rewrite (ai, pppoe_fixup, (void *) len,
     232             :                                          ADJ_FLAG_NONE,
     233             :                                          pppoe_build_rewrite (vnm,
     234             :                                                               sw_if_index,
     235           0 :                                                               adj->ia_link,
     236             :                                                               NULL), 0, 0);
     237           0 :       break;
     238             : 
     239           0 :     case IP_LOOKUP_NEXT_DROP:
     240             :     case IP_LOOKUP_NEXT_PUNT:
     241             :     case IP_LOOKUP_NEXT_LOCAL:
     242             :     case IP_LOOKUP_NEXT_REWRITE:
     243             :     case IP_LOOKUP_NEXT_MIDCHAIN:
     244             :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     245             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
     246             :     case IP_LOOKUP_N_NEXT:
     247           0 :       ASSERT (0);
     248           0 :       break;
     249             :     }
     250             : 
     251           8 :   interface_tx_dpo_add_or_lock (vnet_link_to_dpo_proto (adj->ia_link),
     252             :                                 t->encap_if_index, &dpo);
     253             : 
     254           8 :   adj_nbr_midchain_stack (ai, &dpo);
     255             : 
     256           8 :   dpo_reset (&dpo);
     257           8 : }
     258             : 
     259             : /* *INDENT-OFF* */
     260        2239 : VNET_HW_INTERFACE_CLASS (pppoe_hw_class) =
     261             : {
     262             :   .name = "PPPoE",
     263             :   .format_header = format_pppoe_header_with_length,
     264             :   .build_rewrite = pppoe_build_rewrite,
     265             :   .update_adjacency = pppoe_update_adj,
     266             :   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
     267             : };
     268             : /* *INDENT-ON* */
     269             : 
     270             : #define foreach_copy_field                      \
     271             : _(session_id)                                   \
     272             : _(encap_if_index)                               \
     273             : _(decap_fib_index)                              \
     274             : _(client_ip)
     275             : 
     276             : static bool
     277           8 : pppoe_decap_next_is_valid (pppoe_main_t * pem, u32 is_ip6,
     278             :                            u32 decap_fib_index)
     279             : {
     280           8 :   vlib_main_t *vm = pem->vlib_main;
     281           8 :   u32 input_idx = (!is_ip6) ? ip4_input_node.index : ip6_input_node.index;
     282           8 :   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, input_idx);
     283             : 
     284           8 :   return decap_fib_index < r->n_next_nodes;
     285             : }
     286             : 
     287          18 : int vnet_pppoe_add_del_session
     288             :   (vnet_pppoe_add_del_session_args_t * a, u32 * sw_if_indexp)
     289             : {
     290          18 :   pppoe_main_t *pem = &pppoe_main;
     291          18 :   pppoe_session_t *t = 0;
     292          18 :   vnet_main_t *vnm = pem->vnet_main;
     293          18 :   u32 hw_if_index = ~0;
     294          18 :   u32 sw_if_index = ~0;
     295          18 :   u32 is_ip6 = a->is_ip6;
     296             :   pppoe_entry_key_t cached_key;
     297             :   pppoe_entry_result_t cached_result;
     298             :   u32 bucket;
     299             :   pppoe_entry_key_t key;
     300             :   pppoe_entry_result_t result;
     301             :   vnet_hw_interface_t *hi;
     302             :   vnet_sw_interface_t *si;
     303             :   fib_prefix_t pfx;
     304             : 
     305          18 :   cached_key.raw = ~0;
     306          18 :   cached_result.raw = ~0;       /* warning be gone */
     307          18 :   clib_memset (&pfx, 0, sizeof (pfx));
     308             : 
     309          18 :   if (!is_ip6)
     310             :     {
     311          18 :       pfx.fp_addr.ip4.as_u32 = a->client_ip.ip4.as_u32;
     312          18 :       pfx.fp_len = 32;
     313          18 :       pfx.fp_proto = FIB_PROTOCOL_IP4;
     314             :     }
     315             :   else
     316             :     {
     317           0 :       pfx.fp_addr.ip6.as_u64[0] = a->client_ip.ip6.as_u64[0];
     318           0 :       pfx.fp_addr.ip6.as_u64[1] = a->client_ip.ip6.as_u64[1];
     319           0 :       pfx.fp_len = 128;
     320           0 :       pfx.fp_proto = FIB_PROTOCOL_IP6;
     321             :     }
     322             : 
     323             :   /* Get encap_if_index and local mac address from link_table */
     324          18 :   pppoe_lookup_1 (&pem->link_table, &cached_key, &cached_result,
     325          18 :                   a->client_mac, 0, &key, &bucket, &result);
     326          18 :   a->encap_if_index = result.fields.sw_if_index;
     327             : 
     328          18 :   if (a->encap_if_index == ~0)
     329           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     330             : 
     331          18 :   si = vnet_get_sw_interface (vnm, a->encap_if_index);
     332          18 :   hi = vnet_get_hw_interface (vnm, si->hw_if_index);
     333             : 
     334             :   /* lookup session_table */
     335          18 :   pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
     336          18 :                   a->client_mac, clib_host_to_net_u16 (a->session_id),
     337             :                   &key, &bucket, &result);
     338             : 
     339             :   /* learn client session */
     340          18 :   pppoe_learn_process (&pem->session_table, a->encap_if_index,
     341             :                        &key, &cached_key, &bucket, &result);
     342             : 
     343          18 :   if (a->is_add)
     344             :     {
     345             :       /* adding a session: session must not already exist */
     346           9 :       if (result.fields.session_index != ~0)
     347           1 :         return VNET_API_ERROR_TUNNEL_EXIST;
     348             : 
     349             :       /*if not set explicitly, default to ip4 */
     350           8 :       if (!pppoe_decap_next_is_valid (pem, is_ip6, a->decap_fib_index))
     351           0 :         return VNET_API_ERROR_INVALID_DECAP_NEXT;
     352             : 
     353           8 :       pool_get_aligned (pem->sessions, t, CLIB_CACHE_LINE_BYTES);
     354           8 :       clib_memset (t, 0, sizeof (*t));
     355             : 
     356           8 :       clib_memcpy (t->local_mac, hi->hw_address, vec_len (hi->hw_address));
     357             : 
     358             :       /* copy from arg structure */
     359             : #define _(x) t->x = a->x;
     360           8 :       foreach_copy_field;
     361             : #undef _
     362             : 
     363           8 :       clib_memcpy (t->client_mac, a->client_mac, 6);
     364             : 
     365             :       /* update pppoe fib with session_index */
     366           8 :       result.fields.session_index = t - pem->sessions;
     367           8 :       pppoe_update_1 (&pem->session_table,
     368           8 :                       a->client_mac, clib_host_to_net_u16 (a->session_id),
     369             :                       &key, &bucket, &result);
     370             : 
     371             :       vnet_hw_interface_t *hi;
     372           8 :       if (vec_len (pem->free_pppoe_session_hw_if_indices) > 0)
     373           6 :         {
     374           6 :           vnet_interface_main_t *im = &vnm->interface_main;
     375          12 :           hw_if_index = pem->free_pppoe_session_hw_if_indices
     376           6 :             [vec_len (pem->free_pppoe_session_hw_if_indices) - 1];
     377           6 :           vec_dec_len (pem->free_pppoe_session_hw_if_indices, 1);
     378             : 
     379           6 :           hi = vnet_get_hw_interface (vnm, hw_if_index);
     380           6 :           hi->dev_instance = t - pem->sessions;
     381           6 :           hi->hw_instance = hi->dev_instance;
     382             : 
     383             :           /* clear old stats of freed session before reuse */
     384           6 :           sw_if_index = hi->sw_if_index;
     385           6 :           vnet_interface_counter_lock (im);
     386           6 :           vlib_zero_combined_counter
     387           6 :             (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
     388             :              sw_if_index);
     389           6 :           vlib_zero_combined_counter (&im->combined_sw_if_counters
     390             :                                       [VNET_INTERFACE_COUNTER_RX],
     391             :                                       sw_if_index);
     392           6 :           vlib_zero_simple_counter (&im->sw_if_counters
     393             :                                     [VNET_INTERFACE_COUNTER_DROP],
     394             :                                     sw_if_index);
     395           6 :           vnet_interface_counter_unlock (im);
     396             :         }
     397             :       else
     398             :         {
     399           2 :           hw_if_index = vnet_register_interface
     400           2 :             (vnm, pppoe_device_class.index, t - pem->sessions,
     401           2 :              pppoe_hw_class.index, t - pem->sessions);
     402           2 :           hi = vnet_get_hw_interface (vnm, hw_if_index);
     403             :         }
     404             : 
     405           8 :       t->hw_if_index = hw_if_index;
     406           8 :       t->sw_if_index = sw_if_index = hi->sw_if_index;
     407             : 
     408          14 :       vec_validate_init_empty (pem->session_index_by_sw_if_index, sw_if_index,
     409             :                                ~0);
     410           8 :       pem->session_index_by_sw_if_index[sw_if_index] = t - pem->sessions;
     411             : 
     412           8 :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     413           8 :       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
     414           8 :       vnet_sw_interface_set_flags (vnm, sw_if_index,
     415             :                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     416           8 :       vnet_set_interface_l3_output_node (vnm->vlib_main, sw_if_index,
     417             :                                          (u8 *) "tunnel-output");
     418             : 
     419             :       /* add reverse route for client ip */
     420           8 :       fib_table_entry_path_add (a->decap_fib_index, &pfx,
     421             :                                 pppoe_fib_src, FIB_ENTRY_FLAG_NONE,
     422           8 :                                 fib_proto_to_dpo (pfx.fp_proto),
     423             :                                 &pfx.fp_addr, sw_if_index, ~0,
     424             :                                 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
     425             : 
     426             :     }
     427             :   else
     428             :     {
     429             :       /* deleting a session: session must exist */
     430           9 :       if (result.fields.session_index == ~0)
     431           1 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     432             : 
     433           8 :       t = pool_elt_at_index (pem->sessions, result.fields.session_index);
     434           8 :       sw_if_index = t->sw_if_index;
     435             : 
     436           8 :       vnet_reset_interface_l3_output_node (vnm->vlib_main, sw_if_index);
     437           8 :       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
     438           8 :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
     439           8 :       si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
     440             : 
     441           8 :       vec_add1 (pem->free_pppoe_session_hw_if_indices, t->hw_if_index);
     442             : 
     443           8 :       pem->session_index_by_sw_if_index[t->sw_if_index] = ~0;
     444             : 
     445             :       /* update pppoe fib with session_inde=~0x */
     446           8 :       result.fields.session_index = ~0;
     447           8 :       pppoe_update_1 (&pem->session_table,
     448           8 :                       a->client_mac, clib_host_to_net_u16 (a->session_id),
     449             :                       &key, &bucket, &result);
     450             : 
     451             : 
     452             :       /* delete reverse route for client ip */
     453           8 :       fib_table_entry_path_remove (a->decap_fib_index, &pfx,
     454             :                                    pppoe_fib_src,
     455           8 :                                    fib_proto_to_dpo (pfx.fp_proto),
     456             :                                    &pfx.fp_addr,
     457             :                                    sw_if_index, ~0, 1,
     458             :                                    FIB_ROUTE_PATH_FLAG_NONE);
     459             : 
     460           8 :       pool_put (pem->sessions, t);
     461             :     }
     462             : 
     463          16 :   if (sw_if_indexp)
     464          16 :     *sw_if_indexp = sw_if_index;
     465             : 
     466          16 :   return 0;
     467             : }
     468             : 
     469             : static clib_error_t *
     470           0 : pppoe_add_del_session_command_fn (vlib_main_t * vm,
     471             :                                   unformat_input_t * input,
     472             :                                   vlib_cli_command_t * cmd)
     473             : {
     474           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     475           0 :   u16 session_id = 0;
     476             :   ip46_address_t client_ip;
     477           0 :   u8 is_add = 1;
     478           0 :   u8 client_ip_set = 0;
     479           0 :   u8 ipv4_set = 0;
     480           0 :   u8 ipv6_set = 0;
     481           0 :   u32 encap_if_index = 0;
     482           0 :   u32 decap_fib_index = 0;
     483           0 :   u8 client_mac[6] = { 0 };
     484           0 :   u8 client_mac_set = 0;
     485             :   int rv;
     486             :   u32 tmp;
     487           0 :   vnet_pppoe_add_del_session_args_t _a, *a = &_a;
     488             :   u32 session_sw_if_index;
     489           0 :   clib_error_t *error = NULL;
     490             : 
     491             :   /* Cant "universally zero init" (={0}) due to GCC bug 53119 */
     492           0 :   clib_memset (&client_ip, 0, sizeof client_ip);
     493             : 
     494             :   /* Get a line of input. */
     495           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     496           0 :     return 0;
     497             : 
     498           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     499             :     {
     500           0 :       if (unformat (line_input, "del"))
     501             :         {
     502           0 :           is_add = 0;
     503             :         }
     504           0 :       else if (unformat (line_input, "session-id %d", &session_id))
     505             :         ;
     506           0 :       else if (unformat (line_input, "client-ip %U",
     507             :                          unformat_ip4_address, &client_ip.ip4))
     508             :         {
     509           0 :           client_ip_set = 1;
     510           0 :           ipv4_set = 1;
     511             :         }
     512           0 :       else if (unformat (line_input, "client-ip %U",
     513             :                          unformat_ip6_address, &client_ip.ip6))
     514             :         {
     515           0 :           client_ip_set = 1;
     516           0 :           ipv6_set = 1;
     517             :         }
     518           0 :       else if (unformat (line_input, "decap-vrf-id %d", &tmp))
     519             :         {
     520           0 :           if (ipv6_set)
     521           0 :             decap_fib_index = fib_table_find (FIB_PROTOCOL_IP6, tmp);
     522             :           else
     523           0 :             decap_fib_index = fib_table_find (FIB_PROTOCOL_IP4, tmp);
     524             : 
     525           0 :           if (decap_fib_index == ~0)
     526             :             {
     527             :               error =
     528           0 :                 clib_error_return (0, "nonexistent decap fib id %d", tmp);
     529           0 :               goto done;
     530             :             }
     531             :         }
     532             :       else
     533           0 :         if (unformat
     534             :             (line_input, "client-mac %U", unformat_ethernet_address,
     535             :              client_mac))
     536           0 :         client_mac_set = 1;
     537             :       else
     538             :         {
     539           0 :           error = clib_error_return (0, "parse error: '%U'",
     540             :                                      format_unformat_error, line_input);
     541           0 :           goto done;
     542             :         }
     543             :     }
     544             : 
     545           0 :   if (client_ip_set == 0)
     546             :     {
     547             :       error =
     548           0 :         clib_error_return (0, "session client ip address not specified");
     549           0 :       goto done;
     550             :     }
     551             : 
     552           0 :   if (ipv4_set && ipv6_set)
     553             :     {
     554           0 :       error = clib_error_return (0, "both IPv4 and IPv6 addresses specified");
     555           0 :       goto done;
     556             :     }
     557             : 
     558           0 :   if (client_mac_set == 0)
     559             :     {
     560           0 :       error = clib_error_return (0, "session client mac not specified");
     561           0 :       goto done;
     562             :     }
     563             : 
     564           0 :   clib_memset (a, 0, sizeof (*a));
     565             : 
     566           0 :   a->is_add = is_add;
     567           0 :   a->is_ip6 = ipv6_set;
     568             : 
     569             : #define _(x) a->x = x;
     570           0 :   foreach_copy_field;
     571             : #undef _
     572             : 
     573           0 :   clib_memcpy (a->client_mac, client_mac, 6);
     574             : 
     575           0 :   rv = vnet_pppoe_add_del_session (a, &session_sw_if_index);
     576             : 
     577           0 :   switch (rv)
     578             :     {
     579           0 :     case 0:
     580           0 :       if (is_add)
     581           0 :         vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
     582             :                          vnet_get_main (), session_sw_if_index);
     583           0 :       break;
     584             : 
     585           0 :     case VNET_API_ERROR_TUNNEL_EXIST:
     586           0 :       error = clib_error_return (0, "session already exists...");
     587           0 :       goto done;
     588             : 
     589           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     590           0 :       error = clib_error_return (0, "session does not exist...");
     591           0 :       goto done;
     592             : 
     593           0 :     default:
     594           0 :       error = clib_error_return
     595             :         (0, "vnet_pppoe_add_del_session returned %d", rv);
     596           0 :       goto done;
     597             :     }
     598             : 
     599           0 : done:
     600           0 :   unformat_free (line_input);
     601             : 
     602           0 :   return error;
     603             : }
     604             : 
     605             : /*?
     606             :  * Add or delete a PPPoE Session.
     607             :  *
     608             :  * @cliexpar
     609             :  * Example of how to create a PPPoE Session:
     610             :  * @cliexcmd{create pppoe session client-ip 10.0.3.1 session-id 13
     611             :  *             client-mac 00:01:02:03:04:05 }
     612             :  * Example of how to delete a PPPoE Session:
     613             :  * @cliexcmd{create pppoe session client-ip 10.0.3.1 session-id 13
     614             :  *             client-mac 00:01:02:03:04:05 del }
     615             :  ?*/
     616             : /* *INDENT-OFF* */
     617       46069 : VLIB_CLI_COMMAND (create_pppoe_session_command, static) = {
     618             :   .path = "create pppoe session",
     619             :   .short_help =
     620             :   "create pppoe session client-ip <client-ip> session-id <nn>"
     621             :   " client-mac <client-mac> [decap-vrf-id <nn>] [del]",
     622             :   .function = pppoe_add_del_session_command_fn,
     623             : };
     624             : /* *INDENT-ON* */
     625             : 
     626             : /* *INDENT-OFF* */
     627             : static clib_error_t *
     628          10 : show_pppoe_session_command_fn (vlib_main_t * vm,
     629             :                                unformat_input_t * input,
     630             :                                vlib_cli_command_t * cmd)
     631             : {
     632          10 :   pppoe_main_t *pem = &pppoe_main;
     633             :   pppoe_session_t *t;
     634             : 
     635          10 :   if (pool_elts (pem->sessions) == 0)
     636           6 :     vlib_cli_output (vm, "No pppoe sessions configured...");
     637             : 
     638          16 :   pool_foreach (t, pem->sessions)
     639             :                  {
     640           6 :                     vlib_cli_output (vm, "%U",format_pppoe_session, t);
     641             :                 }
     642             : 
     643          10 :   return 0;
     644             : }
     645             : /* *INDENT-ON* */
     646             : 
     647             : /*?
     648             :  * Display all the PPPoE Session entries.
     649             :  *
     650             :  * @cliexpar
     651             :  * Example of how to display the PPPoE Session entries:
     652             :  * @cliexstart{show pppoe session}
     653             :  * [0] client-ip 10.0.3.1 session_id 13 encap-if-index 0 decap-vrf-id 13 sw_if_index 5
     654             :  *     local-mac a0:b0:c0:d0:e0:f0 client-mac 00:01:02:03:04:05
     655             :  * @cliexend
     656             :  ?*/
     657             : /* *INDENT-OFF* */
     658       46069 : VLIB_CLI_COMMAND (show_pppoe_session_command, static) = {
     659             :     .path = "show pppoe session",
     660             :     .short_help = "show pppoe session",
     661             :     .function = show_pppoe_session_command_fn,
     662             : };
     663             : /* *INDENT-ON* */
     664             : 
     665             : typedef struct pppoe_show_walk_ctx_t_
     666             : {
     667             :   vlib_main_t *vm;
     668             :   u8 first_entry;
     669             :   u32 total_entries;
     670             : } pppoe_show_walk_ctx_t;
     671             : 
     672             : static int
     673          17 : pppoe_show_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
     674             : {
     675          17 :   pppoe_show_walk_ctx_t *ctx = arg;
     676             :   pppoe_entry_result_t result;
     677             :   pppoe_entry_key_t key;
     678             : 
     679          17 :   if (ctx->first_entry)
     680             :     {
     681          10 :       ctx->first_entry = 0;
     682          10 :       vlib_cli_output (ctx->vm,
     683             :                        "%=19s%=12s%=13s%=14s",
     684             :                        "Mac-Address", "session_id", "sw_if_index",
     685             :                        "session_index");
     686             :     }
     687             : 
     688          17 :   key.raw = kvp->key;
     689          17 :   result.raw = kvp->value;
     690             : 
     691          17 :   vlib_cli_output (ctx->vm,
     692             :                    "%=19U%=12d%=13d%=14d",
     693             :                    format_ethernet_address, key.fields.mac,
     694          17 :                    clib_net_to_host_u16 (key.fields.session_id),
     695             :                    result.fields.sw_if_index == ~0
     696             :                    ? -1 : result.fields.sw_if_index,
     697             :                    result.fields.session_index == ~0
     698             :                    ? -1 : result.fields.session_index);
     699          17 :   ctx->total_entries++;
     700             : 
     701          17 :   return (BIHASH_WALK_CONTINUE);
     702             : }
     703             : 
     704             : /** Display the contents of the PPPoE Fib. */
     705             : static clib_error_t *
     706          10 : show_pppoe_fib_command_fn (vlib_main_t * vm,
     707             :                            unformat_input_t * input, vlib_cli_command_t * cmd)
     708             : {
     709          10 :   pppoe_main_t *pem = &pppoe_main;
     710          10 :   pppoe_show_walk_ctx_t ctx = {
     711             :     .first_entry = 1,
     712             :     .vm = vm,
     713             :   };
     714             : 
     715          10 :   BV (clib_bihash_foreach_key_value_pair)
     716             :     (&pem->session_table, pppoe_show_walk_cb, &ctx);
     717             : 
     718          10 :   if (ctx.total_entries == 0)
     719           0 :     vlib_cli_output (vm, "no pppoe fib entries");
     720             :   else
     721          10 :     vlib_cli_output (vm, "%lld pppoe fib entries", ctx.total_entries);
     722             : 
     723          10 :   return 0;
     724             : }
     725             : 
     726             : /*?
     727             :  * This command displays the MAC Address entries of the PPPoE FIB table.
     728             :  * Output can be filtered to just get the number of MAC Addresses or display
     729             :  * each MAC Address.
     730             :  *
     731             :  * @cliexpar
     732             :  * Example of how to display the number of MAC Address entries in the PPPoE
     733             :  * FIB table:
     734             :  * @cliexstart{show pppoe fib}
     735             :  *    Mac Address    session_id    Interface         sw_if_index session_index
     736             :  * 52:54:00:53:18:33   1        GigabitEthernet0/8/0      2          0
     737             :  * 52:54:00:53:18:55   2        GigabitEthernet0/8/1      3          1
     738             :  * @cliexend
     739             : ?*/
     740             : /* *INDENT-OFF* */
     741       46069 : VLIB_CLI_COMMAND (show_pppoe_fib_command, static) = {
     742             :     .path = "show pppoe fib",
     743             :     .short_help = "show pppoe fib",
     744             :     .function = show_pppoe_fib_command_fn,
     745             : };
     746             : /* *INDENT-ON* */
     747             : 
     748             : clib_error_t *
     749         559 : pppoe_init (vlib_main_t * vm)
     750             : {
     751         559 :   pppoe_main_t *pem = &pppoe_main;
     752             : 
     753         559 :   pem->vnet_main = vnet_get_main ();
     754         559 :   pem->vlib_main = vm;
     755             : 
     756             :   /* Create the hash table  */
     757         559 :   BV (clib_bihash_init) (&pem->link_table, "pppoe link table",
     758             :                          PPPOE_NUM_BUCKETS, PPPOE_MEMORY_SIZE);
     759             : 
     760         559 :   BV (clib_bihash_init) (&pem->session_table, "pppoe session table",
     761             :                          PPPOE_NUM_BUCKETS, PPPOE_MEMORY_SIZE);
     762             : 
     763         559 :   ethernet_register_input_type (vm, ETHERNET_TYPE_PPPOE_SESSION,
     764             :                                 pppoe_input_node.index);
     765             : 
     766         559 :   ethernet_register_input_type (vm, ETHERNET_TYPE_PPPOE_DISCOVERY,
     767             :                                 pppoe_cp_dispatch_node.index);
     768             : 
     769         559 :   pppoe_fib_src = fib_source_allocate ("pppoe",
     770             :                                        FIB_SOURCE_PRIORITY_HI,
     771             :                                        FIB_SOURCE_BH_API);
     772             : 
     773         559 :   return 0;
     774             : }
     775             : 
     776        1119 : VLIB_INIT_FUNCTION (pppoe_init);
     777             : 
     778             : /* *INDENT-OFF* */
     779             : VLIB_PLUGIN_REGISTER () = {
     780             :     .version = VPP_BUILD_VER,
     781             :     .description = "PPP over Ethernet (PPPoE)",
     782             : };
     783             : /* *INDENT-ON* */
     784             : 
     785             : /*
     786             :  * fd.io coding-style-patch-verification: ON
     787             :  *
     788             :  * Local Variables:
     789             :  * eval: (c-set-style "gnu")
     790             :  * End:
     791             :  */

Generated by: LCOV version 1.14