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)))
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;
}
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
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)
{
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;
}
{
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;
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;
}
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)
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 *);
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.
*/
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;
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
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)
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);
#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
/* 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);
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))
/* 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);
/* 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.
*/
/* 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. */
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. */
#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 */
/* 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. */
#include "sockopt.h"
#include "thread.h"
#include "if.h"
+#include "stream.h"
#include "log.h"
#include "prefix.h"
#include "linklist.h"
return 0;
}
-void
+static void
ipv6_nd_suppress_ra_set (struct interface *ifp, ipv6_nd_suppress_ra_status status)
{
struct zebra_if *zif;
}
}
+/*
+ * 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",
"Suppress Router Advertisement\n")
{
struct interface *ifp;
+ struct zebra_if *zif;
ifp = vty->index;
}
ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS);
+ zif = ifp->info;
+ zif->rtadv.configured = 0;
return CMD_SUCCESS;
}
"Suppress Router Advertisement\n")
{
struct interface *ifp;
+ struct zebra_if *zif;
ifp = vty->index;
}
ipv6_nd_suppress_ra_set (ifp, RA_ENABLE);
+ zif = ifp->info;
+ zif->rtadv.configured = 1;
return CMD_SUCCESS;
}
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 */
#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)
#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 };
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;