xorp

xrl_mld6igmp_node.hh

00001 // -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
00002 
00003 // Copyright (c) 2001-2011 XORP, Inc and Others
00004 //
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License, Version 2, June
00007 // 1991 as published by the Free Software Foundation. Redistribution
00008 // and/or modification of this program under the terms of any other
00009 // version of the GNU General Public License is not permitted.
00010 // 
00011 // This program is distributed in the hope that it will be useful, but
00012 // WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
00014 // see the GNU General Public License, Version 2, a copy of which can be
00015 // found in the XORP LICENSE.gpl file.
00016 // 
00017 // XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
00018 // http://xorp.net
00019 
00020 // $XORP: xorp/mld6igmp/xrl_mld6igmp_node.hh,v 1.49 2008/10/02 21:57:44 bms Exp $
00021 
00022 #ifndef __MLD6IGMP_XRL_MLD6IGMP_NODE_HH__
00023 #define __MLD6IGMP_XRL_MLD6IGMP_NODE_HH__
00024 
00025 
00026 //
00027 // MLD6IGMP XRL-aware node definition.
00028 //
00029 
00030 #include "libxipc/xrl_std_router.hh"
00031 
00032 #include "libfeaclient/ifmgr_xrl_mirror.hh"
00033 
00034 #include "xrl/interfaces/finder_event_notifier_xif.hh"
00035 #include "xrl/interfaces/fea_rawpkt4_xif.hh"
00036 #ifdef HAVE_IPV6
00037 #include "xrl/interfaces/fea_rawpkt6_xif.hh"
00038 #endif
00039 #include "xrl/interfaces/cli_manager_xif.hh"
00040 #include "xrl/interfaces/mld6igmp_client_xif.hh"
00041 #include "xrl/targets/mld6igmp_base.hh"
00042 
00043 #include "mld6igmp_node.hh"
00044 #include "mld6igmp_node_cli.hh"
00045 
00046 
00047 //
00048 // The top-level class that wraps-up everything together under one roof
00049 //
00050 class XrlMld6igmpNode : public Mld6igmpNode,
00051             public XrlStdRouter,
00052             public XrlMld6igmpTargetBase,
00053             public Mld6igmpNodeCli {
00054 public:
00055     XrlMld6igmpNode(int         family,
00056             xorp_module_id  module_id, 
00057             EventLoop&      eventloop,
00058             const string&   class_name,
00059             const string&   finder_hostname,
00060             uint16_t        finder_port,
00061             const string&   finder_target,
00062             const string&   fea_target,
00063             const string&   mfea_target);
00064     virtual ~XrlMld6igmpNode();
00065 
00071     int startup();
00072 
00078     int shutdown();
00079 
00085     XrlRouter&  xrl_router() { return *this; }
00086 
00092     const XrlRouter& xrl_router() const { return *this; }
00093 
00094     //
00095     // XrlMld6igmpNode front-end interface
00096     //
00097     int enable_cli();
00098     int disable_cli();
00099     int start_cli();
00100     int stop_cli();
00101     int enable_mld6igmp();
00102     int disable_mld6igmp();
00103     int start_mld6igmp();
00104     int stop_mld6igmp();
00105 
00106     // XrlTask relatedMethods that need to be public
00107     void send_register_unregister_interest();
00108     void send_register_unregister_receiver();
00109     void send_join_leave_multicast_group();
00110     void send_protocol_message();
00111 
00112 protected:
00113     //
00114     // XRL target methods
00115     //
00119     XrlCmdError common_0_1_get_target_name(
00120     // Output values, 
00121     string& name);
00122 
00126     XrlCmdError common_0_1_get_version(
00127     // Output values, 
00128     string& version);
00129 
00133     XrlCmdError common_0_1_get_status(// Output values,
00134                       uint32_t& status,
00135                       string&   reason);
00136 
00140     XrlCmdError common_0_1_shutdown();
00141 
00142     XrlCmdError common_0_1_startup();
00143 
00151     XrlCmdError finder_event_observer_0_1_xrl_target_birth(
00152     // Input values,
00153     const string&   target_class,
00154     const string&   target_instance);
00155 
00163     XrlCmdError finder_event_observer_0_1_xrl_target_death(
00164     // Input values,
00165     const string&   target_class,
00166     const string&   target_instance);
00167 
00189     XrlCmdError cli_processor_0_1_process_command(
00190     // Input values, 
00191     const string&   processor_name, 
00192     const string&   cli_term_name, 
00193     const uint32_t& cli_session_id,
00194     const string&   command_name, 
00195     const string&   command_args, 
00196     // Output values, 
00197     string& ret_processor_name, 
00198     string& ret_cli_term_name, 
00199     uint32_t& ret_cli_session_id,
00200     string& ret_command_output);
00201 
00226     XrlCmdError raw_packet4_client_0_1_recv(
00227     // Input values,
00228     const string&   if_name,
00229     const string&   vif_name,
00230     const IPv4& src_address,
00231     const IPv4& dst_address,
00232     const uint32_t& ip_protocol,
00233     const int32_t&  ip_ttl,
00234     const int32_t&  ip_tos,
00235     const bool& ip_router_alert,
00236     const bool& ip_internet_control,
00237     const vector<uint8_t>&  payload);
00238 
00270     XrlCmdError raw_packet6_client_0_1_recv(
00271     // Input values,
00272     const string&   if_name,
00273     const string&   vif_name,
00274     const IPv6& src_address,
00275     const IPv6& dst_address,
00276     const uint32_t& ip_protocol,
00277     const int32_t&  ip_ttl,
00278     const int32_t&  ip_tos,
00279     const bool& ip_router_alert,
00280     const bool& ip_internet_control,
00281     const XrlAtomList&  ext_headers_type,
00282     const XrlAtomList&  ext_headers_payload,
00283     const vector<uint8_t>&  payload);
00284     
00292     XrlCmdError mld6igmp_0_1_enable_vif(
00293     // Input values,
00294     const string&   vif_name,
00295     const bool& enable);
00296 
00297     XrlCmdError mld6igmp_0_1_start_vif(
00298     // Input values, 
00299     const string&   vif_name);
00300 
00301     XrlCmdError mld6igmp_0_1_stop_vif(
00302     // Input values, 
00303     const string&   vif_name);
00304 
00310     XrlCmdError mld6igmp_0_1_enable_all_vifs(
00311     // Input values,
00312     const bool& enable);
00313 
00314     XrlCmdError mld6igmp_0_1_start_all_vifs();
00315 
00316     XrlCmdError mld6igmp_0_1_stop_all_vifs();
00317 
00324     XrlCmdError mld6igmp_0_1_enable_mld6igmp(
00325     // Input values,
00326     const bool& enable);
00327 
00328     XrlCmdError mld6igmp_0_1_start_mld6igmp();
00329 
00330     XrlCmdError mld6igmp_0_1_stop_mld6igmp();
00331 
00338     XrlCmdError mld6igmp_0_1_enable_cli(
00339     // Input values,
00340     const bool& enable);
00341 
00342     XrlCmdError mld6igmp_0_1_start_cli();
00343 
00344     XrlCmdError mld6igmp_0_1_stop_cli();
00345 
00353     XrlCmdError mld6igmp_0_1_get_vif_proto_version(
00354     // Input values, 
00355     const string&   vif_name, 
00356     // Output values, 
00357     uint32_t&   proto_version);
00358 
00366     XrlCmdError mld6igmp_0_1_set_vif_proto_version(
00367     // Input values, 
00368     const string&   vif_name, 
00369     const uint32_t& proto_version);
00370 
00376     XrlCmdError mld6igmp_0_1_reset_vif_proto_version(
00377     // Input values, 
00378     const string&   vif_name);
00379 
00389     XrlCmdError mld6igmp_0_1_get_vif_ip_router_alert_option_check(
00390     // Input values,
00391     const string&   vif_name,
00392     // Output values,
00393     bool&   enabled);
00394 
00404     XrlCmdError mld6igmp_0_1_set_vif_ip_router_alert_option_check(
00405     // Input values,
00406     const string&   vif_name,
00407     const bool& enable);
00408 
00415     XrlCmdError mld6igmp_0_1_reset_vif_ip_router_alert_option_check(
00416     // Input values,
00417     const string&   vif_name);
00418 
00429     XrlCmdError mld6igmp_0_1_get_vif_query_interval(
00430     // Input values,
00431     const string&   vif_name,
00432     // Output values,
00433     uint32_t&   interval_sec,
00434     uint32_t&   interval_usec);
00435 
00446     XrlCmdError mld6igmp_0_1_set_vif_query_interval(
00447     // Input values,
00448     const string&   vif_name,
00449     const uint32_t& interval_sec,
00450     const uint32_t& interval_usec);
00451 
00457     XrlCmdError mld6igmp_0_1_reset_vif_query_interval(
00458     // Input values,
00459     const string&   vif_name);
00460 
00471     XrlCmdError mld6igmp_0_1_get_vif_query_last_member_interval(
00472     // Input values,
00473     const string&   vif_name,
00474     // Output values,
00475     uint32_t&   interval_sec,
00476     uint32_t&   interval_usec);
00477 
00488     XrlCmdError mld6igmp_0_1_set_vif_query_last_member_interval(
00489     // Input values,
00490     const string&   vif_name,
00491     const uint32_t& interval_sec,
00492     const uint32_t& interval_usec);
00493 
00500     XrlCmdError mld6igmp_0_1_reset_vif_query_last_member_interval(
00501     // Input values,
00502     const string&   vif_name);
00503 
00514     XrlCmdError mld6igmp_0_1_get_vif_query_response_interval(
00515     // Input values,
00516     const string&   vif_name,
00517     // Output values,
00518     uint32_t&   interval_sec,
00519     uint32_t&   interval_usec);
00520 
00531     XrlCmdError mld6igmp_0_1_set_vif_query_response_interval(
00532     // Input values,
00533     const string&   vif_name,
00534     const uint32_t& interval_sec,
00535     const uint32_t& interval_usec);
00536 
00542     XrlCmdError mld6igmp_0_1_reset_vif_query_response_interval(
00543     // Input values,
00544     const string&   vif_name);
00545 
00553     XrlCmdError mld6igmp_0_1_get_vif_robust_count(
00554     // Input values,
00555     const string&   vif_name,
00556     // Output values,
00557     uint32_t&   robust_count);
00558 
00566     XrlCmdError mld6igmp_0_1_set_vif_robust_count(
00567     // Input values,
00568     const string&   vif_name,
00569     const uint32_t& robust_count);
00570 
00576     XrlCmdError mld6igmp_0_1_reset_vif_robust_count(
00577     // Input values,
00578     const string&   vif_name);
00579 
00585     XrlCmdError mld6igmp_0_1_log_trace_all(
00586     // Input values,
00587     const bool& enable);
00588 
00606     XrlCmdError mld6igmp_0_1_add_protocol4(
00607     // Input values, 
00608     const string&   xrl_sender_name, 
00609     const string&   protocol_name, 
00610     const uint32_t& protocol_id, 
00611     const string&   vif_name, 
00612     const uint32_t& vif_index);
00613 
00614     XrlCmdError mld6igmp_0_1_add_protocol6(
00615     // Input values, 
00616     const string&   xrl_sender_name, 
00617     const string&   protocol_name, 
00618     const uint32_t& protocol_id, 
00619     const string&   vif_name, 
00620     const uint32_t& vif_index);
00621 
00622     XrlCmdError mld6igmp_0_1_delete_protocol4(
00623     // Input values, 
00624     const string&   xrl_sender_name, 
00625     const string&   protocol_name, 
00626     const uint32_t& protocol_id, 
00627     const string&   vif_name, 
00628     const uint32_t& vif_index);
00629 
00630     XrlCmdError mld6igmp_0_1_delete_protocol6(
00631     // Input values, 
00632     const string&   xrl_sender_name, 
00633     const string&   protocol_name, 
00634     const uint32_t& protocol_id, 
00635     const string&   vif_name, 
00636     const uint32_t& vif_index);
00637     
00638 private:
00639     class XrlTaskBase;
00640 
00641     const ServiceBase* ifmgr_mirror_service_base() const {
00642     return dynamic_cast<const ServiceBase*>(&_ifmgr);
00643     }
00644     const IfMgrIfTree& ifmgr_iftree() const { return _ifmgr.iftree(); }
00645 
00651     virtual void finder_connect_event();
00652 
00658     virtual void finder_disconnect_event();
00659 
00660     //
00661     // Methods to handle the XRL tasks
00662     //
00663     void add_task(XrlTaskBase* xrl_task);
00664     void send_xrl_task();
00665     void pop_xrl_task();
00666     void retry_xrl_task();
00667 
00668     void fea_register_startup();
00669     void mfea_register_startup();
00670     void fea_register_shutdown();
00671     void mfea_register_shutdown();
00672     void finder_send_register_unregister_interest_cb(const XrlError& xrl_error);
00673 
00674     //
00675     // Protocol node methods
00676     //
00677     int register_receiver(const string& if_name, const string& vif_name,
00678               uint8_t ip_protocol,
00679               bool enable_multicast_loopback);
00680     int unregister_receiver(const string& if_name, const string& vif_name,
00681                 uint8_t ip_protocol);
00682     void fea_client_send_register_unregister_receiver_cb(const XrlError& xrl_error);
00683 
00684     int join_multicast_group(const string& if_name, const string& vif_name,
00685                  uint8_t ip_protocol, const IPvX& group_address);
00686     int leave_multicast_group(const string& if_name, const string& vif_name,
00687                   uint8_t ip_protocol, const IPvX& group_address);
00688     void fea_client_send_join_leave_multicast_group_cb(const XrlError& xrl_error);
00689 
00690     int proto_send(const string& if_name,
00691            const string& vif_name,
00692            const IPvX& src_address,
00693            const IPvX& dst_address,
00694            uint8_t ip_protocol,
00695            int32_t ip_ttl,
00696            int32_t ip_tos,
00697            bool ip_router_alert,
00698            bool ip_internet_control,
00699            const uint8_t* sndbuf,
00700            size_t sndlen,
00701            string& error_msg);
00702     void fea_client_send_protocol_message_cb(const XrlError& xrl_error);
00703     
00704     int send_add_membership(const string& dst_module_instance_name,
00705                 xorp_module_id dst_module_id,
00706                 uint32_t vif_index,
00707                 const IPvX& source,
00708                 const IPvX& group);
00709     int send_delete_membership(const string& dst_module_instance_name,
00710                    xorp_module_id dst_module_id,
00711                    uint32_t vif_index,
00712                    const IPvX& source,
00713                    const IPvX& group);
00714     void send_add_delete_membership();
00715     void mld6igmp_client_send_add_delete_membership_cb(const XrlError& xrl_error);
00716     
00717     //
00718     // Protocol node CLI methods
00719     //
00720     int add_cli_command_to_cli_manager(const char *command_name,
00721                        const char *command_help,
00722                        bool is_command_cd,
00723                        const char *command_cd_prompt,
00724                        bool is_command_processor);
00725     void cli_manager_client_send_add_cli_command_cb(const XrlError& xrl_error);
00726     int delete_cli_command_from_cli_manager(const char *command_name);
00727     void cli_manager_client_send_delete_cli_command_cb(const XrlError& xrl_error);
00728 
00729     int family() const { return (Mld6igmpNode::family()); }
00730 
00731 
00735     class XrlTaskBase {
00736     public:
00737     XrlTaskBase(XrlMld6igmpNode& xrl_mld6igmp_node)
00738         : _xrl_mld6igmp_node(xrl_mld6igmp_node) {}
00739     virtual ~XrlTaskBase() {}
00740 
00741     virtual void dispatch() = 0;
00742     virtual const char* operation_name() const = 0;
00743 
00744     protected:
00745     XrlMld6igmpNode&    _xrl_mld6igmp_node;
00746     private:
00747     };
00748 
00753     class RegisterUnregisterInterest : public XrlTaskBase {
00754     public:
00755     RegisterUnregisterInterest(XrlMld6igmpNode& xrl_mld6igmp_node,
00756                    const string&    target_name,
00757                    bool         is_register)
00758         : XrlTaskBase(xrl_mld6igmp_node),
00759           _target_name(target_name),
00760           _is_register(is_register) {}
00761 
00762     void        dispatch() {
00763         _xrl_mld6igmp_node.send_register_unregister_interest();
00764     }
00765     const char* operation_name() const {
00766         return ((_is_register)? "register" : "unregister");
00767     }
00768     const string&   target_name() const { return _target_name; }
00769     bool        is_register() const { return _is_register; }
00770 
00771     private:
00772     string      _target_name;
00773     bool        _is_register;
00774     };
00775 
00780     class RegisterUnregisterReceiver : public XrlTaskBase {
00781     public:
00782     RegisterUnregisterReceiver(XrlMld6igmpNode& xrl_mld6igmp_node,
00783                    const string&    if_name,
00784                    const string&    vif_name,
00785                    uint8_t      ip_protocol,
00786                    bool         enable_multicast_loopback,
00787                    bool         is_register)
00788         : XrlTaskBase(xrl_mld6igmp_node),
00789           _if_name(if_name),
00790           _vif_name(vif_name),
00791           _ip_protocol(ip_protocol),
00792           _enable_multicast_loopback(enable_multicast_loopback),
00793           _is_register(is_register) {}
00794 
00795     void        dispatch() {
00796         _xrl_mld6igmp_node.send_register_unregister_receiver();
00797     }
00798     const char* operation_name() const {
00799         return ((_is_register)? "register" : "unregister");
00800     }
00801     const string&   if_name() const { return _if_name; }
00802     const string&   vif_name() const { return _vif_name; }
00803     uint8_t     ip_protocol() const { return _ip_protocol; }
00804     bool        enable_multicast_loopback() const {
00805         return _enable_multicast_loopback;
00806     }
00807     bool        is_register() const { return _is_register; }
00808 
00809     private:
00810     string      _if_name;
00811     string      _vif_name;
00812     uint8_t     _ip_protocol;
00813     bool        _enable_multicast_loopback;
00814     bool        _is_register;
00815     };
00816 
00820     class JoinLeaveMulticastGroup : public XrlTaskBase {
00821     public:
00822     JoinLeaveMulticastGroup(XrlMld6igmpNode&    xrl_mld6igmp_node,
00823                 const string&       if_name,
00824                 const string&       vif_name,
00825                 uint8_t         ip_protocol,
00826                 const IPvX&     group_address,
00827                 bool            is_join)
00828         : XrlTaskBase(xrl_mld6igmp_node),
00829           _if_name(if_name),
00830           _vif_name(vif_name),
00831           _ip_protocol(ip_protocol),
00832           _group_address(group_address),
00833           _is_join(is_join) {}
00834 
00835     void        dispatch() {
00836         _xrl_mld6igmp_node.send_join_leave_multicast_group();
00837     }
00838     const char* operation_name() const {
00839         return ((_is_join)? "join" : "leave");
00840     }
00841     const string&   if_name() const { return _if_name; }
00842     const string&   vif_name() const { return _vif_name; }
00843     uint8_t     ip_protocol() const { return _ip_protocol; }
00844     const IPvX& group_address() const { return _group_address; }
00845     bool        is_join() const { return _is_join; }
00846 
00847     private:
00848     string      _if_name;
00849     string      _vif_name;
00850     uint8_t     _ip_protocol;
00851     IPvX        _group_address;
00852     bool        _is_join;
00853     };
00854 
00858     class SendProtocolMessage : public XrlTaskBase {
00859     public:
00860     SendProtocolMessage(XrlMld6igmpNode&    xrl_mld6igmp_node,
00861                 const string&   if_name,
00862                 const string&   vif_name,
00863                 const IPvX&     src_address,
00864                 const IPvX&     dst_address,
00865                 uint8_t     ip_protocol,
00866                 int32_t     ip_ttl,
00867                 int32_t     ip_tos,
00868                 bool        ip_router_alert,
00869                 bool        ip_internet_control,
00870                 const uint8_t*  sndbuf,
00871                 size_t      sndlen)
00872         : XrlTaskBase(xrl_mld6igmp_node),
00873           _if_name(if_name),
00874           _vif_name(vif_name),
00875           _src_address(src_address),
00876           _dst_address(dst_address),
00877           _ip_protocol(ip_protocol),
00878           _ip_ttl(ip_ttl),
00879           _ip_tos(ip_tos),
00880           _ip_router_alert(ip_router_alert),
00881           _ip_internet_control(ip_internet_control) {
00882         _payload.resize(sndlen);
00883         for (size_t i = 0; i < sndlen; i++)
00884         _payload[i] = sndbuf[i];
00885     }
00886 
00887     void        dispatch() {
00888         _xrl_mld6igmp_node.send_protocol_message();
00889     }
00890     const char* operation_name() const {
00891         return ("send");
00892     }
00893     const string&   if_name() const { return _if_name; }
00894     const string&   vif_name() const { return _vif_name; }
00895     const IPvX& src_address() const { return _src_address; }
00896     const IPvX& dst_address() const { return _dst_address; }
00897     uint8_t     ip_protocol() const { return _ip_protocol; }
00898     int32_t     ip_ttl() const { return _ip_ttl; }
00899     int32_t     ip_tos() const { return _ip_tos; }
00900     bool        ip_router_alert() const { return _ip_router_alert; }
00901     bool        ip_internet_control() const { return _ip_internet_control; }
00902     const vector<uint8_t>& payload() const { return _payload; }
00903 
00904     private:
00905     string      _if_name;
00906     string      _vif_name;
00907     IPvX        _src_address;
00908     IPvX        _dst_address;
00909     uint8_t     _ip_protocol;
00910     int32_t     _ip_ttl;
00911     int32_t     _ip_tos;
00912     bool        _ip_router_alert;
00913     bool        _ip_internet_control;
00914     vector<uint8_t> _payload;
00915     };
00916 
00920     class SendAddDeleteMembership {
00921     public:
00922     SendAddDeleteMembership(const string& dst_module_instance_name,
00923                 xorp_module_id dst_module_id,
00924                 uint32_t vif_index,
00925                 const IPvX& source,
00926                 const IPvX& group,
00927                 bool is_add)
00928         : _dst_module_instance_name(dst_module_instance_name),
00929           _dst_module_id(dst_module_id),
00930           _vif_index(vif_index),
00931           _source(source),
00932           _group(group),
00933           _is_add(is_add) {}
00934 #ifdef XORP_USE_USTL
00935     SendAddDeleteMembership() { }
00936 #endif
00937 
00938     const char* operation_name() const {
00939         return ((_is_add)? "add membership" : "delete membership");
00940     }
00941     const string& dst_module_instance_name() const { return _dst_module_instance_name; }
00942     xorp_module_id dst_module_id() const { return _dst_module_id; }
00943     uint32_t vif_index() const { return _vif_index; }
00944     const IPvX& source() const { return _source; }
00945     const IPvX& group() const { return _group; }
00946     bool is_add() const { return _is_add; }
00947 
00948     private:
00949     string      _dst_module_instance_name;
00950     xorp_module_id  _dst_module_id;
00951     uint32_t    _vif_index;
00952     IPvX        _source;
00953     IPvX        _group;
00954     bool        _is_add;
00955     };
00956 
00957     EventLoop&          _eventloop;
00958     const string        _finder_target;
00959     const string        _fea_target;
00960     const string        _mfea_target;
00961 
00962     IfMgrXrlMirror      _ifmgr;
00963 
00964     XrlRawPacket4V0p1Client _xrl_fea_client4;
00965 #ifdef HAVE_IPV6
00966     XrlRawPacket6V0p1Client _xrl_fea_client6;
00967 #endif
00968     XrlMld6igmpClientV0p1Client _xrl_mld6igmp_client_client;
00969     XrlCliManagerV0p1Client _xrl_cli_manager_client;
00970     XrlFinderEventNotifierV0p1Client    _xrl_finder_client;
00971 
00972     static const TimeVal    RETRY_TIMEVAL;
00973 
00974     bool            _is_finder_alive;
00975 
00976     bool            _is_fea_alive;
00977     bool            _is_fea_registered;
00978 
00979     bool            _is_mfea_alive;
00980     bool            _is_mfea_registered;
00981 
00982     list<XrlTaskBase* >     _xrl_tasks_queue;
00983     XorpTimer           _xrl_tasks_queue_timer;
00984     list<SendAddDeleteMembership> _send_add_delete_membership_queue;
00985     XorpTimer           _send_add_delete_membership_queue_timer;
00986 };
00987 
00988 #endif // __MLD6IGMP_XRL_MLD6IGMP_NODE_HH__
 All Classes Namespaces Functions Variables Typedefs Enumerations