OSPF: Support of address families in OSPFv3
OSPFv3-AF can handle multiple topologies of diferent address families (IPv4, IPv6, both unicast and multicast) using separate instances distinguished by instance ID ranges.
This commit is contained in:
parent
15a4421f9c
commit
d3f4f92b0e
10 changed files with 262 additions and 136 deletions
|
@ -78,18 +78,66 @@ static void
|
||||||
ospf_proto_finish(void)
|
ospf_proto_finish(void)
|
||||||
{
|
{
|
||||||
struct ospf_config *cf = OSPF_CFG;
|
struct ospf_config *cf = OSPF_CFG;
|
||||||
|
struct ospf_area_config *ac;
|
||||||
if (EMPTY_LIST(cf->area_list))
|
struct ospf_iface_patt *ic;
|
||||||
cf_error( "No configured areas in OSPF");
|
|
||||||
|
|
||||||
/* Define default channel */
|
/* Define default channel */
|
||||||
if (EMPTY_LIST(this_proto->channels))
|
if (EMPTY_LIST(this_proto->channels))
|
||||||
|
{
|
||||||
|
this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
|
||||||
channel_config_new(NULL, this_proto->net_type, this_proto);
|
channel_config_new(NULL, this_proto->net_type, this_proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Propagate global instance ID to interfaces */
|
||||||
|
if (cf->instance_id_set)
|
||||||
|
{
|
||||||
|
WALK_LIST(ac, cf->area_list)
|
||||||
|
WALK_LIST(ic, ac->patt_list)
|
||||||
|
if (!ic->instance_id_set)
|
||||||
|
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
|
||||||
|
|
||||||
|
WALK_LIST(ic, cf->vlink_list)
|
||||||
|
if (!ic->instance_id_set)
|
||||||
|
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ospf_cfg_is_v3())
|
||||||
|
{
|
||||||
|
uint ipv4 = (this_proto->net_type == NET_IP4);
|
||||||
|
uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
|
||||||
|
|
||||||
|
/* RFC 5838 - OSPFv3-AF */
|
||||||
|
if (cf->af_ext)
|
||||||
|
{
|
||||||
|
/* RFC 5838 2.1 - instance IDs based on AFs */
|
||||||
|
WALK_LIST(ac, cf->area_list)
|
||||||
|
WALK_LIST(ic, ac->patt_list)
|
||||||
|
{
|
||||||
|
if (!ic->instance_id_set)
|
||||||
|
ic->instance_id = base;
|
||||||
|
else if (ic->instance_id >= 128)
|
||||||
|
log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
|
||||||
|
else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
|
||||||
|
cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
|
||||||
|
if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
|
||||||
|
cf_error("Vlinks not supported in AFs other than IPv6 unicast");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ipv4 || cf->af_mc)
|
||||||
|
cf_error("Different channel type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EMPTY_LIST(cf->area_list))
|
||||||
|
cf_error("No configured areas in OSPF");
|
||||||
|
|
||||||
int areano = 0;
|
int areano = 0;
|
||||||
int backbone = 0;
|
int backbone = 0;
|
||||||
int nssa = 0;
|
int nssa = 0;
|
||||||
struct ospf_area_config *ac;
|
|
||||||
WALK_LIST(ac, cf->area_list)
|
WALK_LIST(ac, cf->area_list)
|
||||||
{
|
{
|
||||||
areano++;
|
areano++;
|
||||||
|
@ -148,10 +196,11 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
|
||||||
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
|
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
|
||||||
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
|
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
|
||||||
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
|
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
|
||||||
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
|
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST)
|
||||||
|
|
||||||
%type <ld> lsadb_args
|
%type <ld> lsadb_args
|
||||||
%type <i> ospf_variant nbma_eligible
|
%type <i> ospf_variant ospf_af_mc nbma_eligible
|
||||||
|
%type <cc> ospf_channel_start ospf_channel
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -166,12 +215,13 @@ ospf_variant:
|
||||||
ospf_proto_start: proto_start ospf_variant
|
ospf_proto_start: proto_start ospf_variant
|
||||||
{
|
{
|
||||||
this_proto = proto_config_new(&proto_ospf, $1);
|
this_proto = proto_config_new(&proto_ospf, $1);
|
||||||
this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
|
this_proto->net_type = $2 ? NET_IP4 : 0;
|
||||||
|
|
||||||
init_list(&OSPF_CFG->area_list);
|
init_list(&OSPF_CFG->area_list);
|
||||||
init_list(&OSPF_CFG->vlink_list);
|
init_list(&OSPF_CFG->vlink_list);
|
||||||
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
|
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
|
||||||
OSPF_CFG->ospf2 = $2;
|
OSPF_CFG->ospf2 = $2;
|
||||||
|
OSPF_CFG->af_ext = !$2;
|
||||||
};
|
};
|
||||||
|
|
||||||
ospf_proto:
|
ospf_proto:
|
||||||
|
@ -179,16 +229,33 @@ ospf_proto:
|
||||||
| ospf_proto ospf_proto_item ';'
|
| ospf_proto ospf_proto_item ';'
|
||||||
;
|
;
|
||||||
|
|
||||||
|
ospf_af_mc:
|
||||||
|
{ $$ = 0; }
|
||||||
|
| MULTICAST { $$ = 1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* We redefine proto_channel to add multicast flag */
|
||||||
|
ospf_channel_start: net_type ospf_af_mc
|
||||||
|
{
|
||||||
|
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
|
||||||
|
|
||||||
|
/* Save the multicast flag */
|
||||||
|
if (this_channel == proto_cf_main_channel(this_proto))
|
||||||
|
OSPF_CFG->af_mc = $2;
|
||||||
|
};
|
||||||
|
|
||||||
|
ospf_channel: ospf_channel_start channel_opt_list channel_end;
|
||||||
|
|
||||||
ospf_proto_item:
|
ospf_proto_item:
|
||||||
proto_item
|
proto_item
|
||||||
| proto_channel
|
| ospf_channel { this_proto->net_type = $1->net_type; }
|
||||||
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
|
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
|
||||||
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
|
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
|
||||||
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
|
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
|
||||||
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
|
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
|
||||||
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
|
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
|
||||||
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
|
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
|
||||||
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
|
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
|
||||||
| ospf_area
|
| ospf_area
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -293,7 +360,6 @@ ospf_vlink_start: VIRTUAL LINK idval
|
||||||
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
||||||
OSPF_PATT->deadc = DEADC_D;
|
OSPF_PATT->deadc = DEADC_D;
|
||||||
OSPF_PATT->type = OSPF_IT_VLINK;
|
OSPF_PATT->type = OSPF_IT_VLINK;
|
||||||
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
|
|
||||||
init_list(&OSPF_PATT->nbma_list);
|
init_list(&OSPF_PATT->nbma_list);
|
||||||
reset_passwords();
|
reset_passwords();
|
||||||
}
|
}
|
||||||
|
@ -393,7 +459,6 @@ ospf_iface_start:
|
||||||
OSPF_PATT->priority = PRIORITY_D;
|
OSPF_PATT->priority = PRIORITY_D;
|
||||||
OSPF_PATT->deadc = DEADC_D;
|
OSPF_PATT->deadc = DEADC_D;
|
||||||
OSPF_PATT->type = OSPF_IT_UNDEF;
|
OSPF_PATT->type = OSPF_IT_UNDEF;
|
||||||
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
|
|
||||||
init_list(&OSPF_PATT->nbma_list);
|
init_list(&OSPF_PATT->nbma_list);
|
||||||
OSPF_PATT->ptp_netmask = 2; /* not specified */
|
OSPF_PATT->ptp_netmask = 2; /* not specified */
|
||||||
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
|
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
|
||||||
|
@ -404,7 +469,7 @@ ospf_iface_start:
|
||||||
|
|
||||||
ospf_instance_id:
|
ospf_instance_id:
|
||||||
/* empty */
|
/* empty */
|
||||||
| INSTANCE expr { OSPF_PATT->instance_id = $2; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
|
| INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_iface_patt_list:
|
ospf_iface_patt_list:
|
||||||
|
|
|
@ -356,7 +356,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
|
LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
|
||||||
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
|
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
|
||||||
|
|
||||||
if ((rcv_imms == DBDES_IMMS) &&
|
if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
|
||||||
(n->rid > p->router_id) &&
|
(n->rid > p->router_id) &&
|
||||||
(plen == ospf_dbdes_hdrlen(p)))
|
(plen == ospf_dbdes_hdrlen(p)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,10 +32,7 @@ struct ospf_hello3_packet
|
||||||
struct ospf_packet hdr;
|
struct ospf_packet hdr;
|
||||||
|
|
||||||
u32 iface_id;
|
u32 iface_id;
|
||||||
u8 priority;
|
u32 options;
|
||||||
u8 options3;
|
|
||||||
u8 options2;
|
|
||||||
u8 options;
|
|
||||||
u16 helloint;
|
u16 helloint;
|
||||||
u16 deadint;
|
u16 deadint;
|
||||||
u32 dr;
|
u32 dr;
|
||||||
|
@ -91,10 +88,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||||
|
|
||||||
ps->iface_id = htonl(ifa->iface_id);
|
ps->iface_id = htonl(ifa->iface_id);
|
||||||
ps->priority = ifa->priority;
|
ps->options = ntohl(ifa->oa->options | (ifa->priority << 24));
|
||||||
ps->options3 = ifa->oa->options >> 16;
|
|
||||||
ps->options2 = ifa->oa->options >> 8;
|
|
||||||
ps->options = ifa->oa->options;
|
|
||||||
ps->helloint = ntohs(ifa->helloint);
|
ps->helloint = ntohs(ifa->helloint);
|
||||||
ps->deadint = htons(ifa->deadint);
|
ps->deadint = htons(ifa->deadint);
|
||||||
ps->dr = htonl(ifa->drid);
|
ps->dr = htonl(ifa->drid);
|
||||||
|
@ -190,7 +184,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
struct ospf_proto *p = ifa->oa->po;
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
const char *err_dsc = NULL;
|
const char *err_dsc = NULL;
|
||||||
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
|
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
|
||||||
u8 rcv_options, rcv_priority;
|
uint rcv_options, rcv_priority;
|
||||||
|
uint loc_options = ifa->oa->options;
|
||||||
u32 *neighbors;
|
u32 *neighbors;
|
||||||
u32 neigh_count;
|
u32 neigh_count;
|
||||||
uint plen, i, err_val = 0;
|
uint plen, i, err_val = 0;
|
||||||
|
@ -245,8 +240,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
rcv_deadint = ntohs(ps->deadint);
|
rcv_deadint = ntohs(ps->deadint);
|
||||||
rcv_dr = ntohl(ps->dr);
|
rcv_dr = ntohl(ps->dr);
|
||||||
rcv_bdr = ntohl(ps->bdr);
|
rcv_bdr = ntohl(ps->bdr);
|
||||||
rcv_options = ps->options;
|
rcv_options = ntohl(ps->options) & 0x00FFFFFF;
|
||||||
rcv_priority = ps->priority;
|
rcv_priority = ntohl(ps->options) >> 24;
|
||||||
|
|
||||||
neighbors = ps->neighbors;
|
neighbors = ps->neighbors;
|
||||||
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
|
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
|
||||||
|
@ -259,9 +254,13 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
DROP("dead interval mismatch", rcv_deadint);
|
DROP("dead interval mismatch", rcv_deadint);
|
||||||
|
|
||||||
/* Check whether bits E, N match */
|
/* Check whether bits E, N match */
|
||||||
if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
|
if ((rcv_options ^ loc_options) & (OPT_E | OPT_N))
|
||||||
DROP("area type mismatch", rcv_options);
|
DROP("area type mismatch", rcv_options);
|
||||||
|
|
||||||
|
/* RFC 5838 2.4 - AF-bit check unless on IPv6 unicast */
|
||||||
|
if ((loc_options & OPT_AF) && !(loc_options & OPT_V6) && !(rcv_options & OPT_AF))
|
||||||
|
DROP("AF-bit mismatch", rcv_options);
|
||||||
|
|
||||||
/* Check consistency of existing neighbor entry */
|
/* Check consistency of existing neighbor entry */
|
||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1113,9 +1113,6 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||||
{
|
{
|
||||||
struct ospf_proto *p = (struct ospf_proto *) P;
|
struct ospf_proto *p = (struct ospf_proto *) P;
|
||||||
|
|
||||||
if (a->prefix.type != NET_IP6)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (a->flags & IA_SECONDARY)
|
if (a->flags & IA_SECONDARY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1126,6 +1123,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||||
other addresses are used for link-LSA. */
|
other addresses are used for link-LSA. */
|
||||||
if (a->scope == SCOPE_LINK)
|
if (a->scope == SCOPE_LINK)
|
||||||
{
|
{
|
||||||
|
if (a->prefix.type != NET_IP6)
|
||||||
|
return;
|
||||||
|
|
||||||
if (flags & IF_CHANGE_UP)
|
if (flags & IF_CHANGE_UP)
|
||||||
{
|
{
|
||||||
struct ospf_mip_walk s = { .iface = a->iface };
|
struct ospf_mip_walk s = { .iface = a->iface };
|
||||||
|
@ -1143,6 +1143,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (a->prefix.type != ospf_get_af(p))
|
||||||
|
return;
|
||||||
|
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
WALK_LIST(ifa, p->iface_list)
|
WALK_LIST(ifa, p->iface_list)
|
||||||
if (ifa->iface == a->iface)
|
if (ifa->iface == a->iface)
|
||||||
|
|
|
@ -280,7 +280,7 @@ lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric)
|
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric)
|
||||||
{
|
{
|
||||||
if (ospf2)
|
if (ospf2)
|
||||||
{
|
{
|
||||||
|
@ -292,7 +292,7 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopt
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct ospf_lsa_sum3_net *ls = en->lsa_body;
|
struct ospf_lsa_sum3_net *ls = en->lsa_body;
|
||||||
ospf_get_ipv6_prefix(ls->prefix, net, pxopts, NULL);
|
ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL);
|
||||||
*metric = ls->metric & LSA_METRIC_MASK;
|
*metric = ls->metric & LSA_METRIC_MASK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
|
lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt)
|
||||||
{
|
{
|
||||||
if (ospf2)
|
if (ospf2)
|
||||||
{
|
{
|
||||||
|
@ -338,13 +338,13 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct ospf_lsa_ext3 *ext = en->lsa_body;
|
struct ospf_lsa_ext3 *ext = en->lsa_body;
|
||||||
u32 *buf = ospf_get_ipv6_prefix(ext->rest, &rt->net, &rt->pxopts, NULL);
|
u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL);
|
||||||
rt->metric = ext->metric & LSA_METRIC_MASK;
|
rt->metric = ext->metric & LSA_METRIC_MASK;
|
||||||
rt->ebit = ext->metric & LSA_EXT3_EBIT;
|
rt->ebit = ext->metric & LSA_EXT3_EBIT;
|
||||||
|
|
||||||
rt->fbit = ext->metric & LSA_EXT3_FBIT;
|
rt->fbit = ext->metric & LSA_EXT3_FBIT;
|
||||||
if (rt->fbit)
|
if (rt->fbit)
|
||||||
buf = ospf_get_ipv6_addr(buf, &rt->fwaddr);
|
buf = ospf3_get_addr(buf, af, &rt->fwaddr);
|
||||||
else
|
else
|
||||||
rt->fwaddr = IPA_NONE;
|
rt->fwaddr = IPA_NONE;
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
|
||||||
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
|
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
|
||||||
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
|
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
|
||||||
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
|
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
|
||||||
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric);
|
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric);
|
||||||
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
|
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
|
||||||
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
|
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt);
|
||||||
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
|
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
|
||||||
|
|
||||||
#endif /* _BIRD_OSPF_LSALIB_H_ */
|
#endif /* _BIRD_OSPF_LSALIB_H_ */
|
||||||
|
|
|
@ -92,8 +92,10 @@
|
||||||
* - RFC 2328 - main OSPFv2 standard
|
* - RFC 2328 - main OSPFv2 standard
|
||||||
* - RFC 5340 - main OSPFv3 standard
|
* - RFC 5340 - main OSPFv3 standard
|
||||||
* - RFC 3101 - OSPFv2 NSSA areas
|
* - RFC 3101 - OSPFv2 NSSA areas
|
||||||
* - RFC 6549 - OSPFv2 multi-instance extensions
|
* - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
|
||||||
* - RFC 6987 - OSPF stub router advertisement
|
* - RFC 5838 - OSPFv3 Support of Address Families
|
||||||
|
* - RFC 6549 - OSPFv2 Multi-Instance Extensions
|
||||||
|
* - RFC 6987 - OSPF Stub Router Advertisement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -115,9 +117,9 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
||||||
struct area_net_config *anc;
|
struct area_net_config *anc;
|
||||||
struct area_net *an;
|
struct area_net *an;
|
||||||
|
|
||||||
fib_init(&oa->net_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6,
|
fib_init(&oa->net_fib, p->p.pool, ospf_get_af(p),
|
||||||
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
|
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
|
||||||
fib_init(&oa->enet_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6,
|
fib_init(&oa->enet_fib, p->p.pool, ospf_get_af(p),
|
||||||
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
|
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
|
||||||
|
|
||||||
WALK_LIST(anc, ac->net_list)
|
WALK_LIST(anc, ac->net_list)
|
||||||
|
@ -134,6 +136,16 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint
|
||||||
|
ospf_opts(struct ospf_proto *p)
|
||||||
|
{
|
||||||
|
if (ospf_is_v2(p))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ((ospf_is_ip6(p) && !p->af_mc) ? OPT_V6 : 0) |
|
||||||
|
(!p->stub_router ? OPT_R : 0) | (p->af_ext ? OPT_AF : 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
|
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
|
||||||
{
|
{
|
||||||
|
@ -155,10 +167,7 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
|
||||||
if (oa->areaid == 0)
|
if (oa->areaid == 0)
|
||||||
p->backbone = oa;
|
p->backbone = oa;
|
||||||
|
|
||||||
if (ospf_is_v2(p))
|
oa->options = ac->type | ospf_opts(p);
|
||||||
oa->options = ac->type;
|
|
||||||
else
|
|
||||||
oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
|
|
||||||
|
|
||||||
ospf_notify_rt_lsa(oa);
|
ospf_notify_rt_lsa(oa);
|
||||||
}
|
}
|
||||||
|
@ -224,6 +233,8 @@ ospf_start(struct proto *P)
|
||||||
|
|
||||||
p->router_id = proto_get_router_id(P->cf);
|
p->router_id = proto_get_router_id(P->cf);
|
||||||
p->ospf2 = c->ospf2;
|
p->ospf2 = c->ospf2;
|
||||||
|
p->af_ext = c->af_ext;
|
||||||
|
p->af_mc = c->af_mc;
|
||||||
p->rfc1583 = c->rfc1583;
|
p->rfc1583 = c->rfc1583;
|
||||||
p->stub_router = c->stub_router;
|
p->stub_router = c->stub_router;
|
||||||
p->merge_external = c->merge_external;
|
p->merge_external = c->merge_external;
|
||||||
|
@ -238,8 +249,7 @@ ospf_start(struct proto *P)
|
||||||
p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
|
p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
|
||||||
init_list(&(p->iface_list));
|
init_list(&(p->iface_list));
|
||||||
init_list(&(p->area_list));
|
init_list(&(p->area_list));
|
||||||
fib_init(&p->rtf, P->pool, p->ospf2 ? NET_IP4 : NET_IP6,
|
fib_init(&p->rtf, P->pool, ospf_get_af(p), sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
|
||||||
sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
|
|
||||||
if (ospf_is_v3(p))
|
if (ospf_is_v3(p))
|
||||||
idm_init(&p->idm, P->pool, 16);
|
idm_init(&p->idm, P->pool, 16);
|
||||||
p->areano = 0;
|
p->areano = 0;
|
||||||
|
@ -601,11 +611,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
|
|
||||||
oa->ac = nac;
|
oa->ac = nac;
|
||||||
|
oa->options = nac->type | ospf_opts(p);
|
||||||
if (ospf_is_v2(p))
|
|
||||||
oa->options = nac->type;
|
|
||||||
else
|
|
||||||
oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
|
|
||||||
|
|
||||||
if (nac->type != oac->type)
|
if (nac->type != oac->type)
|
||||||
{
|
{
|
||||||
|
@ -659,6 +665,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
|
||||||
if (old->abr != new->abr)
|
if (old->abr != new->abr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
|
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1073,13 +1082,13 @@ show_lsa_network(struct top_hash_entry *he, int ospf2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
|
show_lsa_sum_net(struct top_hash_entry *he, int ospf2, int af)
|
||||||
{
|
{
|
||||||
net_addr net;
|
net_addr net;
|
||||||
u8 pxopts;
|
u8 pxopts;
|
||||||
u32 metric;
|
u32 metric;
|
||||||
|
|
||||||
lsa_parse_sum_net(he, ospf2, &net, &pxopts, &metric);
|
lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric);
|
||||||
cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
|
cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,7 +1105,7 @@ show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
show_lsa_external(struct top_hash_entry *he, int ospf2)
|
show_lsa_external(struct top_hash_entry *he, int ospf2, int af)
|
||||||
{
|
{
|
||||||
struct ospf_lsa_ext_local rt;
|
struct ospf_lsa_ext_local rt;
|
||||||
char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
|
char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
|
||||||
|
@ -1105,7 +1114,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
|
||||||
if (he->lsa_type == LSA_T_EXT)
|
if (he->lsa_type == LSA_T_EXT)
|
||||||
he->domain = 0; /* Unmark the LSA */
|
he->domain = 0; /* Unmark the LSA */
|
||||||
|
|
||||||
lsa_parse_ext(he, ospf2, &rt);
|
lsa_parse_ext(he, ospf2, af, &rt);
|
||||||
|
|
||||||
if (rt.fbit)
|
if (rt.fbit)
|
||||||
bsprintf(str_via, " via %I", rt.fwaddr);
|
bsprintf(str_via, " via %I", rt.fwaddr);
|
||||||
|
@ -1119,7 +1128,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
|
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode, int af)
|
||||||
{
|
{
|
||||||
struct ospf_lsa_prefix *px = he->lsa_body;
|
struct ospf_lsa_prefix *px = he->lsa_body;
|
||||||
u32 *buf;
|
u32 *buf;
|
||||||
|
@ -1142,7 +1151,7 @@ show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
|
||||||
u8 pxopts;
|
u8 pxopts;
|
||||||
u16 metric;
|
u16 metric;
|
||||||
|
|
||||||
buf = ospf_get_ipv6_prefix(buf, &net, &pxopts, &metric);
|
buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric);
|
||||||
|
|
||||||
if (px->ref_type == LSA_T_RT)
|
if (px->ref_type == LSA_T_RT)
|
||||||
cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
|
cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
|
||||||
|
@ -1156,6 +1165,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||||
{
|
{
|
||||||
struct ospf_proto *p = (struct ospf_proto *) P;
|
struct ospf_proto *p = (struct ospf_proto *) P;
|
||||||
int ospf2 = ospf_is_v2(p);
|
int ospf2 = ospf_is_v2(p);
|
||||||
|
int af = ospf_get_af(p);
|
||||||
uint i, ix, j1, jx;
|
uint i, ix, j1, jx;
|
||||||
u32 last_area = 0xFFFFFFFF;
|
u32 last_area = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
@ -1276,7 +1286,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||||
|
|
||||||
case LSA_T_SUM_NET:
|
case LSA_T_SUM_NET:
|
||||||
if (cnode->lsa_type == LSA_T_RT)
|
if (cnode->lsa_type == LSA_T_RT)
|
||||||
show_lsa_sum_net(he, ospf2);
|
show_lsa_sum_net(he, ospf2, af);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LSA_T_SUM_RT:
|
case LSA_T_SUM_RT:
|
||||||
|
@ -1286,11 +1296,11 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||||
|
|
||||||
case LSA_T_EXT:
|
case LSA_T_EXT:
|
||||||
case LSA_T_NSSA:
|
case LSA_T_NSSA:
|
||||||
show_lsa_external(he, ospf2);
|
show_lsa_external(he, ospf2, af);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LSA_T_PREFIX:
|
case LSA_T_PREFIX:
|
||||||
show_lsa_prefix(he, cnode);
|
show_lsa_prefix(he, cnode, af);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,7 +1314,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||||
ix++;
|
ix++;
|
||||||
|
|
||||||
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
|
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
|
||||||
show_lsa_external(hex[ix++], ospf2);
|
show_lsa_external(hex[ix++], ospf2, af);
|
||||||
|
|
||||||
cnode = NULL;
|
cnode = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1338,7 +1348,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||||
last_rt = he->lsa.rt;
|
last_rt = he->lsa.rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
show_lsa_external(he, ospf2);
|
show_lsa_external(he, ospf2, af);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,13 @@ struct ospf_config
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
uint tick;
|
uint tick;
|
||||||
u8 ospf2;
|
u8 ospf2;
|
||||||
|
u8 af_ext;
|
||||||
|
u8 af_mc;
|
||||||
u8 rfc1583;
|
u8 rfc1583;
|
||||||
u8 stub_router;
|
u8 stub_router;
|
||||||
u8 merge_external;
|
u8 merge_external;
|
||||||
u8 instance_id;
|
u8 instance_id;
|
||||||
|
u8 instance_id_set;
|
||||||
u8 abr;
|
u8 abr;
|
||||||
u8 asbr;
|
u8 asbr;
|
||||||
int ecmp;
|
int ecmp;
|
||||||
|
@ -168,9 +171,9 @@ struct ospf_iface_patt
|
||||||
int tx_priority;
|
int tx_priority;
|
||||||
u16 tx_length;
|
u16 tx_length;
|
||||||
u16 rx_buffer;
|
u16 rx_buffer;
|
||||||
|
|
||||||
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
||||||
u8 instance_id;
|
u8 instance_id;
|
||||||
|
u8 instance_id_set;
|
||||||
u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */
|
u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */
|
||||||
u8 strictnbma;
|
u8 strictnbma;
|
||||||
u8 check_link;
|
u8 check_link;
|
||||||
|
@ -211,12 +214,14 @@ struct ospf_proto
|
||||||
int padj; /* Number of neighbors in Exchange or Loading state */
|
int padj; /* Number of neighbors in Exchange or Loading state */
|
||||||
struct fib rtf; /* Routing table */
|
struct fib rtf; /* Routing table */
|
||||||
struct idm idm; /* OSPFv3 LSA ID map */
|
struct idm idm; /* OSPFv3 LSA ID map */
|
||||||
byte ospf2; /* OSPF v2 or v3 */
|
u8 ospf2; /* OSPF v2 or v3 */
|
||||||
byte rfc1583; /* RFC1583 compatibility */
|
u8 af_ext; /* OSPFv3-AF extension */
|
||||||
byte stub_router; /* Do not forward transit traffic */
|
u8 af_mc; /* OSPFv3-AF multicast */
|
||||||
byte merge_external; /* Should i merge external routes? */
|
u8 rfc1583; /* RFC1583 compatibility */
|
||||||
byte asbr; /* May i originate any ext/NSSA lsa? */
|
u8 stub_router; /* Do not forward transit traffic */
|
||||||
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
u8 merge_external; /* Should i merge external routes? */
|
||||||
|
u8 asbr; /* May i originate any ext/NSSA lsa? */
|
||||||
|
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
||||||
struct ospf_area *backbone; /* If exists */
|
struct ospf_area *backbone; /* If exists */
|
||||||
event *flood_event; /* Event for flooding LS updates */
|
event *flood_event; /* Event for flooding LS updates */
|
||||||
void *lsab; /* LSA buffer used when originating router LSAs */
|
void *lsab; /* LSA buffer used when originating router LSAs */
|
||||||
|
@ -449,14 +454,15 @@ struct ospf_neighbor
|
||||||
|
|
||||||
|
|
||||||
/* Generic option flags */
|
/* Generic option flags */
|
||||||
#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */
|
#define OPT_V6 0x0001 /* OSPFv3, LSA relevant for IPv6 routing calculation */
|
||||||
#define OPT_E 0x02 /* Related to AS-external LSAs */
|
#define OPT_E 0x0002 /* Related to AS-external LSAs */
|
||||||
#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */
|
#define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
|
||||||
#define OPT_N 0x08 /* Related to NSSA */
|
#define OPT_N 0x0008 /* Related to NSSA */
|
||||||
#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
#define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
||||||
#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */
|
#define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */
|
||||||
#define OPT_R 0x10 /* OSPFv3, originator is active router */
|
#define OPT_R 0x0010 /* OSPFv3, originator is active router */
|
||||||
#define OPT_DC 0x20 /* Related to demand circuits, not used */
|
#define OPT_DC 0x0020 /* Related to demand circuits, not used */
|
||||||
|
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
|
||||||
|
|
||||||
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
||||||
#define OPT_RT_B (0x01 << 24)
|
#define OPT_RT_B (0x01 << 24)
|
||||||
|
@ -718,74 +724,96 @@ lsa_net_count(struct ospf_lsa_header *lsa)
|
||||||
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
|
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
|
||||||
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
|
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
|
||||||
|
|
||||||
/* FIXME: these functions should be significantly redesigned w.r.t. integration,
|
|
||||||
also should be named as ospf3_* instead of *_ipv6_* */
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ospf_valid_prefix(net_addr *n)
|
ospf_valid_prefix(net_addr *n)
|
||||||
{
|
{
|
||||||
/* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for invalid one */
|
/*
|
||||||
return n->pxlen <= IP6_MAX_PREFIX_LENGTH;
|
* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for
|
||||||
|
* invalid one. But OSPFv3-AF may receive IPv4 net with 32 < pxlen < 128.
|
||||||
|
*/
|
||||||
|
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
|
||||||
|
return n->pxlen <= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In OSPFv3-AF (RFC 5835), IPv4 address is encoded by just placing it in the
|
||||||
|
* first 32 bits of IPv6 address and setting remaining bits to zero. Likewise
|
||||||
|
* for IPv4 prefix, where remaining bits do not matter. We use following
|
||||||
|
* functions to convert between IPv4 and IPv4-in-IPv6 representations:
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline ip4_addr ospf3_6to4(ip6_addr a)
|
||||||
|
{ return _MI4(_I0(a)); }
|
||||||
|
|
||||||
|
static inline ip6_addr ospf3_4to6(ip4_addr a)
|
||||||
|
{ return _MI6(_I(a), 0, 0, 0); }
|
||||||
|
|
||||||
|
|
||||||
static inline u32 *
|
static inline u32 *
|
||||||
ospf_get_ipv6_prefix(u32 *buf, net_addr *N, u8 *pxopts, u16 *rest)
|
ospf3_get_prefix(u32 *buf, int af, net_addr *n, u8 *pxopts, u16 *rest)
|
||||||
{
|
{
|
||||||
net_addr_ip6 *net = (void *) N;
|
ip6_addr px = IP6_NONE;
|
||||||
u8 pxlen = (*buf >> 24);
|
uint pxlen = (*buf >> 24);
|
||||||
*pxopts = (*buf >> 16) & 0xff;
|
*pxopts = (*buf >> 16) & 0xff;
|
||||||
if (rest) *rest = *buf & 0xffff;
|
if (rest) *rest = *buf & 0xffff;
|
||||||
buf++;
|
buf++;
|
||||||
|
|
||||||
*net = NET_ADDR_IP6(IP6_NONE, pxlen);
|
|
||||||
|
|
||||||
if (pxlen > 0)
|
if (pxlen > 0)
|
||||||
_I0(net->prefix) = *buf++;
|
_I0(px) = *buf++;
|
||||||
if (pxlen > 32)
|
if (pxlen > 32)
|
||||||
_I1(net->prefix) = *buf++;
|
_I1(px) = *buf++;
|
||||||
if (pxlen > 64)
|
if (pxlen > 64)
|
||||||
_I2(net->prefix) = *buf++;
|
_I2(px) = *buf++;
|
||||||
if (pxlen > 96)
|
if (pxlen > 96)
|
||||||
_I3(net->prefix) = *buf++;
|
_I3(px) = *buf++;
|
||||||
|
|
||||||
/* Clean up remaining bits */
|
/* Clean up remaining bits */
|
||||||
if (pxlen < 128)
|
if (pxlen < 128)
|
||||||
net->prefix.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
|
px.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
|
||||||
|
|
||||||
|
if (af == NET_IP4)
|
||||||
|
net_fill_ip4(n, ospf3_6to4(px), pxlen);
|
||||||
|
else
|
||||||
|
net_fill_ip6(n, px, pxlen);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 *
|
static inline u32 *
|
||||||
ospf_get_ipv6_addr(u32 *buf, ip_addr *addr)
|
ospf3_put_prefix(u32 *buf, net_addr *n, u8 pxopts, u16 rest)
|
||||||
{
|
{
|
||||||
*addr = ipa_from_ip6(*(ip6_addr *) buf);
|
ip6_addr px = (n->type == NET_IP4) ? ospf3_4to6(net4_prefix(n)) : net6_prefix(n);
|
||||||
return buf + 4;
|
uint pxlen = n->pxlen;
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 *
|
|
||||||
ospf_put_ipv6_prefix(u32 *buf, net_addr *N, u8 pxopts, u16 rest)
|
|
||||||
{
|
|
||||||
net_addr_ip6 *net = (void *) N;
|
|
||||||
u32 pxlen = net->pxlen;
|
|
||||||
|
|
||||||
*buf++ = ((pxlen << 24) | (pxopts << 16) | rest);
|
*buf++ = ((pxlen << 24) | (pxopts << 16) | rest);
|
||||||
|
|
||||||
if (pxlen > 0)
|
if (pxlen > 0)
|
||||||
*buf++ = _I0(net->prefix);
|
*buf++ = _I0(px);
|
||||||
if (pxlen > 32)
|
if (pxlen > 32)
|
||||||
*buf++ = _I1(net->prefix);
|
*buf++ = _I1(px);
|
||||||
if (pxlen > 64)
|
if (pxlen > 64)
|
||||||
*buf++ = _I2(net->prefix);
|
*buf++ = _I2(px);
|
||||||
if (pxlen > 96)
|
if (pxlen > 96)
|
||||||
*buf++ = _I3(net->prefix);
|
*buf++ = _I3(px);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 *
|
static inline u32 *
|
||||||
ospf_put_ipv6_addr(u32 *buf, ip_addr addr)
|
ospf3_get_addr(u32 *buf, int af, ip_addr *addr)
|
||||||
{
|
{
|
||||||
*(ip6_addr *) buf = ipa_to_ip6(addr);
|
ip6_addr a;
|
||||||
|
memcpy(&a, buf, 16);
|
||||||
|
*addr = (af == NET_IP4) ? ipa_from_ip4(ospf3_6to4(a)) : ipa_from_ip6(a);
|
||||||
|
return buf + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 *
|
||||||
|
ospf3_put_addr(u32 *buf, ip_addr addr)
|
||||||
|
{
|
||||||
|
ip6_addr a = ipa_is_ip4(addr) ? ospf3_4to6(ipa_to_ip4(addr)) : ipa_to_ip6(addr);
|
||||||
|
memcpy(buf, &a, 16);
|
||||||
return buf + 4;
|
return buf + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,6 +866,15 @@ static inline int ospf_is_v3(struct ospf_proto *p)
|
||||||
static inline int ospf_get_version(struct ospf_proto *p)
|
static inline int ospf_get_version(struct ospf_proto *p)
|
||||||
{ return ospf_is_v2(p) ? 2 : 3; }
|
{ return ospf_is_v2(p) ? 2 : 3; }
|
||||||
|
|
||||||
|
static inline int ospf_is_ip4(struct ospf_proto *p)
|
||||||
|
{ return p->p.net_type == NET_IP4; }
|
||||||
|
|
||||||
|
static inline int ospf_is_ip6(struct ospf_proto *p)
|
||||||
|
{ return p->p.net_type == NET_IP6; }
|
||||||
|
|
||||||
|
static inline int ospf_get_af(struct ospf_proto *p)
|
||||||
|
{ return p->p.net_type; }
|
||||||
|
|
||||||
struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
|
struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
|
||||||
|
|
||||||
static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)
|
static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)
|
||||||
|
|
|
@ -576,20 +576,20 @@ spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
buf = px->rest;
|
buf = px->rest;
|
||||||
for (i = 0; i < px->pxcount; i++)
|
for (i = 0; i < px->pxcount; i++)
|
||||||
{
|
{
|
||||||
net_addr_ip6 net;
|
net_addr net;
|
||||||
u8 pxopts;
|
u8 pxopts;
|
||||||
u16 metric;
|
u16 metric;
|
||||||
|
|
||||||
buf = ospf_get_ipv6_prefix(buf, (net_addr *) &net, &pxopts, &metric);
|
buf = ospf3_get_prefix(buf, ospf_get_af(p), &net, &pxopts, &metric);
|
||||||
|
|
||||||
if (pxopts & OPT_PX_NU)
|
if (pxopts & OPT_PX_NU)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Store the first global address to use it later as a vlink endpoint */
|
/* Store the first global address to use it later as a vlink endpoint */
|
||||||
if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb))
|
if ((pxopts & OPT_PX_LA) && (net.type == NET_IP6) && ipa_zero(src->lb))
|
||||||
src->lb = ipa_from_ip6(net.prefix);
|
src->lb = ipa_from_ip6(net6_prefix(&net));
|
||||||
|
|
||||||
add_network(oa, (net_addr *) &net, src->dist + metric, src, i);
|
add_network(oa, &net, src->dist + metric, src, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -761,7 +761,7 @@ ospf_rt_sum(struct ospf_area *oa)
|
||||||
|
|
||||||
if (en->lsa_type == LSA_T_SUM_NET)
|
if (en->lsa_type == LSA_T_SUM_NET)
|
||||||
{
|
{
|
||||||
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric);
|
lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
|
||||||
|
|
||||||
if (!ospf_valid_prefix(&net))
|
if (!ospf_valid_prefix(&net))
|
||||||
{
|
{
|
||||||
|
@ -858,7 +858,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
|
||||||
net_addr net;
|
net_addr net;
|
||||||
u8 pxopts;
|
u8 pxopts;
|
||||||
|
|
||||||
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric);
|
lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
|
||||||
|
|
||||||
if (!ospf_valid_prefix(&net))
|
if (!ospf_valid_prefix(&net))
|
||||||
{
|
{
|
||||||
|
@ -1058,7 +1058,7 @@ decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* We do not store needed data in struct orta, we have to parse the LSA */
|
/* We do not store needed data in struct orta, we have to parse the LSA */
|
||||||
lsa_parse_ext(en, ospf_is_v2(p), rt);
|
lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), rt);
|
||||||
|
|
||||||
if (rt->pxopts & OPT_PX_NU)
|
if (rt->pxopts & OPT_PX_NU)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1450,7 +1450,7 @@ ospf_ext_spf(struct ospf_proto *p)
|
||||||
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
|
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
|
||||||
p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
|
p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
|
||||||
|
|
||||||
lsa_parse_ext(en, ospf_is_v2(p), &rt);
|
lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), &rt);
|
||||||
|
|
||||||
if (!ospf_valid_prefix(&rt.net))
|
if (!ospf_valid_prefix(&rt.net))
|
||||||
{
|
{
|
||||||
|
@ -1765,7 +1765,11 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||||
if (ip6_zero(llsa->lladdr))
|
if (ip6_zero(llsa->lladdr))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
|
ip_addr nh = ospf_is_ip4(p) ?
|
||||||
|
ipa_from_ip4(ospf3_6to4(llsa->lladdr)) :
|
||||||
|
ipa_from_ip6(llsa->lladdr);
|
||||||
|
|
||||||
|
return new_nexthop(p, nh, pn->iface, pn->weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1792,9 +1796,9 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||||
if (en->lsa.age == LSA_MAXAGE)
|
if (en->lsa.age == LSA_MAXAGE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT))
|
if (ospf_is_v3(p) && (oa->options & OPT_V6) && (en->lsa_type == LSA_T_RT))
|
||||||
{
|
{
|
||||||
/* In OSPFv3, check V6 flag */
|
/* In OSPFv3 IPv6 unicast, check V6 flag */
|
||||||
struct ospf_lsa_rt *rt = en->lsa_body;
|
struct ospf_lsa_rt *rt = en->lsa_body;
|
||||||
if (!(rt->options & OPT_V6))
|
if (!(rt->options & OPT_V6))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1008,7 +1008,7 @@ prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
|
||||||
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
|
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
|
||||||
IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
|
IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
|
||||||
sum->metric = metric;
|
sum->metric = metric;
|
||||||
ospf_put_ipv6_prefix(sum->prefix, nf->fn.addr, 0, 0);
|
ospf3_put_prefix(sum->prefix, nf->fn.addr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -1097,7 +1097,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
|
||||||
ext->metric = metric & LSA_METRIC_MASK;
|
ext->metric = metric & LSA_METRIC_MASK;
|
||||||
u32 *buf = ext->rest;
|
u32 *buf = ext->rest;
|
||||||
|
|
||||||
buf = ospf_put_ipv6_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
|
buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
|
||||||
|
|
||||||
if (ebit)
|
if (ebit)
|
||||||
ext->metric |= LSA_EXT3_EBIT;
|
ext->metric |= LSA_EXT3_EBIT;
|
||||||
|
@ -1105,7 +1105,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
|
||||||
if (ipa_nonzero(fwaddr))
|
if (ipa_nonzero(fwaddr))
|
||||||
{
|
{
|
||||||
ext->metric |= LSA_EXT3_FBIT;
|
ext->metric |= LSA_EXT3_FBIT;
|
||||||
buf = ospf_put_ipv6_addr(buf, fwaddr);
|
buf = ospf3_put_addr(buf, fwaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag)
|
if (tag)
|
||||||
|
@ -1222,7 +1222,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
{
|
{
|
||||||
WALK_LIST(a, ifa->iface->addrs)
|
WALK_LIST(a, ifa->iface->addrs)
|
||||||
{
|
{
|
||||||
if ((a->prefix.type != NET_IP6) ||
|
if ((a->prefix.type != ospf_get_af(p)) ||
|
||||||
(a->flags & IA_SECONDARY) ||
|
(a->flags & IA_SECONDARY) ||
|
||||||
(a->flags & IA_PEER) ||
|
(a->flags & IA_PEER) ||
|
||||||
(a->scope <= SCOPE_LINK))
|
(a->scope <= SCOPE_LINK))
|
||||||
|
@ -1316,39 +1316,47 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
lsab_put_prefix(struct ospf_proto *p, net_addr *net, u32 cost)
|
lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost)
|
||||||
{
|
{
|
||||||
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net6_pxlen(net)));
|
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net_pxlen(n)));
|
||||||
u8 flags = (net6_pxlen(net) < IP6_MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
|
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
|
||||||
ospf_put_ipv6_prefix(buf, net, flags, cost);
|
u8 flags = (net_pxlen(n) < max) ? 0 : OPT_PX_LA;
|
||||||
|
ospf3_put_prefix(buf, n, flags, cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
|
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
struct ospf_lsa_link *ll;
|
ip_addr nh = ospf_is_ip4(p) ? IPA_NONE : ifa->addr->ip;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
/* Preallocating space for header */
|
||||||
ASSERT(p->lsab_used == 0);
|
ASSERT(p->lsab_used == 0);
|
||||||
ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
|
lsab_allocz(p, sizeof(struct ospf_lsa_link));
|
||||||
ll->options = ifa->oa->options | (ifa->priority << 24);
|
|
||||||
ll->lladdr = ipa_to_ip6(ifa->addr->ip);
|
|
||||||
ll = NULL; /* buffer might be reallocated later */
|
|
||||||
|
|
||||||
struct ifa *a;
|
struct ifa *a;
|
||||||
WALK_LIST(a, ifa->iface->addrs)
|
WALK_LIST(a, ifa->iface->addrs)
|
||||||
{
|
{
|
||||||
if ((a->prefix.type != NET_IP6) ||
|
if ((a->prefix.type != ospf_get_af(p)) ||
|
||||||
(a->flags & IA_SECONDARY) ||
|
(a->flags & IA_SECONDARY) ||
|
||||||
(a->scope <= SCOPE_LINK))
|
(a->scope <= SCOPE_LINK))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (ospf_is_ip4(p) && ipa_zero(nh))
|
||||||
|
nh = a->ip;
|
||||||
|
|
||||||
lsab_put_prefix(p, &a->prefix, 0);
|
lsab_put_prefix(p, &a->prefix, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ll = p->lsab;
|
/* Filling the preallocated header */
|
||||||
|
struct ospf_lsa_link *ll = p->lsab;
|
||||||
|
ll->options = ifa->oa->options | (ifa->priority << 24);
|
||||||
|
ll->lladdr = ospf_is_ip4(p) ? ospf3_4to6(ipa_to_ip4(nh)) : ipa_to_ip6(nh);
|
||||||
ll->pxcount = i;
|
ll->pxcount = i;
|
||||||
|
|
||||||
|
if (ipa_zero(nh))
|
||||||
|
log(L_ERR "%s: Cannot find next hop address for %s", p->p.name, ifa->ifname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1410,7 +1418,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
struct ifa *a;
|
struct ifa *a;
|
||||||
WALK_LIST(a, ifa->iface->addrs)
|
WALK_LIST(a, ifa->iface->addrs)
|
||||||
{
|
{
|
||||||
if ((a->prefix.type != NET_IP6) ||
|
if ((a->prefix.type != ospf_get_af(p)) ||
|
||||||
(a->flags & IA_SECONDARY) ||
|
(a->flags & IA_SECONDARY) ||
|
||||||
(a->flags & IA_PEER) ||
|
(a->flags & IA_PEER) ||
|
||||||
(a->scope <= SCOPE_LINK))
|
(a->scope <= SCOPE_LINK))
|
||||||
|
@ -1448,7 +1456,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
|
|
||||||
/* If there are some configured vlinks, find some global address
|
/* If there are some configured vlinks, find some global address
|
||||||
(even from another area), which will be used as a vlink endpoint. */
|
(even from another area), which will be used as a vlink endpoint. */
|
||||||
if (!EMPTY_LIST(cf->vlink_list) && !host_addr)
|
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && ospf_is_ip6(p))
|
||||||
{
|
{
|
||||||
WALK_LIST(ifa, p->iface_list)
|
WALK_LIST(ifa, p->iface_list)
|
||||||
{
|
{
|
||||||
|
@ -1571,7 +1579,7 @@ add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *px
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Skip link-local prefixes */
|
/* Skip link-local prefixes */
|
||||||
if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
|
if (ospf_is_ip6(p) && (pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
add_prefix(p, pxb, offset, pxc);
|
add_prefix(p, pxb, offset, pxc);
|
||||||
|
|
Loading…
Reference in a new issue