summaryrefslogtreecommitdiff
path: root/isisd/isis_lsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'isisd/isis_lsp.c')
-rw-r--r--isisd/isis_lsp.c138
1 files changed, 136 insertions, 2 deletions
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 9bbba7fc..43170f66 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -35,6 +35,7 @@
#include "if.h"
#include "checksum.h"
#include "md5.h"
+#include "table.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -950,7 +951,7 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
memcpy (in6.s6_addr, ipv6_reach->prefix,
PSIZE (ipv6_reach->prefix_len));
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
- if ((ipv6_reach->control_info &&
+ if ((ipv6_reach->control_info &
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
ntohl (ipv6_reach->metric),
@@ -1144,6 +1145,123 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
return lsp;
}
+static void
+lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
+ struct tlvs *tlv_data)
+{
+ struct route_table *er_table;
+ struct route_node *rn;
+ struct prefix_ipv4 *ipv4;
+ struct isis_ext_info *info;
+ struct ipv4_reachability *ipreach;
+ struct te_ipv4_reachability *te_ipreach;
+
+ er_table = get_ext_reach(area, AF_INET, lsp->level);
+ if (!er_table)
+ return;
+
+ for (rn = route_top(er_table); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+
+ ipv4 = (struct prefix_ipv4*)&rn->p;
+ info = rn->info;
+ if (area->oldmetric)
+ {
+ if (tlv_data->ipv4_ext_reachs == NULL)
+ {
+ tlv_data->ipv4_ext_reachs = list_new();
+ tlv_data->ipv4_ext_reachs->del = free_tlv;
+ }
+ ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
+
+ ipreach->prefix.s_addr = ipv4->prefix.s_addr;
+ masklen2ip(ipv4->prefixlen, &ipreach->mask);
+ ipreach->prefix.s_addr &= ipreach->mask.s_addr;
+
+ if ((info->metric & 0x3f) != info->metric)
+ ipreach->metrics.metric_default = 0x3f;
+ else
+ ipreach->metrics.metric_default = info->metric;
+ ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
+ ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
+ ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
+ listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
+ }
+ if (area->newmetric)
+ {
+ if (tlv_data->te_ipv4_reachs == NULL)
+ {
+ tlv_data->te_ipv4_reachs = list_new();
+ tlv_data->te_ipv4_reachs->del = free_tlv;
+ }
+ te_ipreach =
+ XCALLOC(MTYPE_ISIS_TLV,
+ sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
+ if (info->metric > MAX_WIDE_PATH_METRIC)
+ te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
+ else
+ te_ipreach->te_metric = htonl(info->metric);
+ te_ipreach->control = ipv4->prefixlen & 0x3f;
+ memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
+ PSIZE(ipv4->prefixlen));
+ listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
+ }
+ }
+}
+
+#ifdef HAVE_IPV6
+static void
+lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
+ struct tlvs *tlv_data)
+{
+ struct route_table *er_table;
+ struct route_node *rn;
+ struct prefix_ipv6 *ipv6;
+ struct isis_ext_info *info;
+ struct ipv6_reachability *ip6reach;
+
+ er_table = get_ext_reach(area, AF_INET6, lsp->level);
+ if (!er_table)
+ return;
+
+ for (rn = route_top(er_table); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+
+ ipv6 = (struct prefix_ipv6*)&rn->p;
+ info = rn->info;
+
+ if (tlv_data->ipv6_reachs == NULL)
+ {
+ tlv_data->ipv6_reachs = list_new();
+ tlv_data->ipv6_reachs->del = free_tlv;
+ }
+ ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
+ if (info->metric > MAX_WIDE_PATH_METRIC)
+ ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
+ else
+ ip6reach->metric = htonl(info->metric);
+ ip6reach->control_info = DISTRIBUTION_EXTERNAL;
+ ip6reach->prefix_len = ipv6->prefixlen;
+ memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
+ listnode_add(tlv_data->ipv6_reachs, ip6reach);
+ }
+}
+#endif
+
+static void
+lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
+ struct tlvs *tlv_data)
+{
+ lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
+#ifdef HAVE_IPV6
+ lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
+#endif
+}
+
/*
* Builds the LSP data part. This func creates a new frag whenever
* area->lsp_frag_threshold is exceeded.
@@ -1230,6 +1348,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
sizeof (struct hostname));
+ /* FIXME: check length of hostname */
memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
strlen (unix_hostname ()));
lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
@@ -1478,6 +1597,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
}
}
+ lsp_build_ext_reach(lsp, area, &tlv_data);
+
while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
{
if (lsp->tlv_data.ipv4_int_reachs == NULL)
@@ -1485,12 +1606,25 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
&lsp->tlv_data.ipv4_int_reachs,
IPV4_REACH_LEN, area->lsp_frag_threshold,
- tlv_add_ipv4_reachs);
+ tlv_add_ipv4_int_reachs);
if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+ while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
+ {
+ if (lsp->tlv_data.ipv4_ext_reachs == NULL)
+ lsp->tlv_data.ipv4_ext_reachs = list_new ();
+ lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
+ &lsp->tlv_data.ipv4_ext_reachs,
+ IPV4_REACH_LEN, area->lsp_frag_threshold,
+ tlv_add_ipv4_ext_reachs);
+ if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
+ lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+
/* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
* for now. lsp_tlv_fit() needs to be fixed to deal with variable length
* TLVs (sub TLVs!). */