Commit 57c574d8 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Multipath support for OSPF

parent 9852f810
......@@ -51,7 +51,7 @@ CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, NONBROADCAST, POINTOPOINT, TYPE)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY)
CF_KEYWORDS(WAIT, DELAY, LSADB)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT)
%type <t> opttext
......@@ -76,7 +76,9 @@ ospf_proto:
ospf_proto_item:
proto_item
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| TICK expr { OSPF_CFG->tick = $2 ; if($2<=0) cf_error("Tick must be greater than zero"); }
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
| ospf_area '}'
;
......@@ -193,6 +195,7 @@ ospf_iface_item:
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| STUB bool { OSPF_PATT->stub = $2 ; }
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
| ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| NEIGHBORS '{' ipa_list '}'
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
......
......@@ -436,6 +436,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
ifa->ioprob = OSPF_I_OK;
ifa->rxbuf = ip->rxbuf;
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
#ifdef OSPFv2
ifa->autype = ip->autype;
......@@ -795,6 +796,8 @@ ospf_iface_info(struct ospf_iface *ifa)
ifa->stub ? "(stub)" : "");
cli_msg(-1015, "\tPriority: %u", ifa->priority);
cli_msg(-1015, "\tCost: %u", ifa->cost);
if (ifa->oa->po->ecmp)
cli_msg(-1015, "\tECMP weight: %d", ((int) ifa->ecmp_weight) + 1);
cli_msg(-1015, "\tHello timer: %u", ifa->helloint);
if (ifa->type == OSPF_IT_NBMA)
......
......@@ -147,6 +147,7 @@ ospf_start(struct proto *p)
po->router_id = proto_get_router_id(p->cf);
po->rfc1583 = c->rfc1583;
po->ebit = 0;
po->ecmp = c->ecmp;
po->tick = c->tick;
po->disp_timer = tm_new(p->pool);
po->disp_timer->data = po;
......@@ -157,6 +158,7 @@ ospf_start(struct proto *p)
po->lsab_size = 256;
po->lsab_used = 0;
po->lsab = mb_alloc(p->pool, po->lsab_size);
po->nhpool = lp_new(p->pool, 12*sizeof(struct mpnh));
init_list(&(po->iface_list));
init_list(&(po->area_list));
fib_init(&po->rtf, p->pool, sizeof(ort), 0, ospf_rt_initort);
......@@ -514,6 +516,13 @@ ospf_shutdown(struct proto *p)
if (ifa->state > OSPF_IS_DOWN)
ospf_iface_shutdown(ifa);
/* Cleanup locked rta entries */
FIB_WALK(&po->rtf, nftmp)
{
rta_free(((ort *) nftmp)->old_rta);
}
FIB_WALK_END;
return PS_DOWN;
}
......@@ -648,6 +657,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
schedule_rtcalc(po);
po->tick = new->tick;
po->ecmp = new->ecmp;
po->disp_timer->recurrent = po->tick;
tm_start(po->disp_timer, 1);
......@@ -767,6 +777,14 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
}
/* ECMP weight */
if (oldip->ecmp_weight != newip->ecmp_weight)
{
ifa->ecmp_weight = newip->ecmp_weight;
OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
ifa->iface->name, (int)oldip->ecmp_weight + 1, (int)newip->ecmp_weight + 1);
}
/* strict nbma */
if ((oldip->strictnbma == 0) && (newip->strictnbma != 0))
{
......
......@@ -74,6 +74,7 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#define DEFAULT_OSPFTICK 1
#define DEFAULT_RFC1583 0 /* compatibility with rfc1583 */
#define DEFAULT_STUB_COST 1000
#define DEFAULT_ECMP_LIMIT 16
struct ospf_config
......@@ -81,6 +82,7 @@ struct ospf_config
struct proto_config c;
unsigned tick;
int rfc1583;
int ecmp;
list area_list;
};
......@@ -247,6 +249,7 @@ struct ospf_iface
u8 sk_dr; /* Socket is a member of DRouters group */
u16 rxbuf; /* Buffer size */
u8 check_link; /* Whether iface link change is used */
u8 ecmp_weight; /* Weight used for ECMP */
};
struct ospf_md5
......@@ -730,11 +733,13 @@ struct proto_ospf
list area_list;
int areano; /* Number of area I belong to */
struct fib rtf; /* Routing table */
int rfc1583; /* RFC1583 compatibility */
int ebit; /* Did I originate any ext lsa? */
byte rfc1583; /* RFC1583 compatibility */
byte ebit; /* Did I originate any ext lsa? */
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
struct ospf_area *backbone; /* If exists */
void *lsab; /* LSA buffer used when originating router LSAs */
int lsab_size, lsab_used;
linpool *nhpool; /* Linpool used for next hops computed in SPF */
u32 router_id;
};
......@@ -756,6 +761,7 @@ struct ospf_iface_patt
u32 vid;
u16 rxbuf;
u8 check_link;
u8 ecmp_weight;
#define OSPF_RXBUF_NORMAL 0
#define OSPF_RXBUF_LARGE 1
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
......
This diff is collapsed.
......@@ -40,21 +40,32 @@ typedef struct orta
u32 tag;
u32 rid; /* Router ID of real advertising router */
struct ospf_area *oa;
struct ospf_iface *ifa; /* Outgoing interface */
ip_addr nh; /* Next hop */
struct ospf_area *voa; /* Used when route is replaced in ospf_rt_sum_tr(),
NULL otherwise */
struct mpnh *nhs; /* Next hops computed during SPF */
}
orta;
// struct ospf_iface *ifa; /* Outgoing interface */
// ip_addr nh; /* Next hop */
typedef struct ort
{
/*
* We use fn.x0 to mark persistent rt entries, that are needed for summary
* LSAs that don't have 'proper' rt entry (area networks + default to stubs)
* to keep uid stable (used for LSA ID in OSPFv3 - see fibnode_to_lsaid()).
*
* old_* values are here to represent the last route update. old_rta
* is cached (we keep reference), mainly for multipath nexthops.
* old_rta == NULL means route wasn not in the last update, in that
* case other old_* values are not valid.
*/
struct fib_node fn;
orta n;
orta o;
u32 old_metric1, old_metric2, old_tag, old_rid;
rta *old_rta;
}
ort;
......@@ -64,18 +75,24 @@ ort;
* - only router, network and AS-external LSAs
* - lsa.age < LSA_MAXAGE
* - dist < LSINFINITY (or 2*LSINFINITY for ext-LSAs)
* - nhi are non-NULL unless the node is oa->rt (calculating router itself)
* - beware, nhi is not valid after SPF calculation
* - nh is IFA_NONE iff the node is a local network
* - nhs is non-NULL unless the node is oa->rt (calculating router itself)
* - beware, nhs is not valid after SPF calculation
*
* Invariants for structs orta nodes of fib tables po->rtf, oa->rtr:
* - nodes may be invalid (fn.type == 0), in that case other invariants don't hold
* - n.metric1 may be at most a small multiple of LSINFINITY,
* therefore sums do not overflow
* - n.oa is always non-NULL
* - n.ifa is always non-NULL with one exception - configured stubnet
nodes (in po->rtf). In that case, n.nh is IFA_NONE.
* - n.nhs is always non-NULL with one exception - configured stubnet
* nodes (in po->rtf).
* - oa->rtr does not contain calculating router itself
*
* There are three types of nexthops in nhs fields:
* - gateway nexthops (non-NULL iface, gw != IPA_NONE)
* - device nexthops (non-NULL iface, gw == IPA_NONE)
* - dummy vlink nexthops (NULL iface, gw == IPA_NONE)
* These three types don't mix, nhs field contains either
* one device, one vlink node, or one/more gateway nodes.
*/
void ospf_rt_spf(struct proto_ospf *po);
......
......@@ -1674,14 +1674,12 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
e = sl_alloc(f->hash_slab);
e->color = OUTSPF;
e->dist = LSINFINITY;
e->nhi = NULL;
e->nh = IPA_NONE;
e->nhs = NULL;
e->lb = IPA_NONE;
e->lsa.id = lsa;
e->lsa.rt = rtr;
e->lsa.type = type;
e->lsa_body = NULL;
e->nhi = NULL;
e->domain = domain;
e->next = *ee;
*ee = e;
......
......@@ -20,9 +20,8 @@ struct top_hash_entry
// struct ospf_area *oa;
void *lsa_body;
bird_clock_t inst_t; /* Time of installation into DB */
ip_addr nh; /* Next hop */
struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
struct ospf_iface *nhi; /* Next hop interface - valid only in ospf_rt_spf()*/
#ifdef OSPFv3
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
#endif
......@@ -32,7 +31,8 @@ struct top_hash_entry
#define OUTSPF 0
#define CANDIDATE 1
#define INSPF 2
u8 padding;
u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
See a note in rt.c:merge_nexthops() */
};
struct top_graph
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment