diff options
Diffstat (limited to 'zebra/kernel_socket.c')
| -rw-r--r-- | zebra/kernel_socket.c | 168 |
1 files changed, 142 insertions, 26 deletions
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 3e46a79e96..f3561cc19d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -232,8 +232,11 @@ int dplane_routing_sock = -1; /* Yes I'm checking ugly routing socket behavior. */ /* #define DEBUG */ +size_t _rta_get(caddr_t sap, void *destp, size_t destlen, bool checkaf); size_t rta_get(caddr_t sap, void *dest, size_t destlen); +size_t rta_getattr(caddr_t sap, void *destp, size_t destlen); size_t rta_getsdlname(caddr_t sap, void *dest, short *destlen); +const char *rtatostr(unsigned int flags, char *buf, size_t buflen); /* Supported address family check. */ static inline int af_check(int family) @@ -245,9 +248,10 @@ static inline int af_check(int family) return 0; } -size_t rta_get(caddr_t sap, void *destp, size_t destlen) +size_t _rta_get(caddr_t sap, void *destp, size_t destlen, bool checkaf) { struct sockaddr *sa = (struct sockaddr *)sap; + struct sockaddr_dl *sdl; uint8_t *dest = destp; size_t tlen, copylen; @@ -258,7 +262,21 @@ size_t rta_get(caddr_t sap, void *destp, size_t destlen) copylen = tlen = SAROUNDUP(sap); #endif /* !HAVE_STRUCT_SOCKADDR_SA_LEN */ - if (copylen > 0 && dest != NULL && af_check(sa->sa_family)) { + if (copylen > 0 && dest != NULL) { + if (checkaf && af_check(sa->sa_family) == 0) + return tlen; + /* + * Handle sockaddr_dl corner case: + * RTA_NETMASK might be AF_LINK, but it doesn't anything + * relevant (e.g. zeroed out fields). Check for this + * case and avoid warning log message. + */ + if (sa->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)sa; + if (sdl->sdl_index == 0 || sdl->sdl_nlen == 0) + copylen = destlen; + } + if (copylen > destlen) { zlog_warn("%s: destination buffer too small (%lu vs %lu)", __func__, copylen, destlen); @@ -270,6 +288,16 @@ size_t rta_get(caddr_t sap, void *destp, size_t destlen) return tlen; } +size_t rta_get(caddr_t sap, void *destp, size_t destlen) +{ + return _rta_get(sap, destp, destlen, true); +} + +size_t rta_getattr(caddr_t sap, void *destp, size_t destlen) +{ + return _rta_get(sap, destp, destlen, false); +} + size_t rta_getsdlname(caddr_t sap, void *destp, short *destlen) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sap; @@ -302,6 +330,85 @@ size_t rta_getsdlname(caddr_t sap, void *destp, short *destlen) return tlen; } +const char *rtatostr(unsigned int flags, char *buf, size_t buflen) +{ + const char *flagstr, *bufstart; + int bit, wlen; + char ustr[32]; + + /* Hold the pointer to the buffer beginning. */ + bufstart = buf; + + for (bit = 1; bit; bit <<= 1) { + if ((flags & bit) == 0) + continue; + + switch (bit) { + case RTA_DST: + flagstr = "DST"; + break; + case RTA_GATEWAY: + flagstr = "GATEWAY"; + break; + case RTA_NETMASK: + flagstr = "NETMASK"; + break; +#ifdef RTA_GENMASK + case RTA_GENMASK: + flagstr = "GENMASK"; + break; +#endif /* RTA_GENMASK */ + case RTA_IFP: + flagstr = "IFP"; + break; + case RTA_IFA: + flagstr = "IFA"; + break; +#ifdef RTA_AUTHOR + case RTA_AUTHOR: + flagstr = "AUTHOR"; + break; +#endif /* RTA_AUTHOR */ + case RTA_BRD: + flagstr = "BRD"; + break; +#ifdef RTA_SRC + case RTA_SRC: + flagstr = "SRC"; + break; +#endif /* RTA_SRC */ +#ifdef RTA_SRCMASK + case RTA_SRCMASK: + flagstr = "SRCMASK"; + break; +#endif /* RTA_SRCMASK */ +#ifdef RTA_LABEL + case RTA_LABEL: + flagstr = "LABEL"; + break; +#endif /* RTA_LABEL */ + + default: + snprintf(ustr, sizeof(ustr), "0x%x", bit); + flagstr = ustr; + break; + } + + wlen = snprintf(buf, buflen, "%s,", flagstr); + buf += wlen; + buflen -= wlen; + } + + /* Check for empty buffer. */ + if (bufstart != buf) + buf--; + + /* Remove the last comma. */ + *buf = 0; + + return bufstart; +} + /* Dump routing table flag for debug purpose. */ static void rtm_flag_dump(int flag) { @@ -416,6 +523,7 @@ int ifm_read(struct if_msghdr *ifm) short ifnlen = 0; int maskbit; caddr_t cp; + char fbuf[64]; /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; @@ -461,8 +569,9 @@ int ifm_read(struct if_msghdr *ifm) } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: sdl ifname %s", __func__, - (ifnlen ? ifname : "(nil)")); + zlog_debug("%s: sdl ifname %s addrs {%s}", __func__, + (ifnlen ? ifname : "(nil)"), + rtatostr(ifm->ifm_addrs, fbuf, sizeof(fbuf))); /* * Look up on ifindex first, because ifindices are the primary handle @@ -660,6 +769,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, union sockunion dst; union sockunion gateway; int maskbit; + char fbuf[64]; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen; @@ -684,7 +794,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, pnt += rta_get(pnt, &gateway, sizeof(gateway)); break; case RTA_NETMASK: - pnt += rta_get(pnt, mask, sizeof(*mask)); + pnt += rta_getattr(pnt, mask, sizeof(*mask)); break; case RTA_IFP: pnt += rta_getsdlname(pnt, ifname, ifnlen); @@ -709,40 +819,42 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, } if (IS_ZEBRA_DEBUG_KERNEL) { - int family = sockunion_family(addr); - switch (family) { + switch (sockunion_family(addr)) { case AF_INET: case AF_INET6: { char buf[4][INET6_ADDRSTRLEN]; + int masklen = + (sockunion_family(addr) == AF_INET) + ? ip_masklen(mask->sin.sin_addr) + : ip6_masklen(mask->sin6.sin6_addr); zlog_debug( - "%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " + "%s: ifindex %d, ifname %s, ifam_addrs {%s}, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, - (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, + (ifnlen ? ifname : "(nil)"), + rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)), ifm->ifam_flags, - inet_ntop(family, &addr->sin.sin_addr, buf[0], - sizeof(buf[0])), - ip_masklen(mask->sin.sin_addr), - inet_ntop(family, &brd->sin.sin_addr, buf[1], - sizeof(buf[1])), - inet_ntop(family, &dst.sin.sin_addr, buf[2], - sizeof(buf[2])), - inet_ntop(family, &gateway.sin.sin_addr, buf[3], - sizeof(buf[3]))); + sockunion2str(addr, buf[0], sizeof(buf[0])), + masklen, + sockunion2str(brd, buf[1], sizeof(buf[1])), + sockunion2str(&dst, buf[2], sizeof(buf[2])), + sockunion2str(&gateway, buf[2], + sizeof(buf[2]))); } break; default: - zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", + zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs {%s}", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), - ifm->ifam_addrs); + rtatostr(ifm->ifam_addrs, fbuf, + sizeof(fbuf))); break; } } /* Assert read up end point matches to end point */ pnt = (caddr_t)ROUNDUP((size_t)pnt); - if (pnt != end) + if (pnt != (caddr_t)ROUNDUP((size_t)end)) zlog_debug("ifam_read() doesn't read all socket data"); } @@ -882,7 +994,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest, pnt += rta_get(pnt, gate, sizeof(*gate)); break; case RTA_NETMASK: - pnt += rta_get(pnt, mask, sizeof(*mask)); + pnt += rta_getattr(pnt, mask, sizeof(*mask)); break; case RTA_IFP: pnt += rta_getsdlname(pnt, ifname, ifnlen); @@ -923,6 +1035,7 @@ void rtm_read(struct rt_msghdr *rtm) struct prefix p; ifindex_t ifindex = 0; afi_t afi; + char fbuf[64]; zebra_flags = 0; @@ -932,9 +1045,10 @@ void rtm_read(struct rt_msghdr *rtm) if (!(flags & RTF_DONE)) return; if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: got rtm of type %d (%s)", __func__, + zlog_debug("%s: got rtm of type %d (%s) addrs {%s}", __func__, rtm->rtm_type, - lookup_msg(rtm_type_str, rtm->rtm_type, NULL)); + lookup_msg(rtm_type_str, rtm->rtm_type, NULL), + rtatostr(rtm->rtm_addrs, fbuf, sizeof(fbuf))); #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ if (flags & RTF_CLONED) @@ -1180,12 +1294,14 @@ int rtm_write(int message, union sockunion *dest, union sockunion *mask, /* For debug purpose. */ static void rtmsg_debug(struct rt_msghdr *rtm) { + char fbuf[64]; + zlog_debug("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup_msg(rtm_type_str, rtm->rtm_type, NULL)); rtm_flag_dump(rtm->rtm_flags); zlog_debug("Kernel: message seq %d", rtm->rtm_seq); - zlog_debug("Kernel: pid %lld, rtm_addrs 0x%x", (long long)rtm->rtm_pid, - rtm->rtm_addrs); + zlog_debug("Kernel: pid %lld, rtm_addrs {%s}", (long long)rtm->rtm_pid, + rtatostr(rtm->rtm_addrs, fbuf, sizeof(fbuf))); } /* This is pretty gross, better suggestions welcome -- mhandler */ |
