From 5c610fafc4fc8d2f62d5a043e5029564f7c58824 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 11 Jun 2015 09:19:59 -0700 Subject: [PATCH] --- zebra/interface.c | 62 +++++++++++++++++++++++++++++++++++ zebra/interface.h | 3 ++ zebra/kernel_null.c | 5 +++ zebra/rt_netlink.c | 78 +++++++++++++++++++++++++++++++++++++++++++-- zebra/rt_netlink.h | 3 ++ zebra/zebra_rib.c | 6 ++++ zebra/zserv.c | 5 +++ 7 files changed, 159 insertions(+), 3 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 9a1259c73a..8af7ef7180 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -41,6 +41,7 @@ #include "zebra/debug.h" #include "zebra/irdp.h" #include "zebra/zebra_ptm.h" +#include "zebra/rt_netlink.h" #define ZEBRA_PTM_SUPPORT @@ -528,6 +529,64 @@ if_delete_update (struct interface *ifp) ifp->ifindex = IFINDEX_INTERNAL; } +void +ipv6_ll_address_to_mac (struct in6_addr *address, u_char *mac) +{ + mac[0] = address->s6_addr[8]; + mac[0] &= ~0x02; + mac[1] = address->s6_addr[9]; + mac[2] = address->s6_addr[10]; + mac[3] = address->s6_addr[13]; + mac[4] = address->s6_addr[14]; + mac[5] = address->s6_addr[15]; +} + +void +if_nbr_ipv6ll_to_ipv4ll_neigh_update (struct interface *ifp, + struct in6_addr *address, + int add) +{ + char buf[16] = "169.254.0.1"; + struct in_addr ipv4_ll; + u_char mac[6]; + + inet_pton (AF_INET, buf, &ipv4_ll); + + ipv6_ll_address_to_mac(address, mac); + netlink_neigh_update (add ? RTM_NEWNEIGH : RTM_DELNEIGH, + ifp->ifindex, ipv4_ll.s_addr, mac, 6); +} + +void +if_nbr_ipv6ll_to_ipv4ll_neigh_add_all (struct interface *ifp) +{ + if (listhead(ifp->nbr_connected)) + { + struct nbr_connected *nbr_connected; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected)) + if_nbr_ipv6ll_to_ipv4ll_neigh_update (ifp, + &nbr_connected->address->u.prefix6, + 1); + } +} + +void +if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (struct interface *ifp) +{ + if (listhead(ifp->nbr_connected)) + { + struct nbr_connected *nbr_connected; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected)) + if_nbr_ipv6ll_to_ipv4ll_neigh_update (ifp, + &nbr_connected->address->u.prefix6, + 0); + } +} + /* Interface is up. */ void if_up (struct interface *ifp) @@ -545,6 +604,7 @@ if_up (struct interface *ifp) } zebra_interface_up_update (ifp); + if_nbr_ipv6ll_to_ipv4ll_neigh_add_all (ifp); /* Install connected routes to the kernel. */ if (ifp->connected) @@ -597,6 +657,8 @@ if_down (struct interface *ifp) /* Examine all static routes which direct to the interface. */ rib_update (); + + if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp); } void diff --git a/zebra/interface.h b/zebra/interface.h index d20d991515..72e40044fc 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -213,6 +213,9 @@ struct zebra_if #endif /* SUNOS_5 */ }; +extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update (struct interface *ifp, + struct in6_addr *address, int add); +extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (struct interface *ifp); extern void if_delete_update (struct interface *ifp); extern void if_add_update (struct interface *ifp); extern void if_up (struct interface *); diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 2e833febe6..9b45acb79b 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -48,6 +48,11 @@ int kernel_address_delete_ipv4 (struct interface *a, struct connected *b) return 0; } +int netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen) +{ + return 0; +} + void kernel_init (void) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak route_read = kernel_init diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ab49406cd7..99c4ab54f8 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1483,8 +1483,30 @@ _netlink_route_build_singlepath( size_t req_size, int cmd) { + + if (rtmsg->rtm_family == AF_INET && + (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) + { + char buf[16] = "169.254.0.1"; + struct in_addr ipv4_ll; + + inet_pton (AF_INET, buf, &ipv4_ll); + rtmsg->rtm_flags |= RTNH_F_ONLINK; + addattr_l (nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4); + addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug(" 5549: _netlink_route_build_singlepath() (%s): " + "nexthop via %s if %u", + routedesc, buf, nexthop->ifindex); + return; + } + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; + if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { @@ -1573,14 +1595,38 @@ _netlink_route_build_multipath( struct nexthop *nexthop, struct rtattr *rta, struct rtnexthop *rtnh, - union g_addr **src - ) + struct rtmsg *rtmsg, + union g_addr **src) { rtnh->rtnh_len = sizeof (*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rta->rta_len += rtnh->rtnh_len; + if (rtmsg->rtm_family == AF_INET && + (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) + { + char buf[16] = "169.254.0.1"; + struct in_addr ipv4_ll; + + inet_pton (AF_INET, buf, &ipv4_ll); + bytelen = 4; + rtnh->rtnh_flags |= RTNH_F_ONLINK; + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, + &ipv4_ll, bytelen); + rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; + rtnh->rtnh_ifindex = nexthop->ifindex; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug(" 5549: netlink_route_build_multipath() (%s): " + "nexthop via %s if %u", + routedesc, buf, nexthop->ifindex); + return; + } + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtnh->rtnh_flags |= RTNH_F_ONLINK; @@ -1683,6 +1729,32 @@ _netlink_route_debug( } } +int +netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + + memset(&req.n, 0, sizeof(req.n)); + memset(&req.ndm, 0, sizeof(req.ndm)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = cmd; //RTM_NEWNEIGH or RTM_DELNEIGH + req.ndm.ndm_family = AF_INET; + req.ndm.ndm_state = NUD_PERMANENT; + req.ndm.ndm_ifindex = ifindex; + req.ndm.ndm_type = RTN_UNICAST; + + addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); + addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + + return netlink_talk (&req.n, &netlink_cmd); +} + /* Routing table change via netlink interface. */ /* Update flag indicates whether this is a "replace" or not. */ static int @@ -1874,7 +1946,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, _netlink_route_debug(cmd, p, nexthop, routedesc, family); _netlink_route_build_multipath(routedesc, bytelen, - nexthop, rta, rtnh, &src1); + nexthop, rta, rtnh, &req.r, &src1); rtnh = RTNH_NEXT (rtnh); if (cmd == RTM_NEWROUTE) diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 14e811db31..5b1b48cb0a 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -41,6 +41,9 @@ nl_msg_type_to_str (uint16_t msg_type); extern const char * nl_rtproto_to_str (u_char rtproto); +int +netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen); + extern int netlink_route_read(void); extern int interface_lookup_netlink(void); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7adbcbe534..0d11927e3f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3962,8 +3962,14 @@ rib_close_table (struct route_table *table) void rib_close (void) { + struct listnode *node, *nnode; + struct interface *ifp; + rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + + for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) + if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); } /* Routing information base initialize. */ diff --git a/zebra/zserv.c b/zebra/zserv.c index 61d3a0a55e..cd986daee9 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -44,6 +44,7 @@ #include "zebra/debug.h" #include "zebra/ipforward.h" #include "zebra/zebra_rnh.h" +#include "zebra/rt_netlink.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -415,6 +416,8 @@ nbr_connected_replacement_add_ipv6 (struct interface *ifp, struct in6_addr *addr prefix_copy(ifc->address, &p); zebra_interface_nbr_address_add_update (ifp, ifc); + + if_nbr_ipv6ll_to_ipv4ll_neigh_update (ifp, address, 1); } void @@ -436,6 +439,8 @@ nbr_connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, zebra_interface_nbr_address_delete_update (ifp, ifc); + if_nbr_ipv6ll_to_ipv4ll_neigh_update (ifp, address, 0); + nbr_connected_free (ifc); } -- 2.39.5