Revision 56a2bed4 proto/bgp/attrs.c

View differences:

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);

Also available in: Unified diff