diff options
| -rw-r--r-- | bgpd/bgp_vty.c | 14 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 67 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.h | 3 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 1 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 1 | ||||
| -rw-r--r-- | lib/log.c | 4 | ||||
| -rw-r--r-- | lib/zclient.c | 31 | ||||
| -rw-r--r-- | lib/zclient.h | 3 | ||||
| -rw-r--r-- | lib/zebra.h | 4 | ||||
| -rw-r--r-- | zebra/connected.c | 13 | ||||
| -rw-r--r-- | zebra/interface.c | 18 | ||||
| -rw-r--r-- | zebra/interface.h | 1 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 7 | ||||
| -rw-r--r-- | zebra/rtadv.c | 61 | ||||
| -rw-r--r-- | zebra/rtadv.h | 22 | ||||
| -rw-r--r-- | zebra/rtadv_null.c | 3 | ||||
| -rw-r--r-- | zebra/zserv.c | 7 |
17 files changed, 197 insertions, 63 deletions
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 768abcdf25..bdc57769eb 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2712,6 +2712,14 @@ peer_conf_interface_get (struct vty *vty, const char *conf_if, afi_t afi, if (peer && v6only) SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + + /* Request zebra to initiate IPv6 RAs on this interface. We do this + * any unnumbered peer in order to not worry about run-time transitions + * (e.g., peering is initially IPv4, but the IPv4 /30 or /31 address + * gets deleted later etc.) + */ + if (peer->ifp) + bgp_zebra_initiate_radv (bgp, peer); } else if ((v6only && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) || (!v6only && CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))) @@ -2842,6 +2850,9 @@ DEFUN (no_neighbor, peer = peer_lookup_by_conf_if (vty->index, argv[0]); if (peer) { + /* Request zebra to terminate IPv6 RAs on this interface. */ + if (peer->ifp) + bgp_zebra_terminate_radv (peer->bgp, peer); peer_delete (peer); return CMD_SUCCESS; } @@ -2900,6 +2911,9 @@ DEFUN (no_neighbor_interface_config, peer = peer_lookup_by_conf_if (vty->index, argv[0]); if (peer) { + /* Request zebra to terminate IPv6 RAs on this interface. */ + if (peer->ifp) + bgp_zebra_terminate_radv (peer->bgp, peer); peer_delete (peer); } else diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 43653a36f8..7f5f47e062 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -167,6 +167,31 @@ bgp_read_import_check_update(int command, struct zclient *zclient, return 0; } +/* Set or clear interface on which unnumbered neighbor is configured. This + * would in turn cause BGP to initiate or turn off IPv6 RAs on this + * interface. + */ +static void +bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp, + struct interface *upd_ifp) +{ + struct listnode *node, *nnode; + struct peer *peer; + + for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) + { + if (peer->conf_if && + (strcmp (peer->conf_if, ifp->name) == 0)) + { + peer->ifp = upd_ifp; + if (upd_ifp) + bgp_zebra_initiate_radv (bgp, peer); + else + bgp_zebra_terminate_radv (bgp, peer); + } + } +} + static void bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp) { @@ -241,12 +266,20 @@ bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; + struct bgp *bgp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); + if (!ifp) // unexpected + return 0; if (BGP_DEBUG (zebra, ZEBRA) && ifp) zlog_debug("Rx Intf add VRF %u IF %s", vrf_id, ifp->name); + bgp = bgp_lookup_by_vrf_id (vrf_id); + if (!bgp) + return 0; + + bgp_update_interface_nbrs (bgp, ifp, ifp); return 0; } @@ -256,10 +289,11 @@ bgp_interface_delete (int command, struct zclient *zclient, { struct stream *s; struct interface *ifp; + struct bgp *bgp; s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); - if (! ifp) /* This may happen if we've just unregistered for a VRF. */ + if (!ifp) /* This may happen if we've just unregistered for a VRF. */ return 0; ifp->ifindex = IFINDEX_DELETED; @@ -267,6 +301,11 @@ bgp_interface_delete (int command, struct zclient *zclient, if (BGP_DEBUG (zebra, ZEBRA)) zlog_debug("Rx Intf del VRF %u IF %s", vrf_id, ifp->name); + bgp = bgp_lookup_by_vrf_id (vrf_id); + if (!bgp) + return 0; + + bgp_update_interface_nbrs (bgp, ifp, NULL); return 0; } @@ -1965,6 +2004,32 @@ bgp_zebra_instance_deregister (struct bgp *bgp) zclient_send_dereg_requests (zclient, bgp->vrf_id); } +void +bgp_zebra_initiate_radv (struct bgp *bgp, struct peer *peer) +{ + /* Don't try to initiate if we're not connected to Zebra */ + if (zclient->sock < 0) + return; + + if (BGP_DEBUG (zebra, ZEBRA)) + zlog_debug("%u: Initiating RA for peer %s", bgp->vrf_id, peer->host); + + zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 1); +} + +void +bgp_zebra_terminate_radv (struct bgp *bgp, struct peer *peer) +{ + /* Don't try to terminate if we're not connected to Zebra */ + if (zclient->sock < 0) + return; + + if (BGP_DEBUG (zebra, ZEBRA)) + zlog_debug("%u: Terminating RA for peer %s", bgp->vrf_id, peer->host); + + zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 0); +} + /* BGP has established connection with Zebra. */ static void bgp_zebra_connected (struct zclient *zclient) diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 308834ce2b..1770a2c0d5 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -38,6 +38,9 @@ extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp * extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t); extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); +extern void bgp_zebra_initiate_radv (struct bgp *bgp, struct peer *peer); +extern void bgp_zebra_terminate_radv (struct bgp *bgp, struct peer *peer); + extern void bgp_zebra_instance_register (struct bgp *); extern void bgp_zebra_instance_deregister (struct bgp *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 26c8f48c42..1a2c874c24 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1339,6 +1339,7 @@ bgp_peer_conf_if_to_su_update (struct peer *peer) prev_family = peer->su.sa.sa_family; if ((ifp = if_lookup_by_name_vrf (peer->conf_if, peer->bgp->vrf_id))) { + peer->ifp = ifp; /* If BGP unnumbered is not "v6only", we first see if we can derive the * peer's IPv4 address. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a07bd389f5..d15a58ecd4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -578,6 +578,7 @@ struct peer unsigned int ifindex; /* ifindex of the BGP connection. */ char *conf_if; /* neighbor interface config name. */ + struct interface *ifp; /* corresponding interface */ char *ifname; /* bind interface name. */ char *update_if; union sockunion *update_source; @@ -876,7 +876,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV6_ADD), DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV6_DEL), DESC_ENTRY (ZEBRA_INTERFACE_VRF_UPDATE), - DESC_ENTRY (ZEBRA_BFD_CLIENT_REGISTER) + DESC_ENTRY (ZEBRA_BFD_CLIENT_REGISTER), + DESC_ENTRY (ZEBRA_INTERFACE_ENABLE_RADV), + DESC_ENTRY (ZEBRA_INTERFACE_DISABLE_RADV) }; #undef DESC_ENTRY diff --git a/lib/zclient.c b/lib/zclient.c index 1aa1251bf5..8cc6bd92a4 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -481,6 +481,37 @@ zclient_send_dereg_requests (struct zclient *zclient, vrf_id_t vrf_id) zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, vrf_id); } +/* Send request to zebra daemon to start or stop RA. */ +void +zclient_send_interface_radv_req (struct zclient *zclient, vrf_id_t vrf_id, + struct interface *ifp, int enable) +{ + struct stream *s; + + /* zclient is disabled. */ + if (!zclient->enable) + return; + + /* If not connected to the zebra yet. */ + if (zclient->sock < 0) + return; + + /* Form and send message. */ + s = zclient->obuf; + stream_reset (s); + + if (enable) + zclient_create_header (s, ZEBRA_INTERFACE_ENABLE_RADV, vrf_id); + else + zclient_create_header (s, ZEBRA_INTERFACE_DISABLE_RADV, vrf_id); + + stream_putl (s, ifp->ifindex); + + stream_putw_at (s, 0, stream_get_endp (s)); + + zclient_send_message(zclient); +} + /* Make connection to zebra daemon. */ int zclient_start (struct zclient *zclient) diff --git a/lib/zclient.h b/lib/zclient.h index d411965217..726f254a2a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -175,6 +175,9 @@ extern void redist_del_instance (struct redist_proto *, u_short); extern void zclient_send_reg_requests (struct zclient *, vrf_id_t); extern void zclient_send_dereg_requests (struct zclient *, vrf_id_t); +extern void zclient_send_interface_radv_req (struct zclient *zclient, vrf_id_t vrf_id, + struct interface *ifp, int enable); + /* Send redistribute command to zebra daemon. Do not update zclient state. */ extern int zebra_redistribute_send (int command, struct zclient *, afi_t, int type, u_short instance, vrf_id_t vrf_id); diff --git a/lib/zebra.h b/lib/zebra.h index 751e8ce3df..38a1889e72 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -453,7 +453,9 @@ struct in_pktinfo #define ZEBRA_VRF_DELETE 44 #define ZEBRA_INTERFACE_VRF_UPDATE 45 #define ZEBRA_BFD_CLIENT_REGISTER 46 -#define ZEBRA_MESSAGE_MAX 47 +#define ZEBRA_INTERFACE_ENABLE_RADV 47 +#define ZEBRA_INTERFACE_DISABLE_RADV 48 +#define ZEBRA_MESSAGE_MAX 49 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new diff --git a/zebra/connected.c b/zebra/connected.c index 272689b594..7da40ce03a 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -66,13 +66,6 @@ connected_withdraw (struct connected *ifc) /* The address is not in the kernel anymore, so clear the flag */ UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* Enable RA suppression if there are no IPv6 addresses on this interface */ - if (interface_ipv6_auto_ra_allowed (ifc->ifp)) - { - if (! ipv6_address_configured(ifc->ifp)) - ipv6_nd_suppress_ra_set (ifc->ifp, RA_SUPPRESS); - } - if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { listnode_delete (ifc->ifp->connected, ifc); @@ -100,12 +93,6 @@ connected_announce (struct interface *ifp, struct connected *ifc) if (ifc->address->family == AF_INET) if_subnet_add (ifp, ifc); - else if (ifc->address->family == AF_INET6) - { - if (interface_ipv6_auto_ra_allowed (ifp)) - ipv6_nd_suppress_ra_set (ifp, RA_ENABLE); - } - zebra_interface_address_add_update (ifp, ifc); if (if_is_operative(ifp)) diff --git a/zebra/interface.c b/zebra/interface.c index 66ab536cf6..91eb5c49ce 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -684,9 +684,6 @@ if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id) /* Delete all neighbor addresses learnt through IPv6 RA */ if_down_del_nbr_connected (ifp); - /* Suppress RAs on this interface, if enabled. */ - ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS); - /* Send out notification on interface VRF change. */ /* This is to issue an UPDATE or a DELETE, as appropriate. */ zebra_interface_vrf_update_del (ifp, vrf_id); @@ -701,10 +698,6 @@ if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id) /* Install connected routes (in new VRF). */ if_install_connected (ifp); - /* Enable RAs on this interface, if IPv6 addresses are present. */ - if (ipv6_address_configured(ifp)) - ipv6_nd_suppress_ra_set (ifp, RA_ENABLE); - /* Due to connected route change, schedule RIB processing for both old * and new VRF. */ @@ -1929,10 +1922,6 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, /* Add to linked list. */ listnode_add (ifp->connected, ifc); - - /* Enable RA on this interface */ - if (interface_ipv6_auto_ra_allowed (ifp)) - ipv6_nd_suppress_ra_set (ifp, RA_ENABLE); } /* This address is configured from zebra. */ @@ -2031,13 +2020,6 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp, return CMD_WARNING; } - /* Enable RA suppression if there are no IPv6 addresses on this interface */ - if (interface_ipv6_auto_ra_allowed (ifp)) - { - if (! ipv6_address_configured(ifp)) - ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS); - } - UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* This information will be propagated to the zclients when the * kernel notification is received. */ diff --git a/zebra/interface.h b/zebra/interface.h index 2e88566e1a..3784253e6d 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -172,6 +172,7 @@ struct rtadvconf #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ u_char inFastRexmit; /* True if we're rexmits faster than usual */ + u_char configured; /* Has operator configured RA? */ int NumFastReXmitsRemain; /* Loaded first with number of fast rexmits to do */ #define RTADV_FAST_REXMIT_PERIOD 1 /* 1 sec */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4102cc375d..0c7d72130a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1350,13 +1350,6 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h, /* pre-configured interface, learnt now */ if (ifp->vrf_id != vrf_id) if_update_vrf (ifp, name, strlen(name), vrf_id); - - /* Start IPv6 RA, if any IPv6 addresses on interface. */ - if (interface_ipv6_auto_ra_allowed (ifp)) - { - if (ipv6_address_configured (ifp)) - ipv6_nd_suppress_ra_set (ifp, RA_ENABLE); - } } /* Update interface information. */ diff --git a/zebra/rtadv.c b/zebra/rtadv.c index e3e390d565..9179701302 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -26,6 +26,7 @@ #include "sockopt.h" #include "thread.h" #include "if.h" +#include "stream.h" #include "log.h" #include "prefix.h" #include "linklist.h" @@ -734,7 +735,7 @@ rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp) return 0; } -void +static void ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status status) { struct zebra_if *zif; @@ -783,6 +784,58 @@ ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status statu } } +/* + * Handle client (BGP) message to enable or disable IPv6 RA on an interface. + * Note that while the client could request RA on an interface on which the + * operator has not enabled RA, RA won't be disabled upon client request + * if the operator has explicitly enabled RA. + */ +void +zebra_interface_radv_set (struct zserv *client, int sock, u_short length, + struct zebra_vrf *zvrf, int enable) +{ + struct stream *s; + unsigned int ifindex; + struct interface *ifp; + struct zebra_if *zif; + + s = client->ibuf; + + /* Get interface index. */ + ifindex = stream_getl (s); + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%u: IF %u RA %s from client %s", + zvrf->vrf_id, ifindex, enable ? "enable" : "disable", + zebra_route_string(client->proto)); + + /* Locate interface and check VRF match. */ + ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ifindex); + if (!ifp) + { + zlog_warn("%u: IF %u RA %s client %s - interface unknown", + zvrf->vrf_id, ifindex, enable ? "enable" : "disable", + zebra_route_string(client->proto)); + return; + } + if (ifp->vrf_id != zvrf->vrf_id) + { + zlog_warn("%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u", + zvrf->vrf_id, ifindex, enable ? "enable" : "disable", + zebra_route_string(client->proto), ifp->vrf_id); + return; + } + + zif = ifp->info; + if (enable) + ipv6_nd_suppress_ra_set (ifp, RA_ENABLE); + else + { + if (!zif->rtadv.configured) + ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS); + } +} + DEFUN (ipv6_nd_suppress_ra, ipv6_nd_suppress_ra_cmd, "ipv6 nd suppress-ra", @@ -791,6 +844,7 @@ DEFUN (ipv6_nd_suppress_ra, "Suppress Router Advertisement\n") { struct interface *ifp; + struct zebra_if *zif; ifp = vty->index; @@ -802,6 +856,8 @@ DEFUN (ipv6_nd_suppress_ra, } ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS); + zif = ifp->info; + zif->rtadv.configured = 0; return CMD_SUCCESS; } @@ -814,6 +870,7 @@ DEFUN (no_ipv6_nd_suppress_ra, "Suppress Router Advertisement\n") { struct interface *ifp; + struct zebra_if *zif; ifp = vty->index; @@ -825,6 +882,8 @@ DEFUN (no_ipv6_nd_suppress_ra, } ipv6_nd_suppress_ra_set (ifp, RA_ENABLE); + zif = ifp->info; + zif->rtadv.configured = 1; return CMD_SUCCESS; } diff --git a/zebra/rtadv.h b/zebra/rtadv.h index a3ea425931..3011505dbc 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -108,26 +108,8 @@ typedef enum { extern void rtadv_init (struct zebra_ns *); extern void rtadv_terminate (struct zebra_ns *); extern void rtadv_cmd_init (void); -extern void ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status status); +extern void zebra_interface_radv_set (struct zserv *client, int sock, u_short length, + struct zebra_vrf *zvrf, int enable); -/* Can we turn on IPv6 RAs automatically on this interface? */ -static inline int -interface_ipv6_auto_ra_allowed (struct interface *ifp) -{ -#if defined (HAVE_RTADV) - if (if_is_loopback (ifp) || - CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) - return 0; -#if defined (HAVE_CUMULUS) - if ((strncmp (ifp->name, "eth", strlen("eth")) == 0) || - (strncmp (ifp->name, "switch", strlen("switch")) == 0)) - return 0; -#endif - return 1; -#else - return 0; -#endif -} - #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/rtadv_null.c b/zebra/rtadv_null.c index 851c8e0a64..ee6eda6bdd 100644 --- a/zebra/rtadv_null.c +++ b/zebra/rtadv_null.c @@ -24,7 +24,8 @@ #include <rtadv.h> #include <zebra_ns.h> -void ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status status) +void zebra_interface_radv_set (struct zserv *client, int sock, u_short length, + struct zebra_vrf *zvrf, int enable) { return; } void rtadv_init (struct zebra_ns *zns) diff --git a/zebra/zserv.c b/zebra/zserv.c index 3872d17409..9491b39a91 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -50,6 +50,7 @@ #include "zebra/rt_netlink.h" #include "zebra/interface.h" #include "zebra/zebra_ptm.h" +#include "zebra/rtadv.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -2026,6 +2027,12 @@ zebra_client_read (struct thread *thread) case ZEBRA_BFD_CLIENT_REGISTER: zebra_ptm_bfd_client_register(client, sock, length); break; + case ZEBRA_INTERFACE_ENABLE_RADV: + zebra_interface_radv_set (client, sock, length, zvrf, 1); + break; + case ZEBRA_INTERFACE_DISABLE_RADV: + zebra_interface_radv_set (client, sock, length, zvrf, 0); + break; default: zlog_info ("Zebra received unknown command %d", command); break; |
