Claudio Jeker(cje...@diehard.n-r-g.com) on 2023.10.16 09:23:12 +0200:
> This diff fixes a few more things when establishing connections with
> link-local IPv6 addresses. In get_alternate_addr() the interface scope
> of the connection is recovered and then passed to the RDE. The RDE can
> then use this scope id to insert link-local addresses with the correct
> scope.

looks good.
 
> I built a regress test for this which passes with this diff.
> Now probably more is needed because IPv6 link-local addresses are a gift
> that keep on giving. One thing to implement on top of this is template
> matching for link local -- which allows to auto-configure sessions more
> easily. This will probably follow soon.

it would be nice if that could match just on interfaces. As in "neighbor
<interface>", with some syntactic sugar so its clear this is for
link-local?

 
> -- 
> :wq Claudio
> 
> Index: bgpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.477
> diff -u -p -r1.477 bgpd.h
> --- bgpd.h    30 Aug 2023 08:16:28 -0000      1.477
> +++ bgpd.h    9 Oct 2023 13:50:36 -0000
> @@ -796,6 +796,7 @@ struct session_up {
>       struct bgpd_addr        remote_addr;
>       struct capabilities     capa;
>       uint32_t                remote_bgpid;
> +     unsigned int            if_scope;
>       uint16_t                short_as;
>  };
>  
> @@ -1439,6 +1440,7 @@ void             kr_ifinfo(char *);
>  void          kr_net_reload(u_int, uint64_t, struct network_head *);
>  int           kr_reload(void);
>  int           get_mpe_config(const char *, u_int *, u_int *);
> +uint8_t               mask2prefixlen(sa_family_t, struct sockaddr *);
>  
>  /* log.c */
>  void          log_peer_info(const struct peer_config *, const char *, ...)
> Index: kroute.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
> retrieving revision 1.305
> diff -u -p -r1.305 kroute.c
> --- kroute.c  1 Jun 2023 09:47:34 -0000       1.305
> +++ kroute.c  9 Oct 2023 13:54:25 -0000
> @@ -168,8 +168,6 @@ struct kroute6    *kroute6_match(struct kta
>  void          kroute_detach_nexthop(struct ktable *, struct knexthop *);
>  
>  uint8_t              prefixlen_classful(in_addr_t);
> -uint8_t              mask2prefixlen(in_addr_t);
> -uint8_t              mask2prefixlen6(struct sockaddr_in6 *);
>  uint64_t     ift2ifm(uint8_t);
>  const char   *get_media_descr(uint64_t);
>  const char   *get_linkstate(uint8_t, int);
> @@ -2419,21 +2417,28 @@ prefixlen_classful(in_addr_t ina)
>               return (8);
>  }
>  
> -uint8_t
> -mask2prefixlen(in_addr_t ina)
> +static uint8_t
> +mask2prefixlen4(struct sockaddr_in *sa_in)
>  {
> +     in_addr_t ina;
> +
> +     if (sa_in->sin_len == 0)
> +             return (0);
> +     ina = sa_in->sin_addr.s_addr;
>       if (ina == 0)
>               return (0);
>       else
>               return (33 - ffs(ntohl(ina)));
>  }
>  
> -uint8_t
> +static uint8_t
>  mask2prefixlen6(struct sockaddr_in6 *sa_in6)
>  {
>       uint8_t *ap, *ep;
>       u_int    l = 0;
>  
> +     if (sa_in6->sin6_len == 0)
> +             return (0);
>       /*
>        * sin6_len is the size of the sockaddr so subtract the offset of
>        * the possibly truncated sin6_addr struct.
> @@ -2480,6 +2485,19 @@ mask2prefixlen6(struct sockaddr_in6 *sa_
>       return (l);
>  }
>  
> +uint8_t
> +mask2prefixlen(sa_family_t af, struct sockaddr *mask)
> +{
> +     switch (af) {
> +     case AF_INET:
> +             return mask2prefixlen4((struct sockaddr_in *)mask);
> +     case AF_INET6:
> +             return mask2prefixlen6((struct sockaddr_in6 *)mask);
> +     default:
> +             fatalx("%s: unsupported af", __func__);
> +     }
> +}
> +
>  const struct if_status_description
>               if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
>  const struct ifmedia_description
> @@ -3079,9 +3097,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt
>       case AF_INET:
>               sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
>               if (sa_in != NULL) {
> -                     if (sa_in->sin_len != 0)
> -                             kf->prefixlen =
> -                                 mask2prefixlen(sa_in->sin_addr.s_addr);
> +                     kf->prefixlen = mask2prefixlen4(sa_in);
>               } else if (rtm->rtm_flags & RTF_HOST)
>                       kf->prefixlen = 32;
>               else
> @@ -3091,8 +3107,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt
>       case AF_INET6:
>               sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
>               if (sa_in6 != NULL) {
> -                     if (sa_in6->sin6_len != 0)
> -                             kf->prefixlen = mask2prefixlen6(sa_in6);
> +                     kf->prefixlen = mask2prefixlen6(sa_in6);
>               } else if (rtm->rtm_flags & RTF_HOST)
>                       kf->prefixlen = 128;
>               else
> Index: logmsg.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/logmsg.c,v
> retrieving revision 1.9
> diff -u -p -r1.9 logmsg.c
> --- logmsg.c  24 Aug 2022 17:14:02 -0000      1.9
> +++ logmsg.c  14 Oct 2023 09:49:36 -0000
> @@ -60,55 +60,54 @@ log_fmt_peer(const struct peer_config *p
>  void
>  log_peer_info(const struct peer_config *peer, const char *emsg, ...)
>  {
> -     char    *p, *nfmt;
> +     char    *p, *msg;
>       va_list  ap;
>  
>       p = log_fmt_peer(peer);
> -     if (asprintf(&nfmt, "%s: %s", p, emsg) == -1)
> -             fatal(NULL);
>       va_start(ap, emsg);
> -     vlog(LOG_INFO, nfmt, ap);
> +     if (vasprintf(&msg, emsg, ap) == -1)
> +             fatal(NULL);
>       va_end(ap);
> +     logit(LOG_INFO, "%s: %s", p, msg);
> +     free(msg);
>       free(p);
> -     free(nfmt);
>  }
>  
>  void
>  log_peer_warn(const struct peer_config *peer, const char *emsg, ...)
>  {
> -     char    *p, *nfmt;
> +     char    *p, *msg;
>       va_list  ap;
> +     int      saved_errno = errno;
>  
>       p = log_fmt_peer(peer);
>       if (emsg == NULL) {
> -             if (asprintf(&nfmt, "%s: %s", p, strerror(errno)) == -1)
> -                     fatal(NULL);
> +             logit(LOG_ERR, "%s: %s", p, strerror(saved_errno));
>       } else {
> -             if (asprintf(&nfmt, "%s: %s: %s", p, emsg, strerror(errno)) ==
> -                 -1)
> +             va_start(ap, emsg);
> +             if (vasprintf(&msg, emsg, ap) == -1)
>                       fatal(NULL);
> +             va_end(ap);
> +             logit(LOG_ERR, "%s: %s: %s", p, msg, strerror(saved_errno));
> +             free(msg);
>       }
> -     va_start(ap, emsg);
> -     vlog(LOG_ERR, nfmt, ap);
> -     va_end(ap);
>       free(p);
> -     free(nfmt);
>  }
>  
>  void
>  log_peer_warnx(const struct peer_config *peer, const char *emsg, ...)
>  {
> -     char    *p, *nfmt;
> +     char    *p, *msg;
>       va_list  ap;
>  
>       p = log_fmt_peer(peer);
> -     if (asprintf(&nfmt, "%s: %s", p, emsg) == -1)
> -             fatal(NULL);
>       va_start(ap, emsg);
> -     vlog(LOG_ERR, nfmt, ap);
> +     if (vasprintf(&msg, emsg, ap) == -1)
> +             fatal(NULL);
>       va_end(ap);
> +     logit(LOG_ERR, "%s: %s", p, msg);
> +     free(msg);
>       free(p);
> -     free(nfmt);
>  }
>  
>  void
> Index: rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.610
> diff -u -p -r1.610 rde.c
> --- rde.c     16 Aug 2023 08:26:35 -0000      1.610
> +++ rde.c     9 Oct 2023 14:16:23 -0000
> @@ -59,7 +59,7 @@ int          rde_attr_parse(u_char *, uint16_t,
>  int           rde_attr_add(struct filterstate *, u_char *, uint16_t);
>  uint8_t               rde_attr_missing(struct rde_aspath *, int, uint16_t);
>  int           rde_get_mp_nexthop(u_char *, uint16_t, uint8_t,
> -                 struct filterstate *);
> +                 struct rde_peer *, struct filterstate *);
>  void          rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *);
>  uint8_t               rde_aspa_validity(struct rde_peer *, struct rde_aspath 
> *,
>                   uint8_t);
> @@ -1797,7 +1797,8 @@ rde_update_dispatch(struct rde_peer *pee
>               /* unlock the previously locked nexthop, it is no longer used */
>               nexthop_unref(state.nexthop);
>               state.nexthop = NULL;
> -             if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, &state)) == -1) {
> +             if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, peer,
> +                 &state)) == -1) {
>                       log_peer_warnx(&peer->conf, "bad nlri nexthop");
>                       rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
>                           mpa.reach, mpa.reach_len);
> @@ -2482,7 +2483,7 @@ rde_attr_missing(struct rde_aspath *a, i
>  
>  int
>  rde_get_mp_nexthop(u_char *data, uint16_t len, uint8_t aid,
> -    struct filterstate *state)
> +    struct rde_peer *peer, struct filterstate *state)
>  {
>       struct bgpd_addr        nexthop;
>       uint8_t                 totlen, nhlen;
> @@ -2509,12 +2510,22 @@ rde_get_mp_nexthop(u_char *data, uint16_
>                * traffic.
>                */
>               if (nhlen != 16 && nhlen != 32) {
> -                     log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
> -                         nhlen);
> +                     log_peer_warnx(&peer->conf, "bad %s nexthop, "
> +                         "bad size %d", aid2str(aid), nhlen);
>                       return (-1);
>               }
>               memcpy(&nexthop.v6.s6_addr, data, 16);
>               nexthop.aid = AID_INET6;
> +             if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
> +                     if (peer->local_if_scope != 0) {
> +                             nexthop.scope_id = peer->local_if_scope;
> +                     } else {
> +                             log_peer_warnx(&peer->conf,
> +                                 "unexpected link-local nexthop: %s",
> +                                 log_addr(&nexthop));
> +                             return (-1);
> +                     }
> +             }
>               break;
>       case AID_VPN_IPv4:
>               /*
> @@ -2531,8 +2542,8 @@ rde_get_mp_nexthop(u_char *data, uint16_
>                * AID_VPN_IPv4 in nexthop and kroute.
>                */
>               if (nhlen != 12) {
> -                     log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
> -                         nhlen);
> +                     log_peer_warnx(&peer->conf, "bad %s nexthop, "
> +                         "bad size %d", aid2str(aid), nhlen);
>                       return (-1);
>               }
>               nexthop.aid = AID_INET;
> @@ -2541,26 +2552,37 @@ rde_get_mp_nexthop(u_char *data, uint16_
>               break;
>       case AID_VPN_IPv6:
>               if (nhlen != 24) {
> -                     log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
> -                         nhlen);
> +                     log_peer_warnx(&peer->conf, "bad %s nexthop, "
> +                         "bad size %d", aid2str(aid), nhlen);
>                       return (-1);
>               }
>               memcpy(&nexthop.v6, data + sizeof(uint64_t),
>                   sizeof(nexthop.v6));
>               nexthop.aid = AID_INET6;
> +             if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
> +                     if (peer->local_if_scope != 0) {
> +                             nexthop.scope_id = peer->local_if_scope;
> +                     } else {
> +                             log_peer_warnx(&peer->conf,
> +                                 "unexpected link-local nexthop: %s",
> +                                 log_addr(&nexthop));
> +                             return (-1);
> +                     }
> +             }
>               break;
>       case AID_FLOWSPECv4:
>       case AID_FLOWSPECv6:
>               /* nexthop must be 0 and ignored for flowspec */
>               if (nhlen != 0) {
> -                     log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
> -                         nhlen);
> +                     log_peer_warnx(&peer->conf, "bad %s nexthop, "
> +                         "bad size %d", aid2str(aid), nhlen);
>                       return (-1);
>               }
>               /* also ignore reserved (old SNPA) field as per RFC4760 */
>               return (totlen + 1);
>       default:
> -             log_warnx("bad multiprotocol nexthop, bad AID");
> +             log_peer_warnx(&peer->conf, "bad multiprotocol nexthop, "
> +                 "bad AID");
>               return (-1);
>       }
>  
> Index: rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.296
> diff -u -p -r1.296 rde.h
> --- rde.h     16 Aug 2023 08:26:35 -0000      1.296
> +++ rde.h     9 Oct 2023 07:26:49 -0000
> @@ -92,6 +92,7 @@ struct rde_peer {
>       time_t                           staletime[AID_MAX];
>       uint32_t                         remote_bgpid; /* host byte order! */
>       uint32_t                         path_id_tx;
> +     unsigned int                     local_if_scope;
>       enum peer_state                  state;
>       enum export_type                 export_type;
>       enum role                        role;
> Index: rde_peer.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
> retrieving revision 1.32
> diff -u -p -r1.32 rde_peer.c
> --- rde_peer.c        19 Apr 2023 13:23:33 -0000      1.32
> +++ rde_peer.c        26 Apr 2023 14:04:35 -0000
> @@ -430,6 +430,7 @@ peer_up(struct rde_peer *peer, struct se
>       peer->remote_addr = sup->remote_addr;
>       peer->local_v4_addr = sup->local_v4_addr;
>       peer->local_v6_addr = sup->local_v6_addr;
> +     peer->local_if_scope = sup->if_scope;
>       memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
>  
>       /* clear eor markers depending on GR flags */
> Index: rde_rib.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
> retrieving revision 1.260
> diff -u -p -r1.260 rde_rib.c
> --- rde_rib.c 23 Apr 2023 11:39:10 -0000      1.260
> +++ rde_rib.c 9 Oct 2023 14:05:30 -0000
> @@ -1910,7 +1910,7 @@ nexthop_compare(struct nexthop *na, stru
>       case AID_INET6:
>               return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
>       default:
> -             fatalx("nexthop_cmp: unknown af");
> +             fatalx("nexthop_cmp: unknown aid %s", aid2str(a->aid));
>       }
>       return (-1);
>  }
> Index: session.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
> retrieving revision 1.448
> diff -u -p -r1.448 session.c
> --- session.c 9 Oct 2023 07:11:20 -0000       1.448
> +++ session.c 16 Oct 2023 07:13:58 -0000
> @@ -1202,37 +1202,64 @@ session_setup_socket(struct peer *p)
>       return (0);
>  }
>  
> -/* compare two sockaddrs by converting them into bgpd_addr */
> +/*
> + * compare the bgpd_addr with the sockaddr by converting the latter into
> + * a bgpd_addr. Return true if the two are equal, including any scope
> + */
>  static int
> -sa_equal(struct sockaddr *a, struct sockaddr *b)
> +sa_equal(struct bgpd_addr *ba, struct sockaddr *b)
>  {
> -     struct bgpd_addr ba, bb;
> +     struct bgpd_addr bb;
>  
> -     sa2addr(a, &ba, NULL);
>       sa2addr(b, &bb, NULL);
> -
> -     return (memcmp(&ba, &bb, sizeof(ba)) == 0);
> +     return (memcmp(ba, &bb, sizeof(*ba)) == 0);
>  }
>  
>  static void
> -get_alternate_addr(struct sockaddr *sa, struct bgpd_addr *alt)
> +get_alternate_addr(struct bgpd_addr *local, struct bgpd_addr *remote,
> +    struct bgpd_addr *alt, unsigned int *scope)
>  {
>       struct ifaddrs  *ifap, *ifa, *match;
> +     int connected = 0;
> +     u_int8_t plen;
>  
>       if (getifaddrs(&ifap) == -1)
>               fatal("getifaddrs");
>  
> -     for (match = ifap; match != NULL; match = match->ifa_next)
> -             if (match->ifa_addr != NULL && sa_equal(sa, match->ifa_addr))
> +     for (match = ifap; match != NULL; match = match->ifa_next) {
> +             if (match->ifa_addr == NULL)
> +                     continue;
> +             if (match->ifa_addr->sa_family != AF_INET &&
> +                 match->ifa_addr->sa_family != AF_INET6)
> +                     continue;
> +             if (sa_equal(local, match->ifa_addr)) {
> +                     if (match->ifa_flags & IFF_POINTOPOINT &&
> +                         match->ifa_dstaddr) {
> +                             if (sa_equal(remote, match->ifa_dstaddr))
> +                                     connected = 1;
> +                     } else if (match->ifa_netmask) {
> +                             plen = mask2prefixlen(
> +                                 match->ifa_addr->sa_family,
> +                                 match->ifa_netmask);
> +                             if (plen != 0xff &&
> +                                 prefix_compare(local, remote, plen) == 0)
> +                                     connected = 1;
> +                     }
>                       break;
> +             }
> +     }
>  
>       if (match == NULL) {
>               log_warnx("%s: local address not found", __func__);
>               return;
>       }
> +     if (connected)
> +             *scope = if_nametoindex(match->ifa_name);
> +     else
> +             *scope = 0;
>  
> -     switch (sa->sa_family) {
> -     case AF_INET6:
> +     switch (local->aid) {
> +     case AID_INET6:
>               for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
>                       if (ifa->ifa_addr != NULL &&
>                           ifa->ifa_addr->sa_family == AF_INET &&
> @@ -1242,7 +1269,7 @@ get_alternate_addr(struct sockaddr *sa, 
>                       }
>               }
>               break;
> -     case AF_INET:
> +     case AID_INET:
>               for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
>                       if (ifa->ifa_addr != NULL &&
>                           ifa->ifa_addr->sa_family == AF_INET6 &&
> @@ -1260,8 +1287,8 @@ get_alternate_addr(struct sockaddr *sa, 
>               }
>               break;
>       default:
> -             log_warnx("%s: unsupported address family %d", __func__,
> -                 sa->sa_family);
> +             log_warnx("%s: unsupported address family %s", __func__,
> +                 aid2str(local->aid));
>               break;
>       }
>  
> @@ -1278,11 +1305,13 @@ session_tcp_established(struct peer *pee
>       if (getsockname(peer->fd, (struct sockaddr *)&ss, &len) == -1)
>               log_warn("getsockname");
>       sa2addr((struct sockaddr *)&ss, &peer->local, &peer->local_port);
> -     get_alternate_addr((struct sockaddr *)&ss, &peer->local_alt);
>       len = sizeof(ss);
>       if (getpeername(peer->fd, (struct sockaddr *)&ss, &len) == -1)
>               log_warn("getpeername");
>       sa2addr((struct sockaddr *)&ss, &peer->remote, &peer->remote_port);
> +
> +     get_alternate_addr(&peer->local, &peer->remote, &peer->local_alt,
> +         &peer->if_scope);
>  }
>  
>  void
> @@ -3546,6 +3575,7 @@ session_up(struct peer *p)
>               sup.local_v4_addr = p->local_alt;
>       }
>       sup.remote_addr = p->remote;
> +     sup.if_scope = p->if_scope;
>  
>       sup.remote_bgpid = p->remote_bgpid;
>       sup.short_as = p->short_as;
> Index: session.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
> retrieving revision 1.162
> diff -u -p -r1.162 session.h
> --- session.h 28 Mar 2023 12:15:23 -0000      1.162
> +++ session.h 30 Mar 2023 07:17:19 -0000
> @@ -240,6 +240,7 @@ struct peer {
>       int                      lasterr;
>       u_int                    errcnt;
>       u_int                    IdleHoldTime;
> +     unsigned int             if_scope;      /* interface scope for IPv6 */
>       uint32_t                 remote_bgpid;
>       enum session_state       state;
>       enum session_state       prev_state;
> 

Reply via email to