summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/if.h8
-rw-r--r--sys/net/if_gre.c160
-rw-r--r--sys/net/if_gre.h32
-rw-r--r--sys/netinet/ip_gre.c7
-rw-r--r--sys/sys/sockio.h5
5 files changed, 195 insertions, 17 deletions
diff --git a/sys/net/if.h b/sys/net/if.h
index 9df697c3341..b1d880376b8 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.h,v 1.116 2010/05/28 12:09:09 claudio Exp $ */
+/* $OpenBSD: if.h,v 1.117 2010/06/26 19:49:54 claudio Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
@@ -621,6 +621,12 @@ struct ifmediareq {
int *ifm_ulist; /* media words */
};
+struct ifkalivereq {
+ char ikar_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ int ikar_timeo;
+ int ikar_cnt;
+};
+
/*
* Structure used in SIOCGIFCONF request.
* Used to retrieve interface configuration
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index fde4de2c306..3db43e3e2c1 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_gre.c,v 1.48 2010/05/11 09:22:56 claudio Exp $ */
+/* $OpenBSD: if_gre.c,v 1.49 2010/06/26 19:49:54 claudio Exp $ */
/* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
/*
@@ -115,7 +115,10 @@ int gre_allow = 0;
int gre_wccp = 0;
int ip_mobile_allow = 0;
-static void gre_compute_route(struct gre_softc *sc);
+void gre_compute_route(struct gre_softc *);
+void gre_keepalive(void *);
+void gre_send_keepalive(void *);
+void gre_link_state(struct gre_softc *);
void
greattach(int n)
@@ -151,6 +154,10 @@ gre_clone_create(struct if_clone *ifc, int unit)
sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
sc->g_proto = IPPROTO_GRE;
sc->sc_if.if_flags |= IFF_LINK0;
+ sc->sc_ka_state = GRE_STATE_UKNWN;
+
+ timeout_set(&sc->sc_ka_hold, gre_keepalive, sc);
+ timeout_set(&sc->sc_ka_snd, gre_send_keepalive, sc);
if_attach(&sc->sc_if);
if_alloc_sadl(&sc->sc_if);
@@ -239,7 +246,7 @@ gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
m->m_flags &= ~(M_BCAST|M_MCAST);
-#if NBPFILTER >0
+#if NBPFILTER > 0
if (ifp->if_bpf)
bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
#endif
@@ -448,6 +455,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
struct if_laddrreq *lifr = (struct if_laddrreq *)data;
+ struct ifkalivereq *ikar = (struct ifkalivereq *)data;
struct gre_softc *sc = ifp->if_softc;
int s;
struct sockaddr_in si;
@@ -562,6 +570,34 @@ recompute:
sa = sintosa(&si);
ifr->ifr_addr = *sa;
break;
+ case SIOCSETKALIVE:
+ if ((error = suser(prc, 0)) != 0)
+ break;
+ if (ikar->ikar_timeo < 0 || ikar->ikar_timeo > 86400 ||
+ ikar->ikar_cnt < 0 || ikar->ikar_cnt > 256) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_ka_timout = ikar->ikar_timeo;
+ sc->sc_ka_cnt = ikar->ikar_cnt;
+ if (sc->sc_ka_timout == 0 || sc->sc_ka_cnt == 0) {
+ sc->sc_ka_timout = 0;
+ sc->sc_ka_cnt = 0;
+ sc->sc_ka_state = GRE_STATE_UKNWN;
+ gre_link_state(sc);
+ break;
+ }
+ if (!timeout_pending(&sc->sc_ka_snd)) {
+ sc->sc_ka_holdmax = sc->sc_ka_cnt;
+ timeout_add(&sc->sc_ka_snd, 1);
+ timeout_add_sec(&sc->sc_ka_hold, sc->sc_ka_timout *
+ sc->sc_ka_cnt);
+ }
+ break;
+ case SIOCGETKALIVE:
+ ikar->ikar_timeo = sc->sc_ka_timout;
+ ikar->ikar_cnt = sc->sc_ka_cnt;
+ break;
case SIOCSLIFPHYADDR:
if ((error = suser(prc, 0)) != 0)
break;
@@ -633,7 +669,7 @@ recompute:
* at least a default route which matches.
*/
-static void
+void
gre_compute_route(struct gre_softc *sc)
{
struct route *ro;
@@ -713,4 +749,120 @@ gre_in_cksum(u_int16_t *p, u_int len)
sum += (sum >> 16);
return (~sum);
}
+
+void
+gre_keepalive(void *arg)
+{
+ struct gre_softc *sc = arg;
+
+ if (!sc->sc_ka_timout)
+ return;
+
+ sc->sc_ka_state = GRE_STATE_DOWN;
+ gre_link_state(sc);
+}
+
+void
+gre_send_keepalive(void *arg)
+{
+ struct gre_softc *sc = arg;
+ struct mbuf *m;
+ struct ip *ip;
+ struct gre_h *gh;
+ struct sockaddr dst;
+ int s;
+
+ if (sc->sc_ka_timout)
+ timeout_add_sec(&sc->sc_ka_snd, sc->sc_ka_timout);
+
+ if (sc->g_proto != IPPROTO_GRE)
+ return;
+ if ((sc->sc_if.if_flags & IFF_UP) == 0 ||
+ sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY)
+ return;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ sc->sc_if.if_oerrors++;
+ return;
+ }
+
+ m->m_len = m->m_pkthdr.len = sizeof(*ip) + sizeof(*gh);
+ MH_ALIGN(m, m->m_len);
+
+ /* build the ip header */
+ ip = (struct ip *)m->m_data;
+
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_tos = IPTOS_LOWDELAY;
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip->ip_id = htons(ip_randomid());
+ ip->ip_off = htons(IP_DF);
+ ip->ip_ttl = ip_defttl;
+ ip->ip_p = IPPROTO_GRE;
+ ip->ip_src.s_addr = sc->g_dst.s_addr;
+ ip->ip_dst.s_addr = sc->g_src.s_addr;
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, sizeof(*ip));
+
+ gh = (struct gre_h *)(ip + 1);
+ /* We don't support any GRE flags for now */
+ bzero(gh, sizeof(*gh));
+
+ bzero(&dst, sizeof(dst));
+ dst.sa_family = AF_INET;
+
+ s = splsoftnet();
+ /* should we care about the error? */
+ gre_output(&sc->sc_if, m, &dst, NULL);
+ splx(s);
+}
+
+void
+gre_recv_keepalive(struct gre_softc *sc)
+{
+ if (!sc->sc_ka_timout)
+ return;
+
+ /* link state flap dampening */
+ switch (sc->sc_ka_state) {
+ case GRE_STATE_UKNWN:
+ case GRE_STATE_DOWN:
+ sc->sc_ka_state = GRE_STATE_HOLD;
+ sc->sc_ka_holdcnt = sc->sc_ka_holdmax;
+ sc->sc_ka_holdmax = MIN(sc->sc_ka_holdmax * 2,
+ 16 * sc->sc_ka_cnt);
+ break;
+ case GRE_STATE_HOLD:
+ if (--sc->sc_ka_holdcnt < 1) {
+ sc->sc_ka_state = GRE_STATE_UP;
+ gre_link_state(sc);
+ }
+ break;
+ case GRE_STATE_UP:
+ sc->sc_ka_holdmax = MAX(sc->sc_ka_holdmax--, sc->sc_ka_cnt);
+ break;
+ }
+
+ /* rescedule hold timer */
+ timeout_add_sec(&sc->sc_ka_hold, sc->sc_ka_timout * sc->sc_ka_cnt);
+}
+
+void
+gre_link_state(struct gre_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_if;
+ int link_state = LINK_STATE_UNKNOWN;
+
+ if (sc->sc_ka_state == GRE_STATE_UP)
+ link_state = LINK_STATE_UP;
+ else if (sc->sc_ka_state != GRE_STATE_UKNWN)
+ link_state = LINK_STATE_KALIVE_DOWN;
+
+ if (ifp->if_link_state != link_state) {
+ ifp->if_link_state = link_state;
+ if_link_state_change(ifp);
+ }
+}
#endif
diff --git a/sys/net/if_gre.h b/sys/net/if_gre.h
index 4b4e0c89678..58b2fe51bb1 100644
--- a/sys/net/if_gre.h
+++ b/sys/net/if_gre.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_gre.h,v 1.12 2009/11/21 14:08:14 claudio Exp $ */
+/* $OpenBSD: if_gre.h,v 1.13 2010/06/26 19:49:54 claudio Exp $ */
/* $NetBSD: if_gre.h,v 1.5 1999/11/19 20:41:19 thorpej Exp $ */
/*
@@ -34,16 +34,27 @@
#define _NET_IF_GRE_H
struct gre_softc {
- struct ifnet sc_if;
- LIST_ENTRY(gre_softc) sc_list;
- struct in_addr g_src; /* source address of gre packets */
- struct in_addr g_dst; /* destination address of gre packets */
- struct route route; /* routing entry that determines, where a
- encapsulated packet should go */
- int gre_unit;
- int gre_flags;
+ struct ifnet sc_if;
+ LIST_ENTRY(gre_softc) sc_list;
+ struct timeout sc_ka_hold;
+ struct timeout sc_ka_snd;
+ struct in_addr g_src; /* source address of gre packets */
+ struct in_addr g_dst; /* destination address of gre packets */
+ struct route route; /* routing entry that determines, where
+ an encapsulated packet should go */
u_int g_rtableid; /* routing table used for the tunnel */
- u_char g_proto; /* protocol of encapsulator */
+ int gre_unit;
+ int gre_flags;
+ int sc_ka_timout;
+ int sc_ka_holdmax;
+ int sc_ka_holdcnt;
+ int sc_ka_cnt;
+ u_char g_proto; /* protocol of encapsulator */
+ u_char sc_ka_state;
+#define GRE_STATE_UKNWN 0
+#define GRE_STATE_DOWN 1
+#define GRE_STATE_HOLD 2
+#define GRE_STATE_UP 3
};
@@ -143,5 +154,6 @@ int gre_ioctl(struct ifnet *, u_long, caddr_t);
int gre_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
u_int16_t gre_in_cksum(u_int16_t *, u_int);
+void gre_recv_keepalive(struct gre_softc *);
#endif /* _KERNEL */
#endif /* _NET_IF_GRE_H_ */
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
index a0652b1ed3c..b53af449470 100644
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_gre.c,v 1.37 2010/05/11 09:22:56 claudio Exp $ */
+/* $OpenBSD: ip_gre.c,v 1.38 2010/06/26 19:49:54 claudio Exp $ */
/* $NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
/*
@@ -187,6 +187,11 @@ gre_input2(m , hlen, proto)
af = AF_INET6;
break;
#endif
+ case 0:
+ /* keepalive reply, retrigger hold timer */
+ gre_recv_keepalive(sc);
+ m_freem(m);
+ return (1);
#ifdef MPLS
case ETHERTYPE_MPLS:
case ETHERTYPE_MPLS_MCAST:
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index 6f7358756a8..3b1996bdaf5 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sockio.h,v 1.46 2009/11/21 14:08:14 claudio Exp $ */
+/* $OpenBSD: sockio.h,v 1.47 2010/06/26 19:49:54 claudio Exp $ */
/* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */
/*-
@@ -179,6 +179,9 @@
#define SIOCSLIFPHYRTABLEID _IOW('i', 161, struct ifreq) /* set tunnel VRF id */
#define SIOCGLIFPHYRTABLEID _IOWR('i', 162, struct ifreq) /* get tunnel id */
+#define SIOCSETKALIVE _IOW('i', 163, struct ifkalivereq)
+#define SIOCGETKALIVE _IOWR('i', 164, struct ifkalivereq)
+
#define SIOCSVH _IOWR('i', 245, struct ifreq) /* set carp param */
#define SIOCGVH _IOWR('i', 246, struct ifreq) /* get carp param */