summaryrefslogtreecommitdiff
path: root/sys/netinet/ip_carp.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2020-05-21 03:33:45 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2020-05-21 03:33:45 +0000
commit911a23cd046afe8c7129ce6ecaefa8d3328ff5b9 (patch)
tree7becad2798ef8a4511741a55053a7be8bb571282 /sys/netinet/ip_carp.c
parent618c4dfbd5680d3c5cdc86813ee6493e3afdc01b (diff)
implement a carp_transmit that bypasses the ifq on output.
this is modelled on vlan_transmit, and basically enqueues the packet directly on the parent interface. even though carp is generally not used to transmit packets, we run dhcp relays on it at work and hit a situation where we unecessarily dropped packets because it's ifq maxlen was 1. i've been running this for a month in production. ok jmatthew@
Diffstat (limited to 'sys/netinet/ip_carp.c')
-rw-r--r--sys/netinet/ip_carp.c106
1 files changed, 65 insertions, 41 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index d26399e52ce..ff52eac7418 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.c,v 1.343 2020/04/29 07:04:32 dlg Exp $ */
+/* $OpenBSD: ip_carp.c,v 1.344 2020/05/21 03:33:44 dlg Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -233,6 +233,8 @@ int carp_check_dup_vhids(struct carp_softc *, struct srpl *,
void carp_ifgroup_ioctl(struct ifnet *, u_long, caddr_t);
void carp_ifgattr_ioctl(struct ifnet *, u_long, caddr_t);
void carp_start(struct ifnet *);
+int carp_enqueue(struct ifnet *, struct mbuf *);
+void carp_transmit(struct carp_softc *, struct ifnet *, struct mbuf *);
void carp_setrun_all(struct carp_softc *, sa_family_t);
void carp_setrun(struct carp_vhost_entry *, sa_family_t);
void carp_set_state_all(struct carp_softc *, int);
@@ -830,8 +832,8 @@ carp_clone_create(struct if_clone *ifc, int unit)
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = carp_ioctl;
ifp->if_start = carp_start;
+ ifp->if_enqueue = carp_enqueue;
ifp->if_xflags = IFXF_CLONED;
- IFQ_SET_MAXLEN(&ifp->if_snd, 1);
if_counters_alloc(ifp);
if_attach(ifp);
ether_ifattach(ifp);
@@ -2263,66 +2265,88 @@ void
carp_start(struct ifnet *ifp)
{
struct carp_softc *sc = ifp->if_softc;
+ struct ifnet *ifp0 = sc->sc_carpdev;
struct mbuf *m;
- for (;;) {
- IFQ_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL)
- break;
+ if (ifp0 == NULL) {
+ ifq_purge(&ifp->if_snd);
+ return;
+ }
-#if NBPFILTER > 0
- if (ifp->if_bpf)
- bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
-#endif /* NBPFILTER > 0 */
+ while ((m = ifq_dequeue(&ifp->if_snd)) != NULL)
+ carp_transmit(sc, ifp0, m);
+}
- if ((ifp->if_carpdev->if_flags & (IFF_UP|IFF_RUNNING)) !=
- (IFF_UP|IFF_RUNNING)) {
- ifp->if_oerrors++;
- m_freem(m);
- continue;
- }
+void
+carp_transmit(struct carp_softc *sc, struct ifnet *ifp0, struct mbuf *m)
+{
+ struct ifnet *ifp = &sc->sc_if;
- /*
- * Do not leak the multicast address when sending
- * advertisements in 'ip' and 'ip-stealth' balacing
- * modes.
- */
- if (sc->sc_balancing == CARP_BAL_IP ||
- sc->sc_balancing == CARP_BAL_IPSTEALTH) {
- struct ether_header *eh;
- uint8_t *esrc;
-
- eh = mtod(m, struct ether_header *);
- esrc = ((struct arpcom*)ifp->if_carpdev)->ac_enaddr;
- memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost));
+#if NBPFILTER > 0
+ {
+ caddr_t if_bpf = ifp->if_bpf;
+ if (if_bpf) {
+ if (bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT))
+ m_freem(m);
}
+ }
+#endif /* NBPFILTER > 0 */
- if (if_enqueue(ifp->if_carpdev, m)) {
- ifp->if_oerrors++;
- continue;
- }
- ifp->if_opackets++;
+ if (!ISSET(ifp0->if_flags, IFF_RUNNING)) {
+ counters_inc(ifp->if_counters, ifc_oerrors);
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * Do not leak the multicast address when sending
+ * advertisements in 'ip' and 'ip-stealth' balacing
+ * modes.
+ */
+ if (sc->sc_balancing == CARP_BAL_IP ||
+ sc->sc_balancing == CARP_BAL_IPSTEALTH) {
+ struct ether_header *eh = mtod(m, struct ether_header *);
+ memcpy(eh->ether_shost, sc->sc_ac.ac_enaddr,
+ sizeof(eh->ether_shost));
}
+
+ if (if_enqueue(ifp0, m))
+ counters_inc(ifp->if_counters, ifc_oerrors);
}
int
-carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
- struct rtentry *rt)
+carp_enqueue(struct ifnet *ifp, struct mbuf *m)
{
- struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc);
- struct carp_vhost_entry *vhe;
- struct srp_ref sr;
- int ismaster;
+ struct carp_softc *sc = ifp->if_softc;
+ struct ifnet *ifp0 = sc->sc_carpdev;
+
+ /* no ifq_is_priq, cos hfsc on carp doesn't make sense */
/*
* If the parent of this carp(4) got destroyed while
* `m' was being processed, silently drop it.
*/
- if (sc->sc_carpdev == NULL) {
+ if (ifp0 == NULL) {
m_freem(m);
return (0);
}
+ counters_pkt(ifp->if_counters,
+ ifc_opackets, ifc_obytes, m->m_pkthdr.len);
+ carp_transmit(sc, ifp0, m);
+
+ return (0);
+}
+
+int
+carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
+ struct rtentry *rt)
+{
+ struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc);
+ struct carp_vhost_entry *vhe;
+ struct srp_ref sr;
+ int ismaster;
+
if (sc->cur_vhe == NULL) {
vhe = SRPL_FIRST(&sr, &sc->carp_vhosts);
ismaster = (vhe->state == MASTER);