summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2016-09-21 22:11:53 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2016-09-21 22:11:53 +0000
commit844ec28cee41395cdd1cc0cdf8cf0168f9dc1adf (patch)
treef2fe0a9a71bb075a5f6f43cd992b89f46b95574f /lib
parentd0bfb22c223d645e554290ca82581eb06f94ac3b (diff)
parent039dc61292de5f3ed5f46316b1940ab6bb184c3f (diff)
Merge branch 'cmaster-next' into vtysh-grammar
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com> Conflicts: lib/.gitignore lib/command.c lib/command.h
Diffstat (limited to 'lib')
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/agentx.c106
-rw-r--r--lib/bfd.c4
-rw-r--r--lib/command.c48
-rw-r--r--lib/command.h6
-rw-r--r--lib/filter.h5
-rw-r--r--lib/if.c130
-rw-r--r--lib/if.h163
-rw-r--r--lib/linklist.c87
-rw-r--r--lib/linklist.h5
-rw-r--r--lib/log.c4
-rw-r--r--lib/memory.c14
-rw-r--r--lib/memory.h4
-rw-r--r--lib/memtypes.c7
-rw-r--r--lib/network.c18
-rw-r--r--lib/network.h3
-rw-r--r--lib/nexthop.c33
-rw-r--r--lib/nexthop.h6
-rw-r--r--lib/ns.c734
-rw-r--r--lib/ns.h142
-rw-r--r--lib/plist.c5
-rw-r--r--lib/prefix.c116
-rw-r--r--lib/prefix.h43
-rw-r--r--lib/privs.c7
-rw-r--r--lib/routemap.c4
-rw-r--r--lib/sigevent.c2
-rw-r--r--lib/sockopt.c35
-rw-r--r--lib/sockopt.h11
-rw-r--r--lib/sockunion.c2
-rw-r--r--lib/sockunion.h3
-rw-r--r--lib/str.c42
-rw-r--r--lib/stream.c121
-rw-r--r--lib/stream.h10
-rw-r--r--lib/thread.c141
-rw-r--r--lib/thread.h11
-rw-r--r--lib/vty.h2
-rw-r--r--lib/zclient.c218
-rw-r--r--lib/zclient.h13
-rw-r--r--lib/zebra.h21
40 files changed, 1987 insertions, 344 deletions
diff --git a/lib/.gitignore b/lib/.gitignore
index ca49c1b6a3..8174bda7d8 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -19,3 +19,4 @@ route_types.h
command_lex.c
command_parse.c
command_parse.h
+refix
diff --git a/lib/Makefile.am b/lib/Makefile.am
index b7bb434776..3dfd09e2e6 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -17,7 +17,7 @@ libzebra_la_SOURCES = \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
sigevent.c pqueue.c jhash.c memtypes.c workqueue.c nexthop.c json.c \
- ptm_lib.c csv.c bfd.c vrf.c systemd.c
+ ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c
BUILT_SOURCES = memtypes.h route_types.h gitversion.h command_parse.h
@@ -35,7 +35,7 @@ pkginclude_HEADERS = \
plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
workqueue.h route_types.h libospf.h nexthop.h json.h \
- ptm_lib.h csv.h bfd.h vrf.h systemd.h bitfield.h
+ ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h
noinst_HEADERS = \
plist_int.h
diff --git a/lib/agentx.c b/lib/agentx.c
index bb95903adf..5996b34a0f 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -24,11 +24,110 @@
#if defined HAVE_SNMP && defined SNMP_AGENTX
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/agent/snmp_vars.h>
#include "command.h"
#include "smux.h"
+#include "memory.h"
+#include "linklist.h"
-int agentx_enabled = 0;
+static int agentx_enabled = 0;
+
+static struct thread_master *agentx_tm;
+static struct thread *timeout_thr = NULL;
+static struct list *events = NULL;
+
+static void agentx_events_update(void);
+
+static int
+agentx_timeout(struct thread *t)
+{
+ timeout_thr = NULL;
+
+ snmp_timeout ();
+ run_alarms ();
+ netsnmp_check_outstanding_agent_requests ();
+ agentx_events_update ();
+ return 0;
+}
+
+static int
+agentx_read(struct thread *t)
+{
+ fd_set fds;
+ struct listnode *ln = THREAD_ARG (t);
+ list_delete_node (events, ln);
+
+ FD_ZERO (&fds);
+ FD_SET (THREAD_FD (t), &fds);
+ snmp_read (&fds);
+
+ netsnmp_check_outstanding_agent_requests ();
+ agentx_events_update ();
+ return 0;
+}
+
+static void
+agentx_events_update(void)
+{
+ int maxfd = 0;
+ int block = 1;
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
+ fd_set fds;
+ struct listnode *ln;
+ struct thread *thr;
+ int fd, thr_fd;
+
+ THREAD_OFF (timeout_thr);
+
+ FD_ZERO (&fds);
+ snmp_select_info (&maxfd, &fds, &timeout, &block);
+
+ if (!block)
+ timeout_thr = thread_add_timer_tv (agentx_tm, agentx_timeout, NULL, &timeout);
+
+ ln = listhead (events);
+ thr = ln ? listgetdata (ln) : NULL;
+ thr_fd = thr ? THREAD_FD (thr) : -1;
+
+ /* "two-pointer" / two-list simultaneous iteration
+ * ln/thr/thr_fd point to the next existing event listener to hit while
+ * fd counts to catch up */
+ for (fd = 0; fd < maxfd; fd++)
+ {
+ /* caught up */
+ if (thr_fd == fd)
+ {
+ struct listnode *nextln = listnextnode (ln);
+ if (!FD_ISSET (fd, &fds))
+ {
+ thread_cancel (thr);
+ list_delete_node (events, ln);
+ }
+ ln = nextln;
+ thr = ln ? listgetdata (ln) : NULL;
+ thr_fd = thr ? THREAD_FD (thr) : -1;
+ }
+ /* need listener, but haven't hit one where it would be */
+ else if (FD_ISSET (fd, &fds))
+ {
+ struct listnode *newln;
+ thr = thread_add_read (agentx_tm, agentx_read, NULL, fd);
+ newln = listnode_add_before (events, ln, thr);
+ thr->arg = newln;
+ }
+ }
+
+ /* leftover event listeners at this point have fd > maxfd, delete them */
+ while (ln)
+ {
+ struct listnode *nextln = listnextnode (ln);
+ thread_cancel (listgetdata (ln));
+ list_delete_node (events, ln);
+ ln = nextln;
+ }
+}
/* AgentX node. */
static struct cmd_node agentx_node =
@@ -77,6 +176,8 @@ DEFUN (agentx_enable,
if (!agentx_enabled)
{
init_snmp("quagga");
+ events = list_new();
+ agentx_events_update ();
agentx_enabled = 1;
return CMD_SUCCESS;
}
@@ -99,6 +200,8 @@ DEFUN (no_agentx,
void
smux_init (struct thread_master *tm)
{
+ agentx_tm = tm;
+
netsnmp_enable_subagent ();
snmp_disable_log ();
snmp_enable_calllog ();
@@ -207,6 +310,7 @@ smux_trap (struct variable *vp, size_t vp_len,
send_v2trap (notification_vars);
snmp_free_varbind (notification_vars);
+ agentx_events_update ();
return 1;
}
diff --git a/lib/bfd.c b/lib/bfd.c
index 2116fa5c1f..67a84c95f9 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -504,8 +504,8 @@ bfd_client_sendmsg (struct zclient *zclient, int command)
if (ret < 0)
{
if (bfd_debug)
- zlog_debug ("bfd_client_sendmsg %d: zclient_send_message() failed",
- getpid());
+ zlog_debug ("bfd_client_sendmsg %ld: zclient_send_message() failed",
+ (long) getpid());
return;
}
diff --git a/lib/command.c b/lib/command.c
index f7800aa724..b4ef30a300 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -666,8 +666,12 @@ node_parent ( enum node_type node )
case KEYCHAIN_KEY_NODE:
ret = KEYCHAIN_NODE;
break;
+ case LINK_PARAMS_NODE:
+ ret = INTERFACE_NODE;
+ break;
default:
ret = CONFIG_NODE;
+ break;
}
return ret;
@@ -961,6 +965,7 @@ DEFUN (config_exit,
vty_config_unlock (vty);
break;
case INTERFACE_NODE:
+ case NS_NODE:
case VRF_NODE:
case ZEBRA_NODE:
case BGP_NODE:
@@ -989,6 +994,9 @@ DEFUN (config_exit,
case KEYCHAIN_KEY_NODE:
vty->node = KEYCHAIN_NODE;
break;
+ case LINK_PARAMS_NODE:
+ vty->node = INTERFACE_NODE;
+ break;
default:
break;
}
@@ -1016,6 +1024,7 @@ DEFUN (config_end,
break;
case CONFIG_NODE:
case INTERFACE_NODE:
+ case NS_NODE:
case VRF_NODE:
case ZEBRA_NODE:
case RIP_NODE:
@@ -1038,6 +1047,7 @@ DEFUN (config_end,
case MASC_NODE:
case PIM_NODE:
case VTY_NODE:
+ case LINK_PARAMS_NODE:
vty_config_unlock (vty);
vty->node = ENABLE_NODE;
break;
@@ -1757,6 +1767,10 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
host.logfile = XSTRDUP (MTYPE_HOST, fname);
+#if defined(HAVE_CUMULUS)
+ if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
+ zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED;
+#endif
return CMD_SUCCESS;
}
@@ -1955,11 +1969,25 @@ DEFUN (no_config_log_timestamp_precision,
int
cmd_banner_motd_file (const char *file)
{
- if (host.motdfile)
- XFREE (MTYPE_HOST, host.motdfile);
- host.motdfile = XSTRDUP (MTYPE_HOST, file);
+ int success = CMD_SUCCESS;
+ char p[PATH_MAX];
+ char *rpath;
+ char *in;
- return CMD_SUCCESS;
+ rpath = realpath (file, p);
+ if (!rpath)
+ return CMD_ERR_NO_FILE;
+ in = strstr (rpath, SYSCONFDIR);
+ if (in == rpath)
+ {
+ if (host.motdfile)
+ XFREE (MTYPE_HOST, host.motdfile);
+ host.motdfile = XSTRDUP (MTYPE_HOST, file);
+ }
+ else
+ success = CMD_WARNING;
+
+ return success;
}
DEFUN (banner_motd_file,
@@ -1970,7 +1998,15 @@ DEFUN (banner_motd_file,
"Banner from a file\n"
"Filename\n")
{
- return cmd_banner_motd_file (argv[3]->arg);
+ int cmd = cmd_banner_motd_file (argv[3]->arg);
+
+ if (cmd == CMD_ERR_NO_FILE)
+ vty_out (vty, "%s does not exist", argv[3]->arg);
+ else if (cmd == CMD_WARNING)
+ vty_out (vty, "%s must be in %s",
+ argv[0], SYSCONFDIR);
+
+ return cmd;
}
DEFUN (banner_motd_default,
@@ -2098,7 +2134,6 @@ cmd_init (int terminal)
install_element (RESTRICTED_NODE, &config_enable_cmd);
install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
- install_element (RESTRICTED_NODE, &show_commandtree_cmd);
install_element (RESTRICTED_NODE, &echo_cmd);
}
@@ -2167,7 +2202,6 @@ cmd_init (int terminal)
vrf_install_commands ();
}
- install_element (CONFIG_NODE, &show_commandtree_cmd);
srandom(time(NULL));
}
diff --git a/lib/command.h b/lib/command.h
index 786539034b..5e1b48c68f 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -75,6 +75,7 @@ enum node_type
AAA_NODE, /* AAA node. */
KEYCHAIN_NODE, /* Key-chain node. */
KEYCHAIN_KEY_NODE, /* Key-chain key node. */
+ NS_NODE, /* Logical-Router node. */
VRF_NODE, /* VRF mode node. */
INTERFACE_NODE, /* Interface mode node. */
ZEBRA_NODE, /* zebra connection node. */
@@ -109,6 +110,7 @@ enum node_type
FORWARDING_NODE, /* IP forwarding node. */
PROTOCOL_NODE, /* protocol filtering node */
VTY_NODE, /* Vty node. */
+ LINK_PARAMS_NODE, /* Link-parameters node */
};
/* Node which has some commands and prompt string and configuration
@@ -356,6 +358,10 @@ struct cmd_element
#define AREA_TAG_STR "[area tag]\n"
#define COMMUNITY_AANN_STR "Community number where AA and NN are (0-65535)\n"
#define COMMUNITY_VAL_STR "Community number in AA:NN format (where AA and NN are (0-65535)) or local-AS|no-advertise|no-export|internet or additive\n"
+#define MPLS_TE_STR "MPLS-TE specific commands\n"
+#define LINK_PARAMS_STR "Configure interface link parameters\n"
+#define OSPF_RI_STR "OSPF Router Information specific commands\n"
+#define PCE_STR "PCE Router Information specific commands\n"
#define CONF_BACKUP_EXT ".sav"
diff --git a/lib/filter.h b/lib/filter.h
index 37535cb13b..e6ccd33b3a 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -25,6 +25,11 @@
#include "if.h"
+/* Filter direction. */
+#define FILTER_IN 0
+#define FILTER_OUT 1
+#define FILTER_MAX 2
+
/* Filter type is made by `permit', `deny' and `dynamic'. */
enum filter_type
{
diff --git a/lib/if.c b/lib/if.c
index 8f1461326f..e44882a43e 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -205,6 +205,8 @@ if_delete (struct interface *ifp)
list_free (ifp->connected);
list_free (ifp->nbr_connected);
+ if_link_params_free (ifp);
+
XFREE (MTYPE_IF, ifp);
}
@@ -226,41 +228,41 @@ if_add_hook (int type, int (*func)(struct interface *ifp))
/* Interface existance check by index. */
struct interface *
-if_lookup_by_index_vrf (unsigned int index, vrf_id_t vrf_id)
+if_lookup_by_index_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
{
struct listnode *node;
struct interface *ifp;
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
{
- if (ifp->ifindex == index)
+ if (ifp->ifindex == ifindex)
return ifp;
}
return NULL;
}
struct interface *
-if_lookup_by_index (unsigned int index)
+if_lookup_by_index (ifindex_t ifindex)
{
- return if_lookup_by_index_vrf (index, VRF_DEFAULT);
+ return if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
}
const char *
-ifindex2ifname_vrf (unsigned int index, vrf_id_t vrf_id)
+ifindex2ifname_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
{
struct interface *ifp;
- return ((ifp = if_lookup_by_index_vrf (index, vrf_id)) != NULL) ?
+ return ((ifp = if_lookup_by_index_vrf (ifindex, vrf_id)) != NULL) ?
ifp->name : "unknown";
}
const char *
-ifindex2ifname (unsigned int index)
+ifindex2ifname (ifindex_t ifindex)
{
- return ifindex2ifname_vrf (index, VRF_DEFAULT);
+ return ifindex2ifname_vrf (ifindex, VRF_DEFAULT);
}
-unsigned int
+ifindex_t
ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id)
{
struct interface *ifp;
@@ -269,7 +271,7 @@ ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id)
: IFINDEX_INTERNAL;
}
-unsigned int
+ifindex_t
ifname2ifindex (const char *name)
{
return ifname2ifindex_vrf (name, VRF_DEFAULT);
@@ -1167,7 +1169,7 @@ connected_add_by_prefix (struct interface *ifp, struct prefix *p,
}
#ifndef HAVE_IF_NAMETOINDEX
-unsigned int
+ifindex_t
if_nametoindex (const char *name)
{
struct interface *ifp;
@@ -1179,7 +1181,7 @@ if_nametoindex (const char *name)
#ifndef HAVE_IF_INDEXTONAME
char *
-if_indextoname (unsigned int ifindex, char *name)
+if_indextoname (ifindex_t ifindex, char *name)
{
struct interface *ifp;
@@ -1244,7 +1246,7 @@ ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp)
/* Lookup interface by interface's IP address or interface index. */
static struct interface *
-ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex)
+ifaddr_ipv4_lookup (struct in_addr *addr, ifindex_t ifindex)
{
struct prefix_ipv4 p;
struct route_node *rn;
@@ -1304,3 +1306,105 @@ if_terminate (struct list **intf_list)
list_delete (*intf_list);
*intf_list = NULL;
}
+
+const char *
+if_link_type_str (enum zebra_link_type llt)
+{
+ switch (llt)
+ {
+#define llts(T,S) case (T): return (S)
+ llts(ZEBRA_LLT_UNKNOWN, "Unknown");
+ llts(ZEBRA_LLT_ETHER, "Ethernet");
+ llts(ZEBRA_LLT_EETHER, "Experimental Ethernet");
+ llts(ZEBRA_LLT_AX25, "AX.25 Level 2");
+ llts(ZEBRA_LLT_PRONET, "PROnet token ring");
+ llts(ZEBRA_LLT_IEEE802, "IEEE 802.2 Ethernet/TR/TB");
+ llts(ZEBRA_LLT_ARCNET, "ARCnet");
+ llts(ZEBRA_LLT_APPLETLK, "AppleTalk");
+ llts(ZEBRA_LLT_DLCI, "Frame Relay DLCI");
+ llts(ZEBRA_LLT_ATM, "ATM");
+ llts(ZEBRA_LLT_METRICOM, "Metricom STRIP");
+ llts(ZEBRA_LLT_IEEE1394, "IEEE 1394 IPv4");
+ llts(ZEBRA_LLT_EUI64, "EUI-64");
+ llts(ZEBRA_LLT_INFINIBAND, "InfiniBand");
+ llts(ZEBRA_LLT_SLIP, "SLIP");
+ llts(ZEBRA_LLT_CSLIP, "Compressed SLIP");
+ llts(ZEBRA_LLT_SLIP6, "SLIPv6");
+ llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6");
+ llts(ZEBRA_LLT_ROSE, "ROSE packet radio");
+ llts(ZEBRA_LLT_X25, "CCITT X.25");
+ llts(ZEBRA_LLT_PPP, "PPP");
+ llts(ZEBRA_LLT_CHDLC, "Cisco HDLC");
+ llts(ZEBRA_LLT_RAWHDLC, "Raw HDLC");
+ llts(ZEBRA_LLT_LAPB, "LAPB");
+ llts(ZEBRA_LLT_IPIP, "IPIP Tunnel");
+ llts(ZEBRA_LLT_IPIP6, "IPIP6 Tunnel");
+ llts(ZEBRA_LLT_FRAD, "FRAD");
+ llts(ZEBRA_LLT_SKIP, "SKIP vif");
+ llts(ZEBRA_LLT_LOOPBACK, "Loopback");
+ llts(ZEBRA_LLT_LOCALTLK, "Localtalk");
+ llts(ZEBRA_LLT_FDDI, "FDDI");
+ llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT");
+ llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel");
+ llts(ZEBRA_LLT_IPGRE, "GRE over IP");
+ llts(ZEBRA_LLT_PIMREG, "PIMSM registration");
+ llts(ZEBRA_LLT_HIPPI, "HiPPI");
+ llts(ZEBRA_LLT_IRDA, "IrDA");
+ llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP");
+ llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop");
+ llts(ZEBRA_LLT_FCPL, "Fibre-Channel Public Loop");
+ llts(ZEBRA_LLT_FCFABRIC, "Fibre-Channel Fabric");
+ llts(ZEBRA_LLT_IEEE802_TR, "IEEE 802.2 Token Ring");
+ llts(ZEBRA_LLT_IEEE80211, "IEEE 802.11");
+ llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap");
+ llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4");
+ llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy");
+ default:
+ zlog_warn ("Unknown value %d", llt);
+ return "Unknown type!";
+#undef llts
+ }
+ return NULL;
+}
+
+struct if_link_params *
+if_link_params_get (struct interface *ifp)
+{
+ int i;
+
+ if (ifp->link_params != NULL)
+ return ifp->link_params;
+
+ struct if_link_params *iflp = XCALLOC(MTYPE_IF_LINK_PARAMS,
+ sizeof (struct if_link_params));
+ if (iflp == NULL) return NULL;
+
+ /* Set TE metric == standard metric */
+ iflp->te_metric = ifp->metric;
+
+ /* Compute default bandwidth based on interface */
+ int bw = (float)((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH)
+ * TE_KILO_BIT / TE_BYTE);
+
+ /* Set Max, Reservable and Unreserved Bandwidth */
+ iflp->max_bw = bw;
+ iflp->max_rsv_bw = bw;
+ for (i = 0; i < MAX_CLASS_TYPE; i++)
+ iflp->unrsv_bw[i] = bw;
+
+ /* Update Link parameters status */
+ iflp->lp_status = LP_TE | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW;
+
+ /* Finally attach newly created Link Parameters */
+ ifp->link_params = iflp;
+
+ return iflp;
+}
+
+void
+if_link_params_free (struct interface *ifp)
+{
+ if (ifp->link_params == NULL) return;
+ XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
+ ifp->link_params = NULL;
+}
diff --git a/lib/if.h b/lib/if.h
index 4ec85bc841..17f8565595 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -21,8 +21,69 @@ Boston, MA 02111-1307, USA. */
#ifndef _ZEBRA_IF_H
#define _ZEBRA_IF_H
+#include "zebra.h"
#include "linklist.h"
+/* Interface link-layer type, if known. Derived from:
+ *
+ * net/if_arp.h on various platforms - Linux especially.
+ * http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
+ *
+ * Some of the more obviously defunct technologies left out.
+ */
+enum zebra_link_type {
+ ZEBRA_LLT_UNKNOWN = 0,
+ ZEBRA_LLT_ETHER,
+ ZEBRA_LLT_EETHER,
+ ZEBRA_LLT_AX25,
+ ZEBRA_LLT_PRONET,
+ ZEBRA_LLT_IEEE802,
+ ZEBRA_LLT_ARCNET,
+ ZEBRA_LLT_APPLETLK,
+ ZEBRA_LLT_DLCI,
+ ZEBRA_LLT_ATM,
+ ZEBRA_LLT_METRICOM,
+ ZEBRA_LLT_IEEE1394,
+ ZEBRA_LLT_EUI64,
+ ZEBRA_LLT_INFINIBAND,
+ ZEBRA_LLT_SLIP,
+ ZEBRA_LLT_CSLIP,
+ ZEBRA_LLT_SLIP6,
+ ZEBRA_LLT_CSLIP6,
+ ZEBRA_LLT_RSRVD,
+ ZEBRA_LLT_ADAPT,
+ ZEBRA_LLT_ROSE,
+ ZEBRA_LLT_X25,
+ ZEBRA_LLT_PPP,
+ ZEBRA_LLT_CHDLC,
+ ZEBRA_LLT_LAPB,
+ ZEBRA_LLT_RAWHDLC,
+ ZEBRA_LLT_IPIP,
+ ZEBRA_LLT_IPIP6,
+ ZEBRA_LLT_FRAD,
+ ZEBRA_LLT_SKIP,
+ ZEBRA_LLT_LOOPBACK,
+ ZEBRA_LLT_LOCALTLK,
+ ZEBRA_LLT_FDDI,
+ ZEBRA_LLT_SIT,
+ ZEBRA_LLT_IPDDP,
+ ZEBRA_LLT_IPGRE,
+ ZEBRA_LLT_IP6GRE,
+ ZEBRA_LLT_PIMREG,
+ ZEBRA_LLT_HIPPI,
+ ZEBRA_LLT_ECONET,
+ ZEBRA_LLT_IRDA,
+ ZEBRA_LLT_FCPP,
+ ZEBRA_LLT_FCAL,
+ ZEBRA_LLT_FCPL,
+ ZEBRA_LLT_FCFABRIC,
+ ZEBRA_LLT_IEEE802_TR,
+ ZEBRA_LLT_IEEE80211,
+ ZEBRA_LLT_IEEE80211_RADIOTAP,
+ ZEBRA_LLT_IEEE802154,
+ ZEBRA_LLT_IEEE802154_PHY,
+};
+
/*
Interface name length.
@@ -36,6 +97,8 @@ Boston, MA 02111-1307, USA. */
#define INTERFACE_NAMSIZ 20
#define INTERFACE_HWADDR_MAX 20
+typedef signed int ifindex_t;
+
#ifdef HAVE_PROC_NET_DEV
struct if_stats
{
@@ -68,6 +131,63 @@ struct if_stats
};
#endif /* HAVE_PROC_NET_DEV */
+/* Here are "non-official" architectural constants. */
+#define TE_EXT_MASK 0x0FFFFFFF
+#define TE_EXT_ANORMAL 0x80000000
+#define LOSS_PRECISION 0.000003
+#define TE_KILO_BIT 1000
+#define TE_BYTE 8
+#define DEFAULT_BANDWIDTH 10000
+#define MAX_CLASS_TYPE 8
+#define MAX_PKT_LOSS 50.331642
+
+/* Link Parameters Status: 0: unset, 1: set, */
+#define LP_UNSET 0x0000
+#define LP_TE 0x0001
+#define LP_MAX_BW 0x0002
+#define LP_MAX_RSV_BW 0x0004
+#define LP_UNRSV_BW 0x0008
+#define LP_ADM_GRP 0x0010
+#define LP_RMT_AS 0x0020
+#define LP_DELAY 0x0040
+#define LP_MM_DELAY 0x0080
+#define LP_DELAY_VAR 0x0100
+#define LP_PKT_LOSS 0x0200
+#define LP_RES_BW 0x0400
+#define LP_AVA_BW 0x0800
+#define LP_USE_BW 0x1000
+
+#define IS_PARAM_UNSET(lp, st) !(lp->lp_status & st)
+#define IS_PARAM_SET(lp, st) (lp->lp_status & st)
+#define IS_LINK_PARAMS_SET(lp) (lp->lp_status != LP_UNSET)
+
+#define SET_PARAM(lp, st) (lp->lp_status) |= (st)
+#define UNSET_PARAM(lp, st) (lp->lp_status) &= ~(st)
+#define RESET_LINK_PARAM(lp) (lp->lp_status = LP_UNSET)
+
+/* Link Parameters for Traffic Engineering */
+struct if_link_params {
+ u_int32_t lp_status; /* Status of Link Parameters: */
+ u_int32_t te_metric; /* Traffic Engineering metric */
+ float max_bw; /* Maximum Bandwidth */
+ float max_rsv_bw; /* Maximum Reservable Bandwidth */
+ float unrsv_bw[MAX_CLASS_TYPE]; /* Unreserved Bandwidth per Class Type (8) */
+ u_int32_t admin_grp; /* Administrative group */
+ u_int32_t rmt_as; /* Remote AS number */
+ struct in_addr rmt_ip; /* Remote IP address */
+ u_int32_t av_delay; /* Link Average Delay */
+ u_int32_t min_delay; /* Link Min Delay */
+ u_int32_t max_delay; /* Link Max Delay */
+ u_int32_t delay_var; /* Link Delay Variation */
+ float pkt_loss; /* Link Packet Loss */
+ float res_bw; /* Residual Bandwidth */
+ float ava_bw; /* Available Bandwidth */
+ float use_bw; /* Utilized Bandwidth */
+};
+
+#define INTERFACE_LINK_PARAMS_SIZE sizeof(struct if_link_params)
+#define HAS_LINK_PARAMS(ifp) ((ifp)->link_params != NULL)
+
/* Interface structure */
struct interface
{
@@ -82,9 +202,9 @@ struct interface
/* Interface index (should be IFINDEX_INTERNAL for non-kernel or
deleted interfaces). */
- unsigned int ifindex;
+ ifindex_t ifindex;
#define IFINDEX_INTERNAL 0
-#define IFINDEX_DELETED UINT_MAX
+#define IFINDEX_DELETED INT_MAX
/* Zebra internal interface status */
u_char status;
@@ -103,24 +223,17 @@ struct interface
unsigned int mtu; /* IPv4 MTU */
unsigned int mtu6; /* IPv6 MTU - probably, but not neccessarily same as mtu */
- /* Hardware address. */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
- union {
- /* note that sdl_storage is never accessed, it only exists to make space.
- * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits
- * best with C aliasing rules. */
- struct sockaddr_dl sdl;
- struct sockaddr_storage sdl_storage;
- };
-#else
- unsigned short hw_type;
+ /* Link-layer information and hardware address */
+ enum zebra_link_type ll_type;
u_char hw_addr[INTERFACE_HWADDR_MAX];
int hw_addr_len;
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
/* interface bandwidth, kbits */
unsigned int bandwidth;
+ /* Link parameters for Traffic Engineering */
+ struct if_link_params *link_params;
+
/* description of the interface. */
char *desc;
@@ -264,7 +377,7 @@ struct nbr_connected
/* Prototypes. */
extern int if_cmp_name_func (char *, char *);
extern struct interface *if_create (const char *name, int namelen);
-extern struct interface *if_lookup_by_index (unsigned int);
+extern struct interface *if_lookup_by_index (ifindex_t);
extern struct interface *if_lookup_exact_address (void *matchaddr, int family);
extern struct interface *if_lookup_address (void *matchaddr, int family);
extern struct interface *if_lookup_prefix (struct prefix *prefix);
@@ -273,8 +386,7 @@ extern void if_update_vrf (struct interface *, const char *name, int namelen,
vrf_id_t vrf_id);
extern struct interface *if_create_vrf (const char *name, int namelen,
vrf_id_t vrf_id);
-extern struct interface *if_lookup_by_index_vrf (unsigned int,
- vrf_id_t vrf_id);
+extern struct interface *if_lookup_by_index_vrf (ifindex_t, vrf_id_t vrf_id);
extern struct interface *if_lookup_exact_address_vrf (void *matchaddr, int family,
vrf_id_t vrf_id);
extern struct interface *if_lookup_address_vrf (void *matchaddr, int family,
@@ -328,18 +440,19 @@ extern void if_init (struct list **);
extern void if_terminate (struct list **);
extern void if_dump_all (void);
extern const char *if_flag_dump(unsigned long);
+extern const char *if_link_type_str (enum zebra_link_type);
/* Please use ifindex2ifname instead of if_indextoname where possible;
ifindex2ifname uses internal interface info, whereas if_indextoname must
make a system call. */
-extern const char *ifindex2ifname (unsigned int);
-extern const char *ifindex2ifname_vrf (unsigned int, vrf_id_t vrf_id);
+extern const char *ifindex2ifname (ifindex_t);
+extern const char *ifindex2ifname_vrf (ifindex_t, vrf_id_t vrf_id);
/* Please use ifname2ifindex instead of if_nametoindex where possible;
ifname2ifindex uses internal interface info, whereas if_nametoindex must
make a system call. */
-extern unsigned int ifname2ifindex(const char *ifname);
-extern unsigned int ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id);
+extern ifindex_t ifname2ifindex(const char *ifname);
+extern ifindex_t ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id);
/* Connected address functions. */
extern struct connected *connected_new (void);
@@ -359,12 +472,16 @@ extern void nbr_connected_free (struct nbr_connected *);
struct nbr_connected *nbr_connected_check (struct interface *, struct prefix *);
#ifndef HAVE_IF_NAMETOINDEX
-extern unsigned int if_nametoindex (const char *);
+extern ifindex_t if_nametoindex (const char *);
#endif
#ifndef HAVE_IF_INDEXTONAME
-extern char *if_indextoname (unsigned int, char *);
+extern char *if_indextoname (ifindex_t, char *);
#endif
+/* link parameters */
+struct if_link_params *if_link_params_get (struct interface *);
+void if_link_params_free (struct interface *);
+
/* Exported variables. */
extern struct cmd_element interface_desc_cmd;
extern struct cmd_element no_interface_desc_cmd;
diff --git a/lib/linklist.c b/lib/linklist.c
index 4b16f07dd1..d27a2da848 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -122,7 +122,7 @@ listnode_add_sort (struct list *list, void *val)
list->count++;
}
-void
+struct listnode *
listnode_add_after (struct list *list, struct listnode *pp, void *val)
{
struct listnode *nn;
@@ -157,6 +157,45 @@ listnode_add_after (struct list *list, struct listnode *pp, void *val)
pp->next = nn;
}
list->count++;
+ return nn;
+}
+
+struct listnode *
+listnode_add_before (struct list *list, struct listnode *pp, void *val)
+{
+ struct listnode *nn;
+
+ assert (val != NULL);
+
+ nn = listnode_new ();
+ nn->data = val;
+
+ if (pp == NULL)
+ {
+ if (list->tail)
+ list->tail->next = nn;
+ else
+ list->head = nn;
+
+ nn->prev = list->tail;
+ nn->next = pp;
+
+ list->tail = nn;
+ }
+ else
+ {
+ if (pp->prev)
+ pp->prev->next = nn;
+ else
+ list->head = nn;
+
+ nn->prev = pp->prev;
+ nn->next = pp;
+
+ pp->prev = nn;
+ }
+ list->count++;
+ return nn;
}
/* Move given listnode to tail of the list */
@@ -268,52 +307,6 @@ list_delete_node (struct list *list, struct listnode *node)
/* ospf_spf.c */
void
-list_add_node_prev (struct list *list, struct listnode *current, void *val)
-{
- struct listnode *node;
-
- assert (val != NULL);
-
- node = listnode_new ();
- node->next = current;
- node->data = val;
-
- if (current->prev == NULL)
- list->head = node;
- else
- current->prev->next = node;
-
- node->prev = current->prev;
- current->prev = node;
-
- list->count++;
-}
-
-/* ospf_spf.c */
-void
-list_add_node_next (struct list *list, struct listnode *current, void *val)
-{
- struct listnode *node;
-
- assert (val != NULL);
-
- node = listnode_new ();
- node->prev = current;
- node->data = val;
-
- if (current->next == NULL)
- list->tail = node;
- else
- current->next->prev = node;
-
- node->next = current->next;
- current->next = node;
-
- list->count++;
-}
-
-/* ospf_spf.c */
-void
list_add_list (struct list *l, struct list *m)
{
struct listnode *n;
diff --git a/lib/linklist.h b/lib/linklist.h
index 6209c8b9d6..e99e50f4fa 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -67,7 +67,8 @@ extern void list_free (struct list *);
extern void listnode_add (struct list *, void *);
extern void listnode_add_sort (struct list *, void *);
-extern void listnode_add_after (struct list *, struct listnode *, void *);
+extern struct listnode *listnode_add_after (struct list *, struct listnode *, void *);
+extern struct listnode *listnode_add_before (struct list *, struct listnode *, void *);
extern void listnode_move_to_tail (struct list *, struct listnode *);
extern void listnode_delete (struct list *, void *);
extern struct listnode *listnode_lookup (struct list *, void *);
@@ -80,8 +81,6 @@ extern void list_delete_all_node (struct list *);
extern void list_delete_node (struct list *, struct listnode *);
/* For ospf_spf.c */
-extern void list_add_node_prev (struct list *, struct listnode *, void *);
-extern void list_add_node_next (struct list *, struct listnode *, void *);
extern void list_add_list (struct list *, struct list *);
/* List iteration macro.
diff --git a/lib/log.c b/lib/log.c
index 453a611dcd..ea50ae18cc 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -179,6 +179,7 @@ static void
vzlog (struct zlog *zl, int priority, const char *format, va_list args)
{
char proto_str[32];
+ int original_errno = errno;
struct timestamp_control tsctl;
tsctl.already_rendered = 0;
@@ -197,6 +198,7 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args)
fflush (stderr);
/* In this case we return at here. */
+ errno = original_errno;
return;
}
tsctl.precision = zl->timestamp_precision;
@@ -249,6 +251,8 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args)
if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
vty_log ((zl->record_priority ? zlog_priority[priority] : NULL),
proto_str, format, &tsctl, args);
+
+ errno = original_errno;
}
static char *
diff --git a/lib/memory.c b/lib/memory.c
index 290b999bb8..8d1a03743e 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -80,9 +80,11 @@ zmalloc (int type, size_t size)
/*
* Allocate memory as in zmalloc, and also clear the memory.
+ * Add an extra 'z' prefix to function name to avoid collision when linking
+ * statically with zlib that exports the 'zcalloc' symbol.
*/
void *
-zcalloc (int type, size_t size)
+zzcalloc (int type, size_t size)
{
void *memory;
@@ -97,9 +99,9 @@ zcalloc (int type, size_t size)
}
/*
- * Given a pointer returned by zmalloc or zcalloc, free it and
+ * Given a pointer returned by zmalloc or zzcalloc, free it and
* return a pointer to a new size, basically acting like realloc().
- * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
+ * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the
* same type.
* Effects: Returns a pointer to the new memory, or aborts.
*/
@@ -109,7 +111,7 @@ zrealloc (int type, void *ptr, size_t size)
void *memory;
if (ptr == NULL) /* is really alloc */
- return zcalloc(type, size);
+ return zzcalloc(type, size);
memory = realloc (ptr, size);
if (memory == NULL)
@@ -122,7 +124,7 @@ zrealloc (int type, void *ptr, size_t size)
/*
* Free memory allocated by z*alloc or zstrdup.
- * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
+ * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the
* same type.
* Effects: The memory is freed and may no longer be referenced.
*/
@@ -196,7 +198,7 @@ mtype_zcalloc (const char *file, int line, int type, size_t size)
mstat[type].c_calloc++;
mstat[type].t_calloc++;
- memory = zcalloc (type, size);
+ memory = zzcalloc (type, size);
mtype_log ("xcalloc", memory, file, line, type);
return memory;
diff --git a/lib/memory.h b/lib/memory.h
index 23962235db..501352993d 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -56,7 +56,7 @@ extern struct mlist mlists[];
mtype_zstrdup (__FILE__, __LINE__, (mtype), (str))
#else
#define XMALLOC(mtype, size) zmalloc ((mtype), (size))
-#define XCALLOC(mtype, size) zcalloc ((mtype), (size))
+#define XCALLOC(mtype, size) zzcalloc ((mtype), (size))
#define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size))
#define XFREE(mtype, ptr) do { \
zfree ((mtype), (ptr)); \
@@ -67,7 +67,7 @@ extern struct mlist mlists[];
/* Prototypes of memory function. */
extern void *zmalloc (int type, size_t size);
-extern void *zcalloc (int type, size_t size);
+extern void *zzcalloc (int type, size_t size);
extern void *zrealloc (int type, void *ptr, size_t size);
extern void zfree (int type, void *ptr);
extern char *zstrdup (int type, const char *str);
diff --git a/lib/memtypes.c b/lib/memtypes.c
index d0faecb640..510312f336 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -77,6 +77,10 @@ struct memory_list memory_list_lib[] =
{ MTYPE_VRF, "VRF" },
{ MTYPE_VRF_NAME, "VRF name" },
{ MTYPE_VRF_BITMAP, "VRF bit-map" },
+ { MTYPE_NS, "Logical-Router" },
+ { MTYPE_NS_NAME, "Logical-Router Name" },
+ { MTYPE_NS_BITMAP, "Logical-Router bit-map" },
+ { MTYPE_IF_LINK_PARAMS, "Informational Link Parameters" },
{ -1, NULL },
};
@@ -228,6 +232,8 @@ struct memory_list memory_list_ospf[] =
{ MTYPE_OSPF_IF_INFO, "OSPF if info" },
{ MTYPE_OSPF_IF_PARAMS, "OSPF if params" },
{ MTYPE_OSPF_MESSAGE, "OSPF message" },
+ { MTYPE_OSPF_MPLS_TE, "OSPF MPLS parameters" },
+ { MTYPE_OSPF_PCE_PARAMS, "OSPF PCE parameters" },
{ -1, NULL },
};
@@ -269,6 +275,7 @@ struct memory_list memory_list_isis[] =
{ MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6" },
{ MTYPE_ISIS_DICT, "ISIS dictionary" },
{ MTYPE_ISIS_DICT_NODE, "ISIS dictionary node" },
+ { MTYPE_ISIS_MPLS_TE, "ISIS MPLS_TE parameters" },
{ -1, NULL },
};
diff --git a/lib/network.c b/lib/network.c
index 3373983b3c..5379ecb5a6 100644
--- a/lib/network.c
+++ b/lib/network.c
@@ -93,3 +93,21 @@ set_nonblocking(int fd)
}
return 0;
}
+
+float
+htonf (float host)
+{
+ u_int32_t lu1, lu2;
+ float convert;
+
+ memcpy (&lu1, &host, sizeof (u_int32_t));
+ lu2 = htonl (lu1);
+ memcpy (&convert, &lu2, sizeof (u_int32_t));
+ return convert;
+}
+
+float
+ntohf (float net)
+{
+ return htonf (net);
+}
diff --git a/lib/network.h b/lib/network.h
index 4d9c2284bf..0fcb575d1c 100644
--- a/lib/network.h
+++ b/lib/network.h
@@ -37,4 +37,7 @@ extern int set_nonblocking(int fd);
#define ERRNO_IO_RETRY(EN) \
(((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
+extern float htonf (float);
+extern float ntohf (float);
+
#endif /* _ZEBRA_NETWORK_H */
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 5853884218..14486ea157 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -153,3 +153,36 @@ nexthops_free (struct nexthop *nexthop)
nexthop_free (nh);
}
}
+
+const char *
+nexthop2str (struct nexthop *nexthop, char *str, int size)
+{
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IFINDEX:
+ snprintf (str, size, "if %u", nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ snprintf (str, size, "%s", inet_ntoa (nexthop->gate.ipv4));
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ snprintf (str, size, "%s if %u",
+ inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ snprintf (str, size, "%s", inet6_ntoa (nexthop->gate.ipv6));
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ snprintf (str, size, "%s if %u",
+ inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ snprintf (str, size, "blackhole");
+ break;
+ default:
+ snprintf (str, size, "unknown");
+ break;
+ }
+
+ return str;
+}
diff --git a/lib/nexthop.h b/lib/nexthop.h
index eb9b27ea9e..39e8b5425f 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -26,6 +26,9 @@
#include "prefix.h"
+/* Maximum next hop string length - gateway + ifindex */
+#define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30)
+
union g_addr {
struct in_addr ipv4;
struct in6_addr ipv6;
@@ -48,7 +51,7 @@ struct nexthop
struct nexthop *prev;
/* Interface index. */
- unsigned int ifindex;
+ ifindex_t ifindex;
enum nexthop_types_t type;
@@ -97,4 +100,5 @@ void nexthops_free (struct nexthop *nexthop);
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
+extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size);
#endif /*_LIB_NEXTHOP_H */
diff --git a/lib/ns.c b/lib/ns.c
new file mode 100644
index 0000000000..4765a18ef2
--- /dev/null
+++ b/lib/ns.c
@@ -0,0 +1,734 @@
+/*
+ * NS functions.
+ * Copyright (C) 2014 6WIND S.A.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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.
+ *
+ * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_NETNS
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <sched.h>
+#endif
+
+#include "if.h"
+#include "ns.h"
+#include "prefix.h"
+#include "table.h"
+#include "log.h"
+#include "memory.h"
+
+#include "command.h"
+#include "vty.h"
+
+
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
+#endif
+
+#ifndef HAVE_SETNS
+static inline int setns(int fd, int nstype)
+{
+#ifdef __NR_setns
+ return syscall(__NR_setns, fd, nstype);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif /* HAVE_SETNS */
+
+#ifdef HAVE_NETNS
+
+#define NS_DEFAULT_NAME "/proc/self/ns/net"
+static int have_netns_enabled = -1;
+
+#else /* !HAVE_NETNS */
+
+#define NS_DEFAULT_NAME "Default-logical-router"
+
+#endif /* HAVE_NETNS */
+
+static int have_netns(void)
+{
+#ifdef HAVE_NETNS
+ if (have_netns_enabled < 0)
+ {
+ int fd = open (NS_DEFAULT_NAME, O_RDONLY);
+
+ if (fd < 0)
+ have_netns_enabled = 0;
+ else
+ {
+ have_netns_enabled = 1;
+ close(fd);
+ }
+ }
+ return have_netns_enabled;
+#else
+ return 0;
+#endif
+}
+
+struct ns
+{
+ /* Identifier, same as the vector index */
+ ns_id_t ns_id;
+ /* Name */
+ char *name;
+ /* File descriptor */
+ int fd;
+
+ /* Master list of interfaces belonging to this NS */
+ struct list *iflist;
+
+ /* User data */
+ void *info;
+};
+
+/* Holding NS hooks */
+struct ns_master
+{
+ int (*ns_new_hook) (ns_id_t, void **);
+ int (*ns_delete_hook) (ns_id_t, void **);
+ int (*ns_enable_hook) (ns_id_t, void **);
+ int (*ns_disable_hook) (ns_id_t, void **);
+} ns_master = {0,};
+
+/* NS table */
+struct route_table *ns_table = NULL;
+
+static int ns_is_enabled (struct ns *ns);
+static int ns_enable (struct ns *ns);
+static void ns_disable (struct ns *ns);
+
+
+/* Build the table key */
+static void
+ns_build_key (ns_id_t ns_id, struct prefix *p)
+{
+ p->family = AF_INET;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ p->u.prefix4.s_addr = ns_id;
+}
+
+/* Get a NS. If not found, create one. */
+static struct ns *
+ns_get (ns_id_t ns_id)
+{
+ struct prefix p;
+ struct route_node *rn;
+ struct ns *ns;
+
+ ns_build_key (ns_id, &p);
+ rn = route_node_get (ns_table, &p);
+ if (rn->info)
+ {
+ ns = (struct ns *)rn->info;
+ route_unlock_node (rn); /* get */
+ return ns;
+ }
+
+ ns = XCALLOC (MTYPE_NS, sizeof (struct ns));
+ ns->ns_id = ns_id;
+ ns->fd = -1;
+ rn->info = ns;
+
+ /*
+ * Initialize interfaces.
+ *
+ * I'm not sure if this belongs here or in
+ * the vrf code.
+ */
+ // if_init (&ns->iflist);
+
+ zlog_info ("NS %u is created.", ns_id);
+
+ if (ns_master.ns_new_hook)
+ (*ns_master.ns_new_hook) (ns_id, &ns->info);
+
+ return ns;
+}
+
+/* Delete a NS. This is called in ns_terminate(). */
+static void
+ns_delete (struct ns *ns)
+{
+ zlog_info ("NS %u is to be deleted.", ns->ns_id);
+
+ ns_disable (ns);
+
+ if (ns_master.ns_delete_hook)
+ (*ns_master.ns_delete_hook) (ns->ns_id, &ns->info);
+
+ /*
+ * I'm not entirely sure if the vrf->iflist
+ * needs to be moved into here or not.
+ */
+ //if_terminate (&ns->iflist);
+
+ if (ns->name)
+ XFREE (MTYPE_NS_NAME, ns->name);
+
+ XFREE (MTYPE_NS, ns);
+}
+
+/* Look up a NS by identifier. */
+static struct ns *
+ns_lookup (ns_id_t ns_id)
+{
+ struct prefix p;
+ struct route_node *rn;
+ struct ns *ns = NULL;
+
+ ns_build_key (ns_id, &p);
+ rn = route_node_lookup (ns_table, &p);
+ if (rn)
+ {
+ ns = (struct ns *)rn->info;
+ route_unlock_node (rn); /* lookup */
+ }
+ return ns;
+}
+
+/*
+ * Check whether the NS is enabled - that is, whether the NS
+ * is ready to allocate resources. Currently there's only one
+ * type of resource: socket.
+ */
+static int
+ns_is_enabled (struct ns *ns)
+{
+ if (have_netns())
+ return ns && ns->fd >= 0;
+ else
+ return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT;
+}
+
+/*
+ * Enable a NS - that is, let the NS be ready to use.
+ * The NS_ENABLE_HOOK callback will be called to inform
+ * that they can allocate resources in this NS.
+ *
+ * RETURN: 1 - enabled successfully; otherwise, 0.
+ */
+static int
+ns_enable (struct ns *ns)
+{
+
+ if (!ns_is_enabled (ns))
+ {
+ if (have_netns()) {
+ ns->fd = open (ns->name, O_RDONLY);
+ } else {
+ ns->fd = -2; /* Remember that ns_enable_hook has been called */
+ errno = -ENOTSUP;
+ }
+
+ if (!ns_is_enabled (ns))
+ {
+ zlog_err ("Can not enable NS %u: %s!",
+ ns->ns_id, safe_strerror (errno));
+ return 0;
+ }
+
+ if (have_netns())
+ zlog_info ("NS %u is associated with NETNS %s.",
+ ns->ns_id, ns->name);
+
+ zlog_info ("NS %u is enabled.", ns->ns_id);
+ if (ns_master.ns_enable_hook)
+ (*ns_master.ns_enable_hook) (ns->ns_id, &ns->info);
+ }
+
+ return 1;
+}
+
+/*
+ * Disable a NS - that is, let the NS be unusable.
+ * The NS_DELETE_HOOK callback will be called to inform
+ * that they must release the resources in the NS.
+ */
+static void
+ns_disable (struct ns *ns)
+{
+ if (ns_is_enabled (ns))
+ {
+ zlog_info ("NS %u is to be disabled.", ns->ns_id);
+
+ if (ns_master.ns_disable_hook)
+ (*ns_master.ns_disable_hook) (ns->ns_id, &ns->info);
+
+ if (have_netns())
+ close (ns->fd);
+
+ ns->fd = -1;
+ }
+}
+
+
+/* Add a NS hook. Please add hooks before calling ns_init(). */
+void
+ns_add_hook (int type, int (*func)(ns_id_t, void **))
+{
+ switch (type) {
+ case NS_NEW_HOOK:
+ ns_master.ns_new_hook = func;
+ break;
+ case NS_DELETE_HOOK:
+ ns_master.ns_delete_hook = func;
+ break;
+ case NS_ENABLE_HOOK:
+ ns_master.ns_enable_hook = func;
+ break;
+ case NS_DISABLE_HOOK:
+ ns_master.ns_disable_hook = func;
+ break;
+ default:
+ break;
+ }
+}
+
+/* Return the iterator of the first NS. */
+ns_iter_t
+ns_first (void)
+{
+ struct route_node *rn;
+
+ for (rn = route_top (ns_table); rn; rn = route_next (rn))
+ if (rn->info)
+ {
+ route_unlock_node (rn); /* top/next */
+ return (ns_iter_t)rn;
+ }
+ return NS_ITER_INVALID;
+}
+
+/* Return the next NS iterator to the given iterator. */
+ns_iter_t
+ns_next (ns_iter_t iter)
+{
+ struct route_node *rn = NULL;
+
+ /* Lock it first because route_next() will unlock it. */
+ if (iter != NS_ITER_INVALID)
+ rn = route_next (route_lock_node ((struct route_node *)iter));
+
+ for (; rn; rn = route_next (rn))
+ if (rn->info)
+ {
+ route_unlock_node (rn); /* next */
+ return (ns_iter_t)rn;
+ }
+ return NS_ITER_INVALID;
+}
+
+/* Return the NS iterator of the given NS ID. If it does not exist,
+ * the iterator of the next existing NS is returned. */
+ns_iter_t
+ns_iterator (ns_id_t ns_id)
+{
+ struct prefix p;
+ struct route_node *rn;
+
+ ns_build_key (ns_id, &p);
+ rn = route_node_get (ns_table, &p);
+ if (rn->info)
+ {
+ /* OK, the NS exists. */
+ route_unlock_node (rn); /* get */
+ return (ns_iter_t)rn;
+ }
+
+ /* Find the next NS. */
+ for (rn = route_next (rn); rn; rn = route_next (rn))
+ if (rn->info)
+ {
+ route_unlock_node (rn); /* next */
+ return (ns_iter_t)rn;
+ }
+
+ return NS_ITER_INVALID;
+}
+
+/* Obtain the NS ID from the given NS iterator. */
+ns_id_t
+ns_iter2id (ns_iter_t iter)
+{
+ struct route_node *rn = (struct route_node *) iter;
+ return (rn && rn->info) ? ((struct ns *)rn->info)->ns_id : NS_DEFAULT;
+}
+
+/* Obtain the data pointer from the given NS iterator. */
+void *
+ns_iter2info (ns_iter_t iter)
+{
+ struct route_node *rn = (struct route_node *) iter;
+ return (rn && rn->info) ? ((struct ns *)rn->info)->info : NULL;
+}
+
+/* Obtain the interface list from the given NS iterator. */
+struct list *
+ns_iter2iflist (ns_iter_t iter)
+{
+ struct route_node *rn = (struct route_node *) iter;
+ return (rn && rn->info) ? ((struct ns *)rn->info)->iflist : NULL;
+}
+
+/* Get the data pointer of the specified NS. If not found, create one. */
+void *
+ns_info_get (ns_id_t ns_id)
+{
+ struct ns *ns = ns_get (ns_id);
+ return ns->info;
+}
+
+/* Look up the data pointer of the specified NS. */
+void *
+ns_info_lookup (ns_id_t ns_id)
+{
+ struct ns *ns = ns_lookup (ns_id);
+ return ns ? ns->info : NULL;
+}
+
+/* Look up the interface list in a NS. */
+struct list *
+ns_iflist (ns_id_t ns_id)
+{
+ struct ns * ns = ns_lookup (ns_id);
+ return ns ? ns->iflist : NULL;
+}
+
+/* Get the interface list of the specified NS. Create one if not find. */
+struct list *
+ns_iflist_get (ns_id_t ns_id)
+{
+ struct ns * ns = ns_get (ns_id);
+ return ns->iflist;
+}
+
+/*
+ * NS bit-map
+ */
+
+#define NS_BITMAP_NUM_OF_GROUPS 8
+#define NS_BITMAP_NUM_OF_BITS_IN_GROUP \
+ (UINT16_MAX / NS_BITMAP_NUM_OF_GROUPS)
+#define NS_BITMAP_NUM_OF_BYTES_IN_GROUP \
+ (NS_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
+
+#define NS_BITMAP_GROUP(_id) \
+ ((_id) / NS_BITMAP_NUM_OF_BITS_IN_GROUP)
+#define NS_BITMAP_BIT_OFFSET(_id) \
+ ((_id) % NS_BITMAP_NUM_OF_BITS_IN_GROUP)
+
+#define NS_BITMAP_INDEX_IN_GROUP(_bit_offset) \
+ ((_bit_offset) / CHAR_BIT)
+#define NS_BITMAP_FLAG(_bit_offset) \
+ (((u_char)1) << ((_bit_offset) % CHAR_BIT))
+
+struct ns_bitmap
+{
+ u_char *groups[NS_BITMAP_NUM_OF_GROUPS];
+};
+
+ns_bitmap_t
+ns_bitmap_init (void)
+{
+ return (ns_bitmap_t) XCALLOC (MTYPE_NS_BITMAP, sizeof (struct ns_bitmap));
+}
+
+void
+ns_bitmap_free (ns_bitmap_t bmap)
+{
+ struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+ int i;
+
+ if (bmap == NS_BITMAP_NULL)
+ return;
+
+ for (i = 0; i < NS_BITMAP_NUM_OF_GROUPS; i++)
+ if (bm->groups[i])
+ XFREE (MTYPE_NS_BITMAP, bm->groups[i]);
+
+ XFREE (MTYPE_NS_BITMAP, bm);
+}
+
+void
+ns_bitmap_set (ns_bitmap_t bmap, ns_id_t ns_id)
+{
+ struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+ u_char group = NS_BITMAP_GROUP (ns_id);
+ u_char offset = NS_BITMAP_BIT_OFFSET (ns_id);
+
+ if (bmap == NS_BITMAP_NULL)
+ return;
+
+ if (bm->groups[group] == NULL)
+ bm->groups[group] = XCALLOC (MTYPE_NS_BITMAP,
+ NS_BITMAP_NUM_OF_BYTES_IN_GROUP);
+
+ SET_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)],
+ NS_BITMAP_FLAG (offset));
+}
+
+void
+ns_bitmap_unset (ns_bitmap_t bmap, ns_id_t ns_id)
+{
+ struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+ u_char group = NS_BITMAP_GROUP (ns_id);
+ u_char offset = NS_BITMAP_BIT_OFFSET (ns_id);
+
+ if (bmap == NS_BITMAP_NULL || bm->groups[group] == NULL)
+ return;
+
+ UNSET_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)],
+ NS_BITMAP_FLAG (offset));
+}
+
+int
+ns_bitmap_check (ns_bitmap_t bmap, ns_id_t ns_id)
+{
+ struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+ u_char group = NS_BITMAP_GROUP (ns_id);
+ u_char offset = NS_BITMAP_BIT_OFFSET (ns_id);
+
+ if (bmap == NS_BITMAP_NULL || bm->groups[group] == NULL)
+ return 0;
+
+ return CHECK_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)],
+ NS_BITMAP_FLAG (offset)) ? 1 : 0;
+}
+
+/*
+ * NS realization with NETNS
+ */
+
+static char *
+ns_netns_pathname (struct vty *vty, const char *name)
+{
+ static char pathname[PATH_MAX];
+ char *result;
+
+ if (name[0] == '/') /* absolute pathname */
+ result = realpath (name, pathname);
+ else /* relevant pathname */
+ {
+ char tmp_name[PATH_MAX];
+ snprintf (tmp_name, PATH_MAX, "%s/%s", NS_RUN_DIR, name);
+ result = realpath (tmp_name, pathname);
+ }
+
+ if (! result)
+ {
+ vty_out (vty, "Invalid pathname: %s%s", safe_strerror (errno),
+ VTY_NEWLINE);
+ return NULL;
+ }
+ return pathname;
+}
+
+DEFUN (ns_netns,
+ ns_netns_cmd,
+ "logical-router <1-65535> ns NAME",
+ "Enable a logical-router\n"
+ "Specify the logical-router indentifier\n"
+ "The Name Space\n"
+ "The file name in " NS_RUN_DIR ", or a full pathname\n")
+{
+ ns_id_t ns_id = NS_DEFAULT;
+ struct ns *ns = NULL;
+ char *pathname = ns_netns_pathname (vty, argv[1]);
+
+ if (!pathname)
+ return CMD_WARNING;
+
+ VTY_GET_INTEGER ("NS ID", ns_id, argv[0]);
+ ns = ns_get (ns_id);
+
+ if (ns->name && strcmp (ns->name, pathname) != 0)
+ {
+ vty_out (vty, "NS %u is already configured with NETNS %s%s",
+ ns->ns_id, ns->name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!ns->name)
+ ns->name = XSTRDUP (MTYPE_NS_NAME, pathname);
+
+ if (!ns_enable (ns))
+ {
+ vty_out (vty, "Can not associate NS %u with NETNS %s%s",
+ ns->ns_id, ns->name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ns_netns,
+ no_ns_netns_cmd,
+ "no logical-router <1-65535> ns NAME",
+ NO_STR
+ "Enable a Logical-Router\n"
+ "Specify the Logical-Router identifier\n"
+ "The Name Space\n"
+ "The file name in " NS_RUN_DIR ", or a full pathname\n")
+{
+ ns_id_t ns_id = NS_DEFAULT;
+ struct ns *ns = NULL;
+ char *pathname = ns_netns_pathname (vty, argv[1]);
+
+ if (!pathname)
+ return CMD_WARNING;
+
+ VTY_GET_INTEGER ("NS ID", ns_id, argv[0]);
+ ns = ns_lookup (ns_id);
+
+ if (!ns)
+ {
+ vty_out (vty, "NS %u is not found%s", ns_id, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if (ns->name && strcmp (ns->name, pathname) != 0)
+ {
+ vty_out (vty, "Incorrect NETNS file name%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ns_disable (ns);
+
+ if (ns->name)
+ {
+ XFREE (MTYPE_NS_NAME, ns->name);
+ ns->name = NULL;
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* NS node. */
+static struct cmd_node ns_node =
+{
+ NS_NODE,
+ "", /* NS node has no interface. */
+ 1
+};
+
+/* NS configuration write function. */
+static int
+ns_config_write (struct vty *vty)
+{
+ struct route_node *rn;
+ struct ns *ns;
+ int write = 0;
+
+ for (rn = route_top (ns_table); rn; rn = route_next (rn))
+ if ((ns = rn->info) != NULL &&
+ ns->ns_id != NS_DEFAULT && ns->name)
+ {
+ vty_out (vty, "logical-router %u netns %s%s", ns->ns_id, ns->name, VTY_NEWLINE);
+ write++;
+ }
+
+ return write;
+}
+
+/* Initialize NS module. */
+void
+ns_init (void)
+{
+ struct ns *default_ns;
+
+ /* Allocate NS table. */
+ ns_table = route_table_init ();
+
+ /* The default NS always exists. */
+ default_ns = ns_get (NS_DEFAULT);
+ if (!default_ns)
+ {
+ zlog_err ("ns_init: failed to create the default NS!");
+ exit (1);
+ }
+
+ /* Set the default NS name. */
+ default_ns->name = XSTRDUP (MTYPE_NS_NAME, NS_DEFAULT_NAME);
+
+ /* Enable the default NS. */
+ if (!ns_enable (default_ns))
+ {
+ zlog_err ("ns_init: failed to enable the default NS!");
+ exit (1);
+ }
+
+ if (have_netns())
+ {
+ /* Install NS commands. */
+ install_node (&ns_node, ns_config_write);
+ install_element (CONFIG_NODE, &ns_netns_cmd);
+ install_element (CONFIG_NODE, &no_ns_netns_cmd);
+ }
+}
+
+/* Terminate NS module. */
+void
+ns_terminate (void)
+{
+ struct route_node *rn;
+ struct ns *ns;
+
+ for (rn = route_top (ns_table); rn; rn = route_next (rn))
+ if ((ns = rn->info) != NULL)
+ ns_delete (ns);
+
+ route_table_finish (ns_table);
+ ns_table = NULL;
+}
+
+/* Create a socket for the NS. */
+int
+ns_socket (int domain, int type, int protocol, ns_id_t ns_id)
+{
+ struct ns *ns = ns_lookup (ns_id);
+ int ret = -1;
+
+ if (!ns_is_enabled (ns))
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (have_netns())
+ {
+ ret = (ns_id != NS_DEFAULT) ? setns (ns->fd, CLONE_NEWNET) : 0;
+ if (ret >= 0)
+ {
+ ret = socket (domain, type, protocol);
+ if (ns_id != NS_DEFAULT)
+ setns (ns_lookup (NS_DEFAULT)->fd, CLONE_NEWNET);
+ }
+ }
+ else
+ ret = socket (domain, type, protocol);
+
+ return ret;
+}
diff --git a/lib/ns.h b/lib/ns.h
new file mode 100644
index 0000000000..3fac739861
--- /dev/null
+++ b/lib/ns.h
@@ -0,0 +1,142 @@
+/*
+ * NS related header.
+ * Copyright (C) 2014 6WIND S.A.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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.
+ *
+ * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_NS_H
+#define _ZEBRA_NS_H
+
+#include "linklist.h"
+
+typedef u_int16_t ns_id_t;
+
+/* The default NS ID */
+#define NS_DEFAULT 0
+
+/*
+ * The command strings
+ */
+#define NS_RUN_DIR "/var/run/netns"
+#define NS_CMD_STR "logical-router <0-65535>"
+#define NS_CMD_HELP_STR "Specify the Logical-Router\nThe Logical-Router ID\n"
+
+#define NS_ALL_CMD_STR "logical-router all"
+#define NS_ALL_CMD_HELP_STR "Specify the logical-router\nAll logical-router's\n"
+
+/*
+ * NS hooks
+ */
+
+#define NS_NEW_HOOK 0 /* a new logical-router is just created */
+#define NS_DELETE_HOOK 1 /* a logical-router is to be deleted */
+#define NS_ENABLE_HOOK 2 /* a logical-router is ready to use */
+#define NS_DISABLE_HOOK 3 /* a logical-router is to be unusable */
+
+/*
+ * Add a specific hook ns module.
+ * @param1: hook type
+ * @param2: the callback function
+ * - param 1: the NS ID
+ * - param 2: the address of the user data pointer (the user data
+ * can be stored in or freed from there)
+ */
+extern void ns_add_hook (int, int (*)(ns_id_t, void **));
+
+/*
+ * NS iteration
+ */
+
+typedef void * ns_iter_t;
+#define NS_ITER_INVALID NULL /* invalid value of the iterator */
+
+/*
+ * NS iteration utilities. Example for the usage:
+ *
+ * ns_iter_t iter = ns_first();
+ * for (; iter != NS_ITER_INVALID; iter = ns_next (iter))
+ *
+ * or
+ *
+ * ns_iter_t iter = ns_iterator (<a given NS ID>);
+ * for (; iter != NS_ITER_INVALID; iter = ns_next (iter))
+ */
+
+/* Return the iterator of the first NS. */
+extern ns_iter_t ns_first (void);
+/* Return the next NS iterator to the given iterator. */
+extern ns_iter_t ns_next (ns_iter_t);
+/* Return the NS iterator of the given NS ID. If it does not exist,
+ * the iterator of the next existing NS is returned. */
+extern ns_iter_t ns_iterator (ns_id_t);
+
+/*
+ * NS iterator to properties
+ */
+extern ns_id_t ns_iter2id (ns_iter_t);
+extern void *ns_iter2info (ns_iter_t);
+extern struct list *ns_iter2iflist (ns_iter_t);
+
+/*
+ * Utilities to obtain the user data
+ */
+
+/* Get the data pointer of the specified NS. If not found, create one. */
+extern void *ns_info_get (ns_id_t);
+/* Look up the data pointer of the specified NS. */
+extern void *ns_info_lookup (ns_id_t);
+
+/*
+ * Utilities to obtain the interface list
+ */
+
+/* Look up the interface list of the specified NS. */
+extern struct list *ns_iflist (ns_id_t);
+/* Get the interface list of the specified NS. Create one if not find. */
+extern struct list *ns_iflist_get (ns_id_t);
+
+/*
+ * NS bit-map: maintaining flags, one bit per NS ID
+ */
+
+typedef void * ns_bitmap_t;
+#define NS_BITMAP_NULL NULL
+
+extern ns_bitmap_t ns_bitmap_init (void);
+extern void ns_bitmap_free (ns_bitmap_t);
+extern void ns_bitmap_set (ns_bitmap_t, ns_id_t);
+extern void ns_bitmap_unset (ns_bitmap_t, ns_id_t);
+extern int ns_bitmap_check (ns_bitmap_t, ns_id_t);
+
+/*
+ * NS initializer/destructor
+ */
+/* Please add hooks before calling ns_init(). */
+extern void ns_init (void);
+extern void ns_terminate (void);
+
+/*
+ * NS utilities
+ */
+
+/* Create a socket serving for the given NS */
+extern int ns_socket (int, int, int, ns_id_t);
+
+#endif /*_ZEBRA_NS_H*/
+
diff --git a/lib/plist.c b/lib/plist.c
index a1289801c4..7bb80fa2a4 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -958,6 +958,11 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
return CMD_WARNING;
}
break;
+ case AFI_ETHER:
+ default:
+ vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
}
/* ge and le check. */
diff --git a/lib/prefix.c b/lib/prefix.c
index 256cd3a49a..d2bb028315 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -194,8 +194,9 @@ str2family(const char *string)
return AF_INET;
else if (!strcmp("ipv6", string))
return AF_INET6;
- else
- return -1;
+ else if (!strcmp("ethernet", string))
+ return AF_ETHERNET;
+ return -1;
}
/* Address Famiy Identifier to Address Family converter. */
@@ -208,6 +209,8 @@ afi2family (afi_t afi)
else if (afi == AFI_IP6)
return AF_INET6;
#endif /* HAVE_IPV6 */
+ else if (afi == AFI_ETHER)
+ return AF_ETHERNET;
return 0;
}
@@ -220,10 +223,28 @@ family2afi (int family)
else if (family == AF_INET6)
return AFI_IP6;
#endif /* HAVE_IPV6 */
+ else if (family == AF_ETHERNET)
+ return AFI_ETHER;
return 0;
}
const char *
+afi2str(afi_t afi)
+{
+ switch (afi) {
+ case AFI_IP:
+ return "IPv4";
+ case AFI_IP6:
+ return "IPv6";
+ case AFI_ETHER:
+ return "ethernet";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+const char *
safi2str(safi_t safi)
{
switch (safi) {
@@ -286,6 +307,10 @@ prefix_copy (struct prefix *dest, const struct prefix *src)
dest->u.lp.id = src->u.lp.id;
dest->u.lp.adv_router = src->u.lp.adv_router;
}
+ else if (src->family == AF_ETHERNET)
+ {
+ dest->u.prefix_eth = src->u.prefix_eth;
+ }
else
{
zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d",
@@ -321,6 +346,10 @@ prefix_same (const struct prefix *p1, const struct prefix *p2)
if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr))
return 1;
#endif /* HAVE_IPV6 */
+ if (p1->family == AF_ETHERNET) {
+ if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN))
+ return 1;
+ }
}
return 0;
}
@@ -412,6 +441,8 @@ prefix_family_str (const struct prefix *p)
if (p->family == AF_INET6)
return "inet6";
#endif /* HAVE_IPV6 */
+ if (p->family == AF_ETHERNET)
+ return "ether";
return "unspec";
}
@@ -482,6 +513,60 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
return ret;
}
+/* When string format is invalid return 0. */
+int
+str2prefix_eth (const char *str, struct prefix_eth *p)
+{
+ int ret = 0;
+ int plen = 48;
+ char *pnt;
+ char *cp = NULL;
+ const char *str_addr = str;
+ unsigned int a[6];
+ int i;
+
+ /* Find slash inside string. */
+ pnt = strchr (str, '/');
+
+ if (pnt)
+ {
+ /* Get prefix length. */
+ plen = (u_char) atoi (++pnt);
+ if (plen > 48)
+ {
+ ret = 0;
+ goto done;
+ }
+
+ cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
+ strncpy (cp, str, pnt - str);
+ *(cp + (pnt - str)) = '\0';
+
+ str_addr = cp;
+ }
+
+ /* Convert string to prefix. */
+ if (sscanf(str_addr, "%2x:%2x:%2x:%2x:%2x:%2x",
+ a+0, a+1, a+2, a+3, a+4, a+5) != 6)
+ {
+ ret = 0;
+ goto done;
+ }
+ for (i = 0; i < 6; ++i)
+ {
+ p->eth_addr.octet[i] = a[i] & 0xff;
+ }
+ p->prefixlen = plen;
+ p->family = AF_ETHERNET;
+ ret = 1;
+
+done:
+ if (cp)
+ XFREE (MTYPE_TMP, cp);
+
+ return ret;
+}
+
/* Convert masklen into IP address's netmask (network byte order). */
void
masklen2ip (const int masklen, struct in_addr *netmask)
@@ -572,7 +657,7 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
{
int plen;
- cp = XMALLOC (0, (pnt - str) + 1);
+ cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
strncpy (cp, str, pnt - str);
*(cp + (pnt - str)) = '\0';
ret = inet_pton (AF_INET6, cp, &p->prefix);
@@ -768,6 +853,8 @@ prefix_blen (const struct prefix *p)
return IPV6_MAX_BYTELEN;
break;
#endif /* HAVE_IPV6 */
+ case AF_ETHERNET:
+ return ETHER_ADDR_LEN;
}
return 0;
}
@@ -790,6 +877,11 @@ str2prefix (const char *str, struct prefix *p)
return ret;
#endif /* HAVE_IPV6 */
+ /* Next we try to convert string to struct prefix_eth. */
+ ret = str2prefix_eth (str, (struct prefix_eth *) p);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -799,6 +891,24 @@ prefix2str (union prefix46constptr pu, char *str, int size)
const struct prefix *p = pu.p;
char buf[PREFIX2STR_BUFFER];
+ if (p->family == AF_ETHERNET) {
+ int i;
+ char *s = str;
+
+ assert(size > (3*ETHER_ADDR_LEN) + 1 /* slash */ + 3 /* plen */ );
+ for (i = 0; i < ETHER_ADDR_LEN; ++i) {
+ sprintf(s, "%02x", p->u.prefix_eth.octet[i]);
+ if (i < (ETHER_ADDR_LEN - 1)) {
+ *(s+2) = ':';
+ s += 3;
+ } else {
+ s += 2;
+ }
+ }
+ sprintf(s, "/%d", p->prefixlen);
+ return 0;
+ }
+
snprintf (str, size, "%s/%d",
inet_ntop (p->family, &p->u.prefix, buf, PREFIX2STR_BUFFER),
p->prefixlen);
diff --git a/lib/prefix.h b/lib/prefix.h
index 39c2b62019..85488ccea7 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -23,8 +23,30 @@
#ifndef _ZEBRA_PREFIX_H
#define _ZEBRA_PREFIX_H
+#ifdef SUNOS_5
+# include <sys/ethernet.h>
+#else
+# ifdef GNU_LINUX
+# include <net/ethernet.h>
+# else
+# include <netinet/if_ether.h>
+# endif
+#endif
#include "sockunion.h"
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN ETHERADDRL
+#endif
+
+/*
+ * there isn't a portable ethernet address type. We define our
+ * own to simplify internal handling
+ */
+struct ethaddr {
+ u_char octet[ETHER_ADDR_LEN];
+} __packed;
+
+
/*
* A struct prefix contains an address family, a prefix length, and an
* address. This can represent either a 'network prefix' as defined
@@ -34,6 +56,15 @@
* interface.
*/
+/* different OSes use different names */
+#if defined(AF_PACKET)
+#define AF_ETHERNET AF_PACKET
+#else
+#if defined(AF_LINK)
+#define AF_ETHERNET AF_LINK
+#endif
+#endif
+
/* IPv4 and IPv6 unified prefix structure. */
struct prefix
{
@@ -51,6 +82,7 @@ struct prefix
struct in_addr id;
struct in_addr adv_router;
} lp;
+ struct ethaddr prefix_eth; /* AF_ETHERNET */
u_char val[8];
uintptr_t ptr;
} u __attribute__ ((aligned (8)));
@@ -90,6 +122,14 @@ struct prefix_rd
u_char val[8] __attribute__ ((aligned (8)));
};
+/* Prefix for ethernet. */
+struct prefix_eth
+{
+ u_char family;
+ u_char prefixlen;
+ struct ethaddr eth_addr __attribute__ ((aligned (8))); /* AF_ETHERNET */
+};
+
/* Prefix for a generic pointer */
struct prefix_ptr
{
@@ -174,6 +214,7 @@ extern int str2family(const char *);
extern int afi2family (afi_t);
extern afi_t family2afi (int);
extern const char *safi2str(safi_t safi);
+extern const char *afi2str(afi_t afi);
/* Check bit of the prefix. */
extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen);
@@ -205,6 +246,8 @@ extern struct prefix *sockunion2prefix (const union sockunion *dest,
extern struct prefix *sockunion2hostprefix (const union sockunion *, struct prefix *p);
extern void prefix2sockunion (const struct prefix *, union sockunion *);
+extern int str2prefix_eth (const char *, struct prefix_eth *);
+
extern struct prefix_ipv4 *prefix_ipv4_new (void);
extern void prefix_ipv4_free (struct prefix_ipv4 *);
extern int str2prefix_ipv4 (const char *, struct prefix_ipv4 *);
diff --git a/lib/privs.c b/lib/privs.c
index e6d76b600b..3fb96aed12 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -307,11 +307,18 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
current_caps = cap_get_proc();
if (current_caps)
+ {
current_caps_text = cap_to_text(current_caps, NULL);
+ cap_free(current_caps);
+ }
wanted_caps_text = cap_to_text(zprivs_state.caps, NULL);
fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???");
fprintf(stderr, "Have caps: %s\n", current_caps_text ? current_caps_text : "???");
+ if (current_caps_text)
+ cap_free(current_caps_text);
+ if (wanted_caps_text)
+ cap_free(wanted_caps_text);
exit (1);
}
diff --git a/lib/routemap.c b/lib/routemap.c
index d8d1872d65..9267056df6 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1591,7 +1591,7 @@ DEFUN (rmap_onmatch_goto,
}
if (argc == 1 && argv[0])
- VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
+ VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65535);
else
d = index->pref + 1;
@@ -1669,7 +1669,7 @@ DEFUN (rmap_show_name,
ALIAS (rmap_onmatch_goto,
rmap_continue_index_cmd,
- "continue <1-65536>",
+ "continue <1-65535>",
"Exit policy on matches\n"
"Goto Clause number\n")
diff --git a/lib/sigevent.c b/lib/sigevent.c
index c80a729012..a120028d81 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -237,6 +237,8 @@ core_handler(int signo
, siginfo, program_counter(context)
#endif
);
+ /* dump memory stats on core */
+ log_memstats_stderr ("core_handler");
abort();
}
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 257271bc0b..31b2edbacf 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -219,8 +219,9 @@ setsockopt_ipv6_tclass(int sock, int tclass)
int
setsockopt_ipv4_multicast(int sock,
int optname,
+ struct in_addr if_addr,
unsigned int mcast_addr,
- unsigned int ifindex)
+ ifindex_t ifindex)
{
#ifdef HAVE_RFC3678
struct group_req gr;
@@ -279,18 +280,20 @@ setsockopt_ipv4_multicast(int sock,
#elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */
/* standard BSD API */
- struct in_addr m;
struct ip_mreq mreq;
int ret;
assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
- m.s_addr = htonl(ifindex);
memset (&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr.s_addr = mcast_addr;
- mreq.imr_interface = m;
-
+#if !defined __OpenBSD__
+ mreq.imr_interface.s_addr = htonl (ifindex);
+#else
+ mreq.imr_interface.s_addr = if_addr.s_addr;
+#endif
+
ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq));
if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
{
@@ -318,8 +321,8 @@ setsockopt_ipv4_multicast(int sock,
* Set IP_MULTICAST_IF socket option in an OS-dependent manner.
*/
int
-setsockopt_ipv4_multicast_if(int sock,
- unsigned int ifindex)
+setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr,
+ ifindex_t ifindex)
{
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
@@ -336,7 +339,11 @@ setsockopt_ipv4_multicast_if(int sock,
#elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
struct in_addr m;
- m.s_addr = htonl(ifindex);
+#if !defined __OpenBSD__
+ m.s_addr = htonl (ifindex);
+#else
+ m.s_addr = if_addr.s_addr;
+#endif
return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
#else
@@ -345,7 +352,7 @@ setsockopt_ipv4_multicast_if(int sock,
}
static int
-setsockopt_ipv4_ifindex (int sock, int val)
+setsockopt_ipv4_ifindex (int sock, ifindex_t val)
{
int ret;
@@ -381,7 +388,7 @@ setsockopt_ipv4_tos(int sock, int tos)
int
-setsockopt_ifindex (int af, int sock, int val)
+setsockopt_ifindex (int af, int sock, ifindex_t val)
{
int ret = -1;
@@ -408,11 +415,11 @@ setsockopt_ifindex (int af, int sock, int val)
* Returns the interface index (small integer >= 1) if it can be
* determined, or else 0.
*/
-static int
+static ifindex_t
getsockopt_ipv4_ifindex (struct msghdr *msgh)
{
/* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */
- int ifindex = -1;
+ ifindex_t ifindex = -1;
#if defined(IP_PKTINFO)
/* Linux pktinfo based ifindex retrieval */
@@ -432,7 +439,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh)
struct sockaddr_dl *sdl;
#else
/* SUNOS_5 uses an integer with the index. */
- int *ifindex_p;
+ ifindex_t *ifindex_p;
#endif /* SUNOS_5 */
#ifndef SUNOS_5
@@ -473,7 +480,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh)
}
/* return ifindex, 0 if none found */
-int
+ifindex_t
getsockopt_ifindex (int af, struct msghdr *msgh)
{
switch (af)
diff --git a/lib/sockopt.h b/lib/sockopt.h
index cb14efc7ba..d67b510b66 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -83,16 +83,17 @@ extern int setsockopt_ipv6_tclass (int, int);
(((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \
? SOPT_SIZE_CMSG_PKTINFO_IPV6())
-extern int setsockopt_ipv4_multicast_if(int sock,
- unsigned int ifindex);
+extern int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr,
+ ifindex_t ifindex);
extern int setsockopt_ipv4_multicast(int sock, int optname,
+ struct in_addr if_addr,
unsigned int mcast_addr,
- unsigned int ifindex);
+ ifindex_t ifindex);
extern int setsockopt_ipv4_tos(int sock, int tos);
/* Ask for, and get, ifindex, by whatever method is supported. */
-extern int setsockopt_ifindex (int, int, int);
-extern int getsockopt_ifindex (int, struct msghdr *);
+extern int setsockopt_ifindex (int, int, ifindex_t);
+extern ifindex_t getsockopt_ifindex (int, struct msghdr *);
/* swab the fields in iph between the host order and system order expected
* for IP_HDRINCL.
diff --git a/lib/sockunion.c b/lib/sockunion.c
index b5a2eb954a..9184e500fc 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -291,7 +291,7 @@ sockunion_sizeof (const union sockunion *su)
1 : connect is in progress */
enum connect_result
sockunion_connect (int fd, const union sockunion *peersu, unsigned short port,
- unsigned int ifindex)
+ ifindex_t ifindex)
{
int ret;
int val;
diff --git a/lib/sockunion.h b/lib/sockunion.h
index a33051ae57..105b11a24c 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -24,6 +24,7 @@
#define _ZEBRA_SOCKUNION_H
#include "privs.h"
+#include "if.h"
union sockunion
{
@@ -95,7 +96,7 @@ extern int sockunion_socket (const union sockunion *su);
extern const char *inet_sutop (const union sockunion *su, char *str);
extern enum connect_result sockunion_connect (int fd, const union sockunion *su,
unsigned short port,
- unsigned int);
+ ifindex_t);
extern union sockunion *sockunion_getsockname (int);
extern union sockunion *sockunion_getpeername (int);
extern union sockunion *sockunion_dup (const union sockunion *);
diff --git a/lib/str.c b/lib/str.c
index d8f039a094..16f759c074 100644
--- a/lib/str.c
+++ b/lib/str.c
@@ -54,26 +54,34 @@ snprintf(char *str, size_t size, const char *format, ...)
#endif
#ifndef HAVE_STRLCPY
-/**
- * Like strncpy but does not 0 fill the buffer and always null
- * terminates.
- *
- * @param bufsize is the size of the destination buffer.
- *
- * @return index of the terminating byte.
- **/
+/*
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
size_t
-strlcpy(char *d, const char *s, size_t bufsize)
+strlcpy(char *dst, const char *src, size_t dsize)
{
- size_t len = strlen(s);
- size_t ret = len;
- if (bufsize > 0) {
- if (len >= bufsize)
- len = bufsize-1;
- memcpy(d, s, len);
- d[len] = 0;
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
}
- return ret;
+
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+ while (*src++)
+ ;
+ }
+
+ return(src - osrc - 1); /* count does not include NUL */
}
#endif
diff --git a/lib/stream.c b/lib/stream.c
index 4c237563a5..809e749fb9 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -373,6 +373,47 @@ stream_getw_from (struct stream *s, size_t from)
return w;
}
+/* Get next 3-byte from the stream. */
+u_int32_t
+stream_get3_from (struct stream *s, size_t from)
+{
+ u_int32_t l;
+
+ STREAM_VERIFY_SANE(s);
+
+ if (!GETP_VALID (s, from + 3))
+ {
+ STREAM_BOUND_WARN (s, "get 3byte");
+ return 0;
+ }
+
+ l = s->data[from++] << 16;
+ l |= s->data[from++] << 8;
+ l |= s->data[from];
+
+ return l;
+}
+
+u_int32_t
+stream_get3 (struct stream *s)
+{
+ u_int32_t l;
+
+ STREAM_VERIFY_SANE(s);
+
+ if (STREAM_READABLE (s) < 3)
+ {
+ STREAM_BOUND_WARN (s, "get 3byte");
+ return 0;
+ }
+
+ l = s->data[s->getp++] << 16;
+ l |= s->data[s->getp++] << 8;
+ l |= s->data[s->getp++];
+
+ return l;
+}
+
/* Get next long word from the stream. */
u_int32_t
stream_getl_from (struct stream *s, size_t from)
@@ -502,6 +543,28 @@ stream_get_ipv4 (struct stream *s)
return l;
}
+float
+stream_getf (struct stream *s)
+{
+ union {
+ float r;
+ uint32_t d;
+ } u;
+ u.d = stream_getl (s);
+ return u.r;
+}
+
+double
+stream_getd (struct stream *s)
+{
+ union {
+ double r;
+ uint64_t d;
+ } u;
+ u.d = stream_getq (s);
+ return u.r;
+}
+
/* Copy to source to stream.
*
* XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
@@ -568,6 +631,25 @@ stream_putw (struct stream *s, u_int16_t w)
/* Put long word to the stream. */
int
+stream_put3 (struct stream *s, u_int32_t l)
+{
+ STREAM_VERIFY_SANE (s);
+
+ if (STREAM_WRITEABLE (s) < 3)
+ {
+ STREAM_BOUND_WARN (s, "put");
+ return 0;
+ }
+
+ s->data[s->endp++] = (u_char)(l >> 16);
+ s->data[s->endp++] = (u_char)(l >> 8);
+ s->data[s->endp++] = (u_char)l;
+
+ return 3;
+}
+
+/* Put long word to the stream. */
+int
stream_putl (struct stream *s, u_int32_t l)
{
STREAM_VERIFY_SANE (s);
@@ -611,6 +693,28 @@ stream_putq (struct stream *s, uint64_t q)
}
int
+stream_putf (struct stream *s, float f)
+{
+ union {
+ float i;
+ uint32_t o;
+ } u;
+ u.i = f;
+ return stream_putl (s, u.o);
+}
+
+int
+stream_putd (struct stream *s, double d)
+{
+ union {
+ double i;
+ uint64_t o;
+ } u;
+ u.i = d;
+ return stream_putq (s, u.o);
+}
+
+int
stream_putc_at (struct stream *s, size_t putp, u_char c)
{
STREAM_VERIFY_SANE(s);
@@ -644,6 +748,23 @@ stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
}
int
+stream_put3_at (struct stream *s, size_t putp, u_int32_t l)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!PUT_AT_VALID (s, putp + 3))
+ {
+ STREAM_BOUND_WARN (s, "put");
+ return 0;
+ }
+ s->data[putp] = (u_char)(l >> 16);
+ s->data[putp + 1] = (u_char)(l >> 8);
+ s->data[putp + 2] = (u_char)l;
+
+ return 3;
+}
+
+int
stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
{
STREAM_VERIFY_SANE(s);
diff --git a/lib/stream.h b/lib/stream.h
index 738034438c..1e2bc89b32 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -167,6 +167,8 @@ extern int stream_putc (struct stream *, u_char);
extern int stream_putc_at (struct stream *, size_t, u_char);
extern int stream_putw (struct stream *, u_int16_t);
extern int stream_putw_at (struct stream *, size_t, u_int16_t);
+extern int stream_put3 (struct stream *, u_int32_t);
+extern int stream_put3_at (struct stream *, size_t, u_int32_t);
extern int stream_putl (struct stream *, u_int32_t);
extern int stream_putl_at (struct stream *, size_t, u_int32_t);
extern int stream_putq (struct stream *, uint64_t);
@@ -186,12 +188,20 @@ extern u_char stream_getc (struct stream *);
extern u_char stream_getc_from (struct stream *, size_t);
extern u_int16_t stream_getw (struct stream *);
extern u_int16_t stream_getw_from (struct stream *, size_t);
+extern u_int32_t stream_get3 (struct stream *);
+extern u_int32_t stream_get3_from (struct stream *, size_t);
extern u_int32_t stream_getl (struct stream *);
extern u_int32_t stream_getl_from (struct stream *, size_t);
extern uint64_t stream_getq (struct stream *);
extern uint64_t stream_getq_from (struct stream *, size_t);
extern u_int32_t stream_get_ipv4 (struct stream *);
+/* IEEE-754 floats */
+extern float stream_getf (struct stream *);
+extern double stream_getd (struct stream *);
+extern int stream_putf (struct stream *, float);
+extern int stream_putd (struct stream *, double);
+
#undef stream_read
#undef stream_write
diff --git a/lib/thread.c b/lib/thread.c
index 8d75509b1d..a128786c3d 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -32,15 +32,6 @@
#include "command.h"
#include "sigevent.h"
-#if defined HAVE_SNMP && defined SNMP_AGENTX
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-#include <net-snmp/agent/snmp_vars.h>
-
-extern int agentx_enabled;
-#endif
-
#if defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_time.h>
@@ -48,12 +39,8 @@ extern int agentx_enabled;
/* Recent absolute time of day */
struct timeval recent_time;
-static struct timeval last_recent_time;
/* Relative time, since startup */
static struct timeval relative_time;
-static struct timeval relative_time_base;
-/* init flag */
-static unsigned short timers_inited;
static struct hash *cpu_record = NULL;
@@ -106,27 +93,6 @@ timeval_elapsed (struct timeval a, struct timeval b)
+ (a.tv_usec - b.tv_usec));
}
-#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
-static void
-quagga_gettimeofday_relative_adjust (void)
-{
- struct timeval diff;
- if (timeval_cmp (recent_time, last_recent_time) < 0)
- {
- relative_time.tv_sec++;
- relative_time.tv_usec = 0;
- }
- else
- {
- diff = timeval_subtract (recent_time, last_recent_time);
- relative_time.tv_sec += diff.tv_sec;
- relative_time.tv_usec += diff.tv_usec;
- relative_time = timeval_adjust (relative_time);
- }
- last_recent_time = recent_time;
-}
-#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
-
/* gettimeofday wrapper, to keep recent_time updated */
static int
quagga_gettimeofday (struct timeval *tv)
@@ -137,12 +103,6 @@ quagga_gettimeofday (struct timeval *tv)
if (!(ret = gettimeofday (&recent_time, NULL)))
{
- /* init... */
- if (!timers_inited)
- {
- relative_time_base = last_recent_time = recent_time;
- timers_inited = 1;
- }
/* avoid copy if user passed recent_time pointer.. */
if (tv != &recent_time)
*tv = recent_time;
@@ -182,8 +142,7 @@ quagga_get_relative (struct timeval *tv)
return 0;
}
#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
- if (!(ret = quagga_gettimeofday (&recent_time)))
- quagga_gettimeofday_relative_adjust();
+#error no monotonic clock on this system
#endif /* HAVE_CLOCK_MONOTONIC */
if (tv)
@@ -192,18 +151,6 @@ quagga_get_relative (struct timeval *tv)
return ret;
}
-/* Get absolute time stamp, but in terms of the internal timer
- * Could be wrong, but at least won't go back.
- */
-static void
-quagga_real_stabilised (struct timeval *tv)
-{
- *tv = relative_time_base;
- tv->tv_sec += relative_time.tv_sec;
- tv->tv_usec += relative_time.tv_usec;
- *tv = timeval_adjust (*tv);
-}
-
/* Exported Quagga timestamp function.
* Modelled on POSIX clock_gettime.
*/
@@ -212,29 +159,19 @@ quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
{
switch (clkid)
{
- case QUAGGA_CLK_REALTIME:
- return quagga_gettimeofday (tv);
case QUAGGA_CLK_MONOTONIC:
return quagga_get_relative (tv);
- case QUAGGA_CLK_REALTIME_STABILISED:
- quagga_real_stabilised (tv);
- return 0;
default:
errno = EINVAL;
return -1;
}
}
-/* time_t value in terms of stabilised absolute time.
- * replacement for POSIX time()
- */
time_t
-quagga_time (time_t *t)
+quagga_monotime (void)
{
struct timeval tv;
- quagga_real_stabilised (&tv);
- if (t)
- *t = tv.tv_sec;
+ quagga_get_relative(&tv);
return tv.tv_sec;
}
@@ -983,6 +920,17 @@ funcname_thread_add_timer_msec (struct thread_master *m,
arg, &trel, debugargpass);
}
+/* Add timer event thread with "millisecond" resolution */
+struct thread *
+funcname_thread_add_timer_tv (struct thread_master *m,
+ int (*func) (struct thread *),
+ void *arg, struct timeval *tv,
+ debugargdef)
+{
+ return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
+ arg, tv, debugargpass);
+}
+
/* Add a background thread, with an optional millisec delay */
struct thread *
funcname_thread_add_background (struct thread_master *m,
@@ -1343,12 +1291,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
while (1)
{
int num = 0;
-#if defined HAVE_SNMP && defined SNMP_AGENTX
- struct timeval snmp_timer_wait;
- int snmpblock = 0;
- int fdsetsize;
-#endif
-
+
/* Signals pre-empt everything */
quagga_sigevent_process ();
@@ -1384,35 +1327,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
(!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
timer_wait = timer_wait_bg;
}
-
-#if defined HAVE_SNMP && defined SNMP_AGENTX
- /* When SNMP is enabled, we may have to select() on additional
- FD. snmp_select_info() will add them to `readfd'. The trick
- with this function is its last argument. We need to set it to
- 0 if timer_wait is not NULL and we need to use the provided
- new timer only if it is still set to 0. */
- if (agentx_enabled)
- {
- fdsetsize = FD_SETSIZE;
- snmpblock = 1;
- if (timer_wait)
- {
- snmpblock = 0;
- memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
- }
-#if defined(HAVE_POLL)
- /* clear fdset since there are no other fds in fd_set,
- then add injected fds from snmp_select_info into pollset */
- FD_ZERO(&readfd);
-#endif
- snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
-#if defined(HAVE_POLL)
- add_snmp_pollfds(m, &readfd, fdsetsize);
-#endif
- if (snmpblock == 0)
- timer_wait = &snmp_timer_wait;
- }
-#endif
+
num = fd_select (m, FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
/* Signals should get quick treatment */
@@ -1424,30 +1339,6 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
return NULL;
}
-#if defined HAVE_SNMP && defined SNMP_AGENTX
-#if defined(HAVE_POLL)
- /* re-enter pollfds in fd_set for handling in snmp_read */
- FD_ZERO(&readfd);
- nfds_t i;
- for (i = m->handler.pfdcount; i < m->handler.pfdcountsnmp; ++i)
- {
- if (m->handler.pfds[i].revents == POLLIN)
- FD_SET(m->handler.pfds[i].fd, &readfd);
- }
-#endif
- if (agentx_enabled)
- {
- if (num > 0)
- snmp_read(&readfd);
- else if (num == 0)
- {
- snmp_timeout();
- run_alarms();
- }
- netsnmp_check_outstanding_agent_requests();
- }
-#endif
-
/* Check foreground timers. Historically, they have had higher
priority than I/O threads, so let's push them onto the ready
list in front of the I/O threads. */
diff --git a/lib/thread.h b/lib/thread.h
index 8b42ffe58a..c692142839 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -130,9 +130,7 @@ struct cpu_thread_history
/* Clocks supported by Quagga */
enum quagga_clkid {
- QUAGGA_CLK_REALTIME = 0, /* ala gettimeofday() */
- QUAGGA_CLK_MONOTONIC, /* monotonic, against an indeterminate base */
- QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */
+ QUAGGA_CLK_MONOTONIC = 1, /* monotonic, against an indeterminate base */
};
/* Struct timeval's tv_usec one second value. */
@@ -199,6 +197,7 @@ enum quagga_clkid {
#define thread_add_write(m,f,a,v) funcname_thread_add_read_write(THREAD_WRITE,m,f,a,v,#f,__FILE__,__LINE__)
#define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f,__FILE__,__LINE__)
#define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f,__FILE__,__LINE__)
+#define thread_add_timer_tv(m,f,a,v) funcname_thread_add_timer_tv(m,f,a,v,#f,__FILE__,__LINE__)
#define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f,__FILE__,__LINE__)
#define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f,__FILE__,__LINE__)
@@ -219,6 +218,10 @@ extern struct thread *funcname_thread_add_timer (struct thread_master *,
extern struct thread *funcname_thread_add_timer_msec (struct thread_master *,
int (*)(struct thread *),
void *, long, debugargdef);
+extern struct thread *funcname_thread_add_timer_tv (struct thread_master *,
+ int (*)(struct thread *),
+ void *, struct timeval *,
+ debugargdef);
extern struct thread *funcname_thread_add_event (struct thread_master *,
int (*)(struct thread *),
void *, int, debugargdef);
@@ -253,7 +256,7 @@ extern struct cmd_element clear_thread_cpu_cmd;
* all systems, and fully monotonic on /some/ systems.
*/
extern int quagga_gettime (enum quagga_clkid, struct timeval *);
-extern time_t quagga_time (time_t *);
+extern time_t quagga_monotime (void);
/* Returns elapsed real (wall clock) time. */
extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
diff --git a/lib/vty.h b/lib/vty.h
index 81251e07bb..599882a382 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -220,7 +220,7 @@ do { \
#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \
do { \
- unsigned long tmpl; \
+ unsigned long long tmpl; \
VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \
(V) = tmpl; \
} while (0)
diff --git a/lib/zclient.c b/lib/zclient.c
index ef9516c912..753954fd84 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -32,6 +32,7 @@
#include "zclient.h"
#include "memory.h"
#include "table.h"
+#include "nexthop.h"
/* Zebra client events. */
enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT};
@@ -709,6 +710,8 @@ zclient_connect (struct thread *t)
*
* If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value
*
+ * If ZAPI_MESSAGE_MTU is set, the mtu value is written as a 4 byte value
+ *
* XXX: No attention paid to alignment.
*/
int
@@ -744,7 +747,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
- stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+ stream_putc (s, NEXTHOP_TYPE_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
@@ -753,12 +756,12 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
for (i = 0; i < api->nexthop_num; i++)
{
- stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+ stream_putc (s, NEXTHOP_TYPE_IPV4);
stream_put_in_addr (s, api->nexthop[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
- stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+ stream_putc (s, NEXTHOP_TYPE_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
@@ -769,6 +772,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
+ stream_putl (s, api->mtu);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -809,7 +814,7 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
- stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+ stream_putc (s, NEXTHOP_TYPE_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
@@ -818,12 +823,12 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
for (i = 0; i < api->nexthop_num; i++)
{
- stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+ stream_putc (s, NEXTHOP_TYPE_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
}
for (i = 0; i < api->ifindex_num; i++)
{
- stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+ stream_putc (s, NEXTHOP_TYPE_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
@@ -834,6 +839,8 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
+ stream_putl (s, api->mtu);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -873,7 +880,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
- stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+ stream_putc (s, NEXTHOP_TYPE_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
@@ -882,12 +889,12 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
for (i = 0; i < api->nexthop_num; i++)
{
- stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+ stream_putc (s, NEXTHOP_TYPE_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
}
for (i = 0; i < api->ifindex_num; i++)
{
- stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+ stream_putc (s, NEXTHOP_TYPE_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
@@ -898,6 +905,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
+ stream_putl (s, api->mtu);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -951,8 +960,6 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid)
* ZEBRA_INTERFACE_DELETE from zebra to the client is:
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+
- * | type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ifname |
* | |
@@ -960,20 +967,32 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid)
* | |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | ifindex |
+ * | ifindex |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | status |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | if_flags |
+ * | if_flags |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | metric |
+ * | metric |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | ifmtu |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | ifmtu6 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | ifmtu |
+ * | Link Layer Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | ifmtu6 |
+ * | Harware Address Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | bandwidth |
+ * | Hardware Address if HW lenght different from 0 |
+ * | ... max INTERFACE_HWADDR_MAX |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | sockaddr_dl |
+ * | Link_params? | Whether a link-params follows: 1 or 0.
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Link_params 0 or 1 INTERFACE_LINK_PARAMS_SIZE sized |
+ * | .... (struct if_link_params). |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
@@ -1062,7 +1081,138 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id)
return ifp;
}
-/*
+static void
+link_params_set_value(struct stream *s, struct if_link_params *iflp)
+{
+
+ if (iflp == NULL)
+ return;
+
+ iflp->lp_status = stream_getl (s);
+ iflp->te_metric = stream_getl (s);
+ iflp->max_bw = stream_getf (s);
+ iflp->max_rsv_bw = stream_getf (s);
+ uint32_t bwclassnum = stream_getl (s);
+ {
+ unsigned int i;
+ for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++)
+ iflp->unrsv_bw[i] = stream_getf (s);
+ if (i < bwclassnum)
+ zlog_err ("%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
+ " - outdated library?",
+ __func__, bwclassnum, MAX_CLASS_TYPE);
+ }
+ iflp->admin_grp = stream_getl (s);
+ iflp->rmt_as = stream_getl (s);
+ iflp->rmt_ip.s_addr = stream_get_ipv4 (s);
+
+ iflp->av_delay = stream_getl (s);
+ iflp->min_delay = stream_getl (s);
+ iflp->max_delay = stream_getl (s);
+ iflp->delay_var = stream_getl (s);
+
+ iflp->pkt_loss = stream_getf (s);
+ iflp->res_bw = stream_getf (s);
+ iflp->ava_bw = stream_getf (s);
+ iflp->use_bw = stream_getf (s);
+}
+
+struct interface *
+zebra_interface_link_params_read (struct stream *s)
+{
+ struct if_link_params *iflp;
+ uint32_t ifindex = stream_getl (s);
+
+ struct interface *ifp = if_lookup_by_index (ifindex);
+
+ if (ifp == NULL || s == NULL)
+ {
+ zlog_err ("%s: unknown ifindex %u, shouldn't happen",
+ __func__, ifindex);
+ return NULL;
+ }
+
+ if ((iflp = if_link_params_get (ifp)) == NULL)
+ return NULL;
+
+ link_params_set_value(s, iflp);
+
+ return ifp;
+}
+
+void
+zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
+{
+ u_char link_params_status = 0;
+
+ /* Read interface's index. */
+ ifp->ifindex = stream_getl (s);
+ ifp->status = stream_getc (s);
+
+ /* Read interface's value. */
+ ifp->flags = stream_getq (s);
+ ifp->ptm_enable = stream_getc (s);
+ ifp->ptm_status = stream_getc (s);
+ ifp->metric = stream_getl (s);
+ ifp->mtu = stream_getl (s);
+ ifp->mtu6 = stream_getl (s);
+ ifp->bandwidth = stream_getl (s);
+ ifp->ll_type = stream_getl (s);
+ ifp->hw_addr_len = stream_getl (s);
+ if (ifp->hw_addr_len)
+ stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX));
+
+ /* Read Traffic Engineering status */
+ link_params_status = stream_getc (s);
+ /* Then, Traffic Engineering parameters if any */
+ if (link_params_status)
+ {
+ struct if_link_params *iflp = if_link_params_get (ifp);
+ link_params_set_value(s, iflp);
+ }
+}
+
+size_t
+zebra_interface_link_params_write (struct stream *s, struct interface *ifp)
+{
+ size_t w;
+ struct if_link_params *iflp;
+ int i;
+
+ if (s == NULL || ifp == NULL || ifp->link_params == NULL)
+ return 0;
+
+ iflp = ifp->link_params;
+ w = 0;
+
+ w += stream_putl (s, iflp->lp_status);
+
+ w += stream_putl (s, iflp->te_metric);
+ w += stream_putf (s, iflp->max_bw);
+ w += stream_putf (s, iflp->max_rsv_bw);
+
+ w += stream_putl (s, MAX_CLASS_TYPE);
+ for (i = 0; i < MAX_CLASS_TYPE; i++)
+ w += stream_putf (s, iflp->unrsv_bw[i]);
+
+ w += stream_putl (s, iflp->admin_grp);
+ w += stream_putl (s, iflp->rmt_as);
+ w += stream_put_in_addr (s, &iflp->rmt_ip);
+
+ w += stream_putl (s, iflp->av_delay);
+ w += stream_putl (s, iflp->min_delay);
+ w += stream_putl (s, iflp->max_delay);
+ w += stream_putl (s, iflp->delay_var);
+
+ w += stream_putf (s, iflp->pkt_loss);
+ w += stream_putf (s, iflp->res_bw);
+ w += stream_putf (s, iflp->ava_bw);
+ w += stream_putf (s, iflp->use_bw);
+
+ return w;
+}
+
+/*
* format of message for address additon is:
* 0
* 0 1 2 3 4 5 6 7
@@ -1091,33 +1241,8 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id)
* : :
* | |
* +-+-+-+-+-+-+-+-+
- *
*/
-void
-zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
-{
- /* Read interface's index. */
- ifp->ifindex = stream_getl (s);
- ifp->status = stream_getc (s);
-
- /* Read interface's value. */
- ifp->flags = stream_getq (s);
- ifp->ptm_enable = stream_getc (s);
- ifp->ptm_status = stream_getc (s);
- ifp->metric = stream_getl (s);
- ifp->mtu = stream_getl (s);
- ifp->mtu6 = stream_getl (s);
- ifp->bandwidth = stream_getl (s);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
- stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage));
-#else
- ifp->hw_addr_len = stream_getl (s);
- if (ifp->hw_addr_len)
- stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX));
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
-}
-
static int
memconstant(const void *s, int c, size_t n)
{
@@ -1133,7 +1258,7 @@ memconstant(const void *s, int c, size_t n)
struct connected *
zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
{
- unsigned int ifindex;
+ ifindex_t ifindex;
struct interface *ifp;
struct connected *ifc;
struct prefix p, d;
@@ -1503,6 +1628,9 @@ zclient_read (struct thread *thread)
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
if (zclient->redistribute_route_ipv6_del)
(*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id);
+ case ZEBRA_INTERFACE_LINK_PARAMS:
+ if (zclient->interface_link_params)
+ (*zclient->interface_link_params) (command, zclient, length);
break;
default:
break;
diff --git a/lib/zclient.h b/lib/zclient.h
index f30190c1b4..b95d18ec1a 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -93,6 +93,7 @@ struct zclient
int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*interface_link_params) (int, struct zclient *, uint16_t);
int (*interface_bfd_dest_update) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_nbr_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_nbr_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
@@ -116,6 +117,7 @@ struct zclient
#define ZAPI_MESSAGE_DISTANCE 0x04
#define ZAPI_MESSAGE_METRIC 0x08
#define ZAPI_MESSAGE_TAG 0x10
+#define ZAPI_MESSAGE_MTU 0x20
/* Zserv protocol message header */
struct zserv_header
@@ -146,7 +148,7 @@ struct zapi_ipv4
struct in_addr **nexthop;
u_char ifindex_num;
- unsigned int *ifindex;
+ ifindex_t *ifindex;
u_char distance;
@@ -154,6 +156,8 @@ struct zapi_ipv4
u_short tag;
+ u_int32_t mtu;
+
vrf_id_t vrf_id;
};
@@ -211,6 +215,9 @@ extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid);
extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
struct zapi_ipv4 *);
+extern struct interface *zebra_interface_link_params_read (struct stream *);
+extern size_t zebra_interface_link_params_write (struct stream *,
+ struct interface *);
#ifdef HAVE_IPV6
/* IPv6 prefix add and delete function prototype. */
@@ -229,7 +236,7 @@ struct zapi_ipv6
struct in6_addr **nexthop;
u_char ifindex_num;
- unsigned int *ifindex;
+ ifindex_t *ifindex;
u_char distance;
@@ -237,6 +244,8 @@ struct zapi_ipv6
u_short tag;
+ u_int32_t mtu;
+
vrf_id_t vrf_id;
};
diff --git a/lib/zebra.h b/lib/zebra.h
index 59c154ba46..fdfd471825 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -445,7 +445,8 @@ struct in_pktinfo
#define ZEBRA_INTERFACE_ENABLE_RADV 47
#define ZEBRA_INTERFACE_DISABLE_RADV 48
#define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 49
-#define ZEBRA_MESSAGE_MAX 50
+#define ZEBRA_INTERFACE_LINK_PARAMS 50
+#define ZEBRA_MESSAGE_MAX 51
/* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new
@@ -489,20 +490,10 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_BLACKHOLE 0x04
#define ZEBRA_FLAG_IBGP 0x08
#define ZEBRA_FLAG_SELECTED 0x10
-#define ZEBRA_FLAG_CHANGED 0x20
#define ZEBRA_FLAG_STATIC 0x40
#define ZEBRA_FLAG_REJECT 0x80
#define ZEBRA_FLAG_SCOPE_LINK 0x100
-/* Zebra nexthop flags. */
-#define ZEBRA_NEXTHOP_IFINDEX 1
-#define ZEBRA_NEXTHOP_IPV4 2
-#define ZEBRA_NEXTHOP_IPV4_IFINDEX 3
-#define ZEBRA_NEXTHOP_IPV6 4
-#define ZEBRA_NEXTHOP_IPV6_IFINDEX 5
-#define ZEBRA_NEXTHOP_BLACKHOLE 6
-#define ZEBRA_NEXTHOP_IPV4_ONLINK 7
-
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
#endif
@@ -511,7 +502,8 @@ extern const char *zserv_command_string (unsigned int command);
typedef enum {
AFI_IP = 1,
AFI_IP6 = 2,
-#define AFI_MAX 3
+ AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */
+ AFI_MAX = 4
} afi_t;
/* Subsequent Address Family Identifier. */
@@ -522,11 +514,6 @@ typedef enum {
#define SAFI_ENCAP 7 /* per IANA */
#define SAFI_MAX 8
-/* Filter direction. */
-#define FILTER_IN 0
-#define FILTER_OUT 1
-#define FILTER_MAX 2
-
/* Default Administrative Distance of each protocol. */
#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0
#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0