- struct hostent *h;
- int ibgp;
- int i;
- struct bgp_path_attr a;
- char path_attrs[64];
- char *p = path_attrs;
- in_addr_t ip;
- u32 metric = htonl(BGP_METRIC);
- u32 no_export = htonl(BGP_COMMUNITY_NO_EXPORT);
-
- if (!our_as)
- return 0;
-
- if (peer->state != Disabled)
- bgp_halt(peer);
-
- snprintf(peer->name, sizeof(peer->name), "%s", name);
-
- if (!(h = gethostbyname(name)) || h->h_addrtype != AF_INET)
- {
- log(0, 0, 0, 0, "Can't get address for BGP peer %s (%s)\n", name, h ? "no address" : hstrerror(h_errno));
-
- return 0;
- }
-
- memcpy(&peer->addr, h->h_addr, sizeof(peer->addr));
- peer->as = as > 0 ? as : our_as;
- ibgp = peer->as == our_as;
-
- /* clear buffers, go to Idle state */
- peer->next_state = Idle;
- bgp_clear(peer);
-
- /* set initial routing state */
- peer->routing = enable;
-
- /* all our routes use the same attributes, so prepare it in advance */
- if (peer->path_attrs)
- free(peer->path_attrs);
-
- peer->path_attr_len = 0;
-
- /* ORIGIN */
+ struct hostent *h;
+ int ibgp;
+ int i;
+ struct bgp_path_attr a;
+ char path_attrs[64];
+ char *p = path_attrs;
+ in_addr_t ip;
+ uint32_t metric = htonl(BGP_METRIC);
+ uint32_t no_export = htonl(BGP_COMMUNITY_NO_EXPORT);
+
+ if (!our_as)
+ return 0;
+
+ if (peer->state != Disabled)
+ bgp_halt(peer);
+
+ snprintf(peer->name, sizeof(peer->name), "%s", name);
+
+ if (!(h = gethostbyname(name)) || h->h_addrtype != AF_INET)
+ {
+ LOG(0, 0, 0, "Can't get address for BGP peer %s (%s)\n",
+ name, h ? "no address" : hstrerror(h_errno));
+
+ return 0;
+ }
+
+ memcpy(&peer->addr, h->h_addr, sizeof(peer->addr));
+ peer->as = as > 0 ? as : our_as;
+ ibgp = peer->as == our_as;
+
+ /* set initial timer values */
+ peer->init_keepalive = keepalive == -1 ? BGP_KEEPALIVE_TIME : keepalive;
+ peer->init_hold = hold == -1 ? BGP_HOLD_TIME : hold;
+
+ if (peer->init_hold < 3)
+ peer->init_hold = 3;
+
+ if (peer->init_keepalive * 3 > peer->init_hold)
+ peer->init_keepalive = peer->init_hold / 3;
+
+ /* clear buffers, go to Idle state */
+ peer->next_state = Idle;
+ bgp_clear(peer);
+
+ /* set initial routing state */
+ peer->routing = enable;
+
+ /* all our routes use the same attributes, so prepare it in advance */
+ if (peer->path_attrs)
+ free(peer->path_attrs);
+
+ peer->path_attr_len = 0;
+
+ /* ORIGIN */
+ a.flags = BGP_PATH_ATTR_FLAG_TRANS;
+ a.code = BGP_PATH_ATTR_CODE_ORIGIN;
+ a.data.s.len = 1;
+ a.data.s.value[0] = BGP_PATH_ATTR_CODE_ORIGIN_IGP;
+
+#define ADD_ATTRIBUTE() do { \
+ i = BGP_PATH_ATTR_SIZE(a); \
+ memcpy(p, &a, i); \
+ p += i; \
+ peer->path_attr_len += i; } while (0)
+
+ ADD_ATTRIBUTE();
+
+ /* AS_PATH */
+ a.flags = BGP_PATH_ATTR_FLAG_TRANS;
+ a.code = BGP_PATH_ATTR_CODE_AS_PATH;
+ if (ibgp)
+ {
+ /* empty path */
+ a.data.s.len = 0;
+ }
+ else
+ {
+ /* just our AS */
+ struct {
+ uint8_t type;
+ uint8_t len;
+ uint16_t value;
+ } as_path = {
+ BGP_PATH_ATTR_CODE_AS_PATH_AS_SEQUENCE,
+ 1,
+ htons(our_as),
+ };
+
+ a.data.s.len = sizeof(as_path);
+ memcpy(&a.data.s.value, &as_path, sizeof(as_path));
+ }
+
+ ADD_ATTRIBUTE();
+
+ /* NEXT_HOP */
+ a.flags = BGP_PATH_ATTR_FLAG_TRANS;
+ a.code = BGP_PATH_ATTR_CODE_NEXT_HOP;
+ ip = my_address; /* we're it */
+ a.data.s.len = sizeof(ip);
+ memcpy(a.data.s.value, &ip, sizeof(ip));
+
+ ADD_ATTRIBUTE();
+
+ /* MULTI_EXIT_DISC */
+ a.flags = BGP_PATH_ATTR_FLAG_OPTIONAL;
+ a.code = BGP_PATH_ATTR_CODE_MULTI_EXIT_DISC;
+ a.data.s.len = sizeof(metric);
+ memcpy(a.data.s.value, &metric, sizeof(metric));
+
+ ADD_ATTRIBUTE();
+
+ if (ibgp)
+ {
+ uint32_t local_pref = htonl(BGP_LOCAL_PREF);
+
+ /* LOCAL_PREF */