--- sys/netgraph/ng_iface.c.orig 2017-06-19 19:57:23.302960000 +0700 +++ sys/netgraph/ng_iface.c 2017-07-06 17:24:41.007278000 +0700 @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -112,9 +113,15 @@ struct ng_iface_private { int unit; /* Interface unit number */ node_p node; /* Our netgraph node */ hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */ + struct rmlock lock; /* Protect private data changes */ }; typedef struct ng_iface_private *priv_p; +#define PRIV_RLOCK(priv, t) rm_rlock(&priv->lock, t) +#define PRIV_RUNLOCK(priv, t) rm_runlock(&priv->lock, t) +#define PRIV_WLOCK(priv) rm_wlock(&priv->lock) +#define PRIV_WUNLOCK(priv) rm_wunlock(&priv->lock) + /* Interface methods */ static void ng_iface_start(struct ifnet *ifp); static int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); @@ -134,6 +141,7 @@ static ng_constructor_t ng_iface_constru static ng_rcvmsg_t ng_iface_rcvmsg; static ng_shutdown_t ng_iface_shutdown; static ng_newhook_t ng_iface_newhook; +static ng_findhook_t ng_iface_findhook; static ng_rcvdata_t ng_iface_rcvdata; static ng_disconnect_t ng_iface_disconnect; @@ -185,6 +193,7 @@ static struct ng_type typestruct = { .rcvmsg = ng_iface_rcvmsg, .shutdown = ng_iface_shutdown, .newhook = ng_iface_newhook, + .findhook = ng_iface_findhook, .rcvdata = ng_iface_rcvdata, .disconnect = ng_iface_disconnect, .cmdlist = ng_iface_cmds, @@ -431,6 +440,7 @@ ng_iface_bpftap(struct ifnet *ifp, struc static int ng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa) { + struct rm_priotracker priv_tracker; const priv_p priv = (priv_p) ifp->if_softc; const iffam_p iffam = get_iffam_from_af(sa); int error; @@ -448,7 +458,9 @@ ng_iface_send(struct ifnet *ifp, struct /* Send packet. If hook is not connected, mbuf will get freed. */ NG_OUTBOUND_THREAD_REF(); + PRIV_RLOCK(priv, &priv_tracker); NG_SEND_DATA_ONLY(error, *get_hook_from_iffam(priv, iffam), m); + PRIV_RUNLOCK(priv, &priv_tracker); NG_OUTBOUND_THREAD_UNREF(); /* Update stats. */ @@ -516,6 +528,8 @@ ng_iface_constructor(node_p node) return (ENOMEM); } + rm_init(&priv->lock, "ng_iface private rmlock"); + /* Link them together */ ifp->if_softc = priv; priv->ifp = ifp; @@ -562,19 +576,45 @@ static int ng_iface_newhook(node_p node, hook_p hook, const char *name) { const iffam_p iffam = get_iffam_from_name(name); + const priv_p priv = NG_NODE_PRIVATE(node); hook_p *hookptr; if (iffam == NULL) return (EPFNOSUPPORT); - hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam); - if (*hookptr != NULL) + PRIV_WLOCK(priv); + hookptr = get_hook_from_iffam(priv, iffam); + if (*hookptr != NULL) { + PRIV_WUNLOCK(priv); return (EISCONN); + } *hookptr = hook; NG_HOOK_HI_STACK(hook); NG_HOOK_SET_TO_INBOUND(hook); + PRIV_WUNLOCK(priv); return (0); } +/* Look up hook by name */ +static hook_p +ng_iface_findhook(node_p node, const char *name) +{ + struct rm_priotracker priv_tracker; + const iffam_p iffam = get_iffam_from_name(name); + const priv_p priv = NG_NODE_PRIVATE(node); + hook_p *hookptr; + + if (iffam == NULL) + return (NULL); + PRIV_RLOCK(priv, &priv_tracker); + hookptr = get_hook_from_iffam(priv, iffam); + if (*hookptr && NG_HOOK_IS_VALID(*hookptr)) { + PRIV_RUNLOCK(priv, &priv_tracker); + return (*hookptr); + } + PRIV_RUNLOCK(priv, &priv_tracker); + return (NULL); +} + /* * Receive a control message */ @@ -730,6 +770,7 @@ ng_iface_shutdown(node_p node) CURVNET_RESTORE(); priv->ifp = NULL; free_unr(V_ng_iface_unit, priv->unit); + rm_destroy(&priv->lock); free(priv, M_NETGRAPH_IFACE); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); @@ -748,7 +789,9 @@ ng_iface_disconnect(hook_p hook) if (iffam == NULL) panic("%s", __func__); + PRIV_WLOCK(priv); *get_hook_from_iffam(priv, iffam) = NULL; + PRIV_WUNLOCK(priv); return (0); }