From: Roy Marples Date: Sun, 2 Jun 2013 09:51:30 +0000 (+0000) Subject: Automate the assignment of SLA ids if not given for Prefix Delegation. X-Git-Tag: v5.99.7~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=22ea2b0deb960aa6e669de1a7b599833fb45de37;p=thirdparty%2Fdhcpcd.git Automate the assignment of SLA ids if not given for Prefix Delegation. This means you can just request an ia_pd and let dhcpcd do the rest :) --- diff --git a/dhcp6.c b/dhcp6.c index 4fcde669..af98fd64 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -1495,22 +1495,10 @@ dhcp6_startinit(struct interface *ifp) dhcp6_startdiscover(ifp); } -static struct ipv6_addr * -dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix, - const struct if_sla *sla, struct interface *ifs) +static struct dhcp6_state * +dhcp6_getstate(struct interface *ifp) { - struct in6_addr addr; struct dhcp6_state *state; - struct ipv6_addr *a, *ap; - char iabuf[INET6_ADDRSTRLEN]; - const char *ia; - - if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len, - sla->sla, &addr, sla->prefix_len) == -1) - { - syslog(LOG_ERR, "%s: invalid prefix", ifp->name); - return NULL; - } state = D6_STATE(ifp); if (state == NULL) { @@ -1525,6 +1513,33 @@ dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix, state->state = DH6S_DELEGATED; state->reason = "DELEGATED6"; } + return state; +} + +static struct ipv6_addr * +dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix, + const struct if_sla *sla, struct interface *ifs) +{ + struct in6_addr addr; + struct dhcp6_state *state; + struct ipv6_addr *a, *ap; + char iabuf[INET6_ADDRSTRLEN]; + const char *ia; + + if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len, + sla->sla, &addr, sla->prefix_len) == -1) + { + ia = inet_ntop(AF_INET6, &prefix->prefix.s6_addr, + iabuf, sizeof(iabuf)); + syslog(LOG_ERR, "%s: invalid prefix %s/%d + %d/%d: %m", + ifp->name, ia, prefix->prefix_len, + sla->sla, sla->prefix_len); + return NULL; + } + + state = dhcp6_getstate(ifp); + if (state == NULL) + return NULL; a = calloc(1, sizeof(*a)); if (a == NULL) { @@ -1565,6 +1580,29 @@ dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix, return a; } +static uint32_t +dhcp6_findsla(void) +{ + uint32_t sla; + const struct interface *ifp; + const struct dhcp6_state *state; + + /* Slow, but finding the lowest free SLA is needed if we get a + * /62 or /63 prefix from upstream */ + for (sla = 0; sla < UINT32_MAX; sla++) { + TAILQ_FOREACH(ifp, ifaces, next) { + state = D6_CSTATE(ifp); + if (state && state->sla_set && state->sla == sla) + break; + } + if (ifp == NULL) + return sla; + } + + errno = E2BIG; + return 0; +} + static void dhcp6_delegate_prefix(struct interface *ifp) { @@ -1573,10 +1611,11 @@ dhcp6_delegate_prefix(struct interface *ifp) struct ipv6_addr *ap; size_t i, j, k; struct if_iaid *iaid; - struct if_sla *sla; + struct if_sla *sla, asla; struct interface *ifd; uint8_t carrier_warned; + asla.prefix_len = 64; ifo = ifp->options; state = D6_STATE(ifp); TAILQ_FOREACH(ifd, ifaces, next) { @@ -1593,6 +1632,42 @@ dhcp6_delegate_prefix(struct interface *ifp) if (memcmp(iaid->iaid, ap->iaid, sizeof(iaid->iaid))) continue; + if (iaid->sla_len == 0) { + /* no SLA configured, so lets + * automate it */ + if (ifp == ifd) + continue; + ifd_state = dhcp6_getstate(ifd); + if (ifd_state == NULL) + return; + if (!ifd_state->sla_set) { + errno = 0; + ifd_state->sla = + dhcp6_findsla(); + if (errno) { + syslog(LOG_ERR, + "%s: dhcp6_find_sla:" + " %m", ifd->name); + continue; + } + syslog(LOG_DEBUG, + "%s: set SLA %d", + ifd->name, ifd_state->sla); + ifd_state->sla_set = 1; + } + asla.sla = ifd_state->sla; + if (ifd->carrier == LINK_DOWN) { + syslog(LOG_DEBUG, + "%s: has no carrier, cannot" + " delegate addresses", + ifd->name); + carrier_warned = 1; + break; + } + if (dhcp6_delegate_addr(ifd, ap, + &asla, ifp)) + k++; + } for (j = 0; j < iaid->sla_len; j++) { sla = &iaid->sla[j]; if (strcmp(ifd->name, sla->ifname)) diff --git a/dhcp6.h b/dhcp6.h index 036e0df9..151c3f5e 100644 --- a/dhcp6.h +++ b/dhcp6.h @@ -179,6 +179,8 @@ struct dhcp6_state { uint32_t expire; struct ipv6_addrhead addrs; uint32_t lowpl; + uint32_t sla; + uint8_t sla_set; char leasefile[PATH_MAX]; const char *reason; }; diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index 9f374e1d..6db7c5b5 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -133,7 +133,7 @@ is an empty string then the current system hostname is sent. If .Ar hostname is a FQDN (ie, contains a .) then it will be encoded as such. -.It Ic ia_na Ar iaid +.It Ic ia_na Op Ar iaid Request a DHCPv6 Normal Address for .Ar iaid . If none is specified, a default @@ -141,26 +141,35 @@ If none is specified, a default is used. If the interface name is 4 characters or less then that is used, otherwise the interface index is used. -.It Ic ia_ta Ar iaid +.It Ic ia_ta Op Ar iaid Request a DHCPv6 Temporary Address for .Ar iaid . -.It Ic ia_pd Ar iaid Op Ar interface / Ar sla_id Op / Ar prefix_len +.It Ic ia_pd Op Ar iaid Op Ar interface / Ar sla_id Op / Ar prefix_len Request a DHCPv6 Delegated Prefix for .Ar iaid . -If an +If no +.Ar interface +is given then we will assign a prefix to every other interface with a unique +.Ar sla_id +for each, starting from 0. +Otherwise addresses are only assigned for each .Ar interface and .Ar sla_id -is given, -then an address is also assigned to that -.Ar interface . A default .Ar prefix_len -of 64 is assumed if not given. +of 64 is assumed. .Ar sla_id is an integer and is added to the prefix which must fit inside .Ar prefix_len less the length of the delegated prefix. +You can specify multiple +.Ar interface / +.Ar sla_id / +.Ar prefix_len +per +.Ic ia_pd , +space separated. IPv6RS should be disabled globally when requesting a Prefix Delegation like so: .Pp .D1 noipv6rs diff --git a/ipv6.c b/ipv6.c index 6708d449..e0014ad0 100644 --- a/ipv6.c +++ b/ipv6.c @@ -363,10 +363,10 @@ h64_to_in6(uint64_t vhigh, uint64_t vlow, struct in6_addr *add) int ipv6_userprefix( const struct in6_addr *prefix, // prefix from router - int prefix_len, // length of prefix received + short prefix_len, // length of prefix received uint64_t user_number, // "random" number from user struct in6_addr *result, // resultant prefix - int result_len) // desired prefix length + short result_len) // desired prefix length { uint64_t vh, vl, user_low, user_high; diff --git a/ipv6.h b/ipv6.h index 635f16b6..dcd1480c 100644 --- a/ipv6.h +++ b/ipv6.h @@ -144,8 +144,8 @@ int ipv6_makeaddr(struct in6_addr *, const struct interface *, int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int); int ipv6_mask(struct in6_addr *, int); int ipv6_prefixlen(const struct in6_addr *); -int ipv6_userprefix( const struct in6_addr *, int prefix_len, - uint64_t user_number, struct in6_addr *result, int result_len); +int ipv6_userprefix( const struct in6_addr *, short prefix_len, + uint64_t user_number, struct in6_addr *result, short result_len); int ipv6_addaddr(struct ipv6_addr *); ssize_t ipv6_addaddrs(struct ipv6_addrhead *); void ipv6_handleifa(int, struct if_head *,