From: John Fastabend <john.r.fastabend@intel.com>
To: Jens Osterkamp <jens@linux.vnet.ibm.com>
Cc: "chrisw@redhat.com" <chrisw@redhat.com>,
"evb@yahoogroups.com" <evb@yahoogroups.com>,
"e1000-eedc@lists.sourceforge.net"
<e1000-eedc@lists.sourceforge.net>,
"virtualization@lists.linux-foundation.org"
<virtualization@lists.linux-foundation.org>
Subject: Re: [E1000-eedc] [PATCH 02/10] implementation of IEEE 802.1Qbg in lldpad, part 1
Date: Thu, 23 Sep 2010 12:34:51 -0700 [thread overview]
Message-ID: <4C9BABDB.3040404@intel.com> (raw)
In-Reply-To: <4C9AA43B.9000702@intel.com>
On 9/22/2010 5:50 PM, John Fastabend wrote:
> On 8/25/2010 5:27 AM, Jens Osterkamp wrote:
>> This patch contains the first part of an initial implementation of the
>> IEEE 802.1Qbg standard: it implements code for the exchange of EVB
>> capabilities between a host with virtual machines and an adjacent switch.
>> For this it adds a new EVB TLV to LLDP.
>>
>> Exchange of EVB TLV may be enabled or disabled on a per port basis.
>> Information about the information negotiated by the protocol can be
>> queried on the commandline with lldptool.
>>
>> This patch adds support for querying and setting parameters used in
>> the exchange of EVB TLV messages.
>> The parameters that can be set are:
>>
>> - forwarding mode
>> - host protocol capabilities (RTE, ECP, VDP)
>> - no. of supported VSIs
>> - retransmission timer exponent (RTE)
>>
>> The parameters are implemented as a local policy: all frames received by
>> an adjacent switch are validated against this policy and taken over where
>> appropriate. Negotiated parameters are stored in lldpads config, picked up
>> again and used at the next start.
>>
>> The patch applies to lldpad 0.9.38 and still contains code to log protocol
>> activity more verbosely than it would be necessary in the final version.
>>
>> Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
>> ---
>> Makefile.am | 10 +-
>> include/lldp.h | 19 ++
>> include/lldp_evb.h | 80 ++++++
>> include/lldp_evb_clif.h | 51 ++++
>> include/lldp_evb_cmds.h | 31 +++
>> include/lldp_tlv.h | 1 +
>> lldp_evb.c | 658 +++++++++++++++++++++++++++++++++++++++++++++++
>> lldp_evb_clif.c | 226 ++++++++++++++++
>> lldp_evb_cmds.c | 512 ++++++++++++++++++++++++++++++++++++
>> lldpad.c | 2 +
>> lldptool.c | 2 +
>> 11 files changed, 1588 insertions(+), 4 deletions(-)
>> create mode 100644 include/lldp_evb.h
>> create mode 100644 include/lldp_evb_clif.h
>> create mode 100644 include/lldp_evb_cmds.h
>> create mode 100644 lldp_evb.c
>> create mode 100644 lldp_evb_clif.c
>> create mode 100644 lldp_evb_cmds.c
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index 743e16f..d59a6fa 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -37,7 +37,7 @@ lldpad_include_HEADERS = include/dcb_types.h include/dcbtool.h \
>> include/dcb_osdep.h include/clif.h include/lldp_dcbx_cmds.h include/common.h \
>> include/lldpad.h include/os.h include/includes.h include/lldp_mand_cmds.h \
>> include/clif_msgs.h include/lldp_basman_cmds.h include/lldp_8023_cmds.h \
>> -include/lldp_med_cmds.h include/lldp_dcbx_cfg.h
>> +include/lldp_med_cmds.h include/lldp_dcbx_cfg.h include/lldp_evb_cmds.h
>>
>> noinst_HEADERS = include/config.h include/ctrl_iface.h \
>> include/dcb_driver_if_types.h include/dcb_driver_interface.h \
>> @@ -47,7 +47,7 @@ include/event_iface.h include/messages.h include/parse_cli.h include/version.h \
>> include/lldptool_cli.h include/list.h \
>> include/lldp_mand_clif.h include/lldp_basman_clif.h include/lldp_med_clif.h \
>> include/lldp_8023_clif.h include/lldp_dcbx_clif.h include/lldptool.h \
>> -include/lldp_rtnl.h
>> +include/lldp_rtnl.h include/lldp_evb_clif.h
>>
>> lldpad_SOURCES = lldpad.c config.c drv_cfg.c ctrl_iface.c event_iface.c eloop.c \
>> common.c os_unix.c lldp_dcbx_cmds.c log.c lldpad_shm.c \
>> @@ -62,10 +62,12 @@ lldp_dcbx_cfg.c include/lldp_dcbx_cfg.h \
>> lldp_util.c include/lldp_util.h \
>> lldp_mand.c include/lldp_mand.h \
>> lldp_mand_cmds.c lldp_basman_cmds.c lldp_8023_cmds.c lldp_med_cmds.c \
>> +lldp_evb_cmds.c \
>> lldp_tlv.c include/lldp_tlv.h \
>> lldp_basman.c include/lldp_basman.h \
>> lldp_med.c include/lldp_med.h \
>> -lldp_8023.c include/lldp_8023.h
>> +lldp_8023.c include/lldp_8023.h \
>> +lldp_evb.c include/lldp_evb.h
>>
>>
>>
>> @@ -74,7 +76,7 @@ $(lldpad_include_HEADERS) $(noinst_HEADERS)
>>
>> lldptool_SOURCES = lldptool.c clif.c lldptool_cmds.c common.c os_unix.c \
>> lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c lldp_8023_clif.c \
>> -lldp_dcbx_clif.c $(lldpad_include_HEADERS) $(noinst_HEADERS)
>> +lldp_dcbx_clif.c lldp_evb_clif.c $(lldpad_include_HEADERS) $(noinst_HEADERS)
>>
>> nltest_SOURCES = nltest.c nltest.h
>>
>> diff --git a/include/lldp.h b/include/lldp.h
>> index 66532bd..e00ba7a 100644
>> --- a/include/lldp.h
>> +++ b/include/lldp.h
>> @@ -45,6 +45,8 @@
>> /* Telecommunications Industry Association TR-41 Committee */
>> #define OUI_TIA_TR41 0x0012bb
>>
>> +#define OUI_IEEE_8021Qbg 0x001b3f
>> +
>> /* IEEE 802.3AB Clause 9: TLV Types */
>> #define CHASSIS_ID_TLV 1
>> #define PORT_ID_TLV 2
>> @@ -186,5 +188,22 @@ enum {
>> #define LLDP_8023_LINKAGG_CAPABLE (1 << 0)
>> #define LLDP_8023_LINKAGG_ENABLED (1 << 1)
>>
>> +/* IEEE 802.1Qbg subtype */
>> +#define LLDP_EVB_SUBTYPE 0
>> +
>> +/* forwarding mode */
>> +#define LLDP_EVB_CAPABILITY_FORWARD_STANDARD (1 << 7)
>> +#define LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY (1 << 6)
>> +
>> +/* EVB supported protocols */
>> +#define LLDP_EVB_CAPABILITY_PROTOCOL_RTE (1 << 2)
>> +#define LLDP_EVB_CAPABILITY_PROTOCOL_ECP (1 << 1)
>> +#define LLDP_EVB_CAPABILITY_PROTOCOL_VDP (1 << 0)
>> +
>> +/* EVB specific values */
>> +#define LLDP_EVB_DEFAULT_MAX_VSI 4096
>> +#define LLDP_EVB_DEFAULT_SVSI 3295
>> +#define LLDP_EVB_DEFAULT_RTE 15
>> +
>> void somethingChangedLocal(char *ifname);
>> #endif /* _LLDP_H */
>> diff --git a/include/lldp_evb.h b/include/lldp_evb.h
>> new file mode 100644
>> index 0000000..667f9ad
>> --- /dev/null
>> +++ b/include/lldp_evb.h
>> @@ -0,0 +1,80 @@
>> +/*******************************************************************************
>> +
>> + implementation of EVB TLVs for LLDP
>> + (c) Copyright IBM Corp. 2010
>> +
>> + Author(s): Jens Osterkamp <jens@linux.vnet.ibm.com>
>> +
>> + This program is free software; you can redistribute it and/or modify it
>> + under the terms and conditions of the GNU General Public License,
>> + version 2, as published by the Free Software Foundation.
>> +
>> + This program is distributed in the hope it will be useful, but WITHOUT
>> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + more details.
>> +
>> + You should have received a copy of the GNU General Public License along with
>> + this program; if not, write to the Free Software Foundation, Inc.,
>> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>> +
>> + The full GNU General Public License is included in this distribution in
>> + the file called "COPYING".
>> +
>> +*******************************************************************************/
>> +
>> +#ifndef _LLDP_EVB_H
>> +#define _LLDP_EVB_H
>> +
>> +#include "lldp_mod.h"
>> +
>> +#define LLDP_MOD_EVB OUI_IEEE_8021Qbg
>> +#define LLDP_OUI_SUBTYPE { 0x00, 0x1b, 0x3f, 0x00 }
>> +
>> +typedef enum {
>> + EVB_OFFER_CAPABILITIES = 0,
>> + EVB_CONFIGURE,
>> + EVB_CONFIRMATION
>> +} evb_state;
>> +
>> +struct tlv_info_evb {
>> + u8 oui[3];
>> + u8 sub;
>> + /* supported forwarding mode */
>> + u8 smode;
>> + /* supported capabilities */
>> + u8 scap;
>> + /* currently configured forwarding mode */
>> + u8 cmode;
>> + /* currently configured capabilities */
>> + u8 ccap;
>> + /* supported no. of vsi */
>> + u16 svsi;
>> + /* currently configured no. of vsi */
>> + u16 cvsi;
>> + /* retransmission exponent */
>> + u8 rte;
>> +} __attribute__ ((__packed__));
>> +
>> +struct evb_data {
>> + char ifname[IFNAMSIZ];
>> + struct unpacked_tlv *evb;
>> + struct tlv_info_evb *tie;
>> + /* local policy */
>> + struct tlv_info_evb *policy;
>> + int state;
>> + LIST_ENTRY(evb_data) entry;
>> +};
>> +
>> +struct evb_user_data {
>> + LIST_HEAD(evb_head, evb_data) head;
>> +};
>> +
>> +struct lldp_module *evb_register(void);
>> +void evb_unregister(struct lldp_module *mod);
>> +struct packed_tlv *evb_gettlv(struct port *port);
>> +void evb_ifdown(char *);
>> +void evb_ifup(char *);
>> +struct evb_data *evb_data(char *ifname);
>> +
>> +#endif /* _LLDP_EVB_H */
>> diff --git a/include/lldp_evb_clif.h b/include/lldp_evb_clif.h
>> new file mode 100644
>> index 0000000..acaee5e
>> --- /dev/null
>> +++ b/include/lldp_evb_clif.h
>> @@ -0,0 +1,51 @@
>> +/*******************************************************************************
>> +
>> + implementation of EVB TLVs for LLDP
>> + (c) Copyright IBM Corp. 2010
>> +
>> + Author(s): Jens Osterkamp <jens@linux.vnet.ibm.com>
>> +
>> + This program is free software; you can redistribute it and/or modify it
>> + under the terms and conditions of the GNU General Public License,
>> + version 2, as published by the Free Software Foundation.
>> +
>> + This program is distributed in the hope it will be useful, but WITHOUT
>> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + more details.
>> +
>> + You should have received a copy of the GNU General Public License along with
>> + this program; if not, write to the Free Software Foundation, Inc.,
>> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>> +
>> + The full GNU General Public License is included in this distribution in
>> + the file called "COPYING".
>> +
>> +*******************************************************************************/
>> +
>> +#ifndef _LLDP_EVB_CLIF_H
>> +#define _LLDP_EVB_CLIF_H
>> +
>> +struct lldp_module *evb_cli_register(void);
>> +void evb_cli_unregister(struct lldp_module *);
>> +int evb_print_tlv(u32, u16, char *);
>> +
>> +#define EVB_BUF_SIZE 256
>> +
>> +#define ARG_EVB_FORWARDING_MODE "fmode"
>> +
>> +#define VAL_EVB_FMODE_BRIDGE "bridge"
>> +#define VAL_EVB_FMODE_REFLECTIVE_RELAY "reflectiverelay"
>> +
>> +#define ARG_EVB_CAPABILITIES "capabilities"
>> +
>> +#define VAL_EVB_CAPA_RTE "rte"
>> +#define VAL_EVB_CAPA_ECP "ecp"
>> +#define VAL_EVB_CAPA_VDP "vdp"
>> +#define VAL_EVB_CAPA_NONE "none"
>> +
>> +#define ARG_EVB_VSIS "vsis"
>> +
>> +#define ARG_EVB_RTE "rte"
>> +
>> +#endif
>> diff --git a/include/lldp_evb_cmds.h b/include/lldp_evb_cmds.h
>> new file mode 100644
>> index 0000000..1367e5d
>> --- /dev/null
>> +++ b/include/lldp_evb_cmds.h
>> @@ -0,0 +1,31 @@
>> +/*******************************************************************************
>> +
>> + implementation of EVB TLVs for LLDP
>> + (c) Copyright IBM Corp. 2010
>> +
>> + Author(s): Jens Osterkamp <jens@linux.vnet.ibm.com>
>> +
>> + This program is free software; you can redistribute it and/or modify it
>> + under the terms and conditions of the GNU General Public License,
>> + version 2, as published by the Free Software Foundation.
>> +
>> + This program is distributed in the hope it will be useful, but WITHOUT
>> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + more details.
>> +
>> + You should have received a copy of the GNU General Public License along with
>> + this program; if not, write to the Free Software Foundation, Inc.,
>> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>> +
>> + The full GNU General Public License is included in this distribution in
>> + the file called "COPYING".
>> +
>> +*******************************************************************************/
>> +
>> +#ifndef _LLDP_EVB_CMDS_H
>> +#define _LLDP_EVB_CMDS_H
>> +
>> +struct arg_handlers *evb_get_arg_handlers();
>> +
>> +#endif
>> diff --git a/include/lldp_tlv.h b/include/lldp_tlv.h
>> index a32cc71..fe3a75a 100644
>> --- a/include/lldp_tlv.h
>> +++ b/include/lldp_tlv.h
>> @@ -144,6 +144,7 @@ int tlv_ok(struct unpacked_tlv *tlv);
>> #define TLVID_8021(sub) TLVID(OUI_IEEE_8021, (sub))
>> #define TLVID_8023(sub) TLVID(OUI_IEEE_8023, (sub))
>> #define TLVID_MED(sub) TLVID(OUI_TIA_TR41, (sub))
>> +#define TLVID_8021Qbg(sub) TLVID(OUI_IEEE_8021Qbg, (sub))
>>
>> /* the size in bytes needed for a packed tlv from unpacked tlv */
>> #define TLVSIZE(t) ((t) ? (2 + (t)->length) : 0)
>> diff --git a/lldp_evb.c b/lldp_evb.c
>> new file mode 100644
>> index 0000000..4213137
>> --- /dev/null
>> +++ b/lldp_evb.c
>> @@ -0,0 +1,658 @@
>> +/*******************************************************************************
>> +
>> + implementation of EVB TLVs for LLDP
>> + (c) Copyright IBM Corp. 2010
>> +
>> + Author(s): Jens Osterkamp <jens@linux.vnet.ibm.com>
>> +
>> + This program is free software; you can redistribute it and/or modify it
>> + under the terms and conditions of the GNU General Public License,
>> + version 2, as published by the Free Software Foundation.
>> +
>> + This program is distributed in the hope it will be useful, but WITHOUT
>> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + more details.
>> +
>> + You should have received a copy of the GNU General Public License along with
>> + this program; if not, write to the Free Software Foundation, Inc.,
>> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>> +
>> + The full GNU General Public License is included in this distribution in
>> + the file called "COPYING".
>> +
>> +*******************************************************************************/
>> +
>> +#include <net/if.h>
>> +#include <sys/queue.h>
>> +#include <sys/socket.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/utsname.h>
>> +#include <linux/if_bridge.h>
>> +#include <string.h>
>> +#include "lldp.h"
>> +#include "lldp_evb.h"
>> +#include "messages.h"
>> +#include "config.h"
>> +#include "common.h"
>> +#include "lldp_mand_clif.h"
>> +#include "lldp_evb_clif.h"
>> +#include "lldp_evb_cmds.h"
>> +
>> +extern struct lldp_head lldp_head;
>> +
>> +struct evb_data *evb_data(char *ifname)
>> +{
>> + struct evb_user_data *ud;
>> + struct evb_data *ed = NULL;
>> +
>> + ud = find_module_user_data_by_if(ifname, &lldp_head, LLDP_MOD_EVB);
>> + if (ud) {
>> + LIST_FOREACH(ed, &ud->head, entry) {
>> + if (!strncmp(ifname, ed->ifname, IFNAMSIZ))
>> + return ed;
>> + }
>> + }
>> + return NULL;
>> +}
>> +
>> +static void evb_print_tlvinfo(struct tlv_info_evb *tie)
>> +{
>> + printf("%s(%i): supported forwarding mode: %02x\n", __FILE__, __LINE__, tie->smode);
>> + printf("%s(%i): configured forwarding mode: %02x\n", __FILE__, __LINE__, tie->cmode);
>> + printf("%s(%i): supported capabilities: %02x\n", __FILE__, __LINE__, tie->scap);
>> + printf("%s(%i): configured capabilities: %02x\n", __FILE__, __LINE__, tie->ccap);
>> + printf("%s(%i): supported no. of vsis: %04i\n", __FILE__, __LINE__, tie->svsi);
>> + printf("%s(%i): configured no. of vsis: %04i\n", __FILE__, __LINE__, tie->cvsi);
>> + printf("%s(%i): rte: %02i\n\n", __FILE__, __LINE__, tie->rte);
>> +}
>> +
>> +/*
>> + * evb_bld_cfg_tlv - build the EVB TLV
>> + * @ed: the evb data struct
>> + *
>> + * Returns 0 on success
>> + */
>> +static int evb_bld_cfg_tlv(struct evb_data *ed)
>> +{
>> + int rc = 0;
>> + int i;
>> + struct unpacked_tlv *tlv = NULL;
>> +
>> + /* free ed->evb if it exists */
>> + FREE_UNPKD_TLV(ed, evb);
>> +
>> + if (!is_tlv_txenabled(ed->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE))) {
>> + fprintf(stderr, "%s:%s:EVB tx is currently disabled !\n",
>> + __func__, ed->ifname);
>> + rc = EINVAL;
>> + goto out_err;
>> + }
>> +
>> + tlv = create_tlv();
>> + if (!tlv)
>> + goto out_err;
>> +
>> + tlv->type = ORG_SPECIFIC_TLV;
>> + tlv->length = sizeof(struct tlv_info_evb);
>> + tlv->info = (u8 *)malloc(tlv->length);
>> + if(!tlv->info) {
>> + free(tlv);
>> + tlv = NULL;
>> + rc = ENOMEM;
>> + goto out_err;
>> + }
>> + memcpy(tlv->info, ed->tie, tlv->length);
>> +
>> + printf("### %s:type %i, length %i, info ", __func__, tlv->type, tlv->length);
>> +
>> + for (i=0; i < tlv->length; i++) {
>> + printf("%02x ", tlv->info[i]);
>> + }
>> +
>
> Remove the extra braces around the for statement. Granted the rest of
> lldpad may not follow a consistent coding style but lets try going
> forward and hopefully I get around to lldpad soon.
>
>
>> + printf("\n");
>> +
>> + ed->evb = tlv;
>> +out_err:
>> + return rc;
>> +}
>> +
>> +static void evb_free_tlv(struct evb_data *ed)
>> +{
>> + if (ed) {
>> + FREE_UNPKD_TLV(ed, evb);
>> + }
>
> Same here extra braces.
>
>> +}
>> +
>> +/* evb_init_cfg_tlv:
>> + *
>> + * fill up tlv_info_evb structure with reasonable info
>> + */
>> +static int evb_init_cfg_tlv(struct evb_data *ed)
>> +{
>> + char arg_path[EVB_BUF_SIZE];
>> + char *param;
>> +
>> + /* load policy from config */
>> + ed->policy = (struct tlv_info_evb *) calloc(1, sizeof(struct tlv_info_evb));
>
> Use malloc instead of callod() of one.
>
On second thought disregard this nit. Keep the calloc() calls if you want and ignore the comment. I guess you save a memset() this way...
Thanks,
John
next prev parent reply other threads:[~2010-09-23 19:34 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-25 12:27 implementation of IEEE 802.1Qbg in lldpad Jens Osterkamp
2010-08-25 12:27 ` [PATCH 01/10] consolidation of MIN and MAX macros in common.h Jens Osterkamp
2010-08-25 12:27 ` [PATCH 02/10] implementation of IEEE 802.1Qbg in lldpad, part 1 Jens Osterkamp
2010-09-23 0:50 ` [E1000-eedc] " John Fastabend
2010-09-23 19:34 ` John Fastabend [this message]
2010-09-24 14:23 ` Jens Osterkamp
2010-08-25 12:27 ` [PATCH 03/10] BUGFIX: check for existence of ifup Jens Osterkamp
2010-08-25 12:27 ` [PATCH 04/10] ECP implementation Jens Osterkamp
2010-09-23 0:50 ` [E1000-eedc] " John Fastabend
2010-09-24 14:18 ` Jens Osterkamp
2010-08-25 12:27 ` [PATCH 05/10] implementation of VDP Jens Osterkamp
2010-09-23 0:55 ` [E1000-eedc] " John Fastabend
2010-09-24 14:15 ` Jens Osterkamp
2010-08-25 12:27 ` [PATCH 06/10] VDP commandline interface Jens Osterkamp
2010-09-23 0:57 ` [E1000-eedc] " John Fastabend
2010-09-24 14:13 ` Jens Osterkamp
2010-08-25 12:27 ` [PATCH 07/10] add libnl dependency to configure.ac Jens Osterkamp
2010-08-25 12:27 ` [PATCH 08/10] use connect instead of bind Jens Osterkamp
2010-08-25 12:27 ` [PATCH 09/10] lldpad support for libvirt netlink message Jens Osterkamp
2010-08-25 12:27 ` [PATCH 10/10] do not use macv[tap/lan] interfaces as ports Jens Osterkamp
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C9BABDB.3040404@intel.com \
--to=john.r.fastabend@intel.com \
--cc=chrisw@redhat.com \
--cc=e1000-eedc@lists.sourceforge.net \
--cc=evb@yahoogroups.com \
--cc=jens@linux.vnet.ibm.com \
--cc=virtualization@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.