From 2006038b647bc3f34bb0ff5bf30d8340374decfa Mon Sep 17 00:00:00 2001 From: Chris Riley Date: Tue, 27 Oct 2015 16:09:23 -0400 Subject: =?latin1?q?Added=20support=20for=20static=20and=20virtual=20ip=20ru?= =?latin1?q?les=20for=20use=20with=20policy=20based=20routing=0A(cherry=20pi?= =?latin1?q?cked=20from=20commit=20cc951659f1208c7e94b910e6347d4fe30433ea81)?= --- doc/KEEPALIVED-MIB | 99 +++++++++++++- doc/man/man5/keepalived.conf.5 | 21 ++- doc/samples/keepalived.conf.vrrp.rules | 26 ++++ keepalived/include/vrrp.h | 2 + keepalived/include/vrrp_data.h | 3 + keepalived/include/vrrp_iprule.h | 63 +++++++++ keepalived/include/vrrp_print.h | 1 + keepalived/include/vrrp_snmp.h | 8 ++ keepalived/vrrp/Makefile.in | 8 +- keepalived/vrrp/vrrp.c | 35 ++++- keepalived/vrrp/vrrp_daemon.c | 8 +- keepalived/vrrp/vrrp_data.c | 29 ++++ keepalived/vrrp/vrrp_iprule.c | 235 +++++++++++++++++++++++++++++++++ keepalived/vrrp/vrrp_parser.c | 14 ++ keepalived/vrrp/vrrp_print.c | 32 +++++ keepalived/vrrp/vrrp_snmp.c | 102 ++++++++++++-- 16 files changed, 664 insertions(+), 22 deletions(-) create mode 100644 doc/samples/keepalived.conf.vrrp.rules create mode 100644 keepalived/include/vrrp_iprule.h create mode 100644 keepalived/vrrp/vrrp_iprule.c diff --git a/doc/KEEPALIVED-MIB b/doc/KEEPALIVED-MIB index 13137ac..1e32000 100644 --- a/doc/KEEPALIVED-MIB +++ b/doc/KEEPALIVED-MIB @@ -959,6 +959,93 @@ vrrpRouteStatus OBJECT-TYPE "Is this route set in the kernel?" ::= { vrrpRouteEntry 14 } +-- Rules +-- see vrrp_iprule.h + +vrrpRuleTable OBJECT-TYPE + SYNTAX SEQUENCE OF VrrpRuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table of static and virtual rules." + ::= { vrrp 8 } + +vrrpRuleEntry OBJECT-TYPE + SYNTAX VrrpRuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing a rule. In case of a static rule, + the instance index is 0." + INDEX { vrrpInstanceIndex, vrrpRuleIndex } + ::= { vrrpRuleTable 1 } + +VrrpRuleEntry ::= SEQUENCE { + vrrpRuleIndex Integer32, + vrrpRuleDirection DisplayString, + vrrpRuleAddressType InetAddressType, + vrrpRuleAddress InetAddress, + vrrpRuleAddressMask InetAddressPrefixLength, + vrrpRuleRoutingTable Unsigned32, + vrrpRuleStatus INTEGER +} + +vrrpRuleIndex OBJECT-TYPE + SYNTAX Integer32 (1..2147483647) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Rule index." + ::= { vrrpRuleEntry 1 } + +vrrpRuleDirection OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Traffic direction for this rule." + ::= { vrrpRuleEntry 2 } + +vrrpRuleAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Rule type of internet address." + ::= { vrrpRuleEntry 3 } + +vrrpRuleAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Rule network address." + ::= { vrrpRuleEntry 4 } + +vrrpRuleAddressMask OBJECT-TYPE + SYNTAX InetAddressPrefixLength + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Rule network mask." + ::= { vrrpRuleEntry 5 } + +vrrpRuleRoutingTable OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Routing table where the rule should be inserted." + ::= { vrrpRuleEntry 6 } + +vrrpRuleStatus OBJECT-TYPE + SYNTAX INTEGER { set(1), unset(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Is this rule set in the kernel?" + ::= { vrrpRuleEntry 7 } + -- VRRP scripts -- see vrrp_track.h @@ -968,7 +1055,7 @@ vrrpScriptTable OBJECT-TYPE STATUS current DESCRIPTION "Table of VRRP scripts" - ::= { vrrp 8 } + ::= { vrrp 9 } vrrpScriptEntry OBJECT-TYPE SYNTAX VrrpScriptEntry @@ -1063,7 +1150,7 @@ vrrpScriptFall OBJECT-TYPE -- Traps -vrrpTrap OBJECT IDENTIFIER ::= { vrrp 9 } +vrrpTrap OBJECT IDENTIFIER ::= { vrrp 10 } vrrpTraps OBJECT IDENTIFIER ::= { vrrpTrap 0 } -- Reverse-mappable vrrpTrapControl OBJECT IDENTIFIER ::= { vrrpTrap 1 } @@ -2088,7 +2175,13 @@ vrrpInstanceGroup OBJECT-GROUP vrrpRouteIfIndex, vrrpRouteIfName, vrrpRouteRoutingTable, - vrrpRouteStatus + vrrpRouteStatus, + vrrpRuleDirection, + vrrpRuleAddressType, + vrrpRuleAddress, + vrrpRuleAddressMask, + vrrpRuleRoutingTable, + vrrpRuleStatus } STATUS current DESCRIPTION diff --git a/doc/man/man5/keepalived.conf.5 b/doc/man/man5/keepalived.conf.5 index e4511b2..82bc353 100644 --- a/doc/man/man5/keepalived.conf.5 +++ b/doc/man/man5/keepalived.conf.5 @@ -21,9 +21,10 @@ anywhere in a line. .PP .SH GLOBAL CONFIGURATION contains subblocks of -.B Global definitions +.B Global definitions, +.B Static routes, and -.B Static routes +.B Static rules .PP .SH Global definitions .PP @@ -46,9 +47,9 @@ and } -.SH Static routes/addresses +.SH Static routes/addresses/rules .PP -keepalived can configure static addresses and routes. These addresses are +keepalived can configure static addresses, routes, and rules. These addresses are .B NOT moved by vrrpd, they stay on the machine. If you already have IPs and routes on your machines and @@ -68,6 +69,13 @@ The syntax is the same as for virtual addresses and virtual routes. ... } .PP + static_rules + { + from 192.168.2.0/24 table 1 + to 192.168.2.0/24 table 1 + ... + } +.PP .SH VRRPD CONFIGURATION contains subblocks of .B VRRP synchronization group(s) @@ -229,6 +237,11 @@ which will transition together on any state change. 192.168.113.0/24 via 192.168.200.254 or 192.168.100.254 dev eth1 blackhole 192.168.114.0/24 } + # rules add|del when changing to MASTER, to BACKUP + static_rules { + from 192.168.2.0/24 table 1 + to 192.168.2.0/24 table 1 + } # VRRP will normally preempt a lower priority # machine when a higher priority machine comes diff --git a/doc/samples/keepalived.conf.vrrp.rules b/doc/samples/keepalived.conf.vrrp.rules new file mode 100644 index 0000000..10d032a --- /dev/null +++ b/doc/samples/keepalived.conf.vrrp.rules @@ -0,0 +1,26 @@ +! Configuration File for keepalived + +global_defs { + router_id LVS_DEVEL +} + +static_rules { + from 192.168.100.0/24 table 1 + to 192.168.100./24 table 1 +} + +vrrp_instance VI_1 { + state MASTER + interface eth0 + virtual_router_id 51 + priority 100 + virtual_ipaddress { + 192.168.200.16 + 192.168.200.17 dev eth1 + 192.168.200.18 dev eth2 + } + virtual_rules { + from 192.168.200.0/24 table 2 + to 192.168.200./24 table 2 + } +} diff --git a/keepalived/include/vrrp.h b/keepalived/include/vrrp.h index 2d6dded..37c29ca 100644 --- a/keepalived/include/vrrp.h +++ b/keepalived/include/vrrp.h @@ -30,6 +30,7 @@ /* local include */ #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" +#include "vrrp_iprule.h" #include "vrrp_ipsecah.h" #include "vrrp_if.h" #include "vrrp_track.h" @@ -166,6 +167,7 @@ typedef struct _vrrp_t { * VRRP adverts */ list vroutes; /* list of virtual routes */ + list vrules; /* list of virtual rules */ int adver_int; /* locally configured delay between advertisements*/ int master_adver_int; /* In v3, when we become BACKUP, we use the MASTER's * adver_int. If we become MASTER again, we use the diff --git a/keepalived/include/vrrp_data.h b/keepalived/include/vrrp_data.h index 2bbc6a2..3851f01 100644 --- a/keepalived/include/vrrp_data.h +++ b/keepalived/include/vrrp_data.h @@ -56,6 +56,7 @@ typedef struct _sock { typedef struct _vrrp_data { list static_addresses; list static_routes; + list static_rules; list vrrp_sync_group; list vrrp; list vrrp_index; @@ -72,6 +73,7 @@ extern char *vrrp_buffer; /* prototypes */ extern void alloc_saddress(vector_t *); extern void alloc_sroute(vector_t *); +extern void alloc_srule(vector_t *); extern void alloc_vrrp_sync_group(char *); extern void alloc_vrrp(char *); extern vrrp_stats *alloc_vrrp_stats(void); @@ -82,6 +84,7 @@ extern void alloc_vrrp_track_script(vector_t *); extern void alloc_vrrp_vip(vector_t *); extern void alloc_vrrp_evip(vector_t *); extern void alloc_vrrp_vroute(vector_t *); +extern void alloc_vrrp_vrule(vector_t *); extern void alloc_vrrp_buffer(void); extern void free_vrrp_buffer(void); extern vrrp_data_t *alloc_vrrp_data(void); diff --git a/keepalived/include/vrrp_iprule.h b/keepalived/include/vrrp_iprule.h new file mode 100644 index 0000000..fe2c85e --- /dev/null +++ b/keepalived/include/vrrp_iprule.h @@ -0,0 +1,63 @@ +/* + * Soft: Keepalived is a failover program for the LVS project + * . It monitor & manipulate + * a loadbalanced server pool using multi-layer checks. + * + * Part: vrrp_iprule.c include file. + * + * Author: Chris Riley, + * + * This program 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. + * + * This program 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 of the License, or (at your option) any later version. + * + * Copyright (C) 2015 Chris Riley, + */ + +#ifndef _VRRP_IPRULE_H +#define _VRRP_IPRULE_H + +/* global includes */ +#include +#include +#include + +/* local includes */ +#include "list.h" +#include "vector.h" +#include "utils.h" + + /* types definition */ +typedef struct _ip_rule { + char *dir; + ip_address_t *addr; + uint8_t mask; + int table; + int set; +} ip_rule_t; + +#define IPRULE_DEL 0 +#define IPRULE_ADD 1 + +/* Macro definition */ +#define RULE_ISEQ(X,Y) (string_equal((X)->dir, (Y)->dir) && \ + IP_ISEQ((X)->addr, (Y)->addr) && \ + (X)->mask == (Y)->mask && \ + (X)->table == (Y)->table) + +/* prototypes */ +extern int netlink_rule(ip_rule_t *, int); +extern void netlink_rulelist(list, int); +extern void free_iprule(void *); +extern void dump_iprule(void *); +extern void alloc_rule(list, vector_t *); +extern void clear_diff_rules(list, list); +extern void clear_diff_srules(void); + +#endif diff --git a/keepalived/include/vrrp_print.h b/keepalived/include/vrrp_print.h index 8307260..e2f87fa 100644 --- a/keepalived/include/vrrp_print.h +++ b/keepalived/include/vrrp_print.h @@ -32,4 +32,5 @@ extern void vgroup_print(FILE *file, void *d); extern void vscript_print(FILE *file, void *d); extern void address_print(FILE *file, void *d); extern void route_print(FILE *file, void *d); +extern void rule_print(FILE *file, void *d); extern void if_print(FILE *file, void *d); diff --git a/keepalived/include/vrrp_snmp.h b/keepalived/include/vrrp_snmp.h index 234714d..35205ba 100644 --- a/keepalived/include/vrrp_snmp.h +++ b/keepalived/include/vrrp_snmp.h @@ -101,6 +101,12 @@ #define VRRP_SNMP_TRACKEDINTERFACE_WEIGHT 72 #define VRRP_SNMP_TRACKEDSCRIPT_NAME 74 #define VRRP_SNMP_TRACKEDSCRIPT_WEIGHT 75 +#define VRRP_SNMP_RULE_DIRECTION 77 +#define VRRP_SNMP_RULE_ADDRESSTYPE 78 +#define VRRP_SNMP_RULE_ADDRESS 79 +#define VRRP_SNMP_RULE_ADDRESSMASK 80 +#define VRRP_SNMP_RULE_ROUTINGTABLE 81 +#define VRRP_SNMP_RULE_ISSET 82 #define HEADER_STATE_STATIC_ADDRESS 1 @@ -108,6 +114,8 @@ #define HEADER_STATE_EXCLUDED_VIRTUAL_ADDRESS 3 #define HEADER_STATE_STATIC_ROUTE 4 #define HEADER_STATE_VIRTUAL_ROUTE 5 +#define HEADER_STATE_STATIC_RULE 6 +#define HEADER_STATE_VIRTUAL_RULE 7 #define HEADER_STATE_END 10 diff --git a/keepalived/vrrp/Makefile.in b/keepalived/vrrp/Makefile.in index 99e66d3..8f4a59b 100644 --- a/keepalived/vrrp/Makefile.in +++ b/keepalived/vrrp/Makefile.in @@ -15,7 +15,7 @@ COMPILE = $(CC) $(CFLAGS) $(DEFS) OBJS = vrrp_daemon.o vrrp_print.o vrrp_data.o vrrp_parser.o \ vrrp.o vrrp_notify.o vrrp_scheduler.o vrrp_sync.o vrrp_index.o \ vrrp_netlink.o vrrp_arp.o vrrp_if.o vrrp_track.o vrrp_ipaddress.o \ - vrrp_iproute.o vrrp_ipsecah.o vrrp_ndisc.o vrrp_vmac.o + vrrp_iproute.o vrrp_iprule.o vrrp_ipsecah.o vrrp_ndisc.o vrrp_vmac.o ifeq ($(SNMP_FLAG),_WITH_SNMP_) OBJS += vrrp_snmp.o endif @@ -34,7 +34,7 @@ distclean: clean vrrp_daemon.o: vrrp_daemon.c ../include/vrrp_daemon.h ../include/vrrp_scheduler.h \ ../include/vrrp_if.h ../include/vrrp_arp.h ../include/vrrp_netlink.h ../include/vrrp_iproute.h \ - ../include/vrrp_iproute.h ../include/vrrp_parser.h ../include/vrrp_data.h \ + ../include/vrrp_iproute.h ../include/vrrp_iprule.h ../include/vrrp_parser.h ../include/vrrp_data.h \ ../include/vrrp.h ../include/global_data.h ../include/pidfile.h ../include/daemon.h \ ../include/ipvswrapper.h ../../lib/list.h ../../lib/memory.h ../../lib/parser.h \ ../../lib/signals.h ../../lib/bitops.h ../include/snmp.h ../include/vrrp_snmp.h ../include/vrrp_print.h @@ -76,6 +76,8 @@ vrrp_ipaddress.o: vrrp_ipaddress.c ../include/vrrp_ipaddress.h ../include/vrrp_n ../../lib/bitops.h vrrp_iproute.o: vrrp_iproute.c ../include/vrrp_iproute.h ../include/vrrp_netlink.h \ ../include/vrrp_if.h ../include/vrrp_data.h ../../lib/memory.h ../../lib/utils.h +vrrp_iprule.o: vrrp_iprule.c ../include/vrrp_iprule.h ../include/vrrp_netlink.h \ + ../include/vrrp_if.h ../include/vrrp_data.h ../../lib/memory.h ../../lib/utils.h vrrp_ipsecah.o: vrrp_ipsecah.c ../include/vrrp_ipsecah.h vrrp_ndisc.o: vrrp_ndisc.c ../include/vrrp_ndisc.h ../include/vrrp_ipaddress.h \ ../../lib/utils.h ../../lib/memory.h @@ -84,5 +86,5 @@ vrrp_vmac.o: vrrp_vmac.c ../include/vrrp_vmac.h ../include/vrrp_netlink.h \ ../../lib/bitops.h vrrp_snmp.o: vrrp_snmp.c ../include/vrrp_snmp.h ../include/vrrp_track.h \ ../include/vrrp_data.h ../include/vrrp_ipaddress.h ../include/vrrp_iproute.h \ - ../include/vrrp.h ../../lib/vector.h ../../lib/list.h ../include/snmp.h \ + ../include/vrrp_iprule.h ../include/vrrp.h ../../lib/vector.h ../../lib/list.h ../include/snmp.h \ ../include/global_data.h ../../lib/logger.h diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c index d6f3cc2..bb42a44 100644 --- a/keepalived/vrrp/vrrp.c +++ b/keepalived/vrrp/vrrp.c @@ -71,6 +71,18 @@ vrrp_handle_iproutes(vrrp_t * vrrp, int cmd) return 1; } +/* add/remove Virtual rules */ +static int +vrrp_handle_iprules(vrrp_t * vrrp, int cmd) +{ + if (__test_bit(LOG_DETAIL_BIT, &debug)) + log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol Virtual Rules", + vrrp->iname, + (cmd == IPRULE_ADD) ? "setting" : "removing"); + netlink_rulelist(vrrp->vrules, cmd); + return 1; +} + /* add/remove iptable drop rules based on accept mode */ static void vrrp_handle_accept_mode(vrrp_t *vrrp, int cmd) @@ -1038,6 +1050,10 @@ vrrp_state_become_master(vrrp_t * vrrp) if (!LIST_ISEMPTY(vrrp->vroutes)) vrrp_handle_iproutes(vrrp, IPROUTE_ADD); + /* add virtual rules */ + if (!LIST_ISEMPTY(vrrp->vrules)) + vrrp_handle_iprules(vrrp, IPRULE_ADD); + /* remotes neighbour update */ vrrp_send_link_update(vrrp, vrrp->garp_rep); @@ -1105,6 +1121,10 @@ vrrp_restore_interface(vrrp_t * vrrp, int advF) if (!LIST_ISEMPTY(vrrp->vroutes)) vrrp_handle_iproutes(vrrp, IPROUTE_DEL); + /* remove virtual rules */ + if (!LIST_ISEMPTY(vrrp->vrules)) + vrrp_handle_iprules(vrrp, IPRULE_DEL); + /* * Remove the ip addresses. * @@ -1539,7 +1559,7 @@ shutdown_vrrp_instances(void) for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); - /* Remove VIPs/VROUTEs */ + /* Remove VIPs/VROUTEs/VRULEs */ if (vrrp->state == VRRP_STATE_MAST) vrrp_restore_interface(vrrp, 1); @@ -1677,6 +1697,14 @@ clear_diff_vrrp_vroutes(vrrp_t * old_vrrp) clear_diff_routes(old_vrrp->vroutes, vrrp->vroutes); } +/* Clear virtual rules not present in the new data */ +static void +clear_diff_vrrp_vrules(vrrp_t * old_vrrp) +{ + vrrp_t *vrrp = vrrp_exist(old_vrrp); + clear_diff_rules(old_vrrp->vrules, vrrp->vrules); +} + /* Keep the state from before reload */ static void reset_vrrp_state(vrrp_t * old_vrrp) @@ -1717,6 +1745,8 @@ reset_vrrp_state(vrrp_t * old_vrrp) vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE); if (!LIST_ISEMPTY(vrrp->vroutes)) vrrp_handle_iproutes(vrrp, IPROUTE_ADD); + if (!LIST_ISEMPTY(vrrp->vrules)) + vrrp_handle_iprules(vrrp, IPRULE_ADD); } } @@ -1757,6 +1787,9 @@ clear_diff_vrrp(void) /* virtual routes diff */ clear_diff_vrrp_vroutes(vrrp); + /* virtual rules diff */ + clear_diff_vrrp_vrules(vrrp); + /* * Remove VMAC if it existed in old vrrp instance, * but not the new one. diff --git a/keepalived/vrrp/vrrp_daemon.c b/keepalived/vrrp/vrrp_daemon.c index 914fbff..70aed67 100644 --- a/keepalived/vrrp/vrrp_daemon.c +++ b/keepalived/vrrp/vrrp_daemon.c @@ -28,6 +28,7 @@ #include "vrrp_netlink.h" #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" +#include "vrrp_iprule.h" #include "vrrp_parser.h" #include "vrrp_data.h" #include "vrrp.h" @@ -55,13 +56,12 @@ extern char *vrrp_pidfile; static void stop_vrrp(void) { - signal_handler_destroy(); - if (!__test_bit(DONT_RELEASE_VRRP_BIT, &debug)) shutdown_vrrp_instances(); /* Clear static entries */ netlink_rtlist(vrrp_data->static_routes, IPROUTE_DEL); + netlink_rulelist(vrrp_data->static_rules, IPRULE_DEL); netlink_iplist(vrrp_data->static_addresses, IPADDRESS_DEL); #ifdef _WITH_SNMP_ @@ -90,6 +90,8 @@ stop_vrrp(void) gratuitous_arp_close(); ndisc_close(); + signal_handler_destroy(); + #ifdef _DEBUG_ keepalived_free_final("VRRP Child process"); #endif @@ -139,6 +141,7 @@ start_vrrp(void) if (reload) { clear_diff_saddresses(); + clear_diff_srules(); clear_diff_sroutes(); clear_diff_vrrp(); clear_diff_script(); @@ -157,6 +160,7 @@ start_vrrp(void) /* Set static entries */ netlink_iplist(vrrp_data->static_addresses, IPADDRESS_ADD); + netlink_rulelist(vrrp_data->static_rules, IPRULE_ADD); netlink_rtlist(vrrp_data->static_routes, IPROUTE_ADD); /* Dump configuration */ diff --git a/keepalived/vrrp/vrrp_data.c b/keepalived/vrrp/vrrp_data.c index 7371fc0..07b47f4 100644 --- a/keepalived/vrrp/vrrp_data.c +++ b/keepalived/vrrp/vrrp_data.c @@ -54,6 +54,15 @@ alloc_sroute(vector_t *strvec) alloc_route(vrrp_data->static_routes, strvec); } +/* Static rules facility function */ +void +alloc_srule(vector_t *strvec) +{ + if (LIST_ISEMPTY(vrrp_data->static_rules)) + vrrp_data->static_rules = alloc_list(free_iprule, dump_iprule); + alloc_rule(vrrp_data->static_rules, strvec); +} + /* VRRP facility functions */ static void free_vgroup(void *data) @@ -217,6 +226,7 @@ free_vrrp(void *data) free_list(vrrp->vip); free_list(vrrp->evip); free_list(vrrp->vroutes); + free_list(vrrp->vrules); FREE(vrrp); } static void @@ -299,6 +309,10 @@ dump_vrrp(void *data) log_message(LOG_INFO, " Virtual Routes = %d", LIST_SIZE(vrrp->vroutes)); dump_list(vrrp->vroutes); } + if (!LIST_ISEMPTY(vrrp->vrules)) { + log_message(LOG_INFO, " Virtual Rules = %d", LIST_SIZE(vrrp->vrules)); + dump_list(vrrp->vrules); + } if (vrrp->script_backup) log_message(LOG_INFO, " Backup state transition script = %s", vrrp->script_backup); if (vrrp->script_master) @@ -473,6 +487,16 @@ alloc_vrrp_vroute(vector_t *strvec) } void +alloc_vrrp_vrule(vector_t *strvec) +{ + vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); + + if (LIST_ISEMPTY(vrrp->vrules)) + vrrp->vrules = alloc_list(free_iprule, dump_iprule); + alloc_rule(vrrp->vrules, strvec); +} + +void alloc_vrrp_script(char *sname) { int size = strlen(sname); @@ -526,6 +550,7 @@ free_vrrp_data(vrrp_data_t * data) { free_list(data->static_addresses); free_list(data->static_routes); + free_list(data->static_rules); free_mlist(data->vrrp_index, 255+1); free_mlist(data->vrrp_index_fd, 1024+1); free_list(data->vrrp); @@ -545,6 +570,10 @@ dump_vrrp_data(vrrp_data_t * data) log_message(LOG_INFO, "------< Static Routes >------"); dump_list(data->static_routes); } + if (!LIST_ISEMPTY(data->static_rules)) { + log_message(LOG_INFO, "------< Static Rules >------"); + dump_list(data->static_rules); + } if (!LIST_ISEMPTY(data->vrrp)) { log_message(LOG_INFO, "------< VRRP Topology >------"); dump_list(data->vrrp); diff --git a/keepalived/vrrp/vrrp_iprule.c b/keepalived/vrrp/vrrp_iprule.c new file mode 100644 index 0000000..e11f477 --- /dev/null +++ b/keepalived/vrrp/vrrp_iprule.c @@ -0,0 +1,235 @@ +/* + * Soft: Keepalived is a failover program for the LVS project + * . It monitor & manipulate + * a loadbalanced server pool using multi-layer checks. + * + * Part: NETLINK IPv4 rules manipulation. + * + * Author: Chris Riley, + * + * This program 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. + * + * This program 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 of the License, or (at your option) any later version. + * + * Copyright (C) 2015 Chris Riley, + */ + +/* global includes */ +#include +#include + +/* local include */ +#include "vrrp_ipaddress.h" +#include "vrrp_iprule.h" +#include "vrrp_netlink.h" +#include "vrrp_if.h" +#include "vrrp_data.h" +#include "logger.h" +#include "memory.h" +#include "utils.h" + +/* Utility functions */ +static int +add_addr2req(struct nlmsghdr *n, int maxlen, int type, ip_address_t *ip_address) +{ + void *addr; + int alen; + + if (!ip_address) + return -1; + + addr = (IP_IS6(ip_address)) ? (void *) &ip_address->u.sin6_addr : + (void *) &ip_address->u.sin.sin_addr; + alen = (IP_IS6(ip_address)) ? sizeof(ip_address->u.sin6_addr) : + sizeof(ip_address->u.sin.sin_addr); + + return addattr_l(n, maxlen, type, addr, alen); +} + +/* Add/Delete IP rule to/from a specific IP/network */ +int +netlink_rule(ip_rule_t *iprule, int cmd) +{ + int status = 1; + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + memset(&req, 0, sizeof (req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; + req.n.nlmsg_type = cmd ? RTM_NEWRULE : RTM_DELRULE; + req.r.rtm_family = IP_FAMILY(iprule->addr); + req.r.rtm_table = iprule->table ? iprule->table : RT_TABLE_MAIN; + req.r.rtm_type = RTN_UNSPEC; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_flags = 0; + + if (cmd) { + req.r.rtm_protocol = RTPROT_BOOT; + req.r.rtm_type = RTN_UNICAST; + } + + /* Set rule entry */ + if (strcmp(iprule->dir, "from") == 0) { + req.r.rtm_src_len = iprule->mask; + add_addr2req(&req.n, sizeof(req), FRA_SRC, iprule->addr); + } else if (strcmp(iprule->dir, "to") == 0) { + req.r.rtm_dst_len = iprule->mask; + add_addr2req(&req.n, sizeof(req), FRA_DST, iprule->addr); + } + + if (netlink_talk(&nl_cmd, &req.n) < 0) + status = -1; + return status; +} + +void +netlink_rulelist(list rule_list, int cmd) +{ + ip_rule_t *iprule; + element e; + + /* No rules to add */ + if (LIST_ISEMPTY(rule_list)) + return; + + for (e = LIST_HEAD(rule_list); e; ELEMENT_NEXT(e)) { + iprule = ELEMENT_DATA(e); + if ((cmd && !iprule->set) || + (!cmd && iprule->set)) { + if (netlink_rule(iprule, cmd) > 0) + iprule->set = (cmd) ? 1 : 0; + else + iprule->set = 0; + } + } +} + +/* Rule dump/allocation */ +void +free_iprule(void *rule_data) +{ + FREE(rule_data); +} +void +dump_iprule(void *rule_data) +{ + ip_rule_t *rule = rule_data; + char *log_msg = MALLOC(1024); + char *tmp = MALLOC(INET6_ADDRSTRLEN + 30); + char *tmp_str; + + if (rule->dir) { + snprintf(tmp, INET6_ADDRSTRLEN + 30, "%s ", rule->dir); + strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); + } + if (rule->addr) { + tmp_str = ipaddresstos(rule->addr); + snprintf(tmp, INET6_ADDRSTRLEN + 30, "%s/%d", tmp_str, rule->mask); + strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); + FREE(tmp_str); + } + if (rule->table) { + snprintf(tmp, INET6_ADDRSTRLEN + 30, " table %d", rule->table); + strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); + } + + log_message(LOG_INFO, " %s", log_msg); + + FREE(tmp); + FREE(log_msg); +} +void +alloc_rule(list rule_list, vector_t *strvec) +{ + ip_rule_t *new; + char *str; + int i = 0; + + new = (ip_rule_t *) MALLOC(sizeof(ip_rule_t)); + + /* FMT parse */ + while (i < vector_size(strvec)) { + str = vector_slot(strvec, i); + + if (!strcmp(str, "from")) { + new->dir = "from"; + new->addr = parse_ipaddress(NULL, vector_slot(strvec, ++i)); + new->mask = new->addr->ifa.ifa_prefixlen; + } else if (!strcmp(str, "to")) { + new->dir = "to"; + new->addr = parse_ipaddress(NULL, vector_slot(strvec, ++i)); + new->mask = new->addr->ifa.ifa_prefixlen; + } else if (!strcmp(str, "table")) { + new->table = atoi(vector_slot(strvec, ++i)); + } + i++; + } + + list_add(rule_list, new); +} + +/* Try to find a rule in a list */ +int +rule_exist(list l, ip_rule_t *iprule) +{ + ip_rule_t *ipr; + element e; + + for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { + ipr = ELEMENT_DATA(e); + if (RULE_ISEQ(ipr, iprule)) { + ipr->set = iprule->set; + return 1; + } + } + return 0; +} + +/* Clear diff rules */ +void +clear_diff_rules(list l, list n) +{ + ip_rule_t *iprule; + char *tmp_str; + element e; + + /* No rule in previous conf */ + if (LIST_ISEMPTY(l)) + return; + + /* All Static rules removed */ + if (LIST_ISEMPTY(n)) { + log_message(LOG_INFO, "Removing a VirtualRule block"); + netlink_rulelist(l, IPRULE_DEL); + return; + } + + for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { + iprule = ELEMENT_DATA(e); + if (!rule_exist(n, iprule) && iprule->set) { + tmp_str = ipaddresstos(iprule->addr); + log_message(LOG_INFO, "ip rule %s/%d ... , no longer exist" + , tmp_str, iprule->mask); + FREE(tmp_str); + netlink_rule(iprule, IPRULE_DEL); + } + } +} + +/* Diff conf handler */ +void +clear_diff_srules(void) +{ + clear_diff_rules(old_vrrp_data->static_rules, vrrp_data->static_rules); +} diff --git a/keepalived/vrrp/vrrp_parser.c b/keepalived/vrrp/vrrp_parser.c index 270e550..1788a58 100644 --- a/keepalived/vrrp/vrrp_parser.c +++ b/keepalived/vrrp/vrrp_parser.c @@ -50,6 +50,13 @@ static_routes_handler(vector_t *strvec) alloc_value_block(strvec, alloc_sroute); } +/* Static rules handler */ +static void +static_rules_handler(vector_t *strvec) +{ + alloc_value_block(strvec, alloc_srule); +} + /* VRRP handlers */ static void vrrp_sync_group_handler(vector_t *strvec) @@ -488,6 +495,11 @@ vrrp_vroutes_handler(vector_t *strvec) alloc_value_block(strvec, alloc_vrrp_vroute); } static void +vrrp_vrules_handler(vector_t *strvec) +{ + alloc_value_block(strvec, alloc_vrrp_vrule); +} +static void vrrp_script_handler(vector_t *strvec) { alloc_vrrp_script(vector_slot(strvec, 1)); @@ -568,6 +580,7 @@ vrrp_init_keywords(void) /* Static routes mapping */ install_keyword_root("static_ipaddress", &static_addresses_handler); install_keyword_root("static_routes", &static_routes_handler); + install_keyword_root("static_rules", &static_rules_handler); /* VRRP Instance mapping */ install_keyword_root("vrrp_sync_group", &vrrp_sync_group_handler); @@ -597,6 +610,7 @@ vrrp_init_keywords(void) install_keyword("virtual_ipaddress", &vrrp_vip_handler); install_keyword("virtual_ipaddress_excluded", &vrrp_evip_handler); install_keyword("virtual_routes", &vrrp_vroutes_handler); + install_keyword("virtual_rules", &vrrp_vrules_handler); install_keyword("accept", &vrrp_accept_handler); install_keyword("preempt", &vrrp_preempt_handler); install_keyword("nopreempt", &vrrp_nopreempt_handler); diff --git a/keepalived/vrrp/vrrp_print.c b/keepalived/vrrp/vrrp_print.c index 770fb5c..455accb 100644 --- a/keepalived/vrrp/vrrp_print.c +++ b/keepalived/vrrp/vrrp_print.c @@ -26,6 +26,7 @@ #include "vrrp_data.h" #include "vrrp_print.h" #include "vrrp_iproute.h" +#include "vrrp_iprule.h" #include "vrrp_netlink.h" void @@ -180,6 +181,10 @@ vrrp_print(FILE *file, void *data) fprintf(file, " Virtual Routes = %d\n", LIST_SIZE(vrrp->vroutes)); vrrp_print_list(file, vrrp->vroutes, &route_print); } + if (!LIST_ISEMPTY(vrrp->vrules)) { + fprintf(file, " Virtual Rules = %d\n", LIST_SIZE(vrrp->vrules)); + vrrp_print_list(file, vrrp->vrules, &rule_print); + } if (vrrp->script_backup) fprintf(file, " Backup state transition script = %s\n", vrrp->script_backup); @@ -337,6 +342,33 @@ route_print(FILE *file, void *data) } void +rule_print(FILE *file, void *data) +{ + ip_rule_t *rule = data; + char *msg = MALLOC(150); + char *tmp = MALLOC(30); + + if (rule->dir) { + snprintf(tmp, 30, "%s ", rule->dir); + strncat(msg, tmp, 30); + } + if (rule->addr) { + snprintf(tmp, 30, "%s", ipaddresstos(rule->addr)); + strncat(msg, tmp, 30); + } + if (rule->table) { + snprintf(tmp, 30, " table %d", rule->table); + strncat(msg, tmp, 30); + } + + fprintf(file, " %s\n", msg); + + FREE(tmp); + FREE(msg); + +} + +void if_print(FILE *file, void * data) { tracked_if_t *tip = data; diff --git a/keepalived/vrrp/vrrp_snmp.c b/keepalived/vrrp/vrrp_snmp.c index 436bf3b..e7cac43 100644 --- a/keepalived/vrrp/vrrp_snmp.c +++ b/keepalived/vrrp/vrrp_snmp.c @@ -26,6 +26,7 @@ #include "vrrp_track.h" #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" +#include "vrrp_iprule.h" #include "config.h" #include "vector.h" #include "list.h" @@ -219,6 +220,26 @@ vrrp_header_ar_table(struct variable *vp, oid *name, size_t *length, current[1] = 0; nextstate = HEADER_STATE_VIRTUAL_ROUTE; break; + case HEADER_STATE_STATIC_RULE: + /* Try static routes */ + l2 = vrrp_data->static_rules; + current[1] = 0; + nextstate = HEADER_STATE_VIRTUAL_RULE; + break; + case HEADER_STATE_VIRTUAL_RULE: + /* Try virtual rules */ + if (LIST_ISEMPTY(vrrp_data->vrrp) || + ((e1 != NULL) && (ELEMENT_NEXT(e1), !e1))) { + nextstate = HEADER_STATE_END; + continue; + } + curinstance++; + if (e1 == NULL) + e1 = LIST_HEAD(vrrp_data->vrrp); + l2 = ((vrrp_t *)ELEMENT_DATA(e1))->vrules; + current[1] = 0; + nextstate = HEADER_STATE_VIRTUAL_RULE; + break; default: return NULL; /* Big problem! */ } @@ -434,6 +455,56 @@ vrrp_snmp_route(struct variable *vp, oid *name, size_t *length, } static u_char* +vrrp_snmp_rule(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + ip_rule_t *rule; + int state = HEADER_STATE_STATIC_RULE; + + if ((rule = (ip_rule_t *) + vrrp_header_ar_table(vp, name, length, exact, + var_len, write_method, + &state)) == NULL) + return NULL; + + switch (vp->magic) { + case VRRP_SNMP_RULE_DIRECTION: + *var_len = strlen(rule->dir); + return (u_char *)rule->dir; + case VRRP_SNMP_RULE_ADDRESSTYPE: + long_ret = (rule->addr->ifa.ifa_family == AF_INET6)?2:1; + return (u_char *)&long_ret; + case VRRP_SNMP_RULE_ADDRESS: + if (rule->addr->ifa.ifa_family == AF_INET6) { + *var_len = 16; + return (u_char *)&rule->addr->u.sin6_addr; + } else { + *var_len = 4; + return (u_char *)&rule->addr->u.sin.sin_addr; + } + break; + case VRRP_SNMP_RULE_ADDRESSMASK: + long_ret = rule->mask; + return (u_char *)&long_ret; + case VRRP_SNMP_RULE_ROUTINGTABLE: + long_ret = rule->table; + return (u_char *)&long_ret; + case VRRP_SNMP_RULE_ISSET: + long_ret = (rule->set)?1:2; + return (u_char *)&long_ret; + default: + return NULL; + } + /* If we are here, we asked for a non existent data. Try the + next one. */ + if (!exact && (name[*length-1] < MAX_SUBID)) + return vrrp_snmp_rule(vp, name, length, + exact, var_len, write_method); + return NULL; +} + +static u_char* vrrp_snmp_syncgroup(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { @@ -1272,14 +1343,27 @@ static struct variable8 vrrp_vars[] = { vrrp_snmp_route, 3, {7, 1, 13}}, {VRRP_SNMP_ROUTE_ISSET, ASN_INTEGER, RONLY, vrrp_snmp_route, 3, {7, 1, 14}}, + /* vrrpRuleTable */ + {VRRP_SNMP_RULE_DIRECTION, ASN_OCTET_STR, RONLY, + vrrp_snmp_rule, 3, {8, 1, 2}}, + {VRRP_SNMP_RULE_ADDRESSTYPE, ASN_INTEGER, RONLY, + vrrp_snmp_rule, 3, {8, 1, 3}}, + {VRRP_SNMP_RULE_ADDRESS, ASN_OCTET_STR, RONLY, + vrrp_snmp_rule, 3, {8, 1, 4}}, + {VRRP_SNMP_RULE_ADDRESSMASK, ASN_UNSIGNED, RONLY, + vrrp_snmp_rule, 3, {8, 1, 5}}, + {VRRP_SNMP_RULE_ROUTINGTABLE, ASN_UNSIGNED, RONLY, + vrrp_snmp_rule, 3, {8, 1, 6}}, + {VRRP_SNMP_RULE_ISSET, ASN_INTEGER, RONLY, + vrrp_snmp_rule, 3, {8, 1, 7}}, /* vrrpScriptTable */ - {VRRP_SNMP_SCRIPT_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_script, 3, {8, 1, 2}}, - {VRRP_SNMP_SCRIPT_COMMAND, ASN_OCTET_STR, RONLY, vrrp_snmp_script, 3, {8, 1, 3}}, - {VRRP_SNMP_SCRIPT_INTERVAL, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {8, 1, 4}}, - {VRRP_SNMP_SCRIPT_WEIGHT, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {8, 1, 5}}, - {VRRP_SNMP_SCRIPT_RESULT, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {8, 1, 6}}, - {VRRP_SNMP_SCRIPT_RISE, ASN_UNSIGNED, RONLY, vrrp_snmp_script, 3, {8, 1, 7}}, - {VRRP_SNMP_SCRIPT_FALL, ASN_UNSIGNED, RONLY, vrrp_snmp_script, 3, {8, 1, 8}}, + {VRRP_SNMP_SCRIPT_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_script, 3, {9, 1, 2}}, + {VRRP_SNMP_SCRIPT_COMMAND, ASN_OCTET_STR, RONLY, vrrp_snmp_script, 3, {9, 1, 3}}, + {VRRP_SNMP_SCRIPT_INTERVAL, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {9, 1, 4}}, + {VRRP_SNMP_SCRIPT_WEIGHT, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {9, 1, 5}}, + {VRRP_SNMP_SCRIPT_RESULT, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {9, 1, 6}}, + {VRRP_SNMP_SCRIPT_RISE, ASN_UNSIGNED, RONLY, vrrp_snmp_script, 3, {9, 1, 7}}, + {VRRP_SNMP_SCRIPT_FALL, ASN_UNSIGNED, RONLY, vrrp_snmp_script, 3, {9, 1, 8}}, }; void @@ -1344,7 +1428,7 @@ void vrrp_snmp_instance_trap(vrrp_t *vrrp) { /* OID of the notification */ - oid notification_oid[] = { VRRP_OID, 9, 0, 2 }; + oid notification_oid[] = { VRRP_OID, 10, 0, 2 }; size_t notification_oid_len = OID_LENGTH(notification_oid); /* OID for snmpTrapOID.0 */ oid objid_snmptrap[] = { SNMPTRAP_OID }; @@ -1412,7 +1496,7 @@ void vrrp_snmp_group_trap(vrrp_sgroup_t *group) { /* OID of the notification */ - oid notification_oid[] = { VRRP_OID, 9, 0, 1 }; + oid notification_oid[] = { VRRP_OID, 10, 0, 1 }; size_t notification_oid_len = OID_LENGTH(notification_oid); /* OID for snmpTrapOID.0 */ oid objid_snmptrap[] = { SNMPTRAP_OID }; -- 1.7.12.1