Revision 56a2bed4

View differences:

nest/attrs.h
33 33
int int_set_contains(struct adata *list, u32 val);
34 34
struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
35 35

  
36

  
37 36
#endif
proto/bgp/attrs.c
29 29
  int expected_length;
30 30
  int expected_flags;
31 31
  int type;
32
  int allow_in_ebgp;
32 33
  int (*validate)(struct bgp_proto *p, byte *attr, int len);
33 34
  void (*format)(eattr *ea, byte *buf);
34 35
};
......
78 79
    return 8;
79 80
}
80 81

  
81
static int
82
bgp_check_local_pref(struct bgp_proto *p, byte *a, int len)
83
{
84
  if (!p->is_internal)			/* Ignore local preference from EBGP connections */
85
    return -1;
86
  return 0;
87
}
88

  
89 82
static struct attr_desc bgp_attr_table[] = {
90
  { NULL, -1, 0, 0,						/* Undefined */
83
  { NULL, -1, 0, 0, 0,						/* Undefined */
91 84
    NULL, NULL },
92
  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT,			/* BA_ORIGIN */
85
  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1,		/* BA_ORIGIN */
93 86
    bgp_check_origin, bgp_format_origin },
94
  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH,		/* BA_AS_PATH */
87
  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1,		/* BA_AS_PATH */
95 88
    bgp_check_path, NULL },
96
  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS,		/* BA_NEXT_HOP */
89
  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1,	/* BA_NEXT_HOP */
97 90
    bgp_check_next_hop, NULL },
98
  { "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT,			/* BA_MULTI_EXIT_DISC */
91
  { "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,			/* BA_MULTI_EXIT_DISC */
99 92
    NULL, NULL },
100
  { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT,		/* BA_LOCAL_PREF */
101
    bgp_check_local_pref, NULL },
102
  { "atomic_aggr", 0, BAF_OPTIONAL, EAF_TYPE_OPAQUE,		/* BA_ATOMIC_AGGR */
93
  { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,		/* BA_LOCAL_PREF */
103 94
    NULL, NULL },
104
  { "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE,		/* BA_AGGREGATOR */
95
  { "atomic_aggr", 0, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,		/* BA_ATOMIC_AGGR */
105 96
    NULL, NULL },
106
  { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET,	/* BA_COMMUNITY */
97
  { "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,		/* BA_AGGREGATOR */
98
    NULL, NULL },
99
  { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1,  /* BA_COMMUNITY */
107 100
    NULL, NULL },
108 101
#if 0
109 102
  { 0, 0 },									/* BA_ORIGINATOR_ID */
......
308 301
bgp_get_bucket(struct bgp_proto *p, ea_list *old, ea_list *tmp, int originate)
309 302
{
310 303
  ea_list *t, *new;
311
  unsigned i, cnt;
304
  unsigned i, cnt, hash, code;
312 305
  eattr *a, *d;
313 306
  u32 seen = 0;
314
  unsigned hash;
315 307
  struct bgp_bucket *b;
316 308

  
317 309
  /* Merge the attribute lists */
......
339 331
#endif
340 332
      if (EA_PROTO(a->id) != EAP_BGP)
341 333
	continue;
342
      if (EA_ID(a->id) < 32)
343
	seen |= 1 << EA_ID(a->id);
334
      code = EA_ID(a->id);
335
      if (code < ARRAY_SIZE(bgp_attr_table))
336
	{
337
	  if (!bgp_attr_table[code].allow_in_ebgp && !p->is_internal)
338
	    continue;
339
	}
340
      if (code < 32)
341
	seen |= 1 << code;
344 342
      *d = *a;
345 343
      if ((d->type & EAF_ORIGINATED) && !originate && (d->flags & BAF_TRANSITIVE) && (d->flags & BAF_OPTIONAL))
346 344
	d->flags |= BAF_PARTIAL;
......
562 560
{
563 561
  struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->proto;
564 562
  struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->proto;
565
  eattr *new_lpref = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
566
  eattr *old_lpref = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
563
  eattr *x, *y;
564
  u32 n, o;
567 565

  
568 566
  /* Start with local preferences */
569
  if (new_lpref && old_lpref)		/* Somebody might have undefined them */
567
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
568
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
569
  n = x ? x->u.data : new_bgp->cf->default_local_pref;
570
  o = y ? y->u.data : old_bgp->cf->default_local_pref;
571
  if (n > o)
572
    return 1;
573
  if (n < o)
574
    return 0;
575

  
576
  /* Use AS path lengths */
577
  if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths)
570 578
    {
571
      if (new_lpref->u.data > old_lpref->u.data)
579
      x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
580
      y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
581
      n = x ? as_path_getlen(x->u.ptr) : 100000;
582
      o = y ? as_path_getlen(y->u.ptr) : 100000;
583
      if (n < o)
572 584
	return 1;
573
      if (new_lpref->u.data < old_lpref->u.data)
585
      if (n > o)
574 586
	return 0;
575 587
    }
576 588

  
589
  /* Use origins */
590
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
591
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
592
  n = x ? x->u.data : 2;
593
  o = y ? y->u.data : 2;
594
  if (n < o)
595
    return 1;
596
  if (n > o)
597
    return 0;
598

  
599
  /* Compare MED's */
600
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
601
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
602
  n = x ? x->u.data : new_bgp->cf->default_med;
603
  o = y ? y->u.data : old_bgp->cf->default_med;
604
  if (n < o)
605
    return 1;
606
  if (n > o)
607
    return 0;
608

  
577 609
  /* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
578
  /* FIXME: Look at MULTI_EXIT_DISC, take the lowest */
579 610
  /* We don't have interior distances */
580 611
  /* We prefer external peers */
581 612
  if (new_bgp->is_internal > old_bgp->is_internal)
......
587 618
}
588 619

  
589 620
static int
590
bgp_local_pref(struct bgp_proto *p, rta *a)
591
{
592
  return 0;				/* FIXME (should be compatible with Cisco defaults?) */
593
}
594

  
595
static int
596 621
bgp_path_loopy(struct bgp_proto *p, eattr *a)
597 622
{
598 623
  byte *path = a->u.ptr->data;
......
680 705
	    { errcode = 5; goto err; }
681 706
	  if ((desc->expected_flags ^ flags) & (BAF_OPTIONAL | BAF_TRANSITIVE))
682 707
	    { errcode = 4; goto err; }
708
	  if (!desc->allow_in_ebgp && !bgp->is_internal)
709
	    continue;
683 710
	  if (desc->validate)
684 711
	    {
685 712
	      errcode = desc->validate(bgp, z, l);
......
747 774
	}
748 775
    }
749 776

  
750
  /* Assign local preference if none defined */
751
  if (!(seen[BA_LOCAL_PREF/8] & (1 << (BA_LOCAL_PREF%8))))
752
    {
753
      ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
754
      ea->next = a->eattrs;
755
      a->eattrs = ea;
756
      ea->flags = 0;
757
      ea->count = 1;
758
      ea->attrs[0].id = EA_CODE(EAP_BGP, BA_LOCAL_PREF);
759
      ea->attrs[0].flags = BAF_OPTIONAL;
760
      ea->attrs[0].type = EAF_TYPE_INT;
761
      ea->attrs[0].u.data = bgp_local_pref(bgp, a);
762
    }
763

  
764 777
  /* If the AS path attribute contains our AS, reject the routes */
765 778
  e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
766 779
  ASSERT(e);
proto/bgp/bgp.h
21 21
  int multihop;				/* Number of hops if multihop */
22 22
  ip_addr multihop_via;			/* Multihop: address to route to */
23 23
  int next_hop_self;			/* Always set next hop to local IP address */
24
  int compare_path_lengths;		/* Use path lengths when selecting best route */
25
  u32 default_local_pref;		/* Default value for LOCAL_PREF attribute */
26
  u32 default_med;			/* Default value for MULTI_EXIT_DISC attribute */
24 27
  unsigned connect_retry_time;
25 28
  unsigned hold_time, initial_hold_time;
26 29
  unsigned keepalive_time;
proto/bgp/config.Y
15 15
CF_DECLS
16 16

  
17 17
CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
18
	MULTIHOP, STARTUP, VIA, NEXT, HOP, SELF, BGP_PATH)
18
	MULTIHOP, STARTUP, VIA, NEXT, HOP, SELF, DEFAULT, PATH, METRIC,
19
	BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP,
20
	BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY)
19 21

  
20 22
CF_GRAMMAR
21 23

  
......
27 29
     BGP_CFG->hold_time = 240;
28 30
     BGP_CFG->connect_retry_time = 120;
29 31
     BGP_CFG->initial_hold_time = 240;
32
     BGP_CFG->default_med = ~0;
33
     BGP_CFG->compare_path_lengths = 1;
30 34
  }
31 35
 ;
32 36

  
......
48 52
 | bgp_proto KEEPALIVE TIME NUM ';' { BGP_CFG->connect_retry_time = $4; }
49 53
 | bgp_proto MULTIHOP NUM VIA IPA ';' { BGP_CFG->multihop = $3; BGP_CFG->multihop_via = $5; }
50 54
 | bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; }
