summaryrefslogtreecommitdiff
path: root/share
diff options
context:
space:
mode:
Diffstat (limited to 'share')
-rw-r--r--share/man/man4/Makefile6
-rw-r--r--share/man/man4/multicast.4977
-rw-r--r--share/man/man4/pim.4204
3 files changed, 1184 insertions, 3 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 78b53a167ce..aefaccb1dd7 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.289 2005/01/14 12:35:17 grange Exp $
+# $OpenBSD: Makefile,v 1.290 2005/01/14 14:53:54 mcbride Exp $
MAN= aac.4 ac97.4 acphy.4 addcom.4 adv.4 aha.4 ahb.4 ahc.4 ahd.4 \
aic.4 amdpm.4 ami.4 amphy.4 an.4 aria.4 ast.4 atalk.4 \
@@ -17,11 +17,11 @@ MAN= aac.4 ac97.4 acphy.4 addcom.4 adv.4 aha.4 ahb.4 ahc.4 ahd.4 \
iopsp.4 ip.4 ip6.4 ipcomp.4 ipsec.4 ipw.4 isa.4 isapnp.4 \
ises.4 isp.4 it.4 iwi.4 ksyms.4 kue.4 lc.4 lge.4 lkm.4 \
lm.4 lmc.4 lmtemp.4 lo.4 lofn.4 lpt.4 lxtphy.4 maestro.4 midi.4 \
- mii.4 mpt.4 mpu.4 mtd.4 mtdphy.4 mtio.4 ncr.4 ne.4 neo.4 \
+ mii.4 mpt.4 mpu.4 mtd.4 mtdphy.4 multicast.4 mtio.4 ncr.4 ne.4 neo.4 \
netintro.4 nge.4 noct.4 nofn.4 ns.4 nsclpcsio.4 nsgphy.4 \
nsip.4 nsphy.4 nsphyter.4 null.4 ohci.4 opl.4 options.4 \
oosiop.4 osiop.4 pcdisplay.4 pchb.4 pci.4 pcib.4 pciide.4 pckbc.4 \
- pckbd.4 pcmcia.4 pcppi.4 pcscp.4 pf.4 pflog.4 pfsync.4 piixpm.4 \
+ pckbd.4 pcmcia.4 pcppi.4 pcscp.4 pf.4 pflog.4 pfsync.4 piixpm.4 pim.4 \
pms.4 ppb.4 ppp.4 pppoe.4 pty.4 puc.4 qsphy.4 radio.4 raid.4 \
random.4 ray.4 rd.4 re.4 rgephy.4 rl.4 rln.4 rlphy.4 route.4 rt.4 \
rtfps.4 rtii.4 rtw.4 safe.4 san.4 sbus.4 scsi.4 sd.4 ses.4 sf.4 \
diff --git a/share/man/man4/multicast.4 b/share/man/man4/multicast.4
new file mode 100644
index 00000000000..7823f0106de
--- /dev/null
+++ b/share/man/man4/multicast.4
@@ -0,0 +1,977 @@
+.\" Copyright (c) 2001-2003 International Computer Science Institute
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the "Software"),
+.\" to deal in the Software without restriction, including without limitation
+.\" the rights to use, copy, modify, merge, publish, distribute, sublicense,
+.\" and/or sell copies of the Software, and to permit persons to whom the
+.\" Software is furnished to do so, subject to the following conditions:
+.\"
+.\" The above copyright notice and this permission notice shall be included in
+.\" all copies or substantial portions of the Software.
+.\"
+.\" The names and trademarks of copyright holders may not be used in
+.\" advertising or publicity pertaining to the software without specific
+.\" prior permission. Title to copyright in this software and any associated
+.\" documentation will at all times remain with the copyright holders.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+.\" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+.\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+.\" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+.\" DEALINGS IN THE SOFTWARE.
+.\"
+.\" $FreeBSD: src/share/man/man4/multicast.4,v 1.4 2004/07/09 09:22:36 ru Exp $
+.\" $OpenBSD: multicast.4,v 1.1 2005/01/14 14:53:54 mcbride Exp $
+.\" $NetBSD: multicast.4,v 1.3 2004/09/12 13:12:26 wiz Exp $
+.\"
+.Dd September 4, 2003
+.Dt MULTICAST 4
+.Os
+.\"
+.Sh NAME
+.Nm multicast
+.Nd Multicast Routing
+.\"
+.Sh SYNOPSIS
+.Cd "options MROUTING"
+.Pp
+.In sys/types.h
+.In sys/socket.h
+.In netinet/in.h
+.In netinet/ip_mroute.h
+.In netinet6/ip6_mroute.h
+.Ft int
+.Fn getsockopt "int s" IPPROTO_IP MRT_INIT "void *optval" "socklen_t *optlen"
+.Ft int
+.Fn setsockopt "int s" IPPROTO_IP MRT_INIT "const void *optval" "socklen_t optlen"
+.Ft int
+.Fn getsockopt "int s" IPPROTO_IPV6 MRT6_INIT "void *optval" "socklen_t *optlen"
+.Ft int
+.Fn setsockopt "int s" IPPROTO_IPV6 MRT6_INIT "const void *optval" "socklen_t optlen"
+.Sh DESCRIPTION
+.Tn "Multicast routing"
+is used to efficiently propagate data
+packets to a set of multicast listeners in multipoint networks.
+If unicast is used to replicate the data to all listeners,
+then some of the network links may carry multiple copies of the same
+data packets.
+With multicast routing, the overhead is reduced to one copy
+(at most) per network link.
+.Pp
+All multicast-capable routers must run a common multicast routing
+protocol.
+The Distance Vector Multicast Routing Protocol (DVMRP)
+was the first developed multicast routing protocol.
+Later, other protocols such as Multicast Extensions to OSPF (MOSPF),
+Core Based Trees (CBT),
+Protocol Independent Multicast - Sparse Mode (PIM-SM),
+and Protocol Independent Multicast - Dense Mode (PIM-DM)
+were developed as well.
+.Pp
+To start multicast routing,
+the user must enable multicast forwarding in the kernel
+(see
+.Sx SYNOPSIS
+about the kernel configuration options),
+and must run a multicast routing capable user-level process.
+From developer's point of view,
+the programming guide described in the
+.Sx "Programming Guide"
+section should be used to control the multicast forwarding in the kernel.
+.\"
+.Ss Programming Guide
+This section provides information about the basic multicast routing API.
+The so-called
+.Dq advanced multicast API
+is described in the
+.Sx "Advanced Multicast API Programming Guide"
+section.
+.Pp
+First, a multicast routing socket must be open.
+That socket would be used
+to control the multicast forwarding in the kernel.
+Note that most operations below require certain privilege
+(i.e., root privilege):
+.Bd -literal
+/* IPv4 */
+int mrouter_s4;
+mrouter_s4 = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
+.Ed
+.Bd -literal
+int mrouter_s6;
+mrouter_s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+.Ed
+.Pp
+Note that if the router needs to open an IGMP or ICMPv6 socket
+(in case of IPv4 and IPv6 respectively)
+for sending or receiving of IGMP or MLD multicast group membership messages,
+then the same
+.Va mrouter_s4
+or
+.Va mrouter_s6
+sockets should be used
+for sending and receiving respectively IGMP or MLD messages.
+In case of
+.Bx Ns
+-derived kernel, it may be possible to open separate sockets
+for IGMP or MLD messages only.
+However, some other kernels (e.g.,
+.Tn Linux )
+require that the multicast
+routing socket must be used for sending and receiving of IGMP or MLD
+messages.
+Therefore, for portability reason the multicast
+routing socket should be reused for IGMP and MLD messages as well.
+.Pp
+After the multicast routing socket is open, it can be used to enable
+or disable multicast forwarding in the kernel:
+.Bd -literal
+/* IPv4 */
+int v = 1; /* 1 to enable, or 0 to disable */
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_INIT, (void *)\*[Am]v, sizeof(v));
+.Ed
+.Bd -literal
+/* IPv6 */
+int v = 1; /* 1 to enable, or 0 to disable */
+setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_INIT, (void *)\*[Am]v, sizeof(v));
+\&...
+/* If necessary, filter all ICMPv6 messages */
+struct icmp6_filter filter;
+ICMP6_FILTER_SETBLOCKALL(\*[Am]filter);
+setsockopt(mrouter_s6, IPPROTO_ICMPV6, ICMP6_FILTER, (void *)\*[Am]filter,
+ sizeof(filter));
+.Ed
+.Pp
+After multicast forwarding is enabled, the multicast routing socket
+can be used to enable PIM processing in the kernel if we are running PIM-SM or
+PIM-DM
+(see
+.Xr pim 4 ) .
+.Pp
+For each network interface (e.g., physical or a virtual tunnel)
+that would be used for multicast forwarding, a corresponding
+multicast interface must be added to the kernel:
+.Bd -literal
+/* IPv4 */
+struct vifctl vc;
+memset(\*[Am]vc, 0, sizeof(vc));
+/* Assign all vifctl fields as appropriate */
+vc.vifc_vifi = vif_index;
+vc.vifc_flags = vif_flags;
+vc.vifc_threshold = min_ttl_threshold;
+vc.vifc_rate_limit = max_rate_limit;
+memcpy(\*[Am]vc.vifc_lcl_addr, \*[Am]vif_local_address, sizeof(vc.vifc_lcl_addr));
+if (vc.vifc_flags \*[Am] VIFF_TUNNEL)
+ memcpy(\*[Am]vc.vifc_rmt_addr, \*[Am]vif_remote_address,
+ sizeof(vc.vifc_rmt_addr));
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_VIF, (void *)\*[Am]vc,
+ sizeof(vc));
+.Ed
+.Pp
+The
+.Va vif_index
+must be unique per vif.
+The
+.Va vif_flags
+contains the
+.Dv VIFF_*
+flags as defined in
+.Aq Pa netinet/ip_mroute.h .
+The
+.Va min_ttl_threshold
+contains the minimum TTL a multicast data packet must have to be
+forwarded on that vif.
+Typically, it would have value of 1.
+The
+.Va max_rate_limit
+contains the maximum rate (in bits/s) of the multicast data packets forwarded
+on that vif.
+Value of 0 means no limit.
+The
+.Va vif_local_address
+contains the local IP address of the corresponding local interface.
+The
+.Va vif_remote_address
+contains the remote IP address in case of DVMRP multicast tunnels.
+.Bd -literal
+/* IPv6 */
+struct mif6ctl mc;
+memset(\*[Am]mc, 0, sizeof(mc));
+/* Assign all mif6ctl fields as appropriate */
+mc.mif6c_mifi = mif_index;
+mc.mif6c_flags = mif_flags;
+mc.mif6c_pifi = pif_index;
+setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_ADD_MIF, (void *)\*[Am]mc,
+ sizeof(mc));
+.Ed
+.Pp
+The
+.Va mif_index
+must be unique per vif.
+The
+.Va mif_flags
+contains the
+.Dv MIFF_*
+flags as defined in
+.Aq Pa netinet6/ip6_mroute.h .
+The
+.Va pif_index
+is the physical interface index of the corresponding local interface.
+.Pp
+A multicast interface is deleted by:
+.Bd -literal
+/* IPv4 */
+vifi_t vifi = vif_index;
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_DEL_VIF, (void *)\*[Am]vifi,
+ sizeof(vifi));
+.Ed
+.Bd -literal
+/* IPv6 */
+mifi_t mifi = mif_index;
+setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_DEL_MIF, (void *)\*[Am]mifi,
+ sizeof(mifi));
+.Ed
+.Pp
+After the multicast forwarding is enabled, and the multicast virtual
+interfaces are
+added, the kernel may deliver upcall messages (also called signals
+later in this text) on the multicast routing socket that was open
+earlier with
+.Dv MRT_INIT
+or
+.Dv MRT6_INIT .
+The IPv4 upcalls have
+.Vt "struct igmpmsg"
+header (see
+.Aq Pa netinet/ip_mroute.h )
+with field
+.Va im_mbz
+set to zero.
+Note that this header follows the structure of
+.Vt "struct ip"
+with the protocol field
+.Va ip_p
+set to zero.
+The IPv6 upcalls have
+.Vt "struct mrt6msg"
+header (see
+.Aq Pa netinet6/ip6_mroute.h )
+with field
+.Va im6_mbz
+set to zero.
+Note that this header follows the structure of
+.Vt "struct ip6_hdr"
+with the next header field
+.Va ip6_nxt
+set to zero.
+.Pp
+The upcall header contains field
+.Va im_msgtype
+and
+.Va im6_msgtype
+with the type of the upcall
+.Dv IGMPMSG_*
+and
+.Dv MRT6MSG_*
+for IPv4 and IPv6 respectively.
+The values of the rest of the upcall header fields
+and the body of the upcall message depend on the particular upcall type.
+.Pp
+If the upcall message type is
+.Dv IGMPMSG_NOCACHE
+or
+.Dv MRT6MSG_NOCACHE ,
+this is an indication that a multicast packet has reached the multicast
+router, but the router has no forwarding state for that packet.
+Typically, the upcall would be a signal for the multicast routing
+user-level process to install the appropriate Multicast Forwarding
+Cache (MFC) entry in the kernel.
+.Pp
+An MFC entry is added by:
+.Bd -literal
+/* IPv4 */
+struct mfcctl mc;
+memset(\*[Am]mc, 0, sizeof(mc));
+memcpy(\*[Am]mc.mfcc_origin, \*[Am]source_addr, sizeof(mc.mfcc_origin));
+memcpy(\*[Am]mc.mfcc_mcastgrp, \*[Am]group_addr, sizeof(mc.mfcc_mcastgrp));
+mc.mfcc_parent = iif_index;
+for (i = 0; i \*[Lt] maxvifs; i++)
+ mc.mfcc_ttls[i] = oifs_ttl[i];
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_MFC,
+ (void *)\*[Am]mc, sizeof(mc));
+.Ed
+.Bd -literal
+/* IPv6 */
+struct mf6cctl mc;
+memset(\*[Am]mc, 0, sizeof(mc));
+memcpy(\*[Am]mc.mf6cc_origin, \*[Am]source_addr, sizeof(mc.mf6cc_origin));
+memcpy(\*[Am]mc.mf6cc_mcastgrp, \*[Am]group_addr, sizeof(mf6cc_mcastgrp));
+mc.mf6cc_parent = iif_index;
+for (i = 0; i \*[Lt] maxvifs; i++)
+ if (oifs_ttl[i] \*[Gt] 0)
+ IF_SET(i, \*[Am]mc.mf6cc_ifset);
+setsockopt(mrouter_s4, IPPROTO_IPV6, MRT6_ADD_MFC,
+ (void *)\*[Am]mc, sizeof(mc));
+.Ed
+.Pp
+The
+.Va source_addr
+and
+.Va group_addr
+are the source and group address of the multicast packet (as set
+in the upcall message).
+The
+.Va iif_index
+is the virtual interface index of the multicast interface the multicast
+packets for this specific source and group address should be received on.
+The
+.Va oifs_ttl[]
+array contains the minimum TTL (per interface) a multicast packet
+should have to be forwarded on an outgoing interface.
+If the TTL value is zero, the corresponding interface is not included
+in the set of outgoing interfaces.
+Note that in case of IPv6 only the set of outgoing interfaces can
+be specified.
+.Pp
+An MFC entry is deleted by:
+.Bd -literal
+/* IPv4 */
+struct mfcctl mc;
+memset(\*[Am]mc, 0, sizeof(mc));
+memcpy(\*[Am]mc.mfcc_origin, \*[Am]source_addr, sizeof(mc.mfcc_origin));
+memcpy(\*[Am]mc.mfcc_mcastgrp, \*[Am]group_addr, sizeof(mc.mfcc_mcastgrp));
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_DEL_MFC,
+ (void *)\*[Am]mc, sizeof(mc));
+.Ed
+.Bd -literal
+/* IPv6 */
+struct mf6cctl mc;
+memset(\*[Am]mc, 0, sizeof(mc));
+memcpy(\*[Am]mc.mf6cc_origin, \*[Am]source_addr, sizeof(mc.mf6cc_origin));
+memcpy(\*[Am]mc.mf6cc_mcastgrp, \*[Am]group_addr, sizeof(mf6cc_mcastgrp));
+setsockopt(mrouter_s4, IPPROTO_IPV6, MRT6_DEL_MFC,
+ (void *)\*[Am]mc, sizeof(mc));
+.Ed
+.Pp
+The following method can be used to get various statistics per
+installed MFC entry in the kernel (e.g., the number of forwarded
+packets per source and group address):
+.Bd -literal
+/* IPv4 */
+struct sioc_sg_req sgreq;
+memset(\*[Am]sgreq, 0, sizeof(sgreq));
+memcpy(\*[Am]sgreq.src, \*[Am]source_addr, sizeof(sgreq.src));
+memcpy(\*[Am]sgreq.grp, \*[Am]group_addr, sizeof(sgreq.grp));
+ioctl(mrouter_s4, SIOCGETSGCNT, \*[Am]sgreq);
+.Ed
+.Bd -literal
+/* IPv6 */
+struct sioc_sg_req6 sgreq;
+memset(\*[Am]sgreq, 0, sizeof(sgreq));
+memcpy(\*[Am]sgreq.src, \*[Am]source_addr, sizeof(sgreq.src));
+memcpy(\*[Am]sgreq.grp, \*[Am]group_addr, sizeof(sgreq.grp));
+ioctl(mrouter_s6, SIOCGETSGCNT_IN6, \*[Am]sgreq);
+.Ed
+.Pp
+The following method can be used to get various statistics per
+multicast virtual interface in the kernel (e.g., the number of forwarded
+packets per interface):
+.Bd -literal
+/* IPv4 */
+struct sioc_vif_req vreq;
+memset(\*[Am]vreq, 0, sizeof(vreq));
+vreq.vifi = vif_index;
+ioctl(mrouter_s4, SIOCGETVIFCNT, \*[Am]vreq);
+.Ed
+.Bd -literal
+/* IPv6 */
+struct sioc_mif_req6 mreq;
+memset(\*[Am]mreq, 0, sizeof(mreq));
+mreq.mifi = vif_index;
+ioctl(mrouter_s6, SIOCGETMIFCNT_IN6, \*[Am]mreq);
+.Ed
+.Ss Advanced Multicast API Programming Guide
+If we want to add new features in the kernel, it becomes difficult
+to preserve backward compatibility (binary and API),
+and at the same time to allow user-level processes to take advantage of
+the new features (if the kernel supports them).
+.Pp
+One of the mechanisms that allows us to preserve the backward
+compatibility is a sort of negotiation
+between the user-level process and the kernel:
+.Bl -enum
+.It
+The user-level process tries to enable in the kernel the set of new
+features (and the corresponding API) it would like to use.
+.It
+The kernel returns the (sub)set of features it knows about
+and is willing to be enabled.
+.It
+The user-level process uses only that set of features
+the kernel has agreed on.
+.El
+.\"
+.Pp
+To support backward compatibility, if the user-level process does not
+ask for any new features, the kernel defaults to the basic
+multicast API (see the
+.Sx "Programming Guide"
+section).
+.\" XXX: edit as appropriate after the advanced multicast API is
+.\" supported under IPv6
+Currently, the advanced multicast API exists only for IPv4;
+in the future there will be IPv6 support as well.
+.Pp
+Below is a summary of the expandable API solution.
+Note that all new options and structures are defined
+in
+.Aq Pa netinet/ip_mroute.h
+and
+.Aq Pa netinet6/ip6_mroute.h ,
+unless stated otherwise.
+.Pp
+The user-level process uses new
+.Fn getsockopt Ns / Ns Fn setsockopt
+options to
+perform the API features negotiation with the kernel.
+This negotiation must be performed right after the multicast routing
+socket is open.
+The set of desired/allowed features is stored in a bitset
+(currently, in
+.Vt uint32_t ;
+i.e., maximum of 32 new features).
+The new
+.Fn getsockopt Ns / Ns Fn setsockopt
+options are
+.Dv MRT_API_SUPPORT
+and
+.Dv MRT_API_CONFIG .
+Example:
+.Bd -literal
+uint32_t v;
+getsockopt(sock, IPPROTO_IP, MRT_API_SUPPORT, (void *)\*[Am]v, sizeof(v));
+.Ed
+.Pp
+would set in
+.Va v
+the pre-defined bits that the kernel API supports.
+The eight least significant bits in
+.Vt uint32_t
+are same as the
+eight possible flags
+.Dv MRT_MFC_FLAGS_*
+that can be used in
+.Va mfcc_flags
+as part of the new definition of
+.Vt "struct mfcctl"
+(see below about those flags), which leaves 24 flags for other new features.
+The value returned by
+.Fn getsockopt MRT_API_SUPPORT
+is read-only; in other words,
+.Fn setsockopt MRT_API_SUPPORT
+would fail.
+.Pp
+To modify the API, and to set some specific feature in the kernel, then:
+.Bd -literal
+uint32_t v = MRT_MFC_FLAGS_DISABLE_WRONGVIF;
+if (setsockopt(sock, IPPROTO_IP, MRT_API_CONFIG, (void *)\*[Am]v, sizeof(v))
+ != 0) {
+ return (ERROR);
+}
+if (v \*[Am] MRT_MFC_FLAGS_DISABLE_WRONGVIF)
+ return (OK); /* Success */
+else
+ return (ERROR);
+.Ed
+.Pp
+In other words, when
+.Fn setsockopt MRT_API_CONFIG
+is called, the
+argument to it specifies the desired set of features to
+be enabled in the API and the kernel.
+The return value in
+.Va v
+is the actual (sub)set of features that were enabled in the kernel.
+To obtain later the same set of features that were enabled, then:
+.Bd -literal
+getsockopt(sock, IPPROTO_IP, MRT_API_CONFIG, (void *)\*[Am]v, sizeof(v));
+.Ed
+.Pp
+The set of enabled features is global.
+In other words,
+.Fn setsockopt MRT_API_CONFIG
+should be called right after
+.Fn setsockopt MRT_INIT .
+.Pp
+Currently, the following set of new features is defined:
+.Bd -literal
+#define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 \*[Lt]\*[Lt] 0) /* disable WRONGVIF signals */
+#define MRT_MFC_FLAGS_BORDER_VIF (1 \*[Lt]\*[Lt] 1) /* border vif */
+#define MRT_MFC_RP (1 \*[Lt]\*[Lt] 8) /* enable RP address */
+#define MRT_MFC_BW_UPCALL (1 \*[Lt]\*[Lt] 9) /* enable bw upcalls */
+.Ed
+.\" .Pp
+.\" In the future there might be:
+.\" .Bd -literal
+.\" #define MRT_MFC_GROUP_SPECIFIC (1 \*[Lt]\*[Lt] 10) /* allow (*,G) MFC entries */
+.\" .Ed
+.\" .Pp
+.\" to allow (*,G) MFC entries (i.e., group-specific entries) in the kernel.
+.\" For now this is left-out until it is clear whether
+.\" (*,G) MFC support is the preferred solution instead of something more generic
+.\" solution for example.
+.\"
+.\" 2. The newly defined struct mfcctl2.
+.\"
+.Pp
+The advanced multicast API uses a newly defined
+.Vt "struct mfcctl2"
+instead of the traditional
+.Vt "struct mfcctl" .
+The original
+.Vt "struct mfcctl"
+is kept as is.
+The new
+.Vt "struct mfcctl2"
+is:
+.Bd -literal
+/*
+ * The new argument structure for MRT_ADD_MFC and MRT_DEL_MFC overlays
+ * and extends the old struct mfcctl.
+ */
+struct mfcctl2 {
+ /* the mfcctl fields */
+ struct in_addr mfcc_origin; /* ip origin of mcasts */
+ struct in_addr mfcc_mcastgrp; /* multicast group associated*/
+ vifi_t mfcc_parent; /* incoming vif */
+ u_char mfcc_ttls[MAXVIFS];/* forwarding ttls on vifs */
+
+ /* extension fields */
+ uint8_t mfcc_flags[MAXVIFS];/* the MRT_MFC_FLAGS_* flags*/
+ struct in_addr mfcc_rp; /* the RP address */
+};
+.Ed
+.Pp
+The new fields are
+.Va mfcc_flags[MAXVIFS]
+and
+.Va mfcc_rp .
+Note that for compatibility reasons they are added at the end.
+.Pp
+The
+.Va mfcc_flags[MAXVIFS]
+field is used to set various flags per
+interface per (S,G) entry.
+Currently, the defined flags are:
+.Bd -literal
+#define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 \*[Lt]\*[Lt] 0) /* disable WRONGVIF signals */
+#define MRT_MFC_FLAGS_BORDER_VIF (1 \*[Lt]\*[Lt] 1) /* border vif */
+.Ed
+.Pp
+The
+.Dv MRT_MFC_FLAGS_DISABLE_WRONGVIF
+flag is used to explicitly disable the
+.Dv IGMPMSG_WRONGVIF
+kernel signal at the (S,G) granularity if a multicast data packet
+arrives on the wrong interface.
+Usually, this signal is used to
+complete the shortest-path switch in case of PIM-SM multicast routing,
+or to trigger a PIM assert message.
+However, it should not be delivered for interfaces that are not in
+the outgoing interface set, and that are not expecting to
+become an incoming interface.
+Hence, if the
+.Dv MRT_MFC_FLAGS_DISABLE_WRONGVIF
+flag is set for some of the
+interfaces, then a data packet that arrives on that interface for
+that MFC entry will NOT trigger a WRONGVIF signal.
+If that flag is not set, then a signal is triggered (the default action).
+.Pp
+The
+.Dv MRT_MFC_FLAGS_BORDER_VIF
+flag is used to specify whether the Border-bit in PIM
+Register messages should be set (in case when the Register encapsulation
+is performed inside the kernel).
+If it is set for the special PIM Register kernel virtual interface
+(see
+.Xr pim 4 ) ,
+the Border-bit in the Register messages sent to the RP will be set.
+.Pp
+The remaining six bits are reserved for future usage.
+.Pp
+The
+.Va mfcc_rp
+field is used to specify the RP address (in case of PIM-SM multicast routing)
+for a multicast
+group G if we want to perform kernel-level PIM Register encapsulation.
+The
+.Va mfcc_rp
+field is used only if the
+.Dv MRT_MFC_RP
+advanced API flag/capability has been successfully set by
+.Fn setsockopt MRT_API_CONFIG .
+.Pp
+.\"
+.\" 3. Kernel-level PIM Register encapsulation
+.\"
+If the
+.Dv MRT_MFC_RP
+flag was successfully set by
+.Fn setsockopt MRT_API_CONFIG ,
+then the kernel will attempt to perform
+the PIM Register encapsulation itself instead of sending the
+multicast data packets to user level (inside
+.Dv IGMPMSG_WHOLEPKT
+upcalls) for user-level encapsulation.
+The RP address would be taken from the
+.Va mfcc_rp
+field
+inside the new
+.Vt "struct mfcctl2" .
+However, even if the
+.Dv MRT_MFC_RP
+flag was successfully set, if the
+.Va mfcc_rp
+field was set to
+.Dv INADDR_ANY ,
+then the
+kernel will still deliver an
+.Dv IGMPMSG_WHOLEPKT
+upcall with the
+multicast data packet to the user-level process.
+.Pp
+In addition, if the multicast data packet is too large to fit within
+a single IP packet after the PIM Register encapsulation (e.g., if
+its size was on the order of 65500 bytes), the data packet will be
+fragmented, and then each of the fragments will be encapsulated
+separately.
+Note that typically a multicast data packet can be that
+large only if it was originated locally from the same hosts that
+performs the encapsulation; otherwise the transmission of the
+multicast data packet over Ethernet for example would have
+fragmented it into much smaller pieces.
+.\"
+.\" Note that if this code is ported to IPv6, we may need the kernel to
+.\" perform MTU discovery to the RP, and keep those discoveries inside
+.\" the kernel so the encapsulating router may send back ICMP
+.\" Fragmentation Required if the size of the multicast data packet is
+.\" too large (see "Encapsulating data packets in the Register Tunnel"
+.\" in Section 4.4.1 in the PIM-SM spec
+.\" draft-ietf-pim-sm-v2-new-05.{txt,ps}).
+.\" For IPv4 we may be able to get away without it, but for IPv6 we need
+.\" that.
+.\"
+.\" 4. Mechanism for "multicast bandwidth monitoring and upcalls".
+.\"
+.Pp
+Typically, a multicast routing user-level process would need to know the
+forwarding bandwidth for some data flow.
+For example, the multicast routing process may want to timeout idle MFC
+entries, or in case of PIM-SM it can initiate (S,G) shortest-path switch if
+the bandwidth rate is above a threshold for example.
+.Pp
+The original solution for measuring the bandwidth of a dataflow was
+that a user-level process would periodically
+query the kernel about the number of forwarded packets/bytes per
+(S,G), and then based on those numbers it would estimate whether a source
+has been idle, or whether the source's transmission bandwidth is above a
+threshold.
+That solution is far from being scalable, hence the need for a new
+mechanism for bandwidth monitoring.
+.Pp
+Below is a description of the bandwidth monitoring mechanism.
+.Bl -bullet
+.It
+If the bandwidth of a data flow satisfies some pre-defined filter,
+the kernel delivers an upcall on the multicast routing socket
+to the multicast routing process that has installed that filter.
+.It
+The bandwidth-upcall filters are installed per (S,G).
+There can be
+more than one filter per (S,G).
+.It
+Instead of supporting all possible comparison operations
+(i.e., \*[Lt] \*[Lt]= == != \*[Gt] \*[Gt]= ), there is support only for the
+\*[Lt]= and \*[Gt]= operations,
+because this makes the kernel-level implementation simpler,
+and because practically we need only those two.
+Further, the missing operations can be simulated by secondary
+user-level filtering of those \*[Lt]= and \*[Gt]= filters.
+For example, to simulate !=, then we need to install filter
+.Dq bw \*[Lt]= 0xffffffff ,
+and after an
+upcall is received, we need to check whether
+.Dq measured_bw != expected_bw .
+.It
+The bandwidth-upcall mechanism is enabled by
+.Fn setsockopt MRT_API_CONFIG
+for the
+.Dv MRT_MFC_BW_UPCALL
+flag.
+.It
+The bandwidth-upcall filters are added/deleted by the new
+.Fn setsockopt MRT_ADD_BW_UPCALL
+and
+.Fn setsockopt MRT_DEL_BW_UPCALL
+respectively (with the appropriate
+.Vt "struct bw_upcall"
+argument of course).
+.El
+.Pp
+From application point of view, a developer needs to know about
+the following:
+.Bd -literal
+/*
+ * Structure for installing or delivering an upcall if the
+ * measured bandwidth is above or below a threshold.
+ *
+ * User programs (e.g. daemons) may have a need to know when the
+ * bandwidth used by some data flow is above or below some threshold.
+ * This interface allows the userland to specify the threshold (in
+ * bytes and/or packets) and the measurement interval. Flows are
+ * all packet with the same source and destination IP address.
+ * At the moment the code is only used for multicast destinations
+ * but there is nothing that prevents its use for unicast.
+ *
+ * The measurement interval cannot be shorter than some Tmin (currently, 3s).
+ * The threshold is set in packets and/or bytes per_interval.
+ *
+ * Measurement works as follows:
+ *
+ * For \*[Gt]= measurements:
+ * The first packet marks the start of a measurement interval.
+ * During an interval we count packets and bytes, and when we
+ * pass the threshold we deliver an upcall and we are done.
+ * The first packet after the end of the interval resets the
+ * count and restarts the measurement.
+ *
+ * For \*[Lt]= measurement:
+ * We start a timer to fire at the end of the interval, and
+ * then for each incoming packet we count packets and bytes.
+ * When the timer fires, we compare the value with the threshold,
+ * schedule an upcall if we are below, and restart the measurement
+ * (reschedule timer and zero counters).
+ */
+
+struct bw_data {
+ struct timeval b_time;
+ uint64_t b_packets;
+ uint64_t b_bytes;
+};
+
+struct bw_upcall {
+ struct in_addr bu_src; /* source address */
+ struct in_addr bu_dst; /* destination address */
+ uint32_t bu_flags; /* misc flags (see below) */
+#define BW_UPCALL_UNIT_PACKETS (1 \*[Lt]\*[Lt] 0) /* threshold (in packets) */
+#define BW_UPCALL_UNIT_BYTES (1 \*[Lt]\*[Lt] 1) /* threshold (in bytes) */
+#define BW_UPCALL_GEQ (1 \*[Lt]\*[Lt] 2) /* upcall if bw \*[Gt]= threshold */
+#define BW_UPCALL_LEQ (1 \*[Lt]\*[Lt] 3) /* upcall if bw \*[Lt]= threshold */
+#define BW_UPCALL_DELETE_ALL (1 \*[Lt]\*[Lt] 4) /* delete all upcalls for s,d*/
+ struct bw_data bu_threshold; /* the bw threshold */
+ struct bw_data bu_measured; /* the measured bw */
+};
+
+/* max. number of upcalls to deliver together */
+#define BW_UPCALLS_MAX 128
+/* min. threshold time interval for bandwidth measurement */
+#define BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC 3
+#define BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC 0
+.Ed
+.Pp
+The
+.Vt bw_upcall
+structure is used as an argument to
+.Fn setsockopt MRT_ADD_BW_UPCALL
+and
+.Fn setsockopt MRT_DEL_BW_UPCALL .
+Each
+.Fn setsockopt MRT_ADD_BW_UPCALL
+installs a filter in the kernel
+for the source and destination address in the
+.Vt bw_upcall
+argument,
+and that filter will trigger an upcall according to the following
+pseudo-algorithm:
+.Bd -literal
+ if (bw_upcall_oper IS "\*[Gt]=") {
+ if (((bw_upcall_unit \*[Am] PACKETS == PACKETS) \*[Am]\*[Am]
+ (measured_packets \*[Gt]= threshold_packets)) ||
+ ((bw_upcall_unit \*[Am] BYTES == BYTES) \*[Am]\*[Am]
+ (measured_bytes \*[Gt]= threshold_bytes)))
+ SEND_UPCALL("measured bandwidth is \*[Gt]= threshold");
+ }
+ if (bw_upcall_oper IS "\*[Lt]=" \*[Am]\*[Am] measured_interval \*[Gt]= threshold_interval) {
+ if (((bw_upcall_unit \*[Am] PACKETS == PACKETS) \*[Am]\*[Am]
+ (measured_packets \*[Lt]= threshold_packets)) ||
+ ((bw_upcall_unit \*[Am] BYTES == BYTES) \*[Am]\*[Am]
+ (measured_bytes \*[Lt]= threshold_bytes)))
+ SEND_UPCALL("measured bandwidth is \*[Lt]= threshold");
+ }
+.Ed
+.Pp
+In the same
+.Vt bw_upcall
+the unit can be specified in both BYTES and PACKETS.
+However, the GEQ and LEQ flags are mutually exclusive.
+.Pp
+Basically, an upcall is delivered if the measured bandwidth is \*[Gt]= or
+\*[Lt]= the threshold bandwidth (within the specified measurement
+interval).
+For practical reasons, the smallest value for the measurement
+interval is 3 seconds.
+If smaller values are allowed, then the bandwidth
+estimation may be less accurate, or the potentially very high frequency
+of the generated upcalls may introduce too much overhead.
+For the \*[Gt]= operation, the answer may be known before the end of
+.Va threshold_interval ,
+therefore the upcall may be delivered earlier.
+For the \*[Lt]= operation however, we must wait
+until the threshold interval has expired to know the answer.
+.Pp
+Example of usage:
+.Bd -literal
+struct bw_upcall bw_upcall;
+/* Assign all bw_upcall fields as appropriate */
+memset(\*[Am]bw_upcall, 0, sizeof(bw_upcall));
+memcpy(\*[Am]bw_upcall.bu_src, \*[Am]source, sizeof(bw_upcall.bu_src));
+memcpy(\*[Am]bw_upcall.bu_dst, \*[Am]group, sizeof(bw_upcall.bu_dst));
+bw_upcall.bu_threshold.b_data = threshold_interval;
+bw_upcall.bu_threshold.b_packets = threshold_packets;
+bw_upcall.bu_threshold.b_bytes = threshold_bytes;
+if (is_threshold_in_packets)
+ bw_upcall.bu_flags |= BW_UPCALL_UNIT_PACKETS;
+if (is_threshold_in_bytes)
+ bw_upcall.bu_flags |= BW_UPCALL_UNIT_BYTES;
+do {
+ if (is_geq_upcall) {
+ bw_upcall.bu_flags |= BW_UPCALL_GEQ;
+ break;
+ }
+ if (is_leq_upcall) {
+ bw_upcall.bu_flags |= BW_UPCALL_LEQ;
+ break;
+ }
+ return (ERROR);
+} while (0);
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_BW_UPCALL,
+ (void *)\*[Am]bw_upcall, sizeof(bw_upcall));
+.Ed
+.Pp
+To delete a single filter, then use
+.Dv MRT_DEL_BW_UPCALL ,
+and the fields of bw_upcall must be set
+exactly same as when
+.Dv MRT_ADD_BW_UPCALL
+was called.
+.Pp
+To delete all bandwidth filters for a given (S,G), then
+only the
+.Va bu_src
+and
+.Va bu_dst
+fields in
+.Vt "struct bw_upcall"
+need to be set, and then just set only the
+.Dv BW_UPCALL_DELETE_ALL
+flag inside field
+.Va bw_upcall.bu_flags .
+.Pp
+The bandwidth upcalls are received by aggregating them in the new upcall
+message:
+.Bd -literal
+#define IGMPMSG_BW_UPCALL 4 /* BW monitoring upcall */
+.Ed
+.Pp
+This message is an array of
+.Vt "struct bw_upcall"
+elements (up to
+.Dv BW_UPCALLS_MAX
+= 128).
+The upcalls are
+delivered when there are 128 pending upcalls, or when 1 second has
+expired since the previous upcall (whichever comes first).
+In an
+.Vt "struct upcall"
+element, the
+.Va bu_measured
+field is filled-in to
+indicate the particular measured values.
+However, because of the way
+the particular intervals are measured, the user should be careful how
+.Va bu_measured.b_time
+is used.
+For example, if the
+filter is installed to trigger an upcall if the number of packets
+is \*[Gt]= 1, then
+.Va bu_measured
+may have a value of zero in the upcalls after the
+first one, because the measured interval for \*[Gt]= filters is
+.Dq clocked
+by the forwarded packets.
+Hence, this upcall mechanism should not be used for measuring
+the exact value of the bandwidth of the forwarded data.
+To measure the exact bandwidth, the user would need to
+get the forwarded packets statistics with the
+.Fn ioctl SIOCGETSGCNT
+mechanism
+(see the
+.Sx Programming Guide
+section) .
+.Pp
+Note that the upcalls for a filter are delivered until the specific
+filter is deleted, but no more frequently than once per
+.Va bu_threshold.b_time .
+For example, if the filter is specified to
+deliver a signal if bw \*[Gt]= 1 packet, the first packet will trigger a
+signal, but the next upcall will be triggered no earlier than
+.Va bu_threshold.b_time
+after the previous upcall.
+.\"
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr recvfrom 2 ,
+.Xr recvmsg 2 ,
+.Xr setsockopt 2 ,
+.Xr socket 2 ,
+.Xr icmp6 4 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr intro 4 ,
+.Xr ip 4 ,
+.Xr ip6 4 ,
+.Xr pim 4
+.\"
+.Sh AUTHORS
+.An -nosplit
+The original multicast code was written by
+.An David Waitzman
+(BBN Labs),
+and later modified by the following individuals:
+.An Steve Deering
+(Stanford),
+.An Mark J. Steiglitz
+(Stanford),
+.An Van Jacobson
+(LBL),
+.An Ajit Thyagarajan
+(PARC),
+.An Bill Fenner
+(PARC).
+The IPv6 multicast support was implemented by the KAME project
+.Pq Pa http://www.kame.net ,
+and was based on the IPv4 multicast code.
+The advanced multicast API and the multicast bandwidth
+monitoring were implemented by
+.An Pavlin Radoslavov
+(ICSI)
+in collaboration with
+.An Chris Brown
+(NextHop).
+.Pp
+This manual page was written by
+.An Pavlin Radoslavov
+(ICSI).
diff --git a/share/man/man4/pim.4 b/share/man/man4/pim.4
new file mode 100644
index 00000000000..17423134203
--- /dev/null
+++ b/share/man/man4/pim.4
@@ -0,0 +1,204 @@
+.\" Copyright (c) 2001-2003 International Computer Science Institute
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the "Software"),
+.\" to deal in the Software without restriction, including without limitation
+.\" the rights to use, copy, modify, merge, publish, distribute, sublicense,
+.\" and/or sell copies of the Software, and to permit persons to whom the
+.\" Software is furnished to do so, subject to the following conditions:
+.\"
+.\" The above copyright notice and this permission notice shall be included in
+.\" all copies or substantial portions of the Software.
+.\"
+.\" The names and trademarks of copyright holders may not be used in
+.\" advertising or publicity pertaining to the software without specific
+.\" prior permission. Title to copyright in this software and any associated
+.\" documentation will at all times remain with the copyright holders.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+.\" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+.\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+.\" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+.\" DEALINGS IN THE SOFTWARE.
+.\"
+.\" $FreeBSD: src/share/man/man4/pim.4,v 1.2 2004/07/09 09:22:36 ru Exp $
+.\" $OpenBSD: pim.4,v 1.1 2005/01/14 14:53:54 mcbride Exp $
+.\" $NetBSD: pim.4,v 1.2 2004/09/12 13:06:14 wiz Exp $
+.\"
+.Dd September 4, 2003
+.Dt PIM 4
+.Os
+.\"
+.Sh NAME
+.Nm pim
+.Nd Protocol Independent Multicast
+.\"
+.Sh SYNOPSIS
+.Cd "options MROUTING"
+.Cd "options PIM"
+.Pp
+.In sys/types.h
+.In sys/socket.h
+.In netinet/in.h
+.In netinet/ip_mroute.h
+.In netinet/pim.h
+.Ft int
+.Fn getsockopt "int s" IPPROTO_IP MRT_PIM "void *optval" "socklen_t *optlen"
+.Ft int
+.Fn setsockopt "int s" IPPROTO_IP MRT_PIM "const void *optval" "socklen_t optlen"
+.Ft int
+.Fn getsockopt "int s" IPPROTO_IPV6 MRT6_PIM "void *optval" "socklen_t *optlen"
+.Ft int
+.Fn setsockopt "int s" IPPROTO_IPV6 MRT6_PIM "const void *optval" "socklen_t optlen"
+.Sh DESCRIPTION
+.Tn PIM
+is the common name for two multicast routing protocols:
+Protocol Independent Multicast - Sparse Mode (PIM-SM) and
+Protocol Independent Multicast - Dense Mode (PIM-DM).
+.Pp
+PIM-SM is a multicast routing protocol that can use the underlying
+unicast routing information base or a separate multicast-capable
+routing information base.
+It builds unidirectional shared trees rooted at a Rendezvous
+Point (RP) per group,
+and optionally creates shortest-path trees per source.
+.Pp
+PIM-DM is a multicast routing protocol that uses the underlying
+unicast routing information base to flood multicast datagrams
+to all multicast routers.
+Prune messages are used to prevent future datagrams from propagating
+to routers with no group membership information.
+.Pp
+Both PIM-SM and PIM-DM are fairly complex protocols,
+though PIM-SM is much more complex.
+To enable PIM-SM or PIM-DM multicast routing in a router,
+the user must enable multicast routing and PIM processing in the kernel
+(see
+.Sx SYNOPSIS
+about the kernel configuration options),
+and must run a PIM-SM or PIM-DM capable user-level process.
+From developer's point of view,
+the programming guide described in the
+.Sx "Programming Guide"
+section should be used to control the PIM processing in the kernel.
+.\"
+.Ss Programming Guide
+After a multicast routing socket is open and multicast forwarding
+is enabled in the kernel
+(see
+.Xr multicast 4 ) ,
+one of the following socket options should be used to enable or disable
+PIM processing in the kernel.
+Note that those options require certain privilege
+(i.e., root privilege):
+.Bd -literal
+/* IPv4 */
+int v = 1; /* 1 to enable, or 0 to disable */
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_PIM, (void *)\*[Am]v, sizeof(v));
+.Ed
+.Bd -literal
+/* IPv6 */
+int v = 1; /* 1 to enable, or 0 to disable */
+setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_PIM, (void *)\*[Am]v, sizeof(v));
+.Ed
+.Pp
+After PIM processing is enabled, the multicast-capable interfaces
+should be added
+(see
+.Xr multicast 4 ) .
+In case of PIM-SM, the PIM-Register virtual interface must be added
+as well.
+This can be accomplished by using the following options:
+.Bd -literal
+/* IPv4 */
+struct vifctl vc;
+memset(\*[Am]vc, 0, sizeof(vc));
+/* Assign all vifctl fields as appropriate */
+\&...
+if (is_pim_register_vif)
+ vc.vifc_flags |= VIFF_REGISTER;
+setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_VIF, (void *)\*[Am]vc,
+ sizeof(vc));
+.Ed
+.Bd -literal
+/* IPv6 */
+struct mif6ctl mc;
+memset(\*[Am]mc, 0, sizeof(mc));
+/* Assign all mif6ctl fields as appropriate */
+\&...
+if (is_pim_register_vif)
+ mc.mif6c_flags |= MIFF_REGISTER;
+setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_ADD_MIF, (void *)\*[Am]mc,
+ sizeof(mc));
+.Ed
+.Pp
+Sending or receiving of PIM packets can be accomplished by
+opening first a
+.Dq raw socket
+(see
+.Xr socket 2 ) ,
+with protocol value of
+.Dv IPPROTO_PIM :
+.Bd -literal
+/* IPv4 */
+int pim_s4;
+pim_s4 = socket(AF_INET, SOCK_RAW, IPPROTO_PIM);
+.Ed
+.Bd -literal
+/* IPv6 */
+int pim_s6;
+pim_s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_PIM);
+.Ed
+.Pp
+Then, the following system calls can be used to send or receive PIM
+packets:
+.Xr sendto 2 ,
+.Xr sendmsg 2 ,
+.Xr recvfrom 2 ,
+.Xr recvmsg 2 .
+.\"
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr recvfrom 2 ,
+.Xr recvmsg 2 ,
+.Xr sendmsg 2 ,
+.Xr sendto 2 ,
+.Xr setsockopt 2 ,
+.Xr socket 2 ,
+.Xr inet 4 ,
+.Xr intro 4 ,
+.Xr ip 4 ,
+.Xr multicast 4
+.\"
+.Sh STANDARDS
+.\" XXX the PIM-SM number must be updated after RFC 2362 is
+.\" replaced by a new RFC by the end of year 2003 or so.
+The PIM-SM protocol is specified in RFC 2362 (to be replaced by
+.%T draft-ietf-pim-sm-v2-new-* ) .
+The PIM-DM protocol is specified in
+.%T draft-ietf-pim-dm-new-v2-* ) .
+.\"
+.Sh AUTHORS
+.An -nosplit
+The original IPv4 PIM kernel support for IRIX and SunOS-4.x was
+implemented by
+.An Ahmed Helmy
+(USC and SGI).
+Later the code was ported to various
+.Bx
+flavors and modified by
+.An George Edmond Eddy
+(Rusty) (ISI),
+.An Hitoshi Asaeda
+(WIDE Project), and
+.An Pavlin Radoslavov
+(USC/ISI and ICSI).
+The IPv6 PIM kernel support was implemented by the KAME project
+.Pq Pa http://www.kame.net ,
+and was based on the IPv4 PIM kernel support.
+.Pp
+This manual page was written by
+.An Pavlin Radoslavov
+(ICSI).