[DHCP Relay]: Support Multiple VLANs (Separate DHCP Relay Agents, One Per VLAN) (#999)

* [DHCP Relay]: Support new <DhcpRelays> minigraph tag; support multiple VLANs

* Don't start dhcrelay in quiet mode so as to get startup output in syslog

* Update sonic-cfggen tests to support new '<DhcpRelays>' tag

* <DhcpRelays> tag is only present for VLANs which require a DHCP relay agent -- only parse if present

* Don't attempt to configure a DHCP relay agent for VLANs without specified DHCP servers

* Modify to work with Taoyu's minigraph/DB changes (#942)

* Reduce number of DHCP servers in sonic-cfggen unit tests from 4 to 2

* Remove isc-dhcp-relay sample output file from sonic-cfggen test, as we no longer generate that file

* Update Option 82 isc-dhcp-relay patch to load all interface name-alias maps into memory once at start instead of calling sonic-cfggen on each packet we relay

* Remove executable permission from Jinja2 template

* Set max hop count to 1 so that DHCP relay will only relay packets with a hop count of zero

* Replace tabs with spaces

* Modify overlooked sonic-cfggen call, use Config DB instead of minigraph

* Also ensure > 1 VLAN requires a DHCP relay agent before outputting to template

* Generate port name-alias map file using sonic-cfggen and parse that in lieu of parsing port_config.ini directly

* No longer drop packets with hop count > 0; Instead, drop packets which already contain agent info
This commit is contained in:
Joe LeVeque 2017-10-04 23:35:43 -07:00 committed by lguohan
parent 1cd9818fe9
commit 1d16a37d48
17 changed files with 307 additions and 143 deletions

View File

@ -22,9 +22,7 @@ RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return
RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y
RUN rm -rf /debs
COPY ["start.sh", "isc-dhcp-relay.sh", "/usr/bin/"]
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
COPY ["isc-dhcp-relay.j2", "/usr/share/sonic/templates/"]
COPY ["wait_for_intf.sh.j2", "/usr/share/sonic/templates/"]
COPY ["docker_init.sh", "start.sh", "/usr/bin/"]
COPY ["docker-dhcp-relay.supervisord.conf.j2", "wait_for_intf.sh.j2", "/usr/share/sonic/templates/"]
ENTRYPOINT ["/usr/bin/supervisord"]
ENTRYPOINT ["/usr/bin/docker_init.sh"]

View File

@ -0,0 +1,67 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true
[program:start.sh]
command=/usr/bin/start.sh
priority=1
autostart=true
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:rsyslogd]
command=/usr/sbin/rsyslogd -n
priority=2
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
{# If our configuration has VLANs... #}
{% if VLAN %}
{# Count how many VLANs require a DHCP relay agent... #}
{% set num_relays = { 'count': 0 } %}
{% for vlan_name in VLAN %}
{% if VLAN[vlan_name]['dhcp_servers'] %}
{% set _dummy = num_relays.update({'count': num_relays.count + 1}) %}
{% endif %}
{% endfor %}
{# If one or more of the VLANs require a DHCP relay agent... #}
{% if num_relays.count > 0 %}
[group:isc-dhcp-relay]
programs=
{%- set add_preceding_comma = { 'flag': False } -%}
{%- for vlan_name in VLAN -%}
{%- if VLAN[vlan_name]['dhcp_servers'] -%}
{%- if add_preceding_comma.flag %},{% endif -%}
{%- set _dummy = add_preceding_comma.update({'flag': True}) -%}
isc-dhcp-relay-{{ vlan_name }}
{%- endif %}
{% endfor %}
{# Create a program entry for each DHCP relay agent instance #}
{% for vlan_name in VLAN -%}
{%- if VLAN[vlan_name]['dhcp_servers'] -%}
[program:isc-dhcp-relay-{{ vlan_name }}]
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -i {{ vlan_name }}
{%- for (name, prefix) in INTERFACE -%}
{%- if prefix | ipv4 %} -i {{ name }}{% endif -%}
{%- endfor -%}
{%- for (name, prefix) in PORTCHANNEL_INTERFACE -%}
{%- if prefix | ipv4 %} -i {{ name }}{% endif -%}
{%- endfor -%}
{%- for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %}
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
{% endif %}
{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Generate supervisord config file
mkdir -p /etc/supervisor/conf.d/
sonic-cfggen -d -t /usr/share/sonic/templates/docker-dhcp-relay.supervisord.conf.j2 > /etc/supervisor/conf.d/docker-dhcp-relay.supervisord.conf
# Generate the script that waits for all interfaces to come up and make it executable
sonic-cfggen -d -t /usr/share/sonic/templates/wait_for_intf.sh.j2 > /usr/bin/wait_for_intf.sh
chmod +x /usr/bin/wait_for_intf.sh
# Generate port name-alias map for isc-dhcp-relay to parse. Each line contains one
# name-alias pair of the form "<name> <alias>"
sonic-cfggen -d --var-json "PORT" | python -c "import sys, json, os; [sys.stdout.write('%s %s\n' % (k, v['alias'] if 'alias' in v else k)) for (k, v) in json.load(sys.stdin).iteritems()]" > /tmp/port-name-alias-map.txt
# The docker container should start this script as PID 1, so now that supervisord is
# properly configured, we exec supervisord so that it runs as PID 1 for the
# duration of the container's lifetime
exec /usr/bin/supervisord

View File

@ -1,28 +0,0 @@
SERVERS="{{ DHCP_SERVER | join(' ') }}"
INTERFACES="
{%- set add_preceding_space = { 'flag': False } %}
{%- for (name, prefix) in INTERFACE %}
{%- if prefix | ipv4 %}
{%- if add_preceding_space.flag %} {% endif %}
{{ name }}
{%- set _dummy = add_preceding_space.update({'flag': True}) %}
{%- endif %}
{%- endfor %}
{%- for (name, prefix) in VLAN_INTERFACE %}
{%- if prefix | ipv4 %}
{%- if add_preceding_space.flag %} {% endif %}
{{ name }}
{%- set _dummy = add_preceding_space.update({'flag': True}) %}
{%- endif %}
{%- endfor %}
{%- for (name, prefix) in PORTCHANNEL_INTERFACE %}
{%- if prefix | ipv4 %}
{%- if add_preceding_space.flag %} {% endif %}
{{ name }}
{%- set _dummy = add_preceding_space.update({'flag': True}) %}
{%- endif %}
{%- endfor %}"
# '-a' option provides option 82 circuit_id and remote_id information
OPTIONS="-a %h:%p %P"

View File

@ -1,18 +0,0 @@
#!/usr/bin/env bash
#
# Based off /etc/init.d/isc-dhcp-relay
#
# Read init script configuration (interfaces the daemon should listen on
# and the DHCP server we should forward requests to.)
[ -f /etc/default/isc-dhcp-relay ] && . /etc/default/isc-dhcp-relay
# Build command line for interfaces (will be passed to dhrelay below.)
IFCMD=""
if test "$INTERFACES" != ""; then
for I in $INTERFACES; do
IFCMD=${IFCMD}"-i "${I}" "
done
fi
exec /usr/sbin/dhcrelay -d -q ${OPTIONS} ${IFCMD} ${SERVERS}

View File

@ -1,16 +1,13 @@
#!/usr/bin/env bash
# Create isc-dhcp-relay config file
sonic-cfggen -d -t /usr/share/sonic/templates/isc-dhcp-relay.j2 > /etc/default/isc-dhcp-relay
# Remove stale rsyslog PID file if it exists
rm -f /var/run/rsyslogd.pid
# Start rsyslog
supervisorctl start rsyslogd
# Wait for all interfaces to come up before starting the DHCP relay
sonic-cfggen -d -t /usr/share/sonic/templates/wait_for_intf.sh.j2 > /usr/bin/wait_for_intf.sh
chmod +x /usr/bin/wait_for_intf.sh
# Wait for all interfaces to come up before starting the DHCP relay agent(s)
/usr/bin/wait_for_intf.sh
# Start the DHCP relay
supervisorctl start isc-dhcp-relay
# Start the DHCP relay agent(s)
supervisorctl start isc-dhcp-relay:*

View File

@ -1,28 +0,0 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true
[program:start.sh]
command=/usr/bin/start.sh
priority=1
autostart=true
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:rsyslogd]
command=/usr/sbin/rsyslogd -n
priority=2
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:isc-dhcp-relay]
command=/usr/bin/isc-dhcp-relay.sh
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

1
dockers/docker-dhcp-relay/wait_for_intf.sh.j2 Executable file → Normal file
View File

@ -25,4 +25,3 @@ wait_until_iface_exists {{ name }}
{% for (name, prefix) in PORTCHANNEL_INTERFACE %}
wait_until_iface_exists {{ name }}
{% endfor %}

View File

@ -1,10 +1,10 @@
This patch adds the following functionality to dhcrelay in isc-dhcp v4.3.1-6:
* Add customizable Circuit ID and Remote ID fields
* Support for obtaining name of physical interface of interfaces that are part of a bridge interface
* Support for obtaining name of physical interfaces that are part of a bridge interface
diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
--- a/isc-dhcp/relay/dhcrelay.c 2014-08-06 22:35:02.000000000 +0000
+++ b/isc-dhcp/relay/dhcrelay.c 2017-06-08 21:39:53.856192546 +0000
--- a/isc-dhcp/relay/dhcrelay.c 2017-10-03 01:46:19.811524700 +0000
+++ b/isc-dhcp/relay/dhcrelay.c 2017-10-03 01:45:50.699524700 +0000
@@ -73,6 +73,8 @@
did not match any known circuit ID. */
int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
@ -14,7 +14,33 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
int max_hop_count = 10; /* Maximum hop count */
#ifdef DHCPv6
@@ -140,9 +142,19 @@
@@ -120,6 +122,14 @@
char *dhcrelay_sub_id = NULL;
#endif
+struct interface_name_alias_tuple {
+ char if_name[IFNAMSIZ + 1];
+ char if_alias[IFNAMSIZ + 1];
+};
+
+static struct interface_name_alias_tuple *g_interface_name_alias_map = NULL;
+static size_t g_interface_name_alias_map_size = 0;
+
static void do_relay4(struct interface_info *, struct dhcp_packet *,
unsigned int, unsigned int, struct iaddr,
struct hardware *);
@@ -132,6 +142,10 @@
struct interface_info **,
struct dhcp_packet *, unsigned);
+static int load_interface_alias_map(const char *port_alias_map_file_path);
+static int get_interface_alias_by_name(const char *if_name, char *if_alias_out);
+static void free_interface_alias_map(void);
+
static const char copyright[] =
"Copyright 2004-2014 Internet Systems Consortium.";
static const char arr[] = "All rights reserved.";
@@ -140,28 +154,42 @@
static const char url[] =
"For info, please visit https://www.isc.org/software/dhcp/";
@ -23,7 +49,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+"\n" \
+" %%%% A single %%\n" \
+" %%h Hostname of device\n" \
+" %%p Name of interface that generated the request\n" \
+" %%p Alias of interface that generated the request\n" \
+" %%P Hardware address of interface that generated the request\n" \
+" %%C Client hardware address\n" \
+" %%I DHCP relay agent IP Address\n" \
@ -35,7 +61,13 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
" [-A <length>] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
@@ -154,14 +166,15 @@
+" [--name-alias-map-file <name-alias-map-file>]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" server0 [ ... serverN]\n\n" \
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\n" \
" [-s <subscriber-id>]\n" \
" -l lower0 [ ... -l lowerN]\n" \
" -u upper0 [ ... -u upperN]\n" \
" lower (client link): [address%%]interface[#index]\n" \
@ -49,13 +81,14 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+" [-A <length>] [-c <hops>] [-p <port>]\n" \
+" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
-" server0 [ ... serverN]\n\n"
+" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
#endif
static void usage() {
@@ -287,6 +300,15 @@
@@ -287,6 +315,15 @@
local_family_set = 1;
local_family = AF_INET;
#endif
@ -71,7 +104,59 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
add_agent_options = 1;
} else if (!strcmp(argv[i], "-A")) {
#ifdef DHCPv6
@@ -937,6 +959,166 @@
@@ -383,6 +420,13 @@
no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--no-pid")) {
no_pid_file = ISC_TRUE;
+ } else if (!strcmp(argv[i], "--name-alias-map-file")) {
+ if (++i == argc)
+ usage();
+ if (load_interface_alias_map(argv[i]) != 0)
+ log_fatal("Failed to load interface name-alias map.");
+ path_dhcrelay_pid = argv[i];
+ no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--version")) {
log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
exit(0);
@@ -602,6 +646,8 @@
dispatch();
/* In fact dispatch() never returns. */
+ free_interface_alias_map();
+
return (0);
}
@@ -690,10 +736,9 @@
&to, htop) < 0) {
++server_packet_errors;
} else {
- log_debug("Forwarded BOOTREPLY for %s to %s",
- print_hw_addr(packet->htype, packet->hlen,
- packet->chaddr),
- inet_ntoa(to.sin_addr));
+ //log_debug("Forwarded BOOTREPLY for %s to %s",
+ // print_hw_addr(packet->htype, packet->hlen, packet->chaddr),
+ // inet_ntoa(to.sin_addr));
++server_packets_relayed;
}
@@ -732,10 +777,10 @@
&sp->to, NULL) < 0) {
++client_packet_errors;
} else {
- log_debug("Forwarded BOOTREQUEST for %s to %s",
- print_hw_addr(packet->htype, packet->hlen,
- packet->chaddr),
- inet_ntoa(sp->to.sin_addr));
+ //log_debug("Forwarded BOOTREQUEST for %s to %s",
+ // print_hw_addr(packet->htype, packet->hlen, packet->chaddr),
+ // inet_ntoa(sp->to.sin_addr));
+
++client_packets_relayed;
}
}
@@ -937,6 +982,152 @@
return (-1);
}
@ -106,9 +191,8 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+ if (cmd != NULL) {
+ while (fgets(buf, sizeof(buf), cmd)) {
+ sscanf(buf, FDB_LINE_FORMAT, macAddr, interface, vlanid);
+ log_debug ("bridgefdbquery: macAddr:%s interface: %s vlanid %d",
+ macAddr,
+ interface, *vlanid);
+ //log_debug("bridgefdbquery: macAddr:%s interface: %s vlanid %d",
+ // macAddr, interface, *vlanid);
+ }
+ pclose(cmd);
+ return 0;
@ -149,7 +233,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+
+ case 'p': /* Name of interface that we received the request from */
+ /*
+ * Query FDB to identify the exact physical interface only when source MAC address
+ * Query FDB to identify the exact physical interface only when source MAC address
+ * is present and '20: DHCP relay agent IP address' (giaddr) is not present
+ */
+ if (packet->htype && !packet->giaddr.s_addr) {
@ -160,42 +244,29 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+ &vlanid);
+
+ if (ret < 0) {
+ log_debug("MAC Address: %s (interface:%s vlan:%d) not found in bridge fdb show",
+ print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ ip->name,
+ vlanid);
+ //log_debug("MAC Address: %s (interface:%s vlan:%d) not found in bridge fdb show",
+ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ // ip->name,
+ // vlanid);
+
+ strncpy(ifname, ip->name, IFNAMSIZ);
+ }
+ else if (strlen(ip->name) > 0) {
+ char cmdstr[256] = { 0 };
+ char cmdout[256] = { 0 };
+
+ log_debug("Adding option 82 interface name for MAC Address: %s as %s",
+ print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ ip->name);
+
+ // Translate SONiC interface name to vendor alias
+ sprintf(cmdstr, "sonic-cfggen -m /etc/sonic/minigraph.xml -v \"minigraph_ports['%s'].alias\"", ip->name);
+
+ FILE *cmd = popen(cmdstr, "r");
+
+ if (cmd != NULL) {
+ while (fgets(cmdout, sizeof(cmdout), cmd)) {
+ // Strip any trailing newline
+ if (cmdout[strlen(cmdout) - 1] == '\n')
+ cmdout[strlen(cmdout) - 1] = '\0';
+
+ log_debug ("Retrieved alias %s for interface %s", buf, ip->name);
+ // Translate SONiC interface name to vendor alias
+ if (get_interface_alias_by_name(ip->name, ifname) < 0) {
+ log_error("Failed to retrieve alias for interface name '%s'. Defaulting to interface name.", ip->name);
+ strncpy(ifname, ip->name, IFNAMSIZ);
+ }
+
+ pclose(cmd);
+ //log_debug("Mapped interface name '%s' to alias '%s'", ip->name, ifname);
+
+ //log_debug("Adding option 82 interface alias for MAC Address %s as '%s'",
+ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ // ifname);
+ }
+
+ strncpy(ifname, cmdout, IFNAMSIZ);
+ str = ifname;
+ }
+
+ str = ifname;
+ }
+ break;
+
+ case 'P': /* Physical address of interface that we received the request from */
@ -238,7 +309,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
/*
* Examine a packet to see if it's a candidate to have a Relay
* Agent Information option tacked onto its tail. If it is, tack
@@ -948,6 +1130,8 @@
@@ -948,6 +1139,8 @@
int is_dhcp = 0, mms;
unsigned optlen;
u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
@ -247,7 +318,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
/* If we're not adding agent options to packets, we can skip
this. */
@@ -1077,6 +1261,38 @@
@@ -1077,6 +1270,38 @@
op = sp;
#endif
@ -262,8 +333,8 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+ ip->circuit_id = (uint8_t *)circuit_id_buf;
+ ip->circuit_id_len = len;
+
+ log_debug("sending on %s option82:circuit_id='%s'(%d)",
+ ip->name, (char *)ip->circuit_id, ip->circuit_id_len);
+ //log_debug("Sending on %s option82:circuit_id='%s' (%d)",
+ // ip->name, (char *)ip->circuit_id, ip->circuit_id_len);
+ }
+ }
+
@ -278,12 +349,94 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
+ ip->remote_id = (uint8_t *)remote_id_buf;
+ ip->remote_id_len = len;
+
+ log_debug("sending on %s option82:remote_id='%s'(%d)",
+ ip->name, (char *)ip->remote_id, ip->remote_id_len);
+ //log_debug("Sending on %s option82:remote_id='%s' (%d)",
+ // ip->name, (char *)ip->remote_id, ip->remote_id_len);
+ }
+ }
+
/* Sanity check. Had better not ever happen. */
if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
log_fatal("Circuit ID length %d out of range [1-255] on "
@@ -1102,7 +1327,7 @@
* If not, forward without adding the option.
*/
if (max - sp >= optlen + 3) {
- log_debug("Adding %d-byte relay agent option", optlen + 3);
+ //log_debug("Adding %d-byte relay agent option", optlen + 3);
/* Okay, cons up *our* Relay Agent Information option. */
*sp++ = DHO_DHCP_AGENT_OPTIONS;
@@ -1726,3 +1951,73 @@
exit(0);
}
+
+#define MAX_PORT_CONFIG_LINE_LEN 1024
+
+// Allocates and loads global map g_interface_name_alias_map
+// Also sets global g_interface_name_alias_map_size
+static int
+load_interface_alias_map(const char *port_alias_map_file_path) {
+ int i = 0;
+ FILE *fp = NULL;
+ char line[MAX_PORT_CONFIG_LINE_LEN] = { 0 };
+
+ fp = fopen(port_alias_map_file_path,"r");
+ if (fp == NULL) {
+ log_error("Unable to open %s", port_alias_map_file_path);
+ return -1;
+ }
+
+ g_interface_name_alias_map_size = 0;
+
+ // Count the number of interfaces listed in the file
+ while (fgets(line, sizeof(line), fp)) {
+ g_interface_name_alias_map_size++;
+ }
+
+ // Allocate our map accordingly
+ g_interface_name_alias_map = ((struct interface_name_alias_tuple *)
+ dmalloc((sizeof(struct interface_name_alias_tuple) * g_interface_name_alias_map_size),
+ MDL));
+
+ // Reset file position indicator to beginning of file
+ fseek(fp, 0, SEEK_SET);
+
+ // Every line should contain exactly one name-alias pair
+ while (fgets(line, sizeof(line), fp)) {
+ // Each line should read as "<name><whitespace><alias>"
+ sscanf(line, "%s %s", g_interface_name_alias_map[i].if_name, g_interface_name_alias_map[i].if_alias);
+ i++;
+ }
+
+ fclose(fp);
+
+ log_info("Loaded %d interface name-alias mappings", i);
+
+ return 0;
+}
+
+// Locates alias for port named if_name, copies alias into if_alias_out, up to a
+// max of IFNAMSIZ bytes.
+// Returns 0 on success, -1 on failure
+static int
+get_interface_alias_by_name(const char *if_name, char *if_alias_out) {
+ int i = 0;
+
+ for (i = 0; i < g_interface_name_alias_map_size; i++) {
+ if (strncmp(if_name, g_interface_name_alias_map[i].if_name, IFNAMSIZ) == 0) {
+ strncpy(if_alias_out, g_interface_name_alias_map[i].if_alias, IFNAMSIZ);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+// Frees global map g_interface_name_alias_map
+// Sets g_interface_name_alias_map_size to 0
+static void
+free_interface_alias_map(void) {
+ free(g_interface_name_alias_map);
+ g_interface_name_alias_map_size = 0;
+}

View File

@ -175,6 +175,14 @@ def parse_dpg(dpg, hname):
for i, member in enumerate(vmbr_list):
vmbr_list[i] = port_alias_map.get(member, member)
vlan_attributes = {'members': vmbr_list, 'vlanid': vlanid}
# If this VLAN requires a DHCP relay agent, it will contain a <DhcpRelays> element
# containing a list of DHCP server IPs
if vintf.find(str(QName(ns, "DhcpRelays"))) is not None:
vintfdhcpservers = vintf.find(str(QName(ns, "DhcpRelays"))).text
vdhcpserver_list = vintfdhcpservers.split(';')
vlan_attributes['dhcp_servers'] = vdhcpserver_list
sonic_vlan_name = "Vlan%s" % vlanid
vlans[sonic_vlan_name] = vlan_attributes

View File

@ -108,6 +108,7 @@
<NoDhcpRelay>False</NoDhcpRelay>
<StaticDHCPRelay>0.0.0.0/0</StaticDHCPRelay>
<Type i:nil="true"/>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1000</VlanID>
<Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets>

View File

@ -1,7 +0,0 @@
SERVERS="192.0.0.1 192.0.0.2 192.0.0.3 192.0.0.4 192.0.0.5 192.0.0.6 192.0.0.7 192.0.0.8 192.0.0.9 192.0.0.10 192.0.0.11 192.0.0.12 192.0.0.13 192.0.0.14 192.0.0.15 192.0.0.16 192.0.0.17 192.0.0.18 192.0.0.19 192.0.0.20 192.0.0.21 192.0.0.22 192.0.0.23 192.0.0.24 192.0.0.25 192.0.0.26 192.0.0.27 192.0.0.28 192.0.0.29 192.0.0.30 192.0.0.31 192.0.0.32 192.0.0.33 192.0.0.34 192.0.0.35 192.0.0.36 192.0.0.37 192.0.0.38 192.0.0.39 192.0.0.40 192.0.0.41 192.0.0.42 192.0.0.43 192.0.0.44 192.0.0.45 192.0.0.46 192.0.0.47 192.0.0.48"
INTERFACES="Vlan1000 PortChannel01 PortChannel02 PortChannel03 PortChannel04"
# '-a' option provides option 82 circuit id information
OPTIONS="-a"

View File

@ -130,6 +130,7 @@
<VlanInterface>
<Name>Vlan1000</Name>
<AttachTo>fortyGigE0/8</AttachTo>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1000</VlanID>
<Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets>

View File

@ -203,6 +203,7 @@
<NoDhcpRelay>False</NoDhcpRelay>
<StaticDHCPRelay>0.0.0.0/0</StaticDHCPRelay>
<Type i:nil="true"/>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1000</VlanID>
<Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets>

View File

@ -198,6 +198,7 @@
<NoDhcpRelay>False</NoDhcpRelay>
<StaticDHCPRelay>0.0.0.0/0</StaticDHCPRelay>
<Type i:nil="true"/>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1000</VlanID>
<Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets>

View File

@ -206,6 +206,7 @@
<NoDhcpRelay>False</NoDhcpRelay>
<StaticDHCPRelay>0.0.0.0/0</StaticDHCPRelay>
<Type i:nil="true"/>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1000</VlanID>
<Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets>

View File

@ -83,7 +83,7 @@ class TestCfgGen(TestCase):
def test_minigraph_vlans(self):
argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN'
output = self.run_script(argument)
self.assertEqual(output.strip(), "{'Vlan1000': {'members': ['Ethernet8'], 'vlanid': '1000'}}")
self.assertEqual(output.strip(), "{'Vlan1000': {'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'members': ['Ethernet8'], 'vlanid': '1000'}}")
def test_minigraph_vlan_interfaces(self):
argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VLAN_INTERFACE.keys()"'