* The files contains the API and CLI code for managing IPv6 RAs
*/
-/* *INDENT-OFF* */
/* Router solicitation packet format for ethernet. */
typedef CLIB_PACKED (struct
{
icmp6_neighbor_discovery_prefix_information_option_t
prefix[0];
}) icmp6_router_advertisement_packet_t;
-/* *INDENT-ON* */
#define DEF_MAX_RADV_INTERVAL 200
#define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
#define MAX_DELAY_BETWEEN_RAS 1800 /* seconds */
#define MAX_RA_DELAY_TIME .5 /* seconds */
-/* advertised prefix option */
-typedef struct
-{
- /* basic advertised information */
- ip6_address_t prefix;
- u8 prefix_len;
- int adv_on_link_flag;
- int adv_autonomous_flag;
- u32 adv_valid_lifetime_in_secs;
- u32 adv_pref_lifetime_in_secs;
-
- /* advertised values are computed from these times if decrementing */
- f64 valid_lifetime_expires;
- f64 pref_lifetime_expires;
-
- /* local information */
- int enabled;
- int deprecated_prefix_flag;
- int decrement_lifetime_flag;
-
-#define MIN_ADV_VALID_LIFETIME 7203 /* seconds */
-#define DEF_ADV_VALID_LIFETIME 2592000
-#define DEF_ADV_PREF_LIFETIME 604800
-
- /* extensions are added here, mobile, DNS etc.. */
-} ip6_radv_prefix_t;
-
-typedef struct ip6_ra_t_
-{
- /* advertised config information, zero means unspecified */
- u8 curr_hop_limit;
- int adv_managed_flag;
- int adv_other_flag;
- u16 adv_router_lifetime_in_sec;
- u32 adv_neighbor_reachable_time_in_msec;
- u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations;
-
- /* mtu option */
- u32 adv_link_mtu;
-
- /* local information */
- u32 sw_if_index;
- int send_radv; /* radv on/off on this interface - set by config */
- int cease_radv; /* we are ceasing to send - set byf config */
- int send_unicast;
- int adv_link_layer_address;
- int prefix_option;
- int failed_device_check;
- int ref_count;
-
- /* prefix option */
- ip6_radv_prefix_t *adv_prefixes_pool;
-
- /* Hash table mapping address to index in interface advertised prefix pool. */
- mhash_t address_to_prefix_index;
-
- f64 max_radv_interval;
- f64 min_radv_interval;
- f64 min_delay_between_radv;
- f64 max_delay_between_radv;
- f64 max_rtr_default_lifetime;
-
- f64 last_radv_time;
- f64 last_multicast_time;
- f64 next_multicast_time;
-
-
- u32 initial_adverts_count;
- f64 initial_adverts_interval;
- u32 initial_adverts_sent;
-
- /* stats */
- u32 n_advertisements_sent;
- u32 n_solicitations_rcvd;
- u32 n_solicitations_dropped;
-
- /* router solicitations sending state */
- u8 keep_sending_rs; /* when true then next fields are valid */
- icmp6_send_router_solicitation_params_t params;
- f64 sleep_interval;
- f64 due_time;
- u32 n_left;
- f64 start_time;
- vlib_buffer_t *buffer;
-
- u32 seed;
-
-} ip6_ra_t;
-
static ip6_link_delegate_id_t ip6_ra_delegate_id;
static ip6_ra_t *ip6_ra_pool;
}
}
-static inline ip6_ra_t *
+ip6_ra_t *
ip6_ra_get_itf (u32 sw_if_index)
{
index_t rai;
return (NULL);
}
+u8
+ip6_ra_adv_enabled (u32 sw_if_index)
+{
+ ip6_ra_t *ra;
+
+ ra = ip6_ra_get_itf (sw_if_index);
+
+ return ((ra != NULL) && (ra->send_radv != 0));
+}
+
+void
+ip6_ra_itf_walk (ip6_ra_itf_walk_fn_t fn, void *ctx)
+{
+ ip6_ra_t *radv_info;
+
+ pool_foreach (radv_info, ip6_ra_pool)
+ {
+ if (WALK_STOP == fn (radv_info->sw_if_index, ctx))
+ break;
+ }
+}
+
/* for "syslogging" - use elog for now */
#define foreach_log_level \
_ (DEBUG, "DEBUG") \
{
u32 s[2];
} *ed;
- ed = ELOG_DATA (&vm->elog_main, e);
- ed->s[0] = elog_string (&vm->elog_main, log_level_strings[priority]);
- ed->s[1] = elog_string (&vm->elog_main, (char *) what);
+ ed = ELOG_DATA (vlib_get_elog_main (), e);
+ ed->s[0] =
+ elog_string (vlib_get_elog_main (), log_level_strings[priority]);
+ ed->s[1] = elog_string (vlib_get_elog_main (), (char *) what);
}
va_end (va);
return;
ICMP6_ROUTER_SOLICITATION_N_NEXT,
} icmp6_router_solicitation_or_advertisement_next_t;
+/*
+ * Note: Both periodic RAs and solicited RS come through here.
+ */
static_always_inline uword
icmp6_router_solicitation (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
!is_unspecified && !is_link_local))
{
ip_neighbor_learn_t learn = {
- .type = IP46_TYPE_IP6,
.sw_if_index = sw_if_index0,
- .ip.ip6 = ip0->src_address,
+ .ip = {
+ .ip.ip6 = ip0->src_address,
+ .version = AF_IP6,
+ },
};
memcpy (&learn.mac, o0->ethernet_address, sizeof (learn.mac));
ip_neighbor_learn_dp (&learn);
radv_info = ip6_ra_get_itf (sw_if_index0);
- error0 = ((!radv_info) ?
- ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
- error0);
-
+ error0 = ((!radv_info || 0 == radv_info->send_radv) ?
+ ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
+ error0);
if (error0 == ICMP6_ERROR_NONE)
{
f64 now = vlib_time_now (vm);
/* copy ll address */
clib_memcpy (&h.ethernet_address[0],
- eth_if0->address, 6);
+ ð_if0->address, 6);
if (vlib_buffer_add_data
(vm, &bi0, (void *) &h,
/* add advertised prefix options */
ip6_radv_prefix_t *pr_info;
- /* *INDENT-OFF* */
- pool_foreach (pr_info, radv_info->adv_prefixes_pool,
- ({
+ pool_foreach (pr_info, radv_info->adv_prefixes_pool)
+ {
if(pr_info->enabled &&
(!pr_info->decrement_lifetime_flag
|| (pr_info->pref_lifetime_expires >0)))
}
}
- }));
- /* *INDENT-ON* */
+ }
/* add additional options before here */
/* Reuse current MAC header, copy SMAC to DMAC and
* interface MAC to SMAC */
vlib_buffer_reset (p0);
+ vlib_buffer_advance (
+ p0, vnet_buffer (p0)->l2_hdr_offset);
eth0 = vlib_buffer_get_current (p0);
clib_memcpy (eth0->dst_address, eth0->src_address,
6);
- clib_memcpy (eth0->src_address, eth_if0->address,
+ clib_memcpy (eth0->src_address, ð_if0->address,
6);
next0 =
is_dropped ? next0 :
return frame->n_vectors;
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) =
{
.function = icmp6_router_solicitation,
[ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
},
};
-/* *INDENT-ON* */
/* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always be dropped */
static_always_inline uword
prefix->prefix.fp_proto = FIB_PROTOCOL_IP6;
/* look for matching prefix - if we our advertising it, it better be consistant */
- /* *INDENT-OFF* */
- pool_foreach (pr_info, radv_info->adv_prefixes_pool,
- ({
+ pool_foreach (pr_info, radv_info->adv_prefixes_pool)
+ {
ip6_address_t mask;
ip6_address_mask_from_width(&mask, pr_info->prefix_len);
}
}
break;
- }));
- /* *INDENT-ON* */
+ }
break;
}
default:
return frame->n_vectors;
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) =
{
.function = icmp6_router_advertisement,
[0] = "ip6-drop",
},
};
-/* *INDENT-ON* */
static inline f64
random_f64_from_to (f64 from, f64 to)
}
p0 = vlib_get_buffer (vm, bi0);
- VLIB_BUFFER_TRACE_TRAJECTORY_INIT (p0);
p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index;
next_index = ip6_rewrite_mcast_node.index;
c0 = vlib_buffer_copy (vm, p0);
+ if (c0 == NULL)
+ return radv_info->keep_sending_rs;
+
ci0 = vlib_get_buffer_index (vm, c0);
f = vlib_get_frame_to_node (vm, next_index);
do
{
due_time = current_time + 1e9;
- /* *INDENT-OFF* */
- pool_foreach (radv_info, ip6_ra_pool,
- ({
+ pool_foreach (radv_info, ip6_ra_pool)
+ {
if (check_send_rs (vm, radv_info, current_time, &dt)
&& (dt < due_time))
due_time = dt;
- }));
- /* *INDENT-ON* */
+ }
current_time = vlib_time_now (vm);
}
while (due_time < current_time);
return 0;
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_rs_process_node) = {
.function = send_rs_process,
.type = VLIB_NODE_TYPE_PROCESS,
.name = "ip6-rs-process",
};
-/* *INDENT-ON* */
void
icmp6_send_router_solicitation (vlib_main_t * vm, u32 sw_if_index, u8 stop,
radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
radv_info->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
- /* deafult is to send */
- radv_info->send_radv = 1;
-
/* fill in delegate for this interface that will be needed later */
radv_info->adv_link_mtu =
vnet_sw_interface_get_mtu (vnet_get_main (), sw_if_index, VNET_MTU_IP6);
radv_info = pool_elt_at_index (ip6_ra_pool, rai);
/* clean up prefix and MDP pools */
- /* *INDENT-OFF* */
pool_flush(p, radv_info->adv_prefixes_pool,
({
mhash_unset (&radv_info->address_to_prefix_index, &p->prefix, 0);
}));
- /* *INDENT-ON* */
pool_free (radv_info->adv_prefixes_pool);
ip6_address_mask_from_width (&mask, prefix_len);
vec_reset_length (radv_indices);
- /* *INDENT-OFF* */
- pool_foreach (radv_info, ip6_ra_pool,
- ({
+ pool_foreach (radv_info, ip6_ra_pool)
+ {
vec_add1 (radv_indices, radv_info - ip6_ra_pool);
- }));
- /* *INDENT-ON* */
+ }
/*
* If we have another customer for this prefix,
if (radv_info->sw_if_index == primary_sw_if_index)
continue;
- /* *INDENT-OFF* */
- pool_foreach (this_prefix, radv_info->adv_prefixes_pool,
- ({
+ pool_foreach (this_prefix, radv_info->adv_prefixes_pool)
+ {
if (this_prefix->prefix_len == prefix_len
&& ip6_address_is_equal_masked (&this_prefix->prefix, address,
&mask))
if (rv != 0)
clib_warning ("ip6_neighbor_ra_prefix returned %d", rv);
}
- }));
- /* *INDENT-ON*/
+ }
}
}
f64 now = vlib_time_now (vm);
/* Interface ip6 radv info list */
- /* *INDENT-OFF* */
- pool_foreach (radv_info, ip6_ra_pool,
- ({
+ pool_foreach (radv_info, ip6_ra_pool)
+ {
if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
{
radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
f = 0;
}
}
- }));
- /* *INDENT-ON* */
+ }
if (f)
{
}
static void
-ip6_ra_handle_report (const ip6_ra_report_t * rap)
+ip6_ra_handle_report (ip6_ra_report_t * rap)
{
u32 ii;
vec_foreach_index (ii, ip6_ra_listeners) ip6_ra_listeners[ii] (rap);
+ vec_free (rap->prefixes);
+ clib_mem_free (rap);
}
static uword
ip6_ra_event_process (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
- ip6_ra_report_t *r, *rs;
+ ip6_ra_report_t *r;
uword event_type;
+ uword *event_data = 0;
+ int i;
/* init code here */
{
vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */ );
- rs = vlib_process_get_event_data (vm, &event_type);
+ event_type = vlib_process_get_events (vm, &event_data);
- if (NULL == rs)
+ if (event_type == ~0)
{
/* No events found: timer expired. */
/* process interface list and send RAs as appropriate, update timer info */
}
else
{
- vec_foreach (r, rs) ip6_ra_handle_report (r);
- vec_reset_length (rs);
+ for (i = 0; i < vec_len (event_data); i++)
+ {
+ r = (void *) (event_data[i]);
+ ip6_ra_handle_report (r);
+ }
+ vec_reset_length (event_data);
}
}
return frame->n_vectors;
VLIB_REGISTER_NODE (ip6_ra_process_node) =
{
-.function = ip6_ra_event_process,.name = "ip6-ra-process",.type =
- VLIB_NODE_TYPE_PROCESS,};
+ .function = ip6_ra_event_process,
+ .name = "ip6-ra-process",
+ .type = VLIB_NODE_TYPE_PROCESS,
+};
static void
ip6_ra_signal_report (ip6_ra_report_t * r)
if (!vec_len (ip6_ra_listeners))
return;
- q = vlib_process_signal_event_data (vm,
- ip6_ra_process_node.index,
- 0, 1, sizeof *q);
+ q = clib_mem_alloc (sizeof (*q));
*q = *r;
+
+ vlib_process_signal_event (vm, ip6_ra_process_node.index, 0, (uword) q);
}
static int
if (!radv_info)
return (VNET_API_ERROR_IP6_NOT_ENABLED);
+ /* Start off believing that we're going to send radv's */
+ radv_info->send_radv = 1;
+
if ((max_interval != 0) && (min_interval == 0))
min_interval = .75 * max_interval;
}
else
{
- error = unformat_parse_error (line_input);
- goto done;
+ break;
}
}
indent += 2;
- /* *INDENT-OFF* */
- pool_foreach (p, radv_info->adv_prefixes_pool,
- ({
+ pool_foreach (p, radv_info->adv_prefixes_pool)
+ {
s = format (s, "%Uprefix %U, length %d\n",
format_white_space, indent+2,
format_ip6_address, &p->prefix, p->prefix_len);
- }));
- /* *INDENT-ON* */
+ }
s = format (s, "%UMTU is %d\n",
format_white_space, indent, radv_info->adv_link_mtu);
return (s);
}
-
/*?
* This command is used to configure the neighbor discovery
* parameters on a given interface. Use the '<em>show ip6 interface</em>'
* on a given interface. This command has three formats:
*
*
- * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
+ * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in
+ * a single command)
*
- * '<em><b>ip6 nd <interface> [no] [ra-managed-config-flag] | [ra-other-config-flag] | [ra-suppress] | [ra-suppress-link-layer] | [ra-send-unicast] | [ra-lifetime <lifetime>] | [ra-initial <cnt> <interval>] | [ra-interval <max-interval> [<min-interval>]] | [ra-cease]</b></em>'
+ * @clistart
+ * ip6 nd <interface> [no] [ra-managed-config-flag] |
+ * [ra-other-config-flag] | [ra-suppress] | [ra-suppress-link-layer] |
+ * [ra-send-unicast] | [ra-lifetime <lifetime>] |
+ * [ra-initial <cnt> <interval>] |
+ * [ra-interval <max-interval> [<min-interval>]] | [ra-cease]
+ * @cliend
*
* Where:
*
* and the '<em>no</em>' option returns it to this default state.
*
* <em>[no] ra-send-unicast</em> - Use the source address of the
- * router-solicitation message if availiable. The default is to use
+ * router-solicitation message if available. The default is to use
* multicast address of all nodes, and the '<em>no</em>' option returns
* it to this default state.
*
*
* <b>Format 2 - Prefix Options:</b>
*
- * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> [<valid-lifetime> <pref-lifetime> | infinite] [no-advertise] [off-link] [no-autoconfig] [no-onlink]</b></em>'
+ * @clistart
+ * ip6 nd <interface> [no] prefix <ip6-address>/<width>
+ * [<valid-lifetime> <pref-lifetime> | infinite] [no-advertise] [off-link]
+ * [no-autoconfig] [no-onlink]
+ * @cliend
*
* Where:
*
* <em>no</em> - All additional flags are ignored and the prefix is deleted.
*
- * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
- * length of time in seconds during what the prefix is valid for the purpose of
- * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
- * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
- * length of time in seconds during what addresses generated from the prefix remain
- * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
+ * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is
+ * the length of time in seconds during what the prefix is valid for the
+ * purpose of on-link determination. Range is 7203 to 2592000 seconds and
+ * default is 2592000 seconds (30 days). '<em><pref-lifetime></em>' is the
+ * preferred-lifetime and is the length of time in seconds during what
+ * addresses generated from the prefix remain preferred. Range is 0 to 604800
+ * seconds and default is 604800 seconds (7 days).
*
- * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
- * are inifinte, no timeout.
+ * <em>infinite</em> - Both '<em><valid-lifetime></em>' and
+ * '<em><pref-lifetime></em>' are infinite, no timeout.
*
* <em>no-advertise</em> - Do not send full router address in prefix
* advertisement. Default is to advertise (i.e. - This flag is off by default).
*
- * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
- * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
- * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
+ * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is
+ * on-link (i.e. - This flag is off and L-bit in packet is set by default
+ * and this prefix can be used for on-link determination). '<em>no-onlink</em>'
+ * also controls the L-bit.
*
- * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
- * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
+ * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear
+ * A-bit in packet. Default is autoconfig (i.e. - This flag is off and A-bit
+ * in packet is set by default.
*
- * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
- * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
- * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
- * the L-bit.
+ * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit
+ * in packet. Default is on-link (i.e. - This flag is off and L-bit in packet
+ * is set by default and this prefix can be used for on-link determination).
+ * '<em>off-link</em>' also controls the L-bit.
*
*
* <b>Format 3: - Default of Prefix:</b>
*
- * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
+ * @cliexcmd{ip6 nd <interface> [no] prefix <ip6-address>/<width> default}
*
- * When a new prefix is added (or existing one is being overwritten) <em>default</em>
- * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
- * is ignored and the prefix is deleted.
+ * When a new prefix is added (or existing one is being overwritten)
+ * <em>default</em> uses default values for the prefix. If <em>no</em> is
+ * used, the <em>default</em> is ignored and the prefix is deleted.
*
*
* @cliexpar
* Example of how set a router advertisement option:
* @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
* Example of how to add a prefix:
- * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
+ * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64
+ * infinite no-advertise}
* Example of how to delete a prefix:
* @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
?*/
-/* *INDENT-OFF* */
VLIB_CLI_COMMAND (ip6_nd_command, static) =
{
.path = "ip6 nd",
.short_help = "ip6 nd <interface> ...",
.function = ip6_ra_cmd,
};
-/* *INDENT-ON* */
/**
* VFT for registering as a delegate to an IP6 link
return (NULL);
}
-/* *INDENT-OFF* */
VLIB_INIT_FUNCTION (ip6_ra_init) =
{
.runs_after = VLIB_INITS("icmp6_init"),
};
-/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON