SBR: option to pass the table id (#1088)
* Use of Table ID in IPAM Signed-off-by: Lionel Jouin <lionel.jouin@est.tech> * SBR: option to pass the table id Using the option to set the table number in the SBR meta plugin will create a policy route for each IP added for the interface returned by the main plugin. Unlike the default behavior, the routes will not be moved to the table. The default behavior of the SBR plugin is kept if the table id is not set. Signed-off-by: Lionel Jouin <lionel.jouin@est.tech> --------- Signed-off-by: Lionel Jouin <lionel.jouin@est.tech>
This commit is contained in:
@ -47,6 +47,7 @@ type PluginConf struct {
|
||||
PrevResult *current.Result `json:"-"`
|
||||
|
||||
// Add plugin-specific flags here
|
||||
Table *int `json:"table,omitempty"`
|
||||
}
|
||||
|
||||
// Wrapper that does a lock before and unlock after operations to serialise
|
||||
@ -163,6 +164,9 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
|
||||
// Do the actual work.
|
||||
err = withLockAndNetNS(args.Netns, func(_ ns.NetNS) error {
|
||||
if conf.Table != nil {
|
||||
return doRoutesWithTable(ipCfgs, *conf.Table)
|
||||
}
|
||||
return doRoutes(ipCfgs, args.IfName)
|
||||
})
|
||||
if err != nil {
|
||||
@ -330,31 +334,73 @@ func doRoutes(ipCfgs []*current.IPConfig, iface string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func doRoutesWithTable(ipCfgs []*current.IPConfig, table int) error {
|
||||
for _, ipCfg := range ipCfgs {
|
||||
log.Printf("Set rule for source %s", ipCfg.String())
|
||||
rule := netlink.NewRule()
|
||||
rule.Table = table
|
||||
|
||||
// Source must be restricted to a single IP, not a full subnet
|
||||
var src net.IPNet
|
||||
src.IP = ipCfg.Address.IP
|
||||
if src.IP.To4() != nil {
|
||||
src.Mask = net.CIDRMask(32, 32)
|
||||
} else {
|
||||
src.Mask = net.CIDRMask(128, 128)
|
||||
}
|
||||
|
||||
log.Printf("Source to use %s", src.String())
|
||||
rule.Src = &src
|
||||
|
||||
if err := netlink.RuleAdd(rule); err != nil {
|
||||
return fmt.Errorf("failed to add rule: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cmdDel is called for DELETE requests
|
||||
func cmdDel(args *skel.CmdArgs) error {
|
||||
// We care a bit about config because it sets log level.
|
||||
_, err := parseConfig(args.StdinData)
|
||||
conf, err := parseConfig(args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Cleaning up SBR for %s", args.IfName)
|
||||
err = withLockAndNetNS(args.Netns, func(_ ns.NetNS) error {
|
||||
return tidyRules(args.IfName)
|
||||
return tidyRules(args.IfName, conf.Table)
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Tidy up the rules for the deleted interface
|
||||
func tidyRules(iface string) error {
|
||||
func tidyRules(iface string, table *int) error {
|
||||
// We keep on going on rule deletion error, but return the last failure.
|
||||
var errReturn error
|
||||
var err error
|
||||
var rules []netlink.Rule
|
||||
|
||||
rules, err := netlink.RuleList(netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
log.Printf("Failed to list all rules to tidy: %v", err)
|
||||
return fmt.Errorf("Failed to list all rules to tidy: %v", err)
|
||||
if table != nil {
|
||||
rules, err = netlink.RuleListFiltered(
|
||||
netlink.FAMILY_ALL,
|
||||
&netlink.Rule{
|
||||
Table: *table,
|
||||
},
|
||||
netlink.RT_FILTER_TABLE,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to list rules of table %d to tidy: %v", *table, err)
|
||||
return fmt.Errorf("failed to list rules of table %d to tidy: %v", *table, err)
|
||||
}
|
||||
} else {
|
||||
rules, err = netlink.RuleList(netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
log.Printf("Failed to list all rules to tidy: %v", err)
|
||||
return fmt.Errorf("Failed to list all rules to tidy: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
link, err := netlink.LinkByName(iface)
|
||||
|
@ -543,4 +543,81 @@ var _ = Describe("sbr test", func() {
|
||||
_, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("This plugin must be called as chained plugin"))
|
||||
})
|
||||
|
||||
It("Works with Table ID", func() {
|
||||
ifname := "net1"
|
||||
tableID := 5000
|
||||
conf := `{
|
||||
"cniVersion": "0.3.0",
|
||||
"name": "cni-plugin-sbr-test",
|
||||
"type": "sbr",
|
||||
"table": %d,
|
||||
"prevResult": {
|
||||
"cniVersion": "0.3.0",
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"address": "192.168.1.209/24",
|
||||
"interface": 0
|
||||
},
|
||||
{
|
||||
"address": "192.168.101.209/24",
|
||||
"interface": 0
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`
|
||||
conf = fmt.Sprintf(conf, tableID, ifname, targetNs.Path())
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: targetNs.Path(),
|
||||
IfName: ifname,
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
preStatus := createDefaultStatus()
|
||||
|
||||
err := setup(targetNs, preStatus)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
oldStatus, err := readback(targetNs, []string{"net1", "eth0"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
newStatus, err := readback(targetNs, []string{"net1", "eth0"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Routes have not been moved.
|
||||
Expect(newStatus).To(Equal(oldStatus))
|
||||
|
||||
// Fetch all rules for the requested table ID.
|
||||
var rules []netlink.Rule
|
||||
err = targetNs.Do(func(_ ns.NetNS) error {
|
||||
var err error
|
||||
rules, err = netlink.RuleListFiltered(
|
||||
netlink.FAMILY_ALL, &netlink.Rule{
|
||||
Table: tableID,
|
||||
},
|
||||
netlink.RT_FILTER_TABLE,
|
||||
)
|
||||
return err
|
||||
})
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(rules).To(HaveLen(2))
|
||||
|
||||
// Both IPs have been added as source based routes with requested table ID.
|
||||
Expect(rules[0].Table).To(Equal(tableID))
|
||||
Expect(rules[0].Src.String()).To(Equal("192.168.101.209/32"))
|
||||
Expect(rules[1].Table).To(Equal(tableID))
|
||||
Expect(rules[1].Src.String()).To(Equal("192.168.1.209/32"))
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user