ip_mroute.c revision 119792
11541Srgrimes/* 22531Swollman * IP multicast forwarding procedures 31541Srgrimes * 41541Srgrimes * Written by David Waitzman, BBN Labs, August 1988. 51541Srgrimes * Modified by Steve Deering, Stanford, February 1989. 62531Swollman * Modified by Mark J. Steiglitz, Stanford, May, 1991 72531Swollman * Modified by Van Jacobson, LBL, January 1993 82531Swollman * Modified by Ajit Thyagarajan, PARC, August 1993 99209Swollman * Modified by Bill Fenner, PARC, April 1995 10118622Shsu * Modified by Ahmed Helmy, SGI, June 1996 11118622Shsu * Modified by George Edmond Eddy (Rusty), ISI, February 1998 12118622Shsu * Modified by Pavlin Radoslavov, USC/ISI, May 1998, August 1999, October 2000 13118622Shsu * Modified by Hitoshi Asaeda, WIDE, August 2000 14118622Shsu * Modified by Pavlin Radoslavov, ICSI, October 2002 151541Srgrimes * 169209Swollman * MROUTING Revision: 3.5 17118622Shsu * and PIM-SMv2 and PIM-DM support, advanced API support, 18118622Shsu * bandwidth metering and signaling 19118622Shsu * 2050477Speter * $FreeBSD: head/sys/netinet/ip_mroute.c 119792 2003-09-06 04:53:43Z sam $ 211541Srgrimes */ 221541Srgrimes 23105570Srwatson#include "opt_mac.h" 2414328Speter#include "opt_mrouting.h" 2577574Skris#include "opt_random_ip_id.h" 261541Srgrimes 27118622Shsu#ifdef PIM 28118622Shsu#define _PIM_VT 1 29118622Shsu#endif 30118622Shsu 311541Srgrimes#include <sys/param.h> 3295759Stanimura#include <sys/kernel.h> 3395759Stanimura#include <sys/lock.h> 34105570Srwatson#include <sys/mac.h> 3542777Sfenner#include <sys/malloc.h> 361541Srgrimes#include <sys/mbuf.h> 3795759Stanimura#include <sys/protosw.h> 3895759Stanimura#include <sys/signalvar.h> 391541Srgrimes#include <sys/socket.h> 401541Srgrimes#include <sys/socketvar.h> 4195759Stanimura#include <sys/sockio.h> 4295759Stanimura#include <sys/sx.h> 4380354Sfenner#include <sys/sysctl.h> 442531Swollman#include <sys/syslog.h> 4595759Stanimura#include <sys/systm.h> 4695759Stanimura#include <sys/time.h> 471541Srgrimes#include <net/if.h> 48111888Sjlemon#include <net/netisr.h> 491541Srgrimes#include <net/route.h> 501541Srgrimes#include <netinet/in.h> 5195759Stanimura#include <netinet/igmp.h> 521541Srgrimes#include <netinet/in_systm.h> 5395759Stanimura#include <netinet/in_var.h> 541541Srgrimes#include <netinet/ip.h> 5580354Sfenner#include <netinet/ip_encap.h> 561541Srgrimes#include <netinet/ip_mroute.h> 5795759Stanimura#include <netinet/ip_var.h> 58118622Shsu#ifdef PIM 59118622Shsu#include <netinet/pim.h> 60118622Shsu#include <netinet/pim_var.h> 61118622Shsu#endif 629209Swollman#include <netinet/udp.h> 6360214Sken#include <machine/in_cksum.h> 641541Srgrimes 652531Swollman/* 66106968Sluigi * Control debugging code for rsvp and multicast routing code. 67106968Sluigi * Can only set them with the debugger. 682531Swollman */ 69106968Sluigistatic u_int rsvpdebug; /* non-zero enables debugging */ 701541Srgrimes 71106968Sluigistatic u_int mrtdebug; /* any set of the flags below */ 72106968Sluigi#define DEBUG_MFC 0x02 73106968Sluigi#define DEBUG_FORWARD 0x04 74106968Sluigi#define DEBUG_EXPIRE 0x08 75106968Sluigi#define DEBUG_XMIT 0x10 76118622Shsu#define DEBUG_PIM 0x20 772531Swollman 78118622Shsu#define VIFI_INVALID ((vifi_t) -1) 79118622Shsu 809209Swollman#define M_HASCL(m) ((m)->m_flags & M_EXT) 819209Swollman 8242777Sfennerstatic MALLOC_DEFINE(M_MRTABLE, "mroutetbl", "multicast routing tables"); 832531Swollman 84119792Ssam/* 85119792Ssam * Locking. We use two locks: one for the virtual interface table and 86119792Ssam * one for the forwarding table. These locks may be nested in which case 87119792Ssam * the VIF lock must always be taken first. Note that each lock is used 88119792Ssam * to cover not only the specific data structure but also related data 89119792Ssam * structures. It may be better to add more fine-grained locking later; 90119792Ssam * it's not clear how performance-critical this code is. 91119792Ssam */ 92119792Ssam 9333181Seivindstatic struct mrtstat mrtstat; 9480354SfennerSYSCTL_STRUCT(_net_inet_ip, OID_AUTO, mrtstat, CTLFLAG_RW, 95106968Sluigi &mrtstat, mrtstat, 96106968Sluigi "Multicast Routing Statistics (struct mrtstat, netinet/ip_mroute.h)"); 971541Srgrimes 9842777Sfennerstatic struct mfc *mfctable[MFCTBLSIZ]; 99118501ShsuSYSCTL_OPAQUE(_net_inet_ip, OID_AUTO, mfctable, CTLFLAG_RD, 100118501Shsu &mfctable, sizeof(mfctable), "S,*mfc[MFCTBLSIZ]", 101118501Shsu "Multicast Forwarding Table (struct *mfc[MFCTBLSIZ], netinet/ip_mroute.h)"); 102118501Shsu 103119792Ssamstatic struct mtx mfc_mtx; 104119792Ssam#define MFC_LOCK() mtx_lock(&mfc_mtx) 105119792Ssam#define MFC_UNLOCK() mtx_unlock(&mfc_mtx) 106119792Ssam#define MFC_LOCK_ASSERT() mtx_assert(&mfc_mtx, MA_OWNED) 107119792Ssam#define MFC_LOCK_INIT() mtx_init(&mfc_mtx, "mroute mfc table", NULL, MTX_DEF) 108119792Ssam#define MFC_LOCK_DESTROY() mtx_destroy(&mfc_mtx) 109119792Ssam 11012820Sphkstatic struct vif viftable[MAXVIFS]; 111118501ShsuSYSCTL_OPAQUE(_net_inet_ip, OID_AUTO, viftable, CTLFLAG_RD, 112118501Shsu &viftable, sizeof(viftable), "S,vif[MAXVIFS]", 113118501Shsu "Multicast Virtual Interfaces (struct vif[MAXVIFS], netinet/ip_mroute.h)"); 1142531Swollman 115119792Ssamstatic struct mtx vif_mtx; 116119792Ssam#define VIF_LOCK() mtx_lock(&vif_mtx) 117119792Ssam#define VIF_UNLOCK() mtx_unlock(&vif_mtx) 118119792Ssam#define VIF_LOCK_ASSERT() mtx_assert(&vif_mtx, MA_OWNED) 119119792Ssam#define VIF_LOCK_INIT() mtx_init(&vif_mtx, "mroute vif table", NULL, MTX_DEF) 120119792Ssam#define VIF_LOCK_DESTROY() mtx_destroy(&vif_mtx) 121119792Ssam 122118501Shsustatic u_char nexpire[MFCTBLSIZ]; 123118501Shsu 124119792Ssamstatic struct callout expire_upcalls_ch; 12529681Sgibbs 1269209Swollman#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ 1279209Swollman#define UPCALL_EXPIRE 6 /* number of timeouts */ 1282531Swollman 1291541Srgrimes/* 1302531Swollman * Define the token bucket filter structures 1319209Swollman * tbftable -> each vif has one of these for storing info 1322531Swollman */ 1332531Swollman 13412820Sphkstatic struct tbf tbftable[MAXVIFS]; 13510203Swollman#define TBF_REPROCESS (hz / 100) /* 100x / second */ 1362531Swollman 1372531Swollman/* 1382531Swollman * 'Interfaces' associated with decapsulator (so we can tell 1392531Swollman * packets that went through it from ones that get reflected 1402531Swollman * by a broken gateway). These interfaces are never linked into 1412531Swollman * the system ifnet list & no routes point to them. I.e., packets 1422531Swollman * can't be sent this way. They only exist as a placeholder for 1432531Swollman * multicast source verification. 1442531Swollman */ 14512820Sphkstatic struct ifnet multicast_decap_if[MAXVIFS]; 1462531Swollman 1472531Swollman#define ENCAP_TTL 64 1489209Swollman#define ENCAP_PROTO IPPROTO_IPIP /* 4 */ 1492531Swollman 1502531Swollman/* prototype IP hdr for encapsulated packets */ 15112296Sphkstatic struct ip multicast_encap_iphdr = { 1522754Swollman#if BYTE_ORDER == LITTLE_ENDIAN 1532531Swollman sizeof(struct ip) >> 2, IPVERSION, 1542531Swollman#else 1552531Swollman IPVERSION, sizeof(struct ip) >> 2, 1562531Swollman#endif 1572531Swollman 0, /* tos */ 1582531Swollman sizeof(struct ip), /* total length */ 1592531Swollman 0, /* id */ 1602531Swollman 0, /* frag offset */ 1619209Swollman ENCAP_TTL, ENCAP_PROTO, 1622531Swollman 0, /* checksum */ 1632531Swollman}; 1642531Swollman 1652531Swollman/* 166118622Shsu * Bandwidth meter variables and constants 167118622Shsu */ 168118622Shsustatic MALLOC_DEFINE(M_BWMETER, "bwmeter", "multicast upcall bw meters"); 169118622Shsu/* 170118622Shsu * Pending timeouts are stored in a hash table, the key being the 171118622Shsu * expiration time. Periodically, the entries are analysed and processed. 172118622Shsu */ 173118622Shsu#define BW_METER_BUCKETS 1024 174118622Shsustatic struct bw_meter *bw_meter_timers[BW_METER_BUCKETS]; 175119792Ssamstatic struct callout bw_meter_ch; 176118622Shsu#define BW_METER_PERIOD (hz) /* periodical handling of bw meters */ 177118622Shsu 178118622Shsu/* 179118622Shsu * Pending upcalls are stored in a vector which is flushed when 180118622Shsu * full, or periodically 181118622Shsu */ 182118622Shsustatic struct bw_upcall bw_upcalls[BW_UPCALLS_MAX]; 183118622Shsustatic u_int bw_upcalls_n; /* # of pending upcalls */ 184119792Ssamstatic struct callout bw_upcalls_ch; 185118622Shsu#define BW_UPCALLS_PERIOD (hz) /* periodical flush of bw upcalls */ 186118622Shsu 187118622Shsu#ifdef PIM 188118622Shsustatic struct pimstat pimstat; 189118622ShsuSYSCTL_STRUCT(_net_inet_pim, PIMCTL_STATS, stats, CTLFLAG_RD, 190118622Shsu &pimstat, pimstat, 191118622Shsu "PIM Statistics (struct pimstat, netinet/pim_var.h)"); 192118622Shsu 193118622Shsu/* 194118622Shsu * Note: the PIM Register encapsulation adds the following in front of a 195118622Shsu * data packet: 196118622Shsu * 197118622Shsu * struct pim_encap_hdr { 198118622Shsu * struct ip ip; 199118622Shsu * struct pim_encap_pimhdr pim; 200118622Shsu * } 201118622Shsu * 202118622Shsu */ 203118622Shsu 204118622Shsustruct pim_encap_pimhdr { 205118622Shsu struct pim pim; 206118622Shsu uint32_t flags; 207118622Shsu}; 208118622Shsu 209118622Shsustatic struct ip pim_encap_iphdr = { 210118622Shsu#if BYTE_ORDER == LITTLE_ENDIAN 211118622Shsu sizeof(struct ip) >> 2, 212118622Shsu IPVERSION, 213118622Shsu#else 214118622Shsu IPVERSION, 215118622Shsu sizeof(struct ip) >> 2, 216118622Shsu#endif 217118622Shsu 0, /* tos */ 218118622Shsu sizeof(struct ip), /* total length */ 219118622Shsu 0, /* id */ 220118622Shsu 0, /* frag offset */ 221118622Shsu ENCAP_TTL, 222118622Shsu IPPROTO_PIM, 223118622Shsu 0, /* checksum */ 224118622Shsu}; 225118622Shsu 226118622Shsustatic struct pim_encap_pimhdr pim_encap_pimhdr = { 227118622Shsu { 228118622Shsu PIM_MAKE_VT(PIM_VERSION, PIM_REGISTER), /* PIM vers and message type */ 229118622Shsu 0, /* reserved */ 230118622Shsu 0, /* checksum */ 231118622Shsu }, 232118622Shsu 0 /* flags */ 233118622Shsu}; 234118622Shsu 235118622Shsustatic struct ifnet multicast_register_if; 236118622Shsustatic vifi_t reg_vif_num = VIFI_INVALID; 237118622Shsu#endif /* PIM */ 238118622Shsu 239118622Shsu/* 2401541Srgrimes * Private variables. 2411541Srgrimes */ 242106968Sluigistatic vifi_t numvifs; 243106968Sluigistatic const struct encaptab *encap_cookie; 2441541Srgrimes 2451541Srgrimes/* 24683708Ssumikawa * one-back cache used by mroute_encapcheck to locate a tunnel's vif 2472531Swollman * given a datagram's src ip address. 2482531Swollman */ 2492531Swollmanstatic u_long last_encap_src; 2502531Swollmanstatic struct vif *last_encap_vif; 2512531Swollman 252119792Ssam/* 253119792Ssam * Callout for queue processing. 254119792Ssam */ 255119792Ssamstatic struct callout tbf_reprocess_ch; 256119792Ssam 25792723Salfredstatic u_long X_ip_mcast_src(int vifi); 258106968Sluigistatic int X_ip_mforward(struct ip *ip, struct ifnet *ifp, 259106968Sluigi struct mbuf *m, struct ip_moptions *imo); 26092723Salfredstatic int X_ip_mrouter_done(void); 26192723Salfredstatic int X_ip_mrouter_get(struct socket *so, struct sockopt *m); 26292723Salfredstatic int X_ip_mrouter_set(struct socket *so, struct sockopt *m); 26392723Salfredstatic int X_legal_vif_num(int vif); 26492723Salfredstatic int X_mrt_ioctl(int cmd, caddr_t data); 26512579Sbde 2669209Swollmanstatic int get_sg_cnt(struct sioc_sg_req *); 2679209Swollmanstatic int get_vif_cnt(struct sioc_vif_req *); 26838482Swollmanstatic int ip_mrouter_init(struct socket *, int); 2692531Swollmanstatic int add_vif(struct vifctl *); 27038482Swollmanstatic int del_vif(vifi_t); 271118622Shsustatic int add_mfc(struct mfcctl2 *); 272118622Shsustatic int del_mfc(struct mfcctl2 *); 273118622Shsustatic int set_api_config(uint32_t *); /* chose API capabilities */ 27412579Sbdestatic int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *); 27538482Swollmanstatic int set_assert(int); 2769209Swollmanstatic void expire_upcalls(void *); 277106968Sluigistatic int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *, vifi_t); 2782531Swollmanstatic void phyint_send(struct ip *, struct vif *, struct mbuf *); 2792531Swollmanstatic void encap_send(struct ip *, struct vif *, struct mbuf *); 28010203Swollmanstatic void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long); 28110203Swollmanstatic void tbf_queue(struct vif *, struct mbuf *); 2829209Swollmanstatic void tbf_process_q(struct vif *); 2839209Swollmanstatic void tbf_reprocess_q(void *); 2849209Swollmanstatic int tbf_dq_sel(struct vif *, struct ip *); 28510203Swollmanstatic void tbf_send_packet(struct vif *, struct mbuf *); 2869209Swollmanstatic void tbf_update_tokens(struct vif *); 2872531Swollmanstatic int priority(struct vif *, struct ip *); 2882531Swollman 2892531Swollman/* 290118622Shsu * Bandwidth monitoring 291118622Shsu */ 292118622Shsustatic void free_bw_list(struct bw_meter *list); 293118622Shsustatic int add_bw_upcall(struct bw_upcall *); 294118622Shsustatic int del_bw_upcall(struct bw_upcall *); 295118622Shsustatic void bw_meter_receive_packet(struct bw_meter *x, int plen, 296118622Shsu struct timeval *nowp); 297118622Shsustatic void bw_meter_prepare_upcall(struct bw_meter *x, struct timeval *nowp); 298118622Shsustatic void bw_upcalls_send(void); 299118622Shsustatic void schedule_bw_meter(struct bw_meter *x, struct timeval *nowp); 300118622Shsustatic void unschedule_bw_meter(struct bw_meter *x); 301118622Shsustatic void bw_meter_process(void); 302118622Shsustatic void expire_bw_upcalls_send(void *); 303118622Shsustatic void expire_bw_meter_process(void *); 304118622Shsu 305118622Shsu#ifdef PIM 306118622Shsustatic int pim_register_send(struct ip *, struct vif *, 307118622Shsu struct mbuf *, struct mfc *); 308118622Shsustatic int pim_register_send_rp(struct ip *, struct vif *, 309118622Shsu struct mbuf *, struct mfc *); 310118622Shsustatic int pim_register_send_upcall(struct ip *, struct vif *, 311118622Shsu struct mbuf *, struct mfc *); 312118622Shsustatic struct mbuf *pim_register_prepare(struct ip *, struct mbuf *); 313118622Shsu#endif 314118622Shsu 315118622Shsu/* 3169209Swollman * whether or not special PIM assert processing is enabled. 3178876Srgrimes */ 3189209Swollmanstatic int pim_assert; 3199209Swollman/* 3209209Swollman * Rate limit for assert notification messages, in usec 3219209Swollman */ 3229209Swollman#define ASSERT_MSG_TIME 3000000 3232531Swollman 3242531Swollman/* 325118622Shsu * Kernel multicast routing API capabilities and setup. 326118622Shsu * If more API capabilities are added to the kernel, they should be 327118622Shsu * recorded in `mrt_api_support'. 328118622Shsu */ 329118622Shsustatic const uint32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF | 330118622Shsu MRT_MFC_FLAGS_BORDER_VIF | 331118622Shsu MRT_MFC_RP | 332118622Shsu MRT_MFC_BW_UPCALL); 333118622Shsustatic uint32_t mrt_api_config = 0; 334118622Shsu 335118622Shsu/* 3369209Swollman * Hash function for a source, group entry 3372531Swollman */ 3389209Swollman#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \ 3399209Swollman ((g) >> 20) ^ ((g) >> 10) ^ (g)) 3402531Swollman 3412531Swollman/* 3422531Swollman * Find a route for a given origin IP address and Multicast group address 3432531Swollman * Type of service parameter to be added in the future!!! 344106968Sluigi * Statistics are updated by the caller if needed 345106968Sluigi * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses) 3462531Swollman */ 347106968Sluigistatic struct mfc * 348106968Sluigimfc_find(in_addr_t o, in_addr_t g) 349106968Sluigi{ 350106968Sluigi struct mfc *rt; 3519209Swollman 352119792Ssam MFC_LOCK_ASSERT(); 353119792Ssam 354106968Sluigi for (rt = mfctable[MFCHASH(o,g)]; rt; rt = rt->mfc_next) 355106968Sluigi if ((rt->mfc_origin.s_addr == o) && 356106968Sluigi (rt->mfc_mcastgrp.s_addr == g) && (rt->mfc_stall == NULL)) 357106968Sluigi break; 358106968Sluigi return rt; 3592531Swollman} 3602531Swollman 3612531Swollman/* 3622531Swollman * Macros to compute elapsed time efficiently 3632531Swollman * Borrowed from Van Jacobson's scheduling code 3642531Swollman */ 365106968Sluigi#define TV_DELTA(a, b, delta) { \ 366106968Sluigi int xxs; \ 367106968Sluigi delta = (a).tv_usec - (b).tv_usec; \ 368106968Sluigi if ((xxs = (a).tv_sec - (b).tv_sec)) { \ 369106968Sluigi switch (xxs) { \ 370106968Sluigi case 2: \ 371106968Sluigi delta += 1000000; \ 372106968Sluigi /* FALLTHROUGH */ \ 373106968Sluigi case 1: \ 374106968Sluigi delta += 1000000; \ 375106968Sluigi break; \ 376106968Sluigi default: \ 377106968Sluigi delta += (1000000 * xxs); \ 378106968Sluigi } \ 379106968Sluigi } \ 3802531Swollman} 3812531Swollman 3822531Swollman#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ 3832531Swollman (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) 3842531Swollman 3852531Swollman/* 3869209Swollman * Handle MRT setsockopt commands to modify the multicast routing tables. 3871541Srgrimes */ 38812296Sphkstatic int 389106968SluigiX_ip_mrouter_set(struct socket *so, struct sockopt *sopt) 3901541Srgrimes{ 391106968Sluigi int error, optval; 392106968Sluigi vifi_t vifi; 393106968Sluigi struct vifctl vifc; 394118622Shsu struct mfcctl2 mfc; 395118622Shsu struct bw_upcall bw_upcall; 396118622Shsu uint32_t i; 3971541Srgrimes 398106968Sluigi if (so != ip_mrouter && sopt->sopt_name != MRT_INIT) 399106968Sluigi return EPERM; 40038482Swollman 401106968Sluigi error = 0; 402106968Sluigi switch (sopt->sopt_name) { 403106968Sluigi case MRT_INIT: 404106968Sluigi error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); 405106968Sluigi if (error) 406106968Sluigi break; 407106968Sluigi error = ip_mrouter_init(so, optval); 408106968Sluigi break; 40938482Swollman 410106968Sluigi case MRT_DONE: 411106968Sluigi error = ip_mrouter_done(); 412106968Sluigi break; 41338482Swollman 414106968Sluigi case MRT_ADD_VIF: 415106968Sluigi error = sooptcopyin(sopt, &vifc, sizeof vifc, sizeof vifc); 416106968Sluigi if (error) 417106968Sluigi break; 418106968Sluigi error = add_vif(&vifc); 419106968Sluigi break; 42038482Swollman 421106968Sluigi case MRT_DEL_VIF: 422106968Sluigi error = sooptcopyin(sopt, &vifi, sizeof vifi, sizeof vifi); 423106968Sluigi if (error) 424106968Sluigi break; 425106968Sluigi error = del_vif(vifi); 426106968Sluigi break; 42738482Swollman 428106968Sluigi case MRT_ADD_MFC: 429106968Sluigi case MRT_DEL_MFC: 430118622Shsu /* 431118622Shsu * select data size depending on API version. 432118622Shsu */ 433118622Shsu if (sopt->sopt_name == MRT_ADD_MFC && 434118622Shsu mrt_api_config & MRT_API_FLAGS_ALL) { 435118622Shsu error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl2), 436118622Shsu sizeof(struct mfcctl2)); 437118622Shsu } else { 438118622Shsu error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl), 439118622Shsu sizeof(struct mfcctl)); 440118622Shsu bzero((caddr_t)&mfc + sizeof(struct mfcctl), 441118622Shsu sizeof(mfc) - sizeof(struct mfcctl)); 442118622Shsu } 443106968Sluigi if (error) 444106968Sluigi break; 445106968Sluigi if (sopt->sopt_name == MRT_ADD_MFC) 446106968Sluigi error = add_mfc(&mfc); 447106968Sluigi else 448106968Sluigi error = del_mfc(&mfc); 449106968Sluigi break; 45038482Swollman 451106968Sluigi case MRT_ASSERT: 452106968Sluigi error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); 453106968Sluigi if (error) 454106968Sluigi break; 455106968Sluigi set_assert(optval); 456106968Sluigi break; 45738482Swollman 458118622Shsu case MRT_API_CONFIG: 459118622Shsu error = sooptcopyin(sopt, &i, sizeof i, sizeof i); 460118622Shsu if (!error) 461118622Shsu error = set_api_config(&i); 462118622Shsu if (!error) 463118622Shsu error = sooptcopyout(sopt, &i, sizeof i); 464118622Shsu break; 465118622Shsu 466118622Shsu case MRT_ADD_BW_UPCALL: 467118622Shsu case MRT_DEL_BW_UPCALL: 468118622Shsu error = sooptcopyin(sopt, &bw_upcall, sizeof bw_upcall, 469118622Shsu sizeof bw_upcall); 470118622Shsu if (error) 471118622Shsu break; 472118622Shsu if (sopt->sopt_name == MRT_ADD_BW_UPCALL) 473118622Shsu error = add_bw_upcall(&bw_upcall); 474118622Shsu else 475118622Shsu error = del_bw_upcall(&bw_upcall); 476118622Shsu break; 477118622Shsu 478106968Sluigi default: 479106968Sluigi error = EOPNOTSUPP; 480106968Sluigi break; 481106968Sluigi } 482106968Sluigi return error; 4832531Swollman} 4841541Srgrimes 4852531Swollman/* 4869209Swollman * Handle MRT getsockopt commands 4879209Swollman */ 48812296Sphkstatic int 489106968SluigiX_ip_mrouter_get(struct socket *so, struct sockopt *sopt) 4909209Swollman{ 491106968Sluigi int error; 492106968Sluigi static int version = 0x0305; /* !!! why is this here? XXX */ 4939209Swollman 494106968Sluigi switch (sopt->sopt_name) { 495106968Sluigi case MRT_VERSION: 496106968Sluigi error = sooptcopyout(sopt, &version, sizeof version); 497106968Sluigi break; 4989209Swollman 499106968Sluigi case MRT_ASSERT: 500106968Sluigi error = sooptcopyout(sopt, &pim_assert, sizeof pim_assert); 501106968Sluigi break; 502106968Sluigi 503118622Shsu case MRT_API_SUPPORT: 504118622Shsu error = sooptcopyout(sopt, &mrt_api_support, sizeof mrt_api_support); 505118622Shsu break; 506118622Shsu 507118622Shsu case MRT_API_CONFIG: 508118622Shsu error = sooptcopyout(sopt, &mrt_api_config, sizeof mrt_api_config); 509118622Shsu break; 510118622Shsu 511106968Sluigi default: 512106968Sluigi error = EOPNOTSUPP; 513106968Sluigi break; 514106968Sluigi } 515106968Sluigi return error; 5169209Swollman} 5179209Swollman 5189209Swollman/* 5192531Swollman * Handle ioctl commands to obtain information from the cache 5202531Swollman */ 52112296Sphkstatic int 522106968SluigiX_mrt_ioctl(int cmd, caddr_t data) 5232531Swollman{ 5242531Swollman int error = 0; 5251541Srgrimes 5262531Swollman switch (cmd) { 527106968Sluigi case (SIOCGETVIFCNT): 528106968Sluigi error = get_vif_cnt((struct sioc_vif_req *)data); 529106968Sluigi break; 530106968Sluigi 531106968Sluigi case (SIOCGETSGCNT): 532106968Sluigi error = get_sg_cnt((struct sioc_sg_req *)data); 533106968Sluigi break; 534106968Sluigi 535106968Sluigi default: 536106968Sluigi error = EINVAL; 537106968Sluigi break; 5382531Swollman } 5392531Swollman return error; 5402531Swollman} 5411541Srgrimes 5422531Swollman/* 5439209Swollman * returns the packet, byte, rpf-failure count for the source group provided 5442531Swollman */ 5459209Swollmanstatic int 546106968Sluigiget_sg_cnt(struct sioc_sg_req *req) 5472531Swollman{ 548106968Sluigi struct mfc *rt; 5491541Srgrimes 550119792Ssam MFC_LOCK(); 551106968Sluigi rt = mfc_find(req->src.s_addr, req->grp.s_addr); 552106968Sluigi if (rt == NULL) { 553119792Ssam MFC_UNLOCK(); 5549209Swollman req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; 555106968Sluigi return EADDRNOTAVAIL; 556106968Sluigi } 557106968Sluigi req->pktcnt = rt->mfc_pkt_cnt; 558106968Sluigi req->bytecnt = rt->mfc_byte_cnt; 559106968Sluigi req->wrong_if = rt->mfc_wrong_if; 560119792Ssam MFC_UNLOCK(); 5612531Swollman return 0; 5622531Swollman} 5631541Srgrimes 5642531Swollman/* 5659209Swollman * returns the input and output packet and byte counts on the vif provided 5662531Swollman */ 5679209Swollmanstatic int 568106968Sluigiget_vif_cnt(struct sioc_vif_req *req) 5692531Swollman{ 570106968Sluigi vifi_t vifi = req->vifi; 5711541Srgrimes 572119792Ssam VIF_LOCK(); 573119792Ssam if (vifi >= numvifs) { 574119792Ssam VIF_UNLOCK(); 575106968Sluigi return EINVAL; 576119792Ssam } 5779209Swollman 5782531Swollman req->icount = viftable[vifi].v_pkt_in; 5792531Swollman req->ocount = viftable[vifi].v_pkt_out; 5809209Swollman req->ibytes = viftable[vifi].v_bytes_in; 5819209Swollman req->obytes = viftable[vifi].v_bytes_out; 582119792Ssam VIF_UNLOCK(); 5831541Srgrimes 5842531Swollman return 0; 5852531Swollman} 5862531Swollman 5871541Srgrimes/* 5881541Srgrimes * Enable multicast routing 5891541Srgrimes */ 59012296Sphkstatic int 591106968Sluigiip_mrouter_init(struct socket *so, int version) 5921541Srgrimes{ 5939209Swollman if (mrtdebug) 594106968Sluigi log(LOG_DEBUG, "ip_mrouter_init: so_type = %d, pr_protocol = %d\n", 595106968Sluigi so->so_type, so->so_proto->pr_protocol); 5969209Swollman 597106968Sluigi if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_IGMP) 598106968Sluigi return EOPNOTSUPP; 5991541Srgrimes 60038482Swollman if (version != 1) 6019209Swollman return ENOPROTOOPT; 6029209Swollman 603106968Sluigi if (ip_mrouter != NULL) 604106968Sluigi return EADDRINUSE; 6051541Srgrimes 6062531Swollman ip_mrouter = so; 6071541Srgrimes 6089209Swollman bzero((caddr_t)mfctable, sizeof(mfctable)); 609119792Ssam MFC_LOCK_INIT(); 610119792Ssam VIF_LOCK_INIT(); 6119209Swollman bzero((caddr_t)nexpire, sizeof(nexpire)); 6129209Swollman 6139209Swollman pim_assert = 0; 6149209Swollman 615119792Ssam callout_init(&expire_upcalls_ch, CALLOUT_MPSAFE); 616119792Ssam callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, NULL); 6179209Swollman 618118622Shsu bw_upcalls_n = 0; 619118622Shsu bzero((caddr_t)bw_meter_timers, sizeof(bw_meter_timers)); 620119792Ssam callout_init(&bw_upcalls_ch, CALLOUT_MPSAFE); 621119792Ssam callout_reset(&bw_upcalls_ch, BW_UPCALLS_PERIOD, 622119792Ssam expire_bw_upcalls_send, NULL); 623119792Ssam callout_init(&bw_meter_ch, CALLOUT_MPSAFE); 624119792Ssam callout_reset(&bw_meter_ch, BW_METER_PERIOD, expire_bw_meter_process, NULL); 625118622Shsu 626119792Ssam callout_init(&tbf_reprocess_ch, CALLOUT_MPSAFE); 627119792Ssam 628118622Shsu mrt_api_config = 0; 629118622Shsu 6302531Swollman if (mrtdebug) 63111284Swollman log(LOG_DEBUG, "ip_mrouter_init\n"); 6322531Swollman 6332531Swollman return 0; 6341541Srgrimes} 6351541Srgrimes 6361541Srgrimes/* 6371541Srgrimes * Disable multicast routing 6381541Srgrimes */ 63912296Sphkstatic int 640106968SluigiX_ip_mrouter_done(void) 6411541Srgrimes{ 6422531Swollman vifi_t vifi; 6432531Swollman int i; 6442531Swollman struct ifnet *ifp; 6452531Swollman struct ifreq ifr; 64642777Sfenner struct mfc *rt; 6472531Swollman struct rtdetq *rte; 6481541Srgrimes 649119792Ssam /* 650119792Ssam * Detach/disable hooks to the reset of the system. 651119792Ssam */ 652119792Ssam ip_mrouter = NULL; 653119792Ssam mrt_api_config = 0; 6541541Srgrimes 655119792Ssam VIF_LOCK(); 656119792Ssam if (encap_cookie) { 657119792Ssam encap_detach(encap_cookie); 658119792Ssam encap_cookie = NULL; 659119792Ssam } 660119792Ssam callout_stop(&tbf_reprocess_ch); 661119792Ssam 6622531Swollman /* 6632531Swollman * For each phyint in use, disable promiscuous reception of all IP 6642531Swollman * multicasts. 6652531Swollman */ 6662531Swollman for (vifi = 0; vifi < numvifs; vifi++) { 6672531Swollman if (viftable[vifi].v_lcl_addr.s_addr != 0 && 668118622Shsu !(viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { 669106968Sluigi struct sockaddr_in *so = (struct sockaddr_in *)&(ifr.ifr_addr); 670106968Sluigi 671106968Sluigi so->sin_len = sizeof(struct sockaddr_in); 672106968Sluigi so->sin_family = AF_INET; 673106968Sluigi so->sin_addr.s_addr = INADDR_ANY; 6742531Swollman ifp = viftable[vifi].v_ifp; 67521666Swollman if_allmulti(ifp, 0); 6762531Swollman } 6772531Swollman } 6782531Swollman bzero((caddr_t)tbftable, sizeof(tbftable)); 6792531Swollman bzero((caddr_t)viftable, sizeof(viftable)); 6802531Swollman numvifs = 0; 6819209Swollman pim_assert = 0; 682119792Ssam VIF_UNLOCK(); 683119792Ssam VIF_LOCK_DESTROY(); 6842531Swollman 6852531Swollman /* 6869209Swollman * Free all multicast forwarding cache entries. 6872531Swollman */ 688119792Ssam MFC_LOCK(); 689119792Ssam callout_stop(&expire_upcalls_ch); 690119792Ssam callout_stop(&bw_upcalls_ch); 691119792Ssam callout_stop(&bw_meter_ch); 692119792Ssam 6939209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 69442777Sfenner for (rt = mfctable[i]; rt != NULL; ) { 69542777Sfenner struct mfc *nr = rt->mfc_next; 69642777Sfenner 69742777Sfenner for (rte = rt->mfc_stall; rte != NULL; ) { 69842777Sfenner struct rtdetq *n = rte->next; 69942777Sfenner 70042777Sfenner m_freem(rte->m); 70142777Sfenner free(rte, M_MRTABLE); 70242777Sfenner rte = n; 7032531Swollman } 704118622Shsu free_bw_list(rt->mfc_bw_meter); 70542777Sfenner free(rt, M_MRTABLE); 70642777Sfenner rt = nr; 7071541Srgrimes } 7089209Swollman } 7092531Swollman bzero((caddr_t)mfctable, sizeof(mfctable)); 710119792Ssam bw_upcalls_n = 0; 711118622Shsu bzero(bw_meter_timers, sizeof(bw_meter_timers)); 712119792Ssam MFC_UNLOCK(); 713119792Ssam MFC_LOCK_DESTROY(); 714118622Shsu 7152531Swollman /* 7162531Swollman * Reset de-encapsulation cache 7172531Swollman */ 718106968Sluigi last_encap_src = INADDR_ANY; 7192531Swollman last_encap_vif = NULL; 720118622Shsu#ifdef PIM 721118622Shsu reg_vif_num = VIFI_INVALID; 722118622Shsu#endif 723118622Shsu 7242531Swollman if (mrtdebug) 72511284Swollman log(LOG_DEBUG, "ip_mrouter_done\n"); 7262531Swollman 7272531Swollman return 0; 7281541Srgrimes} 7291541Srgrimes 7301541Srgrimes/* 7319209Swollman * Set PIM assert processing global 7329209Swollman */ 7339209Swollmanstatic int 734106968Sluigiset_assert(int i) 7359209Swollman{ 73638482Swollman if ((i != 1) && (i != 0)) 7379209Swollman return EINVAL; 7389209Swollman 73938482Swollman pim_assert = i; 7409209Swollman 7419209Swollman return 0; 7429209Swollman} 7439209Swollman 7449209Swollman/* 745118622Shsu * Configure API capabilities 746118622Shsu */ 747118622Shsuint 748118622Shsuset_api_config(uint32_t *apival) 749118622Shsu{ 750118622Shsu int i; 751118622Shsu 752118622Shsu /* 753118622Shsu * We can set the API capabilities only if it is the first operation 754118622Shsu * after MRT_INIT. I.e.: 755118622Shsu * - there are no vifs installed 756118622Shsu * - pim_assert is not enabled 757118622Shsu * - the MFC table is empty 758118622Shsu */ 759118622Shsu if (numvifs > 0) { 760118622Shsu *apival = 0; 761118622Shsu return EPERM; 762118622Shsu } 763118622Shsu if (pim_assert) { 764118622Shsu *apival = 0; 765118622Shsu return EPERM; 766118622Shsu } 767118622Shsu for (i = 0; i < MFCTBLSIZ; i++) { 768118622Shsu if (mfctable[i] != NULL) { 769118622Shsu *apival = 0; 770118622Shsu return EPERM; 771118622Shsu } 772118622Shsu } 773118622Shsu 774118622Shsu mrt_api_config = *apival & mrt_api_support; 775118622Shsu *apival = mrt_api_config; 776118622Shsu 777118622Shsu return 0; 778118622Shsu} 779118622Shsu 780118622Shsu/* 78180354Sfenner * Decide if a packet is from a tunnelled peer. 782106968Sluigi * Return 0 if not, 64 if so. XXX yuck.. 64 ??? 78380354Sfenner */ 78480354Sfennerstatic int 78580354Sfennermroute_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 78680354Sfenner{ 78780354Sfenner struct ip *ip = mtod(m, struct ip *); 78880354Sfenner int hlen = ip->ip_hl << 2; 78980354Sfenner 79080354Sfenner /* 79180354Sfenner * don't claim the packet if it's not to a multicast destination or if 79280354Sfenner * we don't have an encapsulating tunnel with the source. 79380354Sfenner * Note: This code assumes that the remote site IP address 79480354Sfenner * uniquely identifies the tunnel (i.e., that this site has 79580354Sfenner * at most one tunnel with the remote site). 79680354Sfenner */ 797106968Sluigi if (!IN_MULTICAST(ntohl(((struct ip *)((char *)ip+hlen))->ip_dst.s_addr))) 79880354Sfenner return 0; 79980354Sfenner if (ip->ip_src.s_addr != last_encap_src) { 800106968Sluigi struct vif *vifp = viftable; 801106968Sluigi struct vif *vife = vifp + numvifs; 802106968Sluigi 80380354Sfenner last_encap_src = ip->ip_src.s_addr; 804106968Sluigi last_encap_vif = NULL; 80580354Sfenner for ( ; vifp < vife; ++vifp) 80680354Sfenner if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) { 807106968Sluigi if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT)) == VIFF_TUNNEL) 80880354Sfenner last_encap_vif = vifp; 80980354Sfenner break; 81080354Sfenner } 81180354Sfenner } 812106968Sluigi if (last_encap_vif == NULL) { 813106968Sluigi last_encap_src = INADDR_ANY; 81480354Sfenner return 0; 81580354Sfenner } 81680354Sfenner return 64; 81780354Sfenner} 81880354Sfenner 81980354Sfenner/* 82080354Sfenner * De-encapsulate a packet and feed it back through ip input (this 82180354Sfenner * routine is called whenever IP gets a packet that mroute_encap_func() 82280354Sfenner * claimed). 82380354Sfenner */ 82480354Sfennerstatic void 82582884Sjulianmroute_encap_input(struct mbuf *m, int off) 82680354Sfenner{ 82780354Sfenner struct ip *ip = mtod(m, struct ip *); 82880354Sfenner int hlen = ip->ip_hl << 2; 82980354Sfenner 83080354Sfenner if (hlen > sizeof(struct ip)) 831106968Sluigi ip_stripoptions(m, (struct mbuf *) 0); 83280354Sfenner m->m_data += sizeof(struct ip); 83380354Sfenner m->m_len -= sizeof(struct ip); 83480354Sfenner m->m_pkthdr.len -= sizeof(struct ip); 83580354Sfenner 83680354Sfenner m->m_pkthdr.rcvif = last_encap_vif->v_ifp; 83780354Sfenner 838111888Sjlemon netisr_queue(NETISR_IP, m); 839106968Sluigi /* 840106968Sluigi * normally we would need a "schednetisr(NETISR_IP)" 841106968Sluigi * here but we were called by ip_input and it is going 842106968Sluigi * to loop back & try to dequeue the packet we just 843106968Sluigi * queued as soon as we return so we avoid the 844106968Sluigi * unnecessary software interrrupt. 845111888Sjlemon * 846111888Sjlemon * XXX 847111888Sjlemon * This no longer holds - we may have direct-dispatched the packet, 848111888Sjlemon * or there may be a queue processing limit. 849106968Sluigi */ 85080354Sfenner} 85180354Sfenner 85280354Sfennerextern struct domain inetdomain; 85382884Sjulianstatic struct protosw mroute_encap_protosw = 85480354Sfenner{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, 85580354Sfenner mroute_encap_input, 0, 0, rip_ctloutput, 85680354Sfenner 0, 85780354Sfenner 0, 0, 0, 0, 85880354Sfenner &rip_usrreqs 85980354Sfenner}; 86080354Sfenner 86180354Sfenner/* 8621541Srgrimes * Add a vif to the vif table 8631541Srgrimes */ 8641541Srgrimesstatic int 865106968Sluigiadd_vif(struct vifctl *vifcp) 8661541Srgrimes{ 867106968Sluigi struct vif *vifp = viftable + vifcp->vifc_vifi; 868106968Sluigi struct sockaddr_in sin = {sizeof sin, AF_INET}; 8692531Swollman struct ifaddr *ifa; 8702531Swollman struct ifnet *ifp; 871119792Ssam int error; 8722531Swollman struct tbf *v_tbf = tbftable + vifcp->vifc_vifi; 8731541Srgrimes 874119792Ssam VIF_LOCK(); 875119792Ssam if (vifcp->vifc_vifi >= MAXVIFS) { 876119792Ssam VIF_UNLOCK(); 877106968Sluigi return EINVAL; 878119792Ssam } 879119792Ssam if (vifp->v_lcl_addr.s_addr != INADDR_ANY) { 880119792Ssam VIF_UNLOCK(); 881106968Sluigi return EADDRINUSE; 882119792Ssam } 883119792Ssam if (vifcp->vifc_lcl_addr.s_addr == INADDR_ANY) { 884119792Ssam VIF_UNLOCK(); 885106968Sluigi return EADDRNOTAVAIL; 886119792Ssam } 8871541Srgrimes 8882531Swollman /* Find the interface with an address in AF_INET family */ 889118622Shsu#ifdef PIM 890118622Shsu if (vifcp->vifc_flags & VIFF_REGISTER) { 891118622Shsu /* 892118622Shsu * XXX: Because VIFF_REGISTER does not really need a valid 893118622Shsu * local interface (e.g. it could be 127.0.0.2), we don't 894118622Shsu * check its address. 895118622Shsu */ 896118622Shsu ifp = NULL; 897118622Shsu } else 898118622Shsu#endif 899118622Shsu { 900118622Shsu sin.sin_addr = vifcp->vifc_lcl_addr; 901118622Shsu ifa = ifa_ifwithaddr((struct sockaddr *)&sin); 902119792Ssam if (ifa == NULL) { 903119792Ssam VIF_UNLOCK(); 904118622Shsu return EADDRNOTAVAIL; 905119792Ssam } 906118622Shsu ifp = ifa->ifa_ifp; 907118622Shsu } 9081541Srgrimes 9092531Swollman if (vifcp->vifc_flags & VIFF_TUNNEL) { 9102531Swollman if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) { 911106968Sluigi /* 912106968Sluigi * An encapsulating tunnel is wanted. Tell 913106968Sluigi * mroute_encap_input() to start paying attention 914106968Sluigi * to encapsulated packets. 915106968Sluigi */ 916106968Sluigi if (encap_cookie == NULL) { 917119792Ssam int i; 918119792Ssam 919106968Sluigi encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV4, 92080354Sfenner mroute_encapcheck, 92180354Sfenner (struct protosw *)&mroute_encap_protosw, NULL); 92280354Sfenner 923106968Sluigi if (encap_cookie == NULL) { 924106968Sluigi printf("ip_mroute: unable to attach encap\n"); 925119792Ssam VIF_UNLOCK(); 926106968Sluigi return EIO; /* XXX */ 9271541Srgrimes } 928119792Ssam for (i = 0; i < MAXVIFS; ++i) { 929119792Ssam multicast_decap_if[i].if_name = "mdecap"; 930119792Ssam multicast_decap_if[i].if_unit = i; 931106968Sluigi } 932106968Sluigi } 933106968Sluigi /* 934106968Sluigi * Set interface to fake encapsulator interface 935106968Sluigi */ 936106968Sluigi ifp = &multicast_decap_if[vifcp->vifc_vifi]; 937106968Sluigi /* 938106968Sluigi * Prepare cached route entry 939106968Sluigi */ 940106968Sluigi bzero(&vifp->v_route, sizeof(vifp->v_route)); 9412531Swollman } else { 94211284Swollman log(LOG_ERR, "source routed tunnels not supported\n"); 943119792Ssam VIF_UNLOCK(); 9449209Swollman return EOPNOTSUPP; 9451541Srgrimes } 946118622Shsu#ifdef PIM 947118622Shsu } else if (vifcp->vifc_flags & VIFF_REGISTER) { 948118622Shsu ifp = &multicast_register_if; 949118622Shsu if (mrtdebug) 950118622Shsu log(LOG_DEBUG, "Adding a register vif, ifp: %p\n", 951118622Shsu (void *)&multicast_register_if); 952118622Shsu if (reg_vif_num == VIFI_INVALID) { 953118622Shsu multicast_register_if.if_name = "register_vif"; 954118622Shsu multicast_register_if.if_unit = 0; 955118622Shsu multicast_register_if.if_flags = IFF_LOOPBACK; 956118622Shsu bzero(&vifp->v_route, sizeof(vifp->v_route)); 957118622Shsu reg_vif_num = vifcp->vifc_vifi; 958118622Shsu } 959118622Shsu#endif 960106968Sluigi } else { /* Make sure the interface supports multicast */ 961119792Ssam if ((ifp->if_flags & IFF_MULTICAST) == 0) { 962119792Ssam VIF_UNLOCK(); 9632531Swollman return EOPNOTSUPP; 964119792Ssam } 9651541Srgrimes 9662531Swollman /* Enable promiscuous reception of all IP multicasts from the if */ 96722967Swollman error = if_allmulti(ifp, 1); 968119792Ssam if (error) { 969119792Ssam VIF_UNLOCK(); 9702531Swollman return error; 971119792Ssam } 9722531Swollman } 9731541Srgrimes 9742531Swollman /* define parameters for the tbf structure */ 9752531Swollman vifp->v_tbf = v_tbf; 97610203Swollman GET_TIME(vifp->v_tbf->tbf_last_pkt_t); 97710203Swollman vifp->v_tbf->tbf_n_tok = 0; 97810203Swollman vifp->v_tbf->tbf_q_len = 0; 97910203Swollman vifp->v_tbf->tbf_max_q_len = MAXQSIZE; 98010203Swollman vifp->v_tbf->tbf_q = vifp->v_tbf->tbf_t = NULL; 9811541Srgrimes 9822531Swollman vifp->v_flags = vifcp->vifc_flags; 9832531Swollman vifp->v_threshold = vifcp->vifc_threshold; 9842531Swollman vifp->v_lcl_addr = vifcp->vifc_lcl_addr; 9852531Swollman vifp->v_rmt_addr = vifcp->vifc_rmt_addr; 9862531Swollman vifp->v_ifp = ifp; 98710203Swollman /* scaling up here allows division by 1024 in critical code */ 98810203Swollman vifp->v_rate_limit= vifcp->vifc_rate_limit * 1024 / 1000; 9899209Swollman vifp->v_rsvp_on = 0; 9909209Swollman vifp->v_rsvpd = NULL; 9912531Swollman /* initialize per vif pkt counters */ 9922531Swollman vifp->v_pkt_in = 0; 9932531Swollman vifp->v_pkt_out = 0; 9949209Swollman vifp->v_bytes_in = 0; 9959209Swollman vifp->v_bytes_out = 0; 9962531Swollman 9972531Swollman /* Adjust numvifs up if the vifi is higher than numvifs */ 9982531Swollman if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1; 9992531Swollman 1000119792Ssam VIF_UNLOCK(); 1001119792Ssam 10022531Swollman if (mrtdebug) 100338373Sbde log(LOG_DEBUG, "add_vif #%d, lcladdr %lx, %s %lx, thresh %x, rate %d\n", 10049209Swollman vifcp->vifc_vifi, 100538373Sbde (u_long)ntohl(vifcp->vifc_lcl_addr.s_addr), 10062531Swollman (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask", 100738373Sbde (u_long)ntohl(vifcp->vifc_rmt_addr.s_addr), 10082531Swollman vifcp->vifc_threshold, 10099209Swollman vifcp->vifc_rate_limit); 10102531Swollman 10112531Swollman return 0; 10121541Srgrimes} 10131541Srgrimes 10141541Srgrimes/* 10151541Srgrimes * Delete a vif from the vif table 10161541Srgrimes */ 10171541Srgrimesstatic int 1018106968Sluigidel_vif(vifi_t vifi) 10191541Srgrimes{ 1020106968Sluigi struct vif *vifp; 10211541Srgrimes 1022119792Ssam VIF_LOCK(); 1023119792Ssam 1024119792Ssam if (vifi >= numvifs) { 1025119792Ssam VIF_UNLOCK(); 1026106968Sluigi return EINVAL; 1027119792Ssam } 1028106968Sluigi vifp = &viftable[vifi]; 1029119792Ssam if (vifp->v_lcl_addr.s_addr == INADDR_ANY) { 1030119792Ssam VIF_UNLOCK(); 1031106968Sluigi return EADDRNOTAVAIL; 1032119792Ssam } 10331541Srgrimes 1034118622Shsu if (!(vifp->v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) 1035106968Sluigi if_allmulti(vifp->v_ifp, 0); 10361541Srgrimes 10372531Swollman if (vifp == last_encap_vif) { 1038106968Sluigi last_encap_vif = NULL; 1039106968Sluigi last_encap_src = INADDR_ANY; 10402531Swollman } 10411541Srgrimes 104210203Swollman /* 104310203Swollman * Free packets queued at the interface 104410203Swollman */ 104510203Swollman while (vifp->v_tbf->tbf_q) { 1046106968Sluigi struct mbuf *m = vifp->v_tbf->tbf_q; 1047106968Sluigi 104810203Swollman vifp->v_tbf->tbf_q = m->m_act; 104910203Swollman m_freem(m); 105010203Swollman } 105110203Swollman 1052118622Shsu#ifdef PIM 1053118622Shsu if (vifp->v_flags & VIFF_REGISTER) 1054118622Shsu reg_vif_num = VIFI_INVALID; 1055118622Shsu#endif 1056118622Shsu 10572531Swollman bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf))); 10582531Swollman bzero((caddr_t)vifp, sizeof (*vifp)); 10591541Srgrimes 106038482Swollman if (mrtdebug) 1061106968Sluigi log(LOG_DEBUG, "del_vif %d, numvifs %d\n", vifi, numvifs); 106238482Swollman 10632531Swollman /* Adjust numvifs down */ 10642531Swollman for (vifi = numvifs; vifi > 0; vifi--) 1065106968Sluigi if (viftable[vifi-1].v_lcl_addr.s_addr != INADDR_ANY) 1066106968Sluigi break; 10672531Swollman numvifs = vifi; 10682531Swollman 1069119792Ssam VIF_UNLOCK(); 10702531Swollman 10712531Swollman return 0; 10721541Srgrimes} 10731541Srgrimes 10741541Srgrimes/* 1075106968Sluigi * update an mfc entry without resetting counters and S,G addresses. 1076106968Sluigi */ 1077106968Sluigistatic void 1078118622Shsuupdate_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp) 1079106968Sluigi{ 1080106968Sluigi int i; 1081106968Sluigi 1082106968Sluigi rt->mfc_parent = mfccp->mfcc_parent; 1083118622Shsu for (i = 0; i < numvifs; i++) { 1084106968Sluigi rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 1085118622Shsu rt->mfc_flags[i] = mfccp->mfcc_flags[i] & mrt_api_config & 1086118622Shsu MRT_MFC_FLAGS_ALL; 1087118622Shsu } 1088118622Shsu /* set the RP address */ 1089118622Shsu if (mrt_api_config & MRT_MFC_RP) 1090118622Shsu rt->mfc_rp = mfccp->mfcc_rp; 1091118622Shsu else 1092118622Shsu rt->mfc_rp.s_addr = INADDR_ANY; 1093106968Sluigi} 1094106968Sluigi 1095106968Sluigi/* 1096106968Sluigi * fully initialize an mfc entry from the parameter. 1097106968Sluigi */ 1098106968Sluigistatic void 1099118622Shsuinit_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp) 1100106968Sluigi{ 1101106968Sluigi rt->mfc_origin = mfccp->mfcc_origin; 1102106968Sluigi rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 1103106968Sluigi 1104106968Sluigi update_mfc_params(rt, mfccp); 1105106968Sluigi 1106106968Sluigi /* initialize pkt counters per src-grp */ 1107106968Sluigi rt->mfc_pkt_cnt = 0; 1108106968Sluigi rt->mfc_byte_cnt = 0; 1109106968Sluigi rt->mfc_wrong_if = 0; 1110106968Sluigi rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 1111106968Sluigi} 1112106968Sluigi 1113106968Sluigi 1114106968Sluigi/* 11152531Swollman * Add an mfc entry 11161541Srgrimes */ 11171541Srgrimesstatic int 1118118622Shsuadd_mfc(struct mfcctl2 *mfccp) 11191541Srgrimes{ 11202531Swollman struct mfc *rt; 11212531Swollman u_long hash; 11222531Swollman struct rtdetq *rte; 1123106968Sluigi u_short nstl; 11241541Srgrimes 1125119792Ssam VIF_LOCK(); 1126119792Ssam MFC_LOCK(); 1127119792Ssam 1128106968Sluigi rt = mfc_find(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); 11291541Srgrimes 11302531Swollman /* If an entry already exists, just update the fields */ 11312531Swollman if (rt) { 11329209Swollman if (mrtdebug & DEBUG_MFC) 113338373Sbde log(LOG_DEBUG,"add_mfc update o %lx g %lx p %x\n", 113438373Sbde (u_long)ntohl(mfccp->mfcc_origin.s_addr), 113538373Sbde (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), 11362531Swollman mfccp->mfcc_parent); 11371541Srgrimes 1138106968Sluigi update_mfc_params(rt, mfccp); 1139119792Ssam MFC_UNLOCK(); 1140119792Ssam VIF_UNLOCK(); 11412531Swollman return 0; 11422531Swollman } 11431541Srgrimes 11449209Swollman /* 11452531Swollman * Find the entry for which the upcall was made and update 11462531Swollman */ 11479209Swollman hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); 114842777Sfenner for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) { 11491541Srgrimes 11509209Swollman if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && 1151106968Sluigi (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) && 1152106968Sluigi (rt->mfc_stall != NULL)) { 11539209Swollman 11549209Swollman if (nstl++) 115538373Sbde log(LOG_ERR, "add_mfc %s o %lx g %lx p %x dbx %p\n", 11569209Swollman "multiple kernel entries", 115738373Sbde (u_long)ntohl(mfccp->mfcc_origin.s_addr), 115838373Sbde (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), 115942777Sfenner mfccp->mfcc_parent, (void *)rt->mfc_stall); 11601541Srgrimes 11619209Swollman if (mrtdebug & DEBUG_MFC) 116238373Sbde log(LOG_DEBUG,"add_mfc o %lx g %lx p %x dbg %p\n", 116338373Sbde (u_long)ntohl(mfccp->mfcc_origin.s_addr), 116438373Sbde (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), 116542777Sfenner mfccp->mfcc_parent, (void *)rt->mfc_stall); 11661541Srgrimes 1167106968Sluigi init_mfc_params(rt, mfccp); 11682531Swollman 11699209Swollman rt->mfc_expire = 0; /* Don't clean this guy up */ 11709209Swollman nexpire[hash]--; 11712531Swollman 11722531Swollman /* free packets Qed at the end of this entry */ 117342777Sfenner for (rte = rt->mfc_stall; rte != NULL; ) { 117442777Sfenner struct rtdetq *n = rte->next; 117542777Sfenner 11769209Swollman ip_mdq(rte->m, rte->ifp, rt, -1); 11772531Swollman m_freem(rte->m); 117842777Sfenner free(rte, M_MRTABLE); 117942777Sfenner rte = n; 11802531Swollman } 118142777Sfenner rt->mfc_stall = NULL; 11821541Srgrimes } 11832531Swollman } 11841541Srgrimes 11852531Swollman /* 11862531Swollman * It is possible that an entry is being inserted without an upcall 11872531Swollman */ 11882531Swollman if (nstl == 0) { 11899209Swollman if (mrtdebug & DEBUG_MFC) 119038373Sbde log(LOG_DEBUG,"add_mfc no upcall h %lu o %lx g %lx p %x\n", 119138373Sbde hash, (u_long)ntohl(mfccp->mfcc_origin.s_addr), 119238373Sbde (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), 11932531Swollman mfccp->mfcc_parent); 11949209Swollman 119542777Sfenner for (rt = mfctable[hash]; rt != NULL; rt = rt->mfc_next) { 11969209Swollman if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && 1197106968Sluigi (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) { 1198106968Sluigi init_mfc_params(rt, mfccp); 11999209Swollman if (rt->mfc_expire) 12009209Swollman nexpire[hash]--; 1201106968Sluigi rt->mfc_expire = 0; 1202106968Sluigi break; /* XXX */ 12032531Swollman } 12042531Swollman } 1205106968Sluigi if (rt == NULL) { /* no upcall, so make a new entry */ 120642777Sfenner rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT); 120742777Sfenner if (rt == NULL) { 1208119792Ssam MFC_UNLOCK(); 1209119792Ssam VIF_UNLOCK(); 12102531Swollman return ENOBUFS; 12112531Swollman } 12129209Swollman 1213106968Sluigi init_mfc_params(rt, mfccp); 12149209Swollman rt->mfc_expire = 0; 121542777Sfenner rt->mfc_stall = NULL; 12169209Swollman 1217118622Shsu rt->mfc_bw_meter = NULL; 1218106968Sluigi /* insert new entry at head of hash chain */ 121942777Sfenner rt->mfc_next = mfctable[hash]; 122042777Sfenner mfctable[hash] = rt; 12212531Swollman } 12222531Swollman } 1223119792Ssam MFC_UNLOCK(); 1224119792Ssam VIF_UNLOCK(); 12252531Swollman return 0; 12261541Srgrimes} 12271541Srgrimes 12281541Srgrimes/* 12292531Swollman * Delete an mfc entry 12301541Srgrimes */ 12311541Srgrimesstatic int 1232118622Shsudel_mfc(struct mfcctl2 *mfccp) 12331541Srgrimes{ 12342531Swollman struct in_addr origin; 12352531Swollman struct in_addr mcastgrp; 12362531Swollman struct mfc *rt; 123742777Sfenner struct mfc **nptr; 12382531Swollman u_long hash; 1239118622Shsu struct bw_meter *list; 12401541Srgrimes 12412531Swollman origin = mfccp->mfcc_origin; 12422531Swollman mcastgrp = mfccp->mfcc_mcastgrp; 12431541Srgrimes 12449209Swollman if (mrtdebug & DEBUG_MFC) 124538373Sbde log(LOG_DEBUG,"del_mfc orig %lx mcastgrp %lx\n", 124638373Sbde (u_long)ntohl(origin.s_addr), (u_long)ntohl(mcastgrp.s_addr)); 12471541Srgrimes 1248119792Ssam MFC_LOCK(); 12499209Swollman 1250106968Sluigi hash = MFCHASH(origin.s_addr, mcastgrp.s_addr); 1251106968Sluigi for (nptr = &mfctable[hash]; (rt = *nptr) != NULL; nptr = &rt->mfc_next) 12522531Swollman if (origin.s_addr == rt->mfc_origin.s_addr && 1253106968Sluigi mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr && 1254106968Sluigi rt->mfc_stall == NULL) 12552531Swollman break; 125642777Sfenner if (rt == NULL) { 1257119792Ssam MFC_UNLOCK(); 12589209Swollman return EADDRNOTAVAIL; 12592531Swollman } 12601541Srgrimes 126142777Sfenner *nptr = rt->mfc_next; 1262118622Shsu 1263118622Shsu /* 1264118622Shsu * free the bw_meter entries 1265118622Shsu */ 1266118622Shsu list = rt->mfc_bw_meter; 1267118622Shsu rt->mfc_bw_meter = NULL; 1268118622Shsu 126942777Sfenner free(rt, M_MRTABLE); 12701541Srgrimes 1271118622Shsu free_bw_list(list); 1272118622Shsu 1273119792Ssam MFC_UNLOCK(); 1274119792Ssam 12752531Swollman return 0; 12761541Srgrimes} 12771541Srgrimes 12781541Srgrimes/* 12799209Swollman * Send a message to mrouted on the multicast routing socket 12809209Swollman */ 12819209Swollmanstatic int 1282106968Sluigisocket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src) 12839209Swollman{ 1284106968Sluigi if (s) { 1285106968Sluigi if (sbappendaddr(&s->so_rcv, (struct sockaddr *)src, mm, NULL) != 0) { 1286106968Sluigi sorwakeup(s); 1287106968Sluigi return 0; 12889209Swollman } 1289106968Sluigi } 1290106968Sluigi m_freem(mm); 1291106968Sluigi return -1; 12929209Swollman} 12939209Swollman 12949209Swollman/* 12952531Swollman * IP multicast forwarding function. This function assumes that the packet 12962531Swollman * pointed to by "ip" has arrived on (or is about to be sent to) the interface 12972531Swollman * pointed to by "ifp", and the packet is to be relayed to other networks 12982531Swollman * that have members of the packet's destination IP multicast group. 12992531Swollman * 13009209Swollman * The packet is returned unscathed to the caller, unless it is 13019209Swollman * erroneous, in which case a non-zero return value tells the caller to 13022531Swollman * discard it. 13031541Srgrimes */ 13042531Swollman 13052531Swollman#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */ 13062531Swollman 130712296Sphkstatic int 1308118622ShsuX_ip_mforward(struct ip *ip, struct ifnet *ifp, struct mbuf *m, 1309118622Shsu struct ip_moptions *imo) 13101541Srgrimes{ 1311106968Sluigi struct mfc *rt; 1312119792Ssam int error; 13139209Swollman vifi_t vifi; 13141541Srgrimes 13159209Swollman if (mrtdebug & DEBUG_FORWARD) 131638373Sbde log(LOG_DEBUG, "ip_mforward: src %lx, dst %lx, ifp %p\n", 131738373Sbde (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr), 131838373Sbde (void *)ifp); 13191541Srgrimes 132080354Sfenner if (ip->ip_hl < (sizeof(struct ip) + TUNNEL_LEN) >> 2 || 1321106968Sluigi ((u_char *)(ip + 1))[1] != IPOPT_LSRR ) { 13222531Swollman /* 13239209Swollman * Packet arrived via a physical interface or 1324118622Shsu * an encapsulated tunnel or a register_vif. 13252531Swollman */ 13262531Swollman } else { 13272531Swollman /* 13282531Swollman * Packet arrived through a source-route tunnel. 13299209Swollman * Source-route tunnels are no longer supported. 13302531Swollman */ 1331106968Sluigi static int last_log; 1332106968Sluigi if (last_log != time_second) { 1333106968Sluigi last_log = time_second; 133438373Sbde log(LOG_ERR, 133538373Sbde "ip_mforward: received source-routed packet from %lx\n", 133638373Sbde (u_long)ntohl(ip->ip_src.s_addr)); 1337106968Sluigi } 13389209Swollman return 1; 13399209Swollman } 13409209Swollman 1341119792Ssam VIF_LOCK(); 1342119792Ssam MFC_LOCK(); 1343118622Shsu if (imo && ((vifi = imo->imo_multicast_vif) < numvifs)) { 13449209Swollman if (ip->ip_ttl < 255) 1345106968Sluigi ip->ip_ttl++; /* compensate for -1 in *_send routines */ 13469209Swollman if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { 1347106968Sluigi struct vif *vifp = viftable + vifi; 1348106968Sluigi 134912296Sphk printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s%d)\n", 135085658Sdillon (long)ntohl(ip->ip_src.s_addr), (long)ntohl(ip->ip_dst.s_addr), 135185658Sdillon vifi, 13529209Swollman (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "", 13539209Swollman vifp->v_ifp->if_name, vifp->v_ifp->if_unit); 13542531Swollman } 1355119792Ssam error = ip_mdq(m, ifp, NULL, vifi); 1356119792Ssam MFC_UNLOCK(); 1357119792Ssam VIF_UNLOCK(); 1358119792Ssam return error; 13592531Swollman } 13609209Swollman if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { 136112296Sphk printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n", 136285658Sdillon (long)ntohl(ip->ip_src.s_addr), (long)ntohl(ip->ip_dst.s_addr)); 1363106968Sluigi if (!imo) 1364106968Sluigi printf("In fact, no options were specified at all\n"); 13659209Swollman } 13662531Swollman 13672531Swollman /* 13682531Swollman * Don't forward a packet with time-to-live of zero or one, 13692531Swollman * or a packet destined to a local-only group. 13702531Swollman */ 1371119792Ssam if (ip->ip_ttl <= 1 || ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP) { 1372119792Ssam MFC_UNLOCK(); 1373119792Ssam VIF_UNLOCK(); 13749209Swollman return 0; 1375119792Ssam } 13762531Swollman 13772531Swollman /* 13782531Swollman * Determine forwarding vifs from the forwarding cache table 13792531Swollman */ 1380106968Sluigi ++mrtstat.mrts_mfc_lookups; 1381106968Sluigi rt = mfc_find(ip->ip_src.s_addr, ip->ip_dst.s_addr); 13822531Swollman 13832531Swollman /* Entry exists, so forward if necessary */ 13842531Swollman if (rt != NULL) { 1385119792Ssam error = ip_mdq(m, ifp, rt, -1); 1386119792Ssam MFC_UNLOCK(); 1387119792Ssam VIF_UNLOCK(); 1388119792Ssam return error; 13899209Swollman } else { 13902531Swollman /* 13912531Swollman * If we don't have a route for packet's origin, 1392106968Sluigi * Make a copy of the packet & send message to routing daemon 13932531Swollman */ 13942531Swollman 1395106968Sluigi struct mbuf *mb0; 1396106968Sluigi struct rtdetq *rte; 1397106968Sluigi u_long hash; 139814549Sfenner int hlen = ip->ip_hl << 2; 13992531Swollman 1400106968Sluigi ++mrtstat.mrts_mfc_misses; 14019209Swollman 14022531Swollman mrtstat.mrts_no_route++; 14039209Swollman if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) 140438373Sbde log(LOG_DEBUG, "ip_mforward: no rte s %lx g %lx\n", 140538373Sbde (u_long)ntohl(ip->ip_src.s_addr), 140638373Sbde (u_long)ntohl(ip->ip_dst.s_addr)); 14072531Swollman 14089209Swollman /* 14099209Swollman * Allocate mbufs early so that we don't do extra work if we are 141014549Sfenner * just going to fail anyway. Make sure to pullup the header so 141114549Sfenner * that other people can't step on it. 14129209Swollman */ 141342777Sfenner rte = (struct rtdetq *)malloc((sizeof *rte), M_MRTABLE, M_NOWAIT); 141442777Sfenner if (rte == NULL) { 1415119792Ssam MFC_UNLOCK(); 1416119792Ssam VIF_UNLOCK(); 14179209Swollman return ENOBUFS; 14189209Swollman } 1419118622Shsu mb0 = m_copypacket(m, M_DONTWAIT); 142014549Sfenner if (mb0 && (M_HASCL(mb0) || mb0->m_len < hlen)) 142114549Sfenner mb0 = m_pullup(mb0, hlen); 14229209Swollman if (mb0 == NULL) { 142342777Sfenner free(rte, M_MRTABLE); 1424119792Ssam MFC_UNLOCK(); 1425119792Ssam VIF_UNLOCK(); 14269209Swollman return ENOBUFS; 14279209Swollman } 14289209Swollman 1429106968Sluigi /* is there an upcall waiting for this flow ? */ 14309209Swollman hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); 143142777Sfenner for (rt = mfctable[hash]; rt; rt = rt->mfc_next) { 14329209Swollman if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && 1433106968Sluigi (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && 1434106968Sluigi (rt->mfc_stall != NULL)) 14352531Swollman break; 14362531Swollman } 14372531Swollman 143842777Sfenner if (rt == NULL) { 14399209Swollman int i; 14409209Swollman struct igmpmsg *im; 1441106968Sluigi struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; 1442106968Sluigi struct mbuf *mm; 14439209Swollman 1444106968Sluigi /* 1445106968Sluigi * Locate the vifi for the incoming interface for this packet. 1446106968Sluigi * If none found, drop packet. 1447106968Sluigi */ 1448118501Shsu for (vifi=0; vifi < numvifs && viftable[vifi].v_ifp != ifp; vifi++) 1449106968Sluigi ; 1450118501Shsu if (vifi >= numvifs) /* vif not found, drop packet */ 1451106968Sluigi goto non_fatal; 1452106968Sluigi 14532531Swollman /* no upcall, so make a new entry */ 145442777Sfenner rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT); 1455106968Sluigi if (rt == NULL) 1456106968Sluigi goto fail; 14579209Swollman /* Make a copy of the header to send to the user level process */ 145817137Sfenner mm = m_copy(mb0, 0, hlen); 1459106968Sluigi if (mm == NULL) 1460106968Sluigi goto fail1; 14612531Swollman 14629209Swollman /* 14639209Swollman * Send message to routing daemon to install 14649209Swollman * a route into the kernel table 14659209Swollman */ 14669209Swollman 14679209Swollman im = mtod(mm, struct igmpmsg *); 1468106968Sluigi im->im_msgtype = IGMPMSG_NOCACHE; 1469106968Sluigi im->im_mbz = 0; 1470106968Sluigi im->im_vif = vifi; 14719209Swollman 14729209Swollman mrtstat.mrts_upcalls++; 14739209Swollman 1474106968Sluigi k_igmpsrc.sin_addr = ip->ip_src; 14759209Swollman if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) { 147611284Swollman log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n"); 14779209Swollman ++mrtstat.mrts_upq_sockfull; 1478106968Sluigifail1: 1479106968Sluigi free(rt, M_MRTABLE); 1480106968Sluigifail: 148142777Sfenner free(rte, M_MRTABLE); 14829266Swollman m_freem(mb0); 1483119792Ssam MFC_UNLOCK(); 1484119792Ssam VIF_UNLOCK(); 14859209Swollman return ENOBUFS; 14869209Swollman } 14879209Swollman 14882531Swollman /* insert new entry at head of hash chain */ 14892531Swollman rt->mfc_origin.s_addr = ip->ip_src.s_addr; 14902531Swollman rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; 14919209Swollman rt->mfc_expire = UPCALL_EXPIRE; 14929209Swollman nexpire[hash]++; 1493118622Shsu for (i = 0; i < numvifs; i++) { 14949209Swollman rt->mfc_ttls[i] = 0; 1495118622Shsu rt->mfc_flags[i] = 0; 1496118622Shsu } 14979209Swollman rt->mfc_parent = -1; 14982531Swollman 1499118622Shsu rt->mfc_rp.s_addr = INADDR_ANY; /* clear the RP address */ 1500118622Shsu 1501118622Shsu rt->mfc_bw_meter = NULL; 1502118622Shsu 15032531Swollman /* link into table */ 150442777Sfenner rt->mfc_next = mfctable[hash]; 150542777Sfenner mfctable[hash] = rt; 150642777Sfenner rt->mfc_stall = rte; 15072531Swollman 15089209Swollman } else { 15099209Swollman /* determine if q has overflowed */ 151042777Sfenner int npkts = 0; 151142777Sfenner struct rtdetq **p; 151242777Sfenner 1513106968Sluigi /* 1514106968Sluigi * XXX ouch! we need to append to the list, but we 1515106968Sluigi * only have a pointer to the front, so we have to 1516106968Sluigi * scan the entire list every time. 1517106968Sluigi */ 151842777Sfenner for (p = &rt->mfc_stall; *p != NULL; p = &(*p)->next) 15199209Swollman npkts++; 15202531Swollman 15219209Swollman if (npkts > MAX_UPQ) { 15229209Swollman mrtstat.mrts_upq_ovflw++; 1523106968Sluiginon_fatal: 152442777Sfenner free(rte, M_MRTABLE); 15259266Swollman m_freem(mb0); 1526119792Ssam MFC_UNLOCK(); 1527119792Ssam VIF_UNLOCK(); 15289209Swollman return 0; 15299209Swollman } 153042777Sfenner 153142777Sfenner /* Add this entry to the end of the queue */ 153242777Sfenner *p = rte; 15332531Swollman } 15342531Swollman 15352531Swollman rte->m = mb0; 15362531Swollman rte->ifp = ifp; 153742777Sfenner rte->next = NULL; 15382531Swollman 1539119792Ssam MFC_UNLOCK(); 1540119792Ssam VIF_UNLOCK(); 15412531Swollman 15422531Swollman return 0; 15439209Swollman } 15441541Srgrimes} 15451541Srgrimes 15461541Srgrimes/* 15472531Swollman * Clean up the cache entry if upcall is not serviced 15481541Srgrimes */ 15492531Swollmanstatic void 15509209Swollmanexpire_upcalls(void *unused) 15511541Srgrimes{ 15522531Swollman struct rtdetq *rte; 155342777Sfenner struct mfc *mfc, **nptr; 15549209Swollman int i; 15551541Srgrimes 1556119792Ssam MFC_LOCK(); 15579209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 15589209Swollman if (nexpire[i] == 0) 15599209Swollman continue; 15609209Swollman nptr = &mfctable[i]; 156142777Sfenner for (mfc = *nptr; mfc != NULL; mfc = *nptr) { 15629209Swollman /* 15639209Swollman * Skip real cache entries 15649209Swollman * Make sure it wasn't marked to not expire (shouldn't happen) 15659209Swollman * If it expires now 15669209Swollman */ 1567106968Sluigi if (mfc->mfc_stall != NULL && mfc->mfc_expire != 0 && 1568106968Sluigi --mfc->mfc_expire == 0) { 15699209Swollman if (mrtdebug & DEBUG_EXPIRE) 157038373Sbde log(LOG_DEBUG, "expire_upcalls: expiring (%lx %lx)\n", 157138373Sbde (u_long)ntohl(mfc->mfc_origin.s_addr), 157238373Sbde (u_long)ntohl(mfc->mfc_mcastgrp.s_addr)); 15739209Swollman /* 15749209Swollman * drop all the packets 15759209Swollman * free the mbuf with the pkt, if, timing info 15769209Swollman */ 157742777Sfenner for (rte = mfc->mfc_stall; rte; ) { 157842777Sfenner struct rtdetq *n = rte->next; 157942777Sfenner 15809209Swollman m_freem(rte->m); 158142777Sfenner free(rte, M_MRTABLE); 158242777Sfenner rte = n; 15839209Swollman } 15849209Swollman ++mrtstat.mrts_cache_cleanups; 15859209Swollman nexpire[i]--; 15862531Swollman 1587118622Shsu /* 1588118622Shsu * free the bw_meter entries 1589118622Shsu */ 1590118622Shsu while (mfc->mfc_bw_meter != NULL) { 1591118622Shsu struct bw_meter *x = mfc->mfc_bw_meter; 1592118622Shsu 1593118622Shsu mfc->mfc_bw_meter = x->bm_mfc_next; 1594118622Shsu free(x, M_BWMETER); 1595118622Shsu } 1596118622Shsu 159742777Sfenner *nptr = mfc->mfc_next; 159842777Sfenner free(mfc, M_MRTABLE); 15999209Swollman } else { 160042777Sfenner nptr = &mfc->mfc_next; 16019209Swollman } 16029209Swollman } 16032531Swollman } 1604119792Ssam MFC_UNLOCK(); 1605119792Ssam 1606119792Ssam callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, NULL); 16071541Srgrimes} 16081541Srgrimes 16091541Srgrimes/* 16102531Swollman * Packet forwarding routine once entry in the cache is made 16111541Srgrimes */ 16121541Srgrimesstatic int 1613106968Sluigiip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif) 16141541Srgrimes{ 1615106968Sluigi struct ip *ip = mtod(m, struct ip *); 1616106968Sluigi vifi_t vifi; 1617106968Sluigi int plen = ip->ip_len; 16181541Srgrimes 1619119792Ssam VIF_LOCK_ASSERT(); 16209209Swollman/* 16219209Swollman * Macro to send packet on vif. Since RSVP packets don't get counted on 16229209Swollman * input, they shouldn't get counted on output, so statistics keeping is 162372091Sasmodai * separate. 16249209Swollman */ 1625118501Shsu#define MC_SEND(ip,vifp,m) { \ 1626118501Shsu if ((vifp)->v_flags & VIFF_TUNNEL) \ 1627118501Shsu encap_send((ip), (vifp), (m)); \ 1628118501Shsu else \ 1629118501Shsu phyint_send((ip), (vifp), (m)); \ 16309209Swollman} 16319209Swollman 16322531Swollman /* 16339209Swollman * If xmt_vif is not -1, send on only the requested vif. 16349209Swollman * 16359209Swollman * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) 16369209Swollman */ 16379209Swollman if (xmt_vif < numvifs) { 1638118622Shsu#ifdef PIM 1639118622Shsu if (viftable[xmt_vif].v_flags & VIFF_REGISTER) 1640118622Shsu pim_register_send(ip, viftable + xmt_vif, m, rt); 1641118622Shsu else 1642118622Shsu#endif 16439209Swollman MC_SEND(ip, viftable + xmt_vif, m); 16449209Swollman return 1; 16459209Swollman } 16469209Swollman 16479209Swollman /* 16482531Swollman * Don't forward if it didn't arrive from the parent vif for its origin. 16492531Swollman */ 16502531Swollman vifi = rt->mfc_parent; 16519209Swollman if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) { 16522531Swollman /* came in the wrong interface */ 16539209Swollman if (mrtdebug & DEBUG_FORWARD) 165438373Sbde log(LOG_DEBUG, "wrong if: ifp %p vifi %d vififp %p\n", 165538373Sbde (void *)ifp, vifi, (void *)viftable[vifi].v_ifp); 16562531Swollman ++mrtstat.mrts_wrong_if; 16579209Swollman ++rt->mfc_wrong_if; 16589209Swollman /* 1659118622Shsu * If we are doing PIM assert processing, send a message 1660118622Shsu * to the routing daemon. 1661118622Shsu * 1662118622Shsu * XXX: A PIM-SM router needs the WRONGVIF detection so it 1663118622Shsu * can complete the SPT switch, regardless of the type 1664118622Shsu * of the iif (broadcast media, GRE tunnel, etc). 16659209Swollman */ 1666118622Shsu if (pim_assert && (vifi < numvifs) && viftable[vifi].v_ifp) { 16679209Swollman struct timeval now; 1668106968Sluigi u_long delta; 16699209Swollman 1670118622Shsu#ifdef PIM 1671118622Shsu if (ifp == &multicast_register_if) 1672118622Shsu pimstat.pims_rcv_registers_wrongiif++; 1673118622Shsu#endif 1674118622Shsu 1675118501Shsu /* Get vifi for the incoming packet */ 1676118501Shsu for (vifi=0; vifi < numvifs && viftable[vifi].v_ifp != ifp; vifi++) 1677118501Shsu ; 1678118501Shsu if (vifi >= numvifs) 1679118622Shsu return 0; /* The iif is not found: ignore the packet. */ 1680118501Shsu 1681118622Shsu if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_DISABLE_WRONGVIF) 1682118622Shsu return 0; /* WRONGVIF disabled: ignore the packet */ 1683118622Shsu 16849209Swollman GET_TIME(now); 16859209Swollman 16869209Swollman TV_DELTA(rt->mfc_last_assert, now, delta); 16879209Swollman 16889209Swollman if (delta > ASSERT_MSG_TIME) { 1689106968Sluigi struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; 1690106968Sluigi struct igmpmsg *im; 1691106968Sluigi int hlen = ip->ip_hl << 2; 1692106968Sluigi struct mbuf *mm = m_copy(m, 0, hlen); 1693106968Sluigi 16949209Swollman if (mm && (M_HASCL(mm) || mm->m_len < hlen)) 16959209Swollman mm = m_pullup(mm, hlen); 1696106968Sluigi if (mm == NULL) 16979209Swollman return ENOBUFS; 16989209Swollman 16999209Swollman rt->mfc_last_assert = now; 17009209Swollman 17019209Swollman im = mtod(mm, struct igmpmsg *); 17029209Swollman im->im_msgtype = IGMPMSG_WRONGVIF; 17039209Swollman im->im_mbz = 0; 17049209Swollman im->im_vif = vifi; 17059209Swollman 1706118501Shsu mrtstat.mrts_upcalls++; 1707118501Shsu 17089209Swollman k_igmpsrc.sin_addr = im->im_src; 1709106968Sluigi if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) { 1710106968Sluigi log(LOG_WARNING, 1711106968Sluigi "ip_mforward: ip_mrouter socket queue full\n"); 1712106968Sluigi ++mrtstat.mrts_upq_sockfull; 1713106968Sluigi return ENOBUFS; 1714106968Sluigi } 17159209Swollman } 17169209Swollman } 17179209Swollman return 0; 17182531Swollman } 17191541Srgrimes 17209209Swollman /* If I sourced this packet, it counts as output, else it was input. */ 17219209Swollman if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) { 17229209Swollman viftable[vifi].v_pkt_out++; 17239209Swollman viftable[vifi].v_bytes_out += plen; 17249209Swollman } else { 17259209Swollman viftable[vifi].v_pkt_in++; 17269209Swollman viftable[vifi].v_bytes_in += plen; 17279209Swollman } 17282531Swollman rt->mfc_pkt_cnt++; 17299209Swollman rt->mfc_byte_cnt += plen; 17301541Srgrimes 17312531Swollman /* 17322531Swollman * For each vif, decide if a copy of the packet should be forwarded. 17332531Swollman * Forward if: 17342531Swollman * - the ttl exceeds the vif's threshold 17352531Swollman * - there are group members downstream on interface 17362531Swollman */ 1737106968Sluigi for (vifi = 0; vifi < numvifs; vifi++) 1738106968Sluigi if ((rt->mfc_ttls[vifi] > 0) && (ip->ip_ttl > rt->mfc_ttls[vifi])) { 1739106968Sluigi viftable[vifi].v_pkt_out++; 1740106968Sluigi viftable[vifi].v_bytes_out += plen; 1741118622Shsu#ifdef PIM 1742118622Shsu if (viftable[vifi].v_flags & VIFF_REGISTER) 1743118622Shsu pim_register_send(ip, viftable + vifi, m, rt); 1744118622Shsu else 1745118622Shsu#endif 1746106968Sluigi MC_SEND(ip, viftable+vifi, m); 17479209Swollman } 17482531Swollman 1749118622Shsu /* 1750118622Shsu * Perform upcall-related bw measuring. 1751118622Shsu */ 1752118622Shsu if (rt->mfc_bw_meter != NULL) { 1753118622Shsu struct bw_meter *x; 1754118622Shsu struct timeval now; 1755118622Shsu 1756118622Shsu GET_TIME(now); 1757119792Ssam MFC_LOCK_ASSERT(); 1758118622Shsu for (x = rt->mfc_bw_meter; x != NULL; x = x->bm_mfc_next) 1759118622Shsu bw_meter_receive_packet(x, plen, &now); 1760118622Shsu } 1761118622Shsu 17622531Swollman return 0; 17631541Srgrimes} 17641541Srgrimes 17659209Swollman/* 1766106968Sluigi * check if a vif number is legal/ok. This is used by ip_output. 17671541Srgrimes */ 176812296Sphkstatic int 1769106968SluigiX_legal_vif_num(int vif) 17709209Swollman{ 1771119792Ssam /* XXX unlocked, matter? */ 1772106968Sluigi return (vif >= 0 && vif < numvifs); 17732531Swollman} 17742531Swollman 17759209Swollman/* 17769209Swollman * Return the local address used by this vif 17779209Swollman */ 177812296Sphkstatic u_long 1779106968SluigiX_ip_mcast_src(int vifi) 17809209Swollman{ 1781119792Ssam /* XXX unlocked, matter? */ 17829209Swollman if (vifi >= 0 && vifi < numvifs) 17839209Swollman return viftable[vifi].v_lcl_addr.s_addr; 17849209Swollman else 17859209Swollman return INADDR_ANY; 17869209Swollman} 17879209Swollman 17882531Swollmanstatic void 1789106968Sluigiphyint_send(struct ip *ip, struct vif *vifp, struct mbuf *m) 17901541Srgrimes{ 1791106968Sluigi struct mbuf *mb_copy; 1792106968Sluigi int hlen = ip->ip_hl << 2; 17931541Srgrimes 1794119792Ssam VIF_LOCK_ASSERT(); 1795119792Ssam 17963571Swollman /* 17979209Swollman * Make a new reference to the packet; make sure that 17989209Swollman * the IP header is actually copied, not just referenced, 17999209Swollman * so that ip_output() only scribbles on the copy. 18003571Swollman */ 1801118622Shsu mb_copy = m_copypacket(m, M_DONTWAIT); 18029209Swollman if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < hlen)) 18039209Swollman mb_copy = m_pullup(mb_copy, hlen); 18043571Swollman if (mb_copy == NULL) 18059209Swollman return; 18063571Swollman 180742777Sfenner if (vifp->v_rate_limit == 0) 180810203Swollman tbf_send_packet(vifp, mb_copy); 18092531Swollman else 181010203Swollman tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len); 18112531Swollman} 18121541Srgrimes 18132531Swollmanstatic void 1814106968Sluigiencap_send(struct ip *ip, struct vif *vifp, struct mbuf *m) 18151541Srgrimes{ 1816106968Sluigi struct mbuf *mb_copy; 1817106968Sluigi struct ip *ip_copy; 1818106968Sluigi int i, len = ip->ip_len; 18191541Srgrimes 1820119792Ssam VIF_LOCK_ASSERT(); 1821119792Ssam 1822119134Shsu /* Take care of delayed checksums */ 1823119134Shsu if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 1824119134Shsu in_delayed_cksum(m); 1825119134Shsu m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 1826119134Shsu } 1827119134Shsu 18282531Swollman /* 182935256Sdes * copy the old packet & pullup its IP header into the 18302531Swollman * new mbuf so we can modify it. Try to fill the new 18312531Swollman * mbuf since if we don't the ethernet driver will. 18322531Swollman */ 1833111119Simp MGETHDR(mb_copy, M_DONTWAIT, MT_HEADER); 18342531Swollman if (mb_copy == NULL) 18352531Swollman return; 1836105570Srwatson#ifdef MAC 1837105570Srwatson mac_create_mbuf_multicast_encap(m, vifp->v_ifp, mb_copy); 1838105570Srwatson#endif 183919940Sfenner mb_copy->m_data += max_linkhdr; 18402531Swollman mb_copy->m_len = sizeof(multicast_encap_iphdr); 18411541Srgrimes 1842118622Shsu if ((mb_copy->m_next = m_copypacket(m, M_DONTWAIT)) == NULL) { 18432531Swollman m_freem(mb_copy); 18442531Swollman return; 18452531Swollman } 18462531Swollman i = MHLEN - M_LEADINGSPACE(mb_copy); 18472531Swollman if (i > len) 18482531Swollman i = len; 18492531Swollman mb_copy = m_pullup(mb_copy, i); 18502531Swollman if (mb_copy == NULL) 18512531Swollman return; 18523571Swollman mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr); 18531541Srgrimes 18542531Swollman /* 18552531Swollman * fill in the encapsulating IP header. 18562531Swollman */ 18572531Swollman ip_copy = mtod(mb_copy, struct ip *); 18582531Swollman *ip_copy = multicast_encap_iphdr; 185977574Skris#ifdef RANDOM_IP_ID 186077574Skris ip_copy->ip_id = ip_randomid(); 186177574Skris#else 186265837Sru ip_copy->ip_id = htons(ip_id++); 186377574Skris#endif 18642531Swollman ip_copy->ip_len += len; 18652531Swollman ip_copy->ip_src = vifp->v_lcl_addr; 18662531Swollman ip_copy->ip_dst = vifp->v_rmt_addr; 18671541Srgrimes 18682531Swollman /* 18692531Swollman * turn the encapsulated IP header back into a valid one. 18702531Swollman */ 18712531Swollman ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr)); 18722531Swollman --ip->ip_ttl; 187390868Smike ip->ip_len = htons(ip->ip_len); 187490868Smike ip->ip_off = htons(ip->ip_off); 18752531Swollman ip->ip_sum = 0; 18762531Swollman mb_copy->m_data += sizeof(multicast_encap_iphdr); 18772531Swollman ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2); 18782531Swollman mb_copy->m_data -= sizeof(multicast_encap_iphdr); 18792531Swollman 188042777Sfenner if (vifp->v_rate_limit == 0) 188110203Swollman tbf_send_packet(vifp, mb_copy); 18822531Swollman else 188310203Swollman tbf_control(vifp, mb_copy, ip, ip_copy->ip_len); 18841541Srgrimes} 18851541Srgrimes 18861541Srgrimes/* 18872531Swollman * Token bucket filter module 18882531Swollman */ 188910203Swollman 18909209Swollmanstatic void 1891106968Sluigitbf_control(struct vif *vifp, struct mbuf *m, struct ip *ip, u_long p_len) 18921541Srgrimes{ 1893106968Sluigi struct tbf *t = vifp->v_tbf; 189410203Swollman 1895119792Ssam VIF_LOCK_ASSERT(); 1896119792Ssam 1897106968Sluigi if (p_len > MAX_BKT_SIZE) { /* drop if packet is too large */ 189810203Swollman mrtstat.mrts_pkt2large++; 189910203Swollman m_freem(m); 190010203Swollman return; 190110203Swollman } 190210203Swollman 19032531Swollman tbf_update_tokens(vifp); 19041541Srgrimes 1905106968Sluigi if (t->tbf_q_len == 0) { /* queue empty... */ 1906106968Sluigi if (p_len <= t->tbf_n_tok) { /* send packet if enough tokens */ 190710203Swollman t->tbf_n_tok -= p_len; 190810203Swollman tbf_send_packet(vifp, m); 1909106968Sluigi } else { /* no, queue packet and try later */ 191010203Swollman tbf_queue(vifp, m); 1911119792Ssam callout_reset(&tbf_reprocess_ch, TBF_REPROCESS, 1912119792Ssam tbf_reprocess_q, vifp); 19132531Swollman } 191410203Swollman } else if (t->tbf_q_len < t->tbf_max_q_len) { 19152531Swollman /* finite queue length, so queue pkts and process queue */ 191610203Swollman tbf_queue(vifp, m); 19172531Swollman tbf_process_q(vifp); 19182531Swollman } else { 1919106968Sluigi /* queue full, try to dq and queue and process */ 19202531Swollman if (!tbf_dq_sel(vifp, ip)) { 19212531Swollman mrtstat.mrts_q_overflow++; 19222531Swollman m_freem(m); 19232531Swollman } else { 192410203Swollman tbf_queue(vifp, m); 19252531Swollman tbf_process_q(vifp); 19262531Swollman } 19272531Swollman } 19282531Swollman} 19291541Srgrimes 19309209Swollman/* 19312531Swollman * adds a packet to the queue at the interface 19322531Swollman */ 19339209Swollmanstatic void 1934106968Sluigitbf_queue(struct vif *vifp, struct mbuf *m) 19352531Swollman{ 1936106968Sluigi struct tbf *t = vifp->v_tbf; 19371541Srgrimes 1938119792Ssam VIF_LOCK_ASSERT(); 1939119792Ssam 1940106968Sluigi if (t->tbf_t == NULL) /* Queue was empty */ 194110203Swollman t->tbf_q = m; 1942106968Sluigi else /* Insert at tail */ 194310203Swollman t->tbf_t->m_act = m; 19441541Srgrimes 1945106968Sluigi t->tbf_t = m; /* Set new tail pointer */ 19461541Srgrimes 194710203Swollman#ifdef DIAGNOSTIC 194810203Swollman /* Make sure we didn't get fed a bogus mbuf */ 194910203Swollman if (m->m_act) 195010203Swollman panic("tbf_queue: m_act"); 195110203Swollman#endif 195210203Swollman m->m_act = NULL; 195310203Swollman 195410203Swollman t->tbf_q_len++; 19552531Swollman} 19561541Srgrimes 19579209Swollman/* 19582531Swollman * processes the queue at the interface 19592531Swollman */ 19609209Swollmanstatic void 1961106968Sluigitbf_process_q(struct vif *vifp) 19622531Swollman{ 1963106968Sluigi struct tbf *t = vifp->v_tbf; 19641541Srgrimes 1965119792Ssam VIF_LOCK_ASSERT(); 1966119792Ssam 19672531Swollman /* loop through the queue at the interface and send as many packets 19682531Swollman * as possible 19692531Swollman */ 197010203Swollman while (t->tbf_q_len > 0) { 1971106968Sluigi struct mbuf *m = t->tbf_q; 1972106968Sluigi int len = mtod(m, struct ip *)->ip_len; 19732531Swollman 19742531Swollman /* determine if the packet can be sent */ 1975106968Sluigi if (len > t->tbf_n_tok) /* not enough tokens, we are done */ 1976106968Sluigi break; 1977106968Sluigi /* ok, reduce no of tokens, dequeue and send the packet. */ 1978106968Sluigi t->tbf_n_tok -= len; 19792531Swollman 1980106968Sluigi t->tbf_q = m->m_act; 1981106968Sluigi if (--t->tbf_q_len == 0) 1982106968Sluigi t->tbf_t = NULL; 19832531Swollman 1984106968Sluigi m->m_act = NULL; 1985106968Sluigi tbf_send_packet(vifp, m); 19862531Swollman } 19871541Srgrimes} 19881541Srgrimes 19899209Swollmanstatic void 1990106968Sluigitbf_reprocess_q(void *xvifp) 19911541Srgrimes{ 1992106968Sluigi struct vif *vifp = xvifp; 1993106968Sluigi 19949209Swollman if (ip_mrouter == NULL) 19952531Swollman return; 1996119792Ssam VIF_LOCK(); 19972531Swollman tbf_update_tokens(vifp); 19982531Swollman tbf_process_q(vifp); 199910203Swollman if (vifp->v_tbf->tbf_q_len) 2000119792Ssam callout_reset(&tbf_reprocess_ch, TBF_REPROCESS, tbf_reprocess_q, vifp); 2001119792Ssam VIF_UNLOCK(); 20022531Swollman} 20032531Swollman 20042531Swollman/* function that will selectively discard a member of the queue 200510203Swollman * based on the precedence value and the priority 20062531Swollman */ 20079209Swollmanstatic int 2008106968Sluigitbf_dq_sel(struct vif *vifp, struct ip *ip) 20092531Swollman{ 2010106968Sluigi u_int p; 2011106968Sluigi struct mbuf *m, *last; 2012106968Sluigi struct mbuf **np; 2013106968Sluigi struct tbf *t = vifp->v_tbf; 20142531Swollman 2015119792Ssam VIF_LOCK_ASSERT(); 2016119792Ssam 20172531Swollman p = priority(vifp, ip); 20182531Swollman 201910203Swollman np = &t->tbf_q; 202010203Swollman last = NULL; 202110203Swollman while ((m = *np) != NULL) { 202210203Swollman if (p > priority(vifp, mtod(m, struct ip *))) { 202310203Swollman *np = m->m_act; 202410203Swollman /* If we're removing the last packet, fix the tail pointer */ 202510203Swollman if (m == t->tbf_t) 202610203Swollman t->tbf_t = last; 202710203Swollman m_freem(m); 2028106968Sluigi /* It's impossible for the queue to be empty, but check anyways. */ 202910203Swollman if (--t->tbf_q_len == 0) 203010203Swollman t->tbf_t = NULL; 20312531Swollman mrtstat.mrts_drop_sel++; 2032106968Sluigi return 1; 20331541Srgrimes } 203410203Swollman np = &m->m_act; 203510203Swollman last = m; 20362531Swollman } 2037106968Sluigi return 0; 20382531Swollman} 20391541Srgrimes 20409209Swollmanstatic void 2041106968Sluigitbf_send_packet(struct vif *vifp, struct mbuf *m) 20422531Swollman{ 2043119792Ssam VIF_LOCK_ASSERT(); 20441541Srgrimes 2045106968Sluigi if (vifp->v_flags & VIFF_TUNNEL) /* If tunnel options */ 2046106968Sluigi ip_output(m, NULL, &vifp->v_route, IP_FORWARDING, NULL, NULL); 2047106968Sluigi else { 2048106968Sluigi struct ip_moptions imo; 2049106968Sluigi int error; 2050106968Sluigi static struct route ro; /* XXX check this */ 2051106968Sluigi 205210203Swollman imo.imo_multicast_ifp = vifp->v_ifp; 205310203Swollman imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; 205410203Swollman imo.imo_multicast_loop = 1; 205510203Swollman imo.imo_multicast_vif = -1; 205610203Swollman 205715292Swollman /* 205815292Swollman * Re-entrancy should not be a problem here, because 205915292Swollman * the packets that we send out and are looped back at us 206015292Swollman * should get rejected because they appear to come from 206115292Swollman * the loopback interface, thus preventing looping. 206215292Swollman */ 2063106968Sluigi error = ip_output(m, NULL, &ro, IP_FORWARDING, &imo, NULL); 20642531Swollman 20659209Swollman if (mrtdebug & DEBUG_XMIT) 206611284Swollman log(LOG_DEBUG, "phyint_send on vif %d err %d\n", 2067106625Sjhb (int)(vifp - viftable), error); 20682531Swollman } 20691541Srgrimes} 20702531Swollman 20712531Swollman/* determine the current time and then 20722531Swollman * the elapsed time (between the last time and time now) 20732531Swollman * in milliseconds & update the no. of tokens in the bucket 20742531Swollman */ 20759209Swollmanstatic void 2076106968Sluigitbf_update_tokens(struct vif *vifp) 20772531Swollman{ 20782531Swollman struct timeval tp; 2079106968Sluigi u_long tm; 2080106968Sluigi struct tbf *t = vifp->v_tbf; 20812531Swollman 2082119792Ssam VIF_LOCK_ASSERT(); 2083119792Ssam 20842531Swollman GET_TIME(tp); 20852531Swollman 208610203Swollman TV_DELTA(tp, t->tbf_last_pkt_t, tm); 20872531Swollman 208810203Swollman /* 208910203Swollman * This formula is actually 209010203Swollman * "time in seconds" * "bytes/second". 209110203Swollman * 209210203Swollman * (tm / 1000000) * (v_rate_limit * 1000 * (1000/1024) / 8) 209310203Swollman * 209410203Swollman * The (1000/1024) was introduced in add_vif to optimize 209510203Swollman * this divide into a shift. 209610203Swollman */ 209710203Swollman t->tbf_n_tok += tm * vifp->v_rate_limit / 1024 / 8; 209810203Swollman t->tbf_last_pkt_t = tp; 20992531Swollman 210010203Swollman if (t->tbf_n_tok > MAX_BKT_SIZE) 210110203Swollman t->tbf_n_tok = MAX_BKT_SIZE; 21022531Swollman} 21032531Swollman 21042531Swollmanstatic int 2105106968Sluigipriority(struct vif *vifp, struct ip *ip) 21062531Swollman{ 2107106968Sluigi int prio = 50; /* the lowest priority -- default case */ 21082531Swollman 21099209Swollman /* temporary hack; may add general packet classifier some day */ 21102531Swollman 21119209Swollman /* 21129209Swollman * The UDP port space is divided up into four priority ranges: 21139209Swollman * [0, 16384) : unclassified - lowest priority 21149209Swollman * [16384, 32768) : audio - highest priority 21159209Swollman * [32768, 49152) : whiteboard - medium priority 21169209Swollman * [49152, 65536) : video - low priority 2117106968Sluigi * 2118106968Sluigi * Everything else gets lowest priority. 21199209Swollman */ 21209209Swollman if (ip->ip_p == IPPROTO_UDP) { 21219209Swollman struct udphdr *udp = (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2)); 21229209Swollman switch (ntohs(udp->uh_dport) & 0xc000) { 2123106968Sluigi case 0x4000: 2124106968Sluigi prio = 70; 2125106968Sluigi break; 2126106968Sluigi case 0x8000: 2127106968Sluigi prio = 60; 2128106968Sluigi break; 2129106968Sluigi case 0xc000: 2130106968Sluigi prio = 55; 2131106968Sluigi break; 21329209Swollman } 21339209Swollman } 21349209Swollman return prio; 21359209Swollman} 21368876Srgrimes 21379209Swollman/* 21389209Swollman * End of token bucket filter modifications 21399209Swollman */ 21402531Swollman 2141106968Sluigistatic int 2142106968SluigiX_ip_rsvp_vif(struct socket *so, struct sockopt *sopt) 21439209Swollman{ 2144119792Ssam int error, vifi; 21459209Swollman 21469209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 21479209Swollman return EOPNOTSUPP; 21489209Swollman 2149106968Sluigi error = sooptcopyin(sopt, &vifi, sizeof vifi, sizeof vifi); 215038482Swollman if (error) 2151106968Sluigi return error; 21529209Swollman 2153119792Ssam VIF_LOCK(); 21542531Swollman 2155106968Sluigi if (vifi < 0 || vifi >= numvifs) { /* Error if vif is invalid */ 2156119792Ssam VIF_UNLOCK(); 21579209Swollman return EADDRNOTAVAIL; 21589209Swollman } 21592531Swollman 2160106968Sluigi if (sopt->sopt_name == IP_RSVP_VIF_ON) { 2161106968Sluigi /* Check if socket is available. */ 2162106968Sluigi if (viftable[vifi].v_rsvpd != NULL) { 2163119792Ssam VIF_UNLOCK(); 2164106968Sluigi return EADDRINUSE; 2165106968Sluigi } 21669209Swollman 2167106968Sluigi viftable[vifi].v_rsvpd = so; 2168106968Sluigi /* This may seem silly, but we need to be sure we don't over-increment 2169106968Sluigi * the RSVP counter, in case something slips up. 2170106968Sluigi */ 2171106968Sluigi if (!viftable[vifi].v_rsvp_on) { 2172106968Sluigi viftable[vifi].v_rsvp_on = 1; 2173106968Sluigi rsvp_on++; 217438482Swollman } 2175106968Sluigi } else { /* must be VIF_OFF */ 217698894Sluigi /* 217798894Sluigi * XXX as an additional consistency check, one could make sure 2178106968Sluigi * that viftable[vifi].v_rsvpd == so, otherwise passing so as 217998894Sluigi * first parameter is pretty useless. 218098894Sluigi */ 2181106968Sluigi viftable[vifi].v_rsvpd = NULL; 218238482Swollman /* 218338482Swollman * This may seem silly, but we need to be sure we don't over-decrement 218438482Swollman * the RSVP counter, in case something slips up. 218538482Swollman */ 2186106968Sluigi if (viftable[vifi].v_rsvp_on) { 2187106968Sluigi viftable[vifi].v_rsvp_on = 0; 2188106968Sluigi rsvp_on--; 218938482Swollman } 2190106968Sluigi } 2191119792Ssam VIF_UNLOCK(); 2192106968Sluigi return 0; 21939209Swollman} 21949209Swollman 2195106968Sluigistatic void 2196106968SluigiX_ip_rsvp_force_done(struct socket *so) 21979209Swollman{ 21989209Swollman int vifi; 21999209Swollman 22009209Swollman /* Don't bother if it is not the right type of socket. */ 22019209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 22029209Swollman return; 22039209Swollman 2204119792Ssam VIF_LOCK(); 22059209Swollman 22069209Swollman /* The socket may be attached to more than one vif...this 22079209Swollman * is perfectly legal. 22089209Swollman */ 22099209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 22109209Swollman if (viftable[vifi].v_rsvpd == so) { 22119209Swollman viftable[vifi].v_rsvpd = NULL; 22129209Swollman /* This may seem silly, but we need to be sure we don't 22139209Swollman * over-decrement the RSVP counter, in case something slips up. 22149209Swollman */ 22159209Swollman if (viftable[vifi].v_rsvp_on) { 22169209Swollman viftable[vifi].v_rsvp_on = 0; 22179209Swollman rsvp_on--; 22189209Swollman } 22199209Swollman } 22209209Swollman } 22219209Swollman 2222119792Ssam VIF_UNLOCK(); 22239209Swollman} 22249209Swollman 2225106968Sluigistatic void 2226106968SluigiX_rsvp_input(struct mbuf *m, int off) 22279209Swollman{ 22289209Swollman int vifi; 2229106968Sluigi struct ip *ip = mtod(m, struct ip *); 2230106968Sluigi struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET }; 22319682Swollman struct ifnet *ifp; 22329209Swollman 22339209Swollman if (rsvpdebug) 22349209Swollman printf("rsvp_input: rsvp_on %d\n",rsvp_on); 22359209Swollman 22369209Swollman /* Can still get packets with rsvp_on = 0 if there is a local member 22379209Swollman * of the group to which the RSVP packet is addressed. But in this 22389209Swollman * case we want to throw the packet away. 22399209Swollman */ 22409209Swollman if (!rsvp_on) { 22419209Swollman m_freem(m); 22429209Swollman return; 22439209Swollman } 22449209Swollman 22459209Swollman if (rsvpdebug) 22469209Swollman printf("rsvp_input: check vifs\n"); 22479209Swollman 22489682Swollman#ifdef DIAGNOSTIC 2249113255Sdes M_ASSERTPKTHDR(m); 22509682Swollman#endif 22519682Swollman 22529682Swollman ifp = m->m_pkthdr.rcvif; 2253119792Ssam 2254119792Ssam VIF_LOCK(); 22559209Swollman /* Find which vif the packet arrived on. */ 225665986Skjc for (vifi = 0; vifi < numvifs; vifi++) 22579209Swollman if (viftable[vifi].v_ifp == ifp) 225865986Skjc break; 22599209Swollman 226065986Skjc if (vifi == numvifs || viftable[vifi].v_rsvpd == NULL) { 226165986Skjc /* 2262119792Ssam * Drop the lock here to avoid holding it across rip_input. 2263119792Ssam * This could make rsvpdebug printfs wrong. If you care, 2264119792Ssam * record the state of stuff before dropping the lock. 2265119792Ssam */ 2266119792Ssam VIF_UNLOCK(); 2267119792Ssam /* 226865986Skjc * If the old-style non-vif-associated socket is set, 226965986Skjc * then use it. Otherwise, drop packet since there 227065986Skjc * is no specific socket for this vif. 227165986Skjc */ 227265986Skjc if (ip_rsvpd != NULL) { 22739209Swollman if (rsvpdebug) 227465986Skjc printf("rsvp_input: Sending packet up old-style socket\n"); 227582884Sjulian rip_input(m, off); /* xxx */ 227665986Skjc } else { 227765986Skjc if (rsvpdebug && vifi == numvifs) 227865986Skjc printf("rsvp_input: Can't find vif for packet.\n"); 227965986Skjc else if (rsvpdebug && viftable[vifi].v_rsvpd == NULL) 228065986Skjc printf("rsvp_input: No socket defined for vif %d\n",vifi); 22819209Swollman m_freem(m); 228265986Skjc } 228365986Skjc return; 22849209Swollman } 22859209Swollman rsvp_src.sin_addr = ip->ip_src; 22869209Swollman 22879209Swollman if (rsvpdebug && m) 228812296Sphk printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n", 22899209Swollman m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); 22909209Swollman 229146568Speter if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) { 22929209Swollman if (rsvpdebug) 22939209Swollman printf("rsvp_input: Failed to append to socket\n"); 229446568Speter } else { 22959209Swollman if (rsvpdebug) 22969209Swollman printf("rsvp_input: send packet up\n"); 229746568Speter } 2298119792Ssam VIF_UNLOCK(); 22999209Swollman} 23009209Swollman 2301118622Shsu/* 2302118622Shsu * Code for bandwidth monitors 2303118622Shsu */ 2304118622Shsu 2305118622Shsu/* 2306118622Shsu * Define common interface for timeval-related methods 2307118622Shsu */ 2308118622Shsu#define BW_TIMEVALCMP(tvp, uvp, cmp) timevalcmp((tvp), (uvp), cmp) 2309118622Shsu#define BW_TIMEVALDECR(vvp, uvp) timevalsub((vvp), (uvp)) 2310118622Shsu#define BW_TIMEVALADD(vvp, uvp) timevaladd((vvp), (uvp)) 2311118622Shsu 2312118622Shsustatic uint32_t 2313118622Shsucompute_bw_meter_flags(struct bw_upcall *req) 2314118622Shsu{ 2315118622Shsu uint32_t flags = 0; 2316118622Shsu 2317118622Shsu if (req->bu_flags & BW_UPCALL_UNIT_PACKETS) 2318118622Shsu flags |= BW_METER_UNIT_PACKETS; 2319118622Shsu if (req->bu_flags & BW_UPCALL_UNIT_BYTES) 2320118622Shsu flags |= BW_METER_UNIT_BYTES; 2321118622Shsu if (req->bu_flags & BW_UPCALL_GEQ) 2322118622Shsu flags |= BW_METER_GEQ; 2323118622Shsu if (req->bu_flags & BW_UPCALL_LEQ) 2324118622Shsu flags |= BW_METER_LEQ; 2325118622Shsu 2326118622Shsu return flags; 2327118622Shsu} 2328118622Shsu 2329118622Shsu/* 2330118622Shsu * Add a bw_meter entry 2331118622Shsu */ 23322763Swollmanstatic int 2333118622Shsuadd_bw_upcall(struct bw_upcall *req) 2334118622Shsu{ 2335118622Shsu struct mfc *mfc; 2336118622Shsu struct timeval delta = { BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC, 2337118622Shsu BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC }; 2338118622Shsu struct timeval now; 2339118622Shsu struct bw_meter *x; 2340118622Shsu uint32_t flags; 2341118622Shsu 2342118622Shsu if (!(mrt_api_config & MRT_MFC_BW_UPCALL)) 2343118622Shsu return EOPNOTSUPP; 2344118622Shsu 2345118622Shsu /* Test if the flags are valid */ 2346118622Shsu if (!(req->bu_flags & (BW_UPCALL_UNIT_PACKETS | BW_UPCALL_UNIT_BYTES))) 2347118622Shsu return EINVAL; 2348118622Shsu if (!(req->bu_flags & (BW_UPCALL_GEQ | BW_UPCALL_LEQ))) 2349118622Shsu return EINVAL; 2350118622Shsu if ((req->bu_flags & (BW_UPCALL_GEQ | BW_UPCALL_LEQ)) 2351118622Shsu == (BW_UPCALL_GEQ | BW_UPCALL_LEQ)) 2352118622Shsu return EINVAL; 2353118622Shsu 2354118622Shsu /* Test if the threshold time interval is valid */ 2355118622Shsu if (BW_TIMEVALCMP(&req->bu_threshold.b_time, &delta, <)) 2356118622Shsu return EINVAL; 2357118622Shsu 2358118622Shsu flags = compute_bw_meter_flags(req); 2359118622Shsu 2360118622Shsu /* 2361118622Shsu * Find if we have already same bw_meter entry 2362118622Shsu */ 2363119792Ssam MFC_LOCK(); 2364118622Shsu mfc = mfc_find(req->bu_src.s_addr, req->bu_dst.s_addr); 2365118622Shsu if (mfc == NULL) { 2366119792Ssam MFC_UNLOCK(); 2367118622Shsu return EADDRNOTAVAIL; 2368118622Shsu } 2369118622Shsu for (x = mfc->mfc_bw_meter; x != NULL; x = x->bm_mfc_next) { 2370118622Shsu if ((BW_TIMEVALCMP(&x->bm_threshold.b_time, 2371118622Shsu &req->bu_threshold.b_time, ==)) && 2372118622Shsu (x->bm_threshold.b_packets == req->bu_threshold.b_packets) && 2373118622Shsu (x->bm_threshold.b_bytes == req->bu_threshold.b_bytes) && 2374118622Shsu (x->bm_flags & BW_METER_USER_FLAGS) == flags) { 2375119792Ssam MFC_UNLOCK(); 2376118622Shsu return 0; /* XXX Already installed */ 2377118622Shsu } 2378118622Shsu } 2379118622Shsu 2380118622Shsu /* Allocate the new bw_meter entry */ 2381118622Shsu x = (struct bw_meter *)malloc(sizeof(*x), M_BWMETER, M_NOWAIT); 2382119792Ssam if (x == NULL) { 2383119792Ssam MFC_UNLOCK(); 2384118622Shsu return ENOBUFS; 2385119792Ssam } 2386118622Shsu 2387118622Shsu /* Set the new bw_meter entry */ 2388118622Shsu x->bm_threshold.b_time = req->bu_threshold.b_time; 2389118622Shsu GET_TIME(now); 2390118622Shsu x->bm_start_time = now; 2391118622Shsu x->bm_threshold.b_packets = req->bu_threshold.b_packets; 2392118622Shsu x->bm_threshold.b_bytes = req->bu_threshold.b_bytes; 2393118622Shsu x->bm_measured.b_packets = 0; 2394118622Shsu x->bm_measured.b_bytes = 0; 2395118622Shsu x->bm_flags = flags; 2396118622Shsu x->bm_time_next = NULL; 2397118622Shsu x->bm_time_hash = BW_METER_BUCKETS; 2398118622Shsu 2399118622Shsu /* Add the new bw_meter entry to the front of entries for this MFC */ 2400118622Shsu x->bm_mfc = mfc; 2401118622Shsu x->bm_mfc_next = mfc->mfc_bw_meter; 2402118622Shsu mfc->mfc_bw_meter = x; 2403118622Shsu schedule_bw_meter(x, &now); 2404119792Ssam MFC_UNLOCK(); 2405118622Shsu 2406118622Shsu return 0; 2407118622Shsu} 2408118622Shsu 2409118622Shsustatic void 2410118622Shsufree_bw_list(struct bw_meter *list) 2411118622Shsu{ 2412118622Shsu while (list != NULL) { 2413118622Shsu struct bw_meter *x = list; 2414118622Shsu 2415118622Shsu list = list->bm_mfc_next; 2416118622Shsu unschedule_bw_meter(x); 2417118622Shsu free(x, M_BWMETER); 2418118622Shsu } 2419118622Shsu} 2420118622Shsu 2421118622Shsu/* 2422118622Shsu * Delete one or multiple bw_meter entries 2423118622Shsu */ 2424118622Shsustatic int 2425118622Shsudel_bw_upcall(struct bw_upcall *req) 2426118622Shsu{ 2427118622Shsu struct mfc *mfc; 2428118622Shsu struct bw_meter *x; 2429118622Shsu 2430118622Shsu if (!(mrt_api_config & MRT_MFC_BW_UPCALL)) 2431118622Shsu return EOPNOTSUPP; 2432118622Shsu 2433119792Ssam MFC_LOCK(); 2434118622Shsu /* Find the corresponding MFC entry */ 2435118622Shsu mfc = mfc_find(req->bu_src.s_addr, req->bu_dst.s_addr); 2436118622Shsu if (mfc == NULL) { 2437119792Ssam MFC_UNLOCK(); 2438118622Shsu return EADDRNOTAVAIL; 2439118622Shsu } else if (req->bu_flags & BW_UPCALL_DELETE_ALL) { 2440118622Shsu /* 2441118622Shsu * Delete all bw_meter entries for this mfc 2442118622Shsu */ 2443118622Shsu struct bw_meter *list; 2444118622Shsu 2445118622Shsu list = mfc->mfc_bw_meter; 2446118622Shsu mfc->mfc_bw_meter = NULL; 2447118622Shsu free_bw_list(list); 2448119792Ssam MFC_UNLOCK(); 2449118622Shsu return 0; 2450118622Shsu } else { /* Delete a single bw_meter entry */ 2451118622Shsu struct bw_meter *prev; 2452118622Shsu uint32_t flags = 0; 2453118622Shsu 2454118622Shsu flags = compute_bw_meter_flags(req); 2455118622Shsu 2456118622Shsu /* Find the bw_meter entry to delete */ 2457118622Shsu for (prev = NULL, x = mfc->mfc_bw_meter; x != NULL; 2458118622Shsu x = x->bm_mfc_next) { 2459118622Shsu if ((BW_TIMEVALCMP(&x->bm_threshold.b_time, 2460118622Shsu &req->bu_threshold.b_time, ==)) && 2461118622Shsu (x->bm_threshold.b_packets == req->bu_threshold.b_packets) && 2462118622Shsu (x->bm_threshold.b_bytes == req->bu_threshold.b_bytes) && 2463118622Shsu (x->bm_flags & BW_METER_USER_FLAGS) == flags) 2464118622Shsu break; 2465118622Shsu } 2466118622Shsu if (x != NULL) { /* Delete entry from the list for this MFC */ 2467118622Shsu if (prev != NULL) 2468118622Shsu prev->bm_mfc_next = x->bm_mfc_next; /* remove from middle*/ 2469118622Shsu else 2470118622Shsu x->bm_mfc->mfc_bw_meter = x->bm_mfc_next;/* new head of list */ 2471118622Shsu 2472118622Shsu unschedule_bw_meter(x); 2473119792Ssam MFC_UNLOCK(); 2474118622Shsu /* Free the bw_meter entry */ 2475118622Shsu free(x, M_BWMETER); 2476118622Shsu return 0; 2477118622Shsu } else { 2478119792Ssam MFC_UNLOCK(); 2479118622Shsu return EINVAL; 2480118622Shsu } 2481118622Shsu } 2482118622Shsu /* NOTREACHED */ 2483118622Shsu} 2484118622Shsu 2485118622Shsu/* 2486118622Shsu * Perform bandwidth measurement processing that may result in an upcall 2487118622Shsu */ 2488118622Shsustatic void 2489118622Shsubw_meter_receive_packet(struct bw_meter *x, int plen, struct timeval *nowp) 2490118622Shsu{ 2491118622Shsu struct timeval delta; 2492118622Shsu 2493119792Ssam MFC_LOCK_ASSERT(); 2494119792Ssam 2495118622Shsu delta = *nowp; 2496118622Shsu BW_TIMEVALDECR(&delta, &x->bm_start_time); 2497118622Shsu 2498118622Shsu if (x->bm_flags & BW_METER_GEQ) { 2499118622Shsu /* 2500118622Shsu * Processing for ">=" type of bw_meter entry 2501118622Shsu */ 2502118622Shsu if (BW_TIMEVALCMP(&delta, &x->bm_threshold.b_time, >)) { 2503118622Shsu /* Reset the bw_meter entry */ 2504118622Shsu x->bm_start_time = *nowp; 2505118622Shsu x->bm_measured.b_packets = 0; 2506118622Shsu x->bm_measured.b_bytes = 0; 2507118622Shsu x->bm_flags &= ~BW_METER_UPCALL_DELIVERED; 2508118622Shsu } 2509118622Shsu 2510118622Shsu /* Record that a packet is received */ 2511118622Shsu x->bm_measured.b_packets++; 2512118622Shsu x->bm_measured.b_bytes += plen; 2513118622Shsu 2514118622Shsu /* 2515118622Shsu * Test if we should deliver an upcall 2516118622Shsu */ 2517118622Shsu if (!(x->bm_flags & BW_METER_UPCALL_DELIVERED)) { 2518118622Shsu if (((x->bm_flags & BW_METER_UNIT_PACKETS) && 2519118622Shsu (x->bm_measured.b_packets >= x->bm_threshold.b_packets)) || 2520118622Shsu ((x->bm_flags & BW_METER_UNIT_BYTES) && 2521118622Shsu (x->bm_measured.b_bytes >= x->bm_threshold.b_bytes))) { 2522118622Shsu /* Prepare an upcall for delivery */ 2523118622Shsu bw_meter_prepare_upcall(x, nowp); 2524118622Shsu x->bm_flags |= BW_METER_UPCALL_DELIVERED; 2525118622Shsu } 2526118622Shsu } 2527118622Shsu } else if (x->bm_flags & BW_METER_LEQ) { 2528118622Shsu /* 2529118622Shsu * Processing for "<=" type of bw_meter entry 2530118622Shsu */ 2531118622Shsu if (BW_TIMEVALCMP(&delta, &x->bm_threshold.b_time, >)) { 2532118622Shsu /* 2533118622Shsu * We are behind time with the multicast forwarding table 2534118622Shsu * scanning for "<=" type of bw_meter entries, so test now 2535118622Shsu * if we should deliver an upcall. 2536118622Shsu */ 2537118622Shsu if (((x->bm_flags & BW_METER_UNIT_PACKETS) && 2538118622Shsu (x->bm_measured.b_packets <= x->bm_threshold.b_packets)) || 2539118622Shsu ((x->bm_flags & BW_METER_UNIT_BYTES) && 2540118622Shsu (x->bm_measured.b_bytes <= x->bm_threshold.b_bytes))) { 2541118622Shsu /* Prepare an upcall for delivery */ 2542118622Shsu bw_meter_prepare_upcall(x, nowp); 2543118622Shsu } 2544118622Shsu /* Reschedule the bw_meter entry */ 2545118622Shsu unschedule_bw_meter(x); 2546118622Shsu schedule_bw_meter(x, nowp); 2547118622Shsu } 2548118622Shsu 2549118622Shsu /* Record that a packet is received */ 2550118622Shsu x->bm_measured.b_packets++; 2551118622Shsu x->bm_measured.b_bytes += plen; 2552118622Shsu 2553118622Shsu /* 2554118622Shsu * Test if we should restart the measuring interval 2555118622Shsu */ 2556118622Shsu if ((x->bm_flags & BW_METER_UNIT_PACKETS && 2557118622Shsu x->bm_measured.b_packets <= x->bm_threshold.b_packets) || 2558118622Shsu (x->bm_flags & BW_METER_UNIT_BYTES && 2559118622Shsu x->bm_measured.b_bytes <= x->bm_threshold.b_bytes)) { 2560118622Shsu /* Don't restart the measuring interval */ 2561118622Shsu } else { 2562118622Shsu /* Do restart the measuring interval */ 2563118622Shsu /* 2564118622Shsu * XXX: note that we don't unschedule and schedule, because this 2565118622Shsu * might be too much overhead per packet. Instead, when we process 2566118622Shsu * all entries for a given timer hash bin, we check whether it is 2567118622Shsu * really a timeout. If not, we reschedule at that time. 2568118622Shsu */ 2569118622Shsu x->bm_start_time = *nowp; 2570118622Shsu x->bm_measured.b_packets = 0; 2571118622Shsu x->bm_measured.b_bytes = 0; 2572118622Shsu x->bm_flags &= ~BW_METER_UPCALL_DELIVERED; 2573118622Shsu } 2574118622Shsu } 2575118622Shsu} 2576118622Shsu 2577118622Shsu/* 2578118622Shsu * Prepare a bandwidth-related upcall 2579118622Shsu */ 2580118622Shsustatic void 2581118622Shsubw_meter_prepare_upcall(struct bw_meter *x, struct timeval *nowp) 2582118622Shsu{ 2583118622Shsu struct timeval delta; 2584118622Shsu struct bw_upcall *u; 2585118622Shsu 2586119792Ssam MFC_LOCK_ASSERT(); 2587118622Shsu 2588118622Shsu /* 2589118622Shsu * Compute the measured time interval 2590118622Shsu */ 2591118622Shsu delta = *nowp; 2592118622Shsu BW_TIMEVALDECR(&delta, &x->bm_start_time); 2593118622Shsu 2594118622Shsu /* 2595118622Shsu * If there are too many pending upcalls, deliver them now 2596118622Shsu */ 2597118622Shsu if (bw_upcalls_n >= BW_UPCALLS_MAX) 2598118622Shsu bw_upcalls_send(); 2599118622Shsu 2600118622Shsu /* 2601118622Shsu * Set the bw_upcall entry 2602118622Shsu */ 2603118622Shsu u = &bw_upcalls[bw_upcalls_n++]; 2604118622Shsu u->bu_src = x->bm_mfc->mfc_origin; 2605118622Shsu u->bu_dst = x->bm_mfc->mfc_mcastgrp; 2606118622Shsu u->bu_threshold.b_time = x->bm_threshold.b_time; 2607118622Shsu u->bu_threshold.b_packets = x->bm_threshold.b_packets; 2608118622Shsu u->bu_threshold.b_bytes = x->bm_threshold.b_bytes; 2609118622Shsu u->bu_measured.b_time = delta; 2610118622Shsu u->bu_measured.b_packets = x->bm_measured.b_packets; 2611118622Shsu u->bu_measured.b_bytes = x->bm_measured.b_bytes; 2612118622Shsu u->bu_flags = 0; 2613118622Shsu if (x->bm_flags & BW_METER_UNIT_PACKETS) 2614118622Shsu u->bu_flags |= BW_UPCALL_UNIT_PACKETS; 2615118622Shsu if (x->bm_flags & BW_METER_UNIT_BYTES) 2616118622Shsu u->bu_flags |= BW_UPCALL_UNIT_BYTES; 2617118622Shsu if (x->bm_flags & BW_METER_GEQ) 2618118622Shsu u->bu_flags |= BW_UPCALL_GEQ; 2619118622Shsu if (x->bm_flags & BW_METER_LEQ) 2620118622Shsu u->bu_flags |= BW_UPCALL_LEQ; 2621118622Shsu} 2622118622Shsu 2623118622Shsu/* 2624118622Shsu * Send the pending bandwidth-related upcalls 2625118622Shsu */ 2626118622Shsustatic void 2627118622Shsubw_upcalls_send(void) 2628118622Shsu{ 2629118622Shsu struct mbuf *m; 2630118622Shsu int len = bw_upcalls_n * sizeof(bw_upcalls[0]); 2631118622Shsu struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; 2632118622Shsu static struct igmpmsg igmpmsg = { 0, /* unused1 */ 2633118622Shsu 0, /* unused2 */ 2634118622Shsu IGMPMSG_BW_UPCALL,/* im_msgtype */ 2635118622Shsu 0, /* im_mbz */ 2636118622Shsu 0, /* im_vif */ 2637118622Shsu 0, /* unused3 */ 2638118622Shsu { 0 }, /* im_src */ 2639118622Shsu { 0 } }; /* im_dst */ 2640118622Shsu 2641119792Ssam MFC_LOCK_ASSERT(); 2642119792Ssam 2643118622Shsu if (bw_upcalls_n == 0) 2644118622Shsu return; /* No pending upcalls */ 2645118622Shsu 2646118622Shsu bw_upcalls_n = 0; 2647118622Shsu 2648118622Shsu /* 2649118622Shsu * Allocate a new mbuf, initialize it with the header and 2650118622Shsu * the payload for the pending calls. 2651118622Shsu */ 2652118622Shsu MGETHDR(m, M_DONTWAIT, MT_HEADER); 2653118622Shsu if (m == NULL) { 2654118622Shsu log(LOG_WARNING, "bw_upcalls_send: cannot allocate mbuf\n"); 2655118622Shsu return; 2656118622Shsu } 2657118622Shsu 2658118622Shsu m->m_len = m->m_pkthdr.len = 0; 2659118622Shsu m_copyback(m, 0, sizeof(struct igmpmsg), (caddr_t)&igmpmsg); 2660118622Shsu m_copyback(m, sizeof(struct igmpmsg), len, (caddr_t)&bw_upcalls[0]); 2661118622Shsu 2662118622Shsu /* 2663118622Shsu * Send the upcalls 2664118622Shsu * XXX do we need to set the address in k_igmpsrc ? 2665118622Shsu */ 2666118622Shsu mrtstat.mrts_upcalls++; 2667118622Shsu if (socket_send(ip_mrouter, m, &k_igmpsrc) < 0) { 2668118622Shsu log(LOG_WARNING, "bw_upcalls_send: ip_mrouter socket queue full\n"); 2669118622Shsu ++mrtstat.mrts_upq_sockfull; 2670118622Shsu } 2671118622Shsu} 2672118622Shsu 2673118622Shsu/* 2674118622Shsu * Compute the timeout hash value for the bw_meter entries 2675118622Shsu */ 2676118622Shsu#define BW_METER_TIMEHASH(bw_meter, hash) \ 2677118622Shsu do { \ 2678118622Shsu struct timeval next_timeval = (bw_meter)->bm_start_time; \ 2679118622Shsu \ 2680118622Shsu BW_TIMEVALADD(&next_timeval, &(bw_meter)->bm_threshold.b_time); \ 2681118622Shsu (hash) = next_timeval.tv_sec; \ 2682118622Shsu if (next_timeval.tv_usec) \ 2683118622Shsu (hash)++; /* XXX: make sure we don't timeout early */ \ 2684118622Shsu (hash) %= BW_METER_BUCKETS; \ 2685118622Shsu } while (0) 2686118622Shsu 2687118622Shsu/* 2688118622Shsu * Schedule a timer to process periodically bw_meter entry of type "<=" 2689118622Shsu * by linking the entry in the proper hash bucket. 2690118622Shsu */ 2691118622Shsustatic void 2692118622Shsuschedule_bw_meter(struct bw_meter *x, struct timeval *nowp) 2693118622Shsu{ 2694119792Ssam int time_hash; 2695118622Shsu 2696119792Ssam MFC_LOCK_ASSERT(); 2697119792Ssam 2698118622Shsu if (!(x->bm_flags & BW_METER_LEQ)) 2699118622Shsu return; /* XXX: we schedule timers only for "<=" entries */ 2700118622Shsu 2701118622Shsu /* 2702118622Shsu * Reset the bw_meter entry 2703118622Shsu */ 2704118622Shsu x->bm_start_time = *nowp; 2705118622Shsu x->bm_measured.b_packets = 0; 2706118622Shsu x->bm_measured.b_bytes = 0; 2707118622Shsu x->bm_flags &= ~BW_METER_UPCALL_DELIVERED; 2708118622Shsu 2709118622Shsu /* 2710118622Shsu * Compute the timeout hash value and insert the entry 2711118622Shsu */ 2712118622Shsu BW_METER_TIMEHASH(x, time_hash); 2713118622Shsu x->bm_time_next = bw_meter_timers[time_hash]; 2714118622Shsu bw_meter_timers[time_hash] = x; 2715118622Shsu x->bm_time_hash = time_hash; 2716118622Shsu} 2717118622Shsu 2718118622Shsu/* 2719118622Shsu * Unschedule the periodic timer that processes bw_meter entry of type "<=" 2720118622Shsu * by removing the entry from the proper hash bucket. 2721118622Shsu */ 2722118622Shsustatic void 2723118622Shsuunschedule_bw_meter(struct bw_meter *x) 2724118622Shsu{ 2725118622Shsu int time_hash; 2726118622Shsu struct bw_meter *prev, *tmp; 2727118622Shsu 2728119792Ssam MFC_LOCK_ASSERT(); 2729119792Ssam 2730118622Shsu if (!(x->bm_flags & BW_METER_LEQ)) 2731118622Shsu return; /* XXX: we schedule timers only for "<=" entries */ 2732118622Shsu 2733118622Shsu /* 2734118622Shsu * Compute the timeout hash value and delete the entry 2735118622Shsu */ 2736118622Shsu time_hash = x->bm_time_hash; 2737118622Shsu if (time_hash >= BW_METER_BUCKETS) 2738118622Shsu return; /* Entry was not scheduled */ 2739118622Shsu 2740118622Shsu for (prev = NULL, tmp = bw_meter_timers[time_hash]; 2741118622Shsu tmp != NULL; prev = tmp, tmp = tmp->bm_time_next) 2742118622Shsu if (tmp == x) 2743118622Shsu break; 2744118622Shsu 2745118622Shsu if (tmp == NULL) 2746118622Shsu panic("unschedule_bw_meter: bw_meter entry not found"); 2747118622Shsu 2748118622Shsu if (prev != NULL) 2749118622Shsu prev->bm_time_next = x->bm_time_next; 2750118622Shsu else 2751118622Shsu bw_meter_timers[time_hash] = x->bm_time_next; 2752118622Shsu 2753118622Shsu x->bm_time_next = NULL; 2754118622Shsu x->bm_time_hash = BW_METER_BUCKETS; 2755118622Shsu} 2756118622Shsu 2757118622Shsu 2758118622Shsu/* 2759118622Shsu * Process all "<=" type of bw_meter that should be processed now, 2760118622Shsu * and for each entry prepare an upcall if necessary. Each processed 2761118622Shsu * entry is rescheduled again for the (periodic) processing. 2762118622Shsu * 2763118622Shsu * This is run periodically (once per second normally). On each round, 2764118622Shsu * all the potentially matching entries are in the hash slot that we are 2765118622Shsu * looking at. 2766118622Shsu */ 2767118622Shsustatic void 2768118622Shsubw_meter_process() 2769118622Shsu{ 2770118622Shsu static uint32_t last_tv_sec; /* last time we processed this */ 2771118622Shsu 2772118622Shsu uint32_t loops; 2773119792Ssam int i; 2774118622Shsu struct timeval now, process_endtime; 2775118622Shsu 2776118622Shsu GET_TIME(now); 2777118622Shsu if (last_tv_sec == now.tv_sec) 2778118622Shsu return; /* nothing to do */ 2779118622Shsu 2780118622Shsu loops = now.tv_sec - last_tv_sec; 2781118622Shsu last_tv_sec = now.tv_sec; 2782118622Shsu if (loops > BW_METER_BUCKETS) 2783118622Shsu loops = BW_METER_BUCKETS; 2784118622Shsu 2785119792Ssam MFC_LOCK(); 2786118622Shsu /* 2787118622Shsu * Process all bins of bw_meter entries from the one after the last 2788118622Shsu * processed to the current one. On entry, i points to the last bucket 2789118622Shsu * visited, so we need to increment i at the beginning of the loop. 2790118622Shsu */ 2791119134Shsu for (i = (now.tv_sec - loops) % BW_METER_BUCKETS; loops > 0; loops--) { 2792118622Shsu struct bw_meter *x, *tmp_list; 2793118622Shsu 2794118622Shsu if (++i >= BW_METER_BUCKETS) 2795118622Shsu i = 0; 2796118622Shsu 2797119134Shsu /* Disconnect the list of bw_meter entries from the bin */ 2798118622Shsu tmp_list = bw_meter_timers[i]; 2799118622Shsu bw_meter_timers[i] = NULL; 2800118622Shsu 2801119134Shsu /* Process the list of bw_meter entries */ 2802118622Shsu while (tmp_list != NULL) { 2803118622Shsu x = tmp_list; 2804118622Shsu tmp_list = tmp_list->bm_time_next; 2805118622Shsu 2806118622Shsu /* Test if the time interval is over */ 2807118622Shsu process_endtime = x->bm_start_time; 2808118622Shsu BW_TIMEVALADD(&process_endtime, &x->bm_threshold.b_time); 2809118622Shsu if (BW_TIMEVALCMP(&process_endtime, &now, >)) { 2810118622Shsu /* Not yet: reschedule, but don't reset */ 2811118622Shsu int time_hash; 2812118622Shsu 2813118622Shsu BW_METER_TIMEHASH(x, time_hash); 2814119134Shsu if (time_hash == i && process_endtime.tv_sec == now.tv_sec) { 2815119134Shsu /* 2816119134Shsu * XXX: somehow the bin processing is a bit ahead of time. 2817119134Shsu * Put the entry in the next bin. 2818119134Shsu */ 2819119134Shsu if (++time_hash >= BW_METER_BUCKETS) 2820119134Shsu time_hash = 0; 2821119134Shsu } 2822118622Shsu x->bm_time_next = bw_meter_timers[time_hash]; 2823118622Shsu bw_meter_timers[time_hash] = x; 2824118622Shsu x->bm_time_hash = time_hash; 2825119134Shsu 2826118622Shsu continue; 2827118622Shsu } 2828118622Shsu 2829118622Shsu /* 2830118622Shsu * Test if we should deliver an upcall 2831118622Shsu */ 2832118622Shsu if (((x->bm_flags & BW_METER_UNIT_PACKETS) && 2833118622Shsu (x->bm_measured.b_packets <= x->bm_threshold.b_packets)) || 2834118622Shsu ((x->bm_flags & BW_METER_UNIT_BYTES) && 2835118622Shsu (x->bm_measured.b_bytes <= x->bm_threshold.b_bytes))) { 2836118622Shsu /* Prepare an upcall for delivery */ 2837118622Shsu bw_meter_prepare_upcall(x, &now); 2838118622Shsu } 2839118622Shsu 2840118622Shsu /* 2841118622Shsu * Reschedule for next processing 2842118622Shsu */ 2843118622Shsu schedule_bw_meter(x, &now); 2844118622Shsu } 2845118622Shsu } 2846118622Shsu 2847118622Shsu /* Send all upcalls that are pending delivery */ 2848118622Shsu bw_upcalls_send(); 2849119792Ssam 2850119792Ssam MFC_UNLOCK(); 2851118622Shsu} 2852118622Shsu 2853118622Shsu/* 2854118622Shsu * A periodic function for sending all upcalls that are pending delivery 2855118622Shsu */ 2856118622Shsustatic void 2857118622Shsuexpire_bw_upcalls_send(void *unused) 2858118622Shsu{ 2859119792Ssam MFC_LOCK(); 2860118622Shsu bw_upcalls_send(); 2861119792Ssam MFC_UNLOCK(); 2862118622Shsu 2863119792Ssam callout_reset(&bw_upcalls_ch, BW_UPCALLS_PERIOD, 2864119792Ssam expire_bw_upcalls_send, NULL); 2865118622Shsu} 2866118622Shsu 2867118622Shsu/* 2868118622Shsu * A periodic function for periodic scanning of the multicast forwarding 2869118622Shsu * table for processing all "<=" bw_meter entries. 2870118622Shsu */ 2871118622Shsustatic void 2872118622Shsuexpire_bw_meter_process(void *unused) 2873118622Shsu{ 2874118622Shsu if (mrt_api_config & MRT_MFC_BW_UPCALL) 2875118622Shsu bw_meter_process(); 2876118622Shsu 2877119792Ssam callout_reset(&bw_meter_ch, BW_METER_PERIOD, expire_bw_meter_process, NULL); 2878118622Shsu} 2879118622Shsu 2880118622Shsu/* 2881118622Shsu * End of bandwidth monitoring code 2882118622Shsu */ 2883118622Shsu 2884118622Shsu#ifdef PIM 2885118622Shsu/* 2886118622Shsu * Send the packet up to the user daemon, or eventually do kernel encapsulation 2887118622Shsu * 2888118622Shsu */ 2889118622Shsustatic int 2890118622Shsupim_register_send(struct ip *ip, struct vif *vifp, 2891118622Shsu struct mbuf *m, struct mfc *rt) 2892118622Shsu{ 2893118622Shsu struct mbuf *mb_copy, *mm; 2894118622Shsu 2895118622Shsu if (mrtdebug & DEBUG_PIM) 2896118622Shsu log(LOG_DEBUG, "pim_register_send: "); 2897118622Shsu 2898118622Shsu mb_copy = pim_register_prepare(ip, m); 2899118622Shsu if (mb_copy == NULL) 2900118622Shsu return ENOBUFS; 2901118622Shsu 2902118622Shsu /* 2903118622Shsu * Send all the fragments. Note that the mbuf for each fragment 2904118622Shsu * is freed by the sending machinery. 2905118622Shsu */ 2906118622Shsu for (mm = mb_copy; mm; mm = mb_copy) { 2907118622Shsu mb_copy = mm->m_nextpkt; 2908118622Shsu mm->m_nextpkt = 0; 2909118622Shsu mm = m_pullup(mm, sizeof(struct ip)); 2910118622Shsu if (mm != NULL) { 2911118622Shsu ip = mtod(mm, struct ip *); 2912118622Shsu if ((mrt_api_config & MRT_MFC_RP) && 2913118622Shsu (rt->mfc_rp.s_addr != INADDR_ANY)) { 2914118622Shsu pim_register_send_rp(ip, vifp, mm, rt); 2915118622Shsu } else { 2916118622Shsu pim_register_send_upcall(ip, vifp, mm, rt); 2917118622Shsu } 2918118622Shsu } 2919118622Shsu } 2920118622Shsu 2921118622Shsu return 0; 2922118622Shsu} 2923118622Shsu 2924118622Shsu/* 2925118622Shsu * Return a copy of the data packet that is ready for PIM Register 2926118622Shsu * encapsulation. 2927118622Shsu * XXX: Note that in the returned copy the IP header is a valid one. 2928118622Shsu */ 2929118622Shsustatic struct mbuf * 2930118622Shsupim_register_prepare(struct ip *ip, struct mbuf *m) 2931118622Shsu{ 2932118622Shsu struct mbuf *mb_copy = NULL; 2933118622Shsu int mtu; 2934118622Shsu 2935119134Shsu /* Take care of delayed checksums */ 2936118622Shsu if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2937118622Shsu in_delayed_cksum(m); 2938118622Shsu m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2939118622Shsu } 2940119134Shsu 2941118622Shsu /* 2942118622Shsu * Copy the old packet & pullup its IP header into the 2943118622Shsu * new mbuf so we can modify it. 2944118622Shsu */ 2945118622Shsu mb_copy = m_copypacket(m, M_DONTWAIT); 2946118622Shsu if (mb_copy == NULL) 2947118622Shsu return NULL; 2948118622Shsu mb_copy = m_pullup(mb_copy, ip->ip_hl << 2); 2949118622Shsu if (mb_copy == NULL) 2950118622Shsu return NULL; 2951118622Shsu 2952118622Shsu /* take care of the TTL */ 2953118622Shsu ip = mtod(mb_copy, struct ip *); 2954118622Shsu --ip->ip_ttl; 2955118622Shsu 2956118622Shsu /* Compute the MTU after the PIM Register encapsulation */ 2957118622Shsu mtu = 0xffff - sizeof(pim_encap_iphdr) - sizeof(pim_encap_pimhdr); 2958119134Shsu 2959119134Shsu if (ip->ip_len <= mtu) { 2960119134Shsu /* Turn the IP header into a valid one */ 2961119134Shsu ip->ip_len = htons(ip->ip_len); 2962119134Shsu ip->ip_off = htons(ip->ip_off); 2963119134Shsu ip->ip_sum = 0; 2964119134Shsu ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2); 2965119134Shsu } else { 2966119134Shsu /* Fragment the packet */ 2967119134Shsu if (ip_fragment(ip, &mb_copy, mtu, 0, CSUM_DELAY_IP) != 0) { 2968119134Shsu m_freem(mb_copy); 2969119134Shsu return NULL; 2970119134Shsu } 2971118622Shsu } 2972118622Shsu return mb_copy; 2973118622Shsu} 2974118622Shsu 2975118622Shsu/* 2976118622Shsu * Send an upcall with the data packet to the user-level process. 2977118622Shsu */ 2978118622Shsustatic int 2979118622Shsupim_register_send_upcall(struct ip *ip, struct vif *vifp, 2980118622Shsu struct mbuf *mb_copy, struct mfc *rt) 2981118622Shsu{ 2982118622Shsu struct mbuf *mb_first; 2983118622Shsu int len = ntohs(ip->ip_len); 2984118622Shsu struct igmpmsg *im; 2985118622Shsu struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; 2986118622Shsu 2987119792Ssam VIF_LOCK_ASSERT(); 2988119792Ssam 2989118622Shsu /* 2990118622Shsu * Add a new mbuf with an upcall header 2991118622Shsu */ 2992118622Shsu MGETHDR(mb_first, M_DONTWAIT, MT_HEADER); 2993118622Shsu if (mb_first == NULL) { 2994118622Shsu m_freem(mb_copy); 2995118622Shsu return ENOBUFS; 2996118622Shsu } 2997118622Shsu mb_first->m_data += max_linkhdr; 2998118622Shsu mb_first->m_pkthdr.len = len + sizeof(struct igmpmsg); 2999118622Shsu mb_first->m_len = sizeof(struct igmpmsg); 3000118622Shsu mb_first->m_next = mb_copy; 3001118622Shsu 3002118622Shsu /* Send message to routing daemon */ 3003118622Shsu im = mtod(mb_first, struct igmpmsg *); 3004118622Shsu im->im_msgtype = IGMPMSG_WHOLEPKT; 3005118622Shsu im->im_mbz = 0; 3006118622Shsu im->im_vif = vifp - viftable; 3007118622Shsu im->im_src = ip->ip_src; 3008118622Shsu im->im_dst = ip->ip_dst; 3009118622Shsu 3010118622Shsu k_igmpsrc.sin_addr = ip->ip_src; 3011118622Shsu 3012118622Shsu mrtstat.mrts_upcalls++; 3013118622Shsu 3014118622Shsu if (socket_send(ip_mrouter, mb_first, &k_igmpsrc) < 0) { 3015118622Shsu if (mrtdebug & DEBUG_PIM) 3016118622Shsu log(LOG_WARNING, 3017118622Shsu "mcast: pim_register_send_upcall: ip_mrouter socket queue full"); 3018118622Shsu ++mrtstat.mrts_upq_sockfull; 3019118622Shsu return ENOBUFS; 3020118622Shsu } 3021118622Shsu 3022118622Shsu /* Keep statistics */ 3023118622Shsu pimstat.pims_snd_registers_msgs++; 3024118622Shsu pimstat.pims_snd_registers_bytes += len; 3025118622Shsu 3026118622Shsu return 0; 3027118622Shsu} 3028118622Shsu 3029118622Shsu/* 3030118622Shsu * Encapsulate the data packet in PIM Register message and send it to the RP. 3031118622Shsu */ 3032118622Shsustatic int 3033118622Shsupim_register_send_rp(struct ip *ip, struct vif *vifp, 3034118622Shsu struct mbuf *mb_copy, struct mfc *rt) 3035118622Shsu{ 3036118622Shsu struct mbuf *mb_first; 3037118622Shsu struct ip *ip_outer; 3038118622Shsu struct pim_encap_pimhdr *pimhdr; 3039118622Shsu int len = ntohs(ip->ip_len); 3040118622Shsu vifi_t vifi = rt->mfc_parent; 3041118622Shsu 3042119792Ssam VIF_LOCK_ASSERT(); 3043119792Ssam 3044118622Shsu if ((vifi >= numvifs) || (viftable[vifi].v_lcl_addr.s_addr == 0)) { 3045118622Shsu m_freem(mb_copy); 3046118622Shsu return EADDRNOTAVAIL; /* The iif vif is invalid */ 3047118622Shsu } 3048118622Shsu 3049118622Shsu /* 3050118622Shsu * Add a new mbuf with the encapsulating header 3051118622Shsu */ 3052118622Shsu MGETHDR(mb_first, M_DONTWAIT, MT_HEADER); 3053118622Shsu if (mb_first == NULL) { 3054118622Shsu m_freem(mb_copy); 3055118622Shsu return ENOBUFS; 3056118622Shsu } 3057118622Shsu mb_first->m_data += max_linkhdr; 3058118622Shsu mb_first->m_len = sizeof(pim_encap_iphdr) + sizeof(pim_encap_pimhdr); 3059118622Shsu mb_first->m_next = mb_copy; 3060118622Shsu 3061118622Shsu mb_first->m_pkthdr.len = len + mb_first->m_len; 3062118622Shsu 3063118622Shsu /* 3064118622Shsu * Fill in the encapsulating IP and PIM header 3065118622Shsu */ 3066118622Shsu ip_outer = mtod(mb_first, struct ip *); 3067118622Shsu *ip_outer = pim_encap_iphdr; 3068118622Shsu#ifdef RANDOM_IP_ID 3069118622Shsu ip_outer->ip_id = ip_randomid(); 3070118622Shsu#else 3071118622Shsu ip_outer->ip_id = htons(ip_id++); 3072118622Shsu#endif 3073118622Shsu ip_outer->ip_len = len + sizeof(pim_encap_iphdr) + sizeof(pim_encap_pimhdr); 3074118622Shsu ip_outer->ip_src = viftable[vifi].v_lcl_addr; 3075118622Shsu ip_outer->ip_dst = rt->mfc_rp; 3076118622Shsu /* 3077118622Shsu * Copy the inner header TOS to the outer header, and take care of the 3078118622Shsu * IP_DF bit. 3079118622Shsu */ 3080118622Shsu ip_outer->ip_tos = ip->ip_tos; 3081118622Shsu if (ntohs(ip->ip_off) & IP_DF) 3082118622Shsu ip_outer->ip_off |= IP_DF; 3083118622Shsu pimhdr = (struct pim_encap_pimhdr *)((caddr_t)ip_outer 3084118622Shsu + sizeof(pim_encap_iphdr)); 3085118622Shsu *pimhdr = pim_encap_pimhdr; 3086118622Shsu /* If the iif crosses a border, set the Border-bit */ 3087118622Shsu if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_BORDER_VIF & mrt_api_config) 3088118622Shsu pimhdr->flags |= htonl(PIM_BORDER_REGISTER); 3089118622Shsu 3090118622Shsu mb_first->m_data += sizeof(pim_encap_iphdr); 3091118622Shsu pimhdr->pim.pim_cksum = in_cksum(mb_first, sizeof(pim_encap_pimhdr)); 3092118622Shsu mb_first->m_data -= sizeof(pim_encap_iphdr); 3093118622Shsu 3094118622Shsu if (vifp->v_rate_limit == 0) 3095118622Shsu tbf_send_packet(vifp, mb_first); 3096118622Shsu else 3097118622Shsu tbf_control(vifp, mb_first, ip, ip_outer->ip_len); 3098118622Shsu 3099118622Shsu /* Keep statistics */ 3100118622Shsu pimstat.pims_snd_registers_msgs++; 3101118622Shsu pimstat.pims_snd_registers_bytes += len; 3102118622Shsu 3103118622Shsu return 0; 3104118622Shsu} 3105118622Shsu 3106118622Shsu/* 3107118622Shsu * PIM-SMv2 and PIM-DM messages processing. 3108118622Shsu * Receives and verifies the PIM control messages, and passes them 3109118622Shsu * up to the listening socket, using rip_input(). 3110118622Shsu * The only message with special processing is the PIM_REGISTER message 3111118622Shsu * (used by PIM-SM): the PIM header is stripped off, and the inner packet 3112118622Shsu * is passed to if_simloop(). 3113118622Shsu */ 3114118622Shsuvoid 3115118622Shsupim_input(struct mbuf *m, int off) 3116118622Shsu{ 3117118622Shsu struct ip *ip = mtod(m, struct ip *); 3118118622Shsu struct pim *pim; 3119118622Shsu int minlen; 3120118622Shsu int datalen = ip->ip_len; 3121118622Shsu int ip_tos; 3122118622Shsu int iphlen = off; 3123118622Shsu 3124118622Shsu /* Keep statistics */ 3125118622Shsu pimstat.pims_rcv_total_msgs++; 3126118622Shsu pimstat.pims_rcv_total_bytes += datalen; 3127118622Shsu 3128118622Shsu /* 3129118622Shsu * Validate lengths 3130118622Shsu */ 3131118622Shsu if (datalen < PIM_MINLEN) { 3132118622Shsu pimstat.pims_rcv_tooshort++; 3133118622Shsu log(LOG_ERR, "pim_input: packet size too small %d from %lx\n", 3134118622Shsu datalen, (u_long)ip->ip_src.s_addr); 3135118622Shsu m_freem(m); 3136118622Shsu return; 3137118622Shsu } 3138118622Shsu 3139118622Shsu /* 3140118622Shsu * If the packet is at least as big as a REGISTER, go agead 3141118622Shsu * and grab the PIM REGISTER header size, to avoid another 3142118622Shsu * possible m_pullup() later. 3143118622Shsu * 3144118622Shsu * PIM_MINLEN == pimhdr + u_int32_t == 4 + 4 = 8 3145118622Shsu * PIM_REG_MINLEN == pimhdr + reghdr + encap_iphdr == 4 + 4 + 20 = 28 3146118622Shsu */ 3147118622Shsu minlen = iphlen + (datalen >= PIM_REG_MINLEN ? PIM_REG_MINLEN : PIM_MINLEN); 3148118622Shsu /* 3149118622Shsu * Get the IP and PIM headers in contiguous memory, and 3150118622Shsu * possibly the PIM REGISTER header. 3151118622Shsu */ 3152118622Shsu if ((m->m_flags & M_EXT || m->m_len < minlen) && 3153118622Shsu (m = m_pullup(m, minlen)) == 0) { 3154118622Shsu log(LOG_ERR, "pim_input: m_pullup failure\n"); 3155118622Shsu return; 3156118622Shsu } 3157118622Shsu /* m_pullup() may have given us a new mbuf so reset ip. */ 3158118622Shsu ip = mtod(m, struct ip *); 3159118622Shsu ip_tos = ip->ip_tos; 3160118622Shsu 3161118622Shsu /* adjust mbuf to point to the PIM header */ 3162118622Shsu m->m_data += iphlen; 3163118622Shsu m->m_len -= iphlen; 3164118622Shsu pim = mtod(m, struct pim *); 3165118622Shsu 3166118622Shsu /* 3167118622Shsu * Validate checksum. If PIM REGISTER, exclude the data packet. 3168118622Shsu * 3169118622Shsu * XXX: some older PIMv2 implementations don't make this distinction, 3170118622Shsu * so for compatibility reason perform the checksum over part of the 3171118622Shsu * message, and if error, then over the whole message. 3172118622Shsu */ 3173118622Shsu if (PIM_VT_T(pim->pim_vt) == PIM_REGISTER && in_cksum(m, PIM_MINLEN) == 0) { 3174118622Shsu /* do nothing, checksum okay */ 3175118622Shsu } else if (in_cksum(m, datalen)) { 3176118622Shsu pimstat.pims_rcv_badsum++; 3177118622Shsu if (mrtdebug & DEBUG_PIM) 3178118622Shsu log(LOG_DEBUG, "pim_input: invalid checksum"); 3179118622Shsu m_freem(m); 3180118622Shsu return; 3181118622Shsu } 3182118622Shsu 3183118622Shsu /* PIM version check */ 3184118622Shsu if (PIM_VT_V(pim->pim_vt) < PIM_VERSION) { 3185118622Shsu pimstat.pims_rcv_badversion++; 3186118622Shsu log(LOG_ERR, "pim_input: incorrect version %d, expecting %d\n", 3187118622Shsu PIM_VT_V(pim->pim_vt), PIM_VERSION); 3188118622Shsu m_freem(m); 3189118622Shsu return; 3190118622Shsu } 3191118622Shsu 3192118622Shsu /* restore mbuf back to the outer IP */ 3193118622Shsu m->m_data -= iphlen; 3194118622Shsu m->m_len += iphlen; 3195118622Shsu 3196118622Shsu if (PIM_VT_T(pim->pim_vt) == PIM_REGISTER) { 3197118622Shsu /* 3198118622Shsu * Since this is a REGISTER, we'll make a copy of the register 3199118622Shsu * headers ip + pim + u_int32 + encap_ip, to be passed up to the 3200118622Shsu * routing daemon. 3201118622Shsu */ 3202118622Shsu struct sockaddr_in dst = { sizeof(dst), AF_INET }; 3203118622Shsu struct mbuf *mcp; 3204118622Shsu struct ip *encap_ip; 3205118622Shsu u_int32_t *reghdr; 3206119792Ssam struct ifnet *vifp; 3207118622Shsu 3208119792Ssam VIF_LOCK(); 3209118622Shsu if ((reg_vif_num >= numvifs) || (reg_vif_num == VIFI_INVALID)) { 3210119792Ssam VIF_UNLOCK(); 3211118622Shsu if (mrtdebug & DEBUG_PIM) 3212118622Shsu log(LOG_DEBUG, 3213118622Shsu "pim_input: register vif not set: %d\n", reg_vif_num); 3214118622Shsu m_freem(m); 3215118622Shsu return; 3216118622Shsu } 3217119792Ssam /* XXX need refcnt? */ 3218119792Ssam vifp = viftable[reg_vif_num].v_ifp; 3219119792Ssam VIF_UNLOCK(); 3220118622Shsu 3221118622Shsu /* 3222118622Shsu * Validate length 3223118622Shsu */ 3224118622Shsu if (datalen < PIM_REG_MINLEN) { 3225118622Shsu pimstat.pims_rcv_tooshort++; 3226118622Shsu pimstat.pims_rcv_badregisters++; 3227118622Shsu log(LOG_ERR, 3228118622Shsu "pim_input: register packet size too small %d from %lx\n", 3229118622Shsu datalen, (u_long)ip->ip_src.s_addr); 3230118622Shsu m_freem(m); 3231118622Shsu return; 3232118622Shsu } 3233118622Shsu 3234118622Shsu reghdr = (u_int32_t *)(pim + 1); 3235118622Shsu encap_ip = (struct ip *)(reghdr + 1); 3236118622Shsu 3237118622Shsu if (mrtdebug & DEBUG_PIM) { 3238118622Shsu log(LOG_DEBUG, 3239118622Shsu "pim_input[register], encap_ip: %lx -> %lx, encap_ip len %d\n", 3240118622Shsu (u_long)ntohl(encap_ip->ip_src.s_addr), 3241118622Shsu (u_long)ntohl(encap_ip->ip_dst.s_addr), 3242118622Shsu ntohs(encap_ip->ip_len)); 3243118622Shsu } 3244118622Shsu 3245118622Shsu /* verify the version number of the inner packet */ 3246118622Shsu if (encap_ip->ip_v != IPVERSION) { 3247118622Shsu pimstat.pims_rcv_badregisters++; 3248118622Shsu if (mrtdebug & DEBUG_PIM) { 3249118622Shsu log(LOG_DEBUG, "pim_input: invalid IP version (%d) " 3250118622Shsu "of the inner packet\n", encap_ip->ip_v); 3251118622Shsu } 3252118622Shsu m_freem(m); 3253118622Shsu return; 3254118622Shsu } 3255118622Shsu 3256118622Shsu /* verify the inner packet is destined to a mcast group */ 3257118622Shsu if (!IN_MULTICAST(ntohl(encap_ip->ip_dst.s_addr))) { 3258118622Shsu pimstat.pims_rcv_badregisters++; 3259118622Shsu if (mrtdebug & DEBUG_PIM) 3260118622Shsu log(LOG_DEBUG, 3261118622Shsu "pim_input: inner packet of register is not " 3262118622Shsu "multicast %lx\n", 3263118622Shsu (u_long)ntohl(encap_ip->ip_dst.s_addr)); 3264118622Shsu m_freem(m); 3265118622Shsu return; 3266118622Shsu } 3267118622Shsu 3268118622Shsu /* 3269118622Shsu * Copy the TOS from the outer IP header to the inner IP header. 3270118622Shsu */ 3271118622Shsu if (encap_ip->ip_tos != ip_tos) { 3272118622Shsu /* Outer TOS -> inner TOS */ 3273118622Shsu encap_ip->ip_tos = ip_tos; 3274118622Shsu /* Recompute the inner header checksum. Sigh... */ 3275118622Shsu 3276118622Shsu /* adjust mbuf to point to the inner IP header */ 3277118622Shsu m->m_data += (iphlen + PIM_MINLEN); 3278118622Shsu m->m_len -= (iphlen + PIM_MINLEN); 3279118622Shsu 3280118622Shsu encap_ip->ip_sum = 0; 3281118622Shsu encap_ip->ip_sum = in_cksum(m, encap_ip->ip_hl << 2); 3282118622Shsu 3283118622Shsu /* restore mbuf to point back to the outer IP header */ 3284118622Shsu m->m_data -= (iphlen + PIM_MINLEN); 3285118622Shsu m->m_len += (iphlen + PIM_MINLEN); 3286118622Shsu } 3287118622Shsu 3288118622Shsu /* If a NULL_REGISTER, pass it to the daemon */ 3289118622Shsu if ((ntohl(*reghdr) & PIM_NULL_REGISTER)) 3290118622Shsu goto pim_input_to_daemon; 3291118622Shsu 3292118622Shsu /* 3293118622Shsu * Decapsulate the inner IP packet and loopback to forward it 3294118622Shsu * as a normal multicast packet. Also, make a copy of the 3295118622Shsu * outer_iphdr + pimhdr + reghdr + encap_iphdr 3296118622Shsu * to pass to the daemon later, so it can take the appropriate 3297118622Shsu * actions (e.g., send back PIM_REGISTER_STOP). 3298118622Shsu * XXX: here m->m_data points to the outer IP header. 3299118622Shsu */ 3300118622Shsu mcp = m_copy(m, 0, iphlen + PIM_REG_MINLEN); 3301118622Shsu if (mcp == NULL) { 3302118622Shsu log(LOG_ERR, 3303118622Shsu "pim_input: pim register: could not copy register head\n"); 3304118622Shsu m_freem(m); 3305118622Shsu return; 3306118622Shsu } 3307118622Shsu 3308118622Shsu /* Keep statistics */ 3309118622Shsu /* XXX: registers_bytes include only the encap. mcast pkt */ 3310118622Shsu pimstat.pims_rcv_registers_msgs++; 3311118622Shsu pimstat.pims_rcv_registers_bytes += ntohs(encap_ip->ip_len); 3312118622Shsu 3313118622Shsu /* 3314118622Shsu * forward the inner ip packet; point m_data at the inner ip. 3315118622Shsu */ 3316118622Shsu m_adj(m, iphlen + PIM_MINLEN); 3317118622Shsu 3318118622Shsu if (mrtdebug & DEBUG_PIM) { 3319118622Shsu log(LOG_DEBUG, 3320118622Shsu "pim_input: forwarding decapsulated register: " 3321118622Shsu "src %lx, dst %lx, vif %d\n", 3322118622Shsu (u_long)ntohl(encap_ip->ip_src.s_addr), 3323118622Shsu (u_long)ntohl(encap_ip->ip_dst.s_addr), 3324118622Shsu reg_vif_num); 3325118622Shsu } 3326119792Ssam /* NB: vifp was collected above; can it change on us? */ 3327119792Ssam if_simloop(vifp, m, dst.sin_family, 0); 3328118622Shsu 3329118622Shsu /* prepare the register head to send to the mrouting daemon */ 3330118622Shsu m = mcp; 3331118622Shsu } 3332118622Shsu 3333118622Shsupim_input_to_daemon: 3334118622Shsu /* 3335118622Shsu * Pass the PIM message up to the daemon; if it is a Register message, 3336118622Shsu * pass the 'head' only up to the daemon. This includes the 3337118622Shsu * outer IP header, PIM header, PIM-Register header and the 3338118622Shsu * inner IP header. 3339118622Shsu * XXX: the outer IP header pkt size of a Register is not adjust to 3340118622Shsu * reflect the fact that the inner multicast data is truncated. 3341118622Shsu */ 3342118622Shsu rip_input(m, iphlen); 3343118622Shsu 3344118622Shsu return; 3345118622Shsu} 3346118622Shsu#endif /* PIM */ 3347118622Shsu 3348118622Shsustatic int 334980354Sfennerip_mroute_modevent(module_t mod, int type, void *unused) 33502763Swollman{ 3351106968Sluigi int s; 33522763Swollman 3353106968Sluigi switch (type) { 3354106968Sluigi case MOD_LOAD: 3355106968Sluigi s = splnet(); 3356106968Sluigi /* XXX Protect against multiple loading */ 3357106968Sluigi ip_mcast_src = X_ip_mcast_src; 3358106968Sluigi ip_mforward = X_ip_mforward; 3359106968Sluigi ip_mrouter_done = X_ip_mrouter_done; 3360106968Sluigi ip_mrouter_get = X_ip_mrouter_get; 3361106968Sluigi ip_mrouter_set = X_ip_mrouter_set; 3362106968Sluigi ip_rsvp_force_done = X_ip_rsvp_force_done; 3363106968Sluigi ip_rsvp_vif = X_ip_rsvp_vif; 3364106968Sluigi legal_vif_num = X_legal_vif_num; 3365106968Sluigi mrt_ioctl = X_mrt_ioctl; 3366106968Sluigi rsvp_input_p = X_rsvp_input; 3367106968Sluigi splx(s); 3368106968Sluigi break; 33692763Swollman 3370106968Sluigi case MOD_UNLOAD: 3371106968Sluigi if (ip_mrouter) 3372106968Sluigi return EINVAL; 33732763Swollman 3374106968Sluigi s = splnet(); 3375106968Sluigi ip_mcast_src = NULL; 3376106968Sluigi ip_mforward = NULL; 3377106968Sluigi ip_mrouter_done = NULL; 3378106968Sluigi ip_mrouter_get = NULL; 3379106968Sluigi ip_mrouter_set = NULL; 3380106968Sluigi ip_rsvp_force_done = NULL; 3381106968Sluigi ip_rsvp_vif = NULL; 3382106968Sluigi legal_vif_num = NULL; 3383106968Sluigi mrt_ioctl = NULL; 3384106968Sluigi rsvp_input_p = NULL; 3385106968Sluigi splx(s); 3386106968Sluigi break; 3387106968Sluigi } 3388106968Sluigi return 0; 33892763Swollman} 33902763Swollman 339180354Sfennerstatic moduledata_t ip_mroutemod = { 3392106968Sluigi "ip_mroute", 3393106968Sluigi ip_mroute_modevent, 3394106968Sluigi 0 339580354Sfenner}; 339680354SfennerDECLARE_MODULE(ip_mroute, ip_mroutemod, SI_SUB_PSEUDO, SI_ORDER_ANY); 3397