1/* $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ */ 2 3/* 4 * Copyright (c) 2002 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 42 unchanged lines hidden (view full) --- 51 */ 52 53#ifdef __FreeBSD__ 54#include "opt_inet.h" 55#include "opt_inet6.h" 56#include "opt_pf.h" 57 58#include <sys/cdefs.h> |
59__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 229850 2012-01-09 08:50:22Z glebius $"); |
60 61#define NBPFILTER 1 62 63#ifdef DEV_PFSYNC 64#define NPFSYNC DEV_PFSYNC 65#else 66#define NPFSYNC 0 67#endif --- 14 unchanged lines hidden (view full) --- 82#ifdef __FreeBSD__ 83#include <sys/endian.h> 84#include <sys/malloc.h> 85#include <sys/module.h> 86#include <sys/sockio.h> 87#include <sys/taskqueue.h> 88#include <sys/lock.h> 89#include <sys/mutex.h> |
90#include <sys/protosw.h> |
91#else 92#include <sys/ioctl.h> 93#include <sys/timeout.h> 94#endif 95#include <sys/sysctl.h> 96#ifndef __FreeBSD__ 97#include <sys/pool.h> 98#endif --- 192 unchanged lines hidden (view full) --- 291 292 TAILQ_HEAD(, tdb) sc_tdb_q; 293 294#ifdef __FreeBSD__ 295 struct callout sc_tmo; 296#else 297 struct timeout sc_tmo; 298#endif |
299}; 300 301#ifdef __FreeBSD__ |
302static MALLOC_DEFINE(M_PFSYNC, "pfsync", "pfsync data"); |
303static VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 304#define V_pfsyncif VNET(pfsyncif) |
305static VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; 306#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) |
307static VNET_DEFINE(struct pfsyncstats, pfsyncstats); 308#define V_pfsyncstats VNET(pfsyncstats) 309static VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW; 310#define V_pfsync_carp_adj VNET(pfsync_carp_adj) 311 |
312static void pfsyncintr(void *); 313static int pfsync_multicast_setup(struct pfsync_softc *); 314static void pfsync_multicast_cleanup(struct pfsync_softc *); 315static int pfsync_init(void); 316static void pfsync_uninit(void); 317 |
318SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 319SYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 320 &VNET_NAME(pfsyncstats), pfsyncstats, 321 "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 322SYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW, 323 &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment"); 324#else 325struct pfsync_softc *pfsyncif = NULL; 326struct pfsyncstats pfsyncstats; 327#define V_pfsyncstats pfsyncstats 328#endif 329 |
330void pfsyncattach(int); 331#ifdef __FreeBSD__ 332int pfsync_clone_create(struct if_clone *, int, caddr_t); 333void pfsync_clone_destroy(struct ifnet *); 334#else 335int pfsync_clone_create(struct if_clone *, int); 336int pfsync_clone_destroy(struct ifnet *); 337#endif --- 29 unchanged lines hidden (view full) --- 367void pfsync_send_bus(struct pfsync_softc *, u_int8_t); 368 369void pfsync_bulk_start(void); 370void pfsync_bulk_status(u_int8_t); 371void pfsync_bulk_update(void *); 372void pfsync_bulk_fail(void *); 373 374#ifdef __FreeBSD__ |
375/* XXX: ugly */ 376#define betoh64 (unsigned long long)be64toh 377#define timeout_del callout_stop 378#endif 379 380#define PFSYNC_MAX_BULKTRIES 12 381#ifndef __FreeBSD__ 382int pfsync_sync_ok; 383#endif 384 385#ifdef __FreeBSD__ |
386VNET_DEFINE(struct ifc_simple_data, pfsync_cloner_data); 387VNET_DEFINE(struct if_clone, pfsync_cloner); 388#define V_pfsync_cloner_data VNET(pfsync_cloner_data) 389#define V_pfsync_cloner VNET(pfsync_cloner) |
390IFC_SIMPLE_DECLARE(pfsync, 1); 391#else 392struct if_clone pfsync_cloner = 393 IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); 394#endif 395 396void 397pfsyncattach(int npfsync) --- 9 unchanged lines hidden (view full) --- 407{ 408 struct pfsync_softc *sc; 409 struct ifnet *ifp; 410 int q; 411 412 if (unit != 0) 413 return (EINVAL); 414 |
415#ifdef __FreeBSD__ 416 sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 417 sc->pfsync_sync_ok = 1; 418#else |
419 pfsync_sync_ok = 1; |
420 sc = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT | M_ZERO); |
421#endif 422 |
423 for (q = 0; q < PFSYNC_S_COUNT; q++) 424 TAILQ_INIT(&sc->sc_qs[q]); 425 426#ifdef __FreeBSD__ |
427 sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, NULL, NULL, NULL, 428 NULL, UMA_ALIGN_PTR, 0); |
429#else 430 pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); 431#endif 432 TAILQ_INIT(&sc->sc_upd_req_list); 433 TAILQ_INIT(&sc->sc_deferrals); 434 sc->sc_deferred = 0; 435 436 TAILQ_INIT(&sc->sc_tdb_q); 437 438 sc->sc_len = PFSYNC_MINPKT; 439 sc->sc_maxupdates = 128; 440 |
441#ifndef __FreeBSD__ |
442 sc->sc_imo.imo_membership = (struct in_multi **)malloc( |
443 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 444 M_WAITOK | M_ZERO); 445 sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 446#endif 447 448#ifdef __FreeBSD__ 449 ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 450 if (ifp == NULL) { |
451 uma_zdestroy(sc->sc_pool); |
452 free(sc, M_PFSYNC); |
453 return (ENOSPC); 454 } 455 if_initname(ifp, ifc->ifc_name, unit); |
456#else |
457 ifp = &sc->sc_if; 458 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); 459#endif 460 ifp->if_softc = sc; 461 ifp->if_ioctl = pfsyncioctl; 462 ifp->if_output = pfsyncoutput; 463 ifp->if_start = pfsyncstart; 464 ifp->if_type = IFT_PFSYNC; --- 41 unchanged lines hidden (view full) --- 506#else 507int 508#endif 509pfsync_clone_destroy(struct ifnet *ifp) 510{ 511 struct pfsync_softc *sc = ifp->if_softc; 512 513#ifdef __FreeBSD__ |
514 PF_LOCK(); 515#endif 516 timeout_del(&sc->sc_bulkfail_tmo); 517 timeout_del(&sc->sc_bulk_tmo); 518 timeout_del(&sc->sc_tmo); 519#ifdef __FreeBSD__ 520 PF_UNLOCK(); 521 if (!sc->pfsync_sync_ok && carp_demote_adj_p) --- 16 unchanged lines hidden (view full) --- 538 539#ifdef __FreeBSD__ 540 UMA_DESTROY(sc->sc_pool); 541#else 542 pool_destroy(&sc->sc_pool); 543#endif 544#ifdef __FreeBSD__ 545 if_free(ifp); |
546 if (sc->sc_imo.imo_membership) 547 pfsync_multicast_cleanup(sc); 548 free(sc, M_PFSYNC); |
549#else 550 free(sc->sc_imo.imo_membership, M_IPMOPTS); |
551 free(sc, M_DEVBUF); |
552#endif |
553 554#ifdef __FreeBSD__ 555 V_pfsyncif = NULL; 556#else 557 pfsyncif = NULL; 558#endif 559 560#ifndef __FreeBSD__ --- 1292 unchanged lines hidden (view full) --- 1853 } 1854#endif 1855 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1856 1857 if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1858 sc->sc_sync_if = NULL; 1859#ifdef __FreeBSD__ 1860 PF_UNLOCK(); |
1861 if (imo->imo_membership) 1862 pfsync_multicast_cleanup(sc); 1863#else |
1864 if (imo->imo_num_memberships > 0) { 1865 in_delmulti(imo->imo_membership[ 1866 --imo->imo_num_memberships]); 1867 imo->imo_multicast_ifp = NULL; 1868 } |
1869#endif |
1870 break; 1871 } 1872 1873#ifdef __FreeBSD__ 1874 PF_UNLOCK(); 1875#endif 1876 if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) 1877 return (EINVAL); --- 8 unchanged lines hidden (view full) --- 1886 if (sifp->if_mtu < sc->sc_if.if_mtu || 1887#endif 1888 (sc->sc_sync_if != NULL && 1889 sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1890 sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1891 pfsync_sendout(); 1892 sc->sc_sync_if = sifp; 1893 |
1894#ifdef __FreeBSD__ |
1895 if (imo->imo_membership) { |
1896 PF_UNLOCK(); |
1897 pfsync_multicast_cleanup(sc); |
1898 PF_LOCK(); |
1899 } 1900#else 1901 if (imo->imo_num_memberships > 0) { 1902 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); |
1903 imo->imo_multicast_ifp = NULL; 1904 } |
1905#endif |
1906 |
1907#ifdef __FreeBSD__ |
1908 if (sc->sc_sync_if && |
1909 sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { |
1910 PF_UNLOCK(); 1911 error = pfsync_multicast_setup(sc); 1912 if (error) 1913 return (error); 1914 PF_LOCK(); 1915 } |
1916#else |
1917 if (sc->sc_sync_if && |
1918 sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { |
1919 struct in_addr addr; 1920 1921 if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 1922 sc->sc_sync_if = NULL; |
1923 splx(s); 1924 return (EADDRNOTAVAIL); 1925 } 1926 |
1927 addr.s_addr = INADDR_PFSYNC_GROUP; |
1928 |
1929 if ((imo->imo_membership[0] = 1930 in_addmulti(&addr, sc->sc_sync_if)) == NULL) { 1931 sc->sc_sync_if = NULL; 1932 splx(s); 1933 return (ENOBUFS); 1934 } |
1935 imo->imo_num_memberships++; 1936 imo->imo_multicast_ifp = sc->sc_sync_if; 1937 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1938 imo->imo_multicast_loop = 0; 1939 } |
1940#endif /* !__FreeBSD__ */ |
1941 1942 ip = &sc->sc_template; 1943 bzero(ip, sizeof(*ip)); 1944 ip->ip_v = IPVERSION; 1945 ip->ip_hl = sizeof(sc->sc_template) >> 2; 1946 ip->ip_tos = IPTOS_LOWDELAY; 1947 /* len and id are set later */ 1948#ifdef __FreeBSD__ --- 382 unchanged lines hidden (view full) --- 2331#endif 2332 2333#ifdef __FreeBSD__ 2334 sc->sc_ifp->if_opackets++; 2335 sc->sc_ifp->if_obytes += m->m_pkthdr.len; 2336 sc->sc_len = PFSYNC_MINPKT; 2337 2338 IFQ_ENQUEUE(&sc->sc_ifp->if_snd, m, dummy_error); |
2339 swi_sched(V_pfsync_swi_cookie, 0); |
2340#else 2341 sc->sc_if.if_opackets++; 2342 sc->sc_if.if_obytes += m->m_pkthdr.len; 2343 2344 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) 2345 pfsyncstats.pfsyncs_opackets++; 2346 else 2347 pfsyncstats.pfsyncs_oerrors++; --- 960 unchanged lines hidden (view full) --- 3308 return (sysctl_struct(oldp, oldlenp, newp, newlen, 3309 &V_pfsyncstats, sizeof(V_pfsyncstats))); 3310 } 3311#endif 3312 return (ENOPROTOOPT); 3313} 3314 3315#ifdef __FreeBSD__ |
3316static int 3317pfsync_multicast_setup(struct pfsync_softc *sc) |
3318{ |
3319 struct ip_moptions *imo = &sc->sc_imo; 3320 int error; |
3321 |
3322 if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 3323 sc->sc_sync_if = NULL; 3324 return (EADDRNOTAVAIL); 3325 } |
3326 |
3327 imo->imo_membership = (struct in_multi **)malloc( 3328 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, 3329 M_WAITOK | M_ZERO); 3330 imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 3331 imo->imo_multicast_vif = -1; |
3332 |
3333 if ((error = in_joingroup(sc->sc_sync_if, &sc->sc_sync_peer, NULL, 3334 &imo->imo_membership[0])) != 0) { 3335 free(imo->imo_membership, M_PFSYNC); 3336 return (error); |
3337 } |
3338 imo->imo_num_memberships++; 3339 imo->imo_multicast_ifp = sc->sc_sync_if; 3340 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 3341 imo->imo_multicast_loop = 0; |
3342 |
3343 return (0); |
3344} 3345 |
3346static void 3347pfsync_multicast_cleanup(struct pfsync_softc *sc) 3348{ 3349 struct ip_moptions *imo = &sc->sc_imo; 3350 3351 in_leavegroup(imo->imo_membership[0], NULL); 3352 free(imo->imo_membership, M_PFSYNC); 3353 imo->imo_membership = NULL; 3354 imo->imo_multicast_ifp = NULL; 3355} 3356 3357#ifdef INET 3358extern struct domain inetdomain; 3359static struct protosw in_pfsync_protosw = { 3360 .pr_type = SOCK_RAW, 3361 .pr_domain = &inetdomain, 3362 .pr_protocol = IPPROTO_PFSYNC, 3363 .pr_flags = PR_ATOMIC|PR_ADDR, 3364 .pr_input = pfsync_input, 3365 .pr_output = (pr_output_t *)rip_output, 3366 .pr_ctloutput = rip_ctloutput, 3367 .pr_usrreqs = &rip_usrreqs 3368}; 3369#endif 3370 |
3371static int |
3372pfsync_init() |
3373{ |
3374 VNET_ITERATOR_DECL(vnet_iter); |
3375 int error = 0; 3376 |
3377 VNET_LIST_RLOCK(); 3378 VNET_FOREACH(vnet_iter) { 3379 CURVNET_SET(vnet_iter); 3380 V_pfsync_cloner = pfsync_cloner; 3381 V_pfsync_cloner_data = pfsync_cloner_data; 3382 V_pfsync_cloner.ifc_data = &V_pfsync_cloner_data; 3383 if_clone_attach(&V_pfsync_cloner); 3384 error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, 3385 SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 3386 CURVNET_RESTORE(); 3387 if (error) 3388 goto fail_locked; 3389 } 3390 VNET_LIST_RUNLOCK(); 3391#ifdef INET 3392 error = pf_proto_register(PF_INET, &in_pfsync_protosw); |
3393 if (error) |
3394 goto fail; 3395 error = ipproto_register(IPPROTO_PFSYNC); 3396 if (error) { 3397 pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3398 goto fail; 3399 } 3400#endif |
3401 PF_LOCK(); 3402 pfsync_state_import_ptr = pfsync_state_import; 3403 pfsync_up_ptr = pfsync_up; 3404 pfsync_insert_state_ptr = pfsync_insert_state; 3405 pfsync_update_state_ptr = pfsync_update_state; 3406 pfsync_delete_state_ptr = pfsync_delete_state; 3407 pfsync_clear_states_ptr = pfsync_clear_states; 3408 pfsync_state_in_use_ptr = pfsync_state_in_use; 3409 pfsync_defer_ptr = pfsync_defer; 3410 PF_UNLOCK(); 3411 3412 return (0); |
3413 3414fail: 3415 VNET_LIST_RLOCK(); 3416fail_locked: 3417 VNET_FOREACH(vnet_iter) { 3418 CURVNET_SET(vnet_iter); 3419 if (V_pfsync_swi_cookie) { 3420 swi_remove(V_pfsync_swi_cookie); 3421 if_clone_detach(&V_pfsync_cloner); 3422 } 3423 CURVNET_RESTORE(); 3424 } 3425 VNET_LIST_RUNLOCK(); 3426 3427 return (error); |
3428} 3429 |
3430static void 3431pfsync_uninit() |
3432{ |
3433 VNET_ITERATOR_DECL(vnet_iter); |
3434 |
3435 PF_LOCK(); 3436 pfsync_state_import_ptr = NULL; 3437 pfsync_up_ptr = NULL; 3438 pfsync_insert_state_ptr = NULL; 3439 pfsync_update_state_ptr = NULL; 3440 pfsync_delete_state_ptr = NULL; 3441 pfsync_clear_states_ptr = NULL; 3442 pfsync_state_in_use_ptr = NULL; 3443 pfsync_defer_ptr = NULL; 3444 PF_UNLOCK(); 3445 |
3446 ipproto_unregister(IPPROTO_PFSYNC); 3447 pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3448 VNET_LIST_RLOCK(); 3449 VNET_FOREACH(vnet_iter) { 3450 CURVNET_SET(vnet_iter); 3451 swi_remove(V_pfsync_swi_cookie); 3452 if_clone_detach(&V_pfsync_cloner); 3453 CURVNET_RESTORE(); 3454 } 3455 VNET_LIST_RUNLOCK(); |
3456} 3457 |
3458static int 3459pfsync_modevent(module_t mod, int type, void *data) 3460{ 3461 int error = 0; 3462 3463 switch (type) { 3464 case MOD_LOAD: |
3465 error = pfsync_init(); |
3466 break; |
3467 case MOD_QUIESCE: 3468 /* 3469 * Module should not be unloaded due to race conditions. 3470 */ 3471 error = EPERM; 3472 break; |
3473 case MOD_UNLOAD: |
3474 pfsync_uninit(); |
3475 break; 3476 default: 3477 error = EINVAL; 3478 break; 3479 } 3480 |
3481 return (error); |
3482} 3483 3484static moduledata_t pfsync_mod = { 3485 "pfsync", 3486 pfsync_modevent, 3487 0 3488}; 3489 3490#define PFSYNC_MODVER 1 3491 |
3492DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); |
3493MODULE_VERSION(pfsync, PFSYNC_MODVER); 3494MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3495#endif /* __FreeBSD__ */ |