55
 | bgp_proto PATH METRIC NUM ';' { BGP_CFG->compare_path_lengths = $4; }
56
 | bgp_proto DEFAULT BGP_MED NUM ';' { BGP_CFG->default_med = $4; }
57
 | bgp_proto DEFAULT BGP_LOCAL_PREF NUM ';' { BGP_CFG->default_local_pref = $4; }
51 58
 ;
52 59

  
53
CF_ADDTO(dynamic_attr, BGP_PATH { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(EAP_BGP, BA_AS_PATH)); })
60
CF_ADDTO(dynamic_attr, BGP_PATH
61
	{ $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(EAP_BGP, BA_AS_PATH)); })
62
CF_ADDTO(dynamic_attr, BGP_LOCAL_PREF
63
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); })
64
CF_ADDTO(dynamic_attr, BGP_MED
65
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); })
66
CF_ADDTO(dynamic_attr, BGP_ORIGIN
67
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_ORIGIN)); })
68
CF_ADDTO(dynamic_attr, BGP_NEXT_HOP
69
	{ $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(EAP_BGP, BA_NEXT_HOP)); })
70
CF_ADDTO(dynamic_attr, BGP_ATOMIC_AGGR
71
	{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(EAP_BGP, BA_ATOMIC_AGGR)); })
72
CF_ADDTO(dynamic_attr, BGP_AGGREGATOR
73
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_AGGREGATOR)); })
74
CF_ADDTO(dynamic_attr, BGP_COMMUNITY
75
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_COMMUNITY)); })
54 76

  
55 77
CF_CODE
56 78

  

Also available in: Unified diff