diff options
| -rw-r--r-- | bgpd/bgp_attr_evpn.c | 8 | ||||
| -rw-r--r-- | bgpd/bgp_evpn.c | 22 | ||||
| -rw-r--r-- | bgpd/bgp_packet.c | 4 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 13 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 37 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 6 | ||||
| -rw-r--r-- | lib/Makefile.am | 3 | ||||
| -rw-r--r-- | lib/bitfield.h | 28 | ||||
| -rw-r--r-- | lib/hash.h | 2 | ||||
| -rw-r--r-- | lib/ipaddr.h | 94 | ||||
| -rw-r--r-- | lib/prefix.c | 83 | ||||
| -rw-r--r-- | lib/prefix.h | 30 | ||||
| -rw-r--r-- | lib/vlan.h | 29 | ||||
| -rw-r--r-- | lib/vxlan.h | 29 | ||||
| -rw-r--r-- | zebra/if_netlink.c | 32 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 38 | ||||
| -rw-r--r-- | zebra/kernel_netlink.h | 4 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 23 |
18 files changed, 394 insertions, 91 deletions
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index e565d0801b..6970d5a679 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -125,13 +125,13 @@ bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst) p_evpn_p->eth_tag = eth_tag; p_evpn_p->ip_prefix_length = p2.prefixlen; if (src->family == AF_INET) { - p_evpn_p->flags = IP_PREFIX_V4; - memcpy(&p_evpn_p->ip.v4_addr, &src->u.prefix4, + SET_IPADDR_V4 (&p_evpn_p->ip); + memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4, sizeof(struct in_addr)); dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; } else { - p_evpn_p->flags = IP_PREFIX_V6; - memcpy(&p_evpn_p->ip.v6_addr, &src->u.prefix6, + SET_IPADDR_V6 (&p_evpn_p->ip); + memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6, sizeof(struct in6_addr)); dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6; } diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index d516f1718b..34a3315c0c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -125,20 +125,20 @@ bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, /* determine IPv4 or IPv6 prefix */ if (route_length - 4 - 10 - 8 - 3 /* label to be read */ >= 32) { - p_evpn_p->flags = IP_PREFIX_V6; - memcpy(&(p_evpn_p->ip.v6_addr), pnt, 16); + SET_IPADDR_V6 (&p_evpn_p->ip); + memcpy(&(p_evpn_p->ip.ipaddr_v6), pnt, 16); pnt += 16; memcpy(&evpn.gw_ip.ipv6, pnt, 16); pnt += 16; } else { - p_evpn_p->flags = IP_PREFIX_V4; - memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4); + SET_IPADDR_V4 (&p_evpn_p->ip); + memcpy(&(p_evpn_p->ip.ipaddr_v4), pnt, 4); pnt += 4; memcpy(&evpn.gw_ip.ipv4, pnt, 4); pnt += 4; } p.family = AFI_L2VPN; - if (p_evpn_p->flags == IP_PREFIX_V4) + if (IS_IPADDR_V4(&p_evpn_p->ip)) p.prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; else @@ -186,7 +186,7 @@ bgp_packet_mpattr_route_type_5(struct stream *s, if (p->family != AF_ETHERNET) return; p_evpn_p = &(p->u.prefix_evpn); - if (p_evpn_p->flags & IP_PREFIX_V4) + if (IS_IPADDR_V4(&p_evpn_p->ip)) len = 8; /* ipv4 */ else len = 32; /* ipv6 */ @@ -201,12 +201,12 @@ bgp_packet_mpattr_route_type_5(struct stream *s, stream_put(s, &temp, 10); stream_putl(s, p_evpn_p->eth_tag); stream_putc(s, p_evpn_p->ip_prefix_length); - if (p_evpn_p->flags & IP_PREFIX_V4) - stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr); + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); else - stream_put(s, &p_evpn_p->ip.v6_addr, 16); + stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); if (attr && attr->extra) { - if (p_evpn_p->flags & IP_PREFIX_V4) + if (IS_IPADDR_V4(&p_evpn_p->ip)) stream_put_ipv4(s, attr->extra->evpn_overlay.gw_ip.ipv4. s_addr); @@ -214,7 +214,7 @@ bgp_packet_mpattr_route_type_5(struct stream *s, stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), 16); } else { - if (p_evpn_p->flags & IP_PREFIX_V4) + if (IS_IPADDR_V4(&p_evpn_p->ip)) stream_put_ipv4(s, 0); else stream_put(s, &temp, 16); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 074524b5d3..0c31d6e9f3 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -247,8 +247,7 @@ bgp_write_packet (struct peer *peer) if (!(PAF_SUBGRP(paf))->t_coalesce && peer->afc_nego[afi][safi] && peer->synctime && ! CHECK_FLAG (peer->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND) - && safi != SAFI_EVPN) + PEER_STATUS_EOR_SEND)) { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND); @@ -1159,6 +1158,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]; + peer->afc_nego[AFI_L2VPN][SAFI_EVPN] = peer->afc[AFI_L2VPN][SAFI_EVPN]; } /* When collision is detected and this peer is closed. Retrun diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index abd6d73e76..12ad65883e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4625,8 +4625,10 @@ bgp_static_set_safi (afi_t afi, safi_t safi, struct vty *vty, const char *ip_str vty_outln (vty, "%% Malformed GatewayIp"); return CMD_WARNING; } - if((gw_ip.family == AF_INET && (p.u.prefix_evpn.flags & IP_PREFIX_V6)) - || (gw_ip.family == AF_INET6 && (p.u.prefix_evpn.flags & IP_PREFIX_V4))) + if((gw_ip.family == AF_INET && + IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)&p)) || + (gw_ip.family == AF_INET6 && + IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)&p))) { vty_outln (vty, "%% GatewayIp family differs with IP prefix"); return CMD_WARNING; @@ -6828,11 +6830,11 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, char *str = esi2str(id); vty_out (vty, "%s", str); XFREE (MTYPE_TMP, str); - if (p->u.prefix_evpn.flags & IP_PREFIX_V4) + if (IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)) { vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4)); } - else if (p->u.prefix_evpn.flags & IP_PREFIX_V6) + else if (IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)p)) { vty_out (vty, "/%s", inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6), @@ -7195,7 +7197,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, /* Line2 display Next-hop, Neighbor, Router-id */ /* Display the nexthop */ - if (p->family == AF_INET && + if ((p->family == AF_INET || + p->family == AF_ETHERNET) && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN || diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0026187598..d7ddd5db8a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1477,17 +1477,28 @@ bgp_recalculate_all_bestpaths (struct bgp *bgp) { afi_t afi; safi_t safi; - struct bgp_node *rn; + struct bgp_node *rn, *nrn; for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) + for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) { if (rn->info != NULL) { - bgp_process (bgp, rn, afi, safi); + /* Special handling for 2-level routing tables. */ + if (safi == SAFI_MPLS_VPN || + safi == SAFI_ENCAP || + safi == SAFI_EVPN) + { + for (nrn = bgp_table_top((struct bgp_table *)(rn->info)); + nrn; nrn = bgp_route_next (nrn)) + bgp_process (bgp, nrn, afi, safi); + } + else + bgp_process (bgp, rn, afi, safi); } } } @@ -3304,6 +3315,8 @@ bgp_free (struct bgp *bgp) { afi_t afi; safi_t safi; + struct bgp_table *table; + struct bgp_node *rn; QOBJ_UNREG (bgp); @@ -3319,6 +3332,18 @@ bgp_free (struct bgp *bgp) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + /* Special handling for 2-level routing tables. */ + if (safi == SAFI_MPLS_VPN || + safi == SAFI_ENCAP || + safi == SAFI_EVPN) + { + for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + { + table = (struct bgp_table *) rn->info; + bgp_table_finish(&table); + } + } if (bgp->route[afi][safi]) bgp_table_finish (&bgp->route[afi][safi]); if (bgp->aggregate[afi][safi]) @@ -3632,7 +3657,8 @@ peer_active (struct peer *peer) || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc[AFI_IP6][SAFI_ENCAP]) + || peer->afc[AFI_IP6][SAFI_ENCAP] + || peer->afc[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; } @@ -3650,7 +3676,8 @@ peer_active_nego (struct peer *peer) || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) + || peer->afc_nego[AFI_IP6][SAFI_ENCAP] + || peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index fbf16b676c..5dc25d00a9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1462,7 +1462,8 @@ peer_afi_active_nego (const struct peer *peer, afi_t afi) || peer->afc_nego[afi][SAFI_MULTICAST] || peer->afc_nego[afi][SAFI_LABELED_UNICAST] || peer->afc_nego[afi][SAFI_MPLS_VPN] - || peer->afc_nego[afi][SAFI_ENCAP]) + || peer->afc_nego[afi][SAFI_ENCAP] + || peer->afc_nego[afi][SAFI_EVPN]) return 1; return 0; } @@ -1482,7 +1483,8 @@ peer_group_af_configured (struct peer_group *group) || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc[AFI_IP6][SAFI_ENCAP]) + || peer->afc[AFI_IP6][SAFI_ENCAP] + || peer->afc[AFI_IP6][SAFI_EVPN]) return 1; return 0; } diff --git a/lib/Makefile.am b/lib/Makefile.am index e1b84587da..5847ad4939 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -86,6 +86,9 @@ pkginclude_HEADERS = \ frr_pthread.h \ vrf_int.h \ termtable.h \ + vlan.h \ + vxlan.h \ + ipaddr.h \ # end noinst_HEADERS = \ diff --git a/lib/bitfield.h b/lib/bitfield.h index 4ff9c7fb2e..1e0b54731a 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -78,12 +78,27 @@ typedef unsigned int word_t; bf_set_bit(v, id); \ } while (0) -/** +/* + * allocate and assign 0th bit in the bitfiled. + */ +#define bf_assign_zero_index(v) \ + do { \ + int id = 0; \ + bf_assign_index(v, id); \ + } while (0) + +/* * return an id to bitfield v */ #define bf_release_index(v, id) \ (v).data[bf_index(id)] &= ~(1 << (bf_offset(id))) +/* + * return 0th index back to bitfield + */ +#define bf_release_zero_index(v) \ + bf_release_index(v, 0) + #define bf_index(b) ((b) / WORD_SIZE) #define bf_offset(b) ((b) % WORD_SIZE) @@ -118,4 +133,15 @@ typedef unsigned int word_t; (b) += (w * WORD_SIZE); \ } while (0) +/* + * Free the allocated memory for data + * @v: an instance of bitfield_t struct. + */ +#define bf_free(v) \ + do { \ + if ((v).data) { \ + free((v).data); \ + } \ + } while (0) + #endif diff --git a/lib/hash.h b/lib/hash.h index 9395440acb..01d2b1ddc8 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -84,6 +84,8 @@ struct hash char *name; }; +#define hashcount(X) ((X)->count) + extern struct hash *hash_create (unsigned int (*) (void *), int (*) (const void *, const void *), const char *); diff --git a/lib/ipaddr.h b/lib/ipaddr.h new file mode 100644 index 0000000000..ea98a1b746 --- /dev/null +++ b/lib/ipaddr.h @@ -0,0 +1,94 @@ +/* + * IP address structure (for generic IPv4 or IPv6 address) + * Copyright (C) 2016, 2017 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __IPADDR_H__ +#define __IPADDR_H__ + +#include <zebra.h> + +/* + * Generic IP address - union of IPv4 and IPv6 address. + */ +enum ipaddr_type_t +{ + IPADDR_NONE = 0, + IPADDR_V4 = 1, /* IPv4 */ + IPADDR_V6 = 2, /* IPv6 */ +}; + +struct ipaddr +{ + enum ipaddr_type_t ipa_type; + union + { + u_char addr; + struct in_addr _v4_addr; + struct in6_addr _v6_addr; + } ip; +#define ipaddr_v4 ip._v4_addr +#define ipaddr_v6 ip._v6_addr +}; + +#define IS_IPADDR_NONE(p) ((p)->ipa_type == IPADDR_NONE) +#define IS_IPADDR_V4(p) ((p)->ipa_type == IPADDR_V4) +#define IS_IPADDR_V6(p) ((p)->ipa_type == IPADDR_V6) + +#define SET_IPADDR_V4(p) (p)->ipa_type = IPADDR_V4 +#define SET_IPADDR_V6(p) (p)->ipa_type = IPADDR_V6 + +static inline int +str2ipaddr (const char *str, struct ipaddr *ip) +{ + int ret; + + memset (ip, 0, sizeof (struct ipaddr)); + + ret = inet_pton (AF_INET, str, &ip->ipaddr_v4); + if (ret > 0) /* Valid IPv4 address. */ + { + ip->ipa_type = IPADDR_V4; + return 0; + } + ret = inet_pton (AF_INET6, str, &ip->ipaddr_v6); + if (ret > 0) /* Valid IPv6 address. */ + { + ip->ipa_type = IPADDR_V6; + return 0; + } + + return -1; +} + +static inline char * +ipaddr2str (struct ipaddr *ip, char *buf, int size) +{ + buf[0] = '\0'; + if (ip) + { + if (IS_IPADDR_V4(ip)) + inet_ntop (AF_INET, &ip->ip.addr, buf, size); + else if (IS_IPADDR_V6(ip)) + inet_ntop (AF_INET6, &ip->ip.addr, buf, size); + } + return buf; +} +#endif /* __IPADDR_H__ */ diff --git a/lib/prefix.c b/lib/prefix.c index 4131f37fbd..f89b5a5ee6 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -877,6 +877,66 @@ str2prefix (const char *str, struct prefix *p) return 0; } +static const char * +prefixeth2str (const struct prefix *p, char *str, int size) +{ + u_char family; + char buf[PREFIX2STR_BUFFER]; + char buf2[ETHER_ADDR_STRLEN]; + + if (p->u.prefix_evpn.route_type == 2) + { + if (IS_EVPN_PREFIX_IPADDR_NONE((struct prefix_evpn *)p)) + snprintf (str, size, "[%d]:[%s]/%d", + p->u.prefix_evpn.route_type, + prefix_mac2str (&p->u.prefix_evpn.mac, buf2, sizeof (buf2)), + p->prefixlen); + else + { + family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p) ? \ + AF_INET : AF_INET6; + snprintf (str, size, "[%d]:[%s]:[%s]/%d", + p->u.prefix_evpn.route_type, + prefix_mac2str (&p->u.prefix_evpn.mac, buf2, sizeof (buf2)), + inet_ntop (family, &p->u.prefix_evpn.ip.ip.addr, + buf, PREFIX2STR_BUFFER), + p->prefixlen); + } + } + else if (p->u.prefix_evpn.route_type == 3) + { + family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p) ? \ + AF_INET : AF_INET6; + snprintf (str, size, "[%d]:[%s]/%d", + p->u.prefix_evpn.route_type, + inet_ntop (family, &p->u.prefix_evpn.ip.ip.addr, + buf, PREFIX2STR_BUFFER), + p->prefixlen); + } + else if (p->u.prefix_evpn.route_type == 5) + { + family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p) ? \ + AF_INET : AF_INET6; + snprintf (str, size, "[%d]:[%u][%s]/%d", + p->u.prefix_evpn.route_type, + p->u.prefix_evpn.eth_tag, + inet_ntop (family, &p->u.prefix_evpn.ip.ip.addr, + buf, PREFIX2STR_BUFFER), + p->prefixlen); + } + else + { + sprintf (str, "UNK AF_ETHER prefix"); + snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", + p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1], + p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3], + p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5], + p->prefixlen); + } + + return str; +} + const char * prefix2str (union prefixconstptr pu, char *str, int size) { @@ -893,28 +953,9 @@ prefix2str (union prefixconstptr pu, char *str, int size) break; case AF_ETHERNET: - if (p->u.prefix_evpn.route_type == 5) - { - u_char family; - family = (p->u.prefix_evpn.flags & (IP_ADDR_V4 | IP_PREFIX_V4)) ? - AF_INET : AF_INET6; - snprintf (str, size, "[%d]:[%u][%s]/%d", - p->u.prefix_evpn.route_type, - p->u.prefix_evpn.eth_tag, - inet_ntop (family, &p->u.prefix_evpn.ip.addr, - buf, PREFIX2STR_BUFFER), - p->prefixlen); - } - else - { - sprintf (str, "UNK AF_ETHER prefix"); - snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", - p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1], - p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3], - p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5], - p->prefixlen); - } + prefixeth2str (p, str, size); break; + default: sprintf (str, "UNK prefix"); break; diff --git a/lib/prefix.h b/lib/prefix.h index 24144e80a3..549798e92e 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -32,6 +32,7 @@ # endif #endif #include "sockunion.h" +#include "ipaddr.h" #ifndef ETHER_ADDR_LEN #ifdef ETHERADDRL @@ -62,30 +63,23 @@ struct ethaddr { struct evpn_addr { u_char route_type; - u_char flags; -#define IP_ADDR_NONE 0x0 -#define IP_ADDR_V4 0x1 -#define IP_ADDR_V6 0x2 -#define IP_PREFIX_V4 0x4 -#define IP_PREFIX_V6 0x8 + u_char ip_prefix_length; struct ethaddr mac; uint32_t eth_tag; - u_char ip_prefix_length; + struct ipaddr ip; +#if 0 union { u_char addr; struct in_addr v4_addr; struct in6_addr v6_addr; } ip; +#endif }; -/* EVPN prefix structure. */ -struct prefix_evpn -{ - u_char family; - u_char prefixlen; - struct evpn_addr prefix __attribute__ ((aligned (8))); -}; +#define IS_EVPN_PREFIX_IPADDR_NONE(evp) IS_IPADDR_NONE(&(evp)->prefix.ip) +#define IS_EVPN_PREFIX_IPADDR_V4(evp) IS_IPADDR_V4(&(evp)->prefix.ip) +#define IS_EVPN_PREFIX_IPADDR_V6(evp) IS_IPADDR_V6(&(evp)->prefix.ip) /* * A struct prefix contains an address family, a prefix length, and an @@ -167,6 +161,14 @@ struct prefix_eth struct ethaddr eth_addr __attribute__ ((aligned (8))); /* AF_ETHERNET */ }; +/* EVPN prefix structure. */ +struct prefix_evpn +{ + u_char family; + u_char prefixlen; + struct evpn_addr prefix __attribute__ ((aligned (8))); +}; + /* Prefix for a generic pointer */ struct prefix_ptr { diff --git a/lib/vlan.h b/lib/vlan.h new file mode 100644 index 0000000000..5e735aac1f --- /dev/null +++ b/lib/vlan.h @@ -0,0 +1,29 @@ +/* VLAN (802.1q) common header. + * Copyright (C) 2016, 2017 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __VLAN_H__ +#define __VLAN_H__ + +/* VLAN Identifier */ +typedef u_int16_t vlanid_t; +#define VLANID_MAX 4095 + +#endif /* __VLAN_H__ */ diff --git a/lib/vxlan.h b/lib/vxlan.h new file mode 100644 index 0000000000..75c7b97347 --- /dev/null +++ b/lib/vxlan.h @@ -0,0 +1,29 @@ +/* VxLAN common header. + * Copyright (C) 2016, 2017 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __VXLAN_H__ +#define __VXLAN_H__ + +/* VxLAN Network Identifier - 24-bit (RFC 7348) */ +typedef u_int32_t vni_t; +#define VNI_MAX 16777215 /* (2^24 - 1) */ + +#endif /* __VXLAN_H__ */ diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8c50a95065..5af6c3a08f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -437,6 +437,32 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, return 0; } +/* Request for specific interface or address information from the kernel */ +static int +netlink_request_intf_addr (struct zebra_ns *zns, + int family, int type, + u_int32_t filter_mask) +{ + struct + { + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[256]; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset (&req, 0, sizeof (req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.ifm.ifi_family = family; + + /* Include filter, if specified. */ + if (filter_mask) + addattr32 (&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask); + + return netlink_request (&zns->netlink_cmd, &req.n); +} + /* Interface lookup by netlink socket. */ int interface_lookup_netlink (struct zebra_ns *zns) @@ -444,7 +470,7 @@ interface_lookup_netlink (struct zebra_ns *zns) int ret; /* Get interface information. */ - ret = netlink_request (AF_PACKET, RTM_GETLINK, &zns->netlink_cmd); + ret = netlink_request_intf_addr (zns, AF_PACKET, RTM_GETLINK, 0); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 1); @@ -452,7 +478,7 @@ interface_lookup_netlink (struct zebra_ns *zns) return ret; /* Get IPv4 address of the interfaces. */ - ret = netlink_request (AF_INET, RTM_GETADDR, &zns->netlink_cmd); + ret = netlink_request_intf_addr (zns, AF_INET, RTM_GETADDR, 0); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1); @@ -460,7 +486,7 @@ interface_lookup_netlink (struct zebra_ns *zns) return ret; /* Get IPv6 address of the interfaces. */ - ret = netlink_request (AF_INET6, RTM_GETADDR, &zns->netlink_cmd); + ret = netlink_request_intf_addr (zns, AF_INET6, RTM_GETADDR, 0); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index be9376b07f..3570676a4a 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -385,6 +385,12 @@ rta_addattr_l (struct rtattr *rta, unsigned int maxlen, int type, } int +addattr16 (struct nlmsghdr *n, unsigned int maxlen, int type, u_int16_t data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(u_int16_t)); +} + +int addattr32 (struct nlmsghdr *n, unsigned int maxlen, int type, int data) { return addattr_l(n, maxlen, type, &data, sizeof(u_int32_t)); @@ -683,6 +689,7 @@ netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, snl.nl_family = AF_NETLINK; n->nlmsg_seq = ++nl->seq; + n->nlmsg_pid = nl->snl.nl_pid; /* Request an acknowledgement by setting NLM_F_ACK */ n->nlmsg_flags |= NLM_F_ACK; @@ -721,20 +728,16 @@ netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, return netlink_parse_info (filter, nl, zns, 0, startup); } -/* Get type specified information from netlink. */ +/* Issue request message to kernel via netlink socket. GET messages + * are issued through this interface. + */ int -netlink_request (int family, int type, struct nlsock *nl) +netlink_request (struct nlsock *nl, struct nlmsghdr *n) { int ret; struct sockaddr_nl snl; int save_errno; - struct - { - struct nlmsghdr nlh; - struct rtgenmsg g; - } req; - /* Check netlink socket. */ if (nl->sock < 0) { @@ -742,27 +745,22 @@ netlink_request (int family, int type, struct nlsock *nl) return -1; } + /* Fill common fields for all requests. */ + n->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + n->nlmsg_pid = nl->snl.nl_pid; + n->nlmsg_seq = ++nl->seq; + memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; - memset (&req, 0, sizeof req); - req.nlh.nlmsg_len = sizeof req; - req.nlh.nlmsg_type = type; - req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - req.nlh.nlmsg_pid = nl->snl.nl_pid; - req.nlh.nlmsg_seq = ++nl->seq; - req.g.rtgen_family = family; - - /* linux appears to check capabilities on every message - * have to raise caps for every message sent - */ + /* Raise capabilities and send message, then lower capabilities. */ if (zserv_privs.change (ZPRIVS_RAISE)) { zlog_err("Can't raise privileges"); return -1; } - ret = sendto (nl->sock, (void *) &req, sizeof req, 0, + ret = sendto (nl->sock, (void *)n, n->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof snl); save_errno = errno; diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 36ab5c3254..d642423232 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -31,6 +31,8 @@ extern int addattr_l (struct nlmsghdr *n, unsigned int maxlen, int type, void *data, unsigned int alen); extern int rta_addattr_l (struct rtattr *rta, unsigned int maxlen, int type, void *data, unsigned int alen); +extern int addattr16 (struct nlmsghdr *n, unsigned int maxlen, + int type, u_int16_t data); extern int addattr32 (struct nlmsghdr *n, unsigned int maxlen, int type, int data); extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); @@ -52,7 +54,7 @@ extern int netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, ns_id_t, int startup), struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, int startup); -extern int netlink_request (int family, int type, struct nlsock *nl); +extern int netlink_request (struct nlsock *nl, struct nlmsghdr *n); #endif /* HAVE_NETLINK */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 0adbe2c27f..471f650588 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -600,6 +600,25 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, return 0; } +/* Request for specific route information from the kernel */ +static int +netlink_request_route (struct zebra_ns *zns, int family, int type) +{ + struct + { + struct nlmsghdr n; + struct rtmsg rtm; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset (&req, 0, sizeof (req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.rtm.rtm_family = family; + + return netlink_request (&zns->netlink_cmd, &req.n); +} + /* Routing table read function using netlink interface. Only called bootstrap time. */ int @@ -608,7 +627,7 @@ netlink_route_read (struct zebra_ns *zns) int ret; /* Get IPv4 routing table. */ - ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd); + ret = netlink_request_route (zns, AF_INET, RTM_GETROUTE); if (ret < 0) return ret; ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1); @@ -616,7 +635,7 @@ netlink_route_read (struct zebra_ns *zns) return ret; /* Get IPv6 routing table. */ - ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd); + ret = netlink_request_route (zns, AF_INET6, RTM_GETROUTE); if (ret < 0) return ret; ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1); |
